Skip to content

Commit 3678a33

Browse files
feat(BaseTable): add ranged selection functionality to selection column (#126)
1 parent aae8183 commit 3678a33

13 files changed

Lines changed: 472 additions & 77 deletions

File tree

README-ru.md

Lines changed: 131 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -79,6 +79,137 @@ const RowSelectionExample = () => {
7979
};
8080
```
8181

82+
### Кастомная колонка с выбором диапазона строк
83+
84+
Хук `useToggleRangeSelectionHandler` возвращает обработчик, который слушает события Shift+click и выполняет выделение диапазона строк. Для доступа к внутренним состояниям таблицы и строки ему необходимо передать экземпляр `CellContext`.
85+
86+
```tsx
87+
import React, {type ChangeEvent, useCallback, useState} from 'react';
88+
89+
import {Table, useToggleRangeSelectionHandler, useTable} from '@gravity-ui/table';
90+
import type {CellContext, ColumnDef, RowSelectionState} from '@gravity-ui/table/tanstack';
91+
import {Checkbox, type CheckboxProps} from '@gravity-ui/uikit';
92+
93+
type CustomRangedSelectionCheckboxProps = Omit<CheckboxProps, 'onChange'> & {
94+
cellContext: CellContext<unknown, unknown>;
95+
};
96+
97+
const CustomRangedSelectionCheckbox = ({
98+
className,
99+
cellContext,
100+
...restProps
101+
}: CustomRangedSelectionCheckboxProps) => {
102+
const rowToggleRangedSelectionHandler = useToggleRangeSelectionHandler(cellContext);
103+
104+
const handleChange = useCallback(
105+
(event: ChangeEvent<HTMLInputElement>): void => {
106+
rowToggleRangedSelectionHandler(event);
107+
},
108+
[rowToggleRangedSelectionHandler],
109+
);
110+
111+
return <Checkbox {...restProps} onChange={handleChange} />;
112+
};
113+
114+
const customSelectionColumn: ColumnDef<unknown> = {
115+
id: '_select',
116+
header: ({table}) => (
117+
<Checkbox
118+
size="l"
119+
checked={table.getIsAllRowsSelected()}
120+
indeterminate={table.getIsSomeRowsSelected()}
121+
onChange={table.getToggleAllRowsSelectedHandler()}
122+
/>
123+
),
124+
cell: (cellContext) => (
125+
<CustomRangedSelectionCheckbox
126+
size="l"
127+
checked={cellContext.row.getIsSelected()}
128+
disabled={!cellContext.row.getCanSelect()}
129+
indeterminate={cellContext.row.getIsSomeSelected()}
130+
cellContext={cellContext}
131+
/>
132+
),
133+
size: 41,
134+
maxSize: 41,
135+
minSize: 41,
136+
enableResizing: false,
137+
enableSorting: false,
138+
};
139+
140+
const columns: ColumnDef<Person>[] = [
141+
customSelectionColumn as ColumnDef<Person>,
142+
// ...other columns
143+
];
144+
145+
const data: Person[] = [
146+
/* ... */
147+
];
148+
149+
const RowRangedSelectionExample = () => {
150+
const [rowSelection, setRowSelection] = useState<RowSelectionState>({});
151+
152+
const table = useTable({
153+
columns,
154+
data,
155+
enableRowSelection: true,
156+
enableMultiRowSelection: true,
157+
onRowSelectionChange: setRowSelection,
158+
state: {
159+
rowSelection,
160+
},
161+
});
162+
163+
return <Table table={table} />;
164+
};
165+
```
166+
167+
Также существует компонент `RangedSelectionCheckbox`, который внутренне использует этот хук и принимает экземпляр `CellContext` в качестве пропса. Этот компонент удобен для добавления функциональности выделения диапазона в кастомную колонку выбора строк.
168+
169+
```tsx
170+
import type {ColumnDef} from '@gravity-ui/table/tanstack';
171+
import {RangedSelectionCheckbox, SelectionCheckbox} from '@gravity-ui/table';
172+
173+
export const selectionColumn: ColumnDef<unknown> = {
174+
id: '_select',
175+
header: ({table}) => (
176+
<SelectionCheckbox
177+
checked={table.getIsAllRowsSelected()}
178+
disabled={!table.options.enableRowSelection}
179+
indeterminate={table.getIsSomeRowsSelected()}
180+
onChange={table.getToggleAllRowsSelectedHandler()}
181+
/>
182+
),
183+
cell: (cellContext) => (
184+
<RangedSelectionCheckbox
185+
checked={cellContext.row.getIsSelected()}
186+
disabled={!cellContext.row.getCanSelect()}
187+
indeterminate={cellContext.row.getIsSomeSelected()}
188+
cellContext={cellContext}
189+
/>
190+
),
191+
meta: {
192+
hideInSettings: true,
193+
},
194+
size: 32,
195+
minSize: 32,
196+
};
197+
```
198+
199+
По умолчанию столбец выбора строк, созданный с помощью `selectionColumn`, уже включает в себя функциональность выделения диапазона.
200+
201+
```tsx
202+
import {selectionColumn} from '@gravity-ui/table';
203+
import type {ColumnDef} from '@gravity-ui/table/tanstack';
204+
205+
const columns: ColumnDef<Person>[] = [
206+
selectionColumn as ColumnDef<Person>,
207+
// ...other columns
208+
];
209+
```
210+
211+
**Обратите внимание**: если в таблице есть вложенные строки, выбор диапазона работать не будет. На данный момент это считается неопределённым поведением.
212+
82213
### Сортировка
83214

84215
Подробности о свойствах столбцов можно найти в [руководстве по сортировке](https://tanstack.com/table/v8/docs/guide/sorting) документации библиотеки React Table.

README.md

Lines changed: 131 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -79,6 +79,137 @@ const RowSelectionExample = () => {
7979
};
8080
```
8181

82+
### Custom Ranged Selection Column
83+
84+
The `useToggleRangeSelectionHandler` hook returns a change handler that listens for Shift+click events and performs ranged row selection. It needs to be passed a `CellContext` instance in order to have access to the table's and row's internal states.
85+
86+
```tsx
87+
import React, {type ChangeEvent, useCallback, useState} from 'react';
88+
89+
import {Table, useToggleRangeSelectionHandler, useTable} from '@gravity-ui/table';
90+
import type {CellContext, ColumnDef, RowSelectionState} from '@gravity-ui/table/tanstack';
91+
import {Checkbox, type CheckboxProps} from '@gravity-ui/uikit';
92+
93+
type CustomRangedSelectionCheckboxProps = Omit<CheckboxProps, 'onChange'> & {
94+
cellContext: CellContext<unknown, unknown>;
95+
};
96+
97+
const CustomRangedSelectionCheckbox = ({
98+
className,
99+
cellContext,
100+
...restProps
101+
}: CustomRangedSelectionCheckboxProps) => {
102+
const rowToggleRangedSelectionHandler = useToggleRangeSelectionHandler(cellContext);
103+
104+
const handleChange = useCallback(
105+
(event: ChangeEvent<HTMLInputElement>): void => {
106+
rowToggleRangedSelectionHandler(event);
107+
},
108+
[rowToggleRangedSelectionHandler],
109+
);
110+
111+
return <Checkbox {...restProps} onChange={handleChange} />;
112+
};
113+
114+
const customSelectionColumn: ColumnDef<unknown> = {
115+
id: '_select',
116+
header: ({table}) => (
117+
<Checkbox
118+
size="l"
119+
checked={table.getIsAllRowsSelected()}
120+
indeterminate={table.getIsSomeRowsSelected()}
121+
onChange={table.getToggleAllRowsSelectedHandler()}
122+
/>
123+
),
124+
cell: (cellContext) => (
125+
<CustomRangedSelectionCheckbox
126+
size="l"
127+
checked={cellContext.row.getIsSelected()}
128+
disabled={!cellContext.row.getCanSelect()}
129+
indeterminate={cellContext.row.getIsSomeSelected()}
130+
cellContext={cellContext}
131+
/>
132+
),
133+
size: 41,
134+
maxSize: 41,
135+
minSize: 41,
136+
enableResizing: false,
137+
enableSorting: false,
138+
};
139+
140+
const columns: ColumnDef<Person>[] = [
141+
customSelectionColumn as ColumnDef<Person>,
142+
// ...other columns
143+
];
144+
145+
const data: Person[] = [
146+
/* ... */
147+
];
148+
149+
const RowRangedSelectionExample = () => {
150+
const [rowSelection, setRowSelection] = useState<RowSelectionState>({});
151+
152+
const table = useTable({
153+
columns,
154+
data,
155+
enableRowSelection: true,
156+
enableMultiRowSelection: true,
157+
onRowSelectionChange: setRowSelection,
158+
state: {
159+
rowSelection,
160+
},
161+
});
162+
163+
return <Table table={table} />;
164+
};
165+
```
166+
167+
There is also a `RangedSelectionCheckbox` component, which internally uses the hook and accepts a `CellContext` instance as a prop. This component provides a shorthand for adding ranged selection functionality to custom selection columns.
168+
169+
```tsx
170+
import type {ColumnDef} from '@gravity-ui/table/tanstack';
171+
import {RangedSelectionCheckbox, SelectionCheckbox} from '@gravity-ui/table';
172+
173+
export const selectionColumn: ColumnDef<unknown> = {
174+
id: '_select',
175+
header: ({table}) => (
176+
<SelectionCheckbox
177+
checked={table.getIsAllRowsSelected()}
178+
disabled={!table.options.enableRowSelection}
179+
indeterminate={table.getIsSomeRowsSelected()}
180+
onChange={table.getToggleAllRowsSelectedHandler()}
181+
/>
182+
),
183+
cell: (cellContext) => (
184+
<RangedSelectionCheckbox
185+
checked={cellContext.row.getIsSelected()}
186+
disabled={!cellContext.row.getCanSelect()}
187+
indeterminate={cellContext.row.getIsSomeSelected()}
188+
cellContext={cellContext}
189+
/>
190+
),
191+
meta: {
192+
hideInSettings: true,
193+
},
194+
size: 32,
195+
minSize: 32,
196+
};
197+
```
198+
199+
By default, the selection column generated with `selectionColumn` includes ranged selection functionality.
200+
201+
```tsx
202+
import {selectionColumn} from '@gravity-ui/table';
203+
import type {ColumnDef} from '@gravity-ui/table/tanstack';
204+
205+
const columns: ColumnDef<Person>[] = [
206+
selectionColumn as ColumnDef<Person>,
207+
// ...other columns
208+
];
209+
```
210+
211+
**Note**: If the table contains nested rows, range selection will not work. At the moment, this is considered undefined behavior.
212+
82213
### Sorting
83214

84215
Learn about the column properties in the react-table [docs](https://tanstack.com/table/v8/docs/guide/sorting)

0 commit comments

Comments
 (0)