@alfalab/core-components-gallery 5.7.4 → 5.8.1

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 (258) hide show
  1. package/Component.js +47 -12
  2. package/components/buttons/index.css +35 -0
  3. package/{buttons-ec113bb4.d.ts → components/buttons/index.d.ts} +6 -1
  4. package/components/buttons/index.js +72 -0
  5. package/components/header/Component.js +33 -12
  6. package/components/header/index.css +5 -19
  7. package/components/header-info-block/Component.js +1 -1
  8. package/components/header-info-block/index.css +5 -5
  9. package/components/header-mobile/Component.d.ts +4 -0
  10. package/components/header-mobile/Component.js +39 -0
  11. package/components/header-mobile/index.css +50 -0
  12. package/components/header-mobile/index.d.ts +1 -0
  13. package/components/header-mobile/index.js +9 -0
  14. package/components/image-preview/Component.js +67 -24
  15. package/components/image-preview/index.css +35 -28
  16. package/components/image-preview/paths.d.ts +2 -0
  17. package/components/image-preview/paths.js +2 -0
  18. package/components/image-viewer/component.js +30 -10
  19. package/components/image-viewer/index.css +37 -25
  20. package/components/image-viewer/slide.js +3 -1
  21. package/components/image-viewer/video/index.css +48 -0
  22. package/components/image-viewer/video/index.d.ts +10 -0
  23. package/components/image-viewer/video/index.js +130 -0
  24. package/components/index.d.ts +2 -0
  25. package/components/index.js +4 -0
  26. package/components/info-bar/Component.d.ts +4 -0
  27. package/components/info-bar/Component.js +47 -0
  28. package/components/info-bar/index.css +37 -0
  29. package/components/info-bar/index.d.ts +1 -0
  30. package/components/info-bar/index.js +9 -0
  31. package/components/navigation-bar/Component.js +3 -2
  32. package/components/navigation-bar/index.css +8 -6
  33. package/context.d.ts +7 -0
  34. package/context.js +7 -0
  35. package/cssm/Component.js +46 -11
  36. package/cssm/components/{header/buttons.d.ts → buttons/index.d.ts} +6 -1
  37. package/cssm/components/buttons/index.js +71 -0
  38. package/cssm/components/buttons/index.module.css +34 -0
  39. package/cssm/components/header/Component.js +28 -10
  40. package/cssm/components/header/index.module.css +3 -17
  41. package/cssm/components/header-mobile/Component.d.ts +4 -0
  42. package/cssm/components/header-mobile/Component.js +38 -0
  43. package/cssm/components/header-mobile/index.d.ts +1 -0
  44. package/cssm/components/header-mobile/index.js +9 -0
  45. package/cssm/components/header-mobile/index.module.css +49 -0
  46. package/cssm/components/image-preview/Component.js +66 -27
  47. package/cssm/components/image-preview/index.module.css +25 -18
  48. package/cssm/components/image-preview/paths.d.ts +2 -0
  49. package/cssm/components/image-preview/paths.js +2 -0
  50. package/cssm/components/image-viewer/component.js +29 -9
  51. package/cssm/components/image-viewer/index.module.css +21 -9
  52. package/cssm/components/image-viewer/slide.js +12 -2
  53. package/cssm/components/image-viewer/video/index.d.ts +10 -0
  54. package/cssm/components/image-viewer/video/index.js +129 -0
  55. package/cssm/components/image-viewer/video/index.module.css +47 -0
  56. package/cssm/components/index.d.ts +2 -0
  57. package/cssm/components/index.js +4 -0
  58. package/cssm/components/info-bar/Component.d.ts +4 -0
  59. package/cssm/components/info-bar/Component.js +46 -0
  60. package/cssm/components/info-bar/index.d.ts +1 -0
  61. package/cssm/components/info-bar/index.js +9 -0
  62. package/cssm/components/info-bar/index.module.css +36 -0
  63. package/cssm/components/navigation-bar/Component.js +2 -1
  64. package/cssm/components/navigation-bar/index.module.css +3 -1
  65. package/cssm/context.d.ts +7 -0
  66. package/cssm/context.js +7 -0
  67. package/cssm/index.d.ts +1 -1
  68. package/cssm/index.js +1 -8
  69. package/cssm/index.module.css +14 -2
  70. package/cssm/types.d.ts +7 -0
  71. package/cssm/utils/constants.d.ts +14 -1
  72. package/cssm/utils/constants.js +19 -0
  73. package/cssm/utils/index.js +7 -0
  74. package/cssm/utils/utils.d.ts +2 -1
  75. package/cssm/utils/utils.js +5 -3
  76. package/esm/Component.js +46 -12
  77. package/esm/components/buttons/index.css +35 -0
  78. package/esm/{buttons-791da71e.d.ts → components/buttons/index.d.ts} +6 -1
  79. package/esm/components/buttons/index.js +55 -0
  80. package/esm/components/header/Component.js +30 -9
  81. package/esm/components/header/index.css +5 -19
  82. package/esm/components/header-info-block/Component.js +1 -1
  83. package/esm/components/header-info-block/index.css +5 -5
  84. package/esm/components/header-mobile/Component.d.ts +4 -0
  85. package/esm/components/header-mobile/Component.js +30 -0
  86. package/esm/components/header-mobile/index.css +50 -0
  87. package/esm/components/header-mobile/index.d.ts +1 -0
  88. package/esm/components/header-mobile/index.js +1 -0
  89. package/esm/components/image-preview/Component.js +69 -26
  90. package/esm/components/image-preview/index.css +35 -28
  91. package/esm/components/image-preview/paths.d.ts +2 -0
  92. package/esm/components/image-preview/paths.js +2 -0
  93. package/esm/components/image-viewer/component.js +31 -11
  94. package/esm/components/image-viewer/index.css +37 -25
  95. package/esm/components/image-viewer/slide.js +3 -1
  96. package/esm/components/image-viewer/video/index.css +48 -0
  97. package/esm/components/image-viewer/video/index.d.ts +10 -0
  98. package/esm/components/image-viewer/video/index.js +119 -0
  99. package/esm/components/index.d.ts +2 -0
  100. package/esm/components/index.js +2 -0
  101. package/esm/components/info-bar/Component.d.ts +4 -0
  102. package/esm/components/info-bar/Component.js +39 -0
  103. package/esm/components/info-bar/index.css +37 -0
  104. package/esm/components/info-bar/index.d.ts +1 -0
  105. package/esm/components/info-bar/index.js +1 -0
  106. package/esm/components/navigation-bar/Component.js +3 -2
  107. package/esm/components/navigation-bar/index.css +8 -6
  108. package/esm/context.d.ts +7 -0
  109. package/esm/context.js +7 -0
  110. package/esm/index.css +17 -5
  111. package/esm/index.d.ts +1 -1
  112. package/esm/index.js +1 -3
  113. package/esm/{slide-7d5a41d1.js → slide-3be75078.js} +15 -5
  114. package/esm/types.d.ts +7 -0
  115. package/esm/utils/constants.d.ts +14 -1
  116. package/esm/utils/constants.js +14 -1
  117. package/esm/utils/index.js +2 -2
  118. package/esm/utils/utils.d.ts +2 -1
  119. package/esm/utils/utils.js +5 -4
  120. package/index.css +17 -5
  121. package/index.d.ts +1 -1
  122. package/index.js +1 -8
  123. package/modern/Component.js +39 -7
  124. package/modern/components/buttons/index.css +35 -0
  125. package/modern/{buttons-1859cb8e.d.ts → components/buttons/index.d.ts} +6 -1
  126. package/modern/components/buttons/index.js +33 -0
  127. package/modern/components/header/Component.js +27 -9
  128. package/modern/components/header/index.css +5 -19
  129. package/modern/components/header-info-block/Component.js +1 -1
  130. package/modern/components/header-info-block/index.css +5 -5
  131. package/modern/components/header-mobile/Component.d.ts +4 -0
  132. package/modern/components/header-mobile/Component.js +28 -0
  133. package/modern/components/header-mobile/index.css +50 -0
  134. package/modern/components/header-mobile/index.d.ts +1 -0
  135. package/modern/components/header-mobile/index.js +1 -0
  136. package/modern/components/image-preview/Component.js +65 -23
  137. package/modern/components/image-preview/index.css +35 -28
  138. package/modern/components/image-preview/paths.d.ts +2 -0
  139. package/modern/components/image-preview/paths.js +2 -0
  140. package/modern/components/image-viewer/component.js +31 -11
  141. package/modern/components/image-viewer/index.css +37 -25
  142. package/modern/components/image-viewer/slide.js +3 -1
  143. package/modern/components/image-viewer/video/index.css +48 -0
  144. package/modern/components/image-viewer/video/index.d.ts +10 -0
  145. package/modern/components/image-viewer/video/index.js +117 -0
  146. package/modern/components/index.d.ts +2 -0
  147. package/modern/components/index.js +2 -0
  148. package/modern/components/info-bar/Component.d.ts +4 -0
  149. package/modern/components/info-bar/Component.js +38 -0
  150. package/modern/components/info-bar/index.css +37 -0
  151. package/modern/components/info-bar/index.d.ts +1 -0
  152. package/modern/components/info-bar/index.js +1 -0
  153. package/modern/components/navigation-bar/Component.js +3 -2
  154. package/modern/components/navigation-bar/index.css +8 -6
  155. package/modern/context.d.ts +7 -0
  156. package/modern/context.js +7 -0
  157. package/modern/index.css +17 -5
  158. package/modern/index.d.ts +1 -1
  159. package/modern/index.js +1 -3
  160. package/modern/{slide-c47386c3.js → slide-df1baab8.js} +15 -5
  161. package/modern/types.d.ts +7 -0
  162. package/modern/utils/constants.d.ts +14 -1
  163. package/modern/utils/constants.js +14 -1
  164. package/modern/utils/index.js +2 -2
  165. package/modern/utils/utils.d.ts +2 -1
  166. package/modern/utils/utils.js +5 -4
  167. package/moderncssm/Component.js +38 -6
  168. package/moderncssm/components/buttons/index.d.ts +16 -0
  169. package/moderncssm/components/buttons/index.js +31 -0
  170. package/moderncssm/components/buttons/index.module.css +20 -0
  171. package/moderncssm/components/header/Component.js +24 -9
  172. package/moderncssm/components/header/index.module.css +0 -19
  173. package/moderncssm/components/header-mobile/Component.d.ts +4 -0
  174. package/moderncssm/components/header-mobile/Component.js +26 -0
  175. package/moderncssm/components/header-mobile/index.d.ts +1 -0
  176. package/moderncssm/components/header-mobile/index.js +1 -0
  177. package/moderncssm/components/header-mobile/index.module.css +35 -0
  178. package/moderncssm/components/image-preview/Component.js +64 -26
  179. package/moderncssm/components/image-preview/index.module.css +30 -13
  180. package/moderncssm/components/image-preview/paths.d.ts +2 -0
  181. package/moderncssm/components/image-preview/paths.js +2 -0
  182. package/moderncssm/components/image-viewer/component.js +30 -10
  183. package/moderncssm/components/image-viewer/index.module.css +29 -6
  184. package/moderncssm/components/image-viewer/slide.js +14 -4
  185. package/moderncssm/components/image-viewer/video/index.d.ts +10 -0
  186. package/moderncssm/components/image-viewer/video/index.js +115 -0
  187. package/moderncssm/components/image-viewer/video/index.module.css +36 -0
  188. package/moderncssm/components/index.d.ts +2 -0
  189. package/moderncssm/components/index.js +2 -0
  190. package/moderncssm/components/info-bar/Component.d.ts +4 -0
  191. package/moderncssm/components/info-bar/Component.js +36 -0
  192. package/moderncssm/components/info-bar/index.d.ts +1 -0
  193. package/moderncssm/components/info-bar/index.js +1 -0
  194. package/moderncssm/components/info-bar/index.module.css +23 -0
  195. package/moderncssm/components/navigation-bar/Component.js +2 -1
  196. package/moderncssm/components/navigation-bar/index.module.css +4 -0
  197. package/moderncssm/context.d.ts +7 -0
  198. package/moderncssm/context.js +7 -0
  199. package/moderncssm/index.d.ts +1 -1
  200. package/moderncssm/index.js +1 -3
  201. package/moderncssm/index.module.css +18 -2
  202. package/moderncssm/types.d.ts +7 -0
  203. package/moderncssm/utils/constants.d.ts +14 -1
  204. package/moderncssm/utils/constants.js +14 -1
  205. package/moderncssm/utils/index.js +2 -2
  206. package/moderncssm/utils/utils.d.ts +2 -1
  207. package/moderncssm/utils/utils.js +5 -4
  208. package/package.json +4 -3
  209. package/{slide-12155967.js → slide-2cbb0733.js} +13 -3
  210. package/src/Component.tsx +48 -6
  211. package/src/components/buttons/index.module.css +21 -0
  212. package/src/components/{header/buttons.tsx → buttons/index.tsx} +77 -0
  213. package/src/components/header/Component.tsx +33 -10
  214. package/src/components/header/index.module.css +0 -20
  215. package/src/components/header-mobile/Component.tsx +57 -0
  216. package/src/components/header-mobile/index.module.css +35 -0
  217. package/src/components/header-mobile/index.ts +1 -0
  218. package/src/components/image-preview/Component.tsx +131 -28
  219. package/src/components/image-preview/index.module.css +28 -9
  220. package/src/components/image-preview/paths.ts +3 -0
  221. package/src/components/image-viewer/component.tsx +32 -11
  222. package/src/components/image-viewer/index.module.css +26 -3
  223. package/src/components/image-viewer/slide.tsx +30 -4
  224. package/src/components/image-viewer/video/index.module.css +36 -0
  225. package/src/components/image-viewer/video/index.tsx +159 -0
  226. package/src/components/index.ts +2 -0
  227. package/src/components/info-bar/Component.tsx +68 -0
  228. package/src/components/info-bar/index.module.css +23 -0
  229. package/src/components/info-bar/index.ts +1 -0
  230. package/src/components/navigation-bar/Component.tsx +2 -1
  231. package/src/components/navigation-bar/index.module.css +4 -0
  232. package/src/context.ts +14 -0
  233. package/src/index.module.css +18 -2
  234. package/src/index.ts +1 -1
  235. package/src/types.ts +15 -5
  236. package/src/utils/constants.ts +17 -0
  237. package/src/utils/utils.ts +5 -3
  238. package/types.d.ts +7 -0
  239. package/utils/constants.d.ts +14 -1
  240. package/utils/constants.js +19 -0
  241. package/utils/index.js +7 -0
  242. package/utils/utils.d.ts +2 -1
  243. package/utils/utils.js +5 -3
  244. package/buttons-ec113bb4.js +0 -37
  245. package/components/header/buttons.d.ts +0 -0
  246. package/components/header/buttons.js +0 -20
  247. package/cssm/components/header/buttons.js +0 -37
  248. package/esm/buttons-791da71e.js +0 -27
  249. package/esm/components/header/buttons.d.ts +0 -0
  250. package/esm/components/header/buttons.js +0 -9
  251. package/modern/buttons-1859cb8e.js +0 -20
  252. package/modern/components/header/buttons.d.ts +0 -0
  253. package/modern/components/header/buttons.js +0 -8
  254. package/moderncssm/components/header/buttons.d.ts +0 -11
  255. package/moderncssm/components/header/buttons.js +0 -18
  256. /package/esm/{slide-7d5a41d1.d.ts → slide-3be75078.d.ts} +0 -0
  257. /package/modern/{slide-c47386c3.d.ts → slide-df1baab8.d.ts} +0 -0
  258. /package/{slide-12155967.d.ts → slide-2cbb0733.d.ts} +0 -0
@@ -1,30 +1,40 @@
1
- import React from 'react';
1
+ import React, { useContext } from 'react';
2
2
  import cn from 'classnames';
3
3
  import { Typography } from '@alfalab/core-components-typography/moderncssm';
4
- import { isSmallImage, getImageAlt } from '../../utils/utils.js';
4
+ import { GalleryContext } from '../../context.js';
5
+ import { isSmallImage, isVideo, getImageAlt } from '../../utils/utils.js';
5
6
  import { TestIds } from '../../utils/constants.js';
6
7
  import { NoImagePaths } from './paths.js';
8
+ import { Video } from './video/index.js';
7
9
  import styles from './index.module.css';
8
10
 
9
- const SlideInner = ({ children, broken, loading, withPlaceholder }) => {
11
+ const SlideInner = ({ children, broken, loading, withPlaceholder, isVideoView, }) => {
10
12
  const content = broken ? (React.createElement("div", { className: styles.brokenImgWrapper },
11
13
  React.createElement("div", { className: styles.brokenImgIcon },
12
14
  React.createElement("svg", { xmlns: 'http://www.w3.org/2000/svg', width: '80', height: '80', viewBox: '0 0 80 80', fill: 'none' },
13
15
  React.createElement("rect", { width: '80', height: '80', fill: 'none' }),
14
16
  React.createElement("path", { fillRule: 'evenodd', clipRule: 'evenodd', d: NoImagePaths.baseImage, fill: '#89898A' }),
15
17
  React.createElement("path", { d: NoImagePaths.triangleImage, fill: '#89898A' }))),
16
- React.createElement(Typography.Text, { view: 'primary-small', color: 'static-secondary-light' }, "\u041D\u0435 \u0443\u0434\u0430\u043B\u043E\u0441\u044C \u0437\u0430\u0433\u0440\u0443\u0437\u0438\u0442\u044C \u0438\u0437\u043E\u0431\u0440\u0430\u0436\u0435\u043D\u0438\u0435"))) : (children);
18
+ React.createElement(Typography.Text, { view: 'primary-small', color: 'static-secondary-light' },
19
+ "\u041D\u0435 \u0443\u0434\u0430\u043B\u043E\u0441\u044C \u0437\u0430\u0433\u0440\u0443\u0437\u0438\u0442\u044C ",
20
+ isVideoView ? 'видео' : 'изображение'))) : (children);
17
21
  return (React.createElement("div", { className: cn(styles.slide, { [styles.slideLoading]: loading }) }, withPlaceholder ? React.createElement("div", { className: styles.placeholder }, content) : content));
18
22
  };
19
23
  const Slide = ({ isActive, meta, swiperAspectRatio, imageAspectRatio, image, index, swiperHeight, slideVisible, handleLoad, handleLoadError, }) => {
24
+ const { view } = useContext(GalleryContext);
20
25
  const broken = Boolean(meta?.broken);
21
26
  const small = isSmallImage(meta);
22
27
  const verticalImageFit = !small && swiperAspectRatio > imageAspectRatio;
23
28
  const horizontalImageFit = !small && swiperAspectRatio <= imageAspectRatio;
29
+ if (isVideo(image.src)) {
30
+ return (React.createElement(SlideInner, { isVideoView: true, active: isActive, broken: broken, withPlaceholder: broken, loading: !meta },
31
+ React.createElement(Video, { url: image.src, index: index, isActive: isActive })));
32
+ }
24
33
  return (React.createElement(SlideInner, { active: isActive, broken: broken, loading: !meta, withPlaceholder: small || broken },
25
34
  React.createElement("img", { src: image.src, alt: getImageAlt(image, index), className: cn({
26
35
  [styles.smallImage]: small,
27
36
  [styles.image]: !small && meta,
37
+ [styles.mobile]: view === 'mobile',
28
38
  [styles.verticalImageFit]: verticalImageFit,
29
39
  [styles.horizontalImageFit]: horizontalImageFit,
30
40
  }), onLoad: (event) => handleLoad(event, index), onError: () => handleLoadError(index), style: {
@@ -0,0 +1,10 @@
1
+ /// <reference types="react" />
2
+ import React from 'react';
3
+ type Props = {
4
+ url: string;
5
+ index: number;
6
+ isActive: boolean;
7
+ className?: string;
8
+ };
9
+ declare const Video: ({ url, index, className, isActive }: Props) => React.JSX.Element;
10
+ export { Video };
@@ -0,0 +1,115 @@
1
+ import React, { useRef, useContext, useEffect } from 'react';
2
+ import cn from 'classnames';
3
+ import Hls from 'hls.js';
4
+ import { Circle } from '@alfalab/core-components/icon-view/circle';
5
+ import PlayCompactMIcon from '@alfalab/icons-glyph/PlayCompactMIcon';
6
+ import { GalleryContext } from '../../../context.js';
7
+ import { GALLERY_EVENTS } from '../../../utils/constants.js';
8
+ import styles from './index.module.css';
9
+
10
+ const Video = ({ url, index, className, isActive }) => {
11
+ const playerRef = useRef(null);
12
+ const timer = useRef();
13
+ const { setImageMeta, mutedVideo, view, playingVideo, setPlayingVideo, setHideNavigation } = useContext(GalleryContext);
14
+ const isMobile = view === 'mobile';
15
+ useEffect(() => {
16
+ setImageMeta({ player: playerRef }, index);
17
+ /* eslint-disable-next-line react-hooks/exhaustive-deps */
18
+ }, [index]);
19
+ useEffect(() => {
20
+ const hls = new Hls();
21
+ if (Hls.isSupported()) {
22
+ hls.on(Hls.Events.ERROR, (_, data) => {
23
+ if (data.fatal) {
24
+ switch (data.type) {
25
+ case Hls.ErrorTypes.MEDIA_ERROR:
26
+ hls.recoverMediaError();
27
+ break;
28
+ case Hls.ErrorTypes.NETWORK_ERROR:
29
+ setImageMeta({ player: { current: null }, broken: true }, index);
30
+ break;
31
+ default:
32
+ hls.destroy();
33
+ break;
34
+ }
35
+ }
36
+ });
37
+ hls.loadSource(url);
38
+ if (playerRef.current) {
39
+ hls.attachMedia(playerRef.current);
40
+ }
41
+ }
42
+ return () => {
43
+ if (hls) {
44
+ hls.destroy();
45
+ }
46
+ if (timer.current) {
47
+ clearTimeout(timer.current);
48
+ }
49
+ };
50
+ /* eslint-disable-next-line react-hooks/exhaustive-deps */
51
+ }, [url, index]);
52
+ const handleWrapperClick = (e) => {
53
+ e.stopPropagation();
54
+ if (isMobile) {
55
+ setHideNavigation(false);
56
+ if (playingVideo) {
57
+ if (timer.current) {
58
+ clearTimeout(timer.current);
59
+ }
60
+ timer.current = setTimeout(() => {
61
+ setHideNavigation(true);
62
+ }, 3000);
63
+ }
64
+ return;
65
+ }
66
+ setPlayingVideo(!playingVideo);
67
+ };
68
+ useEffect(() => {
69
+ if (playerRef.current && isActive) {
70
+ if (playingVideo) {
71
+ playerRef.current.play();
72
+ }
73
+ else {
74
+ playerRef.current.pause();
75
+ }
76
+ }
77
+ if (playerRef.current && !isActive) {
78
+ playerRef.current.pause();
79
+ playerRef.current.currentTime = 0;
80
+ }
81
+ }, [isActive, playingVideo]);
82
+ const onPlay = (e) => {
83
+ const customEvent = new CustomEvent(GALLERY_EVENTS.ON_PLAY, {
84
+ detail: { player: e.target },
85
+ });
86
+ dispatchEvent(customEvent);
87
+ if (timer.current) {
88
+ clearTimeout(timer.current);
89
+ }
90
+ timer.current = setTimeout(() => {
91
+ setHideNavigation(true);
92
+ }, 3000);
93
+ };
94
+ const onPause = (e) => {
95
+ const customEvent = new CustomEvent(GALLERY_EVENTS.ON_PAUSE, {
96
+ detail: { player: e.target },
97
+ });
98
+ dispatchEvent(customEvent);
99
+ if (timer.current) {
100
+ clearTimeout(timer.current);
101
+ timer.current = undefined;
102
+ }
103
+ setHideNavigation(false);
104
+ };
105
+ return (
106
+ // eslint-disable-next-line jsx-a11y/click-events-have-key-events,jsx-a11y/no-static-element-interactions
107
+ React.createElement("div", { onClick: handleWrapperClick, className: styles.videoWrapper },
108
+ React.createElement("video", { onPlay: onPlay, onPause: onPause, ref: playerRef, playsInline: true, muted: mutedVideo, loop: true, src: Hls.isSupported() ? undefined : url, className: cn(styles.video, { [styles.mobile]: view === 'mobile' }, className) },
109
+ React.createElement("track", { kind: 'captions' })),
110
+ view === 'desktop' && !playingVideo && (React.createElement("div", { className: styles.videoButton },
111
+ React.createElement(Circle, { size: 64, shapeClassName: styles.iconShape },
112
+ React.createElement(PlayCompactMIcon, { className: styles.icon }))))));
113
+ };
114
+
115
+ export { Video };
@@ -0,0 +1,36 @@
1
+ /* */
2
+
3
+ .videoWrapper {
4
+ display: flex;
5
+ justify-content: center;
6
+ height: 100%;
7
+ width: 100%;
8
+ position: relative;
9
+ }
10
+
11
+ .video {
12
+ max-width: 100%;
13
+ max-height: 100%;
14
+ border-radius: var(--border-radius-24);
15
+ }
16
+
17
+ .mobile {
18
+ border-radius: 0;
19
+ }
20
+
21
+ .videoButton {
22
+ position: absolute;
23
+ top: 50%;
24
+ left: 50%;
25
+ transform: translate(-50%, -50%);
26
+ z-index: 1;
27
+ color: green;
28
+ }
29
+
30
+ .icon {
31
+ color: var(--color-static-neutral-0);
32
+ }
33
+
34
+ .iconShape {
35
+ fill: var(--color-static-neutral-translucent-700);
36
+ }
@@ -2,3 +2,5 @@ export * from "./navigation-bar/index";
2
2
  export * from "./header/index";
3
3
  export * from "./image-preview/index";
4
4
  export * from "./image-viewer/index";
5
+ export * from "./info-bar/index";
6
+ export * from "./header-mobile/index";
@@ -2,3 +2,5 @@ export { NavigationBar } from './navigation-bar/Component.js';
2
2
  export { Header } from './header/Component.js';
3
3
  export { ImagePreview } from './image-preview/Component.js';
4
4
  export { ImageViewer } from './image-viewer/component.js';
5
+ export { InfoBar } from './info-bar/Component.js';
6
+ export { HeaderMobile } from './header-mobile/Component.js';
@@ -0,0 +1,4 @@
1
+ /// <reference types="react" />
2
+ import React from 'react';
3
+ declare const InfoBar: () => React.JSX.Element;
4
+ export { InfoBar };
@@ -0,0 +1,36 @@
1
+ import React, { useContext, useCallback } from 'react';
2
+ import { Typography } from '@alfalab/core-components-typography/moderncssm';
3
+ import { GalleryContext } from '../../context.js';
4
+ import { isVideo } from '../../utils/utils.js';
5
+ import { GALLERY_EVENTS } from '../../utils/constants.js';
6
+ import { Pause, Play, UnmuteVideo, MuteVideo } from '../buttons/index.js';
7
+ import styles from './index.module.css';
8
+
9
+ const InfoBar = () => {
10
+ const { getCurrentImage, mutedVideo, setMutedVideo, playingVideo, setPlayingVideo, getCurrentImageMeta, } = useContext(GalleryContext);
11
+ const image = getCurrentImage();
12
+ const meta = getCurrentImageMeta();
13
+ const handleMuteVideo = useCallback(() => {
14
+ if (mutedVideo) {
15
+ const customEvent = new CustomEvent(GALLERY_EVENTS.ON_UNMUTE, {
16
+ detail: { player: meta?.player?.current },
17
+ });
18
+ dispatchEvent(customEvent);
19
+ }
20
+ else {
21
+ const customEvent = new CustomEvent(GALLERY_EVENTS.ON_MUTE, {
22
+ detail: { player: meta?.player?.current },
23
+ });
24
+ dispatchEvent(customEvent);
25
+ }
26
+ setMutedVideo(!mutedVideo);
27
+ }, [meta?.player, mutedVideo, setMutedVideo]);
28
+ const handlePlayVideo = useCallback(() => {
29
+ setPlayingVideo(!playingVideo);
30
+ }, [playingVideo, setPlayingVideo]);
31
+ return isVideo(image?.src) ? (React.createElement("section", { className: styles.videoButtons },
32
+ playingVideo ? (React.createElement(Pause, { onClick: handlePlayVideo, className: styles.center })) : (React.createElement(Play, { onClick: handlePlayVideo, className: styles.center })),
33
+ mutedVideo ? (React.createElement(UnmuteVideo, { onClick: handleMuteVideo, className: styles.right })) : (React.createElement(MuteVideo, { onClick: handleMuteVideo, className: styles.right })))) : (React.createElement(Typography.Text, { className: styles.description, tag: 'div', view: 'component', color: 'primary-inverted' }, image?.name));
34
+ };
35
+
36
+ export { InfoBar };
@@ -0,0 +1 @@
1
+ export { InfoBar } from "./Component";
@@ -0,0 +1 @@
1
+ export { InfoBar } from './Component.js';
@@ -0,0 +1,23 @@
1
+ /* */
2
+
3
+ .description {
4
+ text-align: center;
5
+ margin-bottom: var(--gap-8);
6
+ }
7
+
8
+ .videoButtons {
9
+ padding: 0 var(--gap-8);
10
+ position: relative;
11
+ height: 48px;
12
+ }
13
+
14
+ .center {
15
+ position: absolute;
16
+ left: 50%;
17
+ transform: translateX(-50%);
18
+ }
19
+
20
+ .right {
21
+ position: absolute;
22
+ right: 0;
23
+ }
@@ -8,11 +8,12 @@ import styles from './index.module.css';
8
8
  const MIN_SCROLL_STEP = 24;
9
9
  const NavigationBar = () => {
10
10
  const containerRef = useRef(null);
11
- const { images, currentSlideIndex, setCurrentSlideIndex, getSwiper } = useContext(GalleryContext);
11
+ const { images, currentSlideIndex, setCurrentSlideIndex, getSwiper, setPlayingVideo } = useContext(GalleryContext);
12
12
  const swiper = getSwiper();
13
13
  const handlePreviewSelect = (index) => {
14
14
  setCurrentSlideIndex?.(index);
15
15
  if (swiper) {
16
+ setPlayingVideo(true);
16
17
  swiper.slideTo(index);
17
18
  }
18
19
  };
@@ -16,6 +16,10 @@
16
16
  display: none;
17
17
  }
18
18
 
19
+ .previews {
20
+ display: flex;
21
+ }
22
+
19
23
  .preview {
20
24
  flex-shrink: 0;
21
25
  margin: var(--gap-0) var(--gap-2)
@@ -2,13 +2,20 @@
2
2
  import SwiperCore from 'swiper';
3
3
  import { GalleryImage, ImageMeta } from "./types";
4
4
  type GalleryContext = {
5
+ view: 'desktop' | 'mobile';
5
6
  singleSlide: boolean;
6
7
  currentSlideIndex: number;
7
8
  images: GalleryImage[];
8
9
  imagesMeta: ImageMeta[];
9
10
  fullScreen: boolean;
11
+ mutedVideo: boolean;
12
+ playingVideo: boolean;
13
+ hideNavigation: boolean;
14
+ setHideNavigation: (hideNavigation: boolean) => void;
10
15
  initialSlide: number;
11
16
  setFullScreen: (fullScreen: boolean) => void;
17
+ setMutedVideo: (muteVideo: boolean) => void;
18
+ setPlayingVideo: (playingVideo: boolean) => void;
12
19
  setImageMeta: (meta: ImageMeta, index: number) => void;
13
20
  slideTo: (index: number) => void;
14
21
  slideNext: () => void;
@@ -3,11 +3,18 @@ import { createContext } from 'react';
3
3
  const mockFn = () => undefined;
4
4
  // eslint-disable-next-line @typescript-eslint/no-redeclare
5
5
  const GalleryContext = createContext({
6
+ view: 'desktop',
6
7
  singleSlide: false,
7
8
  currentSlideIndex: 0,
8
9
  images: [],
9
10
  imagesMeta: [],
10
11
  fullScreen: false,
12
+ mutedVideo: false,
13
+ playingVideo: false,
14
+ hideNavigation: false,
15
+ setHideNavigation: mockFn,
16
+ setMutedVideo: mockFn,
17
+ setPlayingVideo: mockFn,
11
18
  initialSlide: 0,
12
19
  setFullScreen: mockFn,
13
20
  setImageMeta: mockFn,
@@ -1,2 +1,2 @@
1
1
  export * from "./Component";
2
- export * from "./utils/index";
2
+ export { GALLERY_EVENTS, TestIds } from "./utils/index";
@@ -1,4 +1,2 @@
1
1
  export { Gallery } from './Component.js';
2
- export { splitFilename } from './utils/split-filename.js';
3
- export { PLACEHOLDER_HEIGHT, PLACEHOLDER_WIDTH, getImageAlt, getImageKey, isSmallImage } from './utils/utils.js';
4
- export { TestIds } from './utils/constants.js';
2
+ export { GALLERY_EVENTS, TestIds } from './utils/constants.js';
@@ -1,6 +1,8 @@
1
1
  /* */
2
2
 
3
3
  .container {
4
+ position: relative;
5
+ overflow: hidden;
4
6
  display: flex;
5
7
  flex-direction: column;
6
8
  justify-content: space-between;
@@ -11,7 +13,21 @@
11
13
 
12
14
  .modal {
13
15
  flex-grow: 1;
14
- width: 100%;
15
- height: 100%;
16
+ width: 100vw;
17
+ height: 100vh;
16
18
  background: transparent;
17
19
  }
20
+
21
+ .navigationVideo {
22
+ background-color: var(--color-static-neutral-0-inverted);
23
+ z-index: 3;
24
+ width: 100%;
25
+ position: absolute;
26
+ bottom: 0;
27
+ left: 0;
28
+ transition: transform 0.3s ease-in-out;
29
+ }
30
+
31
+ .hideNavigation {
32
+ transform: translateY(106px);
33
+ }
@@ -1,3 +1,4 @@
1
+ import { RefObject } from 'react';
1
2
  type GalleryImage = {
2
3
  src: string;
3
4
  name?: string;
@@ -9,5 +10,11 @@ type ImageMeta = {
9
10
  width: number;
10
11
  height: number;
11
12
  broken?: boolean;
13
+ player?: never;
14
+ } | {
15
+ width?: never;
16
+ height?: never;
17
+ broken?: boolean;
18
+ player: RefObject<HTMLVideoElement>;
12
19
  };
13
20
  export { GalleryImage, ImageMeta };
@@ -7,5 +7,18 @@ declare const TestIds: {
7
7
  EXIT_FULLSCREEN_BUTTON: string;
8
8
  DOWNLOAD_BUTTON: string;
9
9
  NAVIGATION_BAR: string;
10
+ MUTE_BUTTON: string;
11
+ UNMUTE_BUTTON: string;
10
12
  };
11
- export { TestIds };
13
+ declare const PREVIEW_WIDTH_MOBILE = 36;
14
+ declare const PREVIEW_HEIGHT_MOBILE = 46;
15
+ declare const PREVIEW_WIDTH_DESKTOP = 56;
16
+ declare const PREVIEW_HEIGHT_DESKTOP = 56;
17
+ declare const PREVIEW_VIDEO_MULTIPLIER = 12;
18
+ declare const GALLERY_EVENTS: {
19
+ ON_PLAY: string;
20
+ ON_PAUSE: string;
21
+ ON_MUTE: string;
22
+ ON_UNMUTE: string;
23
+ };
24
+ export { TestIds, PREVIEW_WIDTH_MOBILE, PREVIEW_HEIGHT_MOBILE, PREVIEW_WIDTH_DESKTOP, PREVIEW_HEIGHT_DESKTOP, PREVIEW_VIDEO_MULTIPLIER, GALLERY_EVENTS };
@@ -7,6 +7,19 @@ const TestIds = {
7
7
  EXIT_FULLSCREEN_BUTTON: 'exit-fullscreen-button',
8
8
  DOWNLOAD_BUTTON: 'download-button',
9
9
  NAVIGATION_BAR: 'navigation-bar',
10
+ MUTE_BUTTON: 'mute-button',
11
+ UNMUTE_BUTTON: 'unmute-button',
12
+ };
13
+ const PREVIEW_WIDTH_MOBILE = 36;
14
+ const PREVIEW_HEIGHT_MOBILE = 46;
15
+ const PREVIEW_WIDTH_DESKTOP = 56;
16
+ const PREVIEW_HEIGHT_DESKTOP = 56;
17
+ const PREVIEW_VIDEO_MULTIPLIER = 12;
18
+ const GALLERY_EVENTS = {
19
+ ON_PLAY: 'Gallery:OnPlay',
20
+ ON_PAUSE: 'Gallery:OnPause',
21
+ ON_MUTE: 'Gallery:OnMute',
22
+ ON_UNMUTE: 'Gallery:OnUnmute',
10
23
  };
11
24
 
12
- export { TestIds };
25
+ export { GALLERY_EVENTS, PREVIEW_HEIGHT_DESKTOP, PREVIEW_HEIGHT_MOBILE, PREVIEW_VIDEO_MULTIPLIER, PREVIEW_WIDTH_DESKTOP, PREVIEW_WIDTH_MOBILE, TestIds };
@@ -1,3 +1,3 @@
1
1
  export { splitFilename } from './split-filename.js';
2
- export { PLACEHOLDER_HEIGHT, PLACEHOLDER_WIDTH, getImageAlt, getImageKey, isSmallImage } from './utils.js';
3
- export { TestIds } from './constants.js';
2
+ export { PLACEHOLDER_HEIGHT, PLACEHOLDER_WIDTH, getImageAlt, getImageKey, isSmallImage, isVideo } from './utils.js';
3
+ export { GALLERY_EVENTS, PREVIEW_HEIGHT_DESKTOP, PREVIEW_HEIGHT_MOBILE, PREVIEW_VIDEO_MULTIPLIER, PREVIEW_WIDTH_DESKTOP, PREVIEW_WIDTH_MOBILE, TestIds } from './constants.js';
@@ -4,4 +4,5 @@ declare const PLACEHOLDER_HEIGHT = 300;
4
4
  declare const getImageKey: ({ name, src }: GalleryImage, index: number) => string;
5
5
  declare const getImageAlt: ({ alt, name }: GalleryImage, index: number) => string;
6
6
  declare const isSmallImage: (meta?: ImageMeta) => boolean;
7
- export { PLACEHOLDER_WIDTH, PLACEHOLDER_HEIGHT, getImageKey, getImageAlt, isSmallImage };
7
+ declare const isVideo: (url: string | undefined) => boolean;
8
+ export { PLACEHOLDER_WIDTH, PLACEHOLDER_HEIGHT, getImageKey, getImageAlt, isSmallImage, isVideo };
@@ -3,10 +3,11 @@ const PLACEHOLDER_HEIGHT = 300;
3
3
  const getImageKey = ({ name = '', src }, index) => `${name}-${index}-${src}`;
4
4
  const getImageAlt = ({ alt, name }, index) => alt || name || `Изображение ${index + 1}`;
5
5
  const isSmallImage = (meta) => {
6
- if (!meta) {
7
- return false;
6
+ if (meta && meta.width && meta.height) {
7
+ return meta.width < PLACEHOLDER_WIDTH && meta.height < PLACEHOLDER_HEIGHT;
8
8
  }
9
- return meta.width < PLACEHOLDER_WIDTH && meta.height < PLACEHOLDER_HEIGHT;
9
+ return false;
10
10
  };
11
+ const isVideo = (url) => /(.*?)(\.webm|\.mp4|\.m3u8)$/.test(url ?? '');
11
12
 
12
- export { PLACEHOLDER_HEIGHT, PLACEHOLDER_WIDTH, getImageAlt, getImageKey, isSmallImage };
13
+ export { PLACEHOLDER_HEIGHT, PLACEHOLDER_WIDTH, getImageAlt, getImageKey, isSmallImage, isVideo };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@alfalab/core-components-gallery",
3
- "version": "5.7.4",
3
+ "version": "5.8.1",
4
4
  "description": "",
5
5
  "keywords": [],
6
6
  "license": "MIT",
@@ -16,11 +16,12 @@
16
16
  "dependencies": {
17
17
  "@alfalab/core-components-base-modal": "^5.8.2",
18
18
  "@alfalab/core-components-icon-button": "^6.10.1",
19
- "@alfalab/core-components-tooltip": "^7.5.0",
20
- "@alfalab/core-components-typography": "^4.10.1",
19
+ "@alfalab/core-components-tooltip": "^7.5.1",
20
+ "@alfalab/core-components-typography": "^4.10.2",
21
21
  "@alfalab/hooks": "^1.13.0",
22
22
  "@alfalab/icons-glyph": "^2.139.0",
23
23
  "classnames": "^2.3.1",
24
+ "hls.js": "^1.5.13",
24
25
  "element-closest": "^3.0.2",
25
26
  "swiper": "^6.8.2",
26
27
  "tslib": "^2.4.0"
@@ -3,41 +3,51 @@
3
3
  var React = require('react');
4
4
  var cn = require('classnames');
5
5
  var coreComponentsTypography = require('@alfalab/core-components-typography');
6
+ var context = require('./context.js');
6
7
  var utils_utils = require('./utils/utils.js');
7
8
  var utils_constants = require('./utils/constants.js');
8
9
  var components_imageViewer_paths = require('./components/image-viewer/paths.js');
10
+ var components_imageViewer_video_index = require('./components/image-viewer/video/index.js');
9
11
 
10
12
  function _interopDefaultCompat (e) { return e && typeof e === 'object' && 'default' in e ? e : { default: e }; }
11
13
 
12
14
  var React__default = /*#__PURE__*/_interopDefaultCompat(React);
13
15
  var cn__default = /*#__PURE__*/_interopDefaultCompat(cn);
14
16
 
15
- var styles = {"component":"gallery__component_i28al","swiper":"gallery__swiper_i28al","singleSlide":"gallery__singleSlide_i28al","hidden":"gallery__hidden_i28al","slide":"gallery__slide_i28al","slideLoading":"gallery__slideLoading_i28al","image":"gallery__image_i28al","smallImage":"gallery__smallImage_i28al","verticalImageFit":"gallery__verticalImageFit_i28al","horizontalImageFit":"gallery__horizontalImageFit_i28al","arrow":"gallery__arrow_i28al","focused":"gallery__focused_i28al","placeholder":"gallery__placeholder_i28al","brokenImgWrapper":"gallery__brokenImgWrapper_i28al","brokenImgIcon":"gallery__brokenImgIcon_i28al","fullScreenImage":"gallery__fullScreenImage_i28al"};
17
+ var styles = {"component":"gallery__component_1tvza","swiper":"gallery__swiper_1tvza","mobile":"gallery__mobile_1tvza","mobileVideo":"gallery__mobileVideo_1tvza","singleSlide":"gallery__singleSlide_1tvza","hidden":"gallery__hidden_1tvza","slide":"gallery__slide_1tvza","slideLoading":"gallery__slideLoading_1tvza","image":"gallery__image_1tvza","smallImage":"gallery__smallImage_1tvza","verticalImageFit":"gallery__verticalImageFit_1tvza","horizontalImageFit":"gallery__horizontalImageFit_1tvza","arrow":"gallery__arrow_1tvza","focused":"gallery__focused_1tvza","placeholder":"gallery__placeholder_1tvza","brokenImgWrapper":"gallery__brokenImgWrapper_1tvza","brokenImgIcon":"gallery__brokenImgIcon_1tvza","fullScreenImage":"gallery__fullScreenImage_1tvza","fullScreenVideo":"gallery__fullScreenVideo_1tvza"};
16
18
  require('./components/image-viewer/index.css')
17
19
 
18
20
  var SlideInner = function (_a) {
19
21
  var _b;
20
- var children = _a.children, broken = _a.broken, loading = _a.loading, withPlaceholder = _a.withPlaceholder;
22
+ var children = _a.children, broken = _a.broken, loading = _a.loading, withPlaceholder = _a.withPlaceholder, isVideoView = _a.isVideoView;
21
23
  var content = broken ? (React__default.default.createElement("div", { className: styles.brokenImgWrapper },
22
24
  React__default.default.createElement("div", { className: styles.brokenImgIcon },
23
25
  React__default.default.createElement("svg", { xmlns: 'http://www.w3.org/2000/svg', width: '80', height: '80', viewBox: '0 0 80 80', fill: 'none' },
24
26
  React__default.default.createElement("rect", { width: '80', height: '80', fill: 'none' }),
25
27
  React__default.default.createElement("path", { fillRule: 'evenodd', clipRule: 'evenodd', d: components_imageViewer_paths.NoImagePaths.baseImage, fill: '#89898A' }),
26
28
  React__default.default.createElement("path", { d: components_imageViewer_paths.NoImagePaths.triangleImage, fill: '#89898A' }))),
27
- React__default.default.createElement(coreComponentsTypography.Typography.Text, { view: 'primary-small', color: 'static-secondary-light' }, "\u041D\u0435 \u0443\u0434\u0430\u043B\u043E\u0441\u044C \u0437\u0430\u0433\u0440\u0443\u0437\u0438\u0442\u044C \u0438\u0437\u043E\u0431\u0440\u0430\u0436\u0435\u043D\u0438\u0435"))) : (children);
29
+ React__default.default.createElement(coreComponentsTypography.Typography.Text, { view: 'primary-small', color: 'static-secondary-light' },
30
+ "\u041D\u0435 \u0443\u0434\u0430\u043B\u043E\u0441\u044C \u0437\u0430\u0433\u0440\u0443\u0437\u0438\u0442\u044C ",
31
+ isVideoView ? 'видео' : 'изображение'))) : (children);
28
32
  return (React__default.default.createElement("div", { className: cn__default.default(styles.slide, (_b = {}, _b[styles.slideLoading] = loading, _b)) }, withPlaceholder ? React__default.default.createElement("div", { className: styles.placeholder }, content) : content));
29
33
  };
30
34
  var Slide = function (_a) {
31
35
  var _b;
32
36
  var isActive = _a.isActive, meta = _a.meta, swiperAspectRatio = _a.swiperAspectRatio, imageAspectRatio = _a.imageAspectRatio, image = _a.image, index = _a.index, swiperHeight = _a.swiperHeight, slideVisible = _a.slideVisible, handleLoad = _a.handleLoad, handleLoadError = _a.handleLoadError;
37
+ var view = React.useContext(context.GalleryContext).view;
33
38
  var broken = Boolean(meta === null || meta === void 0 ? void 0 : meta.broken);
34
39
  var small = utils_utils.isSmallImage(meta);
35
40
  var verticalImageFit = !small && swiperAspectRatio > imageAspectRatio;
36
41
  var horizontalImageFit = !small && swiperAspectRatio <= imageAspectRatio;
42
+ if (utils_utils.isVideo(image.src)) {
43
+ return (React__default.default.createElement(SlideInner, { isVideoView: true, active: isActive, broken: broken, withPlaceholder: broken, loading: !meta },
44
+ React__default.default.createElement(components_imageViewer_video_index.Video, { url: image.src, index: index, isActive: isActive })));
45
+ }
37
46
  return (React__default.default.createElement(SlideInner, { active: isActive, broken: broken, loading: !meta, withPlaceholder: small || broken },
38
47
  React__default.default.createElement("img", { src: image.src, alt: utils_utils.getImageAlt(image, index), className: cn__default.default((_b = {},
39
48
  _b[styles.smallImage] = small,
40
49
  _b[styles.image] = !small && meta,
50
+ _b[styles.mobile] = view === 'mobile',
41
51
  _b[styles.verticalImageFit] = verticalImageFit,
42
52
  _b[styles.horizontalImageFit] = horizontalImageFit,
43
53
  _b)), onLoad: function (event) { return handleLoad(event, index); }, onError: function () { return handleLoadError(index); }, style: {