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() {