From b1c707a21d74cb0f2de9b35dea646b85cb42c5f6 Mon Sep 17 00:00:00 2001 From: paul Date: Tue, 4 Mar 2025 19:15:09 +0530 Subject: [PATCH] working on dnd aaaaa..... screammmmm --- src/canvas/canvas.js | 38 +- src/canvas/widgets/base.js | 468 ++++++++----------- src/canvas/widgets/widgetDnd.js | 109 ++--- src/components/draggable/dnd/draggableDnd.js | 1 - src/components/draggable/dnd/droppableDnd.js | 13 +- src/components/draggable/draggableContext.js | 7 +- 6 files changed, 259 insertions(+), 377 deletions(-) diff --git a/src/canvas/canvas.js b/src/canvas/canvas.js index f855d1f..bc7e156 100644 --- a/src/canvas/canvas.js +++ b/src/canvas/canvas.js @@ -665,9 +665,9 @@ class Canvas extends React.Component { * Handles drop event to canvas from the sidebar and on canvas widget movement * @param {DragEvent} e */ - handleDropEvent = (e, draggedElement, widgetClass = null) => { + handleDropEvent = (e, draggedElement, widgetClass = null, initialPos={x: 0, y: 0}) => { - console.log("event: ", e, draggedElement, widgetClass) + console.log("event: ", e, draggedElement, widgetClass, initialPos) // e.preventDefault() @@ -689,24 +689,21 @@ class Canvas extends React.Component { // const {x: draggedElementInitialX, y: draggedElementInitialY} = draggedElement.getBoundingClientRect() const { clientX, clientY } = e.nativeEvent + + const { initial } = e.operation.shape + console.log("event: ", e) // const { x: clientX, y: clientY} = e.delta; // const {clientX: draggedElementInitialX, clientY: draggedElementInitialY} = e.activatorEvent // console.log("wirking: ", clientX, clientY, e, draggedElementInitialX, draggedElementInitialY) - + // TODO: + initial cursor position - final cursor position let finalPosition = { - x: (clientX - canvasRect.left) / this.state.zoom, - y: (clientY - canvasRect.top) / this.state.zoom, + x: ((clientX - canvasRect.left) / this.state.zoom) - (initial.left) / this.state.zoom, + y: ((clientY - canvasRect.top) / this.state.zoom) - (initial.top) / this.state.zoom, } - // let finalPosition = { - // x: ((draggedElementInitialX + clientX) - canvasRect.left) / (this.state.zoom), - // y: ((draggedElementInitialY + clientY) - canvasRect.top) / (this.state.zoom), - // } - // let finalPosition = { - // x: (e.activatorEvent.pageX - canvasRect.left) / (this.state.zoom), - // y: (e.activatorEvent.pageY - canvasRect.top) / (this.state.zoom), - // } + + console.log("container: ", container) if (container === WidgetContainer.SIDEBAR) { @@ -719,26 +716,29 @@ class Canvas extends React.Component { this.createWidget(widgetClass, ({ id, widgetRef }) => { widgetRef.current.setPos(finalPosition.x, finalPosition.y) // widgetRef.current.setPos(10, 10) - console.log("hell ya ", widgetRef.current.setPos, finalPosition) - }) } else if ([WidgetContainer.CANVAS, WidgetContainer.WIDGET].includes(container)) { // snaps to center - finalPosition = { - x: (clientX - canvasRect.left) / this.state.zoom - (elementWidth / 2) / this.state.zoom, - y: (clientY - canvasRect.top) / this.state.zoom - (elementHeight / 2) / this.state.zoom, - } + // finalPosition = { + // x: (clientX - canvasRect.left) / this.state.zoom - (elementWidth / 2) / this.state.zoom, + // y: (clientY - canvasRect.top) / this.state.zoom - (elementHeight / 2) / this.state.zoom, + // } let widgetId = draggedElement.getAttribute("data-widget-id") const widgetObj = this.getWidgetById(widgetId) + + console.log("current pos: ", finalPosition, widgetId, widgetObj) + // console.log("WidgetObj: ", widgetObj) if (container === WidgetContainer.CANVAS) { widgetObj.current.setPos(finalPosition.x, finalPosition.y) + console.log("current pos: ", finalPosition) + } else if (container === WidgetContainer.WIDGET) { // if the widget was inside another widget move it outside diff --git a/src/canvas/widgets/base.js b/src/canvas/widgets/base.js index 440b768..c063049 100644 --- a/src/canvas/widgets/base.js +++ b/src/canvas/widgets/base.js @@ -68,8 +68,8 @@ class Widget extends React.Component { } // This indicates if the draggable can be dropped on this widget, set this to null to disable drops - this.droppableTags = {} - + this.droppableTags = {} + this.state = { zIndex: 0, @@ -91,7 +91,7 @@ class Widget extends React.Component { pos: { x: 0, y: 0 }, size: { width: 100, height: 100 }, - fitContent: {width: false, height: false}, + fitContent: { width: false, height: false }, positionType: PosType.ABSOLUTE, widgetOuterStyling: { @@ -117,7 +117,7 @@ class Widget extends React.Component { this.setAttrValue("styling.backgroundColor", value) } }, - + label: "Styling" }, layout: { @@ -181,7 +181,7 @@ class Widget extends React.Component { this.setPos = this.setPos.bind(this) this.setAttrValue = this.setAttrValue.bind(this) this.setWidgetName = this.setWidgetName.bind(this) - + this.setWidgetInnerStyle = this.setWidgetInnerStyle.bind(this) this.setWidgetOuterStyle = this.setWidgetOuterStyle.bind(this) @@ -201,11 +201,11 @@ class Widget extends React.Component { componentDidMount() { - if (this.state.attrs.layout){ + if (this.state.attrs.layout) { this.setLayout(this.state.attrs.layout.value) // console.log("prior layout: ", this.state.attrs.layout.value) } - + if (this.state.attrs.styling.backgroundColor) this.setWidgetInnerStyle('backgroundColor', this.state.attrs.styling?.backgroundColor.value || "#fff") @@ -276,9 +276,9 @@ class Widget extends React.Component { label: "Fit width", tool: Tools.CHECK_BUTTON, value: this.state.fitContent.width, - onChange: (value) => { + onChange: (value) => { this.updateState((prev) => ({ - fitContent: {...prev.fitContent, width: value} + fitContent: { ...prev.fitContent, width: value } })) } }, @@ -286,9 +286,9 @@ class Widget extends React.Component { label: "Fit height", tool: Tools.CHECK_BUTTON, value: this.state.fitContent.height, - onChange: (value) => { + onChange: (value) => { this.updateState((prev) => ({ - fitContent: {...prev.fitContent, height: value} + fitContent: { ...prev.fitContent, height: value } })) } }, @@ -316,15 +316,15 @@ class Widget extends React.Component { return this.constructor.widgetType } - getRequirements(){ + getRequirements() { return this.constructor.requirements } - getImports(){ + getImports() { return this.constructor.requiredImports } - generateCode(){ + generateCode() { throw new NotImplementedError("generateCode() must be implemented by the subclass") } @@ -406,11 +406,11 @@ class Widget extends React.Component { return this.elementRef.current } - hideDroppableIndicator(){ + hideDroppableIndicator() { console.log("hide drop indicator") this.setState({ showDroppableStyle: { - allow: false, + allow: false, show: false } }, () => { @@ -423,7 +423,7 @@ class Widget extends React.Component { * @param {string} path - eg: styling.backgroundColor * @returns */ - removeAttr = (path) =>{ + removeAttr = (path) => { const newAttrs = removeKeyFromObject(path, this.state.attrs) @@ -444,16 +444,16 @@ class Widget extends React.Component { const keys = path.split('.') const lastKey = keys.pop() - + // Traverse the state and update the nested value immutably let newAttrs = { ...this.state.attrs } let nestedObject = newAttrs - + keys.forEach(key => { nestedObject[key] = { ...nestedObject[key] } // Ensure immutability nestedObject = nestedObject[key] }) - + nestedObject[lastKey].value = value this.updateState({ attrs: newAttrs }) @@ -486,7 +486,7 @@ class Widget extends React.Component { * this is a helper function to remove any non-serializable data associated with attrs * eg: {"styling.backgroundColor": "#ffff", "layout": {layout: "flex", direction: "", grid: }} */ - serializeAttrsValues(){ + serializeAttrsValues() { const serializeValues = (obj, currentPath = "") => { const result = {} @@ -534,28 +534,28 @@ class Widget extends React.Component { * inform the child about the parent layout changes * @param {Layouts} parentLayout */ - setParentLayout(parentLayout){ + setParentLayout(parentLayout) { - if (!parentLayout){ + if (!parentLayout) { // if parent layout is null (i,e the widget is on the canvas) return {} - } + } - const {layout, direction, gap} = parentLayout + const { layout, direction, gap } = parentLayout let updates = { parentLayout: parentLayout, } - if (layout === Layouts.FLEX || layout === Layouts.GRID){ + if (layout === Layouts.FLEX || layout === Layouts.GRID) { updates = { ...updates, positionType: PosType.NONE } - }else if (layout === Layouts.PLACE){ + } else if (layout === Layouts.PLACE) { updates = { ...updates, positionType: PosType.ABSOLUTE @@ -565,11 +565,11 @@ class Widget extends React.Component { this.setState(updates) } - getParentLayout(){ + getParentLayout() { return this.state.parentLayout } - getLayout(){ + getLayout() { return this.state?.attrs?.layout?.value || Layouts.FLEX } @@ -586,18 +586,18 @@ class Widget extends React.Component { gap: `${gap}px`, flexWrap: "wrap", gridTemplateColumns: "repeat(auto-fill, minmax(100px, 1fr))", - gridTemplateRows: "repeat(auto-fill, minmax(100px, 1fr))", + gridTemplateRows: "repeat(auto-fill, minmax(100px, 1fr))", // gridAutoRows: 'minmax(100px, auto)', // Rows with minimum height of 100px, and grow to fit content // gridAutoCols: 'minmax(100px, auto)', // Cols with minimum height of 100px, and grow to fit content } - if (align === "start"){ + if (align === "start") { widgetStyle["alignItems"] = "flex-start" - }else if (align === "center"){ + } else if (align === "center") { widgetStyle["alignItems"] = "center" - }else if (align === "end"){ + } else if (align === "end") { widgetStyle["alignItems"] = "flex-end" - }else{ + } else { widgetStyle["alignItems"] = "unset" } @@ -606,7 +606,7 @@ class Widget extends React.Component { }) this.setAttrValue("layout", value) - this.props.onLayoutUpdate({parentId: this.__id, parentLayout: value})// inform children about the layout update + this.props.onLayoutUpdate({ parentId: this.__id, parentLayout: value })// inform children about the layout update } @@ -623,7 +623,7 @@ class Widget extends React.Component { * @param {string} key - The string in react Style format * @param {string} value - Value of the style */ - setWidgetOuterStyle(key, value){ + setWidgetOuterStyle(key, value) { const widgetStyle = { ...this.state.widgetOuterStyling, [key]: value @@ -641,7 +641,7 @@ class Widget extends React.Component { * @param {string} value - Value of the style */ setWidgetInnerStyle(key, value) { - + const widgetStyle = { ...this.state.widgetInnerStyling, [key]: value @@ -663,7 +663,7 @@ class Widget extends React.Component { const fitWidth = this.state.fitContent?.width const fitHeight = this.state.fitContent?.height - if (fitWidth && fitHeight){ + if (fitWidth && fitHeight) { message.warning("both width and height are set to fit-content, unset it to start resizing") return } @@ -715,7 +715,7 @@ class Widget extends React.Component { * * serialize data for saving */ - serialize(){ + serialize() { // NOTE: when serializing make sure, you are only passing serializable objects not functions or other return ({ zIndex: this.state.zIndex, @@ -737,27 +737,27 @@ class Widget extends React.Component { * @param {object} data * @param {() => void | undefined} callback - optional callback that will be called after load */ - load(data, callback){ + load(data, callback) { if (Object.keys(data).length === 0) return // no data to load - data = {...data} // create a shallow copy + data = { ...data } // create a shallow copy - const {attrs, parentLayout, ...restData} = data + const { attrs, parentLayout, ...restData } = data let layoutUpdates = { parentLayout: parentLayout.layout || null } - if (parentLayout?.layout === Layouts.FLEX || parentLayout?.layout === Layouts.GRID){ + if (parentLayout?.layout === Layouts.FLEX || parentLayout?.layout === Layouts.GRID) { layoutUpdates = { ...layoutUpdates, positionType: PosType.NONE } - }else if (parentLayout?.layout === Layouts.PLACE){ + } else if (parentLayout?.layout === Layouts.PLACE) { layoutUpdates = { ...layoutUpdates, positionType: PosType.ABSOLUTE @@ -769,7 +769,7 @@ class Widget extends React.Component { ...layoutUpdates } - this.setState(newData, () => { + this.setState(newData, () => { // Updates attrs let newAttrs = { ...this.state.attrs } @@ -791,75 +791,36 @@ class Widget extends React.Component { nestedObject[lastKey].value = value }) - if (newAttrs?.styling?.backgroundColor){ + if (newAttrs?.styling?.backgroundColor) { // some widgets don't have background color this.setWidgetInnerStyle("backgroundColor", newAttrs.styling.backgroundColor) } this.updateState({ attrs: newAttrs }, callback) - }) + }) } - handleDragStart = (e, callback) => { - e.stopPropagation() - - callback(this.elementRef?.current || null) - - // this.props.onWidgetDragStart(this.elementRef?.current) - - // Create custom drag image with full opacity, this will ensure the image isn't taken from part of the canvas - const dragImage = this.elementRef?.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 = this.elementRef?.current.getBoundingClientRect() - // snap to mouse pos - // const offsetX = e.clientX - rect.left - // const offsetY = e.clientY - rect.top - - // snap to middle - const offsetX = rect.width / 2 - const offsetY = rect.height / 2 - - // 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) - + handleDragStart = (e, ) => { // NOTE: this line will prevent problem's such as self-drop or dropping inside its own children setTimeout(this.disablePointerEvents, 1) this.setState({ isDragging: true }) - } - handleDragEnter = (e, draggedElement, setOverElement) => { + handleDragEnter = (e, draggedElement) => { - if (!draggedElement || !draggedElement.getAttribute("data-drag-start-within")){ + console.log("Drahg engerted") + + 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 } const dragEleType = draggedElement.getAttribute("data-draggable-type") - // console.log("Drag entering...", dragEleType, draggedElement, this.droppableTags) - // FIXME: the outer widget shouldn't be swallowed by inner widget - if (draggedElement === this.elementRef.current) { - // prevent drop on itself, since the widget is invisible when dragging, if dropped on itself, it may consume itself - return - } - - setOverElement(this.elementRef.current) // provide context to the provider - let showDrop = { allow: true, show: true @@ -891,7 +852,7 @@ class Widget extends React.Component { handleDragOver = (e, draggedElement) => { - if (!draggedElement || !draggedElement.getAttribute("data-drag-start-within")){ + 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 } @@ -902,29 +863,19 @@ class Widget extends React.Component { } // console.log("Drag over: ", e.dataTransfer.getData("text/plain"), e.dataTransfer) - const dragEleType = draggedElement.getAttribute("data-draggable-type") - - const allowDrop = (this.droppableTags && this.droppableTags !== null && (Object.keys(this.droppableTags).length === 0 || - (this.droppableTags.include?.length > 0 && this.droppableTags.include?.includes(dragEleType)) || - (this.droppableTags.exclude?.length > 0 && !this.droppableTags.exclude?.includes(dragEleType)) - )) - - if (allowDrop) { - e.preventDefault() // NOTE: this is necessary to allow drop to take place - } } handleDropEvent = (e, draggedElement, widgetClass = null) => { - if (!draggedElement || !draggedElement.getAttribute("data-drag-start-within")){ + console.log("Dropped: ", draggedElement) + + 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 } - e.preventDefault() - e.stopPropagation() - + // FIXME: sometimes the elements showDroppableStyle is not gone, when dropping on the same widget this.setState({ showDroppableStyle: { @@ -934,9 +885,9 @@ class Widget extends React.Component { }) - if (draggedElement === this.elementRef.current){ + if (draggedElement === this.elementRef.current) { // prevent drop on itself, since the widget is invisible when dragging, if dropped on itself, it may consume itself - return + return } let currentElement = e.currentTarget @@ -965,7 +916,7 @@ class Widget extends React.Component { if (!allowDrop && !swapArea) { // only if both swap and drop is not allowed return, if swap is allowed continue - return + return } // TODO: check if the drop is allowed if ([WidgetContainer.CANVAS, WidgetContainer.WIDGET].includes(container)) { @@ -983,10 +934,10 @@ class Widget extends React.Component { // console.log("Dropped on Sidebar: ", this.__id) this.props.onCreateWidgetRequest(widgetClass, ({ id, widgetRef }) => { this.props.onAddChildWidget({ - event: e, - parentWidgetId: this.__id, - dragElementID: id - }) // if dragged from the sidebar create the widget first + event: e, + parentWidgetId: this.__id, + dragElementID: id + }) // if dragged from the sidebar create the widget first }) } @@ -994,18 +945,15 @@ class Widget extends React.Component { } - handleDragLeave = (e, draggedElement, overElement) => { - - e.preventDefault() - e.stopPropagation() + handleDragLeave = (e) => { const rect = this.getBoundingRect() - - const {clientX, clientY} = e - + + const { clientX, clientY } = e + const isInBoundingBox = (clientX >= rect.left && clientX <= rect.right && clientY >= rect.top && clientY <= rect.bottom) - + // if (!e.currentTarget.contains(draggedElement)) { if (!isInBoundingBox) { // FIXME: if the mouse pointer is over this widget's child, then droppable style should be invisible @@ -1022,11 +970,9 @@ class Widget extends React.Component { } } - handleDragEnd = (callback) => { - callback() + handleDragEnd = () => { this.setState({ isDragging: false }) this.enablePointerEvents() - // this.props.onWidgetDragEnd(this.elementRef?.current) } @@ -1041,40 +987,40 @@ class Widget extends React.Component { this.elementRef.current.style.pointerEvents = "auto" } - getInnerRenderStyling(){ - const {width, height, minWidth, minHeight} = this.getRenderSize() + getInnerRenderStyling() { + const { width, height, minWidth, minHeight } = this.getRenderSize() const styling = { ...this.state.widgetInnerStyling, - width, + width, height, - minWidth, + minWidth, minHeight } return styling } - getRenderSize(){ + getRenderSize() { let width = isNumeric(this.state.size.width) ? `${this.state.size.width}px` : this.state.size.width let height = isNumeric(this.state.size.height) ? `${this.state.size.height}px` : this.state.size.height let fitWidth = this.state.fitContent.width let fitHeight = this.state.fitContent.height - - if (fitWidth){ + + if (fitWidth) { width = "max-content" } - if (fitHeight){ + if (fitHeight) { height = "max-content" } // if fit width is enabled then the minsize is the resizable size let minWidth = fitWidth ? this.state.size.width : this.minSize.width let minHeight = fitHeight ? this.state.size.height : this.minSize.height - - return {width, height, minWidth, minHeight} + + return { width, height, minWidth, minHeight } } @@ -1095,10 +1041,10 @@ class Widget extends React.Component { * This is an internal methods don't override * @returns {HTMLElement} */ - render() { + render() { + + const { width, height, minWidth, minHeight } = this.getRenderSize() - const {width, height, minWidth, minHeight} = this.getRenderSize() - // NOTE: first check tkinter behaviour with the width and height let outerStyle = { @@ -1110,175 +1056,167 @@ class Widget extends React.Component { left: `${this.state.pos.x}px`, width: width, height: height, - minWidth: minWidth, + minWidth: minWidth, minHeight: minHeight, - opacity: this.state.isDragging ? 0.3 : 1, + opacity: this.state.isDragging ? 0.6 : 1, } // const boundingRect = this.getBoundingRect // TODO: rewrite Drag and drop // FIXME: if the parent container has tw-overflow-none, then the resizable indicator are also hidden + // FIXME: renable pointer events return ( // { - ({ draggedElement, widgetClass, onDragStart, onDragEnd, overElement, setOverElement }) => { + ({ draggedElement, widgetClass }) => { - - return ( - this.handleDragOver(e, draggedElement)} - // onDrop={(e) => {this.handleDropEvent(e, draggedElement, widgetClass); onDragEnd()}} + return ( - // onDragEnter={(e) => this.handleDragEnter(e, draggedElement, setOverElement)} - // onDragLeave={(e) => this.handleDragLeave(e, draggedElement, overElement)} + {this.handleDragOver(e, draggedElement)}} + onDragEnd={(e) => this.handleDragEnd()} - // onDragStart={(e) => this.handleDragStart(e, onDragStart)} - // onDragEnd={(e) => this.handleDragEnd(onDragEnd)} - style={outerStyle} + onDrop={(e) => {this.handleDropEvent(e, draggedElement, widgetClass)}} // handle by droppable + onDragEnter={(e) => this.handleDragEnter(e, draggedElement)} // this is by droppable + widgetRef={this.elementRef} - > -
this.handleDragOver(e, draggedElement)} + // onDrop={(e) => {this.handleDropEvent(e, draggedElement, widgetClass); onDragEnd()}} - // data-drag-start-within // this attribute indicates that the drag is occurring from within the project and not a outside file drop + // onDragEnter={(e) => this.handleDragEnter(e, draggedElement, setOverElement)} + // onDragLeave={(e) => this.handleDragLeave(e, draggedElement, overElement)} - // draggable={this.state.dragEnabled} + // onDragStart={(e) => this.handleDragStart(e, onDragStart)} + // onDragEnd={(e) => this.handleDragEnd(onDragEnd)} + style={outerStyle} - // onDragOver={(e) => this.handleDragOver(e, draggedElement)} - // onDrop={(e) => {this.handleDropEvent(e, draggedElement, widgetClass); onDragEnd()}} + > - // onDragEnter={(e) => this.handleDragEnter(e, draggedElement, setOverElement)} - // onDragLeave={(e) => this.handleDragLeave(e, draggedElement, overElement)} +
this.handleDragStart(e, onDragStart)} - // onDragEnd={(e) => this.handleDragEnd(onDragEnd)} > - {/* FIXME: Swappable when the parent layout is flex/grid and gap is more, this trick won't work, add bg color to check */} - {/* FIXME: Swappable, when the parent layout is gap is 0, it doesn't work well */} -
- -
- {/* helps with swappable: if the mouse is in this area while hovering/dropping, then swap */} -
+ style={{ + width: "calc(100% + 10px)", + height: "calc(100% + 10px)", + }} + ref={this.swappableAreaRef} + // swapable area + > + {/* helps with swappable: if the mouse is in this area while hovering/dropping, then swap */} +
-
- {this.renderContent()} -
- { - // show drop style on drag hover - draggedElement && this.state.showDroppableStyle.show && -
+ {this.renderContent()} +
+ { + // show drop style on drag hover + draggedElement && this.state.showDroppableStyle.show && +
-
- } - {/* FIXME: the resize handles get clipped in parent container */} -
+
+ } + {/* FIXME: the resize handles get clipped in parent container */} +
-
{/* ${this.state.isDragging ? "tw-pointer-events-none" : "tw-pointer-events-auto"} */} - {/* ${this.state.isDragging ? "tw-pointer-events-none" : "tw-pointer-events-auto"} */} + + /> -
{ - e.stopPropagation() - e.preventDefault() - this.props.onWidgetResizing("nw") - this.setState({ dragEnabled: false }) - }} - onMouseUp={() => this.setState({ dragEnabled: true })} - /> -
{ - e.stopPropagation() - e.preventDefault() - this.props.onWidgetResizing("ne") - this.setState({ dragEnabled: false }) - }} - onMouseUp={() => this.setState({ dragEnabled: true })} - /> -
{ - e.stopPropagation() - e.preventDefault() - this.props.onWidgetResizing("sw") - this.setState({ dragEnabled: false }) - }} - onMouseUp={() => this.setState({ dragEnabled: true })} - /> -
{ - e.stopPropagation() - e.preventDefault() - this.props.onWidgetResizing("se") - this.setState({ dragEnabled: false }) - }} - onMouseUp={() => this.setState({ dragEnabled: true })} - /> - -
+
{ + e.stopPropagation() + e.preventDefault() + this.props.onWidgetResizing("nw") + this.setState({ dragEnabled: false }) + }} + onMouseUp={() => this.setState({ dragEnabled: true })} + /> +
{ + e.stopPropagation() + e.preventDefault() + this.props.onWidgetResizing("ne") + this.setState({ dragEnabled: false }) + }} + onMouseUp={() => this.setState({ dragEnabled: true })} + /> +
{ + e.stopPropagation() + e.preventDefault() + this.props.onWidgetResizing("sw") + this.setState({ dragEnabled: false }) + }} + onMouseUp={() => this.setState({ dragEnabled: true })} + /> +
{ + e.stopPropagation() + e.preventDefault() + this.props.onWidgetResizing("se") + this.setState({ dragEnabled: false }) + }} + onMouseUp={() => this.setState({ dragEnabled: true })} + />
-
-
- - ) - } - } - + +
+ + + + ) + } +} + + ) } diff --git a/src/canvas/widgets/widgetDnd.js b/src/canvas/widgets/widgetDnd.js index 6c4f176..3c8f6fc 100644 --- a/src/canvas/widgets/widgetDnd.js +++ b/src/canvas/widgets/widgetDnd.js @@ -1,9 +1,12 @@ import React, { useEffect, useRef, useState } from 'react' import { useDragDropManager, useDroppable, useDraggable } from '@dnd-kit/react' import { useDragContext } from '../../components/draggable/draggableContext' +import WidgetContainer from '../constants/containers' -function WidgetDnd({widgetId, droppableTags, onDrop, +// FIXME: widget class is null +function WidgetDnd({widgetId, widgetRef, droppableTags, onDrop, onDragStart, + onDragEnd, onDragEnter, onDragOver, initialPos, ...props}) { const dndRef = useRef(null) @@ -27,7 +30,7 @@ function WidgetDnd({widgetId, droppableTags, onDrop, const { ref: dragRef, draggable } = useDraggable({ id: widgetId, - feedback: "default", + feedback: "move", type: dragElementType, disabled: props.disabled, @@ -38,9 +41,8 @@ function WidgetDnd({widgetId, droppableTags, onDrop, const manager = useDragDropManager() // const {} - const {onDragStart, onDragEnd, disableStyle=false} = useDragContext() - - const [allowDrop, setAllowDrop] = useState({show: false, allow: false}) // indicator if the draggable can be dropped on the droppable + const {onDragStart: onDragContextStart, onDragEnd: onDragContextEnd, disableStyle=false} = useDragContext() + const [allowDrop, setAllowDrop] = useState(false) // indicator if the draggable can be dropped on the droppable useEffect(() => { @@ -49,33 +51,37 @@ function WidgetDnd({widgetId, droppableTags, onDrop, manager?.monitor?.addEventListener("dragmove", handleDragOver) // manager?.monitor?.addEventListener("dragover", onDragEndhandleDragOver) - return () => { manager?.monitor?.removeEventListener("dragstart", handleDragEnter) manager?.monitor?.removeEventListener("dragend", handleDropEvent) manager?.monitor?.removeEventListener("dragmove", handleDragOver) } - }, [manager, draggedElement]) + }, [manager, draggedElement, widgetClass]) const handleRef = (node) => { dndRef.current = node + widgetRef.current = node dropRef(node) dragRef(node) } const handleDragEnter = (e) => { - const {target, source} = e.operation - if (draggable.isDragSource){ + + console.log("widget class: ", widgetClass) + // if the current widget is being dragged - onDragStart(dndRef?.current, widgetClass) + onDragContextStart(dndRef?.current, widgetClass, {}, initialPos) dndRef.current.style.zIndex = 10 + onDragStart(e) + return + }else if (droppable.isDropTarget){ if (!draggedElement || !draggedElement.getAttribute("data-drag-start-within")) { @@ -92,28 +98,14 @@ function WidgetDnd({widgetId, droppableTags, onDrop, (droppableTags.exclude?.length > 0 && !droppableTags.exclude?.includes(dragElementType)) )) - console.log("droppable tags: ", dropAllowed) - - setAllowDrop({allow: dropAllowed, show: true}) - + setAllowDrop(dropAllowed) } - - } const handleDragOver = (e) => { - const {target} = e.operation - - // if (draggable.isDragSource){ - // onDragStart(dndRef?.current, widgetClass) - - // // TODO - // dndRef.current.style.zIndex = 10 - // } - if (droppable.isDropTarget){ if (!draggedElement || !draggedElement.getAttribute("data-drag-start-within")) { @@ -130,28 +122,21 @@ function WidgetDnd({widgetId, droppableTags, onDrop, )) - setAllowDrop({allow: dropAllowed, show: true}) + setAllowDrop(dropAllowed) + onDragOver(e) } - // console.log("Over sir1: ", draggedElement) - - - - // if (allowDrop) { - // e.preventDefault() // this is necessary to allow drop to take place - // } } const handleDropEvent = (e) => { - const {target} = e.operation - if (draggable.isDragSource){ - onDragEnd() + onDragContextEnd() + onDragEnd(e) }else if (droppable.isDropTarget){ - setAllowDrop({allow: false, show: false}) + setAllowDrop(false) if (!draggedElement || !draggedElement.getAttribute("data-drag-start-within")) { @@ -159,11 +144,8 @@ function WidgetDnd({widgetId, droppableTags, onDrop, return } - // e.stopPropagation() - const dragElementType = draggedElement.getAttribute("data-draggable-type") - const dropAllowed = (droppableTags && droppableTags !== null && (Object.keys(droppableTags).length === 0 || (droppableTags.include?.length > 0 && droppableTags.include?.includes(dragElementType)) || (droppableTags.exclude?.length > 0 && !droppableTags.exclude?.includes(dragElementType)) @@ -172,64 +154,27 @@ function WidgetDnd({widgetId, droppableTags, onDrop, if (onDrop && dropAllowed && (droppable.isDropTarget && !draggable.isDragSource)) { onDrop(e, draggedElement, widgetClass) } + } } - // const handleDragLeave = (e) => { - - // const {target} = e.operation - - // if (target && target.id === props.id){ - // handleDropEvent(e) - // }else{ - // setAllowDrop({allow: false, show: false}) - - // } - - // } - - // const handleDragStart = (event) => { - - // const {source} = event.operation - - // if (!source || (source && source.id !== props.dragElementType)){ - // return - // } if (!source || (source && source.id !== props.dragElementType)){ - // return - // } - // // event.dataTransfer.setData("text/plain", "") - // // onDragStart(draggableRef?.current, dragWidgetClass) - // onDragStart(draggableRef?.current, dragWidgetClass, elementMetaData) - - // } - - // const handleDragEnd = (event) => { - // // console.log("Drag end: ", e, e.target.closest('div')) - // const {source} = event.operation - - // if (!source || (source && source.id !== props.dragElementType)){ - // return - // } - - // // onDragEnd() - // } - return (
{props.children} { (droppable.isDropTarget && !draggable.isDragSource) && -
diff --git a/src/components/draggable/dnd/draggableDnd.js b/src/components/draggable/dnd/draggableDnd.js index d4b9bdc..8c111d7 100644 --- a/src/components/draggable/dnd/draggableDnd.js +++ b/src/components/draggable/dnd/draggableDnd.js @@ -59,7 +59,6 @@ function Draggable({dragElementType, dragWidgetClass = null, elementMetaData, .. const handleDragEnd = (event) => { // console.log("Drag end: ", e, e.target.closest('div')) - const {source} = event.operation if (!draggable.isDragSource){ return diff --git a/src/components/draggable/dnd/droppableDnd.js b/src/components/draggable/dnd/droppableDnd.js index acefe71..ea81115 100644 --- a/src/components/draggable/dnd/droppableDnd.js +++ b/src/components/draggable/dnd/droppableDnd.js @@ -8,7 +8,7 @@ function Droppable(props) { const droppableRef = useRef(null) const { droppableTags, onDrop } = props - const { draggedElement, overElement, setOverElement, widgetClass } = useDragContext() + const { draggedElement, setOverElement, widgetClass, initialPosition } = useDragContext() const { ref, isDropTarget, droppable} = useDroppable({ id: props.id, @@ -40,7 +40,7 @@ function Droppable(props) { manager?.monitor?.removeEventListener("dragend", handleDragLeave) manager?.monitor?.removeEventListener("dragmove", handleDragOver) } - }, [manager, draggedElement, widgetClass]) + }, [manager, draggedElement, widgetClass, initialPosition]) const handleRef = (node) => { @@ -72,8 +72,6 @@ function Droppable(props) { (droppableTags.exclude?.length > 0 && !droppableTags.exclude?.includes(dragElementType)) )) - console.log("droppable tags: ", dropAllowed) - setAllowDrop({allow: dropAllowed, show: true}) @@ -137,10 +135,9 @@ function Droppable(props) { (droppableTags.exclude?.length > 0 && !droppableTags.exclude?.includes(dragElementType)) )) - console.log("Widget class1: ", widgetClass, draggedElement) - + console.log("initial POs: ", initialPosition) if (onDrop && dropAllowed) { - onDrop(e, draggedElement, widgetClass) + onDrop(e, draggedElement, widgetClass, initialPosition) } } @@ -165,7 +162,7 @@ function Droppable(props) { { allowDrop.show && -
diff --git a/src/components/draggable/draggableContext.js b/src/components/draggable/draggableContext.js index 55eb741..693ec1a 100644 --- a/src/components/draggable/draggableContext.js +++ b/src/components/draggable/draggableContext.js @@ -12,6 +12,7 @@ export const DragProvider = ({ children }) => { const [draggedElement, setDraggedElement] = useState(null) const [overElement, setOverElement] = useState(null) // the element the dragged items is over + const [initialPosition, setInitialPosition] = useState({x: 0, y: 0}) const [dragElementMetaData, setDragElementMetaData] = useState({}) @@ -19,10 +20,11 @@ export const DragProvider = ({ children }) => { const [isDragging, setIsDragging] = useState(false) - const onDragStart = (element, widgetClass=null, metaData={}, pos={x: 0, y: 0}) => { + const onDragStart = (element, widgetClass=null, metaData={}, initialPos={x: 0, y: 0}) => { setDraggedElement(element) setIsDragging(true) + setInitialPosition(initialPos) setDragElementMetaData(metaData) if (widgetClass && !isSubClassOfWidget(widgetClass)) @@ -45,7 +47,8 @@ export const DragProvider = ({ children }) => { return ( {children}