@invoicebox/ui 0.1.0-alpha.325 → 0.1.0-alpha.327

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 (178) hide show
  1. package/dist/components/common/AdaptiveModalDrawer/index.d.ts +11 -0
  2. package/dist/components/common/AdaptiveModalDrawer/index.js +31 -0
  3. package/dist/components/common/AdaptiveModalDrawer/index.stories.d.ts +5 -0
  4. package/dist/components/common/AdaptiveModalDrawer/index.stories.js +44 -0
  5. package/dist/components/common/AppCardLink/index.js +1 -2
  6. package/dist/components/common/BgCard/index.js +1 -2
  7. package/dist/components/common/BgCard/styles.js +1 -2
  8. package/dist/components/common/Calendar/index.js +1 -2
  9. package/dist/components/common/Calendar/index.stories.js +1 -2
  10. package/dist/components/common/Calendar/styles.js +1 -2
  11. package/dist/components/common/Divider/index.js +1 -2
  12. package/dist/components/common/Drawer/index.js +1 -2
  13. package/dist/components/common/Drawer/index.stories.js +1 -2
  14. package/dist/components/common/Drawer/styles.js +1 -2
  15. package/dist/components/common/Dropdown/index.js +1 -2
  16. package/dist/components/common/Dropdown/styles.js +8 -9
  17. package/dist/components/common/EntityAutocompleteOptionsDrawer/index.js +1 -2
  18. package/dist/components/common/EntityAutocompleteOptionsDrawer/index.stories.js +1 -2
  19. package/dist/components/common/Flag/index.js +1 -2
  20. package/dist/components/common/Flag/styles.js +1 -2
  21. package/dist/components/common/InvoiceboxSpinner/index.js +1 -2
  22. package/dist/components/common/InvoiceboxSpinner/styles.js +1 -2
  23. package/dist/components/common/Modal/assets/CollapseIcon.d.ts +1 -0
  24. package/dist/components/common/Modal/assets/CollapseIcon.js +42 -0
  25. package/dist/components/common/Modal/assets/ExpandIcon.d.ts +1 -0
  26. package/dist/components/common/Modal/assets/ExpandIcon.js +42 -0
  27. package/dist/components/common/Modal/context.d.ts +9 -0
  28. package/dist/components/common/Modal/context.js +14 -0
  29. package/dist/components/common/Modal/index.d.ts +15 -0
  30. package/dist/components/common/Modal/index.js +165 -0
  31. package/dist/components/common/Modal/index.stories.d.ts +6 -0
  32. package/dist/components/common/Modal/index.stories.js +76 -0
  33. package/dist/components/common/Modal/palette.d.ts +9 -0
  34. package/dist/components/common/Modal/palette.js +23 -0
  35. package/dist/components/common/Modal/styles.d.ts +25 -0
  36. package/dist/components/common/Modal/styles.js +69 -0
  37. package/dist/components/common/PointsLoader/index.js +1 -2
  38. package/dist/components/common/QRCode/index.js +2 -2
  39. package/dist/components/common/ReadOnlyLabelValueField/index.js +1 -2
  40. package/dist/components/common/Scrollbar/index.js +1 -2
  41. package/dist/components/common/Scrollbar/styles.js +1 -2
  42. package/dist/components/common/SecondaryButton/index.js +3 -4
  43. package/dist/components/common/SecondaryButton/styles.js +1 -2
  44. package/dist/components/common/Skeleton/index.js +1 -2
  45. package/dist/components/common/Skeleton/styles.js +1 -2
  46. package/dist/components/common/Toast/index.js +1 -2
  47. package/dist/components/common/Tooltip/index.js +1 -2
  48. package/dist/components/common/Typography/index.js +3 -4
  49. package/dist/components/common/WarningIcon/index.js +1 -2
  50. package/dist/components/common/WentWrongModal/assets/icons.d.ts +3 -0
  51. package/dist/components/common/WentWrongModal/assets/icons.js +84 -0
  52. package/dist/components/common/WentWrongModal/assets/racoonImage.d.ts +1 -0
  53. package/dist/components/common/WentWrongModal/assets/racoonImage.js +9 -0
  54. package/dist/components/common/WentWrongModal/index.d.ts +23 -0
  55. package/dist/components/common/WentWrongModal/index.js +193 -0
  56. package/dist/components/common/WentWrongModal/index.stories.d.ts +6 -0
  57. package/dist/components/common/WentWrongModal/index.stories.js +60 -0
  58. package/dist/components/common/WentWrongModal/index.test.d.ts +1 -0
  59. package/dist/components/common/WentWrongModal/index.test.js +209 -0
  60. package/dist/components/common/WentWrongModal/palette.d.ts +11 -0
  61. package/dist/components/common/WentWrongModal/palette.js +22 -0
  62. package/dist/components/common/WentWrongModal/styles.d.ts +24 -0
  63. package/dist/components/common/WentWrongModal/styles.js +88 -0
  64. package/dist/components/form/Autocomplete/components/Autocomplete/index.js +1 -2
  65. package/dist/components/form/Autocomplete/components/Autocomplete/index.stories.js +1 -2
  66. package/dist/components/form/Autocomplete/components/OrganizationAutocompleteItem/index.js +1 -2
  67. package/dist/components/form/Checkbox/index.js +3 -4
  68. package/dist/components/form/Checkbox/index.stories.js +1 -2
  69. package/dist/components/form/CodeInput/index.js +1 -2
  70. package/dist/components/form/CodeInput/index.stories.js +1 -2
  71. package/dist/components/form/CountrySelect/components/CountryItem/index.js +1 -2
  72. package/dist/components/form/CountrySelect/index.js +3 -4
  73. package/dist/components/form/CurrencyInput/CoreCurrencyInput/index.js +1 -2
  74. package/dist/components/form/CurrencyInput/CoreCurrencyInput/index.stories.js +1 -2
  75. package/dist/components/form/CurrencyInput/CurrencyInputNumber/index.js +2 -2
  76. package/dist/components/form/CurrencyInput/CurrencyInputNumber/index.stories.js +1 -2
  77. package/dist/components/form/CurrencyInput/CurrencyInputString/index.js +2 -2
  78. package/dist/components/form/CurrencyInput/CurrencyInputString/index.stories.js +1 -2
  79. package/dist/components/form/DateInput/components/CalendarIcon/index.js +1 -2
  80. package/dist/components/form/DateInput/components/MobileDrawerDateCalendar/index.js +1 -2
  81. package/dist/components/form/DateInput/components/MobileDrawerDateCalendar/index.stories.js +1 -2
  82. package/dist/components/form/DateInput/index.js +1 -2
  83. package/dist/components/form/DateInput/index.stories.js +1 -2
  84. package/dist/components/form/DateTimeInput/components/MobileDatePicker/index.js +1 -2
  85. package/dist/components/form/DateTimeInput/components/MobileDatePicker/index.stories.js +1 -2
  86. package/dist/components/form/DateTimeInput/components/MobileDrawerDateTimeCalendar/index.js +1 -2
  87. package/dist/components/form/DateTimeInput/components/MobileDrawerDateTimeCalendar/index.stories.js +1 -2
  88. package/dist/components/form/DateTimeInput/components/MobileWheelPicker/components/WheelColumn/index.js +1 -2
  89. package/dist/components/form/DateTimeInput/components/MobileWheelPicker/index.js +1 -2
  90. package/dist/components/form/DateTimeInput/components/MobileWheelPicker/index.stories.js +1 -2
  91. package/dist/components/form/DateTimeInput/components/TimePicker/index.js +1 -2
  92. package/dist/components/form/DateTimeInput/components/TimePicker/index.stories.js +1 -2
  93. package/dist/components/form/DateTimeInput/index.js +1 -2
  94. package/dist/components/form/DateTimeInput/index.stories.js +1 -2
  95. package/dist/components/form/InputLabel/index.js +1 -2
  96. package/dist/components/form/InputLabel/styles.js +1 -2
  97. package/dist/components/form/ModernPlaceholder/index.js +1 -2
  98. package/dist/components/form/PhoneInput/index.js +1 -2
  99. package/dist/components/form/PhoneInput/index.stories.js +1 -2
  100. package/dist/components/form/PositiveIntegerInput/index.js +1 -2
  101. package/dist/components/form/PositiveIntegerInput/index.stories.js +1 -2
  102. package/dist/components/form/PureInput/index.js +3 -4
  103. package/dist/components/form/PureInput/styles.js +2 -2
  104. package/dist/components/form/ResetButton/index.js +1 -2
  105. package/dist/components/form/SearchInput/index.js +1 -2
  106. package/dist/components/form/SearchInput/index.stories.js +1 -2
  107. package/dist/components/form/Select/components/Input/index.js +1 -2
  108. package/dist/components/form/Select/components/Loader/index.js +1 -2
  109. package/dist/components/form/Select/components/MultipleValue/index.js +1 -2
  110. package/dist/components/form/Select/components/MultipleValue/styles.js +1 -2
  111. package/dist/components/form/Select/index.js +1 -2
  112. package/dist/components/form/Select/index.stories.js +1 -2
  113. package/dist/components/form/Select/styles.js +1 -2
  114. package/dist/components/form/TagsInput/index.js +1 -2
  115. package/dist/components/form/TagsInput/index.stories.js +1 -2
  116. package/dist/components/form/TagsInput/styles.js +2 -2
  117. package/dist/components/form/TextInput/index.js +1 -2
  118. package/dist/components/form/TextInput/index.stories.js +1 -2
  119. package/dist/components/form/Toggle/index.js +3 -4
  120. package/dist/components/form/Toggle/index.stories.js +1 -2
  121. package/dist/components/form/Toggle/styles.js +10 -10
  122. package/dist/components/form/_hooks/useInputStyles.js +1 -2
  123. package/dist/components/form/common/DrawerHeader/index.js +1 -2
  124. package/dist/esm/components/common/AdaptiveModalDrawer/index.js +24 -0
  125. package/dist/esm/components/common/AdaptiveModalDrawer/index.stories.js +37 -0
  126. package/dist/esm/components/common/Dropdown/styles.js +7 -7
  127. package/dist/esm/components/common/Modal/assets/CollapseIcon.js +35 -0
  128. package/dist/esm/components/common/Modal/assets/ExpandIcon.js +35 -0
  129. package/dist/esm/components/common/Modal/context.js +8 -0
  130. package/dist/esm/components/common/Modal/index.js +147 -0
  131. package/dist/esm/components/common/Modal/index.stories.js +69 -0
  132. package/dist/esm/components/common/Modal/palette.js +16 -0
  133. package/dist/esm/components/common/Modal/styles.js +61 -0
  134. package/dist/esm/components/common/QRCode/index.js +2 -2
  135. package/dist/esm/components/common/SecondaryButton/index.js +2 -2
  136. package/dist/esm/components/common/Typography/index.js +2 -2
  137. package/dist/esm/components/common/WentWrongModal/assets/icons.js +77 -0
  138. package/dist/esm/components/common/WentWrongModal/assets/racoonImage.js +3 -0
  139. package/dist/esm/components/common/WentWrongModal/index.js +186 -0
  140. package/dist/esm/components/common/WentWrongModal/index.stories.js +53 -0
  141. package/dist/esm/components/common/WentWrongModal/index.test.js +208 -0
  142. package/dist/esm/components/common/WentWrongModal/palette.js +15 -0
  143. package/dist/esm/components/common/WentWrongModal/styles.js +81 -0
  144. package/dist/esm/components/form/Checkbox/index.js +2 -2
  145. package/dist/esm/components/form/CountrySelect/index.js +2 -2
  146. package/dist/esm/components/form/CurrencyInput/CurrencyInputNumber/index.js +2 -2
  147. package/dist/esm/components/form/CurrencyInput/CurrencyInputString/index.js +2 -2
  148. package/dist/esm/components/form/PureInput/index.js +2 -2
  149. package/dist/esm/components/form/PureInput/styles.js +2 -2
  150. package/dist/esm/components/form/TagsInput/styles.js +2 -2
  151. package/dist/esm/components/form/Toggle/index.js +2 -2
  152. package/dist/esm/components/form/Toggle/styles.js +10 -10
  153. package/dist/esm/hooks/useQueryFilter/context.js +40 -0
  154. package/dist/esm/hooks/useQueryFilter/helpers.js +58 -0
  155. package/dist/esm/hooks/useQueryFilter/index.js +123 -0
  156. package/dist/esm/hooks/useQueryFilter/index.stories.js +71 -0
  157. package/dist/esm/hooks/useQueryFilter/index.test.js +180 -0
  158. package/dist/esm/index.js +4 -1
  159. package/dist/esm/palette/context.js +5 -1
  160. package/dist/esm/palette/provider.js +5 -1
  161. package/dist/hooks/useQueryFilter/context.d.ts +35 -0
  162. package/dist/hooks/useQueryFilter/context.js +48 -0
  163. package/dist/hooks/useQueryFilter/helpers.d.ts +17 -0
  164. package/dist/hooks/useQueryFilter/helpers.js +64 -0
  165. package/dist/hooks/useQueryFilter/index.d.ts +19 -0
  166. package/dist/hooks/useQueryFilter/index.js +163 -0
  167. package/dist/hooks/useQueryFilter/index.stories.d.ts +4 -0
  168. package/dist/hooks/useQueryFilter/index.stories.js +75 -0
  169. package/dist/hooks/useQueryFilter/index.test.d.ts +1 -0
  170. package/dist/hooks/useQueryFilter/index.test.js +183 -0
  171. package/dist/hooks/useUnupdatableHandler/index.stories.js +1 -2
  172. package/dist/index.d.ts +8 -0
  173. package/dist/index.js +136 -0
  174. package/dist/palette/context.d.ts +4 -0
  175. package/dist/palette/context.js +52 -48
  176. package/dist/palette/provider.js +53 -50
  177. package/dist/palette/usePalette.d.ts +2 -0
  178. package/package.json +2 -1
@@ -0,0 +1,123 @@
1
+ function _slicedToArray(r, e) { return _arrayWithHoles(r) || _iterableToArrayLimit(r, e) || _unsupportedIterableToArray(r, e) || _nonIterableRest(); }
2
+ function _nonIterableRest() { throw new TypeError("Invalid attempt to destructure non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); }
3
+ function _unsupportedIterableToArray(r, a) { if (r) { if ("string" == typeof r) return _arrayLikeToArray(r, a); var t = {}.toString.call(r).slice(8, -1); return "Object" === t && r.constructor && (t = r.constructor.name), "Map" === t || "Set" === t ? Array.from(r) : "Arguments" === t || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(t) ? _arrayLikeToArray(r, a) : void 0; } }
4
+ function _arrayLikeToArray(r, a) { (null == a || a > r.length) && (a = r.length); for (var e = 0, n = Array(a); e < a; e++) n[e] = r[e]; return n; }
5
+ function _iterableToArrayLimit(r, l) { var t = null == r ? null : "undefined" != typeof Symbol && r[Symbol.iterator] || r["@@iterator"]; if (null != t) { var e, n, i, u, a = [], f = !0, o = !1; try { if (i = (t = t.call(r)).next, 0 === l) { if (Object(t) !== t) return; f = !1; } else for (; !(f = (e = i.call(t)).done) && (a.push(e.value), a.length !== l); f = !0); } catch (r) { o = !0, n = r; } finally { try { if (!f && null != t["return"] && (u = t["return"](), Object(u) !== u)) return; } finally { if (o) throw n; } } return a; } }
6
+ function _arrayWithHoles(r) { if (Array.isArray(r)) return r; }
7
+ import { useCallback, useEffect, useMemo, useState } from 'react';
8
+ import { useQueryFilterContext } from './context';
9
+ export { QueryFilterProvider, DEFAULT_PAGE_PARAM_NAME, DEFAULT_FIRST_PAGE } from './context';
10
+ export * from './helpers';
11
+ var getIsEmptyValue = function getIsEmptyValue(value) {
12
+ return value === '' || value === undefined || value === null || Array.isArray(value) && value.length === 0;
13
+ };
14
+
15
+ /**
16
+ * Значение фильтра, которое живёт в строке запроса.
17
+ *
18
+ * - `initialValue` записывается в адрес при монтировании, если параметра там ещё нет;
19
+ * пустое значение (`''`, `null`, `undefined`, `[]`) удаляет параметр.
20
+ * - Смена значения сбрасывает номер страницы на первую (`isResetPageWhenChanged`).
21
+ * - Начальное значение можно передавать выражением (`new Date()`, `[]`): хук сравнивает его
22
+ * по строке, которую оно даёт в адресе, а не по ссылке.
23
+ *
24
+ * Нужен `QueryFilterProvider` выше по дереву.
25
+ */
26
+ export var useQueryFilter = function useQueryFilter(name, initialValue, fromString, toString) {
27
+ var _searchParams$get;
28
+ var isResetPageWhenChanged = arguments.length > 4 && arguments[4] !== undefined ? arguments[4] : true;
29
+ var _useQueryFilterContex = useQueryFilterContext(),
30
+ searchParams = _useQueryFilterContex.searchParams,
31
+ setSearchParams = _useQueryFilterContex.setSearchParams,
32
+ pageParamName = _useQueryFilterContex.pageParamName,
33
+ firstPage = _useQueryFilterContex.firstPage;
34
+
35
+ // для тех случаев когда если initialValue и в случае когда он не успел вставить в квери параметры - возвращать его
36
+ var _useState = useState(false),
37
+ _useState2 = _slicedToArray(_useState, 2),
38
+ acceptInitialValueDone = _useState2[0],
39
+ setAcceptInitialValueDone = _useState2[1];
40
+ var serialize = useCallback(function (value) {
41
+ if (getIsEmptyValue(value)) return '';
42
+ return toString ? toString(value) : String(value);
43
+ }, [toString]);
44
+ var removeAttribute = useCallback(function (isResetPage) {
45
+ if (searchParams.has(name)) {
46
+ searchParams["delete"](name);
47
+ if (isResetPage) {
48
+ searchParams.set(pageParamName, String(firstPage));
49
+ }
50
+ setSearchParams(searchParams);
51
+ }
52
+ }, [firstPage, name, pageParamName, searchParams, setSearchParams]);
53
+ var handleQueryChange = useCallback(function (newValue) {
54
+ if (getIsEmptyValue(newValue)) {
55
+ removeAttribute(isResetPageWhenChanged);
56
+ return;
57
+ }
58
+ searchParams.set(name, serialize(newValue));
59
+ if (isResetPageWhenChanged) {
60
+ searchParams.set(pageParamName, String(firstPage));
61
+ }
62
+ setSearchParams(searchParams);
63
+ }, [firstPage, isResetPageWhenChanged, name, pageParamName, removeAttribute, searchParams, serialize, setSearchParams]);
64
+ var acceptInitialValue = useCallback(function (initial) {
65
+ if (!searchParams.has(name)) {
66
+ if (getIsEmptyValue(initial)) {
67
+ removeAttribute(true);
68
+ setAcceptInitialValueDone(true);
69
+ return;
70
+ }
71
+ searchParams.set(name, serialize(initial));
72
+ setSearchParams(searchParams);
73
+ }
74
+ setAcceptInitialValueDone(true);
75
+ }, [name, removeAttribute, searchParams, serialize, setSearchParams]);
76
+
77
+ /**
78
+ * Начальное значение, стабилизированное по его строковому представлению.
79
+ *
80
+ * Вызывающие часто передают начальное значение выражением (`monthStart()`, `[]`,
81
+ * `new Date()`), то есть новым объектом на каждый рендер. Если зависеть от самой
82
+ * ссылки, эффект ниже срабатывает на каждом рендере (и возвращает в адрес значение
83
+ * по умолчанию, которое пользователь только что сбросил), а значение фильтра каждый
84
+ * раз получает новую ссылку — эффект с запросом перезапускается без конца. Поэтому
85
+ * ссылка меняется только когда меняется строка, которую значение даёт в адресе.
86
+ */
87
+ var initialKey = serialize(initialValue);
88
+ // eslint-disable-next-line react-hooks/exhaustive-deps
89
+ var stableInitialValue = useMemo(function () {
90
+ return initialValue;
91
+ }, [initialKey]);
92
+ useEffect(function () {
93
+ acceptInitialValue(stableInitialValue);
94
+ // eslint-disable-next-line react-hooks/exhaustive-deps
95
+ }, [stableInitialValue]);
96
+ var handleGetValueFromString = useCallback(function (queryValue) {
97
+ if (fromString) {
98
+ return fromString(queryValue);
99
+ }
100
+ return queryValue || '';
101
+ }, [fromString]);
102
+
103
+ /**
104
+ * Строку читаем на каждом рендере, а не кешируем по объекту `searchParams`: эффект
105
+ * начального значения дописывает параметр прямо в текущий объект, а навигация
106
+ * (react-router 7 — переходом с низким приоритетом) приходит позже. Между ними есть
107
+ * рендер, где объект прежний, но строка в нём уже новая, — по ней и надо считать,
108
+ * иначе фильтр на один рендер «пустеет» и уходит лишний запрос.
109
+ *
110
+ * Пока строка в адресе совпадает с начальной, отдаём сам `stableInitialValue`, а не
111
+ * результат разбора: иначе `new Date(...)` из разборщика дал бы новую ссылку при тех
112
+ * же данных и эффект с запросом сработал бы ещё раз.
113
+ */
114
+ var rawQueryValue = (_searchParams$get = searchParams.get(name)) !== null && _searchParams$get !== void 0 ? _searchParams$get : '';
115
+ var isInitialNotAppliedYet = !acceptInitialValueDone && !searchParams.has(name);
116
+ var formattedValue = useMemo(function () {
117
+ if (isInitialNotAppliedYet || rawQueryValue === initialKey) {
118
+ return stableInitialValue;
119
+ }
120
+ return handleGetValueFromString(rawQueryValue || null);
121
+ }, [handleGetValueFromString, initialKey, isInitialNotAppliedYet, rawQueryValue, stableInitialValue]);
122
+ return [formattedValue, handleQueryChange];
123
+ };
@@ -0,0 +1,71 @@
1
+ function _slicedToArray(r, e) { return _arrayWithHoles(r) || _iterableToArrayLimit(r, e) || _unsupportedIterableToArray(r, e) || _nonIterableRest(); }
2
+ function _nonIterableRest() { throw new TypeError("Invalid attempt to destructure non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); }
3
+ function _unsupportedIterableToArray(r, a) { if (r) { if ("string" == typeof r) return _arrayLikeToArray(r, a); var t = {}.toString.call(r).slice(8, -1); return "Object" === t && r.constructor && (t = r.constructor.name), "Map" === t || "Set" === t ? Array.from(r) : "Arguments" === t || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(t) ? _arrayLikeToArray(r, a) : void 0; } }
4
+ function _arrayLikeToArray(r, a) { (null == a || a > r.length) && (a = r.length); for (var e = 0, n = Array(a); e < a; e++) n[e] = r[e]; return n; }
5
+ function _iterableToArrayLimit(r, l) { var t = null == r ? null : "undefined" != typeof Symbol && r[Symbol.iterator] || r["@@iterator"]; if (null != t) { var e, n, i, u, a = [], f = !0, o = !1; try { if (i = (t = t.call(r)).next, 0 === l) { if (Object(t) !== t) return; f = !1; } else for (; !(f = (e = i.call(t)).done) && (a.push(e.value), a.length !== l); f = !0); } catch (r) { o = !0, n = r; } finally { try { if (!f && null != t["return"] && (u = t["return"](), Object(u) !== u)) return; } finally { if (o) throw n; } } return a; } }
6
+ function _arrayWithHoles(r) { if (Array.isArray(r)) return r; }
7
+ import React, { useCallback, useState } from 'react';
8
+ /* eslint-disable react-hooks/rules-of-hooks */
9
+
10
+ import { QueryFilterProvider, getDateOrNullFromQueryString, getQueryStringFromDateOrNull, useQueryFilter } from '.';
11
+ var meta = {
12
+ title: 'hooks/useQueryFilter',
13
+ tags: ['autodocs']
14
+ };
15
+ export default meta;
16
+
17
+ // В приложении сюда передают useSearchParams() роутера; в истории адрес живёт в состоянии
18
+ var InMemoryRouter = function InMemoryRouter(_ref) {
19
+ var children = _ref.children;
20
+ var _useState = useState(function () {
21
+ return new URLSearchParams();
22
+ }),
23
+ _useState2 = _slicedToArray(_useState, 2),
24
+ searchParams = _useState2[0],
25
+ setSearchParamsState = _useState2[1];
26
+ var setSearchParams = useCallback(function (next) {
27
+ return setSearchParamsState(new URLSearchParams(next.toString()));
28
+ }, []);
29
+ return /*#__PURE__*/React.createElement(QueryFilterProvider, {
30
+ searchParams: searchParams,
31
+ setSearchParams: setSearchParams
32
+ }, children(searchParams.toString()));
33
+ };
34
+ var Filters = function Filters() {
35
+ var _useQueryFilter = useQueryFilter('status', 'pending'),
36
+ _useQueryFilter2 = _slicedToArray(_useQueryFilter, 2),
37
+ status = _useQueryFilter2[0],
38
+ setStatus = _useQueryFilter2[1];
39
+ var _useQueryFilter3 = useQueryFilter('from', null, getDateOrNullFromQueryString, getQueryStringFromDateOrNull),
40
+ _useQueryFilter4 = _slicedToArray(_useQueryFilter3, 2),
41
+ from = _useQueryFilter4[0],
42
+ setFrom = _useQueryFilter4[1];
43
+ return /*#__PURE__*/React.createElement("div", null, /*#__PURE__*/React.createElement("p", null, "status: ", status || '—'), /*#__PURE__*/React.createElement("button", {
44
+ type: 'button',
45
+ onClick: function onClick() {
46
+ return setStatus('approved');
47
+ }
48
+ }, "status = approved"), /*#__PURE__*/React.createElement("button", {
49
+ type: 'button',
50
+ onClick: function onClick() {
51
+ return setStatus('');
52
+ }
53
+ }, "\u0421\u0431\u0440\u043E\u0441\u0438\u0442\u044C status"), /*#__PURE__*/React.createElement("p", null, "from: ", from ? from.toLocaleString() : '—'), /*#__PURE__*/React.createElement("button", {
54
+ type: 'button',
55
+ onClick: function onClick() {
56
+ return setFrom(new Date());
57
+ }
58
+ }, "from = \u0441\u0435\u0439\u0447\u0430\u0441"), /*#__PURE__*/React.createElement("button", {
59
+ type: 'button',
60
+ onClick: function onClick() {
61
+ return setFrom(null);
62
+ }
63
+ }, "\u0421\u0431\u0440\u043E\u0441\u0438\u0442\u044C from"));
64
+ };
65
+ export var Default = {
66
+ render: function render() {
67
+ return /*#__PURE__*/React.createElement(InMemoryRouter, null, function (search) {
68
+ return /*#__PURE__*/React.createElement("div", null, /*#__PURE__*/React.createElement("p", null, "\u0410\u0434\u0440\u0435\u0441: ", /*#__PURE__*/React.createElement("code", null, "?", search)), /*#__PURE__*/React.createElement(Filters, null));
69
+ });
70
+ }
71
+ };
@@ -0,0 +1,180 @@
1
+ function _slicedToArray(r, e) { return _arrayWithHoles(r) || _iterableToArrayLimit(r, e) || _unsupportedIterableToArray(r, e) || _nonIterableRest(); }
2
+ function _nonIterableRest() { throw new TypeError("Invalid attempt to destructure non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); }
3
+ function _unsupportedIterableToArray(r, a) { if (r) { if ("string" == typeof r) return _arrayLikeToArray(r, a); var t = {}.toString.call(r).slice(8, -1); return "Object" === t && r.constructor && (t = r.constructor.name), "Map" === t || "Set" === t ? Array.from(r) : "Arguments" === t || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(t) ? _arrayLikeToArray(r, a) : void 0; } }
4
+ function _arrayLikeToArray(r, a) { (null == a || a > r.length) && (a = r.length); for (var e = 0, n = Array(a); e < a; e++) n[e] = r[e]; return n; }
5
+ function _iterableToArrayLimit(r, l) { var t = null == r ? null : "undefined" != typeof Symbol && r[Symbol.iterator] || r["@@iterator"]; if (null != t) { var e, n, i, u, a = [], f = !0, o = !1; try { if (i = (t = t.call(r)).next, 0 === l) { if (Object(t) !== t) return; f = !1; } else for (; !(f = (e = i.call(t)).done) && (a.push(e.value), a.length !== l); f = !0); } catch (r) { o = !0, n = r; } finally { try { if (!f && null != t["return"] && (u = t["return"](), Object(u) !== u)) return; } finally { if (o) throw n; } } return a; } }
6
+ function _arrayWithHoles(r) { if (Array.isArray(r)) return r; }
7
+ /**
8
+ * @jest-environment jsdom
9
+ */
10
+ import React, { act, startTransition, useCallback, useEffect, useState } from 'react';
11
+ import { createRoot } from 'react-dom/client';
12
+ import { booleanFromString, formatDateForQuery, getDateArrOrNullFromQueryString, getQueryStringFromDateArrOrNull, getDateOrNullFromQueryString, getQueryStringFromDateOrNull, QueryFilterProvider, useQueryFilter } from '.';
13
+ globalThis.IS_REACT_ACT_ENVIRONMENT = true;
14
+ var url = '';
15
+
16
+ /**
17
+ * Роутер в памяти, ведущий себя как react-router 7: запись адреса идёт переходом с низким
18
+ * приоритетом, а в следующем рендере приходит новый объект URLSearchParams.
19
+ */
20
+ var MemoryRouter = function MemoryRouter(_ref) {
21
+ var _ref$initial = _ref.initial,
22
+ initial = _ref$initial === void 0 ? '' : _ref$initial,
23
+ children = _ref.children;
24
+ var _useState = useState(function () {
25
+ return new URLSearchParams(initial);
26
+ }),
27
+ _useState2 = _slicedToArray(_useState, 2),
28
+ searchParams = _useState2[0],
29
+ setSearchParamsState = _useState2[1];
30
+ var setSearchParams = useCallback(function (next) {
31
+ var nextString = next.toString();
32
+ url = nextString;
33
+ startTransition(function () {
34
+ return setSearchParamsState(new URLSearchParams(nextString));
35
+ });
36
+ }, []);
37
+ return /*#__PURE__*/React.createElement(QueryFilterProvider, {
38
+ searchParams: searchParams,
39
+ setSearchParams: setSearchParams
40
+ }, children);
41
+ };
42
+ var container;
43
+ var root;
44
+ beforeEach(function () {
45
+ url = '';
46
+ container = document.createElement('div');
47
+ root = createRoot(container);
48
+ });
49
+ afterEach(function () {
50
+ act(function () {
51
+ return root.unmount();
52
+ });
53
+ });
54
+ var render = function render(node) {
55
+ return act(function () {
56
+ return root.render(node);
57
+ });
58
+ };
59
+ describe('useQueryFilter', function () {
60
+ test('строковое значение по умолчанию: попадает в адрес, запрос один', function () {
61
+ var requests = [];
62
+ var setter = function setter() {
63
+ return undefined;
64
+ };
65
+ var List = function List() {
66
+ var _useQueryFilter = useQueryFilter('status', 'pending'),
67
+ _useQueryFilter2 = _slicedToArray(_useQueryFilter, 2),
68
+ status = _useQueryFilter2[0],
69
+ setStatus = _useQueryFilter2[1];
70
+ setter = setStatus;
71
+ useEffect(function () {
72
+ requests.push(status);
73
+ }, [status]);
74
+ return null;
75
+ };
76
+ render(/*#__PURE__*/React.createElement(MemoryRouter, null, /*#__PURE__*/React.createElement(List, null)));
77
+ expect(url).toBe('status=pending');
78
+ expect(requests).toEqual(['pending']);
79
+ act(function () {
80
+ return setter('approved');
81
+ });
82
+ expect(url).toBe('status=approved&page=1');
83
+ expect(requests).toEqual(['pending', 'approved']);
84
+ });
85
+ test('дата по умолчанию выражением: ни лишнего запроса, ни цикла', function () {
86
+ var requests = [];
87
+ var from = new Date(2026, 9, 1, 12, 30, 15);
88
+ var List = function List() {
89
+ // новый объект на каждом рендере — так вызывающие и пишут
90
+ var _useQueryFilter3 = useQueryFilter('from', new Date(from.getTime()), getDateOrNullFromQueryString, getQueryStringFromDateOrNull),
91
+ _useQueryFilter4 = _slicedToArray(_useQueryFilter3, 1),
92
+ dateFrom = _useQueryFilter4[0];
93
+ useEffect(function () {
94
+ requests.push(String(dateFrom === null || dateFrom === void 0 ? void 0 : dateFrom.getTime()));
95
+ }, [dateFrom]);
96
+ return null;
97
+ };
98
+ render(/*#__PURE__*/React.createElement(MemoryRouter, null, /*#__PURE__*/React.createElement(List, null)));
99
+ expect(new URLSearchParams(url).get('from')).toBe(formatDateForQuery(from));
100
+ expect(requests).toEqual([String(from.getTime())]);
101
+ });
102
+ test('значение из адреса важнее значения по умолчанию', function () {
103
+ var value = '';
104
+ var List = function List() {
105
+ var _useQueryFilter5 = useQueryFilter('status', 'pending');
106
+ var _useQueryFilter6 = _slicedToArray(_useQueryFilter5, 1);
107
+ value = _useQueryFilter6[0];
108
+ return null;
109
+ };
110
+ render(/*#__PURE__*/React.createElement(MemoryRouter, {
111
+ initial: "status=rejected&page=3"
112
+ }, /*#__PURE__*/React.createElement(List, null)));
113
+ expect(value).toBe('rejected');
114
+ expect(url).toBe('');
115
+ });
116
+ test('сброс фильтра с непустым значением по умолчанию не возвращает его обратно', function () {
117
+ var value;
118
+ var setter = function setter() {
119
+ return undefined;
120
+ };
121
+ var List = function List() {
122
+ var _useQueryFilter7 = useQueryFilter('ids', ['a', 'b'], function (raw) {
123
+ return raw ? raw.split(',') : undefined;
124
+ }, function (next) {
125
+ return next ? next.join(',') : '';
126
+ });
127
+ var _useQueryFilter8 = _slicedToArray(_useQueryFilter7, 2);
128
+ value = _useQueryFilter8[0];
129
+ setter = _useQueryFilter8[1];
130
+ return null;
131
+ };
132
+ render(/*#__PURE__*/React.createElement(MemoryRouter, null, /*#__PURE__*/React.createElement(List, null)));
133
+ expect(value).toEqual(['a', 'b']);
134
+ act(function () {
135
+ return setter(undefined);
136
+ });
137
+ expect(url).toBe('page=1');
138
+ expect(value).toBeUndefined();
139
+ });
140
+ test('isResetPageWhenChanged=false не трогает страницу', function () {
141
+ var setter = function setter() {
142
+ return undefined;
143
+ };
144
+ var List = function List() {
145
+ var _useQueryFilter9 = useQueryFilter('q', '', undefined, undefined, false);
146
+ var _useQueryFilter0 = _slicedToArray(_useQueryFilter9, 2);
147
+ setter = _useQueryFilter0[1];
148
+ return null;
149
+ };
150
+ render(/*#__PURE__*/React.createElement(MemoryRouter, {
151
+ initial: "page=4"
152
+ }, /*#__PURE__*/React.createElement(List, null)));
153
+ act(function () {
154
+ return setter('abc');
155
+ });
156
+ expect(url).toBe('page=4&q=abc');
157
+ });
158
+ });
159
+ describe('formatDateForQuery', function () {
160
+ test('локальное время со смещением, без миллисекунд', function () {
161
+ var date = new Date(2026, 0, 2, 3, 4, 5, 678);
162
+ var formatted = formatDateForQuery(date);
163
+ expect(formatted).toMatch(/^2026-01-02T03:04:05[+-]\d{2}:\d{2}$/);
164
+ expect(new Date(formatted).getTime()).toBe(new Date(2026, 0, 2, 3, 4, 5).getTime());
165
+ });
166
+ });
167
+ describe('разборщики', function () {
168
+ test('диапазон дат пишется без времени и читается обратно', function () {
169
+ var range = [new Date(2026, 9, 1, 15, 0), new Date(2026, 9, 31, 9, 0)];
170
+ var query = getQueryStringFromDateArrOrNull(range);
171
+ expect(query).toBe('2026-10-01!!!2026-10-31');
172
+ expect(getDateArrOrNullFromQueryString(query)).toHaveLength(2);
173
+ expect(getDateArrOrNullFromQueryString(null)).toBeNull();
174
+ });
175
+ test('булевы значения', function () {
176
+ expect(booleanFromString('true')).toBe(true);
177
+ expect(booleanFromString('false')).toBe(false);
178
+ expect(booleanFromString(null)).toBeNull();
179
+ });
180
+ });
package/dist/esm/index.js CHANGED
@@ -22,7 +22,9 @@ export { ToastContainer, toast } from './components/common/Toast';
22
22
  export { AppCardLink } from './components/common/AppCardLink';
23
23
  export { InvoiceboxLogo } from './components/common/InvoiceboxLogo';
24
24
  export { QRCode } from './components/common/QRCode';
25
-
25
+ export { Modal, useModalExpansion, modalExpansionFlexItem } from './components/common/Modal';
26
+ export { AdaptiveModalDrawer } from './components/common/AdaptiveModalDrawer';
27
+ export { WentWrongModal, WENT_WRONG_MODAL_DEFAULT_CONTACTS } from './components/common/WentWrongModal';
26
28
  // form
27
29
  export { InputLabel } from './components/form/InputLabel';
28
30
  export { PureInput } from './components/form/PureInput';
@@ -50,5 +52,6 @@ export { useLoadingSubmit } from './hooks/useLoadingSubmit';
50
52
  export { breakpoints } from './breakpoints';
51
53
  export { useMobile, useTablet, useLargeTablet, useMiniLaptop } from './hooks/useMedia';
52
54
  export { useModal } from './hooks/useModal';
55
+ export { useQueryFilter, QueryFilterProvider, DEFAULT_PAGE_PARAM_NAME, DEFAULT_FIRST_PAGE, DATA_SPLITTER, formatDateForQuery, formatDateOnlyForQuery, getDateOrNullFromQueryString, getQueryStringFromDateOrNull, getDateArrOrNullFromQueryString, getQueryStringFromDateArrOrNull, getNumberOrNullFromQueryString, getQueryStringFromNumberOrNull, getQueryStringFromArrayString, getArrayStringsFromQueryString, booleanFromString } from './hooks/useQueryFilter';
53
56
  export { LENGTH_VAT_NUMBER } from './validate/utils/vatNumberValidateHelpers';
54
57
  export { Validate } from './validate';
@@ -33,6 +33,8 @@ import { generateDateTimeInputPalette } from '../components/form/DateTimeInput/p
33
33
  import { generateDrawerHeaderPalette } from '../components/form/common/DrawerHeader/palette';
34
34
  import { generateCheckboxPalette } from '../components/form/Checkbox/palette';
35
35
  import { generateTooltipPalette } from '../components/common/Tooltip/palette';
36
+ import { generateModalPalette } from '../components/common/Modal/palette';
37
+ import { generateWentWrongModalPalette } from '../components/common/WentWrongModal/palette';
36
38
  export var PaletteContext = /*#__PURE__*/createContext({
37
39
  skeleton: generateSkeletonPalette(defaultAbstractPalette),
38
40
  invoiceboxSpinner: generateInvoiceboxSpinnerPalette(defaultAbstractPalette),
@@ -66,5 +68,7 @@ export var PaletteContext = /*#__PURE__*/createContext({
66
68
  dateTimeInput: generateDateTimeInputPalette(defaultAbstractPalette),
67
69
  drawerHeader: generateDrawerHeaderPalette(defaultAbstractPalette),
68
70
  checkbox: generateCheckboxPalette(defaultAbstractPalette),
69
- tooltip: generateTooltipPalette(defaultAbstractPalette)
71
+ tooltip: generateTooltipPalette(defaultAbstractPalette),
72
+ modal: generateModalPalette(defaultAbstractPalette),
73
+ wentWrongModal: generateWentWrongModalPalette(defaultAbstractPalette)
70
74
  });
@@ -40,6 +40,8 @@ import { generateDateTimeInputPalette } from '../components/form/DateTimeInput/p
40
40
  import { generateDrawerHeaderPalette } from '../components/form/common/DrawerHeader/palette';
41
41
  import { generateCheckboxPalette } from '../components/form/Checkbox/palette';
42
42
  import { generateTooltipPalette } from '../components/common/Tooltip/palette';
43
+ import { generateModalPalette } from '../components/common/Modal/palette';
44
+ import { generateWentWrongModalPalette } from '../components/common/WentWrongModal/palette';
43
45
  export var PaletteProvider = function PaletteProvider(_ref) {
44
46
  var children = _ref.children,
45
47
  _abstract = _ref["abstract"],
@@ -84,7 +86,9 @@ export var PaletteProvider = function PaletteProvider(_ref) {
84
86
  dateTimeInput: generateDateTimeInputPalette(mergedAbstractPalette),
85
87
  drawerHeader: generateDrawerHeaderPalette(mergedAbstractPalette),
86
88
  checkbox: generateCheckboxPalette(mergedAbstractPalette),
87
- tooltip: generateTooltipPalette(mergedAbstractPalette)
89
+ tooltip: generateTooltipPalette(mergedAbstractPalette),
90
+ modal: generateModalPalette(mergedAbstractPalette),
91
+ wentWrongModal: generateWentWrongModalPalette(mergedAbstractPalette)
88
92
  };
89
93
  }, [mergedSkeletonPalette, mergedAbstractPalette]);
90
94
  return /*#__PURE__*/React.createElement(PaletteContext.Provider, {
@@ -0,0 +1,35 @@
1
+ import { ReactNode } from 'react';
2
+ export declare const DEFAULT_PAGE_PARAM_NAME = "page";
3
+ export declare const DEFAULT_FIRST_PAGE = 1;
4
+ export type TQueryFilterContext = {
5
+ /** Текущие параметры строки запроса (например, `useSearchParams()[0]` из react-router) */
6
+ searchParams: URLSearchParams;
7
+ /**
8
+ * Записать параметры в адрес. Хук передаёт сюда тот же объект `searchParams`, предварительно
9
+ * изменив его, поэтому реализация обязана довести дело до НОВОГО объекта `searchParams`
10
+ * в следующем рендере (react-router так и делает: пишет адрес и разбирает его заново).
11
+ */
12
+ setSearchParams: (nextSearchParams: URLSearchParams) => void;
13
+ /** Имя параметра страницы, который сбрасывается при смене фильтра. По умолчанию `page` */
14
+ pageParamName: string;
15
+ /** Номер первой страницы. По умолчанию `1` */
16
+ firstPage: number;
17
+ };
18
+ export type TQueryFilterProviderProps = {
19
+ searchParams: URLSearchParams;
20
+ setSearchParams: (nextSearchParams: URLSearchParams) => void;
21
+ pageParamName?: string;
22
+ firstPage?: number;
23
+ children: ReactNode;
24
+ };
25
+ /**
26
+ * Подключает `useQueryFilter` к роутеру приложения. Библиотека от роутера не зависит:
27
+ * приложение само передаёт параметры строки запроса и способ их записать.
28
+ *
29
+ * ```tsx
30
+ * const [searchParams, setSearchParams] = useSearchParams();
31
+ * <QueryFilterProvider searchParams={searchParams} setSearchParams={setSearchParams}>
32
+ * ```
33
+ */
34
+ export declare const QueryFilterProvider: ({ searchParams, setSearchParams, pageParamName, firstPage, children, }: TQueryFilterProviderProps) => import("react/jsx-runtime").JSX.Element;
35
+ export declare const useQueryFilterContext: () => TQueryFilterContext;
@@ -0,0 +1,48 @@
1
+ "use strict";
2
+
3
+ function _typeof(o) { "@babel/helpers - typeof"; return _typeof = "function" == typeof Symbol && "symbol" == typeof Symbol.iterator ? function (o) { return typeof o; } : function (o) { return o && "function" == typeof Symbol && o.constructor === Symbol && o !== Symbol.prototype ? "symbol" : typeof o; }, _typeof(o); }
4
+ Object.defineProperty(exports, "__esModule", {
5
+ value: true
6
+ });
7
+ exports.useQueryFilterContext = exports.QueryFilterProvider = exports.DEFAULT_PAGE_PARAM_NAME = exports.DEFAULT_FIRST_PAGE = void 0;
8
+ var _react = _interopRequireWildcard(require("react"));
9
+ function _interopRequireWildcard(e, t) { if ("function" == typeof WeakMap) var r = new WeakMap(), n = new WeakMap(); return (_interopRequireWildcard = function _interopRequireWildcard(e, t) { if (!t && e && e.__esModule) return e; var o, i, f = { __proto__: null, "default": e }; if (null === e || "object" != _typeof(e) && "function" != typeof e) return f; if (o = t ? n : r) { if (o.has(e)) return o.get(e); o.set(e, f); } for (var _t in e) "default" !== _t && {}.hasOwnProperty.call(e, _t) && ((i = (o = Object.defineProperty) && Object.getOwnPropertyDescriptor(e, _t)) && (i.get || i.set) ? o(f, _t, i) : f[_t] = e[_t]); return f; })(e, t); }
10
+ var DEFAULT_PAGE_PARAM_NAME = exports.DEFAULT_PAGE_PARAM_NAME = 'page';
11
+ var DEFAULT_FIRST_PAGE = exports.DEFAULT_FIRST_PAGE = 1;
12
+ var QueryFilterContext = /*#__PURE__*/(0, _react.createContext)(null);
13
+ /**
14
+ * Подключает `useQueryFilter` к роутеру приложения. Библиотека от роутера не зависит:
15
+ * приложение само передаёт параметры строки запроса и способ их записать.
16
+ *
17
+ * ```tsx
18
+ * const [searchParams, setSearchParams] = useSearchParams();
19
+ * <QueryFilterProvider searchParams={searchParams} setSearchParams={setSearchParams}>
20
+ * ```
21
+ */
22
+ var QueryFilterProvider = exports.QueryFilterProvider = function QueryFilterProvider(_ref) {
23
+ var searchParams = _ref.searchParams,
24
+ setSearchParams = _ref.setSearchParams,
25
+ _ref$pageParamName = _ref.pageParamName,
26
+ pageParamName = _ref$pageParamName === void 0 ? DEFAULT_PAGE_PARAM_NAME : _ref$pageParamName,
27
+ _ref$firstPage = _ref.firstPage,
28
+ firstPage = _ref$firstPage === void 0 ? DEFAULT_FIRST_PAGE : _ref$firstPage,
29
+ children = _ref.children;
30
+ var value = (0, _react.useMemo)(function () {
31
+ return {
32
+ searchParams: searchParams,
33
+ setSearchParams: setSearchParams,
34
+ pageParamName: pageParamName,
35
+ firstPage: firstPage
36
+ };
37
+ }, [searchParams, setSearchParams, pageParamName, firstPage]);
38
+ return /*#__PURE__*/_react["default"].createElement(QueryFilterContext.Provider, {
39
+ value: value
40
+ }, children);
41
+ };
42
+ var useQueryFilterContext = exports.useQueryFilterContext = function useQueryFilterContext() {
43
+ var context = (0, _react.useContext)(QueryFilterContext);
44
+ if (!context) {
45
+ throw new Error('useQueryFilter must be used inside QueryFilterProvider');
46
+ }
47
+ return context;
48
+ };
@@ -0,0 +1,17 @@
1
+ export declare const DATA_SPLITTER = "!!!";
2
+ /**
3
+ * Дата в строку запроса: локальное время со смещением, `yyyy-MM-dd'T'HH:mm:ssxxx`
4
+ * (например, `2026-10-06T19:16:00+07:00`). Миллисекунды отбрасываются.
5
+ */
6
+ export declare const formatDateForQuery: (date: Date) => string;
7
+ /** Дата без времени: `yyyy-MM-dd` по местному времени */
8
+ export declare const formatDateOnlyForQuery: (date: Date) => string;
9
+ export declare const getDateOrNullFromQueryString: (value: string | null) => Date | null;
10
+ export declare const getQueryStringFromDateOrNull: (value: Date | null) => string;
11
+ export declare const getDateArrOrNullFromQueryString: (value: string | null) => [Date, Date] | null;
12
+ export declare const getQueryStringFromDateArrOrNull: (value: [Date, Date] | null) => string;
13
+ export declare const getNumberOrNullFromQueryString: (value: string | null) => number | null;
14
+ export declare const getQueryStringFromNumberOrNull: (value: number | null) => string;
15
+ export declare const getQueryStringFromArrayString: (value: Array<string> | undefined) => string;
16
+ export declare const getArrayStringsFromQueryString: (value: string | null) => string[] | undefined;
17
+ export declare const booleanFromString: (value: string | null) => boolean | null;
@@ -0,0 +1,64 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ exports.getQueryStringFromNumberOrNull = exports.getQueryStringFromDateOrNull = exports.getQueryStringFromDateArrOrNull = exports.getQueryStringFromArrayString = exports.getNumberOrNullFromQueryString = exports.getDateOrNullFromQueryString = exports.getDateArrOrNullFromQueryString = exports.getArrayStringsFromQueryString = exports.formatDateOnlyForQuery = exports.formatDateForQuery = exports.booleanFromString = exports.DATA_SPLITTER = void 0;
7
+ var DATA_SPLITTER = exports.DATA_SPLITTER = '!!!';
8
+ var pad = function pad(value) {
9
+ return String(value).padStart(2, '0');
10
+ };
11
+
12
+ /**
13
+ * Дата в строку запроса: локальное время со смещением, `yyyy-MM-dd'T'HH:mm:ssxxx`
14
+ * (например, `2026-10-06T19:16:00+07:00`). Миллисекунды отбрасываются.
15
+ */
16
+ var formatDateForQuery = exports.formatDateForQuery = function formatDateForQuery(date) {
17
+ var offsetMinutes = -date.getTimezoneOffset();
18
+ var sign = offsetMinutes >= 0 ? '+' : '-';
19
+ var absOffset = Math.abs(offsetMinutes);
20
+ return "".concat(date.getFullYear(), "-").concat(pad(date.getMonth() + 1), "-").concat(pad(date.getDate())) + "T".concat(pad(date.getHours()), ":").concat(pad(date.getMinutes()), ":").concat(pad(date.getSeconds())) + "".concat(sign).concat(pad(Math.floor(absOffset / 60)), ":").concat(pad(absOffset % 60));
21
+ };
22
+
23
+ /** Дата без времени: `yyyy-MM-dd` по местному времени */
24
+ var formatDateOnlyForQuery = exports.formatDateOnlyForQuery = function formatDateOnlyForQuery(date) {
25
+ return "".concat(date.getFullYear(), "-").concat(pad(date.getMonth() + 1), "-").concat(pad(date.getDate()));
26
+ };
27
+ var getDateOrNullFromQueryString = exports.getDateOrNullFromQueryString = function getDateOrNullFromQueryString(value) {
28
+ return value ? new Date(value) : null;
29
+ };
30
+ var getQueryStringFromDateOrNull = exports.getQueryStringFromDateOrNull = function getQueryStringFromDateOrNull(value) {
31
+ return value ? formatDateForQuery(value) : '';
32
+ };
33
+ var getDateArrOrNullFromQueryString = exports.getDateArrOrNullFromQueryString = function getDateArrOrNullFromQueryString(value) {
34
+ if (value) {
35
+ var datesArray = value.split(DATA_SPLITTER).map(function (date) {
36
+ return new Date(date);
37
+ });
38
+ if (datesArray.length === 2) {
39
+ return [datesArray[0], datesArray[1]];
40
+ }
41
+ }
42
+ return null;
43
+ };
44
+ // Диапазон дат хранится в адресе без времени — так он и раньше писался в кабинете
45
+ var getQueryStringFromDateArrOrNull = exports.getQueryStringFromDateArrOrNull = function getQueryStringFromDateArrOrNull(value) {
46
+ return value ? value.map(formatDateOnlyForQuery).join(DATA_SPLITTER) : '';
47
+ };
48
+ var getNumberOrNullFromQueryString = exports.getNumberOrNullFromQueryString = function getNumberOrNullFromQueryString(value) {
49
+ return value ? Number(value) : null;
50
+ };
51
+ var getQueryStringFromNumberOrNull = exports.getQueryStringFromNumberOrNull = function getQueryStringFromNumberOrNull(value) {
52
+ return value ? String(value) : '';
53
+ };
54
+ var getQueryStringFromArrayString = exports.getQueryStringFromArrayString = function getQueryStringFromArrayString(value) {
55
+ return (value === null || value === void 0 ? void 0 : value.join(DATA_SPLITTER)) || '';
56
+ };
57
+ var getArrayStringsFromQueryString = exports.getArrayStringsFromQueryString = function getArrayStringsFromQueryString(value) {
58
+ return value ? value.split(DATA_SPLITTER) : undefined;
59
+ };
60
+ var booleanFromString = exports.booleanFromString = function booleanFromString(value) {
61
+ if (value === 'true') return true;
62
+ if (value === 'false') return false;
63
+ return null;
64
+ };
@@ -0,0 +1,19 @@
1
+ export { QueryFilterProvider, DEFAULT_PAGE_PARAM_NAME, DEFAULT_FIRST_PAGE } from './context';
2
+ export type { TQueryFilterProviderProps } from './context';
3
+ export * from './helpers';
4
+ export type TUseQueryArgumentType = string | Array<string> | undefined | [Date, Date] | null | number | Date | boolean | {
5
+ start: Date;
6
+ end: Date;
7
+ };
8
+ /**
9
+ * Значение фильтра, которое живёт в строке запроса.
10
+ *
11
+ * - `initialValue` записывается в адрес при монтировании, если параметра там ещё нет;
12
+ * пустое значение (`''`, `null`, `undefined`, `[]`) удаляет параметр.
13
+ * - Смена значения сбрасывает номер страницы на первую (`isResetPageWhenChanged`).
14
+ * - Начальное значение можно передавать выражением (`new Date()`, `[]`): хук сравнивает его
15
+ * по строке, которую оно даёт в адресе, а не по ссылке.
16
+ *
17
+ * Нужен `QueryFilterProvider` выше по дереву.
18
+ */
19
+ export declare const useQueryFilter: <T extends TUseQueryArgumentType>(name: string, initialValue: T, fromString?: ((value: string | null) => T) | undefined, toString?: ((value: T) => string) | undefined, isResetPageWhenChanged?: boolean) => [T, (newValue: T) => void];