react-helios 2.4.0 → 2.5.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.
package/README.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # react-helios
2
2
 
3
- Production-grade React video player with HLS streaming, adaptive quality selection, live stream support, subtitle tracks, VTT sprite sheet thumbnail preview, Picture-in-Picture, and full keyboard control.
3
+ Production-grade React video player with HLS streaming, audio mode, adaptive quality selection, live stream support, subtitle tracks, VTT sprite sheet thumbnail preview, Picture-in-Picture, and full keyboard control.
4
4
 
5
5
  ## Installation
6
6
 
@@ -24,8 +24,13 @@ export default function App() {
24
24
  return (
25
25
  <VideoPlayer
26
26
  src="https://example.com/video.mp4"
27
+ poster="https://example.com/poster.jpg"
27
28
  controls
28
- autoplay={false}
29
+ options={{
30
+ autoplay: false,
31
+ loop: false,
32
+ thumbnailVtt: "https://example.com/thumbs/storyboard.vtt",
33
+ }}
29
34
  />
30
35
  );
31
36
  }
@@ -41,12 +46,64 @@ Pass any `.m3u8` URL — HLS.js is initialised automatically:
41
46
  <VideoPlayer
42
47
  src="https://example.com/stream.m3u8"
43
48
  controls
44
- enableHLS // default: true
49
+ options={{
50
+ enableHLS: true, // default: true
51
+ hlsConfig: {
52
+ maxBufferLength: 60,
53
+ capLevelToPlayerSize: true,
54
+ },
55
+ }}
45
56
  />
46
57
  ```
47
58
 
48
59
  On Safari the browser's native HLS engine is used. A **LIVE** badge and **GO LIVE** button appear automatically for live streams.
49
60
 
61
+ ## Audio Mode
62
+
63
+ Audio mode hides the video, shows the poster artwork, and keeps the audio stream playing — useful when bandwidth is poor or the user wants to background the content.
64
+
65
+ ```tsx
66
+ <VideoPlayer
67
+ src="https://example.com/stream.m3u8"
68
+ poster="https://example.com/artwork.jpg"
69
+ controls
70
+ options={{
71
+ audioSrc: "https://example.com/audio-only.m3u8",
72
+ audioModeLabel: "Switch to Audio",
73
+ videoModeLabel: "Switch to Video",
74
+ defaultAudioMode: false,
75
+ onAudioModeChange: (isAudio) => console.log("audio mode:", isAudio),
76
+ }}
77
+ />
78
+ ```
79
+
80
+ The audio toggle button only appears in the control bar when `audioSrc` is provided. Custom icons can be passed via `audioModeIcon` / `videoModeIcon`.
81
+
82
+ ### Automatic bandwidth switching
83
+
84
+ For HLS streams the player monitors bandwidth and switches to audio mode automatically when conditions drop below a threshold:
85
+
86
+ ```tsx
87
+ import { AUDIO_BANDWIDTH_THRESHOLDS } from "react-helios";
88
+
89
+ <VideoPlayer
90
+ src="https://example.com/stream.m3u8"
91
+ options={{
92
+ audioBandwidthThreshold: AUDIO_BANDWIDTH_THRESHOLDS.POOR, // 300 Kbps (default)
93
+ // audioBandwidthThreshold: 0, // disable automatic switching
94
+ }}
95
+ />
96
+ ```
97
+
98
+ | Preset | Kbps | Typical connection |
99
+ |--------|------|--------------------|
100
+ | `EXTREME` | 100 | 2G / Edge |
101
+ | `POOR` | 300 | Slow 3G ← **default** |
102
+ | `FAIR` | 700 | 3G |
103
+ | `GOOD` | 1500 | 4G / Wi-Fi |
104
+
105
+ After the user manually toggles audio mode a 60-second cooldown suppresses automatic switching so the player respects their choice.
106
+
50
107
  ## Thumbnail Preview
51
108
 
52
109
  Hover over the progress bar to see a time tooltip. For rich sprite-sheet thumbnails, pass a `thumbnailVtt` URL pointing to a [WebVTT thumbnail file](https://developer.bitmovin.com/playback/docs/webvtt-based-thumbnails).
@@ -54,7 +111,9 @@ Hover over the progress bar to see a time tooltip. For rich sprite-sheet thumbna
54
111
  ```tsx
55
112
  <VideoPlayer
56
113
  src="https://example.com/video.mp4"
57
- thumbnailVtt="https://example.com/thumbs/storyboard.vtt"
114
+ options={{
115
+ thumbnailVtt: "https://example.com/thumbs/storyboard.vtt",
116
+ }}
58
117
  />
59
118
  ```
60
119
 
@@ -80,38 +139,88 @@ The player fetches the VTT file once, parses all cues, and uses CSS `background-
80
139
  To disable the preview entirely:
81
140
 
82
141
  ```tsx
83
- <VideoPlayer src="..." enablePreview={false} />
142
+ <VideoPlayer src="..." options={{ enablePreview: false }} />
84
143
  ```
85
144
 
86
145
  ## Props
87
146
 
147
+ ### Top-level props
148
+
88
149
  | Prop | Type | Default | Description |
89
150
  |------|------|---------|-------------|
90
151
  | `src` | `string` | — | Video URL (MP4, WebM, HLS `.m3u8`, …) |
91
- | `poster` | `string` | — | Poster image shown before playback |
152
+ | `poster` | `string` | — | Poster image shown before playback and in audio mode |
92
153
  | `controls` | `boolean` | `true` | Show the built-in control bar |
154
+ | `className` | `string` | — | CSS class on the player container |
155
+ | `options` | `VideoPlayerOptions` | `{}` | All configuration (see below) |
156
+
157
+ ### `options` — Playback
158
+
159
+ | Option | Type | Default | Description |
160
+ |--------|------|---------|-------------|
93
161
  | `autoplay` | `boolean` | `false` | Start playback on mount |
94
162
  | `muted` | `boolean` | `false` | Start muted |
95
163
  | `loop` | `boolean` | `false` | Loop the video |
96
164
  | `preload` | `"none" \| "metadata" \| "auto"` | `"metadata"` | Native `preload` attribute |
97
- | `playbackRates` | `PlaybackRate[]` | `[0.25, 0.5, 0.75, 1, 1.25, 1.5, 1.75, 2]` | Available speed options |
165
+ | `playbackRates` | `PlaybackRate[]` | `[0.25 2]` | Available speed options |
166
+ | `crossOrigin` | `"anonymous" \| "use-credentials"` | — | CORS attribute for the video element |
167
+ | `subtitles` | `SubtitleTrack[]` | — | Subtitle / caption tracks |
168
+
169
+ ### `options` — HLS
170
+
171
+ | Option | Type | Default | Description |
172
+ |--------|------|---------|-------------|
98
173
  | `enableHLS` | `boolean` | `true` | Enable HLS.js for `.m3u8` sources |
174
+ | `hlsConfig` | `Partial<HlsConfig>` | — | Override any [hls.js config](https://github.com/video-dev/hls.js/blob/master/docs/API.md#fine-tuning) option |
175
+
176
+ ### `options` — Preview
177
+
178
+ | Option | Type | Default | Description |
179
+ |--------|------|---------|-------------|
99
180
  | `enablePreview` | `boolean` | `true` | Show thumbnail / time tooltip on progress bar hover |
100
181
  | `thumbnailVtt` | `string` | — | URL to a WebVTT sprite sheet file for rich thumbnail preview |
101
- | `hlsConfig` | `Partial<HlsConfig>` | — | Override any [hls.js configuration](https://github.com/video-dev/hls.js/blob/master/docs/API.md#fine-tuning) option |
102
- | `subtitles` | `SubtitleTrack[]` | | Subtitle / caption tracks |
103
- | `crossOrigin` | `"anonymous" \| "use-credentials"` | — | CORS attribute for the video element |
104
- | `className` | `string` | | CSS class on the player container |
105
- | `onPlay` | `() => void` | — | Fired when playback starts |
106
- | `onPause` | `() => void` | | Fired when playback pauses |
107
- | `onEnded` | `() => void` | — | Fired when playback ends |
108
- | `onError` | `(error: VideoError) => void` | | Fired on playback or stream errors |
109
- | `onTimeUpdate` | `(time: number) => void` | — | Fired every ~250 ms during playback |
110
- | `onDurationChange` | `(duration: number) => void` | | Fired when video duration becomes known |
111
- | `onBuffering` | `(isBuffering: boolean) => void` | — | Fired when buffering starts / stops |
112
- | `onTheaterModeChange` | `(isTheater: boolean) => void` | — | Fired when theater mode is toggled |
113
- | `contextMenuItems` | `ContextMenuItem[]` | | Extra items appended to the right-click context menu |
114
- | `controlBarItems` | `ControlBarItem[]` | | Extra icon buttons appended to the right side of the control bar |
182
+
183
+ ### `options` — UI
184
+
185
+ | Option | Type | Default | Description |
186
+ |--------|------|---------|-------------|
187
+ | `autoHideControls` | `boolean` | `true` | Hide control bar on mouse leave when playing (video mode only) |
188
+
189
+ ### `options` — Audio mode
190
+
191
+ | Option | Type | Default | Description |
192
+ |--------|------|---------|-------------|
193
+ | `audioSrc` | `string` | — | Audio-only stream URL; the audio toggle button only shows when this is set |
194
+ | `showAudioButton` | `boolean` | `!!audioSrc` | Force-show or hide the audio toggle button |
195
+ | `defaultAudioMode` | `boolean` | `false` | Start in audio mode |
196
+ | `audioModeLabel` | `string` | `"Audio"` | Label on the toggle button when in video mode |
197
+ | `videoModeLabel` | `string` | `"Video"` | Label on the toggle button when in audio mode |
198
+ | `audioModeIcon` | `ReactNode` | built-in headphones icon | Icon shown when in video mode (click → audio) |
199
+ | `videoModeIcon` | `ReactNode` | built-in video icon | Icon shown when in audio mode (click → video) |
200
+ | `audioModeFallback` | `ReactNode` | — | Custom content shown in audio mode when no `poster` is provided |
201
+ | `logo` | `string \| ReactNode` | — | Logo shown in audio mode when no `poster` or `audioModeFallback` is provided |
202
+ | `audioBandwidthThreshold` | `number` | `300` | Kbps — auto-switch to audio mode below this bandwidth. `0` = disabled (HLS only) |
203
+
204
+ ### `options` — Callbacks
205
+
206
+ | Option | Type | Description |
207
+ |--------|------|-------------|
208
+ | `onPlay` | `() => void` | Fired when playback starts |
209
+ | `onPause` | `() => void` | Fired when playback pauses |
210
+ | `onEnded` | `() => void` | Fired when playback ends |
211
+ | `onError` | `(error: VideoError) => void` | Fired on playback or stream errors |
212
+ | `onTimeUpdate` | `(time: number) => void` | Fired every ~250 ms during playback |
213
+ | `onDurationChange` | `(duration: number) => void` | Fired when video duration becomes known |
214
+ | `onBuffering` | `(isBuffering: boolean) => void` | Fired when buffering starts / stops |
215
+ | `onTheaterModeChange` | `(isTheater: boolean) => void` | Fired when theater mode is toggled |
216
+ | `onAudioModeChange` | `(isAudio: boolean) => void` | Fired when audio mode is toggled (manual or automatic) |
217
+
218
+ ### `options` — Custom controls
219
+
220
+ | Option | Type | Description |
221
+ |--------|------|-------------|
222
+ | `contextMenuItems` | `ContextMenuItem[]` | Extra items appended to the right-click context menu |
223
+ | `controlBarItems` | `ControlBarItem[]` | Extra icon buttons appended to the right side of the control bar |
115
224
 
116
225
  ## Quality Selection
117
226
 
@@ -120,8 +229,6 @@ For HLS streams (`.m3u8`) the player automatically parses the available quality
120
229
  - **Speed tab** — always visible, lets you change playback rate.
121
230
  - **Quality tab** — appears only for HLS streams. Lists all levels sorted by bitrate (e.g. 1080p, 720p, 480p) plus an **Auto** option that enables ABR (adaptive bitrate). The current auto-selected level is shown in parentheses next to "Auto".
122
231
 
123
- For plain MP4/WebM files there are no quality levels to switch between, so the Quality tab never appears.
124
-
125
232
  You can also switch quality programmatically via the ref:
126
233
 
127
234
  ```tsx
@@ -131,49 +238,41 @@ playerRef.current?.setQualityLevel(-1); // back to ABR auto
131
238
 
132
239
  ## Custom Control Bar Buttons
133
240
 
134
- Inject your own icon buttons into the right side of the control bar (between the settings gear and the PiP/Theater/Fullscreen buttons) using `controlBarItems`:
241
+ Inject your own icon buttons into the right side of the control bar using `controlBarItems`:
135
242
 
136
243
  ```tsx
137
- import { VideoPlayer, ControlBarItem } from "react-helios";
244
+ import { VideoPlayer } from "react-helios";
245
+ import type { ControlBarItem } from "react-helios";
138
246
 
139
247
  const items: ControlBarItem[] = [
140
248
  {
141
- key: "download",
142
- label: "Download",
143
- icon: <svg width="20" height="20" viewBox="0 0 24 24" fill="currentColor"><path d="M19 9h-4V3H9v6H5l7 7 7-7zm-8 2V5h2v6h1.17L12 13.17 9.83 11H11zm-6 7h14v2H5v-2z"/></svg>,
144
- onClick: () => downloadVideo(),
145
- },
146
- {
147
- key: "share",
148
- label: "Share",
149
- title: "Share this video",
150
- icon: <svg width="20" height="20" viewBox="0 0 24 24" fill="currentColor"><path d="M18 16.08c-.76 0-1.44.3-1.96.77L8.91 12.7c.05-.23.09-.46.09-.7s-.04-.47-.09-.7l7.05-4.11A2.99 2.99 0 0 0 18 8a3 3 0 1 0-3-3c0 .24.04.47.09.7L8.04 9.81A2.99 2.99 0 0 0 6 9a3 3 0 1 0 3 3c0-.24-.04-.47-.09-.7l7.05-4.11c.52.47 1.2.77 1.96.77a3 3 0 0 0 3-3 3 3 0 0 0-3-3z"/></svg>,
151
- onClick: () => openShareDialog(),
249
+ key: "bookmark",
250
+ label: "Bookmark",
251
+ title: "Save current position",
252
+ icon: <BookmarkIcon />,
253
+ onClick: () => saveBookmark(playerRef.current?.getState().currentTime ?? 0),
152
254
  },
153
255
  ];
154
256
 
155
- <VideoPlayer src="..." controlBarItems={items} />
257
+ <VideoPlayer src="..." options={{ controlBarItems: items }} />
156
258
  ```
157
259
 
158
- Buttons receive the same `controlButton` CSS class as built-in buttons (hover highlight, active press scale, no focus outline).
159
-
160
260
  ## Context Menu
161
261
 
162
- Right-clicking the player shows a built-in menu (Play/Pause, Loop, Copy URL, Picture-in-Picture). You can append your own items by passing `contextMenuItems`:
262
+ Right-clicking the player shows a built-in menu (Play/Pause, Loop, Copy URL, Picture-in-Picture). Append your own items via `contextMenuItems`:
163
263
 
164
264
  ```tsx
165
- import { VideoPlayer, ContextMenuItem } from "react-helios";
265
+ import { VideoPlayer } from "react-helios";
266
+ import type { ContextMenuItem } from "react-helios";
166
267
 
167
268
  const items: ContextMenuItem[] = [
168
269
  { label: "Add to Watchlist", onClick: () => addToWatchlist() },
169
270
  { label: "Share", onClick: () => openShareDialog() },
170
271
  ];
171
272
 
172
- <VideoPlayer src="..." contextMenuItems={items} />
273
+ <VideoPlayer src="..." options={{ contextMenuItems: items }} />
173
274
  ```
174
275
 
175
- Each item closes the menu automatically after its `onClick` is called.
176
-
177
276
  ## Imperative API (Ref)
178
277
 
179
278
  Use a `ref` to control the player programmatically:
@@ -192,7 +291,7 @@ export default function App() {
192
291
  <button onClick={() => playerRef.current?.pause()}>Pause</button>
193
292
  <button onClick={() => playerRef.current?.seek(30)}>Jump to 30s</button>
194
293
  <button onClick={() => playerRef.current?.setVolume(0.5)}>50% volume</button>
195
- <button onClick={() => playerRef.current?.setPlaybackRate(1.5)}>1.5× speed</button>
294
+ <button onClick={() => playerRef.current?.toggleAudioMode()}>Toggle Audio</button>
196
295
  </>
197
296
  );
198
297
  }
@@ -213,12 +312,13 @@ export default function App() {
213
312
  | `toggleFullscreen` | `() => Promise<void>` | Toggle fullscreen |
214
313
  | `togglePictureInPicture` | `() => Promise<void>` | Toggle Picture-in-Picture |
215
314
  | `toggleTheaterMode` | `() => void` | Toggle theater (wide) mode |
315
+ | `toggleAudioMode` | `() => void` | Toggle audio-only mode |
216
316
  | `getState` | `() => PlayerState` | Snapshot of current player state |
217
317
  | `getVideoElement` | `() => HTMLVideoElement \| null` | Access the underlying `<video>` element |
218
318
 
219
319
  ## Theater Mode
220
320
 
221
- The player fires `onTheaterModeChange` when theater mode is toggled (via the `T` key, the control bar button, or `playerRef.current?.toggleTheaterMode()`). Wire it to your layout state to widen your container:
321
+ The player fires `onTheaterModeChange` when theater mode is toggled. Wire it to your layout state to widen your container:
222
322
 
223
323
  ```tsx
224
324
  "use client";
@@ -237,24 +337,26 @@ export default function Page() {
237
337
  <VideoPlayer
238
338
  src="https://example.com/stream.m3u8"
239
339
  controls
240
- onTheaterModeChange={(t) => setIsTheater(t)}
340
+ options={{
341
+ onTheaterModeChange: (t) => setIsTheater(t),
342
+ }}
241
343
  />
242
344
  </main>
243
345
  );
244
346
  }
245
347
  ```
246
348
 
247
- The player itself does not manage your page layout — it only notifies you so you can adapt your design.
248
-
249
349
  ## Subtitles
250
350
 
251
351
  ```tsx
252
352
  <VideoPlayer
253
353
  src="https://example.com/video.mp4"
254
- subtitles={[
255
- { id: "en", src: "/subs/en.vtt", label: "English", srclang: "en", default: true },
256
- { id: "es", src: "/subs/es.vtt", label: "Español", srclang: "es" },
257
- ]}
354
+ options={{
355
+ subtitles: [
356
+ { id: "en", src: "/subs/en.vtt", label: "English", srclang: "en", default: true },
357
+ { id: "es", src: "/subs/es.vtt", label: "Español", srclang: "es" },
358
+ ],
359
+ }}
258
360
  />
259
361
  ```
260
362
 
@@ -292,6 +394,7 @@ All types are exported from the package:
292
394
  ```ts
293
395
  import type {
294
396
  VideoPlayerProps,
397
+ VideoPlayerOptions,
295
398
  VideoPlayerRef,
296
399
  PlayerState,
297
400
  PlaybackRate,
@@ -300,13 +403,15 @@ import type {
300
403
  BufferedRange,
301
404
  VideoError,
302
405
  VideoErrorCode,
303
- ThumbnailCue,
304
406
  ContextMenuItem,
305
407
  ControlBarItem,
306
408
  } from "react-helios";
307
409
 
410
+ import { AUDIO_BANDWIDTH_THRESHOLDS } from "react-helios";
411
+
308
412
  // VTT utilities (useful for server-side pre-parsing or custom UIs)
309
413
  import { parseThumbnailVtt, findThumbnailCue } from "react-helios";
414
+ import type { ThumbnailCue } from "react-helios";
310
415
  ```
311
416
 
312
417
  ### `PlayerState`
@@ -325,6 +430,7 @@ interface PlayerState {
325
430
  isFullscreen: boolean;
326
431
  isPictureInPicture: boolean;
327
432
  isTheaterMode: boolean;
433
+ isAudioMode: boolean;
328
434
  isLive: boolean;
329
435
  qualityLevels: HLSQualityLevel[];
330
436
  currentQualityLevel: number; // -1 = ABR auto
@@ -349,20 +455,6 @@ interface VideoError {
349
455
  }
350
456
  ```
351
457
 
352
- ### `ThumbnailCue`
353
-
354
- ```ts
355
- interface ThumbnailCue {
356
- start: number; // seconds
357
- end: number; // seconds
358
- url: string; // absolute URL to the sprite image
359
- x: number; // pixel offset within sprite
360
- y: number;
361
- w: number; // cell width in pixels
362
- h: number; // cell height in pixels
363
- }
364
- ```
365
-
366
458
  ### `ControlBarItem`
367
459
 
368
460
  ```ts
@@ -384,9 +476,21 @@ interface ContextMenuItem {
384
476
  }
385
477
  ```
386
478
 
387
- ## Utility Functions
479
+ ### `ThumbnailCue`
480
+
481
+ ```ts
482
+ interface ThumbnailCue {
483
+ start: number; // seconds
484
+ end: number; // seconds
485
+ url: string; // absolute URL to the sprite image
486
+ x: number; // pixel offset within sprite
487
+ y: number;
488
+ w: number; // cell width in pixels
489
+ h: number; // cell height in pixels
490
+ }
491
+ ```
388
492
 
389
- The package exports a few helper utilities used internally, exposed for custom integrations:
493
+ ## Utility Functions
390
494
 
391
495
  ```ts
392
496
  import { formatTime, isHLSUrl, getMimeType } from "react-helios";
@@ -422,15 +526,17 @@ The player is architected to produce **zero React re-renders during playback**:
422
526
 
423
527
  - `timeupdate` and `progress` events are handled by direct DOM mutation (refs), not React state.
424
528
  - `ProgressBar` and `TimeDisplay` self-subscribe to the video element — the parent tree never re-renders on seek or time change.
529
+ - `Controls` and `AudioModeOverlay` are wrapped in `React.memo` — they only re-render when their own props change, not when unrelated state (buffering, errors) updates.
425
530
  - VTT sprite thumbnails are looked up via binary search (O(log n)) and rendered via CSS `background-position` — no hidden `<video>` element, no canvas, no network requests per hover.
426
531
  - Buffered ranges are the only state that triggers a re-render (fires every few seconds during buffering, not 60× per second).
532
+ - In audio mode the `<video>` element stays mounted with `visibility: hidden` — audio keeps playing without any re-initialisation cost on toggle.
427
533
 
428
534
  ## Project Structure
429
535
 
430
536
  ```
431
537
  react-helios/
432
538
  ├── src/ # Library source
433
- │ ├── components/ # VideoPlayer, Controls, control elements
539
+ │ ├── components/ # VideoPlayer, Controls, AudioModeOverlay, control elements
434
540
  │ ├── hooks/ # useVideoPlayer (state + HLS init)
435
541
  │ ├── lib/ # Types, HLS utilities, VTT parser, format helpers
436
542
  │ └── styles/ # CSS
package/dist/index.d.mts CHANGED
@@ -101,39 +101,36 @@ interface ControlBarItem {
101
101
  title?: string;
102
102
  onClick: () => void;
103
103
  }
104
- interface VideoPlayerProps {
105
- src: string;
106
- poster?: string;
104
+ interface VideoPlayerOptions {
107
105
  autoplay?: boolean;
108
106
  muted?: boolean;
109
107
  loop?: boolean;
110
- controls?: boolean;
111
108
  preload?: "none" | "metadata" | "auto";
112
109
  playbackRates?: PlaybackRate[];
113
- className?: string;
114
110
  enableHLS?: boolean;
111
+ hlsConfig?: Partial<HlsConfig>;
115
112
  enablePreview?: boolean;
116
- /**
117
- * URL to a WebVTT thumbnail track for sprite-sheet preview on the progress bar.
118
- *
119
- * The VTT file should map time ranges to sprite-sheet coordinates using the
120
- * standard `#xywh=x,y,w,h` fragment format:
121
- *
122
- * ```
123
- * WEBVTT
124
- *
125
- * 00:00:00.000 --> 00:00:05.000
126
- * https://cdn.example.com/thumbs/storyboard0.jpg#xywh=0,0,160,90
127
- * ```
128
- *
129
- * When provided, hovering the progress bar shows a thumbnail instead of
130
- * requiring a second video decode. If omitted, only the timestamp tooltip
131
- * is shown.
132
- */
133
113
  thumbnailVtt?: string;
134
- hlsConfig?: Partial<HlsConfig>;
114
+ autoHideControls?: boolean;
135
115
  subtitles?: SubtitleTrack[];
136
116
  crossOrigin?: "anonymous" | "use-credentials";
117
+ logo?: string | ReactNode;
118
+ audioSrc?: string;
119
+ showAudioButton?: boolean;
120
+ audioModeIcon?: ReactNode;
121
+ videoModeIcon?: ReactNode;
122
+ /**
123
+ * Custom content shown in audio mode when no `poster` is provided.
124
+ * Replaces the default animated-gradient + waveform fallback entirely.
125
+ * The `logo` prop is still rendered on top of this if also provided.
126
+ */
127
+ audioModeFallback?: ReactNode;
128
+ /** Label shown next to the icon when in video mode (click → switches to audio). Default: "Audio" */
129
+ audioModeLabel?: string;
130
+ /** Label shown next to the icon when in audio mode (click → switches to video). Default: "Video" */
131
+ videoModeLabel?: string;
132
+ defaultAudioMode?: boolean;
133
+ audioBandwidthThreshold?: number;
137
134
  onPlay?: () => void;
138
135
  onPause?: () => void;
139
136
  onEnded?: () => void;
@@ -142,37 +139,17 @@ interface VideoPlayerProps {
142
139
  onDurationChange?: (duration: number) => void;
143
140
  onBuffering?: (isBuffering: boolean) => void;
144
141
  onTheaterModeChange?: (isTheater: boolean) => void;
145
- /**
146
- * Image URL or ReactNode shown as artwork in audio mode.
147
- * Priority: `poster` prop → `logo` string/ReactNode → waveform-only.
148
- * If a string URL is provided the image is rendered white-normalised (filter invert)
149
- * so it stands out on the dark background.
150
- */
151
- logo?: string | ReactNode;
152
- /**
153
- * Show the headphones / audio-mode toggle button in the control bar.
154
- * @default true
155
- */
156
- showAudioButton?: boolean;
157
- /**
158
- * Start the player in audio-only mode on mount.
159
- * @default false
160
- */
161
- defaultAudioMode?: boolean;
162
- /**
163
- * Bandwidth threshold in **Kbps**. When the measured download speed falls below
164
- * this value the player automatically switches to audio mode.
165
- * Use the exported `AUDIO_BANDWIDTH_THRESHOLDS` presets for convenience.
166
- * Set to `0` to disable automatic switching.
167
- * Only applies to HLS streams (where hls.js measures real segment bandwidth).
168
- * @default 300 (AUDIO_BANDWIDTH_THRESHOLDS.POOR)
169
- */
170
- audioBandwidthThreshold?: number;
171
- /** Fired whenever audio mode is toggled — either automatically or by the user. */
172
142
  onAudioModeChange?: (isAudio: boolean) => void;
173
143
  contextMenuItems?: ContextMenuItem[];
174
144
  controlBarItems?: ControlBarItem[];
175
145
  }
146
+ interface VideoPlayerProps {
147
+ src: string;
148
+ poster?: string;
149
+ className?: string;
150
+ controls?: boolean;
151
+ options?: VideoPlayerOptions;
152
+ }
176
153
 
177
154
  declare const VideoPlayer: react__default.ForwardRefExoticComponent<VideoPlayerProps & react__default.RefAttributes<VideoPlayerRef>>;
178
155
 
@@ -192,12 +169,17 @@ interface ControlsProps {
192
169
  isTheaterMode: boolean;
193
170
  isAudioMode: boolean;
194
171
  showAudioButton: boolean;
172
+ audioModeIcon?: ReactNode;
173
+ videoModeIcon?: ReactNode;
174
+ audioModeLabel?: string;
175
+ videoModeLabel?: string;
195
176
  isLive: boolean;
196
177
  qualityLevels: HLSQualityLevel[];
197
178
  currentQualityLevel: number;
198
179
  controlBarItems?: ControlBarItem[];
180
+ autoHideControls: boolean;
199
181
  }
200
- declare const Controls: react__default.FC<ControlsProps>;
182
+ declare const Controls: react__default.NamedExoticComponent<ControlsProps>;
201
183
 
202
184
  interface TimeDisplayProps {
203
185
  videoRef: React.RefObject<HTMLVideoElement | null>;
@@ -339,4 +321,4 @@ declare function parseThumbnailVtt(text: string, baseUrl?: string): ThumbnailCue
339
321
  */
340
322
  declare function findThumbnailCue(cues: ThumbnailCue[], time: number): ThumbnailCue | null;
341
323
 
342
- export { AUDIO_BANDWIDTH_THRESHOLDS, type BufferedRange, type ContextMenuItem, type ControlBarItem, index as ControlElements, Controls, type HLSQualityLevel, type PlaybackRate, type PlayerState, type SubtitleTrack, type ThumbnailCue, type VideoError, type VideoErrorCode, VideoPlayer, type VideoPlayerProps, type VideoPlayerRef, findThumbnailCue, formatTime, getMimeType, isHLSUrl, parseThumbnailVtt };
324
+ export { AUDIO_BANDWIDTH_THRESHOLDS, type BufferedRange, type ContextMenuItem, type ControlBarItem, index as ControlElements, Controls, type HLSQualityLevel, type PlaybackRate, type PlayerState, type SubtitleTrack, type ThumbnailCue, type VideoError, type VideoErrorCode, VideoPlayer, type VideoPlayerOptions, type VideoPlayerProps, type VideoPlayerRef, findThumbnailCue, formatTime, getMimeType, isHLSUrl, parseThumbnailVtt };