reworking on drag context
This commit is contained in:
51
src/components/draggable/draggable.js
Normal file
51
src/components/draggable/draggable.js
Normal file
@@ -0,0 +1,51 @@
|
||||
import { memo, useRef } from "react"
|
||||
import { useDragContext } from "./draggableContext"
|
||||
|
||||
|
||||
/**
|
||||
*
|
||||
* @param {string} - dragElementType - this will set the data-draggable-type which can be accessed on droppable to check if its allowed or not
|
||||
* @returns
|
||||
*/
|
||||
const DraggableWrapper = memo(({dragElementType, className, children}) => {
|
||||
|
||||
const { onDragStart, onDragEnd } = useDragContext()
|
||||
|
||||
const draggableRef = useRef(null)
|
||||
|
||||
/**
|
||||
*
|
||||
* @param {DragEvent} event
|
||||
*/
|
||||
const handleDragStart = (event) => {
|
||||
|
||||
// event.dataTransfer.setData("text/plain", "")
|
||||
|
||||
if (onDragStart)
|
||||
onDragStart(draggableRef?.current)
|
||||
|
||||
|
||||
}
|
||||
|
||||
const handleDragEnd = (e) => {
|
||||
// console.log("Drag end: ", e, e.target.closest('div'))
|
||||
|
||||
onDragEnd()
|
||||
}
|
||||
|
||||
return (
|
||||
<div className={`${className}`}
|
||||
draggable
|
||||
data-draggable-type={dragElementType}
|
||||
onDragStart={handleDragStart}
|
||||
onDragEnd={handleDragEnd}
|
||||
ref={draggableRef}
|
||||
>
|
||||
{children}
|
||||
</div>
|
||||
)
|
||||
|
||||
})
|
||||
|
||||
|
||||
export default DraggableWrapper
|
||||
24
src/components/draggable/draggableContext.js
Normal file
24
src/components/draggable/draggableContext.js
Normal file
@@ -0,0 +1,24 @@
|
||||
import React, { createContext, useContext, useState } from 'react';
|
||||
|
||||
const DragContext = createContext()
|
||||
|
||||
export const useDragContext = () => useContext(DragContext)
|
||||
|
||||
// Provider component to wrap around parts of your app that need drag-and-drop functionality
|
||||
export const DragProvider = ({ children }) => {
|
||||
const [draggedElement, setDraggedElement] = useState(null)
|
||||
|
||||
const onDragStart = (element) => {
|
||||
setDraggedElement(element)
|
||||
}
|
||||
|
||||
const onDragEnd = () => {
|
||||
setDraggedElement(null)
|
||||
}
|
||||
|
||||
return (
|
||||
<DragContext.Provider value={{ draggedElement, onDragStart, onDragEnd }}>
|
||||
{children}
|
||||
</DragContext.Provider>
|
||||
)
|
||||
}
|
||||
90
src/components/draggable/droppable.js
Normal file
90
src/components/draggable/droppable.js
Normal file
@@ -0,0 +1,90 @@
|
||||
import { memo, useState } from "react"
|
||||
import { useDragContext } from "./draggableContext"
|
||||
|
||||
|
||||
const DroppableWrapper = memo(({onDrop, droppableTags=["widget"], ...props}) => {
|
||||
|
||||
|
||||
const { draggedElement } = useDragContext()
|
||||
|
||||
const [showDroppable, setShowDroppable] = useState({
|
||||
show: false,
|
||||
allow: false
|
||||
})
|
||||
|
||||
|
||||
const handleDragEnter = (e) => {
|
||||
console.log("Drag Enter", draggedElement)
|
||||
|
||||
const dragElementType = draggedElement.getAttribute("data-draggable-type")
|
||||
|
||||
if (droppableTags.length === 0 || droppableTags.includes(dragElementType)){
|
||||
setShowDroppable({
|
||||
allow: true,
|
||||
show: true
|
||||
})
|
||||
}else{
|
||||
setShowDroppable({
|
||||
allow: false,
|
||||
show: true
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
const handleDragOver = (e) => {
|
||||
// console.log("Drag over: ", e.dataTransfer.getData("text/plain"), e.dataTransfer)
|
||||
const dragElementType = draggedElement.getAttribute("data-draggable-type")
|
||||
|
||||
if (droppableTags.length === 0 || droppableTags.includes(dragElementType)){
|
||||
e.preventDefault() // this is necessary to allow drop to take place
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
const handleDropEvent = (e) => {
|
||||
console.log("Drag over: ", e.dataTransfer.getData("text/plain"), e.dataTransfer)
|
||||
|
||||
setShowDroppable({
|
||||
allow: false,
|
||||
show: false
|
||||
})
|
||||
|
||||
if(onDrop){
|
||||
onDrop(e)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
const handleDragLeave = (e) => {
|
||||
if (!e.currentTarget.contains(e.relatedTarget)) {
|
||||
setShowDroppable({
|
||||
allow: false,
|
||||
show: false
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
return (
|
||||
<div className={`${props.className}`}
|
||||
onDragOver={handleDragOver}
|
||||
onDrop={handleDropEvent}
|
||||
onDragEnter={handleDragEnter}
|
||||
onDragLeave={handleDragLeave}
|
||||
>
|
||||
{
|
||||
showDroppable.show &&
|
||||
<div className={`${showDroppable.allow ? "tw-border-green-600" : "tw-border-red-600"}
|
||||
tw-absolute tw-top-0 tw-left-0 tw-w-full tw-h-full tw-z-[2]
|
||||
tw-border-2 tw-border-dashed tw-rounded-lg
|
||||
`}>
|
||||
</div>
|
||||
}
|
||||
{props.children}
|
||||
|
||||
</div>
|
||||
)
|
||||
|
||||
})
|
||||
|
||||
|
||||
export default DroppableWrapper
|
||||
Reference in New Issue
Block a user