@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.
Files changed (35) hide show
  1. package/dist/contentful/index.d.ts +5 -1
  2. package/dist/contentful/index.esm.js +15 -3
  3. package/dist/contentful/index.esm.js.map +1 -1
  4. package/dist/contentful/index.js +15 -3
  5. package/dist/contentful/index.js.map +1 -1
  6. package/dist/core.d.ts +4 -2
  7. package/dist/index.d.ts +2 -0
  8. package/dist/index.esm.js +18 -6
  9. package/dist/index.esm.js.map +1 -1
  10. package/dist/index.js +18 -6
  11. package/dist/index.js.map +1 -1
  12. package/dist/next/index.esm.js +16 -2
  13. package/dist/next/index.esm.js.map +1 -1
  14. package/dist/next/index.js +16 -2
  15. package/dist/next/index.js.map +1 -1
  16. package/dist/styles.css +1 -1
  17. package/package.json +2 -1
  18. package/src/components/next-image/index.tsx +10 -1
  19. package/src/components/video-link/contentful-video-embed.tsx +17 -1
  20. package/src/components/video-link/index.test.tsx +196 -24
  21. package/src/components/video-link/index.tsx +84 -15
  22. package/src/components/video-link/types.ts +15 -1
  23. package/src/components/video-link/vimeo-embed.tsx +51 -2
  24. package/src/components/video-link/youtube-embed.test.tsx +81 -54
  25. package/src/components/video-link/youtube-embed.tsx +97 -16
  26. package/src/components/video-link/youtube-iframe-api-loader.ts +45 -0
  27. package/src/contentful/blocks/image-promo-bar/index.test.tsx +2 -2
  28. package/src/contentful/blocks/image-promo-bar/index.tsx +2 -0
  29. package/src/contentful/blocks/image-promo-bar/types.ts +5 -1
  30. package/src/contentful/blocks/navigation/index.test.tsx +34 -0
  31. package/src/contentful/blocks/navigation/index.tsx +33 -4
  32. package/src/contentful/blocks/navigation/types.ts +3 -0
  33. package/src/hooks/use-fullscreen-toggle.ts +23 -0
  34. package/src/hooks/use-video-analytics.ts +126 -0
  35. 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
+ }