@geekapps/silo-elements-nextjs 0.2.42 → 0.2.44
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.d.ts +9 -20
- package/dist/VideoPlayer.js +69 -52
- package/dist/VideoPlayer.js.map +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.js +68 -51
- package/dist/index.js.map +1 -1
- package/dist/styles.css +1 -1
- package/package.json +1 -1
- package/styles.css +1 -1
package/dist/VideoPlayer.d.ts
CHANGED
|
@@ -8,17 +8,11 @@ type SourceProps = {
|
|
|
8
8
|
type?: VideoSourceType;
|
|
9
9
|
default?: boolean;
|
|
10
10
|
};
|
|
11
|
-
type
|
|
12
|
-
children: ReactNode;
|
|
13
|
-
};
|
|
14
|
-
type SubtitleProps = {
|
|
11
|
+
type CaptionsProps = {
|
|
15
12
|
src: string;
|
|
16
|
-
srclang: string;
|
|
17
|
-
label: string;
|
|
18
|
-
default?: boolean;
|
|
19
13
|
};
|
|
20
|
-
type
|
|
21
|
-
|
|
14
|
+
type ThumbnailProps = {
|
|
15
|
+
src: string;
|
|
22
16
|
};
|
|
23
17
|
type StoryboardFrameProps = {
|
|
24
18
|
start: number;
|
|
@@ -39,7 +33,6 @@ type StoryboardProps = {
|
|
|
39
33
|
type VideoProps = {
|
|
40
34
|
title?: string;
|
|
41
35
|
description?: string;
|
|
42
|
-
poster?: string;
|
|
43
36
|
children: ReactNode;
|
|
44
37
|
className?: string;
|
|
45
38
|
autoHideControls?: boolean;
|
|
@@ -48,20 +41,16 @@ type VideoProps = {
|
|
|
48
41
|
/** Fixed height — disables aspect-ratio so the player stays at exactly this height regardless of video dimensions */
|
|
49
42
|
fixedHeight?: string | number;
|
|
50
43
|
};
|
|
51
|
-
declare function Sources(_props: SourcesProps): null;
|
|
52
|
-
declare namespace Sources {
|
|
53
|
-
var displayName: string;
|
|
54
|
-
}
|
|
55
44
|
declare function Source(_props: SourceProps): null;
|
|
56
45
|
declare namespace Source {
|
|
57
46
|
var displayName: string;
|
|
58
47
|
}
|
|
59
|
-
declare function
|
|
60
|
-
declare namespace
|
|
48
|
+
declare function Captions(_props: CaptionsProps): null;
|
|
49
|
+
declare namespace Captions {
|
|
61
50
|
var displayName: string;
|
|
62
51
|
}
|
|
63
|
-
declare function
|
|
64
|
-
declare namespace
|
|
52
|
+
declare function VideoThumbnail(_props: ThumbnailProps): null;
|
|
53
|
+
declare namespace VideoThumbnail {
|
|
65
54
|
var displayName: string;
|
|
66
55
|
}
|
|
67
56
|
declare function Storyboard(_props: StoryboardProps): null;
|
|
@@ -72,7 +61,7 @@ declare function StoryboardFrame(_props: StoryboardFrameProps): null;
|
|
|
72
61
|
declare namespace StoryboardFrame {
|
|
73
62
|
var displayName: string;
|
|
74
63
|
}
|
|
75
|
-
declare function Video({ title, description,
|
|
64
|
+
declare function Video({ title, description, children, className, autoHideControls, defaultVolume, maxHeight, fixedHeight, }: VideoProps): react__default.JSX.Element;
|
|
76
65
|
declare const VideoPlayer: typeof Video;
|
|
77
66
|
|
|
78
|
-
export {
|
|
67
|
+
export { Captions, type CaptionsProps, Source, type SourceProps, Storyboard, StoryboardFrame, type StoryboardFrameProps, type StoryboardProps, type ThumbnailProps, Video, VideoPlayer, type VideoSourceType, VideoThumbnail };
|
package/dist/VideoPlayer.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import React, { useMemo,
|
|
1
|
+
import React, { useMemo, useState, useEffect, useRef, useCallback } from 'react';
|
|
2
2
|
import gsap from 'gsap';
|
|
3
|
-
import { Pause, Play, VolumeX, Volume2, Captions, Settings, Minimize, Maximize } from 'lucide-react';
|
|
3
|
+
import { Pause, Play, VolumeX, Volume2, Captions as Captions$1, Settings, Minimize, Maximize } from 'lucide-react';
|
|
4
4
|
import { jsxs, jsx, Fragment } from 'react/jsx-runtime';
|
|
5
5
|
|
|
6
6
|
var AUTO_QUALITY = {
|
|
@@ -9,22 +9,18 @@ var AUTO_QUALITY = {
|
|
|
9
9
|
type: "auto"
|
|
10
10
|
};
|
|
11
11
|
var PLAYBACK_SPEEDS = [0.25, 0.5, 0.75, 1, 1.25, 1.5, 2];
|
|
12
|
-
function Sources(_props) {
|
|
13
|
-
return null;
|
|
14
|
-
}
|
|
15
|
-
Sources.displayName = "SiloSources";
|
|
16
12
|
function Source(_props) {
|
|
17
13
|
return null;
|
|
18
14
|
}
|
|
19
15
|
Source.displayName = "SiloSource";
|
|
20
|
-
function
|
|
16
|
+
function Captions(_props) {
|
|
21
17
|
return null;
|
|
22
18
|
}
|
|
23
|
-
|
|
24
|
-
function
|
|
19
|
+
Captions.displayName = "SiloCaptions";
|
|
20
|
+
function VideoThumbnail(_props) {
|
|
25
21
|
return null;
|
|
26
22
|
}
|
|
27
|
-
|
|
23
|
+
VideoThumbnail.displayName = "SiloVideoThumbnail";
|
|
28
24
|
function Storyboard(_props) {
|
|
29
25
|
return null;
|
|
30
26
|
}
|
|
@@ -36,7 +32,6 @@ StoryboardFrame.displayName = "SiloStoryboardFrame";
|
|
|
36
32
|
function Video({
|
|
37
33
|
title,
|
|
38
34
|
description,
|
|
39
|
-
poster,
|
|
40
35
|
children,
|
|
41
36
|
className,
|
|
42
37
|
autoHideControls = true,
|
|
@@ -45,14 +40,40 @@ function Video({
|
|
|
45
40
|
fixedHeight
|
|
46
41
|
}) {
|
|
47
42
|
const parsed = useMemo(() => parseVideoChildren(children), [children]);
|
|
43
|
+
const [captions, setCaptions] = useState([]);
|
|
44
|
+
const [poster, setPoster] = useState(void 0);
|
|
45
|
+
useEffect(() => {
|
|
46
|
+
if (!parsed.captionsSrc) {
|
|
47
|
+
setCaptions([]);
|
|
48
|
+
return;
|
|
49
|
+
}
|
|
50
|
+
let cancelled = false;
|
|
51
|
+
fetch(parsed.captionsSrc, { cache: "no-store" }).then((r) => r.json()).then((data) => {
|
|
52
|
+
if (!cancelled && Array.isArray(data)) {
|
|
53
|
+
setCaptions(data.map((c, i) => ({ ...c, default: i === 0 })));
|
|
54
|
+
}
|
|
55
|
+
}).catch(() => {
|
|
56
|
+
if (!cancelled) setCaptions([]);
|
|
57
|
+
});
|
|
58
|
+
return () => {
|
|
59
|
+
cancelled = true;
|
|
60
|
+
};
|
|
61
|
+
}, [parsed.captionsSrc]);
|
|
62
|
+
useEffect(() => {
|
|
63
|
+
if (!parsed.thumbnailSrc) {
|
|
64
|
+
setPoster(void 0);
|
|
65
|
+
return;
|
|
66
|
+
}
|
|
67
|
+
setPoster(parsed.thumbnailSrc);
|
|
68
|
+
}, [parsed.thumbnailSrc]);
|
|
48
69
|
const initialSourceIndex = useMemo(() => {
|
|
49
70
|
const index = parsed.sources.findIndex((source) => source.default);
|
|
50
71
|
return index >= 0 ? index : 0;
|
|
51
72
|
}, [parsed.sources]);
|
|
52
73
|
const initialSubtitleMode = useMemo(() => {
|
|
53
|
-
const track =
|
|
74
|
+
const track = captions.find((c) => c.default);
|
|
54
75
|
return track?.srclang ?? "off";
|
|
55
|
-
}, [
|
|
76
|
+
}, [captions]);
|
|
56
77
|
const containerRef = useRef(null);
|
|
57
78
|
const chromeRef = useRef(null);
|
|
58
79
|
const playerRef = useRef(null);
|
|
@@ -97,7 +118,6 @@ function Video({
|
|
|
97
118
|
const [isFullscreen, setIsFullscreen] = useState(false);
|
|
98
119
|
const [playerHeight, setPlayerHeight] = useState(0);
|
|
99
120
|
const [playerWidth, setPlayerWidth] = useState(0);
|
|
100
|
-
const [error, setError] = useState(null);
|
|
101
121
|
const activeSource = parsed.sources[sourceIndex] ?? parsed.sources[0] ?? null;
|
|
102
122
|
const progressPercent = duration ? currentTime / duration * 100 : 0;
|
|
103
123
|
const bufferedPercent = duration ? bufferedTime / duration * 100 : 0;
|
|
@@ -158,10 +178,10 @@ function Video({
|
|
|
158
178
|
}
|
|
159
179
|
}, [sourceIndex, parsed.sources.length, initialSourceIndex]);
|
|
160
180
|
useEffect(() => {
|
|
161
|
-
if (subtitleMode !== "off" && !
|
|
181
|
+
if (subtitleMode !== "off" && !captions.some((subtitle) => subtitle.srclang === subtitleMode)) {
|
|
162
182
|
setSubtitleMode(initialSubtitleMode);
|
|
163
183
|
}
|
|
164
|
-
}, [subtitleMode,
|
|
184
|
+
}, [subtitleMode, captions, initialSubtitleMode]);
|
|
165
185
|
useEffect(() => {
|
|
166
186
|
const video = videoRef.current;
|
|
167
187
|
if (!video) return;
|
|
@@ -368,7 +388,6 @@ function Video({
|
|
|
368
388
|
return;
|
|
369
389
|
}
|
|
370
390
|
destroyMediaEngines();
|
|
371
|
-
setError(null);
|
|
372
391
|
setIsLoading(true);
|
|
373
392
|
setCurrentTime(0);
|
|
374
393
|
setBufferedTime(0);
|
|
@@ -413,13 +432,13 @@ function Video({
|
|
|
413
432
|
setIsLoading(false);
|
|
414
433
|
});
|
|
415
434
|
dash.on(dashjs.MediaPlayer.events.ERROR, () => {
|
|
416
|
-
|
|
435
|
+
console.error("[Silo] MPEG-DASH playback failed");
|
|
417
436
|
setIsLoading(false);
|
|
418
437
|
});
|
|
419
438
|
dash.initialize(video, activeSource.src, false);
|
|
420
439
|
} catch {
|
|
421
440
|
if (!cancelled) {
|
|
422
|
-
|
|
441
|
+
console.error("[Silo] MPEG-DASH player load failed");
|
|
423
442
|
setIsLoading(false);
|
|
424
443
|
}
|
|
425
444
|
}
|
|
@@ -485,7 +504,7 @@ function Video({
|
|
|
485
504
|
hls.recoverMediaError();
|
|
486
505
|
return;
|
|
487
506
|
}
|
|
488
|
-
|
|
507
|
+
console.error("[Silo] HLS playback failed");
|
|
489
508
|
setIsLoading(false);
|
|
490
509
|
});
|
|
491
510
|
return;
|
|
@@ -496,11 +515,11 @@ function Video({
|
|
|
496
515
|
setIsLoading(false);
|
|
497
516
|
return;
|
|
498
517
|
}
|
|
499
|
-
|
|
518
|
+
console.error("[Silo] HLS not supported in this browser");
|
|
500
519
|
setIsLoading(false);
|
|
501
520
|
} catch {
|
|
502
521
|
if (!cancelled) {
|
|
503
|
-
|
|
522
|
+
console.error("[Silo] HLS player load failed");
|
|
504
523
|
setIsLoading(false);
|
|
505
524
|
}
|
|
506
525
|
}
|
|
@@ -522,9 +541,18 @@ function Video({
|
|
|
522
541
|
const togglePlay = useCallback(async () => {
|
|
523
542
|
const video = videoRef.current;
|
|
524
543
|
if (!video) return;
|
|
544
|
+
const wasPaused = video.paused;
|
|
525
545
|
try {
|
|
526
|
-
const wasPaused = video.paused;
|
|
527
546
|
if (wasPaused) {
|
|
547
|
+
if (video.readyState < HTMLMediaElement.HAVE_FUTURE_DATA) {
|
|
548
|
+
await new Promise((resolve) => {
|
|
549
|
+
const onReady = () => {
|
|
550
|
+
video.removeEventListener("canplay", onReady);
|
|
551
|
+
resolve();
|
|
552
|
+
};
|
|
553
|
+
video.addEventListener("canplay", onReady);
|
|
554
|
+
});
|
|
555
|
+
}
|
|
528
556
|
await video.play();
|
|
529
557
|
} else {
|
|
530
558
|
video.pause();
|
|
@@ -537,7 +565,6 @@ function Video({
|
|
|
537
565
|
600
|
|
538
566
|
);
|
|
539
567
|
} catch {
|
|
540
|
-
setError("O navegador bloqueou a reprodu\xE7\xE3o autom\xE1tica.");
|
|
541
568
|
}
|
|
542
569
|
}, []);
|
|
543
570
|
const seekRelative = useCallback((seconds) => {
|
|
@@ -591,7 +618,7 @@ function Video({
|
|
|
591
618
|
}
|
|
592
619
|
throw new Error("Fullscreen unavailable");
|
|
593
620
|
} catch {
|
|
594
|
-
|
|
621
|
+
console.error("[Silo] Fullscreen toggle failed");
|
|
595
622
|
}
|
|
596
623
|
}, []);
|
|
597
624
|
const changeAudio = useCallback((trackId) => {
|
|
@@ -778,7 +805,7 @@ function Video({
|
|
|
778
805
|
preload: "metadata",
|
|
779
806
|
crossOrigin: "anonymous",
|
|
780
807
|
children: [
|
|
781
|
-
|
|
808
|
+
captions.map((subtitle) => /* @__PURE__ */ jsx(
|
|
782
809
|
"track",
|
|
783
810
|
{
|
|
784
811
|
kind: "subtitles",
|
|
@@ -826,7 +853,6 @@ function Video({
|
|
|
826
853
|
}
|
|
827
854
|
),
|
|
828
855
|
isLoading && /* @__PURE__ */ jsx("div", { className: "pointer-events-none absolute inset-0 z-20 grid place-items-center bg-black/10", children: /* @__PURE__ */ jsx("div", { className: "size-9 animate-spin rounded-full border-2 border-white/25 border-t-white" }) }),
|
|
829
|
-
error && /* @__PURE__ */ jsx("div", { className: "absolute inset-x-8 top-1/2 z-40 -translate-y-1/2 rounded-2xl border border-white/10 bg-black/75 p-5 text-center text-sm text-white shadow-2xl backdrop-blur-xl", children: error }),
|
|
830
856
|
/* @__PURE__ */ jsxs(
|
|
831
857
|
"div",
|
|
832
858
|
{
|
|
@@ -886,11 +912,11 @@ function Video({
|
|
|
886
912
|
label: "Qualidade",
|
|
887
913
|
value: qualities.find((q) => q.id === selectedQuality)?.label ?? "Auto"
|
|
888
914
|
},
|
|
889
|
-
...
|
|
915
|
+
...captions.length > 0 ? [
|
|
890
916
|
{
|
|
891
917
|
id: "subtitles",
|
|
892
918
|
label: "Legendas",
|
|
893
|
-
value: subtitleStyle.track === "off" ? "Desligado" :
|
|
919
|
+
value: subtitleStyle.track === "off" ? "Desligado" : captions.find(
|
|
894
920
|
(s) => s.srclang === subtitleStyle.track
|
|
895
921
|
)?.label ?? subtitleStyle.track
|
|
896
922
|
}
|
|
@@ -1047,7 +1073,7 @@ function Video({
|
|
|
1047
1073
|
),
|
|
1048
1074
|
/* @__PURE__ */ jsx("div", { className: "py-1.5", children: [
|
|
1049
1075
|
{ srclang: "off", label: "Desligado" },
|
|
1050
|
-
...
|
|
1076
|
+
...captions
|
|
1051
1077
|
].map((s) => /* @__PURE__ */ jsxs(
|
|
1052
1078
|
"button",
|
|
1053
1079
|
{
|
|
@@ -1447,16 +1473,16 @@ function Video({
|
|
|
1447
1473
|
) })
|
|
1448
1474
|
] }),
|
|
1449
1475
|
/* @__PURE__ */ jsx("div", { className: "mx-0.5 h-4 w-px bg-white/20 @md:mx-1" }),
|
|
1450
|
-
|
|
1476
|
+
captions.length > 0 && /* @__PURE__ */ jsx(
|
|
1451
1477
|
"button",
|
|
1452
1478
|
{
|
|
1453
1479
|
type: "button",
|
|
1454
1480
|
onClick: () => setSubtitleMode(
|
|
1455
|
-
(m) => m === "off" ?
|
|
1481
|
+
(m) => m === "off" ? captions[0]?.srclang ?? "off" : "off"
|
|
1456
1482
|
),
|
|
1457
1483
|
className: `grid size-8 place-items-center rounded transition hover:text-white/80 @sm:size-10${subtitleMode !== "off" ? "text-white" : "text-white/60"}`,
|
|
1458
1484
|
"aria-label": "Captions",
|
|
1459
|
-
children: /* @__PURE__ */ jsx(Captions, { className: "size-4 @sm:size-5" })
|
|
1485
|
+
children: /* @__PURE__ */ jsx(Captions$1, { className: "size-4 @sm:size-5" })
|
|
1460
1486
|
}
|
|
1461
1487
|
),
|
|
1462
1488
|
/* @__PURE__ */ jsx("div", { className: "relative", children: /* @__PURE__ */ jsx(
|
|
@@ -1584,8 +1610,7 @@ function Video({
|
|
|
1584
1610
|
var VideoPlayer = Video;
|
|
1585
1611
|
function parseVideoChildren(children) {
|
|
1586
1612
|
const parsed = {
|
|
1587
|
-
sources: []
|
|
1588
|
-
subtitles: []
|
|
1613
|
+
sources: []
|
|
1589
1614
|
};
|
|
1590
1615
|
function dn(child) {
|
|
1591
1616
|
return child.type?.displayName ?? child.type?.name ?? "";
|
|
@@ -1593,25 +1618,17 @@ function parseVideoChildren(children) {
|
|
|
1593
1618
|
React.Children.forEach(children, (child) => {
|
|
1594
1619
|
if (!React.isValidElement(child)) return;
|
|
1595
1620
|
const name = dn(child);
|
|
1596
|
-
if (child.type ===
|
|
1621
|
+
if (child.type === Source || name === "SiloSource") {
|
|
1597
1622
|
const element = child;
|
|
1598
|
-
|
|
1599
|
-
if (!React.isValidElement(sourceChild)) return;
|
|
1600
|
-
const sn = dn(sourceChild);
|
|
1601
|
-
if (sourceChild.type !== Source && sn !== "SiloSource") return;
|
|
1602
|
-
const sourceElement = sourceChild;
|
|
1603
|
-
parsed.sources.push(sourceElement.props);
|
|
1604
|
-
});
|
|
1623
|
+
parsed.sources.push(element.props);
|
|
1605
1624
|
}
|
|
1606
|
-
if (child.type ===
|
|
1625
|
+
if (child.type === Captions || name === "SiloCaptions") {
|
|
1607
1626
|
const element = child;
|
|
1608
|
-
|
|
1609
|
-
|
|
1610
|
-
|
|
1611
|
-
|
|
1612
|
-
|
|
1613
|
-
parsed.subtitles.push(subtitleElement.props);
|
|
1614
|
-
});
|
|
1627
|
+
parsed.captionsSrc = element.props.src;
|
|
1628
|
+
}
|
|
1629
|
+
if (child.type === VideoThumbnail || name === "SiloVideoThumbnail") {
|
|
1630
|
+
const element = child;
|
|
1631
|
+
parsed.thumbnailSrc = element.props.src;
|
|
1615
1632
|
}
|
|
1616
1633
|
if (child.type === Storyboard || name === "SiloStoryboard") {
|
|
1617
1634
|
const element = child;
|
|
@@ -1711,6 +1728,6 @@ function formatTime(seconds) {
|
|
|
1711
1728
|
return `${minutes}:${String(secs).padStart(2, "0")}`;
|
|
1712
1729
|
}
|
|
1713
1730
|
|
|
1714
|
-
export {
|
|
1731
|
+
export { Captions, Source, Storyboard, StoryboardFrame, Video, VideoPlayer, VideoThumbnail };
|
|
1715
1732
|
//# sourceMappingURL=VideoPlayer.js.map
|
|
1716
1733
|
//# sourceMappingURL=VideoPlayer.js.map
|