@cloud-ru/uikit-product-mobile-table 0.16.2 → 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 (107) hide show
  1. package/CHANGELOG.md +24 -0
  2. package/dist/cjs/components/AdaptiveServerTable/AdaptiveServerTable.js +7 -6
  3. package/dist/{esm/components → cjs/components/AdaptiveServerTable}/constants.d.ts +0 -1
  4. package/dist/cjs/components/{constants.js → AdaptiveServerTable/constants.js} +1 -2
  5. package/dist/cjs/components/{utils.d.ts → AdaptiveServerTable/utils.d.ts} +0 -2
  6. package/dist/cjs/components/{utils.js → AdaptiveServerTable/utils.js} +1 -11
  7. package/dist/cjs/components/MobileTable/MobileTable.d.ts +7 -0
  8. package/dist/cjs/components/{MobileTable.js → MobileTable/MobileTable.js} +33 -10
  9. package/dist/cjs/components/MobileTable/hooks/index.d.ts +2 -0
  10. package/dist/cjs/components/MobileTable/hooks/index.js +18 -0
  11. package/dist/cjs/components/MobileTable/hooks/useFilters/index.d.ts +1 -0
  12. package/dist/cjs/components/MobileTable/hooks/useFilters/index.js +17 -0
  13. package/dist/cjs/components/MobileTable/hooks/useFilters/useFilters.d.ts +78 -0
  14. package/dist/cjs/components/MobileTable/hooks/useFilters/useFilters.js +31 -0
  15. package/dist/cjs/components/MobileTable/hooks/useFilters/utils/getInitialColumnsFiltersOpenValue.d.ts +2 -0
  16. package/dist/cjs/components/MobileTable/hooks/useFilters/utils/getInitialColumnsFiltersOpenValue.js +11 -0
  17. package/dist/cjs/components/MobileTable/hooks/useFilters/utils/index.d.ts +1 -0
  18. package/dist/cjs/components/MobileTable/hooks/useFilters/utils/index.js +17 -0
  19. package/dist/cjs/components/{hooks.d.ts → MobileTable/hooks/useLoadingTable.d.ts} +0 -8
  20. package/dist/cjs/components/{hooks.js → MobileTable/hooks/useLoadingTable.js} +1 -15
  21. package/dist/cjs/components/MobileTable/index.d.ts +3 -0
  22. package/dist/cjs/components/MobileTable/index.js +21 -0
  23. package/dist/cjs/components/MobileTable/types.d.ts +11 -0
  24. package/dist/cjs/components/MobileTable/types.js +2 -0
  25. package/dist/cjs/components/MobileTable/utils/fuzzyFilter.d.ts +2 -0
  26. package/dist/cjs/components/MobileTable/utils/fuzzyFilter.js +13 -0
  27. package/dist/cjs/components/MobileTable/utils/index.d.ts +2 -0
  28. package/dist/cjs/components/MobileTable/utils/index.js +18 -0
  29. package/dist/cjs/components/MobileTable/utils/saveTableState/getPersistedStateValidator.d.ts +4 -0
  30. package/dist/cjs/components/MobileTable/utils/saveTableState/getPersistedStateValidator.js +13 -0
  31. package/dist/cjs/components/MobileTable/utils/saveTableState/index.d.ts +3 -0
  32. package/dist/cjs/components/MobileTable/utils/saveTableState/index.js +19 -0
  33. package/dist/cjs/components/MobileTable/utils/saveTableState/mappers.d.ts +18 -0
  34. package/dist/cjs/components/MobileTable/utils/saveTableState/mappers.js +45 -0
  35. package/dist/cjs/components/MobileTable/utils/saveTableState/validators.d.ts +5 -0
  36. package/dist/cjs/components/MobileTable/utils/saveTableState/validators.js +13 -0
  37. package/dist/cjs/constants.d.ts +1 -0
  38. package/dist/cjs/constants.js +2 -1
  39. package/dist/cjs/index.d.ts +1 -0
  40. package/dist/cjs/index.js +1 -0
  41. package/dist/esm/components/AdaptiveServerTable/AdaptiveServerTable.js +5 -4
  42. package/dist/{cjs/components → esm/components/AdaptiveServerTable}/constants.d.ts +0 -1
  43. package/dist/esm/components/{constants.js → AdaptiveServerTable/constants.js} +0 -1
  44. package/dist/esm/components/{utils.d.ts → AdaptiveServerTable/utils.d.ts} +0 -2
  45. package/dist/esm/components/AdaptiveServerTable/utils.js +5 -0
  46. package/dist/esm/components/MobileTable/MobileTable.d.ts +7 -0
  47. package/dist/esm/components/{MobileTable.js → MobileTable/MobileTable.js} +33 -10
  48. package/dist/esm/components/MobileTable/hooks/index.d.ts +2 -0
  49. package/dist/esm/components/MobileTable/hooks/index.js +2 -0
  50. package/dist/esm/components/MobileTable/hooks/useFilters/index.d.ts +1 -0
  51. package/dist/esm/components/MobileTable/hooks/useFilters/index.js +1 -0
  52. package/dist/esm/components/MobileTable/hooks/useFilters/useFilters.d.ts +78 -0
  53. package/dist/esm/components/MobileTable/hooks/useFilters/useFilters.js +28 -0
  54. package/dist/esm/components/MobileTable/hooks/useFilters/utils/getInitialColumnsFiltersOpenValue.d.ts +2 -0
  55. package/dist/esm/components/MobileTable/hooks/useFilters/utils/getInitialColumnsFiltersOpenValue.js +8 -0
  56. package/dist/esm/components/MobileTable/hooks/useFilters/utils/index.d.ts +1 -0
  57. package/dist/esm/components/MobileTable/hooks/useFilters/utils/index.js +1 -0
  58. package/dist/esm/components/{hooks.d.ts → MobileTable/hooks/useLoadingTable.d.ts} +0 -8
  59. package/dist/esm/components/MobileTable/hooks/useLoadingTable.js +17 -0
  60. package/dist/esm/components/MobileTable/index.d.ts +3 -0
  61. package/dist/esm/components/MobileTable/index.js +3 -0
  62. package/dist/esm/components/MobileTable/types.d.ts +11 -0
  63. package/dist/esm/components/MobileTable/types.js +1 -0
  64. package/dist/esm/components/MobileTable/utils/fuzzyFilter.d.ts +2 -0
  65. package/dist/esm/components/{utils.js → MobileTable/utils/fuzzyFilter.js} +0 -5
  66. package/dist/esm/components/MobileTable/utils/index.d.ts +2 -0
  67. package/dist/esm/components/MobileTable/utils/index.js +2 -0
  68. package/dist/esm/components/MobileTable/utils/saveTableState/getPersistedStateValidator.d.ts +4 -0
  69. package/dist/esm/components/MobileTable/utils/saveTableState/getPersistedStateValidator.js +9 -0
  70. package/dist/esm/components/MobileTable/utils/saveTableState/index.d.ts +3 -0
  71. package/dist/esm/components/MobileTable/utils/saveTableState/index.js +3 -0
  72. package/dist/esm/components/MobileTable/utils/saveTableState/mappers.d.ts +18 -0
  73. package/dist/esm/components/MobileTable/utils/saveTableState/mappers.js +37 -0
  74. package/dist/esm/components/MobileTable/utils/saveTableState/validators.d.ts +5 -0
  75. package/dist/esm/components/MobileTable/utils/saveTableState/validators.js +7 -0
  76. package/dist/esm/constants.d.ts +1 -0
  77. package/dist/esm/constants.js +1 -0
  78. package/dist/esm/index.d.ts +1 -0
  79. package/dist/esm/index.js +1 -0
  80. package/package.json +12 -9
  81. package/src/components/AdaptiveServerTable/AdaptiveServerTable.tsx +5 -4
  82. package/src/components/{constants.ts → AdaptiveServerTable/constants.ts} +0 -1
  83. package/src/components/AdaptiveServerTable/utils.ts +12 -0
  84. package/src/components/{MobileTable.tsx → MobileTable/MobileTable.tsx} +50 -55
  85. package/src/components/MobileTable/hooks/index.ts +2 -0
  86. package/src/components/MobileTable/hooks/useFilters/index.ts +1 -0
  87. package/src/components/MobileTable/hooks/useFilters/useFilters.ts +57 -0
  88. package/src/components/MobileTable/hooks/useFilters/utils/getInitialColumnsFiltersOpenValue.ts +13 -0
  89. package/src/components/MobileTable/hooks/useFilters/utils/index.ts +1 -0
  90. package/src/components/{hooks.tsx → MobileTable/hooks/useLoadingTable.tsx} +1 -22
  91. package/src/components/MobileTable/index.ts +3 -0
  92. package/src/components/MobileTable/types.ts +44 -0
  93. package/src/components/{utils.ts → MobileTable/utils/fuzzyFilter.ts} +0 -12
  94. package/src/components/MobileTable/utils/index.ts +2 -0
  95. package/src/components/MobileTable/utils/saveTableState/getPersistedStateValidator.ts +21 -0
  96. package/src/components/MobileTable/utils/saveTableState/index.ts +3 -0
  97. package/src/components/MobileTable/utils/saveTableState/mappers.ts +62 -0
  98. package/src/components/MobileTable/utils/saveTableState/validators.ts +21 -0
  99. package/src/constants.ts +2 -0
  100. package/src/helperComponents/ColumnsSettings/ColumnsSettings.tsx +1 -0
  101. package/src/index.ts +1 -0
  102. package/dist/cjs/components/MobileTable.d.ts +0 -13
  103. package/dist/esm/components/MobileTable.d.ts +0 -13
  104. package/dist/esm/components/hooks.js +0 -30
  105. /package/dist/cjs/components/{styles.module.css → MobileTable/styles.module.css} +0 -0
  106. /package/dist/esm/components/{styles.module.css → MobileTable/styles.module.css} +0 -0
  107. /package/src/components/{styles.module.scss → MobileTable/styles.module.scss} +0 -0
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@cloud-ru/uikit-product-mobile-table",
3
3
  "title": "Mobile Table",
4
- "version": "0.16.2",
4
+ "version": "0.17.0",
5
5
  "sideEffects": [
6
6
  "*.css",
7
7
  "*.woff",
@@ -36,12 +36,14 @@
36
36
  },
37
37
  "scripts": {},
38
38
  "dependencies": {
39
- "@cloud-ru/uikit-product-icons": "16.1.0",
40
- "@cloud-ru/uikit-product-mobile-chips": "0.8.46",
41
- "@cloud-ru/uikit-product-mobile-dropdown": "0.9.30",
42
- "@cloud-ru/uikit-product-mobile-toolbar": "0.4.13",
43
- "@cloud-ru/uikit-product-utils": "8.0.2",
39
+ "@cloud-ru/ft-request-payload-transform": "0.3.0",
40
+ "@cloud-ru/uikit-product-icons": "16.1.1",
41
+ "@cloud-ru/uikit-product-mobile-chips": "0.8.47",
42
+ "@cloud-ru/uikit-product-mobile-dropdown": "0.9.31",
43
+ "@cloud-ru/uikit-product-mobile-toolbar": "0.5.0",
44
+ "@cloud-ru/uikit-product-utils": "8.1.0",
44
45
  "@snack-uikit/button": "0.19.16",
46
+ "@snack-uikit/chips": "0.28.12",
45
47
  "@snack-uikit/figma-tokens": "18.0.1",
46
48
  "@snack-uikit/icons": "0.27.4",
47
49
  "@snack-uikit/info-block": "0.6.35",
@@ -51,11 +53,12 @@
51
53
  "@snack-uikit/status": "0.10.7",
52
54
  "@snack-uikit/table": "0.37.25",
53
55
  "@snack-uikit/toggles": "0.13.23",
56
+ "@snack-uikit/toolbar": "0.14.15",
57
+ "@snack-uikit/utils": "4.0.1",
54
58
  "@tanstack/match-sorter-utils": "8.19.4",
55
59
  "@tanstack/react-table": "8.12.0",
56
60
  "classnames": "2.5.1",
57
- "lodash.debounce": "4.0.8",
58
- "uncontrollable": "8.0.4"
61
+ "lodash.debounce": "4.0.8"
59
62
  },
60
63
  "peerDependencies": {
61
64
  "@cloud-ru/uikit-product-locale": "*"
@@ -63,5 +66,5 @@
63
66
  "devDependencies": {
64
67
  "@types/lodash.debounce": "4.0.9"
65
68
  },
66
- "gitHead": "7303f734eef30f1ac7ac3a279bcf324dcd549059"
69
+ "gitHead": "b8c76e1a66bd22f7c266466eb340860b06581d10"
67
70
  }
@@ -3,11 +3,12 @@ import { useCallback, useEffect, useMemo, useState } from 'react';
3
3
  import { FiltersState } from '@cloud-ru/uikit-product-mobile-chips';
4
4
  import { WithLayoutType } from '@cloud-ru/uikit-product-utils';
5
5
  import { PaginationState, ServerTable as DesktopTable, ServerTableProps } from '@snack-uikit/table';
6
+ import { useValueControl } from '@snack-uikit/utils';
6
7
 
7
- import { DEFAULT_PAGE_SIZE, DEFAULT_PAGINATION_LIMIT } from '../constants';
8
- import { useStateControl } from '../hooks';
8
+ import { DEFAULT_PAGE_SIZE } from '../../constants';
9
9
  import { MobileTable, MobileTableProps } from '../MobileTable';
10
- import { onSearchDebounced } from '../utils';
10
+ import { DEFAULT_PAGINATION_LIMIT } from './constants';
11
+ import { onSearchDebounced } from './utils';
11
12
 
12
13
  export type AdaptiveServerTableProps<TData extends object, TFilters extends FiltersState> = Omit<
13
14
  ServerTableProps<TData, TFilters>,
@@ -34,7 +35,7 @@ export function AdaptiveServerTable<TData extends object, TFilters extends Filte
34
35
  ...rest
35
36
  } = props;
36
37
 
37
- const { state: search, onStateChange: setSearch } = useStateControl<string>(searchProp, '');
38
+ const [search, setSearch] = useValueControl<string>(searchProp ?? { defaultValue: '' });
38
39
 
39
40
  const [tempSearch, setTempSearch] = useState(search || '');
40
41
 
@@ -1,3 +1,2 @@
1
- export const DEFAULT_PAGE_SIZE = 5;
2
1
  export const SEARCH_DELAY = 500;
3
2
  export const DEFAULT_PAGINATION_LIMIT = 10;
@@ -0,0 +1,12 @@
1
+ import debounce from 'lodash.debounce';
2
+
3
+ import { SEARCH_DELAY } from './constants';
4
+
5
+ type OnSearchDebouncedType = (newValue: string, onChange: (newValue: string) => void) => void;
6
+
7
+ export const onSearchDebounced: OnSearchDebouncedType = debounce(
8
+ (newValue: string, onChange: (newValue: string) => void) => {
9
+ onChange(newValue);
10
+ },
11
+ SEARCH_DELAY,
12
+ );
@@ -12,20 +12,22 @@ import cn from 'classnames';
12
12
  import { useCallback, useEffect, useMemo } from 'react';
13
13
 
14
14
  import { useLocale } from '@cloud-ru/uikit-product-locale';
15
- import { FiltersState, MobileChipChoiceRowProps } from '@cloud-ru/uikit-product-mobile-chips';
15
+ import { FiltersState } from '@cloud-ru/uikit-product-mobile-chips';
16
16
  import { MobileToolbar, MobileToolbarProps } from '@cloud-ru/uikit-product-mobile-toolbar';
17
- import { extractSupportProps, WithSupportProps } from '@cloud-ru/uikit-product-utils';
17
+ import { extractSupportProps } from '@cloud-ru/uikit-product-utils';
18
18
  import { SkeletonContextProvider } from '@snack-uikit/skeleton';
19
19
  import {
20
20
  getPinnedGroups,
21
21
  PaginationState,
22
- TableProps,
23
22
  useColumnOrderByDrag,
24
23
  useColumnSettings,
25
24
  usePageReset,
26
25
  } from '@snack-uikit/table';
26
+ import { useValueControl } from '@snack-uikit/utils';
27
27
 
28
+ import { DEFAULT_PAGE_SIZE } from '../../constants';
28
29
  import {
30
+ ColumnsSettings,
29
31
  getRowActionsColumnDef,
30
32
  getStatusColumnDef,
31
33
  TableCard,
@@ -33,50 +35,18 @@ import {
33
35
  TablePagination,
34
36
  TableSorting,
35
37
  useEmptyState,
36
- } from '../helperComponents';
37
- import { ColumnsSettings } from '../helperComponents/ColumnsSettings';
38
- import { DEFAULT_PAGE_SIZE } from './constants';
39
- import { useLoadingTable, useStateControl } from './hooks';
38
+ } from '../../helperComponents';
39
+ import { useFilters, useLoadingTable } from './hooks';
40
40
  import styles from './styles.module.scss';
41
- import { fuzzyFilter } from './utils';
42
-
43
- export type MobileTableProps<TData extends object, TFilters extends FiltersState = Record<string, unknown>> = Pick<
44
- TableProps<TData, TFilters>,
45
- | 'data'
46
- | 'columnDefinitions'
47
- | 'suppressPagination'
48
- | 'suppressToolbar'
49
- | 'suppressSearch'
50
- | 'search'
51
- | 'onRefresh'
52
- | 'moreActions'
53
- | 'className'
54
- | 'enableFuzzySearch'
55
- | 'loading'
56
- | 'dataError'
57
- | 'dataFiltered'
58
- | 'noDataState'
59
- | 'noResultsState'
60
- | 'errorDataState'
61
- | 'sorting'
62
- | 'pagination'
63
- | 'pageCount'
64
- | 'manualFiltering'
65
- | 'manualPagination'
66
- | 'manualSorting'
67
- | 'getRowId'
68
- | 'rowSelection'
69
- | 'bulkActions'
70
- | 'columnsSettings'
71
- | 'savedState'
72
- | 'autoResetPageIndex'
73
- | 'toolbarAfter'
74
- > &
75
- WithSupportProps<{
76
- headlineId?: string;
77
- headerBackground?: 'default' | '1-level' | '2-level';
78
- columnFilters?: MobileChipChoiceRowProps<FiltersState>;
79
- }>;
41
+ import { MobileTableProps } from './types';
42
+ import {
43
+ fuzzyFilter,
44
+ getPersistedStateValidator,
45
+ mapPaginationToRequestPayload,
46
+ mapPaginationToTableState,
47
+ mapSortToRequestPayload,
48
+ mapSortToTableState,
49
+ } from './utils';
80
50
 
81
51
  export function MobileTable<TData extends object, TFilters extends FiltersState = Record<string, unknown>>({
82
52
  data,
@@ -115,16 +85,14 @@ export function MobileTable<TData extends object, TFilters extends FiltersState
115
85
  }: MobileTableProps<TData, TFilters>) {
116
86
  const defaultPaginationState = useMemo(() => ({ pageIndex: 0, pageSize: DEFAULT_PAGE_SIZE }), []);
117
87
 
118
- const { state: sorting, onStateChange: onSortingChange } = useStateControl<SortingState>(sortingProp, []);
119
- const { state: globalFilter, onStateChange: onGlobalFilterChange } = useStateControl<string>(search, '');
120
- const { state: pagination, onStateChange: onPaginationChange } = useStateControl<PaginationState>(
121
- paginationProp,
122
- defaultPaginationState,
88
+ const [sorting = [], onSortingChange] = useValueControl<SortingState>(sortingProp ?? { defaultValue: [] });
89
+ const [globalFilter = '', onGlobalFilterChange] = useValueControl<string>(search ?? { defaultValue: '' });
90
+ const [pagination = defaultPaginationState, onPaginationChange] = useValueControl<PaginationState>(
91
+ paginationProp ?? { defaultValue: defaultPaginationState },
123
92
  );
124
93
 
125
- const { state: rowSelection, onStateChange: onRowSelectionChange } = useStateControl<RowSelectionState>(
126
- rowSelectionProp,
127
- {},
94
+ const [rowSelection = {}, onRowSelectionChange] = useValueControl<RowSelectionState>(
95
+ rowSelectionProp ?? { defaultValue: {} },
128
96
  );
129
97
 
130
98
  const enableRowSelection = useCallback(
@@ -311,6 +279,9 @@ export function MobileTable<TData extends object, TFilters extends FiltersState
311
279
 
312
280
  const tableFilteredRows = table.getFilteredRowModel().rows;
313
281
 
282
+ const { filter, patchedFilter, setFilter, setFilterVisibility } = useFilters({ columnFilters });
283
+ const validatePersistedState = useMemo(() => getPersistedStateValidator(columnFilters), [columnFilters]);
284
+
314
285
  usePageReset({
315
286
  manualPagination,
316
287
  maximumAvailablePage: pageCount || tableFilteredRows.length / pagination.pageSize,
@@ -336,7 +307,7 @@ export function MobileTable<TData extends object, TFilters extends FiltersState
336
307
  }
337
308
  onRefresh={onRefresh ? handleOnRefresh : undefined}
338
309
  outline
339
- filterRow={columnFilters}
310
+ filterRow={patchedFilter}
340
311
  after={
341
312
  toolbarAfter || shouldShowSorting || (areColumnsSettingsEnabled && columnsSettings) ? (
342
313
  <>
@@ -366,6 +337,30 @@ export function MobileTable<TData extends object, TFilters extends FiltersState
366
337
  onCheck={enableSelection ? handleOnToolbarCheck : undefined}
367
338
  checked={table.getIsAllPageRowsSelected()}
368
339
  indeterminate={table.getIsSomePageRowsSelected()}
340
+ persist={
341
+ savedState?.id && savedState?.filterQueryKey
342
+ ? {
343
+ id: savedState.id,
344
+ filterQueryKey: savedState.filterQueryKey,
345
+ validateData: data => validatePersistedState(data),
346
+ state: {
347
+ pagination: mapPaginationToRequestPayload(pagination),
348
+ ordering: mapSortToRequestPayload(sorting),
349
+ filter,
350
+ search: globalFilter || '',
351
+ },
352
+ onLoad: state => {
353
+ state.pagination && onPaginationChange(mapPaginationToTableState(state.pagination));
354
+ state.search && onGlobalFilterChange(state.search);
355
+ state.ordering && onSortingChange(mapSortToTableState(state.ordering));
356
+ if (state.filter) {
357
+ setFilter(state.filter as TFilters);
358
+ setFilterVisibility(Object.keys(state.filter));
359
+ }
360
+ },
361
+ }
362
+ : undefined
363
+ }
369
364
  />
370
365
  </div>
371
366
  )}
@@ -0,0 +1,2 @@
1
+ export * from './useLoadingTable';
2
+ export * from './useFilters';
@@ -0,0 +1 @@
1
+ export * from './useFilters';
@@ -0,0 +1,57 @@
1
+ import { useMemo, useState } from 'react';
2
+
3
+ import { FiltersState } from '@cloud-ru/uikit-product-mobile-chips';
4
+ import { useValueControl } from '@snack-uikit/utils';
5
+
6
+ import { MobileTableProps } from '../../types';
7
+ import { getInitialColumnsFiltersOpenValue } from './utils';
8
+
9
+ type useFiltersProps<TData extends object, TFilters extends FiltersState = Record<string, unknown>> = Pick<
10
+ MobileTableProps<TData, TFilters>,
11
+ 'columnFilters'
12
+ >;
13
+
14
+ export function useFilters<TData extends object, TFilters extends FiltersState = Record<string, unknown>>({
15
+ columnFilters,
16
+ }: useFiltersProps<TData, TFilters>) {
17
+ const [areColumnFiltersOpen, setAreColumnFiltersOpen] = useState<boolean>(() =>
18
+ getInitialColumnsFiltersOpenValue(columnFilters),
19
+ );
20
+
21
+ const [filter, setFilter] = useValueControl<TFilters | undefined>({
22
+ value: columnFilters?.value,
23
+ defaultValue: columnFilters?.defaultValue as TFilters,
24
+ onChange: columnFilters?.onChange,
25
+ });
26
+
27
+ const [filterVisibility = [], setFilterVisibility] = useValueControl<string[]>({
28
+ value: columnFilters?.visibleFilters,
29
+ defaultValue: [],
30
+ onChange: columnFilters?.onVisibleFiltersChange,
31
+ });
32
+
33
+ const patchedFilter = useMemo(() => {
34
+ if (!columnFilters) {
35
+ return undefined;
36
+ }
37
+
38
+ return {
39
+ open: areColumnFiltersOpen,
40
+ onOpenChange: setAreColumnFiltersOpen,
41
+ ...columnFilters,
42
+ value: filter,
43
+ onChange: setFilter as (filter: TFilters) => void,
44
+ visibleFilters: filterVisibility,
45
+ onVisibleFiltersChange: setFilterVisibility,
46
+ };
47
+ }, [columnFilters, areColumnFiltersOpen, filter, setFilter, filterVisibility, setFilterVisibility]);
48
+
49
+ return {
50
+ filter,
51
+ setFilter,
52
+
53
+ patchedFilter,
54
+
55
+ setFilterVisibility,
56
+ };
57
+ }
@@ -0,0 +1,13 @@
1
+ import { MobileTableProps } from '../../../types';
2
+
3
+ export function getInitialColumnsFiltersOpenValue<TData extends object>(
4
+ columnFilters: MobileTableProps<TData>['columnFilters'],
5
+ ) {
6
+ if (!columnFilters) {
7
+ return false;
8
+ }
9
+
10
+ return 'initialOpen' in columnFilters && typeof columnFilters.initialOpen === 'boolean'
11
+ ? columnFilters.initialOpen
12
+ : true;
13
+ }
@@ -0,0 +1 @@
1
+ export * from './getInitialColumnsFiltersOpenValue';
@@ -1,32 +1,11 @@
1
1
  import { getCoreRowModel, useReactTable } from '@tanstack/react-table';
2
2
  import { useMemo } from 'react';
3
- import { useUncontrolledProp } from 'uncontrollable';
4
3
 
5
4
  import { FiltersState } from '@cloud-ru/uikit-product-mobile-chips';
6
5
  import { SkeletonText } from '@snack-uikit/skeleton';
7
6
  import { TableProps } from '@snack-uikit/table';
8
7
 
9
- import { ROW_ACTIONS_COLUMN_ID } from '../constants';
10
-
11
- export function useStateControl<TState>(
12
- control: { initialState?: TState; state?: TState; onChange?(state: TState): void } | undefined,
13
- defaultState: TState,
14
- ) {
15
- const [state, onStateChange] = useUncontrolledProp<TState>(
16
- control?.state,
17
- control?.state ?? control?.initialState ?? defaultState,
18
- (controlState: TState) => {
19
- const newState = typeof controlState === 'function' ? controlState(state) : controlState;
20
-
21
- control?.onChange?.(newState);
22
- },
23
- );
24
-
25
- return {
26
- state,
27
- onStateChange,
28
- };
29
- }
8
+ import { ROW_ACTIONS_COLUMN_ID } from '../../../constants';
30
9
 
31
10
  type UseLoadingTableProps<TData extends object, TFilters extends FiltersState> = {
32
11
  columnDefinitions: TableProps<TData, TFilters>['columnDefinitions'];
@@ -0,0 +1,3 @@
1
+ export * from './MobileTable';
2
+ export * from './types';
3
+ export { formatTableStateToRequestPayload } from './utils/saveTableState/mappers';
@@ -0,0 +1,44 @@
1
+ import { FiltersState, MobileChipChoiceRowProps } from '@cloud-ru/uikit-product-mobile-chips';
2
+ import { WithSupportProps } from '@cloud-ru/uikit-product-utils';
3
+ import { TableProps } from '@snack-uikit/table';
4
+
5
+ export type MobileTableProps<TData extends object, TFilters extends FiltersState = Record<string, unknown>> = Pick<
6
+ TableProps<TData, TFilters>,
7
+ | 'data'
8
+ | 'columnDefinitions'
9
+ | 'suppressPagination'
10
+ | 'suppressToolbar'
11
+ | 'suppressSearch'
12
+ | 'search'
13
+ | 'onRefresh'
14
+ | 'moreActions'
15
+ | 'className'
16
+ | 'enableFuzzySearch'
17
+ | 'loading'
18
+ | 'dataError'
19
+ | 'dataFiltered'
20
+ | 'noDataState'
21
+ | 'noResultsState'
22
+ | 'errorDataState'
23
+ | 'sorting'
24
+ | 'pagination'
25
+ | 'pageCount'
26
+ | 'manualFiltering'
27
+ | 'manualPagination'
28
+ | 'manualSorting'
29
+ | 'getRowId'
30
+ | 'rowSelection'
31
+ | 'bulkActions'
32
+ | 'columnsSettings'
33
+ | 'savedState'
34
+ | 'autoResetPageIndex'
35
+ | 'toolbarAfter'
36
+ > &
37
+ WithSupportProps<{
38
+ headlineId?: string;
39
+ headerBackground?: 'default' | '1-level' | '2-level';
40
+ /** Фильтры */
41
+ columnFilters?: MobileChipChoiceRowProps<TFilters> & {
42
+ initialOpen?: boolean;
43
+ };
44
+ }>;
@@ -1,8 +1,5 @@
1
1
  import { RankingInfo, rankItem } from '@tanstack/match-sorter-utils';
2
2
  import { FilterFn } from '@tanstack/react-table';
3
- import debounce from 'lodash.debounce';
4
-
5
- import { SEARCH_DELAY } from './constants';
6
3
 
7
4
  // eslint-disable-next-line @typescript-eslint/no-explicit-any
8
5
  export const fuzzyFilter: FilterFn<any> = (row, columnId, value, addMeta) => {
@@ -14,12 +11,3 @@ export const fuzzyFilter: FilterFn<any> = (row, columnId, value, addMeta) => {
14
11
 
15
12
  return itemRank.passed;
16
13
  };
17
-
18
- type OnSearchDebouncedType = (newValue: string, onChange: (newValue: string) => void) => void;
19
-
20
- export const onSearchDebounced: OnSearchDebouncedType = debounce(
21
- (newValue: string, onChange: (newValue: string) => void) => {
22
- onChange(newValue);
23
- },
24
- SEARCH_DELAY,
25
- );
@@ -0,0 +1,2 @@
1
+ export * from './fuzzyFilter';
2
+ export * from './saveTableState';
@@ -0,0 +1,21 @@
1
+ import { FiltersState } from '@snack-uikit/chips';
2
+ import { PersistedFilterState } from '@snack-uikit/toolbar';
3
+
4
+ import { MobileTableProps } from '../../types';
5
+ import { validateFilter, validatePaging, validateSorting } from './validators';
6
+
7
+ export const getPersistedStateValidator =
8
+ <TData extends object, TFilters extends FiltersState = Record<string, unknown>>(
9
+ columnFilters: MobileTableProps<TData, TFilters>['columnFilters'],
10
+ ) =>
11
+ (data: unknown): data is PersistedFilterState<TFilters> => {
12
+ const dataAsSettings = data as PersistedFilterState<TFilters>;
13
+ const isPaginationValid = validatePaging(dataAsSettings?.pagination);
14
+ const isSortingValid = validateSorting(dataAsSettings?.ordering);
15
+ const isSearchValid = !dataAsSettings?.search || typeof dataAsSettings?.search === 'string';
16
+ const isFilterValid = Boolean(
17
+ columnFilters?.filters && validateFilter(dataAsSettings.filter, columnFilters.filters),
18
+ );
19
+
20
+ return isPaginationValid && isSortingValid && isSearchValid && isFilterValid;
21
+ };
@@ -0,0 +1,3 @@
1
+ export * from './validators';
2
+ export * from './mappers';
3
+ export * from './getPersistedStateValidator';
@@ -0,0 +1,62 @@
1
+ import { RequestPayloadParams, SortDirection } from '@cloud-ru/ft-request-payload-transform';
2
+ import { PaginationState, SortingState } from '@tanstack/react-table';
3
+
4
+ import { FiltersState } from '@snack-uikit/chips';
5
+ import { formatFilterStateToRequestPayload, PersistedFilterState } from '@snack-uikit/toolbar';
6
+
7
+ import { DEFAULT_PAGE_SIZE } from '../../../../constants';
8
+
9
+ export const mapPaginationToTableState = (value?: RequestPayloadParams['pagination']): PaginationState => {
10
+ if (!value || value.offset === undefined || value.limit === undefined) {
11
+ return { pageSize: DEFAULT_PAGE_SIZE, pageIndex: 0 };
12
+ }
13
+
14
+ return {
15
+ pageSize: value.limit || DEFAULT_PAGE_SIZE,
16
+ pageIndex: Math.floor(value.offset / value.limit),
17
+ };
18
+ };
19
+
20
+ export const mapSortToTableState = (value: RequestPayloadParams['ordering'] = []): SortingState =>
21
+ value.map(column => ({
22
+ id: column.field,
23
+ desc: column.direction === '-',
24
+ }));
25
+
26
+ export const mapPaginationToRequestPayload = (
27
+ value?: PaginationState | RequestPayloadParams['pagination'],
28
+ ): RequestPayloadParams['pagination'] => {
29
+ if (!value) return undefined;
30
+
31
+ if ('limit' in value || 'offset' in value) {
32
+ return value;
33
+ }
34
+
35
+ return {
36
+ limit: value.pageSize,
37
+ offset: value.pageSize * value.pageIndex,
38
+ };
39
+ };
40
+
41
+ export const mapSortToRequestPayload = (value?: SortingState): RequestPayloadParams['ordering'] =>
42
+ value?.map(column => ({
43
+ field: column.id,
44
+ direction: (column.desc ? '-' : '+') as SortDirection,
45
+ }));
46
+
47
+ /** Вспомогательная функция для преобразования состояния таблицы к формату RequestPayloadParams */
48
+ export const formatTableStateToRequestPayload = <T extends FiltersState>({
49
+ pagination,
50
+ sorting,
51
+ search,
52
+ filter,
53
+ }: Omit<PersistedFilterState<T>, 'pagination' | 'sorting'> & {
54
+ pagination?: PaginationState | RequestPayloadParams['pagination'];
55
+ sorting?: SortingState;
56
+ }) =>
57
+ formatFilterStateToRequestPayload({
58
+ filter,
59
+ search,
60
+ pagination: mapPaginationToRequestPayload(pagination),
61
+ ordering: mapSortToRequestPayload(sorting),
62
+ });
@@ -0,0 +1,21 @@
1
+ import { RequestPayloadParams } from '@cloud-ru/ft-request-payload-transform';
2
+
3
+ import { ChipChoiceRowProps } from '@snack-uikit/chips';
4
+
5
+ export const validatePaging = (value: unknown): value is RequestPayloadParams['pagination'] =>
6
+ typeof (value as RequestPayloadParams['pagination'])?.limit === 'number' &&
7
+ typeof (value as RequestPayloadParams['pagination'])?.offset === 'number';
8
+
9
+ export const validateSorting = (value: unknown): value is RequestPayloadParams['ordering'] =>
10
+ !value ||
11
+ (value as NonNullable<RequestPayloadParams['ordering']>).every(
12
+ column => typeof column?.field === 'string' && typeof column?.direction === 'string',
13
+ );
14
+
15
+ export const validateFilter = <TFilters extends Record<string, unknown>>(
16
+ value: unknown,
17
+ filterSettings: ChipChoiceRowProps<TFilters>['filters'],
18
+ ): value is TFilters =>
19
+ typeof value === 'object' &&
20
+ value !== null &&
21
+ Object.keys(value).every(field => Boolean(filterSettings.find(setting => setting.id === field)));
package/src/constants.ts CHANGED
@@ -16,3 +16,5 @@ export const TEST_IDS = {
16
16
  };
17
17
 
18
18
  export const ROW_ACTIONS_COLUMN_ID = 'rowActions';
19
+
20
+ export const DEFAULT_PAGE_SIZE = 5;
@@ -4,6 +4,7 @@ import { FunctionSettingsSVG } from '@snack-uikit/icons';
4
4
  import { GroupSelectItemProps } from '@snack-uikit/list';
5
5
 
6
6
  import styles from './styles.module.scss';
7
+
7
8
  export type ColumnsSettingsProps = {
8
9
  enabledColumns: string[];
9
10
  setEnabledColumns(enabledColumns: string[]): void;
package/src/index.ts CHANGED
@@ -1 +1,2 @@
1
1
  export * from './components';
2
+ export * from './helperComponents';
@@ -1,13 +0,0 @@
1
- import { FiltersState, MobileChipChoiceRowProps } from '@cloud-ru/uikit-product-mobile-chips';
2
- import { WithSupportProps } from '@cloud-ru/uikit-product-utils';
3
- import { TableProps } from '@snack-uikit/table';
4
- export type MobileTableProps<TData extends object, TFilters extends FiltersState = Record<string, unknown>> = Pick<TableProps<TData, TFilters>, 'data' | 'columnDefinitions' | 'suppressPagination' | 'suppressToolbar' | 'suppressSearch' | 'search' | 'onRefresh' | 'moreActions' | 'className' | 'enableFuzzySearch' | 'loading' | 'dataError' | 'dataFiltered' | 'noDataState' | 'noResultsState' | 'errorDataState' | 'sorting' | 'pagination' | 'pageCount' | 'manualFiltering' | 'manualPagination' | 'manualSorting' | 'getRowId' | 'rowSelection' | 'bulkActions' | 'columnsSettings' | 'savedState' | 'autoResetPageIndex' | 'toolbarAfter'> & WithSupportProps<{
5
- headlineId?: string;
6
- headerBackground?: 'default' | '1-level' | '2-level';
7
- columnFilters?: MobileChipChoiceRowProps<FiltersState>;
8
- }>;
9
- export declare function MobileTable<TData extends object, TFilters extends FiltersState = Record<string, unknown>>({ data, columnDefinitions, headlineId, suppressPagination, suppressToolbar, suppressSearch, enableFuzzySearch, search, onRefresh, toolbarAfter, moreActions, columnFilters, className, headerBackground, noDataState, noResultsState, errorDataState, loading, dataError, dataFiltered, pagination: paginationProp, pageCount, sorting: sortingProp, manualSorting, manualPagination, manualFiltering, autoResetPageIndex, getRowId, rowSelection: rowSelectionProp, bulkActions: bulkActionsProp, columnsSettings: columnsSettingsProp, savedState, ...rest }: MobileTableProps<TData, TFilters>): import("react/jsx-runtime").JSX.Element;
10
- export declare namespace MobileTable {
11
- var getRowActionsColumnDef: typeof import("../helperComponents").getRowActionsColumnDef;
12
- var getStatusColumnDef: typeof import("../helperComponents").getStatusColumnDef;
13
- }
@@ -1,13 +0,0 @@
1
- import { FiltersState, MobileChipChoiceRowProps } from '@cloud-ru/uikit-product-mobile-chips';
2
- import { WithSupportProps } from '@cloud-ru/uikit-product-utils';
3
- import { TableProps } from '@snack-uikit/table';
4
- export type MobileTableProps<TData extends object, TFilters extends FiltersState = Record<string, unknown>> = Pick<TableProps<TData, TFilters>, 'data' | 'columnDefinitions' | 'suppressPagination' | 'suppressToolbar' | 'suppressSearch' | 'search' | 'onRefresh' | 'moreActions' | 'className' | 'enableFuzzySearch' | 'loading' | 'dataError' | 'dataFiltered' | 'noDataState' | 'noResultsState' | 'errorDataState' | 'sorting' | 'pagination' | 'pageCount' | 'manualFiltering' | 'manualPagination' | 'manualSorting' | 'getRowId' | 'rowSelection' | 'bulkActions' | 'columnsSettings' | 'savedState' | 'autoResetPageIndex' | 'toolbarAfter'> & WithSupportProps<{
5
- headlineId?: string;
6
- headerBackground?: 'default' | '1-level' | '2-level';
7
- columnFilters?: MobileChipChoiceRowProps<FiltersState>;
8
- }>;
9
- export declare function MobileTable<TData extends object, TFilters extends FiltersState = Record<string, unknown>>({ data, columnDefinitions, headlineId, suppressPagination, suppressToolbar, suppressSearch, enableFuzzySearch, search, onRefresh, toolbarAfter, moreActions, columnFilters, className, headerBackground, noDataState, noResultsState, errorDataState, loading, dataError, dataFiltered, pagination: paginationProp, pageCount, sorting: sortingProp, manualSorting, manualPagination, manualFiltering, autoResetPageIndex, getRowId, rowSelection: rowSelectionProp, bulkActions: bulkActionsProp, columnsSettings: columnsSettingsProp, savedState, ...rest }: MobileTableProps<TData, TFilters>): import("react/jsx-runtime").JSX.Element;
10
- export declare namespace MobileTable {
11
- var getRowActionsColumnDef: typeof import("../helperComponents").getRowActionsColumnDef;
12
- var getStatusColumnDef: typeof import("../helperComponents").getStatusColumnDef;
13
- }
@@ -1,30 +0,0 @@
1
- import { jsx as _jsx } from "react/jsx-runtime";
2
- import { getCoreRowModel, useReactTable } from '@tanstack/react-table';
3
- import { useMemo } from 'react';
4
- import { useUncontrolledProp } from 'uncontrollable';
5
- import { SkeletonText } from '@snack-uikit/skeleton';
6
- import { ROW_ACTIONS_COLUMN_ID } from '../constants';
7
- export function useStateControl(control, defaultState) {
8
- var _a, _b;
9
- const [state, onStateChange] = useUncontrolledProp(control === null || control === void 0 ? void 0 : control.state, (_b = (_a = control === null || control === void 0 ? void 0 : control.state) !== null && _a !== void 0 ? _a : control === null || control === void 0 ? void 0 : control.initialState) !== null && _b !== void 0 ? _b : defaultState, (controlState) => {
10
- var _a;
11
- const newState = typeof controlState === 'function' ? controlState(state) : controlState;
12
- (_a = control === null || control === void 0 ? void 0 : control.onChange) === null || _a === void 0 ? void 0 : _a.call(control, newState);
13
- });
14
- return {
15
- state,
16
- onStateChange,
17
- };
18
- }
19
- export function useLoadingTable({ pageSize, columnDefinitions, }) {
20
- const data = useMemo(() => (Array.from({ length: pageSize }).map(() => ({})) || []), [pageSize]);
21
- const columns = useMemo(() => columnDefinitions
22
- .filter(column => column.id !== ROW_ACTIONS_COLUMN_ID)
23
- .map(column => (Object.assign(Object.assign({}, column), { cell: () => _jsx(SkeletonText, { lines: 1, width: '100%' }) }))), [columnDefinitions]);
24
- const loadingTable = useReactTable({
25
- data,
26
- columns,
27
- getCoreRowModel: getCoreRowModel(),
28
- });
29
- return { loadingTable };
30
- }