From 703048b7b55b6db497d444ebb74edb4306afb6cc Mon Sep 17 00:00:00 2001 From: Ashok Kumar M <35134347+marks0351@users.noreply.github.com> Date: Wed, 4 Oct 2023 17:23:29 +0530 Subject: [PATCH] chore: Layout system wise restructuring of Canvas Widget (#27496) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit > Pull Request Template > > Use this template to quickly create a well written pull request. Delete all quotes before creating the pull request. > ## Description In This PR, we are cleaning up Canvas Widget implementation and taking measures to remove it from the widget suite. more detailed explanation of Why and How of the solution [here](https://www.notion.so/Canvas-Widget-73776a3364ba42eb8f783c79046777d0) In this solution we are going to remove implementation of Editing and Layouting Specific implementation from Canvas Widget and create a new view component which is Layout system specific. #### PR fixes following issue(s) Fixes #27003 #### Media > A video or a GIF is preferred. when using Loom, don’t embed because it looks like it’s a GIF. instead, just link to the video > > #### Type of change > Please delete options that are not relevant. - Chore (housekeeping or task changes that don't impact user perception) > > > ## Testing > #### How Has This Been Tested? > Please describe the tests that you ran to verify your changes. Also list any relevant details for your test configuration. > Delete anything that is not relevant - [ ] Manual - [ ] JUnit - [X] Jest - [ ] Cypress > > #### Test Plan > Add Testsmith test cases links that relate to this PR > > #### Issues raised during DP testing > Link issues raised during DP testing for better visiblity and tracking (copy link from comments dropped on this PR) > > > ## Checklist: #### Dev activity - [ ] My code follows the style guidelines of this project - [ ] I have performed a self-review of my own code - [ ] I have commented my code, particularly in hard-to-understand areas - [ ] I have made corresponding changes to the documentation - [ ] My changes generate no new warnings - [ ] I have added tests that prove my fix is effective or that my feature works - [ ] New and existing unit tests pass locally with my changes - [ ] PR is being merged under a feature flag #### QA activity: - [ ] [Speedbreak features](https://github.com/appsmithorg/TestSmith/wiki/Guidelines-for-test-plans#speedbreakers-) have been covered - [ ] Test plan covers all impacted features and [areas of interest](https://github.com/appsmithorg/TestSmith/wiki/Guidelines-for-test-plans#areas-of-interest-) - [ ] Test plan has been peer reviewed by project stakeholders and other QA members - [ ] Manually tested functionality on DP - [ ] We had an implementation alignment call with stakeholders post QA Round 2 - [ ] Cypress test cases have been added and approved by SDET/manual QA - [ ] Added `Test Plan Approved` label after Cypress tests were reviewed - [ ] Added `Test Plan Approved` label after JUnit tests were reviewed --- CODEOWNERS | 3 - .../src/actions/canvasSelectionActions.ts | 2 +- .../src/layoutSystems/CanvasFactory.test.tsx | 105 +++++ .../src/layoutSystems/CanvasFactory.tsx | 39 ++ .../anvil/editor/AnvilEditorWrapper.tsx | 5 - app/client/src/layoutSystems/anvil/index.ts | 2 +- .../anvil/viewer/AnvilViewerWrapper.tsx | 4 - .../MainContainerResizer.tsx | 187 --------- .../canvas/AutoLayoutCanvasView.tsx | 68 ++++ .../canvas/AutoLayoutEditorCanvas.tsx | 92 +++++ .../canvas/AutoLayoutViewerCanvas.tsx | 40 ++ .../layoutSystems/autolayout/canvas/types.ts | 4 + .../layoutSystems/autolayout/canvas/utils.ts | 16 + .../AutoCanvasDraggingArena.tsx | 2 +- .../hooks/useAutoLayoutHighlights.ts | 2 +- .../hooks/useBlocksToBeDraggedOnCanvas.ts | 4 +- .../hooks/useCanvasDragging.ts | 4 +- .../hooks/useRenderBlocksOnCanvas.ts | 2 +- .../editor/AutoLayoutEditorWrapper.tsx | 5 - .../src/layoutSystems/autolayout/index.ts | 82 +++- .../viewer/AutoLayoutViewerWrapper.tsx | 4 - .../ArenaTypes.ts | 0 .../CanvasMultiPointerArena.tsx | 0 .../StickyCanvasArena.tsx | 0 .../useCanvasDragToScroll.ts | 0 .../canvasViewer/CanvasViewerWrapper.tsx | 33 ++ .../dropTarget}/DragLayerComponent.test.tsx | 0 .../common/dropTarget}/DragLayerComponent.tsx | 0 .../dropTarget}/DropTargetComponent.tsx | 6 +- .../dropTarget/DropTargetComponentWrapper.tsx | 33 ++ .../common/dropTarget}/DropTargetUtils.ts | 0 .../MainContainerResizer.tsx | 0 .../common/resizer/ResizableComponent.tsx | 4 +- .../common/resizer/ResizableUtils.ts | 2 +- .../common/utils/ComponentSizeUtils.ts | 4 +- .../common/utils/canvasDraggingUtils.ts | 2 +- .../layoutSystems/common/utils/canvasUtils.ts | 79 ++++ .../canvas/FixedLayoutEditorCanvas.tsx | 119 ++++++ .../canvas/FixedLayoutViewerCanvas.tsx | 69 ++++ .../layoutSystems/fixedlayout/canvas/types.ts | 4 + .../common/resizer/FixedResizableLayer.tsx | 6 +- .../widgetGrouping}/WidgetsMultiSelectBox.tsx | 0 .../CanvasSelectionArena.tsx | 6 +- .../FixedCanvasDraggingArena.tsx | 2 +- .../hooks/useBlocksToBeDraggedOnCanvas.ts | 4 +- .../hooks/useCanvasDragging.ts | 4 +- .../hooks/useRenderBlocksOnCanvas.ts | 4 +- .../editor/FixedLayoutEditorWrapper.tsx | 4 - .../src/layoutSystems/fixedlayout/index.ts | 76 +++- .../viewer/FixedLayoutViewerWrapper.tsx | 4 - app/client/src/layoutSystems/types/index.ts | 48 ++- .../withLayoutSystemHOC.test.tsx | 370 ------------------ .../withLayoutSystemWidgetHOC.test.tsx | 261 ++++++++++++ ...mHOC.tsx => withLayoutSystemWidgetHOC.tsx} | 34 +- app/client/src/pages/AppViewer/AppPage.tsx | 6 +- app/client/src/pages/Editor/Canvas.tsx | 10 +- .../WidgetsEditor/MainContainerWrapper.tsx | 2 +- .../uiReducers/canvasSelectionReducer.ts | 2 +- .../sagas/CanvasSagas/DraggingCanvasSagas.ts | 4 +- .../selectors/flattenedChildCanvasSelector.ts | 6 +- .../src/utils/WidgetPropsUtils.test.tsx | 2 +- app/client/src/utils/WidgetPropsUtils.tsx | 2 +- .../BaseWidgetHOC/withBaseWidgetHOC.ts | 4 +- app/client/src/widgets/CanvasWidget.tsx | 215 +--------- .../ContainerWidget/component/index.tsx | 1 - .../widgets/ContainerWidget/widget/index.tsx | 10 +- .../src/widgets/ListWidget/widget/index.tsx | 4 +- .../src/widgets/ListWidgetV2/widget/index.tsx | 4 +- app/client/src/widgets/MetaHOC.tsx | 2 +- .../widgets/ModalWidget/component/index.tsx | 4 +- .../src/widgets/TabsWidget/widget/index.tsx | 5 +- 71 files changed, 1239 insertions(+), 894 deletions(-) create mode 100644 app/client/src/layoutSystems/CanvasFactory.test.tsx create mode 100644 app/client/src/layoutSystems/CanvasFactory.tsx delete mode 100644 app/client/src/layoutSystems/autolayout/MainContainerResizer/MainContainerResizer.tsx create mode 100644 app/client/src/layoutSystems/autolayout/canvas/AutoLayoutCanvasView.tsx create mode 100644 app/client/src/layoutSystems/autolayout/canvas/AutoLayoutEditorCanvas.tsx create mode 100644 app/client/src/layoutSystems/autolayout/canvas/AutoLayoutViewerCanvas.tsx create mode 100644 app/client/src/layoutSystems/autolayout/canvas/types.ts create mode 100644 app/client/src/layoutSystems/autolayout/canvas/utils.ts rename app/client/src/layoutSystems/common/{CanvasArenas => canvasArenas}/ArenaTypes.ts (100%) rename app/client/src/layoutSystems/common/{CanvasArenas => canvasArenas}/CanvasMultiPointerArena.tsx (100%) rename app/client/src/layoutSystems/common/{CanvasArenas => canvasArenas}/StickyCanvasArena.tsx (100%) rename app/client/src/layoutSystems/common/{CanvasArenas => canvasArenas}/useCanvasDragToScroll.ts (100%) create mode 100644 app/client/src/layoutSystems/common/canvasViewer/CanvasViewerWrapper.tsx rename app/client/src/{components/editorComponents => layoutSystems/common/dropTarget}/DragLayerComponent.test.tsx (100%) rename app/client/src/{components/editorComponents => layoutSystems/common/dropTarget}/DragLayerComponent.tsx (100%) rename app/client/src/{components/editorComponents => layoutSystems/common/dropTarget}/DropTargetComponent.tsx (99%) create mode 100644 app/client/src/layoutSystems/common/dropTarget/DropTargetComponentWrapper.tsx rename app/client/src/{components/editorComponents => layoutSystems/common/dropTarget}/DropTargetUtils.ts (100%) rename app/client/src/layoutSystems/common/{MainContainerResizer => mainContainerResizer}/MainContainerResizer.tsx (100%) create mode 100644 app/client/src/layoutSystems/common/utils/canvasUtils.ts create mode 100644 app/client/src/layoutSystems/fixedlayout/canvas/FixedLayoutEditorCanvas.tsx create mode 100644 app/client/src/layoutSystems/fixedlayout/canvas/FixedLayoutViewerCanvas.tsx create mode 100644 app/client/src/layoutSystems/fixedlayout/canvas/types.ts rename app/client/src/{pages/Editor => layoutSystems/fixedlayout/common/widgetGrouping}/WidgetsMultiSelectBox.tsx (100%) delete mode 100644 app/client/src/layoutSystems/withLayoutSystemHOC.test.tsx create mode 100644 app/client/src/layoutSystems/withLayoutSystemWidgetHOC.test.tsx rename app/client/src/layoutSystems/{withLayoutSystemHOC.tsx => withLayoutSystemWidgetHOC.tsx} (59%) diff --git a/CODEOWNERS b/CODEOWNERS index 4efa00a7f4..fabb2ca64c 100644 --- a/CODEOWNERS +++ b/CODEOWNERS @@ -69,13 +69,10 @@ app/client/src/normalizers/CanvasWidgetsNormalizer.tsx @appsmithorg/ui-builders app/client/src/pages/Editor/Canvas.tsx @appsmithorg/ui-builders app/client/src/pages/Editor/CanvasLayoutConversion/* @appsmithorg/ui-builders app/client/src/pages/Editor/PropertyPane/* @appsmithorg/ui-builders -app/client/src/pages/Editor/WidgetsMultiSelectBox.tsx @appsmithorg/ui-builders -app/client/src/pages/common/CanvasArenas/* @appsmithorg/ui-builders app/client/src/reducers/entityReducers/autoHeightReducers/* @appsmithorg/ui-builders app/client/src/reducers/entityReducers/canvasWidgetsReducer.ts @appsmithorg/ui-builders app/client/src/reducers/entityReducers/widgetConfigReducer.ts @appsmithorg/ui-builders app/client/src/reflow/* @appsmithorg/ui-builders -app/client/src/resizable/* @appsmithorg/ui-builders app/client/src/sagas/AutoLayoutUpdateSagas.tsx @appsmithorg/ui-builders app/client/src/sagas/CanvasSagas/* @appsmithorg/ui-builders app/client/src/sagas/ReplaySaga.ts @appsmithorg/ui-builders diff --git a/app/client/src/actions/canvasSelectionActions.ts b/app/client/src/actions/canvasSelectionActions.ts index 25e29c5b0e..99bbb6aab3 100644 --- a/app/client/src/actions/canvasSelectionActions.ts +++ b/app/client/src/actions/canvasSelectionActions.ts @@ -1,6 +1,6 @@ import type { ReduxAction } from "@appsmith/constants/ReduxActionConstants"; import { ReduxActionTypes } from "@appsmith/constants/ReduxActionConstants"; -import type { XYCord } from "layoutSystems/common/CanvasArenas/ArenaTypes"; +import type { XYCord } from "layoutSystems/common/canvasArenas/ArenaTypes"; import type { SelectedArenaDimensions } from "layoutSystems/fixedlayout/editor/FixedLayoutCanvasArenas/CanvasSelectionArena"; export const setCanvasSelectionFromEditor = ( diff --git a/app/client/src/layoutSystems/CanvasFactory.test.tsx b/app/client/src/layoutSystems/CanvasFactory.test.tsx new file mode 100644 index 0000000000..3fda0cc93d --- /dev/null +++ b/app/client/src/layoutSystems/CanvasFactory.test.tsx @@ -0,0 +1,105 @@ +import { RenderModes } from "constants/WidgetConstants"; +import * as editorSelectors from "selectors/editorSelectors"; +import { buildChildren } from "test/factories/WidgetFactoryUtils"; +import { renderAppsmithCanvas } from "./CanvasFactory"; +import { render } from "test/testUtils"; +import React from "react"; +import store from "store"; +import type { WidgetProps } from "widgets/BaseWidget"; +import { LayoutSystemTypes } from "./types"; +import * as layoutSystemSelectors from "selectors/layoutSystemSelectors"; + +describe("Layout Based Canvas aka Canvas Widget Test cases", () => { + it("Render Fixed Layout Editor Canvas when layoutSystemType/appPositioningType is FIXED and render mode is CANVAS/PAGE", () => { + const children = buildChildren([ + { + type: "CANVAS_WIDGET", + parentId: "xxxxxx", + children: [], + widgetId: "yyyyyy", + dynamicHeight: "FIXED", + }, + ]); + if (children) { + const canvasProps = children[0]; + jest + .spyOn(editorSelectors, "getRenderMode") + .mockImplementation(() => RenderModes.CANVAS); + jest + .spyOn(layoutSystemSelectors, "getLayoutSystemType") + .mockImplementation(() => LayoutSystemTypes.FIXED); + const state = store.getState(); + const customState = { + ...state, + entities: { + ...state.entities, + canvasWidgets: { + xxxxxx: {} as WidgetProps, + yyyyyy: {} as WidgetProps, + }, + }, + }; + const editorCanvas = render(<>{renderAppsmithCanvas(canvasProps)}, { + initialState: customState, + }); + const editorDropTarget = + editorCanvas.container.getElementsByClassName("t--drop-target")[0]; + expect(editorDropTarget).toBeTruthy(); + jest + .spyOn(editorSelectors, "getRenderMode") + .mockImplementation(() => RenderModes.PAGE); + const viewerCanvas = render(<>{renderAppsmithCanvas(canvasProps)}, { + initialState: customState, + }); + const viewerDropTarget = + viewerCanvas.container.getElementsByClassName("t--drop-target")[0]; + expect(viewerDropTarget).toBeFalsy(); + } + }); + it("Render Auto Layout Editor Canvas when layoutSystemType/appPositioningType is AUTO and render mode is CANVAS/PAGE", () => { + const children = buildChildren([ + { + type: "CANVAS_WIDGET", + parentId: "xxxxxx", + children: [], + widgetId: "yyyyyy", + dynamicHeight: "FIXED", + }, + ]); + if (children) { + const canvasProps = children[0]; + jest + .spyOn(editorSelectors, "getRenderMode") + .mockImplementation(() => RenderModes.CANVAS); + jest + .spyOn(layoutSystemSelectors, "getLayoutSystemType") + .mockImplementation(() => LayoutSystemTypes.AUTO); + const state = store.getState(); + const customState = { + ...state, + entities: { + ...state.entities, + canvasWidgets: { + xxxxxx: {} as WidgetProps, + yyyyyy: {} as WidgetProps, + }, + }, + }; + const editorCanvas = render(<>{renderAppsmithCanvas(canvasProps)}, { + initialState: customState, + }); + const editorDropTarget = + editorCanvas.container.getElementsByClassName("t--drop-target")[0]; + expect(editorDropTarget).toBeTruthy(); + jest + .spyOn(editorSelectors, "getRenderMode") + .mockImplementation(() => RenderModes.PAGE); + const viewerCanvas = render(<>{renderAppsmithCanvas(canvasProps)}, { + initialState: customState, + }); + const viewerDropTarget = + viewerCanvas.container.getElementsByClassName("t--drop-target")[0]; + expect(viewerDropTarget).toBeFalsy(); + } + }); +}); diff --git a/app/client/src/layoutSystems/CanvasFactory.tsx b/app/client/src/layoutSystems/CanvasFactory.tsx new file mode 100644 index 0000000000..83682c80c5 --- /dev/null +++ b/app/client/src/layoutSystems/CanvasFactory.tsx @@ -0,0 +1,39 @@ +import React, { memo, useMemo } from "react"; +import { useSelector } from "react-redux"; +import { getRenderMode } from "selectors/editorSelectors"; +import { getLayoutSystemType } from "selectors/layoutSystemSelectors"; +import type { WidgetProps } from "widgets/BaseWidget"; +import withWidgetProps from "widgets/withWidgetProps"; +import { getLayoutSystem } from "./withLayoutSystemWidgetHOC"; + +// ToDo(#27615): destructure withWidgetProps to withCanvasProps by picking only necessary props of a canvas. + +/** + * Canvas of a Layout System is the module that provides necessary utilities to position and order widgets. + * Canvas also provides editing layout system specific editing experiences like Drag and Drop, Drag to Select, Widget Grouping, etc. + * This Component Hydrates canvas with enhanced properties from withWidgetProps and picks the layout system specific Canvas Implementation. + */ + +const LayoutSystemBasedCanvas = memo((props: WidgetProps) => { + const renderMode = useSelector(getRenderMode); + const layoutSystemType = useSelector(getLayoutSystemType); + const { canvasSystem } = useMemo( + () => getLayoutSystem(renderMode, layoutSystemType), + [ + { + renderMode, + layoutSystemType, + }, + ], + ); + const { Canvas, propertyEnhancer } = canvasSystem; + return ; +}); + +const HydratedLayoutSystemBasedCanvas = withWidgetProps( + LayoutSystemBasedCanvas as any, +); + +export const renderAppsmithCanvas = (props: WidgetProps) => { + return ; +}; diff --git a/app/client/src/layoutSystems/anvil/editor/AnvilEditorWrapper.tsx b/app/client/src/layoutSystems/anvil/editor/AnvilEditorWrapper.tsx index d79d785188..9c4bf1ad56 100644 --- a/app/client/src/layoutSystems/anvil/editor/AnvilEditorWrapper.tsx +++ b/app/client/src/layoutSystems/anvil/editor/AnvilEditorWrapper.tsx @@ -20,10 +20,5 @@ export const AnvilEditorWrapper = (props: WidgetProps) => { : AnvilEditorWidgetOnion; }, [props.type]); - //Canvas_Onion - if (props.type === "CANVAS_WIDGET") { - return props.children; - } - return {props.children}; }; diff --git a/app/client/src/layoutSystems/anvil/index.ts b/app/client/src/layoutSystems/anvil/index.ts index 8638067b99..03a1d09d74 100644 --- a/app/client/src/layoutSystems/anvil/index.ts +++ b/app/client/src/layoutSystems/anvil/index.ts @@ -52,7 +52,7 @@ const getAnvilSystemWrapper = (renderMode: RenderModes) => { return AnvilViewerWrapper; }; -export function getAnvilSystem(renderMode: RenderModes) { +export function getAnvilLayoutSystem(renderMode: RenderModes) { return { LayoutSystemWrapper: getAnvilSystemWrapper(renderMode), propertyEnhancer: getAnvilSystemPropsEnhancer, diff --git a/app/client/src/layoutSystems/anvil/viewer/AnvilViewerWrapper.tsx b/app/client/src/layoutSystems/anvil/viewer/AnvilViewerWrapper.tsx index d8a45d4ac4..d8c952dba0 100644 --- a/app/client/src/layoutSystems/anvil/viewer/AnvilViewerWrapper.tsx +++ b/app/client/src/layoutSystems/anvil/viewer/AnvilViewerWrapper.tsx @@ -19,9 +19,5 @@ export const AnvilViewerWrapper = (props: WidgetProps) => { : AnvilViewerWidgetOnion; }, [props.type]); - if (props.type === "CANVAS_WIDGET") { - return props.children; - } - return {props.children}; }; diff --git a/app/client/src/layoutSystems/autolayout/MainContainerResizer/MainContainerResizer.tsx b/app/client/src/layoutSystems/autolayout/MainContainerResizer/MainContainerResizer.tsx deleted file mode 100644 index 97ea2b2fd8..0000000000 --- a/app/client/src/layoutSystems/autolayout/MainContainerResizer/MainContainerResizer.tsx +++ /dev/null @@ -1,187 +0,0 @@ -import { layoutConfigurations } from "constants/WidgetConstants"; -import React, { useEffect, useRef } from "react"; -import { useDispatch, useSelector } from "react-redux"; -import { getCurrentApplicationLayout } from "selectors/editorSelectors"; -import { setAutoCanvasResizing } from "actions/autoLayoutActions"; -import styled from "styled-components"; -import { AUTOLAYOUT_RESIZER_WIDTH_BUFFER } from "utils/hooks/useDynamicAppLayout"; -import { importSvg } from "design-system-old"; -import { CANVAS_VIEWPORT } from "constants/componentClassNameConstants"; - -const CanvasResizerIcon = importSvg( - () => import("assets/icons/ads/app-icons/canvas-resizer.svg"), -); - -const AutoLayoutCanvasResizer = styled.div` - position: sticky; - cursor: col-resize; - width: 2px; - height: 100%; - display: flex; - background: var(--ads-v2-color-border); - align-items: center; - justify-content: flex-start; - margin-left: 2px; - transition: width 300ms ease; - transition: background 300ms ease; - .canvas-resizer-icon { - border-left: 2px solid; - border-color: var(--ads-v2-color-border); - transition: border 300ms ease; - margin-left: 2px; - & > svg { - fill: var(--ads-v2-color-border); - transition: fill 300ms ease; - } - } - &:hover, - &:active { - width: 3px; - transition: width 300ms ease; - background: #ff9b4e; - transition: background 300ms ease; - .canvas-resizer-icon { - border-color: #ff9b4e; - transition: border 300ms ease; - & > svg { - fill: #ff9b4e; - transition: fill 300ms ease; - } - } - } -`; - -/** - * OldName: CanvasResizer - */ -export function MainContainerResizer({ - currentPageId, - enableMainCanvasResizer, - heightWithTopMargin, - isPageInitiated, - isPreviewMode, - shouldHaveTopMargin, -}: { - heightWithTopMargin: string; - isPageInitiated: boolean; - shouldHaveTopMargin: boolean; - isPreviewMode: boolean; - currentPageId: string; - enableMainCanvasResizer: boolean; -}) { - const appLayout = useSelector(getCurrentApplicationLayout); - const ref = useRef(null); - const dispatch = useDispatch(); - useEffect(() => { - const ele: any = document.getElementById(CANVAS_VIEWPORT); - - if (isPageInitiated && enableMainCanvasResizer) { - const buffer = isPreviewMode ? AUTOLAYOUT_RESIZER_WIDTH_BUFFER : 0; - const fullWidthCSS = `calc(100% - ${AUTOLAYOUT_RESIZER_WIDTH_BUFFER}px)`; - const wrapperElement: any = document.getElementById("widgets-editor"); - - let maxWidth = - wrapperElement.offsetWidth - AUTOLAYOUT_RESIZER_WIDTH_BUFFER; - - if (ele && ele.offsetWidth >= maxWidth) { - ele.style.width = fullWidthCSS; - } - - if (appLayout?.type === "FLUID") { - const smallestWidth = layoutConfigurations.MOBILE.minWidth; - // The current position of mouse - let x = 0; - // let y = 0; - - // The dimension of the element - let w = 0; - // let h = 0; - let events: any = []; - - // Handle the mousedown event - // that's triggered when user drags the resizer - const mouseDownHandler = function (e: any) { - maxWidth = - wrapperElement.offsetWidth - AUTOLAYOUT_RESIZER_WIDTH_BUFFER; - // Get the current mouse position - x = e.clientX; - // y = e.clientY; - - // Calculate the dimension of element - const styles = window.getComputedStyle(ele); - dispatch(setAutoCanvasResizing(true)); - w = parseInt(styles.width, 10) + buffer; - // h = parseInt(styles.height, 10); - const mouseMove = (e: any) => mouseMoveHandler(e); - events.push(mouseMove); - // Attach the listeners to `document` - document.addEventListener("mousemove", mouseMove); - document.addEventListener("mouseup", mouseUpHandler); - // e.stopPropagation(); - }; - - const mouseMoveHandler = function (e: any) { - // How far the mouse has been moved - // const multiplier = rightHandle ? 2 : -2; - const multiplier = 2; - const dx = (e.clientX - x) * multiplier; - if (maxWidth >= w + dx && smallestWidth <= w + dx) { - // Adjust the dimension of element - ele.style.width = `${w + dx}px`; - } - if (maxWidth < w + dx) { - ele.style.width = fullWidthCSS; - } - if (smallestWidth > w + dx) { - ele.style.width = `${smallestWidth}px`; - } - // e.stopPropagation(); - }; - - const mouseUpHandler = function (e: any) { - // Remove the handlers of `mousemove` and `mouseup` - mouseMoveHandler(e); - dispatch(setAutoCanvasResizing(false)); - document.removeEventListener("mousemove", events[0] as any); - document.removeEventListener("mouseup", mouseUpHandler); - events = []; - }; - const rightResizer: any = ref.current; - const rightMove = (e: any) => mouseDownHandler(e); - rightResizer && rightResizer.addEventListener("mousedown", rightMove); - - return () => { - rightResizer && - rightResizer.removeEventListener("mousedown", rightMove); - }; - } - } else { - ele.style.removeProperty("width"); - } - }, [ - appLayout, - isPreviewMode, - currentPageId, - enableMainCanvasResizer, - isPageInitiated, - ]); - return enableMainCanvasResizer ? ( - { - e.preventDefault(); - e.stopPropagation(); - }} - ref={ref} - style={{ - top: "100%", - height: shouldHaveTopMargin ? heightWithTopMargin : "100vh", - }} - > -
- -
-
- ) : null; -} diff --git a/app/client/src/layoutSystems/autolayout/canvas/AutoLayoutCanvasView.tsx b/app/client/src/layoutSystems/autolayout/canvas/AutoLayoutCanvasView.tsx new file mode 100644 index 0000000000..c62be3b9b3 --- /dev/null +++ b/app/client/src/layoutSystems/autolayout/canvas/AutoLayoutCanvasView.tsx @@ -0,0 +1,68 @@ +import { GridDefaults } from "constants/WidgetConstants"; +import type { RenderModes } from "constants/WidgetConstants"; +import { renderChildren } from "layoutSystems/common/utils/canvasUtils"; +import React, { useMemo } from "react"; +import type { BaseWidgetProps } from "widgets/BaseWidgetHOC/withBaseWidgetHOC"; +import FlexBoxComponent from "../common/flexCanvas/FlexBoxComponent"; +import type { AdditionalAutoLayoutProperties } from "./types"; +import type { WidgetProps } from "widgets/BaseWidget"; +import type { LayoutDirection } from "layoutSystems/common/utils/constants"; + +/** + * This is the view component used by Canvas of Auto Layout both in Edit/View mode. + * This component is responsible for rendering the children of a canvas. + * It also adds additional layout specific properties to the children like parentColumnSpace, parentRowSpace, isFlexChild, etc. + */ + +export const AutoLayoutCanvasView = ({ + direction, + renderMode, + snapColumnSpace, + widgetProps, +}: { + widgetProps: BaseWidgetProps; + renderMode: RenderModes; + snapColumnSpace: number; + direction: LayoutDirection; +}) => { + // setting stretchFlexBox to true would stretch the canvas to 100% of the container widgets height when there are no children in it. + // else its set to auto height. + const stretchFlexBox = !widgetProps.children || !widgetProps.children?.length; + const layoutSystemProps: AdditionalAutoLayoutProperties = { + parentColumnSpace: snapColumnSpace, + parentRowSpace: GridDefaults.DEFAULT_GRID_ROW_HEIGHT, + }; + const defaultWidgetProps: Partial = { + isFlexChild: true, + direction, + }; + const canvasChildren = useMemo( + () => + renderChildren( + widgetProps.children, + widgetProps.widgetId, + renderMode, + defaultWidgetProps, + layoutSystemProps, + ), + [ + widgetProps.children, + widgetProps.widgetId, + renderMode, + snapColumnSpace, + direction, + ], + ); + return ( + + {canvasChildren} + + ); +}; diff --git a/app/client/src/layoutSystems/autolayout/canvas/AutoLayoutEditorCanvas.tsx b/app/client/src/layoutSystems/autolayout/canvas/AutoLayoutEditorCanvas.tsx new file mode 100644 index 0000000000..8e79ced318 --- /dev/null +++ b/app/client/src/layoutSystems/autolayout/canvas/AutoLayoutEditorCanvas.tsx @@ -0,0 +1,92 @@ +import { CANVAS_DEFAULT_MIN_HEIGHT_PX } from "constants/AppConstants"; +import { RenderModes } from "constants/WidgetConstants"; +import { DropTargetComponentWrapper } from "layoutSystems/common/dropTarget/DropTargetComponentWrapper"; +import { CanvasSelectionArena } from "layoutSystems/fixedlayout/editor/FixedLayoutCanvasArenas/CanvasSelectionArena"; +import React, { useMemo } from "react"; +import { getSnappedGrid } from "sagas/WidgetOperationUtils"; +import { getCanvasSnapRows } from "utils/WidgetPropsUtils"; +import type { BaseWidgetProps } from "widgets/BaseWidgetHOC/withBaseWidgetHOC"; +import ContainerComponent from "widgets/ContainerWidget/component"; +import { AutoCanvasDraggingArena } from "../editor/AutoLayoutCanvasArenas/AutoCanvasDraggingArena"; +import { AutoLayoutCanvasView } from "./AutoLayoutCanvasView"; +import { getDirection } from "./utils"; + +/** + * This component implements the Canvas for Auto Layout System in Edit mode. + * It renders layers like CanvasDraggingArena, CanvasSelectionArena, etc which are responsible for + * drag and drop, scrolling, etc. + */ + +export const AutoLayoutEditorCanvas = (props: BaseWidgetProps) => { + const { snapGrid } = getSnappedGrid(props, props.componentWidth); + const { snapColumnSpace } = snapGrid; + const direction = getDirection(props.positioning); + const snapRows = getCanvasSnapRows( + props.bottomRow, + props.mobileBottomRow, + props.isMobile, + true, + ); + const autoLayoutDropTargetProps = useMemo( + () => ({ + bottomRow: props.bottomRow, + isListWidgetCanvas: props.isListWidgetCanvas, + isMobile: props.isMobile, + minHeight: props.minHeight || CANVAS_DEFAULT_MIN_HEIGHT_PX, + mobileBottomRow: props.mobileBottomRow, + noPad: props.noPad, + parentId: props.parentId, + snapColumnSpace: snapColumnSpace, + useAutoLayout: props.useAutoLayout, + widgetId: props.widgetId, + }), + [ + props.bottomRow, + props.isListWidgetCanvas, + props.isMobile, + props.minHeight, + props.mobileBottomRow, + props.noPad, + props.parentId, + snapColumnSpace, + props.useAutoLayout, + props.widgetId, + ], + ); + return ( + + + + + + + + ); +}; diff --git a/app/client/src/layoutSystems/autolayout/canvas/AutoLayoutViewerCanvas.tsx b/app/client/src/layoutSystems/autolayout/canvas/AutoLayoutViewerCanvas.tsx new file mode 100644 index 0000000000..51067e570a --- /dev/null +++ b/app/client/src/layoutSystems/autolayout/canvas/AutoLayoutViewerCanvas.tsx @@ -0,0 +1,40 @@ +import { RenderModes } from "constants/WidgetConstants"; +import { CanvasViewerWrapper } from "layoutSystems/common/canvasViewer/CanvasViewerWrapper"; +import React from "react"; +import { getSnappedGrid } from "sagas/WidgetOperationUtils"; +import { getCanvasSnapRows } from "utils/WidgetPropsUtils"; +import type { BaseWidgetProps } from "widgets/BaseWidgetHOC/withBaseWidgetHOC"; +import ContainerComponent from "widgets/ContainerWidget/component"; +import { AutoLayoutCanvasView } from "./AutoLayoutCanvasView"; +import { getDirection } from "./utils"; + +/** + * This component implements the Canvas for Auto Layout System in View mode. + */ + +export const AutoLayoutViewerCanvas = (props: BaseWidgetProps) => { + const { snapGrid } = getSnappedGrid(props, props.componentWidth); + const { snapColumnSpace } = snapGrid; + const direction = getDirection(props.positioning); + const snapRows = getCanvasSnapRows( + props.bottomRow, + props.mobileBottomRow, + props.isMobile, + true, + ); + return ( + + + + + + ); +}; diff --git a/app/client/src/layoutSystems/autolayout/canvas/types.ts b/app/client/src/layoutSystems/autolayout/canvas/types.ts new file mode 100644 index 0000000000..e9528c099c --- /dev/null +++ b/app/client/src/layoutSystems/autolayout/canvas/types.ts @@ -0,0 +1,4 @@ +export type AdditionalAutoLayoutProperties = { + parentColumnSpace: number; + parentRowSpace: number; +}; diff --git a/app/client/src/layoutSystems/autolayout/canvas/utils.ts b/app/client/src/layoutSystems/autolayout/canvas/utils.ts new file mode 100644 index 0000000000..88621e28c8 --- /dev/null +++ b/app/client/src/layoutSystems/autolayout/canvas/utils.ts @@ -0,0 +1,16 @@ +import { + LayoutDirection, + Positioning, +} from "layoutSystems/common/utils/constants"; + +/** + * This utility function returns the direction of the layout based on the positioning + * @param positioning + * @returns + */ + +export const getDirection = (positioning?: Positioning): LayoutDirection => { + return positioning === Positioning.Vertical + ? LayoutDirection.Vertical + : LayoutDirection.Horizontal; +}; diff --git a/app/client/src/layoutSystems/autolayout/editor/AutoLayoutCanvasArenas/AutoCanvasDraggingArena.tsx b/app/client/src/layoutSystems/autolayout/editor/AutoLayoutCanvasArenas/AutoCanvasDraggingArena.tsx index 1110165a77..f5afe09d23 100644 --- a/app/client/src/layoutSystems/autolayout/editor/AutoLayoutCanvasArenas/AutoCanvasDraggingArena.tsx +++ b/app/client/src/layoutSystems/autolayout/editor/AutoLayoutCanvasArenas/AutoCanvasDraggingArena.tsx @@ -3,8 +3,8 @@ import React from "react"; import { useSelector } from "react-redux"; import { getNearestParentCanvas } from "utils/generators"; import { useCanvasDragging } from "./hooks/useCanvasDragging"; +import { StickyCanvasArena } from "layoutSystems/common/canvasArenas/StickyCanvasArena"; import type { LayoutDirection } from "layoutSystems/common/utils/constants"; -import { StickyCanvasArena } from "layoutSystems/common/CanvasArenas/StickyCanvasArena"; export interface AutoCanvasDraggingArenaProps { alignItems?: string; diff --git a/app/client/src/layoutSystems/autolayout/editor/AutoLayoutCanvasArenas/hooks/useAutoLayoutHighlights.ts b/app/client/src/layoutSystems/autolayout/editor/AutoLayoutCanvasArenas/hooks/useAutoLayoutHighlights.ts index 7a3d86445c..0e52f20d44 100644 --- a/app/client/src/layoutSystems/autolayout/editor/AutoLayoutCanvasArenas/hooks/useAutoLayoutHighlights.ts +++ b/app/client/src/layoutSystems/autolayout/editor/AutoLayoutCanvasArenas/hooks/useAutoLayoutHighlights.ts @@ -5,7 +5,7 @@ import WidgetFactory from "WidgetProvider/factory"; import type { HighlightInfo } from "layoutSystems/common/utils/types"; import { useRef } from "react"; import { getIsAutoLayoutMobileBreakPoint } from "selectors/editorSelectors"; -import type { WidgetDraggingBlock } from "layoutSystems/common/CanvasArenas/ArenaTypes"; +import type { WidgetDraggingBlock } from "layoutSystems/common/canvasArenas/ArenaTypes"; import { deriveHighlightsFromLayers } from "layoutSystems/autolayout/utils/highlightUtils"; import type { Point } from "layoutSystems/autolayout/utils/highlightSelectionUtils"; import { getHighlightPayload } from "layoutSystems/autolayout/utils/highlightSelectionUtils"; diff --git a/app/client/src/layoutSystems/autolayout/editor/AutoLayoutCanvasArenas/hooks/useBlocksToBeDraggedOnCanvas.ts b/app/client/src/layoutSystems/autolayout/editor/AutoLayoutCanvasArenas/hooks/useBlocksToBeDraggedOnCanvas.ts index 5bccb7be7c..06e01fb752 100644 --- a/app/client/src/layoutSystems/autolayout/editor/AutoLayoutCanvasArenas/hooks/useBlocksToBeDraggedOnCanvas.ts +++ b/app/client/src/layoutSystems/autolayout/editor/AutoLayoutCanvasArenas/hooks/useBlocksToBeDraggedOnCanvas.ts @@ -8,7 +8,7 @@ import { getOccupiedSpacesWhileMoving } from "selectors/editorSelectors"; import type { WidgetSpace } from "constants/CanvasEditorConstants"; import { getDragDetails, getWidgetByID, getWidgets } from "sagas/selectors"; import { widgetOperationParams } from "utils/WidgetPropsUtils"; -import { DropTargetContext } from "components/editorComponents/DropTargetComponent"; +import { DropTargetContext } from "layoutSystems/common/dropTarget/DropTargetComponent"; import equal from "fast-deep-equal/es6"; import { useDispatch, useSelector } from "react-redux"; import { ReduxActionTypes } from "@appsmith/constants/ReduxActionConstants"; @@ -17,7 +17,7 @@ import type { DragDetails } from "reducers/uiReducers/dragResizeReducer"; import { SelectionRequestType } from "sagas/WidgetSelectUtils"; import { useContext, useEffect, useRef } from "react"; import type { AutoCanvasDraggingArenaProps } from "../AutoCanvasDraggingArena"; -import type { WidgetDraggingBlock } from "../../../../common/CanvasArenas/ArenaTypes"; +import type { WidgetDraggingBlock } from "../../../../common/canvasArenas/ArenaTypes"; import type { HighlightInfo } from "layoutSystems/common/utils/types"; import { LayoutDirection, diff --git a/app/client/src/layoutSystems/autolayout/editor/AutoLayoutCanvasArenas/hooks/useCanvasDragging.ts b/app/client/src/layoutSystems/autolayout/editor/AutoLayoutCanvasArenas/hooks/useCanvasDragging.ts index 99e0f2699d..4b7c11484a 100644 --- a/app/client/src/layoutSystems/autolayout/editor/AutoLayoutCanvasArenas/hooks/useCanvasDragging.ts +++ b/app/client/src/layoutSystems/autolayout/editor/AutoLayoutCanvasArenas/hooks/useCanvasDragging.ts @@ -7,12 +7,12 @@ import { getTotalTopOffset } from "selectors/autoLayoutSelectors"; import { getNearestParentCanvas } from "utils/generators"; import { useWidgetDragResize } from "utils/hooks/dragResizeHooks"; import { useAutoLayoutHighlights } from "./useAutoLayoutHighlights"; -import type { WidgetDraggingBlock } from "../../../../common/CanvasArenas/ArenaTypes"; +import type { WidgetDraggingBlock } from "../../../../common/canvasArenas/ArenaTypes"; import { useBlocksToBeDraggedOnCanvas } from "./useBlocksToBeDraggedOnCanvas"; import { useRenderBlocksOnCanvas } from "./useRenderBlocksOnCanvas"; import type { HighlightInfo } from "layoutSystems/common/utils/types"; import type { AutoCanvasDraggingArenaProps } from "../AutoCanvasDraggingArena"; -import { useCanvasDragToScroll } from "layoutSystems/common/CanvasArenas/useCanvasDragToScroll"; +import { useCanvasDragToScroll } from "layoutSystems/common/canvasArenas/useCanvasDragToScroll"; import { modifyBlockDimension } from "layoutSystems/common/utils/canvasDraggingUtils"; import { CANVAS_VIEWPORT } from "constants/componentClassNameConstants"; diff --git a/app/client/src/layoutSystems/autolayout/editor/AutoLayoutCanvasArenas/hooks/useRenderBlocksOnCanvas.ts b/app/client/src/layoutSystems/autolayout/editor/AutoLayoutCanvasArenas/hooks/useRenderBlocksOnCanvas.ts index 34d636ca20..a4c253f86b 100644 --- a/app/client/src/layoutSystems/autolayout/editor/AutoLayoutCanvasArenas/hooks/useRenderBlocksOnCanvas.ts +++ b/app/client/src/layoutSystems/autolayout/editor/AutoLayoutCanvasArenas/hooks/useRenderBlocksOnCanvas.ts @@ -4,7 +4,7 @@ import { useSelector } from "react-redux"; import { getZoomLevel } from "selectors/editorSelectors"; import type { HighlightInfo } from "layoutSystems/common/utils/types"; import { getAbsolutePixels } from "utils/helpers"; -import type { WidgetDraggingBlock } from "../../../../common/CanvasArenas/ArenaTypes"; +import type { WidgetDraggingBlock } from "../../../../common/canvasArenas/ArenaTypes"; import { modifyDrawingRectangles } from "layoutSystems/common/utils/canvasDraggingUtils"; /** diff --git a/app/client/src/layoutSystems/autolayout/editor/AutoLayoutEditorWrapper.tsx b/app/client/src/layoutSystems/autolayout/editor/AutoLayoutEditorWrapper.tsx index fd3fb05891..101b902384 100644 --- a/app/client/src/layoutSystems/autolayout/editor/AutoLayoutEditorWrapper.tsx +++ b/app/client/src/layoutSystems/autolayout/editor/AutoLayoutEditorWrapper.tsx @@ -24,11 +24,6 @@ export const AutoLayoutEditorWrapper = (props: WidgetProps) => { ? AutoLayoutEditorModalOnion : AutoLayoutEditorWidgetOnion; }, [props.type]); - const canvasWidget = props.type === "CANVAS_WIDGET"; - - if (canvasWidget) { - return props.children; - } return {props.children}; }; diff --git a/app/client/src/layoutSystems/autolayout/index.ts b/app/client/src/layoutSystems/autolayout/index.ts index e71b0bd9b8..eb7c45cced 100644 --- a/app/client/src/layoutSystems/autolayout/index.ts +++ b/app/client/src/layoutSystems/autolayout/index.ts @@ -1,8 +1,13 @@ import type { BaseWidgetProps } from "widgets/BaseWidgetHOC/withBaseWidgetHOC"; import { RenderModes } from "../../constants/WidgetConstants"; +import { AutoLayoutEditorCanvas } from "./canvas/AutoLayoutEditorCanvas"; +import { AutoLayoutViewerCanvas } from "./canvas/AutoLayoutViewerCanvas"; import { AutoLayoutEditorWrapper } from "./editor/AutoLayoutEditorWrapper"; import { AutoLayoutViewerWrapper } from "./viewer/AutoLayoutViewerWrapper"; import { getAutoLayoutComponentDimensions } from "layoutSystems/common/utils/ComponentSizeUtils"; +import type { LayoutSystem } from "layoutSystems/types"; +import { CANVAS_DEFAULT_MIN_HEIGHT_PX } from "constants/AppConstants"; +import type { CanvasProps } from "layoutSystems/fixedlayout/canvas/FixedLayoutEditorCanvas"; import { getAutoDimensionsConfig, getAutoLayoutWidgetConfig, @@ -24,7 +29,7 @@ export const getAutoLayoutDimensionsConfig = ( }; /** - * getAutoLayoutSystemPropsEnhancer + * getAutoLayoutSystemWidgetPropsEnhancer * * utility function to enhance BaseWidgetProps with Auto Layout system specific props * @@ -35,7 +40,7 @@ export const getAutoLayoutDimensionsConfig = ( * */ -const getAutoLayoutSystemPropsEnhancer = (props: BaseWidgetProps) => { +const getAutoLayoutSystemWidgetPropsEnhancer = (props: BaseWidgetProps) => { const autoDimensionConfig = getAutoLayoutDimensionsConfig(props); const { componentHeight, componentWidth } = getAutoLayoutComponentDimensions(props); @@ -47,6 +52,45 @@ const getAutoLayoutSystemPropsEnhancer = (props: BaseWidgetProps) => { }; }; +const defaultAutoLayoutCanvasProps: Partial = { + parentRowSpace: 1, + parentColumnSpace: 1, + topRow: 0, + leftColumn: 0, + containerStyle: "none", + detachFromLayout: true, + shouldScrollContents: false, +}; + +/** + * getAutoLayoutSystemCanvasPropsEnhancer + * + * utility function to enhance BaseWidgetProps of canvas with Auto Layout system specific props + * + * @returns EnhancedBaseWidgetProps + * @property {AutoDimensionValues | undefined} autoDimensionConfig The auto dimension configuration of a widget. + * @property {number} componentHeight The calculated height of a widget in pixels. + * @property {number} componentWidth The calculated width of a widget in pixels. + * + */ + +const getAutoLayoutSystemCanvasPropsEnhancer = (props: BaseWidgetProps) => { + const enhancedProps = { + minHeight: CANVAS_DEFAULT_MIN_HEIGHT_PX, + ...props, + ...defaultAutoLayoutCanvasProps, + }; + const autoDimensionConfig = getAutoLayoutDimensionsConfig(enhancedProps); + const { componentHeight, componentWidth } = + getAutoLayoutComponentDimensions(enhancedProps); + return { + ...enhancedProps, + autoDimensionConfig, + componentHeight, + componentWidth, + }; +}; + /** * getAutoLayoutSystemWrapper * @@ -64,6 +108,22 @@ const getAutoLayoutSystemWrapper = (renderMode: RenderModes) => { } }; +/** + * getAutoLayoutSystemCanvasWrapper + * + * utility function to return the auto layout system canvas implementation based on render mode. + * + * @returns current render mode specific canvas component. + */ + +function getAutoLayoutSystemCanvasWrapper(renderMode: RenderModes) { + if (renderMode === RenderModes.CANVAS) { + return AutoLayoutEditorCanvas; + } else { + return AutoLayoutViewerCanvas; + } +} + /** * getAutoLayoutSystem * @@ -71,15 +131,19 @@ const getAutoLayoutSystemWrapper = (renderMode: RenderModes) => { * wrapper based on render mode and property enhancer function * * @returns - * @function LayoutSystemWrapper - layout and render mode specific component which is wrapped around a widget - * pls check getAutoLayoutSystemWrapper for more details. - * @function propertyEnhancer - layout specific enhancer function which adds more properties generated/used by the layout system. - * pls check getAutoLayoutSystemPropsEnhancer for more details. + * @property widgetSystem - widget specific wrappers and enhancers of a layout system + * @property canvasSystem - canvas specific implementation and enhancers of a layout system */ -export function getAutoLayoutSystem(renderMode: RenderModes) { +export function getAutoLayoutSystem(renderMode: RenderModes): LayoutSystem { return { - LayoutSystemWrapper: getAutoLayoutSystemWrapper(renderMode), - propertyEnhancer: getAutoLayoutSystemPropsEnhancer, + widgetSystem: { + WidgetWrapper: getAutoLayoutSystemWrapper(renderMode), + propertyEnhancer: getAutoLayoutSystemWidgetPropsEnhancer, + }, + canvasSystem: { + Canvas: getAutoLayoutSystemCanvasWrapper(renderMode), + propertyEnhancer: getAutoLayoutSystemCanvasPropsEnhancer, + }, }; } diff --git a/app/client/src/layoutSystems/autolayout/viewer/AutoLayoutViewerWrapper.tsx b/app/client/src/layoutSystems/autolayout/viewer/AutoLayoutViewerWrapper.tsx index 279ad28c0d..879af7d9d2 100644 --- a/app/client/src/layoutSystems/autolayout/viewer/AutoLayoutViewerWrapper.tsx +++ b/app/client/src/layoutSystems/autolayout/viewer/AutoLayoutViewerWrapper.tsx @@ -24,10 +24,6 @@ export const AutoLayoutViewerWrapper = (props: WidgetProps) => { ? AutoLayoutViewerModalOnion : AutoLayoutViewerWidgetOnion; }, [props.type]); - const canvasWidget = props.type === "CANVAS_WIDGET"; - if (canvasWidget) { - return props.children; - } return {props.children}; }; diff --git a/app/client/src/layoutSystems/common/CanvasArenas/ArenaTypes.ts b/app/client/src/layoutSystems/common/canvasArenas/ArenaTypes.ts similarity index 100% rename from app/client/src/layoutSystems/common/CanvasArenas/ArenaTypes.ts rename to app/client/src/layoutSystems/common/canvasArenas/ArenaTypes.ts diff --git a/app/client/src/layoutSystems/common/CanvasArenas/CanvasMultiPointerArena.tsx b/app/client/src/layoutSystems/common/canvasArenas/CanvasMultiPointerArena.tsx similarity index 100% rename from app/client/src/layoutSystems/common/CanvasArenas/CanvasMultiPointerArena.tsx rename to app/client/src/layoutSystems/common/canvasArenas/CanvasMultiPointerArena.tsx diff --git a/app/client/src/layoutSystems/common/CanvasArenas/StickyCanvasArena.tsx b/app/client/src/layoutSystems/common/canvasArenas/StickyCanvasArena.tsx similarity index 100% rename from app/client/src/layoutSystems/common/CanvasArenas/StickyCanvasArena.tsx rename to app/client/src/layoutSystems/common/canvasArenas/StickyCanvasArena.tsx diff --git a/app/client/src/layoutSystems/common/CanvasArenas/useCanvasDragToScroll.ts b/app/client/src/layoutSystems/common/canvasArenas/useCanvasDragToScroll.ts similarity index 100% rename from app/client/src/layoutSystems/common/CanvasArenas/useCanvasDragToScroll.ts rename to app/client/src/layoutSystems/common/canvasArenas/useCanvasDragToScroll.ts diff --git a/app/client/src/layoutSystems/common/canvasViewer/CanvasViewerWrapper.tsx b/app/client/src/layoutSystems/common/canvasViewer/CanvasViewerWrapper.tsx new file mode 100644 index 0000000000..1f8c7b887e --- /dev/null +++ b/app/client/src/layoutSystems/common/canvasViewer/CanvasViewerWrapper.tsx @@ -0,0 +1,33 @@ +import { GridDefaults } from "constants/WidgetConstants"; +import type { CSSProperties, ReactNode } from "react"; +import React from "react"; +import { getCanvasClassName } from "utils/generators"; + +type CanvasViewerWrapperProps = { + snapRows: number; + isListWidgetCanvas: boolean; + children: ReactNode; +}; + +/** + * This component is a wrapper for the canvas in the viewer. + * It is responsible for setting the height of the canvas in view mode. + */ +export const CanvasViewerWrapper = ({ + children, + isListWidgetCanvas, + snapRows, +}: CanvasViewerWrapperProps) => { + const height = snapRows * GridDefaults.DEFAULT_GRID_ROW_HEIGHT; + const style: CSSProperties = { + width: "100%", + height: isListWidgetCanvas ? "auto" : `${height}px`, + background: "none", + position: "relative", + }; + return ( +
+ {children} +
+ ); +}; diff --git a/app/client/src/components/editorComponents/DragLayerComponent.test.tsx b/app/client/src/layoutSystems/common/dropTarget/DragLayerComponent.test.tsx similarity index 100% rename from app/client/src/components/editorComponents/DragLayerComponent.test.tsx rename to app/client/src/layoutSystems/common/dropTarget/DragLayerComponent.test.tsx diff --git a/app/client/src/components/editorComponents/DragLayerComponent.tsx b/app/client/src/layoutSystems/common/dropTarget/DragLayerComponent.tsx similarity index 100% rename from app/client/src/components/editorComponents/DragLayerComponent.tsx rename to app/client/src/layoutSystems/common/dropTarget/DragLayerComponent.tsx diff --git a/app/client/src/components/editorComponents/DropTargetComponent.tsx b/app/client/src/layoutSystems/common/dropTarget/DropTargetComponent.tsx similarity index 99% rename from app/client/src/components/editorComponents/DropTargetComponent.tsx rename to app/client/src/layoutSystems/common/dropTarget/DropTargetComponent.tsx index 554ba8a228..e1520ab819 100644 --- a/app/client/src/components/editorComponents/DropTargetComponent.tsx +++ b/app/client/src/layoutSystems/common/dropTarget/DropTargetComponent.tsx @@ -17,7 +17,6 @@ import styled from "styled-components"; import { getCanvasSnapRows } from "utils/WidgetPropsUtils"; import { calculateDropTargetRows } from "./DropTargetUtils"; -import DragLayerComponent from "./DragLayerComponent"; import { useDispatch } from "react-redux"; import { useShowPropertyPane } from "utils/hooks/dragResizeHooks"; import { @@ -37,10 +36,11 @@ import { isAutoHeightEnabledForWidgetWithLimits, } from "widgets/WidgetUtils"; import { getIsAppSettingsPaneWithNavigationTabOpen } from "selectors/appSettingsPaneSelectors"; -import { LayoutSystemTypes } from "layoutSystems/types"; +import DragLayerComponent from "./DragLayerComponent"; import { getLayoutSystemType } from "selectors/layoutSystemSelectors"; +import { LayoutSystemTypes } from "layoutSystems/types"; -type DropTargetComponentProps = PropsWithChildren<{ +export type DropTargetComponentProps = PropsWithChildren<{ snapColumnSpace: number; widgetId: string; parentId?: string; diff --git a/app/client/src/layoutSystems/common/dropTarget/DropTargetComponentWrapper.tsx b/app/client/src/layoutSystems/common/dropTarget/DropTargetComponentWrapper.tsx new file mode 100644 index 0000000000..e0e1482639 --- /dev/null +++ b/app/client/src/layoutSystems/common/dropTarget/DropTargetComponentWrapper.tsx @@ -0,0 +1,33 @@ +import DropTargetComponent from "layoutSystems/common/dropTarget/DropTargetComponent"; +import type { DropTargetComponentProps } from "layoutSystems/common/dropTarget/DropTargetComponent"; +import type { ReactNode } from "react"; +import { memo } from "react"; +import React from "react"; + +type DropTargetComponentWrapperProps = { + dropTargetProps: DropTargetComponentProps; + dropDisabled: boolean; + children: ReactNode; + snapColumnSpace: number; +}; + +/** + * This component is a wrapper for the DropTargetComponent. + * It decides whether to render the DropTargetComponent or not based on the dropDisabled prop. + */ + +export const DropTargetComponentWrapper = memo( + ({ + children, + dropDisabled, + dropTargetProps, + }: DropTargetComponentWrapperProps) => { + if (dropDisabled) { + //eslint-disable-next-line + return <>{children}; + } + return ( + {children} + ); + }, +); diff --git a/app/client/src/components/editorComponents/DropTargetUtils.ts b/app/client/src/layoutSystems/common/dropTarget/DropTargetUtils.ts similarity index 100% rename from app/client/src/components/editorComponents/DropTargetUtils.ts rename to app/client/src/layoutSystems/common/dropTarget/DropTargetUtils.ts diff --git a/app/client/src/layoutSystems/common/MainContainerResizer/MainContainerResizer.tsx b/app/client/src/layoutSystems/common/mainContainerResizer/MainContainerResizer.tsx similarity index 100% rename from app/client/src/layoutSystems/common/MainContainerResizer/MainContainerResizer.tsx rename to app/client/src/layoutSystems/common/mainContainerResizer/MainContainerResizer.tsx diff --git a/app/client/src/layoutSystems/common/resizer/ResizableComponent.tsx b/app/client/src/layoutSystems/common/resizer/ResizableComponent.tsx index 0f86442fae..ab7b90ef5c 100644 --- a/app/client/src/layoutSystems/common/resizer/ResizableComponent.tsx +++ b/app/client/src/layoutSystems/common/resizer/ResizableComponent.tsx @@ -9,7 +9,7 @@ import { WidgetHeightLimits, } from "constants/WidgetConstants"; import { get, omit } from "lodash"; -import type { XYCord } from "layoutSystems/common/CanvasArenas/ArenaTypes"; +import type { XYCord } from "layoutSystems/common/canvasArenas/ArenaTypes"; import React, { memo, useContext, useMemo } from "react"; import { useDispatch, useSelector } from "react-redux"; import { AutoLayoutResizable } from "layoutSystems/autolayout/common/resizer/AutoLayoutResizable"; @@ -47,7 +47,7 @@ import { isAutoHeightEnabledForWidget, isAutoHeightEnabledForWidgetWithLimits, } from "widgets/WidgetUtils"; -import { DropTargetContext } from "../../../components/editorComponents/DropTargetComponent"; +import { DropTargetContext } from "../dropTarget/DropTargetComponent"; import { BottomHandleStyles, BottomLeftHandleStyles, diff --git a/app/client/src/layoutSystems/common/resizer/ResizableUtils.ts b/app/client/src/layoutSystems/common/resizer/ResizableUtils.ts index 86756cea44..202f94fd20 100644 --- a/app/client/src/layoutSystems/common/resizer/ResizableUtils.ts +++ b/app/client/src/layoutSystems/common/resizer/ResizableUtils.ts @@ -1,6 +1,6 @@ import type { WidgetRowCols } from "widgets/BaseWidget"; import { GridDefaults } from "constants/WidgetConstants"; -import type { XYCord } from "layoutSystems/common/CanvasArenas/ArenaTypes"; +import type { XYCord } from "layoutSystems/common/canvasArenas/ArenaTypes"; import { ReflowDirection } from "reflow/reflowTypes"; import { ResponsiveBehavior } from "layoutSystems/common/utils/constants"; diff --git a/app/client/src/layoutSystems/common/utils/ComponentSizeUtils.ts b/app/client/src/layoutSystems/common/utils/ComponentSizeUtils.ts index d87670e82a..4401749a67 100644 --- a/app/client/src/layoutSystems/common/utils/ComponentSizeUtils.ts +++ b/app/client/src/layoutSystems/common/utils/ComponentSizeUtils.ts @@ -110,12 +110,14 @@ export const getComponentDimensions = memo( ( props: BaseWidgetProps, layoutSystemType: LayoutSystemTypes, - isMobile: boolean, + isMobile = false, ): { componentHeight: number; componentWidth: number; } => { switch (layoutSystemType) { + case LayoutSystemTypes.ANVIL: + return getAnvilComponentDimensions(props); case LayoutSystemTypes.AUTO: return getAutoLayoutComponentDimensions({ ...props, isMobile }); default: diff --git a/app/client/src/layoutSystems/common/utils/canvasDraggingUtils.ts b/app/client/src/layoutSystems/common/utils/canvasDraggingUtils.ts index 2d47c2cebd..17f0a4f3f4 100644 --- a/app/client/src/layoutSystems/common/utils/canvasDraggingUtils.ts +++ b/app/client/src/layoutSystems/common/utils/canvasDraggingUtils.ts @@ -22,7 +22,7 @@ import { getDropZoneOffsets, noCollision, } from "utils/WidgetPropsUtils"; -import type { WidgetDraggingBlock, XYCord } from "../CanvasArenas/ArenaTypes"; +import type { WidgetDraggingBlock, XYCord } from "../canvasArenas/ArenaTypes"; /** * Method to get the Direction appropriate to closest edge of the canvas diff --git a/app/client/src/layoutSystems/common/utils/canvasUtils.ts b/app/client/src/layoutSystems/common/utils/canvasUtils.ts new file mode 100644 index 0000000000..7ede536c88 --- /dev/null +++ b/app/client/src/layoutSystems/common/utils/canvasUtils.ts @@ -0,0 +1,79 @@ +import type { RenderModes } from "constants/WidgetConstants"; +import type { AdditionalAutoLayoutProperties } from "layoutSystems/autolayout/canvas/types"; +import type { AdditionalFixedLayoutProperties } from "layoutSystems/fixedlayout/canvas/types"; +import { map } from "lodash"; +import WidgetFactory from "WidgetProvider/factory"; +import type { WidgetProps } from "widgets/BaseWidget"; + +type LayoutSystemProps = + | AdditionalFixedLayoutProperties + | AdditionalAutoLayoutProperties; + +/** + * This utility function renders a child widget based on the widget data passed to it. + * when enhancing a child widget properties + * layoutSystemProps override childWidgetData and defaultWidgetProps, + * childWidgetData override defaultWidgetProps. + * + * @returns + */ +function renderChildWidget({ + childWidgetData, + defaultWidgetProps, + layoutSystemProps, + noPad, + renderMode, + widgetId, +}: { + childWidgetData: WidgetProps; + widgetId: string; + renderMode: RenderModes; + layoutSystemProps: LayoutSystemProps; + defaultWidgetProps: Record; + noPad: boolean; +}): React.ReactNode { + const childWidget = { + ...defaultWidgetProps, + ...childWidgetData, + ...layoutSystemProps, + }; + if (!childWidgetData) return null; + if (noPad) childWidget.noContainerOffset = true; + childWidget.parentId = widgetId; + return WidgetFactory.createWidget(childWidget, renderMode); +} + +/** + * + * @param children - array of props of the children. + * @param widgetId - id of the parent canvas. + * @param renderMode - current render mode. + * @param defaultWidgetProps - default props of the child widget. + * @param layoutSystemProps - props of the layout system. + * @param noPad - if true, noContainerOffset is set to true to the child widget. + * + * children is an array of childWidgetData + * childWidgetData is props of each individual child widget. + * layoutSystemProps override childWidgetData, childWidgetData override defaultWidgetProps. + * + * @returns array of child widgets. + */ +export const renderChildren = ( + children: WidgetProps[], + widgetId: string, + renderMode: RenderModes, + defaultWidgetProps: Partial = {}, + layoutSystemProps: LayoutSystemProps, + noPad = false, +): React.ReactNode[] => { + return map(children, (childWidgetData: WidgetProps) => + renderChildWidget({ + childWidgetData, + layoutSystemProps, + defaultWidgetProps, + noPad, + renderMode, + widgetId, + }), + ); +}; diff --git a/app/client/src/layoutSystems/fixedlayout/canvas/FixedLayoutEditorCanvas.tsx b/app/client/src/layoutSystems/fixedlayout/canvas/FixedLayoutEditorCanvas.tsx new file mode 100644 index 0000000000..025531c9f8 --- /dev/null +++ b/app/client/src/layoutSystems/fixedlayout/canvas/FixedLayoutEditorCanvas.tsx @@ -0,0 +1,119 @@ +import { CANVAS_DEFAULT_MIN_HEIGHT_PX } from "constants/AppConstants"; +import { GridDefaults, RenderModes } from "constants/WidgetConstants"; +import { renderChildren } from "layoutSystems/common/utils/canvasUtils"; +import { CanvasSelectionArena } from "layoutSystems/fixedlayout/editor/FixedLayoutCanvasArenas/CanvasSelectionArena"; +import WidgetsMultiSelectBox from "layoutSystems/fixedlayout/common/widgetGrouping/WidgetsMultiSelectBox"; +import React, { useMemo } from "react"; +import { getSnappedGrid } from "sagas/WidgetOperationUtils"; +import { getCanvasSnapRows } from "utils/WidgetPropsUtils"; +import type { WidgetProps } from "widgets/BaseWidget"; +import type { BaseWidgetProps } from "widgets/BaseWidgetHOC/withBaseWidgetHOC"; +import ContainerComponent from "widgets/ContainerWidget/component"; +import { DropTargetComponentWrapper } from "../../common/dropTarget/DropTargetComponentWrapper"; +import { FixedCanvasDraggingArena } from "../editor/FixedLayoutCanvasArenas/FixedCanvasDraggingArena"; +import { compact, sortBy } from "lodash"; +import { Positioning } from "layoutSystems/common/utils/constants"; +import type { DSLWidget } from "WidgetProvider/constants"; + +export type CanvasProps = DSLWidget; +/** + * This component implements the Canvas for Fixed Layout System in Edit mode. + * This component adds layers like CanvasDraggingArena, CanvasSelectionArena, etc which are responsible for + * drag and drop, selection, etc. + * This component also renders the children of the canvas with additional layout specific properties like + * parentColumnSpace, parentRowSpace, etc. + */ + +export const FixedLayoutEditorCanvas = (props: BaseWidgetProps) => { + const { snapGrid } = getSnappedGrid(props, props.componentWidth); + const { snapColumnSpace } = snapGrid; + const snapRows = getCanvasSnapRows(props.bottomRow); + const fixedLayoutDropTargetProps = useMemo( + () => ({ + bottomRow: props.bottomRow, + isListWidgetCanvas: props.isListWidgetCanvas, + minHeight: props.minHeight || CANVAS_DEFAULT_MIN_HEIGHT_PX, + noPad: props.noPad, + parentId: props.parentId, + snapColumnSpace: snapColumnSpace, + widgetId: props.widgetId, + }), + [ + props.bottomRow, + props.isListWidgetCanvas, + props.minHeight, + props.noPad, + props.parentId, + snapColumnSpace, + props.widgetId, + ], + ); + const layoutSystemProps = { + parentColumnSpace: snapColumnSpace, + parentRowSpace: GridDefaults.DEFAULT_GRID_ROW_HEIGHT, + }; + const defaultWidgetProps: Partial = { + positioning: props.positioning, + }; + // ToDO(#27617): Remove sorting of children on the view, ideally the model should be sorted, coz they are less frequently happening + // operations. leaving it as is for now, coz it multiple cypress tests are dependent on this. + const canvasChildren = useMemo( + () => + renderChildren( + props.positioning !== Positioning.Fixed + ? props.children + : sortBy( + compact(props.children), + (child: WidgetProps) => child.topRow, + ), + props.widgetId, + RenderModes.CANVAS, + defaultWidgetProps, + layoutSystemProps, + !!props.noPad, + ), + [ + props.children, + props.shouldScrollContents, + props.widgetId, + props.componentHeight, + props.componentWidth, + snapColumnSpace, + ], + ); + return ( + + + + + + {canvasChildren} + + + ); +}; diff --git a/app/client/src/layoutSystems/fixedlayout/canvas/FixedLayoutViewerCanvas.tsx b/app/client/src/layoutSystems/fixedlayout/canvas/FixedLayoutViewerCanvas.tsx new file mode 100644 index 0000000000..4957d5d638 --- /dev/null +++ b/app/client/src/layoutSystems/fixedlayout/canvas/FixedLayoutViewerCanvas.tsx @@ -0,0 +1,69 @@ +import { GridDefaults, RenderModes } from "constants/WidgetConstants"; +import { Positioning } from "layoutSystems/common/utils/constants"; +import { CanvasViewerWrapper } from "layoutSystems/common/canvasViewer/CanvasViewerWrapper"; +import { renderChildren } from "layoutSystems/common/utils/canvasUtils"; +import { compact, sortBy } from "lodash"; +import React, { useMemo } from "react"; +import { getSnappedGrid } from "sagas/WidgetOperationUtils"; +import { getCanvasSnapRows } from "utils/WidgetPropsUtils"; +import type { WidgetProps } from "widgets/BaseWidget"; +import type { BaseWidgetProps } from "widgets/BaseWidgetHOC/withBaseWidgetHOC"; +import ContainerComponent from "widgets/ContainerWidget/component"; +import type { ContainerWidgetProps } from "widgets/ContainerWidget/widget"; +import type { AdditionalFixedLayoutProperties } from "./types"; + +export type CanvasProps = ContainerWidgetProps; + +/** + * This component implements the Canvas for Fixed Layout System in View mode. + * This component also renders the children of the canvas with additional layout specific properties like + * parentColumnSpace, parentRowSpace, etc. + */ + +export const FixedLayoutViewerCanvas = (props: BaseWidgetProps) => { + const { snapGrid } = getSnappedGrid(props, props.componentWidth); + const { snapColumnSpace } = snapGrid; + const layoutSystemProps: AdditionalFixedLayoutProperties = { + parentColumnSpace: snapColumnSpace, + parentRowSpace: GridDefaults.DEFAULT_GRID_ROW_HEIGHT, + }; + const defaultWidgetProps: Partial = { + positioning: props.positioning, + }; + + // ToDO(#27617): Remove sorting of children on the view, ideally the model should be sorted, coz they are less frequently happening + // operations. leaving it as is for now, coz it multiple cypress tests are dependent on this. + const canvasChildren = useMemo( + () => + renderChildren( + props.positioning !== Positioning.Fixed + ? props.children + : sortBy( + compact(props.children), + (child: WidgetProps) => child.topRow, + ), + props.widgetId, + RenderModes.PAGE, + defaultWidgetProps, + layoutSystemProps, + !!props.noPad, + ), + [ + props.children, + props.shouldScrollContents, + props.widgetId, + props.componentHeight, + props.componentWidth, + snapColumnSpace, + ], + ); + const snapRows = getCanvasSnapRows(props.bottomRow); + return ( + + {canvasChildren} + + ); +}; diff --git a/app/client/src/layoutSystems/fixedlayout/canvas/types.ts b/app/client/src/layoutSystems/fixedlayout/canvas/types.ts new file mode 100644 index 0000000000..17e014d9a9 --- /dev/null +++ b/app/client/src/layoutSystems/fixedlayout/canvas/types.ts @@ -0,0 +1,4 @@ +export type AdditionalFixedLayoutProperties = { + parentRowSpace: number; + parentColumnSpace: number; +}; diff --git a/app/client/src/layoutSystems/fixedlayout/common/resizer/FixedResizableLayer.tsx b/app/client/src/layoutSystems/fixedlayout/common/resizer/FixedResizableLayer.tsx index 296e5a0220..1bb91a72f6 100644 --- a/app/client/src/layoutSystems/fixedlayout/common/resizer/FixedResizableLayer.tsx +++ b/app/client/src/layoutSystems/fixedlayout/common/resizer/FixedResizableLayer.tsx @@ -1,9 +1,9 @@ import { WIDGET_PADDING } from "constants/WidgetConstants"; -import React from "react"; +import React, { memo } from "react"; import type { BaseWidgetProps } from "widgets/BaseWidgetHOC/withBaseWidgetHOC"; import { ResizableComponent } from "layoutSystems/common/resizer/ResizableComponent"; -export const FixedResizableLayer = (props: BaseWidgetProps) => { +export const FixedResizableLayer = memo((props: BaseWidgetProps) => { if (props.resizeDisabled || props.type === "SKELETON_WIDGET") { return props.children; } @@ -12,4 +12,4 @@ export const FixedResizableLayer = (props: BaseWidgetProps) => { {props.children} ); -}; +}); diff --git a/app/client/src/pages/Editor/WidgetsMultiSelectBox.tsx b/app/client/src/layoutSystems/fixedlayout/common/widgetGrouping/WidgetsMultiSelectBox.tsx similarity index 100% rename from app/client/src/pages/Editor/WidgetsMultiSelectBox.tsx rename to app/client/src/layoutSystems/fixedlayout/common/widgetGrouping/WidgetsMultiSelectBox.tsx diff --git a/app/client/src/layoutSystems/fixedlayout/editor/FixedLayoutCanvasArenas/CanvasSelectionArena.tsx b/app/client/src/layoutSystems/fixedlayout/editor/FixedLayoutCanvasArenas/CanvasSelectionArena.tsx index 1c2f1c2ac9..d1bb667754 100644 --- a/app/client/src/layoutSystems/fixedlayout/editor/FixedLayoutCanvasArenas/CanvasSelectionArena.tsx +++ b/app/client/src/layoutSystems/fixedlayout/editor/FixedLayoutCanvasArenas/CanvasSelectionArena.tsx @@ -27,9 +27,9 @@ import { } from "selectors/editorSelectors"; import { getNearestParentCanvas } from "utils/generators"; import { getAbsolutePixels } from "utils/helpers"; -import type { XYCord } from "layoutSystems/common/CanvasArenas/ArenaTypes"; -import { useCanvasDragToScroll } from "layoutSystems/common/CanvasArenas/useCanvasDragToScroll"; -import { StickyCanvasArena } from "layoutSystems/common/CanvasArenas/StickyCanvasArena"; +import type { XYCord } from "layoutSystems/common/canvasArenas/ArenaTypes"; +import { useCanvasDragToScroll } from "layoutSystems/common/canvasArenas/useCanvasDragToScroll"; +import { StickyCanvasArena } from "layoutSystems/common/canvasArenas/StickyCanvasArena"; export interface SelectedArenaDimensions { top: number; diff --git a/app/client/src/layoutSystems/fixedlayout/editor/FixedLayoutCanvasArenas/FixedCanvasDraggingArena.tsx b/app/client/src/layoutSystems/fixedlayout/editor/FixedLayoutCanvasArenas/FixedCanvasDraggingArena.tsx index f92dfa940f..cdad979901 100644 --- a/app/client/src/layoutSystems/fixedlayout/editor/FixedLayoutCanvasArenas/FixedCanvasDraggingArena.tsx +++ b/app/client/src/layoutSystems/fixedlayout/editor/FixedLayoutCanvasArenas/FixedCanvasDraggingArena.tsx @@ -1,7 +1,7 @@ import type { AppState } from "@appsmith/reducers"; import { theme } from "constants/DefaultTheme"; import { MAIN_CONTAINER_WIDGET_ID } from "constants/WidgetConstants"; -import { StickyCanvasArena } from "layoutSystems/common/CanvasArenas/StickyCanvasArena"; +import { StickyCanvasArena } from "layoutSystems/common/canvasArenas/StickyCanvasArena"; import React from "react"; import { useSelector } from "react-redux"; import { getNearestParentCanvas } from "utils/generators"; diff --git a/app/client/src/layoutSystems/fixedlayout/editor/FixedLayoutCanvasArenas/hooks/useBlocksToBeDraggedOnCanvas.ts b/app/client/src/layoutSystems/fixedlayout/editor/FixedLayoutCanvasArenas/hooks/useBlocksToBeDraggedOnCanvas.ts index bd88e2d3f3..d84d375e4f 100644 --- a/app/client/src/layoutSystems/fixedlayout/editor/FixedLayoutCanvasArenas/hooks/useBlocksToBeDraggedOnCanvas.ts +++ b/app/client/src/layoutSystems/fixedlayout/editor/FixedLayoutCanvasArenas/hooks/useBlocksToBeDraggedOnCanvas.ts @@ -12,7 +12,7 @@ import type { } from "constants/CanvasEditorConstants"; import { getDragDetails, getWidgetByID, getWidgets } from "sagas/selectors"; import { widgetOperationParams } from "utils/WidgetPropsUtils"; -import { DropTargetContext } from "components/editorComponents/DropTargetComponent"; +import { DropTargetContext } from "layoutSystems/common/dropTarget/DropTargetComponent"; import equal from "fast-deep-equal/es6"; import type { FixedCanvasDraggingArenaProps } from "../FixedCanvasDraggingArena"; import { useDispatch, useSelector } from "react-redux"; @@ -30,7 +30,7 @@ import type { WidgetDraggingBlock, WidgetDraggingUpdateParams, XYCord, -} from "../../../../common/CanvasArenas/ArenaTypes"; +} from "../../../../common/canvasArenas/ArenaTypes"; import { getBlocksToDraw, getParentDiff, diff --git a/app/client/src/layoutSystems/fixedlayout/editor/FixedLayoutCanvasArenas/hooks/useCanvasDragging.ts b/app/client/src/layoutSystems/fixedlayout/editor/FixedLayoutCanvasArenas/hooks/useCanvasDragging.ts index 61dec72cdb..620845d60a 100644 --- a/app/client/src/layoutSystems/fixedlayout/editor/FixedLayoutCanvasArenas/hooks/useCanvasDragging.ts +++ b/app/client/src/layoutSystems/fixedlayout/editor/FixedLayoutCanvasArenas/hooks/useCanvasDragging.ts @@ -29,10 +29,10 @@ import { modifyDrawingRectangles, updateRectanglesPostReflow, } from "layoutSystems/common/utils/canvasDraggingUtils"; -import type { WidgetDraggingBlock } from "../../../../common/CanvasArenas/ArenaTypes"; +import type { WidgetDraggingBlock } from "../../../../common/canvasArenas/ArenaTypes"; import { useBlocksToBeDraggedOnCanvas } from "./useBlocksToBeDraggedOnCanvas"; import { useRenderBlocksOnCanvas } from "./useRenderBlocksOnCanvas"; -import { useCanvasDragToScroll } from "layoutSystems/common/CanvasArenas/useCanvasDragToScroll"; +import { useCanvasDragToScroll } from "layoutSystems/common/canvasArenas/useCanvasDragToScroll"; import type { FixedCanvasDraggingArenaProps } from "../FixedCanvasDraggingArena"; /** diff --git a/app/client/src/layoutSystems/fixedlayout/editor/FixedLayoutCanvasArenas/hooks/useRenderBlocksOnCanvas.ts b/app/client/src/layoutSystems/fixedlayout/editor/FixedLayoutCanvasArenas/hooks/useRenderBlocksOnCanvas.ts index 9146a39b30..4bb63a2e9f 100644 --- a/app/client/src/layoutSystems/fixedlayout/editor/FixedLayoutCanvasArenas/hooks/useRenderBlocksOnCanvas.ts +++ b/app/client/src/layoutSystems/fixedlayout/editor/FixedLayoutCanvasArenas/hooks/useRenderBlocksOnCanvas.ts @@ -4,8 +4,8 @@ import { useSelector } from "react-redux"; import type { SpaceMap } from "reflow/reflowTypes"; import { getZoomLevel } from "selectors/editorSelectors"; import { getAbsolutePixels } from "utils/helpers"; -import type { XYCord } from "../../../../common/CanvasArenas/ArenaTypes"; -import type { WidgetDraggingBlock } from "../../../../common/CanvasArenas/ArenaTypes"; +import type { XYCord } from "../../../../common/canvasArenas/ArenaTypes"; +import type { WidgetDraggingBlock } from "../../../../common/canvasArenas/ArenaTypes"; /** * returns a method that renders dragging blocks on canvas diff --git a/app/client/src/layoutSystems/fixedlayout/editor/FixedLayoutEditorWrapper.tsx b/app/client/src/layoutSystems/fixedlayout/editor/FixedLayoutEditorWrapper.tsx index 45ea892cbc..79edd1dd79 100644 --- a/app/client/src/layoutSystems/fixedlayout/editor/FixedLayoutEditorWrapper.tsx +++ b/app/client/src/layoutSystems/fixedlayout/editor/FixedLayoutEditorWrapper.tsx @@ -24,10 +24,6 @@ export const FixedLayoutEditorWrapper = (props: WidgetProps) => { ? FixedLayoutEditorModalOnion : FixedLayoutEditorWidgetOnion; }, [props.type]); - const canvasWidget = props.type === "CANVAS_WIDGET"; - if (canvasWidget) { - return props.children; - } return {props.children}; }; diff --git a/app/client/src/layoutSystems/fixedlayout/index.ts b/app/client/src/layoutSystems/fixedlayout/index.ts index 10d5d18ef5..c4eb173893 100644 --- a/app/client/src/layoutSystems/fixedlayout/index.ts +++ b/app/client/src/layoutSystems/fixedlayout/index.ts @@ -3,10 +3,15 @@ import { FixedLayoutEditorWrapper } from "./editor/FixedLayoutEditorWrapper"; import { FixedLayoutViewerWrapper } from "./viewer/FixedLayoutViewerWrapper"; import type { BaseWidgetProps } from "widgets/BaseWidgetHOC/withBaseWidgetHOC"; import { getFixedLayoutComponentDimensions } from "layoutSystems/common/utils/ComponentSizeUtils"; +import { FixedLayoutEditorCanvas } from "./canvas/FixedLayoutEditorCanvas"; +import type { CanvasProps } from "./canvas/FixedLayoutEditorCanvas"; +import { FixedLayoutViewerCanvas } from "./canvas/FixedLayoutViewerCanvas"; +import { CANVAS_DEFAULT_MIN_HEIGHT_PX } from "constants/AppConstants"; +import type { LayoutSystem } from "layoutSystems/types"; /** * getLabelWidth - * utiltiy function to compute a widgets label width in Fixed layout system + * utility function to compute a widgets label width in Fixed layout system * */ const getLabelWidth = (props: BaseWidgetProps) => { @@ -19,7 +24,7 @@ const getLabelWidth = (props: BaseWidgetProps) => { * utility function to enhance BaseWidgetProps with Fixed Layout system specific props * */ -const getFixedLayoutSystemPropsEnhancer = (props: BaseWidgetProps) => { +const getFixedLayoutSystemWidgetPropsEnhancer = (props: BaseWidgetProps) => { const { componentHeight, componentWidth } = getFixedLayoutComponentDimensions(props); const labelComponentWidth = getLabelWidth(props); @@ -32,6 +37,42 @@ const getFixedLayoutSystemPropsEnhancer = (props: BaseWidgetProps) => { }; }; +const defaultFixedCanvasProps: Partial = { + parentRowSpace: 1, + parentColumnSpace: 1, + topRow: 0, + leftColumn: 0, + containerStyle: "none", + detachFromLayout: true, + shouldScrollContents: false, +}; + +/** + * getFixedLayoutSystemCanvasPropsEnhancer + * + * utility function to enhance BaseWidgetProps of canvas with Auto Layout system specific props + * + * @returns EnhancedBaseWidgetProps + * @property {number} componentHeight The calculated height of a widget in pixels. + * @property {number} componentWidth The calculated width of a widget in pixels. + * + */ + +const getFixedLayoutSystemCanvasPropsEnhancer = (props: BaseWidgetProps) => { + const enhancedProps = { + minHeight: CANVAS_DEFAULT_MIN_HEIGHT_PX, + ...props, + ...defaultFixedCanvasProps, + }; + const { componentHeight, componentWidth } = + getFixedLayoutComponentDimensions(enhancedProps); + return { + ...enhancedProps, + componentHeight, + componentWidth, + }; +}; + /** * getFixedLayoutSystemWrapper * @@ -47,16 +88,41 @@ const getFixedLayoutSystemWrapper = (renderMode: RenderModes) => { } }; +/** + * + * utility function to return the fixed layout system canvas implementation based on render mode. + * + * @returns current render mode specific canvas component. + */ + +function getFixedLayoutSystemCanvasWrapper(renderMode: RenderModes) { + if (renderMode === RenderModes.CANVAS) { + return FixedLayoutEditorCanvas; + } else { + return FixedLayoutViewerCanvas; + } +} + /** * getFixedLayoutSystem * * utility function to return the fixed layout system config for * wrapper based on render mode and property enhancer function * + * @returns + * @property widgetSystem - widget specific wrappers and enhancers of a layout system + * @property canvasSystem - canvas specific implementation and enhancers of a layout system */ -export function getFixedLayoutSystem(renderMode: RenderModes) { + +export function getFixedLayoutSystem(renderMode: RenderModes): LayoutSystem { return { - LayoutSystemWrapper: getFixedLayoutSystemWrapper(renderMode), - propertyEnhancer: getFixedLayoutSystemPropsEnhancer, + widgetSystem: { + WidgetWrapper: getFixedLayoutSystemWrapper(renderMode), + propertyEnhancer: getFixedLayoutSystemWidgetPropsEnhancer, + }, + canvasSystem: { + Canvas: getFixedLayoutSystemCanvasWrapper(renderMode) as any, + propertyEnhancer: getFixedLayoutSystemCanvasPropsEnhancer, + }, }; } diff --git a/app/client/src/layoutSystems/fixedlayout/viewer/FixedLayoutViewerWrapper.tsx b/app/client/src/layoutSystems/fixedlayout/viewer/FixedLayoutViewerWrapper.tsx index 541e27f7ff..78362cb3f6 100644 --- a/app/client/src/layoutSystems/fixedlayout/viewer/FixedLayoutViewerWrapper.tsx +++ b/app/client/src/layoutSystems/fixedlayout/viewer/FixedLayoutViewerWrapper.tsx @@ -24,9 +24,5 @@ export const FixedLayoutViewerWrapper = (props: WidgetProps) => { ? FixedLayoutViewerModalOnion : FixedLayoutViewerWidgetOnion; }, [props.type]); - const canvasWidget = props.type === "CANVAS_WIDGET"; - if (canvasWidget) { - return props.children; - } return {props.children}; }; diff --git a/app/client/src/layoutSystems/types/index.ts b/app/client/src/layoutSystems/types/index.ts index c077f834bc..916d541d14 100644 --- a/app/client/src/layoutSystems/types/index.ts +++ b/app/client/src/layoutSystems/types/index.ts @@ -1,3 +1,5 @@ +import type { WidgetProps } from "widgets/BaseWidget"; + // Layout system types that Appsmith provides export enum LayoutSystemTypes { FIXED = "FIXED", @@ -8,6 +10,48 @@ export enum LayoutSystemTypes { // interface for appPositioning(aka layoutStystem) details. // It is part of applicationDetails Record of an Application // Refer to ApplicationPayload -export interface LayoutSystemTypeConfig { +export type LayoutSystemTypeConfig = { type: LayoutSystemTypes; -} +}; + +/** + * @type WidgetLayoutSystem + * + * type to define the structure of widget based entities on a specific layout system. + * + * @property WidgetWrapper - component that wraps around a widget + * @property propertyEnhancer - function that is used to enhance/modify widget properties as per the layout system + */ + +export type WidgetLayoutSystem = { + WidgetWrapper: (props: WidgetProps) => JSX.Element; + propertyEnhancer: (props: WidgetProps) => WidgetProps; +}; + +/** + * @type CanvasLayoutSystem + * + * type to define the structure of canvas based entities on a specific layout system. + * @property Canvas - component that renders/positions children as per the layout system. + * @property propertyEnhancer - function that is used to enhance/modify canvas properties as per the layout system + */ + +export type CanvasLayoutSystem = { + Canvas: (props: WidgetProps) => JSX.Element; + propertyEnhancer: (props: WidgetProps) => WidgetProps; +}; + +/** + * @type LayoutSystem + * + * Layout System is the high level system that provides set of wrappers/implementations needed for widgets to function and + * render on both Editor and Viewer of Appsmith. + * + * @property widgetSystem - provides widget specific entities + * @property canvasSystem - provides canvas specific entities + */ + +export type LayoutSystem = { + widgetSystem: WidgetLayoutSystem; + canvasSystem: CanvasLayoutSystem; +}; diff --git a/app/client/src/layoutSystems/withLayoutSystemHOC.test.tsx b/app/client/src/layoutSystems/withLayoutSystemHOC.test.tsx deleted file mode 100644 index 8dea0d4cf1..0000000000 --- a/app/client/src/layoutSystems/withLayoutSystemHOC.test.tsx +++ /dev/null @@ -1,370 +0,0 @@ -import { RenderModes } from "constants/WidgetConstants"; -import React from "react"; -import { LayoutSystemTypes } from "layoutSystems/types"; -import * as editorSelectors from "selectors/editorSelectors"; -import * as layoutSystemSelectors from "selectors/layoutSystemSelectors"; -import { WidgetTypeFactories } from "test/factories/Widgets/WidgetTypeFactories"; -import { render } from "test/testUtils"; -import CanvasWidget from "widgets/CanvasWidget"; -import InputWidget from "widgets/InputWidgetV2/widget"; -import { ModalWidget } from "widgets/ModalWidget/widget"; -import { withLayoutSystemHOC } from "./withLayoutSystemHOC"; - -describe("Layout System HOC's Tests", () => { - describe("Fixed Layout Layers", () => { - it("Layout system hoc should return Fixed Editor for FIXED positioning and CANVAS render mode", () => { - const widget = InputWidget; - const HOC = withLayoutSystemHOC(widget); - const widgetProps = WidgetTypeFactories[InputWidget.type].build(); - jest - .spyOn(editorSelectors, "getRenderMode") - .mockImplementation(() => RenderModes.CANVAS); - jest - .spyOn(layoutSystemSelectors, "getLayoutSystemType") - .mockImplementation(() => LayoutSystemTypes.FIXED); - const component = render(); - const positionedLayer = - component.container.getElementsByClassName("positioned-widget")[0]; - const resizerLayer = - component.container.getElementsByClassName("resize-wrapper")[0]; - expect(positionedLayer).toBeTruthy(); - expect(resizerLayer).toBeTruthy(); - }); - it("Layout system hoc should return Fixed Modal Editor for FIXED positioning and CANVAS render mode", () => { - const widget = ModalWidget; - const HOC = withLayoutSystemHOC(widget); - const widgetProps = WidgetTypeFactories[ModalWidget.type].build({ - isVisible: true, - }); - jest - .spyOn(editorSelectors, "getRenderMode") - .mockImplementation(() => RenderModes.CANVAS); - jest - .spyOn(layoutSystemSelectors, "getLayoutSystemType") - .mockImplementation(() => LayoutSystemTypes.FIXED); - const component = render(); - const positionedLayer = - component.container.getElementsByClassName("positioned-widget")[0]; - const resizerLayer = - component.container.getElementsByClassName("resize-wrapper")[0]; - const overlayLayer = - component.container.getElementsByClassName("bp3-overlay")[0]; - expect(positionedLayer).toBeFalsy(); - expect(overlayLayer).toBeTruthy(); - expect(resizerLayer).toBeTruthy(); - }); - it("Layout system hoc should return no wrapper for CANVAS WIDGET for FIXED positioning and CANVAS render mode", () => { - const widget = CanvasWidget; - const HOC = withLayoutSystemHOC(widget); - const widgetProps = WidgetTypeFactories[CanvasWidget.type].build(); - jest - .spyOn(editorSelectors, "getRenderMode") - .mockImplementation(() => RenderModes.CANVAS); - jest - .spyOn(layoutSystemSelectors, "getLayoutSystemType") - .mockImplementation(() => LayoutSystemTypes.FIXED); - const component = render(); - const positionedLayer = - component.container.getElementsByClassName("positioned-widget")[0]; - const resizerLayer = - component.container.getElementsByClassName("resize-wrapper")[0]; - expect(positionedLayer).toBeFalsy(); - expect(resizerLayer).toBeFalsy(); - }); - it("Layout system hoc should return Fixed Modal Viewer for FIXED positioning and PAGE render mode", () => { - const widget = ModalWidget; - const HOC = withLayoutSystemHOC(widget); - const widgetProps = WidgetTypeFactories[ModalWidget.type].build({ - isVisible: true, - }); - jest - .spyOn(editorSelectors, "getRenderMode") - .mockImplementation(() => RenderModes.PAGE); - jest - .spyOn(layoutSystemSelectors, "getLayoutSystemType") - .mockImplementation(() => LayoutSystemTypes.FIXED); - const component = render(); - const positionedLayer = - component.container.getElementsByClassName("positioned-widget")[0]; - const resizerLayer = - component.container.getElementsByClassName("resize-wrapper")[0]; - const overlayLayer = - component.container.getElementsByClassName("bp3-overlay")[0]; - expect(positionedLayer).toBeFalsy(); - expect(overlayLayer).toBeTruthy(); - expect(resizerLayer).toBeFalsy(); - }); - it("Layout system hoc should return Fixed Viewer for FIXED positioning and PAGE render mode", () => { - const widget = InputWidget; - const HOC = withLayoutSystemHOC(widget); - const widgetProps = WidgetTypeFactories[InputWidget.type].build(); - jest - .spyOn(editorSelectors, "getRenderMode") - .mockImplementation(() => RenderModes.PAGE); - jest - .spyOn(layoutSystemSelectors, "getLayoutSystemType") - .mockImplementation(() => LayoutSystemTypes.FIXED); - const component = render(); - const positionedLayer = - component.container.getElementsByClassName("positioned-widget")[0]; - const resizerLayer = - component.container.getElementsByClassName("resize-wrapper")[0]; - expect(positionedLayer).toBeTruthy(); - expect(resizerLayer).toBeFalsy(); - }); - - it("Layout system hoc should return no wrapper for CANVAS WIDGET for FIXED positioning and PAGE render mode", () => { - const widget = CanvasWidget; - const HOC = withLayoutSystemHOC(widget); - const widgetProps = WidgetTypeFactories[CanvasWidget.type].build(); - jest - .spyOn(editorSelectors, "getRenderMode") - .mockImplementation(() => RenderModes.PAGE); - jest - .spyOn(layoutSystemSelectors, "getLayoutSystemType") - .mockImplementation(() => LayoutSystemTypes.FIXED); - const component = render(); - const positionedLayer = - component.container.getElementsByClassName("positioned-widget")[0]; - const resizerLayer = - component.container.getElementsByClassName("resize-wrapper")[0]; - expect(positionedLayer).toBeFalsy(); - expect(resizerLayer).toBeFalsy(); - }); - }); - describe("Auto Layout Layers", () => { - it("Layout system hoc should return Auto Layout Editor for AUTO positioning and CANVAS render mode", () => { - const widget = InputWidget; - const HOC = withLayoutSystemHOC(widget); - const widgetProps = WidgetTypeFactories[InputWidget.type].build(); - jest - .spyOn(editorSelectors, "getRenderMode") - .mockImplementation(() => RenderModes.CANVAS); - jest - .spyOn(layoutSystemSelectors, "getLayoutSystemType") - .mockImplementation(() => LayoutSystemTypes.AUTO); - const component = render(); - const flexPositionedLayer = component.container.getElementsByClassName( - "auto-layout-child-" + widgetProps.widgetId, - )[0]; - const resizerLayer = - component.container.getElementsByClassName("resize-wrapper")[0]; - expect(flexPositionedLayer).toBeTruthy(); - expect(resizerLayer).toBeTruthy(); - }); - it("Layout system hoc should return Auto Modal Editor for AUTO positioning and CANVAS render mode", () => { - const widget = ModalWidget; - const HOC = withLayoutSystemHOC(widget); - const widgetProps = WidgetTypeFactories[ModalWidget.type].build({ - isVisible: true, - }); - jest - .spyOn(editorSelectors, "getRenderMode") - .mockImplementation(() => RenderModes.CANVAS); - jest - .spyOn(layoutSystemSelectors, "getLayoutSystemType") - .mockImplementation(() => LayoutSystemTypes.AUTO); - const component = render(); - const flexPositionedLayer = component.container.getElementsByClassName( - "auto-layout-child-" + widgetProps.widgetId, - )[0]; - const resizerLayer = - component.container.getElementsByClassName("resize-wrapper")[0]; - const overlayLayer = - component.container.getElementsByClassName("bp3-overlay")[0]; - expect(flexPositionedLayer).toBeFalsy(); - expect(overlayLayer).toBeTruthy(); - expect(resizerLayer).toBeTruthy(); - }); - it("Layout system hoc should return no wrapper for CANVAS WIDGET for AUTO positioning and CANVAS render mode", () => { - const widget = CanvasWidget; - const HOC = withLayoutSystemHOC(widget); - const widgetProps = WidgetTypeFactories[CanvasWidget.type].build(); - jest - .spyOn(editorSelectors, "getRenderMode") - .mockImplementation(() => RenderModes.CANVAS); - jest - .spyOn(layoutSystemSelectors, "getLayoutSystemType") - .mockImplementation(() => LayoutSystemTypes.AUTO); - const component = render(); - const flexPositionedLayer = component.container.getElementsByClassName( - "auto-layout-child-" + widgetProps.widgetId, - )[0]; - const resizerLayer = - component.container.getElementsByClassName("resize-wrapper")[0]; - expect(flexPositionedLayer).toBeFalsy(); - expect(resizerLayer).toBeFalsy(); - }); - it("Layout system hoc should return Auto Modal Viewer for AUTO positioning and PAGE render mode", () => { - const widget = ModalWidget; - const HOC = withLayoutSystemHOC(widget); - const widgetProps = WidgetTypeFactories[ModalWidget.type].build({ - isVisible: true, - }); - jest - .spyOn(editorSelectors, "getRenderMode") - .mockImplementation(() => RenderModes.PAGE); - jest - .spyOn(layoutSystemSelectors, "getLayoutSystemType") - .mockImplementation(() => LayoutSystemTypes.AUTO); - const component = render(); - const flexPositionedLayer = component.container.getElementsByClassName( - "auto-layout-child-" + widgetProps.widgetId, - )[0]; - const resizerLayer = - component.container.getElementsByClassName("resize-wrapper")[0]; - const overlayLayer = - component.container.getElementsByClassName("bp3-overlay")[0]; - expect(flexPositionedLayer).toBeFalsy(); - expect(overlayLayer).toBeTruthy(); - expect(resizerLayer).toBeFalsy(); - }); - it("Layout system hoc should return Auto Viewer for Auto positioning and PAGE render mode", () => { - const widget = InputWidget; - const HOC = withLayoutSystemHOC(widget); - const widgetProps = WidgetTypeFactories[InputWidget.type].build(); - jest - .spyOn(editorSelectors, "getRenderMode") - .mockImplementation(() => RenderModes.PAGE); - jest - .spyOn(layoutSystemSelectors, "getLayoutSystemType") - .mockImplementation(() => LayoutSystemTypes.AUTO); - const component = render(); - const flexPositionedLayer = component.container.getElementsByClassName( - "auto-layout-child-" + widgetProps.widgetId, - )[0]; - const resizerLayer = - component.container.getElementsByClassName("resize-wrapper")[0]; - expect(flexPositionedLayer).toBeTruthy(); - expect(resizerLayer).toBeFalsy(); - }); - - it("Layout system hoc should return no wrapper for CANVAS WIDGET for Auto positioning and PAGE render mode", () => { - const widget = CanvasWidget; - const HOC = withLayoutSystemHOC(widget); - const widgetProps = WidgetTypeFactories[CanvasWidget.type].build(); - jest - .spyOn(editorSelectors, "getRenderMode") - .mockImplementation(() => RenderModes.PAGE); - jest - .spyOn(layoutSystemSelectors, "getLayoutSystemType") - .mockImplementation(() => LayoutSystemTypes.AUTO); - const component = render(); - const flexPositionedLayer = component.container.getElementsByClassName( - "auto-layout-child-" + widgetProps.widgetId, - )[0]; - const resizerLayer = - component.container.getElementsByClassName("resize-wrapper")[0]; - expect(flexPositionedLayer).toBeFalsy(); - expect(resizerLayer).toBeFalsy(); - }); - }); - describe("Anvil Layers", () => { - it("Layout system hoc should return Anvil Editor for ANVIL positioning and CANVAS render mode", () => { - const widget = InputWidget; - const HOC = withLayoutSystemHOC(widget); - const widgetProps = WidgetTypeFactories[InputWidget.type].build(); - jest - .spyOn(editorSelectors, "getRenderMode") - .mockImplementation(() => RenderModes.CANVAS); - jest - .spyOn(layoutSystemSelectors, "getLayoutSystemType") - .mockImplementation(() => LayoutSystemTypes.ANVIL); - const component = render(); - const flexPositionedLayer = component.container.getElementsByClassName( - "anvil-layout-child-" + widgetProps.widgetId, - )[0]; - expect(flexPositionedLayer).toBeTruthy(); - }); - it("should return Auto Modal Editor for ANVIL positioning and CANVAS render mode", () => { - const widget = ModalWidget; - const HOC = withLayoutSystemHOC(widget); - const widgetProps = WidgetTypeFactories[ModalWidget.type].build({ - isVisible: true, - }); - jest - .spyOn(editorSelectors, "getRenderMode") - .mockImplementation(() => RenderModes.CANVAS); - jest - .spyOn(layoutSystemSelectors, "getLayoutSystemType") - .mockImplementation(() => LayoutSystemTypes.ANVIL); - const component = render(); - const flexPositionedLayer = component.container.getElementsByClassName( - "anvil-layout-child-" + widgetProps.widgetId, - )[0]; - const overlayLayer = - component.container.getElementsByClassName("bp3-overlay")[0]; - expect(flexPositionedLayer).toBeFalsy(); - expect(overlayLayer).toBeTruthy(); - }); - it("should return no wrapper for CANVAS WIDGET for ANVIL positioning and CANVAS render mode", () => { - const widget = CanvasWidget; - const HOC = withLayoutSystemHOC(widget); - const widgetProps = WidgetTypeFactories[CanvasWidget.type].build(); - jest - .spyOn(editorSelectors, "getRenderMode") - .mockImplementation(() => RenderModes.CANVAS); - jest - .spyOn(layoutSystemSelectors, "getLayoutSystemType") - .mockImplementation(() => LayoutSystemTypes.ANVIL); - const component = render(); - const flexPositionedLayer = component.container.getElementsByClassName( - "anvil-layout-child-" + widgetProps.widgetId, - )[0]; - expect(flexPositionedLayer).toBeFalsy(); - }); - it("should return Auto Modal Viewer for ANVIL positioning and PAGE render mode", () => { - const widget = ModalWidget; - const HOC = withLayoutSystemHOC(widget); - const widgetProps = WidgetTypeFactories[ModalWidget.type].build({ - isVisible: true, - }); - jest - .spyOn(editorSelectors, "getRenderMode") - .mockImplementation(() => RenderModes.PAGE); - jest - .spyOn(layoutSystemSelectors, "getLayoutSystemType") - .mockImplementation(() => LayoutSystemTypes.ANVIL); - const component = render(); - const flexPositionedLayer = component.container.getElementsByClassName( - "anvil-layout-child-" + widgetProps.widgetId, - )[0]; - const overlayLayer = - component.container.getElementsByClassName("bp3-overlay")[0]; - expect(flexPositionedLayer).toBeFalsy(); - expect(overlayLayer).toBeTruthy(); - }); - it("should return Anvil Viewer for ANVIL positioning and PAGE render mode", () => { - const widget = InputWidget; - const HOC = withLayoutSystemHOC(widget); - const widgetProps = WidgetTypeFactories[InputWidget.type].build(); - jest - .spyOn(editorSelectors, "getRenderMode") - .mockImplementation(() => RenderModes.PAGE); - jest - .spyOn(layoutSystemSelectors, "getLayoutSystemType") - .mockImplementation(() => LayoutSystemTypes.ANVIL); - const component = render(); - const flexPositionedLayer = component.container.getElementsByClassName( - "anvil-layout-child-" + widgetProps.widgetId, - )[0]; - expect(flexPositionedLayer).toBeTruthy(); - }); - it("should return no wrapper for CANVAS WIDGET for ANVIL positioning and PAGE render mode", () => { - const widget = CanvasWidget; - const HOC = withLayoutSystemHOC(widget); - const widgetProps = WidgetTypeFactories[CanvasWidget.type].build(); - jest - .spyOn(editorSelectors, "getRenderMode") - .mockImplementation(() => RenderModes.PAGE); - jest - .spyOn(layoutSystemSelectors, "getLayoutSystemType") - .mockImplementation(() => LayoutSystemTypes.ANVIL); - const component = render(); - const flexPositionedLayer = component.container.getElementsByClassName( - "anvil-layout-child-" + widgetProps.widgetId, - )[0]; - expect(flexPositionedLayer).toBeFalsy(); - }); - }); -}); diff --git a/app/client/src/layoutSystems/withLayoutSystemWidgetHOC.test.tsx b/app/client/src/layoutSystems/withLayoutSystemWidgetHOC.test.tsx new file mode 100644 index 0000000000..e7d503d530 --- /dev/null +++ b/app/client/src/layoutSystems/withLayoutSystemWidgetHOC.test.tsx @@ -0,0 +1,261 @@ +import { RenderModes } from "constants/WidgetConstants"; +import React from "react"; +import * as editorSelectors from "selectors/editorSelectors"; +import { WidgetTypeFactories } from "test/factories/Widgets/WidgetTypeFactories"; +import { render } from "test/testUtils"; +import InputWidget from "widgets/InputWidgetV2/widget"; +import { ModalWidget } from "widgets/ModalWidget/widget"; +import { withLayoutSystemWidgetHOC } from "./withLayoutSystemWidgetHOC"; +import { LayoutSystemTypes } from "./types"; +import * as layoutSystemSelectors from "selectors/layoutSystemSelectors"; + +describe("Layout System HOC's Tests", () => { + describe("Fixed Layout Layers", () => { + it("Layout system hoc should return Fixed Editor for FIXED positioning and CANVAS render mode", () => { + const widget = InputWidget; + const HOC = withLayoutSystemWidgetHOC(widget); + const widgetProps = WidgetTypeFactories[InputWidget.type].build(); + jest + .spyOn(editorSelectors, "getRenderMode") + .mockImplementation(() => RenderModes.CANVAS); + jest + .spyOn(layoutSystemSelectors, "getLayoutSystemType") + .mockImplementation(() => LayoutSystemTypes.FIXED); + const component = render(); + const positionedLayer = + component.container.getElementsByClassName("positioned-widget")[0]; + const resizerLayer = + component.container.getElementsByClassName("resize-wrapper")[0]; + expect(positionedLayer).toBeTruthy(); + expect(resizerLayer).toBeTruthy(); + }); + it("Layout system hoc should return Fixed Modal Editor for FIXED positioning and CANVAS render mode", () => { + const widget = ModalWidget; + const HOC = withLayoutSystemWidgetHOC(widget); + const widgetProps = WidgetTypeFactories[ModalWidget.type].build({ + isVisible: true, + }); + jest + .spyOn(editorSelectors, "getRenderMode") + .mockImplementation(() => RenderModes.CANVAS); + jest + .spyOn(layoutSystemSelectors, "getLayoutSystemType") + .mockImplementation(() => LayoutSystemTypes.FIXED); + const component = render(); + const positionedLayer = + component.container.getElementsByClassName("positioned-widget")[0]; + const resizerLayer = + component.container.getElementsByClassName("resize-wrapper")[0]; + const overlayLayer = + component.container.getElementsByClassName("bp3-overlay")[0]; + expect(positionedLayer).toBeFalsy(); + expect(overlayLayer).toBeTruthy(); + expect(resizerLayer).toBeTruthy(); + }); + it("Layout system hoc should return Fixed Modal Viewer for FIXED positioning and PAGE render mode", () => { + const widget = ModalWidget; + const HOC = withLayoutSystemWidgetHOC(widget); + const widgetProps = WidgetTypeFactories[ModalWidget.type].build({ + isVisible: true, + }); + jest + .spyOn(editorSelectors, "getRenderMode") + .mockImplementation(() => RenderModes.PAGE); + jest + .spyOn(layoutSystemSelectors, "getLayoutSystemType") + .mockImplementation(() => LayoutSystemTypes.FIXED); + const component = render(); + const positionedLayer = + component.container.getElementsByClassName("positioned-widget")[0]; + const resizerLayer = + component.container.getElementsByClassName("resize-wrapper")[0]; + const overlayLayer = + component.container.getElementsByClassName("bp3-overlay")[0]; + expect(positionedLayer).toBeFalsy(); + expect(overlayLayer).toBeTruthy(); + expect(resizerLayer).toBeFalsy(); + }); + it("Layout system hoc should return Fixed Viewer for FIXED positioning and PAGE render mode", () => { + const widget = InputWidget; + const HOC = withLayoutSystemWidgetHOC(widget); + const widgetProps = WidgetTypeFactories[InputWidget.type].build(); + jest + .spyOn(editorSelectors, "getRenderMode") + .mockImplementation(() => RenderModes.PAGE); + jest + .spyOn(layoutSystemSelectors, "getLayoutSystemType") + .mockImplementation(() => LayoutSystemTypes.FIXED); + const component = render(); + const positionedLayer = + component.container.getElementsByClassName("positioned-widget")[0]; + const resizerLayer = + component.container.getElementsByClassName("resize-wrapper")[0]; + expect(positionedLayer).toBeTruthy(); + expect(resizerLayer).toBeFalsy(); + }); + }); + describe("Auto Layout Layers", () => { + it("Layout system hoc should return Auto Layout Editor for AUTO positioning and CANVAS render mode", () => { + const widget = InputWidget; + const HOC = withLayoutSystemWidgetHOC(widget); + const widgetProps = WidgetTypeFactories[InputWidget.type].build(); + jest + .spyOn(editorSelectors, "getRenderMode") + .mockImplementation(() => RenderModes.CANVAS); + jest + .spyOn(layoutSystemSelectors, "getLayoutSystemType") + .mockImplementation(() => LayoutSystemTypes.AUTO); + const component = render(); + const flexPositionedLayer = component.container.getElementsByClassName( + "auto-layout-child-" + widgetProps.widgetId, + )[0]; + const resizerLayer = + component.container.getElementsByClassName("resize-wrapper")[0]; + expect(flexPositionedLayer).toBeTruthy(); + expect(resizerLayer).toBeTruthy(); + }); + it("Layout system hoc should return Auto Modal Editor for AUTO positioning and CANVAS render mode", () => { + const widget = ModalWidget; + const HOC = withLayoutSystemWidgetHOC(widget); + const widgetProps = WidgetTypeFactories[ModalWidget.type].build({ + isVisible: true, + }); + jest + .spyOn(editorSelectors, "getRenderMode") + .mockImplementation(() => RenderModes.CANVAS); + jest + .spyOn(layoutSystemSelectors, "getLayoutSystemType") + .mockImplementation(() => LayoutSystemTypes.AUTO); + const component = render(); + const flexPositionedLayer = component.container.getElementsByClassName( + "auto-layout-child-" + widgetProps.widgetId, + )[0]; + const resizerLayer = + component.container.getElementsByClassName("resize-wrapper")[0]; + const overlayLayer = + component.container.getElementsByClassName("bp3-overlay")[0]; + expect(flexPositionedLayer).toBeFalsy(); + expect(overlayLayer).toBeTruthy(); + expect(resizerLayer).toBeTruthy(); + }); + it("Layout system hoc should return Auto Modal Viewer for AUTO positioning and PAGE render mode", () => { + const widget = ModalWidget; + const HOC = withLayoutSystemWidgetHOC(widget); + const widgetProps = WidgetTypeFactories[ModalWidget.type].build({ + isVisible: true, + }); + jest + .spyOn(editorSelectors, "getRenderMode") + .mockImplementation(() => RenderModes.PAGE); + jest + .spyOn(layoutSystemSelectors, "getLayoutSystemType") + .mockImplementation(() => LayoutSystemTypes.AUTO); + const component = render(); + const flexPositionedLayer = component.container.getElementsByClassName( + "auto-layout-child-" + widgetProps.widgetId, + )[0]; + const resizerLayer = + component.container.getElementsByClassName("resize-wrapper")[0]; + const overlayLayer = + component.container.getElementsByClassName("bp3-overlay")[0]; + expect(flexPositionedLayer).toBeFalsy(); + expect(overlayLayer).toBeTruthy(); + expect(resizerLayer).toBeFalsy(); + }); + it("Layout system hoc should return Auto Viewer for Auto positioning and PAGE render mode", () => { + const widget = InputWidget; + const HOC = withLayoutSystemWidgetHOC(widget); + const widgetProps = WidgetTypeFactories[InputWidget.type].build(); + jest + .spyOn(editorSelectors, "getRenderMode") + .mockImplementation(() => RenderModes.PAGE); + jest + .spyOn(layoutSystemSelectors, "getLayoutSystemType") + .mockImplementation(() => LayoutSystemTypes.AUTO); + const component = render(); + const flexPositionedLayer = component.container.getElementsByClassName( + "auto-layout-child-" + widgetProps.widgetId, + )[0]; + const resizerLayer = + component.container.getElementsByClassName("resize-wrapper")[0]; + expect(flexPositionedLayer).toBeTruthy(); + expect(resizerLayer).toBeFalsy(); + }); + }); + // describe("Anvil Layout Layers", () => { + // it("Layout system hoc should return Anvil Editor for ANVIL positioning and CANVAS render mode", () => { + // const widget = InputWidget; + // const HOC = withLayoutSystemWidgetHOC(widget); + // const widgetProps = WidgetTypeFactories[InputWidget.type].build(); + // jest + // .spyOn(editorSelectors, "getRenderMode") + // .mockImplementation(() => RenderModes.CANVAS); + // jest + // .spyOn(layoutSystemSelectors, "getLayoutSystemType") + // .mockImplementation(() => LayoutSystemTypes.ANVIL); + // const component = render(); + // const flexPositionedLayer = component.container.getElementsByClassName( + // "anvil-layout-child-" + widgetProps.widgetId, + // )[0]; + // expect(flexPositionedLayer).toBeTruthy(); + // }); + // it("should return Auto Modal Editor for ANVIL positioning and CANVAS render mode", () => { + // const widget = ModalWidget; + // const HOC = withLayoutSystemWidgetHOC(widget); + // const widgetProps = WidgetTypeFactories[ModalWidget.type].build({ + // isVisible: true, + // }); + // jest + // .spyOn(editorSelectors, "getRenderMode") + // .mockImplementation(() => RenderModes.CANVAS); + // jest + // .spyOn(layoutSystemSelectors, "getLayoutSystemType") + // .mockImplementation(() => LayoutSystemTypes.ANVIL); + // const component = render(); + // const flexPositionedLayer = component.container.getElementsByClassName( + // "anvil-layout-child-" + widgetProps.widgetId, + // )[0]; + // const overlayLayer = + // component.container.getElementsByClassName("bp3-overlay")[0]; + // expect(flexPositionedLayer).toBeFalsy(); + // expect(overlayLayer).toBeTruthy(); + // }); + // it("should return Auto Modal Viewer for ANVIL positioning and PAGE render mode", () => { + // const widget = ModalWidget; + // const HOC = withLayoutSystemWidgetHOC(widget); + // const widgetProps = WidgetTypeFactories[ModalWidget.type].build({ + // isVisible: true, + // }); + // jest + // .spyOn(editorSelectors, "getRenderMode") + // .mockImplementation(() => RenderModes.PAGE); + // jest + // .spyOn(layoutSystemSelectors, "getLayoutSystemType") + // .mockImplementation(() => LayoutSystemTypes.ANVIL); + // const component = render(); + // const flexPositionedLayer = component.container.getElementsByClassName( + // "anvil-layout-child-" + widgetProps.widgetId, + // )[0]; + // const overlayLayer = + // component.container.getElementsByClassName("bp3-overlay")[0]; + // expect(flexPositionedLayer).toBeFalsy(); + // expect(overlayLayer).toBeTruthy(); + // }); + // it("should return Anvil Viewer for ANVIL positioning and PAGE render mode", () => { + // const widget = InputWidget; + // const HOC = withLayoutSystemWidgetHOC(widget); + // const widgetProps = WidgetTypeFactories[InputWidget.type].build(); + // jest + // .spyOn(editorSelectors, "getRenderMode") + // .mockImplementation(() => RenderModes.PAGE); + // jest + // .spyOn(layoutSystemSelectors, "getLayoutSystemType") + // .mockImplementation(() => LayoutSystemTypes.ANVIL); + // const component = render(); + // const flexPositionedLayer = component.container.getElementsByClassName( + // "anvil-layout-child-" + widgetProps.widgetId, + // )[0]; + // expect(flexPositionedLayer).toBeTruthy(); + // }); + // }); +}); diff --git a/app/client/src/layoutSystems/withLayoutSystemHOC.tsx b/app/client/src/layoutSystems/withLayoutSystemWidgetHOC.tsx similarity index 59% rename from app/client/src/layoutSystems/withLayoutSystemHOC.tsx rename to app/client/src/layoutSystems/withLayoutSystemWidgetHOC.tsx index 23f486e6e1..5d569541f7 100644 --- a/app/client/src/layoutSystems/withLayoutSystemHOC.tsx +++ b/app/client/src/layoutSystems/withLayoutSystemWidgetHOC.tsx @@ -6,21 +6,27 @@ import { getLayoutSystemType } from "selectors/layoutSystemSelectors"; import type { WidgetProps } from "widgets/BaseWidget"; import { getAutoLayoutSystem } from "./autolayout"; import { getFixedLayoutSystem } from "./fixedlayout"; +import type { LayoutSystem } from "./types"; import { LayoutSystemTypes } from "./types"; -import { getAnvilSystem } from "./anvil"; -export type LayoutSystem = { - LayoutSystemWrapper: (props: WidgetProps) => any; - propertyEnhancer: (props: WidgetProps) => WidgetProps; -}; +/** + * + * @param renderMode - render mode specifies whether the application is in edit/deploy mode. + * @param appPositioningType - layout system of the application. + * @returns + * @property — widgetSystem - widget specific wrappers and enhancers of a layout system + * @property — canvasSystem - canvas specific implementation and enhancers of a layout system + */ export const getLayoutSystem = ( renderMode: RenderModes, layoutSystemType: LayoutSystemTypes, ): LayoutSystem => { switch (layoutSystemType) { - case LayoutSystemTypes.ANVIL: - return getAnvilSystem(renderMode); + // Removing Anvil system until canvas system of Anvil is Implemented. + // when re-introducing pls make sure to uncomment anvil based test cases in withLayoutSystemWidgetHOC.test + // case LayoutSystemTypes.ANVIL: + // return getAnvilLayoutSystem(renderMode); case LayoutSystemTypes.AUTO: return getAutoLayoutSystem(renderMode); default: @@ -33,26 +39,24 @@ const LayoutSystemWrapper = ({ widgetProps, }: { widgetProps: WidgetProps; - Widget: (props: WidgetProps) => any; + Widget: (props: WidgetProps) => JSX.Element; }) => { const renderMode = useSelector(getRenderMode); const layoutSystemType = useSelector(getLayoutSystemType); // based on layoutSystemType and renderMode // get the layout system wrapper(adds layout system specific functionality) and // properties enhancer(adds/modifies properties of a widget based on layout system) - const { LayoutSystemWrapper, propertyEnhancer } = getLayoutSystem( - renderMode, - layoutSystemType, - ); + const { widgetSystem } = getLayoutSystem(renderMode, layoutSystemType); + const { propertyEnhancer, WidgetWrapper } = widgetSystem; const enhancedProperties = propertyEnhancer(widgetProps); return ( - + - + ); }; -export const withLayoutSystemHOC = (Widget: any) => { +export const withLayoutSystemWidgetHOC = (Widget: any) => { return function LayoutWrappedWidget(props: WidgetProps) { return ; }; diff --git a/app/client/src/pages/AppViewer/AppPage.tsx b/app/client/src/pages/AppViewer/AppPage.tsx index 3b75874ae5..28f2640382 100644 --- a/app/client/src/pages/AppViewer/AppPage.tsx +++ b/app/client/src/pages/AppViewer/AppPage.tsx @@ -1,9 +1,7 @@ import React, { useEffect } from "react"; -import WidgetFactory from "WidgetProvider/factory"; import AnalyticsUtil from "utils/AnalyticsUtil"; import { useDynamicAppLayout } from "utils/hooks/useDynamicAppLayout"; import type { CanvasWidgetStructure } from "WidgetProvider/constants"; -import { RenderModes } from "constants/WidgetConstants"; import { useSelector } from "react-redux"; import { getCurrentApplication, @@ -16,6 +14,8 @@ import { PageView, PageViewWrapper } from "./AppPage.styled"; import { useIsMobileDevice } from "utils/hooks/useDeviceDetect"; import { APP_MODE } from "entities/App"; import { useLocation } from "react-router"; +import { renderAppsmithCanvas } from "layoutSystems/CanvasFactory"; +import type { WidgetProps } from "widgets/BaseWidget"; type AppPageProps = { appName?: string; @@ -63,7 +63,7 @@ export function AppPage(props: AppPageProps) { > {props.widgetsStructure.widgetId && - WidgetFactory.createWidget(props.widgetsStructure, RenderModes.PAGE)} + renderAppsmithCanvas(props.widgetsStructure as WidgetProps)} ); diff --git a/app/client/src/pages/Editor/Canvas.tsx b/app/client/src/pages/Editor/Canvas.tsx index d0b7fafd5b..921d5c5be3 100644 --- a/app/client/src/pages/Editor/Canvas.tsx +++ b/app/client/src/pages/Editor/Canvas.tsx @@ -3,10 +3,7 @@ import React from "react"; import styled from "styled-components"; import * as Sentry from "@sentry/react"; import { useSelector } from "react-redux"; -import WidgetFactory from "WidgetProvider/factory"; import type { CanvasWidgetStructure } from "WidgetProvider/constants"; - -import { RenderModes } from "constants/WidgetConstants"; import useWidgetFocus from "utils/hooks/useWidgetFocus"; import { useFeatureFlag } from "utils/hooks/useFeatureFlag"; import { previewModeSelector } from "selectors/editorSelectors"; @@ -18,6 +15,8 @@ import { useTheme, } from "@design-system/theming"; import { getIsAppSettingsPaneWithNavigationTabOpen } from "selectors/appSettingsPaneSelectors"; +import { renderAppsmithCanvas } from "layoutSystems/CanvasFactory"; +import type { WidgetProps } from "widgets/BaseWidget"; interface CanvasProps { widgetsStructure: CanvasWidgetStructure; @@ -90,10 +89,7 @@ const Canvas = (props: CanvasProps) => { width={canvasWidth} > {props.widgetsStructure.widgetId && - WidgetFactory.createWidget( - props.widgetsStructure, - RenderModes.CANVAS, - )} + renderAppsmithCanvas(props.widgetsStructure as WidgetProps)} ); diff --git a/app/client/src/pages/Editor/WidgetsEditor/MainContainerWrapper.tsx b/app/client/src/pages/Editor/WidgetsEditor/MainContainerWrapper.tsx index c27c3dfb75..f0eba8c409 100644 --- a/app/client/src/pages/Editor/WidgetsEditor/MainContainerWrapper.tsx +++ b/app/client/src/pages/Editor/WidgetsEditor/MainContainerWrapper.tsx @@ -31,7 +31,6 @@ import { } from "utils/hooks/useDynamicAppLayout"; import Canvas from "../Canvas"; import type { AppState } from "@appsmith/reducers"; -import { MainContainerResizer } from "layoutSystems/autolayout/MainContainerResizer/MainContainerResizer"; import { useFeatureFlag } from "utils/hooks/useFeatureFlag"; import { getIsAnonymousDataPopupVisible } from "selectors/onboardingSelectors"; import { @@ -39,6 +38,7 @@ import { useLayoutSystemFeatures, } from "../../../layoutSystems/common/useLayoutSystemFeatures"; import { CANVAS_VIEWPORT } from "constants/componentClassNameConstants"; +import { MainContainerResizer } from "layoutSystems/common/mainContainerResizer/MainContainerResizer"; type MainCanvasWrapperProps = { isPreviewMode: boolean; diff --git a/app/client/src/reducers/uiReducers/canvasSelectionReducer.ts b/app/client/src/reducers/uiReducers/canvasSelectionReducer.ts index 562d1adf37..5baee6cf51 100644 --- a/app/client/src/reducers/uiReducers/canvasSelectionReducer.ts +++ b/app/client/src/reducers/uiReducers/canvasSelectionReducer.ts @@ -2,7 +2,7 @@ import { createImmerReducer } from "utils/ReducerUtils"; import type { ReduxAction } from "@appsmith/constants/ReduxActionConstants"; import { ReduxActionTypes } from "@appsmith/constants/ReduxActionConstants"; import { MAIN_CONTAINER_WIDGET_ID } from "constants/WidgetConstants"; -import type { XYCord } from "layoutSystems/common/CanvasArenas/ArenaTypes"; +import type { XYCord } from "layoutSystems/common/canvasArenas/ArenaTypes"; const initialState: CanvasSelectionState = { isDraggingForSelection: false, diff --git a/app/client/src/sagas/CanvasSagas/DraggingCanvasSagas.ts b/app/client/src/sagas/CanvasSagas/DraggingCanvasSagas.ts index aea0418006..2354a0c9d3 100644 --- a/app/client/src/sagas/CanvasSagas/DraggingCanvasSagas.ts +++ b/app/client/src/sagas/CanvasSagas/DraggingCanvasSagas.ts @@ -6,7 +6,7 @@ import { import { generateAutoHeightLayoutTreeAction } from "actions/autoHeightActions"; import type { WidgetAddChild } from "actions/pageActions"; import { updateAndSaveLayout } from "actions/pageActions"; -import { calculateDropTargetRows } from "components/editorComponents/DropTargetUtils"; +import { calculateDropTargetRows } from "layoutSystems/common/dropTarget/DropTargetUtils"; import { CANVAS_DEFAULT_MIN_HEIGHT_PX } from "constants/AppConstants"; import type { OccupiedSpace } from "constants/CanvasEditorConstants"; import { @@ -40,7 +40,7 @@ import { collisionCheckPostReflow } from "utils/reflowHookUtils"; import type { WidgetProps } from "widgets/BaseWidget"; import { BlueprintOperationTypes } from "WidgetProvider/constants"; import { toast } from "design-system"; -import type { WidgetDraggingUpdateParams } from "layoutSystems/common/CanvasArenas/ArenaTypes"; +import type { WidgetDraggingUpdateParams } from "layoutSystems/common/canvasArenas/ArenaTypes"; import { getLayoutSystemType } from "selectors/layoutSystemSelectors"; export type WidgetMoveParams = { diff --git a/app/client/src/selectors/flattenedChildCanvasSelector.ts b/app/client/src/selectors/flattenedChildCanvasSelector.ts index 7e2940802e..40aaeab18a 100644 --- a/app/client/src/selectors/flattenedChildCanvasSelector.ts +++ b/app/client/src/selectors/flattenedChildCanvasSelector.ts @@ -1,6 +1,6 @@ import { getCanvasWidgets } from "@appsmith/selectors/entitiesSelector"; import { GridDefaults, type RenderModes } from "constants/WidgetConstants"; -import { getLayoutSystem } from "layoutSystems/withLayoutSystemHOC"; +import { getLayoutSystem } from "layoutSystems/withLayoutSystemWidgetHOC"; import type { CanvasWidgetsReduxState, FlattenedWidgetProps, @@ -21,7 +21,9 @@ function buildFlattenedChildCanvasWidgets( flattenedChildCanvasWidgets: Record = {}, ) { const parentWidget = canvasWidgets[parentWidgetId]; - const { propertyEnhancer } = getLayoutSystem(renderMode, layoutSystemType); + const { + widgetSystem: { propertyEnhancer }, + } = getLayoutSystem(renderMode, layoutSystemType); parentWidget?.children?.forEach((childId) => { const childWidget = canvasWidgets[childId]; let parentRowSpace = diff --git a/app/client/src/utils/WidgetPropsUtils.test.tsx b/app/client/src/utils/WidgetPropsUtils.test.tsx index 81e8d359bd..b50529f811 100644 --- a/app/client/src/utils/WidgetPropsUtils.test.tsx +++ b/app/client/src/utils/WidgetPropsUtils.test.tsx @@ -18,7 +18,7 @@ import { getDraggingSpacesFromBlocks, getMousePositionsOnCanvas, } from "./WidgetPropsUtils"; -import type { WidgetDraggingBlock } from "layoutSystems/common/CanvasArenas/ArenaTypes"; +import type { WidgetDraggingBlock } from "layoutSystems/common/canvasArenas/ArenaTypes"; import { ASSETS_CDN_URL } from "constants/ThirdPartyConstants"; describe("WidgetProps tests", () => { diff --git a/app/client/src/utils/WidgetPropsUtils.tsx b/app/client/src/utils/WidgetPropsUtils.tsx index c4aa8209e7..31f15a7055 100644 --- a/app/client/src/utils/WidgetPropsUtils.tsx +++ b/app/client/src/utils/WidgetPropsUtils.tsx @@ -24,7 +24,7 @@ import { checkIsDSLAutoLayout } from "../layoutSystems/autolayout/utils/AutoLayo import type { WidgetDraggingBlock, XYCord, -} from "layoutSystems/common/CanvasArenas/ArenaTypes"; +} from "layoutSystems/common/canvasArenas/ArenaTypes"; export type WidgetOperationParams = { operation: WidgetOperation; diff --git a/app/client/src/widgets/BaseWidgetHOC/withBaseWidgetHOC.ts b/app/client/src/widgets/BaseWidgetHOC/withBaseWidgetHOC.ts index 3d385e934c..8dd7ac0085 100644 --- a/app/client/src/widgets/BaseWidgetHOC/withBaseWidgetHOC.ts +++ b/app/client/src/widgets/BaseWidgetHOC/withBaseWidgetHOC.ts @@ -4,7 +4,7 @@ import { withLazyRender } from "widgets/withLazyRender"; import type BaseWidget from "widgets/BaseWidget"; import withWidgetProps from "widgets/withWidgetProps"; import * as Sentry from "@sentry/react"; -import { withLayoutSystemHOC } from "../../layoutSystems/withLayoutSystemHOC"; +import { withLayoutSystemWidgetHOC } from "../../layoutSystems/withLayoutSystemWidgetHOC"; export interface BaseWidgetProps extends WidgetProps, WidgetState {} @@ -20,7 +20,7 @@ export const withBaseWidgetHOC = ( ? MetaWidget : withLazyRender(MetaWidget as any); // Adds respective layout specific layers to a widget - const LayoutWrappedWidget = withLayoutSystemHOC(LazyRenderedWidget); + const LayoutWrappedWidget = withLayoutSystemWidgetHOC(LazyRenderedWidget); // Adds/Enhances widget props const HydratedWidget = withWidgetProps(LayoutWrappedWidget as any); // Wraps the widget to be profiled via sentry diff --git a/app/client/src/widgets/CanvasWidget.tsx b/app/client/src/widgets/CanvasWidget.tsx index 4d927fed41..f1d7ec6a2e 100644 --- a/app/client/src/widgets/CanvasWidget.tsx +++ b/app/client/src/widgets/CanvasWidget.tsx @@ -1,36 +1,15 @@ -import { - LayoutDirection, - Positioning, - ResponsiveBehavior, -} from "layoutSystems/common/utils/constants"; -import DropTargetComponent from "components/editorComponents/DropTargetComponent"; -import { CANVAS_DEFAULT_MIN_HEIGHT_PX } from "constants/AppConstants"; +import { ResponsiveBehavior } from "layoutSystems/common/utils/constants"; import { FILL_WIDGET_MIN_WIDTH } from "constants/minWidthConstants"; -import { GridDefaults, RenderModes } from "constants/WidgetConstants"; -import WidgetsMultiSelectBox from "pages/Editor/WidgetsMultiSelectBox"; -import type { CSSProperties } from "react"; -import React from "react"; -import { getCanvasClassName } from "utils/generators"; import type { DerivedPropertiesMap } from "WidgetProvider/factory"; -import WidgetFactory from "WidgetProvider/factory"; -import { getCanvasSnapRows } from "utils/WidgetPropsUtils"; -import type { WidgetProps } from "widgets/BaseWidget"; -import type { ContainerWidgetProps } from "widgets/ContainerWidget/widget"; import ContainerWidget from "widgets/ContainerWidget/widget"; -import type { - CanvasWidgetStructure, - DSLWidget, - WidgetDefaultProps, -} from "../WidgetProvider/constants"; -import ContainerComponent from "./ContainerWidget/component"; -import { LayoutSystemTypes } from "layoutSystems/types"; -import FlexBoxComponent from "../layoutSystems/autolayout/common/flexCanvas/FlexBoxComponent"; -import { AutoCanvasDraggingArena } from "layoutSystems/autolayout/editor/AutoLayoutCanvasArenas/AutoCanvasDraggingArena"; -import { FixedCanvasDraggingArena } from "layoutSystems/fixedlayout/editor/FixedLayoutCanvasArenas/FixedCanvasDraggingArena"; -import { CanvasSelectionArena } from "layoutSystems/fixedlayout/editor/FixedLayoutCanvasArenas/CanvasSelectionArena"; +import type { WidgetDefaultProps } from "../WidgetProvider/constants"; import type { AutocompletionDefinitions } from "WidgetProvider/constants"; import type { SetterConfig } from "entities/AppTheming"; +/** + * Please refer to renderAppsmithCanvas in CanvasFactory to see current version of How CanvasWidget is rendered. + */ + class CanvasWidget extends ContainerWidget { static type = "CANVAS_WIDGET"; @@ -67,188 +46,6 @@ class CanvasWidget extends ContainerWidget { return null; } - getCanvasProps(): DSLWidget & { minHeight: number } { - return { - ...this.props, - parentRowSpace: 1, - parentColumnSpace: 1, - topRow: 0, - leftColumn: 0, - containerStyle: "none", - detachFromLayout: true, - minHeight: this.props.minHeight || CANVAS_DEFAULT_MIN_HEIGHT_PX, - shouldScrollContents: false, - }; - } - - renderAsDropTarget() { - const canvasProps = this.getCanvasProps(); - const { snapColumnSpace } = this.getSnapSpaces(); - return ( - - {this.renderAsContainerComponent(canvasProps)} - - ); - } - - renderChildWidget(childWidgetData: CanvasWidgetStructure): React.ReactNode { - if (!childWidgetData) return null; - - const childWidget = { ...childWidgetData }; - - const snapSpaces = this.getSnapSpaces(); - childWidget.parentColumnSpace = snapSpaces.snapColumnSpace; - childWidget.parentRowSpace = snapSpaces.snapRowSpace; - if (this.props.noPad) childWidget.noContainerOffset = true; - childWidget.parentId = this.props.widgetId; - // Pass layout controls to children - childWidget.positioning = - childWidget?.positioning || this.props.positioning; - childWidget.isFlexChild = this.props.useAutoLayout; - childWidget.direction = this.getDirection(); - - return WidgetFactory.createWidget(childWidget, this.props.renderMode); - } - - renderAsContainerComponent( - props: ContainerWidgetProps, - ): JSX.Element { - const direction = this.getDirection(); - const snapRows = getCanvasSnapRows( - this.props.bottomRow, - this.props.mobileBottomRow, - this.props.isMobile, - this.props.layoutSystemType === LayoutSystemTypes.AUTO, - ); - return ( - - {props.renderMode === RenderModes.CANVAS && ( - <> - { - //Temporary change, will have better separation logic with Canvas onion implementation - !this.props.useAutoLayout ? ( - - ) : ( - - ) - } - - - )} - {this.props.useAutoLayout - ? this.renderFlexCanvas(direction) - : this.renderFixedCanvas(props)} - - ); - } - - renderFlexCanvas(direction: LayoutDirection) { - const stretchFlexBox = !this.props.children || !this.props.children?.length; - return ( - - {this.renderChildren()} - - ); - } - - renderFixedCanvas(props: ContainerWidgetProps) { - return ( - <> - - {this.renderChildren()} - - ); - } - - getDirection(): LayoutDirection { - return this.props.positioning === Positioning.Vertical - ? LayoutDirection.Vertical - : LayoutDirection.Horizontal; - } - - getPageView() { - let height = 0; - const snapRows = getCanvasSnapRows( - this.props.bottomRow, - this.props.mobileBottomRow, - this.props.isMobile, - this.props.layoutSystemType === LayoutSystemTypes.AUTO, - ); - height = snapRows * GridDefaults.DEFAULT_GRID_ROW_HEIGHT; - const style: CSSProperties = { - width: "100%", - height: this.props.isListWidgetCanvas ? "auto" : `${height}px`, - background: "none", - position: "relative", - }; - // This div is the DropTargetComponent alternative for the page view - // DropTargetComponent and this div are responsible for the canvas height - return ( -
- {this.renderAsContainerComponent(this.getCanvasProps())} -
- ); - } - - getWidgetView() { - //ToDo(Ashok): Make sure Layout Factory takes care of render mode based widget view. - // untill then this part of the widget will have a abstraction leak. - if (!this.props.dropDisabled && this.props.renderMode === "CANVAS") { - return this.renderAsDropTarget(); - } - return this.getPageView(); - } - static getDerivedPropertiesMap(): DerivedPropertiesMap { return {}; } diff --git a/app/client/src/widgets/ContainerWidget/component/index.tsx b/app/client/src/widgets/ContainerWidget/component/index.tsx index 6f47e381b9..d511ebb520 100644 --- a/app/client/src/widgets/ContainerWidget/component/index.tsx +++ b/app/client/src/widgets/ContainerWidget/component/index.tsx @@ -131,7 +131,6 @@ function ContainerComponentWrapper( ? "auto-layout" : "" }`} - data-widgetId={props.widgetId} dropDisabled={props.dropDisabled} onClick={props.onClick} onClickCapture={props.onClickCapture} diff --git a/app/client/src/widgets/ContainerWidget/widget/index.tsx b/app/client/src/widgets/ContainerWidget/widget/index.tsx index a33a7ff889..9d826f4fd9 100644 --- a/app/client/src/widgets/ContainerWidget/widget/index.tsx +++ b/app/client/src/widgets/ContainerWidget/widget/index.tsx @@ -1,18 +1,13 @@ import type { MouseEventHandler } from "react"; import React from "react"; - import type { DerivedPropertiesMap } from "WidgetProvider/factory"; -import WidgetFactory from "WidgetProvider/factory"; import type { ContainerStyle } from "../component"; import ContainerComponent from "../component"; - import type { WidgetProps, WidgetState } from "widgets/BaseWidget"; import BaseWidget from "widgets/BaseWidget"; - import { ValidationTypes } from "constants/WidgetValidation"; import { compact, map, sortBy } from "lodash"; -import WidgetsMultiSelectBox from "pages/Editor/WidgetsMultiSelectBox"; - +import WidgetsMultiSelectBox from "layoutSystems/fixedlayout/common/widgetGrouping/WidgetsMultiSelectBox"; import type { SetterConfig, Stylesheet } from "entities/AppTheming"; import { getSnappedGrid } from "sagas/WidgetOperationUtils"; import { ReduxActionTypes } from "@appsmith/constants/ReduxActionConstants"; @@ -38,6 +33,7 @@ import { Positioning, ResponsiveBehavior, } from "layoutSystems/common/utils/constants"; +import { renderAppsmithCanvas } from "layoutSystems/CanvasFactory"; export class ContainerWidget extends BaseWidget< ContainerWidgetProps, @@ -314,7 +310,7 @@ export class ContainerWidget extends BaseWidget< childWidget.useAutoLayout = this.props.positioning ? this.props.positioning === Positioning.Vertical : false; - return WidgetFactory.createWidget(childWidget, this.props.renderMode); + return renderAppsmithCanvas(childWidget as WidgetProps); } renderChildren = () => { diff --git a/app/client/src/widgets/ListWidget/widget/index.tsx b/app/client/src/widgets/ListWidget/widget/index.tsx index 9bf8fbf83c..d78c620dca 100644 --- a/app/client/src/widgets/ListWidget/widget/index.tsx +++ b/app/client/src/widgets/ListWidget/widget/index.tsx @@ -65,6 +65,7 @@ import { getAssetUrl } from "@appsmith/utils/airgapHelpers"; import { ASSETS_CDN_URL } from "constants/ThirdPartyConstants"; import { FILL_WIDGET_MIN_WIDTH } from "constants/minWidthConstants"; import IconSVG from "../icon.svg"; +import { renderAppsmithCanvas } from "layoutSystems/CanvasFactory"; const LIST_WIDGET_PAGINATION_HEIGHT = 36; @@ -865,8 +866,7 @@ class ListWidget extends BaseWidget, WidgetState> { this.props.positioning || childWidgetData.positioning; childWidgetData.positioning = positioning; childWidgetData.useAutoLayout = positioning === Positioning.Vertical; - - return WidgetFactory.createWidget(childWidgetData, this.props.renderMode); + return renderAppsmithCanvas(childWidgetData as WidgetProps); }; getGridGap = () => diff --git a/app/client/src/widgets/ListWidgetV2/widget/index.tsx b/app/client/src/widgets/ListWidgetV2/widget/index.tsx index f4c37027c2..a7e3b88917 100644 --- a/app/client/src/widgets/ListWidgetV2/widget/index.tsx +++ b/app/client/src/widgets/ListWidgetV2/widget/index.tsx @@ -17,7 +17,6 @@ import Loader from "../component/Loader"; import MetaWidgetContextProvider from "../../MetaWidgetContextProvider"; import type { GeneratorOptions, HookOptions } from "../MetaWidgetGenerator"; import MetaWidgetGenerator from "../MetaWidgetGenerator"; -import WidgetFactory from "WidgetProvider/factory"; import type { BatchPropertyUpdatePayload } from "actions/controlActions"; import type { AutocompletionDefinitions, @@ -52,6 +51,7 @@ import { generateTypeDef } from "utils/autocomplete/dataTreeTypeDefCreator"; import defaultProps from "./defaultProps"; import IconSVG from "../icon.svg"; +import { renderAppsmithCanvas } from "layoutSystems/CanvasFactory"; const getCurrentItemsViewBindingTemplate = () => ({ prefix: "{{[", @@ -1217,7 +1217,7 @@ class ListWidget extends BaseWidget< }, }; }); - return WidgetFactory.createWidget(child, this.props.renderMode); + return renderAppsmithCanvas(child as WidgetProps); }, ); diff --git a/app/client/src/widgets/MetaHOC.tsx b/app/client/src/widgets/MetaHOC.tsx index c5dfe27fb9..01a900bfe5 100644 --- a/app/client/src/widgets/MetaHOC.tsx +++ b/app/client/src/widgets/MetaHOC.tsx @@ -1,6 +1,5 @@ import React from "react"; import type { WidgetProps } from "./BaseWidget"; -import type BaseWidget from "./BaseWidget"; import { debounce, fromPairs, isEmpty } from "lodash"; import { EditorContext } from "components/editorComponents/EditorContextProvider"; import AppsmithConsole from "utils/AppsmithConsole"; @@ -12,6 +11,7 @@ import { getWidgetMetaProps } from "sagas/selectors"; import type { AppState } from "@appsmith/reducers"; import { error } from "loglevel"; import WidgetFactory from "WidgetProvider/factory"; +import type BaseWidget from "./BaseWidget"; export type pushAction = ( propertyName: string | batchUpdateWidgetMetaPropertyType, propertyValue?: unknown, diff --git a/app/client/src/widgets/ModalWidget/component/index.tsx b/app/client/src/widgets/ModalWidget/component/index.tsx index 578d63281a..69420cf3a0 100644 --- a/app/client/src/widgets/ModalWidget/component/index.tsx +++ b/app/client/src/widgets/ModalWidget/component/index.tsx @@ -10,13 +10,13 @@ import { scrollCSS } from "widgets/WidgetUtils"; import type { WidgetProps } from "widgets/BaseWidget"; import type { RenderMode } from "constants/WidgetConstants"; import { WIDGET_PADDING } from "constants/WidgetConstants"; -import WidgetFactory from "WidgetProvider/factory"; import { useModalWidth } from "./useModalWidth"; import type { Alignment, Positioning, Spacing, } from "layoutSystems/common/utils/constants"; +import { renderAppsmithCanvas } from "layoutSystems/CanvasFactory"; const Content = styled.div<{ $scroll: boolean }>` overflow-x: hidden; @@ -113,7 +113,7 @@ export default function ModalComponent(props: ModalComponentProps) { childData.positioning = props.positioning; childData.alignment = props.alignment; childData.spacing = props.spacing; - return WidgetFactory.createWidget(childData, props.renderMode); + return renderAppsmithCanvas(childData as WidgetProps); }; const getChildren = (): ReactNode => { if ( diff --git a/app/client/src/widgets/TabsWidget/widget/index.tsx b/app/client/src/widgets/TabsWidget/widget/index.tsx index c7db5ce8c9..3a6a82ee83 100644 --- a/app/client/src/widgets/TabsWidget/widget/index.tsx +++ b/app/client/src/widgets/TabsWidget/widget/index.tsx @@ -12,7 +12,6 @@ import React from "react"; import { LayoutSystemTypes } from "layoutSystems/types"; import type { WidgetProperties } from "selectors/propertyPaneSelectors"; import { AutocompleteDataType } from "utils/autocomplete/AutocompleteDataType"; -import WidgetFactory from "WidgetProvider/factory"; import type { WidgetState } from "../../BaseWidget"; import BaseWidget from "../../BaseWidget"; import TabsComponent from "../component"; @@ -36,6 +35,7 @@ import { import type { WidgetProps } from "widgets/BaseWidget"; import { BlueprintOperationTypes } from "WidgetProvider/constants"; import IconSVG from "../icon.svg"; +import { renderAppsmithCanvas } from "layoutSystems/CanvasFactory"; export function selectedTabValidation( value: unknown, @@ -588,8 +588,7 @@ class TabsWidget extends BaseWidget< : LayoutDirection.Horizontal; childWidgetData.alignment = selectedTabProps?.alignment; childWidgetData.spacing = selectedTabProps?.spacing; - - return WidgetFactory.createWidget(childWidgetData, this.props.renderMode); + return renderAppsmithCanvas(childWidgetData as WidgetProps); }; private getSelectedTabWidgetId() {