// DragItem.tsx
import React, { DragEventHandler, useRef } from "react";
export interface IDragItem<T> {
type: string;
data: T;
}
let _dragItem: IDragItem<any> | null = null;
export function getDragItem<T>(): IDragItem<T> | null {
return _dragItem;
}
export function setDragItem(type: string, data: any) {
_dragItem = { type, data };
}
export function clearDragItem() {
_dragItem = null;
}
export function DragItem(props: { type: string, data?: any; children: any; className?: string, style?: React.CSSProperties }) {
const { type, data, children, className, style } = props;
const ref = useRef<HTMLDivElement>(null);
const onDragStart: DragEventHandler<HTMLDivElement> = (e) => {
setDragItem(type, data);
const div = (e.target as HTMLDivElement);
div.classList.add("dragging");
// let img = new Image();
// img.src = 'example.gif';
// ev.dataTransfer.setDragImage(img, 10, 10);
// e.dataTransfer.dropEffect = "copy"; // copy | move | link
};
const onDragEnd: DragEventHandler<HTMLDivElement> = (e) => {
clearDragItem();
const div = (e.target as HTMLDivElement);
div.classList.remove("dragging");
};
return <div ref={ref} className={className} style={style} draggable onDragStart={onDragStart} onDragEnd={onDragEnd}>{children}</div>;
}
// DropZone.tsx
export interface IOnDroppedEvent<T, U> {
x: number;
y: number;
pageX: number;
pageY: number;
item: T,
data: U,
target: EventTarget;
}
export function DropZone<T, U>(props: { types: string[], children: any, onDropped: (e: IOnDroppedEvent<T, U>) => void, className?: string, style?: React.CSSProperties, item: T }) {
const { types, onDropped, children, className, style, item } = props;
const ref = useRef<HTMLDivElement>(null);
const onDrop: DragEventHandler<HTMLDivElement> = (e) => {
e.preventDefault();
const dragItem = getDragItem<U>();
if (!dragItem) return false;
if (!types.includes(dragItem.type)) return false;
e.stopPropagation();
const div = ref.current!;
const rect = div.getBoundingClientRect();
const event: IOnDroppedEvent<T, U> = {
x: e.pageX - rect.left,
y: e.pageY - rect.top,
pageX: e.pageX,
pageY: e.pageY,
item: item,
data: dragItem.data,
target: e.target
};
onDropped(event);
div.classList.remove("drag-over");
};
const onDragOver: DragEventHandler<HTMLDivElement> = (e) => {
const dragItem = getDragItem<U>();
if (!dragItem) return false;
if (!types.includes(dragItem.type)) return false;
const div = ref.current!;
div.classList.add("drag-over");
e.preventDefault(); // allow drop
e.stopPropagation();
return false;
};
const onDragEnter: DragEventHandler<HTMLDivElement> = (e) => {
const dragItem = getDragItem<U>();
if (!dragItem) return false;
if (!types.includes(dragItem.type)) return false;
const div = ref.current!;
div.classList.add("drag-over");
e.preventDefault(); // allow drop
e.stopPropagation();
return false;
};
const onDragLeave: DragEventHandler<HTMLDivElement> = (e) => {
const div = ref.current!;
div.classList.remove("drag-over");
return false;
};
return <div ref={ref} className={className} style={style}
onDrop={onDrop}
onDragOver={onDragOver}
onDragEnter={onDragEnter}
onDragLeave={onDragLeave}>{children}</div>;
}
568200cookie-checkReact: Drag Drop (Custom Implementation)