diff --git a/client/packages/lowcoder/src/comps/comps/columnLayout/columnLayout.tsx b/client/packages/lowcoder/src/comps/comps/columnLayout/columnLayout.tsx index 7b9c80a24..f30a3f808 100644 --- a/client/packages/lowcoder/src/comps/comps/columnLayout/columnLayout.tsx +++ b/client/packages/lowcoder/src/comps/comps/columnLayout/columnLayout.tsx @@ -72,6 +72,7 @@ const ColWrapper = styled(Col)<{ $minWidth?: string, $matchColumnsHeight: boolean, }>` + min-width: ${(props) => props.$minWidth || 'auto'}; > div { height: ${(props) => props.$matchColumnsHeight ? `calc(100% - ${props.$style?.padding || 0} - ${props.$style?.padding || 0})` : 'auto'}; border-radius: ${(props) => props.$style?.radius}; @@ -122,6 +123,53 @@ const ColumnContainer = (props: ColumnContainerProps) => { ); }; +// Function to apply min-widths to grid template columns +const applyMinWidthsToGridColumns = (columnsDef: string, minWidths: (string | null)[] = []) => { + // Handle empty case + if (!columnsDef?.trim()) return ''; + + // Handle repeat() functions with special parsing + if (columnsDef.includes('repeat(')) { + // For complex repeat patterns, we should return as-is to avoid breaking the layout + // A more complex parser would be needed to fully support repeat with minmax + return columnsDef; + } + + const columns = columnsDef.trim().split(/\s+/); + + const newColumns = columns.map((col, index) => { + const minWidth = minWidths[index]; + + // Skip if no minWidth provided for this column + if (!minWidth) { + return col; + } + + // Keywords that should never be wrapped in minmax() + const keywords = ['auto', 'min-content', 'max-content', 'fit-content', 'subgrid']; + if (keywords.some(keyword => col === keyword)) { + return col; + } + + // Functions that should never be wrapped in minmax() + if (col.includes('(') && col.includes(')')) { + // Already includes a function like calc(), minmax(), etc. + return col; + } + + // Determine if column is flexible and can be wrapped with minmax + // - fr units (e.g., "1fr", "2.5fr") + // - percentage values (e.g., "50%") + // - length values (px, em, rem, etc.) + const isFlexible = /fr$/.test(col) || + /%$/.test(col) || + /^\d+(\.\d+)?(px|em|rem|vh|vw|vmin|vmax|cm|mm|in|pt|pc)$/.test(col); + + return isFlexible ? `minmax(${minWidth}, ${col})` : col; + }); + + return newColumns.join(' '); +}; const ColumnLayout = (props: ColumnLayoutProps) => { let { @@ -138,6 +186,12 @@ const ColumnLayout = (props: ColumnLayoutProps) => { mainScrollbar } = props; + // Extract minWidths from columns + const minWidths = columns.map(column => column.minWidth || null); + + // Apply min-widths to grid template columns + const gridTemplateColumns = applyMinWidthsToGridColumns(templateColumns, minWidths); + return ( @@ -146,7 +200,7 @@ const ColumnLayout = (props: ColumnLayoutProps) => { props.$rowBreak ? `calc(100% / var(--columns))` // Force exact column distribution - : `clamp(${props.$minWidth}, 100% / var(--columns), 100%)`}; // MinWidth respected + : `clamp(${props.$minWidth || "0px"}, calc(100% / var(--columns)), 100%)`}; // MinWidth respected min-width: ${(props) => props.$minWidth}; // Ensure minWidth is respected max-width: 100%; // Prevent more columns than allowed @@ -237,7 +237,8 @@ const ResponsiveLayout = (props: ResponsiveLayoutProps) => { if (!containers[id]) return null; const containerProps = containers[id].children; - const calculatedWidth = 100 / numberOfColumns; + // Use the actual minWidth from column configuration instead of calculated width + const columnMinWidth = column.minWidth || `${100 / numberOfColumns}px`; return ( { sm={rowBreak ? 24 / numberOfColumns : undefined} xs={rowBreak ? 24 / numberOfColumns : undefined} $style={props.columnStyle} - $minWidth={`${calculatedWidth}px`} + $minWidth={columnMinWidth} $matchColumnsHeight={matchColumnsHeight} $rowBreak={rowBreak} >