Revert "Release/2026 02 27 (pull request #3070)"

This commit is contained in:
Patrick Fic
2026-03-04 16:18:44 +00:00
parent 522f2b9e26
commit c9e41ba72a
204 changed files with 5497 additions and 7715 deletions

View File

@@ -1,167 +1,59 @@
import { Card, Col, Row } from "antd";
import { Children, isValidElement } from "react";
import { Col, Divider, Row } from "antd";
import "./layout-form-row.styles.scss";
export default function LayoutFormRow({
header,
children,
grow = false,
noDivider = false,
gutter = [16, 16], // Responsive gutter: horizontal, vertical
rowProps,
export default function LayoutFormRow({ header, children, grow = false, noDivider = false, ...restProps }) {
const DividerHeader = () =>
!noDivider && (
<Divider titlePlacement="left" orientation="horizontal" style={{ marginTop: ".8rem" }}>
{header}
</Divider>
);
// Optional overrides if you ever need per-section customization
surface = true,
surfaceBg,
surfaceHeaderBg,
...cardProps
}) {
const items = Children.toArray(children).filter(Boolean);
if (items.length === 0) return null;
const title = !noDivider && header ? header : undefined;
const bg = surfaceBg ?? (surface ? "var(--imex-form-surface)" : undefined);
const headBg = surfaceHeaderBg ?? (surface ? "var(--imex-form-surface-head)" : undefined);
const mergedStyles = mergeSemanticStyles(
{
header: {
paddingInline: 16,
background: headBg
},
body: {
padding: 16,
background: bg
}
},
cardProps.styles
);
const baseCardStyle = {
marginBottom: ".8rem",
...(bg ? { background: bg } : null), // ensures the “circled area” is tinted
...cardProps.style
};
// single child => just render it
if (items.length === 1) {
if (!children.length) {
//We have only one element. It's going to get the whole thing.
return (
<Card
{...cardProps}
title={cardProps.title ?? title}
size={cardProps.size ?? "small"}
variant={cardProps.variant ?? "outlined"}
className={["imex-form-row", cardProps.className].filter(Boolean).join(" ")}
style={baseCardStyle}
styles={mergedStyles}
>
{items[0]}
</Card>
<div className="imex-form-row" {...restProps} style={{ marginBottom: ".8rem", ...restProps.style }}>
<DividerHeader />
{children}
</div>
);
}
const rowGutter = { gutter: [16, 16] };
const count = items.length;
// Modern responsive strategy leveraging Ant Design 6:
// - xs (phone <576px): Always stack vertically
// - sm (tablet 576-768px): 2 columns for better readability
// - md (tablet 768-992px): 3 columns for tablets
// - lg+ (desktop >992px): Dynamic flex-based columns that adapt to screen width
// Target: 1366px → 4 cols, 1920px → 6 cols, 2560px → 8 cols, 4K → capped at 8-9 cols
// Note: xxl uses higher min-width to naturally cap maximum columns
const baseCol = (() => {
if (grow) {
// Grow mode: use flex with reasonable min-widths
return {
xs: 24,
sm: 12, // Fixed 2 cols on small tablets
md: 8, // Fixed 3 cols on large tablets
lg: { flex: `1 1 320px` }, // Dynamic: ~3 cols at 1200px
xl: { flex: `1 1 280px` }, // Dynamic: ~4 cols at 1366px, ~6 cols at 1920px
xxl: { flex: `1 1 380px` } // Dynamic: ~6 cols at 2560px, ~9 cols at 4K (capped)
};
} else {
// Fixed mode: Use flex without grow to maintain uniform widths across rows
// xxl uses larger min-width to cap maximum columns on 4K/ultrawide
const minWidthLg = count <= 2 ? 500 : count === 3 ? 380 : 320; // 3 cols at 1200px
const minWidthXl = count <= 2 ? 480 : count === 3 ? 360 : 280; // 4 cols at 1366px, ~6 at 1920px
const minWidthXxl = count <= 2 ? 500 : count === 3 ? 400 : 380; // ~6 cols at 2560px, ~9 at 4K (natural cap)
return {
xs: 24,
sm: 12, // Fixed 2 columns on tablet
md: count === 1 ? 24 : count === 2 ? 12 : 8, // Fixed 1-3 cols on large tablet
lg: count === 1 ? 24 : { flex: `0 0 ${minWidthLg}px` }, // Fixed width on desktop
xl: count === 1 ? 24 : { flex: `0 0 ${minWidthXl}px` }, // Fixed width on large desktop
xxl: count === 1 ? 24 : { flex: `0 0 ${minWidthXxl}px` } // Fixed width on ultrawide
};
}
})();
const getColPropsForChild = (child) => {
if (!isValidElement(child)) return baseCol;
// Back-compat: child.props.span can override Col sizing
const spanOverride = child.props?.span;
if (typeof spanOverride === "number") return { span: spanOverride };
if (spanOverride && typeof spanOverride === "object") return spanOverride;
// Explicit override: <Field col={{ md:{span:12}, ... }} />
const colOverride = child.props?.col;
if (colOverride && typeof colOverride === "object") {
// Deep merge: allow partial overrides while keeping baseCol defaults
const merged = { ...baseCol };
Object.keys(colOverride).forEach((bp) => {
merged[bp] = typeof colOverride[bp] === "object" ? { ...baseCol[bp], ...colOverride[bp] } : colOverride[bp];
});
return merged;
}
return baseCol;
const colSpan = (spanOverride) => {
if (spanOverride) return { span: spanOverride };
return {
xs: {
span: !grow ? 24 : Math.max(12, 24 / children.length)
},
sm: {
span: !grow ? 12 : Math.max(12, 24 / children.length)
},
md: {
span: !grow ? 8 : Math.max(8, 24 / children.length)
},
lg: {
span: !grow ? 6 : Math.max(6, 24 / children.length)
},
xl: {
span: !grow ? 4 : Math.max(4, 24 / children.length)
}
};
};
//{header ? <Typography.Title level={4}>{header}</Typography.Title> : null}
return (
<Card
{...cardProps}
title={cardProps.title ?? title}
size={cardProps.size ?? "small"}
variant={cardProps.variant ?? "outlined"}
className={["imex-form-row", cardProps.className].filter(Boolean).join(" ")}
style={baseCardStyle}
styles={mergedStyles}
>
<Row gutter={gutter} wrap {...rowProps}>
{items.map((child, idx) => (
<Col key={child?.key ?? idx} {...getColPropsForChild(child)}>
{child}
</Col>
))}
<div className="imex-form-row" {...restProps} style={{ marginBottom: ".8rem", ...restProps.style }}>
<DividerHeader />
<Row {...rowGutter}>
{children.map(
(c, idx) =>
c && (
<Col key={idx} {...colSpan(c && c.props && c.props.span)}>
{c}
</Col>
)
)}
</Row>
</Card>
</div>
);
}
function mergeSemanticStyles(defaults, userStyles) {
if (!userStyles) return defaults;
if (typeof userStyles === "function") {
return (info) => {
const computed = userStyles(info) || {};
return {
...defaults,
...computed,
header: { ...defaults.header, ...(computed.header || {}) },
body: { ...defaults.body, ...(computed.body || {}) }
};
};
}
return {
...defaults,
...userStyles,
header: { ...defaults.header, ...(userStyles.header || {}) },
body: { ...defaults.body, ...(userStyles.body || {}) }
};
}