@therealtinhtute/baroiplayer 1.2.1 → 2.0.0-beta.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 (302) hide show
  1. package/README.md +90 -71
  2. package/dist/components/icons/index.d.ts +36 -0
  3. package/dist/components/icons/index.d.ts.map +1 -0
  4. package/dist/components/icons/svg-icons/ArrowLeftIcon.d.ts +4 -0
  5. package/dist/components/icons/svg-icons/ArrowLeftIcon.d.ts.map +1 -0
  6. package/dist/components/icons/svg-icons/ArrowRightIcon.d.ts +5 -0
  7. package/dist/components/icons/svg-icons/ArrowRightIcon.d.ts.map +1 -0
  8. package/dist/components/icons/svg-icons/AudioIcon.d.ts +5 -0
  9. package/dist/components/icons/svg-icons/AudioIcon.d.ts.map +1 -0
  10. package/dist/components/icons/svg-icons/BackwardIcon.d.ts +5 -0
  11. package/dist/components/icons/svg-icons/BackwardIcon.d.ts.map +1 -0
  12. package/dist/components/icons/svg-icons/CameraIcon.d.ts +5 -0
  13. package/dist/components/icons/svg-icons/CameraIcon.d.ts.map +1 -0
  14. package/dist/components/icons/svg-icons/CheckIcon.d.ts +5 -0
  15. package/dist/components/icons/svg-icons/CheckIcon.d.ts.map +1 -0
  16. package/dist/components/icons/svg-icons/EnablePiPIcon.d.ts +4 -0
  17. package/dist/components/icons/svg-icons/EnablePiPIcon.d.ts.map +1 -0
  18. package/dist/components/icons/svg-icons/ForwardIcon.d.ts +5 -0
  19. package/dist/components/icons/svg-icons/ForwardIcon.d.ts.map +1 -0
  20. package/dist/components/icons/svg-icons/FullscreenEnterIcon.d.ts +5 -0
  21. package/dist/components/icons/svg-icons/FullscreenEnterIcon.d.ts.map +1 -0
  22. package/dist/components/icons/svg-icons/FullscreenExitIcon.d.ts +5 -0
  23. package/dist/components/icons/svg-icons/FullscreenExitIcon.d.ts.map +1 -0
  24. package/dist/components/icons/svg-icons/LoadingIcon.d.ts +5 -0
  25. package/dist/components/icons/svg-icons/LoadingIcon.d.ts.map +1 -0
  26. package/dist/components/icons/svg-icons/PauseIcon.d.ts +5 -0
  27. package/dist/components/icons/svg-icons/PauseIcon.d.ts.map +1 -0
  28. package/dist/components/icons/svg-icons/PlayIcon.d.ts +5 -0
  29. package/dist/components/icons/svg-icons/PlayIcon.d.ts.map +1 -0
  30. package/dist/components/icons/svg-icons/PlaybackSpeedIcon.d.ts +5 -0
  31. package/dist/components/icons/svg-icons/PlaybackSpeedIcon.d.ts.map +1 -0
  32. package/dist/components/icons/svg-icons/QualityIcon.d.ts +5 -0
  33. package/dist/components/icons/svg-icons/QualityIcon.d.ts.map +1 -0
  34. package/dist/components/icons/svg-icons/SettingsIcon.d.ts +5 -0
  35. package/dist/components/icons/svg-icons/SettingsIcon.d.ts.map +1 -0
  36. package/dist/components/icons/svg-icons/SliderIcon.d.ts +5 -0
  37. package/dist/components/icons/svg-icons/SliderIcon.d.ts.map +1 -0
  38. package/dist/components/icons/svg-icons/SubtitleIcon.d.ts +5 -0
  39. package/dist/components/icons/svg-icons/SubtitleIcon.d.ts.map +1 -0
  40. package/dist/components/icons/svg-icons/SubtitleOffIcon.d.ts +5 -0
  41. package/dist/components/icons/svg-icons/SubtitleOffIcon.d.ts.map +1 -0
  42. package/dist/components/icons/svg-icons/UnPiPIcon.d.ts +4 -0
  43. package/dist/components/icons/svg-icons/UnPiPIcon.d.ts.map +1 -0
  44. package/dist/components/icons/svg-icons/VolumeMutedIcon.d.ts +5 -0
  45. package/dist/components/icons/svg-icons/VolumeMutedIcon.d.ts.map +1 -0
  46. package/dist/components/icons/svg-icons/VolumeOneIcon.d.ts +5 -0
  47. package/dist/components/icons/svg-icons/VolumeOneIcon.d.ts.map +1 -0
  48. package/dist/components/icons/svg-icons/VolumeThreeIcon.d.ts +5 -0
  49. package/dist/components/icons/svg-icons/VolumeThreeIcon.d.ts.map +1 -0
  50. package/dist/components/icons/svg-icons/VolumeTwoIcon.d.ts +5 -0
  51. package/dist/components/icons/svg-icons/VolumeTwoIcon.d.ts.map +1 -0
  52. package/dist/components/variants/gradient/gradient-audio.d.ts +13 -0
  53. package/dist/components/variants/gradient/gradient-audio.d.ts.map +1 -0
  54. package/dist/components/variants/gradient/gradient-controls.d.ts +4 -0
  55. package/dist/components/variants/gradient/gradient-controls.d.ts.map +1 -0
  56. package/dist/components/variants/gradient/gradient-glyphs.d.ts +30 -0
  57. package/dist/components/variants/gradient/gradient-glyphs.d.ts.map +1 -0
  58. package/dist/components/variants/gradient/gradient-video.d.ts +16 -0
  59. package/dist/components/variants/gradient/gradient-video.d.ts.map +1 -0
  60. package/dist/index.css +1 -1
  61. package/dist/index.d.ts +5 -0
  62. package/dist/index.d.ts.map +1 -0
  63. package/dist/index.js +1 -41
  64. package/dist/index.js.map +1 -1
  65. package/dist/index.mjs +750 -5640
  66. package/dist/index.mjs.map +1 -1
  67. package/dist/package.json +3 -0
  68. package/package.json +110 -114
  69. package/src/components/variants/gradient/gradient-audio.tsx +47 -0
  70. package/src/components/variants/gradient/gradient-controls.tsx +254 -0
  71. package/src/components/variants/gradient/gradient-glyphs.test.tsx +69 -0
  72. package/src/components/variants/gradient/gradient-glyphs.tsx +129 -0
  73. package/src/components/variants/gradient/gradient-skin.css +211 -0
  74. package/src/components/variants/gradient/gradient-video.tsx +70 -0
  75. package/src/index.ts +5 -198
  76. package/src/test/accessibility-utils.ts +0 -59
  77. package/dist/context/media.js +0 -1
  78. package/dist/context/media.mjs +0 -3
  79. package/dist/context/store.js +0 -1
  80. package/dist/context/store.mjs +0 -3
  81. package/dist/context-Bzd5QCKM.cjs +0 -7
  82. package/dist/context-Bzd5QCKM.cjs.map +0 -1
  83. package/dist/context-DD_SH4tT.js +0 -1053
  84. package/dist/context-DD_SH4tT.js.map +0 -1
  85. package/dist/core-events-BRnLMB7s.cjs +0 -2
  86. package/dist/core-events-BRnLMB7s.cjs.map +0 -1
  87. package/dist/core-events-v_mKdj5p.js +0 -417
  88. package/dist/core-events-v_mKdj5p.js.map +0 -1
  89. package/dist/core-plugins-CMBv-yVh.cjs +0 -2
  90. package/dist/core-plugins-CMBv-yVh.cjs.map +0 -1
  91. package/dist/core-plugins-CqCxLkbd.js +0 -754
  92. package/dist/core-plugins-CqCxLkbd.js.map +0 -1
  93. package/dist/core.js +0 -15
  94. package/dist/core.js.map +0 -1
  95. package/dist/core.mjs +0 -960
  96. package/dist/core.mjs.map +0 -1
  97. package/dist/enhanced-components-BwjBqSA1.js +0 -2858
  98. package/dist/enhanced-components-BwjBqSA1.js.map +0 -1
  99. package/dist/enhanced-components-C-ka-XLp.cjs +0 -2
  100. package/dist/enhanced-components-C-ka-XLp.cjs.map +0 -1
  101. package/dist/hooks-B-IIWPJr.js +0 -1842
  102. package/dist/hooks-B-IIWPJr.js.map +0 -1
  103. package/dist/hooks-DcHzmBwA.cjs +0 -4
  104. package/dist/hooks-DcHzmBwA.cjs.map +0 -1
  105. package/dist/minimal-components-BYsMQde5.js +0 -1610
  106. package/dist/minimal-components-BYsMQde5.js.map +0 -1
  107. package/dist/minimal-components-CsxQbDp7.cjs +0 -2
  108. package/dist/minimal-components-CsxQbDp7.cjs.map +0 -1
  109. package/dist/minimal-components.css +0 -1
  110. package/dist/mona-loading.gif +0 -0
  111. package/dist/performance-monitor-DCSijLJg.js +0 -312
  112. package/dist/performance-monitor-DCSijLJg.js.map +0 -1
  113. package/dist/performance-monitor-wNFKmqMr.cjs +0 -2
  114. package/dist/performance-monitor-wNFKmqMr.cjs.map +0 -1
  115. package/dist/rolldown-runtime-BmowowmI.js +0 -14
  116. package/dist/rolldown-runtime-mLOUI7ql.cjs +0 -1
  117. package/dist/utils-D2gQ7c2R.js +0 -64
  118. package/dist/utils-D2gQ7c2R.js.map +0 -1
  119. package/dist/utils-DJaAwiZ9.cjs +0 -2
  120. package/dist/utils-DJaAwiZ9.cjs.map +0 -1
  121. package/dist/utils.js +0 -1
  122. package/dist/utils.mjs +0 -3
  123. package/src/adapters/videojs-adapter.tsx +0 -470
  124. package/src/assets/mona-loading.gif +0 -0
  125. package/src/components/AnimateLoading.tsx +0 -111
  126. package/src/components/LoadingState.tsx +0 -239
  127. package/src/components/__tests__/media-player-accessibility.test.tsx +0 -510
  128. package/src/components/__tests__/media-player-react19.test.tsx +0 -457
  129. package/src/components/accessibility/keyboard-help-overlay.tsx +0 -207
  130. package/src/components/audio-player.tsx +0 -85
  131. package/src/components/basic/index.ts +0 -37
  132. package/src/components/enhanced/advanced-features.tsx +0 -311
  133. package/src/components/enhanced/debug-panel.tsx +0 -448
  134. package/src/components/enhanced/enhanced-controls.tsx +0 -597
  135. package/src/components/enhanced/enhanced-media-player.tsx +0 -566
  136. package/src/components/enhanced/error-handling.tsx +0 -338
  137. package/src/components/enhanced/index.ts +0 -39
  138. package/src/components/enhanced/media-player-enhanced.tsx +0 -383
  139. package/src/components/examples/basic-video-player.tsx +0 -50
  140. package/src/components/examples/custom-controls-example.tsx +0 -63
  141. package/src/components/examples/enhanced-controls-example.tsx +0 -100
  142. package/src/components/examples/enhanced-media-player-example.tsx +0 -302
  143. package/src/components/examples/loading-states-demo.tsx +0 -141
  144. package/src/components/examples/react-19-demo.tsx +0 -349
  145. package/src/components/examples/volume-orientation-demo.tsx +0 -105
  146. package/src/components/icon-demo.tsx +0 -196
  147. package/src/components/legacy.tsx +0 -87
  148. package/src/components/media-metadata-display.tsx +0 -99
  149. package/src/components/media-player-audio.tsx +0 -39
  150. package/src/components/media-player-controls.tsx +0 -223
  151. package/src/components/media-player-error.tsx +0 -163
  152. package/src/components/media-player-fullscreen.tsx +0 -109
  153. package/src/components/media-player-hls.tsx +0 -111
  154. package/src/components/media-player-loading.tsx +0 -76
  155. package/src/components/media-player-play.tsx +0 -75
  156. package/src/components/media-player-root.tsx +0 -338
  157. package/src/components/media-player-seek.tsx +0 -168
  158. package/src/components/media-player-time.tsx +0 -99
  159. package/src/components/media-player-tooltip.tsx +0 -58
  160. package/src/components/media-player-video.tsx +0 -54
  161. package/src/components/media-player-volume.tsx +0 -155
  162. package/src/components/media-player.tsx +0 -292
  163. package/src/components/media-suspense.tsx +0 -344
  164. package/src/components/player-settings-form.tsx +0 -158
  165. package/src/components/react-player-wrapper.tsx +0 -651
  166. package/src/components/simple-video-player.tsx +0 -62
  167. package/src/components/ui/blur-poster.tsx +0 -96
  168. package/src/components/ui/empty-state.tsx +0 -91
  169. package/src/components/ui/enhanced-seek-bar.tsx +0 -254
  170. package/src/components/ui/error-state.tsx +0 -124
  171. package/src/components/ui/fullscreen-button.tsx +0 -81
  172. package/src/components/ui/loading-skeleton.tsx +0 -107
  173. package/src/components/ui/media-resource-preloader.tsx +0 -458
  174. package/src/components/ui/offline-message.tsx +0 -98
  175. package/src/components/ui/play-button.tsx +0 -99
  176. package/src/components/ui/seek-bar.tsx +0 -191
  177. package/src/components/ui/time-display.tsx +0 -61
  178. package/src/components/ui/volume-control.tsx +0 -190
  179. package/src/components/unified/base-media-player.tsx +0 -252
  180. package/src/components/unified/media-player.tsx +0 -75
  181. package/src/components/variants/minimal/AccessibleMinimalPlayer.tsx +0 -587
  182. package/src/components/variants/minimal/EnhancedMinimalMediaPlayer.tsx +0 -573
  183. package/src/components/variants/minimal/MinimalControls.tsx +0 -124
  184. package/src/components/variants/minimal/MinimalLoading.tsx +0 -28
  185. package/src/components/variants/minimal/MinimalMediaPlayer.tsx +0 -318
  186. package/src/components/variants/minimal/MinimalOverlay.tsx +0 -58
  187. package/src/components/variants/minimal/MinimalPlayButton.tsx +0 -56
  188. package/src/components/variants/minimal/MinimalSeekBar.tsx +0 -140
  189. package/src/components/variants/minimal/MinimalVolumeControl.tsx +0 -75
  190. package/src/components/variants/minimal/SimpleMinimalPlayer.tsx +0 -206
  191. package/src/components/variants/minimal/components/CenterPlayButton.tsx +0 -22
  192. package/src/components/variants/minimal/components/ControlBar.tsx +0 -142
  193. package/src/components/variants/minimal/components/EnhancedSettingsMenu.tsx +0 -412
  194. package/src/components/variants/minimal/components/PlaybackControls.tsx +0 -46
  195. package/src/components/variants/minimal/components/RightControls.tsx +0 -164
  196. package/src/components/variants/minimal/components/SeekBar.tsx +0 -127
  197. package/src/components/variants/minimal/components/SettingsDropdown.tsx +0 -68
  198. package/src/components/variants/minimal/components/SubtitleDisplay.tsx +0 -21
  199. package/src/components/variants/minimal/components/TimeDisplay.tsx +0 -15
  200. package/src/components/variants/minimal/components/VideoElement.tsx +0 -35
  201. package/src/components/variants/minimal/components/VolumeControl.tsx +0 -220
  202. package/src/components/variants/minimal/index.ts +0 -23
  203. package/src/components/video-player.tsx +0 -100
  204. package/src/context/__tests__/media-store.test.ts +0 -509
  205. package/src/context/error-handling.ts +0 -398
  206. package/src/context/media-context.tsx +0 -254
  207. package/src/context/media-provider.tsx +0 -264
  208. package/src/context/media-store.ts +0 -387
  209. package/src/context/persistence.ts +0 -462
  210. package/src/core/events/event-system.ts +0 -448
  211. package/src/core/events/hooks.ts +0 -325
  212. package/src/core/events/index.ts +0 -22
  213. package/src/core/events/middleware.ts +0 -286
  214. package/src/core/index.ts +0 -22
  215. package/src/core/optimization/bundle-optimizer.tsx +0 -312
  216. package/src/core/performance/cicd.ts +0 -98
  217. package/src/core/performance/index.ts +0 -38
  218. package/src/core/performance/media-loading-optimizer.ts +0 -545
  219. package/src/core/performance/performance-budgets.ts +0 -437
  220. package/src/core/performance/performance-monitor.tsx +0 -488
  221. package/src/core/performance/performance-testing.ts +0 -461
  222. package/src/core/plugins/__tests__/registry.test.ts +0 -595
  223. package/src/core/plugins/base-plugin.ts +0 -225
  224. package/src/core/plugins/enhanced-plugin-system.ts +0 -435
  225. package/src/core/plugins/examples/analytics-plugin.ts +0 -241
  226. package/src/core/plugins/index.ts +0 -39
  227. package/src/core/plugins/registry.ts +0 -546
  228. package/src/core/plugins/types.ts +0 -169
  229. package/src/core/plugins/utils.ts +0 -317
  230. package/src/core/progressive-loading.tsx +0 -331
  231. package/src/core/providers/enhanced-hls-provider.ts +0 -307
  232. package/src/core/providers/lazy-provider.tsx +0 -14
  233. package/src/core/providers/service-provider.tsx +0 -164
  234. package/src/core/utils.tsx +0 -34
  235. package/src/features/media-session/media-session-manager.ts +0 -411
  236. package/src/features/picture-in-picture/pip-manager.ts +0 -428
  237. package/src/features/playlist/playlist-manager.ts +0 -626
  238. package/src/features/subtitles/subtitle-manager.ts +0 -435
  239. package/src/features/subtitles/subtitle-parser.ts +0 -284
  240. package/src/features/thumbnails/thumbnail-generator.ts +0 -528
  241. package/src/hooks/__tests__/currentTime-fix.test.ts +0 -149
  242. package/src/hooks/__tests__/use-media-player.test.ts +0 -712
  243. package/src/hooks/__tests__/use-media-state.test.tsx +0 -316
  244. package/src/hooks/accessibility/index.ts +0 -27
  245. package/src/hooks/accessibility/use-accessibility-preferences.ts +0 -190
  246. package/src/hooks/accessibility/use-focus-management.ts +0 -183
  247. package/src/hooks/accessibility/use-keyboard-shortcuts.ts +0 -152
  248. package/src/hooks/accessibility/use-screen-reader.ts +0 -212
  249. package/src/hooks/core/index.ts +0 -47
  250. package/src/hooks/legacy.ts +0 -21
  251. package/src/hooks/use-buffer-health.ts +0 -218
  252. package/src/hooks/use-enhanced-media-player.ts +0 -575
  253. package/src/hooks/use-focus-trap.tsx +0 -162
  254. package/src/hooks/use-intelligent-preloading.ts +0 -387
  255. package/src/hooks/use-keyboard-controls.ts +0 -115
  256. package/src/hooks/use-keyboard-shortcuts.ts +0 -255
  257. package/src/hooks/use-media-actions.ts +0 -184
  258. package/src/hooks/use-media-metadata.ts +0 -91
  259. package/src/hooks/use-media-optimistic.ts +0 -264
  260. package/src/hooks/use-media-player.ts +0 -343
  261. package/src/hooks/use-media-state.ts +0 -194
  262. package/src/hooks/use-memory-optimization.ts +0 -360
  263. package/src/hooks/use-network-status.ts +0 -124
  264. package/src/hooks/use-optimistic-controls.ts +0 -95
  265. package/src/hooks/use-optimized-media.ts +0 -283
  266. package/src/hooks/use-smart-preload.ts +0 -229
  267. package/src/hooks/use-touch-gestures.ts +0 -461
  268. package/src/hooks/useEnhancedSubtitles.ts +0 -258
  269. package/src/hooks/useKeyboardShortcuts.ts +0 -106
  270. package/src/hooks/useMediaControls.ts +0 -52
  271. package/src/hooks/useScreenshot.ts +0 -77
  272. package/src/hooks/useSubtitles.ts +0 -91
  273. package/src/hooks/useVideoPlayer.ts +0 -278
  274. package/src/icons/components/FullscreenIcon.tsx +0 -36
  275. package/src/icons/components/SettingsIcon.tsx +0 -37
  276. package/src/icons/components/animated/LoadingIcon.tsx +0 -27
  277. package/src/icons/components/animated/PlayPauseIcon.tsx +0 -42
  278. package/src/icons/components/media/PauseIcon.tsx +0 -38
  279. package/src/icons/components/media/PlayIcon.tsx +0 -37
  280. package/src/icons/components/volume/VolumeIcon.tsx +0 -38
  281. package/src/icons/components/volume/VolumeOffIcon.tsx +0 -38
  282. package/src/icons/index.ts +0 -56
  283. package/src/icons/provider.tsx +0 -58
  284. package/src/icons/types.ts +0 -60
  285. package/src/index-enhanced.ts +0 -35
  286. package/src/index-legacy.ts +0 -324
  287. package/src/index.css +0 -102
  288. package/src/lib/__tests__/async-utils.test.ts +0 -291
  289. package/src/lib/async-utils.ts +0 -194
  290. package/src/lib/deprecation.ts +0 -51
  291. package/src/lib/format-time.ts +0 -37
  292. package/src/lib/index.ts +0 -4
  293. package/src/lib/utils.ts +0 -6
  294. package/src/styles/globals.css +0 -462
  295. package/src/styles/minimal-player.css +0 -621
  296. package/src/styles/pixel-art.css +0 -41
  297. package/src/styles/videojs.css +0 -100
  298. package/src/types/assets.d.ts +0 -29
  299. package/src/types/events.ts +0 -47
  300. package/src/types/formats.ts +0 -79
  301. package/src/types/index.ts +0 -203
  302. package/src/types/videojs-plugins.d.ts +0 -14
@@ -1,461 +0,0 @@
1
- "use client"
2
-
3
- import { useDeviceInfo, useHapticFeedback } from "@rp/ui/hooks/use-mobile"
4
- import * as React from "react"
5
-
6
- // Gesture types
7
- export type GestureType =
8
- | "tap"
9
- | "double-tap"
10
- | "long-press"
11
- | "swipe-left"
12
- | "swipe-right"
13
- | "swipe-up"
14
- | "swipe-down"
15
- | "pinch-in"
16
- | "pinch-out"
17
-
18
- // Gesture event data
19
- export interface GestureEvent {
20
- type: GestureType
21
- startPoint: { x: number; y: number }
22
- currentPoint: { x: number; y: number }
23
- velocity?: { x: number; y: number }
24
- scale?: number
25
- rotation?: number
26
- distance?: number
27
- duration: number
28
- preventDefault: () => void
29
- target: HTMLElement
30
- }
31
-
32
- // Gesture configuration
33
- export interface GestureConfig {
34
- enabledGestures?: GestureType[]
35
- tapThreshold?: number // ms
36
- doubleTapThreshold?: number // ms
37
- longPressThreshold?: number // ms
38
- swipeThreshold?: number // px
39
- swipeVelocityThreshold?: number // px/ms
40
- pinchThreshold?: number // scale difference
41
- rotationThreshold?: number // degrees
42
- enableHapticFeedback?: boolean
43
- }
44
-
45
- // Default configuration
46
- const defaultConfig: Required<GestureConfig> = {
47
- enabledGestures: [
48
- "tap",
49
- "double-tap",
50
- "long-press",
51
- "swipe-left",
52
- "swipe-right",
53
- "swipe-up",
54
- "swipe-down",
55
- "pinch-in",
56
- "pinch-out"
57
- ],
58
- tapThreshold: 200,
59
- doubleTapThreshold: 300,
60
- longPressThreshold: 500,
61
- swipeThreshold: 50,
62
- swipeVelocityThreshold: 0.5,
63
- pinchThreshold: 0.1,
64
- rotationThreshold: 15,
65
- enableHapticFeedback: true
66
- }
67
-
68
- // Touch point interface
69
- interface TouchPoint {
70
- id: number
71
- x: number
72
- y: number
73
- timestamp: number
74
- }
75
-
76
- // Gesture state
77
- interface GestureState {
78
- isTracking: boolean
79
- touches: TouchPoint[]
80
- startTouches: TouchPoint[]
81
- lastTap?: { timestamp: number; point: { x: number; y: number } }
82
- longPressTimer?: NodeJS.Timeout
83
- initialDistance?: number
84
- initialScale?: number
85
- lastScale?: number
86
- }
87
-
88
- // Touch gesture hook
89
- export function useTouchGestures(
90
- ref: React.RefObject<HTMLElement>,
91
- onGesture: (event: GestureEvent) => void,
92
- config: GestureConfig = {}
93
- ) {
94
- const mergedConfig = { ...defaultConfig, ...config }
95
- const { isTouchDevice } = useDeviceInfo()
96
- const { triggerHaptic } = useHapticFeedback()
97
- const gestureState = React.useRef<GestureState>({
98
- isTracking: false,
99
- touches: [],
100
- startTouches: []
101
- })
102
-
103
- // Helper functions
104
- const getTouchPoint = (touch: Touch): TouchPoint => ({
105
- id: touch.identifier,
106
- x: touch.clientX,
107
- y: touch.clientY,
108
- timestamp: Date.now()
109
- })
110
-
111
- const getDistance = (p1: TouchPoint, p2: TouchPoint): number =>
112
- Math.sqrt(Math.pow(p2.x - p1.x, 2) + Math.pow(p2.y - p1.y, 2))
113
-
114
- const getVelocity = (start: TouchPoint, end: TouchPoint): { x: number; y: number } => {
115
- const timeDiff = Math.max(end.timestamp - start.timestamp, 1)
116
- return {
117
- x: (end.x - start.x) / timeDiff,
118
- y: (end.y - start.y) / timeDiff
119
- }
120
- }
121
-
122
- const createGestureEvent = (
123
- type: GestureType,
124
- startPoint: TouchPoint,
125
- currentPoint: TouchPoint,
126
- additionalData: Partial<GestureEvent> = {}
127
- ): GestureEvent => ({
128
- type,
129
- startPoint: { x: startPoint.x, y: startPoint.y },
130
- currentPoint: { x: currentPoint.x, y: currentPoint.y },
131
- duration: currentPoint.timestamp - startPoint.timestamp,
132
- target: ref.current!,
133
- preventDefault: () => {},
134
- ...additionalData
135
- })
136
-
137
- // Handle touch start
138
- const handleTouchStart = React.useCallback(
139
- (e: TouchEvent) => {
140
- if (!mergedConfig.enabledGestures.length) return
141
-
142
- const touches = Array.from(e.touches).map(getTouchPoint)
143
- const state = gestureState.current
144
-
145
- state.isTracking = true
146
- state.touches = touches
147
- state.startTouches = [...touches]
148
-
149
- // Clear any existing long press timer
150
- if (state.longPressTimer) {
151
- clearTimeout(state.longPressTimer)
152
- }
153
-
154
- // Set up long press detection for single touch
155
- if (touches.length === 1 && mergedConfig.enabledGestures.includes("long-press")) {
156
- state.longPressTimer = setTimeout(() => {
157
- if (state.touches.length === 1 && touches[0]) {
158
- const gestureEvent = createGestureEvent("long-press", touches[0], touches[0])
159
- onGesture(gestureEvent)
160
-
161
- if (mergedConfig.enableHapticFeedback) {
162
- triggerHaptic("heavy")
163
- }
164
- }
165
- }, mergedConfig.longPressThreshold)
166
- }
167
-
168
- // Handle multi-touch gestures
169
- if (touches.length === 2 && touches[0] && touches[1]) {
170
- state.initialDistance = getDistance(touches[0], touches[1])
171
- state.initialScale = 1
172
- state.lastScale = 1
173
- }
174
- },
175
- [mergedConfig, onGesture, triggerHaptic]
176
- )
177
-
178
- // Handle touch move
179
- const handleTouchMove = React.useCallback(
180
- (e: TouchEvent) => {
181
- const state = gestureState.current
182
- if (!state.isTracking) return
183
-
184
- const touches = Array.from(e.touches).map(getTouchPoint)
185
- state.touches = touches
186
-
187
- // Handle pinch gesture
188
- if (touches.length === 2 && state.initialDistance && touches[0] && touches[1]) {
189
- const currentDistance = getDistance(touches[0], touches[1])
190
- const scale = currentDistance / state.initialDistance
191
- const scaleDiff = Math.abs(scale - (state.lastScale || 1))
192
-
193
- if (scaleDiff > mergedConfig.pinchThreshold) {
194
- const gestureType = scale > (state.lastScale || 1) ? "pinch-out" : "pinch-in"
195
-
196
- if (mergedConfig.enabledGestures.includes(gestureType)) {
197
- const centerPoint = {
198
- x: (touches[0].x + touches[1].x) / 2,
199
- y: (touches[0].y + touches[1].y) / 2,
200
- id: -1,
201
- timestamp: Date.now()
202
- }
203
-
204
- const startCenterPoint = {
205
- x: ((state.startTouches[0]?.x ?? 0) + (state.startTouches[1]?.x ?? 0)) / 2,
206
- y: ((state.startTouches[0]?.y ?? 0) + (state.startTouches[1]?.y ?? 0)) / 2,
207
- id: -1,
208
- timestamp: state.startTouches[0]?.timestamp ?? Date.now()
209
- }
210
-
211
- const gestureEvent = createGestureEvent(gestureType, startCenterPoint, centerPoint, {
212
- scale,
213
- distance: currentDistance
214
- })
215
-
216
- onGesture(gestureEvent)
217
- state.lastScale = scale
218
- }
219
- }
220
- }
221
-
222
- // Clear long press timer on move
223
- if (state.longPressTimer && touches.length === 1 && state.startTouches[0] && touches[0]) {
224
- const startTouch = state.startTouches[0]
225
- const currentTouch = touches[0]
226
- const distance = getDistance(startTouch, currentTouch)
227
-
228
- if (distance > mergedConfig.swipeThreshold) {
229
- clearTimeout(state.longPressTimer)
230
- state.longPressTimer = undefined
231
- }
232
- }
233
- },
234
- [mergedConfig, onGesture]
235
- )
236
-
237
- // Handle touch end
238
- const handleTouchEnd = React.useCallback(
239
- (e: TouchEvent) => {
240
- const state = gestureState.current
241
- if (!state.isTracking) return
242
-
243
- const endTouches = Array.from(e.changedTouches).map(getTouchPoint)
244
- const currentTime = Date.now()
245
-
246
- // Clear long press timer
247
- if (state.longPressTimer) {
248
- clearTimeout(state.longPressTimer)
249
- state.longPressTimer = undefined
250
- }
251
-
252
- // Handle single touch gestures
253
- if (
254
- state.startTouches.length === 1 &&
255
- endTouches.length === 1 &&
256
- state.startTouches[0] &&
257
- endTouches[0]
258
- ) {
259
- const startTouch = state.startTouches[0]
260
- const endTouch = endTouches[0]
261
- const distance = getDistance(startTouch, endTouch)
262
- const duration = endTouch.timestamp - startTouch.timestamp
263
-
264
- // Check for swipe gestures
265
- if (distance > mergedConfig.swipeThreshold) {
266
- const velocity = getVelocity(startTouch, endTouch)
267
- const absVelX = Math.abs(velocity.x)
268
- const absVelY = Math.abs(velocity.y)
269
-
270
- if (
271
- absVelX > mergedConfig.swipeVelocityThreshold ||
272
- absVelY > mergedConfig.swipeVelocityThreshold
273
- ) {
274
- let gestureType: GestureType
275
-
276
- if (absVelX > absVelY) {
277
- gestureType = velocity.x > 0 ? "swipe-right" : "swipe-left"
278
- } else {
279
- gestureType = velocity.y > 0 ? "swipe-down" : "swipe-up"
280
- }
281
-
282
- if (mergedConfig.enabledGestures.includes(gestureType)) {
283
- const gestureEvent = createGestureEvent(gestureType, startTouch, endTouch, {
284
- velocity,
285
- distance
286
- })
287
-
288
- onGesture(gestureEvent)
289
-
290
- if (mergedConfig.enableHapticFeedback) {
291
- triggerHaptic("light")
292
- }
293
- }
294
- }
295
- }
296
- // Check for tap gestures
297
- else if (duration < mergedConfig.tapThreshold && distance < mergedConfig.swipeThreshold) {
298
- // Check for double tap
299
- if (
300
- state.lastTap &&
301
- currentTime - state.lastTap.timestamp < mergedConfig.doubleTapThreshold &&
302
- getDistance(
303
- { ...state.lastTap.point, id: -1, timestamp: state.lastTap.timestamp },
304
- endTouch
305
- ) < mergedConfig.swipeThreshold
306
- ) {
307
- if (mergedConfig.enabledGestures.includes("double-tap")) {
308
- const gestureEvent = createGestureEvent("double-tap", startTouch, endTouch)
309
- onGesture(gestureEvent)
310
-
311
- if (mergedConfig.enableHapticFeedback) {
312
- triggerHaptic("medium")
313
- }
314
- }
315
-
316
- state.lastTap = undefined
317
- } else {
318
- // Single tap
319
- if (mergedConfig.enabledGestures.includes("tap")) {
320
- const gestureEvent = createGestureEvent("tap", startTouch, endTouch)
321
- onGesture(gestureEvent)
322
-
323
- if (mergedConfig.enableHapticFeedback) {
324
- triggerHaptic("light")
325
- }
326
- }
327
-
328
- state.lastTap = {
329
- timestamp: currentTime,
330
- point: { x: endTouch.x, y: endTouch.y }
331
- }
332
- }
333
- }
334
- }
335
-
336
- // Reset gesture state
337
- if (e.touches.length === 0) {
338
- state.isTracking = false
339
- state.touches = []
340
- state.startTouches = []
341
- state.initialDistance = undefined
342
- state.initialScale = undefined
343
- state.lastScale = undefined
344
- }
345
- },
346
- [mergedConfig, onGesture, triggerHaptic]
347
- )
348
-
349
- // Attach event listeners
350
- React.useEffect(() => {
351
- const element = ref.current
352
- if (!element || !isTouchDevice) return
353
-
354
- element.addEventListener("touchstart", handleTouchStart, { passive: false })
355
- element.addEventListener("touchmove", handleTouchMove, { passive: false })
356
- element.addEventListener("touchend", handleTouchEnd, { passive: false })
357
- element.addEventListener("touchcancel", handleTouchEnd, { passive: false })
358
-
359
- return () => {
360
- element.removeEventListener("touchstart", handleTouchStart)
361
- element.removeEventListener("touchmove", handleTouchMove)
362
- element.removeEventListener("touchend", handleTouchEnd)
363
- element.removeEventListener("touchcancel", handleTouchEnd)
364
- }
365
- }, [handleTouchStart, handleTouchMove, handleTouchEnd, isTouchDevice])
366
-
367
- return {
368
- isGestureEnabled: isTouchDevice && mergedConfig.enabledGestures.length > 0
369
- }
370
- }
371
-
372
- // Media player specific gesture hook with predefined actions
373
- export function useMediaGestures(
374
- ref: React.RefObject<HTMLElement>,
375
- actions: {
376
- onPlayPause?: () => void
377
- onSeek?: (direction: "forward" | "backward", amount: number) => void
378
- onVolumeChange?: (direction: "up" | "down", amount: number) => void
379
- onToggleFullscreen?: () => void
380
- onZoom?: (scale: number) => void
381
- }
382
- ) {
383
- const handleGesture = React.useCallback(
384
- (event: GestureEvent) => {
385
- const { type, velocity, distance, scale } = event
386
-
387
- switch (type) {
388
- case "double-tap":
389
- // Double tap to play/pause
390
- actions.onPlayPause?.()
391
- break
392
-
393
- case "swipe-left":
394
- // Swipe left to seek backward
395
- const backwardAmount = Math.min((distance || 0) / 10, 30) // Max 30 seconds
396
- actions.onSeek?.("backward", backwardAmount)
397
- break
398
-
399
- case "swipe-right":
400
- // Swipe right to seek forward
401
- const forwardAmount = Math.min((distance || 0) / 10, 30) // Max 30 seconds
402
- actions.onSeek?.("forward", forwardAmount)
403
- break
404
-
405
- case "swipe-up":
406
- // Swipe up on right side for volume up
407
- if (event.startPoint.x > (ref.current?.clientWidth || 0) / 2) {
408
- const volumeAmount = Math.min((distance || 0) / 100, 0.2) // Max 20%
409
- actions.onVolumeChange?.("up", volumeAmount)
410
- }
411
- break
412
-
413
- case "swipe-down":
414
- // Swipe down on right side for volume down
415
- if (event.startPoint.x > (ref.current?.clientWidth || 0) / 2) {
416
- const volumeAmount = Math.min((distance || 0) / 100, 0.2) // Max 20%
417
- actions.onVolumeChange?.("down", volumeAmount)
418
- }
419
- break
420
-
421
- case "pinch-out":
422
- // Pinch out to zoom in (for video zoom functionality)
423
- actions.onZoom?.(scale || 1)
424
- break
425
-
426
- case "pinch-in":
427
- // Pinch in to zoom out
428
- actions.onZoom?.(scale || 1)
429
- break
430
-
431
- case "long-press":
432
- // Long press for fullscreen toggle
433
- actions.onToggleFullscreen?.()
434
- break
435
-
436
- default:
437
- break
438
- }
439
- },
440
- [actions, ref]
441
- )
442
-
443
- const gestureConfig: GestureConfig = {
444
- enabledGestures: [
445
- "tap",
446
- "double-tap",
447
- "long-press",
448
- "swipe-left",
449
- "swipe-right",
450
- "swipe-up",
451
- "swipe-down",
452
- "pinch-in",
453
- "pinch-out"
454
- ],
455
- enableHapticFeedback: true,
456
- swipeThreshold: 30,
457
- swipeVelocityThreshold: 0.3
458
- }
459
-
460
- return useTouchGestures(ref, handleGesture, gestureConfig)
461
- }
@@ -1,258 +0,0 @@
1
- import { useCallback, useEffect, useMemo, useState } from "react"
2
-
3
- interface SubtitleCue {
4
- start: number
5
- end: number
6
- text: string
7
- }
8
-
9
- export interface SubtitleTrack {
10
- id: string
11
- label: string
12
- language?: string
13
- src?: string
14
- }
15
-
16
- export interface UseEnhancedSubtitlesOptions {
17
- subtitleSrc?: string
18
- subtitleTracks?: SubtitleTrack[]
19
- defaultFontSize?: "small" | "medium" | "large"
20
- onLoadError?: (error: Error) => void
21
- }
22
-
23
- export function useEnhancedSubtitles({
24
- subtitleSrc,
25
- subtitleTracks = [],
26
- defaultFontSize = "medium",
27
- onLoadError
28
- }: UseEnhancedSubtitlesOptions = {}) {
29
- const [subtitlesEnabled, setSubtitlesEnabled] = useState(false)
30
- const [subtitleCues, setSubtitleCues] = useState<SubtitleCue[]>([])
31
- const [currentSubtitle, setCurrentSubtitle] = useState("")
32
- const [currentTrackId, setCurrentTrackId] = useState<string | null>(null)
33
- const [fontSize, setFontSize] = useState<"small" | "medium" | "large">(defaultFontSize)
34
- const [loadError, setLoadError] = useState<Error | null>(null)
35
- const [isLoading, setIsLoading] = useState(false)
36
-
37
- // Size mapping for subtitle font sizes
38
- const sizeMap = {
39
- small: "text-sm",
40
- medium: "text-base",
41
- large: "text-lg"
42
- }
43
-
44
- // Determine if subtitles are available
45
- const hasSubtitles = !!(subtitleSrc || (subtitleTracks && subtitleTracks.length > 0))
46
-
47
- // Parse VTT/WebVTT timestamp
48
- const parseVTTTime = (timeStr: string): number => {
49
- const parts = timeStr.split(":")
50
- const seconds = parts[2] ? parseFloat(parts[2]) : 0
51
- const minutes = parts[1] ? parseInt(parts[1], 10) * 60 : 0
52
- const hours = parts[0] ? parseInt(parts[0], 10) * 3600 : 0
53
- return hours + minutes + seconds
54
- }
55
-
56
- // Parse SRT timestamp
57
- const parseSRTTime = (timeStr: string): number => {
58
- // SRT format: 00:00:00,000 (hours:minutes:seconds,milliseconds)
59
- const [time, ms] = timeStr.split(",")
60
- const parts = (time || "").split(":")
61
- const milliseconds = ms ? parseInt(ms, 10) / 1000 : 0
62
- const seconds = parts[2] ? parseInt(parts[2], 10) : 0
63
- const minutes = parts[1] ? parseInt(parts[1], 10) * 60 : 0
64
- const hours = parts[0] ? parseInt(parts[0], 10) * 3600 : 0
65
- return hours + minutes + seconds + milliseconds
66
- }
67
-
68
- // Load and parse subtitle file
69
- const loadSubtitles = async (url: string) => {
70
- setIsLoading(true)
71
- setLoadError(null)
72
-
73
- try {
74
- const response = await fetch(url)
75
- if (!response.ok) {
76
- throw new Error(`Failed to load subtitles: ${response.status} ${response.statusText}`)
77
- }
78
-
79
- const text = await response.text()
80
- const cues: SubtitleCue[] = []
81
- const lines = text.split("\n")
82
- let i = 0
83
-
84
- // Detect format (VTT or SRT)
85
- const isVTT = text.includes("WEBVTT") || url.endsWith(".vtt")
86
- const isSRT = url.endsWith(".srt") || /^\d+$/.test(lines[0]?.trim() || "")
87
-
88
- if (isVTT) {
89
- // Parse VTT format
90
- while (i < lines.length) {
91
- if (lines[i]?.includes("-->")) {
92
- const [startStr, endStr] = (lines[i] || "").split("-->").map((s) => s.trim())
93
- const start = parseVTTTime(startStr || "")
94
- const end = parseVTTTime(endStr || "")
95
-
96
- i++
97
- let subtitleText = ""
98
- while (i < lines.length && lines[i]?.trim() !== "") {
99
- subtitleText += (subtitleText ? " " : "") + lines[i]?.trim()
100
- i++
101
- }
102
-
103
- if (subtitleText) {
104
- cues.push({ start, end, text: subtitleText })
105
- }
106
- }
107
- i++
108
- }
109
- } else if (isSRT) {
110
- // Parse SRT format
111
- while (i < lines.length) {
112
- // Skip the sequence number
113
- if (/^\d+$/.test(lines[i]?.trim() || "")) {
114
- i++
115
- // Parse timestamp line
116
- if (lines[i]?.includes("-->")) {
117
- const [startStr, endStr] = (lines[i] || "").split("-->").map((s) => s.trim())
118
- const start = parseSRTTime(startStr || "")
119
- const end = parseSRTTime(endStr || "")
120
-
121
- i++
122
- let subtitleText = ""
123
- while (i < lines.length && lines[i]?.trim() !== "") {
124
- subtitleText += (subtitleText ? " " : "") + lines[i]?.trim()
125
- i++
126
- }
127
-
128
- if (subtitleText) {
129
- cues.push({ start, end, text: subtitleText })
130
- }
131
- }
132
- }
133
- i++
134
- }
135
- } else {
136
- throw new Error("Unsupported subtitle format. Only VTT and SRT are supported.")
137
- }
138
-
139
- if (cues.length === 0) {
140
- throw new Error("No subtitle cues found in file")
141
- }
142
-
143
- setSubtitleCues(cues)
144
- setIsLoading(false)
145
- } catch (error) {
146
- const err = error instanceof Error ? error : new Error("Failed to load subtitles")
147
- console.error("Failed to load subtitles:", err)
148
- setLoadError(err)
149
- setIsLoading(false)
150
- setSubtitleCues([])
151
- onLoadError?.(err)
152
- }
153
- }
154
-
155
- // Get current subtitle text based on time
156
- const getCurrentSubtitle = (currentTime: number) => {
157
- if (!subtitlesEnabled || subtitleCues.length === 0) return ""
158
-
159
- const currentCue = subtitleCues.find(
160
- (cue) => currentTime >= cue.start && currentTime <= cue.end
161
- )
162
- return currentCue?.text || ""
163
- }
164
-
165
- // Toggle subtitles on/off
166
- const toggleSubtitles = () => {
167
- setSubtitlesEnabled((prev) => {
168
- const newEnabled = !prev
169
-
170
- if (newEnabled && !loadError) {
171
- // Try to load subtitles if not already loaded
172
- if (subtitleCues.length === 0 && !isLoading) {
173
- // Load default subtitle source or first track
174
- const srcToLoad = subtitleSrc || subtitleTracks[0]?.src
175
- if (srcToLoad) {
176
- loadSubtitles(srcToLoad)
177
- if (subtitleTracks[0]) {
178
- setCurrentTrackId(subtitleTracks[0].id)
179
- }
180
- }
181
- }
182
- } else if (!newEnabled) {
183
- setCurrentSubtitle("")
184
- }
185
-
186
- return newEnabled
187
- })
188
- }
189
-
190
- // Select a specific subtitle track
191
- const selectSubtitleTrack = (trackId: string | null) => {
192
- if (!trackId) {
193
- // Turn off subtitles
194
- setSubtitlesEnabled(false)
195
- setCurrentTrackId(null)
196
- setCurrentSubtitle("")
197
- return
198
- }
199
-
200
- const track = subtitleTracks.find((t) => t.id === trackId)
201
- if (track?.src) {
202
- setCurrentTrackId(trackId)
203
- loadSubtitles(track.src)
204
- setSubtitlesEnabled(true)
205
- }
206
- }
207
-
208
- // Change subtitle font size
209
- const changeSubtitleFontSize = (size: "small" | "medium" | "large") => {
210
- setFontSize(size)
211
- }
212
-
213
- // Get CSS classes for subtitle display
214
- const getSubtitleStyles = {
215
- fontSize: sizeMap[fontSize],
216
- className: `${sizeMap[fontSize]} font-medium`
217
- }
218
-
219
- // Clear subtitle on disable
220
- useEffect(() => {
221
- if (!subtitlesEnabled) {
222
- setCurrentSubtitle("")
223
- }
224
- }, [subtitlesEnabled])
225
-
226
- // Auto-load default subtitles on mount if available
227
- useEffect(() => {
228
- if (subtitleSrc && !subtitleCues.length && !loadError && !isLoading) {
229
- // Don't auto-load, wait for user to enable
230
- // This prevents errors on initial load
231
- }
232
- }, [])
233
-
234
- return {
235
- // State
236
- subtitlesEnabled,
237
- currentSubtitle,
238
- subtitleCues,
239
- currentTrackId,
240
- fontSize,
241
- loadError,
242
- isLoading,
243
- hasSubtitles,
244
-
245
- // Actions
246
- toggleSubtitles,
247
- selectSubtitleTrack,
248
- changeSubtitleFontSize,
249
- setCurrentSubtitle,
250
-
251
- // Utilities
252
- getCurrentSubtitle,
253
- getSubtitleStyles,
254
-
255
- // Track info
256
- availableTracks: subtitleTracks
257
- }
258
- }