@twick/player-react 0.14.21 → 0.15.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/dist/index.js CHANGED
@@ -1,129 +1,453 @@
1
- 'use client';
2
- import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
3
- import { useCallback, useEffect, useRef, useState } from 'react';
4
- import { Controls } from './controls';
5
- import './index.css';
6
- import { shouldShowControls } from './utils';
7
- export function Player({ project, controls = true, variables = {}, playing = false, currentTime = 0, volume = 1, looping = true, fps = 30, width = undefined, height = undefined, quality = undefined, timeDisplayFormat = 'MM:SS', onDurationChange = () => { }, onTimeUpdate = () => { }, onPlayerReady = () => { }, onPlayerResize = () => { }, }) {
8
- const [playingState, setPlaying] = useState(playing);
9
- const [isMouseOver, setIsMouseOver] = useState(false);
10
- const [currentTimeState, setCurrentTime] = useState(currentTime);
11
- const [volumeState, setVolumeState] = useState(volume);
12
- const [duration, setDuration] = useState(-1);
13
- const focus = useRef(false);
14
- const playerRef = useRef(null);
15
- const wrapperRef = useRef(null);
16
- const lastRect = useRef(null);
17
- const onClickHandler = controls ? () => setPlaying(prev => !prev) : undefined;
18
- /**
19
- * Sync the playing prop with the player's own state when it changes.
20
- */
21
- useEffect(() => {
22
- setPlaying(playing);
23
- }, [playing]);
24
- /**
25
- * Sync the current time with the player's own state.
26
- */
27
- useEffect(() => {
28
- const diff = Math.abs(currentTime - currentTimeState);
29
- if (diff > 0.05) {
30
- setForcedTime(currentTime);
1
+ "use client";
2
+
3
+ // src/index.tsx
4
+ import { useCallback, useEffect, useRef, useState as useState2 } from "react";
5
+
6
+ // src/controls.tsx
7
+ import { useState } from "react";
8
+
9
+ // src/icons.tsx
10
+ import { jsx, jsxs } from "react/jsx-runtime";
11
+ function PlayButton() {
12
+ return /* @__PURE__ */ jsx(
13
+ "svg",
14
+ {
15
+ xmlns: "http://www.w3.org/2000/svg",
16
+ viewBox: "0 0 24 24",
17
+ fill: "currentColor",
18
+ className: "w-6 h-6",
19
+ children: /* @__PURE__ */ jsx(
20
+ "path",
21
+ {
22
+ fillRule: "evenodd",
23
+ d: "M4.5 5.653c0-1.427 1.529-2.33 2.779-1.643l11.54 6.347c1.295.712 1.295 2.573 0 3.286L7.28 19.99c-1.25.687-2.779-.217-2.779-1.643V5.653Z",
24
+ clipRule: "evenodd"
31
25
  }
32
- }, [currentTime]);
33
- useEffect(() => {
34
- setForcedVolume(volume);
35
- }, [volume]);
36
- /**
37
- * Receives the current time of the video from the player.
38
- */
39
- const handleTimeUpdate = (event) => {
40
- const e = event;
41
- setCurrentTime(e.detail);
42
- onTimeUpdate(e.detail);
43
- };
44
- /**
45
- * Receives the duration of the video from the player.
46
- */
47
- const handleDurationUpdate = (event) => {
48
- const e = event;
49
- setDuration(e.detail);
50
- onDurationChange(e.detail);
51
- };
52
- /**
53
- * Play and pause using the space key.
54
- */
55
- const handleKeyDown = (event) => {
56
- if (event.code === 'Space' && focus.current) {
57
- event.preventDefault();
58
- setPlaying(prev => !prev);
59
- }
60
- };
61
- const handlePlayerReady = (event) => {
62
- const player = event.detail;
63
- if (player) {
64
- onPlayerReady(player);
65
- }
66
- };
67
- const handlePlayerResize = useCallback((entries) => {
68
- const [firstEntry] = entries;
69
- if (!firstEntry || !wrapperRef.current) {
70
- return;
26
+ )
27
+ }
28
+ );
29
+ }
30
+ function PauseButton() {
31
+ return /* @__PURE__ */ jsx(
32
+ "svg",
33
+ {
34
+ xmlns: "http://www.w3.org/2000/svg",
35
+ viewBox: "0 0 24 24",
36
+ fill: "currentColor",
37
+ className: "w-6 h-6",
38
+ children: /* @__PURE__ */ jsx(
39
+ "path",
40
+ {
41
+ fillRule: "evenodd",
42
+ d: "M6.75 5.25a.75.75 0 0 1 .75-.75H9a.75.75 0 0 1 .75.75v13.5a.75.75 0 0 1-.75.75H7.5a.75.75 0 0 1-.75-.75V5.25Zm7.5 0A.75.75 0 0 1 15 4.5h1.5a.75.75 0 0 1 .75.75v13.5a.75.75 0 0 1-.75.75H15a.75.75 0 0 1-.75-.75V5.25Z",
43
+ clipRule: "evenodd"
71
44
  }
72
- const newRect = wrapperRef.current.getBoundingClientRect();
73
- if (!lastRect.current ||
74
- newRect.width !== lastRect.current.width ||
75
- newRect.height !== lastRect.current.height ||
76
- newRect.x !== lastRect.current.x ||
77
- newRect.y !== lastRect.current.y) {
78
- lastRect.current = newRect;
79
- onPlayerResize(newRect);
45
+ )
46
+ }
47
+ );
48
+ }
49
+ function SoundIcon() {
50
+ return /* @__PURE__ */ jsxs(
51
+ "svg",
52
+ {
53
+ xmlns: "http://www.w3.org/2000/svg",
54
+ viewBox: "0 0 24 24",
55
+ fill: "currentColor",
56
+ className: "p-w-6 p-h-6",
57
+ children: [
58
+ /* @__PURE__ */ jsx("path", { d: "M18.36,19.36a1,1,0,0,1-.7-.29,1,1,0,0,1,0-1.41,8,8,0,0,0,0-11.32,1,1,0,0,1,1.41-1.41,10,10,0,0,1,0,14.14A1,1,0,0,1,18.36,19.36Z" }),
59
+ /* @__PURE__ */ jsx("path", { d: "M15.54,16.54a1,1,0,0,1-.71-.3,1,1,0,0,1,0-1.41,4,4,0,0,0,0-5.66,1,1,0,0,1,1.41-1.41,6,6,0,0,1,0,8.48A1,1,0,0,1,15.54,16.54Z" }),
60
+ /* @__PURE__ */ jsx("path", { d: "M11.38,4.08a1,1,0,0,0-1.09.21L6.59,8H4a2,2,0,0,0-2,2v4a2,2,0,0,0,2,2H6.59l3.7,3.71A1,1,0,0,0,11,20a.84.84,0,0,0,.38-.08A1,1,0,0,0,12,19V5A1,1,0,0,0,11.38,4.08Z" })
61
+ ]
62
+ }
63
+ );
64
+ }
65
+ function MutedSoundIcon() {
66
+ return /* @__PURE__ */ jsxs(
67
+ "svg",
68
+ {
69
+ xmlns: "http://www.w3.org/2000/svg",
70
+ viewBox: "0 0 24 24",
71
+ fill: "currentColor",
72
+ className: "p-w-6 p-h-6",
73
+ children: [
74
+ /* @__PURE__ */ jsx("path", { d: "M11.38,4.08a1,1,0,0,0-1.09.21L6.59,8H4a2,2,0,0,0-2,2v4a2,2,0,0,0,2,2H6.59l3.7,3.71A1,1,0,0,0,11,20a.84.84,0,0,0,.38-.08A1,1,0,0,0,12,19V5A1,1,0,0,0,11.38,4.08Z" }),
75
+ /* @__PURE__ */ jsx("path", { d: "M16,15.5a1,1,0,0,1-.71-.29,1,1,0,0,1,0-1.42l5-5a1,1,0,0,1,1.42,1.42l-5,5A1,1,0,0,1,16,15.5Z" }),
76
+ /* @__PURE__ */ jsx("path", { d: "M21,15.5a1,1,0,0,1-.71-.29l-5-5a1,1,0,0,1,1.42-1.42l5,5a1,1,0,0,1,0,1.42A1,1,0,0,1,21,15.5Z" })
77
+ ]
78
+ }
79
+ );
80
+ }
81
+
82
+ // src/utils.ts
83
+ function getFormattedTime(timeInSeconds, absoluteTimeInSeconds, timeDisplayFormat) {
84
+ function toFormattedTime(timeInSeconds2) {
85
+ const minutes = Math.floor(timeInSeconds2 / 60);
86
+ const seconds = Math.floor(timeInSeconds2 % 60).toString().padStart(2, "0");
87
+ const milliseconds = Math.floor(timeInSeconds2 % 1 * 1e3).toString().padStart(3, "0");
88
+ if (timeDisplayFormat === "MM:SS") {
89
+ return `${minutes}:${seconds}`;
90
+ }
91
+ if (timeDisplayFormat === "MM:SS.m") {
92
+ return `${minutes}:${seconds}.${milliseconds[0]}`;
93
+ }
94
+ if (timeDisplayFormat === "MM:SS.mm") {
95
+ return `${minutes}:${seconds}.${milliseconds.slice(0, 2)}`;
96
+ }
97
+ }
98
+ return `${toFormattedTime(timeInSeconds)} / ${toFormattedTime(absoluteTimeInSeconds)}`;
99
+ }
100
+ function shouldShowControls(playing, isMouseOver, areControlsDisabled) {
101
+ if (areControlsDisabled) {
102
+ return false;
103
+ }
104
+ return !playing || isMouseOver;
105
+ }
106
+
107
+ // src/controls.tsx
108
+ import { jsx as jsx2, jsxs as jsxs2 } from "react/jsx-runtime";
109
+ function PlayPause({
110
+ playing,
111
+ setPlaying
112
+ }) {
113
+ return /* @__PURE__ */ jsx2("button", { type: "button", className: "p-1", onClick: () => setPlaying(!playing), children: playing ? /* @__PURE__ */ jsx2(PauseButton, {}) : /* @__PURE__ */ jsx2(PlayButton, {}) });
114
+ }
115
+ function VolumeSlider({
116
+ volume,
117
+ setVolume
118
+ }) {
119
+ const [isHovering, setIsHovering] = useState(false);
120
+ const [isInteracting, setIsInteracting] = useState(false);
121
+ const [previousVolume, setPreviousVolume] = useState(1);
122
+ const handleIconClick = () => {
123
+ if (volume > 0) {
124
+ setPreviousVolume(volume);
125
+ setVolume(0);
126
+ } else {
127
+ setVolume(previousVolume);
128
+ }
129
+ };
130
+ return /* @__PURE__ */ jsxs2(
131
+ "div",
132
+ {
133
+ className: "flex items-center space-x-2 relative",
134
+ onMouseEnter: () => setIsHovering(true),
135
+ onMouseLeave: () => {
136
+ if (!isInteracting) {
137
+ setIsHovering(false);
80
138
  }
81
- }, [onPlayerResize]);
82
- useEffect(() => {
83
- if (!wrapperRef.current)
84
- return;
85
- const resizeObserver = new ResizeObserver(handlePlayerResize);
86
- resizeObserver.observe(wrapperRef.current);
87
- return () => {
88
- resizeObserver.disconnect();
89
- };
90
- }, [handlePlayerResize]);
91
- /**
92
- * Import the player and add all event listeners.
93
- */
94
- useEffect(() => {
95
- import('./internal').then(() => {
96
- if (playerRef.current) {
97
- playerRef.current.setProject(project);
139
+ },
140
+ children: [
141
+ /* @__PURE__ */ jsx2(
142
+ "div",
143
+ {
144
+ className: "w-6 h-6 flex items-center justify-center cursor-pointer",
145
+ onClick: handleIconClick,
146
+ children: volume === 0 ? /* @__PURE__ */ jsx2(MutedSoundIcon, {}) : /* @__PURE__ */ jsx2(SoundIcon, {})
147
+ }
148
+ ),
149
+ (isHovering || isInteracting) && /* @__PURE__ */ jsx2("div", { className: "flex items-center h-1.5 whitespace-nowrap", children: /* @__PURE__ */ jsxs2("div", { className: "relative w-20 h-1.5 bg-gray-300 rounded-full", children: [
150
+ /* @__PURE__ */ jsx2(
151
+ "div",
152
+ {
153
+ className: "absolute top-0 left-0 h-full bg-gray-100 rounded-full",
154
+ style: { width: `${volume * 100}%` }
98
155
  }
99
- });
100
- playerRef.current?.addEventListener('timeupdate', handleTimeUpdate);
101
- playerRef.current?.addEventListener('duration', handleDurationUpdate);
102
- playerRef.current?.addEventListener('playerready', handlePlayerReady);
103
- document.addEventListener('keydown', handleKeyDown);
104
- return () => {
105
- playerRef.current?.removeEventListener('timeupdate', handleTimeUpdate);
106
- playerRef.current?.removeEventListener('duration', handleDurationUpdate);
107
- playerRef.current?.removeEventListener('playerready', handlePlayerReady);
108
- document.removeEventListener('keydown', handleKeyDown);
109
- };
110
- }, [project]);
111
- /**
112
- * When the forced time changes, seek to that time.
113
- */
114
- function setForcedTime(forcedTime) {
115
- if (playerRef.current) {
116
- playerRef.current.dispatchEvent(new CustomEvent('seekto', { detail: forcedTime }));
117
- }
156
+ ),
157
+ /* @__PURE__ */ jsx2(
158
+ "input",
159
+ {
160
+ type: "range",
161
+ min: 0,
162
+ max: 1,
163
+ step: 0.01,
164
+ value: volume,
165
+ onChange: (e) => {
166
+ const newVolume = Number(e.target.value);
167
+ setVolume(newVolume);
168
+ if (newVolume > 0) {
169
+ setPreviousVolume(newVolume);
170
+ }
171
+ },
172
+ onMouseDown: () => setIsInteracting(true),
173
+ onMouseUp: () => setIsInteracting(false),
174
+ onMouseLeave: () => setIsInteracting(false),
175
+ className: "absolute top-0 left-0 w-full h-full opacity-0 cursor-pointer"
176
+ }
177
+ )
178
+ ] }) })
179
+ ]
180
+ }
181
+ );
182
+ }
183
+ function Timeline({
184
+ currentTime,
185
+ duration,
186
+ setCurrentTime
187
+ }) {
188
+ const progressPercentage = currentTime / duration * 100;
189
+ return /* @__PURE__ */ jsxs2("div", { className: "relative flex-1 w-full h-1.5 bg-gray-300 rounded-full overflow-hidden", children: [
190
+ /* @__PURE__ */ jsx2(
191
+ "div",
192
+ {
193
+ className: "absolute top-0 left-0 h-full bg-gray-100",
194
+ style: { width: `${progressPercentage}%` }
195
+ }
196
+ ),
197
+ /* @__PURE__ */ jsx2(
198
+ "input",
199
+ {
200
+ type: "range",
201
+ value: currentTime,
202
+ min: 0,
203
+ max: duration,
204
+ step: 0.01,
205
+ className: "absolute top-0 left-0 w-full h-full opacity-0 cursor-pointer",
206
+ onChange: (event) => setCurrentTime(Number(event.target.value))
207
+ }
208
+ )
209
+ ] });
210
+ }
211
+ function Controls({
212
+ duration,
213
+ playing,
214
+ setPlaying,
215
+ currentTime,
216
+ setForcedTime,
217
+ timeDisplayFormat,
218
+ volume,
219
+ setVolume
220
+ }) {
221
+ return /* @__PURE__ */ jsxs2("div", { className: "text-white p-4 flex-col space-y-2 bg-gradient-to-t from-gray-500 to-transparent", children: [
222
+ /* @__PURE__ */ jsxs2("div", { className: "flex items-center space-x-2", children: [
223
+ /* @__PURE__ */ jsx2(PlayPause, { playing, setPlaying }),
224
+ /* @__PURE__ */ jsxs2("div", { className: "flex items-center space-x-2", children: [
225
+ /* @__PURE__ */ jsx2(VolumeSlider, { volume, setVolume }),
226
+ /* @__PURE__ */ jsx2("div", { children: /* @__PURE__ */ jsx2("span", { children: getFormattedTime(currentTime, duration, timeDisplayFormat) }) })
227
+ ] }),
228
+ /* @__PURE__ */ jsx2("div", { className: "flex-grow" })
229
+ ] }),
230
+ /* @__PURE__ */ jsx2(
231
+ Timeline,
232
+ {
233
+ currentTime,
234
+ duration,
235
+ setCurrentTime: setForcedTime
236
+ }
237
+ )
238
+ ] });
239
+ }
240
+
241
+ // src/index.tsx
242
+ import { jsx as jsx3, jsxs as jsxs3 } from "react/jsx-runtime";
243
+ function Player({
244
+ project,
245
+ controls = true,
246
+ variables = {},
247
+ playing = false,
248
+ currentTime = 0,
249
+ volume = 1,
250
+ looping = true,
251
+ fps = 30,
252
+ width = void 0,
253
+ height = void 0,
254
+ quality = void 0,
255
+ timeDisplayFormat = "MM:SS",
256
+ onDurationChange = () => {
257
+ },
258
+ onTimeUpdate = () => {
259
+ },
260
+ onPlayerReady = () => {
261
+ },
262
+ onPlayerResize = () => {
263
+ }
264
+ }) {
265
+ const [playingState, setPlaying] = useState2(playing);
266
+ const [isMouseOver, setIsMouseOver] = useState2(false);
267
+ const [currentTimeState, setCurrentTime] = useState2(currentTime);
268
+ const [volumeState, setVolumeState] = useState2(volume);
269
+ const [duration, setDuration] = useState2(-1);
270
+ const focus = useRef(false);
271
+ const playerRef = useRef(null);
272
+ const wrapperRef = useRef(null);
273
+ const lastRect = useRef(null);
274
+ const onClickHandler = controls ? () => setPlaying((prev) => !prev) : void 0;
275
+ useEffect(() => {
276
+ setPlaying(playing);
277
+ }, [playing]);
278
+ useEffect(() => {
279
+ const diff = Math.abs(currentTime - currentTimeState);
280
+ if (diff > 0.05) {
281
+ setForcedTime(currentTime);
118
282
  }
119
- function setForcedVolume(volume) {
120
- setVolumeState(volume);
283
+ }, [currentTime]);
284
+ useEffect(() => {
285
+ setForcedVolume(volume);
286
+ }, [volume]);
287
+ const onTimeUpdateRef = useRef(onTimeUpdate);
288
+ const onDurationChangeRef = useRef(onDurationChange);
289
+ useEffect(() => {
290
+ onTimeUpdateRef.current = onTimeUpdate;
291
+ }, [onTimeUpdate]);
292
+ useEffect(() => {
293
+ onDurationChangeRef.current = onDurationChange;
294
+ }, [onDurationChange]);
295
+ const handleTimeUpdate = useCallback((event) => {
296
+ const e = event;
297
+ setCurrentTime(e.detail);
298
+ onTimeUpdateRef.current(e.detail);
299
+ }, []);
300
+ const handleDurationUpdate = useCallback((event) => {
301
+ const e = event;
302
+ setDuration(e.detail);
303
+ onDurationChangeRef.current(e.detail);
304
+ }, []);
305
+ const handleKeyDown = useCallback((event) => {
306
+ if (event.code === "Space" && focus.current) {
307
+ event.preventDefault();
308
+ setPlaying((prev) => !prev);
309
+ }
310
+ }, []);
311
+ const onPlayerReadyRef = useRef(onPlayerReady);
312
+ useEffect(() => {
313
+ onPlayerReadyRef.current = onPlayerReady;
314
+ }, [onPlayerReady]);
315
+ const handlePlayerReady = useCallback((event) => {
316
+ const player = event.detail;
317
+ if (player) {
318
+ onPlayerReadyRef.current(player);
319
+ }
320
+ const playerElement = playerRef.current;
321
+ if (playerElement) {
322
+ playerElement.removeEventListener("timeupdate", handleTimeUpdate);
323
+ playerElement.removeEventListener("duration", handleDurationUpdate);
324
+ playerElement.addEventListener("timeupdate", handleTimeUpdate);
325
+ playerElement.addEventListener("duration", handleDurationUpdate);
326
+ }
327
+ }, [handleTimeUpdate, handleDurationUpdate]);
328
+ const handlePlayerResize = useCallback(
329
+ (entries) => {
330
+ const [firstEntry] = entries;
331
+ if (!firstEntry || !wrapperRef.current) {
332
+ return;
333
+ }
334
+ const newRect = wrapperRef.current.getBoundingClientRect();
335
+ if (!lastRect.current || newRect.width !== lastRect.current.width || newRect.height !== lastRect.current.height || newRect.x !== lastRect.current.x || newRect.y !== lastRect.current.y) {
336
+ lastRect.current = newRect;
337
+ onPlayerResize(newRect);
338
+ }
339
+ },
340
+ [onPlayerResize]
341
+ );
342
+ useEffect(() => {
343
+ if (!wrapperRef.current) return;
344
+ const resizeObserver = new ResizeObserver(handlePlayerResize);
345
+ resizeObserver.observe(wrapperRef.current);
346
+ return () => {
347
+ resizeObserver.disconnect();
348
+ };
349
+ }, [handlePlayerResize]);
350
+ useEffect(() => {
351
+ let cleanup = null;
352
+ const setupListeners = () => {
353
+ const player = playerRef.current;
354
+ if (!player) return;
355
+ player.removeEventListener("timeupdate", handleTimeUpdate);
356
+ player.removeEventListener("duration", handleDurationUpdate);
357
+ player.removeEventListener("playerready", handlePlayerReady);
358
+ player.addEventListener("timeupdate", handleTimeUpdate);
359
+ player.addEventListener("duration", handleDurationUpdate);
360
+ player.addEventListener("playerready", handlePlayerReady);
361
+ document.addEventListener("keydown", handleKeyDown);
362
+ cleanup = () => {
363
+ player.removeEventListener("timeupdate", handleTimeUpdate);
364
+ player.removeEventListener("duration", handleDurationUpdate);
365
+ player.removeEventListener("playerready", handlePlayerReady);
366
+ document.removeEventListener("keydown", handleKeyDown);
367
+ };
368
+ };
369
+ import("./internal-H4HUGGQY.js").then(() => {
370
+ requestAnimationFrame(() => {
121
371
  if (playerRef.current) {
122
- playerRef.current.dispatchEvent(new CustomEvent('volumechange', { detail: volume }));
372
+ playerRef.current.setProject(project);
373
+ setupListeners();
123
374
  }
375
+ });
376
+ });
377
+ if (playerRef.current) {
378
+ setupListeners();
379
+ }
380
+ return () => {
381
+ if (cleanup) {
382
+ cleanup();
383
+ }
384
+ };
385
+ }, [project, handleTimeUpdate, handleDurationUpdate, handlePlayerReady, handleKeyDown]);
386
+ function setForcedTime(forcedTime) {
387
+ if (playerRef.current) {
388
+ playerRef.current.dispatchEvent(
389
+ new CustomEvent("seekto", { detail: forcedTime })
390
+ );
391
+ }
392
+ }
393
+ function setForcedVolume(volume2) {
394
+ setVolumeState(volume2);
395
+ if (playerRef.current) {
396
+ playerRef.current.dispatchEvent(
397
+ new CustomEvent("volumechange", { detail: volume2 })
398
+ );
399
+ }
400
+ }
401
+ return /* @__PURE__ */ jsx3("div", { className: "twick-player-root", style: { display: "contents" }, children: /* @__PURE__ */ jsx3(
402
+ "div",
403
+ {
404
+ ref: wrapperRef,
405
+ className: "relative cursor-default focus:outline-none",
406
+ onFocus: () => focus.current = true,
407
+ onBlur: () => focus.current = false,
408
+ tabIndex: 0,
409
+ onMouseEnter: () => setIsMouseOver(true),
410
+ onMouseLeave: () => setIsMouseOver(false),
411
+ children: /* @__PURE__ */ jsxs3("div", { className: "relative", children: [
412
+ /* @__PURE__ */ jsx3(
413
+ "twick-player",
414
+ {
415
+ ref: playerRef,
416
+ playing: String(playingState),
417
+ onClick: onClickHandler,
418
+ variables: JSON.stringify(variables),
419
+ looping: looping ? "true" : "false",
420
+ width,
421
+ height,
422
+ quality,
423
+ fps,
424
+ volume: volumeState
425
+ }
426
+ ),
427
+ /* @__PURE__ */ jsx3(
428
+ "div",
429
+ {
430
+ className: `absolute bottom-0 w-full transition-opacity duration-200 ${shouldShowControls(playingState, isMouseOver, !controls) ? "opacity-100" : "opacity-0"}`,
431
+ children: /* @__PURE__ */ jsx3(
432
+ Controls,
433
+ {
434
+ duration,
435
+ playing: playingState,
436
+ setPlaying,
437
+ currentTime: currentTimeState,
438
+ setForcedTime,
439
+ timeDisplayFormat,
440
+ volume: volumeState,
441
+ setVolume: setForcedVolume
442
+ }
443
+ )
444
+ }
445
+ )
446
+ ] })
124
447
  }
125
- return (_jsx("div", { className: "twick-player-root", style: { display: 'contents' }, children: _jsx("div", { ref: wrapperRef, className: "relative cursor-default focus:outline-none", onFocus: () => (focus.current = true), onBlur: () => (focus.current = false), tabIndex: 0, onMouseEnter: () => setIsMouseOver(true), onMouseLeave: () => setIsMouseOver(false), children: _jsxs("div", { className: "relative", children: [_jsx("twick-player", { ref: playerRef, playing: String(playingState), onClick: onClickHandler, variables: JSON.stringify(variables), looping: looping ? 'true' : 'false', width: width, height: height, quality: quality, fps: fps, volume: volumeState }), _jsx("div", { className: `absolute bottom-0 w-full transition-opacity duration-200 ${shouldShowControls(playingState, isMouseOver, !controls)
126
- ? 'opacity-100'
127
- : 'opacity-0'}`, children: _jsx(Controls, { duration: duration, playing: playingState, setPlaying: setPlaying, currentTime: currentTimeState, setForcedTime: setForcedTime, timeDisplayFormat: timeDisplayFormat, volume: volumeState, setVolume: setForcedVolume }) })] }) }) }));
448
+ ) });
128
449
  }
450
+ export {
451
+ Player
452
+ };
129
453
  //# sourceMappingURL=index.js.map
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.tsx"],"names":[],"mappings":"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"}
1
+ {"version":3,"sources":["../src/index.tsx","../src/controls.tsx","../src/icons.tsx","../src/utils.ts"],"sourcesContent":["'use client';\nimport type {Player as CorePlayer, Project} from '@twick/core';\nimport type {ComponentProps} from 'react';\nimport {useCallback, useEffect, useRef, useState} from 'react';\nimport {Controls} from './controls';\nimport './index.css';\nimport {shouldShowControls} from './utils';\n\ninterface TwickPlayerProps {\n playing?: string;\n variables?: string;\n looping?: string;\n width?: number;\n height?: number;\n quality?: number;\n fps?: number;\n volume?: number;\n}\n\ndeclare global {\n namespace JSX {\n interface IntrinsicElements {\n // eslint-disable-next-line\n 'twick-player': TwickPlayerProps & ComponentProps<'div'>;\n }\n }\n}\n\ninterface PlayerProps {\n project: Project;\n controls?: boolean;\n variables?: Record<string, any>;\n playing?: boolean;\n currentTime?: number;\n volume?: number;\n looping?: boolean;\n fps?: number;\n\n width?: number;\n height?: number;\n quality?: number;\n timeDisplayFormat?: 'MM:SS' | 'MM:SS.mm' | 'MM:SS.m';\n\n onDurationChange?: (duration: number) => void;\n onTimeUpdate?: (currentTime: number) => void;\n onPlayerReady?: (player: CorePlayer) => void;\n onPlayerResize?: (rect: DOMRectReadOnly) => void;\n}\n\nexport function Player({\n project,\n controls = true,\n variables = {},\n playing = false,\n currentTime = 0,\n volume = 1,\n looping = true,\n fps = 30,\n\n width = undefined,\n height = undefined,\n quality = undefined,\n timeDisplayFormat = 'MM:SS',\n\n onDurationChange = () => {},\n onTimeUpdate = () => {},\n onPlayerReady = () => {},\n onPlayerResize = () => {},\n}: PlayerProps) {\n const [playingState, setPlaying] = useState(playing);\n const [isMouseOver, setIsMouseOver] = useState(false);\n const [currentTimeState, setCurrentTime] = useState(currentTime);\n const [volumeState, setVolumeState] = useState(volume);\n const [duration, setDuration] = useState(-1);\n\n const focus = useRef(false);\n const playerRef = useRef<HTMLDivElement | null>(null);\n const wrapperRef = useRef<HTMLDivElement | null>(null);\n const lastRect = useRef<DOMRectReadOnly | null>(null);\n\n const onClickHandler = controls ? () => setPlaying(prev => !prev) : undefined;\n\n /**\n * Sync the playing prop with the player's own state when it changes.\n */\n useEffect(() => {\n setPlaying(playing);\n }, [playing]);\n\n /**\n * Sync the current time with the player's own state.\n */\n useEffect(() => {\n const diff = Math.abs(currentTime - currentTimeState);\n if (diff > 0.05) {\n setForcedTime(currentTime);\n }\n }, [currentTime]);\n\n useEffect(() => {\n setForcedVolume(volume);\n }, [volume]);\n\n /**\n * Receives the current time of the video from the player.\n * Use refs to ensure we always call the latest callbacks.\n */\n const onTimeUpdateRef = useRef(onTimeUpdate);\n const onDurationChangeRef = useRef(onDurationChange);\n \n // Update refs when callbacks change\n useEffect(() => {\n onTimeUpdateRef.current = onTimeUpdate;\n }, [onTimeUpdate]);\n \n useEffect(() => {\n onDurationChangeRef.current = onDurationChange;\n }, [onDurationChange]);\n\n const handleTimeUpdate = useCallback((event: Event) => {\n const e = event as CustomEvent;\n setCurrentTime(e.detail);\n onTimeUpdateRef.current(e.detail);\n }, []);\n\n /**\n * Receives the duration of the video from the player.\n */\n const handleDurationUpdate = useCallback((event: Event) => {\n const e = event as CustomEvent;\n setDuration(e.detail);\n onDurationChangeRef.current(e.detail);\n }, []);\n\n /**\n * Play and pause using the space key.\n */\n const handleKeyDown = useCallback((event: KeyboardEvent) => {\n if (event.code === 'Space' && focus.current) {\n event.preventDefault();\n setPlaying(prev => !prev);\n }\n }, []);\n\n const onPlayerReadyRef = useRef(onPlayerReady);\n \n useEffect(() => {\n onPlayerReadyRef.current = onPlayerReady;\n }, [onPlayerReady]);\n\n const handlePlayerReady = useCallback((event: Event) => {\n const player = (event as CustomEvent).detail;\n if (player) {\n onPlayerReadyRef.current(player);\n }\n \n // Ensure event listeners are attached when player becomes ready\n // This is a fallback in case listeners weren't attached earlier\n const playerElement = playerRef.current;\n if (playerElement) {\n // Remove and re-add to ensure they're attached\n playerElement.removeEventListener('timeupdate', handleTimeUpdate);\n playerElement.removeEventListener('duration', handleDurationUpdate);\n playerElement.addEventListener('timeupdate', handleTimeUpdate);\n playerElement.addEventListener('duration', handleDurationUpdate);\n }\n }, [handleTimeUpdate, handleDurationUpdate]);\n\n const handlePlayerResize = useCallback(\n (entries: ResizeObserverEntry[]) => {\n const [firstEntry] = entries;\n if (!firstEntry || !wrapperRef.current) {\n return;\n }\n\n const newRect = wrapperRef.current.getBoundingClientRect();\n if (\n !lastRect.current ||\n newRect.width !== lastRect.current.width ||\n newRect.height !== lastRect.current.height ||\n newRect.x !== lastRect.current.x ||\n newRect.y !== lastRect.current.y\n ) {\n lastRect.current = newRect;\n onPlayerResize(newRect);\n }\n },\n [onPlayerResize],\n );\n\n useEffect(() => {\n if (!wrapperRef.current) return;\n\n const resizeObserver = new ResizeObserver(handlePlayerResize);\n resizeObserver.observe(wrapperRef.current);\n\n return () => {\n resizeObserver.disconnect();\n };\n }, [handlePlayerResize]);\n\n /**\n * Import the player and add all event listeners.\n */\n useEffect(() => {\n let cleanup: (() => void) | null = null;\n\n const setupListeners = () => {\n const player = playerRef.current;\n if (!player) return;\n\n // Remove any existing listeners first to avoid duplicates\n player.removeEventListener('timeupdate', handleTimeUpdate);\n player.removeEventListener('duration', handleDurationUpdate);\n player.removeEventListener('playerready', handlePlayerReady);\n\n // Add event listeners\n player.addEventListener('timeupdate', handleTimeUpdate);\n player.addEventListener('duration', handleDurationUpdate);\n player.addEventListener('playerready', handlePlayerReady);\n document.addEventListener('keydown', handleKeyDown);\n\n cleanup = () => {\n player.removeEventListener('timeupdate', handleTimeUpdate);\n player.removeEventListener('duration', handleDurationUpdate);\n player.removeEventListener('playerready', handlePlayerReady);\n document.removeEventListener('keydown', handleKeyDown);\n };\n };\n\n // Import the custom element definition\n import('./internal').then(() => {\n // Wait for the next tick to ensure the element is in the DOM\n // Use requestAnimationFrame to ensure the custom element is ready\n requestAnimationFrame(() => {\n if (playerRef.current) {\n (playerRef.current as any).setProject(project);\n // Set up listeners after the element is ready\n setupListeners();\n }\n });\n });\n\n // Also set up listeners immediately if element already exists\n // This handles the case where the element was already in the DOM\n if (playerRef.current) {\n setupListeners();\n }\n\n return () => {\n if (cleanup) {\n cleanup();\n }\n };\n }, [project, handleTimeUpdate, handleDurationUpdate, handlePlayerReady, handleKeyDown]);\n\n /**\n * When the forced time changes, seek to that time.\n */\n function setForcedTime(forcedTime: number) {\n if (playerRef.current) {\n playerRef.current.dispatchEvent(\n new CustomEvent('seekto', {detail: forcedTime}),\n );\n }\n }\n\n function setForcedVolume(volume: number) {\n setVolumeState(volume);\n if (playerRef.current) {\n playerRef.current.dispatchEvent(\n new CustomEvent('volumechange', {detail: volume}),\n );\n }\n }\n\n return (\n <div className=\"twick-player-root\" style={{display: 'contents'}}>\n <div\n ref={wrapperRef}\n className=\"relative cursor-default focus:outline-none\"\n onFocus={() => (focus.current = true)}\n onBlur={() => (focus.current = false)}\n tabIndex={0}\n onMouseEnter={() => setIsMouseOver(true)}\n onMouseLeave={() => setIsMouseOver(false)}\n >\n <div className=\"relative\">\n <twick-player\n ref={playerRef}\n playing={String(playingState)}\n onClick={onClickHandler}\n variables={JSON.stringify(variables)}\n looping={looping ? 'true' : 'false'}\n width={width}\n height={height}\n quality={quality}\n fps={fps}\n volume={volumeState}\n />\n <div\n className={`absolute bottom-0 w-full transition-opacity duration-200 ${\n shouldShowControls(playingState, isMouseOver, !controls)\n ? 'opacity-100'\n : 'opacity-0'\n }`}\n >\n <Controls\n duration={duration}\n playing={playingState}\n setPlaying={setPlaying}\n currentTime={currentTimeState}\n setForcedTime={setForcedTime}\n timeDisplayFormat={timeDisplayFormat}\n volume={volumeState}\n setVolume={setForcedVolume}\n />\n </div>\n </div>\n </div>\n </div>\n );\n}\n","import {useState} from 'react';\nimport {MutedSoundIcon, PauseButton, PlayButton, SoundIcon} from './icons';\nimport {getFormattedTime} from './utils';\n\nfunction PlayPause({\n playing,\n setPlaying,\n}: {\n playing: boolean;\n setPlaying: (playing: boolean) => void;\n}) {\n return (\n <button type=\"button\" className=\"p-1\" onClick={() => setPlaying(!playing)}>\n {playing ? <PauseButton /> : <PlayButton />}\n </button>\n );\n}\n\nfunction VolumeSlider({\n volume,\n setVolume,\n}: {\n volume: number;\n setVolume: (volume: number) => void;\n}) {\n const [isHovering, setIsHovering] = useState(false);\n const [isInteracting, setIsInteracting] = useState(false);\n const [previousVolume, setPreviousVolume] = useState(1);\n\n const handleIconClick = () => {\n if (volume > 0) {\n setPreviousVolume(volume);\n setVolume(0);\n } else {\n setVolume(previousVolume);\n }\n };\n\n return (\n <div\n className=\"flex items-center space-x-2 relative\"\n onMouseEnter={() => setIsHovering(true)}\n onMouseLeave={() => {\n if (!isInteracting) {\n setIsHovering(false);\n }\n }}\n >\n <div\n className=\"w-6 h-6 flex items-center justify-center cursor-pointer\"\n onClick={handleIconClick}\n >\n {volume === 0 ? <MutedSoundIcon /> : <SoundIcon />}\n </div>\n {(isHovering || isInteracting) && (\n <div className=\"flex items-center h-1.5 whitespace-nowrap\">\n <div className=\"relative w-20 h-1.5 bg-gray-300 rounded-full\">\n <div\n className=\"absolute top-0 left-0 h-full bg-gray-100 rounded-full\"\n style={{width: `${volume * 100}%`}}\n />\n <input\n type=\"range\"\n min={0}\n max={1}\n step={0.01}\n value={volume}\n onChange={e => {\n const newVolume = Number(e.target.value);\n setVolume(newVolume);\n if (newVolume > 0) {\n setPreviousVolume(newVolume);\n }\n }}\n onMouseDown={() => setIsInteracting(true)}\n onMouseUp={() => setIsInteracting(false)}\n onMouseLeave={() => setIsInteracting(false)}\n className=\"absolute top-0 left-0 w-full h-full opacity-0 cursor-pointer\"\n />\n </div>\n </div>\n )}\n </div>\n );\n}\n\nfunction Timeline({\n currentTime,\n duration,\n setCurrentTime,\n}: {\n currentTime: number;\n duration: number;\n setCurrentTime: (currentTime: number) => void;\n}) {\n const progressPercentage = (currentTime / duration) * 100;\n\n return (\n <div className=\"relative flex-1 w-full h-1.5 bg-gray-300 rounded-full overflow-hidden\">\n <div\n className=\"absolute top-0 left-0 h-full bg-gray-100\"\n style={{width: `${progressPercentage}%`}}\n />\n <input\n type=\"range\"\n value={currentTime}\n min={0}\n max={duration}\n step={0.01}\n className=\"absolute top-0 left-0 w-full h-full opacity-0 cursor-pointer\"\n onChange={event => setCurrentTime(Number(event.target.value))}\n />\n </div>\n );\n}\n\nexport function Controls({\n duration,\n playing,\n setPlaying,\n currentTime,\n setForcedTime,\n timeDisplayFormat,\n volume,\n setVolume,\n}: {\n duration: number;\n playing: boolean;\n setPlaying: (playing: boolean) => void;\n currentTime: number;\n setForcedTime: (currentTime: number) => void;\n timeDisplayFormat: 'MM:SS' | 'MM:SS.m' | 'MM:SS.mm';\n volume: number;\n setVolume: (volume: number) => void;\n}) {\n return (\n <div className=\"text-white p-4 flex-col space-y-2 bg-gradient-to-t from-gray-500 to-transparent\">\n <div className=\"flex items-center space-x-2\">\n <PlayPause playing={playing} setPlaying={setPlaying} />\n <div className=\"flex items-center space-x-2\">\n <VolumeSlider volume={volume} setVolume={setVolume} />\n <div>\n <span>\n {getFormattedTime(currentTime, duration, timeDisplayFormat)}\n </span>\n </div>\n </div>\n <div className=\"flex-grow\" />\n </div>\n <Timeline\n currentTime={currentTime}\n duration={duration}\n setCurrentTime={setForcedTime}\n />\n </div>\n );\n}\n","export function PlayButton() {\n return (\n <svg\n xmlns=\"http://www.w3.org/2000/svg\"\n viewBox=\"0 0 24 24\"\n fill=\"currentColor\"\n className=\"w-6 h-6\"\n >\n <path\n fillRule=\"evenodd\"\n d=\"M4.5 5.653c0-1.427 1.529-2.33 2.779-1.643l11.54 6.347c1.295.712 1.295 2.573 0 3.286L7.28 19.99c-1.25.687-2.779-.217-2.779-1.643V5.653Z\"\n clipRule=\"evenodd\"\n />\n </svg>\n );\n}\n\nexport function PauseButton() {\n return (\n <svg\n xmlns=\"http://www.w3.org/2000/svg\"\n viewBox=\"0 0 24 24\"\n fill=\"currentColor\"\n className=\"w-6 h-6\"\n >\n <path\n fillRule=\"evenodd\"\n d=\"M6.75 5.25a.75.75 0 0 1 .75-.75H9a.75.75 0 0 1 .75.75v13.5a.75.75 0 0 1-.75.75H7.5a.75.75 0 0 1-.75-.75V5.25Zm7.5 0A.75.75 0 0 1 15 4.5h1.5a.75.75 0 0 1 .75.75v13.5a.75.75 0 0 1-.75.75H15a.75.75 0 0 1-.75-.75V5.25Z\"\n clipRule=\"evenodd\"\n />\n </svg>\n );\n}\n\nexport function SoundIcon() {\n return (\n <svg\n xmlns=\"http://www.w3.org/2000/svg\"\n viewBox=\"0 0 24 24\"\n fill=\"currentColor\"\n className=\"p-w-6 p-h-6\"\n >\n <path d=\"M18.36,19.36a1,1,0,0,1-.7-.29,1,1,0,0,1,0-1.41,8,8,0,0,0,0-11.32,1,1,0,0,1,1.41-1.41,10,10,0,0,1,0,14.14A1,1,0,0,1,18.36,19.36Z\" />\n <path d=\"M15.54,16.54a1,1,0,0,1-.71-.3,1,1,0,0,1,0-1.41,4,4,0,0,0,0-5.66,1,1,0,0,1,1.41-1.41,6,6,0,0,1,0,8.48A1,1,0,0,1,15.54,16.54Z\" />\n <path d=\"M11.38,4.08a1,1,0,0,0-1.09.21L6.59,8H4a2,2,0,0,0-2,2v4a2,2,0,0,0,2,2H6.59l3.7,3.71A1,1,0,0,0,11,20a.84.84,0,0,0,.38-.08A1,1,0,0,0,12,19V5A1,1,0,0,0,11.38,4.08Z\" />\n </svg>\n );\n}\n\nexport function MutedSoundIcon() {\n return (\n <svg\n xmlns=\"http://www.w3.org/2000/svg\"\n viewBox=\"0 0 24 24\"\n fill=\"currentColor\"\n className=\"p-w-6 p-h-6\"\n >\n <path d=\"M11.38,4.08a1,1,0,0,0-1.09.21L6.59,8H4a2,2,0,0,0-2,2v4a2,2,0,0,0,2,2H6.59l3.7,3.71A1,1,0,0,0,11,20a.84.84,0,0,0,.38-.08A1,1,0,0,0,12,19V5A1,1,0,0,0,11.38,4.08Z\" />\n <path d=\"M16,15.5a1,1,0,0,1-.71-.29,1,1,0,0,1,0-1.42l5-5a1,1,0,0,1,1.42,1.42l-5,5A1,1,0,0,1,16,15.5Z\" />\n <path d=\"M21,15.5a1,1,0,0,1-.71-.29l-5-5a1,1,0,0,1,1.42-1.42l5,5a1,1,0,0,1,0,1.42A1,1,0,0,1,21,15.5Z\" />\n </svg>\n );\n}\n","export function getFormattedTime(\n timeInSeconds: number,\n absoluteTimeInSeconds: number,\n timeDisplayFormat: 'MM:SS' | 'MM:SS.mm' | 'MM:SS.m',\n) {\n function toFormattedTime(timeInSeconds: number) {\n const minutes = Math.floor(timeInSeconds / 60);\n const seconds = Math.floor(timeInSeconds % 60)\n .toString()\n .padStart(2, '0');\n const milliseconds = Math.floor((timeInSeconds % 1) * 1000)\n .toString()\n .padStart(3, '0');\n\n if (timeDisplayFormat === 'MM:SS') {\n return `${minutes}:${seconds}`;\n }\n\n if (timeDisplayFormat === 'MM:SS.m') {\n return `${minutes}:${seconds}.${milliseconds[0]}`;\n }\n\n if (timeDisplayFormat === 'MM:SS.mm') {\n return `${minutes}:${seconds}.${milliseconds.slice(0, 2)}`;\n }\n }\n\n return `${toFormattedTime(timeInSeconds)} / ${toFormattedTime(absoluteTimeInSeconds)}`;\n}\n\nexport function shouldShowControls(\n playing: boolean,\n isMouseOver: boolean,\n areControlsDisabled: boolean,\n) {\n if (areControlsDisabled) {\n return false;\n }\n\n return !playing || isMouseOver;\n}\n"],"mappings":"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","names":["useState","timeInSeconds","jsx","jsxs","jsx","jsxs","useState","volume"]}