Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
96 changes: 96 additions & 0 deletions README-ru.md
Original file line number Diff line number Diff line change
Expand Up @@ -392,6 +392,102 @@ const ReorderingExample = () => {
};
```

### Переупорядочивание столбцов

Оберните таблицу в `ColumnReorderingProvider`, чтобы включить перетаскивание столбцов за их заголовки.

```tsx
import {ColumnReorderingProvider} from '@gravity-ui/table';

const columns: ColumnDef<Person>[] = [
{accessorKey: 'name', header: 'Name', size: 100},
{accessorKey: 'age', header: 'Age', size: 100},
];

const ColumnReorderingExample = () => {
const table = useTable({
columns,
data,
getRowId: (item) => item.id,
});

return (
<ColumnReorderingProvider table={table}>
<Table table={table} />
</ColumnReorderingProvider>
);
};
```

Если вы управляете `columnOrder` самостоятельно (например, чтобы сохранять его), передайте `onReorder` и примените полученный порядок:

```tsx
const [columnOrder, setColumnOrder] = React.useState<string[]>([]);

const table = useTable({
columns,
data,
state: {columnOrder},
onColumnOrderChange: setColumnOrder,
});

return (
<ColumnReorderingProvider
table={table}
onReorder={({columnOrder}) => setColumnOrder(columnOrder)}
>
<Table table={table} />
</ColumnReorderingProvider>
);
```

Во время перетаскивания:

- плавающее превью столбца (его заголовок и первые строки) следует за курсором;
- перетаскиваемый столбец становится полупрозрачным;
- в месте вставки рисуется синяя линия;

```tsx
<ColumnReorderingProvider
table={table}
autoScroll
dragOverlayRowCount={20}
renderDragOverlay={({columnId}) => <CustomColumnPreview columnId={columnId} />}
>
<Table table={table} />
</ColumnReorderingProvider>
```

CSS API:

| CSS-переменная | Значение по умолчанию | Описание |
| -------------------------------------------- | ----------------------------- | ------------------------------------- |
| `--gt-table-reordering-insertion-line-color` | `#4d8bff` | Цвет линии вставки |
| `--gt-table-reordering-insertion-line-width` | `2px` | Толщина линии вставки |
| `--gt-table-reordering-dragged-opacity` | `0.4` | Прозрачность перетаскиваемого столбца |
| `--gt-table-drag-overlay-background` | `#fff` | Фон превью |
| `--gt-table-drag-overlay-shadow` | `0 3px 12px rgba(0,0,0,0.15)` | Тень превью |
| `--gt-table-drag-overlay-border-radius` | `6px` | Скругление превью |

Чтобы запретить переупорядочивание конкретного столбца, задайте `enableColumnReordering: false` в его определении. Плейсхолдерные (сгруппированные) столбцы перетаскивать нельзя. Параметр `activationDistance` (по умолчанию `8`) задаёт, на сколько должен сдвинуться курсор перед началом перетаскивания, что сохраняет работу кликов по заголовку (например, сортировки).

Закреплённые (pinned) столбцы тоже можно переупорядочивать, но только внутри своей группы: столбец перемещается в пределах левой закреплённой группы, правой закреплённой группы или центральной (незакреплённой) группы — перетаскиванием он никогда не пересекает границу закрепления.

```tsx
<ColumnReorderingProvider
table={table}
onReorder={({columnOrder, columnPinning, pinned}) => {
if (pinned) {
setColumnPinning(columnPinning);
} else {
setColumnOrder(columnOrder);
}
}}
>
<Table table={table} />
</ColumnReorderingProvider>
```

### Виртуализация

Если необходимо настроить контейнер сетки в качестве элемента прокрутки, используйте виртуализацию. Обязательно задайте контейнеру фиксированную высоту, иначе виртуализация работать не будет.
Expand Down
96 changes: 96 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -392,6 +392,102 @@ const ReorderingExample = () => {
};
```

### Column reordering

Wrap the table with `ColumnReorderingProvider` to enable drag-and-drop reordering of columns by their headers.

```tsx
import {ColumnReorderingProvider} from '@gravity-ui/table';

const columns: ColumnDef<Person>[] = [
{accessorKey: 'name', header: 'Name', size: 100},
{accessorKey: 'age', header: 'Age', size: 100},
];

const ColumnReorderingExample = () => {
const table = useTable({
columns,
data,
getRowId: (item) => item.id,
});

return (
<ColumnReorderingProvider table={table}>
<Table table={table} />
</ColumnReorderingProvider>
);
};
```

If you control `columnOrder` yourself (e.g. to persist it), pass `onReorder` and apply the resulting order:

```tsx
const [columnOrder, setColumnOrder] = React.useState<string[]>([]);

const table = useTable({
columns,
data,
state: {columnOrder},
onColumnOrderChange: setColumnOrder,
});

return (
<ColumnReorderingProvider
table={table}
onReorder={({columnOrder}) => setColumnOrder(columnOrder)}
>
<Table table={table} />
</ColumnReorderingProvider>
);
```

CSS API:

| CSS variable | Default | Description |
| -------------------------------------------- | ----------------------------- | -------------------------------- |
| `--gt-table-reordering-insertion-line-color` | `#4d8bff` | Color of the drop insertion line |
| `--gt-table-reordering-insertion-line-width` | `2px` | Width of the drop insertion line |
| `--gt-table-reordering-dragged-opacity` | `0.4` | Opacity of the dragged column |
| `--gt-table-drag-overlay-background` | `#fff` | Drag preview background |
| `--gt-table-drag-overlay-shadow` | `0 3px 12px rgba(0,0,0,0.15)` | Drag preview box-shadow |
| `--gt-table-drag-overlay-border-radius` | `6px` | Drag preview border radius |

To forbid reordering a specific column, set `enableColumnReordering: false` in its column definition. Placeholder (grouped) columns are not draggable. Use `activationDistance` (default `8`) to tune how far the pointer must move before a drag starts, which keeps header clicks (like sorting) working.

Pinned columns can be reordered too, but only among themselves: a column can be moved within the left-pinned group, the right-pinned group, or the center (non-pinned) group — it never crosses a pin boundary by dragging.

```tsx
<ColumnReorderingProvider
table={table}
onReorder={({columnOrder, columnPinning, pinned}) => {
if (pinned) {
setColumnPinning(columnPinning);
} else {
setColumnOrder(columnOrder);
}
}}
>
<Table table={table} />
</ColumnReorderingProvider>
```

While dragging:

- a floating preview of the column (its header plus the first rows) follows the pointer in a drag overlay;
- the dragged column becomes semi-transparent;
- a blue insertion line is drawn where the column will be dropped;

```tsx
<ColumnReorderingProvider
table={table}
autoScroll
dragOverlayRowCount={10}
renderDragOverlay={({columnId}) => <CustomColumnPreview columnId={columnId} />}
>
<Table table={table} />
</ColumnReorderingProvider>
```

### Virtualization

Use if you want to use grid container as the scroll element (if you want to use window see window virtualization section). Be sure to set a fixed height on the container; otherwise, virtualization will not work.
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
import * as React from 'react';

import type {Header} from '../../types/base';
import type {BaseHeaderCellProps} from '../BaseHeaderCell';
import {BaseHeaderCell} from '../BaseHeaderCell';
import {b} from '../BaseTable/BaseTable.classname';
import {ColumnReorderingContext} from '../ColumnReorderingContext';

export interface BaseDraggableHeaderCellProps<TData, TValue>
extends BaseHeaderCellProps<TData, TValue> {}

export const BaseDraggableHeaderCell = <TData, TValue>({
attributes: attributesProp,
header,
...restProps
}: BaseDraggableHeaderCellProps<TData, TValue>) => {
const {activeColumnId, useSortable} = React.useContext(ColumnReorderingContext) ?? {};

const {setNodeRef, listeners, isDragging = false} = useSortable?.({id: header.column.id}) ?? {};

const isDragActive = Boolean(activeColumnId);

const getAttributes = React.useCallback(
(cellHeader: Header<TData, TValue>, parentHeader?: Header<TData, unknown>) => {
const resolvedAttributes =
typeof attributesProp === 'function'
? attributesProp(cellHeader, parentHeader)
: attributesProp;

const handlePointerDown = (event: React.PointerEvent<HTMLTableCellElement>) => {
resolvedAttributes?.onPointerDown?.(event);

if (event.defaultPrevented) {
return;
}

if ((event.target as HTMLElement).closest(`.${b('resize-handle')}`)) {
return;
}

listeners?.onPointerDown?.(event);
};

return {
...resolvedAttributes,
...listeners,
onPointerDown: handlePointerDown,
Comment thread
beliarh marked this conversation as resolved.
'data-draggable': true,
'data-dragging': isDragging,
'data-drag-active': isDragActive,
};
},
[attributesProp, isDragActive, isDragging, listeners],
);

return (
<BaseHeaderCell
ref={setNodeRef}
header={header}
attributes={getAttributes}
{...restProps}
/>
);
};

BaseDraggableHeaderCell.displayName = 'BaseDraggableHeaderCell';
1 change: 1 addition & 0 deletions src/components/BaseDraggableHeaderCell/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export * from './BaseDraggableHeaderCell';
Loading
Loading