funuicss 2.6.1 → 2.6.3
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/css/fun.css +287 -71
- package/hooks/useHls.d.ts +8 -0
- package/hooks/useHls.js +105 -0
- package/hooks/useHls.tsx +69 -0
- package/index.d.ts +1 -0
- package/index.js +3 -1
- package/index.tsx +2 -1
- package/package.json +5 -2
- package/tsconfig.json +1 -1
- package/tsconfig.tsbuildinfo +1 -1
- package/ui/alert/Alert.js +2 -2
- package/ui/alert/Alert.tsx +2 -2
- package/ui/drop/Dropdown.d.ts +6 -0
- package/ui/drop/Dropdown.js +10 -2
- package/ui/drop/Dropdown.tsx +23 -2
- package/ui/specials/Circle.js +2 -2
- package/ui/specials/Circle.tsx +2 -2
- package/ui/theme/darkenUtils.d.ts +2 -0
- package/ui/theme/darkenUtils.js +27 -0
- package/ui/theme/darkenUtils.ts +15 -0
- package/ui/theme/theme.d.ts +1 -1
- package/ui/theme/theme.js +15 -13
- package/ui/theme/theme.tsx +17 -17
- package/ui/theme/themes.d.ts +106 -0
- package/ui/theme/themes.js +63 -0
- package/ui/theme/themes.ts +79 -0
- package/ui/video/Video.d.ts +11 -0
- package/ui/video/Video.js +258 -0
- package/ui/video/Video.tsx +287 -0
- package/ui/video/videoFunctions.d.ts +3 -0
- package/ui/video/videoFunctions.js +19 -0
- package/ui/video/videoFunctions.tsx +19 -0
- package/ui/video/videoShortcuts.d.ts +1 -0
- package/ui/video/videoShortcuts.js +11 -0
- package/ui/video/videoShortcuts.ts +12 -0
- package/ui/video/FunPlayer.d.ts +0 -0
- package/ui/video/FunPlayer.js +0 -203
- package/ui/video/FunPlayer.tsx +0 -221
|
@@ -0,0 +1,258 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
'use client';
|
|
3
|
+
var __assign = (this && this.__assign) || function () {
|
|
4
|
+
__assign = Object.assign || function(t) {
|
|
5
|
+
for (var s, i = 1, n = arguments.length; i < n; i++) {
|
|
6
|
+
s = arguments[i];
|
|
7
|
+
for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p))
|
|
8
|
+
t[p] = s[p];
|
|
9
|
+
}
|
|
10
|
+
return t;
|
|
11
|
+
};
|
|
12
|
+
return __assign.apply(this, arguments);
|
|
13
|
+
};
|
|
14
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
15
|
+
if (k2 === undefined) k2 = k;
|
|
16
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
17
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
18
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
19
|
+
}
|
|
20
|
+
Object.defineProperty(o, k2, desc);
|
|
21
|
+
}) : (function(o, m, k, k2) {
|
|
22
|
+
if (k2 === undefined) k2 = k;
|
|
23
|
+
o[k2] = m[k];
|
|
24
|
+
}));
|
|
25
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
26
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
27
|
+
}) : function(o, v) {
|
|
28
|
+
o["default"] = v;
|
|
29
|
+
});
|
|
30
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
31
|
+
var ownKeys = function(o) {
|
|
32
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
33
|
+
var ar = [];
|
|
34
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
35
|
+
return ar;
|
|
36
|
+
};
|
|
37
|
+
return ownKeys(o);
|
|
38
|
+
};
|
|
39
|
+
return function (mod) {
|
|
40
|
+
if (mod && mod.__esModule) return mod;
|
|
41
|
+
var result = {};
|
|
42
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
43
|
+
__setModuleDefault(result, mod);
|
|
44
|
+
return result;
|
|
45
|
+
};
|
|
46
|
+
})();
|
|
47
|
+
var __rest = (this && this.__rest) || function (s, e) {
|
|
48
|
+
var t = {};
|
|
49
|
+
for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0)
|
|
50
|
+
t[p] = s[p];
|
|
51
|
+
if (s != null && typeof Object.getOwnPropertySymbols === "function")
|
|
52
|
+
for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) {
|
|
53
|
+
if (e.indexOf(p[i]) < 0 && Object.prototype.propertyIsEnumerable.call(s, p[i]))
|
|
54
|
+
t[p[i]] = s[p[i]];
|
|
55
|
+
}
|
|
56
|
+
return t;
|
|
57
|
+
};
|
|
58
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
59
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
60
|
+
};
|
|
61
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
62
|
+
exports.default = Video;
|
|
63
|
+
var react_1 = __importStar(require("react"));
|
|
64
|
+
var pi_1 = require("react-icons/pi");
|
|
65
|
+
var io5_1 = require("react-icons/io5");
|
|
66
|
+
var Text_1 = __importDefault(require("../text/Text"));
|
|
67
|
+
var RowFlex_1 = __importDefault(require("../specials/RowFlex"));
|
|
68
|
+
var ToolTip_1 = __importDefault(require("../tooltip/ToolTip"));
|
|
69
|
+
var Circle_1 = __importDefault(require("../specials/Circle"));
|
|
70
|
+
var Tip_1 = __importDefault(require("../tooltip/Tip"));
|
|
71
|
+
var videoFunctions_1 = require("./videoFunctions");
|
|
72
|
+
var videoShortcuts_1 = require("./videoShortcuts");
|
|
73
|
+
function Video(_a) {
|
|
74
|
+
var src = _a.src, poster = _a.poster, onDuration = _a.onDuration, isPause = _a.isPause, className = _a.className, autoPlay = _a.autoPlay, rest = __rest(_a, ["src", "poster", "onDuration", "isPause", "className", "autoPlay"]);
|
|
75
|
+
var videoRef = (0, react_1.useRef)(null);
|
|
76
|
+
var containerRef = (0, react_1.useRef)(null);
|
|
77
|
+
var animationFrameRef = (0, react_1.useRef)(null);
|
|
78
|
+
var _b = (0, react_1.useState)(false), isPlaying = _b[0], setIsPlaying = _b[1];
|
|
79
|
+
var _c = (0, react_1.useState)(0), currentTime = _c[0], setCurrentTime = _c[1];
|
|
80
|
+
var _d = (0, react_1.useState)(0), duration = _d[0], setDuration = _d[1];
|
|
81
|
+
var _e = (0, react_1.useState)(1), volume = _e[0], setVolume = _e[1];
|
|
82
|
+
var _f = (0, react_1.useState)(false), isFullScreen = _f[0], setIsFullScreen = _f[1];
|
|
83
|
+
var _g = (0, react_1.useState)(false), showVolume = _g[0], setShowVolume = _g[1];
|
|
84
|
+
var _h = (0, react_1.useState)(true), isMouseMoving = _h[0], setIsMouseMoving = _h[1];
|
|
85
|
+
var _j = (0, react_1.useState)(false), hasStarted = _j[0], setHasStarted = _j[1];
|
|
86
|
+
var playVideo = function () {
|
|
87
|
+
var video = videoRef.current;
|
|
88
|
+
if (video && video.paused) {
|
|
89
|
+
video.play().catch(function () { });
|
|
90
|
+
setIsPlaying(true);
|
|
91
|
+
setHasStarted(true);
|
|
92
|
+
}
|
|
93
|
+
};
|
|
94
|
+
var pauseVideo = function () {
|
|
95
|
+
var video = videoRef.current;
|
|
96
|
+
if (video && !video.paused) {
|
|
97
|
+
video.pause();
|
|
98
|
+
setIsPlaying(false);
|
|
99
|
+
}
|
|
100
|
+
};
|
|
101
|
+
(0, react_1.useEffect)(function () {
|
|
102
|
+
var handleKey = function (e) { return (0, videoShortcuts_1.handleKeyDown)(e, isPlaying, playVideo, pauseVideo); };
|
|
103
|
+
document.addEventListener('keydown', handleKey);
|
|
104
|
+
return function () { return document.removeEventListener('keydown', handleKey); };
|
|
105
|
+
}, [isPlaying]);
|
|
106
|
+
var handlePlayPauseToggle = function () {
|
|
107
|
+
isPlaying ? pauseVideo() : playVideo();
|
|
108
|
+
};
|
|
109
|
+
var handleRewind = function () {
|
|
110
|
+
var video = videoRef.current;
|
|
111
|
+
if (video)
|
|
112
|
+
video.currentTime = Math.max(video.currentTime - 10, 0);
|
|
113
|
+
};
|
|
114
|
+
var handleForward = function () {
|
|
115
|
+
var video = videoRef.current;
|
|
116
|
+
if (video)
|
|
117
|
+
video.currentTime = Math.min(video.currentTime + 10, duration);
|
|
118
|
+
};
|
|
119
|
+
var handleToggleFullScreen = function () {
|
|
120
|
+
var _a, _b;
|
|
121
|
+
var element = containerRef.current;
|
|
122
|
+
if (!element)
|
|
123
|
+
return;
|
|
124
|
+
if (!document.fullscreenElement) {
|
|
125
|
+
(_a = element.requestFullscreen) === null || _a === void 0 ? void 0 : _a.call(element);
|
|
126
|
+
}
|
|
127
|
+
else {
|
|
128
|
+
(_b = document.exitFullscreen) === null || _b === void 0 ? void 0 : _b.call(document);
|
|
129
|
+
}
|
|
130
|
+
};
|
|
131
|
+
var updateCurrentTime = (0, react_1.useCallback)(function () {
|
|
132
|
+
var video = videoRef.current;
|
|
133
|
+
if (video) {
|
|
134
|
+
setCurrentTime(video.currentTime);
|
|
135
|
+
animationFrameRef.current = requestAnimationFrame(updateCurrentTime);
|
|
136
|
+
}
|
|
137
|
+
}, []);
|
|
138
|
+
var handleLoadedMetadata = function () {
|
|
139
|
+
var video = videoRef.current;
|
|
140
|
+
if (video) {
|
|
141
|
+
setDuration(video.duration || 0);
|
|
142
|
+
onDuration === null || onDuration === void 0 ? void 0 : onDuration(video.duration);
|
|
143
|
+
if (autoPlay) {
|
|
144
|
+
playVideo();
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
};
|
|
148
|
+
var handleProgressBarChange = function (e) {
|
|
149
|
+
var newTime = parseFloat(e.target.value);
|
|
150
|
+
if (videoRef.current) {
|
|
151
|
+
videoRef.current.currentTime = newTime;
|
|
152
|
+
}
|
|
153
|
+
setCurrentTime(newTime);
|
|
154
|
+
};
|
|
155
|
+
var handleVolumeChange = function (e) {
|
|
156
|
+
var newVolume = parseFloat(e.target.value);
|
|
157
|
+
setVolume(newVolume);
|
|
158
|
+
if (videoRef.current)
|
|
159
|
+
videoRef.current.volume = newVolume;
|
|
160
|
+
};
|
|
161
|
+
(0, react_1.useEffect)(function () {
|
|
162
|
+
if (autoPlay && videoRef.current) {
|
|
163
|
+
var playPromise = videoRef.current.play();
|
|
164
|
+
if (playPromise !== undefined) {
|
|
165
|
+
playPromise.catch(function () { });
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
}, [autoPlay]);
|
|
169
|
+
(0, react_1.useEffect)(function () {
|
|
170
|
+
if (videoRef.current) {
|
|
171
|
+
videoRef.current.volume = volume;
|
|
172
|
+
}
|
|
173
|
+
}, [volume]);
|
|
174
|
+
(0, react_1.useEffect)(function () {
|
|
175
|
+
if (isPause)
|
|
176
|
+
pauseVideo();
|
|
177
|
+
}, [isPause]);
|
|
178
|
+
(0, react_1.useEffect)(function () {
|
|
179
|
+
var handleFullscreenChange = function () {
|
|
180
|
+
setIsFullScreen(!!document.fullscreenElement);
|
|
181
|
+
};
|
|
182
|
+
document.addEventListener('fullscreenchange', handleFullscreenChange);
|
|
183
|
+
return function () { return document.removeEventListener('fullscreenchange', handleFullscreenChange); };
|
|
184
|
+
}, []);
|
|
185
|
+
(0, react_1.useEffect)(function () {
|
|
186
|
+
var timer;
|
|
187
|
+
var handleMouseMove = function (e) {
|
|
188
|
+
var _a;
|
|
189
|
+
if ((_a = containerRef.current) === null || _a === void 0 ? void 0 : _a.contains(e.target)) {
|
|
190
|
+
setIsMouseMoving(true);
|
|
191
|
+
clearTimeout(timer);
|
|
192
|
+
timer = setTimeout(function () { return setIsMouseMoving(false); }, 2000);
|
|
193
|
+
}
|
|
194
|
+
};
|
|
195
|
+
document.addEventListener('mousemove', handleMouseMove);
|
|
196
|
+
document.addEventListener('touchstart', handleMouseMove);
|
|
197
|
+
return function () {
|
|
198
|
+
document.removeEventListener('mousemove', handleMouseMove);
|
|
199
|
+
document.removeEventListener('touchstart', handleMouseMove);
|
|
200
|
+
clearTimeout(timer);
|
|
201
|
+
};
|
|
202
|
+
}, []);
|
|
203
|
+
(0, react_1.useEffect)(function () {
|
|
204
|
+
if (isPlaying) {
|
|
205
|
+
animationFrameRef.current = requestAnimationFrame(updateCurrentTime);
|
|
206
|
+
}
|
|
207
|
+
else if (animationFrameRef.current) {
|
|
208
|
+
cancelAnimationFrame(animationFrameRef.current);
|
|
209
|
+
}
|
|
210
|
+
return function () {
|
|
211
|
+
if (animationFrameRef.current)
|
|
212
|
+
cancelAnimationFrame(animationFrameRef.current);
|
|
213
|
+
};
|
|
214
|
+
}, [isPlaying, updateCurrentTime]);
|
|
215
|
+
(0, react_1.useEffect)(function () {
|
|
216
|
+
return function () {
|
|
217
|
+
pauseVideo();
|
|
218
|
+
};
|
|
219
|
+
}, []);
|
|
220
|
+
return (react_1.default.createElement("div", { ref: containerRef, className: "video_container fit ".concat(className || ''), id: "fun_video_container" },
|
|
221
|
+
poster && !hasStarted && !isPlaying && (react_1.default.createElement("div", { style: { backgroundImage: "url(".concat(poster, ")") }, className: "video_poster" })),
|
|
222
|
+
react_1.default.createElement("video", __assign({ ref: videoRef, preload: "auto", src: src, className: "video_player fit min-w-200", onClick: handlePlayPauseToggle, onLoadedMetadata: handleLoadedMetadata, playsInline: true, controls: false }, rest)),
|
|
223
|
+
react_1.default.createElement("div", { className: "video_controls ".concat(isMouseMoving ? 'show_controls' : 'hide_controls') },
|
|
224
|
+
react_1.default.createElement("div", { className: "w-80-p center animated fade-in" },
|
|
225
|
+
react_1.default.createElement(RowFlex_1.default, { gap: 0.3, funcss: "padding-5", alignItems: "center" },
|
|
226
|
+
react_1.default.createElement("div", { className: 'video_time' },
|
|
227
|
+
react_1.default.createElement(Text_1.default, { text: (0, videoFunctions_1.formatTime)(currentTime), funcss: 'm-0', size: "sm" })),
|
|
228
|
+
react_1.default.createElement("div", { className: "col width-100-p" },
|
|
229
|
+
react_1.default.createElement("input", { type: "range", min: 0, max: duration, value: currentTime, onChange: handleProgressBarChange, className: "width-100-p styled-slider m-0", "aria-label": "Progress bar", style: { '--progress': "".concat((currentTime / duration) * 100) } })),
|
|
230
|
+
react_1.default.createElement("div", { className: "video_time" },
|
|
231
|
+
react_1.default.createElement(Text_1.default, { text: "-".concat((0, videoFunctions_1.formatTime)(duration - currentTime)), funcss: 'm-0', size: "sm" })))),
|
|
232
|
+
react_1.default.createElement("div", { className: "center-play-icon animated fade-in", onClick: handlePlayPauseToggle },
|
|
233
|
+
react_1.default.createElement("div", { className: 'play-button' }, isPlaying ? react_1.default.createElement(pi_1.PiPause, { size: 30 }) : react_1.default.createElement(pi_1.PiPlay, { size: 30 }))),
|
|
234
|
+
react_1.default.createElement(RowFlex_1.default, { funcss: 'animated slide-up', gap: 1, justify: "center" },
|
|
235
|
+
react_1.default.createElement(RowFlex_1.default, { gap: 0.5 },
|
|
236
|
+
react_1.default.createElement(ToolTip_1.default, null,
|
|
237
|
+
react_1.default.createElement(Circle_1.default, { bordered: true, size: 2, onClick: handleRewind },
|
|
238
|
+
react_1.default.createElement(pi_1.PiRewind, null)),
|
|
239
|
+
react_1.default.createElement(Tip_1.default, { tip: "top", animation: "ScaleUp", duration: 0.5, content: "10 sec Back" })),
|
|
240
|
+
react_1.default.createElement(ToolTip_1.default, null,
|
|
241
|
+
react_1.default.createElement(Circle_1.default, { bordered: true, size: 2, onClick: handleForward },
|
|
242
|
+
react_1.default.createElement(pi_1.PiFastForward, null)),
|
|
243
|
+
react_1.default.createElement(Tip_1.default, { tip: "top", animation: "ScaleUp", duration: 0.5, content: "10 sec Forward" })),
|
|
244
|
+
react_1.default.createElement("div", { onMouseEnter: function () { return setShowVolume(true); }, onMouseLeave: function () { return setShowVolume(false); } },
|
|
245
|
+
react_1.default.createElement(RowFlex_1.default, null,
|
|
246
|
+
react_1.default.createElement(Circle_1.default, { bordered: true, size: 2 },
|
|
247
|
+
react_1.default.createElement(pi_1.PiSpeakerLow, null)),
|
|
248
|
+
showVolume && (react_1.default.createElement("input", { type: "range", min: 0, max: 1, step: 0.01, value: volume, onChange: handleVolumeChange, className: "width-100 max-w-50 animated slide-right", style: { height: '3px', marginLeft: 8 }, "aria-label": "Volume" }))))),
|
|
249
|
+
react_1.default.createElement(RowFlex_1.default, { gap: 0.3 },
|
|
250
|
+
react_1.default.createElement(ToolTip_1.default, null,
|
|
251
|
+
react_1.default.createElement(Circle_1.default, { bordered: true, size: 2, onClick: handleToggleFullScreen },
|
|
252
|
+
react_1.default.createElement(pi_1.PiCornersOut, null)),
|
|
253
|
+
react_1.default.createElement(Tip_1.default, { tip: "top", animation: "ScaleUp", duration: 0.5, content: "Expand" })),
|
|
254
|
+
react_1.default.createElement(ToolTip_1.default, null,
|
|
255
|
+
react_1.default.createElement(Circle_1.default, { bordered: true, size: 2, onClick: function () { return window.open(src || '', '_blank'); } },
|
|
256
|
+
react_1.default.createElement(io5_1.IoCloudDownloadOutline, null)),
|
|
257
|
+
react_1.default.createElement(Tip_1.default, { tip: "top", animation: "ScaleUp", duration: 0.5, content: "Download" })))))));
|
|
258
|
+
}
|
|
@@ -0,0 +1,287 @@
|
|
|
1
|
+
|
|
2
|
+
'use client';
|
|
3
|
+
import React, { useState, useRef, useEffect, useCallback } from 'react';
|
|
4
|
+
import {
|
|
5
|
+
PiCornersOut,
|
|
6
|
+
PiFastForward,
|
|
7
|
+
PiPause,
|
|
8
|
+
PiPlay,
|
|
9
|
+
PiRewind,
|
|
10
|
+
PiSpeakerLow,
|
|
11
|
+
} from 'react-icons/pi';
|
|
12
|
+
import { IoCloudDownloadOutline } from 'react-icons/io5';
|
|
13
|
+
import Text from '../text/Text';
|
|
14
|
+
import RowFlex from '../specials/RowFlex';
|
|
15
|
+
import ToolTip from '../tooltip/ToolTip';
|
|
16
|
+
import Circle from '../specials/Circle';
|
|
17
|
+
import Tip from '../tooltip/Tip';
|
|
18
|
+
import Image from 'next/image';
|
|
19
|
+
|
|
20
|
+
import { formatTime, getBufferedPercent } from './videoFunctions';
|
|
21
|
+
import { handleKeyDown } from './videoShortcuts';
|
|
22
|
+
|
|
23
|
+
interface VideoProps {
|
|
24
|
+
src: string;
|
|
25
|
+
poster?: string;
|
|
26
|
+
onDuration?: (duration: number) => void;
|
|
27
|
+
isPause?: boolean;
|
|
28
|
+
className?: string;
|
|
29
|
+
autoPlay?: boolean;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
export default function Video({ src, poster, onDuration, isPause, className, autoPlay , ...rest }: VideoProps) {
|
|
33
|
+
const videoRef = useRef<HTMLVideoElement | null>(null);
|
|
34
|
+
const containerRef = useRef<HTMLDivElement | null>(null);
|
|
35
|
+
const animationFrameRef = useRef<number | null>(null);
|
|
36
|
+
|
|
37
|
+
const [isPlaying, setIsPlaying] = useState(false);
|
|
38
|
+
const [currentTime, setCurrentTime] = useState(0);
|
|
39
|
+
const [duration, setDuration] = useState(0);
|
|
40
|
+
const [volume, setVolume] = useState(1);
|
|
41
|
+
const [isFullScreen, setIsFullScreen] = useState(false);
|
|
42
|
+
const [showVolume, setShowVolume] = useState(false);
|
|
43
|
+
const [isMouseMoving, setIsMouseMoving] = useState(true);
|
|
44
|
+
const [hasStarted, setHasStarted] = useState(false);
|
|
45
|
+
|
|
46
|
+
const playVideo = () => {
|
|
47
|
+
const video = videoRef.current;
|
|
48
|
+
if (video && video.paused) {
|
|
49
|
+
video.play().catch(() => {});
|
|
50
|
+
setIsPlaying(true);
|
|
51
|
+
setHasStarted(true);
|
|
52
|
+
}
|
|
53
|
+
};
|
|
54
|
+
|
|
55
|
+
const pauseVideo = () => {
|
|
56
|
+
const video = videoRef.current;
|
|
57
|
+
if (video && !video.paused) {
|
|
58
|
+
video.pause();
|
|
59
|
+
setIsPlaying(false);
|
|
60
|
+
}
|
|
61
|
+
};
|
|
62
|
+
|
|
63
|
+
useEffect(() => {
|
|
64
|
+
const handleKey = (e: KeyboardEvent) => handleKeyDown(e, isPlaying, playVideo, pauseVideo);
|
|
65
|
+
document.addEventListener('keydown', handleKey);
|
|
66
|
+
return () => document.removeEventListener('keydown', handleKey);
|
|
67
|
+
}, [isPlaying]);
|
|
68
|
+
|
|
69
|
+
const handlePlayPauseToggle = () => {
|
|
70
|
+
isPlaying ? pauseVideo() : playVideo();
|
|
71
|
+
};
|
|
72
|
+
|
|
73
|
+
const handleRewind = () => {
|
|
74
|
+
const video = videoRef.current;
|
|
75
|
+
if (video) video.currentTime = Math.max(video.currentTime - 10, 0);
|
|
76
|
+
};
|
|
77
|
+
|
|
78
|
+
const handleForward = () => {
|
|
79
|
+
const video = videoRef.current;
|
|
80
|
+
if (video) video.currentTime = Math.min(video.currentTime + 10, duration);
|
|
81
|
+
};
|
|
82
|
+
|
|
83
|
+
const handleToggleFullScreen = () => {
|
|
84
|
+
const element = containerRef.current;
|
|
85
|
+
if (!element) return;
|
|
86
|
+
if (!document.fullscreenElement) {
|
|
87
|
+
element.requestFullscreen?.();
|
|
88
|
+
} else {
|
|
89
|
+
document.exitFullscreen?.();
|
|
90
|
+
}
|
|
91
|
+
};
|
|
92
|
+
|
|
93
|
+
const updateCurrentTime = useCallback(() => {
|
|
94
|
+
const video = videoRef.current;
|
|
95
|
+
if (video) {
|
|
96
|
+
setCurrentTime(video.currentTime);
|
|
97
|
+
animationFrameRef.current = requestAnimationFrame(updateCurrentTime);
|
|
98
|
+
}
|
|
99
|
+
}, []);
|
|
100
|
+
|
|
101
|
+
const handleLoadedMetadata = () => {
|
|
102
|
+
const video = videoRef.current;
|
|
103
|
+
if (video) {
|
|
104
|
+
setDuration(video.duration || 0);
|
|
105
|
+
onDuration?.(video.duration);
|
|
106
|
+
if (autoPlay) {
|
|
107
|
+
playVideo();
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
};
|
|
111
|
+
|
|
112
|
+
const handleProgressBarChange = (e: React.ChangeEvent<HTMLInputElement>) => {
|
|
113
|
+
const newTime = parseFloat(e.target.value);
|
|
114
|
+
if (videoRef.current) {
|
|
115
|
+
videoRef.current.currentTime = newTime;
|
|
116
|
+
}
|
|
117
|
+
setCurrentTime(newTime);
|
|
118
|
+
};
|
|
119
|
+
|
|
120
|
+
const handleVolumeChange = (e: React.ChangeEvent<HTMLInputElement>) => {
|
|
121
|
+
const newVolume = parseFloat(e.target.value);
|
|
122
|
+
setVolume(newVolume);
|
|
123
|
+
if (videoRef.current) videoRef.current.volume = newVolume;
|
|
124
|
+
};
|
|
125
|
+
|
|
126
|
+
useEffect(() => {
|
|
127
|
+
if (autoPlay && videoRef.current) {
|
|
128
|
+
const playPromise = videoRef.current.play();
|
|
129
|
+
if (playPromise !== undefined) {
|
|
130
|
+
playPromise.catch(() => {});
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
}, [autoPlay]);
|
|
134
|
+
|
|
135
|
+
useEffect(() => {
|
|
136
|
+
if (videoRef.current) {
|
|
137
|
+
videoRef.current.volume = volume;
|
|
138
|
+
}
|
|
139
|
+
}, [volume]);
|
|
140
|
+
|
|
141
|
+
useEffect(() => {
|
|
142
|
+
if (isPause) pauseVideo();
|
|
143
|
+
}, [isPause]);
|
|
144
|
+
|
|
145
|
+
useEffect(() => {
|
|
146
|
+
const handleFullscreenChange = () => {
|
|
147
|
+
setIsFullScreen(!!document.fullscreenElement);
|
|
148
|
+
};
|
|
149
|
+
document.addEventListener('fullscreenchange', handleFullscreenChange);
|
|
150
|
+
return () => document.removeEventListener('fullscreenchange', handleFullscreenChange);
|
|
151
|
+
}, []);
|
|
152
|
+
|
|
153
|
+
useEffect(() => {
|
|
154
|
+
let timer: NodeJS.Timeout;
|
|
155
|
+
const handleMouseMove = (e: MouseEvent | TouchEvent) => {
|
|
156
|
+
if (containerRef.current?.contains(e.target as Node)) {
|
|
157
|
+
setIsMouseMoving(true);
|
|
158
|
+
clearTimeout(timer);
|
|
159
|
+
timer = setTimeout(() => setIsMouseMoving(false), 2000);
|
|
160
|
+
}
|
|
161
|
+
};
|
|
162
|
+
document.addEventListener('mousemove', handleMouseMove);
|
|
163
|
+
document.addEventListener('touchstart', handleMouseMove);
|
|
164
|
+
return () => {
|
|
165
|
+
document.removeEventListener('mousemove', handleMouseMove);
|
|
166
|
+
document.removeEventListener('touchstart', handleMouseMove);
|
|
167
|
+
clearTimeout(timer);
|
|
168
|
+
};
|
|
169
|
+
}, []);
|
|
170
|
+
|
|
171
|
+
useEffect(() => {
|
|
172
|
+
if (isPlaying) {
|
|
173
|
+
animationFrameRef.current = requestAnimationFrame(updateCurrentTime);
|
|
174
|
+
} else if (animationFrameRef.current) {
|
|
175
|
+
cancelAnimationFrame(animationFrameRef.current);
|
|
176
|
+
}
|
|
177
|
+
return () => {
|
|
178
|
+
if (animationFrameRef.current) cancelAnimationFrame(animationFrameRef.current);
|
|
179
|
+
};
|
|
180
|
+
}, [isPlaying, updateCurrentTime]);
|
|
181
|
+
|
|
182
|
+
useEffect(() => {
|
|
183
|
+
return () => {
|
|
184
|
+
pauseVideo();
|
|
185
|
+
};
|
|
186
|
+
}, []);
|
|
187
|
+
|
|
188
|
+
return (
|
|
189
|
+
<div ref={containerRef} className={`video_container fit ${className || ''}`} id="fun_video_container">
|
|
190
|
+
{poster && !hasStarted && !isPlaying && (
|
|
191
|
+
<div
|
|
192
|
+
style={{ backgroundImage: `url(${poster})` }}
|
|
193
|
+
className="video_poster"
|
|
194
|
+
/>
|
|
195
|
+
)}
|
|
196
|
+
<video
|
|
197
|
+
ref={videoRef}
|
|
198
|
+
preload="auto"
|
|
199
|
+
src={src}
|
|
200
|
+
className="video_player fit min-w-200"
|
|
201
|
+
onClick={handlePlayPauseToggle}
|
|
202
|
+
onLoadedMetadata={handleLoadedMetadata}
|
|
203
|
+
playsInline
|
|
204
|
+
controls={false}
|
|
205
|
+
{...rest}
|
|
206
|
+
/>
|
|
207
|
+
|
|
208
|
+
<div className={`video_controls ${isMouseMoving ? 'show_controls' : 'hide_controls'}`}>
|
|
209
|
+
<div className="w-80-p center animated fade-in">
|
|
210
|
+
<RowFlex gap={0.3} funcss="padding-5" alignItems="center">
|
|
211
|
+
<div className='video_time'>
|
|
212
|
+
<Text text={formatTime(currentTime)} funcss='m-0' size="sm" />
|
|
213
|
+
</div>
|
|
214
|
+
<div className="col width-100-p">
|
|
215
|
+
<input
|
|
216
|
+
type="range"
|
|
217
|
+
min={0}
|
|
218
|
+
max={duration}
|
|
219
|
+
value={currentTime}
|
|
220
|
+
onChange={handleProgressBarChange}
|
|
221
|
+
className="width-100-p styled-slider m-0"
|
|
222
|
+
aria-label="Progress bar"
|
|
223
|
+
style={{ '--progress': `${(currentTime / duration) * 100}` } as React.CSSProperties}
|
|
224
|
+
/>
|
|
225
|
+
</div>
|
|
226
|
+
<div className="video_time">
|
|
227
|
+
<Text text={`-${formatTime(duration - currentTime)}`} funcss='m-0' size="sm" />
|
|
228
|
+
</div>
|
|
229
|
+
</RowFlex>
|
|
230
|
+
</div>
|
|
231
|
+
|
|
232
|
+
<div className="center-play-icon animated fade-in" onClick={handlePlayPauseToggle}>
|
|
233
|
+
<div className='play-button'>
|
|
234
|
+
{isPlaying ? <PiPause size={30} /> : <PiPlay size={30} />}
|
|
235
|
+
</div>
|
|
236
|
+
</div>
|
|
237
|
+
|
|
238
|
+
<RowFlex funcss='animated slide-up' gap={1} justify="center">
|
|
239
|
+
<RowFlex gap={0.5}>
|
|
240
|
+
<ToolTip>
|
|
241
|
+
<Circle bordered size={2} onClick={handleRewind}><PiRewind /></Circle>
|
|
242
|
+
<Tip tip="top" animation="ScaleUp" duration={0.5} content="10 sec Back" />
|
|
243
|
+
</ToolTip>
|
|
244
|
+
|
|
245
|
+
<ToolTip>
|
|
246
|
+
<Circle bordered size={2} onClick={handleForward}><PiFastForward /></Circle>
|
|
247
|
+
<Tip tip="top" animation="ScaleUp" duration={0.5} content="10 sec Forward" />
|
|
248
|
+
</ToolTip>
|
|
249
|
+
|
|
250
|
+
<div onMouseEnter={() => setShowVolume(true)} onMouseLeave={() => setShowVolume(false)}>
|
|
251
|
+
<RowFlex>
|
|
252
|
+
<Circle bordered size={2}><PiSpeakerLow /></Circle>
|
|
253
|
+
{showVolume && (
|
|
254
|
+
<input
|
|
255
|
+
type="range"
|
|
256
|
+
min={0}
|
|
257
|
+
max={1}
|
|
258
|
+
step={0.01}
|
|
259
|
+
value={volume}
|
|
260
|
+
onChange={handleVolumeChange}
|
|
261
|
+
className="width-100 max-w-50 animated slide-right"
|
|
262
|
+
style={{ height: '3px', marginLeft: 8 }}
|
|
263
|
+
aria-label="Volume"
|
|
264
|
+
/>
|
|
265
|
+
)}
|
|
266
|
+
</RowFlex>
|
|
267
|
+
</div>
|
|
268
|
+
</RowFlex>
|
|
269
|
+
|
|
270
|
+
<RowFlex gap={0.3}>
|
|
271
|
+
<ToolTip>
|
|
272
|
+
<Circle bordered size={2} onClick={handleToggleFullScreen}><PiCornersOut /></Circle>
|
|
273
|
+
<Tip tip="top" animation="ScaleUp" duration={0.5} content="Expand" />
|
|
274
|
+
</ToolTip>
|
|
275
|
+
|
|
276
|
+
<ToolTip>
|
|
277
|
+
<Circle bordered size={2} onClick={() => window.open(src || '', '_blank')}>
|
|
278
|
+
<IoCloudDownloadOutline />
|
|
279
|
+
</Circle>
|
|
280
|
+
<Tip tip="top" animation="ScaleUp" duration={0.5} content="Download" />
|
|
281
|
+
</ToolTip>
|
|
282
|
+
</RowFlex>
|
|
283
|
+
</RowFlex>
|
|
284
|
+
</div>
|
|
285
|
+
</div>
|
|
286
|
+
);
|
|
287
|
+
}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.getBufferedPercent = exports.formatTime = void 0;
|
|
4
|
+
var formatTime = function (time) {
|
|
5
|
+
if (isNaN(time))
|
|
6
|
+
return '00:00';
|
|
7
|
+
var minutes = Math.floor(time / 60);
|
|
8
|
+
var seconds = Math.floor(time % 60);
|
|
9
|
+
return "".concat(String(minutes).padStart(2, '0'), ":").concat(String(seconds).padStart(2, '0'));
|
|
10
|
+
};
|
|
11
|
+
exports.formatTime = formatTime;
|
|
12
|
+
var getBufferedPercent = function (videoRef, duration) {
|
|
13
|
+
var video = videoRef.current;
|
|
14
|
+
if (!video || video.buffered.length === 0)
|
|
15
|
+
return 0;
|
|
16
|
+
var end = video.buffered.end(video.buffered.length - 1);
|
|
17
|
+
return (end / duration) * 100;
|
|
18
|
+
};
|
|
19
|
+
exports.getBufferedPercent = getBufferedPercent;
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
// videoFunctions.tsx
|
|
2
|
+
import { MutableRefObject } from 'react';
|
|
3
|
+
|
|
4
|
+
export const formatTime = (time: number): string => {
|
|
5
|
+
if (isNaN(time)) return '00:00';
|
|
6
|
+
const minutes = Math.floor(time / 60);
|
|
7
|
+
const seconds = Math.floor(time % 60);
|
|
8
|
+
return `${String(minutes).padStart(2, '0')}:${String(seconds).padStart(2, '0')}`;
|
|
9
|
+
};
|
|
10
|
+
|
|
11
|
+
export const getBufferedPercent = (
|
|
12
|
+
videoRef: MutableRefObject<HTMLVideoElement | null>,
|
|
13
|
+
duration: number
|
|
14
|
+
): number => {
|
|
15
|
+
const video = videoRef.current;
|
|
16
|
+
if (!video || video.buffered.length === 0) return 0;
|
|
17
|
+
const end = video.buffered.end(video.buffered.length - 1);
|
|
18
|
+
return (end / duration) * 100;
|
|
19
|
+
};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare const handleKeyDown: (e: KeyboardEvent, isPlaying: boolean, playVideo: () => void, pauseVideo: () => void) => void;
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.handleKeyDown = void 0;
|
|
4
|
+
// videoShortcuts.ts
|
|
5
|
+
var handleKeyDown = function (e, isPlaying, playVideo, pauseVideo) {
|
|
6
|
+
if (e.key === ' ') {
|
|
7
|
+
e.preventDefault();
|
|
8
|
+
isPlaying ? pauseVideo() : playVideo();
|
|
9
|
+
}
|
|
10
|
+
};
|
|
11
|
+
exports.handleKeyDown = handleKeyDown;
|
package/ui/video/FunPlayer.d.ts
DELETED
|
File without changes
|