UNPKG

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
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