ts-video-player 0.1.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 (251) hide show
  1. package/LICENSE.md +21 -0
  2. package/README.md +438 -0
  3. package/dist/cdn.d.ts +10 -0
  4. package/dist/cdn.d.ts.map +1 -0
  5. package/dist/cdn.min.js +1046 -0
  6. package/dist/cdn.min.js.map +54 -0
  7. package/dist/cdn.test.d.ts +2 -0
  8. package/dist/cdn.test.d.ts.map +1 -0
  9. package/dist/chunk-36x4yhjn.js +765 -0
  10. package/dist/chunk-36x4yhjn.js.map +12 -0
  11. package/dist/chunk-eajts2jv.js +4243 -0
  12. package/dist/chunk-eajts2jv.js.map +42 -0
  13. package/dist/chunk-z1ehbz9f.js +380 -0
  14. package/dist/chunk-z1ehbz9f.js.map +19 -0
  15. package/dist/config.d.ts +9 -0
  16. package/dist/config.d.ts.map +1 -0
  17. package/dist/core/audio-gain.d.ts +67 -0
  18. package/dist/core/audio-gain.d.ts.map +1 -0
  19. package/dist/core/caption-styles.d.ts +121 -0
  20. package/dist/core/caption-styles.d.ts.map +1 -0
  21. package/dist/core/chapters.d.ts +150 -0
  22. package/dist/core/chapters.d.ts.map +1 -0
  23. package/dist/core/error-overlay.d.ts +71 -0
  24. package/dist/core/error-overlay.d.ts.map +1 -0
  25. package/dist/core/events.d.ts +119 -0
  26. package/dist/core/events.d.ts.map +1 -0
  27. package/dist/core/features.d.ts +64 -0
  28. package/dist/core/features.d.ts.map +1 -0
  29. package/dist/core/i18n.d.ts +132 -0
  30. package/dist/core/i18n.d.ts.map +1 -0
  31. package/dist/core/index.d.ts +37 -0
  32. package/dist/core/index.d.ts.map +1 -0
  33. package/dist/core/live.d.ts +130 -0
  34. package/dist/core/live.d.ts.map +1 -0
  35. package/dist/core/media-session.d.ts +38 -0
  36. package/dist/core/media-session.d.ts.map +1 -0
  37. package/dist/core/orientation.d.ts +22 -0
  38. package/dist/core/orientation.d.ts.map +1 -0
  39. package/dist/core/popover.d.ts +42 -0
  40. package/dist/core/popover.d.ts.map +1 -0
  41. package/dist/core/remote-playback.d.ts +195 -0
  42. package/dist/core/remote-playback.d.ts.map +1 -0
  43. package/dist/core/settings-menu.d.ts +132 -0
  44. package/dist/core/settings-menu.d.ts.map +1 -0
  45. package/dist/core/spinner.d.ts +67 -0
  46. package/dist/core/spinner.d.ts.map +1 -0
  47. package/dist/core/state.d.ts +142 -0
  48. package/dist/core/state.d.ts.map +1 -0
  49. package/dist/core/text-tracks.d.ts +162 -0
  50. package/dist/core/text-tracks.d.ts.map +1 -0
  51. package/dist/core/themes.d.ts +213 -0
  52. package/dist/core/themes.d.ts.map +1 -0
  53. package/dist/core/thumbnails.d.ts +124 -0
  54. package/dist/core/thumbnails.d.ts.map +1 -0
  55. package/dist/core/tooltips.d.ts +100 -0
  56. package/dist/core/tooltips.d.ts.map +1 -0
  57. package/dist/elements/base.d.ts +3 -0
  58. package/dist/elements/base.d.ts.map +1 -0
  59. package/dist/elements/index.d.ts +33 -0
  60. package/dist/elements/index.d.ts.map +1 -0
  61. package/dist/elements/index.js +55 -0
  62. package/dist/elements/index.js.map +9 -0
  63. package/dist/elements/media-airplay-button.d.ts +13 -0
  64. package/dist/elements/media-airplay-button.d.ts.map +1 -0
  65. package/dist/elements/media-error-display.d.ts +13 -0
  66. package/dist/elements/media-error-display.d.ts.map +1 -0
  67. package/dist/elements/media-fullscreen-button.d.ts +13 -0
  68. package/dist/elements/media-fullscreen-button.d.ts.map +1 -0
  69. package/dist/elements/media-live-button.d.ts +13 -0
  70. package/dist/elements/media-live-button.d.ts.map +1 -0
  71. package/dist/elements/media-mute-button.d.ts +13 -0
  72. package/dist/elements/media-mute-button.d.ts.map +1 -0
  73. package/dist/elements/media-pip-button.d.ts +13 -0
  74. package/dist/elements/media-pip-button.d.ts.map +1 -0
  75. package/dist/elements/media-play-button.d.ts +14 -0
  76. package/dist/elements/media-play-button.d.ts.map +1 -0
  77. package/dist/elements/media-playback-rate-button.d.ts +10 -0
  78. package/dist/elements/media-playback-rate-button.d.ts.map +1 -0
  79. package/dist/elements/media-preview-time.d.ts +18 -0
  80. package/dist/elements/media-preview-time.d.ts.map +1 -0
  81. package/dist/elements/media-progress-bar.d.ts +16 -0
  82. package/dist/elements/media-progress-bar.d.ts.map +1 -0
  83. package/dist/elements/media-remote-playback-button.d.ts +16 -0
  84. package/dist/elements/media-remote-playback-button.d.ts.map +1 -0
  85. package/dist/elements/media-seek-button.d.ts +9 -0
  86. package/dist/elements/media-seek-button.d.ts.map +1 -0
  87. package/dist/elements/media-settings-menu.d.ts +32 -0
  88. package/dist/elements/media-settings-menu.d.ts.map +1 -0
  89. package/dist/elements/media-time-display.d.ts +21 -0
  90. package/dist/elements/media-time-display.d.ts.map +1 -0
  91. package/dist/elements/media-time-group.d.ts +22 -0
  92. package/dist/elements/media-time-group.d.ts.map +1 -0
  93. package/dist/elements/media-time-separator.d.ts +13 -0
  94. package/dist/elements/media-time-separator.d.ts.map +1 -0
  95. package/dist/elements/media-volume-slider.d.ts +16 -0
  96. package/dist/elements/media-volume-slider.d.ts.map +1 -0
  97. package/dist/elements/utils.d.ts +27 -0
  98. package/dist/elements/utils.d.ts.map +1 -0
  99. package/dist/elements/video-player.d.ts +23 -0
  100. package/dist/elements/video-player.d.ts.map +1 -0
  101. package/dist/elements/video-skin.d.ts +23 -0
  102. package/dist/elements/video-skin.d.ts.map +1 -0
  103. package/dist/features/captions.d.ts +8 -0
  104. package/dist/features/captions.d.ts.map +1 -0
  105. package/dist/features/create-player.d.ts +45 -0
  106. package/dist/features/create-player.d.ts.map +1 -0
  107. package/dist/features/fullscreen.d.ts +8 -0
  108. package/dist/features/fullscreen.d.ts.map +1 -0
  109. package/dist/features/gestures.d.ts +8 -0
  110. package/dist/features/gestures.d.ts.map +1 -0
  111. package/dist/features/index.d.ts +26 -0
  112. package/dist/features/index.d.ts.map +1 -0
  113. package/dist/features/index.js +31 -0
  114. package/dist/features/index.js.map +9 -0
  115. package/dist/features/keyboard.d.ts +8 -0
  116. package/dist/features/keyboard.d.ts.map +1 -0
  117. package/dist/features/pip.d.ts +8 -0
  118. package/dist/features/pip.d.ts.map +1 -0
  119. package/dist/features/playback.d.ts +8 -0
  120. package/dist/features/playback.d.ts.map +1 -0
  121. package/dist/features/quality.d.ts +8 -0
  122. package/dist/features/quality.d.ts.map +1 -0
  123. package/dist/features/types.d.ts +26 -0
  124. package/dist/features/types.d.ts.map +1 -0
  125. package/dist/features/volume.d.ts +8 -0
  126. package/dist/features/volume.d.ts.map +1 -0
  127. package/dist/index.d.ts +84 -0
  128. package/dist/index.d.ts.map +1 -0
  129. package/dist/index.js +8149 -0
  130. package/dist/index.js.map +31 -0
  131. package/dist/layouts/index.d.ts +58 -0
  132. package/dist/layouts/index.d.ts.map +1 -0
  133. package/dist/player.d.ts +90 -0
  134. package/dist/player.d.ts.map +1 -0
  135. package/dist/plugins/ads.d.ts +311 -0
  136. package/dist/plugins/ads.d.ts.map +1 -0
  137. package/dist/plugins/analytics.d.ts +203 -0
  138. package/dist/plugins/analytics.d.ts.map +1 -0
  139. package/dist/plugins/end-screen.d.ts +184 -0
  140. package/dist/plugins/end-screen.d.ts.map +1 -0
  141. package/dist/plugins/index.d.ts +13 -0
  142. package/dist/plugins/index.d.ts.map +1 -0
  143. package/dist/plugins/index.js +20 -0
  144. package/dist/plugins/index.js.map +9 -0
  145. package/dist/plugins/skip-segments.d.ts +159 -0
  146. package/dist/plugins/skip-segments.d.ts.map +1 -0
  147. package/dist/plugins/watermark.d.ts +157 -0
  148. package/dist/plugins/watermark.d.ts.map +1 -0
  149. package/dist/providers/base.d.ts +56 -0
  150. package/dist/providers/base.d.ts.map +1 -0
  151. package/dist/providers/dash.d.ts +94 -0
  152. package/dist/providers/dash.d.ts.map +1 -0
  153. package/dist/providers/hls.d.ts +182 -0
  154. package/dist/providers/hls.d.ts.map +1 -0
  155. package/dist/providers/html5.d.ts +64 -0
  156. package/dist/providers/html5.d.ts.map +1 -0
  157. package/dist/providers/index.d.ts +41 -0
  158. package/dist/providers/index.d.ts.map +1 -0
  159. package/dist/providers/vimeo.d.ts +157 -0
  160. package/dist/providers/vimeo.d.ts.map +1 -0
  161. package/dist/providers/youtube.d.ts +134 -0
  162. package/dist/providers/youtube.d.ts.map +1 -0
  163. package/dist/stx/index.d.ts +59 -0
  164. package/dist/stx/index.d.ts.map +1 -0
  165. package/dist/stx/index.js +480 -0
  166. package/dist/stx/index.js.map +11 -0
  167. package/dist/types.d.ts +724 -0
  168. package/dist/types.d.ts.map +1 -0
  169. package/dist/ui/components.d.ts +121 -0
  170. package/dist/ui/components.d.ts.map +1 -0
  171. package/dist/ui/index.d.ts +9 -0
  172. package/dist/ui/index.d.ts.map +1 -0
  173. package/dist/ui/index.js +16 -0
  174. package/dist/ui/index.js.map +9 -0
  175. package/package.json +109 -0
  176. package/src/cdn.test.ts +10 -0
  177. package/src/cdn.ts +60 -0
  178. package/src/config.ts +25 -0
  179. package/src/core/audio-gain.ts +171 -0
  180. package/src/core/caption-styles.ts +568 -0
  181. package/src/core/chapters.ts +551 -0
  182. package/src/core/error-overlay.ts +354 -0
  183. package/src/core/events.ts +552 -0
  184. package/src/core/features.ts +287 -0
  185. package/src/core/i18n.ts +590 -0
  186. package/src/core/index.ts +249 -0
  187. package/src/core/live.ts +472 -0
  188. package/src/core/media-session.ts +137 -0
  189. package/src/core/orientation.ts +57 -0
  190. package/src/core/popover.ts +143 -0
  191. package/src/core/remote-playback.ts +661 -0
  192. package/src/core/settings-menu.ts +630 -0
  193. package/src/core/spinner.ts +310 -0
  194. package/src/core/state.ts +476 -0
  195. package/src/core/text-tracks.ts +599 -0
  196. package/src/core/themes.ts +607 -0
  197. package/src/core/thumbnails.ts +457 -0
  198. package/src/core/tooltips.ts +370 -0
  199. package/src/elements/base.ts +2 -0
  200. package/src/elements/index.ts +82 -0
  201. package/src/elements/media-airplay-button.ts +78 -0
  202. package/src/elements/media-error-display.ts +47 -0
  203. package/src/elements/media-fullscreen-button.ts +72 -0
  204. package/src/elements/media-live-button.ts +65 -0
  205. package/src/elements/media-mute-button.ts +69 -0
  206. package/src/elements/media-pip-button.ts +66 -0
  207. package/src/elements/media-play-button.ts +69 -0
  208. package/src/elements/media-playback-rate-button.ts +59 -0
  209. package/src/elements/media-preview-time.ts +75 -0
  210. package/src/elements/media-progress-bar.ts +200 -0
  211. package/src/elements/media-remote-playback-button.ts +108 -0
  212. package/src/elements/media-seek-button.ts +50 -0
  213. package/src/elements/media-settings-menu.ts +302 -0
  214. package/src/elements/media-time-display.ts +99 -0
  215. package/src/elements/media-time-group.ts +41 -0
  216. package/src/elements/media-time-separator.ts +35 -0
  217. package/src/elements/media-volume-slider.ts +140 -0
  218. package/src/elements/utils.ts +82 -0
  219. package/src/elements/video-player.ts +175 -0
  220. package/src/elements/video-skin.ts +127 -0
  221. package/src/features/captions.ts +56 -0
  222. package/src/features/create-player.ts +91 -0
  223. package/src/features/fullscreen.ts +44 -0
  224. package/src/features/gestures.ts +44 -0
  225. package/src/features/index.ts +44 -0
  226. package/src/features/keyboard.ts +89 -0
  227. package/src/features/pip.ts +47 -0
  228. package/src/features/playback.ts +68 -0
  229. package/src/features/quality.ts +19 -0
  230. package/src/features/types.ts +28 -0
  231. package/src/features/volume.ts +46 -0
  232. package/src/index.ts +635 -0
  233. package/src/layouts/index.ts +672 -0
  234. package/src/player.ts +821 -0
  235. package/src/plugins/ads.ts +1045 -0
  236. package/src/plugins/analytics.ts +673 -0
  237. package/src/plugins/end-screen.ts +793 -0
  238. package/src/plugins/index.ts +61 -0
  239. package/src/plugins/skip-segments.ts +537 -0
  240. package/src/plugins/watermark.ts +537 -0
  241. package/src/providers/base.ts +197 -0
  242. package/src/providers/dash.ts +588 -0
  243. package/src/providers/hls.ts +624 -0
  244. package/src/providers/html5.ts +473 -0
  245. package/src/providers/index.ts +97 -0
  246. package/src/providers/vimeo.ts +533 -0
  247. package/src/providers/youtube.ts +542 -0
  248. package/src/stx/index.ts +606 -0
  249. package/src/types.ts +874 -0
  250. package/src/ui/components.ts +910 -0
  251. package/src/ui/index.ts +29 -0
@@ -0,0 +1,607 @@
1
+ /**
2
+ * CSS Variables / Theming System
3
+ *
4
+ * Provides a comprehensive theming system using CSS custom properties.
5
+ *
6
+ * @module core/themes
7
+ */
8
+
9
+ // =============================================================================
10
+ // Theme Types
11
+ // =============================================================================
12
+
13
+ export interface ThemeColors {
14
+ /** Primary brand color (default: #00a8ff) */
15
+ primary?: string
16
+ /** Secondary accent color */
17
+ secondary?: string
18
+ /** Background color */
19
+ background?: string
20
+ /** Text color */
21
+ text?: string
22
+ /** Text color on primary background */
23
+ textOnPrimary?: string
24
+ /** Border color */
25
+ border?: string
26
+ /** Focus ring color */
27
+ focus?: string
28
+ /** Error/danger color */
29
+ error?: string
30
+ /** Success color */
31
+ success?: string
32
+ /** Warning color */
33
+ warning?: string
34
+ }
35
+
36
+ export interface ThemeTypography {
37
+ /** Font family for UI elements */
38
+ fontFamily?: string
39
+ /** Base font size */
40
+ fontSize?: string
41
+ /** Small font size */
42
+ fontSizeSmall?: string
43
+ /** Large font size */
44
+ fontSizeLarge?: string
45
+ /** Font weight */
46
+ fontWeight?: string
47
+ /** Bold font weight */
48
+ fontWeightBold?: string
49
+ /** Line height */
50
+ lineHeight?: string
51
+ }
52
+
53
+ export interface ThemeSpacing {
54
+ /** Extra small spacing (4px) */
55
+ xs?: string
56
+ /** Small spacing (8px) */
57
+ sm?: string
58
+ /** Medium spacing (12px) */
59
+ md?: string
60
+ /** Large spacing (16px) */
61
+ lg?: string
62
+ /** Extra large spacing (24px) */
63
+ xl?: string
64
+ }
65
+
66
+ export interface ThemeBorderRadius {
67
+ /** Small border radius */
68
+ sm?: string
69
+ /** Medium border radius */
70
+ md?: string
71
+ /** Large border radius */
72
+ lg?: string
73
+ /** Full/round border radius */
74
+ full?: string
75
+ }
76
+
77
+ export interface ThemeShadows {
78
+ /** Small shadow */
79
+ sm?: string
80
+ /** Medium shadow */
81
+ md?: string
82
+ /** Large shadow */
83
+ lg?: string
84
+ }
85
+
86
+ export interface ThemeTransitions {
87
+ /** Fast transition duration */
88
+ fast?: string
89
+ /** Normal transition duration */
90
+ normal?: string
91
+ /** Slow transition duration */
92
+ slow?: string
93
+ /** Default easing function */
94
+ easing?: string
95
+ }
96
+
97
+ export interface ThemeSlider {
98
+ /** Slider track height */
99
+ trackHeight?: string
100
+ /** Slider thumb size */
101
+ thumbSize?: string
102
+ /** Slider track background */
103
+ trackBg?: string
104
+ /** Slider track fill background */
105
+ trackFillBg?: string
106
+ /** Slider buffered background */
107
+ bufferedBg?: string
108
+ /** Slider thumb background */
109
+ thumbBg?: string
110
+ /** Slider thumb border */
111
+ thumbBorder?: string
112
+ }
113
+
114
+ export interface ThemeControls {
115
+ /** Controls bar height */
116
+ height?: string
117
+ /** Controls background */
118
+ background?: string
119
+ /** Controls padding */
120
+ padding?: string
121
+ /** Button size */
122
+ buttonSize?: string
123
+ /** Icon size */
124
+ iconSize?: string
125
+ /** Tooltip background */
126
+ tooltipBg?: string
127
+ /** Tooltip text color */
128
+ tooltipText?: string
129
+ }
130
+
131
+ export interface ThemeMenu {
132
+ /** Menu background */
133
+ background?: string
134
+ /** Menu border radius */
135
+ borderRadius?: string
136
+ /** Menu shadow */
137
+ shadow?: string
138
+ /** Menu item height */
139
+ itemHeight?: string
140
+ /** Menu item hover background */
141
+ itemHoverBg?: string
142
+ /** Menu item active background */
143
+ itemActiveBg?: string
144
+ }
145
+
146
+ export interface ThemeCaptions {
147
+ /** Caption font family */
148
+ fontFamily?: string
149
+ /** Caption font size */
150
+ fontSize?: string
151
+ /** Caption text color */
152
+ textColor?: string
153
+ /** Caption background */
154
+ background?: string
155
+ /** Caption text shadow */
156
+ textShadow?: string
157
+ /** Caption border radius */
158
+ borderRadius?: string
159
+ /** Caption padding */
160
+ padding?: string
161
+ }
162
+
163
+ export interface ThemeThumbnails {
164
+ /** Thumbnail width */
165
+ width?: string
166
+ /** Thumbnail height */
167
+ height?: string
168
+ /** Thumbnail border radius */
169
+ borderRadius?: string
170
+ /** Thumbnail border */
171
+ border?: string
172
+ /** Thumbnail shadow */
173
+ shadow?: string
174
+ }
175
+
176
+ export interface ThemeLive {
177
+ /** Live indicator color */
178
+ indicatorColor?: string
179
+ /** Live indicator size */
180
+ indicatorSize?: string
181
+ /** Live badge background */
182
+ badgeBg?: string
183
+ /** Live badge text color */
184
+ badgeText?: string
185
+ }
186
+
187
+ export interface Theme {
188
+ colors?: ThemeColors
189
+ typography?: ThemeTypography
190
+ spacing?: ThemeSpacing
191
+ borderRadius?: ThemeBorderRadius
192
+ shadows?: ThemeShadows
193
+ transitions?: ThemeTransitions
194
+ slider?: ThemeSlider
195
+ controls?: ThemeControls
196
+ menu?: ThemeMenu
197
+ captions?: ThemeCaptions
198
+ thumbnails?: ThemeThumbnails
199
+ live?: ThemeLive
200
+ }
201
+
202
+ // =============================================================================
203
+ // Default Theme
204
+ // =============================================================================
205
+
206
+ export const defaultTheme: Required<Theme> = {
207
+ colors: {
208
+ primary: '#00a8ff',
209
+ secondary: '#6c5ce7',
210
+ background: 'rgba(0, 0, 0, 0.85)',
211
+ text: '#ffffff',
212
+ textOnPrimary: '#ffffff',
213
+ border: 'rgba(255, 255, 255, 0.1)',
214
+ focus: '#00a8ff',
215
+ error: '#ff4757',
216
+ success: '#2ed573',
217
+ warning: '#ffa502',
218
+ },
219
+ typography: {
220
+ fontFamily: '-apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif',
221
+ fontSize: '14px',
222
+ fontSizeSmall: '12px',
223
+ fontSizeLarge: '16px',
224
+ fontWeight: '400',
225
+ fontWeightBold: '600',
226
+ lineHeight: '1.5',
227
+ },
228
+ spacing: {
229
+ xs: '4px',
230
+ sm: '8px',
231
+ md: '12px',
232
+ lg: '16px',
233
+ xl: '24px',
234
+ },
235
+ borderRadius: {
236
+ sm: '4px',
237
+ md: '8px',
238
+ lg: '12px',
239
+ full: '9999px',
240
+ },
241
+ shadows: {
242
+ sm: '0 1px 2px rgba(0, 0, 0, 0.2)',
243
+ md: '0 4px 6px rgba(0, 0, 0, 0.3)',
244
+ lg: '0 10px 15px rgba(0, 0, 0, 0.4)',
245
+ },
246
+ transitions: {
247
+ fast: '100ms',
248
+ normal: '200ms',
249
+ slow: '300ms',
250
+ easing: 'cubic-bezier(0.4, 0, 0.2, 1)',
251
+ },
252
+ slider: {
253
+ trackHeight: '4px',
254
+ thumbSize: '14px',
255
+ trackBg: 'rgba(255, 255, 255, 0.2)',
256
+ trackFillBg: 'var(--tsvp-color-primary)',
257
+ bufferedBg: 'rgba(255, 255, 255, 0.4)',
258
+ thumbBg: '#ffffff',
259
+ thumbBorder: 'none',
260
+ },
261
+ controls: {
262
+ height: '48px',
263
+ background: 'linear-gradient(transparent, rgba(0, 0, 0, 0.7))',
264
+ padding: '0 12px',
265
+ buttonSize: '40px',
266
+ iconSize: '24px',
267
+ tooltipBg: 'rgba(0, 0, 0, 0.9)',
268
+ tooltipText: '#ffffff',
269
+ },
270
+ menu: {
271
+ background: 'rgba(20, 20, 20, 0.95)',
272
+ borderRadius: '8px',
273
+ shadow: '0 4px 20px rgba(0, 0, 0, 0.5)',
274
+ itemHeight: '40px',
275
+ itemHoverBg: 'rgba(255, 255, 255, 0.1)',
276
+ itemActiveBg: 'rgba(0, 168, 255, 0.2)',
277
+ },
278
+ captions: {
279
+ fontFamily: 'inherit',
280
+ fontSize: '1.5em',
281
+ textColor: '#ffffff',
282
+ background: 'rgba(0, 0, 0, 0.75)',
283
+ textShadow: '0 1px 2px rgba(0, 0, 0, 0.5)',
284
+ borderRadius: '4px',
285
+ padding: '4px 8px',
286
+ },
287
+ thumbnails: {
288
+ width: '160px',
289
+ height: '90px',
290
+ borderRadius: '4px',
291
+ border: '2px solid rgba(255, 255, 255, 0.2)',
292
+ shadow: '0 4px 12px rgba(0, 0, 0, 0.4)',
293
+ },
294
+ live: {
295
+ indicatorColor: '#ff0000',
296
+ indicatorSize: '8px',
297
+ badgeBg: '#ff0000',
298
+ badgeText: '#ffffff',
299
+ },
300
+ }
301
+
302
+ // =============================================================================
303
+ // Preset Themes
304
+ // =============================================================================
305
+
306
+ export const darkTheme: Theme = {
307
+ colors: {
308
+ primary: '#00a8ff',
309
+ background: 'rgba(0, 0, 0, 0.9)',
310
+ text: '#ffffff',
311
+ },
312
+ }
313
+
314
+ export const lightTheme: Theme = {
315
+ colors: {
316
+ primary: '#0070f3',
317
+ background: 'rgba(255, 255, 255, 0.95)',
318
+ text: '#1a1a1a',
319
+ textOnPrimary: '#ffffff',
320
+ border: 'rgba(0, 0, 0, 0.1)',
321
+ },
322
+ controls: {
323
+ background: 'linear-gradient(transparent, rgba(255, 255, 255, 0.9))',
324
+ tooltipBg: 'rgba(0, 0, 0, 0.8)',
325
+ },
326
+ menu: {
327
+ background: 'rgba(255, 255, 255, 0.98)',
328
+ shadow: '0 4px 20px rgba(0, 0, 0, 0.15)',
329
+ itemHoverBg: 'rgba(0, 0, 0, 0.05)',
330
+ itemActiveBg: 'rgba(0, 112, 243, 0.1)',
331
+ },
332
+ captions: {
333
+ background: 'rgba(255, 255, 255, 0.9)',
334
+ textColor: '#1a1a1a',
335
+ },
336
+ }
337
+
338
+ export const minimalTheme: Theme = {
339
+ colors: {
340
+ primary: '#ffffff',
341
+ background: 'transparent',
342
+ },
343
+ controls: {
344
+ height: '40px',
345
+ background: 'transparent',
346
+ },
347
+ slider: {
348
+ trackHeight: '2px',
349
+ thumbSize: '10px',
350
+ },
351
+ }
352
+
353
+ export const netflixTheme: Theme = {
354
+ colors: {
355
+ primary: '#e50914',
356
+ background: 'rgba(0, 0, 0, 0.85)',
357
+ },
358
+ slider: {
359
+ trackFillBg: '#e50914',
360
+ },
361
+ live: {
362
+ indicatorColor: '#e50914',
363
+ badgeBg: '#e50914',
364
+ },
365
+ }
366
+
367
+ export const youtubeTheme: Theme = {
368
+ colors: {
369
+ primary: '#ff0000',
370
+ background: 'rgba(0, 0, 0, 0.85)',
371
+ },
372
+ slider: {
373
+ trackHeight: '3px',
374
+ thumbSize: '13px',
375
+ trackFillBg: '#ff0000',
376
+ },
377
+ controls: {
378
+ height: '48px',
379
+ },
380
+ live: {
381
+ indicatorColor: '#ff0000',
382
+ badgeBg: '#ff0000',
383
+ },
384
+ }
385
+
386
+ export const vimeoTheme: Theme = {
387
+ colors: {
388
+ primary: '#00adef',
389
+ background: 'rgba(0, 0, 0, 0.85)',
390
+ },
391
+ slider: {
392
+ trackFillBg: '#00adef',
393
+ },
394
+ }
395
+
396
+ export const presetThemes: Record<string, Theme> = {
397
+ dark: darkTheme,
398
+ light: lightTheme,
399
+ minimal: minimalTheme,
400
+ netflix: netflixTheme,
401
+ youtube: youtubeTheme,
402
+ vimeo: vimeoTheme,
403
+ }
404
+
405
+ export type PresetThemeName = keyof typeof presetThemes
406
+
407
+ // =============================================================================
408
+ // Theme Utilities
409
+ // =============================================================================
410
+
411
+ /**
412
+ * Deep merge two theme objects
413
+ */
414
+ export function mergeThemes(base: Theme, override: Theme): Theme {
415
+ const result: Theme = { ...base }
416
+
417
+ for (const key of Object.keys(override) as (keyof Theme)[]) {
418
+ const baseValue = base[key]
419
+ const overrideValue = override[key]
420
+
421
+ if (overrideValue && typeof overrideValue === 'object') {
422
+ result[key] = {
423
+ ...(baseValue || {}),
424
+ ...overrideValue,
425
+ } as any
426
+ }
427
+ else if (overrideValue !== undefined) {
428
+ result[key] = overrideValue as any
429
+ }
430
+ }
431
+
432
+ return result
433
+ }
434
+
435
+ /**
436
+ * Generate CSS custom properties from a theme
437
+ */
438
+ export function generateThemeCSS(theme: Theme, prefix = 'tsvp'): string {
439
+ const merged = mergeThemes(defaultTheme, theme)
440
+ const vars: string[] = []
441
+
442
+ // Colors
443
+ if (merged.colors) {
444
+ vars.push(`--${prefix}-color-primary: ${merged.colors.primary};`)
445
+ vars.push(`--${prefix}-color-secondary: ${merged.colors.secondary};`)
446
+ vars.push(`--${prefix}-color-background: ${merged.colors.background};`)
447
+ vars.push(`--${prefix}-color-text: ${merged.colors.text};`)
448
+ vars.push(`--${prefix}-color-text-on-primary: ${merged.colors.textOnPrimary};`)
449
+ vars.push(`--${prefix}-color-border: ${merged.colors.border};`)
450
+ vars.push(`--${prefix}-color-focus: ${merged.colors.focus};`)
451
+ vars.push(`--${prefix}-color-error: ${merged.colors.error};`)
452
+ vars.push(`--${prefix}-color-success: ${merged.colors.success};`)
453
+ vars.push(`--${prefix}-color-warning: ${merged.colors.warning};`)
454
+ }
455
+
456
+ // Typography
457
+ if (merged.typography) {
458
+ vars.push(`--${prefix}-font-family: ${merged.typography.fontFamily};`)
459
+ vars.push(`--${prefix}-font-size: ${merged.typography.fontSize};`)
460
+ vars.push(`--${prefix}-font-size-sm: ${merged.typography.fontSizeSmall};`)
461
+ vars.push(`--${prefix}-font-size-lg: ${merged.typography.fontSizeLarge};`)
462
+ vars.push(`--${prefix}-font-weight: ${merged.typography.fontWeight};`)
463
+ vars.push(`--${prefix}-font-weight-bold: ${merged.typography.fontWeightBold};`)
464
+ vars.push(`--${prefix}-line-height: ${merged.typography.lineHeight};`)
465
+ }
466
+
467
+ // Spacing
468
+ if (merged.spacing) {
469
+ vars.push(`--${prefix}-spacing-xs: ${merged.spacing.xs};`)
470
+ vars.push(`--${prefix}-spacing-sm: ${merged.spacing.sm};`)
471
+ vars.push(`--${prefix}-spacing-md: ${merged.spacing.md};`)
472
+ vars.push(`--${prefix}-spacing-lg: ${merged.spacing.lg};`)
473
+ vars.push(`--${prefix}-spacing-xl: ${merged.spacing.xl};`)
474
+ }
475
+
476
+ // Border Radius
477
+ if (merged.borderRadius) {
478
+ vars.push(`--${prefix}-radius-sm: ${merged.borderRadius.sm};`)
479
+ vars.push(`--${prefix}-radius-md: ${merged.borderRadius.md};`)
480
+ vars.push(`--${prefix}-radius-lg: ${merged.borderRadius.lg};`)
481
+ vars.push(`--${prefix}-radius-full: ${merged.borderRadius.full};`)
482
+ }
483
+
484
+ // Shadows
485
+ if (merged.shadows) {
486
+ vars.push(`--${prefix}-shadow-sm: ${merged.shadows.sm};`)
487
+ vars.push(`--${prefix}-shadow-md: ${merged.shadows.md};`)
488
+ vars.push(`--${prefix}-shadow-lg: ${merged.shadows.lg};`)
489
+ }
490
+
491
+ // Transitions
492
+ if (merged.transitions) {
493
+ vars.push(`--${prefix}-transition-fast: ${merged.transitions.fast};`)
494
+ vars.push(`--${prefix}-transition-normal: ${merged.transitions.normal};`)
495
+ vars.push(`--${prefix}-transition-slow: ${merged.transitions.slow};`)
496
+ vars.push(`--${prefix}-transition-easing: ${merged.transitions.easing};`)
497
+ }
498
+
499
+ // Slider
500
+ if (merged.slider) {
501
+ vars.push(`--${prefix}-slider-track-height: ${merged.slider.trackHeight};`)
502
+ vars.push(`--${prefix}-slider-thumb-size: ${merged.slider.thumbSize};`)
503
+ vars.push(`--${prefix}-slider-track-bg: ${merged.slider.trackBg};`)
504
+ vars.push(`--${prefix}-slider-track-fill-bg: ${merged.slider.trackFillBg};`)
505
+ vars.push(`--${prefix}-slider-buffered-bg: ${merged.slider.bufferedBg};`)
506
+ vars.push(`--${prefix}-slider-thumb-bg: ${merged.slider.thumbBg};`)
507
+ vars.push(`--${prefix}-slider-thumb-border: ${merged.slider.thumbBorder};`)
508
+ }
509
+
510
+ // Controls
511
+ if (merged.controls) {
512
+ vars.push(`--${prefix}-controls-height: ${merged.controls.height};`)
513
+ vars.push(`--${prefix}-controls-bg: ${merged.controls.background};`)
514
+ vars.push(`--${prefix}-controls-padding: ${merged.controls.padding};`)
515
+ vars.push(`--${prefix}-controls-button-size: ${merged.controls.buttonSize};`)
516
+ vars.push(`--${prefix}-controls-icon-size: ${merged.controls.iconSize};`)
517
+ vars.push(`--${prefix}-controls-tooltip-bg: ${merged.controls.tooltipBg};`)
518
+ vars.push(`--${prefix}-controls-tooltip-text: ${merged.controls.tooltipText};`)
519
+ }
520
+
521
+ // Menu
522
+ if (merged.menu) {
523
+ vars.push(`--${prefix}-menu-bg: ${merged.menu.background};`)
524
+ vars.push(`--${prefix}-menu-radius: ${merged.menu.borderRadius};`)
525
+ vars.push(`--${prefix}-menu-shadow: ${merged.menu.shadow};`)
526
+ vars.push(`--${prefix}-menu-item-height: ${merged.menu.itemHeight};`)
527
+ vars.push(`--${prefix}-menu-item-hover-bg: ${merged.menu.itemHoverBg};`)
528
+ vars.push(`--${prefix}-menu-item-active-bg: ${merged.menu.itemActiveBg};`)
529
+ }
530
+
531
+ // Captions
532
+ if (merged.captions) {
533
+ vars.push(`--${prefix}-captions-font-family: ${merged.captions.fontFamily};`)
534
+ vars.push(`--${prefix}-captions-font-size: ${merged.captions.fontSize};`)
535
+ vars.push(`--${prefix}-captions-text-color: ${merged.captions.textColor};`)
536
+ vars.push(`--${prefix}-captions-bg: ${merged.captions.background};`)
537
+ vars.push(`--${prefix}-captions-text-shadow: ${merged.captions.textShadow};`)
538
+ vars.push(`--${prefix}-captions-radius: ${merged.captions.borderRadius};`)
539
+ vars.push(`--${prefix}-captions-padding: ${merged.captions.padding};`)
540
+ }
541
+
542
+ // Thumbnails
543
+ if (merged.thumbnails) {
544
+ vars.push(`--${prefix}-thumbnail-width: ${merged.thumbnails.width};`)
545
+ vars.push(`--${prefix}-thumbnail-height: ${merged.thumbnails.height};`)
546
+ vars.push(`--${prefix}-thumbnail-radius: ${merged.thumbnails.borderRadius};`)
547
+ vars.push(`--${prefix}-thumbnail-border: ${merged.thumbnails.border};`)
548
+ vars.push(`--${prefix}-thumbnail-shadow: ${merged.thumbnails.shadow};`)
549
+ }
550
+
551
+ // Live
552
+ if (merged.live) {
553
+ vars.push(`--${prefix}-live-indicator-color: ${merged.live.indicatorColor};`)
554
+ vars.push(`--${prefix}-live-indicator-size: ${merged.live.indicatorSize};`)
555
+ vars.push(`--${prefix}-live-badge-bg: ${merged.live.badgeBg};`)
556
+ vars.push(`--${prefix}-live-badge-text: ${merged.live.badgeText};`)
557
+ }
558
+
559
+ return vars.join('\n ')
560
+ }
561
+
562
+ /**
563
+ * Create a style element with theme CSS
564
+ */
565
+ export function createThemeStyleElement(theme: Theme, selector = '.tsvp-player'): HTMLStyleElement {
566
+ const style = document.createElement('style')
567
+ style.setAttribute('data-tsvp-theme', 'true')
568
+ style.textContent = `
569
+ ${selector} {
570
+ ${generateThemeCSS(theme)}
571
+ }
572
+ `
573
+ return style
574
+ }
575
+
576
+ /**
577
+ * Apply theme to a player element
578
+ */
579
+ export function applyTheme(element: HTMLElement, theme: Theme | PresetThemeName): void {
580
+ const themeObj = typeof theme === 'string' ? presetThemes[theme] : theme
581
+
582
+ // Remove existing inline theme
583
+ element.querySelectorAll('style[data-tsvp-theme]').forEach(el => el.remove())
584
+
585
+ // Apply new theme
586
+ const css = generateThemeCSS(themeObj)
587
+ element.style.cssText += css.split('\n').map(line => line.trim().replace(';', '')).join('; ')
588
+ }
589
+
590
+ /**
591
+ * Inject global theme styles
592
+ */
593
+ export function injectThemeStyles(theme: Theme | PresetThemeName = {}, selector = '.tsvp-player'): void {
594
+ const themeObj = typeof theme === 'string' ? presetThemes[theme] : theme
595
+
596
+ // Remove existing global theme
597
+ document.querySelectorAll('style[data-tsvp-theme-global]').forEach(el => el.remove())
598
+
599
+ const style = document.createElement('style')
600
+ style.setAttribute('data-tsvp-theme-global', 'true')
601
+ style.textContent = `
602
+ ${selector} {
603
+ ${generateThemeCSS(themeObj)}
604
+ }
605
+ `
606
+ document.head.appendChild(style)
607
+ }