@snack-uikit/table 0.16.8 → 0.17.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 (44) hide show
  1. package/CHANGELOG.md +27 -0
  2. package/README.md +2 -0
  3. package/dist/components/Table/Table.d.ts +1 -1
  4. package/dist/components/Table/Table.js +35 -12
  5. package/dist/components/Table/hooks/index.d.ts +1 -0
  6. package/dist/components/Table/hooks/index.js +1 -0
  7. package/dist/components/Table/utils.d.ts +5 -0
  8. package/dist/components/Table/utils.js +16 -0
  9. package/dist/components/types.d.ts +2 -0
  10. package/dist/constants.js +1 -1
  11. package/dist/helperComponents/Cells/CopyCell/styles.module.css +3 -0
  12. package/dist/helperComponents/Cells/HeaderCell/HeaderCell.d.ts +3 -1
  13. package/dist/helperComponents/Cells/HeaderCell/HeaderCell.js +2 -2
  14. package/dist/helperComponents/Cells/HeaderCell/ResizeHandle.js +10 -2
  15. package/dist/helperComponents/Cells/HeaderCell/helpers.d.ts +2 -0
  16. package/dist/helperComponents/Cells/HeaderCell/helpers.js +3 -0
  17. package/dist/helperComponents/Cells/HeaderCell/styles.module.css +34 -20
  18. package/dist/helperComponents/Cells/RowActionsCell/RowActionsCell.d.ts +2 -15
  19. package/dist/helperComponents/Cells/RowActionsCell/RowActionsCell.js +15 -23
  20. package/dist/helperComponents/Cells/RowActionsCell/styles.module.css +2 -8
  21. package/dist/helperComponents/Rows/BodyRow.js +2 -2
  22. package/dist/helperComponents/Rows/HeaderRow.js +1 -1
  23. package/dist/helperComponents/Rows/styles.module.css +1 -0
  24. package/dist/helperComponents/contexts.d.ts +2 -2
  25. package/dist/helperComponents/contexts.js +2 -2
  26. package/dist/types.d.ts +4 -2
  27. package/package.json +5 -6
  28. package/src/components/Table/Table.tsx +40 -14
  29. package/src/components/Table/hooks/index.ts +1 -0
  30. package/src/components/Table/utils.ts +21 -0
  31. package/src/components/types.ts +3 -0
  32. package/src/constants.ts +1 -1
  33. package/src/helperComponents/Cells/CopyCell/styles.module.scss +3 -0
  34. package/src/helperComponents/Cells/HeaderCell/HeaderCell.tsx +6 -2
  35. package/src/helperComponents/Cells/HeaderCell/ResizeHandle.tsx +17 -4
  36. package/src/helperComponents/Cells/HeaderCell/helpers.tsx +5 -0
  37. package/src/helperComponents/Cells/HeaderCell/styles.module.scss +46 -26
  38. package/src/helperComponents/Cells/RowActionsCell/RowActionsCell.tsx +28 -51
  39. package/src/helperComponents/Cells/RowActionsCell/styles.module.scss +2 -11
  40. package/src/helperComponents/Rows/BodyRow.tsx +3 -3
  41. package/src/helperComponents/Rows/HeaderRow.tsx +3 -1
  42. package/src/helperComponents/Rows/styles.module.scss +1 -0
  43. package/src/helperComponents/contexts.ts +4 -4
  44. package/src/types.ts +3 -2
package/CHANGELOG.md CHANGED
@@ -3,6 +3,33 @@
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.17.0 (2024-05-08)
7
+
8
+
9
+ ### Bug Fixes
10
+
11
+ * **PDS-135:** change column sizing when header changes ([985fee7](https://github.com/cloud-ru-tech/snack-uikit/commit/985fee74f695cfc7c19dba2a1c73202a83295bc8))
12
+ * **PDS-135:** fix first resize of columns, add reset of column size on double-click ([3094130](https://github.com/cloud-ru-tech/snack-uikit/commit/309413044ddacafe077f16686469d73fa676ded5))
13
+ * **PDS-135:** keep page number when data is updated ([76b0b74](https://github.com/cloud-ru-tech/snack-uikit/commit/76b0b7448f112575bb35b413ac3db54ab938f70e))
14
+ * **PDS-135:** right-pinned column does not change its place when resizing ([60b96b4](https://github.com/cloud-ru-tech/snack-uikit/commit/60b96b4dd652d5bc106d1d9b5ed1cc5ec9925d67))
15
+ * **PDS-190:** redundant scroll, click on resize handler ([e520169](https://github.com/cloud-ru-tech/snack-uikit/commit/e5201697109c0dbb4e09034401367026c312fe9a))
16
+ * **PDS-197:** fix copyCell flex behaviour ([cb3c2a5](https://github.com/cloud-ru-tech/snack-uikit/commit/cb3c2a516431cd1877756c3e3cc2f8e42b47ce83))
17
+
18
+
19
+ ### Features
20
+
21
+ * **PDS-135:** add enableFuzzySearch prop ([cf203f3](https://github.com/cloud-ru-tech/snack-uikit/commit/cf203f33f27bcd34927de0090c3b7f5a8046fdab))
22
+ * **PDS-208:** add headerAlign prop ([066fb90](https://github.com/cloud-ru-tech/snack-uikit/commit/066fb90898ed542d1763f23556b30a494b63c2b9))
23
+
24
+
25
+ ### BREAKING CHANGES
26
+
27
+
28
+ * **PDS-135:** add full api from list to actions ([aae4ed3](https://github.com/cloud-ru-tech/snack-uikit/commit/aae4ed341d2e397b079e810a9b38762d9a96d952))
29
+
30
+
31
+
32
+
6
33
  ## 0.16.8 (2024-05-08)
7
34
 
8
35
  ### Only dependencies have been changed
package/README.md CHANGED
@@ -114,6 +114,7 @@ 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` | - | Включить нечеткий поиск |
117
118
  | pageSize | `number` | 10 | Максимальное кол-во строк на страницу |
118
119
  | 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>: Текст для селектора кол-ва строк на страницу |
119
120
  | pageCount | `number` | - | Кол-во страниц (используется для внешнего управления) |
@@ -169,6 +170,7 @@ const columnDefinitions: ColumnDefinition<TableData>[] = [
169
170
  | loading | `boolean` | - | Состояние загрузки |
170
171
  | sorting | `{ initialState?: SortingState; state?: SortingState; onChange?(state: SortingState): void; }` | - | Параметры отвечают за возможность сортировки, их стоит использовать если нужно отслеживать состояние <br> <strong>initialState</strong>: Начальное состояние сортировки <br> <strong>state</strong>: Состояние сортировки, жестко устанавливаемое снаружи <br> <strong>onChange</strong>: Колбэк на изменение сортировки |
171
172
  | 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` | - | Включить нечеткий поиск |
172
174
  | onRowClick | `RowClickHandler<TData>` | - | Колбэк клика по строке |
173
175
  | className | `string` | - | CSS-класс |
174
176
  | 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, ...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, enableFuzzySearch, ...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 } from 'react';
15
+ import { useCallback, useEffect, useMemo, useRef } 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';
@@ -22,12 +22,12 @@ import { extractSupportProps } from '@snack-uikit/utils';
22
22
  import { DEFAULT_PAGE_SIZE } from '../../constants';
23
23
  import { BodyRow, ExportButton, getColumnId, getRowActionsColumnDef, getSelectionCellColumnDef, getStatusColumnDef, HeaderRow, STATUS_APPEARANCE, TableContext, TableEmptyState, TablePagination, useEmptyState, } from '../../helperComponents';
24
24
  import { fuzzyFilter } from '../../utils';
25
- import { useLoadingTable } from './hooks';
26
- import { useStateControl } from './hooks/useStateControl';
25
+ import { useLoadingTable, useStateControl } from './hooks';
27
26
  import styles from './styles.module.css';
27
+ import { getColumnStyleVars, getCurrentlyConfiguredHeaderWidth } from './utils';
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 } = _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"]);
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"]);
31
31
  const { state: globalFilter, onStateChange: onGlobalFilterChange } = useStateControl(search, '');
32
32
  const { state: rowSelection, onStateChange: onRowSelectionChange } = useStateControl(rowSelectionProp, {});
33
33
  const defaultPaginationState = useMemo(() => ({
@@ -37,6 +37,11 @@ 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]);
40
45
  const tableColumns = useMemo(() => {
41
46
  let cols = columnDefinitions;
42
47
  if (enableSelection) {
@@ -75,7 +80,7 @@ export function Table(_a) {
75
80
  manualSorting,
76
81
  manualPagination,
77
82
  manualFiltering,
78
- globalFilterFn: fuzzyFilter,
83
+ globalFilterFn: enableFuzzySearch ? fuzzyFilter : undefined,
79
84
  onGlobalFilterChange,
80
85
  getRowId,
81
86
  onRowSelectionChange,
@@ -89,6 +94,7 @@ export function Table(_a) {
89
94
  onSortingChange,
90
95
  getSortedRowModel: getSortedRowModel(),
91
96
  onPaginationChange,
97
+ autoResetPageIndex: false,
92
98
  getPaginationRowModel: getPaginationRowModel(),
93
99
  getCoreRowModel: getCoreRowModel(),
94
100
  columnResizeMode: 'onEnd',
@@ -116,30 +122,47 @@ export function Table(_a) {
116
122
  return;
117
123
  }
118
124
  }, [loading, rowSelectionProp === null || rowSelectionProp === void 0 ? void 0 : rowSelectionProp.multiRow, table]);
119
- useEffect(() => { }, []);
125
+ const columnSizeVarsRef = useRef();
126
+ const headers = table.getFlatHeaders();
120
127
  const columnSizeVars = useMemo(() => {
128
+ var _a;
121
129
  const originalColumnDefs = table._getColumnDefs();
122
- const headers = table.getFlatHeaders();
123
130
  const colSizes = {};
124
131
  for (let i = 0; i < headers.length; i++) {
125
132
  const header = headers[i];
133
+ const { sizeKey, flexKey } = getColumnStyleVars(header.id);
126
134
  const originalColDef = originalColumnDefs.find(col => getColumnId(header) === col.id);
127
135
  const originalColumnDefSize = originalColDef === null || originalColDef === void 0 ? void 0 : originalColDef.size;
128
136
  const initSize = originalColumnDefSize ? `${originalColumnDefSize}px` : '100%';
137
+ const prevSize = (_a = columnSizeVarsRef.current) === null || _a === void 0 ? void 0 : _a[sizeKey];
129
138
  let size = initSize;
130
139
  if (header.column.getCanResize()) {
131
140
  const currentSize = header.getSize();
132
141
  const colDefSize = header.column.columnDef.size;
133
142
  size = currentSize === colDefSize ? initSize : `${currentSize}px`;
143
+ if (prevSize === '100%' && currentSize !== colDefSize) {
144
+ const realSize = getCurrentlyConfiguredHeaderWidth(header.id);
145
+ table.setColumnSizing(old => (Object.assign(Object.assign({}, old), { [header.id]: realSize })));
146
+ size = `${realSize}px`;
147
+ }
134
148
  }
135
- colSizes[`--table-column-${header.id}-size`] = size;
136
- colSizes[`--table-column-${header.id}-flex`] = size === '100%' ? 'unset' : '0';
149
+ colSizes[sizeKey] = size;
150
+ colSizes[flexKey] = size === '100%' ? 'unset' : '0';
137
151
  }
138
152
  return colSizes;
139
- /* effect must be called only on columnSizingInfo.isResizingColumn changes
140
- to reduce unnecessary recalculations */
153
+ /*
154
+ effect must be called only on columnSizingInfo.isResizingColumn changes
155
+ to reduce unnecessary recalculations
156
+
157
+ headers ids can also change, so they also should present here
158
+
159
+ table.getTotalSize() will trigger re-render after double-click size reset
160
+ */
141
161
  // eslint-disable-next-line react-hooks/exhaustive-deps
142
- }, [table.getState().columnSizingInfo.isResizingColumn]);
162
+ }, [table.getState().columnSizingInfo.isResizingColumn, headers, table.getTotalSize()]);
163
+ useEffect(() => {
164
+ columnSizeVarsRef.current = columnSizeVars;
165
+ }, [columnSizeVars]);
143
166
  const tableRows = table.getRowModel().rows;
144
167
  const loadingTableRows = loadingTable.getRowModel().rows;
145
168
  const tablePagination = table.getState().pagination;
@@ -1 +1,2 @@
1
1
  export * from './useLoadingTable';
2
+ export * from './useStateControl';
@@ -1 +1,2 @@
1
1
  export * from './useLoadingTable';
2
+ export * from './useStateControl';
@@ -0,0 +1,5 @@
1
+ export declare function getCurrentlyConfiguredHeaderWidth(id: string): number;
2
+ export declare function getColumnStyleVars(id: string): {
3
+ sizeKey: string;
4
+ flexKey: string;
5
+ };
@@ -0,0 +1,16 @@
1
+ export function getCurrentlyConfiguredHeaderWidth(id) {
2
+ const cell = document.querySelector(`[data-header-id="${id}"]`);
3
+ const resizeHandler = cell === null || cell === void 0 ? void 0 : cell.querySelector('[data-test-id="table__header-cell-resize-handle-moving-part"]');
4
+ if (cell && resizeHandler) {
5
+ const { width } = cell.getBoundingClientRect();
6
+ const offset = parseInt(resizeHandler.style.getPropertyValue('--offset'));
7
+ return width + offset;
8
+ }
9
+ return 0;
10
+ }
11
+ export function getColumnStyleVars(id) {
12
+ return {
13
+ sizeKey: `--table-column-${id}-size`,
14
+ flexKey: `--table-column-${id}-flex`,
15
+ };
16
+ }
@@ -48,6 +48,8 @@ export type TableProps<TData extends object> = WithSupportProps<{
48
48
  loading?: boolean;
49
49
  onChange?(value: string): void;
50
50
  };
51
+ /** Включить нечеткий поиск */
52
+ enableFuzzySearch?: boolean;
51
53
  /** Максимальное кол-во строк на страницу @default 10 */
52
54
  pageSize?: number;
53
55
  /** Параметры отвечают за пагинацию в таблице <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: 'table__body-row__action-option',
20
+ option: 'list__base-item-option',
21
21
  },
22
22
  statusIndicator: 'table__status-indicator',
23
23
  statusLabel: 'table__status-label',
@@ -10,6 +10,9 @@
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
+ }
13
16
  .copyCell:hover .copyButton{
14
17
  display:inline-flex;
15
18
  }
@@ -1,7 +1,9 @@
1
1
  import { Header } from '@tanstack/react-table';
2
+ import { ColumnPinPosition } from '../../../types';
2
3
  import { CellProps } from '../Cell';
3
4
  type HeaderCellProps<TData> = Omit<CellProps, 'align' | 'children' | 'onClick' | 'style'> & {
4
5
  header: Header<TData, unknown>;
6
+ pinPosition?: ColumnPinPosition;
5
7
  };
6
- export declare function HeaderCell<TData>({ header, className }: HeaderCellProps<TData>): import("react/jsx-runtime").JSX.Element;
8
+ export declare function HeaderCell<TData>({ header, pinPosition, className }: HeaderCellProps<TData>): import("react/jsx-runtime").JSX.Element;
7
9
  export {};
@@ -9,7 +9,7 @@ import { Cell } from '../Cell';
9
9
  import { getSortingIcon } from './helpers';
10
10
  import { ResizeHandle } from './ResizeHandle';
11
11
  import styles from './styles.module.css';
12
- export function HeaderCell({ header, className }) {
12
+ export function HeaderCell({ header, pinPosition, className }) {
13
13
  const cellRef = useRef(null);
14
14
  const isSortable = header.column.getCanSort();
15
15
  const isResizable = header.column.getCanResize();
@@ -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-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-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 })] }));
30
30
  }
@@ -1,5 +1,6 @@
1
1
  import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-runtime";
2
2
  import cn from 'classnames';
3
+ import { stopEventPropagation } from './helpers';
3
4
  import styles from './styles.module.css';
4
5
  function getResizeIndicatorOffset({ header, cellRef }) {
5
6
  var _a;
@@ -22,8 +23,15 @@ function getResizeIndicatorOffset({ header, cellRef }) {
22
23
  export function ResizeHandle({ header, cellRef }) {
23
24
  const isResizing = header.column.getIsResizing();
24
25
  const resizeHandler = header.getResizeHandler();
26
+ const handleMouseDown = event => {
27
+ if (event.detail === 2) {
28
+ header.column.resetSize();
29
+ return;
30
+ }
31
+ resizeHandler(event);
32
+ };
25
33
  const offset = isResizing ? getResizeIndicatorOffset({ header, cellRef }) : 0;
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)`,
34
+ return (_jsxs(_Fragment, { children: [_jsx("div", { role: 'button', tabIndex: 0, className: cn(styles.tableHeaderIcon, styles.tableHeaderResizeHandle), "data-resizing": isResizing || undefined, onMouseDown: handleMouseDown, onTouchStart: resizeHandler, onMouseUp: stopEventPropagation }), isResizing && (_jsx("div", { "data-test-id": 'table__header-cell-resize-handle-moving-part', className: styles.tableHeaderResizeIndicator, style: {
35
+ '--offset': `${offset}px`,
28
36
  } }))] }));
29
37
  }
@@ -1,2 +1,4 @@
1
1
  import { SortDirection } from '@tanstack/react-table';
2
+ import { MouseEventHandler } from 'react';
2
3
  export declare function getSortingIcon(sort?: SortDirection | false): import("react/jsx-runtime").JSX.Element | null;
4
+ export declare const stopEventPropagation: MouseEventHandler;
@@ -10,3 +10,6 @@ export function getSortingIcon(sort) {
10
10
  return null;
11
11
  }
12
12
  }
13
+ export const stopEventPropagation = e => {
14
+ e.stopPropagation();
15
+ };
@@ -23,6 +23,27 @@
23
23
  opacity:0;
24
24
  }
25
25
 
26
+ .tableHeaderResizeIndicator{
27
+ cursor:col-resize;
28
+ position:absolute;
29
+ z-index:2;
30
+ top:0;
31
+ right:0;
32
+ transform:translateX(var(--offset));
33
+ width:1px;
34
+ height:100%;
35
+ background-color:var(--sys-neutral-decor-activated, #bfc2cc);
36
+ }
37
+ .tableHeaderResizeIndicator::after{
38
+ content:"";
39
+ position:absolute;
40
+ top:0;
41
+ left:0;
42
+ transform:translateX(-50%);
43
+ width:calc(100% + var(--dimension-4m, 32px));
44
+ height:100%;
45
+ }
46
+
26
47
  .tableHeaderCell{
27
48
  padding-left:var(--space-table-head-column-horizontal-padding, 8px);
28
49
  padding-right:var(--space-table-head-column-horizontal-padding, 8px);
@@ -69,6 +90,19 @@
69
90
  -moz-user-select:none;
70
91
  user-select:none;
71
92
  }
93
+ .tableHeaderCell[data-align=right]{
94
+ justify-content:flex-end;
95
+ }
96
+ .tableHeaderCell[data-pin-position=right]:last-child{
97
+ overflow:hidden;
98
+ }
99
+ .tableHeaderCell[data-pin-position=right]:last-child .tableHeaderResizeHandle{
100
+ right:0;
101
+ transform:none;
102
+ }
103
+ .tableHeaderCell[data-pin-position=right]:last-child .tableHeaderResizeIndicator{
104
+ right:calc(var(--dimension-1m, 8px) / 2);
105
+ }
72
106
 
73
107
  .tableHeaderCellMain{
74
108
  overflow:auto;
@@ -95,24 +129,4 @@
95
129
  .tableHeaderIcon svg{
96
130
  width:var(--size-icon-container-xs, 16px) !important;
97
131
  height:var(--size-icon-container-xs, 16px) !important;
98
- }
99
-
100
- .tableHeaderResizeIndicator{
101
- cursor:col-resize;
102
- position:absolute;
103
- z-index:2;
104
- top:0;
105
- right:0;
106
- width:1px;
107
- height:100%;
108
- background-color:var(--sys-neutral-decor-activated, #bfc2cc);
109
- }
110
- .tableHeaderResizeIndicator::after{
111
- content:"";
112
- position:absolute;
113
- top:0;
114
- left:0;
115
- transform:translateX(-50%);
116
- width:calc(100% + var(--dimension-4m, 32px));
117
- height:100%;
118
132
  }
@@ -1,20 +1,7 @@
1
1
  import { CellContext } from '@tanstack/react-table';
2
- import { MouseEvent, ReactElement } from 'react';
3
- import { BaseItemProps } from '@snack-uikit/list';
2
+ import { DroplistProps } from '@snack-uikit/list';
4
3
  import { ColumnDefinition } from '../../../types';
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>[];
4
+ export type ActionsGenerator<TData> = (cell: CellContext<TData, unknown>) => DroplistProps['items'];
18
5
  export type RowActionsColumnDefProps<TData> = {
19
6
  /** Действия для строки */
20
7
  actionsGenerator: ActionsGenerator<TData>;
@@ -1,39 +1,31 @@
1
1
  import { jsx as _jsx } from "react/jsx-runtime";
2
- import { useMemo, useRef } from 'react';
2
+ import { useCallback, useMemo } from 'react';
3
3
  import { ButtonFunction } from '@snack-uikit/button';
4
4
  import { MoreSVG } from '@snack-uikit/icons';
5
- import { Droplist } from '@snack-uikit/list';
6
- import { Tag } from '@snack-uikit/tag';
5
+ import { Droplist, isBaseItemProps } from '@snack-uikit/list';
7
6
  import { COLUMN_PIN_POSITION, TEST_IDS } from '../../../constants';
8
7
  import { useRowContext } from '../../contexts';
9
8
  import styles from './styles.module.css';
10
9
  function RowActionsCell({ row, actions }) {
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
- };
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
+ }, []);
16
21
  const disabled = !row.getCanSelect();
17
22
  const stopPropagationClick = (e) => {
18
23
  e.stopPropagation();
19
24
  };
20
- const visibleActions = useMemo(() => actions.filter(item => !(item === null || item === void 0 ? void 0 : item.hidden)), [actions]);
25
+ const patchedItems = useMemo(() => actions.map(item => patchItem(item, () => setDropListOpen(false))), [actions, patchItem, setDropListOpen]);
21
26
  return (
22
27
  // eslint-disable-next-line jsx-a11y/no-static-element-interactions
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 }) }) })) }));
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 }) })) }));
37
29
  }
38
30
  /** Вспомогательная функция для создания ячейки с дополнительными действиями у строки */
39
31
  export function getRowActionsColumnDef({ actionsGenerator, pinned, }) {
@@ -16,20 +16,14 @@
16
16
  }
17
17
 
18
18
  .rowActionsCellWrap{
19
+ --offset:0px;
20
+ cursor:pointer;
19
21
  box-sizing:border-box;
20
22
  width:100%;
21
23
  height:100%;
22
- }
23
-
24
- .rowActionsCellTrigger{
25
- --offset:0px;
26
24
  padding-left:var(--space-table-cell-action-padding, 4px);
27
25
  padding-right:var(--space-table-cell-action-padding, 4px);
28
- cursor:pointer;
29
26
  display:flex;
30
27
  align-items:center;
31
28
  justify-content:center;
32
- box-sizing:border-box;
33
- width:100%;
34
- height:100%;
35
29
  }
@@ -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
  }
@@ -7,5 +7,5 @@ import { Row } from './Row';
7
7
  import styles from './styles.module.css';
8
8
  export function HeaderRow() {
9
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 }, header.id))) }))] }));
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)))) }))] }));
11
11
  }
@@ -38,6 +38,7 @@
38
38
  }
39
39
  .rowPinnedCells[data-position=right]{
40
40
  right:0;
41
+ margin-left:auto;
41
42
  }
42
43
  .rowPinnedCells[data-position=right]::after{
43
44
  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,6 +9,8 @@ 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;
12
14
  /** Позиционирование контента ячейки в теле таблицы */
13
15
  align?: ColumnAlign;
14
16
  /** Отключить паддинг у ячейки в теле таблицы */
@@ -37,5 +39,5 @@ type PinnedColumnDefinition<TData> = BaseColumnDefinition<TData> & {
37
39
  size: number;
38
40
  };
39
41
  export type ColumnDefinition<TData> = NormalColumnDefinition<TData> | PinnedColumnDefinition<TData>;
40
- export type { RowActionInfo, RowActionProps, RowActionsColumnDefProps, StatusColumnDefinitionProps, RowInfo, RowClickHandler, ActionsGenerator, CopyCellProps, MapStatusToAppearanceFnType, } from './helperComponents';
41
- export type { PaginationState, SortingState, RowSelectionState, RowSelectionOptions, EmptyStateProps, ToolbarProps, HeaderContext, CellContext, };
42
+ export type { RowActionsColumnDefProps, StatusColumnDefinitionProps, RowInfo, RowClickHandler, ActionsGenerator, CopyCellProps, MapStatusToAppearanceFnType, } from './helperComponents';
43
+ 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.16.8",
7
+ "version": "0.17.0",
8
8
  "sideEffects": [
9
9
  "*.css",
10
10
  "*.woff",
@@ -33,17 +33,16 @@
33
33
  "scripts": {},
34
34
  "dependencies": {
35
35
  "@snack-uikit/button": "0.17.1",
36
- "@snack-uikit/chips": "0.13.4",
36
+ "@snack-uikit/chips": "0.14.0",
37
37
  "@snack-uikit/icon-predefined": "0.5.1",
38
38
  "@snack-uikit/icons": "0.21.0",
39
39
  "@snack-uikit/info-block": "0.3.5",
40
- "@snack-uikit/list": "0.11.5",
40
+ "@snack-uikit/list": "0.12.0",
41
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/tag": "0.9.2",
45
44
  "@snack-uikit/toggles": "0.9.9",
46
- "@snack-uikit/toolbar": "0.7.33",
45
+ "@snack-uikit/toolbar": "0.7.34",
47
46
  "@snack-uikit/truncate-string": "0.4.14",
48
47
  "@snack-uikit/typography": "0.6.2",
49
48
  "@snack-uikit/utils": "3.3.0",
@@ -58,5 +57,5 @@
58
57
  "peerDependencies": {
59
58
  "@snack-uikit/locale": "*"
60
59
  },
61
- "gitHead": "59bd2ac46a341357d543ada864a34e09745b3e42"
60
+ "gitHead": "a308f550fb12d114a27d9b7d6804c212a316a09d"
62
61
  }