2024-09-28 11:29:37 +05:30
|
|
|
import { memo, useEffect, useState } from "react"
|
2024-09-16 12:23:15 +05:30
|
|
|
import { useDragContext } from "./draggableContext"
|
|
|
|
|
|
|
|
|
|
|
2024-09-22 19:23:06 +05:30
|
|
|
/**
|
2024-09-23 12:31:01 +05:30
|
|
|
* @param {{include: [], exclude: []} || {} || null} - droppableTags - if empty object, allows everything to be dropped, if null nothing can be dropped, define include to allow only included widgets, define exclude to exclude
|
2024-09-22 19:23:06 +05:30
|
|
|
*/
|
|
|
|
|
const DroppableWrapper = memo(({onDrop, droppableTags={}, ...props}) => {
|
2024-09-16 12:23:15 +05:30
|
|
|
|
|
|
|
|
|
2024-09-22 12:39:03 +05:30
|
|
|
const { draggedElement, overElement, setOverElement, widgetClass } = useDragContext()
|
2024-09-16 12:23:15 +05:30
|
|
|
|
|
|
|
|
const [showDroppable, setShowDroppable] = useState({
|
|
|
|
|
show: false,
|
|
|
|
|
allow: false
|
|
|
|
|
})
|
|
|
|
|
|
2024-09-28 11:29:37 +05:30
|
|
|
useEffect(() => {
|
|
|
|
|
|
|
|
|
|
if (draggedElement === null){
|
|
|
|
|
setShowDroppable({
|
|
|
|
|
show: false,
|
|
|
|
|
allow: false
|
|
|
|
|
})
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
}, [draggedElement])
|
2024-09-16 12:23:15 +05:30
|
|
|
|
|
|
|
|
const handleDragEnter = (e) => {
|
|
|
|
|
|
2024-09-24 14:33:02 +05:30
|
|
|
if (!draggedElement || !draggedElement.getAttribute("data-drag-start-within")){
|
|
|
|
|
// if the drag is starting from outside (eg: file drop) or if drag doesn't exist
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
|
2024-09-16 12:23:15 +05:30
|
|
|
const dragElementType = draggedElement.getAttribute("data-draggable-type")
|
|
|
|
|
|
2024-09-17 18:32:33 +05:30
|
|
|
|
|
|
|
|
setOverElement(e.currentTarget)
|
|
|
|
|
|
2024-09-23 12:31:01 +05:30
|
|
|
const allowDrop = (droppableTags && droppableTags !== null && (Object.keys(droppableTags).length === 0 ||
|
2024-09-22 19:23:06 +05:30
|
|
|
(droppableTags.include?.length > 0 && droppableTags.include?.includes(dragElementType)) ||
|
|
|
|
|
(droppableTags.exclude?.length > 0 && !droppableTags.exclude?.includes(dragElementType))
|
|
|
|
|
))
|
|
|
|
|
|
|
|
|
|
if (allowDrop){
|
2024-09-16 12:23:15 +05:30
|
|
|
setShowDroppable({
|
|
|
|
|
allow: true,
|
|
|
|
|
show: true
|
|
|
|
|
})
|
|
|
|
|
}else{
|
|
|
|
|
setShowDroppable({
|
|
|
|
|
allow: false,
|
|
|
|
|
show: true
|
|
|
|
|
})
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const handleDragOver = (e) => {
|
2024-09-24 14:33:02 +05:30
|
|
|
|
|
|
|
|
if (!draggedElement || !draggedElement.getAttribute("data-drag-start-within")){
|
|
|
|
|
// if the drag is starting from outside (eg: file drop) or if drag doesn't exist
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
|
2024-09-16 12:23:15 +05:30
|
|
|
// console.log("Drag over: ", e.dataTransfer.getData("text/plain"), e.dataTransfer)
|
|
|
|
|
const dragElementType = draggedElement.getAttribute("data-draggable-type")
|
2024-09-22 19:23:06 +05:30
|
|
|
|
2024-09-23 12:31:01 +05:30
|
|
|
const allowDrop = (droppableTags && droppableTags !== null && (Object.keys(droppableTags).length === 0 ||
|
2024-09-22 19:23:06 +05:30
|
|
|
(droppableTags.include?.length > 0 && droppableTags.include?.includes(dragElementType)) ||
|
|
|
|
|
(droppableTags.exclude?.length > 0 && !droppableTags.exclude?.includes(dragElementType))
|
|
|
|
|
))
|
|
|
|
|
|
|
|
|
|
if (allowDrop){
|
2024-09-16 12:23:15 +05:30
|
|
|
e.preventDefault() // this is necessary to allow drop to take place
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const handleDropEvent = (e) => {
|
2024-09-24 14:33:02 +05:30
|
|
|
|
2024-09-28 11:29:37 +05:30
|
|
|
setShowDroppable({
|
|
|
|
|
allow: false,
|
|
|
|
|
show: false
|
|
|
|
|
})
|
|
|
|
|
|
2024-09-24 14:33:02 +05:30
|
|
|
if (!draggedElement || !draggedElement.getAttribute("data-drag-start-within")){
|
|
|
|
|
// if the drag is starting from outside (eg: file drop) or if drag doesn't exist
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
|
2024-09-17 18:32:33 +05:30
|
|
|
e.stopPropagation()
|
2024-09-16 12:23:15 +05:30
|
|
|
|
2024-09-28 11:29:37 +05:30
|
|
|
|
2024-09-22 19:23:06 +05:30
|
|
|
const dragElementType = draggedElement.getAttribute("data-draggable-type")
|
|
|
|
|
|
|
|
|
|
|
2024-09-23 12:31:01 +05:30
|
|
|
const allowDrop = (droppableTags && droppableTags !== null && (Object.keys(droppableTags).length === 0 ||
|
2024-09-22 19:23:06 +05:30
|
|
|
(droppableTags.include?.length > 0 && droppableTags.include?.includes(dragElementType)) ||
|
|
|
|
|
(droppableTags.exclude?.length > 0 && !droppableTags.exclude?.includes(dragElementType))
|
|
|
|
|
))
|
2024-09-16 12:23:15 +05:30
|
|
|
|
2024-09-22 19:23:06 +05:30
|
|
|
if(onDrop && allowDrop){
|
2024-09-22 12:39:03 +05:30
|
|
|
onDrop(e, draggedElement, widgetClass)
|
2024-09-16 12:23:15 +05:30
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
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}
|
|
|
|
|
>
|
2024-09-17 18:32:33 +05:30
|
|
|
|
|
|
|
|
{props.children}
|
|
|
|
|
|
2024-09-16 12:23:15 +05:30
|
|
|
{
|
|
|
|
|
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]
|
2024-09-17 18:32:33 +05:30
|
|
|
tw-border-2 tw-border-dashed tw-rounded-lg tw-pointer-events-none
|
2024-09-16 12:23:15 +05:30
|
|
|
`}>
|
|
|
|
|
</div>
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
</div>
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
export default DroppableWrapper
|