@snack-uikit/table 0.16.8-preview-fa3ea861.0 → 0.16.8

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 (32) hide show
  1. package/CHANGELOG.md +17 -0
  2. package/README.md +0 -2
  3. package/dist/components/Table/Table.d.ts +1 -1
  4. package/dist/components/Table/Table.js +10 -48
  5. package/dist/components/types.d.ts +0 -2
  6. package/dist/constants.js +1 -1
  7. package/dist/helperComponents/Cells/CopyCell/styles.module.css +0 -3
  8. package/dist/helperComponents/Cells/HeaderCell/HeaderCell.js +1 -1
  9. package/dist/helperComponents/Cells/HeaderCell/ResizeHandle.js +2 -9
  10. package/dist/helperComponents/Cells/HeaderCell/styles.module.css +0 -4
  11. package/dist/helperComponents/Cells/RowActionsCell/RowActionsCell.d.ts +15 -2
  12. package/dist/helperComponents/Cells/RowActionsCell/RowActionsCell.js +23 -15
  13. package/dist/helperComponents/Cells/RowActionsCell/styles.module.css +8 -2
  14. package/dist/helperComponents/Rows/BodyRow.js +2 -2
  15. package/dist/helperComponents/Rows/styles.module.css +0 -1
  16. package/dist/helperComponents/contexts.d.ts +2 -2
  17. package/dist/helperComponents/contexts.js +2 -2
  18. package/dist/types.d.ts +1 -3
  19. package/package.json +11 -10
  20. package/src/components/Table/Table.tsx +12 -59
  21. package/src/components/types.ts +0 -3
  22. package/src/constants.ts +1 -1
  23. package/src/helperComponents/Cells/CopyCell/styles.module.scss +0 -3
  24. package/src/helperComponents/Cells/HeaderCell/HeaderCell.tsx +0 -2
  25. package/src/helperComponents/Cells/HeaderCell/ResizeHandle.tsx +4 -14
  26. package/src/helperComponents/Cells/HeaderCell/styles.module.scss +0 -5
  27. package/src/helperComponents/Cells/RowActionsCell/RowActionsCell.tsx +51 -28
  28. package/src/helperComponents/Cells/RowActionsCell/styles.module.scss +11 -2
  29. package/src/helperComponents/Rows/BodyRow.tsx +3 -3
  30. package/src/helperComponents/Rows/styles.module.scss +0 -1
  31. package/src/helperComponents/contexts.ts +4 -4
  32. package/src/types.ts +2 -2
package/CHANGELOG.md CHANGED
@@ -3,6 +3,23 @@
3
3
  All notable changes to this project will be documented in this file.
4
4
  See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
5
5
 
6
+ ## 0.16.8 (2024-05-08)
7
+
8
+ ### Only dependencies have been changed
9
+ * [@snack-uikit/chips@0.13.4](https://github.com/cloud-ru-tech/snack-uikit/blob/master/packages/chips/CHANGELOG.md)
10
+ * [@snack-uikit/icons@0.21.0](https://github.com/cloud-ru-tech/snack-uikit/blob/master/packages/icons/CHANGELOG.md)
11
+ * [@snack-uikit/info-block@0.3.5](https://github.com/cloud-ru-tech/snack-uikit/blob/master/packages/info-block/CHANGELOG.md)
12
+ * [@snack-uikit/list@0.11.5](https://github.com/cloud-ru-tech/snack-uikit/blob/master/packages/list/CHANGELOG.md)
13
+ * [@snack-uikit/pagination@0.6.8](https://github.com/cloud-ru-tech/snack-uikit/blob/master/packages/pagination/CHANGELOG.md)
14
+ * [@snack-uikit/tag@0.9.2](https://github.com/cloud-ru-tech/snack-uikit/blob/master/packages/tag/CHANGELOG.md)
15
+ * [@snack-uikit/toggles@0.9.9](https://github.com/cloud-ru-tech/snack-uikit/blob/master/packages/toggles/CHANGELOG.md)
16
+ * [@snack-uikit/toolbar@0.7.33](https://github.com/cloud-ru-tech/snack-uikit/blob/master/packages/toolbar/CHANGELOG.md)
17
+ * [@snack-uikit/truncate-string@0.4.14](https://github.com/cloud-ru-tech/snack-uikit/blob/master/packages/truncate-string/CHANGELOG.md)
18
+
19
+
20
+
21
+
22
+
6
23
  ## 0.16.7 (2024-04-27)
7
24
 
8
25
  ### Only dependencies have been changed
package/README.md CHANGED
@@ -114,7 +114,6 @@ const columnDefinitions: ColumnDefinition<TableData>[] = [
114
114
  | sorting | `{ initialState?: SortingState; state?: SortingState; onChange?(state: SortingState): void; }` | - | Параметры отвечают за возможность сортировки, их стоит использовать если нужно отслеживать состояние <br> <strong>initialState</strong>: Начальное состояние сортировки <br> <strong>state</strong>: Состояние сортировки, жестко устанавливаемое снаружи <br> <strong>onChange</strong>: Колбэк на изменение сортировки |
115
115
  | rowSelection | `{ initialState?: RowSelectionState; state?: RowSelectionState; enable?: boolean \| ((row: Row<TData>) => boolean); multiRow?: boolean; onChange?(state: RowSelectionState): void; }` | - | Параметры отвечают за возможность выбора строк <br> <strong>initialState</strong>: Начальное состояние выбора строк <br> <strong>state</strong>: Состояние выбора строк, жестко устанавливаемое снаружи <br> <strong>enable</strong>: Колбэк определяющий можно ли выбрать строку <br> <strong>multiRow</strong>: Мульти-выбор строк (включен по-умолчанию, когда включается выбор) <br> <strong>onChange</strong>: Колбэк на выбор строк |
116
116
  | search | `{ initialValue?: string; state?: string; placeholder?: string; loading?: boolean; onChange?(value: string): void; }` | 'Search'<br> <strong>loading</strong>: Состояние загрузки в строке поиска <br> <strong>onChange</strong>: Колбэк на изменение данных в строке поиска | Параметры отвечают за глобальный поиск в таблице <br> <strong>initialState</strong>: Начальное состояние строки поиска <br> <strong>state</strong>: Состояние строки поиска, жестко устанавливаемое снаружи <br> <strong>placeholder</strong>: Placeholder строки поиска |
117
- | enableFuzzySearch | `boolean` | - | Включить нечеткий поиск |
118
117
  | pageSize | `number` | 10 | Максимальное кол-во строк на страницу |
119
118
  | pagination | `{ state?: PaginationState; options?: number[]; optionsLabel?: string; onChange?(state: PaginationState): void; }` | 'Rows volume: ' <br> <strong>onChange</strong>: Колбэк на изменение пагинации | Параметры отвечают за пагинацию в таблице <br> <strong>state</strong>: Состояние строки поиска, жестко устанавливаемое снаружи <br> <strong>options</strong>: Варианты в выпадающем селекторе для установки кол-ва строк на страницу <br> <strong>optionsLabel</strong>: Текст для селектора кол-ва строк на страницу |
120
119
  | pageCount | `number` | - | Кол-во страниц (используется для внешнего управления) |
@@ -170,7 +169,6 @@ const columnDefinitions: ColumnDefinition<TableData>[] = [
170
169
  | loading | `boolean` | - | Состояние загрузки |
171
170
  | sorting | `{ initialState?: SortingState; state?: SortingState; onChange?(state: SortingState): void; }` | - | Параметры отвечают за возможность сортировки, их стоит использовать если нужно отслеживать состояние <br> <strong>initialState</strong>: Начальное состояние сортировки <br> <strong>state</strong>: Состояние сортировки, жестко устанавливаемое снаружи <br> <strong>onChange</strong>: Колбэк на изменение сортировки |
172
171
  | rowSelection | `{ initialState?: RowSelectionState; state?: RowSelectionState; enable?: boolean \| ((row: Row<TData>) => boolean); multiRow?: boolean; onChange?(state: RowSelectionState): void; }` | - | Параметры отвечают за возможность выбора строк <br> <strong>initialState</strong>: Начальное состояние выбора строк <br> <strong>state</strong>: Состояние выбора строк, жестко устанавливаемое снаружи <br> <strong>enable</strong>: Колбэк определяющий можно ли выбрать строку <br> <strong>multiRow</strong>: Мульти-выбор строк (включен по-умолчанию, когда включается выбор) <br> <strong>onChange</strong>: Колбэк на выбор строк |
173
- | enableFuzzySearch | `boolean` | - | Включить нечеткий поиск |
174
172
  | onRowClick | `RowClickHandler<TData>` | - | Колбэк клика по строке |
175
173
  | className | `string` | - | CSS-класс |
176
174
  | onRefresh | `() => void` | - | Колбек обновления данных |
@@ -1,6 +1,6 @@
1
1
  import { TableProps } from '../types';
2
2
  /** Компонент таблицы */
3
- export declare function Table<TData extends object>({ data, columnDefinitions, rowSelection: rowSelectionProp, search, sorting: sortingProp, columnFilters, pagination: paginationProp, className, onRowClick, onRefresh, onDelete, pageSize, pageCount, loading, outline, moreActions, exportFileName, dataFiltered, dataError, noDataState, noResultsState, errorDataState, suppressToolbar, toolbarBefore, toolbarAfter, suppressPagination, manualSorting, manualPagination, manualFiltering, scrollRef, scrollContainerRef, getRowId, enableFuzzySearch, ...rest }: TableProps<TData>): import("react/jsx-runtime").JSX.Element;
3
+ export declare function Table<TData extends object>({ data, columnDefinitions, rowSelection: rowSelectionProp, search, sorting: sortingProp, columnFilters, pagination: paginationProp, className, onRowClick, onRefresh, onDelete, pageSize, pageCount, loading, outline, moreActions, exportFileName, dataFiltered, dataError, noDataState, noResultsState, errorDataState, suppressToolbar, toolbarBefore, toolbarAfter, suppressPagination, manualSorting, manualPagination, manualFiltering, scrollRef, scrollContainerRef, getRowId, ...rest }: TableProps<TData>): import("react/jsx-runtime").JSX.Element;
4
4
  export declare namespace Table {
5
5
  var getStatusColumnDef: typeof import("../../helperComponents").getStatusColumnDef;
6
6
  var statusAppearances: {
@@ -12,7 +12,7 @@ var __rest = (this && this.__rest) || function (s, e) {
12
12
  import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-runtime";
13
13
  import { getCoreRowModel, getFilteredRowModel, getPaginationRowModel, getSortedRowModel, useReactTable, } from '@tanstack/react-table';
14
14
  import cn from 'classnames';
15
- import { useCallback, useEffect, useMemo, useRef } from 'react';
15
+ import { useCallback, useEffect, useMemo } from 'react';
16
16
  import { useLocale } from '@snack-uikit/locale';
17
17
  import { Scroll } from '@snack-uikit/scroll';
18
18
  import { SkeletonContextProvider } from '@snack-uikit/skeleton';
@@ -27,7 +27,7 @@ import { useStateControl } from './hooks/useStateControl';
27
27
  import styles from './styles.module.css';
28
28
  /** Компонент таблицы */
29
29
  export function Table(_a) {
30
- var { data, columnDefinitions, rowSelection: rowSelectionProp, search, sorting: sortingProp, columnFilters, pagination: paginationProp, className, onRowClick, onRefresh, onDelete, pageSize = DEFAULT_PAGE_SIZE, pageCount, loading = false, outline = false, moreActions, exportFileName, dataFiltered, dataError, noDataState, noResultsState, errorDataState, suppressToolbar = false, toolbarBefore, toolbarAfter, suppressPagination = false, manualSorting = false, manualPagination = false, manualFiltering = false, scrollRef, scrollContainerRef, getRowId, enableFuzzySearch } = _a, rest = __rest(_a, ["data", "columnDefinitions", "rowSelection", "search", "sorting", "columnFilters", "pagination", "className", "onRowClick", "onRefresh", "onDelete", "pageSize", "pageCount", "loading", "outline", "moreActions", "exportFileName", "dataFiltered", "dataError", "noDataState", "noResultsState", "errorDataState", "suppressToolbar", "toolbarBefore", "toolbarAfter", "suppressPagination", "manualSorting", "manualPagination", "manualFiltering", "scrollRef", "scrollContainerRef", "getRowId", "enableFuzzySearch"]);
30
+ var { data, columnDefinitions, rowSelection: rowSelectionProp, search, sorting: sortingProp, columnFilters, pagination: paginationProp, className, onRowClick, onRefresh, onDelete, pageSize = DEFAULT_PAGE_SIZE, pageCount, loading = false, outline = false, moreActions, exportFileName, dataFiltered, dataError, noDataState, noResultsState, errorDataState, suppressToolbar = false, toolbarBefore, toolbarAfter, suppressPagination = false, manualSorting = false, manualPagination = false, manualFiltering = false, scrollRef, scrollContainerRef, getRowId } = _a, rest = __rest(_a, ["data", "columnDefinitions", "rowSelection", "search", "sorting", "columnFilters", "pagination", "className", "onRowClick", "onRefresh", "onDelete", "pageSize", "pageCount", "loading", "outline", "moreActions", "exportFileName", "dataFiltered", "dataError", "noDataState", "noResultsState", "errorDataState", "suppressToolbar", "toolbarBefore", "toolbarAfter", "suppressPagination", "manualSorting", "manualPagination", "manualFiltering", "scrollRef", "scrollContainerRef", "getRowId"]);
31
31
  const { state: globalFilter, onStateChange: onGlobalFilterChange } = useStateControl(search, '');
32
32
  const { state: rowSelection, onStateChange: onRowSelectionChange } = useStateControl(rowSelectionProp, {});
33
33
  const defaultPaginationState = useMemo(() => ({
@@ -37,11 +37,6 @@ export function Table(_a) {
37
37
  const { state: sorting, onStateChange: onSortingChange } = useStateControl(sortingProp, []);
38
38
  const { state: pagination, onStateChange: onPaginationChange } = useStateControl(paginationProp, defaultPaginationState);
39
39
  const enableSelection = Boolean(rowSelectionProp === null || rowSelectionProp === void 0 ? void 0 : rowSelectionProp.enable);
40
- useEffect(() => {
41
- if (pagination.pageIndex >= data.length / pagination.pageSize) {
42
- onPaginationChange(Object.assign(Object.assign({}, pagination), { pageIndex: 0 }));
43
- }
44
- }, [data.length, onPaginationChange, pagination]);
45
40
  const tableColumns = useMemo(() => {
46
41
  let cols = columnDefinitions;
47
42
  if (enableSelection) {
@@ -80,7 +75,7 @@ export function Table(_a) {
80
75
  manualSorting,
81
76
  manualPagination,
82
77
  manualFiltering,
83
- globalFilterFn: enableFuzzySearch ? fuzzyFilter : undefined,
78
+ globalFilterFn: fuzzyFilter,
84
79
  onGlobalFilterChange,
85
80
  getRowId,
86
81
  onRowSelectionChange,
@@ -94,7 +89,6 @@ export function Table(_a) {
94
89
  onSortingChange,
95
90
  getSortedRowModel: getSortedRowModel(),
96
91
  onPaginationChange,
97
- autoResetPageIndex: false,
98
92
  getPaginationRowModel: getPaginationRowModel(),
99
93
  getCoreRowModel: getCoreRowModel(),
100
94
  columnResizeMode: 'onEnd',
@@ -122,62 +116,30 @@ export function Table(_a) {
122
116
  return;
123
117
  }
124
118
  }, [loading, rowSelectionProp === null || rowSelectionProp === void 0 ? void 0 : rowSelectionProp.multiRow, table]);
125
- const columnSizeVarsRef = useRef();
126
- const headers = table.getFlatHeaders();
127
- const columnSizesSnapshot = table
128
- .getAllColumns()
129
- .map(column => column.getSize())
130
- .join('_');
119
+ useEffect(() => { }, []);
131
120
  const columnSizeVars = useMemo(() => {
132
- var _a;
133
- const sizeKey = (id) => `--table-column-${id}-size`;
134
- const flexKey = (id) => `--table-column-${id}-flex`;
135
- const getCurrentlyConfiguredHeaderWidth = (id) => {
136
- const cell = document.querySelector(`[data-header-id="${id}"]`);
137
- const resizeHandler = cell === null || cell === void 0 ? void 0 : cell.querySelector('[data-test-id="table__header-cell-resize-handle-moving-part"]');
138
- if (cell && resizeHandler) {
139
- const { width } = cell.getBoundingClientRect();
140
- const offset = parseInt(resizeHandler.style.getPropertyValue('--offset'));
141
- return width + offset;
142
- }
143
- return 0;
144
- };
145
121
  const originalColumnDefs = table._getColumnDefs();
122
+ const headers = table.getFlatHeaders();
146
123
  const colSizes = {};
147
124
  for (let i = 0; i < headers.length; i++) {
148
125
  const header = headers[i];
149
126
  const originalColDef = originalColumnDefs.find(col => getColumnId(header) === col.id);
150
127
  const originalColumnDefSize = originalColDef === null || originalColDef === void 0 ? void 0 : originalColDef.size;
151
128
  const initSize = originalColumnDefSize ? `${originalColumnDefSize}px` : '100%';
152
- const prevSize = (_a = columnSizeVarsRef.current) === null || _a === void 0 ? void 0 : _a[sizeKey(header.id)];
153
129
  let size = initSize;
154
130
  if (header.column.getCanResize()) {
155
131
  const currentSize = header.getSize();
156
132
  const colDefSize = header.column.columnDef.size;
157
133
  size = currentSize === colDefSize ? initSize : `${currentSize}px`;
158
- if (prevSize === '100%' && currentSize !== colDefSize) {
159
- const realSize = getCurrentlyConfiguredHeaderWidth(header.id);
160
- table.setColumnSizing(old => (Object.assign(Object.assign({}, old), { [header.id]: realSize })));
161
- size = `${realSize}px`;
162
- }
163
134
  }
164
- colSizes[sizeKey(header.id)] = size;
165
- colSizes[flexKey(header.id)] = size === '100%' ? 'unset' : '0';
135
+ colSizes[`--table-column-${header.id}-size`] = size;
136
+ colSizes[`--table-column-${header.id}-flex`] = size === '100%' ? 'unset' : '0';
166
137
  }
167
138
  return colSizes;
168
- /*
169
- effect must be called only on columnSizingInfo.isResizingColumn changes
170
- to reduce unnecessary recalculations
171
-
172
- headers ids can also change, so they also should present here
173
-
174
- columnSizesSnapshot will trigger re-render after double-click size reset
175
- */
139
+ /* effect must be called only on columnSizingInfo.isResizingColumn changes
140
+ to reduce unnecessary recalculations */
176
141
  // eslint-disable-next-line react-hooks/exhaustive-deps
177
- }, [table.getState().columnSizingInfo.isResizingColumn, headers, columnSizesSnapshot]);
178
- useEffect(() => {
179
- columnSizeVarsRef.current = columnSizeVars;
180
- }, [columnSizeVars]);
142
+ }, [table.getState().columnSizingInfo.isResizingColumn]);
181
143
  const tableRows = table.getRowModel().rows;
182
144
  const loadingTableRows = loadingTable.getRowModel().rows;
183
145
  const tablePagination = table.getState().pagination;
@@ -48,8 +48,6 @@ export type TableProps<TData extends object> = WithSupportProps<{
48
48
  loading?: boolean;
49
49
  onChange?(value: string): void;
50
50
  };
51
- /** Включить нечеткий поиск */
52
- enableFuzzySearch?: boolean;
53
51
  /** Максимальное кол-во строк на страницу @default 10 */
54
52
  pageSize?: number;
55
53
  /** Параметры отвечают за пагинацию в таблице <br>
package/dist/constants.js CHANGED
@@ -17,7 +17,7 @@ export const TEST_IDS = {
17
17
  rowActions: {
18
18
  droplistTrigger: 'table__body-row__droplistTrigger',
19
19
  droplist: 'table__body-row__actions-droplist',
20
- option: 'list__base-item-option',
20
+ option: 'table__body-row__action-option',
21
21
  },
22
22
  statusIndicator: 'table__status-indicator',
23
23
  statusLabel: 'table__status-label',
@@ -10,9 +10,6 @@
10
10
  .copyCell .copyButton{
11
11
  display:none;
12
12
  }
13
- .copyCell:hover{
14
- margin-right:calc(0px - (var(--dimension-4m, 32px) + var(--dimension-050m, 4px)));
15
- }
16
13
  .copyCell:hover .copyButton{
17
14
  display:inline-flex;
18
15
  }
@@ -26,5 +26,5 @@ export function HeaderCell({ header, className }) {
26
26
  return;
27
27
  return (_a = header.column.getToggleSortingHandler()) === null || _a === void 0 ? void 0 : _a(e);
28
28
  };
29
- return (_jsxs(Cell, { style: style, onMouseUp: 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, 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 })] }));
29
+ return (_jsxs(Cell, { style: style, onMouseUp: sortingHandler, "data-sortable": isSortable || undefined, "data-no-padding": columnDef.noHeaderCellPadding || undefined, "data-no-offset": columnDef.noHeaderCellBorderOffset || undefined, "data-test-id": TEST_IDS.headerCell, "data-resizing": isResizing || 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 })] }));
30
30
  }
@@ -22,15 +22,8 @@ function getResizeIndicatorOffset({ header, cellRef }) {
22
22
  export function ResizeHandle({ header, cellRef }) {
23
23
  const isResizing = header.column.getIsResizing();
24
24
  const resizeHandler = header.getResizeHandler();
25
- const handleMouseDown = event => {
26
- if (event.detail === 2) {
27
- header.column.resetSize();
28
- return;
29
- }
30
- resizeHandler(event);
31
- };
32
25
  const offset = isResizing ? getResizeIndicatorOffset({ header, cellRef }) : 0;
33
- return (_jsxs(_Fragment, { children: [_jsx("div", { role: 'button', tabIndex: 0, className: cn(styles.tableHeaderIcon, styles.tableHeaderResizeHandle), "data-resizing": isResizing || undefined, onMouseDown: handleMouseDown, onTouchStart: resizeHandler }), isResizing && (_jsx("div", { "data-test-id": 'table__header-cell-resize-handle-moving-part', className: styles.tableHeaderResizeIndicator, style: {
34
- '--offset': `${offset}px`,
26
+ return (_jsxs(_Fragment, { children: [_jsx("div", { className: cn(styles.tableHeaderIcon, styles.tableHeaderResizeHandle), "data-resizing": isResizing || undefined, onMouseDown: resizeHandler, onTouchStart: resizeHandler }), isResizing && (_jsx("div", { className: styles.tableHeaderResizeIndicator, style: {
27
+ transform: `translateX(${offset}px)`,
35
28
  } }))] }));
36
29
  }
@@ -69,9 +69,6 @@
69
69
  -moz-user-select:none;
70
70
  user-select:none;
71
71
  }
72
- .tableHeaderCell[data-align=right]{
73
- justify-content:flex-end;
74
- }
75
72
 
76
73
  .tableHeaderCellMain{
77
74
  overflow:auto;
@@ -106,7 +103,6 @@
106
103
  z-index:2;
107
104
  top:0;
108
105
  right:0;
109
- transform:translateX(var(--offset));
110
106
  width:1px;
111
107
  height:100%;
112
108
  background-color:var(--sys-neutral-decor-activated, #bfc2cc);
@@ -1,7 +1,20 @@
1
1
  import { CellContext } from '@tanstack/react-table';
2
- import { DroplistProps } from '@snack-uikit/list';
2
+ import { MouseEvent, ReactElement } from 'react';
3
+ import { BaseItemProps } from '@snack-uikit/list';
3
4
  import { ColumnDefinition } from '../../../types';
4
- export type ActionsGenerator<TData> = (cell: CellContext<TData, unknown>) => DroplistProps['items'];
5
+ export type RowActionInfo<TData> = {
6
+ rowId: string;
7
+ data: TData;
8
+ itemId?: string;
9
+ };
10
+ export type RowActionProps<TData> = Pick<BaseItemProps, 'content' | 'disabled' | 'data-test-id'> & {
11
+ icon?: ReactElement;
12
+ tagLabel?: string;
13
+ id?: string;
14
+ hidden?: boolean;
15
+ onClick(row: RowActionInfo<TData>, e: MouseEvent<HTMLElement>): void;
16
+ };
17
+ export type ActionsGenerator<TData> = (cell: CellContext<TData, unknown>) => RowActionProps<TData>[];
5
18
  export type RowActionsColumnDefProps<TData> = {
6
19
  /** Действия для строки */
7
20
  actionsGenerator: ActionsGenerator<TData>;
@@ -1,31 +1,39 @@
1
1
  import { jsx as _jsx } from "react/jsx-runtime";
2
- import { useCallback, useMemo } from 'react';
2
+ import { useMemo, useRef } from 'react';
3
3
  import { ButtonFunction } from '@snack-uikit/button';
4
4
  import { MoreSVG } from '@snack-uikit/icons';
5
- import { Droplist, isBaseItemProps } from '@snack-uikit/list';
5
+ import { Droplist } from '@snack-uikit/list';
6
+ import { Tag } from '@snack-uikit/tag';
6
7
  import { COLUMN_PIN_POSITION, TEST_IDS } from '../../../constants';
7
8
  import { useRowContext } from '../../contexts';
8
9
  import styles from './styles.module.css';
9
10
  function RowActionsCell({ row, actions }) {
10
- const { dropListOpened, setDropListOpen } = useRowContext();
11
- const patchItem = useCallback((item, cb) => {
12
- if (isBaseItemProps(item)) {
13
- return Object.assign(Object.assign({}, item), { onClick(e) {
14
- var _a;
15
- (_a = item.onClick) === null || _a === void 0 ? void 0 : _a.call(item, e);
16
- cb(e);
17
- } });
18
- }
19
- return Object.assign(Object.assign({}, item), { items: item.items.map(i => patchItem(i, cb)) });
20
- }, []);
11
+ const { droplistOpened, setDroplistOpen } = useRowContext();
12
+ const triggerRef = useRef(null);
13
+ const handleItemClick = (item) => (e) => {
14
+ item.onClick({ rowId: row.id, itemId: item.id, data: row.original }, e);
15
+ };
21
16
  const disabled = !row.getCanSelect();
22
17
  const stopPropagationClick = (e) => {
23
18
  e.stopPropagation();
24
19
  };
25
- const patchedItems = useMemo(() => actions.map(item => patchItem(item, () => setDropListOpen(false))), [actions, patchItem, setDropListOpen]);
20
+ const visibleActions = useMemo(() => actions.filter(item => !(item === null || item === void 0 ? void 0 : item.hidden)), [actions]);
26
21
  return (
27
22
  // eslint-disable-next-line jsx-a11y/no-static-element-interactions
28
- _jsx("div", { onClick: stopPropagationClick, className: styles.rowActionsCellWrap, "data-open": dropListOpened || undefined, children: !disabled && Boolean(actions.length) && (_jsx(Droplist, { trigger: 'clickAndFocusVisible', open: dropListOpened, onOpenChange: setDropListOpen, placement: 'bottom-end', size: 'm', "data-test-id": TEST_IDS.rowActions.droplist, items: patchedItems, children: _jsx(ButtonFunction, { icon: _jsx(MoreSVG, { size: 24 }), "data-test-id": TEST_IDS.rowActions.droplistTrigger }) })) }));
23
+ _jsx("div", { onClick: stopPropagationClick, className: styles.rowActionsCellWrap, "data-open": droplistOpened || undefined, children: !disabled && Boolean(visibleActions.length) && (_jsx(Droplist, { trigger: 'clickAndFocusVisible', open: droplistOpened, onOpenChange: setDroplistOpen, placement: 'bottom-end', size: 'm', "data-test-id": TEST_IDS.rowActions.droplist, triggerElemRef: triggerRef, items: actions
24
+ .filter(item => !(item === null || item === void 0 ? void 0 : item.hidden))
25
+ .map(item => ({
26
+ id: item.id,
27
+ onClick: e => {
28
+ handleItemClick(item)(e);
29
+ setDroplistOpen(false);
30
+ },
31
+ disabled: item.disabled,
32
+ content: item.content,
33
+ beforeContent: item.icon,
34
+ afterContent: item.tagLabel ? _jsx(Tag, { label: item.tagLabel }) : undefined,
35
+ 'data-test-id': item['data-test-id'] || TEST_IDS.rowActions.option,
36
+ })), children: _jsx("span", { className: styles.rowActionsCellTrigger, children: _jsx(ButtonFunction, { icon: _jsx(MoreSVG, { size: 24 }), "data-test-id": TEST_IDS.rowActions.droplistTrigger, ref: triggerRef }) }) })) }));
29
37
  }
30
38
  /** Вспомогательная функция для создания ячейки с дополнительными действиями у строки */
31
39
  export function getRowActionsColumnDef({ actionsGenerator, pinned, }) {
@@ -16,14 +16,20 @@
16
16
  }
17
17
 
18
18
  .rowActionsCellWrap{
19
- --offset:0px;
20
- cursor:pointer;
21
19
  box-sizing:border-box;
22
20
  width:100%;
23
21
  height:100%;
22
+ }
23
+
24
+ .rowActionsCellTrigger{
25
+ --offset:0px;
24
26
  padding-left:var(--space-table-cell-action-padding, 4px);
25
27
  padding-right:var(--space-table-cell-action-padding, 4px);
28
+ cursor:pointer;
26
29
  display:flex;
27
30
  align-items:center;
28
31
  justify-content:center;
32
+ box-sizing:border-box;
33
+ width:100%;
34
+ height:100%;
29
35
  }
@@ -9,7 +9,7 @@ import { Row } from './Row';
9
9
  import styles from './styles.module.css';
10
10
  export function BodyRow({ row, onRowClick }) {
11
11
  const { pinnedLeft, pinnedRight, unpinned } = useRowCells(row);
12
- const [dropListOpened, setDropListOpen] = useState(false);
12
+ const [droplistOpened, setDroplistOpen] = useState(false);
13
13
  const disabled = !row.getCanSelect();
14
14
  const handleRowClick = (e) => {
15
15
  if (disabled)
@@ -21,5 +21,5 @@ export function BodyRow({ row, onRowClick }) {
21
21
  toggleSelected: row.toggleSelected,
22
22
  });
23
23
  };
24
- 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() || 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))) }))] }) }));
24
+ 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() || 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))) }))] }) }));
25
25
  }
@@ -38,7 +38,6 @@
38
38
  }
39
39
  .rowPinnedCells[data-position=right]{
40
40
  right:0;
41
- margin-left:auto;
42
41
  }
43
42
  .rowPinnedCells[data-position=right]::after{
44
43
  left:0;
@@ -1,8 +1,8 @@
1
1
  import { Table } from '@tanstack/react-table';
2
2
  import { Dispatch, SetStateAction } from 'react';
3
3
  type RowContext = {
4
- dropListOpened: boolean;
5
- setDropListOpen: Dispatch<SetStateAction<boolean>>;
4
+ droplistOpened: boolean;
5
+ setDroplistOpen: Dispatch<SetStateAction<boolean>>;
6
6
  };
7
7
  export declare const RowContext: import("react").Context<RowContext>;
8
8
  export declare const useRowContext: () => RowContext;
@@ -1,7 +1,7 @@
1
1
  import { createContext, useContext } from 'react';
2
2
  export const RowContext = createContext({
3
- dropListOpened: false,
4
- setDropListOpen() { },
3
+ droplistOpened: false,
4
+ setDroplistOpen() { },
5
5
  });
6
6
  export const useRowContext = () => useContext(RowContext);
7
7
  // eslint-disable-next-line @typescript-eslint/no-explicit-any
package/dist/types.d.ts CHANGED
@@ -9,8 +9,6 @@ type ColumnPinPosition = ValueOf<typeof COLUMN_PIN_POSITION>;
9
9
  type BaseColumnDefinition<TData> = Except<ColumnDef<TData>, 'footer' | 'enablePinning' | 'enableGrouping' | 'enableColumnFilter' | 'filterFn' | 'enableGlobalFilter' | 'enableMultiSort' | 'enableHiding'> & {
10
10
  /** Заголовок колонки */
11
11
  header?: string | ((ctx: HeaderContext<TData, unknown>) => string);
12
- /** Позиционирование заголовка колонки */
13
- headerAlign?: ColumnAlign;
14
12
  /** Позиционирование контента ячейки в теле таблицы */
15
13
  align?: ColumnAlign;
16
14
  /** Отключить паддинг у ячейки в теле таблицы */
@@ -39,5 +37,5 @@ type PinnedColumnDefinition<TData> = BaseColumnDefinition<TData> & {
39
37
  size: number;
40
38
  };
41
39
  export type ColumnDefinition<TData> = NormalColumnDefinition<TData> | PinnedColumnDefinition<TData>;
42
- export type { RowActionsColumnDefProps, StatusColumnDefinitionProps, RowInfo, RowClickHandler, ActionsGenerator, CopyCellProps, MapStatusToAppearanceFnType, } from './helperComponents';
40
+ export type { RowActionInfo, RowActionProps, RowActionsColumnDefProps, StatusColumnDefinitionProps, RowInfo, RowClickHandler, ActionsGenerator, CopyCellProps, MapStatusToAppearanceFnType, } from './helperComponents';
43
41
  export type { 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.16.8-preview-fa3ea861.0",
7
+ "version": "0.16.8",
8
8
  "sideEffects": [
9
9
  "*.css",
10
10
  "*.woff",
@@ -33,17 +33,18 @@
33
33
  "scripts": {},
34
34
  "dependencies": {
35
35
  "@snack-uikit/button": "0.17.1",
36
- "@snack-uikit/chips": "0.13.4-preview-fa3ea861.0",
36
+ "@snack-uikit/chips": "0.13.4",
37
37
  "@snack-uikit/icon-predefined": "0.5.1",
38
- "@snack-uikit/icons": "0.20.1",
39
- "@snack-uikit/info-block": "0.3.4",
40
- "@snack-uikit/list": "0.11.5-preview-fa3ea861.0",
41
- "@snack-uikit/pagination": "0.6.7",
38
+ "@snack-uikit/icons": "0.21.0",
39
+ "@snack-uikit/info-block": "0.3.5",
40
+ "@snack-uikit/list": "0.11.5",
41
+ "@snack-uikit/pagination": "0.6.8",
42
42
  "@snack-uikit/scroll": "0.5.3",
43
43
  "@snack-uikit/skeleton": "0.3.4",
44
- "@snack-uikit/toggles": "0.9.8",
45
- "@snack-uikit/toolbar": "0.7.33-preview-fa3ea861.0",
46
- "@snack-uikit/truncate-string": "0.4.13",
44
+ "@snack-uikit/tag": "0.9.2",
45
+ "@snack-uikit/toggles": "0.9.9",
46
+ "@snack-uikit/toolbar": "0.7.33",
47
+ "@snack-uikit/truncate-string": "0.4.14",
47
48
  "@snack-uikit/typography": "0.6.2",
48
49
  "@snack-uikit/utils": "3.3.0",
49
50
  "@tanstack/match-sorter-utils": "8.11.8",
@@ -57,5 +58,5 @@
57
58
  "peerDependencies": {
58
59
  "@snack-uikit/locale": "*"
59
60
  },
60
- "gitHead": "f43a4ee983d921d1e1c8bdccd05a950d278c43ed"
61
+ "gitHead": "59bd2ac46a341357d543ada864a34e09745b3e42"
61
62
  }
@@ -11,7 +11,7 @@ import {
11
11
  useReactTable,
12
12
  } from '@tanstack/react-table';
13
13
  import cn from 'classnames';
14
- import { RefObject, useCallback, useEffect, useMemo, useRef } from 'react';
14
+ import { RefObject, useCallback, useEffect, useMemo } from 'react';
15
15
 
16
16
  import { useLocale } from '@snack-uikit/locale';
17
17
  import { Scroll } from '@snack-uikit/scroll';
@@ -76,7 +76,7 @@ export function Table<TData extends object>({
76
76
  scrollRef,
77
77
  scrollContainerRef,
78
78
  getRowId,
79
- enableFuzzySearch,
79
+
80
80
  ...rest
81
81
  }: TableProps<TData>) {
82
82
  const { state: globalFilter, onStateChange: onGlobalFilterChange } = useStateControl<string>(search, '');
@@ -99,12 +99,6 @@ export function Table<TData extends object>({
99
99
  );
100
100
  const enableSelection = Boolean(rowSelectionProp?.enable);
101
101
 
102
- useEffect(() => {
103
- if (pagination.pageIndex >= data.length / pagination.pageSize) {
104
- onPaginationChange({ ...pagination, pageIndex: 0 });
105
- }
106
- }, [data.length, onPaginationChange, pagination]);
107
-
108
102
  const tableColumns: ColumnDefinition<TData>[] = useMemo(() => {
109
103
  let cols: ColumnDefinition<TData>[] = columnDefinitions;
110
104
  if (enableSelection) {
@@ -112,7 +106,6 @@ export function Table<TData extends object>({
112
106
  }
113
107
  return cols;
114
108
  }, [columnDefinitions, enableSelection]);
115
-
116
109
  const columnPinning = useMemo(() => {
117
110
  const pinningState: Required<ColumnPinningState> = { left: [], right: [] };
118
111
  for (const col of tableColumns) {
@@ -146,7 +139,7 @@ export function Table<TData extends object>({
146
139
  manualPagination,
147
140
  manualFiltering,
148
141
 
149
- globalFilterFn: enableFuzzySearch ? fuzzyFilter : undefined,
142
+ globalFilterFn: fuzzyFilter,
150
143
  onGlobalFilterChange,
151
144
 
152
145
  getRowId,
@@ -161,9 +154,9 @@ export function Table<TData extends object>({
161
154
  onSortingChange,
162
155
  getSortedRowModel: getSortedRowModel(),
163
156
  onPaginationChange,
164
- autoResetPageIndex: false,
165
157
  getPaginationRowModel: getPaginationRowModel(),
166
158
  getCoreRowModel: getCoreRowModel(),
159
+
167
160
  columnResizeMode: 'onEnd',
168
161
  });
169
162
 
@@ -196,41 +189,18 @@ export function Table<TData extends object>({
196
189
  }
197
190
  }, [loading, rowSelectionProp?.multiRow, table]);
198
191
 
199
- const columnSizeVarsRef = useRef<Record<string, string>>();
200
- const headers = table.getFlatHeaders();
201
- const columnSizesSnapshot = table
202
- .getAllColumns()
203
- .map(column => column.getSize())
204
- .join('_');
192
+ useEffect(() => {}, []);
205
193
 
206
194
  const columnSizeVars = useMemo(() => {
207
- const sizeKey = (id: string) => `--table-column-${id}-size`;
208
- const flexKey = (id: string) => `--table-column-${id}-flex`;
209
-
210
- const getCurrentlyConfiguredHeaderWidth = (id: string) => {
211
- const cell = document.querySelector<HTMLDivElement>(`[data-header-id="${id}"]`);
212
- const resizeHandler = cell?.querySelector<HTMLDivElement>(
213
- '[data-test-id="table__header-cell-resize-handle-moving-part"]',
214
- );
215
-
216
- if (cell && resizeHandler) {
217
- const { width } = cell.getBoundingClientRect();
218
- const offset = parseInt(resizeHandler.style.getPropertyValue('--offset'));
219
- return width + offset;
220
- }
221
-
222
- return 0;
223
- };
224
-
225
195
  const originalColumnDefs = table._getColumnDefs();
226
- const colSizes: Record<string, string> = {};
196
+ const headers = table.getFlatHeaders();
197
+ const colSizes: { [key: string]: string } = {};
227
198
 
228
199
  for (let i = 0; i < headers.length; i++) {
229
200
  const header = headers[i];
230
201
  const originalColDef = originalColumnDefs.find(col => getColumnId(header) === col.id);
231
202
  const originalColumnDefSize = originalColDef?.size;
232
203
  const initSize = originalColumnDefSize ? `${originalColumnDefSize}px` : '100%';
233
- const prevSize = columnSizeVarsRef.current?.[sizeKey(header.id)];
234
204
 
235
205
  let size = initSize;
236
206
 
@@ -239,34 +209,17 @@ export function Table<TData extends object>({
239
209
  const colDefSize = header.column.columnDef.size;
240
210
 
241
211
  size = currentSize === colDefSize ? initSize : `${currentSize}px`;
242
-
243
- if (prevSize === '100%' && currentSize !== colDefSize) {
244
- const realSize = getCurrentlyConfiguredHeaderWidth(header.id);
245
- table.setColumnSizing(old => ({ ...old, [header.id]: realSize }));
246
-
247
- size = `${realSize}px`;
248
- }
249
212
  }
250
213
 
251
- colSizes[sizeKey(header.id)] = size;
252
- colSizes[flexKey(header.id)] = size === '100%' ? 'unset' : '0';
214
+ colSizes[`--table-column-${header.id}-size`] = size;
215
+ colSizes[`--table-column-${header.id}-flex`] = size === '100%' ? 'unset' : '0';
253
216
  }
254
217
 
255
218
  return colSizes;
256
- /*
257
- effect must be called only on columnSizingInfo.isResizingColumn changes
258
- to reduce unnecessary recalculations
259
-
260
- headers ids can also change, so they also should present here
261
-
262
- columnSizesSnapshot will trigger re-render after double-click size reset
263
- */
219
+ /* effect must be called only on columnSizingInfo.isResizingColumn changes
220
+ to reduce unnecessary recalculations */
264
221
  // eslint-disable-next-line react-hooks/exhaustive-deps
265
- }, [table.getState().columnSizingInfo.isResizingColumn, headers, columnSizesSnapshot]);
266
-
267
- useEffect(() => {
268
- columnSizeVarsRef.current = columnSizeVars;
269
- }, [columnSizeVars]);
222
+ }, [table.getState().columnSizingInfo.isResizingColumn]);
270
223
 
271
224
  const tableRows = table.getRowModel().rows;
272
225
  const loadingTableRows = loadingTable.getRowModel().rows;
@@ -52,9 +52,6 @@ export type TableProps<TData extends object> = WithSupportProps<{
52
52
  onChange?(value: string): void;
53
53
  };
54
54
 
55
- /** Включить нечеткий поиск */
56
- enableFuzzySearch?: boolean;
57
-
58
55
  /** Максимальное кол-во строк на страницу @default 10 */
59
56
  pageSize?: number;
60
57
 
package/src/constants.ts CHANGED
@@ -19,7 +19,7 @@ export const TEST_IDS = {
19
19
  rowActions: {
20
20
  droplistTrigger: 'table__body-row__droplistTrigger',
21
21
  droplist: 'table__body-row__actions-droplist',
22
- option: 'list__base-item-option',
22
+ option: 'table__body-row__action-option',
23
23
  },
24
24
  statusIndicator: 'table__status-indicator',
25
25
  statusLabel: 'table__status-label',
@@ -10,14 +10,11 @@
10
10
  width: 100%;
11
11
  min-width: 0;
12
12
  max-width: 100%;
13
-
14
13
  .copyButton {
15
14
  display: none;
16
15
  }
17
16
 
18
17
  &:hover {
19
- margin-right: calc(0px - calc($dimension-4m + $dimension-050m));
20
-
21
18
  .copyButton {
22
19
  display: inline-flex;
23
20
  }
@@ -46,8 +46,6 @@ export function HeaderCell<TData>({ header, className }: HeaderCellProps<TData>)
46
46
  data-no-padding={columnDef.noHeaderCellPadding || undefined}
47
47
  data-no-offset={columnDef.noHeaderCellBorderOffset || undefined}
48
48
  data-test-id={TEST_IDS.headerCell}
49
- data-align={columnDef.headerAlign || undefined}
50
- data-header-id={header.id}
51
49
  data-resizing={isResizing || undefined}
52
50
  role='columnheader'
53
51
  className={cn(styles.tableHeaderCell, className, columnDef.headerClassName)}
@@ -1,6 +1,6 @@
1
1
  import { Header } from '@tanstack/react-table';
2
2
  import cn from 'classnames';
3
- import { MouseEventHandler, RefObject } from 'react';
3
+ import { RefObject } from 'react';
4
4
 
5
5
  import styles from './styles.module.scss';
6
6
 
@@ -37,34 +37,24 @@ function getResizeIndicatorOffset<TData>({ header, cellRef }: ResizeHandleProps<
37
37
  export function ResizeHandle<TData>({ header, cellRef }: ResizeHandleProps<TData>) {
38
38
  const isResizing = header.column.getIsResizing();
39
39
  const resizeHandler = header.getResizeHandler();
40
- const handleMouseDown: MouseEventHandler = event => {
41
- if (event.detail === 2) {
42
- header.column.resetSize();
43
- return;
44
- }
45
-
46
- resizeHandler(event);
47
- };
48
40
 
49
41
  const offset = isResizing ? getResizeIndicatorOffset({ header, cellRef }) : 0;
50
42
 
51
43
  return (
52
44
  <>
45
+ {/* eslint-disable-next-line jsx-a11y/no-static-element-interactions */}
53
46
  <div
54
- role='button'
55
- tabIndex={0}
56
47
  className={cn(styles.tableHeaderIcon, styles.tableHeaderResizeHandle)}
57
48
  data-resizing={isResizing || undefined}
58
- onMouseDown={handleMouseDown}
49
+ onMouseDown={resizeHandler}
59
50
  onTouchStart={resizeHandler}
60
51
  />
61
52
 
62
53
  {isResizing && (
63
54
  <div
64
- data-test-id='table__header-cell-resize-handle-moving-part'
65
55
  className={styles.tableHeaderResizeIndicator}
66
56
  style={{
67
- '--offset': `${offset}px`,
57
+ transform: `translateX(${offset}px)`,
68
58
  }}
69
59
  />
70
60
  )}
@@ -92,10 +92,6 @@
92
92
  &[data-resizing] {
93
93
  user-select: none;
94
94
  }
95
-
96
- &[data-align='right'] {
97
- justify-content: flex-end;
98
- }
99
95
  }
100
96
 
101
97
  .tableHeaderCellMain {
@@ -137,7 +133,6 @@
137
133
  z-index: 2;
138
134
  top: 0;
139
135
  right: 0;
140
- transform: translateX(var(--offset));
141
136
 
142
137
  width: 1px;
143
138
  height: 100%;
@@ -1,36 +1,42 @@
1
1
  import { CellContext, Row } from '@tanstack/react-table';
2
- import { MouseEvent, MouseEventHandler, useCallback, useMemo } from 'react';
2
+ import { MouseEvent, ReactElement, useMemo, useRef } from 'react';
3
3
 
4
4
  import { ButtonFunction } from '@snack-uikit/button';
5
5
  import { MoreSVG } from '@snack-uikit/icons';
6
- import { Droplist, DroplistProps, isBaseItemProps, ItemProps } from '@snack-uikit/list';
6
+ import { BaseItemProps, Droplist } from '@snack-uikit/list';
7
+ import { Tag } from '@snack-uikit/tag';
7
8
 
8
9
  import { COLUMN_PIN_POSITION, TEST_IDS } from '../../../constants';
9
10
  import { ColumnDefinition } from '../../../types';
10
11
  import { useRowContext } from '../../contexts';
11
12
  import styles from './styles.module.scss';
12
13
 
14
+ export type RowActionInfo<TData> = {
15
+ rowId: string;
16
+ data: TData;
17
+ itemId?: string;
18
+ };
19
+
20
+ export type RowActionProps<TData> = Pick<BaseItemProps, 'content' | 'disabled' | 'data-test-id'> & {
21
+ icon?: ReactElement;
22
+ tagLabel?: string;
23
+ id?: string;
24
+ hidden?: boolean;
25
+ onClick(row: RowActionInfo<TData>, e: MouseEvent<HTMLElement>): void;
26
+ };
27
+
13
28
  type RowActionsCellProps<TData> = {
14
- actions: DroplistProps['items'];
29
+ actions: RowActionProps<TData>[];
15
30
  row: Row<TData>;
16
31
  };
17
32
 
18
33
  function RowActionsCell<TData>({ row, actions }: RowActionsCellProps<TData>) {
19
- const { dropListOpened, setDropListOpen } = useRowContext();
34
+ const { droplistOpened, setDroplistOpen } = useRowContext();
35
+ const triggerRef = useRef(null);
20
36
 
21
- const patchItem = useCallback((item: ItemProps, cb: MouseEventHandler): ItemProps => {
22
- if (isBaseItemProps(item)) {
23
- return {
24
- ...item,
25
- onClick(e) {
26
- item.onClick?.(e);
27
- cb(e);
28
- },
29
- };
30
- }
31
-
32
- return { ...item, items: item.items.map(i => patchItem(i, cb)) };
33
- }, []);
37
+ const handleItemClick = (item: RowActionProps<TData>) => (e: MouseEvent<HTMLElement>) => {
38
+ item.onClick({ rowId: row.id, itemId: item.id, data: row.original }, e);
39
+ };
34
40
 
35
41
  const disabled = !row.getCanSelect();
36
42
 
@@ -38,32 +44,49 @@ function RowActionsCell<TData>({ row, actions }: RowActionsCellProps<TData>) {
38
44
  e.stopPropagation();
39
45
  };
40
46
 
41
- const patchedItems = useMemo(
42
- () => actions.map(item => patchItem(item, () => setDropListOpen(false))),
43
- [actions, patchItem, setDropListOpen],
44
- );
47
+ const visibleActions: RowActionProps<TData>[] = useMemo(() => actions.filter(item => !item?.hidden), [actions]);
45
48
 
46
49
  return (
47
50
  // eslint-disable-next-line jsx-a11y/no-static-element-interactions
48
- <div onClick={stopPropagationClick} className={styles.rowActionsCellWrap} data-open={dropListOpened || undefined}>
49
- {!disabled && Boolean(actions.length) && (
51
+ <div onClick={stopPropagationClick} className={styles.rowActionsCellWrap} data-open={droplistOpened || undefined}>
52
+ {!disabled && Boolean(visibleActions.length) && (
50
53
  <Droplist
51
54
  trigger='clickAndFocusVisible'
52
- open={dropListOpened}
53
- onOpenChange={setDropListOpen}
55
+ open={droplistOpened}
56
+ onOpenChange={setDroplistOpen}
54
57
  placement='bottom-end'
55
58
  size='m'
56
59
  data-test-id={TEST_IDS.rowActions.droplist}
57
- items={patchedItems}
60
+ triggerElemRef={triggerRef}
61
+ items={actions
62
+ .filter(item => !item?.hidden)
63
+ .map(item => ({
64
+ id: item.id,
65
+ onClick: e => {
66
+ handleItemClick(item)(e);
67
+ setDroplistOpen(false);
68
+ },
69
+ disabled: item.disabled,
70
+ content: item.content,
71
+ beforeContent: item.icon,
72
+ afterContent: item.tagLabel ? <Tag label={item.tagLabel} /> : undefined,
73
+ 'data-test-id': item['data-test-id'] || TEST_IDS.rowActions.option,
74
+ }))}
58
75
  >
59
- <ButtonFunction icon={<MoreSVG size={24} />} data-test-id={TEST_IDS.rowActions.droplistTrigger} />
76
+ <span className={styles.rowActionsCellTrigger}>
77
+ <ButtonFunction
78
+ icon={<MoreSVG size={24} />}
79
+ data-test-id={TEST_IDS.rowActions.droplistTrigger}
80
+ ref={triggerRef}
81
+ />
82
+ </span>
60
83
  </Droplist>
61
84
  )}
62
85
  </div>
63
86
  );
64
87
  }
65
88
 
66
- export type ActionsGenerator<TData> = (cell: CellContext<TData, unknown>) => DroplistProps['items'];
89
+ export type ActionsGenerator<TData> = (cell: CellContext<TData, unknown>) => RowActionProps<TData>[];
67
90
 
68
91
  export type RowActionsColumnDefProps<TData> = {
69
92
  /** Действия для строки */
@@ -24,15 +24,24 @@
24
24
  }
25
25
 
26
26
  .rowActionsCellWrap {
27
- --offset: 0px;
28
- cursor: pointer;
29
27
  box-sizing: border-box;
30
28
  width: 100%;
31
29
  height: 100%;
30
+ }
31
+
32
+ .rowActionsCellTrigger {
33
+ --offset: 0px;
32
34
 
33
35
  @include composite-var($table-cells-action);
36
+
37
+
38
+ cursor: pointer;
34
39
 
35
40
  display: flex;
36
41
  align-items: center;
37
42
  justify-content: center;
43
+
44
+ box-sizing: border-box;
45
+ width: 100%;
46
+ height: 100%;
38
47
  }
@@ -26,7 +26,7 @@ type BodyRowProps<TData> = {
26
26
  export function BodyRow<TData>({ row, onRowClick }: BodyRowProps<TData>) {
27
27
  const { pinnedLeft, pinnedRight, unpinned } = useRowCells(row);
28
28
 
29
- const [dropListOpened, setDropListOpen] = useState(false);
29
+ const [droplistOpened, setDroplistOpen] = useState(false);
30
30
 
31
31
  const disabled = !row.getCanSelect();
32
32
 
@@ -42,13 +42,13 @@ export function BodyRow<TData>({ row, onRowClick }: BodyRowProps<TData>) {
42
42
  };
43
43
 
44
44
  return (
45
- <RowContext.Provider value={{ dropListOpened, setDropListOpen }}>
45
+ <RowContext.Provider value={{ droplistOpened, setDroplistOpen }}>
46
46
  <Row
47
47
  onClick={handleRowClick}
48
48
  data-clickable={Boolean(onRowClick) || undefined}
49
49
  data-disabled={disabled || undefined}
50
50
  data-selected={row.getIsSelected() || undefined}
51
- data-actions-opened={dropListOpened || undefined}
51
+ data-actions-opened={droplistOpened || undefined}
52
52
  data-test-id={TEST_IDS.bodyRow}
53
53
  data-row-id={row.id}
54
54
  className={styles.bodyRow}
@@ -61,7 +61,6 @@ $snack-ui-table-row-background: var(--snack-ui-table-row-background);
61
61
 
62
62
  &[data-position='right'] {
63
63
  right: 0;
64
- margin-left: auto;
65
64
 
66
65
  &::after {
67
66
  left: 0;
@@ -2,13 +2,13 @@ import { Table } from '@tanstack/react-table';
2
2
  import { createContext, Dispatch, SetStateAction, useContext } from 'react';
3
3
 
4
4
  type RowContext = {
5
- dropListOpened: boolean;
6
- setDropListOpen: Dispatch<SetStateAction<boolean>>;
5
+ droplistOpened: boolean;
6
+ setDroplistOpen: Dispatch<SetStateAction<boolean>>;
7
7
  };
8
8
 
9
9
  export const RowContext = createContext<RowContext>({
10
- dropListOpened: false,
11
- setDropListOpen() {},
10
+ droplistOpened: false,
11
+ setDroplistOpen() {},
12
12
  });
13
13
 
14
14
  export const useRowContext = () => useContext(RowContext);
package/src/types.ts CHANGED
@@ -33,8 +33,6 @@ type BaseColumnDefinition<TData> = Except<
33
33
  > & {
34
34
  /** Заголовок колонки */
35
35
  header?: string | ((ctx: HeaderContext<TData, unknown>) => string);
36
- /** Позиционирование заголовка колонки */
37
- headerAlign?: ColumnAlign;
38
36
  /** Позиционирование контента ячейки в теле таблицы */
39
37
  align?: ColumnAlign;
40
38
  /** Отключить паддинг у ячейки в теле таблицы */
@@ -66,6 +64,8 @@ type PinnedColumnDefinition<TData> = BaseColumnDefinition<TData> & {
66
64
  export type ColumnDefinition<TData> = NormalColumnDefinition<TData> | PinnedColumnDefinition<TData>;
67
65
 
68
66
  export type {
67
+ RowActionInfo,
68
+ RowActionProps,
69
69
  RowActionsColumnDefProps,
70
70
  StatusColumnDefinitionProps,
71
71
  RowInfo,