Skip to content

Commit 8b492c2

Browse files
committed
refactor tableCompView
1 parent d4afdb4 commit 8b492c2

File tree

3 files changed

+266
-865
lines changed

3 files changed

+266
-865
lines changed
Lines changed: 131 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,131 @@
1+
import React, { useCallback, useMemo, useState } from "react";
2+
import { default as Table, TableProps, ColumnType } from "antd/es/table";
3+
import ResizeableTitle from "./ResizeableTitle";
4+
import TableCellView from "./TableCellView";
5+
import { COL_MIN_WIDTH, CustomColumnType } from "../tableUtils";
6+
import { TableColumnStyleType } from "comps/controls/styleControlConstants";
7+
import { RowColorViewType, RowHeightViewType } from "../tableTypes";
8+
9+
export type ResizeableTableProps<RecordType> = Omit<TableProps<RecordType>, "components" | "columns"> & {
10+
columns: CustomColumnType<RecordType>[];
11+
viewModeResizable: boolean;
12+
rowColorFn: RowColorViewType;
13+
rowHeightFn: RowHeightViewType;
14+
columnsStyle: TableColumnStyleType;
15+
size?: string;
16+
rowAutoHeight?: boolean;
17+
customLoading?: boolean;
18+
onCellClick: (columnName: string, dataIndex: string) => void;
19+
};
20+
21+
/**
22+
* A table with adjustable column width, width less than 0 means auto column width
23+
*/
24+
function ResizeableTableComp<RecordType extends object>(props: ResizeableTableProps<RecordType>) {
25+
const {
26+
columns,
27+
viewModeResizable,
28+
rowColorFn,
29+
rowHeightFn,
30+
columnsStyle,
31+
size,
32+
rowAutoHeight,
33+
customLoading,
34+
onCellClick,
35+
...restProps
36+
} = props;
37+
const [resizeData, setResizeData] = useState({ index: -1, width: -1 });
38+
39+
const handleResize = useCallback((width: number, index: number) => {
40+
setResizeData({ index, width });
41+
}, []);
42+
43+
const handleResizeStop = useCallback(
44+
(width: number, index: number, onWidthResize?: (width: number) => void) => {
45+
setResizeData({ index: -1, width: -1 });
46+
if (onWidthResize) {
47+
onWidthResize(width);
48+
}
49+
},
50+
[]
51+
);
52+
53+
const createCellHandler = useCallback(
54+
(col: CustomColumnType<RecordType>) => {
55+
return (record: RecordType, index: number) => ({
56+
record,
57+
title: String(col.dataIndex),
58+
rowColorFn,
59+
rowHeightFn,
60+
cellColorFn: col.cellColorFn,
61+
rowIndex: index,
62+
columnsStyle,
63+
columnStyle: col.style,
64+
linkStyle: col.linkStyle,
65+
tableSize: size,
66+
autoHeight: rowAutoHeight,
67+
onClick: () => onCellClick(col.titleText, String(col.dataIndex)),
68+
loading: customLoading,
69+
customAlign: col.align,
70+
});
71+
},
72+
[rowColorFn, rowHeightFn, columnsStyle, size, rowAutoHeight, onCellClick, customLoading]
73+
);
74+
75+
const createHeaderCellHandler = useCallback(
76+
(col: CustomColumnType<RecordType>, index: number, resizeWidth: number) => {
77+
return () => ({
78+
width: resizeWidth,
79+
title: col.titleText,
80+
viewModeResizable,
81+
onResize: (width: React.SyntheticEvent) => {
82+
if (width) {
83+
handleResize(Number(width), index);
84+
}
85+
},
86+
onResizeStop: (e: React.SyntheticEvent, { size }: { size: { width: number } }) => {
87+
handleResizeStop(size.width, index, col.onWidthResize);
88+
},
89+
});
90+
},
91+
[viewModeResizable, handleResize, handleResizeStop]
92+
);
93+
94+
const memoizedColumns = useMemo(() => {
95+
return columns.map((col: CustomColumnType<RecordType>, index: number) => {
96+
const { width, style, linkStyle, cellColorFn, onWidthResize, ...restCol } = col;
97+
const resizeWidth = (resizeData.index === index ? resizeData.width : col.width) ?? 0;
98+
99+
const column: ColumnType<RecordType> = {
100+
...restCol,
101+
width: typeof resizeWidth === "number" && resizeWidth > 0 ? resizeWidth : undefined,
102+
minWidth: typeof resizeWidth === "number" && resizeWidth > 0 ? undefined : COL_MIN_WIDTH,
103+
onCell: (record: RecordType, index?: number) => createCellHandler(col)(record, index ?? 0),
104+
onHeaderCell: () => createHeaderCellHandler(col, index, Number(resizeWidth))(),
105+
};
106+
return column;
107+
});
108+
}, [columns, resizeData, createCellHandler, createHeaderCellHandler]);
109+
110+
return (
111+
<Table<RecordType>
112+
components={{
113+
header: {
114+
cell: ResizeableTitle,
115+
},
116+
body: {
117+
cell: TableCellView,
118+
},
119+
}}
120+
{...restProps}
121+
pagination={false}
122+
columns={memoizedColumns}
123+
scroll={{
124+
x: COL_MIN_WIDTH * columns.length,
125+
}}
126+
/>
127+
);
128+
}
129+
130+
const ResizeableTable = React.memo(ResizeableTableComp) as typeof ResizeableTableComp;
131+
export default ResizeableTable;
Lines changed: 93 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,93 @@
1+
import React, { useCallback, useEffect, useRef, useState } from "react";
2+
import _ from "lodash";
3+
import { Resizable } from "react-resizable";
4+
import styled from "styled-components";
5+
import { useUserViewMode } from "util/hooks";
6+
import { ReactRef, ResizeHandleAxis } from "layout/gridLayoutPropTypes";
7+
8+
const TitleResizeHandle = styled.span`
9+
position: absolute;
10+
top: 0;
11+
right: -5px;
12+
width: 10px;
13+
height: 100%;
14+
cursor: col-resize;
15+
z-index: 1;
16+
`;
17+
18+
const TableTh = styled.th<{ width?: number }>`
19+
overflow: hidden;
20+
21+
> div {
22+
overflow: hidden;
23+
white-space: pre;
24+
text-overflow: ellipsis;
25+
}
26+
27+
${(props) => props.width && `width: ${props.width}px`};
28+
`;
29+
30+
const ResizeableTitle = (props: any) => {
31+
const { onResize, onResizeStop, width, viewModeResizable, ...restProps } = props;
32+
const [childWidth, setChildWidth] = useState(0);
33+
const resizeRef = useRef<HTMLDivElement>(null);
34+
const isUserViewMode = useUserViewMode();
35+
36+
const updateChildWidth = useCallback(() => {
37+
if (resizeRef.current) {
38+
const width = resizeRef.current.getBoundingClientRect().width;
39+
setChildWidth(width);
40+
}
41+
}, []);
42+
43+
useEffect(() => {
44+
updateChildWidth();
45+
const resizeObserver = new ResizeObserver(() => {
46+
updateChildWidth();
47+
});
48+
49+
if (resizeRef.current) {
50+
resizeObserver.observe(resizeRef.current);
51+
}
52+
53+
return () => {
54+
resizeObserver.disconnect();
55+
};
56+
}, [updateChildWidth]);
57+
58+
const isNotDataColumn = _.isNil(restProps.title);
59+
if ((isUserViewMode && !restProps.viewModeResizable) || isNotDataColumn) {
60+
return <TableTh ref={resizeRef} {...restProps} width={width} />;
61+
}
62+
63+
return (
64+
<Resizable
65+
width={width > 0 ? width : childWidth}
66+
height={0}
67+
onResize={(e: React.SyntheticEvent, { size }: { size: { width: number } }) => {
68+
e.stopPropagation();
69+
onResize(size.width);
70+
}}
71+
onResizeStart={(e: React.SyntheticEvent) => {
72+
updateChildWidth();
73+
e.stopPropagation();
74+
e.preventDefault();
75+
}}
76+
onResizeStop={onResizeStop}
77+
draggableOpts={{ enableUserSelectHack: false }}
78+
handle={(axis: ResizeHandleAxis, ref: ReactRef<HTMLDivElement>) => (
79+
<TitleResizeHandle
80+
ref={ref}
81+
onClick={(e) => {
82+
e.preventDefault();
83+
e.stopPropagation();
84+
}}
85+
/>
86+
)}
87+
>
88+
<TableTh ref={resizeRef} {...restProps} title="" />
89+
</Resizable>
90+
);
91+
};
92+
93+
export default ResizeableTitle;

0 commit comments

Comments
 (0)