{"id":5682,"date":"2021-11-22T10:47:30","date_gmt":"2021-11-22T09:47:30","guid":{"rendered":"https:\/\/solidt.eu\/site\/?p=5682"},"modified":"2021-11-22T10:49:13","modified_gmt":"2021-11-22T09:49:13","slug":"react-drag-drop-custom-implementation","status":"publish","type":"post","link":"https:\/\/solidt.eu\/site\/react-drag-drop-custom-implementation\/","title":{"rendered":"React: Drag Drop (Custom Implementation)"},"content":{"rendered":"\n<div style=\"height: 250px; position:relative; margin-bottom: 50px;\" class=\"wp-block-simple-code-block-ace\"><pre class=\"wp-block-simple-code-block-ace\" style=\"position:absolute;top:0;right:0;bottom:0;left:0\" data-mode=\"typescript\" data-theme=\"monokai\" data-fontsize=\"14\" data-lines=\"Infinity\" data-showlines=\"true\" data-copy=\"false\">\/\/ DragItem.tsx\nimport React, { DragEventHandler, useRef } from \"react\";\n\nexport interface IDragItem&lt;T> {\n    type: string;\n    data: T;\n}\n\nlet _dragItem: IDragItem&lt;any> | null = null;\n\nexport function getDragItem&lt;T>(): IDragItem&lt;T> | null {\n    return _dragItem;\n}\n\nexport function setDragItem(type: string, data: any) {\n    _dragItem = { type, data };\n}\n\nexport function clearDragItem() {\n    _dragItem = null;\n}\n\nexport function DragItem(props: { type: string, data?: any; children: any; className?: string, style?: React.CSSProperties }) {\n    const { type, data, children, className, style } = props;\n    const ref = useRef&lt;HTMLDivElement>(null);\n    const onDragStart: DragEventHandler&lt;HTMLDivElement> = (e) => {\n        setDragItem(type, data);\n        const div = (e.target as HTMLDivElement);\n        div.classList.add(\"dragging\");\n        \/\/ let img = new Image();\n        \/\/ img.src = 'example.gif';\n        \/\/ ev.dataTransfer.setDragImage(img, 10, 10);\n        \/\/ e.dataTransfer.dropEffect = \"copy\"; \/\/ copy | move | link\n    };\n    const onDragEnd: DragEventHandler&lt;HTMLDivElement> = (e) => {\n        clearDragItem();\n        const div = (e.target as HTMLDivElement);\n        div.classList.remove(\"dragging\");\n    };\n    return &lt;div ref={ref} className={className} style={style} draggable onDragStart={onDragStart} onDragEnd={onDragEnd}>{children}&lt;\/div>;\n}\n\n\/\/ DropZone.tsx\nexport interface IOnDroppedEvent&lt;T, U> {\n    x: number;\n    y: number;\n    pageX: number;\n    pageY: number;\n    item: T,\n    data: U,\n    target: EventTarget;\n}\n\nexport function DropZone&lt;T, U>(props: { types: string[], children: any, onDropped: (e: IOnDroppedEvent&lt;T, U>) => void, className?: string, style?: React.CSSProperties, item: T }) {\n    const { types, onDropped, children, className, style, item } = props;\n    const ref = useRef&lt;HTMLDivElement>(null);\n    const onDrop: DragEventHandler&lt;HTMLDivElement> = (e) => {\n        e.preventDefault();\n        const dragItem = getDragItem&lt;U>();\n        if (!dragItem) return false;\n        if (!types.includes(dragItem.type)) return false;\n        e.stopPropagation();\n        const div = ref.current!;\n        const rect = div.getBoundingClientRect();\n        const event: IOnDroppedEvent&lt;T, U> = {\n            x: e.pageX - rect.left,\n            y: e.pageY - rect.top,\n            pageX: e.pageX,\n            pageY: e.pageY,\n            item: item,\n            data: dragItem.data,\n            target: e.target\n        };\n        onDropped(event);\n        div.classList.remove(\"drag-over\");\n    };\n    const onDragOver: DragEventHandler&lt;HTMLDivElement> = (e) => {\n        const dragItem = getDragItem&lt;U>();\n        if (!dragItem) return false;\n        if (!types.includes(dragItem.type)) return false;\n        const div = ref.current!;\n        div.classList.add(\"drag-over\");\n        e.preventDefault(); \/\/ allow drop\n        e.stopPropagation();\n        return false;\n    };\n\n    const onDragEnter: DragEventHandler&lt;HTMLDivElement> = (e) => {\n        const dragItem = getDragItem&lt;U>();\n        if (!dragItem) return false;\n        if (!types.includes(dragItem.type)) return false;\n        const div = ref.current!;\n        div.classList.add(\"drag-over\");\n        e.preventDefault(); \/\/ allow drop\n        e.stopPropagation();\n        return false;\n    };\n    const onDragLeave: DragEventHandler&lt;HTMLDivElement> = (e) => {\n        const div = ref.current!;\n        div.classList.remove(\"drag-over\");\n        return false;\n    };\n    return &lt;div ref={ref} className={className} style={style}\n        onDrop={onDrop}\n        onDragOver={onDragOver}\n        onDragEnter={onDragEnter}\n        onDragLeave={onDragLeave}>{children}&lt;\/div>;\n}\n\n\n<\/pre><\/div>\n","protected":false},"excerpt":{"rendered":"","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"inline_featured_image":false,"footnotes":""},"categories":[1],"tags":[],"class_list":["post-5682","post","type-post","status-publish","format-standard","hentry","category-uncategorized"],"_links":{"self":[{"href":"https:\/\/solidt.eu\/site\/wp-json\/wp\/v2\/posts\/5682","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/solidt.eu\/site\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/solidt.eu\/site\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/solidt.eu\/site\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/solidt.eu\/site\/wp-json\/wp\/v2\/comments?post=5682"}],"version-history":[{"count":3,"href":"https:\/\/solidt.eu\/site\/wp-json\/wp\/v2\/posts\/5682\/revisions"}],"predecessor-version":[{"id":5686,"href":"https:\/\/solidt.eu\/site\/wp-json\/wp\/v2\/posts\/5682\/revisions\/5686"}],"wp:attachment":[{"href":"https:\/\/solidt.eu\/site\/wp-json\/wp\/v2\/media?parent=5682"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/solidt.eu\/site\/wp-json\/wp\/v2\/categories?post=5682"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/solidt.eu\/site\/wp-json\/wp\/v2\/tags?post=5682"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}