Skip to content

Commit

Permalink
feat: column resizable
Browse files Browse the repository at this point in the history
  • Loading branch information
linxianxi committed Apr 25, 2024
1 parent b43c2f2 commit c50f2da
Show file tree
Hide file tree
Showing 17 changed files with 646 additions and 118 deletions.
2 changes: 2 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -129,9 +129,11 @@ React.render(<Table columns={columns} data={data} />, mountNode);
| title | React Node | | title of this column |
| dataIndex | String | | display field of the data record |
| width | String \| Number | | width of the specific proportion calculation according to the width of the columns |
| minWidth | Number | | min width of the specific proportion calculation according to the width of the columns |
| fixed | String \| Boolean | | this column will be fixed when table scroll horizontally: true or 'left' or 'right' |
| align | String | | specify how cell content is aligned |
| ellipsis | Boolean | | specify whether cell content be ellipsized |
| resizable | Boolean | | column resize |
| rowScope | 'row' \| 'rowgroup' | | Set scope attribute for all cells in this column |
| onCell | Function(record, index) | | Set custom props per each cell. |
| onHeaderCell | Function(record) | | Set custom props per each header cell. |
Expand Down
30 changes: 30 additions & 0 deletions assets/index.less
Original file line number Diff line number Diff line change
Expand Up @@ -63,9 +63,39 @@
}
}

&-column-resizing {
cursor: col-resize;
}

&-cell {
background: #f4f4f4;

&-resize-handle {
position: absolute;
top: 0;
right: 0;
width: 4px;
height: 100%;
cursor: col-resize;
z-index: 1;
background: red;
}

&-resize-line {
position: absolute;
width: 4px;
background: red;
height: 100%;
top: 0;
transform: translateX(-50%);
z-index: 2;
}


&-fix-right &-resize-handle {
left: 0;
}

&-fix-left,
&-fix-right {
z-index: 2;
Expand Down
184 changes: 98 additions & 86 deletions docs/examples/column-resize.tsx
Original file line number Diff line number Diff line change
@@ -1,95 +1,107 @@
import React from 'react';
import { Resizable } from 'react-resizable';
import Table from 'rc-table';
import React, { useState } from 'react';
import Table, { INTERNAL_HOOKS } from 'rc-table';
import type { ColumnType } from 'rc-table';
import '../../assets/index.less';
import 'react-resizable/css/styles.css';
import type { ColumnType } from '@/interface';

const ResizableTitle = props => {
const { onResize, width, ...restProps } = props;
const data = [
{ a: '123', b: 'xxxxxxxx xxxxxxxx', d: 3, key: '1' },
{ a: 'cdd', b: 'edd12221 edd12221', d: 3, key: '2' },
{ a: '133', c: 'edd12221 edd12221', d: 2, key: '3' },
{ a: '133', c: 'edd12221 edd12221', d: 2, key: '4' },
{ a: '133', c: 'edd12221 edd12221', d: 2, key: '5' },
{ a: '133', c: 'edd12221 edd12221', d: 2, key: '6' },
{ a: '133', c: 'edd12221 edd12221', d: 2, key: '7' },
{ a: '133', c: 'edd12221 edd12221', d: 2, key: '8' },
{ a: '133', c: 'edd12221 edd12221', d: 2, key: '9' },
];

if (!width) {
return <th {...restProps} />;
}
const Demo = () => {
const [widthMap, setWidthMap] = useState<Map<React.Key, number>>(new Map());

const columns1 = [
{ title: 'title1', dataIndex: 'aaa', key: 'aaa', width: 100 },
{ title: 'title2', dataIndex: 'bbb', key: 'bbb', width: 100 },
].map(i => ({
...i,
resizable: true,
width: widthMap.get(i.key ?? i.dataIndex) ?? i.width,
})) as ColumnType<any>[];

const columns2 = [
{ title: 'title1', dataIndex: 'a', key: 'a', fixed: 'left' },
{ title: 'title2', dataIndex: 'b', key: 'b', fixed: 'left' },
{ title: 'title3', dataIndex: 'c', key: 'c' },
{ title: 'title4', dataIndex: 'b', key: 'd' },
{ title: 'title5', dataIndex: 'b', key: 'e' },
{ title: 'title6', dataIndex: 'b', key: 'f' },
{ title: 'title7', dataIndex: 'b', key: 'g' },
{ title: 'title8', dataIndex: 'b', key: 'h' },
{ title: 'title9', dataIndex: 'b', key: 'i' },
{ title: 'title10', dataIndex: 'b', key: 'j' },
{ title: 'title11', dataIndex: 'b', key: 'k', fixed: 'right' },
{ title: 'title12', dataIndex: 'b', key: 'l', fixed: 'right' },
].map(i => ({
...i,
resizable: true,
width: widthMap.get(i.key ?? i.dataIndex) ?? 150,
})) as ColumnType<any>[];

return (
<Resizable width={width} height={0} onResize={onResize}>
<th {...restProps} />
</Resizable>
<div>
table width: 800px {'columns=[{width: 100, width: 100}]'} 情况
<Table
style={{ width: 800 }}
scroll={{ y: 300, x: columns1.reduce((t, c) => t + (c.width as number), 0) }}
columns={columns1}
data={data}
onColumnResizeComplete={({ columnWidths }) => {
setWidthMap(prev => {
const result = new Map(prev);
columnWidths.forEach(i => {
result.set(i.columnKey, i.width);
});
return result;
});
}}
internalHooks={INTERNAL_HOOKS}
getContainerWidth={(ele, width) => {
// Minus border
const borderWidth = getComputedStyle(
ele.querySelector('.rc-table-body'),
).borderInlineStartWidth;
const mergedWidth = width - parseInt(borderWidth, 10);
return mergedWidth;
}}
/>
<br />
大多数情况
<Table
style={{ width: 800 }}
scroll={{ y: 300, x: columns2.reduce((t, c) => t + (c.width as number), 0) }}
columns={columns2}
data={data}
onColumnResizeComplete={({ columnWidths }) => {
setWidthMap(prev => {
const result = new Map(prev);
columnWidths.forEach(i => {
result.set(i.columnKey, i.width);
});
return result;
});
}}
internalHooks={INTERNAL_HOOKS}
getContainerWidth={(ele, width) => {
// Minus border
const borderWidth = getComputedStyle(
ele.querySelector('.rc-table-body'),
).borderInlineStartWidth;
const mergedWidth = width - parseInt(borderWidth, 10);
return mergedWidth;
}}
/>
{/* <Table resizable style={{ width: 800 }} columns={columns} data={data} /> */}
</div>
);
};

interface RecordType {
a: string;
b?: string;
c?: string;
d?: number;
key: string;
}

interface DemoState {
columns: ColumnType<RecordType>[];
}

class Demo extends React.Component<{}, DemoState> {
state: DemoState = {
columns: [
{ title: 'title1', dataIndex: 'a', key: 'a', width: 100 },
{ title: 'title2', dataIndex: 'b', key: 'b', width: 100 },
{ title: 'title3', dataIndex: 'c', key: 'c', width: 200 },
{
title: 'Operations',
dataIndex: '',
key: 'd',
render() {
return <a href="#">Operations</a>;
},
},
],
};

components = {
header: {
cell: ResizableTitle,
},
};

data = [
{ a: '123', key: '1' },
{ a: 'cdd', b: 'edd', key: '2' },
{ a: '1333', c: 'eee', d: 2, key: '3' },
];

handleResize =
index =>
(e, { size }) => {
this.setState(({ columns }) => {
const nextColumns = [...columns];
nextColumns[index] = {
...nextColumns[index],
width: size.width,
};
return { columns: nextColumns };
});
};

render() {
const columns = this.state.columns.map((col, index) => ({
...col,
onHeaderCell: (column: ColumnType<RecordType>) =>
({
width: column.width,
onResize: this.handleResize(index),
}) as any,
}));

return (
<div>
<h2>Integrate with react-resizable</h2>
<Table components={this.components} columns={columns} data={this.data} />
</div>
);
}
}

export default Demo;
1 change: 0 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -98,7 +98,6 @@
"react-dnd": "^2.5.4",
"react-dnd-html5-backend": "^2.5.4",
"react-dom": "^16.0.0",
"react-resizable": "^3.0.5",
"react-virtualized": "^9.12.0",
"react-window": "^1.8.5",
"regenerator-runtime": "^0.14.0",
Expand Down
6 changes: 3 additions & 3 deletions src/Body/MeasureCell.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,15 +3,15 @@ import ResizeObserver from 'rc-resize-observer';

export interface MeasureCellProps {
columnKey: React.Key;
onColumnResize: (key: React.Key, width: number) => void;
onColumnWidthChange: (key: React.Key, width: number) => void;
}

export default function MeasureCell({ columnKey, onColumnResize }: MeasureCellProps) {
export default function MeasureCell({ columnKey, onColumnWidthChange }: MeasureCellProps) {
const cellRef = React.useRef<HTMLTableCellElement>();

React.useEffect(() => {
if (cellRef.current) {
onColumnResize(columnKey, cellRef.current.offsetWidth);
onColumnWidthChange(columnKey, cellRef.current.offsetWidth);
}
}, []);

Expand Down
16 changes: 12 additions & 4 deletions src/Body/MeasureRow.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,15 @@ import MeasureCell from './MeasureCell';

export interface MeasureCellProps {
prefixCls: string;
onColumnResize: (key: React.Key, width: number) => void;
onColumnWidthChange: (key: React.Key, width: number) => void;
columnsKey: React.Key[];
}

export default function MeasureRow({ prefixCls, columnsKey, onColumnResize }: MeasureCellProps) {
export default function MeasureRow({
prefixCls,
columnsKey,
onColumnWidthChange,
}: MeasureCellProps) {
return (
<tr
aria-hidden="true"
Expand All @@ -18,12 +22,16 @@ export default function MeasureRow({ prefixCls, columnsKey, onColumnResize }: Me
<ResizeObserver.Collection
onBatchResize={infoList => {
infoList.forEach(({ data: columnKey, size }) => {
onColumnResize(columnKey, size.offsetWidth);
onColumnWidthChange(columnKey, size.offsetWidth);
});
}}
>
{columnsKey.map(columnKey => (
<MeasureCell key={columnKey} columnKey={columnKey} onColumnResize={onColumnResize} />
<MeasureCell
key={columnKey}
columnKey={columnKey}
onColumnWidthChange={onColumnWidthChange}
/>
))}
</ResizeObserver.Collection>
</tr>
Expand Down
6 changes: 3 additions & 3 deletions src/Body/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ function Body<RecordType>(props: BodyProps<RecordType>) {
const {
prefixCls,
getComponent,
onColumnResize,
onColumnWidthChange,
flattenColumns,
getRowKey,
expandedKeys,
Expand All @@ -34,7 +34,7 @@ function Body<RecordType>(props: BodyProps<RecordType>) {
} = useContext(TableContext, [
'prefixCls',
'getComponent',
'onColumnResize',
'onColumnWidthChange',
'flattenColumns',
'getRowKey',
'expandedKeys',
Expand Down Expand Up @@ -104,7 +104,7 @@ function Body<RecordType>(props: BodyProps<RecordType>) {
<MeasureRow
prefixCls={prefixCls}
columnsKey={columnsKey}
onColumnResize={onColumnResize}
onColumnWidthChange={onColumnWidthChange}
/>
)}

Expand Down
1 change: 0 additions & 1 deletion src/Cell/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -116,7 +116,6 @@ function Cell<RecordType>(props: CellProps<RecordType>) {
additionalProps = {},
isSticky,
} = props;

const cellPrefixCls = `${prefixCls}-cell`;
const { supportSticky, allColumnsFixedLeft, rowHoverable } = useContext(TableContext, [
'supportSticky',
Expand Down
31 changes: 31 additions & 0 deletions src/Header/HeaderCell.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
import * as React from 'react';
import type { CellProps } from '../Cell';
import Cell from '../Cell';
import useCellResize from './useCellResize';
import { useContext } from '@rc-component/context';
import TableContext from '../context/TableContext';

interface HeaderCellProps<RecordType> extends CellProps<RecordType> {
columnKey?: React.Key;
resizable?: boolean;
minWidth?: number;
}

function HeaderCell<RecordType>({
columnKey,
resizable,
minWidth,
...cellProps
}: HeaderCellProps<RecordType>) {
const { supportSticky } = useContext(TableContext, ['supportSticky']);

const { fixRight, prefixCls } = cellProps;
const isFixRight = typeof fixRight === 'number' && supportSticky;
const cellPrefixCls = `${prefixCls}-cell`;

const resizeHandleNode = useCellResize(columnKey, isFixRight, cellPrefixCls, resizable, minWidth);

return <Cell {...cellProps} appendNode={resizeHandleNode} />;
}

export default HeaderCell;
Loading

0 comments on commit c50f2da

Please sign in to comment.