@therealtinhtute/baroiplayer 1.0.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 (244) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +384 -0
  3. package/dist/context/media.js +2 -0
  4. package/dist/context/media.js.map +1 -0
  5. package/dist/context/media.mjs +15 -0
  6. package/dist/context/media.mjs.map +1 -0
  7. package/dist/context/store.js +2 -0
  8. package/dist/context/store.js.map +1 -0
  9. package/dist/context/store.mjs +5 -0
  10. package/dist/context/store.mjs.map +1 -0
  11. package/dist/context-BMteAJDN.js +1140 -0
  12. package/dist/context-BMteAJDN.js.map +1 -0
  13. package/dist/context-DCJ_scmO.cjs +23 -0
  14. package/dist/context-DCJ_scmO.cjs.map +1 -0
  15. package/dist/core-events-B5W_j8yU.js +480 -0
  16. package/dist/core-events-B5W_j8yU.js.map +1 -0
  17. package/dist/core-events-CN0-Vhhq.cjs +2 -0
  18. package/dist/core-events-CN0-Vhhq.cjs.map +1 -0
  19. package/dist/core-plugins-Bq9KLany.js +696 -0
  20. package/dist/core-plugins-Bq9KLany.js.map +1 -0
  21. package/dist/core-plugins-CPDSHMiQ.cjs +2 -0
  22. package/dist/core-plugins-CPDSHMiQ.cjs.map +1 -0
  23. package/dist/core.js +37 -0
  24. package/dist/core.js.map +1 -0
  25. package/dist/core.mjs +1217 -0
  26. package/dist/core.mjs.map +1 -0
  27. package/dist/enhanced-components-DHv0MFvG.js +1073 -0
  28. package/dist/enhanced-components-DHv0MFvG.js.map +1 -0
  29. package/dist/enhanced-components-DTIObgB7.cjs +2 -0
  30. package/dist/enhanced-components-DTIObgB7.cjs.map +1 -0
  31. package/dist/hooks-C_r8wexn.cjs +4 -0
  32. package/dist/hooks-C_r8wexn.cjs.map +1 -0
  33. package/dist/hooks-Da2wVXlF.js +1630 -0
  34. package/dist/hooks-Da2wVXlF.js.map +1 -0
  35. package/dist/index.css +1 -0
  36. package/dist/index.js +112 -0
  37. package/dist/index.js.map +1 -0
  38. package/dist/index.mjs +6126 -0
  39. package/dist/index.mjs.map +1 -0
  40. package/dist/minimal-components-DSq5sQpy.js +2002 -0
  41. package/dist/minimal-components-DSq5sQpy.js.map +1 -0
  42. package/dist/minimal-components-DflWiihN.cjs +2 -0
  43. package/dist/minimal-components-DflWiihN.cjs.map +1 -0
  44. package/dist/minimal-components.css +1 -0
  45. package/dist/mona-loading.gif +0 -0
  46. package/dist/performance-monitor-CUW6f5ll.cjs +2 -0
  47. package/dist/performance-monitor-CUW6f5ll.cjs.map +1 -0
  48. package/dist/performance-monitor-rMW1RgV3.js +302 -0
  49. package/dist/performance-monitor-rMW1RgV3.js.map +1 -0
  50. package/dist/utils-BnscpYYd.js +2798 -0
  51. package/dist/utils-BnscpYYd.js.map +1 -0
  52. package/dist/utils-D_czS_0K.cjs +9 -0
  53. package/dist/utils-D_czS_0K.cjs.map +1 -0
  54. package/dist/utils.js +2 -0
  55. package/dist/utils.js.map +1 -0
  56. package/dist/utils.mjs +7 -0
  57. package/dist/utils.mjs.map +1 -0
  58. package/package.json +114 -0
  59. package/src/adapters/videojs-adapter.tsx +470 -0
  60. package/src/assets/mona-loading.gif +0 -0
  61. package/src/components/AnimateLoading.tsx +115 -0
  62. package/src/components/LoadingState.tsx +248 -0
  63. package/src/components/accessibility/keyboard-help-overlay.tsx +213 -0
  64. package/src/components/audio-player.tsx +85 -0
  65. package/src/components/basic/index.ts +37 -0
  66. package/src/components/enhanced/advanced-features.tsx +316 -0
  67. package/src/components/enhanced/debug-panel.tsx +422 -0
  68. package/src/components/enhanced/enhanced-controls.tsx +600 -0
  69. package/src/components/enhanced/enhanced-media-player.tsx +509 -0
  70. package/src/components/enhanced/error-handling.tsx +345 -0
  71. package/src/components/enhanced/index.ts +39 -0
  72. package/src/components/enhanced/media-player-enhanced.tsx +349 -0
  73. package/src/components/examples/basic-video-player.tsx +55 -0
  74. package/src/components/examples/custom-controls-example.tsx +63 -0
  75. package/src/components/examples/enhanced-controls-example.tsx +114 -0
  76. package/src/components/examples/enhanced-media-player-example.tsx +293 -0
  77. package/src/components/examples/loading-states-demo.tsx +142 -0
  78. package/src/components/examples/react-19-demo.tsx +381 -0
  79. package/src/components/examples/volume-orientation-demo.tsx +114 -0
  80. package/src/components/icon-demo.tsx +209 -0
  81. package/src/components/icons/index.tsx +166 -0
  82. package/src/components/icons/svg-icons/ArrowLeftIcon.tsx +18 -0
  83. package/src/components/icons/svg-icons/ArrowRightIcon.tsx +18 -0
  84. package/src/components/icons/svg-icons/AudioIcon.tsx +22 -0
  85. package/src/components/icons/svg-icons/BackwardIcon.tsx +12 -0
  86. package/src/components/icons/svg-icons/CameraIcon.tsx +19 -0
  87. package/src/components/icons/svg-icons/CheckIcon.tsx +19 -0
  88. package/src/components/icons/svg-icons/EnablePiPIcon.tsx +17 -0
  89. package/src/components/icons/svg-icons/ForwardIcon.tsx +12 -0
  90. package/src/components/icons/svg-icons/FullscreenEnterIcon.tsx +23 -0
  91. package/src/components/icons/svg-icons/FullscreenExitIcon.tsx +23 -0
  92. package/src/components/icons/svg-icons/LoadingIcon.tsx +32 -0
  93. package/src/components/icons/svg-icons/PauseIcon.tsx +23 -0
  94. package/src/components/icons/svg-icons/PlayIcon.tsx +21 -0
  95. package/src/components/icons/svg-icons/PlaybackSpeedIcon.tsx +23 -0
  96. package/src/components/icons/svg-icons/QualityIcon.tsx +21 -0
  97. package/src/components/icons/svg-icons/SettingsIcon.tsx +12 -0
  98. package/src/components/icons/svg-icons/SliderIcon.tsx +21 -0
  99. package/src/components/icons/svg-icons/SubtitleIcon.tsx +21 -0
  100. package/src/components/icons/svg-icons/SubtitleOffIcon.tsx +25 -0
  101. package/src/components/icons/svg-icons/UnPiPIcon.tsx +17 -0
  102. package/src/components/icons/svg-icons/VolumeMutedIcon.tsx +16 -0
  103. package/src/components/icons/svg-icons/VolumeOneIcon.tsx +22 -0
  104. package/src/components/icons/svg-icons/VolumeThreeIcon.tsx +16 -0
  105. package/src/components/icons/svg-icons/VolumeTwoIcon.tsx +16 -0
  106. package/src/components/legacy.tsx +93 -0
  107. package/src/components/media-metadata-display.tsx +100 -0
  108. package/src/components/media-player-audio.tsx +39 -0
  109. package/src/components/media-player-controls.tsx +226 -0
  110. package/src/components/media-player-error.tsx +163 -0
  111. package/src/components/media-player-fullscreen.tsx +109 -0
  112. package/src/components/media-player-hls.tsx +111 -0
  113. package/src/components/media-player-loading.tsx +76 -0
  114. package/src/components/media-player-play.tsx +75 -0
  115. package/src/components/media-player-root.tsx +340 -0
  116. package/src/components/media-player-seek.tsx +168 -0
  117. package/src/components/media-player-time.tsx +99 -0
  118. package/src/components/media-player-tooltip.tsx +58 -0
  119. package/src/components/media-player-video.tsx +39 -0
  120. package/src/components/media-player-volume.tsx +155 -0
  121. package/src/components/media-player.tsx +257 -0
  122. package/src/components/media-suspense.tsx +362 -0
  123. package/src/components/player-settings-form.tsx +163 -0
  124. package/src/components/react-player-wrapper.tsx +651 -0
  125. package/src/components/simple-video-player.tsx +60 -0
  126. package/src/components/ui/enhanced-seek-bar.tsx +235 -0
  127. package/src/components/ui/fullscreen-button.tsx +60 -0
  128. package/src/components/ui/media-resource-preloader.tsx +395 -0
  129. package/src/components/ui/play-button.tsx +107 -0
  130. package/src/components/ui/seek-bar.tsx +161 -0
  131. package/src/components/ui/time-display.tsx +40 -0
  132. package/src/components/ui/volume-control.tsx +143 -0
  133. package/src/components/unified/base-media-player.tsx +246 -0
  134. package/src/components/unified/media-player.tsx +75 -0
  135. package/src/components/variants/minimal/AccessibleMinimalPlayer.tsx +561 -0
  136. package/src/components/variants/minimal/EnhancedMinimalMediaPlayer.tsx +552 -0
  137. package/src/components/variants/minimal/MinimalControls.tsx +142 -0
  138. package/src/components/variants/minimal/MinimalLoading.tsx +32 -0
  139. package/src/components/variants/minimal/MinimalMediaPlayer.tsx +315 -0
  140. package/src/components/variants/minimal/MinimalOverlay.tsx +64 -0
  141. package/src/components/variants/minimal/MinimalPlayButton.tsx +65 -0
  142. package/src/components/variants/minimal/MinimalSeekBar.tsx +150 -0
  143. package/src/components/variants/minimal/MinimalVolumeControl.tsx +80 -0
  144. package/src/components/variants/minimal/SimpleMinimalPlayer.tsx +210 -0
  145. package/src/components/variants/minimal/components/CenterPlayButton.tsx +22 -0
  146. package/src/components/variants/minimal/components/ControlBar.tsx +146 -0
  147. package/src/components/variants/minimal/components/EnhancedSettingsMenu.tsx +361 -0
  148. package/src/components/variants/minimal/components/PlaybackControls.tsx +51 -0
  149. package/src/components/variants/minimal/components/RightControls.tsx +173 -0
  150. package/src/components/variants/minimal/components/SeekBar.tsx +131 -0
  151. package/src/components/variants/minimal/components/SettingsDropdown.tsx +70 -0
  152. package/src/components/variants/minimal/components/SubtitleDisplay.tsx +21 -0
  153. package/src/components/variants/minimal/components/TimeDisplay.tsx +18 -0
  154. package/src/components/variants/minimal/components/VideoElement.tsx +40 -0
  155. package/src/components/variants/minimal/components/VolumeControl.tsx +217 -0
  156. package/src/components/variants/minimal/index.ts +23 -0
  157. package/src/components/video-player.tsx +100 -0
  158. package/src/context/error-handling.ts +394 -0
  159. package/src/context/media-context.tsx +208 -0
  160. package/src/context/media-provider.tsx +265 -0
  161. package/src/context/media-store.ts +379 -0
  162. package/src/context/persistence.ts +453 -0
  163. package/src/core/events/event-system.ts +442 -0
  164. package/src/core/events/hooks.ts +302 -0
  165. package/src/core/events/index.ts +22 -0
  166. package/src/core/events/middleware.ts +269 -0
  167. package/src/core/index.ts +22 -0
  168. package/src/core/optimization/bundle-optimizer.tsx +308 -0
  169. package/src/core/performance/cicd.ts +96 -0
  170. package/src/core/performance/index.ts +38 -0
  171. package/src/core/performance/media-loading-optimizer.ts +538 -0
  172. package/src/core/performance/performance-budgets.ts +432 -0
  173. package/src/core/performance/performance-monitor.tsx +476 -0
  174. package/src/core/performance/performance-testing.ts +459 -0
  175. package/src/core/plugins/base-plugin.ts +224 -0
  176. package/src/core/plugins/enhanced-plugin-system.ts +411 -0
  177. package/src/core/plugins/examples/analytics-plugin.ts +242 -0
  178. package/src/core/plugins/index.ts +39 -0
  179. package/src/core/plugins/registry.ts +327 -0
  180. package/src/core/plugins/types.ts +159 -0
  181. package/src/core/plugins/utils.ts +316 -0
  182. package/src/core/progressive-loading.tsx +322 -0
  183. package/src/core/providers/enhanced-hls-provider.ts +339 -0
  184. package/src/core/providers/service-provider.tsx +168 -0
  185. package/src/core/utils.tsx +38 -0
  186. package/src/features/media-session/media-session-manager.ts +429 -0
  187. package/src/features/picture-in-picture/pip-manager.ts +429 -0
  188. package/src/features/playlist/playlist-manager.ts +606 -0
  189. package/src/features/subtitles/subtitle-manager.ts +441 -0
  190. package/src/features/subtitles/subtitle-parser.ts +280 -0
  191. package/src/features/thumbnails/thumbnail-generator.ts +519 -0
  192. package/src/hooks/accessibility/index.ts +27 -0
  193. package/src/hooks/accessibility/use-accessibility-preferences.ts +188 -0
  194. package/src/hooks/accessibility/use-focus-management.ts +176 -0
  195. package/src/hooks/accessibility/use-keyboard-shortcuts.ts +144 -0
  196. package/src/hooks/accessibility/use-screen-reader.ts +182 -0
  197. package/src/hooks/core/index.ts +47 -0
  198. package/src/hooks/legacy.ts +27 -0
  199. package/src/hooks/use-enhanced-media-player.ts +468 -0
  200. package/src/hooks/use-intelligent-preloading.ts +358 -0
  201. package/src/hooks/use-keyboard-controls.ts +115 -0
  202. package/src/hooks/use-media-actions.ts +175 -0
  203. package/src/hooks/use-media-metadata.ts +89 -0
  204. package/src/hooks/use-media-optimistic.ts +270 -0
  205. package/src/hooks/use-media-player.ts +312 -0
  206. package/src/hooks/use-media-state.ts +190 -0
  207. package/src/hooks/use-memory-optimization.ts +358 -0
  208. package/src/hooks/use-optimistic-controls.ts +92 -0
  209. package/src/hooks/use-optimized-media.ts +263 -0
  210. package/src/hooks/use-touch-gestures.ts +417 -0
  211. package/src/hooks/useEnhancedSubtitles.ts +258 -0
  212. package/src/hooks/useKeyboardShortcuts.ts +74 -0
  213. package/src/hooks/useMediaControls.ts +52 -0
  214. package/src/hooks/useScreenshot.ts +57 -0
  215. package/src/hooks/useSubtitles.ts +91 -0
  216. package/src/hooks/useVideoPlayer.ts +232 -0
  217. package/src/icons/components/FullscreenIcon.tsx +37 -0
  218. package/src/icons/components/SettingsIcon.tsx +38 -0
  219. package/src/icons/components/animated/LoadingIcon.tsx +43 -0
  220. package/src/icons/components/animated/PlayPauseIcon.tsx +50 -0
  221. package/src/icons/components/media/PauseIcon.tsx +39 -0
  222. package/src/icons/components/media/PlayIcon.tsx +38 -0
  223. package/src/icons/components/volume/VolumeIcon.tsx +39 -0
  224. package/src/icons/components/volume/VolumeOffIcon.tsx +39 -0
  225. package/src/icons/index.ts +56 -0
  226. package/src/icons/provider.tsx +64 -0
  227. package/src/icons/types.ts +40 -0
  228. package/src/index-enhanced.ts +35 -0
  229. package/src/index-legacy.ts +326 -0
  230. package/src/index.css +102 -0
  231. package/src/index.ts +216 -0
  232. package/src/lib/deprecation.ts +51 -0
  233. package/src/lib/format-time.ts +37 -0
  234. package/src/lib/index.ts +3 -0
  235. package/src/lib/utils.ts +6 -0
  236. package/src/styles/globals.css +462 -0
  237. package/src/styles/minimal-player.css +589 -0
  238. package/src/styles/pixel-art.css +46 -0
  239. package/src/styles/videojs.css +100 -0
  240. package/src/test/setup.ts +79 -0
  241. package/src/types/events.ts +47 -0
  242. package/src/types/formats.ts +95 -0
  243. package/src/types/index.ts +190 -0
  244. package/src/types/videojs-plugins.d.ts +14 -0
@@ -0,0 +1,232 @@
1
+ import { useState, useRef, useCallback, useEffect } from "react"
2
+
3
+ export interface BufferedRange {
4
+ start: number
5
+ end: number
6
+ percentage: number
7
+ }
8
+
9
+ export interface VideoState {
10
+ isPlaying: boolean
11
+ currentTime: number
12
+ duration: number
13
+ volume: number
14
+ isMuted: boolean
15
+ isFullscreen: boolean
16
+ isLoading: boolean
17
+ isSeeking: boolean
18
+ isBuffering: boolean
19
+ bufferedRanges: BufferedRange[]
20
+ }
21
+
22
+ export interface VideoControls {
23
+ togglePlay: () => void
24
+ seekForward: (seconds?: number) => void
25
+ seekBackward: (seconds?: number) => void
26
+ toggleMute: () => void
27
+ setVolume: (volume: number) => void
28
+ toggleFullscreen: () => void
29
+ seekTo: (time: number) => void
30
+ }
31
+
32
+ export function useVideoPlayer(containerRef: React.RefObject<HTMLDivElement | null>) {
33
+ const videoRef = useRef<HTMLVideoElement>(null)
34
+ const [state, setState] = useState<VideoState>({
35
+ isPlaying: false,
36
+ currentTime: 0,
37
+ duration: 0,
38
+ volume: 1,
39
+ isMuted: false,
40
+ isFullscreen: false,
41
+ isLoading: true,
42
+ isSeeking: false,
43
+ isBuffering: false,
44
+ bufferedRanges: []
45
+ })
46
+
47
+ useEffect(() => {
48
+ const video = videoRef.current
49
+ if (!video) return
50
+
51
+ const handleTimeUpdate = () => {
52
+ setState(prev => ({ ...prev, currentTime: video.currentTime }))
53
+ }
54
+
55
+ const handleLoadedMetadata = () => {
56
+ setState(prev => ({ ...prev, duration: video.duration }))
57
+ }
58
+
59
+ const handlePlay = () => {
60
+ setState(prev => ({ ...prev, isPlaying: true, isBuffering: false }))
61
+ }
62
+
63
+ const handlePause = () => {
64
+ setState(prev => ({ ...prev, isPlaying: false }))
65
+ }
66
+
67
+ const handleVolumeChange = () => {
68
+ setState(prev => ({
69
+ ...prev,
70
+ volume: video.volume,
71
+ isMuted: video.muted
72
+ }))
73
+ }
74
+
75
+ // Loading state handlers
76
+ const handleLoadStart = () => {
77
+ setState(prev => ({ ...prev, isLoading: true }))
78
+ }
79
+
80
+ const handleLoadedData = () => {
81
+ setState(prev => ({ ...prev, isLoading: false }))
82
+ }
83
+
84
+ // Seeking state handlers
85
+ const handleSeeking = () => {
86
+ setState(prev => ({ ...prev, isSeeking: true }))
87
+ }
88
+
89
+ const handleSeeked = () => {
90
+ setState(prev => ({ ...prev, isSeeking: false }))
91
+ }
92
+
93
+ // Buffering state handlers
94
+ const handleWaiting = () => {
95
+ setState(prev => ({ ...prev, isBuffering: true }))
96
+ }
97
+
98
+ const handlePlaying = () => {
99
+ setState(prev => ({ ...prev, isBuffering: false, isLoading: false }))
100
+ }
101
+
102
+ const handleCanPlay = () => {
103
+ setState(prev => ({ ...prev, isLoading: false, isBuffering: false }))
104
+ }
105
+
106
+ // Progress handler for buffered ranges
107
+ const handleProgress = () => {
108
+ if (!video.buffered || video.buffered.length === 0 || video.duration === 0) {
109
+ setState(prev => ({ ...prev, bufferedRanges: [] }))
110
+ return
111
+ }
112
+
113
+ const ranges: BufferedRange[] = []
114
+ for (let i = 0; i < video.buffered.length; i++) {
115
+ const start = video.buffered.start(i)
116
+ const end = video.buffered.end(i)
117
+ ranges.push({
118
+ start,
119
+ end,
120
+ percentage: ((end - start) / video.duration) * 100
121
+ })
122
+ }
123
+ setState(prev => ({ ...prev, bufferedRanges: ranges }))
124
+ }
125
+
126
+ video.addEventListener("timeupdate", handleTimeUpdate)
127
+ video.addEventListener("loadedmetadata", handleLoadedMetadata)
128
+ video.addEventListener("play", handlePlay)
129
+ video.addEventListener("pause", handlePause)
130
+ video.addEventListener("volumechange", handleVolumeChange)
131
+ video.addEventListener("loadstart", handleLoadStart)
132
+ video.addEventListener("loadeddata", handleLoadedData)
133
+ video.addEventListener("seeking", handleSeeking)
134
+ video.addEventListener("seeked", handleSeeked)
135
+ video.addEventListener("waiting", handleWaiting)
136
+ video.addEventListener("playing", handlePlaying)
137
+ video.addEventListener("canplay", handleCanPlay)
138
+ video.addEventListener("progress", handleProgress)
139
+
140
+ return () => {
141
+ video.removeEventListener("timeupdate", handleTimeUpdate)
142
+ video.removeEventListener("loadedmetadata", handleLoadedMetadata)
143
+ video.removeEventListener("play", handlePlay)
144
+ video.removeEventListener("pause", handlePause)
145
+ video.removeEventListener("volumechange", handleVolumeChange)
146
+ video.removeEventListener("loadstart", handleLoadStart)
147
+ video.removeEventListener("loadeddata", handleLoadedData)
148
+ video.removeEventListener("seeking", handleSeeking)
149
+ video.removeEventListener("seeked", handleSeeked)
150
+ video.removeEventListener("waiting", handleWaiting)
151
+ video.removeEventListener("playing", handlePlaying)
152
+ video.removeEventListener("canplay", handleCanPlay)
153
+ video.removeEventListener("progress", handleProgress)
154
+ }
155
+ }, [])
156
+
157
+ const togglePlay = () => {
158
+ const video = videoRef.current
159
+ if (!video) return
160
+
161
+ if (state.isPlaying) {
162
+ video.pause()
163
+ } else {
164
+ video.play()
165
+ }
166
+ }
167
+
168
+ const seekForward = (seconds = 10) => {
169
+ const video = videoRef.current
170
+ if (!video) return
171
+ video.currentTime = Math.min(state.duration, video.currentTime + seconds)
172
+ }
173
+
174
+ const seekBackward = (seconds = 10) => {
175
+ const video = videoRef.current
176
+ if (!video) return
177
+ video.currentTime = Math.max(0, video.currentTime - seconds)
178
+ }
179
+
180
+ const toggleMute = () => {
181
+ const video = videoRef.current
182
+ if (!video) return
183
+ video.muted = !state.isMuted
184
+ }
185
+
186
+ const setVolume = (volume: number) => {
187
+ const video = videoRef.current
188
+ if (!video) return
189
+ video.volume = volume
190
+ if (volume > 0 && state.isMuted) {
191
+ video.muted = false
192
+ }
193
+ }
194
+
195
+ const toggleFullscreen = () => {
196
+ const container = containerRef.current
197
+ if (!container) return
198
+
199
+ if (!state.isFullscreen) {
200
+ if (container.requestFullscreen) {
201
+ container.requestFullscreen()
202
+ }
203
+ } else {
204
+ if (document.exitFullscreen) {
205
+ document.exitFullscreen()
206
+ }
207
+ }
208
+ setState(prev => ({ ...prev, isFullscreen: !prev.isFullscreen }))
209
+ }
210
+
211
+ const seekTo = (time: number) => {
212
+ const video = videoRef.current
213
+ if (!video || state.duration === 0) return
214
+ video.currentTime = Math.max(0, Math.min(state.duration, time))
215
+ }
216
+
217
+ const controls: VideoControls = {
218
+ togglePlay,
219
+ seekForward,
220
+ seekBackward,
221
+ toggleMute,
222
+ setVolume,
223
+ toggleFullscreen,
224
+ seekTo
225
+ }
226
+
227
+ return {
228
+ videoRef,
229
+ state,
230
+ controls
231
+ }
232
+ }
@@ -0,0 +1,37 @@
1
+ import type { IconProps } from '../types'
2
+ import { useIconTheme, useCustomIcon } from '../provider'
3
+
4
+ export function FullscreenIcon(props: IconProps) {
5
+ const theme = useIconTheme()
6
+ const customIcon = useCustomIcon('fullscreen')
7
+
8
+ if (customIcon) {
9
+ return customIcon(props)
10
+ }
11
+
12
+ const {
13
+ size = theme.size,
14
+ color = theme.color,
15
+ strokeWidth = theme.strokeWidth,
16
+ className = theme.className,
17
+ ...rest
18
+ } = props
19
+
20
+ return (
21
+ <svg
22
+ width={size}
23
+ height={size}
24
+ viewBox="0 0 24 24"
25
+ fill="none"
26
+ stroke={color}
27
+ strokeWidth={strokeWidth}
28
+ strokeLinecap="round"
29
+ strokeLinejoin="round"
30
+ className={className}
31
+ aria-hidden="true"
32
+ {...rest}
33
+ >
34
+ <path d="M8 3H5a2 2 0 0 0-2 2v3m18 0V5a2 2 0 0 0-2-2h-3m0 18h3a2 2 0 0 0 2-2v-3M3 16v3a2 2 0 0 0 2 2h3" />
35
+ </svg>
36
+ )
37
+ }
@@ -0,0 +1,38 @@
1
+ import type { IconProps } from '../types'
2
+ import { useIconTheme, useCustomIcon } from '../provider'
3
+
4
+ export function SettingsIcon(props: IconProps) {
5
+ const theme = useIconTheme()
6
+ const customIcon = useCustomIcon('settings')
7
+
8
+ if (customIcon) {
9
+ return customIcon(props)
10
+ }
11
+
12
+ const {
13
+ size = theme.size,
14
+ color = theme.color,
15
+ strokeWidth = theme.strokeWidth,
16
+ className = theme.className,
17
+ ...rest
18
+ } = props
19
+
20
+ return (
21
+ <svg
22
+ width={size}
23
+ height={size}
24
+ viewBox="0 0 24 24"
25
+ fill="none"
26
+ stroke={color}
27
+ strokeWidth={strokeWidth}
28
+ strokeLinecap="round"
29
+ strokeLinejoin="round"
30
+ className={className}
31
+ aria-hidden="true"
32
+ {...rest}
33
+ >
34
+ <circle cx="12" cy="12" r="3" />
35
+ <path d="M12 1v6m0 6v6m11-7h-6m-6 0H1m10.5-4A1.5 1.5 0 0 1 15 12a1.5 1.5 0 0 1-3.5 0 1.5 1.5 0 0 1 3.5 0Z" />
36
+ </svg>
37
+ )
38
+ }
@@ -0,0 +1,43 @@
1
+ import type { IconProps } from '../../types'
2
+ import { useIconTheme, useCustomIcon } from '../../provider'
3
+
4
+ export function LoadingIcon(props: IconProps) {
5
+ const theme = useIconTheme()
6
+ const customIcon = useCustomIcon('loading')
7
+
8
+ if (customIcon) {
9
+ return customIcon(props)
10
+ }
11
+
12
+ const {
13
+ size = theme.size,
14
+ color = theme.color,
15
+ className = theme.className,
16
+ ...rest
17
+ } = props
18
+
19
+ return (
20
+ <svg
21
+ width={size}
22
+ height={size}
23
+ viewBox="0 0 24 24"
24
+ fill="none"
25
+ className={`animate-spin ${className || ''}`}
26
+ aria-hidden="true"
27
+ {...rest}
28
+ >
29
+ <circle
30
+ cx="12"
31
+ cy="12"
32
+ r="10"
33
+ stroke={color}
34
+ strokeWidth="4"
35
+ strokeOpacity="0.25"
36
+ />
37
+ <path
38
+ fill={color}
39
+ d="M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4z"
40
+ />
41
+ </svg>
42
+ )
43
+ }
@@ -0,0 +1,50 @@
1
+ import type { IconProps } from '../../types'
2
+ import { useIconTheme } from '../../provider'
3
+
4
+ interface PlayPauseIconProps extends IconProps {
5
+ isPlaying: boolean
6
+ }
7
+
8
+ export function PlayPauseIcon({ isPlaying, className = '', ...props }: PlayPauseIconProps) {
9
+ const theme = useIconTheme()
10
+
11
+ const {
12
+ size = theme.size,
13
+ color = theme.color,
14
+ strokeWidth = theme.strokeWidth,
15
+ ...rest
16
+ } = props
17
+
18
+ return (
19
+ <svg
20
+ width={size}
21
+ height={size}
22
+ viewBox="0 0 24 24"
23
+ fill="none"
24
+ stroke={color}
25
+ strokeWidth={strokeWidth}
26
+ strokeLinecap="round"
27
+ strokeLinejoin="round"
28
+ className={className}
29
+ aria-hidden="true"
30
+ {...rest}
31
+ >
32
+ {/* Play icon */}
33
+ <g
34
+ className={`origin-center transition-all duration-300 ${isPlaying ? "scale-75 opacity-0" : "scale-100 opacity-100"}
35
+ `}
36
+ >
37
+ <polygon points="5 3 19 12 5 21 5 3" />
38
+ </g>
39
+
40
+ {/* Pause icon */}
41
+ <g
42
+ className={`origin-center transition-all duration-300 ${isPlaying ? "scale-100 opacity-100" : "scale-75 opacity-0"}
43
+ `}
44
+ >
45
+ <rect x="6" y="4" width="4" height="16" />
46
+ <rect x="14" y="4" width="4" height="16" />
47
+ </g>
48
+ </svg>
49
+ )
50
+ }
@@ -0,0 +1,39 @@
1
+ import type { IconProps } from '../../types'
2
+ import { useIconTheme, useCustomIcon } from '../../provider'
3
+
4
+ export function PauseIcon(props: IconProps) {
5
+ const theme = useIconTheme()
6
+ const customIcon = useCustomIcon('pause')
7
+
8
+ // If there's a custom icon, use it
9
+ if (customIcon) {
10
+ return customIcon(props)
11
+ }
12
+
13
+ const {
14
+ size = theme.size,
15
+ color = theme.color,
16
+ strokeWidth = theme.strokeWidth,
17
+ className = theme.className,
18
+ ...rest
19
+ } = props
20
+
21
+ return (
22
+ <svg
23
+ width={size}
24
+ height={size}
25
+ viewBox="0 0 24 24"
26
+ fill="none"
27
+ stroke={color}
28
+ strokeWidth={strokeWidth}
29
+ strokeLinecap="round"
30
+ strokeLinejoin="round"
31
+ className={className}
32
+ aria-hidden="true"
33
+ {...rest}
34
+ >
35
+ <rect x="6" y="4" width="4" height="16" />
36
+ <rect x="14" y="4" width="4" height="16" />
37
+ </svg>
38
+ )
39
+ }
@@ -0,0 +1,38 @@
1
+ import type { IconProps } from '../../types'
2
+ import { useIconTheme, useCustomIcon } from '../../provider'
3
+
4
+ export function PlayIcon(props: IconProps) {
5
+ const theme = useIconTheme()
6
+ const customIcon = useCustomIcon('play')
7
+
8
+ // If there's a custom icon, use it
9
+ if (customIcon) {
10
+ return customIcon(props)
11
+ }
12
+
13
+ const {
14
+ size = theme.size,
15
+ color = theme.color,
16
+ strokeWidth = theme.strokeWidth,
17
+ className = theme.className,
18
+ ...rest
19
+ } = props
20
+
21
+ return (
22
+ <svg
23
+ width={size}
24
+ height={size}
25
+ viewBox="0 0 24 24"
26
+ fill="none"
27
+ stroke={color}
28
+ strokeWidth={strokeWidth}
29
+ strokeLinecap="round"
30
+ strokeLinejoin="round"
31
+ className={className}
32
+ aria-hidden="true"
33
+ {...rest}
34
+ >
35
+ <polygon points="5 3 19 12 5 21 5 3" />
36
+ </svg>
37
+ )
38
+ }
@@ -0,0 +1,39 @@
1
+ import type { IconProps } from '../../types'
2
+ import { useIconTheme, useCustomIcon } from '../../provider'
3
+
4
+ export function VolumeIcon(props: IconProps) {
5
+ const theme = useIconTheme()
6
+ const customIcon = useCustomIcon('volume')
7
+
8
+ if (customIcon) {
9
+ return customIcon(props)
10
+ }
11
+
12
+ const {
13
+ size = theme.size,
14
+ color = theme.color,
15
+ strokeWidth = theme.strokeWidth,
16
+ className = theme.className,
17
+ ...rest
18
+ } = props
19
+
20
+ return (
21
+ <svg
22
+ width={size}
23
+ height={size}
24
+ viewBox="0 0 24 24"
25
+ fill="none"
26
+ stroke={color}
27
+ strokeWidth={strokeWidth}
28
+ strokeLinecap="round"
29
+ strokeLinejoin="round"
30
+ className={className}
31
+ aria-hidden="true"
32
+ {...rest}
33
+ >
34
+ <polygon points="11 5 6 9 2 9 2 15 6 15 11 19 11 5" />
35
+ <path d="M15.54 8.46a5 5 0 0 1 0 7.07" />
36
+ <path d="M19.07 4.93a10 10 0 0 1 0 14.14" />
37
+ </svg>
38
+ )
39
+ }
@@ -0,0 +1,39 @@
1
+ import type { IconProps } from '../../types'
2
+ import { useIconTheme, useCustomIcon } from '../../provider'
3
+
4
+ export function VolumeOffIcon(props: IconProps) {
5
+ const theme = useIconTheme()
6
+ const customIcon = useCustomIcon('volume-off')
7
+
8
+ if (customIcon) {
9
+ return customIcon(props)
10
+ }
11
+
12
+ const {
13
+ size = theme.size,
14
+ color = theme.color,
15
+ strokeWidth = theme.strokeWidth,
16
+ className = theme.className,
17
+ ...rest
18
+ } = props
19
+
20
+ return (
21
+ <svg
22
+ width={size}
23
+ height={size}
24
+ viewBox="0 0 24 24"
25
+ fill="none"
26
+ stroke={color}
27
+ strokeWidth={strokeWidth}
28
+ strokeLinecap="round"
29
+ strokeLinejoin="round"
30
+ className={className}
31
+ aria-hidden="true"
32
+ {...rest}
33
+ >
34
+ <polygon points="11 5 6 9 2 9 2 15 6 15 11 19 11 5" />
35
+ <line x1="23" y1="9" x2="17" y2="15" />
36
+ <line x1="17" y1="9" x2="23" y2="15" />
37
+ </svg>
38
+ )
39
+ }
@@ -0,0 +1,56 @@
1
+ // Export types
2
+ export type { IconProps, IconTheme, IconName, IconComponent, IconSet } from './types'
3
+
4
+ // Export provider and hooks
5
+ export { IconProvider, useIconTheme, useIcon, useCustomIcon } from './provider'
6
+
7
+ // Export media icons
8
+ export { PlayIcon } from './components/media/PlayIcon'
9
+ export { PauseIcon } from './components/media/PauseIcon'
10
+
11
+ // Export volume icons
12
+ export { VolumeIcon } from './components/volume/VolumeIcon'
13
+ export { VolumeOffIcon } from './components/volume/VolumeOffIcon'
14
+
15
+ // Export animated icons
16
+ export { LoadingIcon } from './components/animated/LoadingIcon'
17
+ export { PlayPauseIcon } from './components/animated/PlayPauseIcon'
18
+
19
+ // Export other icons
20
+ export { SettingsIcon } from './components/SettingsIcon'
21
+ export { FullscreenIcon } from './components/FullscreenIcon'
22
+
23
+ // Create a complete icon map for dynamic usage
24
+ import { PlayIcon } from './components/media/PlayIcon'
25
+ import { PauseIcon } from './components/media/PauseIcon'
26
+ import { VolumeIcon } from './components/volume/VolumeIcon'
27
+ import { VolumeOffIcon } from './components/volume/VolumeOffIcon'
28
+ import { LoadingIcon } from './components/animated/LoadingIcon'
29
+ import { SettingsIcon } from './components/SettingsIcon'
30
+ import { FullscreenIcon } from './components/FullscreenIcon'
31
+
32
+ export const Icons = {
33
+ PlayIcon,
34
+ PauseIcon,
35
+ VolumeIcon,
36
+ VolumeOffIcon,
37
+ LoadingIcon,
38
+ SettingsIcon,
39
+ FullscreenIcon
40
+ }
41
+
42
+ // Utility function to get icon by name
43
+ export function getIcon(name: string) {
44
+ const iconMap: Record<string, keyof typeof Icons> = {
45
+ 'play': 'PlayIcon',
46
+ 'pause': 'PauseIcon',
47
+ 'volume': 'VolumeIcon',
48
+ 'volume-off': 'VolumeOffIcon',
49
+ 'loading': 'LoadingIcon',
50
+ 'settings': 'SettingsIcon',
51
+ 'fullscreen': 'FullscreenIcon'
52
+ }
53
+
54
+ const iconKey = iconMap[name]
55
+ return iconKey ? Icons[iconKey] : null
56
+ }
@@ -0,0 +1,64 @@
1
+ import { createContext, useContext, type ReactNode } from 'react'
2
+ import type { IconTheme, IconSet, IconName, IconComponent } from './types'
3
+
4
+ interface IconContextValue {
5
+ theme: IconTheme
6
+ icons: Partial<IconSet>
7
+ }
8
+
9
+ const IconContext = createContext<IconContextValue | null>(null)
10
+
11
+ interface IconProviderProps {
12
+ children: ReactNode
13
+ theme?: IconTheme
14
+ icons?: Partial<IconSet>
15
+ }
16
+
17
+ export function IconProvider({
18
+ children,
19
+ theme = {},
20
+ icons = {}
21
+ }: IconProviderProps) {
22
+ const value: IconContextValue = {
23
+ theme: {
24
+ size: 24,
25
+ color: 'currentColor',
26
+ strokeWidth: 2,
27
+ ...theme
28
+ },
29
+ icons
30
+ }
31
+
32
+ return (
33
+ <IconContext.Provider value={value}>
34
+ {children}
35
+ </IconContext.Provider>
36
+ )
37
+ }
38
+
39
+ export function useIconTheme(): IconTheme {
40
+ const context = useContext(IconContext)
41
+ return context?.theme ?? {
42
+ size: 24,
43
+ color: 'currentColor',
44
+ strokeWidth: 2
45
+ }
46
+ }
47
+
48
+ export function useIcon(name: IconName): IconComponent | null {
49
+ const context = useContext(IconContext)
50
+ const customIcon = context?.icons?.[name]
51
+
52
+ if (customIcon) {
53
+ return customIcon
54
+ }
55
+
56
+ // If no custom icon found, we'll need to import the default one
57
+ // This will be handled by the individual icon components
58
+ return null
59
+ }
60
+
61
+ export function useCustomIcon(name: IconName): IconComponent | null {
62
+ const context = useContext(IconContext)
63
+ return context?.icons?.[name] || null
64
+ }