@alfalab/core-components-gallery 7.2.3 → 7.3.0

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 (285) hide show
  1. package/Component.js +51 -7
  2. package/Component.js.map +1 -1
  3. package/components/bottom-button/index.css +5 -5
  4. package/components/bottom-button/index.module.css.js +1 -1
  5. package/components/buttons/index.css +5 -5
  6. package/components/buttons/index.d.ts +3 -1
  7. package/components/buttons/index.js +49 -12
  8. package/components/buttons/index.js.map +1 -1
  9. package/components/buttons/index.module.css.js +1 -1
  10. package/components/header/Component.js +1 -0
  11. package/components/header/Component.js.map +1 -1
  12. package/components/header/index.css +3 -2
  13. package/components/header/index.module.css.js +1 -1
  14. package/components/header/index.module.css.js.map +1 -1
  15. package/components/header-info-block/Component.js +2 -1
  16. package/components/header-info-block/Component.js.map +1 -1
  17. package/components/header-info-block/index.css +4 -4
  18. package/components/header-info-block/index.module.css.js +1 -1
  19. package/components/header-mobile/index.css +6 -6
  20. package/components/header-mobile/index.module.css.js +1 -1
  21. package/components/image-preview/Component.js +2 -1
  22. package/components/image-preview/Component.js.map +1 -1
  23. package/components/image-preview/index.css +20 -20
  24. package/components/image-preview/index.module.css.js +1 -1
  25. package/components/image-preview/index.module.css.js.map +1 -1
  26. package/components/image-viewer/hooks.js +3 -2
  27. package/components/image-viewer/hooks.js.map +1 -1
  28. package/components/image-viewer/index.css +30 -31
  29. package/components/image-viewer/index.module.css.js +1 -1
  30. package/components/image-viewer/index.module.css.js.map +1 -1
  31. package/components/image-viewer/single.js +1 -0
  32. package/components/image-viewer/single.js.map +1 -1
  33. package/components/image-viewer/slide.js +3 -2
  34. package/components/image-viewer/slide.js.map +1 -1
  35. package/components/image-viewer/video/index.css +22 -10
  36. package/components/image-viewer/video/index.js +50 -15
  37. package/components/image-viewer/video/index.js.map +1 -1
  38. package/components/image-viewer/video/index.module.css.js +1 -1
  39. package/components/image-viewer/video/index.module.css.js.map +1 -1
  40. package/components/info-bar/Component.js +1 -0
  41. package/components/info-bar/Component.js.map +1 -1
  42. package/components/info-bar/index.css +3 -3
  43. package/components/info-bar/index.module.css.js +1 -1
  44. package/components/navigation-bar/Component.js +56 -26
  45. package/components/navigation-bar/Component.js.map +1 -1
  46. package/components/navigation-bar/index.css +21 -11
  47. package/components/navigation-bar/index.module.css.js +1 -1
  48. package/components/navigation-bar/index.module.css.js.map +1 -1
  49. package/components/subtitles/index.css +3 -3
  50. package/components/subtitles/index.module.css.js +1 -1
  51. package/constants.d.ts +1 -1
  52. package/constants.js +1 -1
  53. package/constants.js.map +1 -1
  54. package/cssm/Component.js +51 -7
  55. package/cssm/Component.js.map +1 -1
  56. package/cssm/components/buttons/index.d.ts +3 -1
  57. package/cssm/components/buttons/index.js +54 -17
  58. package/cssm/components/buttons/index.js.map +1 -1
  59. package/cssm/components/header/Component.js +1 -0
  60. package/cssm/components/header/Component.js.map +1 -1
  61. package/cssm/components/header/index.module.css +2 -1
  62. package/cssm/components/header-info-block/Component.js +2 -1
  63. package/cssm/components/header-info-block/Component.js.map +1 -1
  64. package/cssm/components/image-preview/Component.js +2 -1
  65. package/cssm/components/image-preview/Component.js.map +1 -1
  66. package/cssm/components/image-preview/index.module.css +3 -3
  67. package/cssm/components/image-viewer/hooks.js +3 -2
  68. package/cssm/components/image-viewer/hooks.js.map +1 -1
  69. package/cssm/components/image-viewer/index.module.css +2 -3
  70. package/cssm/components/image-viewer/single.js +1 -0
  71. package/cssm/components/image-viewer/single.js.map +1 -1
  72. package/cssm/components/image-viewer/slide.js +3 -2
  73. package/cssm/components/image-viewer/slide.js.map +1 -1
  74. package/cssm/components/image-viewer/video/index.js +50 -15
  75. package/cssm/components/image-viewer/video/index.js.map +1 -1
  76. package/cssm/components/image-viewer/video/index.module.css +15 -3
  77. package/cssm/components/info-bar/Component.js +1 -0
  78. package/cssm/components/info-bar/Component.js.map +1 -1
  79. package/cssm/components/navigation-bar/Component.js +56 -26
  80. package/cssm/components/navigation-bar/Component.js.map +1 -1
  81. package/cssm/components/navigation-bar/index.module.css +13 -3
  82. package/cssm/constants.d.ts +1 -1
  83. package/cssm/constants.js +1 -1
  84. package/cssm/constants.js.map +1 -1
  85. package/cssm/hooks/use-custom-subtitles.js +57 -11
  86. package/cssm/hooks/use-custom-subtitles.js.map +1 -1
  87. package/cssm/index.js +1 -0
  88. package/cssm/index.js.map +1 -1
  89. package/cssm/types.d.ts +4 -2
  90. package/cssm/utils/index.d.ts +1 -0
  91. package/cssm/utils/index.js +2 -0
  92. package/cssm/utils/index.js.map +1 -1
  93. package/cssm/utils/modern-download.d.ts +6 -0
  94. package/cssm/utils/modern-download.js +113 -0
  95. package/cssm/utils/modern-download.js.map +1 -0
  96. package/esm/Component.js +51 -7
  97. package/esm/Component.js.map +1 -1
  98. package/esm/components/bottom-button/index.css +5 -5
  99. package/esm/components/bottom-button/index.module.css.js +1 -1
  100. package/esm/components/buttons/index.css +5 -5
  101. package/esm/components/buttons/index.d.ts +3 -1
  102. package/esm/components/buttons/index.js +50 -13
  103. package/esm/components/buttons/index.js.map +1 -1
  104. package/esm/components/buttons/index.module.css.js +1 -1
  105. package/esm/components/header/Component.js +1 -0
  106. package/esm/components/header/Component.js.map +1 -1
  107. package/esm/components/header/index.css +3 -2
  108. package/esm/components/header/index.module.css.js +1 -1
  109. package/esm/components/header/index.module.css.js.map +1 -1
  110. package/esm/components/header-info-block/Component.js +2 -1
  111. package/esm/components/header-info-block/Component.js.map +1 -1
  112. package/esm/components/header-info-block/index.css +4 -4
  113. package/esm/components/header-info-block/index.module.css.js +1 -1
  114. package/esm/components/header-mobile/index.css +6 -6
  115. package/esm/components/header-mobile/index.module.css.js +1 -1
  116. package/esm/components/image-preview/Component.js +2 -1
  117. package/esm/components/image-preview/Component.js.map +1 -1
  118. package/esm/components/image-preview/index.css +20 -20
  119. package/esm/components/image-preview/index.module.css.js +1 -1
  120. package/esm/components/image-preview/index.module.css.js.map +1 -1
  121. package/esm/components/image-viewer/hooks.js +3 -2
  122. package/esm/components/image-viewer/hooks.js.map +1 -1
  123. package/esm/components/image-viewer/index.css +30 -31
  124. package/esm/components/image-viewer/index.module.css.js +1 -1
  125. package/esm/components/image-viewer/index.module.css.js.map +1 -1
  126. package/esm/components/image-viewer/single.js +1 -0
  127. package/esm/components/image-viewer/single.js.map +1 -1
  128. package/esm/components/image-viewer/slide.js +3 -2
  129. package/esm/components/image-viewer/slide.js.map +1 -1
  130. package/esm/components/image-viewer/video/index.css +22 -10
  131. package/esm/components/image-viewer/video/index.js +51 -16
  132. package/esm/components/image-viewer/video/index.js.map +1 -1
  133. package/esm/components/image-viewer/video/index.module.css.js +1 -1
  134. package/esm/components/image-viewer/video/index.module.css.js.map +1 -1
  135. package/esm/components/info-bar/Component.js +1 -0
  136. package/esm/components/info-bar/Component.js.map +1 -1
  137. package/esm/components/info-bar/index.css +3 -3
  138. package/esm/components/info-bar/index.module.css.js +1 -1
  139. package/esm/components/navigation-bar/Component.js +56 -25
  140. package/esm/components/navigation-bar/Component.js.map +1 -1
  141. package/esm/components/navigation-bar/index.css +21 -11
  142. package/esm/components/navigation-bar/index.module.css.js +1 -1
  143. package/esm/components/navigation-bar/index.module.css.js.map +1 -1
  144. package/esm/components/subtitles/index.css +3 -3
  145. package/esm/components/subtitles/index.module.css.js +1 -1
  146. package/esm/constants.d.ts +1 -1
  147. package/esm/constants.js +1 -1
  148. package/esm/constants.js.map +1 -1
  149. package/esm/hooks/use-custom-subtitles.js +57 -11
  150. package/esm/hooks/use-custom-subtitles.js.map +1 -1
  151. package/esm/index.css +9 -9
  152. package/esm/index.js +1 -0
  153. package/esm/index.js.map +1 -1
  154. package/esm/index.module.css.js +1 -1
  155. package/esm/types.d.ts +4 -2
  156. package/esm/utils/index.d.ts +1 -0
  157. package/esm/utils/index.js +1 -0
  158. package/esm/utils/index.js.map +1 -1
  159. package/esm/utils/modern-download.d.ts +6 -0
  160. package/esm/utils/modern-download.js +109 -0
  161. package/esm/utils/modern-download.js.map +1 -0
  162. package/hooks/use-custom-subtitles.js +57 -11
  163. package/hooks/use-custom-subtitles.js.map +1 -1
  164. package/index.css +9 -9
  165. package/index.js +1 -0
  166. package/index.js.map +1 -1
  167. package/index.module.css.js +1 -1
  168. package/modern/Component.js +50 -7
  169. package/modern/Component.js.map +1 -1
  170. package/modern/components/bottom-button/index.css +5 -5
  171. package/modern/components/bottom-button/index.module.css.js +1 -1
  172. package/modern/components/buttons/index.css +5 -5
  173. package/modern/components/buttons/index.d.ts +3 -1
  174. package/modern/components/buttons/index.js +51 -12
  175. package/modern/components/buttons/index.js.map +1 -1
  176. package/modern/components/buttons/index.module.css.js +1 -1
  177. package/modern/components/header/index.css +3 -2
  178. package/modern/components/header/index.module.css.js +1 -1
  179. package/modern/components/header/index.module.css.js.map +1 -1
  180. package/modern/components/header-info-block/Component.js +1 -1
  181. package/modern/components/header-info-block/Component.js.map +1 -1
  182. package/modern/components/header-info-block/index.css +4 -4
  183. package/modern/components/header-info-block/index.module.css.js +1 -1
  184. package/modern/components/header-mobile/index.css +6 -6
  185. package/modern/components/header-mobile/index.module.css.js +1 -1
  186. package/modern/components/image-preview/Component.js +1 -1
  187. package/modern/components/image-preview/Component.js.map +1 -1
  188. package/modern/components/image-preview/index.css +20 -20
  189. package/modern/components/image-preview/index.module.css.js +1 -1
  190. package/modern/components/image-preview/index.module.css.js.map +1 -1
  191. package/modern/components/image-viewer/hooks.js +3 -2
  192. package/modern/components/image-viewer/hooks.js.map +1 -1
  193. package/modern/components/image-viewer/index.css +30 -31
  194. package/modern/components/image-viewer/index.module.css.js +1 -1
  195. package/modern/components/image-viewer/index.module.css.js.map +1 -1
  196. package/modern/components/image-viewer/slide.js +2 -2
  197. package/modern/components/image-viewer/slide.js.map +1 -1
  198. package/modern/components/image-viewer/video/index.css +22 -10
  199. package/modern/components/image-viewer/video/index.js +47 -12
  200. package/modern/components/image-viewer/video/index.js.map +1 -1
  201. package/modern/components/image-viewer/video/index.module.css.js +1 -1
  202. package/modern/components/image-viewer/video/index.module.css.js.map +1 -1
  203. package/modern/components/info-bar/index.css +3 -3
  204. package/modern/components/info-bar/index.module.css.js +1 -1
  205. package/modern/components/navigation-bar/Component.js +55 -25
  206. package/modern/components/navigation-bar/Component.js.map +1 -1
  207. package/modern/components/navigation-bar/index.css +21 -11
  208. package/modern/components/navigation-bar/index.module.css.js +1 -1
  209. package/modern/components/navigation-bar/index.module.css.js.map +1 -1
  210. package/modern/components/subtitles/index.css +3 -3
  211. package/modern/components/subtitles/index.module.css.js +1 -1
  212. package/modern/constants.d.ts +1 -1
  213. package/modern/constants.js +1 -1
  214. package/modern/constants.js.map +1 -1
  215. package/modern/hooks/use-custom-subtitles.js +56 -9
  216. package/modern/hooks/use-custom-subtitles.js.map +1 -1
  217. package/modern/index.css +9 -9
  218. package/modern/index.module.css.js +1 -1
  219. package/modern/types.d.ts +4 -2
  220. package/modern/utils/index.d.ts +1 -0
  221. package/modern/utils/index.js +1 -0
  222. package/modern/utils/index.js.map +1 -1
  223. package/modern/utils/modern-download.d.ts +6 -0
  224. package/modern/utils/modern-download.js +76 -0
  225. package/modern/utils/modern-download.js.map +1 -0
  226. package/moderncssm/Component.js +50 -7
  227. package/moderncssm/Component.js.map +1 -1
  228. package/moderncssm/components/buttons/index.d.ts +3 -1
  229. package/moderncssm/components/buttons/index.js +51 -12
  230. package/moderncssm/components/buttons/index.js.map +1 -1
  231. package/moderncssm/components/header/index.module.css +1 -1
  232. package/moderncssm/components/header-info-block/Component.js +1 -1
  233. package/moderncssm/components/header-info-block/Component.js.map +1 -1
  234. package/moderncssm/components/image-preview/Component.js +1 -1
  235. package/moderncssm/components/image-preview/Component.js.map +1 -1
  236. package/moderncssm/components/image-preview/index.module.css +2 -2
  237. package/moderncssm/components/image-viewer/hooks.js +3 -2
  238. package/moderncssm/components/image-viewer/hooks.js.map +1 -1
  239. package/moderncssm/components/image-viewer/index.module.css +2 -2
  240. package/moderncssm/components/image-viewer/slide.js +2 -2
  241. package/moderncssm/components/image-viewer/slide.js.map +1 -1
  242. package/moderncssm/components/image-viewer/video/index.js +47 -12
  243. package/moderncssm/components/image-viewer/video/index.js.map +1 -1
  244. package/moderncssm/components/image-viewer/video/index.module.css +16 -3
  245. package/moderncssm/components/navigation-bar/Component.js +55 -25
  246. package/moderncssm/components/navigation-bar/Component.js.map +1 -1
  247. package/moderncssm/components/navigation-bar/index.module.css +14 -2
  248. package/moderncssm/constants.d.ts +1 -1
  249. package/moderncssm/constants.js +1 -1
  250. package/moderncssm/constants.js.map +1 -1
  251. package/moderncssm/hooks/use-custom-subtitles.js +56 -9
  252. package/moderncssm/hooks/use-custom-subtitles.js.map +1 -1
  253. package/moderncssm/types.d.ts +4 -2
  254. package/moderncssm/utils/index.d.ts +1 -0
  255. package/moderncssm/utils/index.js +1 -0
  256. package/moderncssm/utils/index.js.map +1 -1
  257. package/moderncssm/utils/modern-download.d.ts +6 -0
  258. package/moderncssm/utils/modern-download.js +76 -0
  259. package/moderncssm/utils/modern-download.js.map +1 -0
  260. package/package.json +2 -2
  261. package/src/Component.tsx +63 -6
  262. package/src/components/buttons/index.tsx +157 -62
  263. package/src/components/header/index.module.css +1 -1
  264. package/src/components/header-info-block/Component.tsx +2 -2
  265. package/src/components/image-preview/Component.tsx +1 -1
  266. package/src/components/image-preview/index.module.css +2 -2
  267. package/src/components/image-viewer/hooks.ts +3 -2
  268. package/src/components/image-viewer/index.module.css +2 -2
  269. package/src/components/image-viewer/slide.tsx +2 -1
  270. package/src/components/image-viewer/video/index.module.css +16 -3
  271. package/src/components/image-viewer/video/index.tsx +62 -13
  272. package/src/components/navigation-bar/Component.tsx +68 -27
  273. package/src/components/navigation-bar/index.module.css +12 -2
  274. package/src/constants.ts +1 -1
  275. package/src/hooks/use-custom-subtitles.ts +72 -12
  276. package/src/types.ts +4 -2
  277. package/src/utils/index.ts +1 -0
  278. package/src/utils/modern-download.ts +107 -0
  279. package/types.d.ts +4 -2
  280. package/utils/index.d.ts +1 -0
  281. package/utils/index.js +2 -0
  282. package/utils/index.js.map +1 -1
  283. package/utils/modern-download.d.ts +6 -0
  284. package/utils/modern-download.js +113 -0
  285. package/utils/modern-download.js.map +1 -0
@@ -2,6 +2,7 @@ import React, { type FC, type MutableRefObject } from 'react';
2
2
  import cn from 'classnames';
3
3
 
4
4
  import { IconButton, type IconButtonProps } from '@alfalab/core-components-icon-button';
5
+ import { useIsDesktop } from '@alfalab/core-components-mq';
5
6
  import { TooltipDesktop } from '@alfalab/core-components-tooltip/desktop';
6
7
  import { ArrowLeftMIcon } from '@alfalab/icons-glyph/ArrowLeftMIcon';
7
8
  import { ArrowsInwardMIcon } from '@alfalab/icons-glyph/ArrowsInwardMIcon';
@@ -14,6 +15,8 @@ import { ShareMIcon } from '@alfalab/icons-glyph/ShareMIcon';
14
15
  import { SoundCrossMIcon } from '@alfalab/icons-glyph/SoundCrossMIcon';
15
16
  import { SoundMIcon } from '@alfalab/icons-glyph/SoundMIcon';
16
17
 
18
+ import { downloadFile, isVideo } from '../../utils';
19
+
17
20
  import styles from './index.module.css';
18
21
 
19
22
  type Props = Omit<IconButtonProps, 'icon' | 'colors'> & {
@@ -21,13 +24,10 @@ type Props = Omit<IconButtonProps, 'icon' | 'colors'> & {
21
24
  download?: string | boolean;
22
25
  };
23
26
 
24
- export const Fullscreen: FC<Props> = ({ buttonRef, ...restProps }) => (
25
- <TooltipDesktop
26
- trigger='hover'
27
- position='bottom'
28
- content='Открыть в полноэкранном режиме'
29
- fallbackPlacements={['bottom-end']}
30
- >
27
+ export const Fullscreen: FC<Props> = ({ buttonRef, ...restProps }) => {
28
+ const isDesktop = useIsDesktop();
29
+
30
+ const iconButton = (
31
31
  <IconButton
32
32
  {...restProps}
33
33
  ref={buttonRef}
@@ -35,8 +35,23 @@ export const Fullscreen: FC<Props> = ({ buttonRef, ...restProps }) => (
35
35
  aria-label='Открыть в полноэкранном режиме'
36
36
  className={styles.iconButton}
37
37
  />
38
- </TooltipDesktop>
39
- );
38
+ );
39
+
40
+ return isDesktop ? (
41
+ <TooltipDesktop
42
+ view='hint'
43
+ colors='inverted'
44
+ trigger='hover'
45
+ position='bottom'
46
+ content='Открыть в полноэкранном режиме'
47
+ fallbackPlacements={['bottom-end']}
48
+ >
49
+ {iconButton}
50
+ </TooltipDesktop>
51
+ ) : (
52
+ iconButton
53
+ );
54
+ };
40
55
 
41
56
  export const BackArrow: FC<Props> = ({ buttonRef, ...restProps }) => (
42
57
  <IconButton
@@ -68,13 +83,10 @@ export const Pause: FC<Props> = ({ buttonRef, className, ...restProps }) => (
68
83
  />
69
84
  );
70
85
 
71
- export const ExitFullscreen: FC<Props> = ({ buttonRef, ...restProps }) => (
72
- <TooltipDesktop
73
- trigger='hover'
74
- position='bottom'
75
- content='Выйти из полноэкранного режима'
76
- fallbackPlacements={['bottom-end']}
77
- >
86
+ export const ExitFullscreen: FC<Props> = ({ buttonRef, ...restProps }) => {
87
+ const isDesktop = useIsDesktop();
88
+
89
+ const iconButton = (
78
90
  <IconButton
79
91
  {...restProps}
80
92
  ref={buttonRef}
@@ -82,17 +94,28 @@ export const ExitFullscreen: FC<Props> = ({ buttonRef, ...restProps }) => (
82
94
  aria-label='Выйти из полноэкранного режима'
83
95
  className={styles.iconButton}
84
96
  />
85
- </TooltipDesktop>
86
- );
97
+ );
98
+
99
+ return isDesktop ? (
100
+ <TooltipDesktop
101
+ view='hint'
102
+ colors='inverted'
103
+ trigger='hover'
104
+ position='bottom'
105
+ content='Выйти из полноэкранного режима'
106
+ fallbackPlacements={['bottom-end']}
107
+ >
108
+ {iconButton}
109
+ </TooltipDesktop>
110
+ ) : (
111
+ iconButton
112
+ );
113
+ };
87
114
 
88
- export const MuteVideo: FC<Props> = ({ buttonRef, className, ...restProps }) => (
89
- <TooltipDesktop
90
- trigger='hover'
91
- position='bottom'
92
- content='Выключить звук'
93
- fallbackPlacements={['bottom-end']}
94
- targetClassName={className}
95
- >
115
+ export const MuteVideo: FC<Props> = ({ buttonRef, className, ...restProps }) => {
116
+ const isDesktop = useIsDesktop();
117
+
118
+ const iconButton = (
96
119
  <IconButton
97
120
  {...restProps}
98
121
  ref={buttonRef}
@@ -100,17 +123,29 @@ export const MuteVideo: FC<Props> = ({ buttonRef, className, ...restProps }) =>
100
123
  aria-label='Выключить звук'
101
124
  className={styles.iconButton}
102
125
  />
103
- </TooltipDesktop>
104
- );
126
+ );
127
+
128
+ return isDesktop ? (
129
+ <TooltipDesktop
130
+ view='hint'
131
+ colors='inverted'
132
+ trigger='hover'
133
+ position='bottom'
134
+ content='Выключить звук'
135
+ fallbackPlacements={['bottom-end']}
136
+ targetClassName={className}
137
+ >
138
+ {iconButton}
139
+ </TooltipDesktop>
140
+ ) : (
141
+ iconButton
142
+ );
143
+ };
105
144
 
106
- export const UnmuteVideo: FC<Props> = ({ buttonRef, className, ...restProps }) => (
107
- <TooltipDesktop
108
- trigger='hover'
109
- position='bottom'
110
- content='Включить звук'
111
- fallbackPlacements={['bottom-end']}
112
- targetClassName={className}
113
- >
145
+ export const UnmuteVideo: FC<Props> = ({ buttonRef, className, ...restProps }) => {
146
+ const isDesktop = useIsDesktop();
147
+
148
+ const iconButton = (
114
149
  <IconButton
115
150
  {...restProps}
116
151
  ref={buttonRef}
@@ -118,40 +153,100 @@ export const UnmuteVideo: FC<Props> = ({ buttonRef, className, ...restProps }) =
118
153
  aria-label='Включить звук'
119
154
  className={styles.iconButton}
120
155
  />
121
- </TooltipDesktop>
122
- );
156
+ );
123
157
 
124
- export const Download: FC<Props> = (props) => (
125
- <TooltipDesktop
126
- trigger='hover'
127
- position='bottom'
128
- content='Скачать'
129
- fallbackPlacements={['bottom-end']}
130
- >
131
- <IconButton
132
- {...props}
133
- icon={PointerDownMIcon}
134
- aria-label='Скачать'
135
- className={styles.iconButton}
136
- />
137
- </TooltipDesktop>
138
- );
158
+ return isDesktop ? (
159
+ <TooltipDesktop
160
+ view='hint'
161
+ colors='inverted'
162
+ trigger='hover'
163
+ position='bottom'
164
+ content='Включить звук'
165
+ fallbackPlacements={['bottom-end']}
166
+ targetClassName={className}
167
+ >
168
+ {iconButton}
169
+ </TooltipDesktop>
170
+ ) : (
171
+ iconButton
172
+ );
173
+ };
174
+
175
+ export const Download: FC<Props & { href?: string }> = ({ href, ...props }) => {
176
+ const isDesktop = useIsDesktop();
177
+
178
+ const handleMobileVideoDownload = async (e: React.MouseEvent) => {
179
+ e.preventDefault();
180
+
181
+ if (!href) return;
182
+
183
+ const fileName = props.download?.toString() || 'video';
184
+ const fileType = isVideo(href) ? 'video/*' : undefined;
185
+
186
+ await downloadFile({
187
+ url: href,
188
+ fileName,
189
+ fileType,
190
+ });
191
+ };
139
192
 
140
- export const Share: FC<Props> = (props) => (
141
- <TooltipDesktop
142
- trigger='hover'
143
- position='bottom'
144
- content='Поделиться'
145
- fallbackPlacements={['bottom-end']}
146
- >
193
+ const iconButtonProps = {
194
+ ...props,
195
+ icon: PointerDownMIcon,
196
+ 'aria-label': 'Скачать' as const,
197
+ className: styles.iconButton,
198
+ };
199
+
200
+ const iconButton =
201
+ !isDesktop && isVideo(href) ? (
202
+ <IconButton {...iconButtonProps} onClick={handleMobileVideoDownload} />
203
+ ) : (
204
+ <IconButton {...iconButtonProps} href={href} />
205
+ );
206
+
207
+ return isDesktop ? (
208
+ <TooltipDesktop
209
+ view='hint'
210
+ colors='inverted'
211
+ trigger='hover'
212
+ position='bottom'
213
+ content='Скачать'
214
+ fallbackPlacements={['bottom-end']}
215
+ >
216
+ {iconButton}
217
+ </TooltipDesktop>
218
+ ) : (
219
+ iconButton
220
+ );
221
+ };
222
+
223
+ export const Share: FC<Props> = (props) => {
224
+ const isDesktop = useIsDesktop();
225
+
226
+ const iconButton = (
147
227
  <IconButton
148
228
  {...props}
149
229
  icon={ShareMIcon}
150
230
  aria-label='Поделиться'
151
231
  className={styles.iconButton}
152
232
  />
153
- </TooltipDesktop>
154
- );
233
+ );
234
+
235
+ return isDesktop ? (
236
+ <TooltipDesktop
237
+ view='hint'
238
+ colors='inverted'
239
+ trigger='hover'
240
+ position='bottom'
241
+ content='Поделиться'
242
+ fallbackPlacements={['bottom-end']}
243
+ >
244
+ {iconButton}
245
+ </TooltipDesktop>
246
+ ) : (
247
+ iconButton
248
+ );
249
+ };
155
250
 
156
251
  export const Exit: FC<Props> = (props) => (
157
252
  <IconButton {...props} icon={CrossMIcon} aria-label='Закрыть' className={styles.iconButton} />
@@ -5,6 +5,6 @@
5
5
  justify-content: space-between;
6
6
  flex-shrink: 0;
7
7
  width: 100%;
8
- padding: var(--gap-16) var(--gap-32);
8
+ padding: var(--gap-16) var(--gap-24) var(--gap-16) var(--gap-32);
9
9
  box-sizing: border-box;
10
10
  }
@@ -18,9 +18,9 @@ export const HeaderInfoBlock: FC<HeaderInfoBlockProps> = ({ filename, descriptio
18
18
  <div className={styles.info}>
19
19
  <div className={styles.filenameContainer}>
20
20
  <TypographyTitle
21
- tag='h1'
21
+ tag='h2'
22
22
  className={styles.filenameHead}
23
- view='xsmall'
23
+ view='small'
24
24
  font='system'
25
25
  color='static-primary-light'
26
26
  >
@@ -151,7 +151,7 @@ export const ImagePreview: FC<Props> = ({ image, active = false, index, onSelect
151
151
  return (
152
152
  <div
153
153
  className={cn(styles.preview, styles.image, {
154
- [styles.loading]: !meta,
154
+ [styles.loading]: !meta?.loaded,
155
155
  [styles.mobile]: isMobile,
156
156
  })}
157
157
  >
@@ -59,7 +59,7 @@
59
59
  background-color: var(--color-static-neutral-100-inverted);
60
60
 
61
61
  & .active {
62
- background-color: var(--color-static-neutral-300-inverted);
62
+ background-color: var(--color-static-neutral-translucent-100-inverted);
63
63
  }
64
64
  }
65
65
 
@@ -67,7 +67,7 @@
67
67
  display: flex;
68
68
  justify-content: center;
69
69
  align-items: center;
70
- background-color: var(--color-static-neutral-300-inverted);
70
+ background-color: var(--color-static-neutral-translucent-100-inverted);
71
71
  opacity: 0.3;
72
72
 
73
73
  &.active {
@@ -42,9 +42,10 @@ export const useHandleImageViewer = () => {
42
42
 
43
43
  const isPlaceholder = Boolean(eventTarget.closest(`.${styles.placeholder}`));
44
44
 
45
- const isImg = eventTarget.tagName === 'IMG';
45
+ const isContentArea = Boolean(eventTarget.closest('[data-content-area]'));
46
46
 
47
- if (!isImg && !isPlaceholder && !isArrow && !isMobile) {
47
+ // Закрываем галерею только при клике вне элементов контента и только на desktop
48
+ if (!isPlaceholder && !isArrow && !isContentArea && !isMobile) {
48
49
  onClose();
49
50
  }
50
51
  },
@@ -132,7 +132,7 @@
132
132
 
133
133
  max-height: calc(100vh - 80px);
134
134
  max-height: calc(100dvh - 80px);
135
- padding: var(--gap-32);
135
+ padding: var(--gap-0) var(--gap-32) var(--gap-32);
136
136
  box-sizing: border-box;
137
137
 
138
138
  &.mobile {
@@ -242,7 +242,7 @@
242
242
  width: 100%;
243
243
  height: 100%;
244
244
  border-radius: var(--border-radius-8);
245
- background-color: var(--color-static-neutral-300-inverted);
245
+ background-color: var(--color-static-neutral-translucent-100-inverted);
246
246
  }
247
247
 
248
248
  .brokenImgWrapper {
@@ -53,7 +53,7 @@ const SlideInner: FC<SlideInnerProps> = ({ children, broken, loading, isVideoVie
53
53
  );
54
54
 
55
55
  return (
56
- <div className={cn(styles.slide, { [styles.slideLoading]: loading })}>
56
+ <div className={cn(styles.slide, { [styles.slideLoading]: loading && !isVideoView })}>
57
57
  {broken ? <div className={styles.placeholder}>{content}</div> : content}
58
58
  <Spinner className={styles.spinner} preset={48} visible={loading} />
59
59
  </div>
@@ -135,6 +135,7 @@ export const Slide: FC<SlideProps> = ({
135
135
  onLoad={(event) => handleLoad(event, index)}
136
136
  onError={() => handleLoadError(index)}
137
137
  style={imageStyle}
138
+ data-content-area='true'
138
139
  data-test-id={slideVisible ? TestIds.ACTIVE_IMAGE : undefined}
139
140
  />
140
141
  </SlideInner>
@@ -5,10 +5,23 @@
5
5
  align-items: center;
6
6
  justify-content: center;
7
7
  height: 100%;
8
- width: 100%;
9
- min-width: 0;
10
- min-height: 0;
8
+ width: auto;
9
+ max-width: 100%;
11
10
  position: relative;
11
+ min-width: 300px;
12
+ min-height: 200px;
13
+ }
14
+
15
+ .mobileWrapper {
16
+ width: 100%;
17
+ }
18
+
19
+ .videoWrapper.loading {
20
+ width: 100%;
21
+ aspect-ratio: 16/9;
22
+ background-color: var(--color-static-neutral-translucent-100-inverted);
23
+ border-radius: var(--border-radius-24);
24
+ align-items: center;
12
25
  }
13
26
 
14
27
  .video {
@@ -27,9 +27,12 @@ type Props = {
27
27
  };
28
28
 
29
29
  export const Video = ({ url, index, className, isActive }: Props) => {
30
+ const [videoLoaded, setVideoLoaded] = useState(false);
30
31
  const playerRef = useRef<HTMLVideoElement>(null);
31
32
  const timer = useRef<ReturnType<typeof setTimeout>>();
32
33
  const [hlsSupported, setHlsSupported] = useState<boolean>(true);
34
+ const abortController = useRef(new AbortController());
35
+ const [videoError, setVideoError] = useState(false);
33
36
 
34
37
  const {
35
38
  setImageMeta,
@@ -83,6 +86,47 @@ export const Video = ({ url, index, className, isActive }: Props) => {
83
86
  [setImageMeta, index],
84
87
  );
85
88
 
89
+ useEffect(() => () => abortController.current.abort(), []);
90
+
91
+ useEffect(() => {
92
+ const video = playerRef.current;
93
+
94
+ if (!video) {
95
+ return;
96
+ }
97
+
98
+ const { signal } = abortController.current;
99
+
100
+ const handleCanPlay = () => {
101
+ setVideoLoaded(true);
102
+ setVideoError(false);
103
+ setImageMeta(
104
+ {
105
+ player: playerRef,
106
+ width: video.videoWidth || 1920,
107
+ height: video.videoHeight || 1080,
108
+ loaded: true,
109
+ },
110
+ index,
111
+ );
112
+ };
113
+
114
+ const handleError = () => {
115
+ setVideoError(true);
116
+ setVideoLoaded(false);
117
+ setImageMeta({ player: { current: null }, broken: true, loaded: true }, index);
118
+ };
119
+
120
+ const handleLoadStart = () => {
121
+ setVideoLoaded(false);
122
+ setVideoError(false);
123
+ };
124
+
125
+ video.addEventListener('canplay', handleCanPlay, { signal });
126
+ video.addEventListener('error', handleError, { signal });
127
+ video.addEventListener('loadstart', handleLoadStart, { signal });
128
+ }, [setImageMeta, index]);
129
+
86
130
  useEffect(() => {
87
131
  let hls: Hls | null = null;
88
132
 
@@ -158,8 +202,12 @@ export const Video = ({ url, index, className, isActive }: Props) => {
158
202
  }, [isActive, playingVideo]);
159
203
 
160
204
  useEffect(() => {
205
+ const { signal } = abortController.current;
206
+
161
207
  const handleSpacePress = (e: KeyboardEvent) => {
162
208
  if ((e.key === ' ' || e.code === 'Space') && isActive) {
209
+ e.preventDefault();
210
+ e.stopPropagation();
163
211
  if (playingVideo) {
164
212
  setPlayingVideo(false);
165
213
  } else {
@@ -168,11 +216,7 @@ export const Video = ({ url, index, className, isActive }: Props) => {
168
216
  }
169
217
  };
170
218
 
171
- document.addEventListener('keyup', handleSpacePress);
172
-
173
- return () => {
174
- document.removeEventListener('keyup', handleSpacePress);
175
- };
219
+ document.addEventListener('keydown', handleSpacePress, { signal });
176
220
  }, [isActive, playingVideo, setPlayingVideo]);
177
221
 
178
222
  const handleWrapperClick = (e: MouseEvent) => {
@@ -189,11 +233,9 @@ export const Video = ({ url, index, className, isActive }: Props) => {
189
233
  setHideNavigation(true);
190
234
  }, 3000);
191
235
  }
192
-
193
- return;
236
+ } else {
237
+ setPlayingVideo(!playingVideo);
194
238
  }
195
-
196
- setPlayingVideo(!playingVideo);
197
239
  };
198
240
 
199
241
  const handleBottomButtonClick = useCallback(
@@ -230,8 +272,15 @@ export const Video = ({ url, index, className, isActive }: Props) => {
230
272
  };
231
273
 
232
274
  return (
233
- // eslint-disable-next-line jsx-a11y/click-events-have-key-events,jsx-a11y/no-static-element-interactions
234
- <div onClick={handleWrapperClick} className={styles.videoWrapper}>
275
+ <div
276
+ aria-hidden={true}
277
+ onClick={handleWrapperClick}
278
+ data-content-area='true'
279
+ className={cn(styles.videoWrapper, {
280
+ [styles.loading]: !videoLoaded && !videoError,
281
+ [styles.mobileWrapper]: isMobile,
282
+ })}
283
+ >
235
284
  <video
236
285
  onPlay={onPlay}
237
286
  onPause={onPause}
@@ -244,7 +293,7 @@ export const Video = ({ url, index, className, isActive }: Props) => {
244
293
  >
245
294
  <track kind='captions' />
246
295
  </video>
247
- {isDesktop && !playingVideo && (
296
+ {isDesktop && !playingVideo && videoLoaded && (
248
297
  <div className={styles.videoButton}>
249
298
  <Circle size={64} shapeClassName={styles.iconShape}>
250
299
  <PlayCompactMIcon className={styles.icon} />
@@ -252,7 +301,7 @@ export const Video = ({ url, index, className, isActive }: Props) => {
252
301
  </div>
253
302
  )}
254
303
  {isDesktop && <Subtitles />}
255
- {isDesktop && image?.bottomButton && (
304
+ {isDesktop && image?.bottomButton && videoLoaded && (
256
305
  <BottomButton
257
306
  bottomButton={image.bottomButton}
258
307
  onClick={handleBottomButtonClick}