@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,35 @@
1
+ @use '@sbercloud/figma-tokens-cloud-platform/build/scss/styles-theme-variables' as var;
2
+
3
+ .card {
4
+ background-color: var.$sys-neutral-background1-level;
5
+ display: flex;
6
+ flex-direction: column;
7
+ padding: var.$dimension-2m;
8
+ gap: var.$dimension-1m;
9
+ border-radius: var.$dimension-1m;
10
+ }
11
+
12
+ .cardTitle {
13
+ @include var.composite-var(var.$sans-title-m);
14
+
15
+ color: var.$sys-neutral-text-main;
16
+ }
17
+
18
+ .cardBody {
19
+ display: grid;
20
+ grid-template-columns: repeat(2, minmax(150px, 1fr));
21
+ gap: var.$dimension-1m;
22
+
23
+ &[data-mobile] {
24
+ grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
25
+ }
26
+ }
27
+
28
+ .noData {
29
+ @include var.composite-var(var.$sans-body-l);
30
+
31
+ color: var.$sys-neutral-text-light;
32
+ display: flex;
33
+ justify-content: center;
34
+ padding: var.$dimension-2m;
35
+ }
@@ -0,0 +1,51 @@
1
+ import { MainMenuSVG } from '@cloud-ru/uikit-product-icons';
2
+ import { ButtonFunction } from '@snack-uikit/button';
3
+ import { useValueControl } from '@snack-uikit/utils';
4
+
5
+ import { MenuDesktop } from './MenuDesktop';
6
+ import { MenuMobile } from './MenuMobile';
7
+ import { MainMenuProps } from './types';
8
+
9
+ export function MainMenu({
10
+ open: openProp,
11
+ setOpen: setOpenProp,
12
+ settingItems,
13
+ leftTop,
14
+ rightTop,
15
+ serviceGroups,
16
+ favorite,
17
+ search,
18
+ isMobile,
19
+ onLinkChange,
20
+ disabled,
21
+ }: MainMenuProps & { disabled?: boolean }) {
22
+ const [open = false, setOpen] = useValueControl<boolean>({ value: openProp, onChange: setOpenProp });
23
+
24
+ const MenuComponent = isMobile ? MenuMobile : MenuDesktop;
25
+
26
+ return (
27
+ <>
28
+ <ButtonFunction
29
+ disabled={disabled}
30
+ size='m'
31
+ icon={<MainMenuSVG />}
32
+ onClick={() => {
33
+ setOpen(true);
34
+ }}
35
+ data-test-id='header__drawer-menu-button'
36
+ />
37
+
38
+ <MenuComponent
39
+ onLinkChange={onLinkChange}
40
+ settingItems={settingItems}
41
+ serviceGroups={serviceGroups}
42
+ search={search}
43
+ leftTop={leftTop}
44
+ rightTop={rightTop}
45
+ favorite={favorite}
46
+ open={open}
47
+ setOpen={setOpen}
48
+ />
49
+ </>
50
+ );
51
+ }
@@ -0,0 +1,120 @@
1
+ import cn from 'classnames';
2
+ import { useMemo } from 'react';
3
+
4
+ import { DrawerCustom } from '@snack-uikit/drawer';
5
+ import { isBaseItemProps, List } from '@snack-uikit/list';
6
+ import { Scroll } from '@snack-uikit/scroll';
7
+ import { useValueControl } from '@snack-uikit/utils';
8
+
9
+ import { Content } from '../Content';
10
+ import { useMenuItems } from '../hooks';
11
+ import { SearchDesktop } from '../Search';
12
+ import { MainMenuProps } from '../types';
13
+ import styles from './styles.module.scss';
14
+
15
+ export function MenuDesktop({
16
+ open: openProp,
17
+ setOpen: setOpenProp,
18
+ settingItems,
19
+ leftTop,
20
+ rightTop,
21
+ serviceGroups,
22
+ favorite,
23
+ search,
24
+ onLinkChange,
25
+ }: MainMenuProps) {
26
+ const [open = false, setOpen] = useValueControl<boolean>({ value: openProp, onChange: setOpenProp });
27
+
28
+ const { groupItems, scrollRef, searchRef, resultItems } = useMenuItems({
29
+ serviceGroups,
30
+ search,
31
+ favorite,
32
+ });
33
+
34
+ const isInitialEmptyCards = serviceGroups?.length === 0;
35
+ const isNeedRightBlock = rightTop || !isInitialEmptyCards;
36
+
37
+ const settingItemsWithClassName = settingItems.filter(isBaseItemProps).map(item => ({
38
+ ...item,
39
+ className: styles.item,
40
+ }));
41
+
42
+ const groupItemsWithClass = useMemo(
43
+ () =>
44
+ groupItems.map(item => ({
45
+ ...item,
46
+ className: styles.item,
47
+ })),
48
+ [groupItems],
49
+ );
50
+
51
+ return (
52
+ <DrawerCustom
53
+ open={open}
54
+ onClose={() => {
55
+ setOpen(false);
56
+ }}
57
+ size={isNeedRightBlock ? 'm' : 's'}
58
+ position='left'
59
+ className={styles.drawer}
60
+ rootClassName={styles.drawerRoot}
61
+ data-test-id='header__drawer-menu'
62
+ data-small={!isNeedRightBlock || undefined}
63
+ >
64
+ <div className={styles.menu}>
65
+ <div className={styles.left} data-test-id='header__drawer-menu__left'>
66
+ {leftTop && <div className={styles.leftTop}>{leftTop}</div>}
67
+
68
+ {!isInitialEmptyCards && (
69
+ <List
70
+ items={groupItemsWithClass}
71
+ pinBottom={settingItemsWithClassName}
72
+ scroll
73
+ size='m'
74
+ barHideStrategy='never'
75
+ className={styles.list}
76
+ />
77
+ )}
78
+
79
+ {!leftTop && isInitialEmptyCards && <div />}
80
+
81
+ {isInitialEmptyCards && settingItemsWithClassName.length > 0 && (
82
+ <div className={cn(styles.list, styles.halfList)}>
83
+ <List
84
+ items={settingItems.filter(isBaseItemProps).map(item => ({
85
+ ...item,
86
+ className: styles.item,
87
+ }))}
88
+ size='m'
89
+ barHideStrategy='never'
90
+ />
91
+ </div>
92
+ )}
93
+ </div>
94
+
95
+ {isNeedRightBlock && (
96
+ <div className={styles.right} data-test-id='header__drawer-menu__right'>
97
+ <Scroll paddingAbsolute className={styles.scroll} ref={scrollRef} barHideStrategy='never'>
98
+ {isInitialEmptyCards && rightTop && <div className={styles.bannersWrap}>{rightTop}</div>}
99
+
100
+ {!isInitialEmptyCards && (
101
+ <Content
102
+ onClose={() => {
103
+ setOpen(false);
104
+ }}
105
+ className={styles.rightContent}
106
+ search={search && <SearchDesktop {...search} ref={searchRef} />}
107
+ searchValue={search && search.searchValue}
108
+ banners={rightTop}
109
+ favorite={favorite}
110
+ serviceGroups={resultItems}
111
+ onLinkChange={onLinkChange}
112
+ />
113
+ )}
114
+ </Scroll>
115
+ </div>
116
+ )}
117
+ </div>
118
+ </DrawerCustom>
119
+ );
120
+ }
@@ -0,0 +1 @@
1
+ export * from './MenuDesktop';
@@ -0,0 +1,108 @@
1
+ @use '@sbercloud/figma-tokens-cloud-platform/build/scss/styles-theme-variables' as var;
2
+
3
+ .drawer {
4
+ & [data-test-id='drawer__close-button'] {
5
+ display: none;
6
+ }
7
+
8
+ svg {
9
+ fill: currentColor;
10
+ }
11
+ }
12
+
13
+ .scroll {
14
+ padding: 28px 28px 0 12px;
15
+ box-sizing: border-box;
16
+ }
17
+
18
+ .left {
19
+ display: flex;
20
+ flex-direction: column;
21
+ padding: 32px 16px 24px 32px;
22
+ gap: 16px;
23
+ justify-content: space-between;
24
+ position: relative;
25
+ box-sizing: border-box;
26
+ width: 272px;
27
+ }
28
+
29
+ .drawerRoot {
30
+ & [data-test-id='header__drawer-menu'][data-small] {
31
+ width: 316px;
32
+
33
+ .left {
34
+ width: 316px;
35
+ }
36
+ }
37
+
38
+ & [data-test-id='header__drawer-menu']:not([data-small]) {
39
+ min-width: 744px;
40
+ overflow: hidden;
41
+ }
42
+ }
43
+
44
+ .leftTop {
45
+ display: flex;
46
+ flex-direction: column;
47
+ gap: var.$dimension-1m;
48
+ flex-grow: 1;
49
+ min-height: var.$dimension-7m;
50
+ }
51
+
52
+ .right {
53
+ display: flex;
54
+ flex-direction: column;
55
+ height: 100dvh;
56
+ flex: 1;
57
+ min-width: 0;
58
+
59
+ position: relative;
60
+
61
+ &::before {
62
+ content: '';
63
+ position: absolute;
64
+ top: 32px;
65
+ left: 0;
66
+ background-color: var.$sys-neutral-decor-default;
67
+ width: 1px;
68
+ bottom: 24px;
69
+ }
70
+ }
71
+
72
+ .rightContent {
73
+ display: flex;
74
+ flex-direction: column;
75
+ gap: 8px;
76
+ padding: 4px;
77
+ padding-bottom: 24px;
78
+ }
79
+
80
+ .menu {
81
+ display: flex;
82
+ height: 100%;
83
+ box-sizing: border-box;
84
+ background-color: var.$sys-neutral-background;
85
+ }
86
+
87
+ .list {
88
+ /* stylelint-disable-next-line declaration-no-important */
89
+ margin-left: -31px !important;
90
+ /* stylelint-disable-next-line declaration-no-important */
91
+ margin-right: -16px !important;
92
+ }
93
+
94
+ .halfList {
95
+ border-top: 1px solid var.$sys-neutral-decor-default;
96
+ padding-top: 8px;
97
+ }
98
+
99
+ .item {
100
+ /* stylelint-disable-next-line declaration-no-important */
101
+ padding-left: 22px !important;
102
+ box-sizing: border-box;
103
+ }
104
+
105
+ .bannersWrap {
106
+ padding: var.$dimension-050m;
107
+ padding-top: var.$dimension-025m;
108
+ }
@@ -0,0 +1,83 @@
1
+ import { useLocale } from '@cloud-ru/uikit-product-locale';
2
+ import { MobileDrawerCustom } from '@cloud-ru/uikit-product-mobile-drawer';
3
+ import { isBaseItemProps, List } from '@snack-uikit/list';
4
+ import { Scroll } from '@snack-uikit/scroll';
5
+ import { useValueControl } from '@snack-uikit/utils';
6
+
7
+ import { Content } from '../Content';
8
+ import { useMenuItems } from '../hooks';
9
+ import { SearchMobile } from '../Search';
10
+ import { MainMenuProps } from '../types';
11
+ import styles from './styles.module.scss';
12
+
13
+ export function MenuMobile({
14
+ open: openProp,
15
+ setOpen: setOpenProp,
16
+ settingItems,
17
+ leftTop,
18
+ rightTop,
19
+ serviceGroups,
20
+ favorite,
21
+ search,
22
+ onLinkChange,
23
+ }: MainMenuProps) {
24
+ const [open = false, setOpen] = useValueControl<boolean>({ value: openProp, onChange: setOpenProp });
25
+
26
+ const { t } = useLocale('Header');
27
+
28
+ const isInitialEmptyCards = serviceGroups?.length === 0;
29
+
30
+ const { searchRef, resultItems } = useMenuItems({
31
+ serviceGroups,
32
+ search,
33
+ favorite,
34
+ });
35
+
36
+ return (
37
+ <MobileDrawerCustom
38
+ open={open}
39
+ onClose={() => {
40
+ setOpen(false);
41
+ }}
42
+ className={styles.drawerMobile}
43
+ swipeEnabled={false}
44
+ data-test-id='header__drawer-menu-mobile'
45
+ closeOnPopstate
46
+ >
47
+ <MobileDrawerCustom.Header title={t('navigation')} />
48
+
49
+ <Scroll barHideStrategy='never'>
50
+ <div className={styles.scrollMobile}>
51
+ {top && <div className={styles.rightContent}>{leftTop}</div>}
52
+
53
+ {!isInitialEmptyCards && (
54
+ <Content
55
+ isMobile
56
+ onClose={() => {
57
+ setOpen(false);
58
+ }}
59
+ onLinkChange={onLinkChange}
60
+ search={search && <SearchMobile {...search} ref={searchRef} />}
61
+ className={styles.rightContent}
62
+ searchValue={search && search.searchValue}
63
+ banners={rightTop}
64
+ favorite={favorite}
65
+ serviceGroups={resultItems}
66
+ />
67
+ )}
68
+
69
+ {isInitialEmptyCards && rightTop && <div className={styles.bannersWrap}>{rightTop}</div>}
70
+
71
+ {settingItems.length > 0 && (
72
+ <List
73
+ className={styles.settings}
74
+ items={[{ type: 'group', items: [], divider: true }, ...settingItems.filter(isBaseItemProps)]}
75
+ size='m'
76
+ barHideStrategy='never'
77
+ />
78
+ )}
79
+ </div>
80
+ </Scroll>
81
+ </MobileDrawerCustom>
82
+ );
83
+ }
@@ -0,0 +1 @@
1
+ export * from './MenuMobile';
@@ -0,0 +1,26 @@
1
+ @use '@sbercloud/figma-tokens-cloud-platform/build/scss/components/styles-tokens-element' as ste;
2
+
3
+ .rightContent {
4
+ display: flex;
5
+ flex-direction: column;
6
+ gap: ste.$dimension-1m;
7
+ padding-top: 4px;
8
+ }
9
+
10
+ .drawerMobile {
11
+ /* stylelint-disable-next-line declaration-no-important */
12
+ background-color: ste.$sys-neutral-background !important;
13
+ }
14
+
15
+ .scrollMobile {
16
+ padding: ste.$dimension-2m;
17
+ padding-top: 0;
18
+ }
19
+
20
+ .bannersWrap {
21
+ margin-top: ste.$dimension-1m;
22
+ }
23
+
24
+ .settings {
25
+ margin-top: ste.$dimension-1m;
26
+ }
@@ -0,0 +1,46 @@
1
+ import { forwardRef, useState } from 'react';
2
+
3
+ import { useLocale } from '@cloud-ru/uikit-product-locale';
4
+ import { ChipToggle } from '@snack-uikit/chips';
5
+ import { Search } from '@snack-uikit/search';
6
+
7
+ import { SearchSettingsButton } from '../SearchSettingsButton';
8
+ import { SearchProps } from '../types';
9
+ import styles from './styles.module.scss';
10
+
11
+ export const SearchDesktop = forwardRef<HTMLDivElement, SearchProps>(
12
+ ({ searchValue, searchFn, searchFunctions, onChangeSearchFn, onSearchValueChange }, ref) => {
13
+ const { t } = useLocale('Header');
14
+
15
+ const [areSearchSettingsVisible, setAreSearchSettingsVisible] = useState<boolean>(false);
16
+
17
+ return (
18
+ <div className={styles.searchItem} ref={ref}>
19
+ <Search
20
+ size='m'
21
+ outline
22
+ placeholder={t('searchByServices')}
23
+ value={searchValue}
24
+ onChange={onSearchValueChange}
25
+ data-test-id='header__drawer-menu__search'
26
+ className={styles.search}
27
+ postfix={<SearchSettingsButton onClick={() => setAreSearchSettingsVisible(prevOpen => !prevOpen)} />}
28
+ />
29
+ {areSearchSettingsVisible && (
30
+ <div className={styles.searchSettingsChips}>
31
+ {searchFunctions.map(item => (
32
+ <ChipToggle
33
+ key={item.id}
34
+ label={item.label}
35
+ checked={searchFn === item.id}
36
+ onChange={() => onChangeSearchFn(item.id)}
37
+ data-test-id={`header__drawer-menu__search-option-${item.id}`}
38
+ size='xs'
39
+ />
40
+ ))}
41
+ </div>
42
+ )}
43
+ </div>
44
+ );
45
+ },
46
+ );
@@ -0,0 +1 @@
1
+ export * from './SearchDesktop';
@@ -0,0 +1,21 @@
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;
8
+ background-color: ste.$sys-neutral-background;
9
+ padding: 4px;
10
+ padding-bottom: ste.$dimension-1m;
11
+
12
+ display: flex;
13
+ flex-direction: column;
14
+ gap: ste.$dimension-1m;
15
+ }
16
+
17
+ .searchSettingsChips {
18
+ display: flex;
19
+ flex-direction: row;
20
+ gap: ste.$dimension-050m;
21
+ }
@@ -0,0 +1,102 @@
1
+ import { forwardRef, useState } from 'react';
2
+
3
+ import { SearchSVG } from '@cloud-ru/uikit-product-icons';
4
+ import { useLocale } from '@cloud-ru/uikit-product-locale';
5
+ import { MobileModalCustom } from '@cloud-ru/uikit-product-mobile-modal';
6
+ import { ButtonElevated } from '@snack-uikit/button';
7
+ import { List } from '@snack-uikit/list';
8
+ import { Search } from '@snack-uikit/search';
9
+ import { Typography } from '@snack-uikit/typography';
10
+
11
+ import { SearchSettingsButton } from '../SearchSettingsButton';
12
+ import { SearchProps } from '../types';
13
+ import { SEARCH_TRANSITION_TIMEOUT } from './constants';
14
+ import { useSearchAnimation } from './hooks';
15
+ import styles from './styles.module.scss';
16
+
17
+ export const SearchMobile = forwardRef<HTMLDivElement, SearchProps>(
18
+ ({ searchValue, searchFn, searchFunctions, onChangeSearchFn, onSearchValueChange }, ref) => {
19
+ const { t } = useLocale('Header');
20
+
21
+ const [areSearchSettingsVisible, setAreSearchSettingsVisible] = useState<boolean>(false);
22
+
23
+ const {
24
+ searchRef: newSearchRef,
25
+ animationState,
26
+ toggleSearchActive,
27
+ isSearchActive,
28
+ searchInputTabIndex,
29
+ } = useSearchAnimation();
30
+
31
+ return (
32
+ <div className={styles.searchItem} ref={ref}>
33
+ <div
34
+ className={styles.searchWrap}
35
+ style={{
36
+ // eslint-disable-next-line @typescript-eslint/ban-ts-comment
37
+ // @ts-ignore
38
+ '--sc-header-animation-enter': SEARCH_TRANSITION_TIMEOUT.enter,
39
+ '--sc-header-animation-exit': SEARCH_TRANSITION_TIMEOUT.exit,
40
+ }}
41
+ >
42
+ <Typography.SansTitleM>{t('services')}</Typography.SansTitleM>
43
+
44
+ <div
45
+ className={styles.searchMobile}
46
+ data-transition-status={animationState.status}
47
+ data-is-mounted={animationState.isMounted || undefined}
48
+ >
49
+ <Search
50
+ size='m'
51
+ placeholder={t('searchByServices')}
52
+ value={searchValue}
53
+ onChange={onSearchValueChange}
54
+ data-test-id='header__drawer-menu__search'
55
+ ref={newSearchRef}
56
+ tabIndex={searchInputTabIndex}
57
+ postfix={<SearchSettingsButton onClick={() => setAreSearchSettingsVisible(true)} />}
58
+ />
59
+
60
+ <MobileModalCustom
61
+ open={areSearchSettingsVisible}
62
+ onClose={() => setAreSearchSettingsVisible(false)}
63
+ closeOnPopstate
64
+ closeButtonEnabled
65
+ >
66
+ <MobileModalCustom.Header title={t('searchSettingsMobileModalHeader')} />
67
+ <div className={styles.searchModalBody}>
68
+ <List
69
+ className={styles.searchSettingsMobileOptions}
70
+ items={searchFunctions.map(item => ({
71
+ id: item.id,
72
+ content: {
73
+ option: item.label,
74
+ },
75
+ }))}
76
+ size='m'
77
+ selection={{
78
+ mode: 'single',
79
+ value: searchFn,
80
+ onChange: value => {
81
+ onChangeSearchFn(value);
82
+ setAreSearchSettingsVisible(false);
83
+ },
84
+ }}
85
+ />
86
+ </div>
87
+ </MobileModalCustom>
88
+ </div>
89
+
90
+ <ButtonElevated
91
+ size='m'
92
+ className={styles.searchButton}
93
+ icon={<SearchSVG />}
94
+ onClick={toggleSearchActive}
95
+ data-test-id='header__drawer-menu__close-search-icon'
96
+ data-search-active={isSearchActive || undefined}
97
+ />
98
+ </div>
99
+ </div>
100
+ );
101
+ },
102
+ );
@@ -0,0 +1,4 @@
1
+ export const SEARCH_TRANSITION_TIMEOUT = {
2
+ enter: 150,
3
+ exit: 100,
4
+ };
@@ -0,0 +1,43 @@
1
+ import { useEffect, useRef, useState } from 'react';
2
+ import useTransition from 'react-transition-state';
3
+
4
+ import { SEARCH_TRANSITION_TIMEOUT } from './constants';
5
+
6
+ export function useSearchAnimation() {
7
+ const searchRef = useRef<HTMLInputElement>(null);
8
+
9
+ const [isSearchActive, setIsSearchActive] = useState<boolean>(false);
10
+
11
+ const searchInputTabIndex = isSearchActive ? undefined : -1;
12
+
13
+ const [animationState, toggle] = useTransition({
14
+ mountOnEnter: true,
15
+ unmountOnExit: true,
16
+ initialEntered: isSearchActive,
17
+ timeout: SEARCH_TRANSITION_TIMEOUT,
18
+ });
19
+
20
+ useEffect(() => toggle(isSearchActive), [isSearchActive]);
21
+
22
+ const toggleSearchActive = () => setIsSearchActive(prevState => !prevState);
23
+
24
+ useEffect(() => {
25
+ if (isSearchActive) {
26
+ searchRef.current?.focus();
27
+ }
28
+
29
+ return () => {
30
+ if (isSearchActive) {
31
+ setIsSearchActive(false);
32
+ }
33
+ };
34
+ }, [isSearchActive]);
35
+
36
+ return {
37
+ searchRef,
38
+ toggleSearchActive,
39
+ isSearchActive,
40
+ animationState,
41
+ searchInputTabIndex,
42
+ };
43
+ }
@@ -0,0 +1 @@
1
+ export * from './SearchMobile';