From 74dada642cbd45a5566790da71ef527a0471c041 Mon Sep 17 00:00:00 2001 From: Nakul Nagargade Date: Wed, 2 Jul 2025 10:48:16 +0530 Subject: [PATCH] fix for modal and resolve merge conflicts --- .../src/AppBuilder/AppCanvas/Container.jsx | 101 ++---------------- .../src/AppBuilder/AppCanvas/Grid/Grid.jsx | 35 +++--- .../AppBuilder/AppCanvas/Grid/gridUtils.js | 26 +++++ .../Grid/hooks/useElementGudelines.js | 23 ++-- .../AppBuilder/_stores/slices/gridSlice.js | 2 + 5 files changed, 57 insertions(+), 130 deletions(-) diff --git a/frontend/src/AppBuilder/AppCanvas/Container.jsx b/frontend/src/AppBuilder/AppCanvas/Container.jsx index b1c2893ca5..65fec613d1 100644 --- a/frontend/src/AppBuilder/AppCanvas/Container.jsx +++ b/frontend/src/AppBuilder/AppCanvas/Container.jsx @@ -4,26 +4,18 @@ import cx from 'classnames'; import WidgetWrapper from './WidgetWrapper'; import useStore from '@/AppBuilder/_stores/store'; import { shallow } from 'zustand/shallow'; -import { useDrop, useDragLayer, useDragDropManager } from 'react-dnd'; -import { - addChildrenWidgetsToParent, - addNewWidgetToTheEditor, - computeViewerBackgroundColor, - getSubContainerWidthAfterPadding, - addDefaultButtonIdToForm, -} from './appCanvasUtils'; -import { CANVAS_WIDTHS, NO_OF_GRIDS, WIDGETS_WITH_DEFAULT_CHILDREN, GRID_HEIGHT } from './appCanvasConstants'; +import { useDrop, useDragLayer } from 'react-dnd'; +import { computeViewerBackgroundColor, getSubContainerWidthAfterPadding } from './appCanvasUtils'; +import { CANVAS_WIDTHS, NO_OF_GRIDS, GRID_HEIGHT } 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 { noop } from 'lodash'; import { useGhostMoveable } from '@/AppBuilder/_hooks/useGhostMoveable'; import { useCanvasDropHandler } from './useCanvasDropHandler'; +import { findNewParentIdFromMousePosition } from './Grid/gridUtils'; //TODO: Revisit the logic of height (dropRef) @@ -102,14 +94,7 @@ export const Container = React.memo( const appCanvasWidth = realCanvasRef?.current?.offsetWidth || 0; if (clientOffset) { - const elementAtPoint = document.elementFromPoint(clientOffset.x, clientOffset.y); - const closestCanvas = elementAtPoint?.closest('.real-canvas'); - const canvasId = - closestCanvas?.getAttribute('data-parentId') || - closestCanvas?.id?.replace('canvas-', '') || - (closestCanvas?.id === 'real-canvas' ? 'real-canvas' : null); - - // Only update if this container is the most specific one under the mouse + const canvasId = findNewParentIdFromMousePosition(clientOffset.x, clientOffset.y, id); if (canvasId === id) { setCurrentDragCanvasId(id); } @@ -117,11 +102,9 @@ export const Container = React.memo( // Calculate width based on the app canvas's grid let width = (appCanvasWidth * item.component?.defaultSize?.width) / NO_OF_GRIDS; const componentSize = { - width: width, + width, height: item.component?.defaultSize?.height, }; - - // const clientOffset = monitor.getClientOffset(); if (clientOffset && id === 'canvas') { activateGhost(componentSize, clientOffset, realCanvasRef); } @@ -129,78 +112,6 @@ export const Container = React.memo( drop: (item, monitor) => { handleDrop(item, monitor, id); }, - // drop: async ({ componentType, component }, monitor) => { - // setShowModuleBorder(false); - // if (currentMode === 'view' || (appType === 'module' && componentType !== 'ModuleContainer')) return; - - // const didDrop = monitor.didDrop(); - // if (didDrop) return; - - // 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); - // } - - // 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', - // }); - // } - // }, - - // collect: (monitor) => ({ - // isOverCurrent: monitor.isOver({ shallow: true }), - // }), }); const showEmptyContainer = diff --git a/frontend/src/AppBuilder/AppCanvas/Grid/Grid.jsx b/frontend/src/AppBuilder/AppCanvas/Grid/Grid.jsx index e94bb0419f..d58cd1ed39 100644 --- a/frontend/src/AppBuilder/AppCanvas/Grid/Grid.jsx +++ b/frontend/src/AppBuilder/AppCanvas/Grid/Grid.jsx @@ -24,6 +24,7 @@ import { computeScrollDeltaOnDrag, getDraggingWidgetWidth, positionDragGhostWidget, + findNewParentIdFromMousePosition, } from './gridUtils'; import { dragContextBuilder, getAdjustedDropPosition } from './helpers/dragEnd'; import useStore from '@/AppBuilder/_stores/store'; @@ -73,15 +74,11 @@ 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, - draggingComponentId, - resizingComponentId, dragParentId, getResolvedValue, virtualTarget @@ -97,6 +94,8 @@ export default function Grid({ gridWidth, currentLayout }) { 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) { @@ -350,6 +349,7 @@ export default function Grid({ gridWidth, currentLayout }) { moveableRef.current.updateTarget(); } }, [temporaryHeight]); + useEffect(() => { reloadGrid(); // eslint-disable-next-line react-hooks/exhaustive-deps @@ -601,8 +601,8 @@ export default function Grid({ gridWidth, currentLayout }) { const components = Array.from(document.querySelectorAll('.active-target')).filter( (component) => !selectedComponents.includes(component.getAttribute('widgetid')) ); - const draggingOrResizing = draggingComponentId || resizingComponentId; - if (!draggingOrResizing && components.length > 0 && !virtualTarget) { + const draggingOrResizingComponentId = draggingComponentId || resizingComponentId; + if (!draggingOrResizingComponentId && components.length > 0 && !virtualTarget) { for (const component of components) { component?.classList?.remove('active-target'); } @@ -639,7 +639,7 @@ export default function Grid({ gridWidth, currentLayout }) { onResize={(e) => { const temporaryLayouts = getTemporaryLayouts(); if (resizingComponentId !== e.target.id) { - useGridStore.getState().actions.setResizingComponentId(e.target.id); + useStore.getState().setResizingComponentId(e.target.id); showGridLines(); } @@ -715,7 +715,7 @@ export default function Grid({ gridWidth, currentLayout }) { }} onResizeEnd={(e) => { try { - useGridStore.getState().actions.setResizingComponentId(null); + useStore.getState().setResizingComponentId(null); const currentWidget = boxList.find(({ id }) => { return id === e.target.id; }); @@ -1018,10 +1018,10 @@ export default function Grid({ gridWidth, currentLayout }) { e.target.style.width = `${draggingWidgetWidth}px`; // This logic is to handle the case when the dragged element is over a new canvas - // if (_dragParentId !== currentParentId) { - // left = e.translate[0]; - // top = e.translate[1]; - // } + if (_dragParentId !== currentParentId) { + left = e.translate[0]; + top = e.translate[1]; + } // Special case for Modal const oldParentId = boxList.find((b) => b.id === e.target.id)?.parent; @@ -1066,16 +1066,7 @@ 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)) { - 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; + let newParentId = findNewParentIdFromMousePosition(e.clientX, e.clientY, e.target.id); if (newParentId === e.target.id) { newParentId = boxList.find((box) => box.id === e.target.id)?.component?.parent; diff --git a/frontend/src/AppBuilder/AppCanvas/Grid/gridUtils.js b/frontend/src/AppBuilder/AppCanvas/Grid/gridUtils.js index 07a56a3c4c..ba42d4152f 100644 --- a/frontend/src/AppBuilder/AppCanvas/Grid/gridUtils.js +++ b/frontend/src/AppBuilder/AppCanvas/Grid/gridUtils.js @@ -551,3 +551,29 @@ export const positionDragGhostWidget = (draggedElement) => { ghostElement.style.width = `${draggedRect.width}px`; ghostElement.style.height = `${draggedRect.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; +}; diff --git a/frontend/src/AppBuilder/AppCanvas/Grid/hooks/useElementGudelines.js b/frontend/src/AppBuilder/AppCanvas/Grid/hooks/useElementGudelines.js index 6b6ea394da..55587b33fd 100644 --- a/frontend/src/AppBuilder/AppCanvas/Grid/hooks/useElementGudelines.js +++ b/frontend/src/AppBuilder/AppCanvas/Grid/hooks/useElementGudelines.js @@ -1,19 +1,12 @@ 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, - draggingComponentId, - resizingComponentId, - dragParentId, - getResolvedValue, - virtualTarget -) => { +export const useElementGudelines = (boxList, selectedComponents, dragParentId, getResolvedValue, virtualTarget) => { const [elementGuidelines, setElementGuidelines] = useState([]); - - // Get current drag canvas ID from store instead of drag layer + const draggingComponentId = useStore((state) => state.draggingComponentId); + const resizingComponentId = useStore((state) => state.resizingComponentId); const currentDragCanvasId = useGridStore((state) => state.currentDragCanvasId); useEffect(() => { @@ -23,6 +16,7 @@ export const useElementGudelines = ( 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) => { @@ -33,9 +27,13 @@ export const useElementGudelines = ( // 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) { - // For main canvas (id = 'canvas'), show components with no parent or parent = 'canvas' if (currentDragCanvasId === 'canvas') { if (box.parent && box.parent !== 'canvas') return false; } else { @@ -58,7 +56,6 @@ export const useElementGudelines = ( return true; }) .map((box) => `.ele-${box.id}`); - setElementGuidelines(guidelines); }, [ boxList, diff --git a/frontend/src/AppBuilder/_stores/slices/gridSlice.js b/frontend/src/AppBuilder/_stores/slices/gridSlice.js index 97e04ae4bf..6a74c12049 100644 --- a/frontend/src/AppBuilder/_stores/slices/gridSlice.js +++ b/frontend/src/AppBuilder/_stores/slices/gridSlice.js @@ -10,6 +10,7 @@ const initialState = { lastCanvasClickPosition: null, temporaryLayouts: {}, draggingComponentId: null, + resizingComponentId: null, reorderContainerChildren: { containerId: null, triggerUpdate: 0, @@ -36,6 +37,7 @@ 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 = {};