From 0b282f45d03536bc4e2583bdef0d67a1bf653eed Mon Sep 17 00:00:00 2001 From: Johnson Cherian Date: Wed, 9 Jul 2025 00:14:28 +0530 Subject: [PATCH] Revert "Add support to show guidelines on component drop" --- .vscode/settings.json | 3 - frontend/package-lock.json | 11 +- frontend/package.json | 2 +- .../src/AppBuilder/AppCanvas/Container.jsx | 173 +++++++++++++----- .../src/AppBuilder/AppCanvas/Grid/Grid.jsx | 158 ++++++++-------- .../AppBuilder/AppCanvas/Grid/gridUtils.js | 50 +---- .../Grid/hooks/useElementGudelines.js | 72 -------- .../AppBuilder/AppCanvas/WidgetWrapper.jsx | 5 +- .../AppBuilder/AppCanvas/appCanvasUtils.js | 23 ++- .../AppCanvas/useCanvasDropHandler.js | 113 ------------ .../ComponentManagerTab/DragLayer.jsx | 85 +++++++-- .../_hooks/useDropVirtualMoveableGhost.js | 101 ---------- .../src/AppBuilder/_hooks/useGhostMoveable.js | 107 ----------- .../AppBuilder/_stores/slices/gridSlice.js | 6 - frontend/src/_stores/gridStore.js | 21 +-- .../BaseColorSwatches/BaseColorSwatches.jsx | 1 + 16 files changed, 301 insertions(+), 630 deletions(-) delete mode 100644 frontend/src/AppBuilder/AppCanvas/Grid/hooks/useElementGudelines.js delete mode 100644 frontend/src/AppBuilder/AppCanvas/useCanvasDropHandler.js delete mode 100644 frontend/src/AppBuilder/_hooks/useDropVirtualMoveableGhost.js delete mode 100644 frontend/src/AppBuilder/_hooks/useGhostMoveable.js diff --git a/.vscode/settings.json b/.vscode/settings.json index 16c9f25d4d..ac6e6079cc 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -10,9 +10,6 @@ ], "eslint.format.enable": true, "editor.formatOnSave": true, - "editor.codeActionsOnSave": { - "source.fixAll.eslint": "explicit" - }, "json.schemas": [ { "fileMatch": [ diff --git a/frontend/package-lock.json b/frontend/package-lock.json index e09315a4b6..b165f8fb62 100644 --- a/frontend/package-lock.json +++ b/frontend/package-lock.json @@ -121,7 +121,7 @@ "react-loading-skeleton": "^3.1.1", "react-markdown": "^9.0.0", "react-mentions": "^4.4.7", - "react-moveable": "^0.56.0", + "react-moveable": "^0.54.1", "react-multi-select-component": "^4.3.4", "react-pdf": "^6.2.2", "react-phone-input-2": "^2.15.1", @@ -30697,9 +30697,10 @@ } }, "node_modules/react-moveable": { - "version": "0.56.0", - "resolved": "https://registry.npmjs.org/react-moveable/-/react-moveable-0.56.0.tgz", - "integrity": "sha512-FmJNmIOsOA36mdxbrc/huiE4wuXSRlmon/o+/OrfNhSiYYYL0AV5oObtPluEhb2Yr/7EfYWBHTxF5aWAvjg1SA==", + "version": "0.54.2", + "resolved": "https://registry.npmjs.org/react-moveable/-/react-moveable-0.54.2.tgz", + "integrity": "sha512-NGaVLbn0i9pb3+BWSKGWFqI/Mgm4+WMeWHxXXQ4Qi1tHxWCXrUrbGvpxEpt69G/hR7dez+/m68ex+fabjnvcUg==", + "license": "MIT", "dependencies": { "@daybrush/utils": "^1.13.0", "@egjs/agent": "^2.2.1", @@ -30710,7 +30711,7 @@ "@scena/matrix": "^1.1.1", "css-to-mat": "^1.1.1", "framework-utils": "^1.1.0", - "gesto": "^1.19.3", + "gesto": "^1.19.0", "overlap-area": "^1.1.0", "react-css-styled": "^1.1.9", "react-selecto": "^1.25.0" diff --git a/frontend/package.json b/frontend/package.json index ffe5da76ac..6a65305bb8 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -116,7 +116,7 @@ "react-loading-skeleton": "^3.1.1", "react-markdown": "^9.0.0", "react-mentions": "^4.4.7", - "react-moveable": "^0.56.0", + "react-moveable": "^0.54.1", "react-multi-select-component": "^4.3.4", "react-pdf": "^6.2.2", "react-phone-input-2": "^2.15.1", diff --git a/frontend/src/AppBuilder/AppCanvas/Container.jsx b/frontend/src/AppBuilder/AppCanvas/Container.jsx index 1f37c2bb5b..808a29f90c 100644 --- a/frontend/src/AppBuilder/AppCanvas/Container.jsx +++ b/frontend/src/AppBuilder/AppCanvas/Container.jsx @@ -4,17 +4,32 @@ import cx from 'classnames'; import WidgetWrapper from './WidgetWrapper'; import useStore from '@/AppBuilder/_stores/store'; import { shallow } from 'zustand/shallow'; -import { useDrop, useDragLayer } from 'react-dnd'; -import { computeViewerBackgroundColor, getSubContainerWidthAfterPadding } from './appCanvasUtils'; -import { CANVAS_WIDTHS, NO_OF_GRIDS, GRID_HEIGHT } from './appCanvasConstants'; +import { useDrop } from 'react-dnd'; +import { + addChildrenWidgetsToParent, + addNewWidgetToTheEditor, + computeViewerBackgroundColor, + getSubContainerWidthAfterPadding, + addDefaultButtonIdToForm, +} from './appCanvasUtils'; +import { + CANVAS_WIDTHS, + NO_OF_GRIDS, + WIDGETS_WITH_DEFAULT_CHILDREN, + GRID_HEIGHT, + CONTAINER_FORM_CANVAS_PADDING, + SUBCONTAINER_CANVAS_BORDER_WIDTH, + BOX_PADDING, +} from './appCanvasConstants'; import { useGridStore } from '@/_stores/gridStore'; import NoComponentCanvasContainer from './NoComponentCanvasContainer'; +import { RIGHT_SIDE_BAR_TAB } from '../RightSideBar/rightSidebarConstants'; +import { isPDFSupported } from '@/_helpers/appUtils'; +import toast from 'react-hot-toast'; import { ModuleContainerBlank } from '@/modules/Modules/components'; import { useModuleContext } from '@/AppBuilder/_contexts/ModuleContext'; import useSortedComponents from '../_hooks/useSortedComponents'; -import { useDropVirtualMoveableGhost } from '@/AppBuilder/_hooks/useDropVirtualMoveableGhost'; -import { useCanvasDropHandler } from './useCanvasDropHandler'; -import { findNewParentIdFromMousePosition } from './Grid/gridUtils'; +import { noop } from 'lodash'; //TODO: Revisit the logic of height (dropRef) @@ -36,72 +51,112 @@ export const Container = React.memo( columns, darkMode, canvasMaxWidth, + isViewerSidebarPinned, + pageSidebarStyle, + pagePositionType, componentType, appType, }) => { const { moduleId } = useModuleContext(); const realCanvasRef = useRef(null); const components = useStore((state) => state.getContainerChildrenMapping(id, moduleId), shallow); + + const addComponentToCurrentPage = useStore((state) => state.addComponentToCurrentPage, shallow); + const setActiveRightSideBarTab = useStore((state) => state.setActiveRightSideBarTab, shallow); const setLastCanvasClickPosition = useStore((state) => state.setLastCanvasClickPosition, shallow); const canvasBgColor = useStore( (state) => (id === 'canvas' ? state.getCanvasBackgroundColor('canvas', darkMode) : ''), shallow ); + const isPagesSidebarHidden = useStore((state) => state.getPagesSidebarVisibility('canvas'), shallow); const currentMode = useStore((state) => state.modeStore.modules[moduleId].currentMode, shallow); const currentLayout = useStore((state) => state.currentLayout, shallow); const setFocusedParentId = useStore((state) => state.setFocusedParentId, shallow); - - // Initialize ghost moveable hook - const { activateMoveableGhost, deactivateMoveableGhost } = useDropVirtualMoveableGhost(); - - // // Monitor drag layer to update ghost position continuously - const { isDragging } = useDragLayer((monitor) => ({ - isDragging: monitor.isDragging(), - })); - - // // // Cleanup ghost when drag ends - useEffect(() => { - if (!isDragging) { - deactivateMoveableGhost(); - } - }, [id, isDragging, deactivateMoveableGhost]); + const setShowModuleBorder = useStore((state) => state.setShowModuleBorder, shallow) || noop; const isContainerReadOnly = useMemo(() => { return (index !== 0 && (componentType === 'Listview' || componentType === 'Kanban')) || currentMode === 'view'; }, [index, componentType, currentMode]); - const setCurrentDragCanvasId = useGridStore((state) => state.actions.setCurrentDragCanvasId); - - const { handleDrop } = useCanvasDropHandler({ - appType, - }); - const [{ isOverCurrent }, drop] = useDrop({ accept: 'box', - hover: (item, monitor) => { - const clientOffset = monitor.getClientOffset(); + hover: (item) => { + item.canvasRef = realCanvasRef?.current; + item.canvasId = id; + item.canvasWidth = getContainerCanvasWidth(); + }, + drop: async ({ componentType, component }, monitor) => { + setShowModuleBorder(false); + if (currentMode === 'view' || (appType === 'module' && componentType !== 'ModuleContainer')) return; - const appCanvasWidth = realCanvasRef?.current?.offsetWidth || 0; + const didDrop = monitor.didDrop(); + if (didDrop) return; - if (clientOffset) { - const canvasId = findNewParentIdFromMousePosition(clientOffset.x, clientOffset.y, id); - if (canvasId === id) { - setCurrentDragCanvasId(id); + const moduleInfo = component?.moduleId + ? { + moduleId: component.moduleId, + versionId: component.versionId, + environmentId: component.environmentId, + moduleName: component.displayName, + moduleContainer: component.moduleContainer, + } + : undefined; + + let addedComponent; + + if (WIDGETS_WITH_DEFAULT_CHILDREN.includes(componentType)) { + let parentComponent = addNewWidgetToTheEditor( + componentType, + monitor, + currentLayout, + realCanvasRef, + id, + moduleInfo + ); + const childComponents = addChildrenWidgetsToParent(componentType, parentComponent?.id, currentLayout); + if (componentType === 'Form') { + parentComponent = addDefaultButtonIdToForm(parentComponent, childComponents); } + addedComponent = [parentComponent, ...childComponents]; + await addComponentToCurrentPage(addedComponent); + } else { + const newComponent = addNewWidgetToTheEditor( + componentType, + monitor, + currentLayout, + realCanvasRef, + id, + moduleInfo + ); + addedComponent = [newComponent]; + await addComponentToCurrentPage(addedComponent); } - // Calculate width based on the app canvas's grid - let width = (appCanvasWidth * item.component?.defaultSize?.width) / NO_OF_GRIDS; - const componentSize = { - width, - height: item.component?.defaultSize?.height, - }; - if (clientOffset && id === 'canvas') { - activateMoveableGhost(componentSize, clientOffset, realCanvasRef); + + setActiveRightSideBarTab(RIGHT_SIDE_BAR_TAB.CONFIGURATION); + + const canvas = document.querySelector('.canvas-container'); + const sidebar = document.querySelector('.editor-sidebar'); + const droppedElem = document.getElementById(addedComponent?.[0]?.id); + + if (!canvas || !sidebar || !droppedElem) return; + + const droppedRect = droppedElem.getBoundingClientRect(); + const sidebarRect = sidebar.getBoundingClientRect(); + + const isOverlapping = droppedRect.right > sidebarRect.left && droppedRect.left < sidebarRect.right; + + if (isOverlapping) { + const overlap = droppedRect.right - sidebarRect.left; + canvas.scrollTo({ + left: canvas.scrollLeft + overlap, + behavior: 'smooth', + }); } }, - drop: (item, monitor) => { - handleDrop(item, id); - }, + + collect: (monitor) => ({ + isOverCurrent: monitor.isOver({ shallow: true }), + }), }); const showEmptyContainer = @@ -120,12 +175,34 @@ export const Container = React.memo( } const gridWidth = getContainerCanvasWidth() / NO_OF_GRIDS; - useEffect(() => { useGridStore.getState().actions.setSubContainerWidths(id, gridWidth); // eslint-disable-next-line react-hooks/exhaustive-deps }, [canvasWidth, listViewMode, columns]); + const getCanvasWidth = useCallback(() => { + // if ( + // id === 'canvas' && + // !isPagesSidebarHidden && + // isViewerSidebarPinned && + // currentLayout !== 'mobile' && + // pagePositionType == 'side' && + // appType !== 'module' + // ) { + // return `calc(100% - ${pageSidebarStyle === 'icon' ? '85px' : '226px'})`; + // } + // if ( + // id === 'canvas' && + // !isPagesSidebarHidden && + // !isViewerSidebarPinned && + // currentLayout !== 'mobile' && + // pagePositionType == 'side' + // ) { + // return `calc(100% - ${'44px'})`; + // } + return '100%'; + }, [id, isPagesSidebarHidden, isViewerSidebarPinned, currentLayout, pagePositionType, pageSidebarStyle]); + const handleCanvasClick = useCallback( (e) => { const realCanvas = e.target.closest('.real-canvas'); @@ -174,8 +251,8 @@ export const Container = React.memo( currentMode === 'view' ? computeViewerBackgroundColor(darkMode, canvasBgColor) : id === 'canvas' - ? canvasBgColor - : '#f0f0f0', + ? canvasBgColor + : '#f0f0f0', width: '100%', maxWidth: (() => { // For Main Canvas diff --git a/frontend/src/AppBuilder/AppCanvas/Grid/Grid.jsx b/frontend/src/AppBuilder/AppCanvas/Grid/Grid.jsx index 8afd3c303c..dbe9ed941d 100644 --- a/frontend/src/AppBuilder/AppCanvas/Grid/Grid.jsx +++ b/frontend/src/AppBuilder/AppCanvas/Grid/Grid.jsx @@ -1,5 +1,5 @@ // import '@/Editor/wdyr'; -import React, { useEffect, useState, useRef, useCallback, useMemo } from 'react'; +import React, { useEffect, useState, useRef, useCallback } from 'react'; // eslint-disable-next-line import/no-unresolved import Moveable from 'react-moveable'; import { shallow } from 'zustand/shallow'; @@ -10,8 +10,10 @@ import { useGridStore, useIsGroupHandleHoverd, useOpenModalWidgetId } from '@/_s import toast from 'react-hot-toast'; import { individualGroupableProps, + getMouseDistanceFromParentDiv, findChildrenAndGrandchildren, findHighestLevelofSelection, + getOffset, hasParentWithClass, getPositionForGroupDrag, adjustWidth, @@ -23,8 +25,7 @@ import { computeScrollDelta, computeScrollDeltaOnDrag, getDraggingWidgetWidth, - positionGhostElement, - findNewParentIdFromMousePosition, + positionDragGhostWidget, } from './gridUtils'; import { dragContextBuilder, getAdjustedDropPosition } from './helpers/dragEnd'; import useStore from '@/AppBuilder/_stores/store'; @@ -32,8 +33,6 @@ import './Grid.css'; import { useGroupedTargetsScrollHandler } from './hooks/useGroupedTargetsScrollHandler'; import { DROPPABLE_PARENTS, NO_OF_GRIDS, SUBCONTAINER_WIDGETS } from '../appCanvasConstants'; import { useModuleContext } from '@/AppBuilder/_contexts/ModuleContext'; -import { useElementGudelines } from './hooks/useElementGudelines'; - const CANVAS_BOUNDS = { left: 0, top: 0, right: 0, position: 'css' }; const RESIZABLE_CONFIG = { edge: ['nw', 'n', 'ne', 'w', 'e', 'sw', 's', 'se'], @@ -74,15 +73,10 @@ export default function Grid({ gridWidth, currentLayout }) { const getTemporaryLayouts = useStore((state) => state.getTemporaryLayouts, shallow); const updateContainerAutoHeight = useStore((state) => state.updateContainerAutoHeight, shallow); const [canvasBounds, setCanvasBounds] = useState(CANVAS_BOUNDS); + const draggingComponentId = useGridStore((state) => state.draggingComponentId, shallow); + const resizingComponentId = useGridStore((state) => state.resizingComponentId, shallow); const [dragParentId, setDragParentId] = useState(null); - const virtualTarget = useGridStore((state) => state.virtualTarget, shallow); - const { elementGuidelines } = useElementGudelines( - boxList, - selectedComponents, - dragParentId, - getResolvedValue, - virtualTarget - ); + const [elementGuidelines, setElementGuidelines] = useState([]); const componentsSnappedTo = useRef(null); const prevDragParentId = useRef(null); const newDragParentId = useRef(null); @@ -90,39 +84,42 @@ export default function Grid({ gridWidth, currentLayout }) { const checkIfAnyWidgetVisibilityChanged = useStore((state) => state.checkIfAnyWidgetVisibilityChanged(), shallow); const getExposedValueOfComponent = useStore((state) => state.getExposedValueOfComponent, shallow); const setReorderContainerChildren = useStore((state) => state.setReorderContainerChildren, shallow); - const currentDragCanvasId = useGridStore((state) => state.currentDragCanvasId, shallow); - const groupedTargets = [...findHighestLevelofSelection().map((component) => '.ele-' + component.id)]; const [isVerticalExpansionRestricted, setIsVerticalExpansionRestricted] = useState(false); const toggleRightSidebar = useStore((state) => state.toggleRightSidebar, shallow); - const draggingComponentId = useStore((state) => state.draggingComponentId, shallow); - const resizingComponentId = useStore((state) => state.resizingComponentId, shallow); - const snapContainer = useMemo(() => { - if (currentDragCanvasId) { - return `#canvas-${currentDragCanvasId}`; - } - if (dragParentId) { - return `#canvas-${dragParentId}`; - } - return '#real-canvas'; - }, [currentDragCanvasId, dragParentId]); - - const getMoveableTarget = () => { - if (virtualTarget) { - return '#moveable-ghost-element'; - } - return groupedTargets?.length > 1 ? groupedTargets : '.target'; - }; - - // Set moveable reference in grid store for access by other components useEffect(() => { - if (moveableRef.current) { - useGridStore.getState().setMoveableRef(moveableRef.current); - } - return () => { - useGridStore.getState().setMoveableRef(null); - }; - }, []); + const selectedSet = new Set(selectedComponents); + const draggingOrResizingId = draggingComponentId || resizingComponentId; + const isGrouped = findHighestLevelofSelection().length > 1; + const firstSelectedParent = + selectedComponents.length > 0 ? boxList.find((b) => b.id === selectedComponents[0])?.parent : null; + const selectedParent = dragParentId || firstSelectedParent; + + const guidelines = boxList + .filter((box) => { + const isVisible = + getResolvedValue(box?.component?.definition?.properties?.visibility?.value) || + getResolvedValue(box?.component?.definition?.styles?.visibility?.value); + + // Early return for non-visible elements + if (!isVisible) return false; + + if (isGrouped) { + // If component is selected, don't show its guidelines + if (selectedSet.has(box.id)) return false; + return selectedParent ? box.parent === selectedParent : !box.parent; + } + + if (draggingOrResizingId) { + if (box.id === draggingOrResizingId) return false; + return dragParentId ? box.parent === dragParentId : !box.parent; + } + + return true; + }) + .map((box) => `.ele-${box.id}`); + setElementGuidelines(guidelines); + }, [boxList, dragParentId, draggingComponentId, resizingComponentId, selectedComponents, getResolvedValue]); useEffect(() => { setBoxList( @@ -344,12 +341,13 @@ export default function Grid({ gridWidth, currentLayout }) { }); }, [selectedComponents]); + const groupedTargets = [...findHighestLevelofSelection().map((component) => '.ele-' + component.id)]; + useEffect(() => { if (moveableRef.current) { moveableRef.current.updateTarget(); } }, [temporaryHeight]); - useEffect(() => { reloadGrid(); // eslint-disable-next-line react-hooks/exhaustive-deps @@ -536,8 +534,9 @@ export default function Grid({ gridWidth, currentLayout }) { const _top = originalBox.top; // Apply transform to return to original position - ev.target.style.transform = `translate(${Math.round(_left / _gridWidth) * _gridWidth}px, ${Math.round(_top / GRID_HEIGHT) * GRID_HEIGHT - }px)`; + ev.target.style.transform = `translate(${Math.round(_left / _gridWidth) * _gridWidth}px, ${ + Math.round(_top / GRID_HEIGHT) * GRID_HEIGHT + }px)`; } }); @@ -600,16 +599,18 @@ export default function Grid({ gridWidth, currentLayout }) { const components = Array.from(document.querySelectorAll('.active-target')).filter( (component) => !selectedComponents.includes(component.getAttribute('widgetid')) ); - const draggingOrResizingComponentId = draggingComponentId || resizingComponentId; - if (!draggingOrResizingComponentId && components.length > 0 && !virtualTarget) { + const draggingOrResizing = draggingComponentId || resizingComponentId; + if (!draggingOrResizing && components.length > 0) { for (const component of components) { component?.classList?.remove('active-target'); } } - }, [draggingComponentId, resizingComponentId, isGroupDragging, selectedComponents, virtualTarget]); + }, [draggingComponentId, resizingComponentId, isGroupDragging, selectedComponents]); useGroupedTargetsScrollHandler(groupedTargets, boxList, moveableRef); + if (mode !== 'edit') return null; + return ( <> 1, }} flushSync={flushSync} - target={getMoveableTarget()} + target={groupedTargets?.length > 1 ? groupedTargets : '.target'} origin={false} - individualGroupable={virtualTarget ? false : groupedTargets.length <= 1} + individualGroupable={groupedTargets.length <= 1} draggable={!shouldFreeze && mode !== 'view'} resizable={ !shouldFreeze @@ -638,7 +639,7 @@ export default function Grid({ gridWidth, currentLayout }) { onResize={(e) => { const temporaryLayouts = getTemporaryLayouts(); if (resizingComponentId !== e.target.id) { - useStore.getState().setResizingComponentId(e.target.id); + useGridStore.getState().actions.setResizingComponentId(e.target.id); showGridLines(); } @@ -647,8 +648,12 @@ export default function Grid({ gridWidth, currentLayout }) { let _gridWidth = useGridStore.getState().subContainerWidths[currentWidget.component?.parent] || gridWidth; // Show grid during resize - showGridLines(); - + if (currentWidget.component?.parent) { + document.getElementById('canvas-' + currentWidget.component?.parent)?.classList.add('show-grid'); + setDragParentId(currentWidget.component?.parent); + } else { + document.getElementById('real-canvas').classList.add('show-grid'); + } handleActivateTargets(currentWidget.component?.parent); const currentWidth = currentWidget.width * _gridWidth; @@ -692,7 +697,6 @@ export default function Grid({ gridWidth, currentLayout }) { e.target.style.transform = `translate(${transformX}px, ${transformY}px)`; if (e.width > 0) e.target.style.width = `${e.width}px`; if (e.height > 0) e.target.style.height = `${e.height}px`; - positionGhostElement(e.target, 'resize-ghost-widget'); }} onResizeStart={(e) => { if ( @@ -711,7 +715,7 @@ export default function Grid({ gridWidth, currentLayout }) { }} onResizeEnd={(e) => { try { - useStore.getState().setResizingComponentId(null); + useGridStore.getState().actions.setResizingComponentId(null); const currentWidget = boxList.find(({ id }) => { return id === e.target.id; }); @@ -748,8 +752,9 @@ export default function Grid({ gridWidth, currentLayout }) { const roundedTransformY = Math.round(transformY / GRID_HEIGHT) * GRID_HEIGHT; transformY = transformY % GRID_HEIGHT === 5 ? roundedTransformY - GRID_HEIGHT : roundedTransformY; - e.target.style.transform = `translate(${Math.round(transformX / _gridWidth) * _gridWidth}px, ${Math.round(transformY / GRID_HEIGHT) * GRID_HEIGHT - }px)`; + e.target.style.transform = `translate(${Math.round(transformX / _gridWidth) * _gridWidth}px, ${ + Math.round(transformY / GRID_HEIGHT) * GRID_HEIGHT + }px)`; if (!maxWidthHit || e.width < e.target.clientWidth) { e.target.style.width = `${Math.round(e.lastEvent.width / _gridWidth) * _gridWidth}px`; } @@ -862,9 +867,6 @@ export default function Grid({ gridWidth, currentLayout }) { }} checkInput onDragStart={(e) => { - if (e.target.id === 'moveable-ghost-element') { - return true; - } // This is to prevent parent component from being dragged and the stop the propagation of the event if (getHoveredComponentForGrid() !== e.target.id) { return false; @@ -917,9 +919,6 @@ export default function Grid({ gridWidth, currentLayout }) { }} onDragEnd={(e) => { handleDeactivateTargets(); - if (e.target.id === 'moveable-ghost-element') { - return; - } try { if (isDraggingRef.current) { useStore.getState().setDraggingComponentId(null); @@ -932,6 +931,7 @@ export default function Grid({ gridWidth, currentLayout }) { setDragParentId(null); if (!e.lastEvent) return; + // Build the drag context from the event const dragContext = dragContextBuilder({ event: e, widgets: boxList, isModuleEditor }); const { target, source, dragged } = dragContext; @@ -978,21 +978,6 @@ export default function Grid({ gridWidth, currentLayout }) { toggleCanvasUpdater(); }} onDrag={(e) => { - if (e.target.id === 'moveable-ghost-element') { - showGridLines(); - const _gridWidth = useGridStore.getState().subContainerWidths[currentDragCanvasId] || gridWidth; - let left = e.translate[0]; - let top = e.translate[1]; - - if (currentDragCanvasId === 'canvas') { - left = Math.round(e.translate[0] / _gridWidth) * _gridWidth; - top = Math.round(e.translate[1] / GRID_HEIGHT) * GRID_HEIGHT; - } - - useGridStore.getState().actions.setGhostDragPosition({ left, top, e }); - e.target.style.transform = `translate(${left}px, ${top}px)`; - return false; - } // Since onDrag is called multiple times when dragging, hence we are using isDraggingRef to prevent setting state again and again if (!isDraggingRef.current) { useStore.getState().setDraggingComponentId(e.target.id); @@ -1061,7 +1046,16 @@ export default function Grid({ gridWidth, currentLayout }) { // This block is to show grid lines on the canvas when the dragged element is over a new canvas if (document.elementFromPoint(e.clientX, e.clientY)) { - let newParentId = findNewParentIdFromMousePosition(e.clientX, e.clientY, e.target.id); + const targetElems = document.elementsFromPoint(e.clientX, e.clientY); + const draggedOverElements = targetElems.filter( + (ele) => + (ele.id !== e.target.id && ele.classList.contains('target')) || ele.classList.contains('real-canvas') + ); + const draggedOverElem = draggedOverElements.find((ele) => ele.classList.contains('target')); + const draggedOverContainer = draggedOverElements.find((ele) => ele.classList.contains('real-canvas')); + + // Determine potential new parent + let newParentId = draggedOverContainer?.getAttribute('data-parentId') || draggedOverElem?.id; if (newParentId === e.target.id) { newParentId = boxList.find((box) => box.id === e.target.id)?.component?.parent; @@ -1089,7 +1083,7 @@ export default function Grid({ gridWidth, currentLayout }) { `translate: ${e.translate[0]} | Round: ${Math.round(e.translate[0] / gridWidth) * gridWidth} | ${gridWidth}` ); - positionGhostElement(e.target, 'moveable-drag-ghost'); + positionDragGhostWidget(e.target); }} onDragGroup={(ev) => { const { events } = ev; @@ -1172,10 +1166,8 @@ export default function Grid({ gridWidth, currentLayout }) { component.element.classList.add('active-target'); } }} - // snapGridAll={true} + snapGridAll={true} scrollable={true} - // snapContainer={snapContainer} - // snapGridWidth={100} /> ); diff --git a/frontend/src/AppBuilder/AppCanvas/Grid/gridUtils.js b/frontend/src/AppBuilder/AppCanvas/Grid/gridUtils.js index 1a3bc36b64..07a56a3c4c 100644 --- a/frontend/src/AppBuilder/AppCanvas/Grid/gridUtils.js +++ b/frontend/src/AppBuilder/AppCanvas/Grid/gridUtils.js @@ -530,58 +530,24 @@ export const getDraggingWidgetWidth = (canvasParentId, widgetWidth) => { return draggingWidgetWidth; }; -/** - * Positions a ghost/feedback element relative to the main canvas - * @param {HTMLElement} targetElement - The element being dragged/resized - * @param {string} ghostElementId - The ID of the ghost element to position - * @param {Object} options - Additional positioning options - * @param {boolean} options.includeSize - Whether to update width/height of ghost element - */ -export const positionGhostElement = (targetElement, ghostElementId) => { - const ghostElement = document.getElementById(ghostElementId); +export const positionDragGhostWidget = (draggedElement) => { + const ghostElement = document.getElementById('moveable-drag-ghost'); - if (!ghostElement || !targetElement) return; + if (!ghostElement || !draggedElement) return; const mainCanvas = document.getElementById('real-canvas'); if (!mainCanvas) return; const mainCanvasRect = mainCanvas.getBoundingClientRect(); - const targetRect = targetElement.getBoundingClientRect(); + const draggedRect = draggedElement.getBoundingClientRect(); // Calculate position relative to main canvas - const relativeLeft = targetRect.left - mainCanvasRect.left; - const relativeTop = targetRect.top - mainCanvasRect.top; + const relativeLeft = draggedRect.left - mainCanvasRect.left; + const relativeTop = draggedRect.top - mainCanvasRect.top; // Apply the position ghostElement.style.left = `${relativeLeft}px`; ghostElement.style.top = `${relativeTop}px`; - ghostElement.style.width = `${targetRect.width}px`; - ghostElement.style.height = `${targetRect.height}px`; -}; - - -/** - * Finds the new parent ID based on the current mouse position during drag operations - * @param {number} clientX - The X coordinate of the mouse position - * @param {number} clientY - The Y coordinate of the mouse position - * @param {string} currentTargetId - The ID of the currently dragged element to exclude from search - * @returns {string|null} - The new parent ID or null if no valid parent is found - */ -export const findNewParentIdFromMousePosition = (clientX, clientY, currentTargetId) => { - if (!document.elementFromPoint(clientX, clientY)) { - return null; - } - - const targetElems = document.elementsFromPoint(clientX, clientY); - const draggedOverElements = targetElems.filter( - (ele) => (ele.id !== currentTargetId && ele.classList.contains('target')) || ele.classList.contains('real-canvas') - ); - - const draggedOverElem = draggedOverElements.find((ele) => ele.classList.contains('target')); - const draggedOverContainer = draggedOverElements.find((ele) => ele.classList.contains('real-canvas')); - - // Determine potential new parent - const newParentId = draggedOverContainer?.getAttribute('data-parentId') || draggedOverElem?.id; - - return newParentId || null; + ghostElement.style.width = `${draggedRect.width}px`; + ghostElement.style.height = `${draggedRect.height}px`; }; diff --git a/frontend/src/AppBuilder/AppCanvas/Grid/hooks/useElementGudelines.js b/frontend/src/AppBuilder/AppCanvas/Grid/hooks/useElementGudelines.js deleted file mode 100644 index 55587b33fd..0000000000 --- a/frontend/src/AppBuilder/AppCanvas/Grid/hooks/useElementGudelines.js +++ /dev/null @@ -1,72 +0,0 @@ -import { useEffect, useState } from 'react'; -import { findHighestLevelofSelection } from '../gridUtils'; -import { useGridStore } from '@/_stores/gridStore'; -import useStore from '@/AppBuilder/_stores/store'; - -export const useElementGudelines = (boxList, selectedComponents, dragParentId, getResolvedValue, virtualTarget) => { - const [elementGuidelines, setElementGuidelines] = useState([]); - const draggingComponentId = useStore((state) => state.draggingComponentId); - const resizingComponentId = useStore((state) => state.resizingComponentId); - const currentDragCanvasId = useGridStore((state) => state.currentDragCanvasId); - - useEffect(() => { - const selectedSet = new Set(selectedComponents); - const draggingOrResizingId = draggingComponentId || resizingComponentId; - const isGrouped = findHighestLevelofSelection().length > 1; - const firstSelectedParent = - selectedComponents.length > 0 ? boxList.find((b) => b.id === selectedComponents[0])?.parent : null; - const selectedParent = dragParentId || firstSelectedParent; - const isAnyModalOpen = document.querySelector('#modal-container') ? true : false; - - const guidelines = boxList - .filter((box) => { - const isVisible = - getResolvedValue(box?.component?.definition?.properties?.visibility?.value) || - getResolvedValue(box?.component?.definition?.styles?.visibility?.value); - - // Early return for non-visible elements - if (!isVisible) return false; - - // Don't show guidelines for components which are outside the modal specially on main canvas - if (virtualTarget && isAnyModalOpen) { - if (box.parent === 'canvas' || !box.parent) return false; - } - - // This block is for first time drop using react-dnd - if (virtualTarget && currentDragCanvasId !== null) { - if (currentDragCanvasId === 'canvas') { - if (box.parent && box.parent !== 'canvas') return false; - } else { - // For sub-containers, only show components whose parent matches the canvasId - if (box.parent !== currentDragCanvasId) return false; - } - } - - if (isGrouped) { - // If component is selected, don't show its guidelines - if (selectedSet.has(box.id)) return false; - return selectedParent ? box.parent === selectedParent : !box.parent; - } - - if (draggingOrResizingId) { - if (box.id === draggingOrResizingId) return false; - return dragParentId ? box.parent === dragParentId : !box.parent; - } - - return true; - }) - .map((box) => `.ele-${box.id}`); - setElementGuidelines(guidelines); - }, [ - boxList, - dragParentId, - draggingComponentId, - resizingComponentId, - selectedComponents, - getResolvedValue, - currentDragCanvasId, - virtualTarget, - ]); - - return { elementGuidelines }; -}; diff --git a/frontend/src/AppBuilder/AppCanvas/WidgetWrapper.jsx b/frontend/src/AppBuilder/AppCanvas/WidgetWrapper.jsx index 954be5607a..057781f8ec 100644 --- a/frontend/src/AppBuilder/AppCanvas/WidgetWrapper.jsx +++ b/frontend/src/AppBuilder/AppCanvas/WidgetWrapper.jsx @@ -1,8 +1,9 @@ import React, { memo } from 'react'; import useStore from '@/AppBuilder/_stores/store'; import { shallow } from 'zustand/shallow'; -import { ResizeGhostWidget } from './GhostWidgets'; +import { DragGhostWidget, ResizeGhostWidget } from './GhostWidgets'; import { ConfigHandle } from './ConfigHandle/ConfigHandle'; +import { useGridStore } from '@/_stores/gridStore'; import cx from 'classnames'; import RenderWidget from './RenderWidget'; import { useModuleContext } from '@/AppBuilder/_contexts/ModuleContext'; @@ -34,7 +35,7 @@ const WidgetWrapper = memo( const temporaryLayouts = useStore((state) => state.temporaryLayouts?.[id], shallow); const isWidgetActive = useStore((state) => state.selectedComponents.find((sc) => sc === id) && !readOnly, shallow); const isDragging = useStore((state) => state.draggingComponentId === id); - const isResizing = useStore((state) => state.resizingComponentId === id); + const isResizing = useGridStore((state) => state.resizingComponentId === id); const componentType = useStore( (state) => state.getComponentDefinition(id, moduleId)?.component?.component, shallow diff --git a/frontend/src/AppBuilder/AppCanvas/appCanvasUtils.js b/frontend/src/AppBuilder/AppCanvas/appCanvasUtils.js index debc47c61e..c689adb51c 100644 --- a/frontend/src/AppBuilder/AppCanvas/appCanvasUtils.js +++ b/frontend/src/AppBuilder/AppCanvas/appCanvasUtils.js @@ -5,7 +5,7 @@ import useStore from '@/AppBuilder/_stores/store'; import { toast } from 'react-hot-toast'; import _, { debounce } from 'lodash'; import { useGridStore } from '@/_stores/gridStore'; -import { findHighestLevelofSelection, getMouseDistanceFromParentDiv } from './Grid/gridUtils'; +import { findHighestLevelofSelection } from './Grid/gridUtils'; import { CANVAS_WIDTHS, NO_OF_GRIDS, @@ -29,32 +29,32 @@ export function snapToGrid(canvasWidth, x, y) { //TODO: componentTypes should be a key value pair and get the definition directly by passing the componentType export const addNewWidgetToTheEditor = ( componentType, + eventMonitorObject, currentLayout, realCanvasRef, parentId, moduleInfo = undefined ) => { - const canvasBoundingRect = realCanvasRef?.getBoundingClientRect(); + const canvasBoundingRect = realCanvasRef?.current?.getBoundingClientRect(); const componentMeta = componentTypes.find((component) => component.component === componentType); const componentName = computeComponentName(componentType, useStore.getState().getCurrentPageComponents()); - const parentCanvasType = realCanvasRef?.getAttribute('component-type'); + const componentData = deepClone(componentMeta); const defaultWidth = componentData.defaultSize.width; const defaultHeight = componentData.defaultSize.height; - const { e } = useGridStore.getState().getGhostDragPosition(); + const offsetFromTopOfWindow = canvasBoundingRect?.top; + const offsetFromLeftOfWindow = canvasBoundingRect?.left; + const currentOffset = eventMonitorObject?.getSourceClientOffset(); const subContainerWidth = canvasBoundingRect?.width; - const { left: _left, top: _top } = getMouseDistanceFromParentDiv( - e, - parentId === 'canvas' ? 'real-canvas' : parentId, - parentCanvasType - ); - let [left, top] = snapToGrid(subContainerWidth, _left, _top); + let left = Math.round(currentOffset?.x - offsetFromLeftOfWindow); + let top = Math.round(currentOffset?.y - offsetFromTopOfWindow); + + [left, top] = snapToGrid(subContainerWidth, left, top); const gridWidth = subContainerWidth / NO_OF_GRIDS; left = Math.round(left / gridWidth); - // Adjust widget width based on the dropping canvas width const mainCanvasWidth = useGridStore.getState().subContainerWidths['canvas']; let width = Math.round((defaultWidth * mainCanvasWidth) / gridWidth); @@ -85,7 +85,6 @@ export const addNewWidgetToTheEditor = ( left = Math.max(0, NO_OF_GRIDS - width); width = Math.min(width, NO_OF_GRIDS); } - if (currentLayout === 'mobile') { componentData.definition.others.showOnDesktop.value = `{{false}}`; componentData.definition.others.showOnMobile.value = `{{true}}`; diff --git a/frontend/src/AppBuilder/AppCanvas/useCanvasDropHandler.js b/frontend/src/AppBuilder/AppCanvas/useCanvasDropHandler.js deleted file mode 100644 index 05a9a36502..0000000000 --- a/frontend/src/AppBuilder/AppCanvas/useCanvasDropHandler.js +++ /dev/null @@ -1,113 +0,0 @@ -import useStore from '@/AppBuilder/_stores/store'; -import { useGridStore } from '@/_stores/gridStore'; -import { shallow } from 'zustand/shallow'; -import { noop } from 'lodash'; -import { - addChildrenWidgetsToParent, - addNewWidgetToTheEditor, - addDefaultButtonIdToForm, -} from '../AppCanvas/appCanvasUtils'; -import { WIDGETS_WITH_DEFAULT_CHILDREN } from '../AppCanvas/appCanvasConstants'; -import { RIGHT_SIDE_BAR_TAB } from '../RightSideBar/rightSidebarConstants'; -import { isPDFSupported } from '@/_helpers/appUtils'; -import toast from 'react-hot-toast'; -import { useModuleContext } from '@/AppBuilder/_contexts/ModuleContext'; -import { handleDeactivateTargets, hideGridLines } from '../AppCanvas/Grid/gridUtils'; - -export const useCanvasDropHandler = ({ appType }) => { - const { moduleId } = useModuleContext(); - - const addComponentToCurrentPage = useStore((state) => state.addComponentToCurrentPage, shallow); - const setActiveRightSideBarTab = useStore((state) => state.setActiveRightSideBarTab, shallow); - const setShowModuleBorder = useStore((state) => state.setShowModuleBorder, shallow) || noop; - const currentMode = useStore((state) => state.modeStore.modules[moduleId].currentMode, shallow); - const currentLayout = useStore((state) => state.currentLayout, shallow); - const setCurrentDragCanvasId = useGridStore((state) => state.actions.setCurrentDragCanvasId); - - const handleDrop = async ({ componentType: draggedComponentType, component }, canvasId) => { - const realCanvasRef = - !canvasId || canvasId === 'canvas' - ? document.getElementById(`real-canvas`) - : document.getElementById(`canvas-${canvasId}`); - - handleDeactivateTargets(); - hideGridLines(); - - setShowModuleBorder(false); // Hide the module border when dropping - - if (currentMode === 'view' || (appType === 'module' && draggedComponentType !== 'ModuleContainer')) { - return; - } - - if (draggedComponentType === 'PDF' && !isPDFSupported()) { - toast.error( - 'PDF is not supported in this version of browser. We recommend upgrading to the latest version for full support.' - ); - return; - } - - // IMPORTANT: This logic needs to be changed when we implement the module versioning - const moduleInfo = component?.moduleId - ? { - moduleId: component.moduleId, - versionId: component.versionId, - environmentId: component.environmentId, - moduleName: component.displayName, - moduleContainer: component.moduleContainer, - } - : undefined; - - let addedComponent; - - if (WIDGETS_WITH_DEFAULT_CHILDREN.includes(draggedComponentType)) { - let parentComponent = addNewWidgetToTheEditor( - draggedComponentType, - currentLayout, - realCanvasRef, - canvasId, - moduleInfo - ); - const childComponents = addChildrenWidgetsToParent(draggedComponentType, parentComponent?.id, currentLayout); - if (draggedComponentType === 'Form') { - parentComponent = addDefaultButtonIdToForm(parentComponent, childComponents); - } - addedComponent = [parentComponent, ...childComponents]; - await addComponentToCurrentPage(addedComponent); - } else { - const newComponent = addNewWidgetToTheEditor( - draggedComponentType, - currentLayout, - realCanvasRef, - canvasId, - moduleInfo - ); - addedComponent = [newComponent]; - await addComponentToCurrentPage(addedComponent); - } - - setActiveRightSideBarTab(RIGHT_SIDE_BAR_TAB.CONFIGURATION); - - const canvas = document.querySelector('.canvas-container'); - const sidebar = document.querySelector('.editor-sidebar'); - const droppedElem = document.getElementById(addedComponent?.[0]?.id); - - if (!canvas || !sidebar || !droppedElem) return; - - const droppedRect = droppedElem.getBoundingClientRect(); - const sidebarRect = sidebar.getBoundingClientRect(); - - const isOverlapping = droppedRect.right > sidebarRect.left && droppedRect.left < sidebarRect.right; - - if (isOverlapping) { - const overlap = droppedRect.right - sidebarRect.left; - canvas.scrollTo({ - left: canvas.scrollLeft + overlap, - behavior: 'smooth', - }); - } - // Reset canvas ID when dropping - setCurrentDragCanvasId(null); - }; - - return { handleDrop }; -}; diff --git a/frontend/src/AppBuilder/RightSideBar/ComponentManagerTab/DragLayer.jsx b/frontend/src/AppBuilder/RightSideBar/ComponentManagerTab/DragLayer.jsx index 73ba1cda16..16b8a74f77 100644 --- a/frontend/src/AppBuilder/RightSideBar/ComponentManagerTab/DragLayer.jsx +++ b/frontend/src/AppBuilder/RightSideBar/ComponentManagerTab/DragLayer.jsx @@ -1,4 +1,4 @@ -import React, { useEffect, useRef } from 'react'; +import React, { useEffect } from 'react'; import { WidgetBox } from '../WidgetBox'; import { ModuleWidgetBox } from '@/modules/Modules/components'; import { useDrag, useDragLayer } from 'react-dnd'; @@ -9,8 +9,6 @@ import useStore from '@/AppBuilder/_stores/store'; import { shallow } from 'zustand/shallow'; import { useModuleContext } from '@/AppBuilder/_contexts/ModuleContext'; import { noop } from 'lodash'; -import { useGridStore } from '@/_stores/gridStore'; -import { useCanvasDropHandler } from '@/AppBuilder/AppCanvas/useCanvasDropHandler'; export const DragLayer = ({ index, component, isModuleTab = false, disabled = false }) => { const [isRightSidebarOpen, toggleRightSidebar] = useStore( @@ -20,20 +18,11 @@ export const DragLayer = ({ index, component, isModuleTab = false, disabled = fa const isRightSidebarPinned = useStore((state) => state.isRightSidebarPinned); const { isModuleEditor } = useModuleContext(); const setShowModuleBorder = useStore((state) => state.setShowModuleBorder, shallow) || noop; - const { handleDrop } = useCanvasDropHandler({ appType: isModuleTab ? 'module' : 'app' }) || noop; - const [{ isDragging }, drag, preview] = useDrag( () => ({ type: 'box', item: { componentType: component.component, component }, collect: (monitor) => ({ isDragging: monitor.isDragging() }), - end: (item, monitor) => { - const clientOffset = monitor.getClientOffset(); - const currentDragCanvasId = useGridStore.getState().currentDragCanvasId; - if (clientOffset) { - handleDrop(item, currentDragCanvasId); - } - }, }), [component.component] ); @@ -57,14 +46,80 @@ export const DragLayer = ({ index, component, isModuleTab = false, disabled = fa // ? component.module_container.layouts[currentLayout] // : component.defaultSize || { width: 30, height: 40 }; + const size = component.defaultSize || { width: 30, height: 40 }; + return ( <> + {isDragging && }
- {isModuleTab ? : } + style={{ height: '100%', width: isModuleTab && '100%' }} + > + {isModuleTab ? ( + + ) : ( + + )}
); -}; \ No newline at end of file +}; + +const CustomDragLayer = ({ size }) => { + const { currentOffset, item } = useDragLayer((monitor) => ({ + currentOffset: monitor.getSourceClientOffset(), + item: monitor.getItem(), + })); + console.log(currentOffset, 'currentOffset'); + if (!currentOffset) return null; + + const canvasWidth = item?.canvasWidth; + const canvasBounds = item?.canvasRef?.getBoundingClientRect(); + const height = size.height; + + const appCanvasWidth = document.getElementById('real-canvas')?.offsetWidth || 0; + + // Calculate width based on the app canvas's grid + let width = (appCanvasWidth * size.width) / NO_OF_GRIDS; + + // Calculate position relative to the current canvas (parent or child) + const left = currentOffset.x - (canvasBounds?.left || 0); + const top = currentOffset.y - (canvasBounds?.top || 0); + + // Ensure width doesn't exceed the current container's width + if (width > canvasWidth) { + width = canvasWidth; + } + + // Snap width to grid (round to nearest grid unit) + const gridUnitWidth = canvasWidth / NO_OF_GRIDS; + const gridUnits = Math.round(width / gridUnitWidth); + width = gridUnits * gridUnitWidth; + + const [x, y] = snapToGrid(canvasWidth, left, top); + return ( +
+
+
+ ); +}; diff --git a/frontend/src/AppBuilder/_hooks/useDropVirtualMoveableGhost.js b/frontend/src/AppBuilder/_hooks/useDropVirtualMoveableGhost.js deleted file mode 100644 index e2795235eb..0000000000 --- a/frontend/src/AppBuilder/_hooks/useDropVirtualMoveableGhost.js +++ /dev/null @@ -1,101 +0,0 @@ -import { useRef } from 'react'; -import { useGridStore } from '@/_stores/gridStore'; - -export const useDropVirtualMoveableGhost = () => { - const ghostElementRef = useRef(null); - const isActiveRef = useRef(false); - - const getMoveableRef = useGridStore((state) => state.moveableRef); - const setVirtualTarget = useGridStore((state) => state.actions.setVirtualTarget); - - const createGhostMoveElement = (componentSize) => { - if (ghostElementRef.current) return; - - const ghost = document.createElement('div'); - ghost.id = 'moveable-ghost-element'; - ghost.className = 'moveable-ghost target'; - ghost.style.cssText = ` - position: absolute; - width: ${componentSize.width || 100}px; - height: ${componentSize.height || 40}px; - background: #D9E2FC; - opacity: 0.7; - pointer-events: none; - z-index: 9998; - box-sizing: border-box; - top: 0; - left: 0; - `; - - const container = document.getElementById('real-canvas'); - container.appendChild(ghost); - ghostElementRef.current = ghost; - - return ghost; - }; - - const updateMoveableGhostPosition = (mousePosition, canvasRef) => { - if (!ghostElementRef.current || !canvasRef?.current || !mousePosition) return; - - const canvasRect = canvasRef.current.getBoundingClientRect(); - const relativeX = mousePosition.x - canvasRect.left; - const relativeY = mousePosition.y - canvasRect.top; - - ghostElementRef.current.style.transform = `translate(${relativeX}px, ${relativeY}px)`; - }; - - const activateMoveableGhost = (componentSize, mousePosition, canvasRef) => { - if (isActiveRef.current) return; - - isActiveRef.current = true; - - const ghost = createGhostMoveElement(componentSize, canvasRef); - if (ghost && mousePosition) { - updateMoveableGhostPosition(mousePosition, canvasRef); - - // Trigger moveable drag on the ghost element to show guidelines - const moveableInstance = getMoveableRef; - if (moveableInstance && ghost) { - try { - const fakeEvent = new MouseEvent('mousedown', { - clientX: mousePosition.x, - clientY: mousePosition.y, - bubbles: true, - cancelable: true, - view: window, - button: 0, - buttons: 1, - }); - moveableInstance.waitToChangeTarget().then((e) => { - moveableInstance.dragStart(fakeEvent, ghost); - }); - setVirtualTarget(ghost); - } catch (error) { - console.warn('Failed to trigger moveable dragStart:', error); - } - } - } - }; - - const deactivateMoveableGhost = () => { - if (!isActiveRef.current) return; - - isActiveRef.current = false; - - const moveableInstance = getMoveableRef; - if (moveableInstance && ghostElementRef.current) { - try { - setVirtualTarget(null); - ghostElementRef.current.remove(); - ghostElementRef.current = null; - } catch (error) { - console.warn('Failed to trigger moveable dragEnd:', error); - } - } - }; - - return { - activateMoveableGhost, - deactivateMoveableGhost, - }; -}; diff --git a/frontend/src/AppBuilder/_hooks/useGhostMoveable.js b/frontend/src/AppBuilder/_hooks/useGhostMoveable.js deleted file mode 100644 index 0e5adaa9c1..0000000000 --- a/frontend/src/AppBuilder/_hooks/useGhostMoveable.js +++ /dev/null @@ -1,107 +0,0 @@ -import { useRef } from 'react'; -import { useGridStore } from '@/_stores/gridStore'; -import { NO_OF_GRIDS, GRID_HEIGHT } from '@/AppBuilder/AppCanvas/appCanvasConstants'; -import { snapToGrid } from '@/AppBuilder/AppCanvas/appCanvasUtils'; - -export const useGhostMoveable = () => { - const ghostElementRef = useRef(null); - const isActiveRef = useRef(false); - - const getMoveableRef = useGridStore((state) => state.moveableRef); - const setVirtualTarget = useGridStore((state) => state.actions.setVirtualTarget); - - const createGhostElement = (componentSize) => { - if (ghostElementRef.current) return; - - const ghost = document.createElement('div'); - ghost.id = 'moveable-ghost-element'; - ghost.className = 'moveable-ghost target'; - ghost.style.cssText = ` - position: absolute; - width: ${componentSize.width || 100}px; - height: ${componentSize.height || 40}px; - background: #D9E2FC; - opacity: 0.7; - pointer-events: none; - z-index: 9998; - box-sizing: border-box; - top: 0; - left: 0; - `; - - const container = document.getElementById('real-canvas'); - container.appendChild(ghost); - ghostElementRef.current = ghost; - - return ghost; - }; - - const updateGhostPosition = (mousePosition, canvasRef) => { - if (!ghostElementRef.current || !canvasRef?.current || !mousePosition) return; - - const canvasRect = canvasRef.current.getBoundingClientRect(); - const relativeX = mousePosition.x - canvasRect.left; - const relativeY = mousePosition.y - canvasRect.top; - - // Apply grid snapping - // const gridWidth = canvasRef.current.offsetWidth / NO_OF_GRIDS; - // const snappedX = Math.round(relativeX / gridWidth) * gridWidth; - // const snappedY = Math.round(relativeY / GRID_HEIGHT) * GRID_HEIGHT; - ghostElementRef.current.style.transform = `translate(${relativeX}px, ${relativeY}px)`; - }; - - const activateGhost = (componentSize, mousePosition, canvasRef) => { - if (isActiveRef.current) return; - - isActiveRef.current = true; - - const ghost = createGhostElement(componentSize, canvasRef); - if (ghost && mousePosition) { - updateGhostPosition(mousePosition, canvasRef); - - // Trigger moveable drag on the ghost element to show guidelines - const moveableInstance = getMoveableRef; - if (moveableInstance && ghost) { - try { - const fakeEvent = new MouseEvent('mousedown', { - clientX: mousePosition.x, - clientY: mousePosition.y, - bubbles: true, - cancelable: true, - view: window, - button: 0, - buttons: 1, - }); - moveableInstance.waitToChangeTarget().then((e) => { - moveableInstance.dragStart(fakeEvent, ghost); - }); - setVirtualTarget(ghost); - } catch (error) { - console.warn('Failed to trigger moveable dragStart:', error); - } - } - } - }; - - const deactivateGhost = () => { - if (!isActiveRef.current) return; - - isActiveRef.current = false; - - const moveableInstance = getMoveableRef; - if (moveableInstance && ghostElementRef.current) { - try { - setVirtualTarget(null); - ghostElementRef.current.remove(); - ghostElementRef.current = null; - } catch (error) { - console.warn('Failed to trigger moveable dragEnd:', error); - } - } - }; - - return { - activateGhost, - deactivateGhost, - }; -}; diff --git a/frontend/src/AppBuilder/_stores/slices/gridSlice.js b/frontend/src/AppBuilder/_stores/slices/gridSlice.js index 6a74c12049..9c4d0e1203 100644 --- a/frontend/src/AppBuilder/_stores/slices/gridSlice.js +++ b/frontend/src/AppBuilder/_stores/slices/gridSlice.js @@ -10,12 +10,10 @@ const initialState = { lastCanvasClickPosition: null, temporaryLayouts: {}, draggingComponentId: null, - resizingComponentId: null, reorderContainerChildren: { containerId: null, triggerUpdate: 0, }, - shouldPreventDrop: false, }; export const createGridSlice = (set, get) => ({ @@ -37,7 +35,6 @@ export const createGridSlice = (set, get) => ({ get().toggleCanvasUpdater(); }, 200), setDraggingComponentId: (id) => set(() => ({ draggingComponentId: id })), - setResizingComponentId: (id) => set(() => ({ resizingComponentId: id })), moveComponentPosition: (direction) => { const { setComponentLayout, currentLayout, getSelectedComponentsDefinition, debouncedToggleCanvasUpdater } = get(); let layouts = {}; @@ -473,7 +470,4 @@ export const createGridSlice = (set, get) => ({ reorderContainerChildren: { containerId, triggerUpdate: state.reorderContainerChildren.triggerUpdate + 1 }, })); }, - setShouldPreventDrop: (shouldPreventDrop) => { - set(() => ({ shouldPreventDrop })); - }, }); diff --git a/frontend/src/_stores/gridStore.js b/frontend/src/_stores/gridStore.js index 6b9822f6dd..213f07ac16 100644 --- a/frontend/src/_stores/gridStore.js +++ b/frontend/src/_stores/gridStore.js @@ -12,15 +12,11 @@ const initialState = { idGroupDragged: false, openModalWidgetId: null, subContainerWidths: {}, - moveableRef: null, - virtualTarget: null, - currentDragCanvasId: null, - ghostDragPosition: null, }; export const useGridStore = create( zustandDevTools( - (set, get) => ({ + (set) => ({ ...initialState, actions: { setResizingComponentId: (id) => set({ resizingComponentId: id }), @@ -30,22 +26,7 @@ export const useGridStore = create( setOpenModalWidgetId: (openModalWidgetId) => set({ openModalWidgetId }), setSubContainerWidths: (id, width) => set((state) => ({ subContainerWidths: { ...state.subContainerWidths, [id]: width } })), - setVirtualTarget: (target) => set({ virtualTarget: target }), - setCurrentDragCanvasId: (canvasId) => set({ currentDragCanvasId: canvasId }), - setGhostDragPosition: (position) => set({ ghostDragPosition: position }), }, - addToElementGuidelines: (selector) => - set((state) => ({ - dynamicElementGuidelines: [...state.dynamicElementGuidelines, selector], - })), - removeFromElementGuidelines: (selector) => - set((state) => ({ - dynamicElementGuidelines: state.dynamicElementGuidelines.filter((item) => item !== selector), - })), - clearDynamicElementGuidelines: () => set({ dynamicElementGuidelines: [] }), - setMoveableRef: (ref) => set({ moveableRef: ref }), - - getGhostDragPosition: () => get().ghostDragPosition, }), { name: 'Grid Store' } ) diff --git a/frontend/src/modules/common/components/BaseColorSwatches/BaseColorSwatches.jsx b/frontend/src/modules/common/components/BaseColorSwatches/BaseColorSwatches.jsx index 0da388a0eb..160799dc9d 100644 --- a/frontend/src/modules/common/components/BaseColorSwatches/BaseColorSwatches.jsx +++ b/frontend/src/modules/common/components/BaseColorSwatches/BaseColorSwatches.jsx @@ -116,6 +116,7 @@ const BaseColorSwatches = ({ ); }; const ColorPickerInputBox = () => { + console.log('onReset', onReset); return (