react-video-seek-slider
Version:
A lightweight, dependency-free React video seek slider component with YouTube-like functionality, time codes, and video preview support
330 lines (329 loc) • 8.26 kB
JavaScript
import { jsxs as L, jsx as f, Fragment as z } from "react/jsx-runtime";
import { memo as J, useCallback as K, useEffect as B, useRef as E, useState as A } from "react";
function Q(t, e) {
const n = t || -1;
return e * 100 / n;
}
const M = (t, e, n) => t >= e && t <= n;
function D(t, e, n, c) {
const o = M(t, e, n), r = n - e, l = t - e, u = o ? l / r : 0;
return c ? 1 : u;
}
const G = J(
({
label: t = "",
startTime: e,
maxTime: n,
endTime: c,
currentTime: o,
seekHoverTime: r,
bufferTime: l,
isTimePassed: u = !1,
isBufferPassed: d = !1,
isHoverPassed: p = !1,
onHover: T = () => {
},
withGap: i
}) => {
const h = Q(n, e), a = (c - e) / n * 100, P = `main${i ? " with-gap" : ""}`, w = D(
o,
e,
c,
u
), S = D(
r,
e,
c,
p
), v = D(
l,
e,
c,
d
);
return /* @__PURE__ */ L(
"div",
{
className: P,
onMouseMove: () => T(t),
style: {
width: `${a}%`,
left: `${h}%`
},
children: [
/* @__PURE__ */ f(
"div",
{
className: "inner-seek-block buffered",
"data-test-id": "test-buffered",
style: { transform: `scaleX(${v})` }
}
),
/* @__PURE__ */ f(
"div",
{
className: "inner-seek-block seek-hover",
"data-test-id": "test-seek-hover",
style: { transform: `scaleX(${S})` }
}
),
/* @__PURE__ */ f(
"div",
{
className: "inner-seek-block connect",
style: { transform: `scaleX(${w})` }
}
)
]
}
);
}
);
function q(t, e, n) {
const c = e * 100 / n;
return Math.floor(+(c * (t / 100)));
}
const R = (t, e, n) => e + 1 < t.length ? t[e + 1].fromMs : n, Y = ({
max: t = 1e3,
currentTime: e = 0,
bufferTime: n = 0,
seekHoverPosition: c = 0,
timeCodes: o,
trackWidth: r,
mobileSeeking: l,
label: u,
setLabel: d
}) => {
const p = q(t, c, r), T = K(
(i) => {
u !== i && d(i);
},
[u]
);
return B(() => {
if (!l)
return;
const i = o?.find(({ fromMs: h }, g) => {
const a = R(o, g, t);
return M(e, h, a);
});
i?.description !== u && d(i?.description || "");
}, [e, u, t, o]), /* @__PURE__ */ f(z, { children: o?.map(({ fromMs: i, description: h }, g) => {
const a = R(o, g, t), P = a <= e, w = a <= n, S = a <= p;
let v = M(e, i, a);
const H = P || !v ? 0 : e;
v = M(n, i, a);
const N = w || !v ? 0 : n;
return v = M(p, i, a), /* @__PURE__ */ f(
G,
{
label: h,
maxTime: t,
startTime: i,
endTime: a,
isTimePassed: P,
isBufferPassed: w,
isHoverPassed: S,
currentTime: H,
bufferTime: N,
seekHoverTime: S || !v ? 0 : p,
onHover: T,
withGap: !0
},
i
);
}) });
};
function Z(t, e, n, c) {
let o = 0;
return e && (o = t - e.offsetWidth / 2, c && (o < 0 ? o = 0 : o + e.offsetWidth > n && (o = n - e.offsetWidth))), { transform: `translateX(${o}px)` };
}
function _(t, e = 0) {
const n = Math.round(t / 1e3 + e), c = Math.floor(n / 3600), o = n % 3600, r = Math.floor(o / 60), l = Math.ceil(o % 60);
return {
hh: c.toString(),
mm: r < 10 ? `0${r}` : r.toString(),
ss: l < 10 ? `0${l}` : l.toString()
};
}
function U(t, e, n = 0, c = "", o = "") {
const r = _(e, n);
return t + n < 60 * 1e3 ? o + r.ss : t + n < 3600 * 1e3 ? `${c + r.mm}:${r.ss}` : `${r.hh}:${r.mm}:${r.ss}`;
}
const x = ({
max: t,
hoverTimeValue: e,
offset: n,
trackWidth: c,
seekHoverPosition: o,
isThumbActive: r,
limitTimeTooltipBySides: l,
label: u,
minutesPrefix: d,
secondsPrefix: p,
getPreviewScreenUrl: T
}) => {
const i = E(null), h = r ? "hover-time active" : "hover-time", g = Z(
o,
i?.current,
c,
l
), a = U(
t,
e,
n,
d,
p
);
return /* @__PURE__ */ L(
"div",
{
className: h,
style: g,
ref: i,
"data-testid": "hover-time",
children: [
r && T && /* @__PURE__ */ f(
"div",
{
className: "preview-screen",
style: {
backgroundImage: `url(${T(e)})`
}
}
),
u && /* @__PURE__ */ f("div", { children: u }),
a
]
}
);
}, ee = ({ max: t, currentTime: e, isThumbActive: n }) => /* @__PURE__ */ f(
"div",
{
className: "thumb active",
"data-testid": "testThumb",
style: {
left: `calc(${e / t * 100}% + -6px)`
},
children: /* @__PURE__ */ f("div", { className: "handler" })
}
), se = ({
max: t = 1e3,
currentTime: e = 0,
bufferTime: n = 0,
hideThumbTooltip: c = !1,
offset: o = 0,
secondsPrefix: r = "",
minutesPrefix: l = "",
limitTimeTooltipBySides: u = !0,
timeCodes: d,
onChange: p = () => {
},
getPreviewScreenUrl: T
}) => {
const [i, h] = A(0), [g, a] = A(""), P = E(!1), w = E(!1), S = E(null), v = S.current?.offsetWidth || 0, H = i > 0 || P.current, N = q(t, i, v), y = (s) => {
const m = S.current?.getBoundingClientRect(), k = m?.left || 0, b = m?.width || 0;
let $ = s - k;
$ = $ < 0 ? 0 : $, $ = $ > b ? b : $;
const V = +($ * 100 / b * (t / 100)).toFixed(0);
h($), p(V, V + o);
}, W = (s) => {
if (s.preventDefault(), s.stopPropagation(), !w.current)
return;
const { changedTouches: m } = s;
let k = m?.[m.length - 1]?.pageX || 0;
k = k < 0 ? 0 : k, y(k);
}, X = (s) => {
P.current && y(s.pageX);
}, C = (s, m) => {
const k = S.current?.getBoundingClientRect().left || 0, b = s ? 0 : m.pageX - k;
h(b);
}, I = (s = !0) => {
w.current = s, h(s ? i : 0);
}, F = (s, m) => {
m.preventDefault(), X(m), P.current = s, h(s ? i : 0);
}, j = (s) => {
F(!1, s);
}, O = () => {
I(!1);
};
return B(() => {
if (!w.current)
return;
const s = d?.find(({ fromMs: m }, k) => {
const b = R(d, k, t);
return M(e, m, b);
});
s?.description !== g && a(s?.description || "");
}, [e, g, t, d]), B(() => (window.addEventListener("mousemove", X), window.addEventListener("mouseup", j), window.addEventListener("touchmove", W), window.addEventListener("touchend", O), () => {
window.removeEventListener("mousemove", X), window.removeEventListener("mouseup", j), window.removeEventListener("touchmove", W), window.removeEventListener("touchend", O);
}), [t, o, v]), /* @__PURE__ */ L("div", { className: "ui-video-seek-slider", children: [
/* @__PURE__ */ L(
"div",
{
className: H ? "track active" : "track",
ref: S,
onMouseMove: (s) => C(!1, s),
onMouseLeave: (s) => C(!0, s),
onMouseDown: (s) => F(!0, s),
onTouchStart: () => I(!0),
"data-testid": "main-track",
children: [
!!d?.length && /* @__PURE__ */ f(
Y,
{
currentTime: e,
max: t,
bufferTime: n,
seekHoverPosition: i,
timeCodes: d,
mobileSeeking: w.current,
trackWidth: v,
label: g,
setLabel: a
}
),
!d && /* @__PURE__ */ f(
G,
{
maxTime: t,
startTime: 0,
endTime: t,
currentTime: e,
bufferTime: n,
seekHoverTime: N
}
)
]
}
),
!c && /* @__PURE__ */ f(
x,
{
max: t,
hoverTimeValue: N,
isThumbActive: H,
label: g,
limitTimeTooltipBySides: u,
offset: o,
seekHoverPosition: i,
trackWidth: v,
getPreviewScreenUrl: T,
minutesPrefix: l,
secondsPrefix: r
}
),
/* @__PURE__ */ f(
ee,
{
max: t,
currentTime: e,
isThumbActive: H
}
)
] });
};
export {
se as VideoSeekSlider
};
//# sourceMappingURL=index.mjs.map