Skip to content

Commit 15a98e8

Browse files
author
FalkWolsky
committedFeb 8, 2025·
Update to ANTd 5.23.4 - Adaptions on Responsive Layout and Introduction for SplitLayout Component
1 parent 80934b5 commit 15a98e8

File tree

20 files changed

+595
-223
lines changed

20 files changed

+595
-223
lines changed
 

‎client/packages/lowcoder-design/src/components/CustomModal.tsx

+12-6
Original file line numberDiff line numberDiff line change
@@ -220,10 +220,13 @@ const DEFAULT_PROPS = {
220220
autoFocusButton: "ok",
221221
} as const;
222222

223-
function CustomModalRender(props: CustomModalProps & ModalFuncProps) {
223+
function CustomModalRender(props: Omit<CustomModalProps & ModalFuncProps, "width"> & { width?: string | number }) {
224224
return (
225225
<Draggable handle=".handle" disabled={!props.draggable}>
226-
<ModalWrapper $width={props.width} $customStyles={props?.customStyles}>
226+
<ModalWrapper
227+
$width={props.width}
228+
$customStyles={props?.customStyles}
229+
>
227230
<>
228231
<ModalHeaderWrapper className="handle" $draggable={props.draggable}>
229232
<ModalHeader
@@ -249,20 +252,21 @@ function CustomModalRender(props: CustomModalProps & ModalFuncProps) {
249252
);
250253
}
251254

255+
252256
/**
253257
* an antd modal capsulation
254258
*/
255-
256259
function CustomModal(props: CustomModalProps) {
257260
return (
258261
<AntdModal
259262
{...props}
260-
width="fit-content"
261-
modalRender={() => <CustomModalRender {...DEFAULT_PROPS} {...props} />}
263+
width={typeof props.width === "object" ? undefined : props.width} // Ensure valid type
264+
modalRender={() => <CustomModalRender {...props} width={typeof props.width === "object" ? undefined : props.width} />}
262265
/>
263266
);
264267
}
265268

269+
266270
const TitleIcon = {
267271
error: <ErrorIcon />,
268272
warn: <WarningIcon />,
@@ -285,6 +289,8 @@ CustomModal.confirm = (props: {
285289
customStyles?:React.CSSProperties;
286290
}): any => {
287291

292+
const fixedWidth = typeof props.width === "object" ? undefined : props.width;
293+
288294
const defaultConfirmProps: ModalFuncProps = {
289295
...DEFAULT_PROPS,
290296
okText: trans("ok"),
@@ -301,7 +307,7 @@ CustomModal.confirm = (props: {
301307
};
302308
// create model
303309
const model = modalInstance.confirm({
304-
width: "fit-content",
310+
width: fixedWidth,
305311
style: props.style,
306312
centered: true,
307313
onCancel: () => {

‎client/packages/lowcoder/package.json

+1-1
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@
3838
"@types/react-virtualized": "^9.21.21",
3939
"alasql": "^4.6.2",
4040
"animate.css": "^4.1.1",
41-
"antd": "^5.20.0",
41+
"antd": "^5.23.4",
4242
"axios": "^1.7.7",
4343
"buffer": "^6.0.3",
4444
"clsx": "^2.0.0",

‎client/packages/lowcoder/src/comps/comps/responsiveLayout/responsiveLayout.tsx

+106-27
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ import { NameGenerator } from "comps/utils";
2121
import { Section, controlItem, sectionNames } from "lowcoder-design";
2222
import { HintPlaceHolder } from "lowcoder-design";
2323
import _ from "lodash";
24-
import React, { useEffect } from "react";
24+
import React, { useRef, useState, useEffect } from "react";
2525
import styled from "styled-components";
2626
import { IContainer } from "../containerBase/iContainer";
2727
import { SimpleContainerComp } from "../containerBase/simpleContainerComp";
@@ -44,11 +44,14 @@ import { disabledPropertyView, hiddenPropertyView } from "comps/utils/propertyUt
4444
import { DisabledContext } from "comps/generators/uiCompBuilder";
4545
import SliderControl from "@lowcoder-ee/comps/controls/sliderControl";
4646
import { getBackgroundStyle } from "@lowcoder-ee/util/styleUtils";
47+
import { useScreenInfo } from "../../hooks/screenInfoComp";
48+
4749

4850
const RowWrapper = styled(Row)<{
4951
$style: ResponsiveLayoutRowStyleType;
5052
$animationStyle: AnimationStyleType;
51-
$showScrollbar:boolean
53+
$showScrollbar: boolean;
54+
$columnCount: number;
5255
}>`
5356
${(props) => props.$animationStyle}
5457
height: 100%;
@@ -57,26 +60,40 @@ const RowWrapper = styled(Row)<{
5760
border-color: ${(props) => props.$style?.border};
5861
border-style: ${(props) => props.$style?.borderStyle};
5962
padding: ${(props) => props.$style.padding};
60-
rotate: ${props=> props.$style.rotation}
63+
rotate: ${(props) => props.$style.rotation};
6164
overflow: ${(props) => (props.$showScrollbar ? 'auto' : 'hidden')};
62-
::-webkit-scrollbar {
65+
display: flex;
66+
flex-wrap: wrap; // Ensure columns wrap properly when rowBreak = true
67+
::-webkit-scrollbar {
6368
display: ${(props) => (props.$showScrollbar ? 'block' : 'none')};
64-
}
69+
}
6570
${props => getBackgroundStyle(props.$style)}
71+
72+
--columns: ${(props) => props.$columnCount || 3};
6673
`;
6774

6875
const ColWrapper = styled(Col)<{
69-
$style: ResponsiveLayoutColStyleType | undefined,
70-
$minWidth?: string,
71-
$matchColumnsHeight: boolean,
76+
$style: ResponsiveLayoutColStyleType | undefined;
77+
$minWidth?: string;
78+
$matchColumnsHeight: boolean;
79+
$rowBreak: boolean;
7280
}>`
7381
display: flex;
7482
flex-direction: column;
75-
flex-basis: ${(props) => props.$minWidth};
76-
max-width: ${(props) => props.$minWidth};
83+
flex-grow: 1;
84+
85+
// When rowBreak is true, columns are stretched evenly based on configured number
86+
// When rowBreak is false, they stay at minWidth but break only if necessary
87+
flex-basis: ${(props) =>
88+
props.$rowBreak
89+
? `calc(100% / var(--columns))` // Force exact column distribution
90+
: `clamp(${props.$minWidth}, 100% / var(--columns), 100%)`}; // MinWidth respected
91+
92+
min-width: ${(props) => props.$minWidth}; // Ensure minWidth is respected
93+
max-width: 100%; // Prevent more columns than allowed
7794
7895
> div {
79-
height: ${(props) => props.$matchColumnsHeight ? '100%' : 'auto'};
96+
height: ${(props) => (props.$matchColumnsHeight ? "100%" : "auto")};
8097
border-radius: ${(props) => props.$style?.radius};
8198
border-width: ${(props) => props.$style?.borderWidth}px;
8299
border-color: ${(props) => props.$style?.border};
@@ -87,6 +104,8 @@ const ColWrapper = styled(Col)<{
87104
}
88105
`;
89106

107+
108+
90109
const childrenMap = {
91110
disabled: BoolCodeControl,
92111
columns: ColumnOptionControl,
@@ -96,7 +115,8 @@ const childrenMap = {
96115
}),
97116
horizontalGridCells: SliderControl,
98117
autoHeight: AutoHeightControl,
99-
rowBreak: withDefault(BoolControl, false),
118+
rowBreak: withDefault(BoolControl, true),
119+
useComponentWidth: withDefault(BoolControl, true),
100120
matchColumnsHeight: withDefault(BoolControl, true),
101121
style: styleControl(ResponsiveLayoutRowStyle , 'style'),
102122
columnStyle: styleControl(ResponsiveLayoutColStyle , 'columnStyle'),
@@ -127,13 +147,17 @@ const ColumnContainer = (props: ColumnContainerProps) => {
127147
);
128148
};
129149

130-
131150
const ResponsiveLayout = (props: ResponsiveLayoutProps) => {
151+
const screenInfo = useScreenInfo();
152+
const containerRef = useRef<HTMLDivElement | null>(null);
153+
const [componentWidth, setComponentWidth] = useState<number | null>(null);
154+
132155
let {
133156
columns,
134157
containers,
135158
dispatch,
136159
rowBreak,
160+
useComponentWidth,
137161
matchColumnsHeight,
138162
style,
139163
columnStyle,
@@ -148,33 +172,84 @@ const ResponsiveLayout = (props: ResponsiveLayoutProps) => {
148172
autoHeight
149173
} = props;
150174

175+
// Ensure screenInfo is initialized properly
176+
const safeScreenInfo = screenInfo && screenInfo.width
177+
? screenInfo
178+
: { width: window.innerWidth, height: window.innerHeight, deviceType: "desktop" };
179+
180+
// Get device type based on width
181+
const getDeviceType = (width: number) => {
182+
if (width < 768) return "mobile";
183+
if (width < 1024) return "tablet";
184+
return "desktop";
185+
};
186+
187+
// Observe component width dynamically
188+
useEffect(() => {
189+
if (!containerRef.current) return;
190+
191+
const resizeObserver = new ResizeObserver((entries) => {
192+
for (let entry of entries) {
193+
setComponentWidth(entry.contentRect.width);
194+
}
195+
});
196+
197+
resizeObserver.observe(containerRef.current);
198+
return () => resizeObserver.disconnect();
199+
}, []);
200+
201+
const totalColumns = columns.length;
202+
203+
// Decide between screen width or component width
204+
const effectiveWidth = useComponentWidth ? componentWidth ?? safeScreenInfo.width : safeScreenInfo.width;
205+
const effectiveDeviceType = useComponentWidth ? getDeviceType(effectiveWidth || 1000) : safeScreenInfo.deviceType;
206+
207+
// Get columns per row based on device type
208+
let configuredColumnsPerRow = effectiveDeviceType === "mobile"
209+
? columnPerRowSM
210+
: effectiveDeviceType === "tablet"
211+
? columnPerRowMD
212+
: columnPerRowLG;
213+
214+
// Calculate max columns that fit based on minWidth
215+
let maxColumnsThatFit = componentWidth
216+
? Math.floor(componentWidth / Math.max(...columns.map((col) => parseFloat(col.minWidth || "0"))))
217+
: configuredColumnsPerRow;
218+
219+
// Determine actual number of columns
220+
let numberOfColumns = rowBreak ? configuredColumnsPerRow : Math.min(maxColumnsThatFit, totalColumns);
221+
151222
return (
152223
<BackgroundColorContext.Provider value={props.style.background}>
153224
<DisabledContext.Provider value={props.disabled}>
154-
<div style={{padding: style.margin, height: '100%'}}>
225+
<div ref={containerRef} style={{ padding: style.margin, height: "100%" }}>
155226
<RowWrapper
156-
$style={style}
227+
$style={{ ...style }}
157228
$animationStyle={animationStyle}
158229
$showScrollbar={mainScrollbar}
230+
$columnCount={numberOfColumns}
159231
wrap={rowBreak}
160232
gutter={[horizontalSpacing, verticalSpacing]}
161233
>
162-
{columns.map(column => {
234+
{columns.map((column) => {
163235
const id = String(column.id);
164236
const childDispatch = wrapDispatch(wrapDispatch(dispatch, "containers"), id);
165-
if(!containers[id]) return null
237+
if (!containers[id]) return null;
166238
const containerProps = containers[id].children;
167-
const noOfColumns = columns.length;
239+
240+
const calculatedWidth = 100 / numberOfColumns;
241+
168242
return (
169243
<ColWrapper
170244
key={id}
171-
lg={24/(noOfColumns < columnPerRowLG ? noOfColumns : columnPerRowLG)}
172-
md={24/(noOfColumns < columnPerRowMD ? noOfColumns : columnPerRowMD)}
173-
sm={24/(noOfColumns < columnPerRowSM ? noOfColumns : columnPerRowSM)}
174-
xs={24/(noOfColumns < columnPerRowSM ? noOfColumns : columnPerRowSM)}
245+
lg={rowBreak ? 24 / numberOfColumns : undefined}
246+
md={rowBreak ? 24 / numberOfColumns : undefined}
247+
sm={rowBreak ? 24 / numberOfColumns : undefined}
248+
xs={rowBreak ? 24 / numberOfColumns : undefined}
175249
$style={props.columnStyle}
176-
$minWidth={column.minWidth}
250+
$minWidth={`${calculatedWidth}px`}
177251
$matchColumnsHeight={matchColumnsHeight}
252+
$rowBreak={rowBreak}
178253
>
179254
<ColumnContainer
180255
layout={containerProps.layout.getView()}
@@ -186,16 +261,16 @@ const ResponsiveLayout = (props: ResponsiveLayoutProps) => {
186261
style={columnStyle}
187262
/>
188263
</ColWrapper>
189-
)
190-
})
191-
}
264+
);
265+
})}
192266
</RowWrapper>
193267
</div>
194-
</DisabledContext.Provider>
268+
</DisabledContext.Provider>
195269
</BackgroundColorContext.Provider>
196270
);
197271
};
198272

273+
199274
export const ResponsiveLayoutBaseComp = (function () {
200275
return new UICompBuilder(childrenMap, (props, dispatch) => {
201276
return (
@@ -234,6 +309,10 @@ export const ResponsiveLayoutBaseComp = (function () {
234309
{children.rowBreak.propertyView({
235310
label: trans("responsiveLayout.rowBreak")
236311
})}
312+
{children.useComponentWidth.propertyView({
313+
label: trans("responsiveLayout.useComponentWidth"),
314+
tooltip : trans("responsiveLayout.useComponentWidthDesc")
315+
})}
237316
{controlItem({}, (
238317
<div style={{ marginTop: '8px' }}>
239318
{trans("responsiveLayout.columnsPerRow")}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
export { SplitLayoutComp } from "./splitLayout";

0 commit comments

Comments
 (0)
Please sign in to comment.