@videojs/react 0.1.0-preview.2

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.
@@ -0,0 +1,905 @@
1
+ import { a as useMediaStore, i as useMediaSelector } from "./store-DpQF8Ges.js";
2
+ import { currentTimeDisplayStateDefinition, durationDisplayStateDefinition, fullscreenButtonStateDefinition, muteButtonStateDefinition, playButtonStateDefinition, previewTimeDisplayStateDefinition, timeSliderStateDefinition, volumeSliderStateDefinition } from "@videojs/core/store";
3
+ import { formatDisplayTime, shallowEqual } from "@videojs/utils";
4
+ import * as React$1 from "react";
5
+ import { Children, cloneElement, createContext, forwardRef, useCallback, useContext, useEffect, useMemo, useRef, useState, useSyncExternalStore } from "react";
6
+ import { jsx, jsxs } from "react/jsx-runtime";
7
+ import { FloatingFocusManager, FloatingPortal, arrow, autoUpdate, flip, offset, safePolygon, shift, useClientPoint, useDismiss, useFloating, useFocus, useHover, useInteractions, useRole, useTransitionStatus } from "@floating-ui/react";
8
+ import { TimeSlider, VolumeSlider } from "@videojs/core";
9
+
10
+ //#region src/utils/component-factory.tsx
11
+ const Context$1 = createContext(null);
12
+ /**
13
+ * Generic factory function to create connected components following the hooks pattern
14
+ * inspired by Adobe React Spectrum and Base UI architectures.
15
+ *
16
+ * @param useStateHook - Hook that provides component state
17
+ * @param usePropsHook - Hook that enhances props with state-derived values
18
+ * @param defaultRender - Default render function for the component
19
+ * @param displayName - Display name for React DevTools
20
+ * @returns Connected component with customizable render prop
21
+ */
22
+ function toConnectedComponent(useStateHook, usePropsHook, defaultRender, displayName) {
23
+ const ConnectedComponent = forwardRef(({ render = defaultRender,...props }, ref) => {
24
+ const propsWithRef = ref ? {
25
+ ...props,
26
+ ref
27
+ } : props;
28
+ const connectedState = useStateHook(propsWithRef);
29
+ const connectedProps = usePropsHook(propsWithRef, connectedState);
30
+ return /* @__PURE__ */ jsx(Context$1.Provider, {
31
+ value: connectedState,
32
+ children: render(connectedProps, connectedState)
33
+ });
34
+ });
35
+ ConnectedComponent.displayName = displayName;
36
+ return ConnectedComponent;
37
+ }
38
+ /**
39
+ * Factory function to create context-based components that don't use toConnectedComponent
40
+ * These components rely on context provided by a parent component.
41
+ *
42
+ * @param usePropsHook - Hook that enhances props with context-derived values
43
+ * @param defaultRender - Default render function for the component
44
+ * @param displayName - Display name for React DevTools
45
+ * @returns Context-based component with customizable render prop
46
+ */
47
+ function toContextComponent(usePropsHook, defaultRender, displayName) {
48
+ const ContextComponent = forwardRef(({ render = defaultRender,...props }, ref) => {
49
+ const context = useContext(Context$1);
50
+ return render(usePropsHook(ref ? {
51
+ ...props,
52
+ ref
53
+ } : props, context), context);
54
+ });
55
+ ContextComponent.displayName = displayName;
56
+ return ContextComponent;
57
+ }
58
+ /**
59
+ * Hook that manages a CoreClass instance and triggers re-renders when state changes.
60
+ * Uses useSyncExternalStore for optimal performance with external state subscriptions.
61
+ */
62
+ function useCore(CoreClass, state) {
63
+ const coreRef = useRef(null);
64
+ const snapshotRef = useRef(null);
65
+ if (!coreRef.current) {
66
+ coreRef.current = new CoreClass();
67
+ snapshotRef.current = coreRef.current.getState();
68
+ }
69
+ useEffect(() => {
70
+ coreRef.current?.setState(state);
71
+ }, [...Object.values(state)]);
72
+ useSyncExternalStore(useCallback((onStoreChange) => {
73
+ if (!coreRef.current) return () => {};
74
+ return coreRef.current.subscribe((newState) => {
75
+ snapshotRef.current = newState;
76
+ onStoreChange();
77
+ });
78
+ }, []), useCallback(() => {
79
+ return snapshotRef.current;
80
+ }, []), () => null);
81
+ return coreRef.current;
82
+ }
83
+
84
+ //#endregion
85
+ //#region src/components/CurrentTimeDisplay.tsx
86
+ function useCurrentTimeDisplayState(_props) {
87
+ /** @TODO Fix type issues with hooks (CJP) */
88
+ const mediaState = useMediaSelector(currentTimeDisplayStateDefinition.stateTransform, shallowEqual);
89
+ return {
90
+ currentTime: mediaState.currentTime ?? 0,
91
+ duration: mediaState.duration ?? 0
92
+ };
93
+ }
94
+ function useCurrentTimeDisplayProps(props, _state) {
95
+ return { ...props };
96
+ }
97
+ function renderCurrentTimeDisplay(props, state) {
98
+ const { showRemaining,...restProps } = props;
99
+ /** @TODO Should this live here or elsewhere? (CJP) */
100
+ const timeLabel = showRemaining && state.duration != null && state.currentTime != null ? formatDisplayTime(-(state.duration - state.currentTime)) : formatDisplayTime(state.currentTime);
101
+ return /* @__PURE__ */ jsx("span", {
102
+ ...restProps,
103
+ children: timeLabel
104
+ });
105
+ }
106
+ const CurrentTimeDisplay = toConnectedComponent(useCurrentTimeDisplayState, useCurrentTimeDisplayProps, renderCurrentTimeDisplay, "CurrentTimeDisplay");
107
+
108
+ //#endregion
109
+ //#region src/components/DurationDisplay.tsx
110
+ function useDurationDisplayState(_props) {
111
+ return { duration: useMediaSelector(durationDisplayStateDefinition.stateTransform, shallowEqual).duration ?? 0 };
112
+ }
113
+ function useDurationDisplayProps(props) {
114
+ return { ...props };
115
+ }
116
+ function renderDurationDisplay(props, state) {
117
+ return /* @__PURE__ */ jsx("span", {
118
+ ...props,
119
+ children: formatDisplayTime(state.duration)
120
+ });
121
+ }
122
+ const DurationDisplay = toConnectedComponent(useDurationDisplayState, useDurationDisplayProps, renderDurationDisplay, "DurationDisplay");
123
+
124
+ //#endregion
125
+ //#region src/components/FullscreenButton.tsx
126
+ function useFullscreenButtonState(_props) {
127
+ const mediaStore = useMediaStore();
128
+ const mediaState = useMediaSelector(fullscreenButtonStateDefinition.stateTransform, shallowEqual);
129
+ const methods = useMemo(() => fullscreenButtonStateDefinition.createRequestMethods(mediaStore.dispatch), [mediaStore]);
130
+ return {
131
+ fullscreen: mediaState.fullscreen,
132
+ requestEnterFullscreen: methods.requestEnterFullscreen,
133
+ requestExitFullscreen: methods.requestExitFullscreen
134
+ };
135
+ }
136
+ function getFullscreenButtonProps(props, state) {
137
+ const baseProps = {
138
+ role: "button",
139
+ "aria-label": state.fullscreen ? "exit fullscreen" : "enter fullscreen",
140
+ "data-tooltip": state.fullscreen ? "Exit Fullscreen" : "Enter Fullscreen",
141
+ ...props
142
+ };
143
+ if (state.fullscreen) baseProps["data-fullscreen"] = "";
144
+ return baseProps;
145
+ }
146
+ function renderFullscreenButton(props, state) {
147
+ return /* @__PURE__ */ jsx("button", {
148
+ type: "button",
149
+ ...props,
150
+ onClick: () => {
151
+ if (props.disabled) return;
152
+ if (state.fullscreen) state.requestExitFullscreen();
153
+ else state.requestEnterFullscreen();
154
+ },
155
+ children: props.children
156
+ });
157
+ }
158
+ const FullscreenButton = toConnectedComponent(useFullscreenButtonState, getFullscreenButtonProps, renderFullscreenButton, "FullscreenButton");
159
+
160
+ //#endregion
161
+ //#region src/utils/use-composed-refs.ts
162
+ /**
163
+ * Set a given ref to a given value
164
+ * This utility takes care of different types of refs: callback refs and RefObject(s)
165
+ */
166
+ function setRef(ref, value) {
167
+ if (typeof ref === "function") return ref(value);
168
+ else if (ref !== null && ref !== void 0) ref.current = value;
169
+ }
170
+ /**
171
+ * A utility to compose multiple refs together
172
+ * Accepts callback refs and RefObject(s)
173
+ */
174
+ function composeRefs(...refs) {
175
+ return (node) => {
176
+ let hasCleanup = false;
177
+ const cleanups = refs.map((ref) => {
178
+ const cleanup = setRef(ref, node);
179
+ if (!hasCleanup && typeof cleanup == "function") hasCleanup = true;
180
+ return cleanup;
181
+ });
182
+ if (hasCleanup) return () => {
183
+ for (let i = 0; i < cleanups.length; i++) {
184
+ const cleanup = cleanups[i];
185
+ if (typeof cleanup == "function") cleanup();
186
+ else setRef(refs[i], null);
187
+ }
188
+ };
189
+ };
190
+ }
191
+ /**
192
+ * A custom hook that composes multiple refs
193
+ * Accepts callback refs and RefObject(s)
194
+ */
195
+ function useComposedRefs(...refs) {
196
+ return React$1.useCallback(composeRefs(...refs), refs);
197
+ }
198
+
199
+ //#endregion
200
+ //#region src/components/MediaContainer.tsx
201
+ /**
202
+ * Hook to associate a React element as the fullscreen container for the media store.
203
+ * This is equivalent to Media Chrome's useMediaFullscreenRef but for VJS-10.
204
+ *
205
+ * The ref callback will register the element as the container state owner
206
+ * in the media store, enabling fullscreen functionality.
207
+ *
208
+ * @example
209
+ * import { useMediaContainerRef } from '@videojs/react';
210
+ *
211
+ * const PlayerContainer = ({ children }) => {
212
+ * const containerRef = useMediaContainerRef();
213
+ * return <div ref={containerRef}>{children}</div>;
214
+ * };
215
+ */
216
+ function useMediaContainerRef() {
217
+ const mediaStore = useMediaStore();
218
+ return useCallback((containerElement) => {
219
+ if (!mediaStore) return;
220
+ mediaStore.dispatch({
221
+ type: "containerstateownerchangerequest",
222
+ detail: containerElement
223
+ });
224
+ }, [mediaStore]);
225
+ }
226
+ /**
227
+ * MediaContainer component that automatically registers itself as the fullscreen container.
228
+ * This provides a simple wrapper component for fullscreen functionality.
229
+ *
230
+ * @example
231
+ * import { MediaContainer } from '@videojs/react';
232
+ *
233
+ * const MyPlayer = () => (
234
+ * <MediaContainer>
235
+ * <video src="video.mp4" />
236
+ * <div>Controls here</div>
237
+ * </MediaContainer>
238
+ * );
239
+ */
240
+ const MediaContainer = forwardRef(({ children, portalId = "@default_portal_id",...props }, ref) => {
241
+ const composedRef = useComposedRefs(ref, useMediaContainerRef());
242
+ const mediaStore = useMediaStore();
243
+ const mediaState = useMediaSelector(playButtonStateDefinition.stateTransform, shallowEqual);
244
+ const methods = useMemo(() => playButtonStateDefinition.createRequestMethods(mediaStore.dispatch), [mediaStore]);
245
+ return /* @__PURE__ */ jsxs("div", {
246
+ ref: composedRef,
247
+ onClick: useCallback((event) => {
248
+ if (!["video", "audio"].includes(event.target.localName || "")) return;
249
+ if (mediaState.paused) methods.requestPlay();
250
+ else methods.requestPause();
251
+ }, [mediaState.paused, methods]),
252
+ ...props,
253
+ children: [children, /* @__PURE__ */ jsx("div", {
254
+ id: portalId,
255
+ style: {
256
+ position: "absolute",
257
+ zIndex: 10
258
+ }
259
+ })]
260
+ });
261
+ });
262
+
263
+ //#endregion
264
+ //#region src/components/MuteButton.tsx
265
+ function useMuteButtonState(_props) {
266
+ const mediaStore = useMediaStore();
267
+ const mediaState = useMediaSelector(muteButtonStateDefinition.stateTransform, shallowEqual);
268
+ const methods = useMemo(() => muteButtonStateDefinition.createRequestMethods(mediaStore.dispatch), [mediaStore]);
269
+ return {
270
+ volumeLevel: mediaState.volumeLevel,
271
+ muted: mediaState.muted,
272
+ requestMute: methods.requestMute,
273
+ requestUnmute: methods.requestUnmute
274
+ };
275
+ }
276
+ function getMuteButtonProps(props, state) {
277
+ const baseProps = {
278
+ "data-volume-level": state.volumeLevel,
279
+ role: "button",
280
+ "aria-label": state.muted ? "unmute" : "mute",
281
+ "data-tooltip": state.muted ? "Unmute" : "Mute",
282
+ ...props
283
+ };
284
+ if (state.muted) baseProps["data-muted"] = "";
285
+ return baseProps;
286
+ }
287
+ function renderMuteButton(props, state) {
288
+ return /* @__PURE__ */ jsx("button", {
289
+ type: "button",
290
+ ...props,
291
+ onClick: () => {
292
+ if (props.disabled) return;
293
+ if (state.volumeLevel === "off") state.requestUnmute();
294
+ else state.requestMute();
295
+ },
296
+ children: props.children
297
+ });
298
+ }
299
+ const MuteButton = toConnectedComponent(useMuteButtonState, getMuteButtonProps, renderMuteButton, "MuteButton");
300
+ var MuteButton_default = MuteButton;
301
+
302
+ //#endregion
303
+ //#region src/components/PlayButton.tsx
304
+ function usePlayButtonState(_props) {
305
+ const mediaStore = useMediaStore();
306
+ const mediaState = useMediaSelector(playButtonStateDefinition.stateTransform, shallowEqual);
307
+ const methods = useMemo(() => playButtonStateDefinition.createRequestMethods(mediaStore.dispatch), [mediaStore]);
308
+ return {
309
+ paused: mediaState.paused,
310
+ requestPlay: methods.requestPlay,
311
+ requestPause: methods.requestPause
312
+ };
313
+ }
314
+ function getPlayButtonProps(props, state) {
315
+ const baseProps = {
316
+ role: "button",
317
+ "aria-label": state.paused ? "play" : "pause",
318
+ "data-tooltip": state.paused ? "Play" : "Pause",
319
+ ...props
320
+ };
321
+ if (state.paused) baseProps["data-paused"] = "";
322
+ return baseProps;
323
+ }
324
+ function renderPlayButton(props, state) {
325
+ return /* @__PURE__ */ jsx("button", {
326
+ type: "button",
327
+ ...props,
328
+ onClick: () => {
329
+ if (props.disabled) return;
330
+ if (state.paused) state.requestPlay();
331
+ else state.requestPause();
332
+ },
333
+ children: props.children
334
+ });
335
+ }
336
+ const PlayButton = toConnectedComponent(usePlayButtonState, getPlayButtonProps, renderPlayButton, "PlayButton");
337
+ var PlayButton_default = PlayButton;
338
+
339
+ //#endregion
340
+ //#region src/components/Popover.tsx
341
+ const PopoverContext = createContext(null);
342
+ function usePopoverContext() {
343
+ const context = useContext(PopoverContext);
344
+ if (!context) throw new Error("Popover components must be used within PopoverRoot");
345
+ return context;
346
+ }
347
+ function PopoverRoot({ openOnHover = false, delay = 0, closeDelay = 0, children }) {
348
+ const [open, setOpen] = useState(false);
349
+ const [placement, setPlacement] = useState("top");
350
+ const [sideOffset, setSideOffset] = useState(5);
351
+ const [openReason, setOpenReason] = useState(null);
352
+ const { refs, floatingStyles, context } = useFloating({
353
+ open,
354
+ onOpenChange: (open$1, _event, reason) => {
355
+ setOpen(open$1);
356
+ setOpenReason(reason || null);
357
+ },
358
+ placement,
359
+ middleware: [
360
+ offset(sideOffset),
361
+ flip(),
362
+ shift()
363
+ ],
364
+ whileElementsMounted: autoUpdate
365
+ });
366
+ const { status: transitionStatus } = useTransitionStatus(context);
367
+ const { getReferenceProps, getFloatingProps } = useInteractions([
368
+ useHover(context, {
369
+ enabled: openOnHover,
370
+ mouseOnly: true,
371
+ move: false,
372
+ delay: {
373
+ open: delay,
374
+ close: closeDelay
375
+ },
376
+ handleClose: safePolygon({ blockPointerEvents: true })
377
+ }),
378
+ useFocus(context),
379
+ useDismiss(context),
380
+ useRole(context)
381
+ ]);
382
+ const updatePositioning = useCallback((newPlacement, newSideOffset) => {
383
+ setPlacement(newPlacement);
384
+ setSideOffset(newSideOffset);
385
+ }, []);
386
+ const value = useMemo(() => ({
387
+ open,
388
+ setOpen,
389
+ openReason,
390
+ refs,
391
+ floatingStyles,
392
+ getReferenceProps,
393
+ getFloatingProps,
394
+ context,
395
+ updatePositioning,
396
+ transitionStatus
397
+ }), [
398
+ open,
399
+ openReason,
400
+ refs,
401
+ floatingStyles,
402
+ getReferenceProps,
403
+ getFloatingProps,
404
+ context,
405
+ updatePositioning,
406
+ transitionStatus
407
+ ]);
408
+ return /* @__PURE__ */ jsx(PopoverContext.Provider, {
409
+ value,
410
+ children
411
+ });
412
+ }
413
+ function PopoverTrigger({ children }) {
414
+ const { refs, getReferenceProps, open } = usePopoverContext();
415
+ return cloneElement(Children.only(children), {
416
+ ref: refs.setReference,
417
+ ...getReferenceProps(),
418
+ "data-popup-open": open ? "" : void 0
419
+ });
420
+ }
421
+ function PopoverPositioner({ side = "top", sideOffset = 5, children }) {
422
+ const { refs, floatingStyles, updatePositioning } = usePopoverContext();
423
+ useEffect(() => {
424
+ updatePositioning(side, sideOffset);
425
+ }, [
426
+ side,
427
+ sideOffset,
428
+ updatePositioning
429
+ ]);
430
+ return /* @__PURE__ */ jsx("div", {
431
+ ref: refs.setFloating,
432
+ style: floatingStyles,
433
+ children
434
+ });
435
+ }
436
+ function PopoverPopup({ className, children }) {
437
+ const { getFloatingProps, context, transitionStatus } = usePopoverContext();
438
+ const { refs, placement } = context;
439
+ const triggerElement = refs.reference.current;
440
+ const dataAttributes = triggerElement?.attributes ? Object.fromEntries(Array.from(triggerElement.attributes).filter((attr) => attr.name.startsWith("data-")).map((attr) => [attr.name, attr.value])) : {};
441
+ return /* @__PURE__ */ jsx(FloatingFocusManager, {
442
+ context,
443
+ modal: false,
444
+ initialFocus: -1,
445
+ returnFocus: false,
446
+ children: /* @__PURE__ */ jsx("div", {
447
+ className,
448
+ ...getFloatingProps(),
449
+ ...dataAttributes,
450
+ "data-side": placement,
451
+ "data-starting-style": transitionStatus === "initial" ? "" : void 0,
452
+ "data-open": transitionStatus === "initial" || transitionStatus === "open" ? "" : void 0,
453
+ "data-ending-style": transitionStatus === "close" || transitionStatus === "unmounted" ? "" : void 0,
454
+ "data-closed": transitionStatus === "close" || transitionStatus === "unmounted" ? "" : void 0,
455
+ children
456
+ })
457
+ });
458
+ }
459
+ function PopoverPortal({ children, root, rootId = "@default_portal_id" }) {
460
+ return /* @__PURE__ */ jsx(FloatingPortal, {
461
+ root,
462
+ id: rootId,
463
+ children
464
+ });
465
+ }
466
+ const Popover = {
467
+ Root: PopoverRoot,
468
+ Trigger: PopoverTrigger,
469
+ Positioner: PopoverPositioner,
470
+ Popup: PopoverPopup,
471
+ Portal: PopoverPortal
472
+ };
473
+ var Popover_default = Popover;
474
+
475
+ //#endregion
476
+ //#region src/components/PreviewTimeDisplay.tsx
477
+ function usePreviewTimeDisplayState(_props) {
478
+ return { previewTime: useMediaSelector(previewTimeDisplayStateDefinition.stateTransform, shallowEqual).previewTime ?? 0 };
479
+ }
480
+ function getPreviewTimeDisplayProps(props, _state) {
481
+ return { ...props };
482
+ }
483
+ function renderPreviewTimeDisplay(props, state) {
484
+ const { showRemaining,...restProps } = props;
485
+ /** @TODO Should this live here or elsewhere? (CJP) */
486
+ const timeLabel = formatDisplayTime(state.previewTime);
487
+ return /* @__PURE__ */ jsx("span", {
488
+ ...restProps,
489
+ children: timeLabel
490
+ });
491
+ }
492
+ const PreviewTimeDisplay = toConnectedComponent(usePreviewTimeDisplayState, getPreviewTimeDisplayProps, renderPreviewTimeDisplay, "PreviewTimeDisplay");
493
+ var PreviewTimeDisplay_default = PreviewTimeDisplay;
494
+
495
+ //#endregion
496
+ //#region src/components/TimeSlider.tsx
497
+ function useTimeSliderRootState(props) {
498
+ const { orientation = "horizontal" } = props;
499
+ const mediaStore = useMediaStore();
500
+ const mediaState = useMediaSelector(timeSliderStateDefinition.stateTransform, shallowEqual);
501
+ const mediaMethods = useMemo(() => timeSliderStateDefinition.createRequestMethods(mediaStore.dispatch), [mediaStore]);
502
+ const core = useCore(TimeSlider, {
503
+ ...mediaState,
504
+ ...mediaMethods
505
+ });
506
+ return {
507
+ ...mediaState,
508
+ ...mediaMethods,
509
+ orientation,
510
+ core
511
+ };
512
+ }
513
+ function useTimeSliderRootProps(props, state) {
514
+ const { _fillWidth, _pointerWidth, _currentTimeText, _durationText } = state.core.getState();
515
+ const { children, className, id, style, orientation = "horizontal", ref } = props;
516
+ return {
517
+ ref: useComposedRefs(ref, useCallback((el) => {
518
+ if (!el) return;
519
+ state.core?.attach(el);
520
+ }, [state.core])),
521
+ id,
522
+ role: "slider",
523
+ tabIndex: 0,
524
+ "aria-label": "Seek",
525
+ "aria-valuemin": 0,
526
+ "aria-valuemax": Math.round(state.duration),
527
+ "aria-valuenow": Math.round(state.currentTime),
528
+ "aria-valuetext": `${_currentTimeText} of ${_durationText}`,
529
+ "aria-orientation": orientation,
530
+ "data-orientation": orientation,
531
+ "data-current-time": state.currentTime,
532
+ "data-duration": state.duration,
533
+ className,
534
+ style: {
535
+ ...style,
536
+ "--slider-fill": `${_fillWidth.toFixed(3)}%`,
537
+ "--slider-pointer": `${(_pointerWidth * 100).toFixed(3)}%`
538
+ },
539
+ children
540
+ };
541
+ }
542
+ function renderTimeSliderRoot(props) {
543
+ return /* @__PURE__ */ jsx("div", { ...props });
544
+ }
545
+ const TimeSliderRoot = toConnectedComponent(useTimeSliderRootState, useTimeSliderRootProps, renderTimeSliderRoot, "TimeSlider.Root");
546
+ function useTimeSliderTrackProps(props, context) {
547
+ return {
548
+ ref: useCallback((el) => {
549
+ context.core?.setState({ _trackElement: el });
550
+ }, [context.core]),
551
+ "data-orientation": context.orientation,
552
+ ...props,
553
+ style: {
554
+ ...props.style,
555
+ [context.orientation === "horizontal" ? "width" : "height"]: "100%"
556
+ }
557
+ };
558
+ }
559
+ function renderTimeSliderTrack(props) {
560
+ return /* @__PURE__ */ jsx("div", { ...props });
561
+ }
562
+ const TimeSliderTrack = toContextComponent(useTimeSliderTrackProps, renderTimeSliderTrack, "TimeSlider.Track");
563
+ function getTimeSliderThumbProps(props, context) {
564
+ return {
565
+ "data-orientation": context.orientation,
566
+ ...props,
567
+ style: {
568
+ ...props.style,
569
+ [context.orientation === "horizontal" ? "insetInlineStart" : "insetBlockEnd"]: "var(--slider-fill)",
570
+ [context.orientation === "horizontal" ? "top" : "left"]: "50%",
571
+ translate: context.orientation === "horizontal" ? "-50% -50%" : "-50% 50%",
572
+ position: "absolute"
573
+ }
574
+ };
575
+ }
576
+ function renderTimeSliderThumb(props) {
577
+ return /* @__PURE__ */ jsx("div", { ...props });
578
+ }
579
+ const TimeSliderThumb = toContextComponent(getTimeSliderThumbProps, renderTimeSliderThumb, "TimeSlider.Thumb");
580
+ function getTimeSliderPointerProps(props, context) {
581
+ return {
582
+ "data-orientation": context.orientation,
583
+ ...props,
584
+ style: {
585
+ ...props.style,
586
+ [context.orientation === "horizontal" ? "width" : "height"]: "var(--slider-pointer, 0%)",
587
+ [context.orientation === "horizontal" ? "height" : "width"]: "100%",
588
+ position: "absolute"
589
+ }
590
+ };
591
+ }
592
+ function renderTimeSliderPointer(props) {
593
+ return /* @__PURE__ */ jsx("div", { ...props });
594
+ }
595
+ const TimeSliderPointer = toContextComponent(getTimeSliderPointerProps, renderTimeSliderPointer, "TimeSlider.Pointer");
596
+ function getTimeSliderProgressProps(props, context) {
597
+ return {
598
+ "data-orientation": context.orientation,
599
+ ...props,
600
+ style: {
601
+ ...props.style,
602
+ [context.orientation === "horizontal" ? "width" : "height"]: "var(--slider-fill, 0%)",
603
+ [context.orientation === "horizontal" ? "height" : "width"]: "100%",
604
+ [context.orientation === "horizontal" ? "top" : "bottom"]: "0",
605
+ position: "absolute"
606
+ }
607
+ };
608
+ }
609
+ function renderTimeSliderProgress(props) {
610
+ return /* @__PURE__ */ jsx("div", { ...props });
611
+ }
612
+ const TimeSliderProgress = toContextComponent(getTimeSliderProgressProps, renderTimeSliderProgress, "TimeSlider.Progress");
613
+ const TimeSlider$1 = Object.assign({}, {
614
+ Root: TimeSliderRoot,
615
+ Track: TimeSliderTrack,
616
+ Thumb: TimeSliderThumb,
617
+ Pointer: TimeSliderPointer,
618
+ Progress: TimeSliderProgress
619
+ });
620
+
621
+ //#endregion
622
+ //#region src/components/Tooltip.tsx
623
+ const TooltipContext = createContext(null);
624
+ const TooltipPositionerContext = createContext(null);
625
+ function useTooltipContext() {
626
+ const context = useContext(TooltipContext);
627
+ if (!context) throw new Error("Tooltip components must be used within TooltipRoot");
628
+ return context;
629
+ }
630
+ function useTooltipPositionerContext() {
631
+ const context = useContext(TooltipPositionerContext);
632
+ if (!context) throw new Error("TooltipArrow must be used within TooltipPositioner");
633
+ return context;
634
+ }
635
+ function TooltipRoot({ delay = 0, closeDelay = 0, trackCursorAxis, children }) {
636
+ const [open, setOpen] = useState(false);
637
+ const [placement, setPlacement] = useState("top");
638
+ const [sideOffset, setSideOffset] = useState(0);
639
+ const [collisionPadding, setCollisionPadding] = useState(0);
640
+ const arrowRef = useRef(null);
641
+ const { context } = useFloating({
642
+ open,
643
+ onOpenChange: setOpen,
644
+ placement,
645
+ middleware: [
646
+ offset(sideOffset),
647
+ flip(),
648
+ shift({ padding: collisionPadding }),
649
+ arrow({ element: arrowRef })
650
+ ],
651
+ whileElementsMounted: autoUpdate
652
+ });
653
+ const { status: transitionStatus } = useTransitionStatus(context);
654
+ const hover = useHover(context, { delay: {
655
+ open: delay,
656
+ close: closeDelay
657
+ } });
658
+ const focus = useFocus(context);
659
+ const dismiss = useDismiss(context);
660
+ const role = useRole(context, { role: "tooltip" });
661
+ const clientPoint = useClientPoint(context, {
662
+ axis: trackCursorAxis || "both",
663
+ enabled: !!trackCursorAxis
664
+ });
665
+ const { getReferenceProps, getFloatingProps } = useInteractions(trackCursorAxis ? [
666
+ hover,
667
+ focus,
668
+ dismiss,
669
+ role,
670
+ clientPoint
671
+ ] : [
672
+ hover,
673
+ focus,
674
+ dismiss,
675
+ role
676
+ ]);
677
+ const updatePositioning = useCallback(({ side, sideOffset: sideOffset$1, collisionPadding: collisionPadding$1 }) => {
678
+ setPlacement(side);
679
+ setSideOffset(sideOffset$1);
680
+ setCollisionPadding(collisionPadding$1);
681
+ }, []);
682
+ const value = useMemo(() => ({
683
+ getReferenceProps,
684
+ getFloatingProps,
685
+ context,
686
+ updatePositioning,
687
+ arrowRef,
688
+ transitionStatus,
689
+ trackCursorAxis
690
+ }), [
691
+ getReferenceProps,
692
+ getFloatingProps,
693
+ context,
694
+ updatePositioning,
695
+ transitionStatus,
696
+ trackCursorAxis
697
+ ]);
698
+ return /* @__PURE__ */ jsx(TooltipContext.Provider, {
699
+ value,
700
+ children
701
+ });
702
+ }
703
+ function TooltipTrigger({ children }) {
704
+ const { context, getReferenceProps } = useTooltipContext();
705
+ const { refs, open } = context;
706
+ return cloneElement(Children.only(children), {
707
+ ref: refs.setReference,
708
+ ...getReferenceProps(),
709
+ "data-popup-open": open ? "" : void 0
710
+ });
711
+ }
712
+ function TooltipPositioner({ side = "top", sideOffset = 0, collisionPadding = 0, children }) {
713
+ const { context, updatePositioning, trackCursorAxis } = useTooltipContext();
714
+ const { refs, floatingStyles } = context;
715
+ useEffect(() => {
716
+ updatePositioning({
717
+ side,
718
+ sideOffset,
719
+ collisionPadding
720
+ });
721
+ }, [
722
+ side,
723
+ sideOffset,
724
+ collisionPadding,
725
+ updatePositioning
726
+ ]);
727
+ const positionerContextValue = useMemo(() => ({ side }), [side]);
728
+ return /* @__PURE__ */ jsx(TooltipPositionerContext.Provider, {
729
+ value: positionerContextValue,
730
+ children: /* @__PURE__ */ jsx("div", {
731
+ ref: refs.setFloating,
732
+ style: {
733
+ ...floatingStyles,
734
+ pointerEvents: trackCursorAxis ? "none" : void 0
735
+ },
736
+ children
737
+ })
738
+ });
739
+ }
740
+ function TooltipPopup({ className = "", children }) {
741
+ const { context, getFloatingProps, transitionStatus } = useTooltipContext();
742
+ const { refs, placement } = context;
743
+ const triggerElement = refs.reference.current;
744
+ const dataAttributes = triggerElement?.attributes ? Object.fromEntries(Array.from(triggerElement.attributes).filter((attr) => attr.name.startsWith("data-")).map((attr) => [attr.name, attr.value])) : {};
745
+ return /* @__PURE__ */ jsx("div", {
746
+ className,
747
+ ...getFloatingProps(),
748
+ ...dataAttributes,
749
+ "data-side": placement,
750
+ "data-starting-style": transitionStatus === "initial" ? "" : void 0,
751
+ "data-open": transitionStatus === "initial" || transitionStatus === "open" ? "" : void 0,
752
+ "data-ending-style": transitionStatus === "close" || transitionStatus === "unmounted" ? "" : void 0,
753
+ "data-closed": transitionStatus === "close" || transitionStatus === "unmounted" ? "" : void 0,
754
+ children
755
+ });
756
+ }
757
+ function TooltipArrow({ className = "", children }) {
758
+ const { arrowRef, context } = useTooltipContext();
759
+ const { side } = useTooltipPositionerContext();
760
+ const { x: arrowX, y: arrowY } = context.middlewareData.arrow || {
761
+ x: 0,
762
+ y: 0
763
+ };
764
+ return /* @__PURE__ */ jsx("div", {
765
+ ref: arrowRef,
766
+ className,
767
+ "aria-hidden": "true",
768
+ "data-side": side,
769
+ style: {
770
+ left: arrowX != null ? `${arrowX}px` : void 0,
771
+ top: arrowY != null ? `${arrowY}px` : void 0
772
+ },
773
+ children
774
+ });
775
+ }
776
+ function TooltipPortal({ children, root, rootId = "@default_portal_id" }) {
777
+ return /* @__PURE__ */ jsx(FloatingPortal, {
778
+ root,
779
+ id: rootId,
780
+ children
781
+ });
782
+ }
783
+ const Tooltip = {
784
+ Root: TooltipRoot,
785
+ Trigger: TooltipTrigger,
786
+ Positioner: TooltipPositioner,
787
+ Popup: TooltipPopup,
788
+ Arrow: TooltipArrow,
789
+ Portal: TooltipPortal
790
+ };
791
+ var Tooltip_default = Tooltip;
792
+
793
+ //#endregion
794
+ //#region src/components/VolumeSlider.tsx
795
+ function useVolumeSliderRootState(props) {
796
+ const { orientation = "horizontal" } = props;
797
+ const mediaStore = useMediaStore();
798
+ const mediaState = useMediaSelector(volumeSliderStateDefinition.stateTransform, shallowEqual);
799
+ const mediaMethods = useMemo(() => volumeSliderStateDefinition.createRequestMethods(mediaStore.dispatch), [mediaStore]);
800
+ const core = useCore(VolumeSlider, {
801
+ ...mediaState,
802
+ ...mediaMethods
803
+ });
804
+ return {
805
+ ...mediaState,
806
+ ...mediaMethods,
807
+ orientation,
808
+ core
809
+ };
810
+ }
811
+ function useVolumeSliderRootProps(props, state) {
812
+ const { _fillWidth, _pointerWidth, _volumeText } = state.core.getState();
813
+ const { children, className, id, style, orientation = "horizontal" } = props;
814
+ return {
815
+ ref: useCallback((el) => {
816
+ if (!el) return;
817
+ state.core?.attach(el);
818
+ }, []),
819
+ id,
820
+ role: "slider",
821
+ tabIndex: 0,
822
+ "aria-label": "Volume",
823
+ "aria-valuemin": 0,
824
+ "aria-valuemax": 100,
825
+ "aria-valuenow": Math.round(state.volume * 100),
826
+ "aria-valuetext": _volumeText,
827
+ "aria-orientation": orientation,
828
+ "data-orientation": orientation,
829
+ "data-muted": state.muted,
830
+ "data-volume-level": state.volumeLevel,
831
+ className,
832
+ style: {
833
+ ...style,
834
+ "--slider-fill": `${_fillWidth.toFixed(3)}%`,
835
+ "--slider-pointer": `${_pointerWidth.toFixed(3)}%`
836
+ },
837
+ children
838
+ };
839
+ }
840
+ function renderVolumeSliderRoot(props) {
841
+ return /* @__PURE__ */ jsx("div", { ...props });
842
+ }
843
+ const VolumeSliderRoot = toConnectedComponent(useVolumeSliderRootState, useVolumeSliderRootProps, renderVolumeSliderRoot, "VolumeSlider.Root");
844
+ function useVolumeSliderTrackProps(props, context) {
845
+ return {
846
+ ref: useCallback((el) => {
847
+ context.core?.setState({ _trackElement: el });
848
+ }, []),
849
+ "data-orientation": context.orientation,
850
+ ...props,
851
+ style: {
852
+ ...props.style,
853
+ [context.orientation === "horizontal" ? "width" : "height"]: "100%"
854
+ }
855
+ };
856
+ }
857
+ function renderVolumeSliderTrack(props) {
858
+ return /* @__PURE__ */ jsx("div", { ...props });
859
+ }
860
+ const VolumeSliderTrack = toContextComponent(useVolumeSliderTrackProps, renderVolumeSliderTrack, "VolumeSlider.Track");
861
+ function getVolumeSliderThumbProps(props, context) {
862
+ return {
863
+ "data-orientation": context.orientation,
864
+ ...props,
865
+ style: {
866
+ ...props.style,
867
+ [context.orientation === "horizontal" ? "insetInlineStart" : "insetBlockEnd"]: "var(--slider-fill)",
868
+ [context.orientation === "horizontal" ? "top" : "left"]: "50%",
869
+ translate: context.orientation === "horizontal" ? "-50% -50%" : "-50% 50%",
870
+ position: "absolute"
871
+ }
872
+ };
873
+ }
874
+ function renderVolumeSliderThumb(props) {
875
+ return /* @__PURE__ */ jsx("div", { ...props });
876
+ }
877
+ const VolumeSliderThumb = toContextComponent(getVolumeSliderThumbProps, renderVolumeSliderThumb, "VolumeSlider.Thumb");
878
+ function getVolumeSliderProgressProps(props, context) {
879
+ return {
880
+ "data-orientation": context.orientation,
881
+ ...props,
882
+ style: {
883
+ ...props.style,
884
+ [context.orientation === "horizontal" ? "width" : "height"]: "var(--slider-fill, 0%)",
885
+ [context.orientation === "horizontal" ? "height" : "width"]: "100%",
886
+ [context.orientation === "horizontal" ? "top" : "bottom"]: "0",
887
+ position: "absolute"
888
+ }
889
+ };
890
+ }
891
+ function renderVolumeSliderProgress(props) {
892
+ return /* @__PURE__ */ jsx("div", { ...props });
893
+ }
894
+ const VolumeSliderProgress = toContextComponent(getVolumeSliderProgressProps, renderVolumeSliderProgress, "VolumeSlider.Progress");
895
+ const VolumeSlider$1 = Object.assign({}, {
896
+ Root: VolumeSliderRoot,
897
+ Track: VolumeSliderTrack,
898
+ Thumb: VolumeSliderThumb,
899
+ Progress: VolumeSliderProgress
900
+ });
901
+ var VolumeSlider_default = VolumeSlider$1;
902
+
903
+ //#endregion
904
+ export { DurationDisplay as _, TimeSlider$1 as a, Popover as c, PlayButton_default as d, MuteButton as f, FullscreenButton as g, useMediaContainerRef as h, Tooltip_default as i, Popover_default as l, MediaContainer as m, VolumeSlider_default as n, PreviewTimeDisplay as o, MuteButton_default as p, Tooltip as r, PreviewTimeDisplay_default as s, VolumeSlider$1 as t, PlayButton as u, CurrentTimeDisplay as v };
905
+ //# sourceMappingURL=VolumeSlider-DoR6idnJ.js.map