100 lines
2.9 KiB
JavaScript
100 lines
2.9 KiB
JavaScript
import { Grid, Table } from "antd";
|
|
import { useMemo } from "react";
|
|
import "./responsive-table.styles.scss";
|
|
|
|
function ResponsiveTable({ className, columns, mobileColumnKeys, scroll, tableLayout, ...rest }) {
|
|
const screens = Grid.useBreakpoint();
|
|
const isPhone = !screens.md;
|
|
const isCompactViewport = !screens.lg;
|
|
const prefersHorizontalScroll = isPhone || isCompactViewport;
|
|
const isResponsiveFilteringEnabled = ["1", "true", "yes", "on"].includes(
|
|
String(import.meta.env.VITE_APP_ENABLE_RESPONSIVE_TABLE_FILTERING || "")
|
|
.trim()
|
|
.toLowerCase()
|
|
);
|
|
|
|
const resolvedColumns = useMemo(() => {
|
|
if (
|
|
!isResponsiveFilteringEnabled ||
|
|
!Array.isArray(columns) ||
|
|
!isPhone ||
|
|
!Array.isArray(mobileColumnKeys) ||
|
|
mobileColumnKeys.length === 0
|
|
) {
|
|
return columns;
|
|
}
|
|
|
|
const visibleColumnKeys = new Set(mobileColumnKeys);
|
|
const filteredColumns = columns.filter((column) => {
|
|
const key = column?.key ?? column?.dataIndex;
|
|
|
|
// Keep columns with no stable key to avoid accidental loss.
|
|
if (key == null) return true;
|
|
|
|
if (Array.isArray(key)) {
|
|
return key.some((part) => visibleColumnKeys.has(part));
|
|
}
|
|
|
|
return visibleColumnKeys.has(key);
|
|
});
|
|
|
|
return filteredColumns.length > 0 ? filteredColumns : columns;
|
|
}, [columns, isPhone, isResponsiveFilteringEnabled, mobileColumnKeys]);
|
|
|
|
const resolvedScroll = useMemo(() => {
|
|
if (prefersHorizontalScroll) {
|
|
if (scroll == null) {
|
|
return { x: "max-content" };
|
|
}
|
|
|
|
if (typeof scroll !== "object" || Array.isArray(scroll)) {
|
|
return scroll;
|
|
}
|
|
|
|
const { x, ...baseScroll } = scroll;
|
|
|
|
return { ...baseScroll, x: x ?? "max-content" };
|
|
}
|
|
|
|
if (scroll == null) {
|
|
// Explicitly override ConfigProvider table.scroll desktop defaults.
|
|
return {};
|
|
}
|
|
|
|
if (typeof scroll !== "object" || Array.isArray(scroll)) {
|
|
return scroll;
|
|
}
|
|
|
|
const { x, ...desktopScroll } = scroll;
|
|
|
|
// On desktop we prefer fitting columns with ellipsis over forced horizontal scroll.
|
|
if (x == null) {
|
|
return desktopScroll;
|
|
}
|
|
|
|
return desktopScroll;
|
|
}, [prefersHorizontalScroll, scroll]);
|
|
|
|
const resolvedTableLayout = tableLayout ?? (prefersHorizontalScroll ? "auto" : "fixed");
|
|
const responsiveClassName = prefersHorizontalScroll ? undefined : "responsive-table-fit";
|
|
const resolvedClassName = [responsiveClassName, className].filter(Boolean).join(" ");
|
|
|
|
return (
|
|
<Table
|
|
className={resolvedClassName}
|
|
columns={resolvedColumns}
|
|
scroll={resolvedScroll}
|
|
tableLayout={resolvedTableLayout}
|
|
{...rest}
|
|
/>
|
|
);
|
|
}
|
|
|
|
ResponsiveTable.Summary = Table.Summary;
|
|
ResponsiveTable.Column = Table.Column;
|
|
ResponsiveTable.ColumnGroup = Table.ColumnGroup;
|
|
ResponsiveTable.SELECTION_COLUMN = Table.SELECTION_COLUMN;
|
|
ResponsiveTable.EXPAND_COLUMN = Table.EXPAND_COLUMN;
|
|
|
|
export default ResponsiveTable;
|