@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
@@ -1,6 +1,7 @@
1
1
  import React, { type FC, useCallback, useContext, useEffect, useRef, useState } from 'react';
2
2
  import cn from 'classnames';
3
- import throttle from 'lodash/throttle';
3
+
4
+ import { isClient } from '@alfalab/core-components-shared';
4
5
 
5
6
  import { GalleryContext } from '../../context';
6
7
  import { getImageKey, TestIds } from '../../utils';
@@ -9,13 +10,15 @@ import { ImagePreview } from '../image-preview';
9
10
  import styles from './index.module.css';
10
11
 
11
12
  const MIN_SCROLL_STEP = 24;
12
- const SCROLL_SPEED = 2; // Коэффициент скорости прокрутки (можно настроить)
13
- const SCROLL_THRESHOLD = 150; // Расстояние от границы, при котором начинается прокрутка
13
+ const DRAG_CLICK_THRESHOLD = 5;
14
14
 
15
15
  export const NavigationBar: FC = () => {
16
16
  const containerRef = useRef<HTMLDivElement>(null);
17
+ const dragStartXRef = useRef<number>(0);
18
+ const dragStartScrollLeftRef = useRef<number>(0);
19
+ const suppressClickRef = useRef<boolean>(false);
17
20
 
18
- const [isNavMouseDowned, setIsNavMouseDowned] = useState<boolean>(false);
21
+ const [isDragging, setIsDragging] = useState<boolean>(false);
19
22
 
20
23
  const { images, currentSlideIndex, setCurrentSlideIndex, getSwiper, setPlayingVideo, view } =
21
24
  useContext(GalleryContext);
@@ -41,38 +44,72 @@ export const NavigationBar: FC = () => {
41
44
  }
42
45
  }, []);
43
46
 
44
- const handlePreviewMouseDown = () => {
45
- setIsNavMouseDowned(true);
46
- };
47
-
48
- const handlePreviewMouseUp = () => {
49
- setIsNavMouseDowned(false);
50
- if (containerRef.current) {
51
- containerRef.current.style.scrollBehavior = 'auto'; // Отключаем плавность для резкой остановки
47
+ const handlePreviewMouseDown = (e: React.MouseEvent<HTMLDivElement>) => {
48
+ if (e.button !== 0 || !containerRef.current) {
49
+ return;
52
50
  }
51
+
52
+ dragStartXRef.current = e.clientX;
53
+ dragStartScrollLeftRef.current = containerRef.current.scrollLeft;
54
+ suppressClickRef.current = false;
55
+ setIsDragging(true);
53
56
  };
54
57
 
55
- const handleMouseNavigationMove = throttle((e: React.MouseEvent<HTMLDivElement>) => {
56
- if (!containerRef.current || !isNavMouseDowned) return;
58
+ const handlePreviewMouseUp = useCallback(() => {
59
+ setIsDragging(false);
60
+ }, []);
57
61
 
62
+ const dragTo = useCallback((clientX: number) => {
58
63
  const container = containerRef.current;
59
- const { width: containerWidth, left: containerLeft } = container.getBoundingClientRect();
60
- const mouseX = e.clientX;
61
64
 
62
- // Если курсор близко к правой границе
63
- if (mouseX > containerWidth + containerLeft - SCROLL_THRESHOLD) {
64
- const scrollValue =
65
- (mouseX - (containerWidth + containerLeft - SCROLL_THRESHOLD)) * SCROLL_SPEED;
65
+ if (!container) {
66
+ return;
67
+ }
68
+
69
+ const deltaX = clientX - dragStartXRef.current;
66
70
 
67
- container.scrollBy({ left: scrollValue, behavior: 'smooth' });
71
+ if (Math.abs(deltaX) > DRAG_CLICK_THRESHOLD) {
72
+ suppressClickRef.current = true;
68
73
  }
69
- // Если курсор близко к левой границе
70
- else if (mouseX < containerLeft + SCROLL_THRESHOLD) {
71
- const scrollValue = (mouseX - (containerLeft + SCROLL_THRESHOLD)) * SCROLL_SPEED;
72
74
 
73
- container.scrollBy({ left: scrollValue, behavior: 'smooth' });
75
+ container.scrollLeft = dragStartScrollLeftRef.current - deltaX;
76
+ }, []);
77
+
78
+ const handleMouseNavigationMove = (e: React.MouseEvent<HTMLDivElement>) => {
79
+ if (!isDragging) {
80
+ return;
74
81
  }
75
- }, 150);
82
+
83
+ dragTo(e.clientX);
84
+ };
85
+
86
+ const handleClickCapture = (e: React.MouseEvent<HTMLDivElement>) => {
87
+ if (!suppressClickRef.current) {
88
+ return;
89
+ }
90
+
91
+ e.preventDefault();
92
+ e.stopPropagation();
93
+ suppressClickRef.current = false;
94
+ };
95
+
96
+ useEffect(() => {
97
+ if (!isClient() || !isDragging) {
98
+ return undefined;
99
+ }
100
+
101
+ const handleDocumentMouseMove = (event: MouseEvent) => {
102
+ dragTo(event.clientX);
103
+ };
104
+
105
+ document.addEventListener('mousemove', handleDocumentMouseMove);
106
+ document.addEventListener('mouseup', handlePreviewMouseUp);
107
+
108
+ return () => {
109
+ document.removeEventListener('mousemove', handleDocumentMouseMove);
110
+ document.removeEventListener('mouseup', handlePreviewMouseUp);
111
+ };
112
+ }, [dragTo, handlePreviewMouseUp, isDragging]);
76
113
 
77
114
  const handlePreviewPosition = useCallback(
78
115
  (preview: Element, containerWidth: number) => {
@@ -110,12 +147,16 @@ export const NavigationBar: FC = () => {
110
147
  return (
111
148
  // eslint-disable-next-line jsx-a11y/no-static-element-interactions
112
149
  <div
113
- className={cn(styles.component, { [styles.mobile]: view === 'mobile' })}
150
+ className={cn(styles.component, {
151
+ [styles.mobile]: view === 'mobile',
152
+ [styles.dragging]: isDragging,
153
+ })}
114
154
  ref={containerRef}
115
155
  data-test-id={TestIds.NAVIGATION_BAR}
116
156
  onMouseDown={handlePreviewMouseDown}
117
157
  onMouseUp={handlePreviewMouseUp}
118
158
  onMouseMove={handleMouseNavigationMove}
159
+ onClickCapture={handleClickCapture}
119
160
  >
120
161
  {images.map((image, index) => {
121
162
  const active = index === currentSlideIndex;
@@ -8,12 +8,22 @@
8
8
  flex-shrink: 0;
9
9
  overflow-x: auto;
10
10
  box-sizing: border-box;
11
- padding: var(--gap-12) var(--gap-24);
11
+ padding: var(--gap-12) var(--gap-32);
12
12
  scrollbar-width: none;
13
13
  background-color: var(--color-static-neutral-0-inverted);
14
+ cursor: grab;
15
+ user-select: none;
14
16
 
15
17
  &.mobile {
16
- padding: var(--gap-8) var(--gap-24);
18
+ padding: var(--gap-8);
19
+ }
20
+
21
+ &.dragging {
22
+ cursor: grabbing;
23
+
24
+ & * {
25
+ cursor: grabbing;
26
+ }
17
27
  }
18
28
 
19
29
  &::-webkit-scrollbar {
package/src/constants.ts CHANGED
@@ -1,4 +1,4 @@
1
- export const SWIPE_THRESHOLD = -250;
1
+ export const SWIPE_THRESHOLD = 250;
2
2
 
3
3
  export const PREVIEW_WIDTH_MOBILE = 46;
4
4
  export const PREVIEW_HEIGHT_MOBILE = 46;
@@ -2,7 +2,7 @@ import { useContext, useEffect, useState } from 'react';
2
2
 
3
3
  import { GalleryContext } from '../context';
4
4
 
5
- const SUBTITLES_ANIMATION_SPEED = 0.5;
5
+ const SUBTITLES_FADE_DURATION_SECONDS = 0.5;
6
6
 
7
7
  export const useCustomSubtitles = () => {
8
8
  const { getCurrentImageMeta } = useContext(GalleryContext);
@@ -15,14 +15,25 @@ export const useCustomSubtitles = () => {
15
15
  const player = meta?.player?.current;
16
16
 
17
17
  useEffect(() => {
18
- const intervalId = setInterval(() => {
19
- if (!player) {
20
- return;
18
+ if (!player) {
19
+ return undefined;
20
+ }
21
+
22
+ const { textTracks } = player;
23
+
24
+ let textTrack: TextTrack | undefined;
25
+ let hideTimeoutId: ReturnType<typeof setTimeout> | undefined;
26
+
27
+ const clearHideTimeout = () => {
28
+ if (hideTimeoutId !== undefined) {
29
+ clearTimeout(hideTimeoutId);
30
+ hideTimeoutId = undefined;
21
31
  }
32
+ };
33
+
34
+ const syncSubtitles = () => {
35
+ clearHideTimeout();
22
36
 
23
- const textTrack = [...(Array.from(player.textTracks) || [])].find(
24
- (track) => track.kind === 'subtitles',
25
- );
26
37
  const activeCue = textTrack?.activeCues?.[0] as VTTCue | undefined;
27
38
 
28
39
  if (!activeCue?.text) {
@@ -31,16 +42,65 @@ export const useCustomSubtitles = () => {
31
42
  return;
32
43
  }
33
44
 
34
- const isVisible =
35
- player?.currentTime >= activeCue.startTime &&
36
- player?.currentTime <= activeCue.endTime - SUBTITLES_ANIMATION_SPEED;
45
+ const fadeStartTime = activeCue.endTime - SUBTITLES_FADE_DURATION_SECONDS;
46
+ const isVisible = player.currentTime <= fadeStartTime;
37
47
 
38
48
  setCurrentSub(activeCue.text);
39
49
  setShowSub(isVisible);
40
- });
50
+
51
+ if (!isVisible || player.paused || player.playbackRate <= 0) {
52
+ return;
53
+ }
54
+
55
+ const timeUntilFadeMs =
56
+ ((fadeStartTime - player.currentTime) / player.playbackRate) * 1000;
57
+
58
+ hideTimeoutId = setTimeout(() => {
59
+ setShowSub(false);
60
+ }, timeUntilFadeMs);
61
+ };
62
+
63
+ const connectTextTrack = () => {
64
+ const nextTextTrack = Array.from(textTracks).find(
65
+ (track) => track.kind === 'subtitles',
66
+ );
67
+
68
+ if (nextTextTrack === textTrack) {
69
+ syncSubtitles();
70
+
71
+ return;
72
+ }
73
+
74
+ textTrack?.removeEventListener('cuechange', syncSubtitles);
75
+ textTrack = nextTextTrack;
76
+ textTrack?.addEventListener('cuechange', syncSubtitles);
77
+ syncSubtitles();
78
+ };
79
+
80
+ player.addEventListener('play', syncSubtitles);
81
+ player.addEventListener('playing', syncSubtitles);
82
+ player.addEventListener('pause', clearHideTimeout);
83
+ player.addEventListener('waiting', clearHideTimeout);
84
+ player.addEventListener('seeking', clearHideTimeout);
85
+ player.addEventListener('seeked', syncSubtitles);
86
+ player.addEventListener('ratechange', syncSubtitles);
87
+ textTracks.addEventListener('addtrack', connectTextTrack);
88
+ textTracks.addEventListener('change', connectTextTrack);
89
+
90
+ connectTextTrack();
41
91
 
42
92
  return () => {
43
- clearInterval(intervalId);
93
+ clearHideTimeout();
94
+ textTrack?.removeEventListener('cuechange', syncSubtitles);
95
+ player.removeEventListener('play', syncSubtitles);
96
+ player.removeEventListener('playing', syncSubtitles);
97
+ player.removeEventListener('pause', clearHideTimeout);
98
+ player.removeEventListener('waiting', clearHideTimeout);
99
+ player.removeEventListener('seeking', clearHideTimeout);
100
+ player.removeEventListener('seeked', syncSubtitles);
101
+ player.removeEventListener('ratechange', syncSubtitles);
102
+ textTracks.removeEventListener('addtrack', connectTextTrack);
103
+ textTracks.removeEventListener('change', connectTextTrack);
44
104
  };
45
105
  }, [player]);
46
106
 
package/src/types.ts CHANGED
@@ -44,10 +44,12 @@ export type ImageMeta =
44
44
  height: number;
45
45
  broken?: boolean;
46
46
  player?: never;
47
+ loaded?: boolean;
47
48
  }
48
49
  | {
49
- width?: never;
50
- height?: never;
50
+ width?: number;
51
+ height?: number;
51
52
  broken?: boolean;
52
53
  player: RefObject<HTMLVideoElement>;
54
+ loaded?: boolean;
53
55
  };
@@ -1,3 +1,4 @@
1
1
  export * from './split-filename';
2
2
  export * from './utils';
3
3
  export * from './constants';
4
+ export * from './modern-download';
@@ -0,0 +1,107 @@
1
+ const downloadWithBlob = (blob: Blob, fileName: string): void => {
2
+ const url = URL.createObjectURL(blob);
3
+ const link = document.createElement('a');
4
+
5
+ link.href = url;
6
+ link.download = fileName;
7
+ document.body.appendChild(link);
8
+ link.click();
9
+ document.body.removeChild(link);
10
+ setTimeout(() => URL.revokeObjectURL(url), 100);
11
+ };
12
+
13
+ const downloadWithLink = (url: string, fileName: string): void => {
14
+ const link = document.createElement('a');
15
+
16
+ link.href = url;
17
+ link.download = fileName;
18
+ link.target = '_blank';
19
+ link.rel = 'noopener noreferrer';
20
+ document.body.appendChild(link);
21
+ link.click();
22
+ document.body.removeChild(link);
23
+ };
24
+
25
+ const canUseBlobDownload = (): boolean =>
26
+ typeof fetch === 'function' &&
27
+ typeof URL.createObjectURL === 'function' &&
28
+ typeof URL.revokeObjectURL === 'function';
29
+
30
+ const canUseFileShare = (): boolean =>
31
+ typeof File === 'function' &&
32
+ typeof navigator !== 'undefined' &&
33
+ typeof navigator.share === 'function' &&
34
+ typeof navigator.canShare === 'function';
35
+
36
+ const canShareFiles = (files: File[]): boolean =>
37
+ canUseFileShare() && navigator.canShare({ files });
38
+
39
+ const getBlob = async (url: string): Promise<Blob> => {
40
+ const response = await fetch(url);
41
+
42
+ if (!response.ok) {
43
+ throw new Error('Network error');
44
+ }
45
+
46
+ return response.blob();
47
+ };
48
+
49
+ const isAbortError = (error: unknown): boolean =>
50
+ typeof DOMException !== 'undefined' &&
51
+ error instanceof DOMException &&
52
+ error.name === 'AbortError';
53
+
54
+ export interface DownloadOptions {
55
+ url: string;
56
+ fileName?: string;
57
+ fileType?: string;
58
+ }
59
+
60
+ export const downloadFile = async ({
61
+ url,
62
+ fileName = 'download',
63
+ fileType,
64
+ }: DownloadOptions): Promise<void> => {
65
+ if (!canUseBlobDownload()) {
66
+ downloadWithLink(url, fileName);
67
+
68
+ return;
69
+ }
70
+
71
+ if (canUseFileShare() && canShareFiles([new File([], fileName, { type: fileType })])) {
72
+ try {
73
+ const blob = await getBlob(url);
74
+
75
+ const file = new File([blob], fileName, { type: blob.type || fileType });
76
+
77
+ if (!canShareFiles([file])) {
78
+ downloadWithBlob(blob, fileName);
79
+
80
+ return;
81
+ }
82
+
83
+ await navigator.share({
84
+ files: [file],
85
+ title: `Скачать ${fileName}`,
86
+ });
87
+
88
+ return;
89
+ } catch (error) {
90
+ if (isAbortError(error)) {
91
+ return;
92
+ }
93
+
94
+ downloadWithLink(url, fileName);
95
+
96
+ return;
97
+ }
98
+ }
99
+
100
+ try {
101
+ const blob = await getBlob(url);
102
+
103
+ downloadWithBlob(blob, fileName);
104
+ } catch {
105
+ downloadWithLink(url, fileName);
106
+ }
107
+ };
package/types.d.ts CHANGED
@@ -40,9 +40,11 @@ export type ImageMeta = {
40
40
  height: number;
41
41
  broken?: boolean;
42
42
  player?: never;
43
+ loaded?: boolean;
43
44
  } | {
44
- width?: never;
45
- height?: never;
45
+ width?: number;
46
+ height?: number;
46
47
  broken?: boolean;
47
48
  player: RefObject<HTMLVideoElement>;
49
+ loaded?: boolean;
48
50
  };
package/utils/index.d.ts CHANGED
@@ -1,3 +1,4 @@
1
1
  export * from './split-filename';
2
2
  export * from './utils';
3
3
  export * from './constants';
4
+ export * from './modern-download';
package/utils/index.js CHANGED
@@ -5,6 +5,7 @@ Object.defineProperty(exports, '__esModule', { value: true });
5
5
  var splitFilename = require('./split-filename.js');
6
6
  var utils = require('./utils.js');
7
7
  var constants = require('./constants.js');
8
+ var modernDownload = require('./modern-download.js');
8
9
 
9
10
 
10
11
 
@@ -16,4 +17,5 @@ exports.getImageKey = utils.getImageKey;
16
17
  exports.isSmallImage = utils.isSmallImage;
17
18
  exports.isVideo = utils.isVideo;
18
19
  exports.TestIds = constants.TestIds;
20
+ exports.downloadFile = modernDownload.downloadFile;
19
21
  //# sourceMappingURL=index.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;;;;;;;;;;;;;"}
1
+ {"version":3,"file":"index.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;"}
@@ -0,0 +1,6 @@
1
+ export interface DownloadOptions {
2
+ url: string;
3
+ fileName?: string;
4
+ fileType?: string;
5
+ }
6
+ export declare const downloadFile: ({ url, fileName, fileType, }: DownloadOptions) => Promise<void>;
@@ -0,0 +1,113 @@
1
+ 'use strict';
2
+
3
+ Object.defineProperty(exports, '__esModule', { value: true });
4
+
5
+ var tslib = require('tslib');
6
+
7
+ var downloadWithBlob = function (blob, fileName) {
8
+ var url = URL.createObjectURL(blob);
9
+ var link = document.createElement('a');
10
+ link.href = url;
11
+ link.download = fileName;
12
+ document.body.appendChild(link);
13
+ link.click();
14
+ document.body.removeChild(link);
15
+ setTimeout(function () { return URL.revokeObjectURL(url); }, 100);
16
+ };
17
+ var downloadWithLink = function (url, fileName) {
18
+ var link = document.createElement('a');
19
+ link.href = url;
20
+ link.download = fileName;
21
+ link.target = '_blank';
22
+ link.rel = 'noopener noreferrer';
23
+ document.body.appendChild(link);
24
+ link.click();
25
+ document.body.removeChild(link);
26
+ };
27
+ var canUseBlobDownload = function () {
28
+ return typeof fetch === 'function' &&
29
+ typeof URL.createObjectURL === 'function' &&
30
+ typeof URL.revokeObjectURL === 'function';
31
+ };
32
+ var canUseFileShare = function () {
33
+ return typeof File === 'function' &&
34
+ typeof navigator !== 'undefined' &&
35
+ typeof navigator.share === 'function' &&
36
+ typeof navigator.canShare === 'function';
37
+ };
38
+ var canShareFiles = function (files) {
39
+ return canUseFileShare() && navigator.canShare({ files: files });
40
+ };
41
+ var getBlob = function (url) { return tslib.__awaiter(void 0, void 0, void 0, function () {
42
+ var response;
43
+ return tslib.__generator(this, function (_a) {
44
+ switch (_a.label) {
45
+ case 0: return [4 /*yield*/, fetch(url)];
46
+ case 1:
47
+ response = _a.sent();
48
+ if (!response.ok) {
49
+ throw new Error('Network error');
50
+ }
51
+ return [2 /*return*/, response.blob()];
52
+ }
53
+ });
54
+ }); };
55
+ var isAbortError = function (error) {
56
+ return typeof DOMException !== 'undefined' &&
57
+ error instanceof DOMException &&
58
+ error.name === 'AbortError';
59
+ };
60
+ var downloadFile = function (_a) { return tslib.__awaiter(void 0, [_a], void 0, function (_b) {
61
+ var blob, file, error_1, blob;
62
+ var url = _b.url, _d = _b.fileName, fileName = _d === void 0 ? 'download' : _d, fileType = _b.fileType;
63
+ return tslib.__generator(this, function (_e) {
64
+ switch (_e.label) {
65
+ case 0:
66
+ if (!canUseBlobDownload()) {
67
+ downloadWithLink(url, fileName);
68
+ return [2 /*return*/];
69
+ }
70
+ if (!(canUseFileShare() && canShareFiles([new File([], fileName, { type: fileType })]))) return [3 /*break*/, 5];
71
+ _e.label = 1;
72
+ case 1:
73
+ _e.trys.push([1, 4, , 5]);
74
+ return [4 /*yield*/, getBlob(url)];
75
+ case 2:
76
+ blob = _e.sent();
77
+ file = new File([blob], fileName, { type: blob.type || fileType });
78
+ if (!canShareFiles([file])) {
79
+ downloadWithBlob(blob, fileName);
80
+ return [2 /*return*/];
81
+ }
82
+ return [4 /*yield*/, navigator.share({
83
+ files: [file],
84
+ title: "\u0421\u043A\u0430\u0447\u0430\u0442\u044C ".concat(fileName),
85
+ })];
86
+ case 3:
87
+ _e.sent();
88
+ return [2 /*return*/];
89
+ case 4:
90
+ error_1 = _e.sent();
91
+ if (isAbortError(error_1)) {
92
+ return [2 /*return*/];
93
+ }
94
+ downloadWithLink(url, fileName);
95
+ return [2 /*return*/];
96
+ case 5:
97
+ _e.trys.push([5, 7, , 8]);
98
+ return [4 /*yield*/, getBlob(url)];
99
+ case 6:
100
+ blob = _e.sent();
101
+ downloadWithBlob(blob, fileName);
102
+ return [3 /*break*/, 8];
103
+ case 7:
104
+ _e.sent();
105
+ downloadWithLink(url, fileName);
106
+ return [3 /*break*/, 8];
107
+ case 8: return [2 /*return*/];
108
+ }
109
+ });
110
+ }); };
111
+
112
+ exports.downloadFile = downloadFile;
113
+ //# sourceMappingURL=modern-download.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"modern-download.js","sources":["../src/utils/modern-download.ts"],"sourcesContent":["const downloadWithBlob = (blob: Blob, fileName: string): void => {\n const url = URL.createObjectURL(blob);\n const link = document.createElement('a');\n\n link.href = url;\n link.download = fileName;\n document.body.appendChild(link);\n link.click();\n document.body.removeChild(link);\n setTimeout(() => URL.revokeObjectURL(url), 100);\n};\n\nconst downloadWithLink = (url: string, fileName: string): void => {\n const link = document.createElement('a');\n\n link.href = url;\n link.download = fileName;\n link.target = '_blank';\n link.rel = 'noopener noreferrer';\n document.body.appendChild(link);\n link.click();\n document.body.removeChild(link);\n};\n\nconst canUseBlobDownload = (): boolean =>\n typeof fetch === 'function' &&\n typeof URL.createObjectURL === 'function' &&\n typeof URL.revokeObjectURL === 'function';\n\nconst canUseFileShare = (): boolean =>\n typeof File === 'function' &&\n typeof navigator !== 'undefined' &&\n typeof navigator.share === 'function' &&\n typeof navigator.canShare === 'function';\n\nconst canShareFiles = (files: File[]): boolean =>\n canUseFileShare() && navigator.canShare({ files });\n\nconst getBlob = async (url: string): Promise<Blob> => {\n const response = await fetch(url);\n\n if (!response.ok) {\n throw new Error('Network error');\n }\n\n return response.blob();\n};\n\nconst isAbortError = (error: unknown): boolean =>\n typeof DOMException !== 'undefined' &&\n error instanceof DOMException &&\n error.name === 'AbortError';\n\nexport interface DownloadOptions {\n url: string;\n fileName?: string;\n fileType?: string;\n}\n\nexport const downloadFile = async ({\n url,\n fileName = 'download',\n fileType,\n}: DownloadOptions): Promise<void> => {\n if (!canUseBlobDownload()) {\n downloadWithLink(url, fileName);\n\n return;\n }\n\n if (canUseFileShare() && canShareFiles([new File([], fileName, { type: fileType })])) {\n try {\n const blob = await getBlob(url);\n\n const file = new File([blob], fileName, { type: blob.type || fileType });\n\n if (!canShareFiles([file])) {\n downloadWithBlob(blob, fileName);\n\n return;\n }\n\n await navigator.share({\n files: [file],\n title: `Скачать ${fileName}`,\n });\n\n return;\n } catch (error) {\n if (isAbortError(error)) {\n return;\n }\n\n downloadWithLink(url, fileName);\n\n return;\n }\n }\n\n try {\n const blob = await getBlob(url);\n\n downloadWithBlob(blob, fileName);\n } catch {\n downloadWithLink(url, fileName);\n }\n};\n"],"names":["__awaiter"],"mappings":"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"}