softbuilders-react-video-player 1.1.8 → 1.1.10

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 (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;