@design-edito/tools 0.4.11 → 0.4.12
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/agnostic/arrays/index.d.ts +1 -1
- package/agnostic/arrays/index.js +1 -1
- package/agnostic/colors/index.d.ts +2 -2
- package/agnostic/colors/index.js +2 -2
- package/agnostic/css/index.d.ts +1 -1
- package/agnostic/css/index.js +1 -1
- package/agnostic/html/deep-select/index.d.ts +31 -0
- package/agnostic/html/deep-select/index.js +52 -0
- package/agnostic/html/hyper-json/smart-tags/coalesced/index.d.ts +14 -14
- package/agnostic/html/hyper-json/smart-tags/coalesced/index.js +14 -14
- package/agnostic/html/hyper-json/smart-tags/isolated/index.d.ts +2 -2
- package/agnostic/html/hyper-json/smart-tags/isolated/index.js +2 -2
- package/agnostic/html/index.d.ts +3 -1
- package/agnostic/html/index.js +3 -1
- package/agnostic/html/watch-selection/index.d.ts +41 -0
- package/agnostic/html/watch-selection/index.js +50 -0
- package/agnostic/index.d.ts +3 -3
- package/agnostic/index.js +3 -3
- package/agnostic/misc/index.d.ts +3 -3
- package/agnostic/misc/index.js +3 -3
- package/agnostic/misc/logs/index.d.ts +1 -1
- package/agnostic/misc/logs/index.js +1 -1
- package/agnostic/numbers/index.d.ts +2 -2
- package/agnostic/numbers/index.js +2 -2
- package/agnostic/objects/index.d.ts +3 -3
- package/agnostic/objects/index.js +3 -3
- package/agnostic/random/index.d.ts +1 -1
- package/agnostic/random/index.js +1 -1
- package/agnostic/sanitization/index.d.ts +1 -1
- package/agnostic/sanitization/index.js +1 -1
- package/agnostic/strings/index.d.ts +3 -2
- package/agnostic/strings/index.js +3 -2
- package/agnostic/strings/split-trim/index.d.ts +27 -0
- package/agnostic/strings/split-trim/index.js +36 -0
- package/components/Video/index.controlled.d.ts +153 -0
- package/components/Video/index.controlled.js +255 -0
- package/components/Video/index.d.ts +10 -114
- package/components/Video/index.js +140 -265
- package/components/Video/utils.d.ts +11 -10
- package/components/Video/utils.js +30 -37
- package/components/public-classnames.d.ts +1 -0
- package/components/public-classnames.js +1 -0
- package/index.d.ts +1 -1
- package/index.js +1 -1
- package/node/@google-cloud/storage/file/index.d.ts +2 -2
- package/node/@google-cloud/storage/file/index.js +2 -2
- package/node/ftps/file/index.d.ts +2 -2
- package/node/ftps/file/index.js +2 -2
- package/node/images/transform/operations/index.d.ts +1 -1
- package/node/images/transform/operations/index.js +1 -1
- package/node/index.d.ts +1 -1
- package/node/index.js +1 -1
- package/package.json +22 -1
|
@@ -1,297 +1,172 @@
|
|
|
1
|
-
import { jsx as _jsx
|
|
1
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
2
|
import { useCallback, useEffect, useMemo, useRef, useState } from 'react';
|
|
3
3
|
import { clss } from '../../agnostic/css/clss/index.js';
|
|
4
4
|
import { Disclaimer } from '../Disclaimer/index.js';
|
|
5
5
|
import { IntersectionObserverComponent } from '../IntersectionObserver/index.js';
|
|
6
|
-
import { Subtitles } from '../Subtitles/index.js';
|
|
7
6
|
import { mergeClassNames } from '../utils/index.js';
|
|
8
|
-
import {
|
|
9
|
-
import {
|
|
7
|
+
import { videoWrapper as publicClassName } from '../public-classnames.js';
|
|
8
|
+
import { muteAttributeWorkaround } from './utils.js';
|
|
10
9
|
import cssModule from './styles.module.css';
|
|
10
|
+
import { ControlledVideo } from './index.controlled.js';
|
|
11
11
|
/**
|
|
12
12
|
* Full-featured video player component. Wraps a native `<video>` element with
|
|
13
13
|
* playback controls, volume, playback rate, a timeline, optional subtitles,
|
|
14
14
|
* an optional disclaimer gate, and viewport-driven auto-play/mute behaviours.
|
|
15
15
|
*
|
|
16
|
-
* ### Root element modifiers
|
|
17
|
-
* The root `<figure>` receives the public class name defined by `video` and
|
|
18
|
-
* the following BEM-style modifier classes:
|
|
19
|
-
* - `--play-on` / `--play-off` — reflects current playback state.
|
|
20
|
-
* - `--fullscreen-on` / `--fullscreen-off` — reflects fullscreen state.
|
|
21
|
-
* - `--loud` / `--muted` — reflects mute state.
|
|
22
|
-
*
|
|
23
|
-
* ### Data attributes on the root element
|
|
24
|
-
* - `data-play-on` — present (empty string) when playing.
|
|
25
|
-
* - `data-play-off` — present (empty string) when paused.
|
|
26
|
-
* - `data-fullscreen-on` — present (empty string) when in fullScreen.
|
|
27
|
-
* - `data-fullscreen-off` — present (empty string) when not in fullScreen.
|
|
28
|
-
* - `data-loud` — present (empty string) when unmuted.
|
|
29
|
-
* - `data-muted` — present (empty string) when muted.
|
|
30
|
-
* - `data-volume` — current volume as a `0–1` float.
|
|
31
|
-
* - `data-volume-percent` — current volume as a `0–100` float.
|
|
32
|
-
* - `data-playback-rate` — current playback rate (e.g. `1`, `1.5`).
|
|
33
|
-
* - `data-current-time-ms` — current time in milliseconds, fixed to 2 decimals.
|
|
34
|
-
* - `data-current-time-ratio` — current / total ratio, fixed to 8 decimals.
|
|
35
|
-
* - `data-total-time-ms` — total duration in milliseconds.
|
|
36
|
-
*
|
|
37
|
-
* ### CSS custom properties on the root element
|
|
38
|
-
* - `--video-current-time-ratio` — current / total ratio, fixed to 8 decimals.
|
|
39
|
-
* Useful for driving progress-bar animations purely in CSS.
|
|
40
|
-
*
|
|
41
16
|
* @param props - Component properties.
|
|
42
17
|
* @see {@link Props}
|
|
43
18
|
* @returns A `<figure>` element containing the video, its controls, optional
|
|
44
19
|
* subtitles, and an optional disclaimer overlay.
|
|
45
20
|
*/
|
|
46
|
-
export const Video = ({
|
|
21
|
+
export const Video = ({ loop, disclaimer, autoPlayWhenVisible, autoPauseWhenHidden, autoMuteWhenHidden, autoLoudWhenVisible, wrapperClassName, ...controlledProps }) => {
|
|
47
22
|
// State & refs
|
|
48
|
-
const [
|
|
49
|
-
const [
|
|
50
|
-
const [
|
|
51
|
-
const [
|
|
52
|
-
const [
|
|
53
|
-
const [volume, setVolume] = useState(0);
|
|
54
|
-
const [playbackRate, setPlaybackRate] = useState(0);
|
|
55
|
-
const [hasBeenAutoPlayed, setHasBeenAutoPlayed] = useState(false);
|
|
23
|
+
const [play, setPlay] = useState(false);
|
|
24
|
+
const [volume, setVolume] = useState(1);
|
|
25
|
+
const [mute, setMute] = useState(false);
|
|
26
|
+
const [playbackRate, setPlaybackRate] = useState(1);
|
|
27
|
+
const [fullscreen, setFullscreen] = useState(false);
|
|
56
28
|
const [isDisclaimerOn, setIsDisclaimerOn] = useState(disclaimer?.isOn === true
|
|
57
29
|
|| disclaimer?.defaultIsOn === true
|
|
58
30
|
|| (disclaimer !== undefined && disclaimer.defaultIsOn === undefined));
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
const
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
31
|
+
const hasBeenAutoPlayed = useRef(false);
|
|
32
|
+
const needsDisclaimer = useMemo(() => disclaimer !== undefined, [disclaimer]);
|
|
33
|
+
const shouldDisclaimerBeOn = useMemo(() => {
|
|
34
|
+
if (disclaimer?.isOn === false)
|
|
35
|
+
return false;
|
|
36
|
+
if (disclaimer?.isOn === true)
|
|
37
|
+
return true;
|
|
38
|
+
return isDisclaimerOn;
|
|
39
|
+
}, [disclaimer, isDisclaimerOn]);
|
|
40
|
+
const needsObserve = useMemo(() => autoLoudWhenVisible === true
|
|
41
|
+
|| autoMuteWhenHidden === true
|
|
42
|
+
|| autoPlayWhenVisible === true
|
|
43
|
+
|| autoPauseWhenHidden === true, [
|
|
44
|
+
autoLoudWhenVisible,
|
|
45
|
+
autoMuteWhenHidden,
|
|
46
|
+
autoPlayWhenVisible,
|
|
47
|
+
autoPauseWhenHidden
|
|
48
|
+
]);
|
|
49
|
+
// Intrisic event handlers
|
|
50
|
+
const handleOnPlayEvent = useCallback((e) => {
|
|
51
|
+
controlledProps.onPlay?.(e);
|
|
52
|
+
if (shouldDisclaimerBeOn) {
|
|
53
|
+
setPlay(false);
|
|
74
54
|
return;
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
}, [
|
|
83
|
-
const
|
|
84
|
-
|
|
85
|
-
setVolume(volume);
|
|
86
|
-
|
|
87
|
-
}, [
|
|
88
|
-
const
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
}, [
|
|
97
|
-
const
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
const
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
const
|
|
55
|
+
}
|
|
56
|
+
setPlay(true);
|
|
57
|
+
hasBeenAutoPlayed.current = true;
|
|
58
|
+
}, [controlledProps?.onPlay, shouldDisclaimerBeOn]);
|
|
59
|
+
const handleOnPauseEvent = useCallback((e) => {
|
|
60
|
+
setPlay(false);
|
|
61
|
+
controlledProps.onPause?.(e);
|
|
62
|
+
}, [controlledProps?.onPause]);
|
|
63
|
+
const handleOnVolumeChangeEvent = useCallback((e) => {
|
|
64
|
+
setMute(Boolean(e.currentTarget.muted));
|
|
65
|
+
setVolume(Number(e.currentTarget.volume));
|
|
66
|
+
controlledProps.onVolumeChange?.(e);
|
|
67
|
+
}, [controlledProps?.onVolumeChange]);
|
|
68
|
+
const handleOnRateChangeEvent = useCallback((e) => {
|
|
69
|
+
setPlaybackRate(Number(e.currentTarget.playbackRate));
|
|
70
|
+
controlledProps.onRateChange?.(e);
|
|
71
|
+
}, [controlledProps?.onRateChange]);
|
|
72
|
+
const handleOnFullscreenChangeEvent = useCallback((e) => {
|
|
73
|
+
if (document.fullscreenElement === null || shouldDisclaimerBeOn) {
|
|
74
|
+
setFullscreen(false);
|
|
75
|
+
}
|
|
76
|
+
}, [shouldDisclaimerBeOn]);
|
|
77
|
+
const handleOnLoadedMetadataEvent = useCallback((e) => {
|
|
78
|
+
muteAttributeWorkaround(e.currentTarget, controlledProps.muted ?? false);
|
|
79
|
+
controlledProps.onLoadedMetadata?.(e);
|
|
80
|
+
}, [controlledProps?.onLoadedMetadata, controlledProps?.muted]);
|
|
81
|
+
// User actions
|
|
82
|
+
const handlePlayButtonClick = useCallback((e, isPlaying, video) => {
|
|
83
|
+
controlledProps.actionHandlers?.playButtonClick?.(e, isPlaying, video);
|
|
84
|
+
setPlay(!shouldDisclaimerBeOn);
|
|
85
|
+
}, [controlledProps.actionHandlers, shouldDisclaimerBeOn]);
|
|
86
|
+
const handlePauseButtonClick = useCallback((e, isPlaying, video) => {
|
|
87
|
+
controlledProps.actionHandlers?.pauseButtonClick?.(e, isPlaying, video);
|
|
88
|
+
setPlay(false);
|
|
89
|
+
}, [controlledProps.actionHandlers]);
|
|
90
|
+
const handleLoudButtonClick = useCallback((e, isLoud, video) => {
|
|
91
|
+
controlledProps.actionHandlers?.loudButtonClick?.(e, isLoud, video);
|
|
92
|
+
setMute(false);
|
|
93
|
+
}, [controlledProps.actionHandlers]);
|
|
94
|
+
const handleMuteButtonClick = useCallback((e, isLoud, video) => {
|
|
95
|
+
controlledProps.actionHandlers?.muteButtonClick?.(e, isLoud, video);
|
|
96
|
+
setMute(true);
|
|
97
|
+
}, [controlledProps.actionHandlers]);
|
|
98
|
+
const handleRateRangeChange = useCallback((e, targetRate, currentRate, video) => {
|
|
99
|
+
controlledProps.actionHandlers?.rateRangeChange?.(e, targetRate, currentRate, video);
|
|
100
|
+
setPlaybackRate(targetRate);
|
|
101
|
+
}, [controlledProps.actionHandlers]);
|
|
102
|
+
const handleVolumeRangeChange = useCallback((e, targetVolume, currentVolume, video) => {
|
|
103
|
+
controlledProps.actionHandlers?.volumeRangeChange?.(e, targetVolume, currentVolume, video);
|
|
104
|
+
setVolume(targetVolume);
|
|
105
|
+
}, [controlledProps.actionHandlers]);
|
|
106
|
+
const handleFullscreenButtonClick = useCallback((e, isFullscreen, video) => {
|
|
107
|
+
controlledProps.actionHandlers?.fullscreenButtonClick?.(e, isFullscreen, video);
|
|
108
|
+
setFullscreen((prev) => shouldDisclaimerBeOn ? false : !isFullscreen);
|
|
109
|
+
}, [controlledProps.actionHandlers, shouldDisclaimerBeOn]);
|
|
110
|
+
// Intersection Observer + Disclaimer
|
|
111
|
+
const onIntersected = useCallback(({ ioEntry }) => {
|
|
112
|
+
if (ioEntry === undefined)
|
|
113
|
+
return;
|
|
114
|
+
const { isIntersecting = false } = ioEntry;
|
|
115
|
+
if (autoPauseWhenHidden === true && !isIntersecting) {
|
|
116
|
+
setPlay(false);
|
|
117
|
+
}
|
|
118
|
+
if (autoLoudWhenVisible === true && isIntersecting) {
|
|
119
|
+
setMute(false);
|
|
120
|
+
}
|
|
121
|
+
if (autoPlayWhenVisible === true && !shouldDisclaimerBeOn && !hasBeenAutoPlayed.current && isIntersecting) {
|
|
122
|
+
setPlay(true);
|
|
123
|
+
}
|
|
124
|
+
if (autoMuteWhenHidden === true && !shouldDisclaimerBeOn && !hasBeenAutoPlayed.current && !isIntersecting) {
|
|
125
|
+
setMute(true);
|
|
126
|
+
}
|
|
127
|
+
}, [autoPlayWhenVisible, autoPauseWhenHidden, autoMuteWhenHidden, autoLoudWhenVisible, shouldDisclaimerBeOn]);
|
|
128
|
+
const handleDiclaimerDismiss = useCallback((prevIsOn) => {
|
|
149
129
|
setIsDisclaimerOn(false);
|
|
150
|
-
if (
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
130
|
+
if (controlledProps.autoPlay === true && !hasBeenAutoPlayed.current) {
|
|
131
|
+
setPlay(true);
|
|
132
|
+
}
|
|
133
|
+
disclaimer?.actionHandlers?.dismissClick?.(prevIsOn);
|
|
134
|
+
}, [controlledProps.autoPlay, disclaimer?.actionHandlers?.dismissClick]);
|
|
154
135
|
useEffect(() => {
|
|
155
|
-
if (isDisclaimerOn !== shouldDisclaimerBeOn)
|
|
136
|
+
if (isDisclaimerOn !== shouldDisclaimerBeOn) {
|
|
156
137
|
setIsDisclaimerOn(shouldDisclaimerBeOn);
|
|
157
|
-
if (shouldDisclaimerBeOn) {
|
|
158
|
-
forceMute(videoRef.current, setIsLoud);
|
|
159
|
-
forcePause(videoRef.current, setIsPlaying);
|
|
160
|
-
void forceExitFullScreen(videoRef.current, setIsFullScreen);
|
|
161
|
-
}
|
|
162
|
-
else if (intrinsicVideoAttributes.autoPlay === true) {
|
|
163
|
-
if (videoRef.current === null)
|
|
164
|
-
return;
|
|
165
|
-
if (hasBeenAutoPlayed)
|
|
166
|
-
return;
|
|
167
|
-
if (videoRef.current.paused)
|
|
168
|
-
void forcePlay(videoRef.current, shouldDisclaimerBeOn, setIsPlaying);
|
|
169
138
|
}
|
|
170
|
-
}, [
|
|
171
|
-
shouldDisclaimerBeOn,
|
|
172
|
-
intrinsicVideoAttributes,
|
|
173
|
-
hasBeenAutoPlayed
|
|
174
|
-
]);
|
|
175
|
-
useEffect(() => {
|
|
176
|
-
stateHandlers?.isPlaying?.(isPlaying);
|
|
177
|
-
}, [isPlaying, stateHandlers?.isPlaying]);
|
|
178
|
-
useEffect(() => {
|
|
179
|
-
stateHandlers?.isFullScreen?.(isFullScreen);
|
|
180
|
-
}, [isFullScreen, stateHandlers?.isFullScreen]);
|
|
139
|
+
}, [isDisclaimerOn, shouldDisclaimerBeOn]);
|
|
181
140
|
useEffect(() => {
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
}, [volume, stateHandlers?.volume]);
|
|
187
|
-
useEffect(() => {
|
|
188
|
-
stateHandlers?.playbackRate?.(playbackRate);
|
|
189
|
-
}, [playbackRate, stateHandlers?.playbackRate]);
|
|
190
|
-
useEffect(() => {
|
|
191
|
-
stateHandlers?.currentTime?.(currentTime);
|
|
192
|
-
}, [currentTime, stateHandlers?.currentTime]);
|
|
193
|
-
// Parsing sources & tracks props
|
|
194
|
-
const parsedSources = useMemo(() => {
|
|
195
|
-
if (sources === undefined)
|
|
196
|
-
return [];
|
|
197
|
-
if (typeof sources === 'string')
|
|
198
|
-
return [{ src: sources }];
|
|
199
|
-
if (Array.isArray(sources)) {
|
|
200
|
-
if (sources.length === 0)
|
|
201
|
-
return [];
|
|
202
|
-
if (typeof sources[0] === 'string')
|
|
203
|
-
return sources.map(src => ({ src }));
|
|
204
|
-
return sources;
|
|
141
|
+
if (shouldDisclaimerBeOn) {
|
|
142
|
+
setMute(true);
|
|
143
|
+
setPlay(false);
|
|
144
|
+
setFullscreen(false);
|
|
205
145
|
}
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
const parsedTracks = useMemo(() => {
|
|
209
|
-
if (tracks === undefined)
|
|
210
|
-
return [];
|
|
211
|
-
if (typeof tracks === 'string')
|
|
212
|
-
return [{ src: tracks }];
|
|
213
|
-
if (Array.isArray(tracks)) {
|
|
214
|
-
if (tracks.length === 0)
|
|
215
|
-
return [];
|
|
216
|
-
if (typeof tracks[0] === 'string')
|
|
217
|
-
return tracks.map(src => ({ src }));
|
|
218
|
-
return tracks;
|
|
146
|
+
else if (controlledProps.autoPlay === true && !hasBeenAutoPlayed.current) {
|
|
147
|
+
setPlay(true);
|
|
219
148
|
}
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
// Rendering
|
|
149
|
+
}, [shouldDisclaimerBeOn]);
|
|
150
|
+
// Render
|
|
223
151
|
const c = clss(publicClassName, { cssModule });
|
|
224
|
-
const rootClss = mergeClassNames(c(null, {
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
'data-volume': volume,
|
|
240
|
-
'data-volume-percent': volumePercent,
|
|
241
|
-
'data-playback-rate': playbackRate,
|
|
242
|
-
'data-current-time-ms': currentTimeMs.toFixed(2),
|
|
243
|
-
'data-current-time-ratio': (currentTime / totalTime).toFixed(8),
|
|
244
|
-
'data-total-time-ms': totalTimeMs
|
|
245
|
-
};
|
|
246
|
-
const rootStyles = {
|
|
247
|
-
[`--${publicClassName}-elapsed-time-ratio`]: (currentTime / totalTime).toFixed(8)
|
|
248
|
-
};
|
|
249
|
-
const videoClss = c('video');
|
|
250
|
-
const videoControlsClss = c('video-controls');
|
|
251
|
-
const playBtnClss = c('play-btn');
|
|
252
|
-
const pauseBtnClss = c('pause-btn');
|
|
253
|
-
const loudBtnClss = c('loud-btn');
|
|
254
|
-
const muteBtnClss = c('mute-btn');
|
|
255
|
-
const volumePcntClss = c('volume-percent');
|
|
256
|
-
const fullScreenBtnClss = c('fullscreen-btn');
|
|
257
|
-
const volumeRangeClss = c('volume-range');
|
|
258
|
-
const playbackRateRangeClss = c('playback-rate-range');
|
|
259
|
-
const playbackRateClss = c('playback-rate');
|
|
260
|
-
const timeControlsClss = c('time-controls');
|
|
261
|
-
const currentTimeClss = c('current-time');
|
|
262
|
-
const totalTimeClss = c('total-time');
|
|
263
|
-
const timelineClss = c('timeline');
|
|
264
|
-
const sensitiveContent = _jsxs(_Fragment, { children: [_jsxs("video", { ref: videoRef, className: videoClss, onVolumeChange: handleVolumeChangeEvent, onLoadedMetadata: handleMetadataLoadEvent, onPlay: handlePlayEvent, onPause: handlePauseEvent, onTimeUpdate: handleTimeUpdateEvent, onRateChange: handleRateChangeEvent, ...intrinsicVideoAttributes, autoPlay: shouldDisclaimerBeOn ? false : intrinsicVideoAttributes.autoPlay, muted: shouldDisclaimerBeOn ? true : intrinsicVideoAttributes.muted, children: [parsedSources.map((source, index) => typeof source === 'string'
|
|
265
|
-
? _jsx("source", { src: source }, index)
|
|
266
|
-
: _jsx("source", { src: source.src, type: source.type }, index)), parsedTracks.map((track, index) => typeof track === 'string'
|
|
267
|
-
? _jsx("track", { src: track }, index)
|
|
268
|
-
: _jsx("track", { src: track.src, kind: track.kind, srcLang: track.srclang, label: track.label, default: track.default }, index)), children] }), _jsxs("div", { className: videoControlsClss, children: [_jsx("button", { className: playBtnClss, onClick: handlePlayButtonClick, children: playBtnContent }), _jsx("button", { className: pauseBtnClss, onClick: handlePauseButtonClick, children: pauseBtnContent }), _jsx("button", { className: loudBtnClss, onClick: handleLoudButtonClick, children: loudBtnContent }), _jsx("button", { className: muteBtnClss, onClick: handleMuteButtonClick, children: muteBtnContent }), _jsx("input", { type: "range", className: volumeRangeClss, value: volumePercent, onChange: handleVolumeRangeChange, min: 0, max: 100, step: 1 }), _jsx("span", { className: volumePcntClss, children: volumePercent }), _jsx("button", { className: fullScreenBtnClss, onClick: handleFullScreenButtonClick, children: fullScreenBtnContent }), _jsx("input", { type: "range", className: playbackRateRangeClss, value: playbackRate, onChange: handleRateRangeChange, min: 0.25, max: 4, step: 0.25 }), _jsx("span", { className: playbackRateClss, children: playbackRate })] }), _jsxs("div", { className: timeControlsClss, children: [_jsx("span", { className: currentTimeClss, children: formatTime(currentTimeMs, 'mm:ss:ms') }), _jsx("span", { className: totalTimeClss, children: formatTime(totalTimeMs, 'mm:ss:ms') }), _jsx("div", { className: timelineClss, onClick: handleTimelineClick })] }), subtitles !== undefined && _jsx(Subtitles, { ...subtitles, timecodeMs: currentTimeMs })] });
|
|
269
|
-
const disclaimedContent = disclaimer !== undefined
|
|
270
|
-
? _jsx(Disclaimer, { ...disclaimer, isOn: shouldDisclaimerBeOn, actionHandlers: {
|
|
271
|
-
dismissClick: handleDisclaimerDismiss
|
|
152
|
+
const rootClss = mergeClassNames(c(null, {}), wrapperClassName);
|
|
153
|
+
const sensitiveContent = _jsx(ControlledVideo, { ...controlledProps, play: play, volume: volume, mute: mute, playbackRate: playbackRate, fullscreen: fullscreen, onPlay: handleOnPlayEvent, onPause: handleOnPauseEvent, onVolumeChange: handleOnVolumeChangeEvent, onRateChange: handleOnRateChangeEvent, onLoadedMetadata: handleOnLoadedMetadataEvent, onFullscreenChange: handleOnFullscreenChangeEvent, actionHandlers: {
|
|
154
|
+
...controlledProps.actionHandlers,
|
|
155
|
+
playButtonClick: handlePlayButtonClick,
|
|
156
|
+
pauseButtonClick: handlePauseButtonClick,
|
|
157
|
+
loudButtonClick: handleLoudButtonClick,
|
|
158
|
+
muteButtonClick: handleMuteButtonClick,
|
|
159
|
+
volumeRangeChange: handleVolumeRangeChange,
|
|
160
|
+
rateRangeChange: handleRateRangeChange,
|
|
161
|
+
fullscreenButtonClick: handleFullscreenButtonClick
|
|
162
|
+
} });
|
|
163
|
+
const disclaimedContent = needsDisclaimer
|
|
164
|
+
? _jsx(Disclaimer, { ...disclaimer, actionHandlers: {
|
|
165
|
+
...disclaimer?.actionHandlers,
|
|
166
|
+
dismissClick: handleDiclaimerDismiss
|
|
272
167
|
}, children: sensitiveContent })
|
|
273
168
|
: sensitiveContent;
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|| autoPauseWhenHidden === true
|
|
278
|
-
? _jsx(IntersectionObserverComponent, { onIntersected: ({ ioEntry }) => {
|
|
279
|
-
const { isIntersecting = false } = ioEntry ?? {};
|
|
280
|
-
if (autoMuteWhenHidden === true && !isIntersecting)
|
|
281
|
-
forceMute(videoRef.current, setIsLoud);
|
|
282
|
-
if (autoPauseWhenHidden === true && !isIntersecting)
|
|
283
|
-
forcePause(videoRef.current, setIsPlaying);
|
|
284
|
-
if (autoPlayWhenVisible === true
|
|
285
|
-
&& !hasBeenAutoPlayed
|
|
286
|
-
&& !shouldDisclaimerBeOn
|
|
287
|
-
&& isIntersecting)
|
|
288
|
-
void forcePlay(videoRef.current, shouldDisclaimerBeOn, setIsPlaying);
|
|
289
|
-
if (autoLoudWhenVisible === true
|
|
290
|
-
&& !hasBeenAutoPlayed
|
|
291
|
-
&& !shouldDisclaimerBeOn
|
|
292
|
-
&& isIntersecting)
|
|
293
|
-
forceLoud(videoRef.current, setIsLoud);
|
|
294
|
-
}, children: disclaimedContent })
|
|
295
|
-
: disclaimedContent;
|
|
296
|
-
return _jsx("figure", { className: rootClss, ...rootAttributes, ref: $root, style: rootStyles, children: observedContent });
|
|
169
|
+
return (_jsx("div", { className: rootClss, children: needsObserve
|
|
170
|
+
? _jsx(IntersectionObserverComponent, { onIntersected: onIntersected, children: disclaimedContent })
|
|
171
|
+
: disclaimedContent }));
|
|
297
172
|
};
|
|
@@ -1,14 +1,15 @@
|
|
|
1
1
|
import type { Dispatch, SetStateAction } from 'react';
|
|
2
|
-
export declare const muteAttributeWorkaround: (video: HTMLVideoElement | null, shouldMute: boolean
|
|
3
|
-
export declare const forceMute: (video: HTMLVideoElement | null
|
|
4
|
-
export declare const forceLoud: (video: HTMLVideoElement | null
|
|
5
|
-
export declare const forceVolume: (video: HTMLVideoElement | null,
|
|
2
|
+
export declare const muteAttributeWorkaround: (video: HTMLVideoElement | null, shouldMute: boolean) => void;
|
|
3
|
+
export declare const forceMute: (video: HTMLVideoElement | null) => void;
|
|
4
|
+
export declare const forceLoud: (video: HTMLVideoElement | null) => void;
|
|
5
|
+
export declare const forceVolume: (video: HTMLVideoElement | null, volume: number) => void;
|
|
6
6
|
export declare const forceCurrentTime: (video: HTMLVideoElement | null, time: number, setCurrentTime: Dispatch<SetStateAction<number>>) => void;
|
|
7
|
-
export declare const forcePlay: (video: HTMLVideoElement | null
|
|
8
|
-
export declare const forcePause: (video: HTMLVideoElement | null
|
|
9
|
-
export declare const forcePlaybackRate: (video: HTMLVideoElement | null, rate: number
|
|
10
|
-
export declare const
|
|
11
|
-
export declare const
|
|
7
|
+
export declare const forcePlay: (video: HTMLVideoElement | null) => Promise<boolean>;
|
|
8
|
+
export declare const forcePause: (video: HTMLVideoElement | null) => Promise<boolean>;
|
|
9
|
+
export declare const forcePlaybackRate: (video: HTMLVideoElement | null, rate: number) => void;
|
|
10
|
+
export declare const forceFullscreen: (video: HTMLVideoElement | null) => Promise<boolean>;
|
|
11
|
+
export declare const forceExitFullscreen: (video: HTMLVideoElement | null) => Promise<boolean>;
|
|
12
12
|
export declare function secondsToMs(seconds: number): number;
|
|
13
|
+
export declare function msToSeconds(ms: number): number;
|
|
13
14
|
export declare function formatTime(ms: number, format: string, fps?: number): string;
|
|
14
|
-
export declare const getTimelineClickProgress: (event: React.MouseEvent<HTMLDivElement
|
|
15
|
+
export declare const getTimelineClickProgress: (event: React.MouseEvent<HTMLDivElement>, timeline: HTMLDivElement | null, video: HTMLVideoElement | null) => number;
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/* Video element triggers */
|
|
2
|
-
export const muteAttributeWorkaround = (video, shouldMute
|
|
2
|
+
export const muteAttributeWorkaround = (video, shouldMute) => {
|
|
3
3
|
if (video === null)
|
|
4
4
|
return;
|
|
5
5
|
if (!shouldMute)
|
|
@@ -9,26 +9,21 @@ export const muteAttributeWorkaround = (video, shouldMute, setIsSoundOn) => {
|
|
|
9
9
|
return;
|
|
10
10
|
video.setAttribute('muted', '');
|
|
11
11
|
video.load();
|
|
12
|
-
setIsSoundOn(false);
|
|
13
12
|
};
|
|
14
|
-
export const forceMute = (video
|
|
13
|
+
export const forceMute = (video) => {
|
|
15
14
|
if (video === null)
|
|
16
15
|
return;
|
|
17
16
|
video.muted = true;
|
|
18
|
-
setIsSoundOn(false);
|
|
19
17
|
};
|
|
20
|
-
export const forceLoud = (video
|
|
18
|
+
export const forceLoud = (video) => {
|
|
21
19
|
if (video === null)
|
|
22
20
|
return;
|
|
23
21
|
video.muted = false;
|
|
24
|
-
setIsSoundOn(true);
|
|
25
22
|
};
|
|
26
|
-
export const forceVolume = (video,
|
|
23
|
+
export const forceVolume = (video, volume) => {
|
|
27
24
|
if (video === null)
|
|
28
25
|
return;
|
|
29
|
-
const volume = volumePercent / 100;
|
|
30
26
|
video.volume = volume;
|
|
31
|
-
setVolume(volume);
|
|
32
27
|
};
|
|
33
28
|
export const forceCurrentTime = (video, time, setCurrentTime) => {
|
|
34
29
|
if (video === null)
|
|
@@ -36,73 +31,71 @@ export const forceCurrentTime = (video, time, setCurrentTime) => {
|
|
|
36
31
|
video.currentTime = time;
|
|
37
32
|
setCurrentTime(time);
|
|
38
33
|
};
|
|
39
|
-
export const forcePlay = async (video
|
|
40
|
-
if (shouldDisclaimerBeOn) {
|
|
41
|
-
setIsPlaying(false);
|
|
42
|
-
return;
|
|
43
|
-
}
|
|
34
|
+
export const forcePlay = async (video) => {
|
|
44
35
|
if (video === null)
|
|
45
|
-
return;
|
|
36
|
+
return false;
|
|
37
|
+
if (!video.paused)
|
|
38
|
+
return true;
|
|
46
39
|
try {
|
|
47
40
|
await video.play();
|
|
48
|
-
|
|
41
|
+
return video.paused;
|
|
49
42
|
}
|
|
50
43
|
catch (e) {
|
|
51
44
|
console.error(e);
|
|
52
45
|
}
|
|
46
|
+
return false;
|
|
53
47
|
};
|
|
54
|
-
export const forcePause = (video
|
|
55
|
-
if (video === null)
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
48
|
+
export const forcePause = async (video) => {
|
|
49
|
+
if (video === null)
|
|
50
|
+
return false;
|
|
51
|
+
if (video.paused)
|
|
52
|
+
return true;
|
|
59
53
|
try {
|
|
60
54
|
video.pause();
|
|
61
|
-
|
|
55
|
+
return video.paused;
|
|
62
56
|
}
|
|
63
57
|
catch (e) {
|
|
64
58
|
console.error(e);
|
|
65
59
|
}
|
|
60
|
+
return false;
|
|
66
61
|
};
|
|
67
|
-
export const forcePlaybackRate = (video, rate
|
|
62
|
+
export const forcePlaybackRate = (video, rate) => {
|
|
68
63
|
if (video === null)
|
|
69
64
|
return;
|
|
70
65
|
video.playbackRate = rate;
|
|
71
|
-
setPlaybackRate(rate);
|
|
72
66
|
};
|
|
73
|
-
export const
|
|
74
|
-
if (
|
|
75
|
-
return;
|
|
76
|
-
if (video === null) {
|
|
77
|
-
setIsFullscreen(false);
|
|
78
|
-
return;
|
|
79
|
-
}
|
|
67
|
+
export const forceFullscreen = async (video) => {
|
|
68
|
+
if (video === null)
|
|
69
|
+
return false;
|
|
80
70
|
try {
|
|
81
71
|
await video.requestFullscreen();
|
|
82
|
-
|
|
72
|
+
return document.fullscreenElement === video;
|
|
83
73
|
}
|
|
84
74
|
catch (e) {
|
|
85
|
-
setIsFullscreen(false);
|
|
86
75
|
console.error(e);
|
|
87
76
|
}
|
|
77
|
+
return false;
|
|
88
78
|
};
|
|
89
|
-
export const
|
|
79
|
+
export const forceExitFullscreen = async (video) => {
|
|
90
80
|
if (video === null || document.fullscreenElement !== video) {
|
|
91
|
-
|
|
92
|
-
return;
|
|
81
|
+
return false;
|
|
93
82
|
}
|
|
94
83
|
try {
|
|
95
84
|
await document.exitFullscreen();
|
|
96
|
-
|
|
85
|
+
return document.fullscreenElement !== video;
|
|
97
86
|
}
|
|
98
87
|
catch (e) {
|
|
99
88
|
console.error(e);
|
|
100
89
|
}
|
|
90
|
+
return false;
|
|
101
91
|
};
|
|
102
92
|
/* Time & formats */
|
|
103
93
|
export function secondsToMs(seconds) {
|
|
104
94
|
return seconds * 1000;
|
|
105
95
|
}
|
|
96
|
+
export function msToSeconds(ms) {
|
|
97
|
+
return ms / 1000;
|
|
98
|
+
}
|
|
106
99
|
export function formatTime(ms, format, fps = 25) {
|
|
107
100
|
const totalSeconds = Math.floor(ms / 1000);
|
|
108
101
|
const hours = Math.floor(totalSeconds / 3600);
|
package/index.d.ts
CHANGED
package/index.js
CHANGED