softbuilders-react-video-player 1.1.8 → 1.1.10

Sign up to get free protection for your applications and to get access to all the features.
Files changed (64) hide show
  1. package/LICENSE +21 -21
  2. package/README.md +126 -126
  3. package/dist/components/BigPlayButton/index.js +1 -1
  4. package/dist/components/BigPlayButton/index.js.map +1 -1
  5. package/dist/components/BigPlayButton/index.tsx +33 -31
  6. package/dist/components/BufferTracker/index.tsx +19 -19
  7. package/dist/components/ChapterTooltip/index.tsx +65 -65
  8. package/dist/components/ChaptersPanal/index.tsx +40 -40
  9. package/dist/components/ControlBar/index.d.ts +2 -1
  10. package/dist/components/ControlBar/index.js +21 -6
  11. package/dist/components/ControlBar/index.js.map +1 -1
  12. package/dist/components/ControlBar/index.tsx +150 -127
  13. package/dist/components/CreateNoteMenu/index.tsx +61 -61
  14. package/dist/components/CurrentTimeLabel/index.tsx +13 -13
  15. package/dist/components/CurrentTimeTracker/index.tsx +18 -18
  16. package/dist/components/Menu/index.tsx +49 -49
  17. package/dist/components/MenuButton/index.js +1 -1
  18. package/dist/components/MenuButton/index.js.map +1 -1
  19. package/dist/components/MenuButton/index.tsx +67 -67
  20. package/dist/components/NoteTooltip/index.tsx +46 -46
  21. package/dist/components/NotesPanal/index.tsx +34 -34
  22. package/dist/components/QualityMenu/index.js +2 -2
  23. package/dist/components/QualityMenu/index.js.map +1 -1
  24. package/dist/components/QualityMenu/index.tsx +122 -122
  25. package/dist/components/Slider/index.d.ts +1 -1
  26. package/dist/components/Slider/index.js +3 -3
  27. package/dist/components/Slider/index.js.map +1 -1
  28. package/dist/components/Slider/index.tsx +36 -37
  29. package/dist/components/Slider/style.css +49 -15
  30. package/dist/components/SoftBuildersVideoPlayer/index.js +1 -1
  31. package/dist/components/SoftBuildersVideoPlayer/index.js.map +1 -1
  32. package/dist/components/SoftBuildersVideoPlayer/index.tsx +110 -109
  33. package/dist/components/SubtitleMenu/index.js +2 -2
  34. package/dist/components/SubtitleMenu/index.js.map +1 -1
  35. package/dist/components/SubtitleMenu/index.tsx +107 -108
  36. package/dist/components/TimeSlider/index.js +13 -13
  37. package/dist/components/TimeSlider/index.tsx +107 -107
  38. package/dist/components/TimeSliderContainer/index.tsx +35 -35
  39. package/dist/components/Tooltip/index.tsx +16 -16
  40. package/dist/components/VideoPlayerComponent/index.d.ts +2 -1
  41. package/dist/components/VideoPlayerComponent/index.js +54 -38
  42. package/dist/components/VideoPlayerComponent/index.js.map +1 -1
  43. package/dist/components/VideoPlayerComponent/index.tsx +271 -249
  44. package/dist/components/VideoPlayerComponent/provider.tsx +82 -82
  45. package/dist/components/VideoPlayerComponent/style/style.css +36 -36
  46. package/dist/components/VolumeSlider/index.d.ts +4 -2
  47. package/dist/components/VolumeSlider/index.js +12 -2
  48. package/dist/components/VolumeSlider/index.js.map +1 -1
  49. package/dist/components/VolumeSlider/index.tsx +91 -52
  50. package/dist/components/icons/SubIcon.d.ts +3 -0
  51. package/dist/components/icons/SubIcon.js +4 -0
  52. package/dist/components/icons/SubIcon.js.map +1 -0
  53. package/dist/components/icons/SubIcon.tsx +28 -0
  54. package/dist/components/icons/index.d.ts +1 -0
  55. package/dist/components/icons/index.js +1 -0
  56. package/dist/components/icons/index.js.map +1 -1
  57. package/dist/components/icons/index.ts +15 -14
  58. package/dist/images/index.d.ts +1 -0
  59. package/dist/images/index.js +1 -0
  60. package/dist/images/index.js.map +1 -1
  61. package/dist/index.css +78 -3
  62. package/dist/index.mjs +276 -169
  63. package/dist/styles/tailwind.css +140 -87
  64. package/package.json +45 -45
@@ -1,249 +1,271 @@
1
- import React, { useEffect, useRef, useState } from "react";
2
- import ReactDOM from "react-dom/client";
3
- import videojs from "video.js";
4
- import Player from "video.js/dist/types/player";
5
- import "video.js/dist/video-js.css";
6
- import ControlBar from "../ControlBar";
7
- import {
8
- SoftBuildersVideoPlayerChapter,
9
- SoftBuildersVideoPlayerNote,
10
- SoftBuildersVideoPlayerOptions,
11
- } from "../../types";
12
-
13
- import "./style/style.css";
14
- import "../../styles/tailwind.css";
15
- import { SoftBuildersVideoPlayerProvider } from "./provider";
16
- import BigPlayButton from "../BigPlayButton";
17
-
18
- let bigPlayButtonRoot: {
19
- [key: string]: ReactDOM.Root | undefined;
20
- } = {};
21
-
22
- const renderBigPlayButton = (
23
- id: string,
24
- player: Player | undefined,
25
- isPaused: boolean,
26
- setIsPaused: React.Dispatch<React.SetStateAction<boolean>>
27
- ) => {
28
- const container = document.getElementById(`video-container-${id}`);
29
- if (container) {
30
- const element: any = container.querySelector(".vjs-big-play-button");
31
- if (element) {
32
- if (!bigPlayButtonRoot[id]) {
33
- // If bigPlayButtonRoot hasn't been created, create it
34
- bigPlayButtonRoot[id] = ReactDOM.createRoot(element as HTMLElement);
35
- }
36
-
37
- bigPlayButtonRoot[id].render(
38
- <BigPlayButton
39
- player={player}
40
- isPaused={isPaused}
41
- setIsPaused={setIsPaused}
42
- />
43
- );
44
- }
45
- }
46
- };
47
-
48
- let controlBarRoot: {
49
- [key: string]: ReactDOM.Root | undefined;
50
- } = {};
51
-
52
- const renderControlBar = <T,>(
53
- id: string,
54
- player: Player | undefined,
55
- isPaused: boolean,
56
- setIsPaused: React.Dispatch<React.SetStateAction<boolean>>,
57
- duration: number,
58
- notes: SoftBuildersVideoPlayerNote[],
59
- chapters: SoftBuildersVideoPlayerChapter[],
60
- seekStep: number = 5,
61
- handleSaveNoteAction?: (time: number, note: string) => Promise<T>
62
- ) => {
63
- const container = document.getElementById(`video-container-${id}`);
64
- if (container) {
65
- const element: any = container.querySelector(".vjs-control-bar");
66
- if (element) {
67
- if (!controlBarRoot[id]) {
68
- // If controlBarRoot hasn't been created, create it
69
- controlBarRoot[id] = ReactDOM.createRoot(element as HTMLElement);
70
- }
71
-
72
- element.style.display = "block";
73
- controlBarRoot[id].render(
74
- <SoftBuildersVideoPlayerProvider>
75
- <ControlBar
76
- player={player}
77
- isPaused={isPaused}
78
- setIsPaused={setIsPaused}
79
- duration={duration}
80
- notes={notes}
81
- chapters={chapters}
82
- seekStep={seekStep}
83
- handleSaveNoteAction={handleSaveNoteAction}
84
- />
85
- </SoftBuildersVideoPlayerProvider>
86
- );
87
- }
88
- }
89
- };
90
-
91
- export type Props<T = any> = {
92
- id: string;
93
- options: SoftBuildersVideoPlayerOptions;
94
- notes: SoftBuildersVideoPlayerNote[];
95
- chapters: SoftBuildersVideoPlayerChapter[];
96
- startTime?: number;
97
- handleSaveNoteAction?: (time: number, note: string) => Promise<T>;
98
- onPlay?: (time: number) => void;
99
- onPause?: (time: number) => void;
100
- };
101
-
102
- const VideoPlayerComponent = <T,>({
103
- id,
104
- options,
105
- notes,
106
- chapters,
107
- startTime = 0,
108
- handleSaveNoteAction,
109
- onPlay,
110
- onPause,
111
- }: Props<T>) => {
112
- const videoRef = useRef<any>(undefined);
113
- const playerRef = useRef<Player | undefined>(undefined);
114
-
115
- const [isReady, setIsReady] = useState(false);
116
- const [isPaused, setIsPaused] = useState(!options.autoplay);
117
- const [duration, setDuratoin] = useState(1);
118
-
119
- const onReady = (player: Player) => {
120
- if (playerRef) {
121
- playerRef.current = player;
122
- setIsReady(true);
123
-
124
- player.currentTime(startTime);
125
-
126
- player.on("waiting", () => {});
127
-
128
- player.on("dispose", () => {
129
- videojs.log("player will dispose");
130
- setIsReady(false);
131
- });
132
-
133
- player.on("loadedmetadata", () => {
134
- const d = player.duration() || 0;
135
- setDuratoin(d);
136
- });
137
- }
138
- };
139
-
140
- useEffect(() => {
141
- if (!playerRef.current) {
142
- const videoElement = document.createElement("video-js");
143
- videoElement.classList.add("vjs-big-play-centered");
144
- videoRef.current.appendChild(videoElement);
145
-
146
- playerRef.current = videojs(videoElement, options, () => {
147
- onReady(playerRef.current as Player);
148
- });
149
- }
150
-
151
- return () => {
152
- if (playerRef)
153
- if (playerRef.current) {
154
- // Dispose of the player properly on component unmount
155
- playerRef.current.dispose();
156
- playerRef.current = undefined;
157
-
158
- // Defer unmounting of big play button and control bar to avoid race conditions
159
- setTimeout(() => {
160
- if (bigPlayButtonRoot[id]) {
161
- bigPlayButtonRoot[id].unmount();
162
- bigPlayButtonRoot[id] = undefined;
163
- }
164
- if (controlBarRoot[id]) {
165
- controlBarRoot[id].unmount();
166
- controlBarRoot[id] = undefined;
167
- }
168
- }, 0);
169
- }
170
- };
171
- }, [options]);
172
-
173
- useEffect(() => {
174
- if (playerRef && playerRef?.current && isReady) {
175
- const currentTime = playerRef.current.currentTime() || 0;
176
-
177
- if (isPaused) {
178
- if (onPause) onPause(currentTime);
179
- } else {
180
- if (onPlay) onPlay(currentTime);
181
- }
182
- }
183
- }, [isPaused, isReady]);
184
-
185
- useEffect(() => {
186
- if (isReady) {
187
- const controlBarTimeout = setTimeout(() => {
188
- renderControlBar(
189
- id,
190
- playerRef.current,
191
- isPaused,
192
- setIsPaused,
193
- duration,
194
- notes,
195
- chapters,
196
- 5,
197
- handleSaveNoteAction
198
- );
199
- }, 500);
200
-
201
- return () => clearTimeout(controlBarTimeout); // Clean up the timeout
202
- }
203
- }, [
204
- id,
205
- playerRef,
206
- isPaused,
207
- setIsPaused,
208
- notes,
209
- chapters,
210
- isReady,
211
- handleSaveNoteAction,
212
- duration,
213
- ]);
214
-
215
- useEffect(() => {
216
- if (isReady && playerRef) {
217
- const playButtonTimeout = setTimeout(() => {
218
- renderBigPlayButton(id, playerRef.current, isPaused, setIsPaused);
219
- }, 500);
220
-
221
- return () => clearTimeout(playButtonTimeout); // Clean up the timeout
222
- }
223
- }, [id, isPaused, isReady]);
224
-
225
- useEffect(() => {
226
- if (playerRef) {
227
- if (playerRef.current) {
228
- const intervalId = setInterval(() => {
229
- if (playerRef.current) setIsPaused(playerRef.current.paused());
230
- }, 500);
231
-
232
- return () => clearInterval(intervalId);
233
- }
234
- }
235
- }, []);
236
-
237
- return (
238
- <div
239
- id={`video-container-${id}`}
240
- className="sb-relative sb-rounded-md sb-overflow-hidden"
241
- >
242
- <div data-vjs-player>
243
- <div ref={videoRef} />
244
- </div>
245
- </div>
246
- );
247
- };
248
-
249
- export default VideoPlayerComponent;
1
+ import React, { useEffect, useRef, useState } from "react";
2
+ import ReactDOM from "react-dom/client";
3
+ import videojs from "video.js";
4
+ import Player from "video.js/dist/types/player";
5
+ import "video.js/dist/video-js.css";
6
+ import ControlBar from "../ControlBar";
7
+ import {
8
+ SoftBuildersVideoPlayerChapter,
9
+ SoftBuildersVideoPlayerNote,
10
+ SoftBuildersVideoPlayerOptions,
11
+ } from "../../types";
12
+
13
+ import "./style/style.css";
14
+ import "../../styles/tailwind.css";
15
+ import { SoftBuildersVideoPlayerProvider } from "./provider";
16
+ import BigPlayButton from "../BigPlayButton";
17
+
18
+ let bigPlayButtonRoot: {
19
+ [key: string]: ReactDOM.Root | undefined;
20
+ } = {};
21
+
22
+ const renderBigPlayButton = (
23
+ id: string,
24
+ player: Player | undefined,
25
+ isPaused: boolean,
26
+ setIsPaused: React.Dispatch<React.SetStateAction<boolean>>
27
+ ) => {
28
+ const container = document.getElementById(`video-container-${id}`);
29
+ if (container) {
30
+ const element: any = container.querySelector(".vjs-big-play-button");
31
+ if (element) {
32
+ if (!bigPlayButtonRoot[id]) {
33
+ bigPlayButtonRoot[id] = ReactDOM.createRoot(element as HTMLElement);
34
+ }
35
+
36
+ bigPlayButtonRoot[id].render(
37
+ <BigPlayButton
38
+ player={player}
39
+ isPaused={isPaused}
40
+ setIsPaused={setIsPaused}
41
+ />
42
+ );
43
+ }
44
+ }
45
+ };
46
+
47
+ let controlBarRoot: {
48
+ [key: string]: ReactDOM.Root | undefined;
49
+ } = {};
50
+
51
+ const renderControlBar = <T,>(
52
+ id: string,
53
+ player: Player | undefined,
54
+ isPaused: boolean,
55
+ setIsPaused: React.Dispatch<React.SetStateAction<boolean>>,
56
+ duration: number,
57
+ notes: SoftBuildersVideoPlayerNote[],
58
+ chapters: SoftBuildersVideoPlayerChapter[],
59
+ seekStep: number = 5,
60
+ handleSaveNoteAction?: (time: number, note: string) => Promise<T>
61
+ ) => {
62
+ const container = document.getElementById(`video-container-${id}`);
63
+
64
+ if (container) {
65
+ const element: any = container.querySelector(".vjs-control-bar");
66
+ if (element) {
67
+ if (!controlBarRoot[id]) {
68
+ controlBarRoot[id] = ReactDOM.createRoot(element as HTMLElement);
69
+ }
70
+
71
+ element.style.display = "flex";
72
+ element.style.height = "100%";
73
+ element.style.alignItems = "flex-end";
74
+ controlBarRoot[id].render(
75
+ <SoftBuildersVideoPlayerProvider>
76
+ <ControlBar
77
+ id={id}
78
+ player={player}
79
+ isPaused={isPaused}
80
+ setIsPaused={setIsPaused}
81
+ duration={duration}
82
+ notes={notes}
83
+ chapters={chapters}
84
+ seekStep={seekStep}
85
+ handleSaveNoteAction={handleSaveNoteAction}
86
+ />
87
+ </SoftBuildersVideoPlayerProvider>
88
+ );
89
+ }
90
+ }
91
+ };
92
+
93
+ export type Props<T = any> = {
94
+ id: string;
95
+ options: SoftBuildersVideoPlayerOptions;
96
+ notes: SoftBuildersVideoPlayerNote[];
97
+ chapters: SoftBuildersVideoPlayerChapter[];
98
+ startTime?: number;
99
+ poster?: string; // Changed to string type for poster URL
100
+ handleSaveNoteAction?: (time: number, note: string) => Promise<T>;
101
+ onPlay?: (time: number) => void;
102
+ onPause?: (time: number) => void;
103
+ };
104
+
105
+ const VideoPlayerComponent = <T,>({
106
+ id,
107
+ options,
108
+ notes,
109
+ chapters,
110
+ startTime = 0,
111
+ handleSaveNoteAction,
112
+ poster,
113
+ onPlay,
114
+ onPause,
115
+ }: Props<T>) => {
116
+ const videoRef = useRef<any>(undefined);
117
+ const playerRef = useRef<Player | undefined>(undefined);
118
+
119
+ const [isReady, setIsReady] = useState(false);
120
+ const [isPaused, setIsPaused] = useState(!options.autoplay);
121
+ const [duration, setDuration] = useState(1);
122
+
123
+ const onReady = (player: Player) => {
124
+ if (playerRef) {
125
+ playerRef.current = player;
126
+ setIsReady(true);
127
+ player.currentTime(startTime);
128
+
129
+ player.on("waiting", () => {});
130
+
131
+ player.on("dispose", () => {
132
+ videojs.log("player will dispose");
133
+ setIsReady(false);
134
+ });
135
+
136
+ player.on("loadedmetadata", () => {
137
+ const d = player.duration() || 0;
138
+ setDuration(d);
139
+ });
140
+ }
141
+ };
142
+
143
+ useEffect(() => {
144
+ if (!playerRef.current) {
145
+ const videoElement = document.createElement("video-js");
146
+ videoElement.classList.add("vjs-big-play-centered");
147
+ // Set the poster attribute here
148
+ if (poster) {
149
+ videoElement.setAttribute("poster", poster);
150
+ }
151
+ videoRef.current.appendChild(videoElement);
152
+
153
+ playerRef.current = videojs(videoElement, options, () => {
154
+ onReady(playerRef.current as Player);
155
+ });
156
+ }
157
+
158
+ return () => {
159
+ if (playerRef.current) {
160
+ playerRef.current.dispose();
161
+ playerRef.current = undefined;
162
+
163
+ setTimeout(() => {
164
+ if (bigPlayButtonRoot[id]) {
165
+ bigPlayButtonRoot[id].unmount();
166
+ bigPlayButtonRoot[id] = undefined;
167
+ }
168
+ if (controlBarRoot[id]) {
169
+ controlBarRoot[id].unmount();
170
+ controlBarRoot[id] = undefined;
171
+ }
172
+ }, 0);
173
+ }
174
+ };
175
+ }, [options, poster]); // Added poster to dependency array
176
+
177
+ useEffect(() => {
178
+ if (playerRef.current && isReady) {
179
+ const currentTime = playerRef.current.currentTime() || 0;
180
+
181
+ if (isPaused) {
182
+ if (onPause) onPause(currentTime);
183
+ } else {
184
+ if (onPlay) onPlay(currentTime);
185
+ }
186
+ }
187
+ }, [isPaused, isReady]);
188
+
189
+ useEffect(() => {
190
+ if (isReady) {
191
+ const controlBarTimeout = setTimeout(() => {
192
+ renderControlBar(
193
+ id,
194
+ playerRef.current,
195
+ isPaused,
196
+ setIsPaused,
197
+ duration,
198
+ notes,
199
+ chapters,
200
+ 5,
201
+ handleSaveNoteAction
202
+ );
203
+ }, 500);
204
+
205
+ return () => clearTimeout(controlBarTimeout);
206
+ }
207
+ }, [
208
+ id,
209
+ playerRef,
210
+ isPaused,
211
+ setIsPaused,
212
+ notes,
213
+ chapters,
214
+ isReady,
215
+ handleSaveNoteAction,
216
+ duration,
217
+ ]);
218
+
219
+ useEffect(() => {
220
+ if (isReady) {
221
+ const playButtonTimeout = setTimeout(() => {
222
+ renderBigPlayButton(id, playerRef.current, isPaused, setIsPaused);
223
+ }, 500);
224
+
225
+ return () => clearTimeout(playButtonTimeout);
226
+ }
227
+ }, [id, isPaused, isReady]);
228
+
229
+ useEffect(() => {
230
+ if (playerRef.current) {
231
+ const intervalId = setInterval(() => {
232
+ if (playerRef.current) setIsPaused(playerRef.current.paused());
233
+ }, 500);
234
+
235
+ return () => clearInterval(intervalId);
236
+ }
237
+ }, []);
238
+
239
+ const handlePlayerClick = () => {
240
+ if (playerRef.current) {
241
+ if (playerRef.current.paused()) {
242
+ playerRef.current.play();
243
+ setIsPaused(false);
244
+ } else {
245
+ playerRef.current.pause();
246
+ setIsPaused(true);
247
+ if (onPause) onPause(playerRef.current.currentTime());
248
+ }
249
+ }
250
+ };
251
+
252
+ return (
253
+ <div
254
+ id={`video-container-${id}`}
255
+ className="sb-relative sb-rounded-md sb-overflow-hidden hover:sb-cursor-pointer"
256
+ onClick={handlePlayerClick}
257
+ >
258
+ <div
259
+ data-vjs-player
260
+ style={{
261
+ height: "100%",
262
+ position: "relative",
263
+ }}
264
+ >
265
+ <div ref={videoRef} />
266
+ </div>
267
+ </div>
268
+ );
269
+ };
270
+
271
+ export default VideoPlayerComponent;