@snack-uikit/table 0.29.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 (66) hide show
  1. package/CHANGELOG.md +11 -0
  2. package/README.md +2 -0
  3. package/dist/cjs/components/Table/Table.d.ts +1 -1
  4. package/dist/cjs/components/Table/Table.js +141 -104
  5. package/dist/cjs/components/Table/hooks/index.d.ts +1 -0
  6. package/dist/cjs/components/Table/hooks/index.js +2 -1
  7. package/dist/cjs/components/Table/hooks/useColumnOrderByDrag.d.ts +9 -0
  8. package/dist/cjs/components/Table/hooks/useColumnOrderByDrag.js +76 -0
  9. package/dist/cjs/components/Table/utils.js +6 -3
  10. package/dist/cjs/components/types.d.ts +2 -0
  11. package/dist/cjs/constants.d.ts +1 -0
  12. package/dist/cjs/constants.js +3 -2
  13. package/dist/cjs/helperComponents/Cells/BodyCell/BodyCell.d.ts +2 -1
  14. package/dist/cjs/helperComponents/Cells/BodyCell/BodyCell.js +13 -3
  15. package/dist/cjs/helperComponents/Cells/HeaderCell/DragHandle.d.ts +6 -0
  16. package/dist/cjs/helperComponents/Cells/HeaderCell/DragHandle.js +27 -0
  17. package/dist/cjs/helperComponents/Cells/HeaderCell/HeaderCell.d.ts +2 -1
  18. package/dist/cjs/helperComponents/Cells/HeaderCell/HeaderCell.js +22 -2
  19. package/dist/cjs/helperComponents/Cells/HeaderCell/styles.module.css +11 -0
  20. package/dist/cjs/helperComponents/Rows/BodyRow.d.ts +4 -1
  21. package/dist/cjs/helperComponents/Rows/BodyRow.js +30 -12
  22. package/dist/cjs/helperComponents/Rows/HeaderRow.d.ts +7 -1
  23. package/dist/cjs/helperComponents/Rows/HeaderRow.js +33 -13
  24. package/dist/cjs/helperComponents/hooks.d.ts +22 -13
  25. package/dist/cjs/helperComponents/hooks.js +63 -15
  26. package/dist/cjs/types.d.ts +5 -0
  27. package/dist/esm/components/Table/Table.d.ts +1 -1
  28. package/dist/esm/components/Table/Table.js +34 -25
  29. package/dist/esm/components/Table/hooks/index.d.ts +1 -0
  30. package/dist/esm/components/Table/hooks/index.js +1 -0
  31. package/dist/esm/components/Table/hooks/useColumnOrderByDrag.d.ts +9 -0
  32. package/dist/esm/components/Table/hooks/useColumnOrderByDrag.js +66 -0
  33. package/dist/esm/components/Table/utils.js +6 -3
  34. package/dist/esm/components/types.d.ts +2 -0
  35. package/dist/esm/constants.d.ts +1 -0
  36. package/dist/esm/constants.js +1 -0
  37. package/dist/esm/helperComponents/Cells/BodyCell/BodyCell.d.ts +2 -1
  38. package/dist/esm/helperComponents/Cells/BodyCell/BodyCell.js +7 -3
  39. package/dist/esm/helperComponents/Cells/HeaderCell/DragHandle.d.ts +6 -0
  40. package/dist/esm/helperComponents/Cells/HeaderCell/DragHandle.js +6 -0
  41. package/dist/esm/helperComponents/Cells/HeaderCell/HeaderCell.d.ts +2 -1
  42. package/dist/esm/helperComponents/Cells/HeaderCell/HeaderCell.js +13 -4
  43. package/dist/esm/helperComponents/Cells/HeaderCell/styles.module.css +11 -0
  44. package/dist/esm/helperComponents/Rows/BodyRow.d.ts +4 -1
  45. package/dist/esm/helperComponents/Rows/BodyRow.js +4 -3
  46. package/dist/esm/helperComponents/Rows/HeaderRow.d.ts +7 -1
  47. package/dist/esm/helperComponents/Rows/HeaderRow.js +4 -3
  48. package/dist/esm/helperComponents/hooks.d.ts +22 -13
  49. package/dist/esm/helperComponents/hooks.js +58 -15
  50. package/dist/esm/types.d.ts +5 -0
  51. package/package.json +6 -2
  52. package/src/components/Table/Table.tsx +151 -117
  53. package/src/components/Table/hooks/index.ts +1 -0
  54. package/src/components/Table/hooks/useColumnOrderByDrag.ts +100 -0
  55. package/src/components/Table/utils.ts +8 -3
  56. package/src/components/types.ts +3 -0
  57. package/src/constants.tsx +2 -0
  58. package/src/helperComponents/Cells/BodyCell/BodyCell.tsx +9 -2
  59. package/src/helperComponents/Cells/HeaderCell/DragHandle.tsx +18 -0
  60. package/src/helperComponents/Cells/HeaderCell/HeaderCell.tsx +19 -4
  61. package/src/helperComponents/Cells/HeaderCell/styles.module.scss +15 -4
  62. package/src/helperComponents/Rows/BodyRow.tsx +36 -9
  63. package/src/helperComponents/Rows/HeaderRow.tsx +51 -18
  64. package/src/helperComponents/Rows/styles.module.scss +2 -2
  65. package/src/helperComponents/hooks.ts +78 -15
  66. package/src/types.ts +6 -0
@@ -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
+ }
@@ -3,10 +3,13 @@ export function getCurrentlyConfiguredHeaderWidth(id) {
3
3
  if (isBrowser()) {
4
4
  const cell = document.querySelector(`[data-header-id="${id}"]`);
5
5
  const resizeHandler = cell === null || cell === void 0 ? void 0 : cell.querySelector('[data-test-id="table__header-cell-resize-handle-moving-part"]');
6
- if (cell && resizeHandler) {
6
+ if (cell) {
7
7
  const { width } = cell.getBoundingClientRect();
8
- const offset = parseInt(resizeHandler.style.getPropertyValue('--offset'));
9
- return width + offset;
8
+ if (resizeHandler) {
9
+ const offset = parseInt(resizeHandler.style.getPropertyValue('--offset'));
10
+ return width + offset;
11
+ }
12
+ return width;
10
13
  }
11
14
  }
12
15
  return 0;
@@ -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 {};
@@ -1,15 +1,17 @@
1
1
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { useSortable } from '@dnd-kit/sortable';
2
3
  import { flexRender } from '@tanstack/react-table';
3
4
  import cn from 'classnames';
4
5
  import { useRef } from 'react';
5
6
  import { TruncateString } from '@snack-uikit/truncate-string';
6
- import { TEST_IDS } from '../../../constants';
7
+ import { TEST_IDS, UNDRAGGABLE_COLUMNS } from '../../../constants';
7
8
  import { useCellSizes } from '../../hooks';
8
9
  import { Cell } from '../Cell';
10
+ import { DragHandle } from './DragHandle';
9
11
  import { getSortingIcon } from './helpers';
10
12
  import { ResizeHandle } from './ResizeHandle';
11
13
  import styles from './styles.module.css';
12
- export function HeaderCell({ header, pinPosition, className }) {
14
+ export function HeaderCell({ header, pinPosition, isDraggable, className }) {
13
15
  const cellRef = useRef(null);
14
16
  const isSortable = header.column.getCanSort();
15
17
  const isResizable = header.column.getCanResize();
@@ -19,12 +21,19 @@ export function HeaderCell({ header, pinPosition, className }) {
19
21
  const columnSizingInfo = header.getContext().table.getState().columnSizingInfo;
20
22
  const isSomeColumnResizing = columnSizingInfo.isResizingColumn;
21
23
  const columnDef = header.column.columnDef;
22
- const style = useCellSizes(header);
24
+ const style = useCellSizes(header, { isDraggable });
25
+ const { attributes, listeners, setNodeRef } = useSortable({
26
+ id: header.column.id,
27
+ });
23
28
  const sortingHandler = (e) => {
24
29
  var _a;
25
30
  if (isSomeColumnResizing)
26
31
  return;
27
32
  return (_a = header.column.getToggleSortingHandler()) === null || _a === void 0 ? void 0 : _a(e);
28
33
  };
29
- return (_jsxs(Cell, { style: style, onClick: sortingHandler, "data-sortable": isSortable || undefined, "data-no-padding": columnDef.noHeaderCellPadding || undefined, "data-no-offset": columnDef.noHeaderCellBorderOffset || undefined, "data-test-id": TEST_IDS.headerCell, "data-align": columnDef.headerAlign || undefined, "data-header-id": header.id, "data-resizing": isResizing || undefined, "data-pin-position": pinPosition || undefined, role: 'columnheader', className: cn(styles.tableHeaderCell, className, columnDef.headerClassName), ref: cellRef, children: [_jsxs("div", { className: styles.tableHeaderCellMain, children: [columnDef.header && (_jsx("div", { className: styles.tableHeaderCellName, children: _jsx(TruncateString, { text: flexRender(columnDef.header, header.getContext()) }) })), Boolean(sortIcon) && (_jsx("div", { className: styles.tableHeaderIcon, "data-sort-direction": sortDirection, "data-test-id": TEST_IDS.headerSortIndicator, children: sortIcon }))] }), Boolean(isResizable) && _jsx(ResizeHandle, { header: header, cellRef: cellRef })] }));
34
+ const isAvailableForDrag = !UNDRAGGABLE_COLUMNS.includes(header.column.id);
35
+ return (_jsxs(Cell, { style: style, onClick: sortingHandler, "data-sortable": isSortable || undefined, "data-draggable": isDraggable || undefined, "data-no-padding": columnDef.noHeaderCellPadding || undefined, "data-no-offset": columnDef.noHeaderCellBorderOffset || undefined, "data-test-id": TEST_IDS.headerCell, "data-align": columnDef.headerAlign || undefined, "data-header-id": header.id, "data-resizing": isResizing || undefined, "data-pin-position": pinPosition || undefined, role: 'columnheader', className: cn(styles.tableHeaderCell, className, columnDef.headerClassName), ref: element => {
36
+ setNodeRef(element);
37
+ return cellRef;
38
+ }, children: [_jsxs("div", { className: styles.tableHeaderCellMain, children: [columnDef.header && (_jsx("div", { className: styles.tableHeaderCellName, children: _jsx(TruncateString, { text: flexRender(columnDef.header, header.getContext()) }) })), Boolean(sortIcon) && (_jsx("div", { className: styles.tableHeaderIcon, "data-sort-direction": sortDirection, "data-test-id": TEST_IDS.headerSortIndicator, children: sortIcon }))] }), isAvailableForDrag && Boolean(isDraggable) && _jsx(DragHandle, { attributes: attributes, listeners: listeners }), Boolean(isResizable) && _jsx(ResizeHandle, { header: header, cellRef: cellRef })] }));
30
39
  }
@@ -129,4 +129,15 @@
129
129
  .tableHeaderIcon svg{
130
130
  width:var(--size-icon-container-xs, 16px) !important;
131
131
  height:var(--size-icon-container-xs, 16px) !important;
132
+ }
133
+
134
+ .dragHandle{
135
+ cursor:pointer;
136
+ display:flex;
137
+ flex-direction:row;
138
+ gap:2px;
139
+ }
140
+
141
+ .dragIcon{
142
+ color:var(--sys-neutral-text-light, #8b8e9b);
132
143
  }
@@ -1,5 +1,6 @@
1
1
  import { Row as TableRow } from '@tanstack/react-table';
2
2
  import { MouseEvent } from 'react';
3
+ import { GroupedColumnOrderState } from '../../types';
3
4
  export type RowInfo<TData> = {
4
5
  id: string;
5
6
  data: TData;
@@ -10,5 +11,7 @@ export type RowClickHandler<TData> = (e: MouseEvent<HTMLDivElement>, row: RowInf
10
11
  export type BodyRowProps<TData> = {
11
12
  row: TableRow<TData>;
12
13
  onRowClick?: RowClickHandler<TData>;
14
+ groupedColumnOrderState: GroupedColumnOrderState;
15
+ enableColumnsOrderSortByDrag?: boolean;
13
16
  };
14
- export declare function BodyRow<TData>({ row, onRowClick }: BodyRowProps<TData>): import("react/jsx-runtime").JSX.Element;
17
+ export declare function BodyRow<TData>({ row, onRowClick, groupedColumnOrderState, enableColumnsOrderSortByDrag, }: BodyRowProps<TData>): import("react/jsx-runtime").JSX.Element;
@@ -1,4 +1,5 @@
1
1
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { horizontalListSortingStrategy, SortableContext } from '@dnd-kit/sortable';
2
3
  import { useState } from 'react';
3
4
  import { COLUMN_PIN_POSITION, TEST_IDS } from '../../constants';
4
5
  import { BodyCell } from '../Cells';
@@ -7,8 +8,8 @@ import { useRowCells } from '../hooks';
7
8
  import { PinnedCells } from './PinnedCells';
8
9
  import { Row } from './Row';
9
10
  import styles from './styles.module.css';
10
- export function BodyRow({ row, onRowClick }) {
11
- const { pinnedLeft, pinnedRight, unpinned } = useRowCells(row);
11
+ export function BodyRow({ row, onRowClick, groupedColumnOrderState, enableColumnsOrderSortByDrag, }) {
12
+ const { leftPinned, rightPinned, unpinned } = useRowCells(row, groupedColumnOrderState);
12
13
  const [dropListOpened, setDropListOpen] = useState(false);
13
14
  const disabled = !row.getCanSelect();
14
15
  const handleRowClick = (e) => {
@@ -23,5 +24,5 @@ export function BodyRow({ row, onRowClick }) {
23
24
  };
24
25
  return (_jsx(RowContext.Provider, { value: { dropListOpened, setDropListOpen }, children: _jsxs(Row, { onClick: handleRowClick, "data-clickable": Boolean(onRowClick) || undefined, "data-disabled": disabled || undefined, "data-selected": row.getIsSelected() ||
25
26
  (row.getIsSomeSelected() && !row.getCanMultiSelect() && !row.getIsExpanded()) ||
26
- undefined, "data-actions-opened": dropListOpened || undefined, "data-test-id": TEST_IDS.bodyRow, "data-row-id": row.id, className: styles.bodyRow, children: [pinnedLeft && (_jsx(PinnedCells, { position: COLUMN_PIN_POSITION.Left, children: pinnedLeft.map(cell => (_jsx(BodyCell, { cell: cell }, cell.id))) })), unpinned.map(cell => (_jsx(BodyCell, { cell: cell }, cell.id))), pinnedRight && (_jsx(PinnedCells, { position: COLUMN_PIN_POSITION.Right, children: pinnedRight.map(cell => (_jsx(BodyCell, { cell: cell }, cell.id))) }))] }) }));
27
+ undefined, "data-actions-opened": dropListOpened || undefined, "data-test-id": TEST_IDS.bodyRow, "data-row-id": row.id, className: styles.bodyRow, children: [leftPinned && (_jsx(PinnedCells, { position: COLUMN_PIN_POSITION.Left, children: leftPinned.map(cell => (_jsx(SortableContext, { items: groupedColumnOrderState.leftPinned, strategy: horizontalListSortingStrategy, children: _jsx(BodyCell, { cell: cell, isDraggable: enableColumnsOrderSortByDrag }, cell.id) }, cell.id))) })), unpinned.map(cell => (_jsx(SortableContext, { items: groupedColumnOrderState.unpinned, strategy: horizontalListSortingStrategy, children: _jsx(BodyCell, { cell: cell, isDraggable: enableColumnsOrderSortByDrag }, cell.id) }, cell.id))), rightPinned && (_jsx(PinnedCells, { position: COLUMN_PIN_POSITION.Right, children: rightPinned.map(cell => (_jsx(SortableContext, { items: groupedColumnOrderState.rightPinned, strategy: horizontalListSortingStrategy, children: _jsx(BodyCell, { cell: cell, isDraggable: enableColumnsOrderSortByDrag }, cell.id) }, cell.id))) }))] }) }));
27
28
  }
@@ -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 {};
@@ -1,11 +1,12 @@
1
1
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { horizontalListSortingStrategy, SortableContext } from '@dnd-kit/sortable';
2
3
  import { COLUMN_PIN_POSITION, TEST_IDS } from '../../constants';
3
4
  import { HeaderCell } from '../Cells';
4
5
  import { useHeaderGroups } from '../hooks';
5
6
  import { PinnedCells } from './PinnedCells';
6
7
  import { Row } from './Row';
7
8
  import styles from './styles.module.css';
8
- export function HeaderRow() {
9
- const { leftPinned, unpinned, rightPinned } = useHeaderGroups();
10
- return (_jsxs(Row, { className: styles.tableHeader, "data-test-id": TEST_IDS.headerRow, children: [leftPinned && (_jsx(PinnedCells, { position: COLUMN_PIN_POSITION.Left, children: leftPinned.map(headerGroup => headerGroup.headers.map(header => header.isPlaceholder ? null : _jsx(HeaderCell, { header: header }, header.id))) })), unpinned.map(headerGroup => headerGroup.headers.map(header => _jsx(HeaderCell, { header: header }, header.id))), rightPinned && (_jsx(PinnedCells, { position: COLUMN_PIN_POSITION.Right, children: rightPinned.map(headerGroup => headerGroup.headers.map(header => header.isPlaceholder ? null : (_jsx(HeaderCell, { header: header, pinPosition: COLUMN_PIN_POSITION.Right }, header.id)))) }))] }));
9
+ export function HeaderRow({ groupedColumnOrderState, enableColumnsOrderSortByDrag }) {
10
+ const { leftPinned, unpinned, rightPinned } = useHeaderGroups(groupedColumnOrderState);
11
+ return (_jsxs(Row, { className: styles.tableHeader, "data-test-id": TEST_IDS.headerRow, children: [leftPinned && (_jsx(SortableContext, { items: groupedColumnOrderState.leftPinned, strategy: horizontalListSortingStrategy, children: _jsx(PinnedCells, { position: COLUMN_PIN_POSITION.Left, children: leftPinned.map(headerGroup => headerGroup.headers.map(header => header.isPlaceholder ? null : (_jsx(HeaderCell, { header: header, isDraggable: enableColumnsOrderSortByDrag && groupedColumnOrderState.leftPinned.length > 1 }, header.id)))) }) })), _jsx(SortableContext, { items: groupedColumnOrderState.unpinned, strategy: horizontalListSortingStrategy, children: unpinned.map(headerGroup => headerGroup.headers.map(header => (_jsx(HeaderCell, { header: header, isDraggable: enableColumnsOrderSortByDrag && groupedColumnOrderState.unpinned.length > 1 }, header.id)))) }), rightPinned && (_jsx(SortableContext, { items: groupedColumnOrderState.rightPinned, strategy: horizontalListSortingStrategy, children: _jsx(PinnedCells, { position: COLUMN_PIN_POSITION.Right, children: rightPinned.map(headerGroup => headerGroup.headers.map(header => header.isPlaceholder ? null : (_jsx(HeaderCell, { header: header, pinPosition: COLUMN_PIN_POSITION.Right, isDraggable: enableColumnsOrderSortByDrag && groupedColumnOrderState.rightPinned.length > 1 }, header.id)))) }) }))] }));
11
12
  }
@@ -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 {};
@@ -1,12 +1,23 @@
1
+ import { useSortable } from '@dnd-kit/sortable';
2
+ import { CSS } from '@dnd-kit/utilities';
1
3
  import { useMemo } from 'react';
2
4
  import { useTableContext } from './contexts';
3
5
  function hasHeaders(groups) {
4
6
  return groups.some(group => group.headers.length);
5
7
  }
6
- export function useHeaderGroups() {
8
+ const sortHeaderGroup = (groups, groupOrder) => groups.map(group => (Object.assign(Object.assign({}, group), { headers: group.headers.sort((a, b) => {
9
+ const indexA = groupOrder.findIndex(columnId => columnId === a.id);
10
+ const indexB = groupOrder.findIndex(columnId => columnId === b.id);
11
+ if (indexA > -1 && indexB > -1) {
12
+ return indexA - indexB;
13
+ }
14
+ return 0;
15
+ }) })));
16
+ export function useHeaderGroups(groupedColumnOrderState) {
7
17
  const { table } = useTableContext();
8
18
  const columnDefs = table._getColumnDefs();
9
19
  const pinEnabled = table.getIsSomeColumnsPinned();
20
+ const { columnOrder } = table.getState();
10
21
  return useMemo(() => {
11
22
  if (!pinEnabled) {
12
23
  return {
@@ -16,18 +27,29 @@ export function useHeaderGroups() {
16
27
  const left = table.getLeftHeaderGroups();
17
28
  const right = table.getRightHeaderGroups();
18
29
  return {
19
- leftPinned: hasHeaders(left) ? left : undefined,
20
- rightPinned: hasHeaders(right) ? right : undefined,
30
+ leftPinned: hasHeaders(left) ? sortHeaderGroup(left, groupedColumnOrderState.leftPinned) : undefined,
31
+ rightPinned: hasHeaders(right) ? sortHeaderGroup(right, groupedColumnOrderState.rightPinned) : undefined,
21
32
  unpinned: table.getCenterHeaderGroups(),
22
33
  };
23
34
  // need to rebuild if columnDefinitions has changed
24
35
  // eslint-disable-next-line react-hooks/exhaustive-deps
25
- }, [table, pinEnabled, columnDefs]);
36
+ }, [table, pinEnabled, columnDefs, columnOrder, groupedColumnOrderState]);
37
+ }
38
+ function sortPinnedColumnsByOrderState(groupOrder) {
39
+ return (a, b) => {
40
+ const indexA = groupOrder.findIndex(columnId => columnId === a.column.id);
41
+ const indexB = groupOrder.findIndex(columnId => columnId === b.column.id);
42
+ if (indexA > -1 && indexB > -1) {
43
+ return indexA - indexB;
44
+ }
45
+ return 0;
46
+ };
26
47
  }
27
- export function useRowCells(row) {
48
+ export function useRowCells(row, groupedColumnOrderState) {
28
49
  const { table } = useTableContext();
29
50
  const pinEnabled = table.getIsSomeColumnsPinned();
30
51
  const columnDefs = table._getColumnDefs();
52
+ const { columnOrder } = table.getState();
31
53
  return useMemo(() => {
32
54
  if (!pinEnabled) {
33
55
  return {
@@ -37,24 +59,45 @@ export function useRowCells(row) {
37
59
  const left = row.getLeftVisibleCells();
38
60
  const right = row.getRightVisibleCells();
39
61
  return {
40
- pinnedLeft: left.length ? left : undefined,
41
- pinnedRight: right.length ? right : undefined,
62
+ leftPinned: left.length
63
+ ? left.slice().sort(sortPinnedColumnsByOrderState(groupedColumnOrderState.leftPinned))
64
+ : undefined,
65
+ rightPinned: right.length
66
+ ? right.slice().sort(sortPinnedColumnsByOrderState(groupedColumnOrderState.rightPinned))
67
+ : undefined,
42
68
  unpinned: row.getCenterVisibleCells(),
43
69
  };
44
70
  // need to rebuild if columnDefinitions has changed
45
71
  // eslint-disable-next-line react-hooks/exhaustive-deps
46
- }, [row, pinEnabled, columnDefs]);
72
+ }, [row, pinEnabled, columnDefs, columnOrder, groupedColumnOrderState]);
47
73
  }
48
- export function useCellSizes(element) {
74
+ export function useCellSizes(element, options) {
49
75
  const column = element.column;
76
+ const { isDragging, transform } = useSortable({
77
+ id: column.id,
78
+ });
50
79
  const minWidth = column.columnDef.minSize;
51
80
  const maxWidth = column.columnDef.maxSize;
52
81
  const width = `var(--table-column-${column.id}-size)`;
53
82
  const flexShrink = `var(--table-column-${column.id}-flex)`;
54
- return useMemo(() => ({
55
- minWidth,
56
- width,
57
- maxWidth,
58
- flexShrink,
59
- }), [flexShrink, maxWidth, minWidth, width]);
83
+ const isHeaderCell = 'headerGroup' in element;
84
+ return useMemo(() => {
85
+ const styles = {
86
+ minWidth,
87
+ width,
88
+ maxWidth,
89
+ flexShrink,
90
+ };
91
+ if (options === null || options === void 0 ? void 0 : options.isDraggable) {
92
+ styles.opacity = isDragging ? 0.8 : 1;
93
+ styles.position = 'relative';
94
+ styles.transform = CSS.Translate.toString(transform);
95
+ styles.transition = 'width transform 0.2s ease-in-out';
96
+ styles.zIndex = isDragging ? 1 : 0;
97
+ if (isHeaderCell) {
98
+ styles.whiteSpace = 'nowrap';
99
+ }
100
+ }
101
+ return styles;
102
+ }, [options === null || options === void 0 ? void 0 : options.isDraggable, flexShrink, isDragging, isHeaderCell, maxWidth, minWidth, transform, width]);
60
103
  }
@@ -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, };
package/package.json CHANGED
@@ -4,7 +4,7 @@
4
4
  "access": "public"
5
5
  },
6
6
  "title": "Table",
7
- "version": "0.29.0",
7
+ "version": "0.30.1-preview-9a03a1c9.0",
8
8
  "sideEffects": [
9
9
  "*.css",
10
10
  "*.woff",
@@ -36,6 +36,10 @@
36
36
  "license": "Apache-2.0",
37
37
  "scripts": {},
38
38
  "dependencies": {
39
+ "@dnd-kit/core": "6.3.1",
40
+ "@dnd-kit/modifiers": "9.0.0",
41
+ "@dnd-kit/sortable": "10.0.0",
42
+ "@dnd-kit/utilities": "3.2.2",
39
43
  "@snack-uikit/button": "0.19.7",
40
44
  "@snack-uikit/chips": "0.25.3",
41
45
  "@snack-uikit/icon-predefined": "0.7.3",
@@ -61,5 +65,5 @@
61
65
  "peerDependencies": {
62
66
  "@snack-uikit/locale": "*"
63
67
  },
64
- "gitHead": "59426d0dd21ec9b22909d8350ca1d988665b4215"
68
+ "gitHead": "a7e76287bbbbb376afb7bc895cfa1e125751608f"
65
69
  }