docs: add drag column sorting demo (#48434)

* docs(table): add drag column sorting demo

* update test snap

* chore: add script to adapt os memory

* Revert "update test snap"

This reverts commit be1a30e7ec.

revert commit#

* revert

* revert

* snap

* add more column data

* update snap

* chore: column drag style

* update snap

* chore: optimize code

---------

Co-authored-by: afc163 <afc163@gmail.com>
This commit is contained in:
George H 2024-04-29 11:08:51 +08:00 committed by GitHub
parent c150885f5c
commit 786dfc0339
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
6 changed files with 908 additions and 0 deletions

View File

@ -4104,6 +4104,351 @@ exports[`renders components/table/demo/custom-filter-panel.tsx extend context co
exports[`renders components/table/demo/custom-filter-panel.tsx extend context correctly 2`] = `[]`;
exports[`renders components/table/demo/drag-column-sorting.tsx extend context correctly 1`] = `
Array [
<div
class="ant-table-wrapper"
>
<div
class="ant-spin-nested-loading"
>
<div
class="ant-spin-container"
>
<div
class="ant-table"
>
<div
class="ant-table-container"
>
<div
class="ant-table-content"
>
<table
style="table-layout: auto;"
>
<colgroup />
<thead
class="ant-table-thead"
>
<tr>
<th
aria-describedby="DndDescribedBy-5"
aria-disabled="false"
aria-roledescription="sortable"
class="ant-table-cell"
id="0"
role="button"
scope="col"
style="cursor: move;"
tabindex="0"
>
Name
</th>
<th
aria-describedby="DndDescribedBy-5"
aria-disabled="false"
aria-roledescription="sortable"
class="ant-table-cell"
id="1"
role="button"
scope="col"
style="cursor: move;"
tabindex="0"
>
Gender
</th>
<th
aria-describedby="DndDescribedBy-5"
aria-disabled="false"
aria-roledescription="sortable"
class="ant-table-cell"
id="2"
role="button"
scope="col"
style="cursor: move;"
tabindex="0"
>
Age
</th>
<th
aria-describedby="DndDescribedBy-5"
aria-disabled="false"
aria-roledescription="sortable"
class="ant-table-cell"
id="3"
role="button"
scope="col"
style="cursor: move;"
tabindex="0"
>
Email
</th>
<th
aria-describedby="DndDescribedBy-5"
aria-disabled="false"
aria-roledescription="sortable"
class="ant-table-cell"
id="4"
role="button"
scope="col"
style="cursor: move;"
tabindex="0"
>
Address
</th>
</tr>
</thead>
<tbody
class="ant-table-tbody"
>
<tr
class="ant-table-row ant-table-row-level-0"
data-row-key="1"
>
<td
class="ant-table-cell"
id="0"
>
John Brown
</td>
<td
class="ant-table-cell"
id="1"
>
male
</td>
<td
class="ant-table-cell"
id="2"
>
32
</td>
<td
class="ant-table-cell"
id="3"
>
John Brown@example.com
</td>
<td
class="ant-table-cell"
id="4"
>
London No. 1 Lake Park
</td>
</tr>
<tr
class="ant-table-row ant-table-row-level-0"
data-row-key="2"
>
<td
class="ant-table-cell"
id="0"
>
Jim Green
</td>
<td
class="ant-table-cell"
id="1"
>
female
</td>
<td
class="ant-table-cell"
id="2"
>
42
</td>
<td
class="ant-table-cell"
id="3"
>
jimGreen@example.com
</td>
<td
class="ant-table-cell"
id="4"
>
London No. 1 Lake Park
</td>
</tr>
<tr
class="ant-table-row ant-table-row-level-0"
data-row-key="3"
>
<td
class="ant-table-cell"
id="0"
>
Joe Black
</td>
<td
class="ant-table-cell"
id="1"
>
female
</td>
<td
class="ant-table-cell"
id="2"
>
32
</td>
<td
class="ant-table-cell"
id="3"
>
JoeBlack@example.com
</td>
<td
class="ant-table-cell"
id="4"
>
Sidney No. 1 Lake Park
</td>
</tr>
<tr
class="ant-table-row ant-table-row-level-0"
data-row-key="4"
>
<td
class="ant-table-cell"
id="0"
>
George Hcc
</td>
<td
class="ant-table-cell"
id="1"
>
male
</td>
<td
class="ant-table-cell"
id="2"
>
20
</td>
<td
class="ant-table-cell"
id="3"
>
george@example.com
</td>
<td
class="ant-table-cell"
id="4"
>
Sidney No. 1 Lake Park
</td>
</tr>
</tbody>
</table>
</div>
</div>
</div>
<ul
class="ant-pagination ant-table-pagination ant-table-pagination-right"
>
<li
aria-disabled="true"
class="ant-pagination-prev ant-pagination-disabled"
title="Previous Page"
>
<button
class="ant-pagination-item-link"
disabled=""
tabindex="-1"
type="button"
>
<span
aria-label="left"
class="anticon anticon-left"
role="img"
>
<svg
aria-hidden="true"
data-icon="left"
fill="currentColor"
focusable="false"
height="1em"
viewBox="64 64 896 896"
width="1em"
>
<path
d="M724 218.3V141c0-6.7-7.7-10.4-12.9-6.3L260.3 486.8a31.86 31.86 0 000 50.3l450.8 352.1c5.3 4.1 12.9.4 12.9-6.3v-77.3c0-4.9-2.3-9.6-6.1-12.6l-360-281 360-281.1c3.8-3 6.1-7.7 6.1-12.6z"
/>
</svg>
</span>
</button>
</li>
<li
class="ant-pagination-item ant-pagination-item-1 ant-pagination-item-active"
tabindex="0"
title="1"
>
<a
rel="nofollow"
>
1
</a>
</li>
<li
aria-disabled="true"
class="ant-pagination-next ant-pagination-disabled"
title="Next Page"
>
<button
class="ant-pagination-item-link"
disabled=""
tabindex="-1"
type="button"
>
<span
aria-label="right"
class="anticon anticon-right"
role="img"
>
<svg
aria-hidden="true"
data-icon="right"
fill="currentColor"
focusable="false"
height="1em"
viewBox="64 64 896 896"
width="1em"
>
<path
d="M765.7 486.8L314.9 134.7A7.97 7.97 0 00302 141v77.3c0 4.9 2.3 9.6 6.1 12.6l360 281.1-360 281.1c-3.9 3-6.1 7.7-6.1 12.6V883c0 6.7 7.7 10.4 12.9 6.3l450.8-352.1a31.96 31.96 0 000-50.4z"
/>
</svg>
</span>
</button>
</li>
</ul>
</div>
</div>
</div>,
<div
id="DndDescribedBy-5"
style="display: none;"
>
To pick up a draggable item, press the space bar.
While dragging, use the arrow keys to move the item.
Press space again to drop the item in its new position, or press escape to cancel.
</div>,
<div
aria-atomic="true"
aria-live="assertive"
id="DndLiveRegion-5"
role="status"
style="position: fixed; width: 1px; height: 1px; margin: -1px; border: 0px; padding: 0px; overflow: hidden; clip-path: inset(100%); white-space: nowrap;"
/>,
]
`;
exports[`renders components/table/demo/drag-column-sorting.tsx extend context correctly 2`] = `[]`;
exports[`renders components/table/demo/drag-sorting.tsx extend context correctly 1`] = `
Array [
<div

View File

@ -3582,6 +3582,332 @@ exports[`renders components/table/demo/custom-filter-panel.tsx correctly 1`] = `
</div>
`;
exports[`renders components/table/demo/drag-column-sorting.tsx correctly 1`] = `
<div
class="ant-table-wrapper"
>
<div
class="ant-spin-nested-loading"
>
<div
class="ant-spin-container"
>
<div
class="ant-table"
>
<div
class="ant-table-container"
>
<div
class="ant-table-content"
>
<table
style="table-layout:auto"
>
<colgroup />
<thead
class="ant-table-thead"
>
<tr>
<th
aria-describedby="DndDescribedBy-2"
aria-disabled="false"
aria-roledescription="sortable"
class="ant-table-cell"
id="0"
role="button"
scope="col"
style="cursor:move"
tabindex="0"
>
Name
</th>
<th
aria-describedby="DndDescribedBy-2"
aria-disabled="false"
aria-roledescription="sortable"
class="ant-table-cell"
id="1"
role="button"
scope="col"
style="cursor:move"
tabindex="0"
>
Gender
</th>
<th
aria-describedby="DndDescribedBy-2"
aria-disabled="false"
aria-roledescription="sortable"
class="ant-table-cell"
id="2"
role="button"
scope="col"
style="cursor:move"
tabindex="0"
>
Age
</th>
<th
aria-describedby="DndDescribedBy-2"
aria-disabled="false"
aria-roledescription="sortable"
class="ant-table-cell"
id="3"
role="button"
scope="col"
style="cursor:move"
tabindex="0"
>
Email
</th>
<th
aria-describedby="DndDescribedBy-2"
aria-disabled="false"
aria-roledescription="sortable"
class="ant-table-cell"
id="4"
role="button"
scope="col"
style="cursor:move"
tabindex="0"
>
Address
</th>
</tr>
</thead>
<tbody
class="ant-table-tbody"
>
<tr
class="ant-table-row ant-table-row-level-0"
data-row-key="1"
>
<td
class="ant-table-cell"
id="0"
>
John Brown
</td>
<td
class="ant-table-cell"
id="1"
>
male
</td>
<td
class="ant-table-cell"
id="2"
>
32
</td>
<td
class="ant-table-cell"
id="3"
>
John Brown@example.com
</td>
<td
class="ant-table-cell"
id="4"
>
London No. 1 Lake Park
</td>
</tr>
<tr
class="ant-table-row ant-table-row-level-0"
data-row-key="2"
>
<td
class="ant-table-cell"
id="0"
>
Jim Green
</td>
<td
class="ant-table-cell"
id="1"
>
female
</td>
<td
class="ant-table-cell"
id="2"
>
42
</td>
<td
class="ant-table-cell"
id="3"
>
jimGreen@example.com
</td>
<td
class="ant-table-cell"
id="4"
>
London No. 1 Lake Park
</td>
</tr>
<tr
class="ant-table-row ant-table-row-level-0"
data-row-key="3"
>
<td
class="ant-table-cell"
id="0"
>
Joe Black
</td>
<td
class="ant-table-cell"
id="1"
>
female
</td>
<td
class="ant-table-cell"
id="2"
>
32
</td>
<td
class="ant-table-cell"
id="3"
>
JoeBlack@example.com
</td>
<td
class="ant-table-cell"
id="4"
>
Sidney No. 1 Lake Park
</td>
</tr>
<tr
class="ant-table-row ant-table-row-level-0"
data-row-key="4"
>
<td
class="ant-table-cell"
id="0"
>
George Hcc
</td>
<td
class="ant-table-cell"
id="1"
>
male
</td>
<td
class="ant-table-cell"
id="2"
>
20
</td>
<td
class="ant-table-cell"
id="3"
>
george@example.com
</td>
<td
class="ant-table-cell"
id="4"
>
Sidney No. 1 Lake Park
</td>
</tr>
</tbody>
</table>
</div>
</div>
</div>
<ul
class="ant-pagination ant-table-pagination ant-table-pagination-right"
>
<li
aria-disabled="true"
class="ant-pagination-prev ant-pagination-disabled"
title="Previous Page"
>
<button
class="ant-pagination-item-link"
disabled=""
tabindex="-1"
type="button"
>
<span
aria-label="left"
class="anticon anticon-left"
role="img"
>
<svg
aria-hidden="true"
data-icon="left"
fill="currentColor"
focusable="false"
height="1em"
viewBox="64 64 896 896"
width="1em"
>
<path
d="M724 218.3V141c0-6.7-7.7-10.4-12.9-6.3L260.3 486.8a31.86 31.86 0 000 50.3l450.8 352.1c5.3 4.1 12.9.4 12.9-6.3v-77.3c0-4.9-2.3-9.6-6.1-12.6l-360-281 360-281.1c3.8-3 6.1-7.7 6.1-12.6z"
/>
</svg>
</span>
</button>
</li>
<li
class="ant-pagination-item ant-pagination-item-1 ant-pagination-item-active"
tabindex="0"
title="1"
>
<a
rel="nofollow"
>
1
</a>
</li>
<li
aria-disabled="true"
class="ant-pagination-next ant-pagination-disabled"
title="Next Page"
>
<button
class="ant-pagination-item-link"
disabled=""
tabindex="-1"
type="button"
>
<span
aria-label="right"
class="anticon anticon-right"
role="img"
>
<svg
aria-hidden="true"
data-icon="right"
fill="currentColor"
focusable="false"
height="1em"
viewBox="64 64 896 896"
width="1em"
>
<path
d="M765.7 486.8L314.9 134.7A7.97 7.97 0 00302 141v77.3c0 4.9 2.3 9.6 6.1 12.6l360 281.1-360 281.1c-3.9 3-6.1 7.7-6.1 12.6V883c0 6.7 7.7 10.4 12.9 6.3l450.8-352.1a31.96 31.96 0 000-50.4z"
/>
</svg>
</span>
</button>
</li>
</ul>
</div>
</div>
</div>
`;
exports[`renders components/table/demo/drag-sorting.tsx correctly 1`] = `
<div
class="ant-table-wrapper"

View File

@ -0,0 +1,7 @@
## zh-CN
使用自定义元素,我们可以集成 [dnd-kit](https://github.com/clauderic/dnd-kit) 来实现列拖拽排序。
## en-US
By using `components`, we can integrate table with [dnd-kit](https://github.com/clauderic/dnd-kit) to implement column drag sorting function.

View File

@ -0,0 +1,228 @@
import React, { createContext, useContext, useState } from 'react';
import type { DragEndEvent, DragOverEvent, UniqueIdentifier } from '@dnd-kit/core';
import {
closestCenter,
DndContext,
DragOverlay,
PointerSensor,
useSensor,
useSensors,
} from '@dnd-kit/core';
import { restrictToHorizontalAxis } from '@dnd-kit/modifiers';
import {
arrayMove,
horizontalListSortingStrategy,
SortableContext,
useSortable,
} from '@dnd-kit/sortable';
import { Table } from 'antd';
import type { TableColumnsType } from 'antd';
interface DataType {
key: string;
name: string;
gender: string;
age: number;
email: string;
address: string;
}
interface HeaderCellProps extends React.HTMLAttributes<HTMLTableCellElement> {
id: string;
}
interface BodyCellProps extends React.HTMLAttributes<HTMLTableCellElement> {
id: string;
}
type DragIndexState = {
active: UniqueIdentifier;
over: UniqueIdentifier | undefined;
direction?: 'left' | 'right';
};
const DragIndexContext = createContext<DragIndexState>({ active: -1, over: -1 });
const dragActiveStyle = (dragState: DragIndexState, id: string) => {
const { active, over, direction } = dragState;
// drag active style
let style = {};
if (active && active === id) {
style = { backgroundColor: 'gray', opacity: 0.5 };
}
// dragover dashed style
else if (over && id === over && active !== over) {
style =
direction === 'right'
? { borderRight: '1px dashed gray' }
: { borderLeft: '1px dashed gray' };
}
return style;
};
const TableBodyCell = (props: BodyCellProps) => {
const dragState = useContext<DragIndexState>(DragIndexContext);
return (
<td
{...props}
style={{
...props.style,
...dragActiveStyle(dragState, props.id),
}}
/>
);
};
const TableHeaderCell = (props: HeaderCellProps) => {
const dragState = useContext(DragIndexContext);
const { attributes, listeners, setNodeRef, isDragging } = useSortable({
id: props.id,
});
const style: React.CSSProperties = {
...props.style,
cursor: 'move',
...(isDragging ? { position: 'relative', zIndex: 9999, userSelect: 'none' } : {}),
...dragActiveStyle(dragState, props.id),
};
return <th {...props} ref={setNodeRef} style={style} {...attributes} {...listeners} />;
};
const dataSource: DataType[] = [
{
key: '1',
name: 'John Brown',
gender: 'male',
age: 32,
email: 'John Brown@example.com',
address: 'London No. 1 Lake Park',
},
{
key: '2',
name: 'Jim Green',
gender: 'female',
age: 42,
email: 'jimGreen@example.com',
address: 'London No. 1 Lake Park',
},
{
key: '3',
name: 'Joe Black',
gender: 'female',
age: 32,
email: 'JoeBlack@example.com',
address: 'Sidney No. 1 Lake Park',
},
{
key: '4',
name: 'George Hcc',
gender: 'male',
age: 20,
email: 'george@example.com',
address: 'Sidney No. 1 Lake Park',
},
];
const baseColumns: TableColumnsType<DataType> = [
{
title: 'Name',
dataIndex: 'name',
},
{
title: 'Gender',
dataIndex: 'gender',
},
{
title: 'Age',
dataIndex: 'age',
},
{
title: 'Email',
dataIndex: 'email',
},
{
title: 'Address',
dataIndex: 'address',
},
];
const App: React.FC = () => {
const [dragIndex, setDragIndex] = useState<DragIndexState>({ active: -1, over: -1 });
const [columns, setColumns] = useState(() =>
baseColumns.map((column, i) => ({
...column,
key: `${i}`,
onHeaderCell: () => ({
id: `${i}`,
}),
onCell: () => ({
id: `${i}`,
}),
})),
);
const sensors = useSensors(
useSensor(PointerSensor, {
activationConstraint: {
// https://docs.dndkit.com/api-documentation/sensors/pointer#activation-constraints
distance: 1,
},
}),
);
const onDragEnd = ({ active, over }: DragEndEvent) => {
if (active.id !== over?.id) {
setColumns((prev) => {
const activeIndex = prev.findIndex((i) => i.key === active.id);
const overIndex = prev.findIndex((i) => i.key === over?.id);
return arrayMove(prev, activeIndex, overIndex);
});
}
setDragIndex({ active: -1, over: -1 });
};
const onDrageOver = ({ active, over }: DragOverEvent) => {
const activeIndex = columns.findIndex((i) => i.key === active.id);
const overIndex = columns.findIndex((i) => i.key === over?.id);
setDragIndex({
active: active.id,
over: over?.id,
direction: overIndex > activeIndex ? 'right' : 'left',
});
};
return (
<DndContext
sensors={sensors}
modifiers={[restrictToHorizontalAxis]}
onDragEnd={onDragEnd}
onDragOver={onDrageOver}
collisionDetection={closestCenter}
>
<SortableContext items={columns.map((i) => i.key)} strategy={horizontalListSortingStrategy}>
<DragIndexContext.Provider value={dragIndex}>
<Table
components={{
header: {
cell: TableHeaderCell,
},
body: {
cell: TableBodyCell,
},
}}
rowKey="key"
columns={columns}
dataSource={dataSource}
/>
</DragIndexContext.Provider>
</SortableContext>
<DragOverlay>
{/* TODO: Since the tableheadercell custom component uses antd to render the cell style, it is currently not possible to copy the same component as tableheadercell. */}
<th style={{ backgroundColor: 'gray', padding: 16 }}>
{columns[columns.findIndex((i) => i.key === dragIndex.active)]?.title as React.ReactNode}
</th>
</DragOverlay>
</DndContext>
);
};
export default App;

View File

@ -93,6 +93,7 @@ const columns = [
<code src="./demo/edit-row.tsx">Editable Rows</code>
<code src="./demo/nested-table.tsx">Nested tables</code>
<code src="./demo/drag-sorting.tsx">Drag sorting</code>
<code src="./demo/drag-column-sorting.tsx">Drag Column sorting</code>
<code src="./demo/drag-sorting-handler.tsx">Drag sorting with handler</code>
<code src="./demo/resizable-column.tsx" debug>Resizable column</code>
<code src="./demo/ellipsis.tsx">ellipsis column</code>

View File

@ -94,6 +94,7 @@ const columns = [
<code src="./demo/edit-row.tsx">可编辑行</code>
<code src="./demo/nested-table.tsx">嵌套子表格</code>
<code src="./demo/drag-sorting.tsx">拖拽排序</code>
<code src="./demo/drag-column-sorting.tsx">列拖拽排序</code>
<code src="./demo/drag-sorting-handler.tsx">拖拽手柄列</code>
<code src="./demo/resizable-column.tsx" debug>可伸缩列</code>
<code src="./demo/ellipsis.tsx">单元格自动省略</code>