Skip to content

Commit

Permalink
feat(Table): drag column added
Browse files Browse the repository at this point in the history
  • Loading branch information
DanisAvko committed Sep 12, 2024
1 parent 951b48c commit bf12531
Show file tree
Hide file tree
Showing 25 changed files with 187 additions and 106 deletions.
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -188,10 +188,10 @@ const GroupingExample = () => {

```tsx
import type {ReorderingProviderProps} from '@gravity-ui/table';
import {defaultDragHandleColumn, ReorderingProvider} from '@gravity-ui/table';
import {baseDragHandleColumn, ReorderingProvider} from '@gravity-ui/table';

const columns: ColumnDef<Person>[] = [
defaultDragHandleColumn,
baseDragHandleColumn,
// ...other columns
];

Expand Down
8 changes: 5 additions & 3 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 2 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@
"@dnd-kit/core": "^6.1.0",
"@dnd-kit/sortable": "^8.0.0",
"@gravity-ui/eslint-config": "^3.2.0",
"@gravity-ui/icons": "^2.11.0",
"@gravity-ui/prettier-config": "^1.1.0",
"@gravity-ui/stylelint-config": "^4.0.1",
"@gravity-ui/tsconfig": "^1.0.0",
Expand Down Expand Up @@ -98,6 +99,7 @@
"peerDependencies": {
"@dnd-kit/core": "^6.0.0",
"@dnd-kit/sortable": "^8.0.0",
"@gravity-ui/icons": "^2.0.0",
"@gravity-ui/uikit": "^6.0.0",
"react": "^17.0.0 || ^18.0.0",
"react-dom": "^17.0.0 || ^18.0.0"
Expand Down
43 changes: 0 additions & 43 deletions src/components/BaseDragHandle/BaseDragHandle.tsx

This file was deleted.

1 change: 0 additions & 1 deletion src/components/BaseDragHandle/index.ts

This file was deleted.

This file was deleted.

16 changes: 0 additions & 16 deletions src/components/BaseDraggableRowMarker/BaseDraggableRowMarker.scss

This file was deleted.

13 changes: 0 additions & 13 deletions src/components/BaseDraggableRowMarker/BaseDraggableRowMarker.tsx

This file was deleted.

1 change: 0 additions & 1 deletion src/components/BaseDraggableRowMarker/index.ts

This file was deleted.

1 change: 0 additions & 1 deletion src/components/BaseTable/BaseTable.scss
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@ $block: '.#{variables.$ns}table';

#{$block} {
--gc-tree-view-padding: 0px;
--gc-draggable-row-marker-offset: 20px;

border-spacing: 0;
border-collapse: separate;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import React from 'react';

import type {ColumnDef} from '@tanstack/react-table';

import {defaultDragHandleColumn} from '../../../../constants';
import {dragHandleColumn} from '../../../../constants';
import {useTable} from '../../../../hooks';
import {BaseTable} from '../../../BaseTable';
import {ReorderingProvider} from '../../../ReorderingProvider';
Expand All @@ -11,7 +11,7 @@ import {columns as originalColumns} from '../constants/columns';
import {data as originalData} from '../constants/data';
import type {Item} from '../types';

const columns: ColumnDef<Item>[] = [defaultDragHandleColumn as ColumnDef<Item>, ...originalColumns];
const columns: ColumnDef<Item>[] = [dragHandleColumn as ColumnDef<Item>, ...originalColumns];

export const ReorderingStory = () => {
const [data, setData] = React.useState(originalData);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import React from 'react';

import type {ColumnDef, ExpandedState} from '@tanstack/react-table';

import {defaultDragHandleColumn} from '../../../../constants';
import {dragHandleColumn} from '../../../../constants';
import {useTable} from '../../../../hooks';
import {ReorderingProvider} from '../../../ReorderingProvider';
import {BaseTable} from '../../BaseTable';
Expand All @@ -11,7 +11,7 @@ import {draggableTreeColumns, data as originalData} from '../constants/tree';
import {useTreeDataReordering} from '../hooks/useTreeDataReordering';

const columns: ColumnDef<TreeItem>[] = [
defaultDragHandleColumn as ColumnDef<TreeItem>,
dragHandleColumn as ColumnDef<TreeItem>,
...draggableTreeColumns,
];

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import React from 'react';

import type {ColumnDef} from '@tanstack/react-table';

import {defaultDragHandleColumn} from '../../../../constants';
import {dragHandleColumn} from '../../../../constants';
import {useTable, useWindowRowVirtualizer} from '../../../../hooks';
import {getVirtualRowRangeExtractor} from '../../../../utils';
import {BaseTable} from '../../../BaseTable';
Expand All @@ -16,7 +16,7 @@ import {cnVirtualizationStory} from './VirtualizationStory.classname';

import './VirtualizationStory.scss';

const columns: ColumnDef<Item>[] = [defaultDragHandleColumn as ColumnDef<Item>, ...originalColumns];
const columns: ColumnDef<Item>[] = [dragHandleColumn as ColumnDef<Item>, ...originalColumns];

export const ReorderingWithVirtualizationStory = () => {
const tableRef = React.useRef<HTMLTableElement>(null);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@ $block: '.#{variables.$ns}drag-handle';
#{$block} {
cursor: grab;

color: var(--g-color-text-secondary);

&[aria-pressed] {
cursor: grabbing;
}
Expand Down
28 changes: 28 additions & 0 deletions src/components/DragHandle/DragHandle.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
import React from 'react';

import {useSortable} from '@dnd-kit/sortable';
import {Grip as GripIcon} from '@gravity-ui/icons';
import {Icon} from '@gravity-ui/uikit';
import type {Row} from '@tanstack/react-table';

import {b} from './DragHandle.classname';

import './DragHandle.scss';

export interface DragHandleProps<TData> {
row: Row<TData>;
}

export const DragHandle = <TData,>({row}: DragHandleProps<TData>) => {
const {attributes, listeners} = useSortable({
id: row.id,
});

return (
<span {...attributes} {...listeners} className={b()} data-role="drag-handle">
<Icon data={GripIcon} size={16} />
</span>
);
};

DragHandle.displayName = 'DragHandle';
1 change: 1 addition & 0 deletions src/components/DragHandle/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export * from './DragHandle';
10 changes: 10 additions & 0 deletions src/components/Table/__stories__/Table.stories.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@ import type {Meta, StoryObj} from '@storybook/react';
import {Table} from '../index';

import {DefaultStory} from './stories/DefaultStory';
import {ReorderingStory} from './stories/ReorderingStory';
import {ReorderingWithVirtualizationStory} from './stories/ReorderingWithVirtualizationStory';
import {StickyHeaderStory} from './stories/StickyHeaderStory';
import {VirtualizationStory} from './stories/VirtualizationStory';
import {WindowVirtualizationStory} from './stories/WindowVirtualizationStory';
Expand All @@ -23,6 +25,10 @@ export const WithSelection: StoryObj<typeof WithSelectionStory> = {
render: WithSelectionStory,
};

export const Reordering: StoryObj<typeof ReorderingStory> = {
render: ReorderingStory,
};

export const Virtualization: StoryObj<typeof VirtualizationStory> = {
render: VirtualizationStory,
};
Expand All @@ -31,6 +37,10 @@ export const WindowVirtualization: StoryObj<typeof WindowVirtualizationStory> =
render: WindowVirtualizationStory,
};

export const ReorderingWithVirtualization: StoryObj<typeof ReorderingWithVirtualizationStory> = {
render: ReorderingWithVirtualizationStory,
};

export const StickyHeader: StoryObj<typeof StickyHeaderStory> = {
render: StickyHeaderStory,
};
53 changes: 53 additions & 0 deletions src/components/Table/__stories__/stories/ReorderingStory.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
import React from 'react';

import type {ColumnDef} from '@tanstack/react-table';

import {dragHandleColumn} from '../../../../constants';
import {useTable} from '../../../../hooks';
import {columns as originalColumns} from '../../../BaseTable/__stories__/constants/columns';
import {data as originalData} from '../../../BaseTable/__stories__/constants/data';
import type {Item} from '../../../BaseTable/__stories__/types';
import type {ReorderingProviderProps} from '../../../ReorderingProvider';
import {ReorderingProvider} from '../../../ReorderingProvider';
import {Table} from '../../Table';

const columns: ColumnDef<Item>[] = [dragHandleColumn as ColumnDef<Item>, ...originalColumns];

export const ReorderingStory = () => {
const [data, setData] = React.useState(originalData);

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

const handleReorder = React.useCallback<
NonNullable<ReorderingProviderProps<Item>['onReorder']>
>(({draggedItemKey, baseItemKey}) => {
setData((prevData) => {
const dataClone = prevData.slice();

const index = dataClone.findIndex((item) => item.id === draggedItemKey);

if (index >= 0) {
const dragged = dataClone.splice(index, 1)[0] as Item;
const insertIndex = dataClone.findIndex((item) => item.id === baseItemKey);

if (insertIndex >= 0) {
dataClone.splice(insertIndex + 1, 0, dragged);
} else {
dataClone.unshift(dragged);
}
}

return dataClone;
});
}, []);

return (
<ReorderingProvider table={table} onReorder={handleReorder}>
<Table table={table} />
</ReorderingProvider>
);
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
import React from 'react';

import type {ColumnDef} from '@tanstack/react-table';

import {dragHandleColumn} from '../../../../constants';
import {useTable, useWindowRowVirtualizer} from '../../../../hooks';
import {getVirtualRowRangeExtractor} from '../../../../utils';
import {columns as originalColumns} from '../../../BaseTable/__stories__/constants/columns';
import type {Item} from '../../../BaseTable/__stories__/types';
import {generateData} from '../../../BaseTable/__stories__/utils';
import type {ReorderingProviderProps} from '../../../ReorderingProvider';
import {ReorderingProvider} from '../../../ReorderingProvider';
import {Table} from '../../Table';

const columns: ColumnDef<Item>[] = [dragHandleColumn as ColumnDef<Item>, ...originalColumns];

export const ReorderingWithVirtualizationStory = () => {
const tableRef = React.useRef<HTMLTableElement>(null);
const [data, setData] = React.useState(() => generateData(300));

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

const rowVirtualizer = useWindowRowVirtualizer({
count: table.getRowModel().rows.length,
estimateSize: () => 20,
overscan: 5,
rangeExtractor: getVirtualRowRangeExtractor(tableRef.current),
});

const handleReorder = React.useCallback<
NonNullable<ReorderingProviderProps<Item>['onReorder']>
>(({draggedItemKey, baseItemKey}) => {
setData((prevData) => {
const dataClone = prevData.slice();

const index = dataClone.findIndex((item) => item.id === draggedItemKey);

if (index >= 0) {
const dragged = dataClone.splice(index, 1)[0] as Item;
const insertIndex = dataClone.findIndex((item) => item.id === baseItemKey);

if (insertIndex >= 0) {
dataClone.splice(insertIndex + 1, 0, dragged);
} else {
dataClone.unshift(dragged);
}
}

return dataClone;
});
}, []);

return (
<ReorderingProvider table={table} onReorder={handleReorder}>
<Table ref={tableRef} table={table} rowVirtualizer={rowVirtualizer} stickyHeader />
</ReorderingProvider>
);
};
Loading

0 comments on commit bf12531

Please sign in to comment.