@snack-uikit/table 0.30.0 → 0.30.1-preview-9a03a1c9.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (61) hide show
  1. package/README.md +2 -0
  2. package/dist/cjs/components/Table/Table.d.ts +1 -1
  3. package/dist/cjs/components/Table/Table.js +116 -89
  4. package/dist/cjs/components/Table/hooks/index.d.ts +1 -0
  5. package/dist/cjs/components/Table/hooks/index.js +2 -1
  6. package/dist/cjs/components/Table/hooks/useColumnOrderByDrag.d.ts +9 -0
  7. package/dist/cjs/components/Table/hooks/useColumnOrderByDrag.js +76 -0
  8. package/dist/cjs/components/types.d.ts +2 -0
  9. package/dist/cjs/constants.d.ts +1 -0
  10. package/dist/cjs/constants.js +3 -2
  11. package/dist/cjs/helperComponents/Cells/BodyCell/BodyCell.d.ts +2 -1
  12. package/dist/cjs/helperComponents/Cells/BodyCell/BodyCell.js +13 -3
  13. package/dist/cjs/helperComponents/Cells/HeaderCell/DragHandle.d.ts +6 -0
  14. package/dist/cjs/helperComponents/Cells/HeaderCell/DragHandle.js +27 -0
  15. package/dist/cjs/helperComponents/Cells/HeaderCell/HeaderCell.d.ts +2 -1
  16. package/dist/cjs/helperComponents/Cells/HeaderCell/HeaderCell.js +22 -2
  17. package/dist/cjs/helperComponents/Cells/HeaderCell/styles.module.css +11 -0
  18. package/dist/cjs/helperComponents/Rows/BodyRow.d.ts +4 -1
  19. package/dist/cjs/helperComponents/Rows/BodyRow.js +30 -12
  20. package/dist/cjs/helperComponents/Rows/HeaderRow.d.ts +7 -1
  21. package/dist/cjs/helperComponents/Rows/HeaderRow.js +33 -13
  22. package/dist/cjs/helperComponents/hooks.d.ts +22 -13
  23. package/dist/cjs/helperComponents/hooks.js +63 -15
  24. package/dist/cjs/types.d.ts +5 -0
  25. package/dist/esm/components/Table/Table.d.ts +1 -1
  26. package/dist/esm/components/Table/Table.js +17 -12
  27. package/dist/esm/components/Table/hooks/index.d.ts +1 -0
  28. package/dist/esm/components/Table/hooks/index.js +1 -0
  29. package/dist/esm/components/Table/hooks/useColumnOrderByDrag.d.ts +9 -0
  30. package/dist/esm/components/Table/hooks/useColumnOrderByDrag.js +66 -0
  31. package/dist/esm/components/types.d.ts +2 -0
  32. package/dist/esm/constants.d.ts +1 -0
  33. package/dist/esm/constants.js +1 -0
  34. package/dist/esm/helperComponents/Cells/BodyCell/BodyCell.d.ts +2 -1
  35. package/dist/esm/helperComponents/Cells/BodyCell/BodyCell.js +7 -3
  36. package/dist/esm/helperComponents/Cells/HeaderCell/DragHandle.d.ts +6 -0
  37. package/dist/esm/helperComponents/Cells/HeaderCell/DragHandle.js +6 -0
  38. package/dist/esm/helperComponents/Cells/HeaderCell/HeaderCell.d.ts +2 -1
  39. package/dist/esm/helperComponents/Cells/HeaderCell/HeaderCell.js +13 -4
  40. package/dist/esm/helperComponents/Cells/HeaderCell/styles.module.css +11 -0
  41. package/dist/esm/helperComponents/Rows/BodyRow.d.ts +4 -1
  42. package/dist/esm/helperComponents/Rows/BodyRow.js +4 -3
  43. package/dist/esm/helperComponents/Rows/HeaderRow.d.ts +7 -1
  44. package/dist/esm/helperComponents/Rows/HeaderRow.js +4 -3
  45. package/dist/esm/helperComponents/hooks.d.ts +22 -13
  46. package/dist/esm/helperComponents/hooks.js +58 -15
  47. package/dist/esm/types.d.ts +5 -0
  48. package/package.json +6 -2
  49. package/src/components/Table/Table.tsx +133 -102
  50. package/src/components/Table/hooks/index.ts +1 -0
  51. package/src/components/Table/hooks/useColumnOrderByDrag.ts +100 -0
  52. package/src/components/types.ts +3 -0
  53. package/src/constants.tsx +2 -0
  54. package/src/helperComponents/Cells/BodyCell/BodyCell.tsx +9 -2
  55. package/src/helperComponents/Cells/HeaderCell/DragHandle.tsx +18 -0
  56. package/src/helperComponents/Cells/HeaderCell/HeaderCell.tsx +19 -4
  57. package/src/helperComponents/Cells/HeaderCell/styles.module.scss +11 -0
  58. package/src/helperComponents/Rows/BodyRow.tsx +36 -9
  59. package/src/helperComponents/Rows/HeaderRow.tsx +51 -18
  60. package/src/helperComponents/hooks.ts +78 -15
  61. package/src/types.ts +6 -0
@@ -10,6 +10,7 @@ Object.defineProperty(exports, "__esModule", {
10
10
  });
11
11
  exports.BodyRow = BodyRow;
12
12
  const jsx_runtime_1 = require("react/jsx-runtime");
13
+ const sortable_1 = require("@dnd-kit/sortable");
13
14
  const react_1 = require("react");
14
15
  const constants_1 = require("../../constants");
15
16
  const Cells_1 = require("../Cells");
@@ -21,13 +22,15 @@ const styles_module_scss_1 = __importDefault(require('./styles.module.css'));
21
22
  function BodyRow(_ref) {
22
23
  let {
23
24
  row,
24
- onRowClick
25
+ onRowClick,
26
+ groupedColumnOrderState,
27
+ enableColumnsOrderSortByDrag
25
28
  } = _ref;
26
29
  const {
27
- pinnedLeft,
28
- pinnedRight,
30
+ leftPinned,
31
+ rightPinned,
29
32
  unpinned
30
- } = (0, hooks_1.useRowCells)(row);
33
+ } = (0, hooks_1.useRowCells)(row, groupedColumnOrderState);
31
34
  const [dropListOpened, setDropListOpen] = (0, react_1.useState)(false);
32
35
  const disabled = !row.getCanSelect();
33
36
  const handleRowClick = e => {
@@ -53,17 +56,32 @@ function BodyRow(_ref) {
53
56
  "data-test-id": constants_1.TEST_IDS.bodyRow,
54
57
  "data-row-id": row.id,
55
58
  className: styles_module_scss_1.default.bodyRow,
56
- children: [pinnedLeft && (0, jsx_runtime_1.jsx)(PinnedCells_1.PinnedCells, {
59
+ children: [leftPinned && (0, jsx_runtime_1.jsx)(PinnedCells_1.PinnedCells, {
57
60
  position: constants_1.COLUMN_PIN_POSITION.Left,
58
- children: pinnedLeft.map(cell => (0, jsx_runtime_1.jsx)(Cells_1.BodyCell, {
59
- cell: cell
61
+ children: leftPinned.map(cell => (0, jsx_runtime_1.jsx)(sortable_1.SortableContext, {
62
+ items: groupedColumnOrderState.leftPinned,
63
+ strategy: sortable_1.horizontalListSortingStrategy,
64
+ children: (0, jsx_runtime_1.jsx)(Cells_1.BodyCell, {
65
+ cell: cell,
66
+ isDraggable: enableColumnsOrderSortByDrag
67
+ }, cell.id)
60
68
  }, cell.id))
61
- }), unpinned.map(cell => (0, jsx_runtime_1.jsx)(Cells_1.BodyCell, {
62
- cell: cell
63
- }, cell.id)), pinnedRight && (0, jsx_runtime_1.jsx)(PinnedCells_1.PinnedCells, {
69
+ }), unpinned.map(cell => (0, jsx_runtime_1.jsx)(sortable_1.SortableContext, {
70
+ items: groupedColumnOrderState.unpinned,
71
+ strategy: sortable_1.horizontalListSortingStrategy,
72
+ children: (0, jsx_runtime_1.jsx)(Cells_1.BodyCell, {
73
+ cell: cell,
74
+ isDraggable: enableColumnsOrderSortByDrag
75
+ }, cell.id)
76
+ }, cell.id)), rightPinned && (0, jsx_runtime_1.jsx)(PinnedCells_1.PinnedCells, {
64
77
  position: constants_1.COLUMN_PIN_POSITION.Right,
65
- children: pinnedRight.map(cell => (0, jsx_runtime_1.jsx)(Cells_1.BodyCell, {
66
- cell: cell
78
+ children: rightPinned.map(cell => (0, jsx_runtime_1.jsx)(sortable_1.SortableContext, {
79
+ items: groupedColumnOrderState.rightPinned,
80
+ strategy: sortable_1.horizontalListSortingStrategy,
81
+ children: (0, jsx_runtime_1.jsx)(Cells_1.BodyCell, {
82
+ cell: cell,
83
+ isDraggable: enableColumnsOrderSortByDrag
84
+ }, cell.id)
67
85
  }, cell.id))
68
86
  })]
69
87
  })
@@ -1 +1,7 @@
1
- export declare function HeaderRow(): import("react/jsx-runtime").JSX.Element;
1
+ import { GroupedColumnOrderState } from '../../types';
2
+ type Props = {
3
+ groupedColumnOrderState: GroupedColumnOrderState;
4
+ enableColumnsOrderSortByDrag?: boolean;
5
+ };
6
+ export declare function HeaderRow({ groupedColumnOrderState, enableColumnsOrderSortByDrag }: Props): import("react/jsx-runtime").JSX.Element;
7
+ export {};
@@ -10,34 +10,54 @@ Object.defineProperty(exports, "__esModule", {
10
10
  });
11
11
  exports.HeaderRow = HeaderRow;
12
12
  const jsx_runtime_1 = require("react/jsx-runtime");
13
+ const sortable_1 = require("@dnd-kit/sortable");
13
14
  const constants_1 = require("../../constants");
14
15
  const Cells_1 = require("../Cells");
15
16
  const hooks_1 = require("../hooks");
16
17
  const PinnedCells_1 = require("./PinnedCells");
17
18
  const Row_1 = require("./Row");
18
19
  const styles_module_scss_1 = __importDefault(require('./styles.module.css'));
19
- function HeaderRow() {
20
+ function HeaderRow(_ref) {
21
+ let {
22
+ groupedColumnOrderState,
23
+ enableColumnsOrderSortByDrag
24
+ } = _ref;
20
25
  const {
21
26
  leftPinned,
22
27
  unpinned,
23
28
  rightPinned
24
- } = (0, hooks_1.useHeaderGroups)();
29
+ } = (0, hooks_1.useHeaderGroups)(groupedColumnOrderState);
25
30
  return (0, jsx_runtime_1.jsxs)(Row_1.Row, {
26
31
  className: styles_module_scss_1.default.tableHeader,
27
32
  "data-test-id": constants_1.TEST_IDS.headerRow,
28
- children: [leftPinned && (0, jsx_runtime_1.jsx)(PinnedCells_1.PinnedCells, {
29
- position: constants_1.COLUMN_PIN_POSITION.Left,
30
- children: leftPinned.map(headerGroup => headerGroup.headers.map(header => header.isPlaceholder ? null : (0, jsx_runtime_1.jsx)(Cells_1.HeaderCell, {
31
- header: header
32
- }, header.id)))
33
- }), unpinned.map(headerGroup => headerGroup.headers.map(header => (0, jsx_runtime_1.jsx)(Cells_1.HeaderCell, {
34
- header: header
35
- }, header.id))), rightPinned && (0, jsx_runtime_1.jsx)(PinnedCells_1.PinnedCells, {
36
- position: constants_1.COLUMN_PIN_POSITION.Right,
37
- children: rightPinned.map(headerGroup => headerGroup.headers.map(header => header.isPlaceholder ? null : (0, jsx_runtime_1.jsx)(Cells_1.HeaderCell, {
33
+ children: [leftPinned && (0, jsx_runtime_1.jsx)(sortable_1.SortableContext, {
34
+ items: groupedColumnOrderState.leftPinned,
35
+ strategy: sortable_1.horizontalListSortingStrategy,
36
+ children: (0, jsx_runtime_1.jsx)(PinnedCells_1.PinnedCells, {
37
+ position: constants_1.COLUMN_PIN_POSITION.Left,
38
+ children: leftPinned.map(headerGroup => headerGroup.headers.map(header => header.isPlaceholder ? null : (0, jsx_runtime_1.jsx)(Cells_1.HeaderCell, {
39
+ header: header,
40
+ isDraggable: enableColumnsOrderSortByDrag && groupedColumnOrderState.leftPinned.length > 1
41
+ }, header.id)))
42
+ })
43
+ }), (0, jsx_runtime_1.jsx)(sortable_1.SortableContext, {
44
+ items: groupedColumnOrderState.unpinned,
45
+ strategy: sortable_1.horizontalListSortingStrategy,
46
+ children: unpinned.map(headerGroup => headerGroup.headers.map(header => (0, jsx_runtime_1.jsx)(Cells_1.HeaderCell, {
38
47
  header: header,
39
- pinPosition: constants_1.COLUMN_PIN_POSITION.Right
48
+ isDraggable: enableColumnsOrderSortByDrag && groupedColumnOrderState.unpinned.length > 1
40
49
  }, header.id)))
50
+ }), rightPinned && (0, jsx_runtime_1.jsx)(sortable_1.SortableContext, {
51
+ items: groupedColumnOrderState.rightPinned,
52
+ strategy: sortable_1.horizontalListSortingStrategy,
53
+ children: (0, jsx_runtime_1.jsx)(PinnedCells_1.PinnedCells, {
54
+ position: constants_1.COLUMN_PIN_POSITION.Right,
55
+ children: rightPinned.map(headerGroup => headerGroup.headers.map(header => header.isPlaceholder ? null : (0, jsx_runtime_1.jsx)(Cells_1.HeaderCell, {
56
+ header: header,
57
+ pinPosition: constants_1.COLUMN_PIN_POSITION.Right,
58
+ isDraggable: enableColumnsOrderSortByDrag && groupedColumnOrderState.rightPinned.length > 1
59
+ }, header.id)))
60
+ })
41
61
  })]
42
62
  });
43
63
  }
@@ -1,25 +1,34 @@
1
1
  import { Cell, Header, HeaderGroup, Row } from '@tanstack/react-table';
2
- export declare function useHeaderGroups(): {
2
+ import { CSSProperties } from 'react';
3
+ import { GroupedColumnOrderState } from '../types';
4
+ export declare function useHeaderGroups(groupedColumnOrderState: GroupedColumnOrderState): {
3
5
  unpinned: HeaderGroup<any>[];
4
6
  leftPinned?: undefined;
5
7
  rightPinned?: undefined;
6
8
  } | {
7
- leftPinned: HeaderGroup<any>[] | undefined;
8
- rightPinned: HeaderGroup<any>[] | undefined;
9
+ leftPinned: {
10
+ headers: Header<unknown, unknown>[];
11
+ depth: number;
12
+ id: string;
13
+ }[] | undefined;
14
+ rightPinned: {
15
+ headers: Header<unknown, unknown>[];
16
+ depth: number;
17
+ id: string;
18
+ }[] | undefined;
9
19
  unpinned: HeaderGroup<any>[];
10
20
  };
11
- export declare function useRowCells<TData>(row: Row<TData>): {
21
+ export declare function useRowCells<TData>(row: Row<TData>, groupedColumnOrderState: GroupedColumnOrderState): {
12
22
  unpinned: Cell<TData, unknown>[];
13
- pinnedLeft?: undefined;
14
- pinnedRight?: undefined;
23
+ leftPinned?: undefined;
24
+ rightPinned?: undefined;
15
25
  } | {
16
- pinnedLeft: Cell<TData, unknown>[] | undefined;
17
- pinnedRight: Cell<TData, unknown>[] | undefined;
26
+ leftPinned: Cell<TData, unknown>[] | undefined;
27
+ rightPinned: Cell<TData, unknown>[] | undefined;
18
28
  unpinned: Cell<TData, unknown>[];
19
29
  };
20
- export declare function useCellSizes<TData>(element: Cell<TData, unknown> | Header<TData, unknown>): {
21
- minWidth: number | undefined;
22
- width: string;
23
- maxWidth: number | undefined;
24
- flexShrink: string;
30
+ type CellSizesOptions = {
31
+ isDraggable?: boolean;
25
32
  };
33
+ export declare function useCellSizes<TData>(element: Cell<TData, unknown> | Header<TData, unknown>, options?: CellSizesOptions): CSSProperties;
34
+ export {};
@@ -6,17 +6,32 @@ Object.defineProperty(exports, "__esModule", {
6
6
  exports.useHeaderGroups = useHeaderGroups;
7
7
  exports.useRowCells = useRowCells;
8
8
  exports.useCellSizes = useCellSizes;
9
+ const sortable_1 = require("@dnd-kit/sortable");
10
+ const utilities_1 = require("@dnd-kit/utilities");
9
11
  const react_1 = require("react");
10
12
  const contexts_1 = require("./contexts");
11
13
  function hasHeaders(groups) {
12
14
  return groups.some(group => group.headers.length);
13
15
  }
14
- function useHeaderGroups() {
16
+ const sortHeaderGroup = (groups, groupOrder) => groups.map(group => Object.assign(Object.assign({}, group), {
17
+ headers: group.headers.sort((a, b) => {
18
+ const indexA = groupOrder.findIndex(columnId => columnId === a.id);
19
+ const indexB = groupOrder.findIndex(columnId => columnId === b.id);
20
+ if (indexA > -1 && indexB > -1) {
21
+ return indexA - indexB;
22
+ }
23
+ return 0;
24
+ })
25
+ }));
26
+ function useHeaderGroups(groupedColumnOrderState) {
15
27
  const {
16
28
  table
17
29
  } = (0, contexts_1.useTableContext)();
18
30
  const columnDefs = table._getColumnDefs();
19
31
  const pinEnabled = table.getIsSomeColumnsPinned();
32
+ const {
33
+ columnOrder
34
+ } = table.getState();
20
35
  return (0, react_1.useMemo)(() => {
21
36
  if (!pinEnabled) {
22
37
  return {
@@ -26,20 +41,33 @@ function useHeaderGroups() {
26
41
  const left = table.getLeftHeaderGroups();
27
42
  const right = table.getRightHeaderGroups();
28
43
  return {
29
- leftPinned: hasHeaders(left) ? left : undefined,
30
- rightPinned: hasHeaders(right) ? right : undefined,
44
+ leftPinned: hasHeaders(left) ? sortHeaderGroup(left, groupedColumnOrderState.leftPinned) : undefined,
45
+ rightPinned: hasHeaders(right) ? sortHeaderGroup(right, groupedColumnOrderState.rightPinned) : undefined,
31
46
  unpinned: table.getCenterHeaderGroups()
32
47
  };
33
48
  // need to rebuild if columnDefinitions has changed
34
49
  // eslint-disable-next-line react-hooks/exhaustive-deps
35
- }, [table, pinEnabled, columnDefs]);
50
+ }, [table, pinEnabled, columnDefs, columnOrder, groupedColumnOrderState]);
36
51
  }
37
- function useRowCells(row) {
52
+ function sortPinnedColumnsByOrderState(groupOrder) {
53
+ return (a, b) => {
54
+ const indexA = groupOrder.findIndex(columnId => columnId === a.column.id);
55
+ const indexB = groupOrder.findIndex(columnId => columnId === b.column.id);
56
+ if (indexA > -1 && indexB > -1) {
57
+ return indexA - indexB;
58
+ }
59
+ return 0;
60
+ };
61
+ }
62
+ function useRowCells(row, groupedColumnOrderState) {
38
63
  const {
39
64
  table
40
65
  } = (0, contexts_1.useTableContext)();
41
66
  const pinEnabled = table.getIsSomeColumnsPinned();
42
67
  const columnDefs = table._getColumnDefs();
68
+ const {
69
+ columnOrder
70
+ } = table.getState();
43
71
  return (0, react_1.useMemo)(() => {
44
72
  if (!pinEnabled) {
45
73
  return {
@@ -49,24 +77,44 @@ function useRowCells(row) {
49
77
  const left = row.getLeftVisibleCells();
50
78
  const right = row.getRightVisibleCells();
51
79
  return {
52
- pinnedLeft: left.length ? left : undefined,
53
- pinnedRight: right.length ? right : undefined,
80
+ leftPinned: left.length ? left.slice().sort(sortPinnedColumnsByOrderState(groupedColumnOrderState.leftPinned)) : undefined,
81
+ rightPinned: right.length ? right.slice().sort(sortPinnedColumnsByOrderState(groupedColumnOrderState.rightPinned)) : undefined,
54
82
  unpinned: row.getCenterVisibleCells()
55
83
  };
56
84
  // need to rebuild if columnDefinitions has changed
57
85
  // eslint-disable-next-line react-hooks/exhaustive-deps
58
- }, [row, pinEnabled, columnDefs]);
86
+ }, [row, pinEnabled, columnDefs, columnOrder, groupedColumnOrderState]);
59
87
  }
60
- function useCellSizes(element) {
88
+ function useCellSizes(element, options) {
61
89
  const column = element.column;
90
+ const {
91
+ isDragging,
92
+ transform
93
+ } = (0, sortable_1.useSortable)({
94
+ id: column.id
95
+ });
62
96
  const minWidth = column.columnDef.minSize;
63
97
  const maxWidth = column.columnDef.maxSize;
64
98
  const width = `var(--table-column-${column.id}-size)`;
65
99
  const flexShrink = `var(--table-column-${column.id}-flex)`;
66
- return (0, react_1.useMemo)(() => ({
67
- minWidth,
68
- width,
69
- maxWidth,
70
- flexShrink
71
- }), [flexShrink, maxWidth, minWidth, width]);
100
+ const isHeaderCell = 'headerGroup' in element;
101
+ return (0, react_1.useMemo)(() => {
102
+ const styles = {
103
+ minWidth,
104
+ width,
105
+ maxWidth,
106
+ flexShrink
107
+ };
108
+ if (options === null || options === void 0 ? void 0 : options.isDraggable) {
109
+ styles.opacity = isDragging ? 0.8 : 1;
110
+ styles.position = 'relative';
111
+ styles.transform = utilities_1.CSS.Translate.toString(transform);
112
+ styles.transition = 'width transform 0.2s ease-in-out';
113
+ styles.zIndex = isDragging ? 1 : 0;
114
+ if (isHeaderCell) {
115
+ styles.whiteSpace = 'nowrap';
116
+ }
117
+ }
118
+ return styles;
119
+ }, [options === null || options === void 0 ? void 0 : options.isDraggable, flexShrink, isDragging, isHeaderCell, maxWidth, minWidth, transform, width]);
72
120
  }
@@ -40,5 +40,10 @@ type PinnedColumnDefinition<TData> = BaseColumnDefinition<TData> & {
40
40
  size: number;
41
41
  };
42
42
  export type ColumnDefinition<TData> = NormalColumnDefinition<TData> | PinnedColumnDefinition<TData>;
43
+ export type GroupedColumnOrderState = {
44
+ leftPinned: string[];
45
+ rightPinned: string[];
46
+ unpinned: string[];
47
+ };
43
48
  export type { RowActionsColumnDefProps, StatusColumnDefinitionProps, RowInfo, RowClickHandler, ActionsGenerator, CopyCellProps, MapStatusToAppearanceFnType, } from './helperComponents';
44
49
  export type { ColumnPinPosition, PaginationState, SortingState, RowSelectionState, RowSelectionOptions, EmptyStateProps, ToolbarProps, HeaderContext, CellContext, };
@@ -1,7 +1,7 @@
1
1
  import { FiltersState } from '@snack-uikit/chips';
2
2
  import { TableProps } from '../types';
3
3
  /** Компонент таблицы */
4
- export declare function Table<TData extends object, TFilters extends FiltersState = Record<string, unknown>>({ data, rowPinning, columnDefinitions, keepPinnedRows, copyPinnedRows, enableSelectPinned, rowSelection: rowSelectionProp, search, sorting: sortingProp, columnFilters, pagination: paginationProp, className, onRowClick, onRefresh, pageSize, pageCount, loading, outline, moreActions, exportSettings, dataFiltered, dataError, noDataState, noResultsState, errorDataState, suppressToolbar, suppressSearch, toolbarAfter, suppressPagination, manualSorting, manualPagination, manualFiltering, autoResetPageIndex, scrollRef, scrollContainerRef, getRowId, enableFuzzySearch, savedState, expanding, bulkActions: bulkActionsProp, ...rest }: TableProps<TData, TFilters>): import("react/jsx-runtime").JSX.Element;
4
+ export declare function Table<TData extends object, TFilters extends FiltersState = Record<string, unknown>>({ data, rowPinning, columnDefinitions, keepPinnedRows, copyPinnedRows, enableSelectPinned, rowSelection: rowSelectionProp, search, sorting: sortingProp, columnFilters, pagination: paginationProp, className, onRowClick, onRefresh, pageSize, pageCount, loading, outline, moreActions, exportSettings, dataFiltered, dataError, noDataState, noResultsState, errorDataState, suppressToolbar, suppressSearch, toolbarAfter, suppressPagination, manualSorting, manualPagination, manualFiltering, autoResetPageIndex, scrollRef, scrollContainerRef, getRowId, enableFuzzySearch, savedState, expanding, bulkActions: bulkActionsProp, enableColumnsOrderSortByDrag, ...rest }: TableProps<TData, TFilters>): import("react/jsx-runtime").JSX.Element;
5
5
  export declare namespace Table {
6
6
  var getStatusColumnDef: typeof import("../../helperComponents").getStatusColumnDef;
7
7
  var statusAppearances: Record<string, string>;
@@ -10,6 +10,8 @@ var __rest = (this && this.__rest) || function (s, e) {
10
10
  return t;
11
11
  };
12
12
  import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-runtime";
13
+ import { closestCenter, DndContext } from '@dnd-kit/core';
14
+ import { restrictToHorizontalAxis } from '@dnd-kit/modifiers';
13
15
  import { getCoreRowModel, getExpandedRowModel, getFilteredRowModel, getPaginationRowModel, getSortedRowModel, useReactTable, } from '@tanstack/react-table';
14
16
  import cn from 'classnames';
15
17
  import { useCallback, useEffect, useMemo, useRef } from 'react';
@@ -24,7 +26,7 @@ import { CellAutoResizeContext, useCellAutoResizeController } from '../../contex
24
26
  import { BodyRow, ExportButton, getColumnId, getRowActionsColumnDef, getSelectionCellColumnDef, getStatusColumnDef, HeaderRow, STATUS_APPEARANCE, TableContext, TableEmptyState, TablePagination, useEmptyState, } from '../../helperComponents';
25
27
  import { getTreeColumnDef } from '../../helperComponents/Cells/TreeCell';
26
28
  import { fuzzyFilter } from '../../utils';
27
- import { useLoadingTable, useStateControl } from './hooks';
29
+ import { useColumnOrderByDrag, useLoadingTable, useStateControl } from './hooks';
28
30
  import { usePageReset } from './hooks/usePageReset';
29
31
  import styles from './styles.module.css';
30
32
  import { getColumnStyleVars, getCurrentlyConfiguredHeaderWidth, getInitColumnSizeFromLocalStorage, saveStateToLocalStorage, } from './utils';
@@ -32,7 +34,7 @@ import { getColumnStyleVars, getCurrentlyConfiguredHeaderWidth, getInitColumnSiz
32
34
  export function Table(_a) {
33
35
  var { data, rowPinning = {
34
36
  top: [],
35
- }, columnDefinitions, keepPinnedRows = false, copyPinnedRows = false, enableSelectPinned = false, rowSelection: rowSelectionProp, search, sorting: sortingProp, columnFilters, pagination: paginationProp, className, onRowClick, onRefresh, pageSize = DEFAULT_PAGE_SIZE, pageCount, loading = false, outline = false, moreActions, exportSettings, dataFiltered, dataError, noDataState, noResultsState, errorDataState, suppressToolbar = false, suppressSearch = false, toolbarAfter, suppressPagination = false, manualSorting = false, manualPagination = false, manualFiltering = false, autoResetPageIndex = false, scrollRef, scrollContainerRef, getRowId, enableFuzzySearch, savedState, expanding, bulkActions: bulkActionsProp } = _a, rest = __rest(_a, ["data", "rowPinning", "columnDefinitions", "keepPinnedRows", "copyPinnedRows", "enableSelectPinned", "rowSelection", "search", "sorting", "columnFilters", "pagination", "className", "onRowClick", "onRefresh", "pageSize", "pageCount", "loading", "outline", "moreActions", "exportSettings", "dataFiltered", "dataError", "noDataState", "noResultsState", "errorDataState", "suppressToolbar", "suppressSearch", "toolbarAfter", "suppressPagination", "manualSorting", "manualPagination", "manualFiltering", "autoResetPageIndex", "scrollRef", "scrollContainerRef", "getRowId", "enableFuzzySearch", "savedState", "expanding", "bulkActions"]);
37
+ }, columnDefinitions, keepPinnedRows = false, copyPinnedRows = false, enableSelectPinned = false, rowSelection: rowSelectionProp, search, sorting: sortingProp, columnFilters, pagination: paginationProp, className, onRowClick, onRefresh, pageSize = DEFAULT_PAGE_SIZE, pageCount, loading = false, outline = false, moreActions, exportSettings, dataFiltered, dataError, noDataState, noResultsState, errorDataState, suppressToolbar = false, suppressSearch = false, toolbarAfter, suppressPagination = false, manualSorting = false, manualPagination = false, manualFiltering = false, autoResetPageIndex = false, scrollRef, scrollContainerRef, getRowId, enableFuzzySearch, savedState, expanding, bulkActions: bulkActionsProp, enableColumnsOrderSortByDrag } = _a, rest = __rest(_a, ["data", "rowPinning", "columnDefinitions", "keepPinnedRows", "copyPinnedRows", "enableSelectPinned", "rowSelection", "search", "sorting", "columnFilters", "pagination", "className", "onRowClick", "onRefresh", "pageSize", "pageCount", "loading", "outline", "moreActions", "exportSettings", "dataFiltered", "dataError", "noDataState", "noResultsState", "errorDataState", "suppressToolbar", "suppressSearch", "toolbarAfter", "suppressPagination", "manualSorting", "manualPagination", "manualFiltering", "autoResetPageIndex", "scrollRef", "scrollContainerRef", "getRowId", "enableFuzzySearch", "savedState", "expanding", "bulkActions", "enableColumnsOrderSortByDrag"]);
36
38
  const { state: globalFilter, onStateChange: onGlobalFilterChange } = useStateControl(search, '');
37
39
  const { state: rowSelection, onStateChange: onRowSelectionChange } = useStateControl(rowSelectionProp, {});
38
40
  const defaultPaginationState = useMemo(() => ({
@@ -52,6 +54,7 @@ export function Table(_a) {
52
54
  }
53
55
  return cols;
54
56
  }, [columnDefinitions, enableSelection, enableSelectPinned, expanding]);
57
+ const { columnOrder, setColumnOrder, groupedColumnOrderState, sensors, handleDragEnd } = useColumnOrderByDrag(tableColumns);
55
58
  const columnPinning = useMemo(() => {
56
59
  var _a;
57
60
  const pinningState = { left: [], right: [] };
@@ -78,6 +81,7 @@ export function Table(_a) {
78
81
  columns: tableColumns,
79
82
  state: {
80
83
  columnPinning,
84
+ columnOrder,
81
85
  globalFilter,
82
86
  rowSelection,
83
87
  sorting,
@@ -91,6 +95,7 @@ export function Table(_a) {
91
95
  minSize: 40,
92
96
  cell: (cell) => _jsx(TruncateString, { text: String(cell.getValue()), maxLines: 1 }),
93
97
  },
98
+ onColumnOrderChange: setColumnOrder,
94
99
  manualSorting,
95
100
  manualPagination,
96
101
  manualFiltering,
@@ -240,16 +245,16 @@ export function Table(_a) {
240
245
  });
241
246
  const { updateCellMap } = useCellAutoResizeController(table);
242
247
  const showToolbar = !suppressToolbar;
243
- return (_jsx(CellAutoResizeContext.Provider, { value: { updateCellMap }, children: _jsxs("div", Object.assign({ style: {
244
- '--page-size': cssPageSize,
245
- }, className: cn(styles.wrapper, className) }, extractSupportProps(rest), { children: [showToolbar && (_jsx("div", { className: styles.header, children: _jsx(Toolbar, { search: suppressSearch
246
- ? undefined
247
- : {
248
- value: globalFilter,
249
- onChange: onGlobalFilterChange,
250
- loading: search === null || search === void 0 ? void 0 : search.loading,
251
- placeholder: (search === null || search === void 0 ? void 0 : search.placeholder) || t('searchPlaceholder'),
252
- }, className: styles.toolbar, onRefresh: onRefresh ? handleOnRefresh : undefined, bulkActions: bulkActions, selectionMode: (rowSelectionProp === null || rowSelectionProp === void 0 ? void 0 : rowSelectionProp.multiRow) ? 'multiple' : 'single', checked: table.getIsAllPageRowsSelected(), indeterminate: table.getIsSomePageRowsSelected(), onCheck: enableSelection ? handleOnToolbarCheck : undefined, outline: outline, after: toolbarAfter || exportSettings ? (_jsxs(_Fragment, { children: [toolbarAfter, exportSettings && (_jsx(ExportButton, { settings: exportSettings, columnDefinitions: columnDefinitions, data: data, topRows: filteredTopRows, centerRows: centerRows }))] })) : undefined, moreActions: moreActions, filterRow: columnFilters, "data-test-id": TEST_IDS.toolbar }) })), _jsx("div", { className: styles.scrollWrapper, "data-outline": outline || undefined, children: _jsxs(Scroll, { size: 's', className: styles.table, ref: scrollContainerRef, children: [_jsx("div", { className: styles.tableContent, style: columnSizes.vars, children: _jsx(TableContext.Provider, { value: { table }, children: loading ? (_jsxs(SkeletonContextProvider, { loading: true, children: [_jsx(HeaderRow, {}), loadingTableRows.map(row => (_jsx(BodyRow, { row: row }, row.id)))] })) : (_jsxs(_Fragment, { children: [centerRows.length || filteredTopRows.length ? _jsx(HeaderRow, {}) : null, filteredTopRows.length ? (_jsx("div", { className: styles.topRowWrapper, children: filteredTopRows.map(row => (_jsx(BodyRow, { row: row, onRowClick: onRowClick }, row.id))) })) : null, centerRows.map(row => (_jsx(BodyRow, { row: row, onRowClick: onRowClick }, row.id))), _jsx(TableEmptyState, { emptyStates: emptyStates, dataError: dataError, dataFiltered: dataFiltered || Boolean(table.getState().globalFilter), tableRowsLength: tableRows.length + filteredTopRows.length })] })) }) }), _jsx("div", { className: styles.scrollStub, ref: scrollRef })] }) }), !suppressPagination && (_jsx(TablePagination, { table: table, options: paginationProp === null || paginationProp === void 0 ? void 0 : paginationProp.options, optionsLabel: paginationProp === null || paginationProp === void 0 ? void 0 : paginationProp.optionsLabel, pageCount: pageCount, optionsRender: paginationProp === null || paginationProp === void 0 ? void 0 : paginationProp.optionsRender }))] })) }));
248
+ return (_jsx(DndContext, { collisionDetection: closestCenter, modifiers: [restrictToHorizontalAxis], onDragEnd: handleDragEnd, sensors: sensors, children: _jsx(CellAutoResizeContext.Provider, { value: { updateCellMap }, children: _jsxs("div", Object.assign({ style: {
249
+ '--page-size': cssPageSize,
250
+ }, className: cn(styles.wrapper, className) }, extractSupportProps(rest), { children: [showToolbar && (_jsx("div", { className: styles.header, children: _jsx(Toolbar, { search: suppressSearch
251
+ ? undefined
252
+ : {
253
+ value: globalFilter,
254
+ onChange: onGlobalFilterChange,
255
+ loading: search === null || search === void 0 ? void 0 : search.loading,
256
+ placeholder: (search === null || search === void 0 ? void 0 : search.placeholder) || t('searchPlaceholder'),
257
+ }, className: styles.toolbar, onRefresh: onRefresh ? handleOnRefresh : undefined, bulkActions: bulkActions, selectionMode: (rowSelectionProp === null || rowSelectionProp === void 0 ? void 0 : rowSelectionProp.multiRow) ? 'multiple' : 'single', checked: table.getIsAllPageRowsSelected(), indeterminate: table.getIsSomePageRowsSelected(), onCheck: enableSelection ? handleOnToolbarCheck : undefined, outline: outline, after: toolbarAfter || exportSettings ? (_jsxs(_Fragment, { children: [toolbarAfter, exportSettings && (_jsx(ExportButton, { settings: exportSettings, columnDefinitions: columnDefinitions, data: data, topRows: filteredTopRows, centerRows: centerRows }))] })) : undefined, moreActions: moreActions, filterRow: columnFilters, "data-test-id": TEST_IDS.toolbar }) })), _jsx("div", { className: styles.scrollWrapper, "data-outline": outline || undefined, children: _jsxs(Scroll, { size: 's', className: styles.table, ref: scrollContainerRef, children: [_jsx("div", { className: styles.tableContent, style: columnSizes.vars, children: _jsx(TableContext.Provider, { value: { table }, children: loading ? (_jsxs(SkeletonContextProvider, { loading: true, children: [_jsx(HeaderRow, { groupedColumnOrderState: groupedColumnOrderState }), loadingTableRows.map(row => (_jsx(BodyRow, { row: row, groupedColumnOrderState: groupedColumnOrderState }, row.id)))] })) : (_jsxs(_Fragment, { children: [centerRows.length || filteredTopRows.length ? (_jsx(HeaderRow, { groupedColumnOrderState: groupedColumnOrderState, enableColumnsOrderSortByDrag: enableColumnsOrderSortByDrag })) : null, filteredTopRows.length ? (_jsx("div", { className: styles.topRowWrapper, children: filteredTopRows.map(row => (_jsx(BodyRow, { row: row, onRowClick: onRowClick, groupedColumnOrderState: groupedColumnOrderState }, row.id))) })) : null, centerRows.map(row => (_jsx(BodyRow, { row: row, onRowClick: onRowClick, groupedColumnOrderState: groupedColumnOrderState, enableColumnsOrderSortByDrag: enableColumnsOrderSortByDrag }, row.id))), _jsx(TableEmptyState, { emptyStates: emptyStates, dataError: dataError, dataFiltered: dataFiltered || Boolean(table.getState().globalFilter), tableRowsLength: tableRows.length + filteredTopRows.length })] })) }) }), _jsx("div", { className: styles.scrollStub, ref: scrollRef })] }) }), !suppressPagination && (_jsx(TablePagination, { table: table, options: paginationProp === null || paginationProp === void 0 ? void 0 : paginationProp.options, optionsLabel: paginationProp === null || paginationProp === void 0 ? void 0 : paginationProp.optionsLabel, pageCount: pageCount, optionsRender: paginationProp === null || paginationProp === void 0 ? void 0 : paginationProp.optionsRender }))] })) }) }));
253
258
  }
254
259
  Table.getStatusColumnDef = getStatusColumnDef;
255
260
  Table.statusAppearances = STATUS_APPEARANCE;
@@ -1,2 +1,3 @@
1
1
  export * from './useLoadingTable';
2
2
  export * from './useStateControl';
3
+ export * from './useColumnOrderByDrag';
@@ -1,2 +1,3 @@
1
1
  export * from './useLoadingTable';
2
2
  export * from './useStateControl';
3
+ export * from './useColumnOrderByDrag';
@@ -0,0 +1,9 @@
1
+ import { DragEndEvent } from '@dnd-kit/core';
2
+ import { ColumnDefinition, GroupedColumnOrderState } from '../../../types';
3
+ export declare function useColumnOrderByDrag<TData extends object>(tableColumns: ColumnDefinition<TData>[]): {
4
+ columnOrder: string[];
5
+ setColumnOrder: import("react").Dispatch<import("react").SetStateAction<string[]>>;
6
+ groupedColumnOrderState: GroupedColumnOrderState;
7
+ handleDragEnd: ({ active, over }: DragEndEvent) => void;
8
+ sensors: import("@dnd-kit/core").SensorDescriptor<import("@dnd-kit/core").SensorOptions>[];
9
+ };
@@ -0,0 +1,66 @@
1
+ import { KeyboardSensor, MouseSensor, TouchSensor, useSensor, useSensors } from '@dnd-kit/core';
2
+ import { arrayMove } from '@dnd-kit/sortable';
3
+ import { useCallback, useMemo, useState } from 'react';
4
+ import { UNDRAGGABLE_COLUMNS } from '../../../constants';
5
+ function preparePinnedColumnsMap(tableColumns) {
6
+ return tableColumns.reduce((accMap, columnDefinition) => {
7
+ switch (columnDefinition.pinned) {
8
+ case 'left':
9
+ accMap[columnDefinition.id] = 'leftPinned';
10
+ break;
11
+ case 'right':
12
+ accMap[columnDefinition.id] = 'rightPinned';
13
+ break;
14
+ default:
15
+ }
16
+ return accMap;
17
+ }, {});
18
+ }
19
+ function prepareInitialState(tableColumns) {
20
+ return tableColumns.map(c => c.id).filter(id => !UNDRAGGABLE_COLUMNS.includes(id));
21
+ }
22
+ function prepareGroupedColumnOrderState(columnOrder, pinnedColumnsMap) {
23
+ return columnOrder.reduce((accState, columnId) => {
24
+ var _a;
25
+ if (UNDRAGGABLE_COLUMNS.includes(columnId)) {
26
+ return accState;
27
+ }
28
+ const groupName = (_a = pinnedColumnsMap[columnId]) !== null && _a !== void 0 ? _a : 'unpinned';
29
+ accState[groupName].push(columnId);
30
+ return accState;
31
+ }, {
32
+ leftPinned: [],
33
+ unpinned: [],
34
+ rightPinned: [],
35
+ });
36
+ }
37
+ export function useColumnOrderByDrag(tableColumns) {
38
+ const [columnOrder, setColumnOrder] = useState(() => prepareInitialState(tableColumns));
39
+ const pinnedColumnsMap = useMemo(() => preparePinnedColumnsMap(tableColumns), [tableColumns]);
40
+ const groupedColumnOrderState = useMemo(() => prepareGroupedColumnOrderState(columnOrder, pinnedColumnsMap), [columnOrder, pinnedColumnsMap]);
41
+ const handleDragEnd = useCallback(({ active, over }) => {
42
+ if (active && over && active.id !== over.id) {
43
+ if (UNDRAGGABLE_COLUMNS.includes(over.id.toString())) {
44
+ return;
45
+ }
46
+ const activeGroup = pinnedColumnsMap[active.id.toString()];
47
+ const overGroup = pinnedColumnsMap[over.id.toString()];
48
+ if (activeGroup !== overGroup) {
49
+ return;
50
+ }
51
+ setColumnOrder(columnOrder => {
52
+ const oldIndex = columnOrder.indexOf(active.id.toString());
53
+ const newIndex = columnOrder.indexOf(over.id.toString());
54
+ return arrayMove(columnOrder, oldIndex, newIndex);
55
+ });
56
+ }
57
+ }, [pinnedColumnsMap]);
58
+ const sensors = useSensors(useSensor(MouseSensor, {}), useSensor(TouchSensor, {}), useSensor(KeyboardSensor, {}));
59
+ return {
60
+ columnOrder,
61
+ setColumnOrder,
62
+ groupedColumnOrderState,
63
+ handleDragEnd,
64
+ sensors,
65
+ };
66
+ }
@@ -30,6 +30,8 @@ export type TableProps<TData extends object, TFilters extends FiltersState = Rec
30
30
  state?: SortingState;
31
31
  onChange?(state: SortingState): void;
32
32
  };
33
+ /** Включение сортировки порядка столбцов вручную перетаскиванием */
34
+ enableColumnsOrderSortByDrag?: boolean;
33
35
  /** Параметр отвечает за общие настройки раскрывающихся строк*/
34
36
  expanding?: {
35
37
  /** Метод отвечает за получение дочерних строк*/
@@ -35,3 +35,4 @@ export declare const SORT_FN: {
35
35
  readonly AlphaNumeric: "alphanumeric";
36
36
  };
37
37
  export declare const DEFAULT_PAGE_SIZE = 10;
38
+ export declare const UNDRAGGABLE_COLUMNS: string[];
@@ -35,3 +35,4 @@ export const SORT_FN = {
35
35
  AlphaNumeric: 'alphanumeric',
36
36
  };
37
37
  export const DEFAULT_PAGE_SIZE = 10;
38
+ export const UNDRAGGABLE_COLUMNS = ['snack_predefined_statusColumn', 'selectionCell', 'rowActions'];
@@ -2,6 +2,7 @@ import { Cell as TableCell } from '@tanstack/react-table';
2
2
  import { CellProps } from '../Cell';
3
3
  type BodyCellProps<TData> = Omit<CellProps, 'style' | 'children'> & {
4
4
  cell: TableCell<TData, unknown>;
5
+ isDraggable?: boolean;
5
6
  };
6
- export declare function BodyCell<TData>({ cell, className, ...props }: BodyCellProps<TData>): import("react/jsx-runtime").JSX.Element;
7
+ export declare function BodyCell<TData>({ cell, className, isDraggable, ...props }: BodyCellProps<TData>): import("react/jsx-runtime").JSX.Element;
7
8
  export {};
@@ -10,6 +10,7 @@ var __rest = (this && this.__rest) || function (s, e) {
10
10
  return t;
11
11
  };
12
12
  import { jsx as _jsx } from "react/jsx-runtime";
13
+ import { useSortable } from '@dnd-kit/sortable';
13
14
  import { flexRender } from '@tanstack/react-table';
14
15
  import cn from 'classnames';
15
16
  import { TEST_IDS } from '../../../constants';
@@ -17,8 +18,11 @@ import { useCellSizes } from '../../hooks';
17
18
  import { Cell } from '../Cell';
18
19
  import styles from './styles.module.css';
19
20
  export function BodyCell(_a) {
20
- var { cell, className } = _a, props = __rest(_a, ["cell", "className"]);
21
+ var { cell, className, isDraggable } = _a, props = __rest(_a, ["cell", "className", "isDraggable"]);
21
22
  const columnDef = cell.column.columnDef;
22
- const style = useCellSizes(cell);
23
- return (_jsx(Cell, Object.assign({}, props, { style: style, className: cn(styles.tableBodyCell, className, columnDef.cellClassName), "data-align": columnDef.align, "data-no-padding": columnDef.noBodyCellPadding || undefined, "data-column-id": cell.column.id, "data-test-id": TEST_IDS.bodyCell, children: flexRender(columnDef.cell, cell.getContext()) })));
23
+ const style = useCellSizes(cell, { isDraggable });
24
+ const { setNodeRef } = useSortable({
25
+ id: cell.column.id,
26
+ });
27
+ return (_jsx(Cell, Object.assign({}, props, { ref: setNodeRef, style: style, className: cn(styles.tableBodyCell, className, columnDef.cellClassName), "data-align": columnDef.align, "data-no-padding": columnDef.noBodyCellPadding || undefined, "data-column-id": cell.column.id, "data-test-id": TEST_IDS.bodyCell, children: flexRender(columnDef.cell, cell.getContext()) })));
24
28
  }
@@ -0,0 +1,6 @@
1
+ import { useSortable } from '@dnd-kit/sortable';
2
+ import { CSSProperties } from 'react';
3
+ export type DragHandleProps = Pick<ReturnType<typeof useSortable>, 'attributes' | 'listeners'> & {
4
+ style?: CSSProperties;
5
+ };
6
+ export declare function DragHandle({ attributes, listeners }: DragHandleProps): import("react/jsx-runtime").JSX.Element;
@@ -0,0 +1,6 @@
1
+ import { jsx as _jsx } from "react/jsx-runtime";
2
+ import { KebabSVG } from '@snack-uikit/icons';
3
+ import styles from './styles.module.css';
4
+ export function DragHandle({ attributes, listeners }) {
5
+ return (_jsx("div", Object.assign({ className: styles.dragHandle }, attributes, listeners, { children: _jsx(KebabSVG, { className: styles.dragIcon }) })));
6
+ }
@@ -4,6 +4,7 @@ import { CellProps } from '../Cell';
4
4
  type HeaderCellProps<TData> = Omit<CellProps, 'align' | 'children' | 'onClick' | 'style'> & {
5
5
  header: Header<TData, unknown>;
6
6
  pinPosition?: ColumnPinPosition;
7
+ isDraggable?: boolean;
7
8
  };
8
- export declare function HeaderCell<TData>({ header, pinPosition, className }: HeaderCellProps<TData>): import("react/jsx-runtime").JSX.Element;
9
+ export declare function HeaderCell<TData>({ header, pinPosition, isDraggable, className }: HeaderCellProps<TData>): import("react/jsx-runtime").JSX.Element;
9
10
  export {};