@rixl/media-core 1.0.1 → 1.1.0
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/README.md +74 -84
- package/dist/chunks/B-QvSqjj.js +1 -0
- package/dist/chunks/B2DDE32u.js +1 -0
- package/dist/chunks/BZFoe94X.js +1 -0
- package/dist/chunks/DMkwQjgA.js +1 -0
- package/dist/index.d.ts +2005 -82
- package/dist/index.js +6 -73
- package/package.json +13 -6
- package/dist/api/analytics.d.ts +0 -16
- package/dist/api/analytics.js +0 -227
- package/dist/api/feed.js +0 -52
- package/dist/api/heatmap.d.ts +0 -6
- package/dist/api/heatmap.js +0 -28
- package/dist/api/hot-segments.d.ts +0 -7
- package/dist/api/hot-segments.js +0 -20
- package/dist/api/image.js +0 -11
- package/dist/api/rixl-client.d.ts +0 -3
- package/dist/api/rixl-client.js +0 -14
- package/dist/api/upload.d.ts +0 -76
- package/dist/api/upload.js +0 -150
- package/dist/api/video.js +0 -11
- package/dist/lib/analytics-builders.d.ts +0 -59
- package/dist/lib/analytics-builders.js +0 -88
- package/dist/lib/analytics-initialize.d.ts +0 -1
- package/dist/lib/analytics-initialize.js +0 -59
- package/dist/lib/analytics-utils.d.ts +0 -43
- package/dist/lib/analytics-utils.js +0 -85
- package/dist/lib/analytics-wire.js +0 -153
- package/dist/lib/buffer-progress.d.ts +0 -20
- package/dist/lib/buffer-progress.js +0 -37
- package/dist/lib/caption-styles.d.ts +0 -20
- package/dist/lib/caption-styles.js +0 -56
- package/dist/lib/caption-utils.d.ts +0 -80
- package/dist/lib/caption-utils.js +0 -111
- package/dist/lib/chapter-utils.d.ts +0 -102
- package/dist/lib/chapter-utils.js +0 -147
- package/dist/lib/click-disambiguation.d.ts +0 -44
- package/dist/lib/click-disambiguation.js +0 -80
- package/dist/lib/click-outside.d.ts +0 -68
- package/dist/lib/click-outside.js +0 -64
- package/dist/lib/colors.d.ts +0 -6
- package/dist/lib/colors.js +0 -16
- package/dist/lib/content-analytics.d.ts +0 -27
- package/dist/lib/content-analytics.js +0 -38
- package/dist/lib/environment-effects.d.ts +0 -89
- package/dist/lib/environment-effects.js +0 -139
- package/dist/lib/feed-autoscroll.d.ts +0 -10
- package/dist/lib/feed-autoscroll.js +0 -13
- package/dist/lib/feed-container-height.d.ts +0 -7
- package/dist/lib/feed-container-height.js +0 -11
- package/dist/lib/feed-description-overflow.d.ts +0 -1
- package/dist/lib/feed-description-overflow.js +0 -9
- package/dist/lib/feed-dwell.d.ts +0 -2
- package/dist/lib/feed-dwell.js +0 -8
- package/dist/lib/feed-loop.d.ts +0 -10
- package/dist/lib/feed-loop.js +0 -21
- package/dist/lib/feed-scroll.d.ts +0 -11
- package/dist/lib/feed-scroll.js +0 -19
- package/dist/lib/feed-transforms.d.ts +0 -5
- package/dist/lib/feed-transforms.js +0 -30
- package/dist/lib/filter-undefined.js +0 -11
- package/dist/lib/fullscreen-utils.d.ts +0 -1
- package/dist/lib/fullscreen-utils.js +0 -7
- package/dist/lib/hls-buffer-flush.js +0 -46
- package/dist/lib/hls-error-recovery.d.ts +0 -35
- package/dist/lib/hls-error-recovery.js +0 -75
- package/dist/lib/hls-event-handlers.js +0 -61
- package/dist/lib/hls-loader.js +0 -23
- package/dist/lib/hls-setup.d.ts +0 -72
- package/dist/lib/hls-setup.js +0 -144
- package/dist/lib/hls-utils.d.ts +0 -31
- package/dist/lib/hls-utils.js +0 -34
- package/dist/lib/image-render.d.ts +0 -29
- package/dist/lib/image-render.js +0 -63
- package/dist/lib/keyboard-config.d.ts +0 -66
- package/dist/lib/keyboard-config.js +0 -127
- package/dist/lib/keyboard-utils.d.ts +0 -4
- package/dist/lib/keyboard-utils.js +0 -11
- package/dist/lib/lifecycle-effects.d.ts +0 -67
- package/dist/lib/lifecycle-effects.js +0 -78
- package/dist/lib/loading-debounce.d.ts +0 -26
- package/dist/lib/loading-debounce.js +0 -38
- package/dist/lib/numbers.d.ts +0 -6
- package/dist/lib/numbers.js +0 -36
- package/dist/lib/pip-utils.d.ts +0 -16
- package/dist/lib/pip-utils.js +0 -32
- package/dist/lib/playback-handlers.d.ts +0 -33
- package/dist/lib/playback-handlers.js +0 -51
- package/dist/lib/playback-slider.d.ts +0 -23
- package/dist/lib/playback-slider.js +0 -24
- package/dist/lib/player-labels.d.ts +0 -23
- package/dist/lib/player-labels.js +0 -132
- package/dist/lib/player-menu-labels.d.ts +0 -80
- package/dist/lib/player-menu-labels.js +0 -829
- package/dist/lib/player-ui-actions.d.ts +0 -10
- package/dist/lib/player-ui-actions.js +0 -58
- package/dist/lib/progress-fraction.d.ts +0 -11
- package/dist/lib/progress-fraction.js +0 -20
- package/dist/lib/progress-persist.d.ts +0 -28
- package/dist/lib/progress-persist.js +0 -54
- package/dist/lib/segment-analytics.d.ts +0 -20
- package/dist/lib/segment-analytics.js +0 -29
- package/dist/lib/subtitle-logic.d.ts +0 -31
- package/dist/lib/subtitle-logic.js +0 -75
- package/dist/lib/subtitle-utils.d.ts +0 -16
- package/dist/lib/subtitle-utils.js +0 -37
- package/dist/lib/time.d.ts +0 -1
- package/dist/lib/time.js +0 -17
- package/dist/lib/track-persistence.d.ts +0 -4
- package/dist/lib/track-persistence.js +0 -35
- package/dist/lib/video-preload-config.d.ts +0 -34
- package/dist/lib/video-preload-config.js +0 -41
- package/dist/lib/video-spinner.d.ts +0 -25
- package/dist/lib/video-spinner.js +0 -35
- package/dist/lib/video-stats.d.ts +0 -28
- package/dist/lib/video-stats.js +0 -44
- package/dist/lib/volume-utils.d.ts +0 -59
- package/dist/lib/volume-utils.js +0 -55
- package/dist/progressbar.d.ts +0 -10
- package/dist/progressbar.js +0 -123
- package/dist/store/analytics-context-store.d.ts +0 -4
- package/dist/store/analytics-context-store.js +0 -13
- package/dist/store/analytics-device-store.d.ts +0 -8
- package/dist/store/analytics-device-store.js +0 -44
- package/dist/store/analytics-session-store.d.ts +0 -8
- package/dist/store/analytics-session-store.js +0 -40
- package/dist/store/analytics-store.d.ts +0 -30
- package/dist/store/analytics-store.js +0 -88
- package/dist/store/controls-store.d.ts +0 -16
- package/dist/store/controls-store.js +0 -53
- package/dist/store/feed-cache-store.d.ts +0 -24
- package/dist/store/feed-cache-store.js +0 -165
- package/dist/store/feed-interaction-store.d.ts +0 -17
- package/dist/store/feed-interaction-store.js +0 -32
- package/dist/store/feed-store.d.ts +0 -16
- package/dist/store/feed-store.js +0 -38
- package/dist/store/generic-store.js +0 -24
- package/dist/store/image-store.d.ts +0 -2
- package/dist/store/image-store.js +0 -8
- package/dist/store/player-container-element-store.d.ts +0 -10
- package/dist/store/player-container-element-store.js +0 -38
- package/dist/store/player-global-actions.js +0 -53
- package/dist/store/player-media-element-store.d.ts +0 -10
- package/dist/store/player-media-element-store.js +0 -38
- package/dist/store/player-store-actions.js +0 -197
- package/dist/store/player-store.d.ts +0 -94
- package/dist/store/player-store.js +0 -127
- package/dist/store/player-track-actions.js +0 -44
- package/dist/store/postStore.d.ts +0 -20
- package/dist/store/postStore.js +0 -112
- package/dist/store/settings/constants.d.ts +0 -15
- package/dist/store/settings/constants.js +0 -47
- package/dist/store/settings/defaults.d.ts +0 -2
- package/dist/store/settings/defaults.js +0 -24
- package/dist/store/settings/storage.d.ts +0 -3
- package/dist/store/settings/storage.js +0 -28
- package/dist/store/settings/store.d.ts +0 -32
- package/dist/store/settings/store.js +0 -59
- package/dist/store/settings/types.d.ts +0 -27
- package/dist/store/settings/validation.d.ts +0 -7
- package/dist/store/settings/validation.js +0 -55
- package/dist/store/settings-menu-store.d.ts +0 -19
- package/dist/store/settings-menu-store.js +0 -30
- package/dist/store/video-store.d.ts +0 -2
- package/dist/store/video-store.js +0 -8
- package/dist/types/analytics.d.ts +0 -113
- package/dist/types/feed.d.ts +0 -21
- package/dist/types/file.d.ts +0 -12
- package/dist/types/heatmap.d.ts +0 -5
- package/dist/types/hot-segments.d.ts +0 -9
- package/dist/types/image.d.ts +0 -9
- package/dist/types/uuid.d.ts +0 -1
- package/dist/types/video.d.ts +0 -22
|
@@ -1,147 +0,0 @@
|
|
|
1
|
-
// src/lib/chapter-utils.ts
|
|
2
|
-
/**
|
|
3
|
-
* Check if a single chapter is within the video duration
|
|
4
|
-
* @param chapter - The chapter to validate
|
|
5
|
-
* @param videoDuration - The total video duration in seconds
|
|
6
|
-
* @param tolerance - Tolerance in seconds for rounding errors (default: 1)
|
|
7
|
-
* @returns Whether the chapter is within valid bounds
|
|
8
|
-
*/
|
|
9
|
-
function isChapterWithinDuration(chapter, videoDuration, tolerance = 1) {
|
|
10
|
-
return chapter.start_time_sec <= videoDuration + tolerance && chapter.end_time_sec <= videoDuration + tolerance;
|
|
11
|
-
}
|
|
12
|
-
/**
|
|
13
|
-
* Validate chapters for use with chaptered progress bar
|
|
14
|
-
* Returns false if:
|
|
15
|
-
* - chapters is undefined or empty
|
|
16
|
-
* - less than 2 chapters (need multiple for chaptered bar)
|
|
17
|
-
* - any chapter exceeds video duration
|
|
18
|
-
*
|
|
19
|
-
* @param chapters - Array of chapters to validate
|
|
20
|
-
* @param videoDuration - The total video duration in seconds
|
|
21
|
-
* @param tolerance - Tolerance in seconds for rounding errors (default: 1)
|
|
22
|
-
* @returns Whether chapters are valid for chaptered progress bar
|
|
23
|
-
*/
|
|
24
|
-
function validateChapters(chapters, videoDuration, tolerance = 1) {
|
|
25
|
-
if (!chapters || chapters.length <= 1) return false;
|
|
26
|
-
if (videoDuration <= 0) return false;
|
|
27
|
-
return chapters.every((chapter) => isChapterWithinDuration(chapter, videoDuration, tolerance));
|
|
28
|
-
}
|
|
29
|
-
/**
|
|
30
|
-
* Calculate chapter end times based on next chapter start or video duration
|
|
31
|
-
*/
|
|
32
|
-
function calculateChaptersWithEnd(chapters, duration) {
|
|
33
|
-
return chapters.map((chapter, index) => {
|
|
34
|
-
const nextChapter = chapters[index + 1];
|
|
35
|
-
const endTime = nextChapter ? nextChapter.start_time_sec : duration;
|
|
36
|
-
return {
|
|
37
|
-
...chapter,
|
|
38
|
-
endTime,
|
|
39
|
-
durationSec: endTime - chapter.start_time_sec
|
|
40
|
-
};
|
|
41
|
-
});
|
|
42
|
-
}
|
|
43
|
-
function sliceHeatmapData({ heatmapData, chapterStartTime, chapterEndTime, videoDuration }) {
|
|
44
|
-
if (!heatmapData?.length || videoDuration <= 0) return [];
|
|
45
|
-
const startPercent = chapterStartTime / videoDuration;
|
|
46
|
-
const endPercent = chapterEndTime / videoDuration;
|
|
47
|
-
const startIndex = Math.floor(startPercent * heatmapData.length);
|
|
48
|
-
const endIndex = Math.ceil(endPercent * heatmapData.length);
|
|
49
|
-
return heatmapData.slice(startIndex, Math.max(startIndex + 1, endIndex));
|
|
50
|
-
}
|
|
51
|
-
/**
|
|
52
|
-
* Calculate all heatmap slices for chapters
|
|
53
|
-
*/
|
|
54
|
-
function calculateHeatmapSlices(heatmapData, chapters, duration) {
|
|
55
|
-
if (!heatmapData?.length) return chapters.map(() => []);
|
|
56
|
-
return chapters.map((chapter) => sliceHeatmapData({
|
|
57
|
-
heatmapData,
|
|
58
|
-
chapterStartTime: chapter.start_time_sec,
|
|
59
|
-
chapterEndTime: chapter.endTime,
|
|
60
|
-
videoDuration: duration
|
|
61
|
-
}));
|
|
62
|
-
}
|
|
63
|
-
/**
|
|
64
|
-
* Calculate global max value from heatmap data for consistent normalization
|
|
65
|
-
*/
|
|
66
|
-
function calculateGlobalMax(heatmapData) {
|
|
67
|
-
if (!heatmapData?.length) return 0;
|
|
68
|
-
return Math.max(...heatmapData);
|
|
69
|
-
}
|
|
70
|
-
/**
|
|
71
|
-
* Calculate progress percentage within a chapter segment
|
|
72
|
-
* @returns 0-100 percentage
|
|
73
|
-
*/
|
|
74
|
-
function calculateSegmentProgress(currentPosition, chapterStart, chapterEnd) {
|
|
75
|
-
if (currentPosition <= chapterStart) return 0;
|
|
76
|
-
if (currentPosition >= chapterEnd) return 100;
|
|
77
|
-
return (currentPosition - chapterStart) / (chapterEnd - chapterStart) * 100;
|
|
78
|
-
}
|
|
79
|
-
function calculateSegmentBufferRanges({ globalBufferRanges, chapterStart, chapterEnd, videoDuration }) {
|
|
80
|
-
if (chapterEnd - chapterStart <= 0 || videoDuration <= 0) return [];
|
|
81
|
-
const chapterStartPercent = chapterStart / videoDuration * 100;
|
|
82
|
-
const chapterEndPercent = chapterEnd / videoDuration * 100;
|
|
83
|
-
return globalBufferRanges.map((range) => {
|
|
84
|
-
if (range.end <= chapterStartPercent || range.start >= chapterEndPercent) return null;
|
|
85
|
-
const clampedStart = Math.max(range.start, chapterStartPercent);
|
|
86
|
-
const clampedEnd = Math.min(range.end, chapterEndPercent);
|
|
87
|
-
return {
|
|
88
|
-
start: (clampedStart - chapterStartPercent) / (chapterEndPercent - chapterStartPercent) * 100,
|
|
89
|
-
end: (clampedEnd - chapterStartPercent) / (chapterEndPercent - chapterStartPercent) * 100
|
|
90
|
-
};
|
|
91
|
-
}).filter((r) => r !== null);
|
|
92
|
-
}
|
|
93
|
-
/**
|
|
94
|
-
* Calculate flex grow ratio for a chapter based on its duration
|
|
95
|
-
*/
|
|
96
|
-
function calculateFlexGrow(chapterDuration, videoDuration) {
|
|
97
|
-
if (videoDuration <= 0) return 0;
|
|
98
|
-
return chapterDuration / videoDuration;
|
|
99
|
-
}
|
|
100
|
-
function getCurrentPosition({ isDragging, progress, duration, currentTime }) {
|
|
101
|
-
return isDragging ? progress * duration : currentTime;
|
|
102
|
-
}
|
|
103
|
-
/**
|
|
104
|
-
* Find which segment is hovered based on mouse X position
|
|
105
|
-
* @param segments - Array of segment DOM elements
|
|
106
|
-
* @param mouseX - Mouse X coordinate (clientX)
|
|
107
|
-
* @returns Index of hovered segment, or null if none
|
|
108
|
-
*/
|
|
109
|
-
function findHoveredSegmentIndex(segments, mouseX) {
|
|
110
|
-
for (let i = 0; i < segments.length; i++) {
|
|
111
|
-
const segRef = segments[i];
|
|
112
|
-
if (!segRef) continue;
|
|
113
|
-
const segRect = segRef.getBoundingClientRect();
|
|
114
|
-
if (mouseX >= segRect.left && mouseX <= segRect.right) return i;
|
|
115
|
-
}
|
|
116
|
-
return null;
|
|
117
|
-
}
|
|
118
|
-
/**
|
|
119
|
-
* Start time of the first chapter after the current position, or null when
|
|
120
|
-
* already in the last chapter. Mirrors React useChapterNavigation.
|
|
121
|
-
*/
|
|
122
|
-
function getNextChapterStart(chapters, currentTime) {
|
|
123
|
-
if (!chapters?.length) return null;
|
|
124
|
-
const next = chapters.find((ch) => ch.start_time_sec > currentTime);
|
|
125
|
-
return next ? next.start_time_sec : null;
|
|
126
|
-
}
|
|
127
|
-
/** Seconds into a chapter after which Shift+P restarts it instead of jumping back. */
|
|
128
|
-
const CHAPTER_RESTART_THRESHOLD_SECONDS = 3;
|
|
129
|
-
/**
|
|
130
|
-
* Target for "previous chapter": restart the current chapter when more than
|
|
131
|
-
* 3s in (or when it is the first), otherwise jump to the previous chapter.
|
|
132
|
-
* Mirrors React useChapterNavigation.
|
|
133
|
-
*/
|
|
134
|
-
function getPrevChapterTarget(chapters, currentTime) {
|
|
135
|
-
if (!chapters?.length) return null;
|
|
136
|
-
let currentChapterIndex = -1;
|
|
137
|
-
for (let i = chapters.length - 1; i >= 0; i--) if (chapters[i].start_time_sec <= currentTime) {
|
|
138
|
-
currentChapterIndex = i;
|
|
139
|
-
break;
|
|
140
|
-
}
|
|
141
|
-
if (currentChapterIndex < 0) return null;
|
|
142
|
-
const currentChapter = chapters[currentChapterIndex];
|
|
143
|
-
if (currentTime - currentChapter.start_time_sec > CHAPTER_RESTART_THRESHOLD_SECONDS || currentChapterIndex === 0) return currentChapter.start_time_sec;
|
|
144
|
-
return chapters[currentChapterIndex - 1].start_time_sec;
|
|
145
|
-
}
|
|
146
|
-
|
|
147
|
-
export { calculateChaptersWithEnd, calculateFlexGrow, calculateGlobalMax, calculateHeatmapSlices, calculateSegmentBufferRanges, calculateSegmentProgress, findHoveredSegmentIndex, getCurrentPosition, getNextChapterStart, getPrevChapterTarget, isChapterWithinDuration, sliceHeatmapData, validateChapters };
|
|
@@ -1,44 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Delay in milliseconds for single-click detection
|
|
3
|
-
* Used to distinguish between single click (toggle play) and double click (fullscreen)
|
|
4
|
-
*/
|
|
5
|
-
export declare const SINGLE_CLICK_DELAY_MS = 250;
|
|
6
|
-
/**
|
|
7
|
-
* Maximum time between clicks to be considered a double-click
|
|
8
|
-
*/
|
|
9
|
-
export declare const DOUBLE_CLICK_THRESHOLD_MS = 400;
|
|
10
|
-
export interface ClickDisambiguationState {
|
|
11
|
-
singleClickTimerId: ReturnType<typeof setTimeout> | null;
|
|
12
|
-
lastClickTime: number;
|
|
13
|
-
}
|
|
14
|
-
/**
|
|
15
|
-
* Create initial click disambiguation state
|
|
16
|
-
*/
|
|
17
|
-
export declare function createClickDisambiguationState(): ClickDisambiguationState;
|
|
18
|
-
export interface HandleClickOptions {
|
|
19
|
-
state: ClickDisambiguationState;
|
|
20
|
-
hideUI: boolean;
|
|
21
|
-
allowFullscreen: boolean;
|
|
22
|
-
isExcludedTarget: boolean;
|
|
23
|
-
onTogglePlay: () => void;
|
|
24
|
-
}
|
|
25
|
-
/**
|
|
26
|
-
* Handle a click event with disambiguation logic
|
|
27
|
-
* Returns true if the click was handled, false if ignored
|
|
28
|
-
*/
|
|
29
|
-
export declare function handleClick(options: HandleClickOptions): boolean;
|
|
30
|
-
export interface HandleDoubleClickOptions {
|
|
31
|
-
state: ClickDisambiguationState;
|
|
32
|
-
allowFullscreen: boolean;
|
|
33
|
-
isExcludedTarget: boolean;
|
|
34
|
-
onToggleFullscreen: () => void;
|
|
35
|
-
}
|
|
36
|
-
/**
|
|
37
|
-
* Handle a double-click event
|
|
38
|
-
* Returns true if the double-click was handled, false if ignored
|
|
39
|
-
*/
|
|
40
|
-
export declare function handleDoubleClick(options: HandleDoubleClickOptions): boolean;
|
|
41
|
-
/**
|
|
42
|
-
* Clean up click disambiguation state (clear any pending timers)
|
|
43
|
-
*/
|
|
44
|
-
export declare function cleanupClickDisambiguation(state: ClickDisambiguationState): void;
|
|
@@ -1,80 +0,0 @@
|
|
|
1
|
-
// src/lib/click-disambiguation.ts
|
|
2
|
-
/**
|
|
3
|
-
* Delay in milliseconds for single-click detection
|
|
4
|
-
* Used to distinguish between single click (toggle play) and double click (fullscreen)
|
|
5
|
-
*/
|
|
6
|
-
const SINGLE_CLICK_DELAY_MS = 250;
|
|
7
|
-
/**
|
|
8
|
-
* Maximum time between clicks to be considered a double-click
|
|
9
|
-
*/
|
|
10
|
-
const DOUBLE_CLICK_THRESHOLD_MS = 400;
|
|
11
|
-
/**
|
|
12
|
-
* Create initial click disambiguation state
|
|
13
|
-
*/
|
|
14
|
-
function createClickDisambiguationState() {
|
|
15
|
-
return {
|
|
16
|
-
singleClickTimerId: null,
|
|
17
|
-
lastClickTime: 0
|
|
18
|
-
};
|
|
19
|
-
}
|
|
20
|
-
/**
|
|
21
|
-
* Clear any pending single-click timer
|
|
22
|
-
*/
|
|
23
|
-
function clearPendingSingleClick(state) {
|
|
24
|
-
if (state.singleClickTimerId !== null) {
|
|
25
|
-
clearTimeout(state.singleClickTimerId);
|
|
26
|
-
state.singleClickTimerId = null;
|
|
27
|
-
}
|
|
28
|
-
}
|
|
29
|
-
/**
|
|
30
|
-
* Schedule a single-click action after a delay
|
|
31
|
-
* Allows time for a potential double-click to cancel it
|
|
32
|
-
*/
|
|
33
|
-
function scheduleSingleClick(state, onSingleClick) {
|
|
34
|
-
clearPendingSingleClick(state);
|
|
35
|
-
state.singleClickTimerId = setTimeout(() => {
|
|
36
|
-
onSingleClick();
|
|
37
|
-
state.singleClickTimerId = null;
|
|
38
|
-
}, 250);
|
|
39
|
-
}
|
|
40
|
-
/**
|
|
41
|
-
* Handle a click event with disambiguation logic
|
|
42
|
-
* Returns true if the click was handled, false if ignored
|
|
43
|
-
*/
|
|
44
|
-
function handleClick(options) {
|
|
45
|
-
const { state, hideUI, allowFullscreen, isExcludedTarget, onTogglePlay } = options;
|
|
46
|
-
if (hideUI || isExcludedTarget) return false;
|
|
47
|
-
const now = Date.now();
|
|
48
|
-
const timeSinceLastClick = now - state.lastClickTime;
|
|
49
|
-
state.lastClickTime = now;
|
|
50
|
-
if (timeSinceLastClick > 0 && timeSinceLastClick < 400) {
|
|
51
|
-
clearPendingSingleClick(state);
|
|
52
|
-
return true;
|
|
53
|
-
}
|
|
54
|
-
if (!allowFullscreen) {
|
|
55
|
-
onTogglePlay();
|
|
56
|
-
return true;
|
|
57
|
-
}
|
|
58
|
-
scheduleSingleClick(state, onTogglePlay);
|
|
59
|
-
return true;
|
|
60
|
-
}
|
|
61
|
-
/**
|
|
62
|
-
* Handle a double-click event
|
|
63
|
-
* Returns true if the double-click was handled, false if ignored
|
|
64
|
-
*/
|
|
65
|
-
function handleDoubleClick(options) {
|
|
66
|
-
const { state, allowFullscreen, isExcludedTarget, onToggleFullscreen } = options;
|
|
67
|
-
if (!allowFullscreen || isExcludedTarget) return false;
|
|
68
|
-
clearPendingSingleClick(state);
|
|
69
|
-
state.lastClickTime = 0;
|
|
70
|
-
onToggleFullscreen();
|
|
71
|
-
return true;
|
|
72
|
-
}
|
|
73
|
-
/**
|
|
74
|
-
* Clean up click disambiguation state (clear any pending timers)
|
|
75
|
-
*/
|
|
76
|
-
function cleanupClickDisambiguation(state) {
|
|
77
|
-
clearPendingSingleClick(state);
|
|
78
|
-
}
|
|
79
|
-
|
|
80
|
-
export { DOUBLE_CLICK_THRESHOLD_MS, SINGLE_CLICK_DELAY_MS, cleanupClickDisambiguation, clearPendingSingleClick, createClickDisambiguationState, handleClick, handleDoubleClick, scheduleSingleClick };
|
|
@@ -1,68 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Generic "click outside" detection with an optional exclusion attribute.
|
|
3
|
-
*
|
|
4
|
-
* Use case: a settings menu that should close when the user clicks outside it,
|
|
5
|
-
* but NOT when the user clicks the button that opens it (otherwise the button
|
|
6
|
-
* both opens and immediately closes the menu in the same pointer cycle).
|
|
7
|
-
*
|
|
8
|
-
* Pure, DOM-only, framework-agnostic. React/Lit/Vue wrappers call
|
|
9
|
-
* `bindClickOutside` from their lifecycle hooks.
|
|
10
|
-
*/
|
|
11
|
-
export interface ClickOutsideOptions {
|
|
12
|
-
/**
|
|
13
|
-
* Function that returns the "inside" element. Called on every pointer event,
|
|
14
|
-
* so the caller can pass a ref-like getter that may be null until the
|
|
15
|
-
* referenced element is mounted.
|
|
16
|
-
*/
|
|
17
|
-
getContainer: () => HTMLElement | null;
|
|
18
|
-
/**
|
|
19
|
-
* Optional attribute name (e.g. `"data-settings-button"`). Any pointer event
|
|
20
|
-
* whose target is inside an element carrying this attribute is treated as
|
|
21
|
-
* "inside" and does NOT trigger `onOutsideClick`.
|
|
22
|
-
*
|
|
23
|
-
* This is what lets the button that toggles the menu coexist with a
|
|
24
|
-
* close-on-outside-click listener: the button's own clicks are ignored here,
|
|
25
|
-
* letting the button's own onClick decide whether to toggle.
|
|
26
|
-
*/
|
|
27
|
-
excludeAttribute?: string;
|
|
28
|
-
/**
|
|
29
|
-
* Invoked when a pointer event lands outside both the container and (if
|
|
30
|
-
* configured) any element carrying `excludeAttribute`.
|
|
31
|
-
*/
|
|
32
|
-
onOutsideClick: (event: MouseEvent) => void;
|
|
33
|
-
}
|
|
34
|
-
/**
|
|
35
|
-
* Returns `true` when the given event target is inside an element carrying
|
|
36
|
-
* the supplied attribute. When `attribute` is undefined, always returns false.
|
|
37
|
-
*/
|
|
38
|
-
export declare function isInsideExcludedElement(target: EventTarget | null, attribute: string | undefined): boolean;
|
|
39
|
-
/**
|
|
40
|
-
* Returns `true` when the event lands outside both the container and any
|
|
41
|
-
* excluded element.
|
|
42
|
-
*
|
|
43
|
-
* Checks the composed path as well as the plain target: document-level
|
|
44
|
-
* listeners see shadow-DOM events retargeted to the host, and
|
|
45
|
-
* `document.querySelector` cannot see into shadow roots — the composed path
|
|
46
|
-
* is the only reliable record of where the click really landed.
|
|
47
|
-
*/
|
|
48
|
-
export declare function isClickOutside(event: MouseEvent, container: HTMLElement | null, excludeAttribute: string | undefined): boolean;
|
|
49
|
-
/**
|
|
50
|
-
* Bind a `mousedown` listener on the document that invokes `onOutsideClick`
|
|
51
|
-
* whenever the event lands outside the container and outside any element
|
|
52
|
-
* carrying `excludeAttribute`.
|
|
53
|
-
*
|
|
54
|
-
* Returns a teardown function that removes the listener.
|
|
55
|
-
*
|
|
56
|
-
* The container is looked up via `getContainer()` on every event so the caller
|
|
57
|
-
* can wire it to a ref that may be null at bind time.
|
|
58
|
-
*/
|
|
59
|
-
export declare function bindClickOutside({ getContainer, excludeAttribute, onOutsideClick }: ClickOutsideOptions): () => void;
|
|
60
|
-
/**
|
|
61
|
-
* Bind a `visibilitychange` listener that fires `onHidden` when the document
|
|
62
|
-
* is hidden. Returns a teardown function.
|
|
63
|
-
*
|
|
64
|
-
* Settings menus use this to close themselves when the user tabs away.
|
|
65
|
-
* Lives next to `bindClickOutside` because the two are almost always wired
|
|
66
|
-
* together for "dismissible overlay" behaviour.
|
|
67
|
-
*/
|
|
68
|
-
export declare function bindDocumentHidden(onHidden: () => void): () => void;
|
|
@@ -1,64 +0,0 @@
|
|
|
1
|
-
// src/lib/click-outside.ts
|
|
2
|
-
/**
|
|
3
|
-
* Returns `true` when the given event target is inside an element carrying
|
|
4
|
-
* the supplied attribute. When `attribute` is undefined, always returns false.
|
|
5
|
-
*/
|
|
6
|
-
function isInsideExcludedElement(target, attribute) {
|
|
7
|
-
if (!attribute) return false;
|
|
8
|
-
if (!(target instanceof Node)) return false;
|
|
9
|
-
const excluded = document.querySelector(`[${attribute}]`);
|
|
10
|
-
return Boolean(excluded?.contains(target));
|
|
11
|
-
}
|
|
12
|
-
/**
|
|
13
|
-
* Returns `true` when the event lands outside both the container and any
|
|
14
|
-
* excluded element.
|
|
15
|
-
*
|
|
16
|
-
* Checks the composed path as well as the plain target: document-level
|
|
17
|
-
* listeners see shadow-DOM events retargeted to the host, and
|
|
18
|
-
* `document.querySelector` cannot see into shadow roots — the composed path
|
|
19
|
-
* is the only reliable record of where the click really landed.
|
|
20
|
-
*/
|
|
21
|
-
function isClickOutside(event, container, excludeAttribute) {
|
|
22
|
-
if (!container) return false;
|
|
23
|
-
const target = event.target;
|
|
24
|
-
if (!(target instanceof Node)) return false;
|
|
25
|
-
const path = event.composedPath();
|
|
26
|
-
if (path.includes(container) || container.contains(target)) return false;
|
|
27
|
-
if (excludeAttribute && path.some((node) => node instanceof Element && node.hasAttribute(excludeAttribute))) return false;
|
|
28
|
-
if (isInsideExcludedElement(target, excludeAttribute)) return false;
|
|
29
|
-
return true;
|
|
30
|
-
}
|
|
31
|
-
/**
|
|
32
|
-
* Bind a `mousedown` listener on the document that invokes `onOutsideClick`
|
|
33
|
-
* whenever the event lands outside the container and outside any element
|
|
34
|
-
* carrying `excludeAttribute`.
|
|
35
|
-
*
|
|
36
|
-
* Returns a teardown function that removes the listener.
|
|
37
|
-
*
|
|
38
|
-
* The container is looked up via `getContainer()` on every event so the caller
|
|
39
|
-
* can wire it to a ref that may be null at bind time.
|
|
40
|
-
*/
|
|
41
|
-
function bindClickOutside({ getContainer, excludeAttribute, onOutsideClick }) {
|
|
42
|
-
const handler = (event) => {
|
|
43
|
-
if (isClickOutside(event, getContainer(), excludeAttribute)) onOutsideClick(event);
|
|
44
|
-
};
|
|
45
|
-
document.addEventListener("mousedown", handler);
|
|
46
|
-
return () => document.removeEventListener("mousedown", handler);
|
|
47
|
-
}
|
|
48
|
-
/**
|
|
49
|
-
* Bind a `visibilitychange` listener that fires `onHidden` when the document
|
|
50
|
-
* is hidden. Returns a teardown function.
|
|
51
|
-
*
|
|
52
|
-
* Settings menus use this to close themselves when the user tabs away.
|
|
53
|
-
* Lives next to `bindClickOutside` because the two are almost always wired
|
|
54
|
-
* together for "dismissible overlay" behaviour.
|
|
55
|
-
*/
|
|
56
|
-
function bindDocumentHidden(onHidden) {
|
|
57
|
-
const handler = () => {
|
|
58
|
-
if (document.visibilityState === "hidden") onHidden();
|
|
59
|
-
};
|
|
60
|
-
document.addEventListener("visibilitychange", handler);
|
|
61
|
-
return () => document.removeEventListener("visibilitychange", handler);
|
|
62
|
-
}
|
|
63
|
-
|
|
64
|
-
export { bindClickOutside, bindDocumentHidden, isClickOutside, isInsideExcludedElement };
|
package/dist/lib/colors.d.ts
DELETED
package/dist/lib/colors.js
DELETED
|
@@ -1,16 +0,0 @@
|
|
|
1
|
-
// src/lib/colors.ts
|
|
2
|
-
function hexToRGB(hex) {
|
|
3
|
-
hex = hex.replace("#", "");
|
|
4
|
-
return {
|
|
5
|
-
r: parseInt(hex.substring(0, 2), 16),
|
|
6
|
-
g: parseInt(hex.substring(2, 4), 16),
|
|
7
|
-
b: parseInt(hex.substring(4, 6), 16)
|
|
8
|
-
};
|
|
9
|
-
}
|
|
10
|
-
function hexToRGBAString(hex, alpha = 100) {
|
|
11
|
-
const { r, g, b } = hexToRGB(hex);
|
|
12
|
-
alpha /= 100;
|
|
13
|
-
return `rgba(${r}, ${g}, ${b}, ${alpha})`;
|
|
14
|
-
}
|
|
15
|
-
|
|
16
|
-
export { hexToRGB, hexToRGBAString };
|
|
@@ -1,27 +0,0 @@
|
|
|
1
|
-
import { BuildEventParams } from "./analytics-utils.js";
|
|
2
|
-
import { ContentType, Segment, ViewType } from "../types/analytics.js";
|
|
3
|
-
export interface VideoAnalyticsPayload {
|
|
4
|
-
videoPositionMs?: number;
|
|
5
|
-
videoTotalDurationMs?: number;
|
|
6
|
-
segments?: Segment[];
|
|
7
|
-
}
|
|
8
|
-
export interface VideoSnapshot {
|
|
9
|
-
currentTime: number;
|
|
10
|
-
duration: number;
|
|
11
|
-
}
|
|
12
|
-
export interface BuildVideoAnalyticsPayloadParams {
|
|
13
|
-
contentType: ContentType;
|
|
14
|
-
viewType: ViewType;
|
|
15
|
-
video?: VideoSnapshot | null;
|
|
16
|
-
playerId?: string;
|
|
17
|
-
}
|
|
18
|
-
/**
|
|
19
|
-
* Build and POST a single content-view event.
|
|
20
|
-
*/
|
|
21
|
-
export declare function postContentEvent(params: BuildEventParams): void;
|
|
22
|
-
/**
|
|
23
|
-
* Compute the video position / duration / segments to attach to a
|
|
24
|
-
* content-view event. Returns an empty payload for non-video content
|
|
25
|
-
* or when the video snapshot is unavailable.
|
|
26
|
-
*/
|
|
27
|
-
export declare function buildVideoAnalyticsPayload({ contentType, viewType, video, playerId }: BuildVideoAnalyticsPayloadParams): VideoAnalyticsPayload;
|
|
@@ -1,38 +0,0 @@
|
|
|
1
|
-
import { buildContentViewEvent, secondsToMs, shouldIncludeSegments } from "./analytics-utils.js";
|
|
2
|
-
import { postAnalytics } from "../api/analytics.js";
|
|
3
|
-
import { analyticsStoreActions } from "../store/analytics-store.js";
|
|
4
|
-
|
|
5
|
-
// src/lib/content-analytics.ts
|
|
6
|
-
/**
|
|
7
|
-
* Pure content-analytics helpers extracted from useContentAnalytics.
|
|
8
|
-
*
|
|
9
|
-
* - postContentEvent: build a content-view event and POST it.
|
|
10
|
-
* - buildVideoAnalyticsPayload: derive the video position/duration/segments
|
|
11
|
-
* fields included in a content-view event. Reads currentTime/duration off
|
|
12
|
-
* a video-shaped snapshot; no React refs, no DOM dependencies beyond
|
|
13
|
-
* HTMLVideoElement properties.
|
|
14
|
-
*/
|
|
15
|
-
/**
|
|
16
|
-
* Build and POST a single content-view event.
|
|
17
|
-
*/
|
|
18
|
-
function postContentEvent(params) {
|
|
19
|
-
postAnalytics([buildContentViewEvent(params)]);
|
|
20
|
-
}
|
|
21
|
-
/**
|
|
22
|
-
* Compute the video position / duration / segments to attach to a
|
|
23
|
-
* content-view event. Returns an empty payload for non-video content
|
|
24
|
-
* or when the video snapshot is unavailable.
|
|
25
|
-
*/
|
|
26
|
-
function buildVideoAnalyticsPayload({ contentType, viewType, video, playerId }) {
|
|
27
|
-
if (contentType !== "video" || !video) return {};
|
|
28
|
-
const videoPositionMs = secondsToMs(video.currentTime);
|
|
29
|
-
const videoTotalDurationMs = secondsToMs(video.duration);
|
|
30
|
-
const segments = playerId && shouldIncludeSegments(viewType) ? analyticsStoreActions.getSegmentsWithCurrent(playerId, videoPositionMs) : void 0;
|
|
31
|
-
return {
|
|
32
|
-
videoPositionMs,
|
|
33
|
-
videoTotalDurationMs,
|
|
34
|
-
segments: segments && segments.length > 0 ? segments : void 0
|
|
35
|
-
};
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
export { buildVideoAnalyticsPayload, postContentEvent };
|
|
@@ -1,89 +0,0 @@
|
|
|
1
|
-
import { Viewport } from "./caption-utils.js";
|
|
2
|
-
/**
|
|
3
|
-
* Pure helpers for video-element environment effects.
|
|
4
|
-
*
|
|
5
|
-
* "Environment effects" = things the player has to keep in sync with the
|
|
6
|
-
* surrounding document/window: fullscreen state, picture-in-picture state,
|
|
7
|
-
* tab visibility, viewport size, and the volume/mute state derived from
|
|
8
|
-
* player + user-interaction inputs.
|
|
9
|
-
*
|
|
10
|
-
* Everything in this module is framework-agnostic. React/Lit/Vue wrappers
|
|
11
|
-
* supply the DOM listeners and the store-update callbacks; this module
|
|
12
|
-
* supplies the predicates, the state derivations, and the listener factories.
|
|
13
|
-
*/
|
|
14
|
-
/**
|
|
15
|
-
* Bind the `document` `fullscreenchange` event to a callback that receives the
|
|
16
|
-
* current fullscreen state.
|
|
17
|
-
*
|
|
18
|
-
* Returns a teardown function that removes the listener.
|
|
19
|
-
*/
|
|
20
|
-
export declare function bindFullscreenChangeListener(onChange: (isFullscreen: boolean) => void): () => void;
|
|
21
|
-
/**
|
|
22
|
-
* Bind `enterpictureinpicture` and `leavepictureinpicture` events on a
|
|
23
|
-
* video element to a callback that receives the current PiP state.
|
|
24
|
-
*
|
|
25
|
-
* Returns a teardown function.
|
|
26
|
-
*/
|
|
27
|
-
export declare function bindPictureInPictureChangeListener(videoElement: HTMLVideoElement | null, onChange: (isPip: boolean) => void): () => void;
|
|
28
|
-
export interface PipReentryOptions {
|
|
29
|
-
videoElement: HTMLVideoElement | null;
|
|
30
|
-
isCurrentlyInPip: boolean;
|
|
31
|
-
}
|
|
32
|
-
/**
|
|
33
|
-
* Decide whether to re-request PiP when the document becomes hidden.
|
|
34
|
-
*
|
|
35
|
-
* Returns `true` when the caller should re-enter PiP on the supplied
|
|
36
|
-
* video element. The actual `requestPictureInPicture()` call is left to the
|
|
37
|
-
* caller (since it returns a promise and the caller chooses how to handle
|
|
38
|
-
* errors).
|
|
39
|
-
*/
|
|
40
|
-
export declare function shouldReenterPictureInPicture({ videoElement, isCurrentlyInPip }: PipReentryOptions): boolean;
|
|
41
|
-
/**
|
|
42
|
-
* Bind a `visibilitychange` handler that re-enters PiP whenever the document
|
|
43
|
-
* becomes hidden and the player believes itself to be in PiP but the browser
|
|
44
|
-
* has dropped out.
|
|
45
|
-
*
|
|
46
|
-
* Returns a teardown function.
|
|
47
|
-
*/
|
|
48
|
-
export declare function bindPipVisibilityReentry(getOptions: () => PipReentryOptions, onError?: (error: unknown) => void): () => void;
|
|
49
|
-
export interface AppliedVolumeSync {
|
|
50
|
-
/** The `muted` value that should be assigned to the video element. */
|
|
51
|
-
muted: boolean;
|
|
52
|
-
/** The `volume` value that should be assigned, or `null` if not changing. */
|
|
53
|
-
volume: number | null;
|
|
54
|
-
/** When non-null, the store's current `volume` should be updated to this value. */
|
|
55
|
-
storeVolumeUpdate: number | null;
|
|
56
|
-
}
|
|
57
|
-
export interface DeriveVolumeSyncOptions {
|
|
58
|
-
/** Hard mute applied by the consumer (e.g. theme override). */
|
|
59
|
-
forcedMuted: boolean;
|
|
60
|
-
/** The player's persisted `muted` state. */
|
|
61
|
-
playerMuted: boolean;
|
|
62
|
-
/** Whether the user has interacted with the player yet. */
|
|
63
|
-
playerInteracted: boolean;
|
|
64
|
-
/** The player's persisted `volume`. */
|
|
65
|
-
playerVolume: number;
|
|
66
|
-
/** The player's persisted `previousVolume` (used to restore on unmute). */
|
|
67
|
-
playerPreviousVolume: number;
|
|
68
|
-
}
|
|
69
|
-
/**
|
|
70
|
-
* Pure derivation of the values that should be written to the video element
|
|
71
|
-
* (and back to the store) given the current player state.
|
|
72
|
-
*
|
|
73
|
-
* Mirrors the behaviour previously implemented inside `useVolumeEffect`:
|
|
74
|
-
*
|
|
75
|
-
* 1. When the caller forces mute, nothing else is touched.
|
|
76
|
-
* 2. Otherwise, `shouldBeMuted` decides the effective mute state.
|
|
77
|
-
* 3. When unmuted, `getRestoredVolume` resolves the volume to assign, and the
|
|
78
|
-
* store is updated only when the current persisted volume is `0`.
|
|
79
|
-
*/
|
|
80
|
-
export declare function deriveVolumeSync({ forcedMuted, playerMuted, playerInteracted, playerVolume, playerPreviousVolume }: DeriveVolumeSyncOptions): AppliedVolumeSync | null;
|
|
81
|
-
/**
|
|
82
|
-
* Observe a container element's viewport size, invoking the callback with the
|
|
83
|
-
* current `{width, height}` whenever it changes (via `ResizeObserver`) or
|
|
84
|
-
* the window resizes.
|
|
85
|
-
*
|
|
86
|
-
* Returns a teardown function.
|
|
87
|
-
*/
|
|
88
|
-
export declare function observeViewport(container: HTMLElement | null, onChange: (viewport: Viewport) => void): () => void;
|
|
89
|
-
export type { Viewport };
|