@cloud-ru/uikit-product-header 5.0.17

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 (240) hide show
  1. package/CHANGELOG.md +3498 -0
  2. package/LICENSE +201 -0
  3. package/README.md +322 -0
  4. package/dist/cjs/components/HeaderLayout/HeaderLayout.d.ts +12 -0
  5. package/dist/cjs/components/HeaderLayout/HeaderLayout.js +25 -0
  6. package/dist/cjs/components/HeaderLayout/index.d.ts +1 -0
  7. package/dist/cjs/components/HeaderLayout/index.js +17 -0
  8. package/dist/cjs/components/HeaderLayout/styles.module.css +35 -0
  9. package/dist/cjs/components/Logo/Logo.d.ts +20 -0
  10. package/dist/cjs/components/Logo/Logo.js +61 -0
  11. package/dist/cjs/components/Logo/index.d.ts +1 -0
  12. package/dist/cjs/components/Logo/index.js +17 -0
  13. package/dist/cjs/components/Logo/styles.module.css +28 -0
  14. package/dist/cjs/components/MainMenu/Content/Content.d.ts +20 -0
  15. package/dist/cjs/components/MainMenu/Content/Content.js +36 -0
  16. package/dist/cjs/components/MainMenu/Content/index.d.ts +1 -0
  17. package/dist/cjs/components/MainMenu/Content/index.js +17 -0
  18. package/dist/cjs/components/MainMenu/Content/styles.module.css +40 -0
  19. package/dist/cjs/components/MainMenu/MainMenu.d.ts +4 -0
  20. package/dist/cjs/components/MainMenu/MainMenu.js +16 -0
  21. package/dist/cjs/components/MainMenu/MenuDesktop/MenuDesktop.d.ts +2 -0
  22. package/dist/cjs/components/MainMenu/MenuDesktop/MenuDesktop.js +34 -0
  23. package/dist/cjs/components/MainMenu/MenuDesktop/index.d.ts +1 -0
  24. package/dist/cjs/components/MainMenu/MenuDesktop/index.js +17 -0
  25. package/dist/cjs/components/MainMenu/MenuDesktop/styles.module.css +94 -0
  26. package/dist/cjs/components/MainMenu/MenuMobile/MenuMobile.d.ts +2 -0
  27. package/dist/cjs/components/MainMenu/MenuMobile/MenuMobile.js +31 -0
  28. package/dist/cjs/components/MainMenu/MenuMobile/index.d.ts +1 -0
  29. package/dist/cjs/components/MainMenu/MenuMobile/index.js +17 -0
  30. package/dist/cjs/components/MainMenu/MenuMobile/styles.module.css +23 -0
  31. package/dist/cjs/components/MainMenu/Search/SearchDesktop/SearchDesktop.d.ts +2 -0
  32. package/dist/cjs/components/MainMenu/Search/SearchDesktop/SearchDesktop.js +18 -0
  33. package/dist/cjs/components/MainMenu/Search/SearchDesktop/index.d.ts +1 -0
  34. package/dist/cjs/components/MainMenu/Search/SearchDesktop/index.js +17 -0
  35. package/dist/cjs/components/MainMenu/Search/SearchDesktop/styles.module.css +17 -0
  36. package/dist/cjs/components/MainMenu/Search/SearchMobile/SearchMobile.d.ts +2 -0
  37. package/dist/cjs/components/MainMenu/Search/SearchMobile/SearchMobile.js +42 -0
  38. package/dist/cjs/components/MainMenu/Search/SearchMobile/constants.d.ts +4 -0
  39. package/dist/cjs/components/MainMenu/Search/SearchMobile/constants.js +7 -0
  40. package/dist/cjs/components/MainMenu/Search/SearchMobile/hooks.d.ts +12 -0
  41. package/dist/cjs/components/MainMenu/Search/SearchMobile/hooks.js +40 -0
  42. package/dist/cjs/components/MainMenu/Search/SearchMobile/index.d.ts +1 -0
  43. package/dist/cjs/components/MainMenu/Search/SearchMobile/index.js +17 -0
  44. package/dist/cjs/components/MainMenu/Search/SearchMobile/styles.module.css +57 -0
  45. package/dist/cjs/components/MainMenu/Search/SearchSettingsButton/SearchSettingsButton.d.ts +4 -0
  46. package/dist/cjs/components/MainMenu/Search/SearchSettingsButton/SearchSettingsButton.js +13 -0
  47. package/dist/cjs/components/MainMenu/Search/SearchSettingsButton/index.d.ts +1 -0
  48. package/dist/cjs/components/MainMenu/Search/SearchSettingsButton/index.js +17 -0
  49. package/dist/cjs/components/MainMenu/Search/SearchSettingsButton/styles.module.css +11 -0
  50. package/dist/cjs/components/MainMenu/Search/index.d.ts +3 -0
  51. package/dist/cjs/components/MainMenu/Search/index.js +19 -0
  52. package/dist/cjs/components/MainMenu/Search/types.d.ts +14 -0
  53. package/dist/cjs/components/MainMenu/Search/types.js +2 -0
  54. package/dist/cjs/components/MainMenu/Search/useSearch.d.ts +8 -0
  55. package/dist/cjs/components/MainMenu/Search/useSearch.js +169 -0
  56. package/dist/cjs/components/MainMenu/hooks.d.ts +10 -0
  57. package/dist/cjs/components/MainMenu/hooks.js +108 -0
  58. package/dist/cjs/components/MainMenu/index.d.ts +4 -0
  59. package/dist/cjs/components/MainMenu/index.js +20 -0
  60. package/dist/cjs/components/MainMenu/styles.module.css +28 -0
  61. package/dist/cjs/components/MainMenu/types.d.ts +49 -0
  62. package/dist/cjs/components/MainMenu/types.js +2 -0
  63. package/dist/cjs/components/PathBreadcrumbs/PathBreadcrumbs.d.ts +7 -0
  64. package/dist/cjs/components/PathBreadcrumbs/PathBreadcrumbs.js +12 -0
  65. package/dist/cjs/components/PathBreadcrumbs/index.d.ts +1 -0
  66. package/dist/cjs/components/PathBreadcrumbs/index.js +17 -0
  67. package/dist/cjs/components/PathBreadcrumbs/styles.module.css +5 -0
  68. package/dist/cjs/components/PlatformLogo/Container.d.ts +12 -0
  69. package/dist/cjs/components/PlatformLogo/Container.js +28 -0
  70. package/dist/cjs/components/PlatformLogo/index.d.ts +4 -0
  71. package/dist/cjs/components/PlatformLogo/index.js +9 -0
  72. package/dist/cjs/components/PlatformLogo/styles.module.css +11 -0
  73. package/dist/cjs/components/UserMenu/UserMenu.d.ts +14 -0
  74. package/dist/cjs/components/UserMenu/UserMenu.js +54 -0
  75. package/dist/cjs/components/UserMenu/hooks/useLogoutItem.d.ts +6 -0
  76. package/dist/cjs/components/UserMenu/hooks/useLogoutItem.js +21 -0
  77. package/dist/cjs/components/UserMenu/hooks/useProfileItem.d.ts +3 -0
  78. package/dist/cjs/components/UserMenu/hooks/useProfileItem.js +29 -0
  79. package/dist/cjs/components/UserMenu/hooks/useThemeItem.d.ts +6 -0
  80. package/dist/cjs/components/UserMenu/hooks/useThemeItem.js +75 -0
  81. package/dist/cjs/components/UserMenu/hooks/useUserMenuItems.d.ts +13 -0
  82. package/dist/cjs/components/UserMenu/hooks/useUserMenuItems.js +42 -0
  83. package/dist/cjs/components/UserMenu/index.d.ts +2 -0
  84. package/dist/cjs/components/UserMenu/index.js +18 -0
  85. package/dist/cjs/components/UserMenu/styles.module.css +21 -0
  86. package/dist/cjs/components/UserMenu/types.d.ts +20 -0
  87. package/dist/cjs/components/UserMenu/types.js +8 -0
  88. package/dist/cjs/components/index.d.ts +6 -0
  89. package/dist/cjs/components/index.js +22 -0
  90. package/dist/cjs/hooks/index.d.ts +1 -0
  91. package/dist/cjs/hooks/index.js +17 -0
  92. package/dist/cjs/hooks/useLocalStorage.d.ts +1 -0
  93. package/dist/cjs/hooks/useLocalStorage.js +13 -0
  94. package/dist/cjs/index.d.ts +2 -0
  95. package/dist/cjs/index.js +18 -0
  96. package/dist/esm/components/HeaderLayout/HeaderLayout.d.ts +12 -0
  97. package/dist/esm/components/HeaderLayout/HeaderLayout.js +19 -0
  98. package/dist/esm/components/HeaderLayout/index.d.ts +1 -0
  99. package/dist/esm/components/HeaderLayout/index.js +1 -0
  100. package/dist/esm/components/HeaderLayout/styles.module.css +35 -0
  101. package/dist/esm/components/Logo/Logo.d.ts +20 -0
  102. package/dist/esm/components/Logo/Logo.js +54 -0
  103. package/dist/esm/components/Logo/index.d.ts +1 -0
  104. package/dist/esm/components/Logo/index.js +1 -0
  105. package/dist/esm/components/Logo/styles.module.css +28 -0
  106. package/dist/esm/components/MainMenu/Content/Content.d.ts +20 -0
  107. package/dist/esm/components/MainMenu/Content/Content.js +30 -0
  108. package/dist/esm/components/MainMenu/Content/index.d.ts +1 -0
  109. package/dist/esm/components/MainMenu/Content/index.js +1 -0
  110. package/dist/esm/components/MainMenu/Content/styles.module.css +40 -0
  111. package/dist/esm/components/MainMenu/MainMenu.d.ts +4 -0
  112. package/dist/esm/components/MainMenu/MainMenu.js +13 -0
  113. package/dist/esm/components/MainMenu/MenuDesktop/MenuDesktop.d.ts +2 -0
  114. package/dist/esm/components/MainMenu/MenuDesktop/MenuDesktop.js +28 -0
  115. package/dist/esm/components/MainMenu/MenuDesktop/index.d.ts +1 -0
  116. package/dist/esm/components/MainMenu/MenuDesktop/index.js +1 -0
  117. package/dist/esm/components/MainMenu/MenuDesktop/styles.module.css +94 -0
  118. package/dist/esm/components/MainMenu/MenuMobile/MenuMobile.d.ts +2 -0
  119. package/dist/esm/components/MainMenu/MenuMobile/MenuMobile.js +25 -0
  120. package/dist/esm/components/MainMenu/MenuMobile/index.d.ts +1 -0
  121. package/dist/esm/components/MainMenu/MenuMobile/index.js +1 -0
  122. package/dist/esm/components/MainMenu/MenuMobile/styles.module.css +23 -0
  123. package/dist/esm/components/MainMenu/Search/SearchDesktop/SearchDesktop.d.ts +2 -0
  124. package/dist/esm/components/MainMenu/Search/SearchDesktop/SearchDesktop.js +12 -0
  125. package/dist/esm/components/MainMenu/Search/SearchDesktop/index.d.ts +1 -0
  126. package/dist/esm/components/MainMenu/Search/SearchDesktop/index.js +1 -0
  127. package/dist/esm/components/MainMenu/Search/SearchDesktop/styles.module.css +17 -0
  128. package/dist/esm/components/MainMenu/Search/SearchMobile/SearchMobile.d.ts +2 -0
  129. package/dist/esm/components/MainMenu/Search/SearchMobile/SearchMobile.js +36 -0
  130. package/dist/esm/components/MainMenu/Search/SearchMobile/constants.d.ts +4 -0
  131. package/dist/esm/components/MainMenu/Search/SearchMobile/constants.js +4 -0
  132. package/dist/esm/components/MainMenu/Search/SearchMobile/hooks.d.ts +12 -0
  133. package/dist/esm/components/MainMenu/Search/SearchMobile/hooks.js +34 -0
  134. package/dist/esm/components/MainMenu/Search/SearchMobile/index.d.ts +1 -0
  135. package/dist/esm/components/MainMenu/Search/SearchMobile/index.js +1 -0
  136. package/dist/esm/components/MainMenu/Search/SearchMobile/styles.module.css +57 -0
  137. package/dist/esm/components/MainMenu/Search/SearchSettingsButton/SearchSettingsButton.d.ts +4 -0
  138. package/dist/esm/components/MainMenu/Search/SearchSettingsButton/SearchSettingsButton.js +7 -0
  139. package/dist/esm/components/MainMenu/Search/SearchSettingsButton/index.d.ts +1 -0
  140. package/dist/esm/components/MainMenu/Search/SearchSettingsButton/index.js +1 -0
  141. package/dist/esm/components/MainMenu/Search/SearchSettingsButton/styles.module.css +11 -0
  142. package/dist/esm/components/MainMenu/Search/index.d.ts +3 -0
  143. package/dist/esm/components/MainMenu/Search/index.js +3 -0
  144. package/dist/esm/components/MainMenu/Search/types.d.ts +14 -0
  145. package/dist/esm/components/MainMenu/Search/types.js +1 -0
  146. package/dist/esm/components/MainMenu/Search/useSearch.d.ts +8 -0
  147. package/dist/esm/components/MainMenu/Search/useSearch.js +161 -0
  148. package/dist/esm/components/MainMenu/hooks.d.ts +10 -0
  149. package/dist/esm/components/MainMenu/hooks.js +101 -0
  150. package/dist/esm/components/MainMenu/index.d.ts +4 -0
  151. package/dist/esm/components/MainMenu/index.js +4 -0
  152. package/dist/esm/components/MainMenu/styles.module.css +28 -0
  153. package/dist/esm/components/MainMenu/types.d.ts +49 -0
  154. package/dist/esm/components/MainMenu/types.js +1 -0
  155. package/dist/esm/components/PathBreadcrumbs/PathBreadcrumbs.d.ts +7 -0
  156. package/dist/esm/components/PathBreadcrumbs/PathBreadcrumbs.js +6 -0
  157. package/dist/esm/components/PathBreadcrumbs/index.d.ts +1 -0
  158. package/dist/esm/components/PathBreadcrumbs/index.js +1 -0
  159. package/dist/esm/components/PathBreadcrumbs/styles.module.css +5 -0
  160. package/dist/esm/components/PlatformLogo/Container.d.ts +12 -0
  161. package/dist/esm/components/PlatformLogo/Container.js +20 -0
  162. package/dist/esm/components/PlatformLogo/index.d.ts +4 -0
  163. package/dist/esm/components/PlatformLogo/index.js +6 -0
  164. package/dist/esm/components/PlatformLogo/styles.module.css +11 -0
  165. package/dist/esm/components/UserMenu/UserMenu.d.ts +14 -0
  166. package/dist/esm/components/UserMenu/UserMenu.js +48 -0
  167. package/dist/esm/components/UserMenu/hooks/useLogoutItem.d.ts +6 -0
  168. package/dist/esm/components/UserMenu/hooks/useLogoutItem.js +18 -0
  169. package/dist/esm/components/UserMenu/hooks/useProfileItem.d.ts +3 -0
  170. package/dist/esm/components/UserMenu/hooks/useProfileItem.js +23 -0
  171. package/dist/esm/components/UserMenu/hooks/useThemeItem.d.ts +6 -0
  172. package/dist/esm/components/UserMenu/hooks/useThemeItem.js +72 -0
  173. package/dist/esm/components/UserMenu/hooks/useUserMenuItems.d.ts +13 -0
  174. package/dist/esm/components/UserMenu/hooks/useUserMenuItems.js +39 -0
  175. package/dist/esm/components/UserMenu/index.d.ts +2 -0
  176. package/dist/esm/components/UserMenu/index.js +2 -0
  177. package/dist/esm/components/UserMenu/styles.module.css +21 -0
  178. package/dist/esm/components/UserMenu/types.d.ts +20 -0
  179. package/dist/esm/components/UserMenu/types.js +5 -0
  180. package/dist/esm/components/index.d.ts +6 -0
  181. package/dist/esm/components/index.js +6 -0
  182. package/dist/esm/hooks/index.d.ts +1 -0
  183. package/dist/esm/hooks/index.js +1 -0
  184. package/dist/esm/hooks/useLocalStorage.d.ts +1 -0
  185. package/dist/esm/hooks/useLocalStorage.js +10 -0
  186. package/dist/esm/index.d.ts +2 -0
  187. package/dist/esm/index.js +2 -0
  188. package/package.json +68 -0
  189. package/src/components/HeaderLayout/HeaderLayout.tsx +46 -0
  190. package/src/components/HeaderLayout/index.ts +1 -0
  191. package/src/components/HeaderLayout/styles.module.scss +38 -0
  192. package/src/components/Logo/Logo.tsx +93 -0
  193. package/src/components/Logo/index.ts +1 -0
  194. package/src/components/Logo/styles.module.scss +30 -0
  195. package/src/components/MainMenu/Content/Content.tsx +137 -0
  196. package/src/components/MainMenu/Content/index.ts +1 -0
  197. package/src/components/MainMenu/Content/styles.module.scss +35 -0
  198. package/src/components/MainMenu/MainMenu.tsx +51 -0
  199. package/src/components/MainMenu/MenuDesktop/MenuDesktop.tsx +120 -0
  200. package/src/components/MainMenu/MenuDesktop/index.ts +1 -0
  201. package/src/components/MainMenu/MenuDesktop/styles.module.scss +108 -0
  202. package/src/components/MainMenu/MenuMobile/MenuMobile.tsx +83 -0
  203. package/src/components/MainMenu/MenuMobile/index.ts +1 -0
  204. package/src/components/MainMenu/MenuMobile/styles.module.scss +26 -0
  205. package/src/components/MainMenu/Search/SearchDesktop/SearchDesktop.tsx +46 -0
  206. package/src/components/MainMenu/Search/SearchDesktop/index.ts +1 -0
  207. package/src/components/MainMenu/Search/SearchDesktop/styles.module.scss +21 -0
  208. package/src/components/MainMenu/Search/SearchMobile/SearchMobile.tsx +102 -0
  209. package/src/components/MainMenu/Search/SearchMobile/constants.ts +4 -0
  210. package/src/components/MainMenu/Search/SearchMobile/hooks.ts +43 -0
  211. package/src/components/MainMenu/Search/SearchMobile/index.ts +1 -0
  212. package/src/components/MainMenu/Search/SearchMobile/styles.module.scss +72 -0
  213. package/src/components/MainMenu/Search/SearchSettingsButton/SearchSettingsButton.tsx +22 -0
  214. package/src/components/MainMenu/Search/SearchSettingsButton/index.ts +1 -0
  215. package/src/components/MainMenu/Search/SearchSettingsButton/styles.module.scss +13 -0
  216. package/src/components/MainMenu/Search/index.ts +3 -0
  217. package/src/components/MainMenu/Search/types.ts +20 -0
  218. package/src/components/MainMenu/Search/useSearch.tsx +212 -0
  219. package/src/components/MainMenu/hooks.tsx +135 -0
  220. package/src/components/MainMenu/index.ts +4 -0
  221. package/src/components/MainMenu/styles.module.scss +28 -0
  222. package/src/components/MainMenu/types.ts +62 -0
  223. package/src/components/PathBreadcrumbs/PathBreadcrumbs.tsx +21 -0
  224. package/src/components/PathBreadcrumbs/index.ts +1 -0
  225. package/src/components/PathBreadcrumbs/styles.module.scss +10 -0
  226. package/src/components/PlatformLogo/Container.tsx +32 -0
  227. package/src/components/PlatformLogo/index.ts +8 -0
  228. package/src/components/PlatformLogo/styles.module.scss +13 -0
  229. package/src/components/UserMenu/UserMenu.tsx +138 -0
  230. package/src/components/UserMenu/hooks/useLogoutItem.tsx +28 -0
  231. package/src/components/UserMenu/hooks/useProfileItem.tsx +41 -0
  232. package/src/components/UserMenu/hooks/useThemeItem.tsx +116 -0
  233. package/src/components/UserMenu/hooks/useUserMenuItems.ts +77 -0
  234. package/src/components/UserMenu/index.ts +2 -0
  235. package/src/components/UserMenu/styles.module.scss +21 -0
  236. package/src/components/UserMenu/types.ts +24 -0
  237. package/src/components/index.ts +6 -0
  238. package/src/hooks/index.ts +1 -0
  239. package/src/hooks/useLocalStorage.ts +15 -0
  240. package/src/index.ts +2 -0
@@ -0,0 +1,72 @@
1
+ @use '@sbercloud/figma-tokens-cloud-platform/build/scss/components/styles-tokens-element' as ste;
2
+
3
+ .searchItem {
4
+ position: sticky;
5
+ /* stylelint-disable-next-line declaration-property-value-allowed-list */
6
+ z-index: 1;
7
+ top: -0.5px;
8
+ background-color: ste.$sys-neutral-background;
9
+
10
+ display: flex;
11
+ flex-direction: column;
12
+ gap: ste.$dimension-1m;
13
+
14
+ padding: 0;
15
+ padding-bottom: ste.$dimension-1m;
16
+ padding-top: 1px;
17
+ margin-top: 7px;
18
+ }
19
+
20
+ .searchWrap {
21
+ position: relative;
22
+ display: flex;
23
+ justify-content: space-between;
24
+ align-items: center;
25
+ color: ste.$sys-neutral-text-main;
26
+ }
27
+
28
+ .searchMobile {
29
+ position: absolute;
30
+ top: 0;
31
+ bottom: 0;
32
+ height: 100%;
33
+ right: 0;
34
+ overflow: hidden;
35
+
36
+ display: flex;
37
+ align-items: center;
38
+
39
+ transition-timing-function: ease-in-out;
40
+ transition-property: all;
41
+ transition-duration: calc(var(--sc-header-animation-enter) * 1ms);
42
+
43
+ width: 100%;
44
+ max-width: ste.$size-button-m;
45
+ box-sizing: border-box;
46
+
47
+ opacity: 0;
48
+
49
+ &[data-transition-status='entering'],
50
+ &[data-transition-status='entered'] {
51
+ max-width: 100%;
52
+ right: 0;
53
+ width: 100%;
54
+ opacity: 1;
55
+ transition-duration: calc(var(--sc-header-animation-exit) * 1ms);
56
+ }
57
+ }
58
+
59
+ .searchButton {
60
+ // TODO: почему-то сломался порядок стилей при интеграции компонента в сервис хедера
61
+ &[data-appearance='primary'] {
62
+ background-color: ste.$sys-neutral-background2-level;
63
+ }
64
+
65
+ &[data-search-active] {
66
+ visibility: hidden;
67
+ }
68
+ }
69
+
70
+ .searchModalBody {
71
+ padding: ste.$dimension-2m 0;
72
+ }
@@ -0,0 +1,22 @@
1
+ import { ConfigurationSVG } from '@cloud-ru/uikit-product-icons';
2
+ import { ButtonFunction } from '@snack-uikit/button';
3
+
4
+ import styles from './styles.module.scss';
5
+
6
+ export type SearchSettingsButtonProps = {
7
+ onClick(): void;
8
+ };
9
+
10
+ export function SearchSettingsButton({ onClick }: SearchSettingsButtonProps) {
11
+ return (
12
+ <div className={styles.searchSettings}>
13
+ <ButtonFunction
14
+ icon={<ConfigurationSVG />}
15
+ size='xs'
16
+ className={styles.searchSettingsButton}
17
+ onClick={onClick}
18
+ data-test-id='header__drawer-menu__search-config-button'
19
+ />
20
+ </div>
21
+ );
22
+ }
@@ -0,0 +1 @@
1
+ export * from './SearchSettingsButton';
@@ -0,0 +1,13 @@
1
+ @use '@sbercloud/figma-tokens-cloud-platform/build/scss/components/styles-tokens-element' as ste;
2
+
3
+ .searchSettings {
4
+ border-left: 1px solid ste.$sys-neutral-decor-default;
5
+ height: 100%;
6
+ display: flex;
7
+ flex-direction: column;
8
+ justify-content: center;
9
+ }
10
+
11
+ .searchSettingsButton {
12
+ margin-left: ste.$dimension-1m;
13
+ }
@@ -0,0 +1,3 @@
1
+ export * from './SearchDesktop';
2
+ export * from './SearchMobile';
3
+ export * from './types';
@@ -0,0 +1,20 @@
1
+ import { LinksGroup } from '../types';
2
+
3
+ export type SearchHandler = (searchValue: string, items: LinksGroup[]) => LinksGroup[] | undefined;
4
+ export type SearchFunction = {
5
+ id: string;
6
+ label: string;
7
+ handler: SearchHandler;
8
+ };
9
+
10
+ export type SearchProps = {
11
+ searchValue: string;
12
+ // Колбек на измение значения в поиске
13
+ onSearchValueChange(value: string): void;
14
+ // Опции для чипов
15
+ searchFunctions: SearchFunction[];
16
+ // Колбек на смену функции
17
+ onChangeSearchFn(id: string): void;
18
+ // Выбранная функция (по id из searchFunctions)
19
+ searchFn?: string;
20
+ };
@@ -0,0 +1,212 @@
1
+ import Fuse from 'fuse.js';
2
+ import { useMemo, useState } from 'react';
3
+
4
+ import { useLocale } from '@cloud-ru/uikit-product-locale';
5
+
6
+ import { InnerLink, LinksGroup } from '../types';
7
+ import { SearchFunction, SearchProps } from './types';
8
+
9
+ export enum SearchGroupsAccessor {
10
+ GroupLabelText = 'label.text',
11
+ ItemLabelText = 'items.label',
12
+ ItemAliases = 'items.aliases',
13
+ }
14
+
15
+ function matchSearchString(value: string, search: string) {
16
+ return value.trim().toLowerCase().includes(search.trim().toLowerCase());
17
+ }
18
+
19
+ const prepareItemAccessorKey = (groupId: string, alias: string): string => `${groupId}-${alias}`;
20
+
21
+ type ItemsMap = Record<string, InnerLink>;
22
+
23
+ function createItemsMap(links: LinksGroup[]): ItemsMap {
24
+ const itemsMap: ItemsMap = {};
25
+
26
+ links.forEach(group => {
27
+ group.items.forEach(item => {
28
+ item.aliases.forEach(alias => {
29
+ const key = prepareItemAccessorKey(group.id, alias);
30
+ itemsMap[key] = item;
31
+ });
32
+ });
33
+ });
34
+
35
+ return itemsMap;
36
+ }
37
+
38
+ const enCharacters = "qwertyuiop[]asdfghjkl;'zxcvbnm,./`";
39
+ const ruCharacters = 'йцукенгшщзхъфывапролджэячсмитьбю.ё';
40
+
41
+ const enToRuMap: Record<string, string> = {};
42
+ const ruToEnMap: Record<string, string> = {};
43
+
44
+ for (let i = 0; i < enCharacters.length; i++) {
45
+ enToRuMap[enCharacters[i]] = ruCharacters[i];
46
+ ruToEnMap[ruCharacters[i]] = enCharacters[i];
47
+ }
48
+
49
+ function convertLayout(text: string, direction: 'en-ru' | 'ru-en' = 'en-ru') {
50
+ const map = direction === 'en-ru' ? enToRuMap : ruToEnMap;
51
+ return text
52
+ .split('')
53
+ .map(ch => map[ch] ?? ch)
54
+ .join('');
55
+ }
56
+
57
+ function isCyrillic(text: string): boolean {
58
+ return /[а-яё]/i.test(text);
59
+ }
60
+
61
+ function isLatin(text: string): boolean {
62
+ return /[a-z]/i.test(text);
63
+ }
64
+
65
+ export function toggleLayout(text: string): string {
66
+ const lowercaseValue = text.toLowerCase();
67
+
68
+ if (isCyrillic(lowercaseValue)) {
69
+ return convertLayout(lowercaseValue, 'ru-en');
70
+ }
71
+
72
+ if (isLatin(lowercaseValue)) {
73
+ return convertLayout(lowercaseValue, 'en-ru');
74
+ }
75
+
76
+ return text;
77
+ }
78
+
79
+ export function useSearch(): SearchProps {
80
+ const [searchValue, onSearchValueChange] = useState<string>('');
81
+
82
+ const { t } = useLocale('Header');
83
+
84
+ const [searchFn, onChangeSearchFn] = useState<string>('fuzzy');
85
+
86
+ const searchFunctions: SearchFunction[] = useMemo(
87
+ () => [
88
+ {
89
+ id: 'fuzzy',
90
+ label: t('searchSettingsFuzzyChipLabel'),
91
+ handler: (searchValue, links) => {
92
+ if (!searchValue) {
93
+ return links;
94
+ }
95
+
96
+ const itemsMap = createItemsMap(links);
97
+ const linksFuse = new Fuse(links, {
98
+ keys: Object.values(SearchGroupsAccessor),
99
+ includeMatches: true,
100
+ threshold: 0.3,
101
+ });
102
+
103
+ let fuseSearchResults = linksFuse.search(searchValue);
104
+
105
+ if (fuseSearchResults.length < 1) {
106
+ const fixedLayoutValue = toggleLayout(searchValue);
107
+ fuseSearchResults = linksFuse.search(fixedLayoutValue);
108
+ }
109
+
110
+ return fuseSearchResults.reduce((accResult, fuseResult) => {
111
+ if (!fuseResult.matches) {
112
+ return accResult;
113
+ }
114
+
115
+ const isMatchByGroup = fuseResult.matches.find(match => match.key === SearchGroupsAccessor.GroupLabelText);
116
+ if (isMatchByGroup) {
117
+ accResult.push(fuseResult.item);
118
+ return accResult;
119
+ }
120
+
121
+ const group = fuseResult.item;
122
+
123
+ const originalGroupIndex = fuseResult.refIndex;
124
+ const itemsInnerMap: Record<string, InnerLink> = {};
125
+ const items: InnerLink[] = [];
126
+
127
+ fuseResult.matches.forEach(match => {
128
+ if (match.refIndex === undefined) {
129
+ return;
130
+ }
131
+
132
+ switch (match.key) {
133
+ case SearchGroupsAccessor.ItemLabelText: {
134
+ const item = links[originalGroupIndex].items[match.refIndex];
135
+ if (item && !itemsInnerMap[item.id]) {
136
+ itemsInnerMap[item.id] = item;
137
+ items.push(item);
138
+ }
139
+ break;
140
+ }
141
+
142
+ case SearchGroupsAccessor.ItemAliases: {
143
+ if (!match.value) {
144
+ break;
145
+ }
146
+
147
+ const groupId = fuseResult.item.id;
148
+ const alias = match.value;
149
+ const key = prepareItemAccessorKey(groupId, alias);
150
+
151
+ const item = itemsMap[key];
152
+ if (item && !itemsInnerMap[item.id]) {
153
+ itemsInnerMap[item.id] = item;
154
+ items.push(item);
155
+ }
156
+ break;
157
+ }
158
+
159
+ case SearchGroupsAccessor.GroupLabelText:
160
+ default:
161
+ return;
162
+ }
163
+ });
164
+
165
+ if (items.length > 0) {
166
+ accResult.push({
167
+ ...group,
168
+ items,
169
+ });
170
+ }
171
+
172
+ return accResult;
173
+ }, [] as LinksGroup[]);
174
+ },
175
+ },
176
+ {
177
+ id: 'precise',
178
+ label: t('searchSettingsPreciseChipLabel'),
179
+ handler: (searchValue, links) => {
180
+ if (!searchValue || links.length < 1) {
181
+ return links;
182
+ }
183
+
184
+ return links.reduce((result, group) => {
185
+ if (group.label && matchSearchString(group.label.text, searchValue)) {
186
+ result.push(group);
187
+ return result;
188
+ }
189
+
190
+ const items = group.items.filter(item => matchSearchString(item.label, searchValue));
191
+
192
+ if (items.length > 0) {
193
+ result.push({ ...group, items });
194
+ return result;
195
+ }
196
+
197
+ return result;
198
+ }, [] as LinksGroup[]);
199
+ },
200
+ },
201
+ ],
202
+ [t],
203
+ );
204
+
205
+ return {
206
+ searchValue,
207
+ onSearchValueChange,
208
+ searchFunctions,
209
+ onChangeSearchFn,
210
+ searchFn,
211
+ };
212
+ }
@@ -0,0 +1,135 @@
1
+ import debounce from 'lodash.debounce';
2
+ import { useMemo, useRef } from 'react';
3
+
4
+ import { useLocale } from '@cloud-ru/uikit-product-locale';
5
+ import { BaseItemProps } from '@snack-uikit/list';
6
+
7
+ import { SearchHandler } from './Search/types';
8
+ import styles from './styles.module.scss';
9
+ import { InnerLink, LinksGroup, MainMenuProps } from './types';
10
+
11
+ export function useHighlight(className: string) {
12
+ const element = useRef<HTMLElement>();
13
+
14
+ const highlight = useMemo(
15
+ () => {
16
+ const scheduleHighlight = debounce(() => {
17
+ element.current?.classList.add(className);
18
+ setTimeout(
19
+ () => {
20
+ element.current?.classList.remove(className);
21
+ element.current = undefined;
22
+ },
23
+ 300,
24
+ { trailing: false },
25
+ );
26
+ }, 80);
27
+
28
+ return (elementToHighlight?: HTMLElement | null) => {
29
+ if (elementToHighlight) {
30
+ element.current = elementToHighlight;
31
+ }
32
+ scheduleHighlight();
33
+ };
34
+ },
35
+ // eslint-disable-next-line react-hooks/exhaustive-deps
36
+ [],
37
+ );
38
+
39
+ return highlight;
40
+ }
41
+
42
+ type UseMenuItemsProps = Pick<MainMenuProps, 'favorite' | 'serviceGroups' | 'search'>;
43
+
44
+ export function useMenuItems({ search, serviceGroups, favorite }: UseMenuItemsProps) {
45
+ const { t } = useLocale('Header');
46
+
47
+ const { searchValue = '', searchFn, searchFunctions, onSearchValueChange } = search || {};
48
+
49
+ const searchRef = useRef<HTMLInputElement>(null);
50
+ const scrollRef = useRef<HTMLDivElement>(null);
51
+
52
+ const highlight = useHighlight(styles.highlight);
53
+
54
+ const groupWithFavorites = useMemo(() => {
55
+ if (!favorite || !favorite.value) {
56
+ return serviceGroups;
57
+ }
58
+
59
+ const flatMapItems = serviceGroups.flatMap(serviceGroup => serviceGroup.items);
60
+
61
+ const favoriteServices = favorite.value.reduce((acc, cur) => {
62
+ const item = flatMapItems.find(item => item.id === cur);
63
+ if (item) {
64
+ acc.push(item);
65
+ }
66
+ return acc;
67
+ }, [] as InnerLink[]);
68
+
69
+ return [
70
+ {
71
+ id: 'favorite',
72
+ label: {
73
+ text: t('favorite'),
74
+ },
75
+ items: favoriteServices,
76
+ } as LinksGroup,
77
+ ].concat(serviceGroups);
78
+ }, [favorite, serviceGroups, t]);
79
+
80
+ const groupItems: BaseItemProps[] = groupWithFavorites
81
+ .filter(group => group.items.length > 0)
82
+ .map(({ id, label: { text } }) => ({
83
+ id,
84
+ content: {
85
+ option: text,
86
+ truncate: {
87
+ option: 2,
88
+ },
89
+ },
90
+
91
+ onClick() {
92
+ onSearchValueChange?.('');
93
+
94
+ setTimeout(() => {
95
+ // TODO: remove or move
96
+ // eslint-disable-next-line @cloud-ru/ssr-safe-react/domApi
97
+ const element = document.getElementById(id);
98
+ if (!element) return;
99
+
100
+ scrollRef.current?.scrollTo({
101
+ left: 0,
102
+ top: element.offsetTop - (searchRef.current?.offsetHeight || 0),
103
+ behavior: 'smooth',
104
+ });
105
+
106
+ // Задержка approximately равна времени скроллинга
107
+ setTimeout(() => {
108
+ highlight(element);
109
+ }, 500);
110
+ }, 0);
111
+ },
112
+ }));
113
+
114
+ const searchFnMap = searchFunctions?.reduce(
115
+ (acc, cur) => {
116
+ acc[cur.id] = cur.handler;
117
+
118
+ return acc;
119
+ },
120
+ {} as Record<string, SearchHandler>,
121
+ );
122
+
123
+ const itemsWithoutEmptyGroups = groupWithFavorites.filter(group => group.items.length > 0);
124
+
125
+ const resultItems =
126
+ (searchFn ? searchFnMap?.[searchFn] : searchFunctions?.[0]?.handler)?.(searchValue, itemsWithoutEmptyGroups) ||
127
+ itemsWithoutEmptyGroups;
128
+
129
+ return {
130
+ resultItems,
131
+ groupItems,
132
+ searchRef,
133
+ scrollRef,
134
+ };
135
+ }
@@ -0,0 +1,4 @@
1
+ export * from './MainMenu';
2
+ export * from './types';
3
+ export * from './Search/useSearch';
4
+ export * from './Search/types';
@@ -0,0 +1,28 @@
1
+ .highlight {
2
+ animation: shake-animation 300ms ease 1;
3
+ transform-origin: 100% 100%;
4
+ }
5
+
6
+ @keyframes shake-animation {
7
+ 0% {
8
+ transform: translate(0, 0);
9
+ }
10
+ 18% {
11
+ transform: translate(5px, 0);
12
+ }
13
+ 35% {
14
+ transform: translate(0, 0);
15
+ }
16
+ 53% {
17
+ transform: translate(5px, 0);
18
+ }
19
+ 71% {
20
+ transform: translate(0, 0);
21
+ }
22
+ 89% {
23
+ transform: translate(3px, 0);
24
+ }
25
+ 100% {
26
+ transform: translate(0, 0);
27
+ }
28
+ }
@@ -0,0 +1,62 @@
1
+ import { JSXElementConstructor, MouseEvent, MouseEventHandler, ReactNode } from 'react';
2
+
3
+ import { CardServiceSmallProps } from '@cloud-ru/uikit-product-card-predefined';
4
+ import { ListProps } from '@snack-uikit/list';
5
+
6
+ import { SearchProps } from './Search/types';
7
+
8
+ export type InnerLink = {
9
+ id: string;
10
+ icon: JSXElementConstructor<{
11
+ size?: number;
12
+ className?: string;
13
+ }>;
14
+ label: string;
15
+ onClick(e?: MouseEvent<HTMLElement>): void;
16
+ href?: string;
17
+ disabled?: boolean;
18
+ hidden?: boolean;
19
+ badge?: CardServiceSmallProps['promoBadge'];
20
+ aliases: string[];
21
+ };
22
+
23
+ type TitleStatic = {
24
+ text: string;
25
+ onClick?: never;
26
+ };
27
+
28
+ type TitleClickable = {
29
+ text: string;
30
+ onClick?: MouseEventHandler<HTMLAnchorElement>;
31
+ };
32
+
33
+ export type LinksGroupTitle = TitleStatic | TitleClickable;
34
+
35
+ export type LinksGroup = {
36
+ id: string;
37
+ label: LinksGroupTitle;
38
+ hidden?: boolean;
39
+ items: InnerLink[];
40
+ };
41
+
42
+ export type MainMenuProps = {
43
+ open?: boolean;
44
+ setOpen?(open: boolean): void;
45
+
46
+ leftTop?: ReactNode;
47
+ rightTop?: ReactNode;
48
+
49
+ settingItems: ListProps['items'];
50
+ serviceGroups: LinksGroup[];
51
+
52
+ onLinkChange?(value: string): void;
53
+
54
+ favorite?: {
55
+ value: string[];
56
+ onChange: (productId: string) => (addingValue: boolean) => void;
57
+ };
58
+
59
+ search?: SearchProps;
60
+
61
+ isMobile?: boolean;
62
+ };
@@ -0,0 +1,21 @@
1
+ import { Breadcrumbs, BreadcrumbsProps } from '@snack-uikit/breadcrumbs';
2
+
3
+ import styles from './styles.module.scss';
4
+
5
+ type PathBreadcrumbsProps = {
6
+ items: BreadcrumbsProps['items'];
7
+ isMobile?: boolean;
8
+ };
9
+
10
+ export function PathBreadcrumbs({ isMobile, items }: PathBreadcrumbsProps) {
11
+ return (
12
+ <Breadcrumbs
13
+ items={items}
14
+ className={styles.breadcrumbs}
15
+ inactiveLastItem={items.length > 1}
16
+ separator='/'
17
+ size={isMobile ? 'xs' : 's'}
18
+ data-test-id='header__breadcrumbs'
19
+ />
20
+ );
21
+ }
@@ -0,0 +1 @@
1
+ export * from './PathBreadcrumbs';
@@ -0,0 +1,10 @@
1
+ @use '@sbercloud/figma-tokens-cloud-platform/build/scss/components/styles-tokens-element' as ste;
2
+
3
+ .breadcrumbs {
4
+ /* stylelint-disable-next-line declaration-no-important */
5
+ padding: ste.$dimension-1m !important;
6
+ /* stylelint-disable-next-line declaration-no-important */
7
+ margin: calc(0px - #{ste.$dimension-1m}) 0 !important;
8
+
9
+ min-width: 0;
10
+ }
@@ -0,0 +1,32 @@
1
+ import { JSXElementConstructor, PropsWithChildren } from 'react';
2
+
3
+ import { WithSupportProps } from '@cloud-ru/uikit-product-utils';
4
+
5
+ import styled from './styles.module.scss';
6
+
7
+ export type ContainerProps = PropsWithChildren<
8
+ WithSupportProps<{
9
+ className?: string;
10
+ }>
11
+ >;
12
+
13
+ export function Container({ children, ...otherProps }: ContainerProps) {
14
+ return (
15
+ <div className={styled.container} {...otherProps}>
16
+ {children}
17
+ </div>
18
+ );
19
+ }
20
+
21
+ export type IconComponentProps = {
22
+ className?: string;
23
+ };
24
+
25
+ export const getPlatformIconComponent = (Icon: JSXElementConstructor<{ size: number }>) =>
26
+ function IconComponent(props: IconComponentProps) {
27
+ return (
28
+ <Container {...props}>
29
+ <Icon size={24} />
30
+ </Container>
31
+ );
32
+ };
@@ -0,0 +1,8 @@
1
+ import { AdvancedSVG, EvolutionSVG, MlSpaceSVG, VmwareSVG } from '@cloud-ru/uikit-product-icons';
2
+
3
+ import { getPlatformIconComponent } from './Container';
4
+
5
+ export const AdvancedPlatformLogo = getPlatformIconComponent(AdvancedSVG);
6
+ export const EnterprisePlatformLogo = getPlatformIconComponent(VmwareSVG);
7
+ export const EvolutionPlatformLogo = getPlatformIconComponent(EvolutionSVG);
8
+ export const MLSpacePlatformLogo = getPlatformIconComponent(MlSpaceSVG);
@@ -0,0 +1,13 @@
1
+ @use '@sbercloud/figma-tokens-cloud-platform/build/scss/styles-theme-variables' as var;
2
+
3
+ .container {
4
+ width: 24px;
5
+ height: 24px;
6
+ color: var.$sys-primary-on-accent;
7
+ fill: var.$sys-primary-on-accent;
8
+ background-color: var.$sys-neutral-accent-default;
9
+ border-radius: var.$dimension-050m;
10
+ display: flex;
11
+ align-items: center;
12
+ justify-content: center;
13
+ }