@nikelroot/video-player 0.1.12 → 0.2.1

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
@@ -37,7 +37,19 @@ export function Example() {
37
37
  }
38
38
  ```
39
39
 
40
- When `active` is `true`, pressing `F` toggles fullscreen.
40
+ When `active` is `true`, pressing `F` toggles fullscreen. When `active` is `false`, the player releases its media source and waits until it becomes active again. In lists with several players, pass `active={index === activeIndex}` so inactive videos do not keep HLS/media pipelines open.
41
+
42
+ For public CDN-hosted videos, prefer non-credentialed requests unless the CDN is explicitly configured for cookies:
43
+
44
+ ```tsx
45
+ <VideoPlayer
46
+ videoSrc="https://cdn.example.com/stream.m3u8"
47
+ hlsCredentials="same-origin"
48
+ crossOrigin="anonymous"
49
+ />
50
+ ```
51
+
52
+ If you use `hlsCredentials="include"` or `crossOrigin="use-credentials"`, the CDN must allow credentialed CORS and should not forward `Cookie` into the cache key for public media.
41
53
 
42
54
  Build before publishing:
43
55
 
package/dist/index.cjs CHANGED
@@ -471,39 +471,39 @@ var TimeBlock = ({ duration, currentTime }) => {
471
471
  formatTime(duration)
472
472
  ] });
473
473
  };
474
+ var ICON_PATHS = {
475
+ back: /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_jsx_runtime.Fragment, { children: [
476
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("path", { d: "M11 7l-6 5 6 5V7z" }),
477
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("path", { d: "M19 7l-6 5 6 5V7z" })
478
+ ] }),
479
+ forward: /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_jsx_runtime.Fragment, { children: [
480
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("path", { d: "M5 7l6 5-6 5V7z" }),
481
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("path", { d: "M13 7l6 5-6 5V7z" })
482
+ ] }),
483
+ fullscreen: /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_jsx_runtime.Fragment, { children: [
484
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("path", { d: "M5 10V5h5" }),
485
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("path", { d: "M14 5h5v5" }),
486
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("path", { d: "M19 14v5h-5" }),
487
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("path", { d: "M10 19H5v-5" })
488
+ ] }),
489
+ mute: /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_jsx_runtime.Fragment, { children: [
490
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("path", { d: "M4 10v4h4l5 4V6l-5 4H4z" }),
491
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("path", { d: "M17 9l4 6" }),
492
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("path", { d: "M21 9l-4 6" })
493
+ ] }),
494
+ pause: /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_jsx_runtime.Fragment, { children: [
495
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("path", { d: "M8 6h3v12H8z" }),
496
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("path", { d: "M13 6h3v12h-3z" })
497
+ ] }),
498
+ play: /* @__PURE__ */ (0, import_jsx_runtime.jsx)("path", { d: "M8 5v14l11-7L8 5z" }),
499
+ sound: /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_jsx_runtime.Fragment, { children: [
500
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("path", { d: "M4 10v4h4l5 4V6l-5 4H4z" }),
501
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("path", { d: "M16 9a4 4 0 010 6" }),
502
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("path", { d: "M18.5 6.5a8 8 0 010 11" })
503
+ ] })
504
+ };
474
505
  var Icon = ({ name }) => {
475
- const paths = {
476
- back: /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_jsx_runtime.Fragment, { children: [
477
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("path", { d: "M11 7l-6 5 6 5V7z" }),
478
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("path", { d: "M19 7l-6 5 6 5V7z" })
479
- ] }),
480
- forward: /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_jsx_runtime.Fragment, { children: [
481
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("path", { d: "M5 7l6 5-6 5V7z" }),
482
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("path", { d: "M13 7l6 5-6 5V7z" })
483
- ] }),
484
- fullscreen: /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_jsx_runtime.Fragment, { children: [
485
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("path", { d: "M5 10V5h5" }),
486
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("path", { d: "M14 5h5v5" }),
487
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("path", { d: "M19 14v5h-5" }),
488
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("path", { d: "M10 19H5v-5" })
489
- ] }),
490
- mute: /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_jsx_runtime.Fragment, { children: [
491
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("path", { d: "M4 10v4h4l5 4V6l-5 4H4z" }),
492
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("path", { d: "M17 9l4 6" }),
493
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("path", { d: "M21 9l-4 6" })
494
- ] }),
495
- pause: /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_jsx_runtime.Fragment, { children: [
496
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("path", { d: "M8 6h3v12H8z" }),
497
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("path", { d: "M13 6h3v12h-3z" })
498
- ] }),
499
- play: /* @__PURE__ */ (0, import_jsx_runtime.jsx)("path", { d: "M8 5v14l11-7L8 5z" }),
500
- sound: /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_jsx_runtime.Fragment, { children: [
501
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("path", { d: "M4 10v4h4l5 4V6l-5 4H4z" }),
502
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("path", { d: "M16 9a4 4 0 010 6" }),
503
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("path", { d: "M18.5 6.5a8 8 0 010 11" })
504
- ] })
505
- };
506
- 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] });
506
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsx)("svg", { "aria-hidden": "true", className: "video-player-icon", focusable: "false", viewBox: "0 0 24 24", children: ICON_PATHS[name] });
507
507
  };
508
508
  var ControlButton = ({
509
509
  disabled,
@@ -828,7 +828,6 @@ var VideoPlayerBase = (props, ref) => {
828
828
  scrollTo = true,
829
829
  muted: mutedProp,
830
830
  defaultMuted = false,
831
- currentTime: currentTimeProp,
832
831
  duration: durationProp,
833
832
  hlsConfig,
834
833
  vodHlsConfig,
@@ -863,17 +862,20 @@ var VideoPlayerBase = (props, ref) => {
863
862
  const [showControl, setControlVisible] = (0, import_react3.useState)(true);
864
863
  const [errorState, setErrorState] = (0, import_react3.useState)(null);
865
864
  const [reloadToken, setReloadToken] = (0, import_react3.useState)(0);
865
+ const showControlRef = (0, import_react3.useRef)(showControl);
866
866
  const playing = playingProp != null ? playingProp : playingState;
867
867
  const muted = mutedProp != null ? mutedProp : mutedState;
868
868
  const isDurationControlled = durationProp !== void 0;
869
- const isCurrentTimeControlled = currentTimeProp !== void 0;
870
869
  const duration = durationProp != null ? durationProp : durationState;
871
- const currentTime = currentTimeProp != null ? currentTimeProp : currentTimeState;
870
+ const currentTime = currentTimeState;
872
871
  const fullscreenAllowed = active != null ? active : true;
872
+ const shouldLoadMedia = active !== false;
873
873
  const onTimeChangeRef = (0, import_react3.useRef)(onTimeChange);
874
874
  const onDurationChangeRef = (0, import_react3.useRef)(onDurationChange);
875
875
  onTimeChangeRef.current = onTimeChange;
876
876
  onDurationChangeRef.current = onDurationChange;
877
+ showControlRef.current = showControl;
878
+ const { currentTime: _ignoredCurrentTime, ...domVideoProps } = videoProps;
877
879
  const setTimeD = (0, import_react3.useRef)(
878
880
  createThrottledNumberFn((value) => {
879
881
  const v = videoRef.current;
@@ -881,6 +883,7 @@ var VideoPlayerBase = (props, ref) => {
881
883
  v.currentTime = value;
882
884
  }, 30)
883
885
  );
886
+ const setCurrentTimeUi = (0, import_react3.useRef)(createThrottledNumberFn((value) => setCurrentTimeState(value), 250));
884
887
  const clearTimers = (0, import_react3.useCallback)(() => {
885
888
  if (reloadTimer.current) {
886
889
  clearTimeout(reloadTimer.current);
@@ -954,9 +957,9 @@ var VideoPlayerBase = (props, ref) => {
954
957
  const el = videoRef.current;
955
958
  if (!el) return;
956
959
  const nextTime = Number.isFinite(el.currentTime) ? el.currentTime : 0;
957
- if (!isCurrentTimeControlled) setCurrentTimeState(nextTime);
960
+ setCurrentTimeUi.current(nextTime);
958
961
  (_a = onTimeChangeRef.current) == null ? void 0 : _a.call(onTimeChangeRef, nextTime, el);
959
- }, [isCurrentTimeControlled]);
962
+ }, []);
960
963
  const onDur = (0, import_react3.useCallback)(() => {
961
964
  var _a;
962
965
  const el = videoRef.current;
@@ -1037,10 +1040,11 @@ var VideoPlayerBase = (props, ref) => {
1037
1040
  if (!el) return;
1038
1041
  const next = clampTime(value, duration);
1039
1042
  setTimeD.current(next);
1040
- if (currentTimeProp === void 0) setCurrentTimeState(next);
1043
+ setCurrentTimeUi.current.cancel();
1044
+ setCurrentTimeState(next);
1041
1045
  notifyActiveChange(el, "seek");
1042
1046
  },
1043
- [currentTimeProp, duration, notifyActiveChange]
1047
+ [duration, notifyActiveChange]
1044
1048
  );
1045
1049
  const seekPrevAction = (0, import_react3.useCallback)(
1046
1050
  (sec = 15) => {
@@ -1288,10 +1292,10 @@ var VideoPlayerBase = (props, ref) => {
1288
1292
  notifyActiveChange(null, "destroy");
1289
1293
  setNextPlaying(false);
1290
1294
  if (durationProp === void 0) setDurationState(0);
1291
- if (currentTimeProp === void 0) setCurrentTimeState(0);
1295
+ setCurrentTimeUi.current.cancel();
1296
+ setCurrentTimeState(0);
1292
1297
  }, [
1293
1298
  clearTimers,
1294
- currentTimeProp,
1295
1299
  durationProp,
1296
1300
  notifyActiveChange,
1297
1301
  onDur,
@@ -1353,8 +1357,12 @@ var VideoPlayerBase = (props, ref) => {
1353
1357
  }, [clearErrorState]);
1354
1358
  const mouseMoveHandler = (0, import_react3.useCallback)(() => {
1355
1359
  if (controlTime.current) clearTimeout(controlTime.current);
1356
- setControlVisible(true);
1360
+ if (!showControlRef.current) {
1361
+ showControlRef.current = true;
1362
+ setControlVisible(true);
1363
+ }
1357
1364
  controlTime.current = setTimeout(() => {
1365
+ showControlRef.current = false;
1358
1366
  setControlVisible(false);
1359
1367
  }, 1e3 * 10);
1360
1368
  }, []);
@@ -1380,12 +1388,6 @@ var VideoPlayerBase = (props, ref) => {
1380
1388
  if (playingProp) void playAction();
1381
1389
  else pauseAction();
1382
1390
  }, [pauseAction, playAction, playingProp]);
1383
- (0, import_react3.useEffect)(() => {
1384
- const el = videoRef.current;
1385
- if (!el || currentTimeProp === void 0) return;
1386
- if (Math.abs(el.currentTime - currentTimeProp) < 0.25) return;
1387
- el.currentTime = clampTime(currentTimeProp, duration);
1388
- }, [currentTimeProp, duration]);
1389
1391
  (0, import_react3.useEffect)(() => {
1390
1392
  if (!videoRef.current) return;
1391
1393
  const loadId = sourceLoadId.current + 1;
@@ -1397,6 +1399,17 @@ var VideoPlayerBase = (props, ref) => {
1397
1399
  liveStabilityMode.current = false;
1398
1400
  liveStallEvents.current = [];
1399
1401
  resetMediaForSourceChange();
1402
+ if (!shouldLoadMedia) {
1403
+ setTimeD.current.cancel();
1404
+ setCurrentTimeUi.current.cancel();
1405
+ setDurationState(0);
1406
+ setCurrentTimeState(0);
1407
+ setPlayingState(false);
1408
+ return () => {
1409
+ sourceLoadId.current += 1;
1410
+ resetMediaForSourceChange();
1411
+ };
1412
+ }
1400
1413
  if (sourceType === "native" || type === "video") loadVideoNative(loadId);
1401
1414
  else if (sourceType === "hls") void loadVideo(initialTime, loadId);
1402
1415
  else if (isLikelyHlsSource(videoSrc)) void loadVideoHls(loadId);
@@ -1411,6 +1424,7 @@ var VideoPlayerBase = (props, ref) => {
1411
1424
  loadVideoHls,
1412
1425
  loadVideoNative,
1413
1426
  initialTime,
1427
+ shouldLoadMedia,
1414
1428
  resetMediaForSourceChange,
1415
1429
  reloadKey,
1416
1430
  reloadToken,
@@ -1459,6 +1473,7 @@ var VideoPlayerBase = (props, ref) => {
1459
1473
  (0, import_react3.useEffect)(() => {
1460
1474
  return () => {
1461
1475
  setTimeD.current.cancel();
1476
+ setCurrentTimeUi.current.cancel();
1462
1477
  destroy();
1463
1478
  };
1464
1479
  }, [destroy]);
@@ -1500,13 +1515,13 @@ var VideoPlayerBase = (props, ref) => {
1500
1515
  /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
1501
1516
  "video",
1502
1517
  {
1503
- ...videoProps,
1518
+ ...domVideoProps,
1504
1519
  controls: false,
1505
1520
  ref: setVideoEl,
1506
1521
  crossOrigin,
1507
1522
  playsInline: true,
1508
1523
  muted,
1509
- preload,
1524
+ preload: shouldLoadMedia ? preload : "none",
1510
1525
  loop,
1511
1526
  onPlay: () => setNextPlaying(true),
1512
1527
  onPause: () => setNextPlaying(false),
package/dist/index.d.cts CHANGED
@@ -58,7 +58,6 @@ interface VideoPlayerProps extends Omit<React.VideoHTMLAttributes<HTMLVideoEleme
58
58
  defaultPlaying?: boolean;
59
59
  playing?: boolean;
60
60
  onPlayingChange?: (playing: boolean) => void;
61
- currentTime?: number;
62
61
  duration?: number;
63
62
  onTimeChange?: (time: number, video: HTMLVideoElement) => void;
64
63
  onDurationChange?: (duration: number, video: HTMLVideoElement) => void;
package/dist/index.d.ts CHANGED
@@ -58,7 +58,6 @@ interface VideoPlayerProps extends Omit<React.VideoHTMLAttributes<HTMLVideoEleme
58
58
  defaultPlaying?: boolean;
59
59
  playing?: boolean;
60
60
  onPlayingChange?: (playing: boolean) => void;
61
- currentTime?: number;
62
61
  duration?: number;
63
62
  onTimeChange?: (time: number, video: HTMLVideoElement) => void;
64
63
  onDurationChange?: (duration: number, video: HTMLVideoElement) => void;
package/dist/index.js CHANGED
@@ -442,39 +442,39 @@ var TimeBlock = ({ duration, currentTime }) => {
442
442
  formatTime(duration)
443
443
  ] });
444
444
  };
445
+ var ICON_PATHS = {
446
+ back: /* @__PURE__ */ jsxs(Fragment, { children: [
447
+ /* @__PURE__ */ jsx("path", { d: "M11 7l-6 5 6 5V7z" }),
448
+ /* @__PURE__ */ jsx("path", { d: "M19 7l-6 5 6 5V7z" })
449
+ ] }),
450
+ forward: /* @__PURE__ */ jsxs(Fragment, { children: [
451
+ /* @__PURE__ */ jsx("path", { d: "M5 7l6 5-6 5V7z" }),
452
+ /* @__PURE__ */ jsx("path", { d: "M13 7l6 5-6 5V7z" })
453
+ ] }),
454
+ fullscreen: /* @__PURE__ */ jsxs(Fragment, { children: [
455
+ /* @__PURE__ */ jsx("path", { d: "M5 10V5h5" }),
456
+ /* @__PURE__ */ jsx("path", { d: "M14 5h5v5" }),
457
+ /* @__PURE__ */ jsx("path", { d: "M19 14v5h-5" }),
458
+ /* @__PURE__ */ jsx("path", { d: "M10 19H5v-5" })
459
+ ] }),
460
+ mute: /* @__PURE__ */ jsxs(Fragment, { children: [
461
+ /* @__PURE__ */ jsx("path", { d: "M4 10v4h4l5 4V6l-5 4H4z" }),
462
+ /* @__PURE__ */ jsx("path", { d: "M17 9l4 6" }),
463
+ /* @__PURE__ */ jsx("path", { d: "M21 9l-4 6" })
464
+ ] }),
465
+ pause: /* @__PURE__ */ jsxs(Fragment, { children: [
466
+ /* @__PURE__ */ jsx("path", { d: "M8 6h3v12H8z" }),
467
+ /* @__PURE__ */ jsx("path", { d: "M13 6h3v12h-3z" })
468
+ ] }),
469
+ play: /* @__PURE__ */ jsx("path", { d: "M8 5v14l11-7L8 5z" }),
470
+ sound: /* @__PURE__ */ jsxs(Fragment, { children: [
471
+ /* @__PURE__ */ jsx("path", { d: "M4 10v4h4l5 4V6l-5 4H4z" }),
472
+ /* @__PURE__ */ jsx("path", { d: "M16 9a4 4 0 010 6" }),
473
+ /* @__PURE__ */ jsx("path", { d: "M18.5 6.5a8 8 0 010 11" })
474
+ ] })
475
+ };
445
476
  var Icon = ({ name }) => {
446
- const paths = {
447
- back: /* @__PURE__ */ jsxs(Fragment, { children: [
448
- /* @__PURE__ */ jsx("path", { d: "M11 7l-6 5 6 5V7z" }),
449
- /* @__PURE__ */ jsx("path", { d: "M19 7l-6 5 6 5V7z" })
450
- ] }),
451
- forward: /* @__PURE__ */ jsxs(Fragment, { children: [
452
- /* @__PURE__ */ jsx("path", { d: "M5 7l6 5-6 5V7z" }),
453
- /* @__PURE__ */ jsx("path", { d: "M13 7l6 5-6 5V7z" })
454
- ] }),
455
- fullscreen: /* @__PURE__ */ jsxs(Fragment, { children: [
456
- /* @__PURE__ */ jsx("path", { d: "M5 10V5h5" }),
457
- /* @__PURE__ */ jsx("path", { d: "M14 5h5v5" }),
458
- /* @__PURE__ */ jsx("path", { d: "M19 14v5h-5" }),
459
- /* @__PURE__ */ jsx("path", { d: "M10 19H5v-5" })
460
- ] }),
461
- mute: /* @__PURE__ */ jsxs(Fragment, { children: [
462
- /* @__PURE__ */ jsx("path", { d: "M4 10v4h4l5 4V6l-5 4H4z" }),
463
- /* @__PURE__ */ jsx("path", { d: "M17 9l4 6" }),
464
- /* @__PURE__ */ jsx("path", { d: "M21 9l-4 6" })
465
- ] }),
466
- pause: /* @__PURE__ */ jsxs(Fragment, { children: [
467
- /* @__PURE__ */ jsx("path", { d: "M8 6h3v12H8z" }),
468
- /* @__PURE__ */ jsx("path", { d: "M13 6h3v12h-3z" })
469
- ] }),
470
- play: /* @__PURE__ */ jsx("path", { d: "M8 5v14l11-7L8 5z" }),
471
- sound: /* @__PURE__ */ jsxs(Fragment, { children: [
472
- /* @__PURE__ */ jsx("path", { d: "M4 10v4h4l5 4V6l-5 4H4z" }),
473
- /* @__PURE__ */ jsx("path", { d: "M16 9a4 4 0 010 6" }),
474
- /* @__PURE__ */ jsx("path", { d: "M18.5 6.5a8 8 0 010 11" })
475
- ] })
476
- };
477
- return /* @__PURE__ */ jsx("svg", { "aria-hidden": "true", className: "video-player-icon", focusable: "false", viewBox: "0 0 24 24", children: paths[name] });
477
+ return /* @__PURE__ */ jsx("svg", { "aria-hidden": "true", className: "video-player-icon", focusable: "false", viewBox: "0 0 24 24", children: ICON_PATHS[name] });
478
478
  };
479
479
  var ControlButton = ({
480
480
  disabled,
@@ -799,7 +799,6 @@ var VideoPlayerBase = (props, ref) => {
799
799
  scrollTo = true,
800
800
  muted: mutedProp,
801
801
  defaultMuted = false,
802
- currentTime: currentTimeProp,
803
802
  duration: durationProp,
804
803
  hlsConfig,
805
804
  vodHlsConfig,
@@ -834,17 +833,20 @@ var VideoPlayerBase = (props, ref) => {
834
833
  const [showControl, setControlVisible] = useState(true);
835
834
  const [errorState, setErrorState] = useState(null);
836
835
  const [reloadToken, setReloadToken] = useState(0);
836
+ const showControlRef = useRef2(showControl);
837
837
  const playing = playingProp != null ? playingProp : playingState;
838
838
  const muted = mutedProp != null ? mutedProp : mutedState;
839
839
  const isDurationControlled = durationProp !== void 0;
840
- const isCurrentTimeControlled = currentTimeProp !== void 0;
841
840
  const duration = durationProp != null ? durationProp : durationState;
842
- const currentTime = currentTimeProp != null ? currentTimeProp : currentTimeState;
841
+ const currentTime = currentTimeState;
843
842
  const fullscreenAllowed = active != null ? active : true;
843
+ const shouldLoadMedia = active !== false;
844
844
  const onTimeChangeRef = useRef2(onTimeChange);
845
845
  const onDurationChangeRef = useRef2(onDurationChange);
846
846
  onTimeChangeRef.current = onTimeChange;
847
847
  onDurationChangeRef.current = onDurationChange;
848
+ showControlRef.current = showControl;
849
+ const { currentTime: _ignoredCurrentTime, ...domVideoProps } = videoProps;
848
850
  const setTimeD = useRef2(
849
851
  createThrottledNumberFn((value) => {
850
852
  const v = videoRef.current;
@@ -852,6 +854,7 @@ var VideoPlayerBase = (props, ref) => {
852
854
  v.currentTime = value;
853
855
  }, 30)
854
856
  );
857
+ const setCurrentTimeUi = useRef2(createThrottledNumberFn((value) => setCurrentTimeState(value), 250));
855
858
  const clearTimers = useCallback(() => {
856
859
  if (reloadTimer.current) {
857
860
  clearTimeout(reloadTimer.current);
@@ -925,9 +928,9 @@ var VideoPlayerBase = (props, ref) => {
925
928
  const el = videoRef.current;
926
929
  if (!el) return;
927
930
  const nextTime = Number.isFinite(el.currentTime) ? el.currentTime : 0;
928
- if (!isCurrentTimeControlled) setCurrentTimeState(nextTime);
931
+ setCurrentTimeUi.current(nextTime);
929
932
  (_a = onTimeChangeRef.current) == null ? void 0 : _a.call(onTimeChangeRef, nextTime, el);
930
- }, [isCurrentTimeControlled]);
933
+ }, []);
931
934
  const onDur = useCallback(() => {
932
935
  var _a;
933
936
  const el = videoRef.current;
@@ -1008,10 +1011,11 @@ var VideoPlayerBase = (props, ref) => {
1008
1011
  if (!el) return;
1009
1012
  const next = clampTime(value, duration);
1010
1013
  setTimeD.current(next);
1011
- if (currentTimeProp === void 0) setCurrentTimeState(next);
1014
+ setCurrentTimeUi.current.cancel();
1015
+ setCurrentTimeState(next);
1012
1016
  notifyActiveChange(el, "seek");
1013
1017
  },
1014
- [currentTimeProp, duration, notifyActiveChange]
1018
+ [duration, notifyActiveChange]
1015
1019
  );
1016
1020
  const seekPrevAction = useCallback(
1017
1021
  (sec = 15) => {
@@ -1259,10 +1263,10 @@ var VideoPlayerBase = (props, ref) => {
1259
1263
  notifyActiveChange(null, "destroy");
1260
1264
  setNextPlaying(false);
1261
1265
  if (durationProp === void 0) setDurationState(0);
1262
- if (currentTimeProp === void 0) setCurrentTimeState(0);
1266
+ setCurrentTimeUi.current.cancel();
1267
+ setCurrentTimeState(0);
1263
1268
  }, [
1264
1269
  clearTimers,
1265
- currentTimeProp,
1266
1270
  durationProp,
1267
1271
  notifyActiveChange,
1268
1272
  onDur,
@@ -1324,8 +1328,12 @@ var VideoPlayerBase = (props, ref) => {
1324
1328
  }, [clearErrorState]);
1325
1329
  const mouseMoveHandler = useCallback(() => {
1326
1330
  if (controlTime.current) clearTimeout(controlTime.current);
1327
- setControlVisible(true);
1331
+ if (!showControlRef.current) {
1332
+ showControlRef.current = true;
1333
+ setControlVisible(true);
1334
+ }
1328
1335
  controlTime.current = setTimeout(() => {
1336
+ showControlRef.current = false;
1329
1337
  setControlVisible(false);
1330
1338
  }, 1e3 * 10);
1331
1339
  }, []);
@@ -1351,12 +1359,6 @@ var VideoPlayerBase = (props, ref) => {
1351
1359
  if (playingProp) void playAction();
1352
1360
  else pauseAction();
1353
1361
  }, [pauseAction, playAction, playingProp]);
1354
- useEffect(() => {
1355
- const el = videoRef.current;
1356
- if (!el || currentTimeProp === void 0) return;
1357
- if (Math.abs(el.currentTime - currentTimeProp) < 0.25) return;
1358
- el.currentTime = clampTime(currentTimeProp, duration);
1359
- }, [currentTimeProp, duration]);
1360
1362
  useEffect(() => {
1361
1363
  if (!videoRef.current) return;
1362
1364
  const loadId = sourceLoadId.current + 1;
@@ -1368,6 +1370,17 @@ var VideoPlayerBase = (props, ref) => {
1368
1370
  liveStabilityMode.current = false;
1369
1371
  liveStallEvents.current = [];
1370
1372
  resetMediaForSourceChange();
1373
+ if (!shouldLoadMedia) {
1374
+ setTimeD.current.cancel();
1375
+ setCurrentTimeUi.current.cancel();
1376
+ setDurationState(0);
1377
+ setCurrentTimeState(0);
1378
+ setPlayingState(false);
1379
+ return () => {
1380
+ sourceLoadId.current += 1;
1381
+ resetMediaForSourceChange();
1382
+ };
1383
+ }
1371
1384
  if (sourceType === "native" || type === "video") loadVideoNative(loadId);
1372
1385
  else if (sourceType === "hls") void loadVideo(initialTime, loadId);
1373
1386
  else if (isLikelyHlsSource(videoSrc)) void loadVideoHls(loadId);
@@ -1382,6 +1395,7 @@ var VideoPlayerBase = (props, ref) => {
1382
1395
  loadVideoHls,
1383
1396
  loadVideoNative,
1384
1397
  initialTime,
1398
+ shouldLoadMedia,
1385
1399
  resetMediaForSourceChange,
1386
1400
  reloadKey,
1387
1401
  reloadToken,
@@ -1430,6 +1444,7 @@ var VideoPlayerBase = (props, ref) => {
1430
1444
  useEffect(() => {
1431
1445
  return () => {
1432
1446
  setTimeD.current.cancel();
1447
+ setCurrentTimeUi.current.cancel();
1433
1448
  destroy();
1434
1449
  };
1435
1450
  }, [destroy]);
@@ -1471,13 +1486,13 @@ var VideoPlayerBase = (props, ref) => {
1471
1486
  /* @__PURE__ */ jsx2(
1472
1487
  "video",
1473
1488
  {
1474
- ...videoProps,
1489
+ ...domVideoProps,
1475
1490
  controls: false,
1476
1491
  ref: setVideoEl,
1477
1492
  crossOrigin,
1478
1493
  playsInline: true,
1479
1494
  muted,
1480
- preload,
1495
+ preload: shouldLoadMedia ? preload : "none",
1481
1496
  loop,
1482
1497
  onPlay: () => setNextPlaying(true),
1483
1498
  onPause: () => setNextPlaying(false),
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@nikelroot/video-player",
3
- "version": "0.1.12",
3
+ "version": "0.2.1",
4
4
  "description": "Standalone React video player with HLS support.",
5
5
  "type": "module",
6
6
  "main": "./dist/index.cjs",