@eluvio/elv-player-js 1.0.140 → 2.0.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.
Files changed (102) hide show
  1. package/README.md +35 -6
  2. package/dist/.vite/manifest.json +67 -0
  3. package/dist/Analytics-MzZmvYgy.mjs +2028 -0
  4. package/dist/Analytics-jM8HcyUa.js +29 -0
  5. package/dist/dash.all.min-16Sl6Y0h.js +25 -0
  6. package/dist/dash.all.min-2ST8aEXP.mjs +19428 -0
  7. package/dist/elv-player-js.cjs.js +1 -0
  8. package/dist/elv-player-js.css +1 -0
  9. package/dist/elv-player-js.es.js +5 -0
  10. package/dist/hls-1eCRapWm.mjs +15461 -0
  11. package/dist/hls-6O5SV1FQ.js +26 -0
  12. package/dist/index-BThzGsbn.js +23 -0
  13. package/dist/index-Cw8L2-NE.js +367 -0
  14. package/dist/index-herSXPMN.mjs +2273 -0
  15. package/dist/index-mO9GR6Op.mjs +67432 -0
  16. package/lib/index.js +7 -0
  17. package/{src → lib/player}/Analytics.js +9 -8
  18. package/lib/player/Controls.js +912 -0
  19. package/{src → lib/player}/FairPlay.js +2 -0
  20. package/lib/player/Player.js +881 -0
  21. package/lib/player/PlayerParameters.js +173 -0
  22. package/lib/static/icons/Icons.js +29 -0
  23. package/lib/static/icons/svgs/backward-circle.svg +5 -0
  24. package/lib/static/icons/svgs/backward.svg +4 -0
  25. package/lib/static/icons/svgs/captions-off.svg +7 -0
  26. package/lib/static/icons/svgs/captions.svg +6 -0
  27. package/lib/static/icons/svgs/check.svg +1 -0
  28. package/lib/static/icons/svgs/chevron-left.svg +1 -0
  29. package/lib/static/icons/svgs/chevron-right.svg +1 -0
  30. package/lib/static/icons/svgs/forward-circle.svg +5 -0
  31. package/lib/static/icons/svgs/forward.svg +4 -0
  32. package/{src/static/icons/media/Full Screen icon.svg → lib/static/icons/svgs/full-screen.svg} +1 -1
  33. package/lib/static/icons/svgs/large-play-circle.svg +4 -0
  34. package/lib/static/icons/svgs/list.svg +1 -0
  35. package/{src/static/icons → lib/static/icons/svgs}/minimize.svg +1 -1
  36. package/{src/static/icons/media/Pause icon.svg → lib/static/icons/svgs/pause-circle.svg} +3 -3
  37. package/lib/static/icons/svgs/pause.svg +1 -0
  38. package/{src/static/icons/media/Play icon.svg → lib/static/icons/svgs/play-circle.svg} +1 -1
  39. package/lib/static/icons/svgs/play.svg +1 -0
  40. package/lib/static/icons/svgs/rotate-cw.svg +1 -0
  41. package/lib/static/icons/svgs/settings.svg +11 -0
  42. package/{src/static/icons/media/skip back icon.svg → lib/static/icons/svgs/skip-backward.svg} +2 -3
  43. package/{src/static/icons/media/Skip forward icon.svg → lib/static/icons/svgs/skip-forward.svg} +2 -3
  44. package/{src/static/icons/media/Volume icon.svg → lib/static/icons/svgs/volume-high.svg} +3 -3
  45. package/lib/static/icons/svgs/volume-low.svg +10 -0
  46. package/{src/static/icons/media/low volume icon.svg → lib/static/icons/svgs/volume-medium.svg} +2 -2
  47. package/{src/static/icons/media/no volume icon.svg → lib/static/icons/svgs/volume-off.svg} +3 -3
  48. package/lib/static/stylesheets/common.module.scss +486 -0
  49. package/lib/static/stylesheets/controls-tv.module.scss +488 -0
  50. package/lib/static/stylesheets/controls-web.module.scss +422 -0
  51. package/lib/static/stylesheets/player-profile-form.module.scss +141 -0
  52. package/lib/static/stylesheets/player.module.scss +92 -0
  53. package/lib/static/stylesheets/reset.module.scss +79 -0
  54. package/lib/static/stylesheets/ticket-form.module.scss +123 -0
  55. package/lib/ui/BuildIcons.cjs +44 -0
  56. package/lib/ui/Common.js +210 -0
  57. package/lib/ui/Components.jsx +342 -0
  58. package/lib/ui/Observers.js +449 -0
  59. package/lib/ui/PlayerProfileForm.jsx +106 -0
  60. package/lib/ui/PlayerUI.jsx +316 -0
  61. package/lib/ui/TVControls.jsx +337 -0
  62. package/lib/ui/TicketForm.jsx +147 -0
  63. package/lib/ui/WebControls.jsx +290 -0
  64. package/package.json +35 -47
  65. package/dist/index.js +0 -2
  66. package/dist/index.js.LICENSE.txt +0 -80
  67. package/src/BuildIcons.js +0 -27
  68. package/src/PlayerControls.js +0 -1478
  69. package/src/index.js +0 -1417
  70. package/src/static/icons/Icons.js +0 -15
  71. package/src/static/icons/Settings icon.svg +0 -4
  72. package/src/static/icons/chat icon collapse.svg +0 -1
  73. package/src/static/icons/chat icon.svg +0 -11
  74. package/src/static/icons/chat send.svg +0 -1
  75. package/src/static/icons/full screen.svg +0 -1
  76. package/src/static/icons/media/LargePlayIcon.svg +0 -4
  77. package/src/static/icons/media/Settings icon.svg +0 -4
  78. package/src/static/icons/media/Skip backward icon.svg +0 -4
  79. package/src/static/icons/media/list.svg +0 -1
  80. package/src/static/icons/media/loop icon.svg +0 -12
  81. package/src/static/icons/media/shuffle icon.svg +0 -13
  82. package/src/static/icons/muted.svg +0 -11
  83. package/src/static/icons/pause.svg +0 -1
  84. package/src/static/icons/play circle.svg +0 -1
  85. package/src/static/icons/play.svg +0 -1
  86. package/src/static/icons/settings.svg +0 -1
  87. package/src/static/icons/slider circle.svg +0 -1
  88. package/src/static/icons/unmuted.svg +0 -10
  89. package/src/static/images/ELUV.IO logo embed player.png +0 -0
  90. package/src/static/images/ELUV.IO logo embed player.svg +0 -1
  91. package/src/static/images/ELUV.IO white 20 px V2.png +0 -0
  92. package/src/static/images/ELUVIO white.svg +0 -26
  93. package/src/static/images/Logo.png +0 -0
  94. package/src/static/stylesheets/player.scss +0 -1065
  95. package/webpack.config.js +0 -152
  96. /package/{src/static/icons → lib/static/icons/svgs}/arrow-left.svg +0 -0
  97. /package/{src/static/icons/live icon.svg → lib/static/icons/svgs/live.svg} +0 -0
  98. /package/{src/static/icons → lib/static/icons/svgs}/multiview.svg +0 -0
  99. /package/{src/static/icons/media → lib/static/icons/svgs}/next.svg +0 -0
  100. /package/{src/static/icons/media → lib/static/icons/svgs}/previous.svg +0 -0
  101. /package/{src/static/icons → lib/static/icons/svgs}/x.svg +0 -0
  102. /package/{dist/5897e28fa3e8ac0a2fae.png → lib/static/images/Logo.png} +0 -0
@@ -0,0 +1,147 @@
1
+ import TicketFormStyles from "../static/stylesheets/ticket-form.module.scss";
2
+
3
+ import React, {useEffect, useState} from "react";
4
+ import {Spinner} from "./Components.jsx";
5
+
6
+ const TicketForm = ({parameters, dimensions, onComplete}) => {
7
+ let { tenantId, ntpId, ticketCode, ticketSubject } = (parameters.clientOptions || {});
8
+
9
+ // If tenant ID or NTP ID not specified, code cannot be redeemed
10
+ const invalid = !tenantId || !ntpId;
11
+
12
+ const [code, setCode] = useState(ticketCode || "");
13
+ const [initialCodeSubmitting, setInitialCodeSubmitting] = useState(!!ticketCode);
14
+ const [submitting, setSubmitting] = useState(false);
15
+ const [errorMessage, setErrorMessage] = useState(!invalid ? "" : "Error: Tenant ID or NTP ID not specified");
16
+ const [client, setClient] = useState(undefined);
17
+
18
+ const RedeemCode = async ({client, code}) => {
19
+ if(!code || !client) { return; }
20
+
21
+ setErrorMessage("");
22
+ setSubmitting(true);
23
+
24
+ try {
25
+ let subject = ticketSubject;
26
+ if(code.includes(":")) {
27
+ subject = code.split(":")[0];
28
+ code = code.split(":")[1];
29
+ }
30
+
31
+ await client.RedeemCode({
32
+ tenantId,
33
+ ntpId,
34
+ code: code.trim(),
35
+ email: subject
36
+ });
37
+
38
+ onComplete(client);
39
+ } catch(error) {
40
+ // eslint-disable-next-line no-console
41
+ console.log(error);
42
+
43
+ setErrorMessage("Invalid Code");
44
+ setInitialCodeSubmitting(false);
45
+ } finally {
46
+ setSubmitting(false);
47
+ }
48
+ };
49
+
50
+ useEffect(() => {
51
+ // Ticket redemption always uses new client
52
+ import("@eluvio/elv-client-js")
53
+ .then(async ({ElvClient}) => {
54
+ const client = await ElvClient.FromConfigurationUrl({
55
+ configUrl: parameters.clientOptions.network
56
+ });
57
+
58
+ setClient(client);
59
+
60
+ if(ticketCode) {
61
+ RedeemCode({client, code: ticketCode});
62
+ }
63
+ });
64
+
65
+
66
+ }, []);
67
+
68
+ if(initialCodeSubmitting) {
69
+ return (
70
+ <div
71
+ role="complementary"
72
+ tabIndex={-1}
73
+ style={{
74
+ backgroundColor: parameters.playerOptions.backgroundColor || "transparent",
75
+ "--portal-width": `${dimensions.width}px`,
76
+ "--portal-height": `${dimensions.height}px`
77
+ }}
78
+ className={[TicketFormStyles["ticket-form-container"], TicketFormStyles[`size-${dimensions.size}`], TicketFormStyles[`orientation-${dimensions.orientation}`]].join(" ")}
79
+ >
80
+ <div className={TicketFormStyles["ticket-form-overlay"]}>
81
+ <Spinner className={TicketFormStyles["spinner"]} />
82
+ </div>
83
+ </div>
84
+ );
85
+ }
86
+
87
+ return (
88
+ <div
89
+ role="complementary"
90
+ tabIndex={-1}
91
+ style={{
92
+ backgroundColor: parameters.playerOptions.backgroundColor || "transparent",
93
+ "--portal-width": `${dimensions.width}px`,
94
+ "--portal-height": `${dimensions.height}px`
95
+ }}
96
+ className={[TicketFormStyles["ticket-form-container"], TicketFormStyles[`size-${dimensions.size}`], TicketFormStyles[`orientation-${dimensions.orientation}`]].join(" ")}
97
+ >
98
+ <div className={TicketFormStyles["ticket-form-overlay"]}>
99
+ <form
100
+ onSubmit={event => {
101
+ event.preventDefault();
102
+ RedeemCode({client, code});
103
+ }}
104
+ className={TicketFormStyles["ticket-form"]}
105
+ >
106
+ <div className={TicketFormStyles["text"]}>
107
+ <h2 className={TicketFormStyles["title"]}>
108
+ { parameters.clientOptions.ticketTitle || "This content requires a code to view" }
109
+ </h2>
110
+ <p className={TicketFormStyles["description"]}>
111
+ { parameters.clientOptions.ticketDescription || "Please enter your code below" }
112
+ </p>
113
+ </div>
114
+ <div className={TicketFormStyles["inputs"]}>
115
+ <input
116
+ disabled={invalid}
117
+ autoFocus
118
+ type="text"
119
+ placeholder="Ticket Code"
120
+ value={code}
121
+ aria-label="Ticket Code"
122
+ aria-invalid={!!errorMessage && !invalid}
123
+ aria-errormessage={errorMessage}
124
+ onKeyDown={event => event.key === "Enter" && RedeemCode({client, code})}
125
+ onChange={event => {
126
+ setErrorMessage("");
127
+ setCode(event.target.value);
128
+ }}
129
+ className={TicketFormStyles["input"]}
130
+ />
131
+ <button
132
+ type="submit"
133
+ aria-label="Submit Code"
134
+ disabled={!code || !client || invalid}
135
+ className={TicketFormStyles["submit"]}
136
+ >
137
+ { submitting ? <Spinner light /> : "Submit" }
138
+ </button>
139
+ </div>
140
+ <div className={TicketFormStyles["error-message"]}>{ errorMessage } </div>
141
+ </form>
142
+ </div>
143
+ </div>
144
+ );
145
+ };
146
+
147
+ export default TicketForm;
@@ -0,0 +1,290 @@
1
+ import ControlStyles from "../static/stylesheets/controls-web.module.scss";
2
+
3
+ // eslint-disable-next-line no-unused-vars
4
+ import React, {useEffect, useState} from "react";
5
+ import * as Icons from "../static/icons/Icons.js";
6
+ import {ObserveVideo, ObserveVideoTime} from "./Observers.js";
7
+ import "focus-visible";
8
+ import {ImageUrl, PlayerClick, Time} from "./Common.js";
9
+ import EluvioPlayerParameters from "../player/PlayerParameters.js";
10
+
11
+ import EluvioLogo from "../static/images/Logo.png";
12
+ import {CollectionMenu, SeekBar, SettingsMenu, VolumeControls} from "./Components.jsx";
13
+
14
+ export const IconButton = ({icon, ...props}) => {
15
+ return (
16
+ <button {...props} className={`${ControlStyles["icon-button"]} ${props.className || ""}`} dangerouslySetInnerHTML={{__html: icon}} />
17
+ );
18
+ };
19
+
20
+ const TimeIndicator = ({player, videoState}) => {
21
+ const [currentTime, setCurrentTime] = useState(player.video.currentTime);
22
+
23
+ useEffect(() => {
24
+ const disposeVideoTimeObserver = ObserveVideoTime({video: player.video, setCurrentTime, rate: 10});
25
+
26
+ return () => disposeVideoTimeObserver && disposeVideoTimeObserver();
27
+ }, []);
28
+
29
+ if(player.isLive) {
30
+ return (
31
+ <div className={ControlStyles["live-indicator"]}>
32
+ Live
33
+ </div>
34
+ );
35
+ }
36
+
37
+ return (
38
+ <div className={ControlStyles["time"]}>
39
+ { Time(currentTime, videoState.duration) } / { Time(videoState.duration, videoState.duration) }
40
+ </div>
41
+ );
42
+ };
43
+
44
+ const CollectionControls = ({player}) => {
45
+ const collectionInfo = player.controls.GetCollectionInfo();
46
+
47
+ if(!collectionInfo || collectionInfo.mediaLength === 0 || !collectionInfo.isPlaylist) { return null; }
48
+
49
+ const previousMedia = collectionInfo.content[collectionInfo.mediaIndex - 1];
50
+ const nextMedia = collectionInfo.content[collectionInfo.mediaIndex + 1];
51
+
52
+ const playerReady = player.controls.IsReady();
53
+ return (
54
+ <>
55
+ {
56
+ !previousMedia ? null :
57
+ <div
58
+ key={`media-previous-${collectionInfo.mediaIndex}`}
59
+ className={`${ControlStyles["collection-button-container"]} ${!playerReady ? ControlStyles["collection-button-container--loading"] : ""}`}
60
+ >
61
+ <IconButton aria-label={`Play Previous: ${previousMedia.title}`} disabled={!playerReady} icon={Icons.PreviousTrackIcon} onClick={() => player.controls.CollectionPlayPrevious()} />
62
+ <div className={ControlStyles["collection-button-text"]}>{ previousMedia.title }</div>
63
+ </div>
64
+ }
65
+ {
66
+ !nextMedia ? null :
67
+ <div
68
+ key={`media-next-${collectionInfo.mediaIndex}`}
69
+ className={`${ControlStyles["collection-button-container"]} ${!playerReady ? ControlStyles["collection-button-container--loading"] : ""}`}
70
+ >
71
+ <IconButton aria-label={`Play Next: ${nextMedia.title}`} disabled={!playerReady} icon={Icons.NextTrackIcon} onClick={() => player.controls.CollectionPlayNext()} />
72
+ <div className={ControlStyles["collection-button-text"]}>{ nextMedia.title }</div>
73
+ </div>
74
+ }
75
+ </>
76
+ );
77
+ };
78
+
79
+ const MenuButton = ({label, icon, player, setMenuActive, MenuComponent}) => {
80
+ const [show, setShow] = useState(false);
81
+
82
+ return (
83
+ <div className={ControlStyles["menu-control-container"]}>
84
+ <IconButton
85
+ aria-label={show ? `Hide ${label} Menu` : label}
86
+ aria-haspopup
87
+ icon={icon}
88
+ onClick={() => {
89
+ setMenuActive(!show);
90
+ setShow(!show);
91
+ }}
92
+ className={show ? ControlStyles["icon-button-active"] : ""}
93
+ />
94
+ {
95
+ !show ? null :
96
+ <MenuComponent
97
+ player={player}
98
+ Hide={() => {
99
+ setShow(false);
100
+ setMenuActive(false);
101
+ }}
102
+ />
103
+ }
104
+ </div>
105
+ );
106
+ };
107
+
108
+ const ContentInfo = ({player}) => {
109
+ const [imageUrl, setImageUrl] = useState(undefined);
110
+
111
+ const { title, subtitle, description, image, headers } = (player.controls.GetContentInfo() || {});
112
+
113
+ useEffect(() => {
114
+ setImageUrl(undefined);
115
+
116
+ if(!image) { return; }
117
+
118
+ ImageUrl({player, pathOrUrl: image, width: 200})
119
+ .then(imageUrl => setImageUrl(imageUrl));
120
+ }, [image]);
121
+
122
+ if(
123
+ !title ||
124
+ (player.playerOptions.title === EluvioPlayerParameters.title.FULLSCREEN_ONLY && !player.controls.IsFullscreen()) ||
125
+ player.playerOptions.title === EluvioPlayerParameters.title.OFF
126
+ ) {
127
+ return null;
128
+ }
129
+
130
+ return (
131
+ <div className={ControlStyles["info-container"]}>
132
+ {
133
+ !imageUrl ? null :
134
+ <div className={ControlStyles["info-image-container"]}>
135
+ <img src={imageUrl} alt="Image" className={ControlStyles["info-image"]} />
136
+ </div>
137
+ }
138
+ <div className={ControlStyles["info-text"]}>
139
+ {
140
+ headers.length === 0 ? null :
141
+ <div className={ControlStyles["info-headers"]}>
142
+ {headers.map((text, index) =>
143
+ <div key={`header-${index}`} className={ControlStyles["info-header"]}>
144
+ { text }
145
+ </div>
146
+ )}
147
+ </div>
148
+ }
149
+ { !title ? null : <div className={ControlStyles["info-title"]}>{title}</div> }
150
+ { !subtitle ? null : <div className={ControlStyles["info-subtitle"]}>{subtitle}</div> }
151
+ { !description ? null : <div className={ControlStyles["info-description"]}>{description}</div> }
152
+ </div>
153
+ </div>
154
+ );
155
+ };
156
+
157
+ const WebControls = ({player, playbackStarted, canPlay, recentlyInteracted, setRecentUserAction, className=""}) => {
158
+ const [videoState, setVideoState] = useState(undefined);
159
+ const [playerClickHandler, setPlayerClickHandler] = useState(undefined);
160
+ const [activeMenus, setActiveMenus] = useState(0);
161
+
162
+ useEffect(() => {
163
+ setPlayerClickHandler(PlayerClick({player, setRecentUserAction}));
164
+
165
+ const disposeVideoObserver = ObserveVideo({target: player.target, video: player.video, setVideoState});
166
+
167
+ return () => disposeVideoObserver && disposeVideoObserver();
168
+ }, []);
169
+
170
+ if(!videoState) { return null; }
171
+
172
+ const collectionInfo = player.controls.GetCollectionInfo();
173
+ const menuActive = activeMenus > 0;
174
+ const setMenuActive = active => setActiveMenus(active ? activeMenus + 1 : Math.max(0, activeMenus - 1));
175
+
176
+ // Title autohide is not dependent on controls settings
177
+ const showUI = recentlyInteracted || !playbackStarted || menuActive;
178
+ const hideControls = !showUI && player.playerOptions.controls === EluvioPlayerParameters.controls.AUTO_HIDE;
179
+
180
+ player.__SetControlsVisibility(!hideControls);
181
+
182
+ return (
183
+ <div
184
+ onClick={playerClickHandler}
185
+ className={[
186
+ className,
187
+ ControlStyles["container"],
188
+ showUI ? "" : ControlStyles["autohide"],
189
+ player.playerOptions.controls !== EluvioPlayerParameters.controls.DEFAULT ? "" : ControlStyles["container--default-controls"],
190
+ menuActive ? "menu-active" : ""
191
+ ].join(" ")}
192
+ >
193
+ <ContentInfo key={`content-info-${collectionInfo && collectionInfo.mediaIndex}`} player={player} />
194
+ {
195
+ // Main bottom control bar
196
+ [
197
+ EluvioPlayerParameters.controls.DEFAULT,
198
+ EluvioPlayerParameters.controls.OFF,
199
+ EluvioPlayerParameters.controls.OFF_WITH_VOLUME_TOGGLE
200
+ ].includes(player.playerOptions.controls) ? null :
201
+ <>
202
+ <IconButton
203
+ aria-label="Play"
204
+ tabIndex={playbackStarted ? -1 : 0}
205
+ icon={Icons.CenterPlayCircleIcon}
206
+ onClick={() => {
207
+ player.controls.Play();
208
+ // Take focus off of this button because it should no longer be selectable after playback starts
209
+ player.target.firstChild.focus();
210
+ }}
211
+ className={`${ControlStyles["center-play-button"]} ${canPlay && !playbackStarted ? "" : ControlStyles["center-play-button--hidden"]}`}
212
+ />
213
+ <div className={`${ControlStyles["bottom-controls-container"]} ${hideControls ? ControlStyles["bottom-controls-container--autohide"] : ""}`}>
214
+ <div className={ControlStyles["bottom-controls-gradient"]} />
215
+ <SeekBar player={player} videoState={videoState} setRecentUserAction={setRecentUserAction} className={ControlStyles["seek"]} />
216
+ <div className={ControlStyles["controls"]}>
217
+ <IconButton
218
+ aria-label={videoState.playing ? "Pause" : "Play"}
219
+ icon={videoState.playing ? Icons.PauseCircleIcon : Icons.PlayCircleIcon}
220
+ onClick={() => player.controls.TogglePlay()}
221
+ className={ControlStyles["play-pause-button"]}
222
+ />
223
+ <CollectionControls player={player} />
224
+ <VolumeControls player={player} videoState={videoState} />
225
+ <TimeIndicator player={player} videoState={videoState}/>
226
+
227
+ <div className={ControlStyles["spacer"]}/>
228
+
229
+ {
230
+ !collectionInfo ? null :
231
+ <MenuButton
232
+ label="Collection Menu"
233
+ icon={Icons.CollectionIcon}
234
+ player={player}
235
+ setMenuActive={setMenuActive}
236
+ MenuComponent={CollectionMenu}
237
+ />
238
+ }
239
+ {
240
+ !player.controls.IsRotatable() ? null :
241
+ <IconButton
242
+ aria-label="Rotate Video"
243
+ icon={Icons.RotateIcon}
244
+ onClick={() => player.controls.SetAllowRotation(!player.controls.AllowRotation())}
245
+ />
246
+ }
247
+ {
248
+ !player.controls.GetOptions().hasAnyOptions ? null :
249
+ <MenuButton
250
+ label="Settings Menu"
251
+ icon={Icons.SettingsIcon}
252
+ player={player}
253
+ setMenuActive={setMenuActive}
254
+ MenuComponent={SettingsMenu}
255
+ />
256
+ }
257
+ <IconButton
258
+ aria-label={videoState.fullscreen ? "Exit Fullscreen" : "Fullscreen"}
259
+ icon={videoState.fullscreen ? Icons.ExitFullscreenIcon : Icons.FullscreenIcon}
260
+ onClick={() => player.controls.ToggleFullscreen()}
261
+ />
262
+ </div>
263
+ </div>
264
+ </>
265
+ }
266
+ {
267
+ // Floating volume control for 'off with volume toggle' setting
268
+ player.playerOptions.controls !== EluvioPlayerParameters.controls.OFF_WITH_VOLUME_TOGGLE ? null :
269
+ <div className={ControlStyles["floating-volume-toggle"]}>
270
+ <IconButton
271
+ key="mute-button"
272
+ aria-label={videoState.muted ? "Unmute" : "Mute"}
273
+ icon={videoState.muted || videoState.volume === 0 ? Icons.MutedIcon : Icons.VolumeHighIcon}
274
+ onClick={() => player.controls.ToggleMuted()}
275
+ className={ControlStyles["volume-button"]}
276
+ />
277
+ </div>
278
+ }
279
+ {
280
+ // Watermark
281
+ player.playerOptions.watermark === EluvioPlayerParameters.watermark.OFF ? null :
282
+ <div className={ControlStyles["watermark"]}>
283
+ <img src={EluvioLogo} alt="Eluvio" />
284
+ </div>
285
+ }
286
+ </div>
287
+ );
288
+ };
289
+
290
+ export default WebControls;
package/package.json CHANGED
@@ -1,25 +1,26 @@
1
1
  {
2
2
  "name": "@eluvio/elv-player-js",
3
- "version": "1.0.140",
4
- "description": "![Eluvio Logo](src/static/images/Logo.png \"Eluvio Logo\")",
5
- "main": "src/index.js",
3
+ "version": "2.0.0",
4
+ "description": "![Eluvio Logo](lib/static/images/Logo.png \"Eluvio Logo\")",
5
+ "main": "lib/index.js",
6
6
  "license": "MIT",
7
7
  "homepage": "https://github.com/eluv-io/elv-player-js",
8
8
  "scripts": {
9
+ "prepublishOnly": "npm run build",
9
10
  "bump-version": "npm --git-tag-version --no-commit-hooks version patch",
10
- "serve": "TEST_PAGE=true webpack-dev-server --hot --port 8089 --host=0.0.0.0",
11
- "serve-example": "EXAMPLE_PAGE=true webpack-dev-server --hot --port 8089 --host=0.0.0.0",
12
- "build": "BUILD_LIBRARY=true node ./node_modules/webpack-cli/bin/cli.js --mode=production --devtool false",
13
- "build-test": "TEST_PAGE=true node ./node_modules/webpack-cli/bin/cli.js --mode=production --devtool false",
14
- "build-example": "EXAMPLE_PAGE=true node ./node_modules/webpack-cli/bin/cli.js --mode=production --devtool false",
15
- "build-analyze": "ANALYZE_BUNDLE=true node ./node_modules/webpack-cli/bin/cli.js --mode=production --devtool false",
16
- "build-icons": "node src/BuildIcons.js",
17
- "lint": "npm run fix-scss ; npm run lint-scss ; npm run fix-js",
11
+ "serve": "vite --host 0.0.0.0 --port 8089",
12
+ "serve-https": "SERVE_HTTPS=true vite --host 0.0.0.0 --port 8089",
13
+ "build": "npm run build-icons ; vite build",
14
+ "build-analyze": "vite-bundle-visualizer",
15
+ "build-docs": "./node_modules/.bin/jsdoc --configure ./.jsdoc.json --readme README.md",
16
+ "preview": "vite preview",
17
+ "build-icons": "node lib/ui/BuildIcons.cjs",
18
+ "lint": "npm run fix-scss ; npm run fix-js",
18
19
  "lint-show": "npm run lint-scss ; npm run lint-js",
19
- "lint-js": "eslint \"src/**/*.js\"",
20
- "lint-scss": "./node_modules/sass-lint/bin/sass-lint.js -c .scss-lint.yml -v -q",
20
+ "lint-js": "eslint \"lib/**/*.js\"",
21
+ "lint-scss": "npx stylelint \"lib/**/*.css\" \"lib/**/*.module.scss\"",
21
22
  "fix-js": "npm run lint-js -- --fix",
22
- "fix-scss": "./node_modules/sass-lint-auto-fix/dist/index.js"
23
+ "fix-scss": "npx stylelint --fix \"lib/**/*.css\" \"lib/**/*.module.scss\""
23
24
  },
24
25
  "pre-commit": {
25
26
  "run": [
@@ -28,54 +29,41 @@
28
29
  },
29
30
  "files": [
30
31
  "/dist",
31
- "/src",
32
+ "/lib",
32
33
  "LICENSE",
33
34
  "README.md",
34
35
  "package.json",
35
- "package-lock.json",
36
- "webpack.config.js"
36
+ "package-lock.json"
37
37
  ],
38
38
  "dependencies": {
39
39
  "@eluvio/elv-client-js": "^4.0.76",
40
40
  "dashjs": "~4.7.0",
41
41
  "focus-visible": "^5.2.0",
42
42
  "hls.js": "~1.4.12",
43
- "lodash": "^4.17.21",
44
43
  "mux-embed": "^4.30.0",
44
+ "react": "^18.2.0",
45
+ "react-dom": "^18.2.0",
45
46
  "resize-observer-polyfill": "^1.5.1",
46
47
  "url-join": "^4.0.1"
47
48
  },
48
49
  "devDependencies": {
49
- "@babel/core": "^7.23.0",
50
- "@babel/preset-env": "^7.22.20",
51
- "@babel/preset-react": "^7.22.15",
52
- "@babel/runtime": "^7.23.1",
50
+ "@vitejs/plugin-basic-ssl": "^1.1.0",
51
+ "@vitejs/plugin-react-swc": "^3.5.0",
53
52
  "autoprefixer": "^10.4.16",
54
- "babel-cli": "^6.26.0",
55
- "babel-core": "^7.0.0-bridge.0",
56
- "babel-eslint": "^10.0.1",
57
- "babel-loader": "^9.1.3",
58
- "css-loader": "^6.8.1",
59
- "eslint": "^5.16.0",
60
- "eslint-plugin-react": "^7.12.4",
61
- "html-webpack-plugin": "^5.5.3",
62
- "postcss-loader": "^7.3.3",
63
- "regenerator-runtime": "^0.12.1",
64
- "sass": "^1.69.2",
65
- "sass-lint": "^1.13.1",
66
- "sass-lint-auto-fix": "^0.21.0",
67
- "sass-loader": "^13.3.2",
68
- "stream-browserify": "^3.0.0",
69
- "style-loader": "^3.3.3",
70
- "svg-inline-loader": "^0.8.0",
71
- "svg-inline-react": "^3.1.0",
72
- "url": "^0.11.3",
73
- "uuid": "^7.0.2",
74
- "webpack": "^5.88.2",
75
- "webpack-bundle-analyzer": "^4.9.1",
76
- "webpack-cli": "^5.1.4",
77
- "webpack-dev-server": "^4.15.1",
78
- "yaml-loader": "^0.8.0"
53
+ "babel-eslint": "^10.1.0",
54
+ "eslint": "^8.56.0",
55
+ "eslint-plugin-react": "^7.33.2",
56
+ "eslint-plugin-react-hooks": "^4.6.0",
57
+ "eslint-plugin-react-refresh": "^0.4.5",
58
+ "jsdoc": "^4.0.0",
59
+ "stylelint": "^16.2.0",
60
+ "stylelint-config-standard": "^36.0.0",
61
+ "stylelint-order": "^6.0.4",
62
+ "stylelint-scss": "^6.1.0",
63
+ "taffydb": "^2.7.3",
64
+ "vite": "^5.0.11",
65
+ "vite-bundle-visualizer": "^1.0.0",
66
+ "vite-plugin-svgr": "^4.2.0"
79
67
  },
80
68
  "directories": {
81
69
  "test": "test"