diff --git a/.vscode/settings.json b/.vscode/settings.json
index e13d54d778..50d6d9e897 100644
--- a/.vscode/settings.json
+++ b/.vscode/settings.json
@@ -8,8 +8,11 @@
"typescript",
"typescriptreact"
],
- "eslint.format.enable": false,
- "editor.formatOnSave": false,
+ "eslint.format.enable": true,
+ "editor.formatOnSave": true,
+ "editor.codeActionsOnSave": {
+ "source.fixAll.eslint": "explicit"
+ },
"json.schemas": [
{
"fileMatch": [
diff --git a/frontend/src/AppBuilder/AppCanvas/Container.jsx b/frontend/src/AppBuilder/AppCanvas/Container.jsx
index be6aab2803..4bdafa8a15 100644
--- a/frontend/src/AppBuilder/AppCanvas/Container.jsx
+++ b/frontend/src/AppBuilder/AppCanvas/Container.jsx
@@ -4,19 +4,14 @@ 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 { useDrop, useDragLayer, useDragDropManager } from 'react-dnd';
import {
addChildrenWidgetsToParent,
addNewWidgetToTheEditor,
computeViewerBackgroundColor,
getSubContainerWidthAfterPadding,
} from './appCanvasUtils';
-import {
- CANVAS_WIDTHS,
- NO_OF_GRIDS,
- WIDGETS_WITH_DEFAULT_CHILDREN,
- GRID_HEIGHT,
-} from './appCanvasConstants';
+import { CANVAS_WIDTHS, NO_OF_GRIDS, WIDGETS_WITH_DEFAULT_CHILDREN, GRID_HEIGHT } from './appCanvasConstants';
import { useGridStore } from '@/_stores/gridStore';
import NoComponentCanvasContainer from './NoComponentCanvasContainer';
import { RIGHT_SIDE_BAR_TAB } from '../RightSideBar/rightSidebarConstants';
@@ -27,6 +22,7 @@ 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';
//TODO: Revisit the logic of height (dropRef)
@@ -70,7 +66,7 @@ export const Container = React.memo(
const setFocusedParentId = useStore((state) => state.setFocusedParentId, shallow);
const setShowModuleBorder = useStore((state) => state.setShowModuleBorder, shallow) || noop;
- // Initialize ghost moveable hook (only for main canvas)
+ // Initialize ghost moveable hook
const { activateGhost, deactivateGhost } = useGhostMoveable(id);
// Monitor drag layer to update ghost position continuously
@@ -78,14 +74,12 @@ export const Container = React.memo(
isDragging: monitor.isDragging(),
}));
- // // Cleanup ghost when drag ends
- // useEffect(() => {
- // if (!isDragging) {
- // setTimeout(() => {
- // deactivateGhost();
- // }, 1000);
- // }
- // }, [id, isDragging, deactivateGhost]);
+ // // // Cleanup ghost when drag ends
+ useEffect(() => {
+ if (!isDragging) {
+ deactivateGhost();
+ }
+ }, [id, isDragging, deactivateGhost]);
const isContainerReadOnly = useMemo(() => {
return (index !== 0 && (componentType === 'Listview' || componentType === 'Kanban')) || currentMode === 'view';
@@ -93,29 +87,29 @@ export const Container = React.memo(
const setCurrentDragCanvasId = useGridStore((state) => state.actions.setCurrentDragCanvasId);
+ // Get the drop handler from the new hook
+ const handleDrop = useCanvasDropHandler({
+ appType,
+ });
+
const [{ isOverCurrent }, drop] = useDrop({
accept: 'box',
- hover: (item, monitor) => {
- // Use mouse position to determine the most specific container
+ hover: (item, monitor) => {
const clientOffset = monitor.getClientOffset();
-
- // If no client offset, the drag might be ending - clean up ghost
- // if (!clientOffset) {
- // deactivateGhost();
- // return;
- // }
-
+
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' ? 'canvas' : null);
-
+ const canvasId =
+ closestCanvas?.getAttribute('data-parentId') ||
+ closestCanvas?.id?.replace('canvas-', '') ||
+ (closestCanvas?.id === 'real-canvas' ? 'canvas' : null);
+
// Only update if this container is the most specific one under the mouse
if (canvasId === id) {
+ // console.log('Container hover', canvasId, id);
setCurrentDragCanvasId(id);
}
}
@@ -123,73 +117,17 @@ export const Container = React.memo(
let width = (appCanvasWidth * item.component?.defaultSize?.width) / NO_OF_GRIDS;
const componentSize = {
width: width,
- height: item.component?.defaultSize?.height
+ height: item.component?.defaultSize?.height,
};
// const clientOffset = monitor.getClientOffset();
- if (clientOffset) {
+ if (clientOffset && id === 'canvas') {
activateGhost(componentSize, clientOffset, realCanvasRef);
}
},
- drop: async ({ componentType, component }, monitor) => {
- console.log('drop');
- // Reset canvas ID when dropping
- setCurrentDragCanvasId(null);
-
- // Ensure ghost is deactivated before processing drop
- deactivateGhost();
-
- // Add a small delay to allow moveable to properly clean up
- // await new Promise(resolve => setTimeout(resolve, 10));
-
- // Deactivate ghost when dropping
- setShowModuleBorder(false); // Hide the module border when dropping
- if (currentMode === 'view' || (appType === 'module' && componentType !== 'ModuleContainer')) return;
- const didDrop = monitor.didDrop();
- if (didDrop) return;
- if (componentType === '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;
-
- if (WIDGETS_WITH_DEFAULT_CHILDREN.includes(componentType)) {
- const parentComponent = addNewWidgetToTheEditor(
- componentType,
- monitor,
- currentLayout,
- realCanvasRef,
- id,
- moduleInfo
- );
- const childComponents = addChildrenWidgetsToParent(componentType, parentComponent?.id, currentLayout);
- const newComponents = [parentComponent, ...childComponents];
- await addComponentToCurrentPage(newComponents);
- setActiveRightSideBarTab(RIGHT_SIDE_BAR_TAB.CONFIGURATION);
- } else {
- const newComponent = addNewWidgetToTheEditor(
- componentType,
- monitor,
- currentLayout,
- realCanvasRef,
- id,
- moduleInfo
- );
- await addComponentToCurrentPage([newComponent]);
- setActiveRightSideBarTab(RIGHT_SIDE_BAR_TAB.CONFIGURATION);
- }
+ drop: (item, monitor) => {
+ console.log('Container drop', item, monitor.getClientOffset());
+ handleDrop(item, monitor, id);
},
collect: (monitor) => ({
isOverCurrent: monitor.isOver({ shallow: true }),
diff --git a/frontend/src/AppBuilder/AppCanvas/Grid/Grid.jsx b/frontend/src/AppBuilder/AppCanvas/Grid/Grid.jsx
index 2e15c2926b..297be699a0 100644
--- a/frontend/src/AppBuilder/AppCanvas/Grid/Grid.jsx
+++ b/frontend/src/AppBuilder/AppCanvas/Grid/Grid.jsx
@@ -86,12 +86,17 @@ export default function Grid({ gridWidth, currentLayout }) {
const getExposedValueOfComponent = useStore((state) => state.getExposedValueOfComponent, shallow);
const setReorderContainerChildren = useStore((state) => state.setReorderContainerChildren, shallow);
const currentDragCanvasId = useGridStore((state) => state.currentDragCanvasId, shallow);
+
const snapContainer = useMemo(() => {
if (currentDragCanvasId) {
return `#canvas-${currentDragCanvasId}`;
}
+ if (dragParentId) {
+ return `#canvas-${dragParentId}`;
+ }
return '#real-canvas';
- }, [currentDragCanvasId]);
+ }, [currentDragCanvasId, dragParentId]);
+
const moveableTarget = useMemo(() => {
if (virtualTarget) {
return '#moveable-ghost-element';
@@ -109,57 +114,6 @@ export default function Grid({ gridWidth, currentLayout }) {
};
}, []);
- // 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 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 (virtualTarget) {
- // // return true;
- // // }
-
- // 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;
- // }
-
- // // if (virtualTarget) {
- // // return true;
- // // }
-
- // return true;
- // })
- // .map((box) => `.ele-${box.id}`);
-
- // // Combine static guidelines with dynamic ones (for ghost elements)
- // setElementGuidelines(guidelines);
- // }, [
- // boxList,
- // dragParentId,
- // draggingComponentId,
- // resizingComponentId,
- // selectedComponents,
- // getResolvedValue,
- // ]);
-
useEffect(() => {
setBoxList(
Object.keys(currentPageComponents)
@@ -626,12 +580,12 @@ export default function Grid({ gridWidth, currentLayout }) {
(component) => !selectedComponents.includes(component.getAttribute('widgetid'))
);
const draggingOrResizing = draggingComponentId || resizingComponentId;
- if (!draggingOrResizing && components.length > 0) {
+ if (!draggingOrResizing && components.length > 0 && !virtualTarget) {
for (const component of components) {
component?.classList?.remove('active-target');
}
}
- }, [draggingComponentId, resizingComponentId, isGroupDragging, selectedComponents]);
+ }, [draggingComponentId, resizingComponentId, isGroupDragging, selectedComponents, virtualTarget]);
useGroupedTargetsScrollHandler(groupedTargets, boxList, moveableRef);
if (mode !== 'edit') return null;
@@ -995,18 +949,17 @@ export default function Grid({ gridWidth, currentLayout }) {
}}
onDrag={(e) => {
if (e.target.id === 'moveable-ghost-element') {
- // showGridLines();
- //
+ showGridLines();
const _gridWidth = useGridStore.getState().subContainerWidths[currentDragCanvasId] || gridWidth;
let left = e.translate[0];
let top = e.translate[1];
// console.log('e.translate', e.translate);
- if (currentDragCanvasId === 'canvas') {
- left = Math.round(e.translate[0] / _gridWidth) * _gridWidth;
- top = Math.round(e.translate[1] / GRID_HEIGHT) * GRID_HEIGHT;
- }
+ // if (currentDragCanvasId === 'canvas') {
+ // console.log('e.translate', e.translate, _gridWidth);
+ left = Math.round(e.translate[0] / _gridWidth) * _gridWidth;
+ top = Math.round(e.translate[1] / GRID_HEIGHT) * GRID_HEIGHT;
+ console.log('e.translate', e.translate, left, top);
e.target.style.transform = `translate(${left}px, ${top}px)`;
- console.log('e.target', false);
return false;
}
// Since onDrag is called multiple times when dragging, hence we are using isDraggingRef to prevent setting state again and again
@@ -1029,10 +982,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;
@@ -1200,7 +1153,7 @@ export default function Grid({ gridWidth, currentLayout }) {
// snapGridAll={true}
scrollable={true}
snapContainer={snapContainer}
- snapGridWidth={100}
+ // snapGridWidth={100}
/>
>
);
diff --git a/frontend/src/AppBuilder/AppCanvas/appCanvasUtils.js b/frontend/src/AppBuilder/AppCanvas/appCanvasUtils.js
index 6222cc596d..fd58bf2959 100644
--- a/frontend/src/AppBuilder/AppCanvas/appCanvasUtils.js
+++ b/frontend/src/AppBuilder/AppCanvas/appCanvasUtils.js
@@ -34,7 +34,7 @@ export const addNewWidgetToTheEditor = (
parentId,
moduleInfo = undefined
) => {
- const canvasBoundingRect = realCanvasRef?.current?.getBoundingClientRect();
+ const canvasBoundingRect = realCanvasRef?.current?.getBoundingClientRect() || realCanvasRef?.getBoundingClientRect();
const componentMeta = componentTypes.find((component) => component.component === componentType);
const componentName = computeComponentName(componentType, useStore.getState().getCurrentPageComponents());
diff --git a/frontend/src/AppBuilder/AppCanvas/useCanvasDropHandler.js b/frontend/src/AppBuilder/AppCanvas/useCanvasDropHandler.js
new file mode 100644
index 0000000000..557ec8a697
--- /dev/null
+++ b/frontend/src/AppBuilder/AppCanvas/useCanvasDropHandler.js
@@ -0,0 +1,94 @@
+import useStore from '@/AppBuilder/_stores/store';
+import { useGridStore } from '@/_stores/gridStore';
+import { shallow } from 'zustand/shallow';
+import { noop } from 'lodash';
+import { addChildrenWidgetsToParent, addNewWidgetToTheEditor } 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 { useGhostMoveable } from '../_hooks/useGhostMoveable';
+
+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 { deactivateGhost } = useGhostMoveable();
+ const currentDragCanvasId = useGridStore((state) => state.currentDragCanvasId, shallow);
+
+ // console.log('currentDragCanvasId', currentDragCanvasId);
+
+ const handleDrop = ({ componentType: draggedComponentType, component }, monitor, canvasId) => {
+ const realCanvasRef =
+ document.getElementById(`canvas-${currentDragCanvasId}`) || document.getElementById(`real-canvas`);
+ // Reset canvas ID when dropping
+ setCurrentDragCanvasId(null);
+
+ // Ensure ghost is deactivated before processing drop
+ deactivateGhost();
+
+ // Deactivate ghost when dropping
+ setShowModuleBorder(false); // Hide the module border when dropping
+
+ if (currentMode === 'view' || (appType === 'module' && draggedComponentType !== 'ModuleContainer')) {
+ return;
+ }
+
+ // const didDrop = monitor.didDrop();
+ // if (didDrop) {
+ // 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;
+
+ if (WIDGETS_WITH_DEFAULT_CHILDREN.includes(draggedComponentType)) {
+ const parentComponent = addNewWidgetToTheEditor(
+ draggedComponentType,
+ monitor,
+ currentLayout,
+ realCanvasRef,
+ currentDragCanvasId,
+ moduleInfo
+ );
+ const childComponents = addChildrenWidgetsToParent(draggedComponentType, parentComponent?.id, currentLayout);
+ const newComponents = [parentComponent, ...childComponents];
+ addComponentToCurrentPage(newComponents);
+ setActiveRightSideBarTab(RIGHT_SIDE_BAR_TAB.CONFIGURATION);
+ } else {
+ const newComponent = addNewWidgetToTheEditor(
+ draggedComponentType,
+ monitor,
+ currentLayout,
+ realCanvasRef,
+ currentDragCanvasId,
+ moduleInfo
+ );
+ addComponentToCurrentPage([newComponent]);
+ setActiveRightSideBarTab(RIGHT_SIDE_BAR_TAB.CONFIGURATION);
+ }
+ };
+
+ return handleDrop;
+};
diff --git a/frontend/src/AppBuilder/RightSideBar/ComponentManagerTab/DragLayer.jsx b/frontend/src/AppBuilder/RightSideBar/ComponentManagerTab/DragLayer.jsx
index d0d6249c98..fb925d5cee 100644
--- a/frontend/src/AppBuilder/RightSideBar/ComponentManagerTab/DragLayer.jsx
+++ b/frontend/src/AppBuilder/RightSideBar/ComponentManagerTab/DragLayer.jsx
@@ -10,21 +10,36 @@ 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 }) => {
const { isModuleEditor } = useModuleContext();
const setShowModuleBorder = useStore((state) => state.setShowModuleBorder, shallow) || noop;
+ const handleDrop = useCanvasDropHandler({ appType: isModuleTab ? 'module' : 'app' }) || noop;
+ const currentDragCanvasId = useGridStore((state) => state.currentDragCanvasId, shallow);
+
const [{ isDragging }, drag, preview] = useDrag(
() => ({
type: 'box',
item: { componentType: component.component, component },
collect: (monitor) => ({ isDragging: monitor.isDragging() }),
+ end: (item, monitor) => {
+ const clientOffset = monitor.getClientOffset();
+ console.log('end', item, monitor.getDropResult(), monitor.getClientOffset());
+ console.log('currentDragCanvasId', currentDragCanvasId);
+ if (clientOffset) {
+ // const canvas = document.getElementById(`canvas-${currentDragCanvasId}`);
+ const realCanvas = document.getElementById(`real-canvas`);
+ handleDrop(item, monitor, realCanvas, currentDragCanvasId);
+ }
+ // if (didDrop) {
+ // handleDrop(item, monitor);
+ // }
+ },
}),
[component.component]
);
- const getMoveableRef = useGridStore((state) => state.moveableRef);
- const setVirtualTarget = useGridStore((state) => state.actions.setVirtualTarget);
- const newDiv = useRef(null);
+
useEffect(() => {
preview(getEmptyImage(), { captureDraggingState: true });
}, []);
@@ -41,7 +56,6 @@ export const DragLayer = ({ index, component, isModuleTab = false }) => {
// ? component.module_container.layouts[currentLayout]
// : component.defaultSize || { width: 30, height: 40 };
-
return (
<>
{/* {isDragging &&