@snack-uikit/table 0.37.36 → 0.38.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.
package/CHANGELOG.md CHANGED
@@ -3,6 +3,22 @@
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.38.0 (2026-02-20)
7
+
8
+
9
+ ### Bug Fixes
10
+
11
+ * **FF-8050:** restore pagination from saved state ([e360318](https://github.com/cloud-ru-tech/snack-uikit/commit/e360318bdcea29cf4f623c0c1ac0f50d6fef0d05))
12
+
13
+
14
+ ### Features
15
+
16
+ * **FF-8050:** expose serializer and parser for table saved state ([e42d1b8](https://github.com/cloud-ru-tech/snack-uikit/commit/e42d1b8bd2e1234ed89429fdbeacc497c70f5aa4))
17
+
18
+
19
+
20
+
21
+
6
22
  ## 0.37.36 (2026-02-20)
7
23
 
8
24
 
package/README.md CHANGED
@@ -117,7 +117,7 @@ const columnDefinitions: ColumnDefinition<TableData>[] = [
117
117
  | name | type | default value | description |
118
118
  |------|------|---------------|-------------|
119
119
  | columnSettings* | `{ enableDrag?: boolean; enableSettingsMenu?: boolean; }` | - | |
120
- | savedState* | `{ id: string; filterQueryKey?: string; resize?: boolean; columnSettings?: boolean; }` | - | |
120
+ | savedState* | `Pick<ToolbarPersistConfig<Record<string, unknown>>, "serializer" \| "parser"> & { id: string; filterQueryKey?: string; resize?: boolean; columnSettings?: boolean; }` | - | |
121
121
  | tableColumns* | `ColumnDefinition<TData>[]` | - | |
122
122
  ## useColumnSettings
123
123
  ### Props
@@ -125,7 +125,7 @@ const columnDefinitions: ColumnDefinition<TableData>[] = [
125
125
  |------|------|---------------|-------------|
126
126
  | pinnedGroups* | `PinnedGroupsState<TData>` | - | |
127
127
  | columnDefinitions* | `ColumnDefinition<TData>[]` | - | Определение внешнего вида и функционала колонок |
128
- | savedState | `{ id: string; filterQueryKey?: string; resize?: boolean; columnSettings?: boolean; }` | - | Конфиг для сохранения состояния в localStorage и queryParams. <br> Поле id должно быть уникальным для разных таблиц в рамках приложения. <br> Для корректной работы необходимо наличие id в конфиге columnDefinitions |
128
+ | savedState | `Pick<ToolbarPersistConfig<TFilters>, "serializer" \| "parser"> & { id: string; filterQueryKey?: string; resize?: boolean; columnSettings?: boolean; }` | - | Конфиг для сохранения состояния в localStorage и queryParams. <br> Поле id должно быть уникальным для разных таблиц в рамках приложения. <br> Для корректной работы необходимо наличие id в конфиге columnDefinitions |
129
129
  | columnsSettings | `{ enableDrag?: boolean; enableSettingsMenu?: boolean; }` | - | Параметры отвечают за настройки колонок <br> <strong>enableDrag</strong>: Включение сортировки порядка столбцов вручную перетаскиванием <br> <strong>enableSettingsMenu</strong>: Включение настроек показа колонок <br> |
130
130
  | rowSelection | `{ initialState?: RowSelectionState; state?: RowSelectionState; enable?: boolean \| ((row: Row<TData>) => boolean); multiRow?: boolean; onChange?(state: RowSelectionState): void; appearance?: RowAppearance; }` | - | Параметры отвечают за возможность выбора строк <br> <strong>initialState</strong>: Начальное состояние выбора строк <br> <strong>state</strong>: Состояние выбора строк, жестко устанавливаемое снаружи <br> <strong>enable</strong>: Колбэк определяющий можно ли выбрать строку <br> <strong>appearance</strong>: Режим отображения недоступной для выбора строки. Опции: RowAppearance.Disabled (по дефолту) - серый фон, чекбокс/радиобаттон скрыт, RowAppearance.HideToggler - обычный фон, чекбокс/радиобаттон скрыт <br> <strong>multiRow</strong>: Мульти-выбор строк (включен по-умолчанию, когда включается выбор) <br> <strong>onChange</strong>: Колбэк на выбор строк |
131
131
  | expanding | `{ getSubRows: (element: TData) => TData[]; expandingColumnDefinition: TreeColumnDefinitionProps<TData>; state?: ExpandedState; onChange?(state: ExpandedState): void; }` | - | Параметр отвечает за общие настройки раскрывающихся строк <br> <strong>getSubRows</strong>: Метод отвечает за получение дочерних строк <br> <strong>expandingColumnDefinition</strong>: Описание колонок для дочерних строк <br> <strong>state</strong>: Состояние открытых строк <br> <strong>onExpandedChange</strong>: Колбэк на раскрытие строк <br> |
@@ -214,7 +214,7 @@ const columnDefinitions: ColumnDefinition<TableData>[] = [
214
214
  | scrollRef | `RefObject<HTMLElement>` | - | Ссылка на элемент, обозначающий самый конец прокручиваемого списка |
215
215
  | scrollContainerRef | `RefObject<HTMLElement>` | - | Ссылка на контейнер, который скроллится |
216
216
  | rowPinning | `Pick<RowPinningState, "top">` | { top: [], } | Определение какие строки должны быть закреплены в таблице |
217
- | savedState | `{ id: string; filterQueryKey?: string; resize?: boolean; columnSettings?: boolean; }` | - | Конфиг для сохранения состояния в localStorage и queryParams. <br> Поле id должно быть уникальным для разных таблиц в рамках приложения. <br> Для корректной работы необходимо наличие id в конфиге columnDefinitions |
217
+ | savedState | `Pick<ToolbarPersistConfig<TFilters>, "serializer" \| "parser"> & { id: string; filterQueryKey?: string; resize?: boolean; columnSettings?: boolean; }` | - | Конфиг для сохранения состояния в localStorage и queryParams. <br> Поле id должно быть уникальным для разных таблиц в рамках приложения. <br> Для корректной работы необходимо наличие id в конфиге columnDefinitions |
218
218
  | getRowBackgroundColor | `(data: TData) => TableRowColor` | - | Функция для определения цвета фона строки на основе данных строки @param data - данные строки таблицы @returns цвет фона строки или undefined, если цвет не должен применяться |
219
219
  | pagination | `{ state?: PaginationState; options?: number[]; optionsLabel?: string; onChange?(state: PaginationState): void; optionsRender?(value: string \| number, idx: number): string \| number; }` | 'Rows volume: ' <br> <strong>onChange</strong>: Колбэк на изменение пагинации | Параметры отвечают за пагинацию в таблице <br> <strong>state</strong>: Состояние строки поиска, жестко устанавливаемое снаружи <br> <strong>options</strong>: Варианты в выпадающем селекторе для установки кол-ва строк на страницу <br> <strong>optionsLabel</strong>: Текст для селектора кол-ва строк на страницу |
220
220
  | autoResetPageIndex | `boolean` | - | Автоматический сброс пагинации к первой странице при изменении данных или состояния (e.g фильтры, сортировки, и т.д) |
@@ -251,7 +251,7 @@ const columnDefinitions: ColumnDefinition<TableData>[] = [
251
251
  |------|------|---------------|-------------|
252
252
  | onChangePage* | `(offset: number, limit: number) => void` | - | |
253
253
  | columnDefinitions* | `ColumnDefinition<TData>[]` | - | Определение внешнего вида и функционала колонок |
254
- | savedState | `{ id: string; filterQueryKey?: string; resize?: boolean; columnSettings?: boolean; }` | - | Конфиг для сохранения состояния в localStorage и queryParams. <br> Поле id должно быть уникальным для разных таблиц в рамках приложения. <br> Для корректной работы необходимо наличие id в конфиге columnDefinitions |
254
+ | savedState | `Pick<ToolbarPersistConfig<TFilters>, "serializer" \| "parser"> & { id: string; filterQueryKey?: string; resize?: boolean; columnSettings?: boolean; }` | - | Конфиг для сохранения состояния в localStorage и queryParams. <br> Поле id должно быть уникальным для разных таблиц в рамках приложения. <br> Для корректной работы необходимо наличие id в конфиге columnDefinitions |
255
255
  | columnsSettings | `{ enableDrag?: boolean; enableSettingsMenu?: boolean; }` | - | Параметры отвечают за настройки колонок <br> <strong>enableDrag</strong>: Включение сортировки порядка столбцов вручную перетаскиванием <br> <strong>enableSettingsMenu</strong>: Включение настроек показа колонок <br> |
256
256
  | rowSelection | `{ initialState?: RowSelectionState; state?: RowSelectionState; enable?: boolean \| ((row: Row<TData>) => boolean); multiRow?: boolean; onChange?(state: RowSelectionState): void; appearance?: RowAppearance; }` | - | Параметры отвечают за возможность выбора строк <br> <strong>initialState</strong>: Начальное состояние выбора строк <br> <strong>state</strong>: Состояние выбора строк, жестко устанавливаемое снаружи <br> <strong>enable</strong>: Колбэк определяющий можно ли выбрать строку <br> <strong>appearance</strong>: Режим отображения недоступной для выбора строки. Опции: RowAppearance.Disabled (по дефолту) - серый фон, чекбокс/радиобаттон скрыт, RowAppearance.HideToggler - обычный фон, чекбокс/радиобаттон скрыт <br> <strong>multiRow</strong>: Мульти-выбор строк (включен по-умолчанию, когда включается выбор) <br> <strong>onChange</strong>: Колбэк на выбор строк |
257
257
  | expanding | `{ getSubRows: (element: TData) => TData[]; expandingColumnDefinition: TreeColumnDefinitionProps<TData>; state?: ExpandedState; onChange?(state: ExpandedState): void; }` | - | Параметр отвечает за общие настройки раскрывающихся строк <br> <strong>getSubRows</strong>: Метод отвечает за получение дочерних строк <br> <strong>expandingColumnDefinition</strong>: Описание колонок для дочерних строк <br> <strong>state</strong>: Состояние открытых строк <br> <strong>onExpandedChange</strong>: Колбэк на раскрытие строк <br> |
@@ -112,7 +112,7 @@ function Table(_a) {
112
112
  const isPaginationValid = (0, validators_1.validatePaging)(dataAsSettings === null || dataAsSettings === void 0 ? void 0 : dataAsSettings.pagination);
113
113
  const isSortingValid = (0, validators_1.validateSorting)(dataAsSettings === null || dataAsSettings === void 0 ? void 0 : dataAsSettings.ordering);
114
114
  const isSearchValid = !(dataAsSettings === null || dataAsSettings === void 0 ? void 0 : dataAsSettings.search) || typeof (dataAsSettings === null || dataAsSettings === void 0 ? void 0 : dataAsSettings.search) === 'string';
115
- const isFilterValid = Boolean((columnFilters === null || columnFilters === void 0 ? void 0 : columnFilters.filters) && (0, validators_1.validateFilter)(dataAsSettings.filter, columnFilters.filters));
115
+ const isFilterValid = !(columnFilters === null || columnFilters === void 0 ? void 0 : columnFilters.filters) || Boolean((0, validators_1.validateFilter)(dataAsSettings.filter, columnFilters.filters));
116
116
  return isPaginationValid && isSortingValid && isSearchValid && isFilterValid;
117
117
  }, [columnFilters === null || columnFilters === void 0 ? void 0 : columnFilters.filters]);
118
118
  const enableSelection = Boolean(rowSelectionProp === null || rowSelectionProp === void 0 ? void 0 : rowSelectionProp.enable);
@@ -407,6 +407,8 @@ function Table(_a) {
407
407
  filter,
408
408
  search: globalFilter || ''
409
409
  },
410
+ serializer: savedState.serializer,
411
+ parser: savedState.parser,
410
412
  onLoad: state => {
411
413
  state.pagination && onPaginationChange((0, mappers_1.mapPaginationToTableState)(state.pagination));
412
414
  state.search && onGlobalFilterChange(state.search);
@@ -4,7 +4,15 @@ Object.defineProperty(exports, "__esModule", {
4
4
  value: true
5
5
  });
6
6
  exports.validateFilter = exports.validateSorting = exports.validatePaging = void 0;
7
- const validatePaging = value => typeof (value === null || value === void 0 ? void 0 : value.limit) === 'number' && typeof (value === null || value === void 0 ? void 0 : value.offset) === 'number';
7
+ const validatePaging = value => {
8
+ if (!value) {
9
+ return true;
10
+ }
11
+ if (typeof value !== 'object') {
12
+ return false;
13
+ }
14
+ return 'limit' in value && typeof value.limit === 'number' && 'offset' in value && typeof value.offset === 'number';
15
+ };
8
16
  exports.validatePaging = validatePaging;
9
17
  const validateSorting = value => !value || value.every(column => typeof (column === null || column === void 0 ? void 0 : column.field) === 'string' && typeof (column === null || column === void 0 ? void 0 : column.direction) === 'string');
10
18
  exports.validateSorting = validateSorting;
@@ -1,7 +1,7 @@
1
1
  import { PaginationState, Row, RowPinningState, RowSelectionOptions, RowSelectionState, SortingState } from '@tanstack/react-table';
2
2
  import { ReactNode, RefObject } from 'react';
3
3
  import { FiltersState } from '@snack-uikit/chips';
4
- import { FilterRow, ToolbarProps } from '@snack-uikit/toolbar';
4
+ import { FilterRow, ToolbarPersistConfig, ToolbarProps } from '@snack-uikit/toolbar';
5
5
  import { ValueOf, WithSupportProps } from '@snack-uikit/utils';
6
6
  import { TABLE_ROW_COLOR } from '../constants';
7
7
  import { EmptyStateProps, ExportButtonProps, RowClickHandler, TreeColumnDefinitionProps } from '../helperComponents';
@@ -144,7 +144,7 @@ type BaseTableProps<TData extends object, TFilters extends FiltersState = Record
144
144
  * Поле id должно быть уникальным для разных таблиц в рамках приложения. <br>
145
145
  * Для корректной работы необходимо наличие id в конфиге columnDefinitions
146
146
  * */
147
- savedState?: {
147
+ savedState?: Pick<ToolbarPersistConfig<TFilters>, 'serializer' | 'parser'> & {
148
148
  id: string;
149
149
  filterQueryKey?: string;
150
150
  resize?: boolean;
@@ -50,7 +50,7 @@ export function Table(_a) {
50
50
  const isPaginationValid = validatePaging(dataAsSettings === null || dataAsSettings === void 0 ? void 0 : dataAsSettings.pagination);
51
51
  const isSortingValid = validateSorting(dataAsSettings === null || dataAsSettings === void 0 ? void 0 : dataAsSettings.ordering);
52
52
  const isSearchValid = !(dataAsSettings === null || dataAsSettings === void 0 ? void 0 : dataAsSettings.search) || typeof (dataAsSettings === null || dataAsSettings === void 0 ? void 0 : dataAsSettings.search) === 'string';
53
- const isFilterValid = Boolean((columnFilters === null || columnFilters === void 0 ? void 0 : columnFilters.filters) && validateFilter(dataAsSettings.filter, columnFilters.filters));
53
+ const isFilterValid = !(columnFilters === null || columnFilters === void 0 ? void 0 : columnFilters.filters) || Boolean(validateFilter(dataAsSettings.filter, columnFilters.filters));
54
54
  return isPaginationValid && isSortingValid && isSearchValid && isFilterValid;
55
55
  }, [columnFilters === null || columnFilters === void 0 ? void 0 : columnFilters.filters]);
56
56
  const enableSelection = Boolean(rowSelectionProp === null || rowSelectionProp === void 0 ? void 0 : rowSelectionProp.enable);
@@ -289,6 +289,8 @@ export function Table(_a) {
289
289
  filter,
290
290
  search: globalFilter || '',
291
291
  },
292
+ serializer: savedState.serializer,
293
+ parser: savedState.parser,
292
294
  onLoad: state => {
293
295
  state.pagination && onPaginationChange(mapPaginationToTableState(state.pagination));
294
296
  state.search && onGlobalFilterChange(state.search);
@@ -1,5 +1,12 @@
1
- export const validatePaging = (value) => typeof (value === null || value === void 0 ? void 0 : value.limit) === 'number' &&
2
- typeof (value === null || value === void 0 ? void 0 : value.offset) === 'number';
1
+ export const validatePaging = (value) => {
2
+ if (!value) {
3
+ return true;
4
+ }
5
+ if (typeof value !== 'object') {
6
+ return false;
7
+ }
8
+ return 'limit' in value && typeof value.limit === 'number' && 'offset' in value && typeof value.offset === 'number';
9
+ };
3
10
  export const validateSorting = (value) => !value ||
4
11
  value.every(column => typeof (column === null || column === void 0 ? void 0 : column.field) === 'string' && typeof (column === null || column === void 0 ? void 0 : column.direction) === 'string');
5
12
  export const validateFilter = (value, filterSettings) => typeof value === 'object' &&
@@ -1,7 +1,7 @@
1
1
  import { PaginationState, Row, RowPinningState, RowSelectionOptions, RowSelectionState, SortingState } from '@tanstack/react-table';
2
2
  import { ReactNode, RefObject } from 'react';
3
3
  import { FiltersState } from '@snack-uikit/chips';
4
- import { FilterRow, ToolbarProps } from '@snack-uikit/toolbar';
4
+ import { FilterRow, ToolbarPersistConfig, ToolbarProps } from '@snack-uikit/toolbar';
5
5
  import { ValueOf, WithSupportProps } from '@snack-uikit/utils';
6
6
  import { TABLE_ROW_COLOR } from '../constants';
7
7
  import { EmptyStateProps, ExportButtonProps, RowClickHandler, TreeColumnDefinitionProps } from '../helperComponents';
@@ -144,7 +144,7 @@ type BaseTableProps<TData extends object, TFilters extends FiltersState = Record
144
144
  * Поле id должно быть уникальным для разных таблиц в рамках приложения. <br>
145
145
  * Для корректной работы необходимо наличие id в конфиге columnDefinitions
146
146
  * */
147
- savedState?: {
147
+ savedState?: Pick<ToolbarPersistConfig<TFilters>, 'serializer' | 'parser'> & {
148
148
  id: string;
149
149
  filterQueryKey?: string;
150
150
  resize?: boolean;
package/package.json CHANGED
@@ -4,7 +4,7 @@
4
4
  "access": "public"
5
5
  },
6
6
  "title": "Table",
7
- "version": "0.37.36",
7
+ "version": "0.38.0",
8
8
  "sideEffects": [
9
9
  "*.css",
10
10
  "*.woff",
@@ -65,5 +65,5 @@
65
65
  "peerDependencies": {
66
66
  "@snack-uikit/locale": "*"
67
67
  },
68
- "gitHead": "01cbc73996330f5ecfabdb474b338cf0de112a57"
68
+ "gitHead": "78bf4a7f8687eea71199ee1fbb88d9490d4cb603"
69
69
  }
@@ -157,9 +157,8 @@ export function Table<TData extends object, TFilters extends FiltersState = Reco
157
157
  const isPaginationValid = validatePaging(dataAsSettings?.pagination);
158
158
  const isSortingValid = validateSorting(dataAsSettings?.ordering);
159
159
  const isSearchValid = !dataAsSettings?.search || typeof dataAsSettings?.search === 'string';
160
- const isFilterValid = Boolean(
161
- columnFilters?.filters && validateFilter(dataAsSettings.filter, columnFilters.filters),
162
- );
160
+ const isFilterValid =
161
+ !columnFilters?.filters || Boolean(validateFilter(dataAsSettings.filter, columnFilters.filters));
163
162
 
164
163
  return isPaginationValid && isSortingValid && isSearchValid && isFilterValid;
165
164
  },
@@ -478,6 +477,8 @@ export function Table<TData extends object, TFilters extends FiltersState = Reco
478
477
  filter,
479
478
  search: globalFilter || '',
480
479
  },
480
+ serializer: savedState.serializer,
481
+ parser: savedState.parser,
481
482
  onLoad: state => {
482
483
  state.pagination && onPaginationChange(mapPaginationToTableState(state.pagination));
483
484
  state.search && onGlobalFilterChange(state.search);
@@ -1,9 +1,17 @@
1
1
  import { RequestPayloadParams } from '@cloud-ru/ft-request-payload-transform';
2
2
  import { ChipChoiceRowProps } from '@snack-uikit/chips';
3
3
 
4
- export const validatePaging = (value: unknown): value is RequestPayloadParams['pagination'] =>
5
- typeof (value as RequestPayloadParams['pagination'])?.limit === 'number' &&
6
- typeof (value as RequestPayloadParams['pagination'])?.offset === 'number';
4
+ export const validatePaging = (value: unknown): value is RequestPayloadParams['pagination'] => {
5
+ if (!value) {
6
+ return true;
7
+ }
8
+
9
+ if (typeof value !== 'object') {
10
+ return false;
11
+ }
12
+
13
+ return 'limit' in value && typeof value.limit === 'number' && 'offset' in value && typeof value.offset === 'number';
14
+ };
7
15
 
8
16
  export const validateSorting = (value: unknown): value is RequestPayloadParams['ordering'] =>
9
17
  !value ||
@@ -9,7 +9,7 @@ import {
9
9
  import { ReactNode, RefObject } from 'react';
10
10
 
11
11
  import { FiltersState } from '@snack-uikit/chips';
12
- import { FilterRow, ToolbarProps } from '@snack-uikit/toolbar';
12
+ import { FilterRow, ToolbarPersistConfig, ToolbarProps } from '@snack-uikit/toolbar';
13
13
  import { ValueOf, WithSupportProps } from '@snack-uikit/utils';
14
14
 
15
15
  import { TABLE_ROW_COLOR } from '../constants';
@@ -177,7 +177,7 @@ type BaseTableProps<TData extends object, TFilters extends FiltersState = Record
177
177
  * Поле id должно быть уникальным для разных таблиц в рамках приложения. <br>
178
178
  * Для корректной работы необходимо наличие id в конфиге columnDefinitions
179
179
  * */
180
- savedState?: {
180
+ savedState?: Pick<ToolbarPersistConfig<TFilters>, 'serializer' | 'parser'> & {
181
181
  id: string;
182
182
  filterQueryKey?: string;
183
183
  resize?: boolean;