@snack-uikit/toolbar 0.14.15 → 0.14.16
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 +9 -0
- package/README.md +122 -1
- package/dist/cjs/components/Toolbar/hooks/usePersistState/utils/isDateString.d.ts +10 -0
- package/dist/cjs/components/Toolbar/hooks/usePersistState/utils/isDateString.js +31 -3
- package/dist/cjs/components/index.d.ts +1 -0
- package/dist/cjs/components/index.js +8 -1
- package/dist/esm/components/Toolbar/hooks/usePersistState/utils/isDateString.d.ts +10 -0
- package/dist/esm/components/Toolbar/hooks/usePersistState/utils/isDateString.js +38 -3
- package/dist/esm/components/index.d.ts +1 -0
- package/dist/esm/components/index.js +1 -0
- package/package.json +2 -2
- package/src/components/Toolbar/hooks/usePersistState/utils/isDateString.ts +44 -3
- package/src/components/index.ts +1 -0
package/CHANGELOG.md
CHANGED
|
@@ -3,6 +3,15 @@
|
|
|
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
|
+
## <small>0.14.16 (2026-01-19)</small>
|
|
7
|
+
|
|
8
|
+
* fix(FF-7903): improved and exported date detection parsing utility from toolbar package ([1c71cba](https://github.com/cloud-ru-tech/snack-uikit/commit/1c71cba))
|
|
9
|
+
* docs(FF-7788): readme update ([e3142b8](https://github.com/cloud-ru-tech/snack-uikit/commit/e3142b8))
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
|
|
6
15
|
## <small>0.14.15 (2025-12-17)</small>
|
|
7
16
|
|
|
8
17
|
* fix(FF-7656): date parse issue ([edddd6c](https://github.com/cloud-ru-tech/snack-uikit/commit/edddd6c))
|
package/README.md
CHANGED
|
@@ -5,7 +5,115 @@
|
|
|
5
5
|
|
|
6
6
|
[Changelog](./CHANGELOG.md)
|
|
7
7
|
|
|
8
|
-
|
|
8
|
+
## Description
|
|
9
|
+
|
|
10
|
+
- Пакет `@snack-uikit/toolbar` предоставляет компонент `Toolbar` — универсальную панель инструментов для управления данными в таблицах, списках и других представлениях контента.
|
|
11
|
+
- Компонент объединяет в себе строку поиска, массовые действия для выбранных элементов, кнопку обновления, фильтры и дополнительные действия в единый интерфейс.
|
|
12
|
+
- Поддерживает два режима выбора: `single` (одиночный) и `multiple` (множественный) с чекбоксом и массовыми действиями (`bulkActions`), которые автоматически скрываются при отсутствии выбранных элементов.
|
|
13
|
+
- Включает строку поиска с возможностью загрузки (`loading`), обработчиками изменения значения и подтверждения поиска.
|
|
14
|
+
- Интегрирует систему фильтров через `filterRow` на базе `ChipChoiceRow`, позволяющую добавлять, удалять и управлять активными фильтрами с отображением их количества на кнопке фильтра.
|
|
15
|
+
- Предоставляет слот `after` для размещения произвольных React-компонентов в правой части тулбара и выпадающий список дополнительных действий (`moreActions`).
|
|
16
|
+
- Поддерживает сохранение состояния фильтров и поиска в `localStorage` и `queryParams` через конфигурацию `persist` для восстановления состояния при перезагрузке страницы.
|
|
17
|
+
- Может отображаться с внешним бордером (`outline`) для визуального отделения от контента.
|
|
18
|
+
- Figma: [`Toolbar`](https://www.figma.com/file/jtGxAPvFJOMir7V0eQFukN/Snack-UI-Kit-1.1.0?node-id=41%3A224846&mode=design).
|
|
19
|
+
|
|
20
|
+
## Example
|
|
21
|
+
|
|
22
|
+
```tsx
|
|
23
|
+
import { useState } from 'react';
|
|
24
|
+
import { Toolbar } from '@snack-uikit/toolbar';
|
|
25
|
+
import { ButtonFunction } from '@snack-uikit/button';
|
|
26
|
+
import { PlaceholderSVG } from '@snack-uikit/icons';
|
|
27
|
+
|
|
28
|
+
function Example() {
|
|
29
|
+
const [searchValue, setSearchValue] = useState('');
|
|
30
|
+
const [checked, setChecked] = useState(false);
|
|
31
|
+
const [filtersValue, setFiltersValue] = useState<Record<string, unknown>>({});
|
|
32
|
+
const [visibleFilters, setVisibleFilters] = useState<string[]>([]);
|
|
33
|
+
|
|
34
|
+
const bulkActions = [
|
|
35
|
+
{
|
|
36
|
+
label: 'Confirm',
|
|
37
|
+
icon: PlaceholderSVG,
|
|
38
|
+
onClick: () => console.log('Confirm'),
|
|
39
|
+
'data-test-id': 'confirm-action',
|
|
40
|
+
},
|
|
41
|
+
{
|
|
42
|
+
label: 'Delete',
|
|
43
|
+
icon: PlaceholderSVG,
|
|
44
|
+
onClick: () => console.log('Delete'),
|
|
45
|
+
'data-test-id': 'delete-action',
|
|
46
|
+
},
|
|
47
|
+
];
|
|
48
|
+
|
|
49
|
+
const moreActions = [
|
|
50
|
+
{
|
|
51
|
+
id: 'export',
|
|
52
|
+
content: { option: 'Export' },
|
|
53
|
+
onClick: () => console.log('Export'),
|
|
54
|
+
},
|
|
55
|
+
{
|
|
56
|
+
id: 'import',
|
|
57
|
+
content: { option: 'Import' },
|
|
58
|
+
onClick: () => console.log('Import'),
|
|
59
|
+
},
|
|
60
|
+
];
|
|
61
|
+
|
|
62
|
+
const filterRow = {
|
|
63
|
+
showAddButton: true,
|
|
64
|
+
showClearButton: true,
|
|
65
|
+
filters: [
|
|
66
|
+
{
|
|
67
|
+
id: 'status',
|
|
68
|
+
label: 'Status',
|
|
69
|
+
type: 'single',
|
|
70
|
+
pinned: true,
|
|
71
|
+
options: [
|
|
72
|
+
{ label: 'Active', value: 'active' },
|
|
73
|
+
{ label: 'Inactive', value: 'inactive' },
|
|
74
|
+
],
|
|
75
|
+
},
|
|
76
|
+
],
|
|
77
|
+
open: visibleFilters.length > 0,
|
|
78
|
+
value: filtersValue,
|
|
79
|
+
onChange: setFiltersValue,
|
|
80
|
+
visibleFilters,
|
|
81
|
+
onVisibleFiltersChange: setVisibleFilters,
|
|
82
|
+
};
|
|
83
|
+
|
|
84
|
+
return (
|
|
85
|
+
<Toolbar
|
|
86
|
+
search={{
|
|
87
|
+
value: searchValue,
|
|
88
|
+
onChange: setSearchValue,
|
|
89
|
+
onSubmit: (value) => console.log('Search:', value),
|
|
90
|
+
placeholder: 'Search',
|
|
91
|
+
}}
|
|
92
|
+
selectionMode="multiple"
|
|
93
|
+
checked={checked}
|
|
94
|
+
onCheck={() => setChecked(!checked)}
|
|
95
|
+
bulkActions={bulkActions}
|
|
96
|
+
onRefresh={() => console.log('Refresh')}
|
|
97
|
+
moreActions={moreActions}
|
|
98
|
+
filterRow={filterRow}
|
|
99
|
+
after={
|
|
100
|
+
<>
|
|
101
|
+
<ButtonFunction icon={<PlaceholderSVG />} size="m" />
|
|
102
|
+
<ButtonFunction icon={<PlaceholderSVG />} size="m" />
|
|
103
|
+
</>
|
|
104
|
+
}
|
|
105
|
+
persist={{
|
|
106
|
+
id: 'example-toolbar',
|
|
107
|
+
filterQueryKey: 'filters',
|
|
108
|
+
onLoad: ({ filter, search }) => {
|
|
109
|
+
if (filter) setFiltersValue(filter);
|
|
110
|
+
if (search) setSearchValue(search);
|
|
111
|
+
},
|
|
112
|
+
}}
|
|
113
|
+
/>
|
|
114
|
+
);
|
|
115
|
+
}
|
|
116
|
+
```
|
|
9
117
|
|
|
10
118
|
[//]: DOCUMENTATION_SECTION_START
|
|
11
119
|
[//]: THIS_SECTION_IS_AUTOGENERATED_PLEASE_DONT_EDIT_IT
|
|
@@ -18,6 +126,19 @@ Toolbar
|
|
|
18
126
|
| ordering | `FieldSort[]` | - | |
|
|
19
127
|
| search | `string` | - | |
|
|
20
128
|
| filter | `FiltersState` | - | |
|
|
129
|
+
## isDateString
|
|
130
|
+
Утилита для проверки значения на соответствие дате.
|
|
131
|
+
Поддерживает:
|
|
132
|
+
- ISO форматы: '2021-01-01T00:00:00Z', '2021-01-01T15:55:42.000Z'
|
|
133
|
+
- Форматы с точками: '12.03.2025', '12.03.2025 12:00'
|
|
134
|
+
- Частичные даты: '2026', '2026-01'
|
|
135
|
+
- Timestamps: '1768492519666', '-62167219200000'
|
|
136
|
+
- Временные зоны: '+03:00', '-05:00'
|
|
137
|
+
С полным списком поддерживаемых значений можно ознакомиться
|
|
138
|
+
в файле с unit тестами packages/toolbar/__tests__/isDateString.spec.ts
|
|
139
|
+
### Props
|
|
140
|
+
| name | type | default value | description |
|
|
141
|
+
|------|------|---------------|-------------|
|
|
21
142
|
## Toolbar
|
|
22
143
|
### Props
|
|
23
144
|
| name | type | default value | description |
|
|
@@ -1 +1,11 @@
|
|
|
1
|
+
/** Утилита для проверки значения на соответствие дате.
|
|
2
|
+
* Поддерживает:
|
|
3
|
+
* - ISO форматы: '2021-01-01T00:00:00Z', '2021-01-01T15:55:42.000Z'
|
|
4
|
+
* - Форматы с точками: '12.03.2025', '12.03.2025 12:00'
|
|
5
|
+
* - Частичные даты: '2026', '2026-01'
|
|
6
|
+
* - Timestamps: '1768492519666', '-62167219200000'
|
|
7
|
+
* - Временные зоны: '+03:00', '-05:00'
|
|
8
|
+
* С полным списком поддерживаемых значений можно ознакомиться
|
|
9
|
+
* в файле с unit тестами packages/toolbar/__tests__/isDateString.spec.ts
|
|
10
|
+
*/
|
|
1
11
|
export declare const isDateString: (value: unknown) => value is Date;
|
|
@@ -4,11 +4,39 @@ Object.defineProperty(exports, "__esModule", {
|
|
|
4
4
|
value: true
|
|
5
5
|
});
|
|
6
6
|
exports.isDateString = void 0;
|
|
7
|
-
const
|
|
7
|
+
const DATE_SYMBOLS_REGEXP = /[\d\-:.TZ+\s]/g;
|
|
8
|
+
/** Утилита для проверки значения на соответствие дате.
|
|
9
|
+
* Поддерживает:
|
|
10
|
+
* - ISO форматы: '2021-01-01T00:00:00Z', '2021-01-01T15:55:42.000Z'
|
|
11
|
+
* - Форматы с точками: '12.03.2025', '12.03.2025 12:00'
|
|
12
|
+
* - Частичные даты: '2026', '2026-01'
|
|
13
|
+
* - Timestamps: '1768492519666', '-62167219200000'
|
|
14
|
+
* - Временные зоны: '+03:00', '-05:00'
|
|
15
|
+
* С полным списком поддерживаемых значений можно ознакомиться
|
|
16
|
+
* в файле с unit тестами packages/toolbar/__tests__/isDateString.spec.ts
|
|
17
|
+
*/
|
|
8
18
|
const isDateString = value => {
|
|
9
19
|
if (typeof value !== 'string') return false;
|
|
10
|
-
const
|
|
20
|
+
const trimmed = value.trim();
|
|
21
|
+
if (trimmed.length === 0) return false;
|
|
22
|
+
const nonDateSymbols = trimmed.replaceAll(DATE_SYMBOLS_REGEXP, '');
|
|
11
23
|
if (nonDateSymbols.length > 0) return false;
|
|
12
|
-
|
|
24
|
+
if (/^-?\d+$/.test(trimmed)) {
|
|
25
|
+
if (trimmed.length <= 2) return false;
|
|
26
|
+
const num = Number(trimmed);
|
|
27
|
+
const date = new Date(num);
|
|
28
|
+
if (isNaN(date.getTime())) return false;
|
|
29
|
+
return date.getTime() === num;
|
|
30
|
+
}
|
|
31
|
+
if (/^\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}$/.test(trimmed)) {
|
|
32
|
+
return false;
|
|
33
|
+
}
|
|
34
|
+
const date = new Date(trimmed);
|
|
35
|
+
if (isNaN(date.getTime())) return false;
|
|
36
|
+
const hasDateLikeStructure = /^\d{4}/.test(trimmed) || /^\d{1,2}[.-]\d{1,2}[.-]\d{4}/.test(trimmed) || /^\d{4}[.-]\d{1,2}[.-]\d{1,2}/.test(trimmed) || /T/.test(trimmed);
|
|
37
|
+
if (!hasDateLikeStructure && !trimmed.includes(':')) {
|
|
38
|
+
return false;
|
|
39
|
+
}
|
|
40
|
+
return date.toString() !== 'Invalid Date';
|
|
13
41
|
};
|
|
14
42
|
exports.isDateString = isDateString;
|
|
@@ -1,3 +1,4 @@
|
|
|
1
1
|
export * from './Toolbar';
|
|
2
2
|
export type { FilterRow, PersistedFilterState, ToolbarPersistConfig } from './Toolbar/types';
|
|
3
3
|
export { formatFilterStateToRequestPayload } from './Toolbar/hooks/usePersistState/utils';
|
|
4
|
+
export { isDateString } from './Toolbar/hooks/usePersistState/utils/isDateString';
|
|
@@ -22,7 +22,7 @@ var __exportStar = void 0 && (void 0).__exportStar || function (m, exports) {
|
|
|
22
22
|
Object.defineProperty(exports, "__esModule", {
|
|
23
23
|
value: true
|
|
24
24
|
});
|
|
25
|
-
exports.formatFilterStateToRequestPayload = void 0;
|
|
25
|
+
exports.isDateString = exports.formatFilterStateToRequestPayload = void 0;
|
|
26
26
|
__exportStar(require("./Toolbar"), exports);
|
|
27
27
|
var utils_1 = require("./Toolbar/hooks/usePersistState/utils");
|
|
28
28
|
Object.defineProperty(exports, "formatFilterStateToRequestPayload", {
|
|
@@ -30,4 +30,11 @@ Object.defineProperty(exports, "formatFilterStateToRequestPayload", {
|
|
|
30
30
|
get: function () {
|
|
31
31
|
return utils_1.formatFilterStateToRequestPayload;
|
|
32
32
|
}
|
|
33
|
+
});
|
|
34
|
+
var isDateString_1 = require("./Toolbar/hooks/usePersistState/utils/isDateString");
|
|
35
|
+
Object.defineProperty(exports, "isDateString", {
|
|
36
|
+
enumerable: true,
|
|
37
|
+
get: function () {
|
|
38
|
+
return isDateString_1.isDateString;
|
|
39
|
+
}
|
|
33
40
|
});
|
|
@@ -1 +1,11 @@
|
|
|
1
|
+
/** Утилита для проверки значения на соответствие дате.
|
|
2
|
+
* Поддерживает:
|
|
3
|
+
* - ISO форматы: '2021-01-01T00:00:00Z', '2021-01-01T15:55:42.000Z'
|
|
4
|
+
* - Форматы с точками: '12.03.2025', '12.03.2025 12:00'
|
|
5
|
+
* - Частичные даты: '2026', '2026-01'
|
|
6
|
+
* - Timestamps: '1768492519666', '-62167219200000'
|
|
7
|
+
* - Временные зоны: '+03:00', '-05:00'
|
|
8
|
+
* С полным списком поддерживаемых значений можно ознакомиться
|
|
9
|
+
* в файле с unit тестами packages/toolbar/__tests__/isDateString.spec.ts
|
|
10
|
+
*/
|
|
1
11
|
export declare const isDateString: (value: unknown) => value is Date;
|
|
@@ -1,9 +1,44 @@
|
|
|
1
|
-
const
|
|
1
|
+
const DATE_SYMBOLS_REGEXP = /[\d\-:.TZ+\s]/g;
|
|
2
|
+
/** Утилита для проверки значения на соответствие дате.
|
|
3
|
+
* Поддерживает:
|
|
4
|
+
* - ISO форматы: '2021-01-01T00:00:00Z', '2021-01-01T15:55:42.000Z'
|
|
5
|
+
* - Форматы с точками: '12.03.2025', '12.03.2025 12:00'
|
|
6
|
+
* - Частичные даты: '2026', '2026-01'
|
|
7
|
+
* - Timestamps: '1768492519666', '-62167219200000'
|
|
8
|
+
* - Временные зоны: '+03:00', '-05:00'
|
|
9
|
+
* С полным списком поддерживаемых значений можно ознакомиться
|
|
10
|
+
* в файле с unit тестами packages/toolbar/__tests__/isDateString.spec.ts
|
|
11
|
+
*/
|
|
2
12
|
export const isDateString = (value) => {
|
|
3
13
|
if (typeof value !== 'string')
|
|
4
14
|
return false;
|
|
5
|
-
const
|
|
15
|
+
const trimmed = value.trim();
|
|
16
|
+
if (trimmed.length === 0)
|
|
17
|
+
return false;
|
|
18
|
+
const nonDateSymbols = trimmed.replaceAll(DATE_SYMBOLS_REGEXP, '');
|
|
6
19
|
if (nonDateSymbols.length > 0)
|
|
7
20
|
return false;
|
|
8
|
-
|
|
21
|
+
if (/^-?\d+$/.test(trimmed)) {
|
|
22
|
+
if (trimmed.length <= 2)
|
|
23
|
+
return false;
|
|
24
|
+
const num = Number(trimmed);
|
|
25
|
+
const date = new Date(num);
|
|
26
|
+
if (isNaN(date.getTime()))
|
|
27
|
+
return false;
|
|
28
|
+
return date.getTime() === num;
|
|
29
|
+
}
|
|
30
|
+
if (/^\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}$/.test(trimmed)) {
|
|
31
|
+
return false;
|
|
32
|
+
}
|
|
33
|
+
const date = new Date(trimmed);
|
|
34
|
+
if (isNaN(date.getTime()))
|
|
35
|
+
return false;
|
|
36
|
+
const hasDateLikeStructure = /^\d{4}/.test(trimmed) ||
|
|
37
|
+
/^\d{1,2}[.-]\d{1,2}[.-]\d{4}/.test(trimmed) ||
|
|
38
|
+
/^\d{4}[.-]\d{1,2}[.-]\d{1,2}/.test(trimmed) ||
|
|
39
|
+
/T/.test(trimmed);
|
|
40
|
+
if (!hasDateLikeStructure && !trimmed.includes(':')) {
|
|
41
|
+
return false;
|
|
42
|
+
}
|
|
43
|
+
return date.toString() !== 'Invalid Date';
|
|
9
44
|
};
|
|
@@ -1,3 +1,4 @@
|
|
|
1
1
|
export * from './Toolbar';
|
|
2
2
|
export type { FilterRow, PersistedFilterState, ToolbarPersistConfig } from './Toolbar/types';
|
|
3
3
|
export { formatFilterStateToRequestPayload } from './Toolbar/hooks/usePersistState/utils';
|
|
4
|
+
export { isDateString } from './Toolbar/hooks/usePersistState/utils/isDateString';
|
package/package.json
CHANGED
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
"access": "public"
|
|
5
5
|
},
|
|
6
6
|
"title": "Toolbar",
|
|
7
|
-
"version": "0.14.
|
|
7
|
+
"version": "0.14.16",
|
|
8
8
|
"sideEffects": [
|
|
9
9
|
"*.css",
|
|
10
10
|
"*.woff",
|
|
@@ -52,5 +52,5 @@
|
|
|
52
52
|
"peerDependencies": {
|
|
53
53
|
"@snack-uikit/locale": "*"
|
|
54
54
|
},
|
|
55
|
-
"gitHead": "
|
|
55
|
+
"gitHead": "2baa589b36417cff3006e42bee78144c8ec5e83a"
|
|
56
56
|
}
|
|
@@ -1,10 +1,51 @@
|
|
|
1
|
-
const
|
|
1
|
+
const DATE_SYMBOLS_REGEXP = /[\d\-:.TZ+\s]/g;
|
|
2
2
|
|
|
3
|
+
/** Утилита для проверки значения на соответствие дате.
|
|
4
|
+
* Поддерживает:
|
|
5
|
+
* - ISO форматы: '2021-01-01T00:00:00Z', '2021-01-01T15:55:42.000Z'
|
|
6
|
+
* - Форматы с точками: '12.03.2025', '12.03.2025 12:00'
|
|
7
|
+
* - Частичные даты: '2026', '2026-01'
|
|
8
|
+
* - Timestamps: '1768492519666', '-62167219200000'
|
|
9
|
+
* - Временные зоны: '+03:00', '-05:00'
|
|
10
|
+
* С полным списком поддерживаемых значений можно ознакомиться
|
|
11
|
+
* в файле с unit тестами packages/toolbar/__tests__/isDateString.spec.ts
|
|
12
|
+
*/
|
|
3
13
|
export const isDateString = (value: unknown): value is Date => {
|
|
4
14
|
if (typeof value !== 'string') return false;
|
|
5
15
|
|
|
6
|
-
const
|
|
16
|
+
const trimmed = value.trim();
|
|
17
|
+
if (trimmed.length === 0) return false;
|
|
18
|
+
|
|
19
|
+
const nonDateSymbols = trimmed.replaceAll(DATE_SYMBOLS_REGEXP, '');
|
|
7
20
|
if (nonDateSymbols.length > 0) return false;
|
|
8
21
|
|
|
9
|
-
|
|
22
|
+
if (/^-?\d+$/.test(trimmed)) {
|
|
23
|
+
if (trimmed.length <= 2) return false;
|
|
24
|
+
|
|
25
|
+
const num = Number(trimmed);
|
|
26
|
+
const date = new Date(num);
|
|
27
|
+
|
|
28
|
+
if (isNaN(date.getTime())) return false;
|
|
29
|
+
|
|
30
|
+
return date.getTime() === num;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
if (/^\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}$/.test(trimmed)) {
|
|
34
|
+
return false;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
const date = new Date(trimmed);
|
|
38
|
+
if (isNaN(date.getTime())) return false;
|
|
39
|
+
|
|
40
|
+
const hasDateLikeStructure =
|
|
41
|
+
/^\d{4}/.test(trimmed) ||
|
|
42
|
+
/^\d{1,2}[.-]\d{1,2}[.-]\d{4}/.test(trimmed) ||
|
|
43
|
+
/^\d{4}[.-]\d{1,2}[.-]\d{1,2}/.test(trimmed) ||
|
|
44
|
+
/T/.test(trimmed);
|
|
45
|
+
|
|
46
|
+
if (!hasDateLikeStructure && !trimmed.includes(':')) {
|
|
47
|
+
return false;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
return date.toString() !== 'Invalid Date';
|
|
10
51
|
};
|
package/src/components/index.ts
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
1
|
export * from './Toolbar';
|
|
2
2
|
export type { FilterRow, PersistedFilterState, ToolbarPersistConfig } from './Toolbar/types';
|
|
3
3
|
export { formatFilterStateToRequestPayload } from './Toolbar/hooks/usePersistState/utils';
|
|
4
|
+
export { isDateString } from './Toolbar/hooks/usePersistState/utils/isDateString';
|