@windstream/react-shared-components 0.2.50 → 0.2.52
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/contentful/index.d.ts +5 -1
- package/dist/contentful/index.esm.js +15 -3
- package/dist/contentful/index.esm.js.map +1 -1
- package/dist/contentful/index.js +15 -3
- package/dist/contentful/index.js.map +1 -1
- package/dist/core.d.ts +4 -2
- package/dist/index.d.ts +2 -0
- package/dist/index.esm.js +18 -6
- package/dist/index.esm.js.map +1 -1
- package/dist/index.js +18 -6
- package/dist/index.js.map +1 -1
- package/dist/next/index.esm.js +16 -2
- package/dist/next/index.esm.js.map +1 -1
- package/dist/next/index.js +16 -2
- package/dist/next/index.js.map +1 -1
- package/dist/styles.css +1 -1
- package/package.json +2 -1
- package/src/components/next-image/index.tsx +10 -1
- package/src/components/video-link/contentful-video-embed.tsx +17 -1
- package/src/components/video-link/index.test.tsx +196 -24
- package/src/components/video-link/index.tsx +84 -15
- package/src/components/video-link/types.ts +15 -1
- package/src/components/video-link/vimeo-embed.tsx +51 -2
- package/src/components/video-link/youtube-embed.test.tsx +81 -54
- package/src/components/video-link/youtube-embed.tsx +97 -16
- package/src/components/video-link/youtube-iframe-api-loader.ts +45 -0
- package/src/contentful/blocks/image-promo-bar/index.test.tsx +2 -2
- package/src/contentful/blocks/image-promo-bar/index.tsx +2 -0
- package/src/contentful/blocks/image-promo-bar/types.ts +5 -1
- package/src/contentful/blocks/navigation/index.test.tsx +34 -0
- package/src/contentful/blocks/navigation/index.tsx +33 -4
- package/src/contentful/blocks/navigation/types.ts +3 -0
- package/src/hooks/use-fullscreen-toggle.ts +23 -0
- package/src/hooks/use-video-analytics.ts +126 -0
- package/src/types/vimeo-player.d.ts +11 -0
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
import { useRef } from "react";
|
|
2
|
+
|
|
3
|
+
export type VideoProvider = "youtube" | "vimeo" | "contentful";
|
|
4
|
+
|
|
5
|
+
export type VideoAnalyticsEventName =
|
|
6
|
+
| "played"
|
|
7
|
+
| "paused"
|
|
8
|
+
| "progress"
|
|
9
|
+
| "completed"
|
|
10
|
+
| "fullscreen_toggled"
|
|
11
|
+
| "closed";
|
|
12
|
+
|
|
13
|
+
export type VideoAnalyticsPayload = {
|
|
14
|
+
videoId: string;
|
|
15
|
+
videoTitle?: string;
|
|
16
|
+
provider: VideoProvider;
|
|
17
|
+
position: number;
|
|
18
|
+
duration: number;
|
|
19
|
+
percentComplete: number;
|
|
20
|
+
isFullscreen?: boolean;
|
|
21
|
+
};
|
|
22
|
+
|
|
23
|
+
export type VideoAnalyticsHandler = (
|
|
24
|
+
event: VideoAnalyticsEventName,
|
|
25
|
+
payload: VideoAnalyticsPayload
|
|
26
|
+
) => void;
|
|
27
|
+
|
|
28
|
+
export type VideoAnalyticsMeta = {
|
|
29
|
+
videoId: string;
|
|
30
|
+
videoTitle?: string;
|
|
31
|
+
provider: VideoProvider;
|
|
32
|
+
};
|
|
33
|
+
|
|
34
|
+
const PROGRESS_MILESTONES = [25, 50, 75];
|
|
35
|
+
|
|
36
|
+
// Centralizes progress-milestone/completion dedup so each provider embed
|
|
37
|
+
// only has to report raw play/pause/timeupdate/ended/fullscreen callbacks -
|
|
38
|
+
// none of them know about Segment or the unified event schema.
|
|
39
|
+
export function useVideoAnalytics(onVideoEvent?: VideoAnalyticsHandler) {
|
|
40
|
+
const firedMilestones = useRef<Set<number>>(new Set());
|
|
41
|
+
const hasCompleted = useRef(false);
|
|
42
|
+
const lastPosition = useRef(0);
|
|
43
|
+
const lastDuration = useRef(0);
|
|
44
|
+
|
|
45
|
+
const emit = (
|
|
46
|
+
meta: VideoAnalyticsMeta,
|
|
47
|
+
event: VideoAnalyticsEventName,
|
|
48
|
+
extra?: Partial<VideoAnalyticsPayload>
|
|
49
|
+
) => {
|
|
50
|
+
if (!onVideoEvent) return;
|
|
51
|
+
onVideoEvent(event, {
|
|
52
|
+
videoId: meta.videoId,
|
|
53
|
+
videoTitle: meta.videoTitle,
|
|
54
|
+
provider: meta.provider,
|
|
55
|
+
position: lastPosition.current,
|
|
56
|
+
duration: lastDuration.current,
|
|
57
|
+
percentComplete:
|
|
58
|
+
lastDuration.current > 0
|
|
59
|
+
? Math.min(
|
|
60
|
+
100,
|
|
61
|
+
Math.round((lastPosition.current / lastDuration.current) * 100)
|
|
62
|
+
)
|
|
63
|
+
: 0,
|
|
64
|
+
...extra,
|
|
65
|
+
});
|
|
66
|
+
};
|
|
67
|
+
|
|
68
|
+
const reset = () => {
|
|
69
|
+
firedMilestones.current = new Set();
|
|
70
|
+
hasCompleted.current = false;
|
|
71
|
+
lastPosition.current = 0;
|
|
72
|
+
lastDuration.current = 0;
|
|
73
|
+
};
|
|
74
|
+
|
|
75
|
+
const handlePlay = (meta: VideoAnalyticsMeta) => emit(meta, "played");
|
|
76
|
+
|
|
77
|
+
const handlePause = (meta: VideoAnalyticsMeta) => emit(meta, "paused");
|
|
78
|
+
|
|
79
|
+
const handleFullscreenToggle = (
|
|
80
|
+
meta: VideoAnalyticsMeta,
|
|
81
|
+
isFullscreen: boolean
|
|
82
|
+
) => emit(meta, "fullscreen_toggled", { isFullscreen });
|
|
83
|
+
|
|
84
|
+
const handleClosed = (meta: VideoAnalyticsMeta) => emit(meta, "closed");
|
|
85
|
+
|
|
86
|
+
const handleTimeUpdate = (
|
|
87
|
+
meta: VideoAnalyticsMeta,
|
|
88
|
+
position: number,
|
|
89
|
+
duration: number
|
|
90
|
+
) => {
|
|
91
|
+
const safePosition = Number.isFinite(position) ? position : 0;
|
|
92
|
+
const safeDuration = Number.isFinite(duration) ? duration : 0;
|
|
93
|
+
lastPosition.current = safePosition;
|
|
94
|
+
lastDuration.current = safeDuration;
|
|
95
|
+
if (safeDuration <= 0) return;
|
|
96
|
+
const percent = Math.min(100, (safePosition / safeDuration) * 100);
|
|
97
|
+
PROGRESS_MILESTONES.forEach(milestone => {
|
|
98
|
+
if (percent >= milestone && !firedMilestones.current.has(milestone)) {
|
|
99
|
+
firedMilestones.current.add(milestone);
|
|
100
|
+
emit(meta, "progress");
|
|
101
|
+
}
|
|
102
|
+
});
|
|
103
|
+
|
|
104
|
+
if (percent >= 99.5 && !hasCompleted.current) {
|
|
105
|
+
hasCompleted.current = true;
|
|
106
|
+
emit(meta, "completed");
|
|
107
|
+
}
|
|
108
|
+
};
|
|
109
|
+
|
|
110
|
+
const handleEnded = (meta: VideoAnalyticsMeta) => {
|
|
111
|
+
if (hasCompleted.current) return;
|
|
112
|
+
hasCompleted.current = true;
|
|
113
|
+
if (lastDuration.current > 0) lastPosition.current = lastDuration.current;
|
|
114
|
+
emit(meta, "completed");
|
|
115
|
+
};
|
|
116
|
+
|
|
117
|
+
return {
|
|
118
|
+
handlePlay,
|
|
119
|
+
handlePause,
|
|
120
|
+
handleFullscreenToggle,
|
|
121
|
+
handleClosed,
|
|
122
|
+
handleTimeUpdate,
|
|
123
|
+
handleEnded,
|
|
124
|
+
reset,
|
|
125
|
+
};
|
|
126
|
+
}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
declare module "@vimeo/player" {
|
|
2
|
+
export default class Player {
|
|
3
|
+
constructor(
|
|
4
|
+
element: HTMLIFrameElement | HTMLElement | string,
|
|
5
|
+
options?: any
|
|
6
|
+
);
|
|
7
|
+
on(event: string, callback: (data: any) => void): void;
|
|
8
|
+
off(event: string, callback?: (data: any) => void): void;
|
|
9
|
+
destroy(): Promise<void>;
|
|
10
|
+
}
|
|
11
|
+
}
|