diff --git a/app/client/src/layoutSystems/anvil/canvas/AnvilCanvas.tsx b/app/client/src/layoutSystems/anvil/canvas/AnvilCanvas.tsx index 7ececea6fb..2957b12a33 100644 --- a/app/client/src/layoutSystems/anvil/canvas/AnvilCanvas.tsx +++ b/app/client/src/layoutSystems/anvil/canvas/AnvilCanvas.tsx @@ -6,7 +6,6 @@ import type { WidgetProps } from "widgets/BaseWidget"; import { renderLayouts } from "../utils/layouts/renderUtils"; import { getAnvilCanvasId } from "./utils"; import { RenderModes } from "constants/WidgetConstants"; -import { getCanvasClassName } from "utils/generators"; export const AnvilCanvas = (props: BaseWidgetProps) => { const map: LayoutComponentProps["childrenMap"] = {}; @@ -14,9 +13,7 @@ export const AnvilCanvas = (props: BaseWidgetProps) => { map[child.widgetId] = child; }); - const className: string = `anvil-canvas ${getCanvasClassName()} ${props.classList?.join( - " ", - )}`; + const className: string = `anvil-canvas ${props.classList?.join(" ")}`; return (
diff --git a/app/client/src/layoutSystems/anvil/canvasArenas/hooks/useAnvilDnDStates.ts b/app/client/src/layoutSystems/anvil/canvasArenas/hooks/useAnvilDnDStates.ts index d767701af5..8d4c551664 100644 --- a/app/client/src/layoutSystems/anvil/canvasArenas/hooks/useAnvilDnDStates.ts +++ b/app/client/src/layoutSystems/anvil/canvasArenas/hooks/useAnvilDnDStates.ts @@ -24,7 +24,7 @@ export interface AnvilDnDStates { draggedBlocks: DraggedWidget[]; dragDetails: DragDetails; selectedWidgets: string[]; - isChildOfCanvas: boolean; + isChildOfLayout: boolean; isCurrentDraggedCanvas: boolean; isDragging: boolean; isNewWidget: boolean; @@ -94,7 +94,6 @@ const checkIfWidgetTypeDraggedIsAllowedToDrop = ( export const useAnvilDnDStates = ({ allowedWidgetTypes, - canvasId, layoutId, }: AnvilDnDStatesProps): AnvilDnDStates => { const mainCanvasLayoutId: string = useSelector((state) => @@ -122,9 +121,9 @@ export const useAnvilDnDStates = ({ */ const isNewWidget = !!newWidget && !dragParent; /** - * boolean to indicate if the widget being dragged is this particular canvas's child. + * boolean to indicate if the widget being dragged is this particular layout's child. */ - const isChildOfCanvas = dragParent === canvasId; + const isChildOfLayout = dragParent === layoutId; /** * boolean to indicate if the widget is being dragged on this particular canvas. */ @@ -172,7 +171,7 @@ export const useAnvilDnDStates = ({ draggedBlocks, dragDetails, selectedWidgets, - isChildOfCanvas, + isChildOfLayout, isCurrentDraggedCanvas, isDragging, isNewWidget, diff --git a/app/client/src/layoutSystems/anvil/canvasArenas/hooks/useCanvasActivation.ts b/app/client/src/layoutSystems/anvil/canvasArenas/hooks/useCanvasActivation.ts index f650b5b99f..f005b35f02 100644 --- a/app/client/src/layoutSystems/anvil/canvasArenas/hooks/useCanvasActivation.ts +++ b/app/client/src/layoutSystems/anvil/canvasArenas/hooks/useCanvasActivation.ts @@ -1,6 +1,7 @@ import { CANVAS_ART_BOARD } from "constants/componentClassNameConstants"; import { Indices } from "constants/Layers"; import { MAIN_CONTAINER_WIDGET_ID } from "constants/WidgetConstants"; +import type { LayoutElementPosition } from "layoutSystems/common/types"; import { positionObserver } from "layoutSystems/common/utils/LayoutElementPositionsObserver"; import { getAnvilLayoutDOMId } from "layoutSystems/common/utils/LayoutElementPositionsObserver/utils"; import { useEffect, useRef } from "react"; @@ -11,6 +12,22 @@ export const AnvilCanvasZIndex = { activated: Indices.Layer10.toString(), deactivated: "", }; + +const checkIfMousePositionIsInsideBlock = ( + e: MouseEvent, + mainCanvasRect: DOMRect, + layoutElementPosition: LayoutElementPosition, +) => { + return ( + layoutElementPosition.left <= e.clientX - mainCanvasRect.left && + e.clientX - mainCanvasRect.left <= + layoutElementPosition.left + layoutElementPosition.width && + layoutElementPosition.top <= e.clientY - mainCanvasRect.top && + e.clientY - mainCanvasRect.top <= + layoutElementPosition.top + layoutElementPosition.height + ); +}; + export const useCanvasActivation = ( anvilDragStates: AnvilDnDStates, layoutId: string, @@ -26,6 +43,9 @@ export const useCanvasActivation = ( const mainContainerDOMNode = document.getElementById(CANVAS_ART_BOARD); const { setDraggingCanvas, setDraggingNewWidget, setDraggingState } = useWidgetDragResize(); + const draggedWidgetPositions = anvilDragStates.selectedWidgets.map((each) => { + return layoutElementPositions[each]; + }); /** * boolean ref that indicates if the mouse position is outside of main canvas while dragging * this is being tracked in order to activate/deactivate canvas. @@ -72,6 +92,7 @@ export const useCanvasActivation = ( return currentPositions && !!layoutInfo.isDropTarget; }) .map((each) => allLayouts[each].layoutId); + /** * layoutIds sorted by area of each layout in ascending order. * This is done because a point can be inside multiple canvas areas, but only the smallest of them is the immediate parent. @@ -101,21 +122,23 @@ export const useCanvasActivation = ( smallToLargeSortedDroppableLayoutIds.length > 0 ) { const mainCanvasRect = mainContainerDOMNode.getBoundingClientRect(); - const hoveredCanvas = smallToLargeSortedDroppableLayoutIds.find( - (each) => { - const currentCanvasPositions = layoutElementPositions[each]; - if (currentCanvasPositions) { - return ( - currentCanvasPositions.left <= e.clientX - mainCanvasRect.left && - e.clientX - mainCanvasRect.left <= - currentCanvasPositions.left + currentCanvasPositions.width && - currentCanvasPositions.top <= e.clientY - mainCanvasRect.top && - e.clientY - mainCanvasRect.top <= - currentCanvasPositions.top + currentCanvasPositions.height - ); - } - }, - ); + const isMousePositionOutsideOfDraggingWidgets = + !isNewWidget && + draggedWidgetPositions.find((each) => { + return checkIfMousePositionIsInsideBlock(e, mainCanvasRect, each); + }); + const hoveredCanvas = isMousePositionOutsideOfDraggingWidgets + ? dragDetails.dragGroupActualParent + : smallToLargeSortedDroppableLayoutIds.find((each) => { + const currentCanvasPositions = layoutElementPositions[each]; + if (currentCanvasPositions) { + return checkIfMousePositionIsInsideBlock( + e, + mainCanvasRect, + currentCanvasPositions, + ); + } + }); if (dragDetails.draggedOn !== hoveredCanvas) { if (hoveredCanvas) { isMouseOutOfMainCanvas.current = false; diff --git a/app/client/src/layoutSystems/anvil/editor/AnvilEditorWidgetOnion.tsx b/app/client/src/layoutSystems/anvil/editor/AnvilEditorWidgetOnion.tsx index bff06ccbd1..c93d042206 100644 --- a/app/client/src/layoutSystems/anvil/editor/AnvilEditorWidgetOnion.tsx +++ b/app/client/src/layoutSystems/anvil/editor/AnvilEditorWidgetOnion.tsx @@ -26,15 +26,14 @@ import { getWidgetSizeConfiguration } from "../utils/widgetUtils"; * @returns Enhanced Widget */ export const AnvilEditorWidgetOnion = (props: BaseWidgetProps) => { - const { layoutId, parentId } = props; + const { layoutId } = props; // if layoutId is not present on widget props then we need a selector to fetch layout id of a widget. // const layoutId = useSelector(getLayoutIdByWidgetId(props.widgetId)); const generateDragState = useCallback(() => { return generateDragStateForAnvilLayout({ - canvasId: parentId || "", - layoutId: layoutId, + layoutId, }); - }, [layoutId, parentId]); + }, [layoutId]); const widgetSize: SizeConfig = useMemo( () => getWidgetSizeConfiguration(props.type, props), [props.type], diff --git a/app/client/src/layoutSystems/anvil/integrations/sagas/draggingSagas.ts b/app/client/src/layoutSystems/anvil/integrations/sagas/draggingSagas.ts index 1e3e504670..fd62abae66 100644 --- a/app/client/src/layoutSystems/anvil/integrations/sagas/draggingSagas.ts +++ b/app/client/src/layoutSystems/anvil/integrations/sagas/draggingSagas.ts @@ -15,6 +15,8 @@ import { addWidgetsToPreset } from "../../utils/layouts/update/additionUtils"; import { moveWidgets } from "../../utils/layouts/update/moveUtils"; import { AnvilReduxActionTypes } from "../actions/actionTypes"; import { generateDefaultLayoutPreset } from "layoutSystems/anvil/layoutComponents/presets/DefaultLayoutPreset"; +import { selectWidgetInitAction } from "actions/widgetSelectionActions"; +import { SelectionRequestType } from "sagas/WidgetSelectUtils"; function* addWidgetsSaga( actionPayload: ReduxAction<{ @@ -82,6 +84,9 @@ function* addWidgetsSaga( }, }; yield put(updateAndSaveLayout(updatedWidgets)); + yield put( + selectWidgetInitAction(SelectionRequestType.One, [newWidget.newWidgetId]), + ); log.debug("Anvil : add new widget took", performance.now() - start, "ms"); } catch (error) { yield put({ diff --git a/app/client/src/layoutSystems/anvil/integrations/utils.test.ts b/app/client/src/layoutSystems/anvil/integrations/utils.test.ts deleted file mode 100644 index dbdb1d030b..0000000000 --- a/app/client/src/layoutSystems/anvil/integrations/utils.test.ts +++ /dev/null @@ -1,151 +0,0 @@ -import type { CanvasWidgetsReduxState } from "reducers/entityReducers/canvasWidgetsReducer"; -import type { WidgetProps } from "widgets/BaseWidget"; -import { getAffectedWidgetsFromLayers, getAllChildWidgets } from "./utils"; - -const widgets = { - "0": { - children: ["1", "3", "4"], - detachFromLayout: true, - flexLayers: [ - { children: [{ id: "1" }, { id: "3" }] }, - { children: [{ id: "4" }] }, - ], - }, - "1": { - children: ["2"], - }, - "2": { - children: ["5", "6", "7", "8"], - detachFromLayout: true, - flexLayers: [ - { children: [{ id: "5" }] }, - { children: [{ id: "6" }, { id: "7" }] }, - { children: [{ id: "8" }] }, - ], - }, - "3": { children: [] }, - "4": { children: [] }, - "5": { children: [] }, - "6": { children: [] }, - "7": { children: [] }, - "8": { children: [] }, -} as unknown as CanvasWidgetsReduxState; - -describe("should test getAffectedWidgetsFromLayers", () => { - const layerQueue1 = { - "0": 0, - }; - - const layerQueue2 = { - "0": 1, - "2": 1, - }; - - const layerQueue3 = { - "2": 0, - }; - - const layerQueue4 = { - "0": 1, - "2": 2, - }; - - const affectedWidgets1 = { - "1": true, - "3": true, - "4": true, - "5": true, - "6": true, - "7": true, - "8": true, - }; - - const affectedWidgets2 = { - "4": true, - "6": true, - "7": true, - "8": true, - }; - - const affectedWidgets3 = { - "5": true, - "6": true, - "7": true, - "8": true, - }; - - const affectedWidgets4 = { - "4": true, - "8": true, - }; - - it("should return all the affected widgets derived from layer queue", () => { - expect(getAffectedWidgetsFromLayers(layerQueue1, widgets)).toEqual( - affectedWidgets1, - ); - expect(getAffectedWidgetsFromLayers(layerQueue2, widgets)).toEqual( - affectedWidgets2, - ); - expect(getAffectedWidgetsFromLayers(layerQueue3, widgets)).toEqual( - affectedWidgets3, - ); - expect(getAffectedWidgetsFromLayers(layerQueue4, widgets)).toEqual( - affectedWidgets4, - ); - }); -}); - -describe("should test getAllChildWidgets", () => { - const widget1 = { - widgetId: "0", - children: ["1", "3", "4"], - } as unknown as WidgetProps; - - const widget2 = { - widgetId: "1", - children: ["2"], - } as unknown as WidgetProps; - - const widget3 = { - widgetId: "2", - children: ["5", "6", "7", "8"], - } as unknown as WidgetProps; - - const widget4 = { - widgetId: "3", - children: [], - } as unknown as WidgetProps; - - const childWidgets1 = { - "1": true, - "3": true, - "4": true, - "5": true, - "6": true, - "7": true, - "8": true, - }; - - const childWidgets2 = { - "5": true, - "6": true, - "7": true, - "8": true, - }; - - const childWidgets3 = { - "5": true, - "6": true, - "7": true, - "8": true, - }; - - const childWidgets4 = {}; - - it("should return all the child widgets except canvas widgets", () => { - expect(getAllChildWidgets(widget1, widgets)).toEqual(childWidgets1); - expect(getAllChildWidgets(widget2, widgets)).toEqual(childWidgets2); - expect(getAllChildWidgets(widget3, widgets)).toEqual(childWidgets3); - expect(getAllChildWidgets(widget4, widgets)).toEqual(childWidgets4); - }); -}); diff --git a/app/client/src/layoutSystems/anvil/integrations/utils.ts b/app/client/src/layoutSystems/anvil/integrations/utils.ts deleted file mode 100644 index e7c71f1572..0000000000 --- a/app/client/src/layoutSystems/anvil/integrations/utils.ts +++ /dev/null @@ -1,90 +0,0 @@ -import type { CanvasWidgetsReduxState } from "reducers/entityReducers/canvasWidgetsReducer"; -import type { WidgetProps } from "widgets/BaseWidget"; - -/** - * This method is used to determine all the affected widgets from all the layers that have changed - * @param layersProcessQueue Changed layer Ids, will have one layer id per canvas - * @param widgets all widget dsl Properties - * @returns list of all affected widgets - */ -export function getAffectedWidgetsFromLayers( - layersProcessQueue: { - [canvasId: string]: number; - }, - widgets: CanvasWidgetsReduxState, -) { - let affectedWidgets: { [widgetDOMId: string]: boolean } = {}; - - //Even though it has many nested iterations it will go through all teh affected widgets only once - //Iterate through all the canvases and it's first layer that got affected - for (const [canvasId, layerIndex] of Object.entries(layersProcessQueue)) { - const flexLayers = widgets[canvasId]?.flexLayers || []; - - //iterate through all the layers below the changed layer id inculuding the layer - for (let i = layerIndex; i < flexLayers.length; i++) { - const children = flexLayers[i]?.children || []; - //iterate through all the child widgets inside the layer - for (const child of children) { - const childWidget = widgets[child.id]; - - if (!childWidget) continue; - - affectedWidgets[child.id] = true; - - //if the widget has children get all the nested children - if (childWidget.children && childWidget.children.length > 0) { - affectedWidgets = { - ...affectedWidgets, - ...getAllChildWidgets(childWidget, widgets, layersProcessQueue), - }; - } - } - } - } - - return affectedWidgets; -} - -/** - * This Method gets all the nested child widgets, - * within the given widgets ignoring the canvas type widgets - * @param widget Widget whose nested children have to be found - * @param widgets all widget dsl Properties - * @returns list of all the nested child widgets of widget - */ -export function getAllChildWidgets( - widget: WidgetProps, - widgets: CanvasWidgetsReduxState, - layersProcessQueue?: { - [canvasId: string]: number; - }, -) { - let childWidgets: { [widgetDOMId: string]: boolean } = {}; - - const children = widget.children; - - //iterate through children if widget - for (const childId of children) { - const childWidget = widgets[childId]; - - if (!childWidget) continue; - - //if the child widget is not a canvas add it to the list - if (!childWidget.detachFromLayout) { - childWidgets[childId] = true; - } else if (layersProcessQueue) { - //If it is a canvas widget remove the widget from the layer queue to avoid processing it again - delete layersProcessQueue[childId]; - } - - //if the widget further has nested children call the getAllChildWidgets recursively. - if (childWidget.children && childWidget.children.length > 0) { - childWidgets = { - ...childWidgets, - ...getAllChildWidgets(childWidget, widgets, layersProcessQueue), - }; - } - } - - return childWidgets; -} diff --git a/app/client/src/layoutSystems/anvil/utils/widgetUtils.ts b/app/client/src/layoutSystems/anvil/utils/widgetUtils.ts index ae9c496d24..d3f3b1957e 100644 --- a/app/client/src/layoutSystems/anvil/utils/widgetUtils.ts +++ b/app/client/src/layoutSystems/anvil/utils/widgetUtils.ts @@ -36,15 +36,13 @@ export const validateResponsiveProp = ( ) => data && Object.keys(data)?.length; export const generateDragStateForAnvilLayout = ({ - canvasId, layoutId, }: { - canvasId: string; layoutId: string; }): SetDraggingStateActionPayload => { return { isDragging: true, - dragGroupActualParent: canvasId || "", + dragGroupActualParent: layoutId || "", draggedOn: layoutId, }; }; diff --git a/app/client/src/sagas/WidgetAdditionSagas.ts b/app/client/src/sagas/WidgetAdditionSagas.ts index 093127e9b7..187e0af60e 100644 --- a/app/client/src/sagas/WidgetAdditionSagas.ts +++ b/app/client/src/sagas/WidgetAdditionSagas.ts @@ -49,6 +49,9 @@ import { } from "selectors/editorSelectors"; import { getWidgetMinMaxDimensionsInPixel } from "layoutSystems/autolayout/utils/flexWidgetUtils"; import { isFunction } from "lodash"; +import type { LayoutComponentProps } from "layoutSystems/anvil/utils/anvilTypes"; +import { getLayoutSystemType } from "selectors/layoutSystemSelectors"; +import { LayoutSystemTypes } from "layoutSystems/types"; const WidgetTypes = WidgetFactory.widgetTypes; @@ -73,6 +76,7 @@ function* getChildWidgetProps( widgets: { [widgetId: string]: FlattenedWidgetProps }, ) { const { leftColumn, newWidgetId, topRow, type } = params; + const layoutSystemType: LayoutSystemTypes = yield select(getLayoutSystemType); let { columns, parentColumnSpace, parentRowSpace, props, rows, widgetName } = params; let minHeight = undefined; @@ -108,6 +112,21 @@ function* getChildWidgetProps( draft.children = []; } }); + if ( + layoutSystemType === LayoutSystemTypes.ANVIL && + props.layout && + props.layout.length + ) { + props = { + ...props, + layout: props.layout.map((each: LayoutComponentProps) => { + return { + ...each, + layoutId: generateReactKey(), + }; + }), + }; + } } }