urfu-ui-kit-react 2.1.5 → 2.1.6

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 (187) hide show
  1. package/dist/components/Accordion/Accordion.d.ts +1 -1
  2. package/dist/components/Accordion/Accordion.d.ts.map +1 -1
  3. package/dist/components/Accordion/Accordion.js +9 -8
  4. package/dist/components/Accordion/Accordion.types.d.ts +2 -0
  5. package/dist/components/Accordion/Accordion.types.d.ts.map +1 -1
  6. package/dist/components/BreadCrumbs/BreadCrumbs.d.ts.map +1 -1
  7. package/dist/components/BreadCrumbs/BreadCrumbs.js +20 -19
  8. package/dist/components/Calendar/Calendar.d.ts.map +1 -1
  9. package/dist/components/Calendar/Calendar.js +145 -144
  10. package/dist/components/Calendar/Calendar.types.d.ts +9 -4
  11. package/dist/components/Calendar/Calendar.types.d.ts.map +1 -1
  12. package/dist/components/Card/Card.d.ts.map +1 -1
  13. package/dist/components/Card/Card.js +37 -31
  14. package/dist/components/ColumnSettings/ColumnSettings.d.ts.map +1 -1
  15. package/dist/components/ColumnSettings/ColumnSettings.js +72 -72
  16. package/dist/components/Drawer/Drawer.d.ts +11 -0
  17. package/dist/components/Drawer/Drawer.d.ts.map +1 -0
  18. package/dist/components/Drawer/Drawer.js +87 -0
  19. package/dist/components/Drawer/Drawer.types.d.ts +44 -0
  20. package/dist/components/Drawer/Drawer.types.d.ts.map +1 -0
  21. package/dist/components/ErrorScreen/ErrorScreen.d.ts.map +1 -1
  22. package/dist/components/ErrorScreen/ErrorScreen.js +172 -138
  23. package/dist/components/FormField/FormField.d.ts +1 -1
  24. package/dist/components/FormField/FormField.d.ts.map +1 -1
  25. package/dist/components/FormField/FormField.js +42 -29
  26. package/dist/components/FormField/FormField.types.d.ts +6 -0
  27. package/dist/components/FormField/FormField.types.d.ts.map +1 -1
  28. package/dist/components/InfiniteScroll/InfiniteScroll.d.ts +22 -0
  29. package/dist/components/InfiniteScroll/InfiniteScroll.d.ts.map +1 -0
  30. package/dist/components/InfiniteScroll/InfiniteScroll.js +27 -0
  31. package/dist/components/InputText/InputText.d.ts +39 -2
  32. package/dist/components/InputText/InputText.d.ts.map +1 -1
  33. package/dist/components/InputText/InputText.js +103 -94
  34. package/dist/components/InputText/InputText.types.d.ts +11 -0
  35. package/dist/components/InputText/InputText.types.d.ts.map +1 -1
  36. package/dist/components/InputTime/inputTimeKeyDown.d.ts +17 -2
  37. package/dist/components/InputTime/inputTimeKeyDown.d.ts.map +1 -1
  38. package/dist/components/InputTime/useInputTimeWheel.d.ts +13 -1
  39. package/dist/components/InputTime/useInputTimeWheel.d.ts.map +1 -1
  40. package/dist/components/Menu/Menu.d.ts.map +1 -1
  41. package/dist/components/Menu/Menu.js +54 -49
  42. package/dist/components/Modal/Modal.d.ts.map +1 -1
  43. package/dist/components/Modal/Modal.js +52 -49
  44. package/dist/components/Modal/Modal.types.d.ts +4 -2
  45. package/dist/components/Modal/Modal.types.d.ts.map +1 -1
  46. package/dist/components/Notification/Notification.d.ts.map +1 -1
  47. package/dist/components/Notification/Notification.js +97 -86
  48. package/dist/components/OfflineBanner/OfflineBanner.d.ts.map +1 -1
  49. package/dist/components/OfflineBanner/OfflineBanner.js +40 -32
  50. package/dist/components/Pagination/Pagination.d.ts.map +1 -1
  51. package/dist/components/Pagination/Pagination.js +61 -66
  52. package/dist/components/SearchSelect/SearchSelect.d.ts.map +1 -1
  53. package/dist/components/SearchSelect/SearchSelect.js +137 -134
  54. package/dist/components/TabPanels/TabPanels.d.ts +13 -0
  55. package/dist/components/TabPanels/TabPanels.d.ts.map +1 -0
  56. package/dist/components/TabPanels/TabPanels.js +8 -0
  57. package/dist/components/Table/Filter/Filter.d.ts.map +1 -1
  58. package/dist/components/Table/Filter/Filter.js +47 -47
  59. package/dist/components/Table/Filter/Filter.types.d.ts +2 -1
  60. package/dist/components/Table/Filter/Filter.types.d.ts.map +1 -1
  61. package/dist/components/Table/Filter/SelectFilter.d.ts.map +1 -1
  62. package/dist/components/Table/Filter/SelectFilter.js +9 -9
  63. package/dist/components/Table/Table.d.ts +1 -1
  64. package/dist/components/Table/Table.d.ts.map +1 -1
  65. package/dist/components/Table/Table.dataPipeline.d.ts +4 -3
  66. package/dist/components/Table/Table.dataPipeline.d.ts.map +1 -1
  67. package/dist/components/Table/Table.dataPipeline.js +64 -63
  68. package/dist/components/Table/Table.js +299 -299
  69. package/dist/components/Table/Table.rowTypes.d.ts +6 -0
  70. package/dist/components/Table/Table.rowTypes.d.ts.map +1 -0
  71. package/dist/components/Table/Table.types.d.ts +10 -3
  72. package/dist/components/Table/Table.types.d.ts.map +1 -1
  73. package/dist/components/Table/TableHead.d.ts +27 -19
  74. package/dist/components/Table/TableHead.d.ts.map +1 -1
  75. package/dist/components/Table/TableHead.js +1 -1
  76. package/dist/components/Table/TableMobileCard.d.ts +11 -11
  77. package/dist/components/Table/TableMobileCard.d.ts.map +1 -1
  78. package/dist/components/Table/TableMobileCard.js +81 -84
  79. package/dist/components/Table/TableMobileView.d.ts +7 -5
  80. package/dist/components/Table/TableMobileView.d.ts.map +1 -1
  81. package/dist/components/Table/TableRow.d.ts +10 -8
  82. package/dist/components/Table/TableRow.d.ts.map +1 -1
  83. package/dist/components/Table/TableRow.js +116 -112
  84. package/dist/components/Table/useTableColumnPinning.d.ts.map +1 -1
  85. package/dist/components/Table/useTableVirtualization.d.ts +5 -5
  86. package/dist/components/Table/useTableVirtualization.d.ts.map +1 -1
  87. package/dist/components/Tabs/Tabs.d.ts +1 -1
  88. package/dist/components/Tabs/Tabs.d.ts.map +1 -1
  89. package/dist/components/Tabs/Tabs.js +109 -104
  90. package/dist/components/Tabs/Tabs.types.d.ts +29 -1
  91. package/dist/components/Tabs/Tabs.types.d.ts.map +1 -1
  92. package/dist/components/Tabs/distributeTabs.d.ts +6 -0
  93. package/dist/components/Tabs/distributeTabs.d.ts.map +1 -1
  94. package/dist/components/Tabs/tabsIndicator.d.ts +7 -3
  95. package/dist/components/Tabs/tabsIndicator.d.ts.map +1 -1
  96. package/dist/components/Tabs/tabsScroll.d.ts +20 -0
  97. package/dist/components/Tabs/tabsScroll.d.ts.map +1 -0
  98. package/dist/components/Tabs/useTabsOverflow.d.ts +3 -1
  99. package/dist/components/Tabs/useTabsOverflow.d.ts.map +1 -1
  100. package/dist/components/Tabs/useTabsOverflow.js +33 -33
  101. package/dist/components/Tabs/useTabsScroll.d.ts +4 -0
  102. package/dist/components/Tabs/useTabsScroll.d.ts.map +1 -0
  103. package/dist/components/Tabs/useTabsScroll.js +17 -0
  104. package/dist/components/Textarea/Textarea.d.ts +22 -2
  105. package/dist/components/Textarea/Textarea.d.ts.map +1 -1
  106. package/dist/components/Textarea/Textarea.js +48 -43
  107. package/dist/components/Textarea/Textarea.types.d.ts +1 -0
  108. package/dist/components/Textarea/Textarea.types.d.ts.map +1 -1
  109. package/dist/components/Tooltip/Tooltip.d.ts +1 -1
  110. package/dist/components/Tooltip/Tooltip.d.ts.map +1 -1
  111. package/dist/components/Tooltip/Tooltip.js +150 -131
  112. package/dist/components/Tooltip/Tooltip.types.d.ts +7 -2
  113. package/dist/components/Tooltip/Tooltip.types.d.ts.map +1 -1
  114. package/dist/components/TreeView/TreeView.js +95 -95
  115. package/dist/components/TreeView/TreeView.types.d.ts +1 -1
  116. package/dist/components/TreeView/TreeView.types.d.ts.map +1 -1
  117. package/dist/components/VirtualList/VirtualList.d.ts +45 -0
  118. package/dist/components/VirtualList/VirtualList.d.ts.map +1 -0
  119. package/dist/components/VirtualList/VirtualList.js +62 -0
  120. package/dist/dev/index.js +1306 -584
  121. package/dist/dev/types/react/src/dev/index.d.ts +1 -1
  122. package/dist/dev/types/vanilla/src/core/motion.d.ts +41 -0
  123. package/dist/dev/types/vanilla/src/core/requestLog.d.ts +29 -0
  124. package/dist/dev/types/vanilla/src/dev/highlight.d.ts +32 -0
  125. package/dist/dev/types/vanilla/src/dev/intercept.d.ts +4 -1
  126. package/dist/dev/types/vanilla/src/dev/motionModes.d.ts +30 -0
  127. package/dist/dev/types/vanilla/src/dev/panelKit.d.ts +49 -0
  128. package/dist/dev/types/vanilla/src/dev/panelStyles.d.ts +7 -0
  129. package/dist/dev/types/vanilla/src/dev/rules.d.ts +31 -0
  130. package/dist/dev/types/vanilla/src/dev/store.d.ts +7 -4
  131. package/dist/dev/types/vanilla/src/dev/types.d.ts +14 -3
  132. package/dist/dev/types/vanilla/src/dev/viewModes.d.ts +22 -0
  133. package/dist/hooks/useCollapseMotion.d.ts +18 -0
  134. package/dist/hooks/useCollapseMotion.d.ts.map +1 -0
  135. package/dist/hooks/useCollapseMotion.js +9 -0
  136. package/dist/hooks/useDismiss.d.ts +7 -1
  137. package/dist/hooks/useDismiss.d.ts.map +1 -1
  138. package/dist/hooks/useDismiss.js +19 -17
  139. package/dist/hooks/useEnterMotion.d.ts +9 -0
  140. package/dist/hooks/useEnterMotion.d.ts.map +1 -0
  141. package/dist/hooks/useEnterMotion.js +10 -0
  142. package/dist/hooks/useForwardedRef.d.ts +8 -0
  143. package/dist/hooks/useForwardedRef.d.ts.map +1 -0
  144. package/dist/hooks/useForwardedRef.js +8 -0
  145. package/dist/hooks/useInfiniteScroll.d.ts +27 -0
  146. package/dist/hooks/useInfiniteScroll.d.ts.map +1 -0
  147. package/dist/hooks/useInfiniteScroll.js +13 -0
  148. package/dist/hooks/useMountTransition.d.ts +1 -1
  149. package/dist/hooks/useMountTransition.d.ts.map +1 -1
  150. package/dist/hooks/useMountTransition.js +14 -13
  151. package/dist/hooks/useVirtualList.d.ts +34 -0
  152. package/dist/hooks/useVirtualList.d.ts.map +1 -0
  153. package/dist/hooks/useVirtualList.js +21 -0
  154. package/dist/index.d.ts +15 -1
  155. package/dist/index.d.ts.map +1 -1
  156. package/dist/shared/collapseMotion.d.ts +32 -0
  157. package/dist/shared/collapseMotion.d.ts.map +1 -0
  158. package/dist/shared/infiniteScroll.d.ts +42 -0
  159. package/dist/shared/infiniteScroll.d.ts.map +1 -0
  160. package/dist/shared/kitCopy.js +1 -1
  161. package/dist/shared/linkClick.d.ts +7 -0
  162. package/dist/shared/linkClick.d.ts.map +1 -0
  163. package/dist/shared/motion.d.ts +42 -0
  164. package/dist/shared/motion.d.ts.map +1 -0
  165. package/dist/shared/popupTransition.d.ts +10 -2
  166. package/dist/shared/popupTransition.d.ts.map +1 -1
  167. package/dist/shared/popupTransition.js +6 -5
  168. package/dist/shared/virtualList.d.ts +103 -0
  169. package/dist/shared/virtualList.d.ts.map +1 -0
  170. package/dist/style-no-fonts.css +1 -1
  171. package/dist/style.css +1 -1
  172. package/dist/style.layer.css +2 -2
  173. package/dist/style.shell.css +5 -5
  174. package/dist/urfu-ui-kit-react.js +53 -45
  175. package/dist/utils/describeError.d.ts +12 -1
  176. package/dist/utils/describeError.d.ts.map +1 -1
  177. package/dist/vanilla/core/collapseMotion.js +58 -0
  178. package/dist/vanilla/core/describeError.js +172 -115
  179. package/dist/vanilla/core/distributeTabs.js +23 -20
  180. package/dist/vanilla/core/infiniteScroll.js +79 -0
  181. package/dist/vanilla/core/linkClick.js +2 -0
  182. package/dist/vanilla/core/motion.js +29 -0
  183. package/dist/vanilla/core/requestLog.js +40 -0
  184. package/dist/vanilla/core/tabsIndicator.js +29 -26
  185. package/dist/vanilla/core/tabsScroll.js +29 -0
  186. package/dist/vanilla/core/virtualList.js +213 -0
  187. package/package.json +1 -1
@@ -12,4 +12,4 @@ export declare function useDevFault(id: string, service?: string): boolean;
12
12
  export declare function DevCrashProbe({ scope, service }: {
13
13
  scope: 'app' | 'page';
14
14
  service?: string;
15
- }): any;
15
+ }): null;
@@ -0,0 +1,41 @@
1
+ /**
2
+ * Шкала движения кита в миллисекундах — те же числа, что у `--u-duration-*` в
3
+ * styles/const/tokens-scale.less (сверяет тест react/src/shared/motion.test.ts).
4
+ * Нужна там, где анимацию ведёт JS (WAAPI, таймер размонтирования): CSS-переменную
5
+ * в `element.animate()` не передать.
6
+ */
7
+ export declare const MOTION_MS: {
8
+ readonly instant: 100;
9
+ readonly fast: 150;
10
+ readonly base: 200;
11
+ readonly moderate: 250;
12
+ readonly slow: 300;
13
+ };
14
+ /** Кривые шкалы — те же, что у `--u-ease-*`. */
15
+ export declare const MOTION_EASE: {
16
+ readonly standard: "ease-in-out";
17
+ readonly move: "cubic-bezier(.2, 0, 0, 1)";
18
+ readonly enter: "cubic-bezier(0, 0, .2, 1)";
19
+ readonly exit: "cubic-bezier(.4, 0, 1, 1)";
20
+ readonly sheet: "cubic-bezier(.22, 1, .36, 1)";
21
+ };
22
+ /** Сдвиг при появлении, px — как `--u-motion-shift-sm`. */
23
+ export declare const MOTION_SHIFT_SM = 4;
24
+ /**
25
+ * Атрибуты на `<html>`, которыми dev-панель включает режимы «Вид» на всю страницу —
26
+ * их видят все копии кита (оболочка, сервисы, песочница qiankun), в отличие от переменной модуля.
27
+ */
28
+ export declare const MOTION_REDUCE_ATTR = "data-u-motion";
29
+ export declare const MOTION_SCALE_ATTR = "data-u-motion-scale";
30
+ /** Системная настройка «уменьшить движение» или её эмуляция из dev-панели (`data-u-motion="reduce"`). */
31
+ export declare const prefersReducedMotion: () => boolean;
32
+ /** Множитель длительностей: 1, а в режиме dev-панели «Анимации ×5» — 5. */
33
+ export declare const motionScale: () => number;
34
+ /** Ставит или (при 1) снимает множитель длительностей — только для dev-панели. */
35
+ export declare const setMotionScale: (scale: number) => void;
36
+ /**
37
+ * Длительность для JS-анимации с учётом множителя: шаг шкалы или своё число мс.
38
+ * `MOTION_MS` читать напрямую там, где анимацию ведёт JS, не стоит — не заметит «×5».
39
+ */
40
+ export declare const motionMs: (duration: keyof typeof MOTION_MS | number) => number;
41
+ export declare const playEnterMotion: (element: HTMLElement | null | undefined) => (() => void);
@@ -0,0 +1,29 @@
1
+ /**
2
+ * Журнал последних запросов для расширенных подробностей ошибки («Дополнительные сведения»).
3
+ *
4
+ * Читает Resource Timing (`PerformanceObserver`), а не подменяет `fetch` и XHR: ни тел, ни заголовков,
5
+ * ни токенов такой журнал по устройству не видит. Из адреса вырезаны query и hash. Запускают его
6
+ * `configureErrorReport({ diagnostics: true })` и dev-панель (у неё своя копия в сборке `/dev`);
7
+ * сам по себе модуль при импорте ничего не делает.
8
+ */
9
+ export interface RequestLogEntry {
10
+ /** Время начала запроса, мс с эпохи. */
11
+ time: number;
12
+ /** Путь без query и hash; у чужого хоста — с хостом. */
13
+ path: string;
14
+ /** Код ответа. Браузер отдаёт его не везде: у чужого хоста без Timing-Allow-Origin — 0. */
15
+ status?: number;
16
+ /** Длительность, мс. */
17
+ duration: number;
18
+ }
19
+ /** Сколько последних запросов помним. */
20
+ export declare const REQUEST_LOG_SIZE = 10;
21
+ /** Путь запроса для отчёта: без query и hash; хост остаётся, только если он не свой. */
22
+ export declare function sanitizeRequestUrl(raw: string, page?: string): string;
23
+ /** Последние запросы, старые первыми. */
24
+ export declare function getRequestLog(): readonly RequestLogEntry[];
25
+ /**
26
+ * Запустить журнал. Возвращает остановку; без `PerformanceObserver` (jsdom, старые браузеры)
27
+ * ничего не делает и не бросает.
28
+ */
29
+ export declare function startRequestLog(): () => void;
@@ -0,0 +1,32 @@
1
+ /**
2
+ * Подсветка «не из кита» (dev-панель, «Вид»): рамкой отмечены видимые кнопки, поля, ссылки,
3
+ * таблицы, окна, svg и заголовки, свёрстанные сервисом мимо компонентов кита.
4
+ *
5
+ * Из кита — элемент с классом компонента кита или лежащий внутри такого. Содержимое, которое
6
+ * сервис кладёт в слот компонента (тело Modal, Drawer, Card, ячейка таблицы), — снова сервиса.
7
+ * Утилиты (`u-fw`, `u-focus-ring`, типографика `.h5`, отступы) китом не считаются: ими
8
+ * оформляют свою вёрстку. Список префиксов сверяет со стилями кита тест kitClasses.
9
+ */
10
+ /** Префиксы классов компонентов: `u-<префикс>`, `u-<префикс>-…`, `u-<префикс>__…`. */
11
+ export declare const KIT_PREFIXES: readonly ["accordion", "bc", "breadcrumbs", "button", "calendar", "card", "checkbox", "collapsible", "drawer", "empty", "error", "expand", "file", "filter", "form", "help", "icon", "infinite", "input", "menu", "message", "modal", "multiselectbox", "notification", "number", "offline", "pagination", "paginator", "password", "popup", "preloader", "radio", "react", "rich", "search", "selectbox", "skeleton", "status", "switch", "tab", "table", "tabs", "textarea", "upward", "virtual"];
12
+ /** Классы без префикса `u-`, которые рисует сам кит: календарь air-datepicker, дерево TreeView, список фильтра. */
13
+ export declare const KIT_UNPREFIXED: readonly ["air-datepicker", "treeview", "select-column"];
14
+ /** Слоты: внутри — содержимое сервиса, хотя вокруг компонент кита. */
15
+ export declare const KIT_SLOTS: readonly ["u-card", "u-card-second", "u-react-card__body", "u-modal__body", "u-drawer__body", "u-drawer__footer", "u-form-field__control", "u-accordion-content", "u-collapsible-menu-body", "u-help__content", "u-message", "u-react-sticky-action-bar", "u-tabs-content", "u-table-mobile-card__fields--body", "u-table-mobile-card__actions", "u-virtual-list__item"];
16
+ export declare const isKitClass: (name: string) => boolean;
17
+ /** Ближайшее решает: класс кита — из кита; слот или ячейка таблицы — содержимое сервиса. */
18
+ export declare const isFromKit: (element: Element) => boolean;
19
+ export declare const HIGHLIGHT_SELECTOR = "button, input, select, textarea, a[href], table, [role=\"dialog\"], dialog, svg, h1, h2, h3, h4, h5, h6";
20
+ /** Группа для счётчика. */
21
+ export declare const highlightType: (element: Element) => string;
22
+ /** Кандидаты в отметку: не из кита, не панель, не svg внутри svg и не скрытое поле. */
23
+ export declare const findForeign: (scope?: ParentNode) => Element[];
24
+ /** Путь для консоли: `main > div.cards > button.save:nth-of-type(2)`, до ближайшего id. */
25
+ export declare const selectorPath: (element: Element) => string;
26
+ export interface HighlightStats {
27
+ total: number;
28
+ byType: Record<string, number>;
29
+ }
30
+ export declare const highlightStats: () => HighlightStats;
31
+ export declare const enableHighlight: (onStats?: (stats: HighlightStats) => void) => HighlightStats;
32
+ export declare const disableHighlight: () => void;
@@ -14,7 +14,10 @@ export type DevDecision = {
14
14
  kind: 'pass';
15
15
  delay: number;
16
16
  };
17
- /** Путь запроса после `apiBase`; `null` — запрос не к API этого сервиса. */
17
+ /**
18
+ * Путь запроса после `apiBase`; `null` — запрос не к API этого сервиса. Абсолютный `apiBase`
19
+ * (`https://api.example.ru/api/v1`) сверяется и с хостом: тот же префикс на другом домене — чужой запрос.
20
+ */
18
21
  export declare function apiPath(url: string, apiBase?: string): string | null;
19
22
  /** Шаблон пути: `*` — один сегмент, `**` — любое число сегментов. */
20
23
  export declare function matchPath(pattern: string, path: string): boolean;
@@ -0,0 +1,30 @@
1
+ export declare const MOTION_SLOW_FACTOR = 5;
2
+ export interface ReducedMotionStats {
3
+ /** Скопировано блоков `@media (prefers-reduced-motion: reduce)`. */
4
+ blocks: number;
5
+ /** Выключено блоков `no-preference`. */
6
+ disabled: number;
7
+ /** Таблиц стилей, правила которых браузер не отдаёт (чужой домен без CORS). */
8
+ blocked: number;
9
+ }
10
+ /**
11
+ * Условие копии вместо `@media` с RM: '' — без условия, null — блок к RM не относится.
12
+ * Из списка через запятую берутся только варианты с RM: остальные и так действуют сами.
13
+ */
14
+ export declare const reducedMediaCondition: (mediaText: string) => string | null;
15
+ /**
16
+ * Запрос блока на время режима: такие варианты списка — `not all`, остальные (`print`) прежние;
17
+ * null — выключать нечего.
18
+ */
19
+ export declare const disabledMediaText: (mediaText: string) => string | null;
20
+ export declare const reducedMotionStats: () => ReducedMotionStats;
21
+ /** Включает эмуляцию: правила RM из всех стилей страницы действуют без условия, `data-u-motion="reduce"` — для JS. */
22
+ export declare const enableReducedMotion: (listener?: (stats: ReducedMotionStats) => void) => ReducedMotionStats;
23
+ export declare const disableReducedMotion: () => void;
24
+ /**
25
+ * CSS-переменные — на каждый элемент с `!important`, а не только на `:root`: оболочка ЛК ставит
26
+ * свои токены на ветки разметки, и значение с `:root` до её компонентов бы не дошло.
27
+ * JS-анимации кита берут множитель из `data-u-motion-scale` (`motionMs`).
28
+ */
29
+ export declare const enableSlowMotion: () => void;
30
+ export declare const disableSlowMotion: () => void;
@@ -0,0 +1,49 @@
1
+ /**
2
+ * Контролы dev-панели — разметкой компонентов кита (Switch, Select, Search, InputNumber, Tabs, Button):
3
+ * панель выглядит и ведёт себя как сервис, своих полей и переключателей у неё нет.
4
+ * Панель живёт в Shadow DOM, классы документа внутрь не проходят: CSS этих компонентов приходит
5
+ * копией в KIT.css (отбор — tools/styles/dev-panel-css.mjs, подставляет vite.dev.config пакета).
6
+ */
7
+ /** Стили кита для панели. Без dev-сборки (тесты) — пусто: разметка та же, вида нет. */
8
+ export declare const KIT: {
9
+ css: string;
10
+ hostAttrs: string[];
11
+ };
12
+ export declare const escape: (value: unknown) => string;
13
+ /** Switch кита: переключатель слева, подпись справа, под ней — пояснение. `attrs` — готовые атрибуты input. */
14
+ export declare function switchRow(label: string, attrs: string, hint?: string): string;
15
+ /** Button кита: `kind` — outline, simple, text, text-danger; `attrs` — data-* и прочее. */
16
+ export declare function button(text: string, kind: 'primary' | 'outline' | 'simple' | 'text' | 'text-danger', attrs: string, type?: string): string;
17
+ /** Кнопка-иконка кита (крестик закрытия, удаления). */
18
+ export declare function iconButton(icon: string, label: string, attrs: string): string;
19
+ /** Search кита: лупа слева, крестик очистки, пока есть текст. */
20
+ export declare function search(value: string, placeholder: string, label: string): string;
21
+ /** InputNumber кита: «−» и «+» по бокам; шаг — `stepNumber` по клику на `[data-step]`. */
22
+ export declare function number(label: string, attrs: string): string;
23
+ export declare function stepNumber(trigger: HTMLElement): void;
24
+ /** FormField кита: подпись сверху, контрол, подсказка снизу. */
25
+ export declare function field(title: string, control: string, hint?: string, className?: string): string;
26
+ /** Tabs кита, вариант segment на всю ширину. */
27
+ export declare function tabs(items: {
28
+ id: string;
29
+ title: string;
30
+ }[], active: string): string;
31
+ export interface SelectOption {
32
+ value: string;
33
+ label: string;
34
+ }
35
+ /**
36
+ * Select кита (`.u-selectbox`). Значение — в скрытом поле: `name` для формы или data-атрибут (`data-service`),
37
+ * на нём же панель слушает `change`. Сброс формы скрытое поле не возвращает — для этого `resetSelects`.
38
+ */
39
+ export declare function select(key: string, label: string, options: SelectOption[], value: string, fieldAttrs: string): string;
40
+ export declare function syncSelects(scope: ParentNode): void;
41
+ export declare function resetSelects(scope: ParentNode): void;
42
+ export declare const openSelectOf: (scope: ParentNode) => HTMLElement;
43
+ /** Открыть список; не помещается под полем в прокручиваемом теле панели — раскрывается вверх. */
44
+ export declare function setSelectOpen(trigger: HTMLElement, open: boolean): void;
45
+ export declare function closeSelects(scope: ParentNode): void;
46
+ /** Выбор пункта: значение в скрытое поле, фокус на поле, `change` — обработчику панели. */
47
+ export declare function chooseOption(option: HTMLElement): void;
48
+ /** Клавиатура на поле выбора, как у Select кита. Escape обрабатывает панель (`onKey`): он закрывает список, а не её. */
49
+ export declare function onSelectKey(event: KeyboardEvent, trigger: HTMLElement): void;
@@ -0,0 +1,7 @@
1
+ /**
2
+ * Стили dev-панели поверх CSS кита (KIT.css из panelKit): контролы — классы компонентов кита,
3
+ * здесь только раскладка панели и то, чего в ките нет (кнопка Dev, строки правил и запросов,
4
+ * список «ключ — значение»). Цвета, радиусы, тени и движение — токены кита (`--u-*`):
5
+ * CSS-переменные документа проходят в Shadow DOM, `all: initial` их не сбрасывает.
6
+ */
7
+ export declare const STYLES = "\n:host { all: initial; }\n* { box-sizing: border-box; }\n.root {\n /* \u00AB\u0410\u043D\u0438\u043C\u0430\u0446\u0438\u0438 \u00D75\u00BB \u0441\u0442\u0430\u0432\u0438\u0442 \u0434\u043B\u0438\u0442\u0435\u043B\u044C\u043D\u043E\u0441\u0442\u0438 \u043D\u0430 \u043A\u0430\u0436\u0434\u044B\u0439 \u044D\u043B\u0435\u043C\u0435\u043D\u0442 \u0434\u043E\u043A\u0443\u043C\u0435\u043D\u0442\u0430, \u0432 \u0442\u043E\u043C \u0447\u0438\u0441\u043B\u0435 \u043D\u0430 \u0445\u043E\u0441\u0442 \u043F\u0430\u043D\u0435\u043B\u0438:\n \u0440\u0435\u0436\u0438\u043C \u0437\u0430\u043C\u0435\u0434\u043B\u044F\u0435\u0442 \u0441\u0435\u0440\u0432\u0438\u0441, \u0430 \u043D\u0435 \u0438\u043D\u0441\u0442\u0440\u0443\u043C\u0435\u043D\u0442, \u043A\u043E\u0442\u043E\u0440\u044B\u043C \u0435\u0433\u043E \u0432\u043A\u043B\u044E\u0447\u0438\u043B\u0438. */\n --u-duration-instant: 100ms; --u-duration-fast: 150ms; --u-duration-base: 200ms; --u-duration-moderate: 250ms; --u-duration-slow: 300ms;\n /* \u041E\u0442\u0441\u0442\u0443\u043F \u043A\u043D\u043E\u043F\u043A\u0438 \u0441\u043D\u0438\u0437\u0443: StickyActionBar \u043A\u0438\u0442\u0430, \u043F\u043E\u043A\u0430 \u0441\u0442\u043E\u0438\u0442 \u0443 \u043D\u0438\u0436\u043D\u0435\u0433\u043E \u043A\u0440\u0430\u044F, \u0437\u0430\u0434\u0430\u0451\u0442 \u043D\u0430 <html>\n --u-dev-launcher-bottom (\u0435\u0433\u043E \u0432\u044B\u0441\u043E\u0442\u0430 + 12px) \u2014 \u043A\u043D\u043E\u043F\u043A\u0430 \u0438 \u043F\u0430\u043D\u0435\u043B\u044C \u043F\u043E\u0434\u043D\u0438\u043C\u0430\u044E\u0442\u0441\u044F \u043D\u0430\u0434 \u043D\u0438\u043C. */\n --launcher-bottom: var(--u-dev-launcher-bottom, calc(12px + env(safe-area-inset-bottom, 0px)));\n font-family: Montserrat, \"Segoe UI\", Arial, sans-serif; font-size: 14px; line-height: 1.4; color: var(--u-color-text, #222); }\nbutton, input, textarea { font: inherit; color: inherit; }\n/* \u041A\u043D\u043E\u043F\u043A\u0430 \u043F\u0430\u043D\u0435\u043B\u0438 \u2014 \u0432 \u0446\u0432\u0435\u0442\u0430\u0445 \u043A\u0438\u0442\u0430: \u0442\u043E\u043A\u0435\u043D\u044B --u-color-* \u0441 :root \u0441\u0435\u0440\u0432\u0438\u0441\u0430 \u043F\u0440\u043E\u0445\u043E\u0434\u044F\u0442 \u0432 shadow DOM\n (all: initial \u0438\u0445 \u043D\u0435 \u0441\u0431\u0440\u0430\u0441\u044B\u0432\u0430\u0435\u0442), \u0437\u0430\u043F\u0430\u0441\u043D\u044B\u0435 \u0437\u043D\u0430\u0447\u0435\u043D\u0438\u044F \u2014 \u043A\u0430\u043A \u0432 \u043A\u0438\u0442\u0435. \u0412 \u043F\u043E\u043A\u043E\u0435 \u2014 \u043A\u0440\u0443\u0433 \u0441 \u043B\u043E\u0433\u043E\u0442\u0438\u043F\u043E\u043C,\n \u0447\u0442\u043E\u0431\u044B \u043C\u0435\u043D\u044C\u0448\u0435 \u0437\u0430\u043A\u0440\u044B\u0432\u0430\u0442\u044C \u043D\u0438\u0436\u043D\u0438\u0435 \u043B\u0438\u043F\u043A\u0438\u0435 \u043F\u0430\u043D\u0435\u043B\u0438 \u0441\u0435\u0440\u0432\u0438\u0441\u0430; \u043F\u0440\u0438 \u043D\u0430\u0432\u0435\u0434\u0435\u043D\u0438\u0438 \u0438 \u0444\u043E\u043A\u0443\u0441\u0435 \u0440\u0430\u0441\u043A\u0440\u044B\u0432\u0430\u0435\u0442\u0441\u044F\n \u0432 \u00AB\u043B\u043E\u0433\u043E\u0442\u0438\u043F + Dev\u00BB; \u043F\u0440\u0438 \u0432\u043A\u043B\u044E\u0447\u0451\u043D\u043D\u044B\u0445 \u0441\u0431\u043E\u044F\u0445 \u0440\u0430\u0441\u043A\u0440\u044B\u0442\u0430 \u0432\u0441\u0435\u0433\u0434\u0430, \u0446\u0432\u0435\u0442 \u043E\u0448\u0438\u0431\u043A\u0438 \u0438 \u0447\u0438\u0441\u043B\u043E \u0441\u0431\u043E\u0435\u0432. */\n.pill { --kit-p: var(--u-color-primary, #1e4391); --kit-error: var(--u-color-error, #ef302b);\n --kit-surface: var(--u-color-surface, #fff); --kit-line: var(--u-color-border, #748ab9);\n position: fixed; left: 12px; bottom: var(--launcher-bottom); z-index: 2147483000;\n display: inline-flex; align-items: center; height: 36px; padding: 0; border: 1px solid var(--kit-line); border-radius: 18px;\n background: var(--kit-surface); color: var(--kit-p); font-size: 13px; font-weight: 500; white-space: nowrap; cursor: pointer;\n box-shadow: 0 2px 8px rgba(0,0,0,.15);\n transition: background-color var(--u-duration-fast) var(--u-ease-standard), border-color var(--u-duration-fast) var(--u-ease-standard); }\n.pill .logo { flex: none; display: grid; place-items: center; width: 34px; height: 34px; border-radius: 50%; background: var(--kit-surface); }\n.pill .logo svg { display: block; width: 20px; height: 20px; }\n.pill .label { max-width: 0; overflow: hidden; opacity: 0; padding: 0;\n transition: max-width var(--u-duration-base) var(--u-ease-move), opacity var(--u-duration-base) var(--u-ease-move), padding var(--u-duration-base) var(--u-ease-move); }\n.pill:hover .label, .pill:focus-visible .label, .pill.on .label { max-width: 260px; opacity: 1; padding: 0 14px 0 2px; }\n.pill.on { background: var(--kit-error); border-color: var(--kit-error); color: #fff; }\n.pill.on .logo { width: 30px; height: 30px; margin: 0 1px 0 2px; }\n.pill:focus-visible { outline: 2px solid var(--kit-p); outline-offset: 2px; }\n.panel { position: fixed; left: 12px; bottom: calc(var(--launcher-bottom) + 44px); z-index: 2147483001;\n width: 400px; max-width: calc(100vw - 24px); max-height: min(75vh, 680px); display: flex; flex-direction: column;\n background: var(--u-color-surface, #fff); border: 1px solid var(--u-color-border-light, #d3d3d3); border-radius: var(--u-radius, 10px);\n box-shadow: var(--u-shadow-popup, 0 8px 24px rgba(15,43,94,.16)); }\n.panel.alone { bottom: var(--launcher-bottom); }\n/* \u041F\u043E\u0434\u0441\u043A\u0430\u0437\u043A\u0430 \u0443 \u043A\u043D\u043E\u043F\u043A\u0438 \u2014 \u043F\u0443\u0437\u044B\u0440\u044C, \u043A\u0430\u043A \u0443 Tooltip \u043A\u0438\u0442\u0430. */\n.hint { position: fixed; left: 12px; bottom: var(--launcher-bottom); z-index: 2147483000;\n max-width: min(360px, calc(100vw - 24px)); padding: 8px 12px; border-radius: var(--u-radius-small, 8px);\n background: var(--u-color-text, #222); color: var(--u-color-surface, #fff); font-size: 12px; box-shadow: var(--u-shadow-popup); }\n.pill ~ .hint { bottom: calc(var(--launcher-bottom) + 44px); }\n/* min-height \u0443 u-message-small \u043E\u0442\u043C\u0435\u043D\u044F\u0435\u0442 \u0437\u0430\u0449\u0438\u0442\u0443 \u0444\u043B\u0435\u043A\u0441-\u044D\u043B\u0435\u043C\u0435\u043D\u0442\u0430 \u043E\u0442 \u0441\u0436\u0430\u0442\u0438\u044F: \u0431\u0435\u0437 flex-shrink \u0442\u0435\u043A\u0441\u0442 \u043E\u0431\u0440\u0435\u0437\u0430\u0435\u0442\u0441\u044F. */\n.note { margin: 0 16px 8px; overflow-wrap: anywhere; flex-shrink: 0; }\n.head { display: flex; align-items: center; gap: 4px; padding: 10px 8px 2px 16px; }\n.title { flex: 1; min-width: 0; font-weight: 600; font-size: 16px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }\n.title .u-selectbox { width: 100%; }\n.title .u-selectbox-select-title { font-weight: 600; }\n.intro, .caption, .escape { margin: 0; color: var(--u-color-text-secondary, #545454); }\n.intro { padding: 0 16px 10px; }\n.tabs { padding: 0 16px 8px; }\n.tabs .u-tab-segment { padding: 6px 4px; }\n.body { overflow: auto; padding: 4px 16px 12px; display: flex; flex-direction: column; gap: 14px; }\n.body .u-search { display: block; width: 100%; }\n.group { display: flex; flex-direction: column; gap: 8px; }\n.group-title { font-weight: 600; color: var(--u-color-text-secondary, #545454); }\n.u-switch { align-items: flex-start; }\n.u-switch .tt { padding-top: 3px; }\n.u-switch .sub { display: block; color: var(--u-color-text-secondary, #545454); font-size: 12px; }\n/* Select \u043A\u0438\u0442\u0430: \u043E\u0442\u043C\u0435\u0442\u043A\u0430 \u0432\u044B\u0431\u0440\u0430\u043D\u043D\u043E\u0433\u043E \u0438 \u043F\u0443\u043D\u043A\u0442\u0430 \u043F\u043E\u0434 \u043A\u043B\u0430\u0432\u0438\u0430\u0442\u0443\u0440\u043E\u0439 \u2014 \u043A\u0430\u043A \u0443 Select \u0432 React \u0438 Vue. */\n.u-selectbox-option[aria-selected=\"true\"] { background: var(--u-color-background, #f6f6f6); }\n.u-selectbox-option.active { background: var(--u-color-selected, #e7f2ff); }\n.u-selectbox-select-icon-arrow { transition: transform var(--u-duration-fast) var(--u-ease-standard); }\n.u-selectbox-select-open .u-selectbox-select-icon-arrow { transform: rotate(180deg); }\n.rule { display: flex; align-items: center; gap: 10px; padding: 6px 4px 6px 10px; border-radius: var(--u-radius-small, 8px);\n background: var(--u-color-background-light, #f9f9f9); }\n.rule .text { flex: 1; min-width: 0; font-family: Consolas, monospace; font-size: 12px; overflow-wrap: anywhere; }\n.rule small, .req small, .shown small { display: block; color: var(--u-color-text-secondary, #545454);\n font-family: Montserrat, \"Segoe UI\", Arial, sans-serif; font-size: 12px; }\n.add { display: grid; grid-template-columns: 1fr 1fr; gap: 10px 8px; }\n.add .wide { grid-column: 1 / -1; }\n.add .u-textarea { height: auto; min-height: 76px; font-family: Consolas, monospace; font-size: 12px; resize: vertical; }\n.add .u-form-field__hint { color: var(--u-color-warning, #e98446); }\n.add [type=\"submit\"] { align-self: end; }\n.foot { display: flex; flex-direction: column; gap: 8px; padding: 10px 16px 12px; border-top: 1px solid var(--u-color-border-light, #d3d3d3); }\n.actions { display: flex; gap: 8px; flex-wrap: wrap; }\n.empty { margin: 0; color: var(--u-color-text-secondary, #545454); }\n.list-head { display: flex; align-items: center; justify-content: space-between; gap: 8px; color: var(--u-color-text-secondary, #545454); }\n.requests { display: flex; flex-direction: column; }\n.req { display: grid; grid-template-columns: 52px 1fr auto auto; gap: 8px; align-items: center; padding: 6px 0;\n border-bottom: 1px solid var(--u-color-background, #f6f6f6); font-family: Consolas, monospace; font-size: 12px; }\n.req .path { min-width: 0; overflow-wrap: break-word; }\n/* \u041F\u0443\u0442\u044C \u043F\u0435\u0440\u0435\u043D\u043E\u0441\u0438\u0442\u0441\u044F \u043F\u043E \u00AB/\u00BB (<wbr>), \u0430 \u043D\u0435 \u043F\u043E\u0441\u0440\u0435\u0434\u0438 \u0441\u043B\u043E\u0432\u0430; \u0434\u043B\u0438\u043D\u043D\u044B\u0439 \u043E\u0431\u0440\u0435\u0437\u0430\u0435\u0442\u0441\u044F \u043D\u0430 \u0432\u0442\u043E\u0440\u043E\u0439 \u0441\u0442\u0440\u043E\u043A\u0435, \u043F\u043E\u043B\u043D\u044B\u0439 \u2014 \u0432 title. */\n.req .path .p { display: -webkit-box; -webkit-box-orient: vertical; -webkit-line-clamp: 2; line-clamp: 2; overflow: hidden; }\n.req .u-status { font-family: Montserrat, \"Segoe UI\", Arial, sans-serif; }\n.shown { padding: 8px 0; border-bottom: 1px solid var(--u-color-background, #f6f6f6); }\n.shown-head { display: flex; justify-content: space-between; gap: 8px; color: var(--u-color-text-secondary, #545454); font-size: 12px; }\n.shown-head .kind { font-weight: 600; color: var(--u-color-error, #ef302b); }\n.shown-head .kind.warning { color: var(--u-color-warning, #e98446); }\n.shown-title { font-weight: 600; }\n.shown .cause { margin-top: 2px; font-family: Consolas, monospace; font-size: 12px; }\ndl { display: grid; grid-template-columns: auto 1fr; gap: 6px 12px; margin: 0; }\ndt { color: var(--u-color-text-secondary, #545454); }\ndd { margin: 0; font-family: Consolas, monospace; font-size: 12px; overflow-wrap: anywhere; }\n@media (max-width: 576px) {\n .panel { left: 0; right: 0; bottom: 0; width: auto; max-width: none; max-height: 80vh;\n border-radius: var(--u-radius, 10px) var(--u-radius, 10px) 0 0; padding-bottom: env(safe-area-inset-bottom, 0px); }\n .panel ~ .pill { display: none; }\n}\n@media (prefers-reduced-motion: reduce) { .u-selectbox-select-icon-arrow, .pill, .pill .label { transition: none; } }\n";
@@ -0,0 +1,31 @@
1
+ import type { DevCustomRule, DevRequestRule } from './types';
2
+ /** Самая долгая задержка правила: дольше ждать ответ в dev незачем, а мусор из хранилища так не зависнет. */
3
+ export declare const MAX_RULE_DELAY_MS = 60000;
4
+ /** Тело длиннее не хранится: localStorage небольшой, а ссылка и подавно. */
5
+ export declare const MAX_RULE_BODY = 100000;
6
+ /** Тело длиннее этого в ссылку на сбои не кладётся. */
7
+ export declare const LINK_BODY_LIMIT = 1500;
8
+ /** Разбирается ли текст как JSON: по этому выбирается `Content-Type` своего тела. */
9
+ export declare function isJsonText(text: string): boolean;
10
+ /** Задержка правила в допустимых пределах; `undefined` — задержки нет. */
11
+ export declare function cleanDelay(value: unknown): number | undefined;
12
+ /** Правило из ненадёжного источника (хранилище, ссылка): без обязательных полей — `null`, мусор в необязательных отбрасывается. */
13
+ export declare function cleanRule(raw: unknown): DevRequestRule | null;
14
+ /** Правило из хранилища: к проверенным полям добавляются `id` и `enabled`. */
15
+ export declare function cleanStoredRule(raw: unknown): DevCustomRule | null;
16
+ export interface LinkedRule {
17
+ service: string;
18
+ rule: DevRequestRule;
19
+ }
20
+ /** Параметр адреса со своими правилами рядом с `?dev=`. */
21
+ export declare const RULES_PARAM = "devRules";
22
+ /**
23
+ * Свои правила для ссылки. Тело, которое длиннее `LINK_BODY_LIMIT`, не переносится — правило идёт
24
+ * без него, а число таких правил возвращается, чтобы подсказать это разработчику.
25
+ */
26
+ export declare function encodeRules(rules: readonly LinkedRule[]): {
27
+ value: string;
28
+ droppedBodies: number;
29
+ };
30
+ /** Правила из ссылки; битое значение даёт пустой список, как и ненужные поля. */
31
+ export declare function decodeRules(value: string): LinkedRule[];
@@ -16,9 +16,10 @@ export interface DevServiceEntry {
16
16
  kit?: DevKitInfo;
17
17
  }
18
18
  /**
19
- * Параметр `dev` в адресе: `off` снимает сбои всех сервисов (выход, если панели не видно),
20
- * `a,b` — включает этот набор сбоев (ссылка на сценарий). Параметр сразу убирается из адреса
21
- * (остальные параметры, hash и `history.state` роутера сохраняются): F5 не применяет его снова.
19
+ * Параметры `dev` и `devRules` в адресе. `dev=off` снимает сбои всех сервисов (выход, если панели
20
+ * не видно), `dev=a,b` — включает этот набор сбоев (ссылка на сценарий), `devRules` — свои правила
21
+ * «адрес → ответ» из той же ссылки. Параметры сразу убираются из адреса (остальные параметры, hash и
22
+ * `history.state` роутера сохраняются): F5 не применяет их снова.
22
23
  */
23
24
  export declare function applyUrl(): void;
24
25
  export declare function setKitInfo(info: DevKitInfo | undefined): void;
@@ -32,11 +33,13 @@ export declare function setFault(entry: DevServiceEntry, id: string, enabled: bo
32
33
  export declare function addRule(entry: DevServiceEntry, rule: Omit<DevCustomRule, 'id' | 'enabled'>): void;
33
34
  export declare function setRuleEnabled(entry: DevServiceEntry, id: string, enabled: boolean): void;
34
35
  export declare function removeRule(entry: DevServiceEntry, id: string): void;
35
- /** «Сбросить всё»: флаги и свои правила всех подключённых сервисов. Выбор кнопки — настройка, а не сбой: остаётся. */
36
+ /** Флаги и свои правила всех подключённых сервисов. Выбор кнопки — настройка, а не сбой: его снимает `resetLauncher`. */
36
37
  export declare function resetAll(): void;
37
38
  /** Сколько сбоев включено сейчас: флаги и правила. */
38
39
  export declare function activeCount(entry: DevServiceEntry): number;
39
40
  /** Кнопка «Dev» сервиса: выбор в панели, иначе конфиг, иначе видна. */
40
41
  export declare function launcherOf(entry: DevServiceEntry): DevLauncher;
42
+ /** Забыть выбор кнопки у всех сервисов: снова действует `config.launcher` («Сбросить всё» в панели). */
43
+ export declare function resetLauncher(): void;
41
44
  /** «Скрыть кнопку» / «Показывать кнопку»: кнопка в окне одна, поэтому выбор — для всех подключённых сервисов. */
42
45
  export declare function setLauncher(launcher: DevLauncher): void;
@@ -11,12 +11,23 @@ export interface DevRequestRule {
11
11
  * `**` — любое число сегментов (`/assets/*`, `/dictionaries/**`).
12
12
  */
13
13
  path: string;
14
- /** Код ответа: 400, 403, 404, 409, 429, 500, 502, 503, 504… */
14
+ /** Код ответа: 200, 201, 204 (со своим `body`) или ошибка — 400, 403, 404, 409, 429, 500, 502, 503, 504… */
15
15
  status: number;
16
16
  /** Текст ошибки в теле `{ statusCode, message }`. */
17
17
  message?: string;
18
18
  /** Тело HTML вместо JSON — как у шлюза (502 Bad Gateway). */
19
19
  html?: boolean;
20
+ /**
21
+ * Своё тело ответа: JSON или простой текст, отдаётся как есть (`message` и `html` тогда не нужны).
22
+ * `Content-Type` — `application/json`, если тело разбирается как JSON, иначе `text/plain`.
23
+ * У 204 тела нет.
24
+ */
25
+ body?: string;
26
+ /**
27
+ * Задержка ответа, мс. Если включены «Медленные ответы», действует большая из двух.
28
+ * Отмена запроса (`AbortController`, `xhr.abort()`) прерывает ожидание.
29
+ */
30
+ delay?: number;
20
31
  }
21
32
  /** Пункт панели: флаг, который сервис читает сам, и (необязательно) подмена ответа. */
22
33
  export interface DevFaultItem {
@@ -46,7 +57,7 @@ export interface DevPanelUser {
46
57
  export interface DevPanelConfig {
47
58
  /** Имя сервиса: подпись панели и ключ хранения флагов (`urfu-ui-kit:dev:<service>`). */
48
59
  service: string;
49
- /** Версия сервиса для вкладки «Смотреть». */
60
+ /** Версия сервиса для вкладки «Среда». */
50
61
  version?: string;
51
62
  /**
52
63
  * Префикс API (`/api/v1`). Сбои касаются только адресов с ним; шаблоны правил — путь после него.
@@ -60,7 +71,7 @@ export interface DevPanelConfig {
60
71
  builtins?: readonly DevBuiltinFault[];
61
72
  /** Свои сценарии сервиса — группы, как в панели it-assets. */
62
73
  groups?: readonly DevFaultGroup[];
63
- /** Текущий пользователь для вкладки «Смотреть». */
74
+ /** Текущий пользователь для вкладки «Среда». */
64
75
  user?: () => DevPanelUser | null | undefined;
65
76
  /** «Перезапросить данные» — сбросить кеш запросов сервиса (RTK Query, TanStack Query…). */
66
77
  onRefetch?: () => void;
@@ -0,0 +1,22 @@
1
+ /**
2
+ * Режимы «Вид» dev-панели: «Уменьшенная анимация», «Анимации ×5», «Подсветка не из кита».
3
+ *
4
+ * Режимы действуют на всю страницу, а не на один сервис, поэтому хранятся отдельным ключом
5
+ * `urfu-ui-kit:dev:~view`, а не в состоянии сервиса: формат состояния сервиса не меняется,
6
+ * `?dev=off` снимает и этот ключ (он под тем же префиксом).
7
+ */
8
+ import { type HighlightStats } from './highlight';
9
+ import { type ReducedMotionStats } from './motionModes';
10
+ export declare const VIEW_MODES: readonly ["reduce", "slow", "highlight"];
11
+ export type DevViewMode = (typeof VIEW_MODES)[number];
12
+ export declare const VIEW_STORAGE_KEY = "urfu-ui-kit:dev:~view";
13
+ export declare function isViewMode(mode: DevViewMode): boolean;
14
+ export declare function setViewMode(mode: DevViewMode, on: boolean): void;
15
+ /** При монтировании панели: включает сохранённые режимы. `listener` — счётчики режимов изменились. */
16
+ export declare function startViewModes(listener: () => void): void;
17
+ /** При размонтировании панели: режимы снимаются со страницы, выбор в хранилище остаётся до следующего входа. */
18
+ export declare function stopViewModes(): void;
19
+ export declare function viewStats(): {
20
+ reduce: ReducedMotionStats;
21
+ highlight: HighlightStats;
22
+ };
@@ -0,0 +1,18 @@
1
+ /**
2
+ * Анимация высоты для `details` и появления/исчезновения блока на общем ядре кита:
3
+ * раскрытие 250 мс, сворачивание 200, кривая `--u-ease-move`. Тот же набор, что у
4
+ * Vue `useCollapseMotion`; при размонтировании отменяет только свои анимации.
5
+ */
6
+ export declare function useCollapseMotion(): {
7
+ enterCollapse: (element: Element, done?: () => void) => void;
8
+ leaveCollapse: (element: Element, done?: () => void) => void;
9
+ cancelCollapse: (element: Element) => void;
10
+ toggleDetailsAnimated: (event: {
11
+ readonly button: number;
12
+ readonly currentTarget: EventTarget | null;
13
+ readonly target: EventTarget | null;
14
+ readonly defaultPrevented: boolean;
15
+ preventDefault: () => void;
16
+ }) => void;
17
+ };
18
+ //# sourceMappingURL=useCollapseMotion.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"useCollapseMotion.d.ts","sourceRoot":"","sources":["../../src/hooks/useCollapseMotion.ts"],"names":[],"mappings":"AAGA;;;;GAIG;AACH,wBAAgB,iBAAiB;;;;;;;;;;;EAKhC"}
@@ -0,0 +1,9 @@
1
+ import { useState as a, useEffect as n } from "react";
2
+ import { createCollapseMotion$u as i } from "../vanilla/core/collapseMotion.js";
3
+ function c() {
4
+ const [e] = a(i);
5
+ n(() => e.dispose, [e]);
6
+ const { enterCollapse: o, leaveCollapse: t, cancelCollapse: l, toggleDetailsAnimated: s } = e;
7
+ return { enterCollapse: o, leaveCollapse: t, cancelCollapse: l, toggleDetailsAnimated: s };
8
+ }
9
+ export { c as useCollapseMotion$u };
@@ -11,7 +11,13 @@ type Params = {
11
11
  enabled?: boolean;
12
12
  };
13
13
  /**
14
- * Закрывает попап по клику вне его.
14
+ * Закрывает попап по клику вне его и по Escape.
15
+ *
16
+ * Escape ловится на document в фазе перехвата и гасится `preventDefault`: Modal и
17
+ * Drawer слушают всплытие и пропускают обработанное событие, поэтому закрывается
18
+ * только попап, а не окно вокруг него — даже когда фокус ушёл с поля на пункт
19
+ * списка (чекбокс Multiselect) и до обработчика клавиш поля Escape не доходит.
20
+ * Так же устроен `useDropdown` во Vue-ките.
15
21
  *
16
22
  * Заменяет пару `useOutsideClick` + `useOutsideAlerter`, которые делали одно и то
17
23
  * же и в каждом селекте вызывались вместе. Попутно чинит их поломки:
@@ -1 +1 @@
1
- {"version":3,"file":"useDismiss.d.ts","sourceRoot":"","sources":["../../src/hooks/useDismiss.ts"],"names":[],"mappings":"AAAA,OAAO,EAAqB,KAAK,SAAS,EAAE,MAAM,OAAO,CAAC;AAE1D,KAAK,MAAM,GAAG,SAAS,CAAC,WAAW,GAAG,IAAI,CAAC,GAAG,IAAI,GAAG,SAAS,CAAC;AAE/D,KAAK,MAAM,GAAG;IACV;;;OAGG;IACH,IAAI,EAAE,MAAM,EAAE,CAAC;IACf,SAAS,EAAE,MAAM,IAAI,CAAC;IACtB,2CAA2C;IAC3C,OAAO,CAAC,EAAE,OAAO,CAAC;CACrB,CAAC;AAEF;;;;;;;;;;;;;;;GAeG;AACH,eAAO,MAAM,UAAU,GAAI,8BAAqC,MAAM,SA+BrE,CAAC"}
1
+ {"version":3,"file":"useDismiss.d.ts","sourceRoot":"","sources":["../../src/hooks/useDismiss.ts"],"names":[],"mappings":"AAAA,OAAO,EAAqB,KAAK,SAAS,EAAE,MAAM,OAAO,CAAC;AAE1D,KAAK,MAAM,GAAG,SAAS,CAAC,WAAW,GAAG,IAAI,CAAC,GAAG,IAAI,GAAG,SAAS,CAAC;AAE/D,KAAK,MAAM,GAAG;IACV;;;OAGG;IACH,IAAI,EAAE,MAAM,EAAE,CAAC;IACf,SAAS,EAAE,MAAM,IAAI,CAAC;IACtB,2CAA2C;IAC3C,OAAO,CAAC,EAAE,OAAO,CAAC;CACrB,CAAC;AAEF;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,eAAO,MAAM,UAAU,GAAI,8BAAqC,MAAM,SAuCrE,CAAC"}
@@ -1,20 +1,22 @@
1
- import { useRef as d, useEffect as m } from "react";
2
- const v = ({ refs: n, onDismiss: r, enabled: o = !0 }) => {
3
- const s = d(r);
4
- s.current = r;
5
- const i = d(n);
6
- i.current = n, m(() => {
7
- if (!o) return;
8
- const u = (f) => {
9
- const e = f.target;
10
- !(e instanceof Node) || !e.isConnected || i.current.some((t) => {
11
- var c;
12
- return (c = t == null ? void 0 : t.current) == null ? void 0 : c.contains(e);
13
- }) || s.current();
1
+ import { useRef as f, useEffect as m } from "react";
2
+ const w = ({ refs: o, onDismiss: s, enabled: u = !0 }) => {
3
+ const t = f(s);
4
+ t.current = s;
5
+ const c = f(o);
6
+ c.current = o, m(() => {
7
+ if (!u) return;
8
+ const i = (e) => {
9
+ const n = e.target;
10
+ !(n instanceof Node) || !n.isConnected || c.current.some((r) => {
11
+ var a;
12
+ return (a = r == null ? void 0 : r.current) == null ? void 0 : a.contains(n);
13
+ }) || t.current();
14
+ }, d = (e) => {
15
+ e.key !== "Escape" || e.defaultPrevented || (e.preventDefault(), t.current());
14
16
  };
15
- return document.addEventListener("pointerdown", u, !0), () => {
16
- document.removeEventListener("pointerdown", u, !0);
17
+ return document.addEventListener("pointerdown", i, !0), document.addEventListener("keydown", d, !0), () => {
18
+ document.removeEventListener("pointerdown", i, !0), document.removeEventListener("keydown", d, !0);
17
19
  };
18
- }, [o]);
20
+ }, [u]);
19
21
  };
20
- export { v as useDismiss$u };
22
+ export { w as useDismiss$u };
@@ -0,0 +1,9 @@
1
+ import { type RefObject } from 'react';
2
+ /**
3
+ * Проигрывает появление (`playEnterMotion`: прозрачность и сдвиг на 4 px, 200 мс) на
4
+ * элементе `ref`, когда меняется `key` — например, ключ активной вкладки. Первый
5
+ * показ и prefers-reduced-motion — без анимации; дети не пересоздаются. Эффект
6
+ * layout-уровня: анимация стартует до отрисовки, без кадра в конечном состоянии.
7
+ */
8
+ export declare function useEnterMotion(ref: RefObject<HTMLElement | null>, key: unknown): void;
9
+ //# sourceMappingURL=useEnterMotion.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"useEnterMotion.d.ts","sourceRoot":"","sources":["../../src/hooks/useEnterMotion.ts"],"names":[],"mappings":"AAAA,OAAO,EAA2B,KAAK,SAAS,EAAE,MAAM,OAAO,CAAC;AAGhE;;;;;GAKG;AACH,wBAAgB,cAAc,CAAC,GAAG,EAAE,SAAS,CAAC,WAAW,GAAG,IAAI,CAAC,EAAE,GAAG,EAAE,OAAO,QAO9E"}
@@ -0,0 +1,10 @@
1
+ import { useRef as n, useLayoutEffect as e } from "react";
2
+ import { playEnterMotion$u as u } from "../vanilla/core/motion.js";
3
+ function f(t, r) {
4
+ const o = n(r);
5
+ e(() => {
6
+ if (!Object.is(o.current, r))
7
+ return o.current = r, u(t.current);
8
+ }, [t, r]);
9
+ }
10
+ export { f as useEnterMotion$u };
@@ -0,0 +1,8 @@
1
+ import { type ForwardedRef } from 'react';
2
+ /**
3
+ * Свой ref на элемент и ref, переданный снаружи (`forwardRef`), на одном узле.
4
+ * Снаружи элемент нужен формам: `register` из react-hook-form читает значение
5
+ * и ставит фокус на ошибку через ref.
6
+ */
7
+ export declare const useForwardedRef: <T extends HTMLElement>(forwardedRef: ForwardedRef<T>) => readonly [import("react").MutableRefObject<T>, (node: T | null) => void];
8
+ //# sourceMappingURL=useForwardedRef.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"useForwardedRef.d.ts","sourceRoot":"","sources":["../../src/hooks/useForwardedRef.ts"],"names":[],"mappings":"AAAA,OAAO,EAAuB,KAAK,YAAY,EAAE,MAAM,OAAO,CAAC;AAE/D;;;;GAIG;AACH,eAAO,MAAM,eAAe,GAAI,CAAC,SAAS,WAAW,EAAE,cAAc,YAAY,CAAC,CAAC,CAAC,2DAE9C,CAAC,GAAG,IAAI,UAM7C,CAAC"}
@@ -0,0 +1,8 @@
1
+ import { useRef as n, useCallback as e } from "react";
2
+ const i = (t) => {
3
+ const u = n(null), c = e((s) => {
4
+ u.current = s, typeof t == "function" ? t(s) : t && (t.current = s);
5
+ }, [t]);
6
+ return [u, c];
7
+ };
8
+ export { i as useForwardedRef$u };
@@ -0,0 +1,27 @@
1
+ export interface UseInfiniteScrollOptions {
2
+ /** Загрузить следующую порцию. Вернёт промис — повторного вызова не будет до его завершения. */
3
+ onLoadMore: () => unknown;
4
+ /** Есть ли ещё порции. */
5
+ hasMore: boolean;
6
+ /** Порция грузится: пока `true`, `onLoadMore` не вызывается. */
7
+ loading?: boolean;
8
+ /** Не грузить — например, пока показана ошибка. */
9
+ disabled?: boolean;
10
+ /** Насколько заранее начинать подгрузку. По умолчанию `200px`. */
11
+ rootMargin?: string;
12
+ /** Область прокрутки; не задана — ближайший прокручиваемый предок датчика (тело Modal) или страница. */
13
+ root?: Element | null;
14
+ }
15
+ export interface UseInfiniteScrollResult {
16
+ /** Ref датчика — пустого элемента после последней строки. */
17
+ sentinelRef: (element: Element | null) => void;
18
+ /** Повторить после ошибки порции (отклонённого промиса), не дожидаясь прокрутки. */
19
+ retry: () => void;
20
+ }
21
+ /**
22
+ * Ленивая подгрузка на общем ядре кита (то же, что у Vue `useInfiniteScroll`):
23
+ * IntersectionObserver на датчике, без повторных вызовов, пока порция грузится.
24
+ * Готовый датчик с индикатором и объявлением для скринридера — компонент `InfiniteScroll`.
25
+ */
26
+ export declare function useInfiniteScroll({ onLoadMore, hasMore, loading, disabled, rootMargin, root }: UseInfiniteScrollOptions): UseInfiniteScrollResult;
27
+ //# sourceMappingURL=useInfiniteScroll.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"useInfiniteScroll.d.ts","sourceRoot":"","sources":["../../src/hooks/useInfiniteScroll.ts"],"names":[],"mappings":"AAGA,MAAM,WAAW,wBAAwB;IACvC,gGAAgG;IAChG,UAAU,EAAE,MAAM,OAAO,CAAC;IAC1B,0BAA0B;IAC1B,OAAO,EAAE,OAAO,CAAC;IACjB,gEAAgE;IAChE,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,mDAAmD;IACnD,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,kEAAkE;IAClE,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,wGAAwG;IACxG,IAAI,CAAC,EAAE,OAAO,GAAG,IAAI,CAAC;CACvB;AAED,MAAM,WAAW,uBAAuB;IACtC,6DAA6D;IAC7D,WAAW,EAAE,CAAC,OAAO,EAAE,OAAO,GAAG,IAAI,KAAK,IAAI,CAAC;IAC/C,oFAAoF;IACpF,KAAK,EAAE,MAAM,IAAI,CAAC;CACnB;AAED;;;;GAIG;AACH,wBAAgB,iBAAiB,CAAC,EAAE,UAAU,EAAE,OAAO,EAAE,OAAO,EAAE,QAAQ,EAAE,UAAU,EAAE,IAAI,EAAE,EAAE,wBAAwB,GAAG,uBAAuB,CAajJ"}
@@ -0,0 +1,13 @@
1
+ import { useState as p, useRef as S, useCallback as t, useEffect as y } from "react";
2
+ import { InfiniteScrollCore$u as C } from "../vanilla/core/infiniteScroll.js";
3
+ function k({ onLoadMore: r, hasMore: n, loading: c, disabled: o, rootMargin: s, root: f }) {
4
+ const [e] = p(() => new C()), u = S(r);
5
+ u.current = r;
6
+ const l = t(() => u.current(), []);
7
+ y(() => {
8
+ e.setOptions({ onLoadMore: l, hasMore: n, loading: c, disabled: o, rootMargin: s, root: f });
9
+ }, [e, l, n, c, o, s, f]);
10
+ const i = t((m) => e.attach(m), [e]), a = t(() => e.retry(), [e]);
11
+ return { sentinelRef: i, retry: a };
12
+ }
13
+ export { k as useInfiniteScroll$u };
@@ -1,7 +1,7 @@
1
1
  export type TransitionStatus = "closed" | "entering" | "open" | "exiting";
2
2
  type Params = {
3
3
  isOpen: boolean;
4
- /** Длительность анимации закрытия, мс. Должна совпадать с CSS. */
4
+ /** Длительность анимации закрытия, мс. Должна совпадать с CSS; множитель «×5» dev-панели хук учитывает сам. */
5
5
  duration?: number;
6
6
  /**
7
7
  * Отключить анимацию целиком — узел появляется и исчезает мгновенно,
@@ -1 +1 @@
1
- {"version":3,"file":"useMountTransition.d.ts","sourceRoot":"","sources":["../../src/hooks/useMountTransition.ts"],"names":[],"mappings":"AAEA,MAAM,MAAM,gBAAgB,GAAG,QAAQ,GAAG,UAAU,GAAG,MAAM,GAAG,SAAS,CAAC;AAE1E,KAAK,MAAM,GAAG;IACV,MAAM,EAAE,OAAO,CAAC;IAChB,kEAAkE;IAClE,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB;;;OAGG;IACH,QAAQ,CAAC,EAAE,OAAO,CAAC;CACtB,CAAC;AAOF;;;;;;;;;GASG;AACH,eAAO,MAAM,kBAAkB,GAAI,gCAA8C,MAAM;;;;CAgFtF,CAAC"}
1
+ {"version":3,"file":"useMountTransition.d.ts","sourceRoot":"","sources":["../../src/hooks/useMountTransition.ts"],"names":[],"mappings":"AAGA,MAAM,MAAM,gBAAgB,GAAG,QAAQ,GAAG,UAAU,GAAG,MAAM,GAAG,SAAS,CAAC;AAE1E,KAAK,MAAM,GAAG;IACV,MAAM,EAAE,OAAO,CAAC;IAChB,+GAA+G;IAC/G,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB;;;OAGG;IACH,QAAQ,CAAC,EAAE,OAAO,CAAC;CACtB,CAAC;AAEF;;;;;;;;;GASG;AACH,eAAO,MAAM,kBAAkB,GAAI,gCAA4D,MAAM;;;;CAgFpG,CAAC"}