analytica-frontend-lib 1.1.10 → 1.1.12
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/dist/VideoPlayer/index.js +367 -183
- package/dist/VideoPlayer/index.js.map +1 -1
- package/dist/VideoPlayer/index.mjs +373 -184
- package/dist/VideoPlayer/index.mjs.map +1 -1
- package/dist/index.css +10 -3
- package/dist/index.css.map +1 -1
- package/dist/index.js +367 -183
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +373 -184
- package/dist/index.mjs.map +1 -1
- package/dist/styles.css +10 -3
- package/dist/styles.css.map +1 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -6826,12 +6826,93 @@ var NotFound_default = NotFound;
|
|
|
6826
6826
|
var import_react22 = require("react");
|
|
6827
6827
|
var import_phosphor_react18 = require("phosphor-react");
|
|
6828
6828
|
var import_jsx_runtime36 = require("react/jsx-runtime");
|
|
6829
|
+
var CONTROLS_HIDE_TIMEOUT = 3e3;
|
|
6830
|
+
var LEAVE_HIDE_TIMEOUT = 1e3;
|
|
6829
6831
|
var formatTime = (seconds) => {
|
|
6830
6832
|
if (!seconds || isNaN(seconds)) return "0:00";
|
|
6831
6833
|
const mins = Math.floor(seconds / 60);
|
|
6832
6834
|
const secs = Math.floor(seconds % 60);
|
|
6833
6835
|
return `${mins}:${secs.toString().padStart(2, "0")}`;
|
|
6834
6836
|
};
|
|
6837
|
+
var ProgressBar2 = ({
|
|
6838
|
+
currentTime,
|
|
6839
|
+
duration,
|
|
6840
|
+
progressPercentage,
|
|
6841
|
+
onSeek
|
|
6842
|
+
}) => /* @__PURE__ */ (0, import_jsx_runtime36.jsx)("div", { className: "px-4 pb-2", children: /* @__PURE__ */ (0, import_jsx_runtime36.jsx)(
|
|
6843
|
+
"input",
|
|
6844
|
+
{
|
|
6845
|
+
type: "range",
|
|
6846
|
+
min: 0,
|
|
6847
|
+
max: duration || 100,
|
|
6848
|
+
value: currentTime,
|
|
6849
|
+
onChange: (e) => onSeek(parseFloat(e.target.value)),
|
|
6850
|
+
className: "w-full h-1 bg-neutral-600 rounded-full appearance-none cursor-pointer slider:bg-primary-600 focus:outline-none focus:ring-2 focus:ring-primary-500",
|
|
6851
|
+
"aria-label": "Video progress",
|
|
6852
|
+
style: {
|
|
6853
|
+
background: `linear-gradient(to right, var(--color-primary-700) ${progressPercentage}%, var(--color-secondary-300) ${progressPercentage}%)`
|
|
6854
|
+
}
|
|
6855
|
+
}
|
|
6856
|
+
) });
|
|
6857
|
+
var VolumeControls = ({
|
|
6858
|
+
volume,
|
|
6859
|
+
isMuted,
|
|
6860
|
+
onVolumeChange,
|
|
6861
|
+
onToggleMute
|
|
6862
|
+
}) => /* @__PURE__ */ (0, import_jsx_runtime36.jsxs)("div", { className: "flex items-center gap-2", children: [
|
|
6863
|
+
/* @__PURE__ */ (0, import_jsx_runtime36.jsx)(
|
|
6864
|
+
IconButton_default,
|
|
6865
|
+
{
|
|
6866
|
+
icon: isMuted ? /* @__PURE__ */ (0, import_jsx_runtime36.jsx)(import_phosphor_react18.SpeakerSlash, { size: 24 }) : /* @__PURE__ */ (0, import_jsx_runtime36.jsx)(import_phosphor_react18.SpeakerHigh, { size: 24 }),
|
|
6867
|
+
onClick: onToggleMute,
|
|
6868
|
+
"aria-label": isMuted ? "Unmute" : "Mute",
|
|
6869
|
+
className: "!bg-transparent !text-white hover:!bg-white/20"
|
|
6870
|
+
}
|
|
6871
|
+
),
|
|
6872
|
+
/* @__PURE__ */ (0, import_jsx_runtime36.jsx)(
|
|
6873
|
+
"input",
|
|
6874
|
+
{
|
|
6875
|
+
type: "range",
|
|
6876
|
+
min: 0,
|
|
6877
|
+
max: 100,
|
|
6878
|
+
value: Math.round(volume * 100),
|
|
6879
|
+
onChange: (e) => onVolumeChange(parseInt(e.target.value)),
|
|
6880
|
+
className: "w-20 h-1 bg-neutral-600 rounded-full appearance-none cursor-pointer focus:outline-none focus:ring-2 focus:ring-primary-500",
|
|
6881
|
+
"aria-label": "Volume control",
|
|
6882
|
+
style: {
|
|
6883
|
+
background: `linear-gradient(to right, var(--color-primary-700) ${volume * 100}%, var(--color-secondary-300) ${volume * 100}%)`
|
|
6884
|
+
}
|
|
6885
|
+
}
|
|
6886
|
+
)
|
|
6887
|
+
] });
|
|
6888
|
+
var SpeedMenu = ({
|
|
6889
|
+
showSpeedMenu,
|
|
6890
|
+
playbackRate,
|
|
6891
|
+
onToggleMenu,
|
|
6892
|
+
onSpeedChange
|
|
6893
|
+
}) => /* @__PURE__ */ (0, import_jsx_runtime36.jsxs)("div", { className: "relative", children: [
|
|
6894
|
+
/* @__PURE__ */ (0, import_jsx_runtime36.jsx)(
|
|
6895
|
+
IconButton_default,
|
|
6896
|
+
{
|
|
6897
|
+
icon: /* @__PURE__ */ (0, import_jsx_runtime36.jsx)(import_phosphor_react18.DotsThreeVertical, { size: 24 }),
|
|
6898
|
+
onClick: onToggleMenu,
|
|
6899
|
+
"aria-label": "Playback speed",
|
|
6900
|
+
className: "!bg-transparent !text-white hover:!bg-white/20"
|
|
6901
|
+
}
|
|
6902
|
+
),
|
|
6903
|
+
showSpeedMenu && /* @__PURE__ */ (0, import_jsx_runtime36.jsx)("div", { className: "absolute bottom-12 right-0 bg-black/90 rounded-lg p-2 min-w-20", children: [0.5, 0.75, 1, 1.25, 1.5, 2].map((speed) => /* @__PURE__ */ (0, import_jsx_runtime36.jsxs)(
|
|
6904
|
+
"button",
|
|
6905
|
+
{
|
|
6906
|
+
onClick: () => onSpeedChange(speed),
|
|
6907
|
+
className: `block w-full text-left px-3 py-1 text-sm rounded hover:bg-white/20 transition-colors ${playbackRate === speed ? "text-primary-400" : "text-white"}`,
|
|
6908
|
+
children: [
|
|
6909
|
+
speed,
|
|
6910
|
+
"x"
|
|
6911
|
+
]
|
|
6912
|
+
},
|
|
6913
|
+
speed
|
|
6914
|
+
)) })
|
|
6915
|
+
] });
|
|
6835
6916
|
var VideoPlayer = ({
|
|
6836
6917
|
src,
|
|
6837
6918
|
poster,
|
|
@@ -6856,10 +6937,68 @@ var VideoPlayer = ({
|
|
|
6856
6937
|
const [showControls, setShowControls] = (0, import_react22.useState)(true);
|
|
6857
6938
|
const [hasCompleted, setHasCompleted] = (0, import_react22.useState)(false);
|
|
6858
6939
|
const [showCaptions, setShowCaptions] = (0, import_react22.useState)(false);
|
|
6940
|
+
(0, import_react22.useEffect)(() => {
|
|
6941
|
+
setHasCompleted(false);
|
|
6942
|
+
}, [src]);
|
|
6859
6943
|
const [playbackRate, setPlaybackRate] = (0, import_react22.useState)(1);
|
|
6860
6944
|
const [showSpeedMenu, setShowSpeedMenu] = (0, import_react22.useState)(false);
|
|
6861
6945
|
const lastSaveTimeRef = (0, import_react22.useRef)(0);
|
|
6862
6946
|
const trackRef = (0, import_react22.useRef)(null);
|
|
6947
|
+
const controlsTimeoutRef = (0, import_react22.useRef)(null);
|
|
6948
|
+
const lastMousePositionRef = (0, import_react22.useRef)({ x: 0, y: 0 });
|
|
6949
|
+
const mouseMoveTimeoutRef = (0, import_react22.useRef)(null);
|
|
6950
|
+
const isUserInteracting = (0, import_react22.useCallback)(() => {
|
|
6951
|
+
if (showSpeedMenu) return true;
|
|
6952
|
+
const activeElement = document.activeElement;
|
|
6953
|
+
const videoContainer = videoRef.current?.parentElement;
|
|
6954
|
+
if (activeElement && videoContainer?.contains(activeElement)) {
|
|
6955
|
+
const isControl = activeElement.matches("button, input, [tabindex]");
|
|
6956
|
+
if (isControl) return true;
|
|
6957
|
+
}
|
|
6958
|
+
return false;
|
|
6959
|
+
}, [showSpeedMenu]);
|
|
6960
|
+
const clearControlsTimeout = (0, import_react22.useCallback)(() => {
|
|
6961
|
+
if (controlsTimeoutRef.current) {
|
|
6962
|
+
clearTimeout(controlsTimeoutRef.current);
|
|
6963
|
+
controlsTimeoutRef.current = null;
|
|
6964
|
+
}
|
|
6965
|
+
}, []);
|
|
6966
|
+
const clearMouseMoveTimeout = (0, import_react22.useCallback)(() => {
|
|
6967
|
+
if (mouseMoveTimeoutRef.current) {
|
|
6968
|
+
clearTimeout(mouseMoveTimeoutRef.current);
|
|
6969
|
+
mouseMoveTimeoutRef.current = null;
|
|
6970
|
+
}
|
|
6971
|
+
}, []);
|
|
6972
|
+
const showControlsWithTimer = (0, import_react22.useCallback)(() => {
|
|
6973
|
+
setShowControls(true);
|
|
6974
|
+
clearControlsTimeout();
|
|
6975
|
+
if (isPlaying) {
|
|
6976
|
+
controlsTimeoutRef.current = window.setTimeout(() => {
|
|
6977
|
+
setShowControls(false);
|
|
6978
|
+
}, CONTROLS_HIDE_TIMEOUT);
|
|
6979
|
+
}
|
|
6980
|
+
}, [isPlaying, clearControlsTimeout]);
|
|
6981
|
+
const handleMouseMove = (0, import_react22.useCallback)(
|
|
6982
|
+
(event) => {
|
|
6983
|
+
const currentX = event.clientX;
|
|
6984
|
+
const currentY = event.clientY;
|
|
6985
|
+
const lastPos = lastMousePositionRef.current;
|
|
6986
|
+
const hasMoved = Math.abs(currentX - lastPos.x) > 5 || Math.abs(currentY - lastPos.y) > 5;
|
|
6987
|
+
if (hasMoved) {
|
|
6988
|
+
lastMousePositionRef.current = { x: currentX, y: currentY };
|
|
6989
|
+
showControlsWithTimer();
|
|
6990
|
+
}
|
|
6991
|
+
},
|
|
6992
|
+
[showControlsWithTimer]
|
|
6993
|
+
);
|
|
6994
|
+
const handleMouseLeave = (0, import_react22.useCallback)(() => {
|
|
6995
|
+
clearControlsTimeout();
|
|
6996
|
+
if (isPlaying && !isUserInteracting()) {
|
|
6997
|
+
controlsTimeoutRef.current = window.setTimeout(() => {
|
|
6998
|
+
setShowControls(false);
|
|
6999
|
+
}, LEAVE_HIDE_TIMEOUT);
|
|
7000
|
+
}
|
|
7001
|
+
}, [isPlaying, clearControlsTimeout, isUserInteracting]);
|
|
6863
7002
|
(0, import_react22.useEffect)(() => {
|
|
6864
7003
|
if (videoRef.current) {
|
|
6865
7004
|
videoRef.current.volume = volume;
|
|
@@ -6867,84 +7006,129 @@ var VideoPlayer = ({
|
|
|
6867
7006
|
}
|
|
6868
7007
|
}, [volume, isMuted]);
|
|
6869
7008
|
(0, import_react22.useEffect)(() => {
|
|
6870
|
-
|
|
6871
|
-
|
|
6872
|
-
const
|
|
6873
|
-
const
|
|
6874
|
-
const
|
|
6875
|
-
|
|
6876
|
-
|
|
6877
|
-
|
|
6878
|
-
|
|
6879
|
-
|
|
7009
|
+
const video = videoRef.current;
|
|
7010
|
+
if (!video) return;
|
|
7011
|
+
const onPlay = () => setIsPlaying(true);
|
|
7012
|
+
const onPause = () => setIsPlaying(false);
|
|
7013
|
+
const onEnded = () => setIsPlaying(false);
|
|
7014
|
+
video.addEventListener("play", onPlay);
|
|
7015
|
+
video.addEventListener("pause", onPause);
|
|
7016
|
+
video.addEventListener("ended", onEnded);
|
|
7017
|
+
return () => {
|
|
7018
|
+
video.removeEventListener("play", onPlay);
|
|
7019
|
+
video.removeEventListener("pause", onPause);
|
|
7020
|
+
video.removeEventListener("ended", onEnded);
|
|
7021
|
+
};
|
|
7022
|
+
}, []);
|
|
7023
|
+
(0, import_react22.useEffect)(() => {
|
|
7024
|
+
if (isPlaying) {
|
|
7025
|
+
showControlsWithTimer();
|
|
6880
7026
|
} else {
|
|
6881
|
-
|
|
7027
|
+
clearControlsTimeout();
|
|
7028
|
+
setShowControls(true);
|
|
7029
|
+
}
|
|
7030
|
+
}, [isPlaying, showControlsWithTimer, clearControlsTimeout]);
|
|
7031
|
+
(0, import_react22.useEffect)(() => {
|
|
7032
|
+
const handleFullscreenChange = () => {
|
|
7033
|
+
const isCurrentlyFullscreen = !!document.fullscreenElement;
|
|
7034
|
+
setIsFullscreen(isCurrentlyFullscreen);
|
|
7035
|
+
if (isCurrentlyFullscreen) {
|
|
7036
|
+
showControlsWithTimer();
|
|
7037
|
+
}
|
|
7038
|
+
};
|
|
7039
|
+
document.addEventListener("fullscreenchange", handleFullscreenChange);
|
|
7040
|
+
return () => {
|
|
7041
|
+
document.removeEventListener("fullscreenchange", handleFullscreenChange);
|
|
7042
|
+
};
|
|
7043
|
+
}, [showControlsWithTimer]);
|
|
7044
|
+
const getInitialTime = (0, import_react22.useCallback)(() => {
|
|
7045
|
+
if (!autoSave || !storageKey) {
|
|
7046
|
+
return Number.isFinite(initialTime) && initialTime >= 0 ? initialTime : void 0;
|
|
6882
7047
|
}
|
|
7048
|
+
const saved = Number(localStorage.getItem(`${storageKey}-${src}`) || NaN);
|
|
7049
|
+
const hasValidInitial = Number.isFinite(initialTime) && initialTime >= 0;
|
|
7050
|
+
const hasValidSaved = Number.isFinite(saved) && saved >= 0;
|
|
7051
|
+
if (hasValidInitial) return initialTime;
|
|
7052
|
+
if (hasValidSaved) return saved;
|
|
7053
|
+
return void 0;
|
|
7054
|
+
}, [autoSave, storageKey, src, initialTime]);
|
|
7055
|
+
(0, import_react22.useEffect)(() => {
|
|
7056
|
+
const start = getInitialTime();
|
|
6883
7057
|
if (start !== void 0 && videoRef.current) {
|
|
6884
7058
|
videoRef.current.currentTime = start;
|
|
6885
7059
|
setCurrentTime(start);
|
|
6886
7060
|
}
|
|
6887
|
-
}, [
|
|
6888
|
-
const saveProgress = (0, import_react22.useCallback)(
|
|
6889
|
-
|
|
6890
|
-
|
|
6891
|
-
|
|
6892
|
-
|
|
6893
|
-
|
|
6894
|
-
|
|
6895
|
-
}, [autoSave, storageKey, src, currentTime]);
|
|
6896
|
-
const togglePlayPause = (0, import_react22.useCallback)(() => {
|
|
6897
|
-
if (videoRef.current) {
|
|
6898
|
-
if (isPlaying) {
|
|
6899
|
-
videoRef.current.pause();
|
|
6900
|
-
} else {
|
|
6901
|
-
videoRef.current.play();
|
|
7061
|
+
}, [getInitialTime]);
|
|
7062
|
+
const saveProgress = (0, import_react22.useCallback)(
|
|
7063
|
+
(time) => {
|
|
7064
|
+
if (!autoSave || !storageKey) return;
|
|
7065
|
+
const now = Date.now();
|
|
7066
|
+
if (now - lastSaveTimeRef.current > 5e3) {
|
|
7067
|
+
localStorage.setItem(`${storageKey}-${src}`, time.toString());
|
|
7068
|
+
lastSaveTimeRef.current = now;
|
|
6902
7069
|
}
|
|
6903
|
-
|
|
7070
|
+
},
|
|
7071
|
+
[autoSave, storageKey, src]
|
|
7072
|
+
);
|
|
7073
|
+
const togglePlayPause = (0, import_react22.useCallback)(async () => {
|
|
7074
|
+
const video = videoRef.current;
|
|
7075
|
+
if (!video) return;
|
|
7076
|
+
if (!video.paused) {
|
|
7077
|
+
video.pause();
|
|
7078
|
+
return;
|
|
7079
|
+
}
|
|
7080
|
+
try {
|
|
7081
|
+
await video.play();
|
|
7082
|
+
} catch {
|
|
6904
7083
|
}
|
|
6905
|
-
}, [
|
|
7084
|
+
}, []);
|
|
6906
7085
|
const handleVolumeChange = (0, import_react22.useCallback)(
|
|
6907
7086
|
(newVolume) => {
|
|
6908
|
-
|
|
6909
|
-
|
|
6910
|
-
|
|
6911
|
-
|
|
6912
|
-
|
|
6913
|
-
|
|
6914
|
-
|
|
6915
|
-
|
|
6916
|
-
|
|
6917
|
-
|
|
6918
|
-
|
|
7087
|
+
const video = videoRef.current;
|
|
7088
|
+
if (!video) return;
|
|
7089
|
+
const volumeValue = newVolume / 100;
|
|
7090
|
+
video.volume = volumeValue;
|
|
7091
|
+
setVolume(volumeValue);
|
|
7092
|
+
const shouldMute = volumeValue === 0;
|
|
7093
|
+
const shouldUnmute = volumeValue > 0 && isMuted;
|
|
7094
|
+
if (shouldMute) {
|
|
7095
|
+
video.muted = true;
|
|
7096
|
+
setIsMuted(true);
|
|
7097
|
+
} else if (shouldUnmute) {
|
|
7098
|
+
video.muted = false;
|
|
7099
|
+
setIsMuted(false);
|
|
6919
7100
|
}
|
|
6920
7101
|
},
|
|
6921
7102
|
[isMuted]
|
|
6922
7103
|
);
|
|
6923
7104
|
const toggleMute = (0, import_react22.useCallback)(() => {
|
|
6924
|
-
|
|
6925
|
-
|
|
6926
|
-
|
|
6927
|
-
|
|
6928
|
-
|
|
6929
|
-
|
|
6930
|
-
|
|
6931
|
-
|
|
6932
|
-
|
|
6933
|
-
|
|
6934
|
-
|
|
7105
|
+
const video = videoRef.current;
|
|
7106
|
+
if (!video) return;
|
|
7107
|
+
if (isMuted) {
|
|
7108
|
+
const restoreVolume = volume > 0 ? volume : 0.5;
|
|
7109
|
+
video.volume = restoreVolume;
|
|
7110
|
+
video.muted = false;
|
|
7111
|
+
setVolume(restoreVolume);
|
|
7112
|
+
setIsMuted(false);
|
|
7113
|
+
} else {
|
|
7114
|
+
video.muted = true;
|
|
7115
|
+
setIsMuted(true);
|
|
6935
7116
|
}
|
|
6936
7117
|
}, [isMuted, volume]);
|
|
7118
|
+
const handleSeek = (0, import_react22.useCallback)((newTime) => {
|
|
7119
|
+
const video = videoRef.current;
|
|
7120
|
+
if (video) {
|
|
7121
|
+
video.currentTime = newTime;
|
|
7122
|
+
}
|
|
7123
|
+
}, []);
|
|
6937
7124
|
const toggleFullscreen = (0, import_react22.useCallback)(() => {
|
|
6938
7125
|
const container = videoRef.current?.parentElement;
|
|
6939
7126
|
if (!container) return;
|
|
6940
|
-
if (!isFullscreen) {
|
|
6941
|
-
|
|
6942
|
-
|
|
6943
|
-
}
|
|
6944
|
-
} else if (document.exitFullscreen) {
|
|
7127
|
+
if (!isFullscreen && container.requestFullscreen) {
|
|
7128
|
+
container.requestFullscreen();
|
|
7129
|
+
} else if (isFullscreen && document.exitFullscreen) {
|
|
6945
7130
|
document.exitFullscreen();
|
|
6946
7131
|
}
|
|
6947
|
-
setIsFullscreen(!isFullscreen);
|
|
6948
7132
|
}, [isFullscreen]);
|
|
6949
7133
|
const handleSpeedChange = (0, import_react22.useCallback)((speed) => {
|
|
6950
7134
|
if (videoRef.current) {
|
|
@@ -6962,29 +7146,28 @@ var VideoPlayer = ({
|
|
|
6962
7146
|
setShowCaptions(newShowCaptions);
|
|
6963
7147
|
trackRef.current.track.mode = newShowCaptions && subtitles ? "showing" : "hidden";
|
|
6964
7148
|
}, [showCaptions, subtitles]);
|
|
6965
|
-
const
|
|
6966
|
-
|
|
6967
|
-
|
|
6968
|
-
|
|
6969
|
-
|
|
6970
|
-
onTimeUpdate?.(current);
|
|
6971
|
-
if (duration > 0) {
|
|
6972
|
-
const progressPercent = current / duration * 100;
|
|
6973
|
-
onProgress?.(progressPercent);
|
|
6974
|
-
if (progressPercent >= 95 && !hasCompleted) {
|
|
6975
|
-
setHasCompleted(true);
|
|
6976
|
-
onVideoComplete?.();
|
|
6977
|
-
}
|
|
7149
|
+
const checkVideoCompletion = (0, import_react22.useCallback)(
|
|
7150
|
+
(progressPercent) => {
|
|
7151
|
+
if (progressPercent >= 95 && !hasCompleted) {
|
|
7152
|
+
setHasCompleted(true);
|
|
7153
|
+
onVideoComplete?.();
|
|
6978
7154
|
}
|
|
7155
|
+
},
|
|
7156
|
+
[hasCompleted, onVideoComplete]
|
|
7157
|
+
);
|
|
7158
|
+
const handleTimeUpdate = (0, import_react22.useCallback)(() => {
|
|
7159
|
+
const video = videoRef.current;
|
|
7160
|
+
if (!video) return;
|
|
7161
|
+
const current = video.currentTime;
|
|
7162
|
+
setCurrentTime(current);
|
|
7163
|
+
saveProgress(current);
|
|
7164
|
+
onTimeUpdate?.(current);
|
|
7165
|
+
if (duration > 0) {
|
|
7166
|
+
const progressPercent = current / duration * 100;
|
|
7167
|
+
onProgress?.(progressPercent);
|
|
7168
|
+
checkVideoCompletion(progressPercent);
|
|
6979
7169
|
}
|
|
6980
|
-
}, [
|
|
6981
|
-
duration,
|
|
6982
|
-
saveProgress,
|
|
6983
|
-
onTimeUpdate,
|
|
6984
|
-
onProgress,
|
|
6985
|
-
onVideoComplete,
|
|
6986
|
-
hasCompleted
|
|
6987
|
-
]);
|
|
7170
|
+
}, [duration, saveProgress, onTimeUpdate, onProgress, checkVideoCompletion]);
|
|
6988
7171
|
const handleLoadedMetadata = (0, import_react22.useCallback)(() => {
|
|
6989
7172
|
if (videoRef.current) {
|
|
6990
7173
|
setDuration(videoRef.current.duration);
|
|
@@ -7013,9 +7196,78 @@ var VideoPlayer = ({
|
|
|
7013
7196
|
return () => {
|
|
7014
7197
|
document.removeEventListener("visibilitychange", handleVisibilityChange);
|
|
7015
7198
|
window.removeEventListener("blur", handleBlur);
|
|
7199
|
+
clearControlsTimeout();
|
|
7200
|
+
clearMouseMoveTimeout();
|
|
7016
7201
|
};
|
|
7017
|
-
}, [isPlaying]);
|
|
7202
|
+
}, [isPlaying, clearControlsTimeout, clearMouseMoveTimeout]);
|
|
7018
7203
|
const progressPercentage = duration > 0 ? currentTime / duration * 100 : 0;
|
|
7204
|
+
const getTopControlsOpacity = (0, import_react22.useCallback)(() => {
|
|
7205
|
+
if (isFullscreen) {
|
|
7206
|
+
return showControls ? "opacity-100" : "opacity-0";
|
|
7207
|
+
}
|
|
7208
|
+
return !isPlaying || showControls ? "opacity-100" : "opacity-0 group-hover:opacity-100";
|
|
7209
|
+
}, [isFullscreen, showControls, isPlaying]);
|
|
7210
|
+
const getBottomControlsOpacity = (0, import_react22.useCallback)(() => {
|
|
7211
|
+
if (isFullscreen) {
|
|
7212
|
+
return showControls ? "opacity-100" : "opacity-0";
|
|
7213
|
+
}
|
|
7214
|
+
return !isPlaying || showControls ? "opacity-100" : "opacity-0 group-hover:opacity-100";
|
|
7215
|
+
}, [isFullscreen, showControls, isPlaying]);
|
|
7216
|
+
const handleVideoKeyDown = (0, import_react22.useCallback)(
|
|
7217
|
+
(e) => {
|
|
7218
|
+
if (e.key) {
|
|
7219
|
+
e.stopPropagation();
|
|
7220
|
+
showControlsWithTimer();
|
|
7221
|
+
}
|
|
7222
|
+
switch (e.key) {
|
|
7223
|
+
case " ":
|
|
7224
|
+
case "Enter":
|
|
7225
|
+
e.preventDefault();
|
|
7226
|
+
togglePlayPause();
|
|
7227
|
+
break;
|
|
7228
|
+
case "ArrowLeft":
|
|
7229
|
+
e.preventDefault();
|
|
7230
|
+
if (videoRef.current) {
|
|
7231
|
+
videoRef.current.currentTime -= 10;
|
|
7232
|
+
}
|
|
7233
|
+
break;
|
|
7234
|
+
case "ArrowRight":
|
|
7235
|
+
e.preventDefault();
|
|
7236
|
+
if (videoRef.current) {
|
|
7237
|
+
videoRef.current.currentTime += 10;
|
|
7238
|
+
}
|
|
7239
|
+
break;
|
|
7240
|
+
case "ArrowUp":
|
|
7241
|
+
e.preventDefault();
|
|
7242
|
+
handleVolumeChange(Math.min(100, volume * 100 + 10));
|
|
7243
|
+
break;
|
|
7244
|
+
case "ArrowDown":
|
|
7245
|
+
e.preventDefault();
|
|
7246
|
+
handleVolumeChange(Math.max(0, volume * 100 - 10));
|
|
7247
|
+
break;
|
|
7248
|
+
case "m":
|
|
7249
|
+
case "M":
|
|
7250
|
+
e.preventDefault();
|
|
7251
|
+
toggleMute();
|
|
7252
|
+
break;
|
|
7253
|
+
case "f":
|
|
7254
|
+
case "F":
|
|
7255
|
+
e.preventDefault();
|
|
7256
|
+
toggleFullscreen();
|
|
7257
|
+
break;
|
|
7258
|
+
default:
|
|
7259
|
+
break;
|
|
7260
|
+
}
|
|
7261
|
+
},
|
|
7262
|
+
[
|
|
7263
|
+
showControlsWithTimer,
|
|
7264
|
+
togglePlayPause,
|
|
7265
|
+
handleVolumeChange,
|
|
7266
|
+
volume,
|
|
7267
|
+
toggleMute,
|
|
7268
|
+
toggleFullscreen
|
|
7269
|
+
]
|
|
7270
|
+
);
|
|
7019
7271
|
return /* @__PURE__ */ (0, import_jsx_runtime36.jsxs)("div", { className: cn("flex flex-col", className), children: [
|
|
7020
7272
|
(title || subtitleText) && /* @__PURE__ */ (0, import_jsx_runtime36.jsx)("div", { className: "bg-subject-1 rounded-t-xl px-8 py-4 flex items-end justify-between min-h-20", children: /* @__PURE__ */ (0, import_jsx_runtime36.jsxs)("div", { className: "flex flex-col gap-1", children: [
|
|
7021
7273
|
title && /* @__PURE__ */ (0, import_jsx_runtime36.jsx)(
|
|
@@ -7042,12 +7294,18 @@ var VideoPlayer = ({
|
|
|
7042
7294
|
)
|
|
7043
7295
|
] }) }),
|
|
7044
7296
|
/* @__PURE__ */ (0, import_jsx_runtime36.jsxs)(
|
|
7045
|
-
"
|
|
7297
|
+
"section",
|
|
7046
7298
|
{
|
|
7047
7299
|
className: cn(
|
|
7048
7300
|
"relative w-full bg-background overflow-hidden group",
|
|
7049
|
-
title || subtitleText ? "rounded-b-xl" : "rounded-xl"
|
|
7301
|
+
title || subtitleText ? "rounded-b-xl" : "rounded-xl",
|
|
7302
|
+
// Hide cursor when controls are hidden and video is playing
|
|
7303
|
+
isPlaying && !showControls ? "cursor-none group-hover:cursor-default" : "cursor-default"
|
|
7050
7304
|
),
|
|
7305
|
+
"aria-label": title ? `Video player: ${title}` : "Video player",
|
|
7306
|
+
onMouseMove: handleMouseMove,
|
|
7307
|
+
onMouseEnter: showControlsWithTimer,
|
|
7308
|
+
onMouseLeave: handleMouseLeave,
|
|
7051
7309
|
children: [
|
|
7052
7310
|
/* @__PURE__ */ (0, import_jsx_runtime36.jsx)(
|
|
7053
7311
|
"video",
|
|
@@ -7060,39 +7318,7 @@ var VideoPlayer = ({
|
|
|
7060
7318
|
onTimeUpdate: handleTimeUpdate,
|
|
7061
7319
|
onLoadedMetadata: handleLoadedMetadata,
|
|
7062
7320
|
onClick: togglePlayPause,
|
|
7063
|
-
onKeyDown:
|
|
7064
|
-
if (e.key) {
|
|
7065
|
-
setShowControls(true);
|
|
7066
|
-
}
|
|
7067
|
-
if (e.key === " " || e.key === "Enter") {
|
|
7068
|
-
e.preventDefault();
|
|
7069
|
-
togglePlayPause();
|
|
7070
|
-
}
|
|
7071
|
-
if (e.key === "ArrowLeft" && videoRef.current) {
|
|
7072
|
-
e.preventDefault();
|
|
7073
|
-
videoRef.current.currentTime -= 10;
|
|
7074
|
-
}
|
|
7075
|
-
if (e.key === "ArrowRight" && videoRef.current) {
|
|
7076
|
-
e.preventDefault();
|
|
7077
|
-
videoRef.current.currentTime += 10;
|
|
7078
|
-
}
|
|
7079
|
-
if (e.key === "ArrowUp") {
|
|
7080
|
-
e.preventDefault();
|
|
7081
|
-
handleVolumeChange(Math.min(100, volume * 100 + 10));
|
|
7082
|
-
}
|
|
7083
|
-
if (e.key === "ArrowDown") {
|
|
7084
|
-
e.preventDefault();
|
|
7085
|
-
handleVolumeChange(Math.max(0, volume * 100 - 10));
|
|
7086
|
-
}
|
|
7087
|
-
if (e.key === "m" || e.key === "M") {
|
|
7088
|
-
e.preventDefault();
|
|
7089
|
-
toggleMute();
|
|
7090
|
-
}
|
|
7091
|
-
if (e.key === "f" || e.key === "F") {
|
|
7092
|
-
e.preventDefault();
|
|
7093
|
-
toggleFullscreen();
|
|
7094
|
-
}
|
|
7095
|
-
},
|
|
7321
|
+
onKeyDown: handleVideoKeyDown,
|
|
7096
7322
|
tabIndex: 0,
|
|
7097
7323
|
"aria-label": title ? `Video: ${title}` : "Video player",
|
|
7098
7324
|
children: /* @__PURE__ */ (0, import_jsx_runtime36.jsx)(
|
|
@@ -7122,9 +7348,9 @@ var VideoPlayer = ({
|
|
|
7122
7348
|
{
|
|
7123
7349
|
className: cn(
|
|
7124
7350
|
"absolute top-0 left-0 right-0 p-4 bg-gradient-to-b from-black/70 to-transparent transition-opacity",
|
|
7125
|
-
|
|
7351
|
+
getTopControlsOpacity()
|
|
7126
7352
|
),
|
|
7127
|
-
children: /* @__PURE__ */ (0, import_jsx_runtime36.jsx)("div", { className: "
|
|
7353
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime36.jsx)("div", { className: "flex justify-start", children: /* @__PURE__ */ (0, import_jsx_runtime36.jsx)(
|
|
7128
7354
|
IconButton_default,
|
|
7129
7355
|
{
|
|
7130
7356
|
icon: isFullscreen ? /* @__PURE__ */ (0, import_jsx_runtime36.jsx)(import_phosphor_react18.ArrowsInSimple, { size: 24 }) : /* @__PURE__ */ (0, import_jsx_runtime36.jsx)(import_phosphor_react18.ArrowsOutSimple, { size: 24 }),
|
|
@@ -7140,29 +7366,18 @@ var VideoPlayer = ({
|
|
|
7140
7366
|
{
|
|
7141
7367
|
className: cn(
|
|
7142
7368
|
"absolute bottom-0 left-0 right-0 bg-gradient-to-t from-black/90 to-transparent transition-opacity",
|
|
7143
|
-
|
|
7369
|
+
getBottomControlsOpacity()
|
|
7144
7370
|
),
|
|
7145
7371
|
children: [
|
|
7146
|
-
/* @__PURE__ */ (0, import_jsx_runtime36.jsx)(
|
|
7147
|
-
|
|
7372
|
+
/* @__PURE__ */ (0, import_jsx_runtime36.jsx)(
|
|
7373
|
+
ProgressBar2,
|
|
7148
7374
|
{
|
|
7149
|
-
|
|
7150
|
-
|
|
7151
|
-
|
|
7152
|
-
|
|
7153
|
-
onChange: (e) => {
|
|
7154
|
-
const newTime = parseFloat(e.target.value);
|
|
7155
|
-
if (videoRef.current) {
|
|
7156
|
-
videoRef.current.currentTime = newTime;
|
|
7157
|
-
}
|
|
7158
|
-
},
|
|
7159
|
-
className: "w-full h-1 bg-neutral-600 rounded-full appearance-none cursor-pointer slider:bg-primary-600 focus:outline-none focus:ring-2 focus:ring-primary-500",
|
|
7160
|
-
"aria-label": "Video progress",
|
|
7161
|
-
style: {
|
|
7162
|
-
background: `linear-gradient(to right, #2271C4 ${progressPercentage}%, #D5D4D4 ${progressPercentage}%)`
|
|
7163
|
-
}
|
|
7375
|
+
currentTime,
|
|
7376
|
+
duration,
|
|
7377
|
+
progressPercentage,
|
|
7378
|
+
onSeek: handleSeek
|
|
7164
7379
|
}
|
|
7165
|
-
)
|
|
7380
|
+
),
|
|
7166
7381
|
/* @__PURE__ */ (0, import_jsx_runtime36.jsxs)("div", { className: "flex items-center justify-between px-4 pb-4", children: [
|
|
7167
7382
|
/* @__PURE__ */ (0, import_jsx_runtime36.jsxs)("div", { className: "flex items-center gap-4", children: [
|
|
7168
7383
|
/* @__PURE__ */ (0, import_jsx_runtime36.jsx)(
|
|
@@ -7174,32 +7389,15 @@ var VideoPlayer = ({
|
|
|
7174
7389
|
className: "!bg-transparent !text-white hover:!bg-white/20"
|
|
7175
7390
|
}
|
|
7176
7391
|
),
|
|
7177
|
-
/* @__PURE__ */ (0, import_jsx_runtime36.
|
|
7178
|
-
|
|
7179
|
-
|
|
7180
|
-
|
|
7181
|
-
|
|
7182
|
-
|
|
7183
|
-
|
|
7184
|
-
|
|
7185
|
-
|
|
7186
|
-
),
|
|
7187
|
-
/* @__PURE__ */ (0, import_jsx_runtime36.jsx)(
|
|
7188
|
-
"input",
|
|
7189
|
-
{
|
|
7190
|
-
type: "range",
|
|
7191
|
-
min: 0,
|
|
7192
|
-
max: 100,
|
|
7193
|
-
value: Math.round(volume * 100),
|
|
7194
|
-
onChange: (e) => handleVolumeChange(parseInt(e.target.value)),
|
|
7195
|
-
className: "w-20 h-1 bg-neutral-600 rounded-full appearance-none cursor-pointer focus:outline-none focus:ring-2 focus:ring-primary-500",
|
|
7196
|
-
"aria-label": "Volume control",
|
|
7197
|
-
style: {
|
|
7198
|
-
background: `linear-gradient(to right, #2271C4 ${volume * 100}%, #D5D4D4 ${volume * 100}%)`
|
|
7199
|
-
}
|
|
7200
|
-
}
|
|
7201
|
-
)
|
|
7202
|
-
] }),
|
|
7392
|
+
/* @__PURE__ */ (0, import_jsx_runtime36.jsx)(
|
|
7393
|
+
VolumeControls,
|
|
7394
|
+
{
|
|
7395
|
+
volume,
|
|
7396
|
+
isMuted,
|
|
7397
|
+
onVolumeChange: handleVolumeChange,
|
|
7398
|
+
onToggleMute: toggleMute
|
|
7399
|
+
}
|
|
7400
|
+
),
|
|
7203
7401
|
subtitles && /* @__PURE__ */ (0, import_jsx_runtime36.jsx)(
|
|
7204
7402
|
IconButton_default,
|
|
7205
7403
|
{
|
|
@@ -7218,29 +7416,15 @@ var VideoPlayer = ({
|
|
|
7218
7416
|
formatTime(duration)
|
|
7219
7417
|
] })
|
|
7220
7418
|
] }),
|
|
7221
|
-
/* @__PURE__ */ (0, import_jsx_runtime36.jsx)("div", { className: "flex items-center gap-4", children: /* @__PURE__ */ (0, import_jsx_runtime36.
|
|
7222
|
-
|
|
7223
|
-
|
|
7224
|
-
|
|
7225
|
-
|
|
7226
|
-
|
|
7227
|
-
|
|
7228
|
-
|
|
7229
|
-
|
|
7230
|
-
),
|
|
7231
|
-
showSpeedMenu && /* @__PURE__ */ (0, import_jsx_runtime36.jsx)("div", { className: "absolute bottom-12 right-0 bg-black/90 rounded-lg p-2 min-w-20", children: [0.5, 0.75, 1, 1.25, 1.5, 2].map((speed) => /* @__PURE__ */ (0, import_jsx_runtime36.jsxs)(
|
|
7232
|
-
"button",
|
|
7233
|
-
{
|
|
7234
|
-
onClick: () => handleSpeedChange(speed),
|
|
7235
|
-
className: `block w-full text-left px-3 py-1 text-sm rounded hover:bg-white/20 transition-colors ${playbackRate === speed ? "text-primary-400" : "text-white"}`,
|
|
7236
|
-
children: [
|
|
7237
|
-
speed,
|
|
7238
|
-
"x"
|
|
7239
|
-
]
|
|
7240
|
-
},
|
|
7241
|
-
speed
|
|
7242
|
-
)) })
|
|
7243
|
-
] }) })
|
|
7419
|
+
/* @__PURE__ */ (0, import_jsx_runtime36.jsx)("div", { className: "flex items-center gap-4", children: /* @__PURE__ */ (0, import_jsx_runtime36.jsx)(
|
|
7420
|
+
SpeedMenu,
|
|
7421
|
+
{
|
|
7422
|
+
showSpeedMenu,
|
|
7423
|
+
playbackRate,
|
|
7424
|
+
onToggleMenu: toggleSpeedMenu,
|
|
7425
|
+
onSpeedChange: handleSpeedChange
|
|
7426
|
+
}
|
|
7427
|
+
) })
|
|
7244
7428
|
] })
|
|
7245
7429
|
]
|
|
7246
7430
|
}
|