@livepeer-frameworks/player-react 0.1.0 → 0.1.2
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 +7 -9
- package/dist/cjs/_virtual/_rollupPluginBabelHelpers.js +359 -0
- package/dist/cjs/_virtual/_rollupPluginBabelHelpers.js.map +1 -0
- package/dist/cjs/assets/logomark.svg.js +8 -0
- package/dist/cjs/assets/logomark.svg.js.map +1 -0
- package/dist/cjs/components/DevModePanel.js +826 -0
- package/dist/cjs/components/DevModePanel.js.map +1 -0
- package/dist/cjs/components/DvdLogo.js +200 -0
- package/dist/cjs/components/DvdLogo.js.map +1 -0
- package/dist/cjs/components/Icons.js +439 -0
- package/dist/cjs/components/Icons.js.map +1 -0
- package/dist/cjs/components/IdleScreen.js +587 -0
- package/dist/cjs/components/IdleScreen.js.map +1 -0
- package/dist/cjs/components/LoadingScreen.js +523 -0
- package/dist/cjs/components/LoadingScreen.js.map +1 -0
- package/dist/cjs/components/Player.js +420 -0
- package/dist/cjs/components/Player.js.map +1 -0
- package/dist/cjs/components/PlayerControls.js +798 -0
- package/dist/cjs/components/PlayerControls.js.map +1 -0
- package/dist/cjs/components/PlayerErrorBoundary.js +80 -0
- package/dist/cjs/components/PlayerErrorBoundary.js.map +1 -0
- package/dist/cjs/components/SeekBar.js +253 -0
- package/dist/cjs/components/SeekBar.js.map +1 -0
- package/dist/cjs/components/SkipIndicator.js +92 -0
- package/dist/cjs/components/SkipIndicator.js.map +1 -0
- package/dist/cjs/components/SpeedIndicator.js +43 -0
- package/dist/cjs/components/SpeedIndicator.js.map +1 -0
- package/dist/cjs/components/StatsPanel.js +202 -0
- package/dist/cjs/components/StatsPanel.js.map +1 -0
- package/dist/cjs/components/StreamStateOverlay.js +229 -0
- package/dist/cjs/components/StreamStateOverlay.js.map +1 -0
- package/dist/cjs/components/ThumbnailOverlay.js +86 -0
- package/dist/cjs/components/ThumbnailOverlay.js.map +1 -0
- package/dist/cjs/components/TitleOverlay.js +32 -0
- package/dist/cjs/components/TitleOverlay.js.map +1 -0
- package/dist/cjs/context/PlayerContext.js +46 -0
- package/dist/cjs/context/PlayerContext.js.map +1 -0
- package/dist/cjs/hooks/useMetaTrack.js +165 -0
- package/dist/cjs/hooks/useMetaTrack.js.map +1 -0
- package/dist/cjs/hooks/usePlaybackQuality.js +131 -0
- package/dist/cjs/hooks/usePlaybackQuality.js.map +1 -0
- package/dist/cjs/hooks/usePlayerController.js +518 -0
- package/dist/cjs/hooks/usePlayerController.js.map +1 -0
- package/dist/cjs/hooks/usePlayerSelection.js +90 -0
- package/dist/cjs/hooks/usePlayerSelection.js.map +1 -0
- package/dist/cjs/hooks/useStreamState.js +360 -0
- package/dist/cjs/hooks/useStreamState.js.map +1 -0
- package/dist/cjs/hooks/useTelemetry.js +120 -0
- package/dist/cjs/hooks/useTelemetry.js.map +1 -0
- package/dist/cjs/hooks/useViewerEndpoints.js +222 -0
- package/dist/cjs/hooks/useViewerEndpoints.js.map +1 -0
- package/dist/cjs/index.js +97 -1
- package/dist/cjs/index.js.map +1 -1
- package/dist/cjs/ui/badge.js +34 -0
- package/dist/cjs/ui/badge.js.map +1 -0
- package/dist/cjs/ui/button.js +74 -0
- package/dist/cjs/ui/button.js.map +1 -0
- package/dist/cjs/ui/context-menu.js +163 -0
- package/dist/cjs/ui/context-menu.js.map +1 -0
- package/dist/cjs/ui/slider.js +60 -0
- package/dist/cjs/ui/slider.js.map +1 -0
- package/dist/esm/_virtual/_rollupPluginBabelHelpers.js +329 -0
- package/dist/esm/_virtual/_rollupPluginBabelHelpers.js.map +1 -0
- package/dist/esm/assets/logomark.svg.js +4 -0
- package/dist/esm/assets/logomark.svg.js.map +1 -0
- package/dist/esm/components/DevModePanel.js +822 -0
- package/dist/esm/components/DevModePanel.js.map +1 -0
- package/dist/esm/components/DvdLogo.js +196 -0
- package/dist/esm/components/DvdLogo.js.map +1 -0
- package/dist/esm/components/Icons.js +421 -0
- package/dist/esm/components/Icons.js.map +1 -0
- package/dist/esm/components/IdleScreen.js +582 -0
- package/dist/esm/components/IdleScreen.js.map +1 -0
- package/dist/esm/components/LoadingScreen.js +519 -0
- package/dist/esm/components/LoadingScreen.js.map +1 -0
- package/dist/esm/components/Player.js +416 -0
- package/dist/esm/components/Player.js.map +1 -0
- package/dist/esm/components/PlayerControls.js +794 -0
- package/dist/esm/components/PlayerControls.js.map +1 -0
- package/dist/esm/components/PlayerErrorBoundary.js +76 -0
- package/dist/esm/components/PlayerErrorBoundary.js.map +1 -0
- package/dist/esm/components/SeekBar.js +249 -0
- package/dist/esm/components/SeekBar.js.map +1 -0
- package/dist/esm/components/SkipIndicator.js +88 -0
- package/dist/esm/components/SkipIndicator.js.map +1 -0
- package/dist/esm/components/SpeedIndicator.js +39 -0
- package/dist/esm/components/SpeedIndicator.js.map +1 -0
- package/dist/esm/components/StatsPanel.js +198 -0
- package/dist/esm/components/StatsPanel.js.map +1 -0
- package/dist/esm/components/StreamStateOverlay.js +224 -0
- package/dist/esm/components/StreamStateOverlay.js.map +1 -0
- package/dist/esm/components/ThumbnailOverlay.js +82 -0
- package/dist/esm/components/ThumbnailOverlay.js.map +1 -0
- package/dist/esm/components/TitleOverlay.js +28 -0
- package/dist/esm/components/TitleOverlay.js.map +1 -0
- package/dist/esm/context/PlayerContext.js +41 -0
- package/dist/esm/context/PlayerContext.js.map +1 -0
- package/dist/esm/hooks/useMetaTrack.js +163 -0
- package/dist/esm/hooks/useMetaTrack.js.map +1 -0
- package/dist/esm/hooks/usePlaybackQuality.js +129 -0
- package/dist/esm/hooks/usePlaybackQuality.js.map +1 -0
- package/dist/esm/hooks/usePlayerController.js +516 -0
- package/dist/esm/hooks/usePlayerController.js.map +1 -0
- package/dist/esm/hooks/usePlayerSelection.js +88 -0
- package/dist/esm/hooks/usePlayerSelection.js.map +1 -0
- package/dist/esm/hooks/useStreamState.js +358 -0
- package/dist/esm/hooks/useStreamState.js.map +1 -0
- package/dist/esm/hooks/useTelemetry.js +118 -0
- package/dist/esm/hooks/useTelemetry.js.map +1 -0
- package/dist/esm/hooks/useViewerEndpoints.js +220 -0
- package/dist/esm/hooks/useViewerEndpoints.js.map +1 -0
- package/dist/esm/index.js +23 -1
- package/dist/esm/index.js.map +1 -1
- package/dist/esm/ui/badge.js +31 -0
- package/dist/esm/ui/badge.js.map +1 -0
- package/dist/esm/ui/button.js +52 -0
- package/dist/esm/ui/button.js.map +1 -0
- package/dist/esm/ui/context-menu.js +132 -0
- package/dist/esm/ui/context-menu.js.map +1 -0
- package/dist/esm/ui/slider.js +38 -0
- package/dist/esm/ui/slider.js.map +1 -0
- package/dist/types/components/DvdLogo.d.ts +1 -1
- package/dist/types/components/Icons.d.ts +1 -1
- package/dist/types/components/Player.d.ts +1 -1
- package/dist/types/components/PlayerErrorBoundary.d.ts +2 -1
- package/dist/types/components/StreamStateOverlay.d.ts +2 -2
- package/dist/types/components/SubtitleRenderer.d.ts +2 -2
- package/dist/types/context/PlayerContext.d.ts +2 -2
- package/dist/types/context/index.d.ts +2 -2
- package/dist/types/hooks/useMetaTrack.d.ts +3 -3
- package/dist/types/hooks/usePlaybackQuality.d.ts +2 -2
- package/dist/types/hooks/usePlayerController.d.ts +26 -3
- package/dist/types/hooks/usePlayerSelection.d.ts +1 -1
- package/dist/types/hooks/useStreamState.d.ts +1 -1
- package/dist/types/hooks/useTelemetry.d.ts +1 -1
- package/dist/types/hooks/useViewerEndpoints.d.ts +3 -3
- package/dist/types/index.d.ts +28 -28
- package/dist/types/types.d.ts +3 -3
- package/dist/types/ui/select.d.ts +1 -1
- package/package.json +22 -14
- package/src/components/DevModePanel.tsx +244 -143
- package/src/components/DvdLogo.tsx +1 -1
- package/src/components/Icons.tsx +105 -25
- package/src/components/IdleScreen.tsx +262 -128
- package/src/components/LoadingScreen.tsx +169 -151
- package/src/components/LogoOverlay.tsx +3 -6
- package/src/components/Player.tsx +126 -59
- package/src/components/PlayerControls.tsx +384 -272
- package/src/components/PlayerErrorBoundary.tsx +7 -13
- package/src/components/SeekBar.tsx +96 -88
- package/src/components/SkipIndicator.tsx +2 -12
- package/src/components/SpeedIndicator.tsx +2 -11
- package/src/components/StatsPanel.tsx +31 -22
- package/src/components/StreamStateOverlay.tsx +105 -49
- package/src/components/SubtitleRenderer.tsx +29 -29
- package/src/components/ThumbnailOverlay.tsx +5 -6
- package/src/components/TitleOverlay.tsx +2 -8
- package/src/context/PlayerContext.tsx +4 -8
- package/src/context/index.ts +3 -3
- package/src/hooks/useMetaTrack.ts +27 -27
- package/src/hooks/usePlaybackQuality.ts +3 -3
- package/src/hooks/usePlayerController.ts +246 -138
- package/src/hooks/usePlayerSelection.ts +6 -6
- package/src/hooks/useStreamState.ts +51 -56
- package/src/hooks/useTelemetry.ts +18 -3
- package/src/hooks/useViewerEndpoints.ts +34 -23
- package/src/index.tsx +36 -28
- package/src/types.ts +8 -8
- package/src/ui/badge.tsx +6 -5
- package/src/ui/button.tsx +9 -8
- package/src/ui/context-menu.tsx +42 -61
- package/src/ui/select.tsx +13 -7
- package/src/ui/slider.tsx +18 -29
- package/dist/types/components/players/DashJsPlayer.d.ts +0 -18
- package/dist/types/components/players/HlsJsPlayer.d.ts +0 -18
- package/dist/types/components/players/MewsWsPlayer/index.d.ts +0 -18
- package/dist/types/components/players/MistPlayer.d.ts +0 -20
- package/dist/types/components/players/MistWebRTCPlayer/index.d.ts +0 -20
- package/dist/types/components/players/NativePlayer.d.ts +0 -19
- package/dist/types/components/players/VideoJsPlayer.d.ts +0 -18
- package/src/components/players/DashJsPlayer.tsx +0 -56
- package/src/components/players/HlsJsPlayer.tsx +0 -56
- package/src/components/players/MewsWsPlayer/index.tsx +0 -56
- package/src/components/players/MistPlayer.tsx +0 -60
- package/src/components/players/MistWebRTCPlayer/index.tsx +0 -59
- package/src/components/players/NativePlayer.tsx +0 -58
- package/src/components/players/VideoJsPlayer.tsx +0 -56
|
@@ -1,13 +1,14 @@
|
|
|
1
|
-
import React, { useState, useCallback } from "react";
|
|
1
|
+
import React, { useState, useCallback, useEffect } from "react";
|
|
2
2
|
import IdleScreen from "./IdleScreen";
|
|
3
3
|
import TitleOverlay from "./TitleOverlay";
|
|
4
4
|
import StatsPanel from "./StatsPanel";
|
|
5
5
|
import PlayerControls from "./PlayerControls";
|
|
6
6
|
import DevModePanel from "./DevModePanel";
|
|
7
7
|
import SpeedIndicator from "./SpeedIndicator";
|
|
8
|
-
import
|
|
8
|
+
import type { SkipDirection } from "./SkipIndicator";
|
|
9
|
+
import SkipIndicator from "./SkipIndicator";
|
|
9
10
|
import { StatsIcon, SettingsIcon, PictureInPictureIcon } from "./Icons";
|
|
10
|
-
import { PlayerProps } from "../types";
|
|
11
|
+
import type { PlayerProps } from "../types";
|
|
11
12
|
import { usePlayerController } from "../hooks/usePlayerController";
|
|
12
13
|
import { cn } from "@livepeer-frameworks/player-core";
|
|
13
14
|
import type { PlaybackMode, EndpointInfo } from "@livepeer-frameworks/player-core";
|
|
@@ -28,7 +29,7 @@ const PlayerInner: React.FC<PlayerProps> = ({
|
|
|
28
29
|
thumbnailUrl = null,
|
|
29
30
|
options,
|
|
30
31
|
endpoints: propsEndpoints,
|
|
31
|
-
onStateChange
|
|
32
|
+
onStateChange,
|
|
32
33
|
}) => {
|
|
33
34
|
// ============================================================================
|
|
34
35
|
// UI-only State (stays in wrapper)
|
|
@@ -38,7 +39,9 @@ const PlayerInner: React.FC<PlayerProps> = ({
|
|
|
38
39
|
const [skipDirection, setSkipDirection] = useState<SkipDirection>(null);
|
|
39
40
|
|
|
40
41
|
// Playback mode preference (persistent)
|
|
41
|
-
const [devPlaybackMode, setDevPlaybackMode] = useState<PlaybackMode>(
|
|
42
|
+
const [devPlaybackMode, setDevPlaybackMode] = useState<PlaybackMode>(
|
|
43
|
+
options?.playbackMode || "auto"
|
|
44
|
+
);
|
|
42
45
|
|
|
43
46
|
// ============================================================================
|
|
44
47
|
// PlayerController Hook - ALL business logic
|
|
@@ -55,6 +58,7 @@ const PlayerInner: React.FC<PlayerProps> = ({
|
|
|
55
58
|
setVolume,
|
|
56
59
|
selectQuality,
|
|
57
60
|
clearError,
|
|
61
|
+
dismissToast,
|
|
58
62
|
retry,
|
|
59
63
|
reload,
|
|
60
64
|
jumpToLive,
|
|
@@ -78,31 +82,33 @@ const PlayerInner: React.FC<PlayerProps> = ({
|
|
|
78
82
|
onStateChange?.(playerState);
|
|
79
83
|
},
|
|
80
84
|
onError: (error) => {
|
|
81
|
-
console.warn(
|
|
85
|
+
console.warn("[Player] Error:", error);
|
|
82
86
|
},
|
|
83
87
|
});
|
|
84
88
|
|
|
85
89
|
// ============================================================================
|
|
86
90
|
// Dev Mode Callbacks
|
|
87
91
|
// ============================================================================
|
|
88
|
-
const handleDevSettingsChange = useCallback(
|
|
89
|
-
forcePlayer?: string;
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
}, [setDevModeOptions]);
|
|
92
|
+
const handleDevSettingsChange = useCallback(
|
|
93
|
+
(settings: { forcePlayer?: string; forceType?: string; forceSource?: number }) => {
|
|
94
|
+
// One-shot selection - controller handles the state
|
|
95
|
+
setDevModeOptions({
|
|
96
|
+
forcePlayer: settings.forcePlayer,
|
|
97
|
+
forceType: settings.forceType,
|
|
98
|
+
forceSource: settings.forceSource,
|
|
99
|
+
});
|
|
100
|
+
},
|
|
101
|
+
[setDevModeOptions]
|
|
102
|
+
);
|
|
100
103
|
|
|
101
|
-
const handleModeChange = useCallback(
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
104
|
+
const handleModeChange = useCallback(
|
|
105
|
+
(mode: PlaybackMode) => {
|
|
106
|
+
setDevPlaybackMode(mode);
|
|
107
|
+
// Mode is a persistent preference
|
|
108
|
+
setDevModeOptions({ playbackMode: mode });
|
|
109
|
+
},
|
|
110
|
+
[setDevModeOptions]
|
|
111
|
+
);
|
|
106
112
|
|
|
107
113
|
const handleReload = useCallback(() => {
|
|
108
114
|
clearError();
|
|
@@ -110,7 +116,7 @@ const PlayerInner: React.FC<PlayerProps> = ({
|
|
|
110
116
|
}, [clearError, reload]);
|
|
111
117
|
|
|
112
118
|
const handleStatsToggle = useCallback(() => {
|
|
113
|
-
setIsStatsOpen(prev => !prev);
|
|
119
|
+
setIsStatsOpen((prev) => !prev);
|
|
114
120
|
}, []);
|
|
115
121
|
|
|
116
122
|
// Clear skip indicator after animation
|
|
@@ -118,28 +124,42 @@ const PlayerInner: React.FC<PlayerProps> = ({
|
|
|
118
124
|
setSkipDirection(null);
|
|
119
125
|
}, []);
|
|
120
126
|
|
|
127
|
+
// Auto-dismiss toast after 3 seconds
|
|
128
|
+
useEffect(() => {
|
|
129
|
+
if (!state.toast) return;
|
|
130
|
+
const timer = setTimeout(() => {
|
|
131
|
+
dismissToast();
|
|
132
|
+
}, 3000);
|
|
133
|
+
return () => clearTimeout(timer);
|
|
134
|
+
}, [state.toast, dismissToast]);
|
|
135
|
+
|
|
121
136
|
// ============================================================================
|
|
122
137
|
// Derived Values
|
|
123
138
|
// ============================================================================
|
|
124
139
|
const primaryEndpoint = state.endpoints?.primary as EndpointInfo | undefined;
|
|
125
|
-
const isLegacyPlayer = state.currentPlayerInfo?.shortname ===
|
|
140
|
+
const isLegacyPlayer = state.currentPlayerInfo?.shortname === "mist-legacy";
|
|
126
141
|
const useStockControls = options?.stockControls === true || isLegacyPlayer;
|
|
127
142
|
|
|
128
143
|
// Title overlay visibility: show on hover or when paused
|
|
129
|
-
const showTitleOverlay =
|
|
130
|
-
|
|
144
|
+
const showTitleOverlay =
|
|
145
|
+
(state.isHovering || state.isPaused) &&
|
|
146
|
+
!state.shouldShowIdleScreen &&
|
|
147
|
+
!state.isBuffering &&
|
|
148
|
+
!state.error;
|
|
131
149
|
|
|
132
150
|
// Buffering spinner: only during active playback
|
|
133
|
-
const showBufferingSpinner =
|
|
134
|
-
state.isBuffering && !state.error && state.hasPlaybackStarted;
|
|
151
|
+
const showBufferingSpinner =
|
|
152
|
+
!state.shouldShowIdleScreen && state.isBuffering && !state.error && state.hasPlaybackStarted;
|
|
135
153
|
|
|
136
154
|
// ============================================================================
|
|
137
155
|
// Waiting for Endpoint (shown as overlay, not early return)
|
|
138
156
|
// ============================================================================
|
|
139
|
-
const showWaitingForEndpoint = !state.endpoints?.primary && state.state !==
|
|
157
|
+
const showWaitingForEndpoint = !state.endpoints?.primary && state.state !== "booting";
|
|
140
158
|
const waitingMessage = options?.gatewayUrl
|
|
141
|
-
?
|
|
142
|
-
|
|
159
|
+
? state.state === "gateway_loading"
|
|
160
|
+
? "Resolving viewing endpoint..."
|
|
161
|
+
: "Waiting for endpoint..."
|
|
162
|
+
: "Waiting for endpoint...";
|
|
143
163
|
|
|
144
164
|
// ============================================================================
|
|
145
165
|
// Render
|
|
@@ -159,10 +179,7 @@ const PlayerInner: React.FC<PlayerProps> = ({
|
|
|
159
179
|
onMouseMove={handleMouseMove}
|
|
160
180
|
>
|
|
161
181
|
{/* Player area */}
|
|
162
|
-
<div className={cn(
|
|
163
|
-
"relative",
|
|
164
|
-
options?.devMode ? "flex-1 min-w-0" : "w-full h-full"
|
|
165
|
-
)}>
|
|
182
|
+
<div className={cn("relative", options?.devMode ? "flex-1 min-w-0" : "w-full h-full")}>
|
|
166
183
|
{/* Video container - PlayerController attaches here */}
|
|
167
184
|
<div ref={containerRef} className="fw-player-container" />
|
|
168
185
|
|
|
@@ -207,9 +224,7 @@ const PlayerInner: React.FC<PlayerProps> = ({
|
|
|
207
224
|
)}
|
|
208
225
|
|
|
209
226
|
{/* Speed indicator */}
|
|
210
|
-
{state.isHoldingSpeed &&
|
|
211
|
-
<SpeedIndicator isVisible={true} speed={state.holdSpeed} />
|
|
212
|
-
)}
|
|
227
|
+
{state.isHoldingSpeed && <SpeedIndicator isVisible={true} speed={state.holdSpeed} />}
|
|
213
228
|
|
|
214
229
|
{/* Skip indicator */}
|
|
215
230
|
<SkipIndicator
|
|
@@ -219,15 +234,13 @@ const PlayerInner: React.FC<PlayerProps> = ({
|
|
|
219
234
|
/>
|
|
220
235
|
|
|
221
236
|
{/* Waiting for endpoint overlay */}
|
|
222
|
-
{showWaitingForEndpoint &&
|
|
223
|
-
<IdleScreen status="OFFLINE" message={waitingMessage} />
|
|
224
|
-
)}
|
|
237
|
+
{showWaitingForEndpoint && <IdleScreen status="OFFLINE" message={waitingMessage} />}
|
|
225
238
|
|
|
226
239
|
{/* Idle screen */}
|
|
227
240
|
{!showWaitingForEndpoint && state.shouldShowIdleScreen && (
|
|
228
241
|
<IdleScreen
|
|
229
242
|
status={state.isEffectivelyLive ? state.streamState?.status : undefined}
|
|
230
|
-
message={state.isEffectivelyLive ? state.streamState?.message :
|
|
243
|
+
message={state.isEffectivelyLive ? state.streamState?.message : "Loading video..."}
|
|
231
244
|
percentage={state.isEffectivelyLive ? state.streamState?.percentage : undefined}
|
|
232
245
|
/>
|
|
233
246
|
)}
|
|
@@ -253,21 +266,29 @@ const PlayerInner: React.FC<PlayerProps> = ({
|
|
|
253
266
|
aria-live="assertive"
|
|
254
267
|
className={cn(
|
|
255
268
|
"fw-error-overlay",
|
|
256
|
-
state.isPassiveError
|
|
269
|
+
state.isPassiveError
|
|
270
|
+
? "fw-error-overlay--passive"
|
|
271
|
+
: "fw-error-overlay--fullscreen"
|
|
257
272
|
)}
|
|
258
273
|
>
|
|
259
|
-
<div
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
"fw-error-
|
|
269
|
-
|
|
270
|
-
|
|
274
|
+
<div
|
|
275
|
+
className={cn(
|
|
276
|
+
"fw-error-popup",
|
|
277
|
+
state.isPassiveError ? "fw-error-popup--passive" : "fw-error-popup--fullscreen"
|
|
278
|
+
)}
|
|
279
|
+
>
|
|
280
|
+
<div
|
|
281
|
+
className={cn(
|
|
282
|
+
"fw-error-header",
|
|
283
|
+
state.isPassiveError ? "fw-error-header--warning" : "fw-error-header--error"
|
|
284
|
+
)}
|
|
285
|
+
>
|
|
286
|
+
<span
|
|
287
|
+
className={cn(
|
|
288
|
+
"fw-error-title",
|
|
289
|
+
state.isPassiveError ? "fw-error-title--warning" : "fw-error-title--error"
|
|
290
|
+
)}
|
|
291
|
+
>
|
|
271
292
|
{state.isPassiveError ? "Warning" : "Error"}
|
|
272
293
|
</span>
|
|
273
294
|
<button
|
|
@@ -277,7 +298,12 @@ const PlayerInner: React.FC<PlayerProps> = ({
|
|
|
277
298
|
aria-label="Dismiss"
|
|
278
299
|
>
|
|
279
300
|
<svg width="12" height="12" viewBox="0 0 12 12" fill="none">
|
|
280
|
-
<path
|
|
301
|
+
<path
|
|
302
|
+
d="M9 3L3 9M3 3L9 9"
|
|
303
|
+
stroke="currentColor"
|
|
304
|
+
strokeWidth="1.5"
|
|
305
|
+
strokeLinecap="round"
|
|
306
|
+
/>
|
|
281
307
|
</svg>
|
|
282
308
|
</button>
|
|
283
309
|
</div>
|
|
@@ -289,7 +315,10 @@ const PlayerInner: React.FC<PlayerProps> = ({
|
|
|
289
315
|
type="button"
|
|
290
316
|
className="fw-error-btn"
|
|
291
317
|
aria-label="Retry playback"
|
|
292
|
-
onClick={() => {
|
|
318
|
+
onClick={() => {
|
|
319
|
+
clearError();
|
|
320
|
+
retry();
|
|
321
|
+
}}
|
|
293
322
|
>
|
|
294
323
|
Retry
|
|
295
324
|
</button>
|
|
@@ -298,6 +327,34 @@ const PlayerInner: React.FC<PlayerProps> = ({
|
|
|
298
327
|
</div>
|
|
299
328
|
)}
|
|
300
329
|
|
|
330
|
+
{/* Toast notification */}
|
|
331
|
+
{state.toast && (
|
|
332
|
+
<div
|
|
333
|
+
className="absolute bottom-20 left-1/2 -translate-x-1/2 z-30 animate-in fade-in slide-in-from-bottom-2 duration-200"
|
|
334
|
+
role="status"
|
|
335
|
+
aria-live="polite"
|
|
336
|
+
>
|
|
337
|
+
<div className="flex items-center gap-2 rounded-lg border border-white/10 bg-black/80 px-4 py-2 text-sm text-white shadow-lg backdrop-blur-sm">
|
|
338
|
+
<span>{state.toast.message}</span>
|
|
339
|
+
<button
|
|
340
|
+
type="button"
|
|
341
|
+
onClick={dismissToast}
|
|
342
|
+
className="ml-2 text-white/60 hover:text-white"
|
|
343
|
+
aria-label="Dismiss"
|
|
344
|
+
>
|
|
345
|
+
<svg width="12" height="12" viewBox="0 0 12 12" fill="none">
|
|
346
|
+
<path
|
|
347
|
+
d="M9 3L3 9M3 3L9 9"
|
|
348
|
+
stroke="currentColor"
|
|
349
|
+
strokeWidth="1.5"
|
|
350
|
+
strokeLinecap="round"
|
|
351
|
+
/>
|
|
352
|
+
</svg>
|
|
353
|
+
</button>
|
|
354
|
+
</div>
|
|
355
|
+
</div>
|
|
356
|
+
)}
|
|
357
|
+
|
|
301
358
|
{/* Player controls */}
|
|
302
359
|
{!useStockControls && (
|
|
303
360
|
<PlayerControls
|
|
@@ -376,7 +433,17 @@ const PlayerInner: React.FC<PlayerProps> = ({
|
|
|
376
433
|
<span>Picture-in-Picture</span>
|
|
377
434
|
</ContextMenuItem>
|
|
378
435
|
<ContextMenuItem onClick={toggleLoop} className="gap-2">
|
|
379
|
-
<svg
|
|
436
|
+
<svg
|
|
437
|
+
width="14"
|
|
438
|
+
height="14"
|
|
439
|
+
viewBox="0 0 24 24"
|
|
440
|
+
fill="none"
|
|
441
|
+
stroke="currentColor"
|
|
442
|
+
strokeWidth="2"
|
|
443
|
+
strokeLinecap="round"
|
|
444
|
+
strokeLinejoin="round"
|
|
445
|
+
className="opacity-70 flex-shrink-0"
|
|
446
|
+
>
|
|
380
447
|
<polyline points="17 1 21 5 17 9"></polyline>
|
|
381
448
|
<path d="M3 11V9a4 4 0 0 1 4-4h14"></path>
|
|
382
449
|
<polyline points="7 23 3 19 7 15"></polyline>
|