diff --git a/src/canvas/canvas.js b/src/canvas/canvas.js index 602238e..0bdd86f 100644 --- a/src/canvas/canvas.js +++ b/src/canvas/canvas.js @@ -20,6 +20,7 @@ import { WidgetContext } from './context/widgetContext' import DotsBackground from "../assets/background/dots.svg" import DroppableWrapper from "../components/draggable/droppable" import { ActiveWidgetContext, ActiveWidgetProvider, withActiveWidget } from "./activeWidgetContext" +import { DragWidgetProvider } from "./widgets/draggableWidgetContext" // const DotsBackground = require("../assets/background/dots.svg") @@ -302,7 +303,7 @@ class Canvas extends React.Component { const newPosX = x + (deltaX/this.state.zoom) // account for the zoom, since the widget is relative to canvas const newPosY = y + (deltaY/this.state.zoom) // account for the zoom, since the widget is relative to canvas - widget.setPos(newPosX, newPosY) + // widget.setPos(newPosX, newPosY) }) } @@ -468,7 +469,7 @@ class Canvas extends React.Component { callback({id, widgetRef}) if (this._onWidgetListUpdated) - this._onWidgetListUpdated(widgets) + this._onWidgetListUpdated(widgets) // inform the parent container }) @@ -476,6 +477,11 @@ class Canvas extends React.Component { return {id, widgetRef} } + getWidgetById(id){ + + return this.widgetRefs[id] + } + /** * delete's the selected widgets from the canvas * @param {null|Widget} widgets - optional widgets that can be deleted along the selected widgets @@ -558,13 +564,17 @@ class Canvas extends React.Component { } /** - * Handles drop event to canvas from the sidebar + * Handles drop event to canvas from the sidebar and on canvas widget movement * @param {DragEvent} e */ - handleDropEvent = (e) => { + handleDropEvent = (e, draggedElement) => { e.preventDefault() + + const container = draggedElement.getAttribute("data-container") + console.log("dragged element: ", e, draggedElement, container) + // const canvasContainerRect = this.getCanvasContainerBoundingRect() const canvasRect = this.canvasRef.current.getBoundingClientRect() const { clientX, clientY } = e @@ -572,11 +582,18 @@ class Canvas extends React.Component { const finalPosition = { x: (clientX - canvasRect.left) / this.state.zoom, y: (clientY - canvasRect.top) / this.state.zoom, - } + } - this.addWidget(Widget, ({id, widgetRef}) => { - widgetRef.current.setPos(finalPosition.x, finalPosition.y) - }) + if (container === "sidebar"){ + this.addWidget(Widget, ({id, widgetRef}) => { + widgetRef.current.setPos(finalPosition.x, finalPosition.y) + }) + }else if (container === "canvas"){ + + const widgetObj = this.getWidgetById(draggedElement.getAttribute("data-widget-id")) + // console.log("WidgetObj: ", widgetObj) + widgetObj.current.setPos(finalPosition.x, finalPosition.y) + } } @@ -607,30 +624,33 @@ class Canvas extends React.Component { {/* */} - -
- {/* Canvas */} -
-
- { - this.state.widgets.map(this.renderWidget) - } + className="tw-w-full tw-h-full" + onDrop={this.handleDropEvent}> + {/* */} + +
+ {/* Canvas */} +
+
+ { + this.state.widgets.map(this.renderWidget) + } +
-
- + + {/* */} +
{this.renderContent()} @@ -565,6 +572,7 @@ class Widget extends React.Component {
+ ) } diff --git a/src/canvas/widgets/draggableWidgetContext.js b/src/canvas/widgets/draggableWidgetContext.js new file mode 100644 index 0000000..2532041 --- /dev/null +++ b/src/canvas/widgets/draggableWidgetContext.js @@ -0,0 +1,24 @@ +import React, { createContext, useContext, useState } from 'react'; + +const DragWidgetContext = createContext() + +export const useDragWidgetContext = () => useContext(DragWidgetContext) + +// Provider component to wrap around parts of your app that need drag-and-drop functionality +export const DragWidgetProvider = ({ children }) => { + const [draggedElement, setDraggedElement] = useState(null) + + const onDragStart = (element) => { + setDraggedElement(element) + } + + const onDragEnd = () => { + setDraggedElement(null) + } + + return ( + + {children} + + ) +} diff --git a/src/canvas/widgets/widgetDragDrop.js b/src/canvas/widgets/widgetDragDrop.js new file mode 100644 index 0000000..71ad66b --- /dev/null +++ b/src/canvas/widgets/widgetDragDrop.js @@ -0,0 +1,127 @@ +import { memo, useState } from "react" +import { useDragWidgetContext } from "./draggableWidgetContext" +import { useDragContext } from "../../components/draggable/draggableContext" + + +const WidgetDraggable = memo(({ widgetRef, dragElementType="widget", onDrop, droppableTags = ["widget"], ...props }) => { + + + // const { draggedElement, onDragStart, onDragEnd } = useDragWidgetContext() + const { draggedElement, onDragStart, onDragEnd } = useDragContext() + + const [isDragging, setIsDragging] = useState(false) + + const [showDroppable, setShowDroppable] = useState({ + show: false, + allow: false + }) + + const handleDragStart = (e) => { + setIsDragging(true) + + console.log("Draggable widget ref: ", widgetRef) + onDragStart(widgetRef?.current || null) + + // Create custom drag image with full opacity, this will ensure the image isn't taken from part of the canvas + const dragImage = widgetRef?.current.cloneNode(true) + dragImage.style.opacity = '1' // Ensure full opacity + dragImage.style.position = 'absolute' + dragImage.style.top = '-9999px' // Move it out of view + + document.body.appendChild(dragImage) + const rect = widgetRef?.current.getBoundingClientRect() + const offsetX = e.clientX - rect.left + const offsetY = e.clientY - rect.top + + // Set the custom drag image with correct offset to avoid snapping to the top-left corner + e.dataTransfer.setDragImage(dragImage, offsetX, offsetY) + + // Remove the custom drag image after some time to avoid leaving it in the DOM + setTimeout(() => { + document.body.removeChild(dragImage) + }, 0) + } + + const handleDragEnter = (e) => { + + const dragEleType = draggedElement.getAttribute("data-draggable-type") + + if (droppableTags.length === 0 || droppableTags.includes(dragEleType)) { + 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 dragEleType = draggedElement.getAttribute("data-draggable-type") + + if (droppableTags.length === 0 || droppableTags.includes(dragEleType)) { + e.preventDefault() // this is necessary to allow drop to take place + } + + } + + const handleDropEvent = (e) => { + + setShowDroppable({ + allow: false, + show: false + }) + + if (onDrop) { + onDrop(e, draggedElement) + } + } + + + const handleDragLeave = (e) => { + if (!e.currentTarget.contains(e.relatedTarget)) { + setShowDroppable({ + allow: false, + show: false + }) + } + } + + const handleDragEnd = () => { + onDragEnd() + setIsDragging(false) + } + + return ( +
+ { + showDroppable.show && +
+
+ } + {props.children} + +
+ ) + +}) + + +export default WidgetDraggable \ No newline at end of file diff --git a/src/components/cards.js b/src/components/cards.js index 7bb22e8..7a7281d 100644 --- a/src/components/cards.js +++ b/src/components/cards.js @@ -30,7 +30,7 @@ export function DraggableWidgetCard({ name, img, url, innerRef}){ return ( // - +
{ +const DraggableWrapper = memo(({dragElementType, className, children, ...props}) => { const { onDragStart, onDragEnd } = useDragContext() @@ -40,6 +40,7 @@ const DraggableWrapper = memo(({dragElementType, className, children}) => { onDragStart={handleDragStart} onDragEnd={handleDragEnd} ref={draggableRef} + {...props} > {children}
diff --git a/src/components/draggable/droppable.js b/src/components/draggable/droppable.js index 569f33f..b7173ab 100644 --- a/src/components/draggable/droppable.js +++ b/src/components/draggable/droppable.js @@ -14,7 +14,6 @@ const DroppableWrapper = memo(({onDrop, droppableTags=["widget"], ...props}) => const handleDragEnter = (e) => { - console.log("Drag Enter", draggedElement) const dragElementType = draggedElement.getAttribute("data-draggable-type") @@ -42,7 +41,6 @@ const DroppableWrapper = memo(({onDrop, droppableTags=["widget"], ...props}) => } const handleDropEvent = (e) => { - console.log("Drag over: ", e.dataTransfer.getData("text/plain"), e.dataTransfer) setShowDroppable({ allow: false, @@ -50,7 +48,7 @@ const DroppableWrapper = memo(({onDrop, droppableTags=["widget"], ...props}) => }) if(onDrop){ - onDrop(e) + onDrop(e, draggedElement) } }