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,354 @@
1
+ /**
2
+ * Error Overlay
3
+ *
4
+ * Visual error display with retry functionality.
5
+ *
6
+ * @module core/error-overlay
7
+ */
8
+
9
+ import type { MediaError } from '../types'
10
+
11
+ // =============================================================================
12
+ // Types
13
+ // =============================================================================
14
+
15
+ export interface ErrorOverlayConfig {
16
+ /** Show retry button */
17
+ showRetry?: boolean
18
+ /** Retry button text */
19
+ retryText?: string
20
+ /** Custom error messages by code */
21
+ messages?: Record<number, string>
22
+ /** Show error details (for debugging) */
23
+ showDetails?: boolean
24
+ /** Auto-hide delay (0 = no auto-hide) */
25
+ autoHideDelay?: number
26
+ /** Custom icon SVG */
27
+ icon?: string
28
+ }
29
+
30
+ // =============================================================================
31
+ // Default Error Messages
32
+ // =============================================================================
33
+
34
+ const defaultErrorMessages: Record<number, string> = {
35
+ 1: 'The media playback was aborted.',
36
+ 2: 'A network error occurred while loading the media.',
37
+ 3: 'The media could not be decoded.',
38
+ 4: 'The media format is not supported.',
39
+ }
40
+
41
+ // =============================================================================
42
+ // Error Overlay Component
43
+ // =============================================================================
44
+
45
+ export class ErrorOverlay {
46
+ private container: HTMLElement
47
+ private config: Required<ErrorOverlayConfig>
48
+ private currentError: MediaError | null = null
49
+ private onRetry: (() => void) | null = null
50
+ private autoHideTimeout: ReturnType<typeof setTimeout> | null = null
51
+
52
+ constructor(config: ErrorOverlayConfig = {}) {
53
+ this.config = {
54
+ showRetry: config.showRetry ?? true,
55
+ retryText: config.retryText || 'Try Again',
56
+ messages: { ...defaultErrorMessages, ...config.messages },
57
+ showDetails: config.showDetails ?? false,
58
+ autoHideDelay: config.autoHideDelay ?? 0,
59
+ icon: config.icon || this.getDefaultIcon(),
60
+ }
61
+
62
+ this.container = document.createElement('div')
63
+ this.container.className = 'tsvp-error-overlay'
64
+ this.container.setAttribute('role', 'alert')
65
+ this.container.setAttribute('aria-live', 'assertive')
66
+
67
+ this.applyStyles()
68
+ this.hide()
69
+ }
70
+
71
+ private applyStyles(): void {
72
+ this.container.style.cssText = `
73
+ position: absolute;
74
+ inset: 0;
75
+ display: flex;
76
+ flex-direction: column;
77
+ align-items: center;
78
+ justify-content: center;
79
+ gap: 16px;
80
+ background: rgba(0, 0, 0, 0.85);
81
+ color: var(--tsvp-color-text, #ffffff);
82
+ font-family: var(--tsvp-font-family, sans-serif);
83
+ z-index: 20;
84
+ padding: 24px;
85
+ text-align: center;
86
+ `
87
+ }
88
+
89
+ private getDefaultIcon(): string {
90
+ return `
91
+ <svg viewBox="0 0 24 24" width="48" height="48" fill="currentColor">
92
+ <path d="M12 2C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2zm1 15h-2v-2h2v2zm0-4h-2V7h2v6z"/>
93
+ </svg>
94
+ `
95
+ }
96
+
97
+ /**
98
+ * Get error message
99
+ */
100
+ private getMessage(error: MediaError): string {
101
+ return this.config.messages[error.code] || error.message || 'An error occurred.'
102
+ }
103
+
104
+ /**
105
+ * Render error content
106
+ */
107
+ private render(): void {
108
+ if (!this.currentError) return
109
+
110
+ this.container.innerHTML = ''
111
+
112
+ // Icon
113
+ const icon = document.createElement('div')
114
+ icon.className = 'tsvp-error-icon'
115
+ icon.innerHTML = this.config.icon
116
+ icon.style.cssText = `
117
+ color: var(--tsvp-color-error, #ff4757);
118
+ opacity: 0.9;
119
+ `
120
+ this.container.appendChild(icon)
121
+
122
+ // Title
123
+ const title = document.createElement('h3')
124
+ title.className = 'tsvp-error-title'
125
+ title.textContent = 'Playback Error'
126
+ title.style.cssText = `
127
+ margin: 0;
128
+ font-size: var(--tsvp-font-size-lg, 18px);
129
+ font-weight: var(--tsvp-font-weight-bold, 600);
130
+ `
131
+ this.container.appendChild(title)
132
+
133
+ // Message
134
+ const message = document.createElement('p')
135
+ message.className = 'tsvp-error-message'
136
+ message.textContent = this.getMessage(this.currentError)
137
+ message.style.cssText = `
138
+ margin: 0;
139
+ font-size: var(--tsvp-font-size, 14px);
140
+ opacity: 0.8;
141
+ max-width: 400px;
142
+ `
143
+ this.container.appendChild(message)
144
+
145
+ // Details (optional)
146
+ if (this.config.showDetails && this.currentError.details) {
147
+ const details = document.createElement('pre')
148
+ details.className = 'tsvp-error-details'
149
+ details.textContent = typeof this.currentError.details === 'string'
150
+ ? this.currentError.details
151
+ : JSON.stringify(this.currentError.details, null, 2)
152
+ details.style.cssText = `
153
+ margin: 8px 0 0;
154
+ padding: 8px 12px;
155
+ background: rgba(0, 0, 0, 0.3);
156
+ border-radius: var(--tsvp-radius-sm, 4px);
157
+ font-size: 11px;
158
+ font-family: monospace;
159
+ text-align: left;
160
+ max-width: 100%;
161
+ overflow-x: auto;
162
+ opacity: 0.7;
163
+ `
164
+ this.container.appendChild(details)
165
+ }
166
+
167
+ // Retry button
168
+ if (this.config.showRetry) {
169
+ const retryBtn = document.createElement('button')
170
+ retryBtn.className = 'tsvp-error-retry'
171
+ retryBtn.type = 'button'
172
+ retryBtn.textContent = this.config.retryText
173
+
174
+ retryBtn.style.cssText = `
175
+ margin-top: 8px;
176
+ padding: 10px 24px;
177
+ border: none;
178
+ border-radius: var(--tsvp-radius-full, 9999px);
179
+ background: var(--tsvp-color-primary, #00a8ff);
180
+ color: var(--tsvp-color-text-on-primary, #ffffff);
181
+ font-size: var(--tsvp-font-size, 14px);
182
+ font-weight: var(--tsvp-font-weight-bold, 600);
183
+ font-family: var(--tsvp-font-family, sans-serif);
184
+ cursor: pointer;
185
+ transition: transform 150ms ease, background 150ms ease;
186
+ `
187
+
188
+ retryBtn.addEventListener('mouseenter', () => {
189
+ retryBtn.style.transform = 'scale(1.05)'
190
+ })
191
+
192
+ retryBtn.addEventListener('mouseleave', () => {
193
+ retryBtn.style.transform = 'scale(1)'
194
+ })
195
+
196
+ retryBtn.addEventListener('click', () => {
197
+ if (this.onRetry) {
198
+ this.onRetry()
199
+ }
200
+ this.hide()
201
+ })
202
+
203
+ this.container.appendChild(retryBtn)
204
+ }
205
+
206
+ // Dismiss on background click
207
+ this.container.addEventListener('click', (e) => {
208
+ if (e.target === this.container) {
209
+ this.hide()
210
+ }
211
+ })
212
+ }
213
+
214
+ /**
215
+ * Show error
216
+ */
217
+ show(error: MediaError): void {
218
+ this.currentError = error
219
+ this.render()
220
+ this.container.style.display = 'flex'
221
+
222
+ // Fade in
223
+ this.container.style.opacity = '0'
224
+ requestAnimationFrame(() => {
225
+ this.container.style.transition = 'opacity 200ms ease'
226
+ this.container.style.opacity = '1'
227
+ })
228
+
229
+ // Auto-hide if configured
230
+ if (this.config.autoHideDelay > 0) {
231
+ if (this.autoHideTimeout) {
232
+ clearTimeout(this.autoHideTimeout)
233
+ }
234
+ this.autoHideTimeout = setTimeout(() => {
235
+ this.hide()
236
+ }, this.config.autoHideDelay)
237
+ }
238
+ }
239
+
240
+ /**
241
+ * Hide error overlay
242
+ */
243
+ hide(): void {
244
+ if (this.autoHideTimeout) {
245
+ clearTimeout(this.autoHideTimeout)
246
+ this.autoHideTimeout = null
247
+ }
248
+
249
+ this.container.style.opacity = '0'
250
+ setTimeout(() => {
251
+ this.container.style.display = 'none'
252
+ this.currentError = null
253
+ }, 200)
254
+ }
255
+
256
+ /**
257
+ * Set retry handler
258
+ */
259
+ setRetryHandler(handler: () => void): void {
260
+ this.onRetry = handler
261
+ }
262
+
263
+ /**
264
+ * Get element
265
+ */
266
+ getElement(): HTMLElement {
267
+ return this.container
268
+ }
269
+
270
+ /**
271
+ * Check if visible
272
+ */
273
+ isVisible(): boolean {
274
+ return this.container.style.display !== 'none'
275
+ }
276
+
277
+ /**
278
+ * Get current error
279
+ */
280
+ getError(): MediaError | null {
281
+ return this.currentError
282
+ }
283
+
284
+ /**
285
+ * Destroy
286
+ */
287
+ destroy(): void {
288
+ if (this.autoHideTimeout) {
289
+ clearTimeout(this.autoHideTimeout)
290
+ }
291
+ this.container.remove()
292
+ }
293
+ }
294
+
295
+ // =============================================================================
296
+ // Factory
297
+ // =============================================================================
298
+
299
+ export function createErrorOverlay(config?: ErrorOverlayConfig): ErrorOverlay {
300
+ return new ErrorOverlay(config)
301
+ }
302
+
303
+ // =============================================================================
304
+ // CSS Styles
305
+ // =============================================================================
306
+
307
+ export const ERROR_OVERLAY_STYLES = `
308
+ .tsvp-error-overlay {
309
+ position: absolute;
310
+ inset: 0;
311
+ display: flex;
312
+ flex-direction: column;
313
+ align-items: center;
314
+ justify-content: center;
315
+ gap: 16px;
316
+ background: rgba(0, 0, 0, 0.85);
317
+ color: var(--tsvp-color-text, #ffffff);
318
+ font-family: var(--tsvp-font-family, sans-serif);
319
+ z-index: 20;
320
+ padding: 24px;
321
+ text-align: center;
322
+ }
323
+
324
+ .tsvp-error-icon {
325
+ color: var(--tsvp-color-error, #ff4757);
326
+ }
327
+
328
+ .tsvp-error-title {
329
+ margin: 0;
330
+ font-size: var(--tsvp-font-size-lg, 18px);
331
+ font-weight: var(--tsvp-font-weight-bold, 600);
332
+ }
333
+
334
+ .tsvp-error-message {
335
+ margin: 0;
336
+ opacity: 0.8;
337
+ max-width: 400px;
338
+ }
339
+
340
+ .tsvp-error-retry {
341
+ padding: 10px 24px;
342
+ border: none;
343
+ border-radius: var(--tsvp-radius-full, 9999px);
344
+ background: var(--tsvp-color-primary, #00a8ff);
345
+ color: var(--tsvp-color-text-on-primary, #ffffff);
346
+ font-weight: var(--tsvp-font-weight-bold, 600);
347
+ cursor: pointer;
348
+ transition: transform 150ms ease;
349
+ }
350
+
351
+ .tsvp-error-retry:hover {
352
+ transform: scale(1.05);
353
+ }
354
+ `