From eecb9a374701677a9cc7b031cd0815770e304eff Mon Sep 17 00:00:00 2001 From: kungurovsergey Date: Sun, 12 Jul 2026 23:59:30 +0400 Subject: [PATCH] Add fill height mode for fixed-row canvas --- .../src/comps/comps/appSettingsComp.tsx | 5 +++ .../comps/gridLayoutComp/canvasView.test.ts | 19 +++++++++ .../comps/comps/gridLayoutComp/canvasView.tsx | 39 +++++++++++++++---- .../lowcoder/src/pages/editor/editorView.tsx | 12 +++--- 4 files changed, 63 insertions(+), 12 deletions(-) create mode 100644 client/packages/lowcoder/src/comps/comps/gridLayoutComp/canvasView.test.ts diff --git a/client/packages/lowcoder/src/comps/comps/appSettingsComp.tsx b/client/packages/lowcoder/src/comps/comps/appSettingsComp.tsx index b38260eedf..9d8dee219c 100644 --- a/client/packages/lowcoder/src/comps/comps/appSettingsComp.tsx +++ b/client/packages/lowcoder/src/comps/comps/appSettingsComp.tsx @@ -221,6 +221,7 @@ const childrenMap = { gridRowCount: withDefault(NumberControl, DEFAULT_ROW_COUNT), gridPaddingX: withDefault(NumberControl, 0), gridPaddingY: withDefault(NumberControl, 0), + gridStretchHeight: withDefault(BoolControl, false), gridBg: ColorControl, gridBgImage: StringControl, gridBgImageRepeat: StringControl, @@ -355,6 +356,7 @@ function AppCanvasSettingsModal(props: ChildrenInstance) { gridColumns, gridRowHeight, gridRowCount, + gridStretchHeight, gridPaddingX, gridPaddingY, gridBg, @@ -478,6 +480,9 @@ function AppCanvasSettingsModal(props: ChildrenInstance) { label: trans("appSetting.gridRowCount"), placeholder: 'Infinity', })} + {gridRowCount.getView() !== DEFAULT_ROW_COUNT && gridStretchHeight.propertyView({ + label: "Stretch canvas to available height", + })} {gridPaddingX.propertyView({ label: trans("appSetting.gridPaddingX"), placeholder: '0', diff --git a/client/packages/lowcoder/src/comps/comps/gridLayoutComp/canvasView.test.ts b/client/packages/lowcoder/src/comps/comps/gridLayoutComp/canvasView.test.ts new file mode 100644 index 0000000000..82ddbbf0fa --- /dev/null +++ b/client/packages/lowcoder/src/comps/comps/gridLayoutComp/canvasView.test.ts @@ -0,0 +1,19 @@ +import { DEFAULT_ROW_COUNT } from "@lowcoder-ee/layout/calculateUtils"; +import { + shouldShowStretchCanvasHeight, + shouldStretchCanvasHeight, +} from "./canvasView"; + +describe("canvas stretch height helpers", () => { + it("shows stretch only for fixed row count", () => { + expect(shouldShowStretchCanvasHeight(DEFAULT_ROW_COUNT)).toBe(false); + expect(shouldShowStretchCanvasHeight(24)).toBe(true); + }); + + it("enables stretch only in runtime for fixed row count", () => { + expect(shouldStretchCanvasHeight(DEFAULT_ROW_COUNT, true, true)).toBe(false); + expect(shouldStretchCanvasHeight(24, false, true)).toBe(false); + expect(shouldStretchCanvasHeight(24, true, false)).toBe(false); + expect(shouldStretchCanvasHeight(24, true, true)).toBe(true); + }); +}); diff --git a/client/packages/lowcoder/src/comps/comps/gridLayoutComp/canvasView.tsx b/client/packages/lowcoder/src/comps/comps/gridLayoutComp/canvasView.tsx index d830a8e867..1a82113d03 100644 --- a/client/packages/lowcoder/src/comps/comps/gridLayoutComp/canvasView.tsx +++ b/client/packages/lowcoder/src/comps/comps/gridLayoutComp/canvasView.tsx @@ -27,6 +27,7 @@ import { getBackgroundStyle } from "@lowcoder-ee/util/styleUtils"; const UICompContainer = styled.div<{ $maxWidth?: number; $rowCount?: number; + $fillHeight?: boolean; readOnly?: boolean; $bgColor: string; $bgImage?: string; @@ -35,8 +36,8 @@ const UICompContainer = styled.div<{ $bgImageOrigin?: string; $bgImagePosition?: string; }>` - height: auto; - min-height: ${props => props.$rowCount === Infinity ? '100%' : 'auto'}; + height: ${props => props.$fillHeight ? '100%' : 'auto'}; + min-height: ${props => props.$fillHeight ? '0' : props.$rowCount === Infinity ? '100%' : 'auto'}; margin: 0 auto; max-width: ${(props) => props.$maxWidth || 1600}px; @@ -68,6 +69,18 @@ const gridLayoutCanvasProps = { isCanvas: true, }; +export function shouldShowStretchCanvasHeight(rowCount: number) { + return rowCount !== DEFAULT_ROW_COUNT; +} + +export function shouldStretchCanvasHeight( + rowCount: number, + readOnly: boolean, + gridStretchHeight?: boolean +) { + return readOnly && Boolean(gridStretchHeight) && rowCount !== DEFAULT_ROW_COUNT; +} + function getDragSelectedNames( items: GridItemsType, layout: GridLayoutType, @@ -176,7 +189,7 @@ export const CanvasView = React.memo((props: ContainerBaseProps) => { const externalState = useContext(ExternalEditorContext); const { - readOnly, + readOnly = false, appType, rootContainerExtraHeight = DEFAULT_EXTRA_HEIGHT, rootContainerPadding, @@ -271,6 +284,10 @@ export const CanvasView = React.memo((props: ContainerBaseProps) => { || defaultTheme?.gridRowCount || DEFAULT_ROW_COUNT; }, [preventStylesOverwriting, appSettings, currentTheme, defaultTheme]); + const isStretchCanvasHeight = useMemo( + () => shouldStretchCanvasHeight(defaultRowCount ?? DEFAULT_ROW_COUNT, readOnly, (appSettings as any).gridStretchHeight), + [appSettings, defaultRowCount, readOnly] + ); const defaultContainerPadding: [number, number] = useMemo(() => { const DEFAULT_PADDING = isMobile ? DEFAULT_MOBILE_PADDING : DEFAULT_CONTAINER_PADDING; @@ -305,10 +322,11 @@ export const CanvasView = React.memo((props: ContainerBaseProps) => { if (readOnly) { return ( - { {...props} positionParams={positionParams} {...gridLayoutCanvasProps} + autoHeight={!isStretchCanvasHeight} + rowCount={defaultRowCount} + isRowCountLocked={isStretchCanvasHeight} bgColor={bgColor} radius="0px" emptyRows={defaultRowCount} @@ -341,6 +362,7 @@ export const CanvasView = React.memo((props: ContainerBaseProps) => { { overflow={rootContainerOverflow} {...props} {...gridLayoutCanvasProps} + autoHeight={!isStretchCanvasHeight} + rowCount={defaultRowCount} + isRowCountLocked={isStretchCanvasHeight} dragSelectedComps={dragSelectedComps} scrollContainerRef={scrollContainerRef} isDroppable={!isModule} diff --git a/client/packages/lowcoder/src/pages/editor/editorView.tsx b/client/packages/lowcoder/src/pages/editor/editorView.tsx index 60edc7249f..5dc198c4fe 100644 --- a/client/packages/lowcoder/src/pages/editor/editorView.tsx +++ b/client/packages/lowcoder/src/pages/editor/editorView.tsx @@ -116,6 +116,9 @@ const Height100Div = lazy( () => import('pages/common/styledComponent') .then(module => ({default: module.Height100Div})) ); +const PreviewContainer = styled.div` + height: 100%; +`; const LeftPanel = lazy( () => import('pages/common/styledComponent') .then(module => ({default: module.LeftPanel})) @@ -539,14 +542,14 @@ function EditorView(props: EditorViewProps) { deviceType={editorState.deviceType} deviceOrientation={editorState.deviceOrientation} > -
+ {uiComp.getView()} -
+ ) : ( -
+ {uiComp.getView()} -
+ ) ) }, [ @@ -794,4 +797,3 @@ function EditorView(props: EditorViewProps) { export default React.memo(EditorView, (prevProps, newProps) => { return isEqual(prevProps, newProps); }); -