@nikelroot/video-player 0.1.3 → 0.1.5

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
@@ -17,13 +17,18 @@ npm install react react-dom styled-components
17
17
  ## Usage
18
18
 
19
19
  ```tsx
20
+ import { useRef } from 'react';
20
21
  import VideoPlayer from '@nikelroot/video-player';
21
22
 
22
23
  export function Example() {
24
+ const videoRef = useRef<HTMLVideoElement | null>(null);
25
+
23
26
  return (
24
27
  <VideoPlayer
28
+ videoRef={videoRef}
25
29
  videoSrc="https://example.com/stream.m3u8"
26
30
  controlsVariant="full"
31
+ active={true}
27
32
  live={false}
28
33
  autoPlay={false}
29
34
  onTimeChange={(time) => console.log(time)}
package/dist/index.cjs CHANGED
@@ -87,6 +87,15 @@ var VideoPlayerControlStyles = import_styled_components.styled.div`
87
87
  outline: none;
88
88
  }
89
89
 
90
+ .video-player-control-button:disabled {
91
+ opacity: 0.42;
92
+ cursor: not-allowed;
93
+ }
94
+
95
+ .video-player-control-button:disabled:hover {
96
+ background: rgba(255, 255, 255, 0.12);
97
+ }
98
+
90
99
  .video-player-icon {
91
100
  width: 17px;
92
101
  height: 17px;
@@ -482,11 +491,23 @@ var Icon = ({ name }) => {
482
491
  return /* @__PURE__ */ (0, import_jsx_runtime.jsx)("svg", { "aria-hidden": "true", className: "video-player-icon", focusable: "false", viewBox: "0 0 24 24", children: paths[name] });
483
492
  };
484
493
  var ControlButton = ({
494
+ disabled,
485
495
  icon,
486
496
  label,
487
497
  onClick
488
498
  }) => {
489
- return /* @__PURE__ */ (0, import_jsx_runtime.jsx)("button", { "aria-label": label, className: "video-player-control-button", onClick: () => void onClick(), title: label, type: "button", children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Icon, { name: icon }) });
499
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
500
+ "button",
501
+ {
502
+ "aria-label": label,
503
+ className: "video-player-control-button",
504
+ disabled,
505
+ onClick: () => void onClick(),
506
+ title: label,
507
+ type: "button",
508
+ children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Icon, { name: icon })
509
+ }
510
+ );
490
511
  };
491
512
  var stopControlClick = (e) => {
492
513
  e.preventDefault();
@@ -496,6 +517,7 @@ var VideoPlayerControls = (props) => {
496
517
  const {
497
518
  variant,
498
519
  fullScreenAction,
520
+ fullscreenAllowed,
499
521
  showControl,
500
522
  playAction,
501
523
  pauseAction,
@@ -521,7 +543,7 @@ var VideoPlayerControls = (props) => {
521
543
  return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(VideoPlayerControlStyles, { $isMobile: isMobile, onClick: stopControlClick, $showControl: showControl, children: /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "video-player-control-row", children: [
522
544
  /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "full" }),
523
545
  /* @__PURE__ */ (0, import_jsx_runtime.jsx)(ControlButton, { icon: muted ? "mute" : "sound", label: muted ? "Unmute" : "Mute", onClick: () => onMutedChange(!muted) }),
524
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)(ControlButton, { icon: "fullscreen", label: "Fullscreen", onClick: fullScreenAction })
546
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(ControlButton, { disabled: !fullscreenAllowed, icon: "fullscreen", label: "Fullscreen", onClick: fullScreenAction })
525
547
  ] }) });
526
548
  }
527
549
  return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(VideoPlayerControlStyles, { $isMobile: isMobile, onClick: stopControlClick, $showControl: showControl, children: /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "video-player-control-row", children: [
@@ -533,7 +555,7 @@ var VideoPlayerControls = (props) => {
533
555
  /* @__PURE__ */ (0, import_jsx_runtime.jsx)(SeekSlider, { playAction, duration, currentTime, seekSetTime }),
534
556
  /* @__PURE__ */ (0, import_jsx_runtime.jsx)(TimeBlock, { duration, currentTime }),
535
557
  /* @__PURE__ */ (0, import_jsx_runtime.jsx)(ControlButton, { icon: muted ? "mute" : "sound", label: muted ? "Unmute" : "Mute", onClick: () => onMutedChange(!muted) }),
536
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)(ControlButton, { icon: "fullscreen", label: "Fullscreen", onClick: fullScreenAction })
558
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(ControlButton, { disabled: !fullscreenAllowed, icon: "fullscreen", label: "Fullscreen", onClick: fullScreenAction })
537
559
  ] }) });
538
560
  };
539
561
 
@@ -740,9 +762,18 @@ var isLikelyHlsSource = (src) => {
740
762
  return /\.m3u8($|[?#])/i.test(src);
741
763
  }
742
764
  };
765
+ var assignRef = (ref, value) => {
766
+ if (!ref) return;
767
+ if (typeof ref === "function") {
768
+ ref(value);
769
+ return;
770
+ }
771
+ ref.current = value;
772
+ };
743
773
  var VideoPlayerBase = (props, ref) => {
744
774
  const {
745
775
  controlsVariant = "none",
776
+ active,
746
777
  autoPlay = false,
747
778
  preload = "metadata",
748
779
  loop = false,
@@ -760,6 +791,7 @@ var VideoPlayerBase = (props, ref) => {
760
791
  alwaysShowSegments = false,
761
792
  initialTime = 0,
762
793
  reloadKey,
794
+ videoRef: externalVideoRef,
763
795
  onVideoRefChange,
764
796
  handleClick = true,
765
797
  onPointerDown,
@@ -815,6 +847,7 @@ var VideoPlayerBase = (props, ref) => {
815
847
  const muted = mutedProp != null ? mutedProp : mutedState;
816
848
  const duration = durationProp != null ? durationProp : durationState;
817
849
  const currentTime = currentTimeProp != null ? currentTimeProp : currentTimeState;
850
+ const fullscreenAllowed = active != null ? active : true;
818
851
  const setTimeD = (0, import_react2.useRef)(
819
852
  createThrottledNumberFn((value) => {
820
853
  const v = videoRef.current;
@@ -901,6 +934,7 @@ var VideoPlayerBase = (props, ref) => {
901
934
  prev.removeEventListener("durationchange", onDur);
902
935
  }
903
936
  videoRef.current = el;
937
+ assignRef(externalVideoRef, el);
904
938
  onVideoRefChange == null ? void 0 : onVideoRefChange(el);
905
939
  notifyActiveChange(el, "ref");
906
940
  if (!el) return;
@@ -908,7 +942,7 @@ var VideoPlayerBase = (props, ref) => {
908
942
  el.addEventListener("timeupdate", onTime);
909
943
  el.addEventListener("durationchange", onDur);
910
944
  },
911
- [muted, notifyActiveChange, onDur, onTime, onVideoRefChange]
945
+ [externalVideoRef, muted, notifyActiveChange, onDur, onTime, onVideoRefChange]
912
946
  );
913
947
  const pauseOtherVideos = (0, import_react2.useCallback)(
914
948
  (el) => {
@@ -1235,6 +1269,7 @@ var VideoPlayerBase = (props, ref) => {
1235
1269
  else if (doc.msExitFullscreen) void doc.msExitFullscreen();
1236
1270
  return;
1237
1271
  }
1272
+ if (!fullscreenAllowed) return;
1238
1273
  if (containerEl) {
1239
1274
  if (containerEl.requestFullscreen) void containerEl.requestFullscreen();
1240
1275
  else if (containerEl.webkitRequestFullscreen) void containerEl.webkitRequestFullscreen();
@@ -1246,7 +1281,7 @@ var VideoPlayerBase = (props, ref) => {
1246
1281
  if (videoEl.requestFullscreen) void videoEl.requestFullscreen();
1247
1282
  else if (videoEl.webkitEnterFullscreen) void videoEl.webkitEnterFullscreen();
1248
1283
  }
1249
- }, []);
1284
+ }, [fullscreenAllowed]);
1250
1285
  const videoDbClickHandler = (0, import_react2.useCallback)(() => {
1251
1286
  if (!handleClick) return;
1252
1287
  fullScreenAction();
@@ -1429,6 +1464,7 @@ var VideoPlayerBase = (props, ref) => {
1429
1464
  {
1430
1465
  variant: controlsVariant,
1431
1466
  fullScreenAction,
1467
+ fullscreenAllowed,
1432
1468
  showControl,
1433
1469
  playAction,
1434
1470
  pauseAction,
package/dist/index.d.cts CHANGED
@@ -37,6 +37,7 @@ interface VideoPlayerProps extends Omit<React.VideoHTMLAttributes<HTMLVideoEleme
37
37
  sourceType?: 'auto' | 'hls' | 'native';
38
38
  type?: string;
39
39
  controlsVariant: ControlsVariant;
40
+ active?: boolean;
40
41
  autoPlay?: boolean;
41
42
  preload?: '' | 'none' | 'auto' | 'metadata';
42
43
  loop?: boolean;
@@ -61,6 +62,7 @@ interface VideoPlayerProps extends Omit<React.VideoHTMLAttributes<HTMLVideoEleme
61
62
  duration?: number;
62
63
  onTimeChange?: (time: number, video: HTMLVideoElement) => void;
63
64
  onDurationChange?: (duration: number, video: HTMLVideoElement) => void;
65
+ videoRef?: React.Ref<HTMLVideoElement>;
64
66
  onVideoRefChange?: (video: HTMLVideoElement | null) => void;
65
67
  onActiveChange?: (payload: VideoPlayerActiveChangePayload) => void;
66
68
  onPlaybackError?: (payload: VideoPlayerPlaybackError) => void;
package/dist/index.d.ts CHANGED
@@ -37,6 +37,7 @@ interface VideoPlayerProps extends Omit<React.VideoHTMLAttributes<HTMLVideoEleme
37
37
  sourceType?: 'auto' | 'hls' | 'native';
38
38
  type?: string;
39
39
  controlsVariant: ControlsVariant;
40
+ active?: boolean;
40
41
  autoPlay?: boolean;
41
42
  preload?: '' | 'none' | 'auto' | 'metadata';
42
43
  loop?: boolean;
@@ -61,6 +62,7 @@ interface VideoPlayerProps extends Omit<React.VideoHTMLAttributes<HTMLVideoEleme
61
62
  duration?: number;
62
63
  onTimeChange?: (time: number, video: HTMLVideoElement) => void;
63
64
  onDurationChange?: (duration: number, video: HTMLVideoElement) => void;
65
+ videoRef?: React.Ref<HTMLVideoElement>;
64
66
  onVideoRefChange?: (video: HTMLVideoElement | null) => void;
65
67
  onActiveChange?: (payload: VideoPlayerActiveChangePayload) => void;
66
68
  onPlaybackError?: (payload: VideoPlayerPlaybackError) => void;
package/dist/index.js CHANGED
@@ -58,6 +58,15 @@ var VideoPlayerControlStyles = styled.div`
58
58
  outline: none;
59
59
  }
60
60
 
61
+ .video-player-control-button:disabled {
62
+ opacity: 0.42;
63
+ cursor: not-allowed;
64
+ }
65
+
66
+ .video-player-control-button:disabled:hover {
67
+ background: rgba(255, 255, 255, 0.12);
68
+ }
69
+
61
70
  .video-player-icon {
62
71
  width: 17px;
63
72
  height: 17px;
@@ -453,11 +462,23 @@ var Icon = ({ name }) => {
453
462
  return /* @__PURE__ */ jsx("svg", { "aria-hidden": "true", className: "video-player-icon", focusable: "false", viewBox: "0 0 24 24", children: paths[name] });
454
463
  };
455
464
  var ControlButton = ({
465
+ disabled,
456
466
  icon,
457
467
  label,
458
468
  onClick
459
469
  }) => {
460
- return /* @__PURE__ */ jsx("button", { "aria-label": label, className: "video-player-control-button", onClick: () => void onClick(), title: label, type: "button", children: /* @__PURE__ */ jsx(Icon, { name: icon }) });
470
+ return /* @__PURE__ */ jsx(
471
+ "button",
472
+ {
473
+ "aria-label": label,
474
+ className: "video-player-control-button",
475
+ disabled,
476
+ onClick: () => void onClick(),
477
+ title: label,
478
+ type: "button",
479
+ children: /* @__PURE__ */ jsx(Icon, { name: icon })
480
+ }
481
+ );
461
482
  };
462
483
  var stopControlClick = (e) => {
463
484
  e.preventDefault();
@@ -467,6 +488,7 @@ var VideoPlayerControls = (props) => {
467
488
  const {
468
489
  variant,
469
490
  fullScreenAction,
491
+ fullscreenAllowed,
470
492
  showControl,
471
493
  playAction,
472
494
  pauseAction,
@@ -492,7 +514,7 @@ var VideoPlayerControls = (props) => {
492
514
  return /* @__PURE__ */ jsx(VideoPlayerControlStyles, { $isMobile: isMobile, onClick: stopControlClick, $showControl: showControl, children: /* @__PURE__ */ jsxs("div", { className: "video-player-control-row", children: [
493
515
  /* @__PURE__ */ jsx("div", { className: "full" }),
494
516
  /* @__PURE__ */ jsx(ControlButton, { icon: muted ? "mute" : "sound", label: muted ? "Unmute" : "Mute", onClick: () => onMutedChange(!muted) }),
495
- /* @__PURE__ */ jsx(ControlButton, { icon: "fullscreen", label: "Fullscreen", onClick: fullScreenAction })
517
+ /* @__PURE__ */ jsx(ControlButton, { disabled: !fullscreenAllowed, icon: "fullscreen", label: "Fullscreen", onClick: fullScreenAction })
496
518
  ] }) });
497
519
  }
498
520
  return /* @__PURE__ */ jsx(VideoPlayerControlStyles, { $isMobile: isMobile, onClick: stopControlClick, $showControl: showControl, children: /* @__PURE__ */ jsxs("div", { className: "video-player-control-row", children: [
@@ -504,7 +526,7 @@ var VideoPlayerControls = (props) => {
504
526
  /* @__PURE__ */ jsx(SeekSlider, { playAction, duration, currentTime, seekSetTime }),
505
527
  /* @__PURE__ */ jsx(TimeBlock, { duration, currentTime }),
506
528
  /* @__PURE__ */ jsx(ControlButton, { icon: muted ? "mute" : "sound", label: muted ? "Unmute" : "Mute", onClick: () => onMutedChange(!muted) }),
507
- /* @__PURE__ */ jsx(ControlButton, { icon: "fullscreen", label: "Fullscreen", onClick: fullScreenAction })
529
+ /* @__PURE__ */ jsx(ControlButton, { disabled: !fullscreenAllowed, icon: "fullscreen", label: "Fullscreen", onClick: fullScreenAction })
508
530
  ] }) });
509
531
  };
510
532
 
@@ -711,9 +733,18 @@ var isLikelyHlsSource = (src) => {
711
733
  return /\.m3u8($|[?#])/i.test(src);
712
734
  }
713
735
  };
736
+ var assignRef = (ref, value) => {
737
+ if (!ref) return;
738
+ if (typeof ref === "function") {
739
+ ref(value);
740
+ return;
741
+ }
742
+ ref.current = value;
743
+ };
714
744
  var VideoPlayerBase = (props, ref) => {
715
745
  const {
716
746
  controlsVariant = "none",
747
+ active,
717
748
  autoPlay = false,
718
749
  preload = "metadata",
719
750
  loop = false,
@@ -731,6 +762,7 @@ var VideoPlayerBase = (props, ref) => {
731
762
  alwaysShowSegments = false,
732
763
  initialTime = 0,
733
764
  reloadKey,
765
+ videoRef: externalVideoRef,
734
766
  onVideoRefChange,
735
767
  handleClick = true,
736
768
  onPointerDown,
@@ -786,6 +818,7 @@ var VideoPlayerBase = (props, ref) => {
786
818
  const muted = mutedProp != null ? mutedProp : mutedState;
787
819
  const duration = durationProp != null ? durationProp : durationState;
788
820
  const currentTime = currentTimeProp != null ? currentTimeProp : currentTimeState;
821
+ const fullscreenAllowed = active != null ? active : true;
789
822
  const setTimeD = useRef(
790
823
  createThrottledNumberFn((value) => {
791
824
  const v = videoRef.current;
@@ -872,6 +905,7 @@ var VideoPlayerBase = (props, ref) => {
872
905
  prev.removeEventListener("durationchange", onDur);
873
906
  }
874
907
  videoRef.current = el;
908
+ assignRef(externalVideoRef, el);
875
909
  onVideoRefChange == null ? void 0 : onVideoRefChange(el);
876
910
  notifyActiveChange(el, "ref");
877
911
  if (!el) return;
@@ -879,7 +913,7 @@ var VideoPlayerBase = (props, ref) => {
879
913
  el.addEventListener("timeupdate", onTime);
880
914
  el.addEventListener("durationchange", onDur);
881
915
  },
882
- [muted, notifyActiveChange, onDur, onTime, onVideoRefChange]
916
+ [externalVideoRef, muted, notifyActiveChange, onDur, onTime, onVideoRefChange]
883
917
  );
884
918
  const pauseOtherVideos = useCallback(
885
919
  (el) => {
@@ -1206,6 +1240,7 @@ var VideoPlayerBase = (props, ref) => {
1206
1240
  else if (doc.msExitFullscreen) void doc.msExitFullscreen();
1207
1241
  return;
1208
1242
  }
1243
+ if (!fullscreenAllowed) return;
1209
1244
  if (containerEl) {
1210
1245
  if (containerEl.requestFullscreen) void containerEl.requestFullscreen();
1211
1246
  else if (containerEl.webkitRequestFullscreen) void containerEl.webkitRequestFullscreen();
@@ -1217,7 +1252,7 @@ var VideoPlayerBase = (props, ref) => {
1217
1252
  if (videoEl.requestFullscreen) void videoEl.requestFullscreen();
1218
1253
  else if (videoEl.webkitEnterFullscreen) void videoEl.webkitEnterFullscreen();
1219
1254
  }
1220
- }, []);
1255
+ }, [fullscreenAllowed]);
1221
1256
  const videoDbClickHandler = useCallback(() => {
1222
1257
  if (!handleClick) return;
1223
1258
  fullScreenAction();
@@ -1400,6 +1435,7 @@ var VideoPlayerBase = (props, ref) => {
1400
1435
  {
1401
1436
  variant: controlsVariant,
1402
1437
  fullScreenAction,
1438
+ fullscreenAllowed,
1403
1439
  showControl,
1404
1440
  playAction,
1405
1441
  pauseAction,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@nikelroot/video-player",
3
- "version": "0.1.3",
3
+ "version": "0.1.5",
4
4
  "description": "Standalone React video player with HLS support.",
5
5
  "type": "module",
6
6
  "main": "./dist/index.cjs",