@aidenlx/vidstack-react
Version:
UI component library for building high-quality, accessible video and audio experiences on the web.
671 lines (639 loc) • 22.6 kB
JavaScript
"use client"
import * as React from 'react';
import { useReactContext, createReactComponent, composeRefs, useSignal, useStateContext } from 'maverick.js/react';
import { mediaContext, AirPlayButtonInstance, Primitive, PlayButtonInstance, CaptionButtonInstance, FullscreenButtonInstance, MuteButtonInstance, PIPButtonInstance, SeekButtonInstance, LiveButtonInstance, SliderValueInstance, SliderInstance, SliderPreviewInstance, useSliderState, VolumeSliderInstance, IS_SERVER, ThumbnailInstance, TimeSliderInstance, SliderChaptersInstance, SliderThumbnailInstance, SliderVideoInstance, mediaState, RadioGroupInstance, RadioInstance, MenuInstance, MenuButtonInstance, useMediaState, MenuItemsInstance, MenuItemInstance, GestureInstance, TimeInstance, isTrackCaptionKind } from './vidstack-B1ySk2FQ.js';
import { signal, effect } from 'maverick.js';
import { noop, isString } from 'maverick.js/std';
import { createPortal } from 'react-dom';
function useMediaContext() {
return useReactContext(mediaContext);
}
const AirPlayButtonBridge = createReactComponent(AirPlayButtonInstance, {
domEventsRegex: /^onMedia/
});
const AirPlayButton = React.forwardRef(
({ children, ...props }, forwardRef) => {
return /* @__PURE__ */ React.createElement(AirPlayButtonBridge, { ...props }, (props2) => /* @__PURE__ */ React.createElement(
Primitive.button,
{
...props2,
ref: composeRefs(props2.ref, forwardRef)
},
children
));
}
);
AirPlayButton.displayName = "AirPlayButton";
const PlayButtonBridge = createReactComponent(PlayButtonInstance, {
domEventsRegex: /^onMedia/
});
const PlayButton = React.forwardRef(
({ children, ...props }, forwardRef) => {
return /* @__PURE__ */ React.createElement(PlayButtonBridge, { ...props }, (props2) => /* @__PURE__ */ React.createElement(
Primitive.button,
{
...props2,
ref: composeRefs(props2.ref, forwardRef)
},
children
));
}
);
PlayButton.displayName = "PlayButton";
const CaptionButtonBridge = createReactComponent(CaptionButtonInstance, {
domEventsRegex: /^onMedia/
});
const CaptionButton = React.forwardRef(
({ children, ...props }, forwardRef) => {
return /* @__PURE__ */ React.createElement(CaptionButtonBridge, { ...props }, (props2) => /* @__PURE__ */ React.createElement(
Primitive.button,
{
...props2,
ref: composeRefs(props2.ref, forwardRef)
},
children
));
}
);
CaptionButton.displayName = "CaptionButton";
const FullscreenButtonBridge = createReactComponent(FullscreenButtonInstance, {
domEventsRegex: /^onMedia/
});
const FullscreenButton = React.forwardRef(
({ children, ...props }, forwardRef) => {
return /* @__PURE__ */ React.createElement(FullscreenButtonBridge, { ...props }, (props2) => /* @__PURE__ */ React.createElement(
Primitive.button,
{
...props2,
ref: composeRefs(props2.ref, forwardRef)
},
children
));
}
);
FullscreenButton.displayName = "FullscreenButton";
const MuteButtonBridge = createReactComponent(MuteButtonInstance, {
domEventsRegex: /^onMedia/
});
const MuteButton = React.forwardRef(
({ children, ...props }, forwardRef) => {
return /* @__PURE__ */ React.createElement(MuteButtonBridge, { ...props }, (props2) => /* @__PURE__ */ React.createElement(
Primitive.button,
{
...props2,
ref: composeRefs(props2.ref, forwardRef)
},
children
));
}
);
MuteButton.displayName = "MuteButton";
const PIPButtonBridge = createReactComponent(PIPButtonInstance, {
domEventsRegex: /^onMedia/
});
const PIPButton = React.forwardRef(
({ children, ...props }, forwardRef) => {
return /* @__PURE__ */ React.createElement(PIPButtonBridge, { ...props }, (props2) => /* @__PURE__ */ React.createElement(
Primitive.button,
{
...props2,
ref: composeRefs(props2.ref, forwardRef)
},
children
));
}
);
PIPButton.displayName = "PIPButton";
const SeekButtonBridge = createReactComponent(SeekButtonInstance, {
domEventsRegex: /^onMedia/
});
const SeekButton = React.forwardRef(
({ children, ...props }, forwardRef) => {
return /* @__PURE__ */ React.createElement(SeekButtonBridge, { ...props }, (props2) => /* @__PURE__ */ React.createElement(
Primitive.button,
{
...props2,
ref: composeRefs(props2.ref, forwardRef)
},
children
));
}
);
SeekButton.displayName = "SeekButton";
const LiveButtonBridge = createReactComponent(LiveButtonInstance, {
domEventsRegex: /^onMedia/
});
const LiveButton = React.forwardRef(
({ children, ...props }, forwardRef) => {
return /* @__PURE__ */ React.createElement(LiveButtonBridge, { ...props }, (props2) => /* @__PURE__ */ React.createElement(
Primitive.button,
{
...props2,
ref: composeRefs(props2.ref, forwardRef)
},
children
));
}
);
LiveButton.displayName = "LiveButton";
const sliderCallbacks = [
"onDragStart",
"onDragEnd",
"onDragValueChange",
"onValueChange",
"onPointerValueChange"
];
const SliderValueBridge = createReactComponent(SliderValueInstance);
const SliderBridge = createReactComponent(SliderInstance, {
events: sliderCallbacks
});
const Root$5 = React.forwardRef(({ children, ...props }, forwardRef) => {
return /* @__PURE__ */ React.createElement(SliderBridge, { ...props, ref: forwardRef }, (props2) => /* @__PURE__ */ React.createElement(Primitive.div, { ...props2 }, children));
});
Root$5.displayName = "Slider";
const Thumb = React.forwardRef((props, forwardRef) => /* @__PURE__ */ React.createElement(Primitive.div, { ...props, ref: forwardRef }));
Thumb.displayName = "SliderThumb";
const Track = React.forwardRef((props, forwardRef) => /* @__PURE__ */ React.createElement(Primitive.div, { ...props, ref: forwardRef }));
Track.displayName = "SliderTrack";
const TrackFill = React.forwardRef((props, forwardRef) => /* @__PURE__ */ React.createElement(Primitive.div, { ...props, ref: forwardRef }));
TrackFill.displayName = "SliderTrackFill";
const PreviewBridge = createReactComponent(SliderPreviewInstance);
const Preview = React.forwardRef(
({ children, ...props }, forwardRef) => {
return /* @__PURE__ */ React.createElement(PreviewBridge, { ...props }, (props2) => /* @__PURE__ */ React.createElement(
Primitive.div,
{
...props2,
ref: composeRefs(props2.ref, forwardRef)
},
children
));
}
);
Preview.displayName = "SliderPreview";
const Value = React.forwardRef(({ children, ...props }, forwardRef) => {
return /* @__PURE__ */ React.createElement(SliderValueBridge, { ...props }, (props2, instance) => {
const $text = useSignal(() => instance.getValueText(), instance);
return /* @__PURE__ */ React.createElement(Primitive.div, { ...props2, ref: forwardRef }, $text, children);
});
});
Value.displayName = "SliderValue";
const Steps = React.forwardRef(({ children, ...props }, forwardRef) => {
const $min = useSliderState("min"), $max = useSliderState("max"), $step = useSliderState("step"), steps = ($max - $min) / $step;
return /* @__PURE__ */ React.createElement(Primitive.div, { ...props, ref: forwardRef }, Array.from({ length: Math.floor(steps) + 1 }).map((_, step) => children(step)));
});
Steps.displayName = "SliderSteps";
var slider = /*#__PURE__*/Object.freeze({
__proto__: null,
Preview: Preview,
Root: Root$5,
Steps: Steps,
Thumb: Thumb,
Track: Track,
TrackFill: TrackFill,
Value: Value
});
const VolumeSliderBridge = createReactComponent(VolumeSliderInstance, {
events: sliderCallbacks,
domEventsRegex: /^onMedia/
});
const Root$4 = React.forwardRef(
({ children, ...props }, forwardRef) => {
return /* @__PURE__ */ React.createElement(VolumeSliderBridge, { ...props, ref: forwardRef }, (props2) => /* @__PURE__ */ React.createElement(Primitive.div, { ...props2 }, children));
}
);
Root$4.displayName = "VolumeSlider";
var volumeSlider = /*#__PURE__*/Object.freeze({
__proto__: null,
Preview: Preview,
Root: Root$4,
Steps: Steps,
Thumb: Thumb,
Track: Track,
TrackFill: TrackFill,
Value: Value
});
function createVTTCue(startTime = 0, endTime = 0, text = "") {
if (IS_SERVER) {
return {
startTime,
endTime,
text,
addEventListener: noop,
removeEventListener: noop,
dispatchEvent: noop
};
}
return new window.VTTCue(startTime, endTime, text);
}
function appendParamsToURL(baseUrl, params) {
const url = new URL(baseUrl);
for (const key of Object.keys(params)) {
url.searchParams.set(key, params[key] + "");
}
return url.toString();
}
const ThumbnailBridge = createReactComponent(ThumbnailInstance);
const Root$3 = React.forwardRef(({ children, ...props }, forwardRef) => {
return /* @__PURE__ */ React.createElement(ThumbnailBridge, { ...props }, (props2) => /* @__PURE__ */ React.createElement(
Primitive.div,
{
...props2,
ref: composeRefs(props2.ref, forwardRef)
},
children
));
});
Root$3.displayName = "Thumbnail";
const Img = React.forwardRef(({ children, ...props }, forwardRef) => {
const { src, img, crossOrigin } = useStateContext(ThumbnailInstance.state), $src = useSignal(src), $crossOrigin = useSignal(crossOrigin);
return /* @__PURE__ */ React.createElement(
Primitive.img,
{
crossOrigin: $crossOrigin,
...props,
src: $src || void 0,
ref: composeRefs(img.set, forwardRef)
},
children
);
});
Img.displayName = "ThumbnailImg";
var thumbnail = /*#__PURE__*/Object.freeze({
__proto__: null,
Img: Img,
Root: Root$3
});
const TimeSliderContext = React.createContext({
$chapters: signal(null)
});
TimeSliderContext.displayName = "TimeSliderContext";
const TimeSliderBridge = createReactComponent(TimeSliderInstance, {
events: sliderCallbacks,
domEventsRegex: /^onMedia/
});
const Root$2 = React.forwardRef(
({ children, ...props }, forwardRef) => {
const $chapters = React.useMemo(() => signal(null), []);
return /* @__PURE__ */ React.createElement(TimeSliderContext.Provider, { value: { $chapters } }, /* @__PURE__ */ React.createElement(TimeSliderBridge, { ...props, ref: forwardRef }, (props2) => /* @__PURE__ */ React.createElement(Primitive.div, { ...props2 }, children)));
}
);
Root$2.displayName = "TimeSlider";
const SliderChaptersBridge = createReactComponent(SliderChaptersInstance);
const Chapters = React.forwardRef(
({ children, ...props }, forwardRef) => {
return /* @__PURE__ */ React.createElement(SliderChaptersBridge, { ...props }, (props2, instance) => /* @__PURE__ */ React.createElement(
Primitive.div,
{
...props2,
ref: composeRefs(props2.ref, forwardRef)
},
/* @__PURE__ */ React.createElement(ChapterTracks, { instance }, children)
));
}
);
Chapters.displayName = "SliderChapters";
function ChapterTracks({ instance, children }) {
const $cues = useSignal(() => instance.cues, instance), refs = React.useRef([]), emptyCue = React.useRef(null), { $chapters } = React.useContext(TimeSliderContext);
if (!emptyCue.current) {
emptyCue.current = createVTTCue();
}
React.useEffect(() => {
$chapters.set(instance);
return () => void $chapters.set(null);
}, [instance]);
React.useEffect(() => {
instance.setRefs(refs.current);
}, [$cues]);
return children($cues.length ? $cues : [emptyCue.current], (el) => {
if (!el) {
refs.current.length = 0;
return;
}
refs.current.push(el);
});
}
ChapterTracks.displayName = "SliderChapterTracks";
const ChapterTitle = React.forwardRef(
({ children, ...props }, forwardRef) => {
const { $chapters } = React.useContext(TimeSliderContext), [title, setTitle] = React.useState();
React.useEffect(() => {
return effect(() => {
const chapters = $chapters(), cue = chapters?.activePointerCue || chapters?.activeCue;
setTitle(cue?.text || "");
});
}, []);
return /* @__PURE__ */ React.createElement(Primitive.div, { ...props, ref: forwardRef }, title, children);
}
);
ChapterTitle.displayName = "SliderChapterTitle";
const Progress = React.forwardRef((props, forwardRef) => /* @__PURE__ */ React.createElement(Primitive.div, { ...props, ref: forwardRef }));
Progress.displayName = "SliderProgress";
const SliderThumbnailBridge = createReactComponent(SliderThumbnailInstance);
const ThumbnailRoot = React.forwardRef(
({ children, ...props }, forwardRef) => {
return /* @__PURE__ */ React.createElement(SliderThumbnailBridge, { ...props }, (props2) => /* @__PURE__ */ React.createElement(Primitive.div, { ...props2, ref: composeRefs(props2.ref, forwardRef) }, children));
}
);
ThumbnailRoot.displayName = "SliderThumbnail";
const Thumbnail = {
Root: ThumbnailRoot,
Img: Img
};
const VideoBridge = createReactComponent(SliderVideoInstance, {
events: ["onCanPlay", "onError"]
});
const Video = React.forwardRef(
({ children, ...props }, forwardRef) => {
return /* @__PURE__ */ React.createElement(VideoBridge, { ...props }, (props2, instance) => /* @__PURE__ */ React.createElement(
VideoProvider,
{
...props2,
instance,
ref: composeRefs(props2.ref, forwardRef)
},
children
));
}
);
Video.displayName = "SliderVideo";
const VideoProvider = React.forwardRef(
({ instance, children, ...props }, forwardRef) => {
const { canLoad } = useStateContext(mediaState), { src, video, crossOrigin } = instance.$state, $src = useSignal(src), $canLoad = useSignal(canLoad), $crossOrigin = useSignal(crossOrigin);
return /* @__PURE__ */ React.createElement(
Primitive.video,
{
style: { maxWidth: "unset" },
...props,
src: $src || void 0,
muted: true,
playsInline: true,
preload: $canLoad ? "auto" : "none",
crossOrigin: $crossOrigin || void 0,
ref: composeRefs(video.set, forwardRef)
},
children
);
}
);
VideoProvider.displayName = "SliderVideoProvider";
var timeSlider = /*#__PURE__*/Object.freeze({
__proto__: null,
ChapterTitle: ChapterTitle,
Chapters: Chapters,
Preview: Preview,
Progress: Progress,
Root: Root$2,
Steps: Steps,
Thumb: Thumb,
Thumbnail: Thumbnail,
Track: Track,
TrackFill: TrackFill,
Value: Value,
Video: Video
});
const RadioGroupBridge = createReactComponent(RadioGroupInstance, {
events: ["onChange"]
});
const Root$1 = React.forwardRef(
({ children, ...props }, forwardRef) => {
return /* @__PURE__ */ React.createElement(RadioGroupBridge, { ...props, ref: forwardRef }, (props2) => /* @__PURE__ */ React.createElement(Primitive.div, { ...props2 }, children));
}
);
Root$1.displayName = "RadioGroup";
const ItemBridge$1 = createReactComponent(RadioInstance, {
events: ["onChange", "onSelect"]
});
const Item$1 = React.forwardRef(({ children, ...props }, forwardRef) => {
return /* @__PURE__ */ React.createElement(ItemBridge$1, { ...props }, (props2) => /* @__PURE__ */ React.createElement(
Primitive.div,
{
...props2,
ref: composeRefs(props2.ref, forwardRef)
},
children
));
});
Item$1.displayName = "RadioItem";
var radioGroup = /*#__PURE__*/Object.freeze({
__proto__: null,
Item: Item$1,
Root: Root$1
});
const MenuBridge = createReactComponent(MenuInstance, {
events: ["onOpen", "onClose"],
domEventsRegex: /^onMedia/
});
const Root = React.forwardRef(({ children, ...props }, forwardRef) => {
return /* @__PURE__ */ React.createElement(MenuBridge, { ...props, ref: forwardRef }, (props2, instance) => /* @__PURE__ */ React.createElement(
Primitive.div,
{
...props2,
style: { display: !instance.isSubmenu ? "contents" : void 0, ...props2.style }
},
children
));
});
Root.displayName = "Menu";
const ButtonBridge = createReactComponent(MenuButtonInstance, {
events: ["onSelect"]
});
const Button = React.forwardRef(
({ children, ...props }, forwardRef) => {
return /* @__PURE__ */ React.createElement(ButtonBridge, { ...props }, (props2) => /* @__PURE__ */ React.createElement(
Primitive.button,
{
...props2,
ref: composeRefs(props2.ref, forwardRef)
},
children
));
}
);
Button.displayName = "MenuButton";
const Portal = React.forwardRef(
({ container = null, disabled = false, children, ...props }, forwardRef) => {
let fullscreen = useMediaState("fullscreen"), shouldPortal = disabled === "fullscreen" ? !fullscreen : !disabled;
const target = React.useMemo(() => {
if (IS_SERVER) return null;
const node = isString(container) ? document.querySelector(container) : container;
return node ?? document.body;
}, [container]);
return !target || !shouldPortal ? children : createPortal(
/* @__PURE__ */ React.createElement(
Primitive.div,
{
...props,
style: { display: "contents", ...props.style },
ref: forwardRef
},
children
),
target
);
}
);
Portal.displayName = "MenuPortal";
const ItemsBridge = createReactComponent(MenuItemsInstance);
const Items = React.forwardRef(({ children, ...props }, forwardRef) => {
return /* @__PURE__ */ React.createElement(ItemsBridge, { ...props }, (props2) => /* @__PURE__ */ React.createElement(
Primitive.div,
{
...props2,
ref: composeRefs(props2.ref, forwardRef)
},
children
));
});
Items.displayName = "MenuItems";
const ItemBridge = createReactComponent(MenuItemInstance);
const Item = React.forwardRef(({ children, ...props }, forwardRef) => {
return /* @__PURE__ */ React.createElement(ItemBridge, { ...props }, (props2) => /* @__PURE__ */ React.createElement(
Primitive.div,
{
...props2,
ref: composeRefs(props2.ref, forwardRef)
},
children
));
});
Item.displayName = "MenuItem";
var menu = /*#__PURE__*/Object.freeze({
__proto__: null,
Button: Button,
Content: Items,
Item: Item,
Items: Items,
Portal: Portal,
Radio: Item$1,
RadioGroup: Root$1,
Root: Root
});
const GestureBridge = createReactComponent(GestureInstance, {
events: ["onWillTrigger", "onTrigger"]
});
const Gesture = React.forwardRef(
({ children, ...props }, forwardRef) => {
return /* @__PURE__ */ React.createElement(GestureBridge, { ...props, ref: forwardRef }, (props2) => /* @__PURE__ */ React.createElement(Primitive.div, { ...props2 }, children));
}
);
Gesture.displayName = "Gesture";
const TimeBridge = createReactComponent(TimeInstance);
const Time = React.forwardRef(({ children, ...props }, forwardRef) => {
return /* @__PURE__ */ React.createElement(TimeBridge, { ...props }, (props2, instance) => /* @__PURE__ */ React.createElement(
TimeText,
{
...props2,
instance,
ref: composeRefs(props2.ref, forwardRef)
},
children
));
});
Time.displayName = "Time";
const TimeText = React.forwardRef(
({ instance, children, ...props }, forwardRef) => {
const { timeText } = instance.$state, $timeText = useSignal(timeText);
return /* @__PURE__ */ React.createElement(Primitive.div, { ...props, ref: forwardRef }, $timeText, children);
}
);
TimeText.displayName = "TimeText";
function useMediaPlayer() {
const context = useMediaContext();
if (!context) {
throw Error(
"[vidstack] no media context was found - was this called outside of `<MediaPlayer>`?"
);
}
return context?.player || null;
}
function useAudioOptions() {
const media = useMediaContext(), { audioTracks, audioTrack } = media.$state, $audioTracks = useSignal(audioTracks);
useSignal(audioTrack);
return React.useMemo(() => {
const options = $audioTracks.map((track) => ({
track,
label: track.label,
value: getTrackValue$1(track),
get selected() {
return audioTrack() === track;
},
select(trigger) {
const index = audioTracks().indexOf(track);
if (index >= 0) media.remote.changeAudioTrack(index, trigger);
}
}));
Object.defineProperty(options, "disabled", {
get() {
return options.length <= 1;
}
});
Object.defineProperty(options, "selectedTrack", {
get() {
return audioTrack();
}
});
Object.defineProperty(options, "selectedValue", {
get() {
const track = audioTrack();
return track ? getTrackValue$1(track) : void 0;
}
});
return options;
}, [$audioTracks]);
}
function getTrackValue$1(track) {
return track.label.toLowerCase();
}
function useCaptionOptions({ off = true } = {}) {
const media = useMediaContext(), { textTracks, textTrack } = media.$state, $textTracks = useSignal(textTracks);
useSignal(textTrack);
return React.useMemo(() => {
const captionTracks = $textTracks.filter(isTrackCaptionKind), options = captionTracks.map((track) => ({
track,
label: track.label,
value: getTrackValue(track),
get selected() {
return textTrack() === track;
},
select(trigger) {
const index = textTracks().indexOf(track);
if (index >= 0) media.remote.changeTextTrackMode(index, "showing", trigger);
}
}));
if (off) {
options.unshift({
track: null,
label: isString(off) ? off : "Off",
value: "off",
get selected() {
return !textTrack();
},
select(trigger) {
media.remote.toggleCaptions(trigger);
}
});
}
Object.defineProperty(options, "disabled", {
get() {
return !captionTracks.length;
}
});
Object.defineProperty(options, "selectedTrack", {
get() {
return textTrack();
}
});
Object.defineProperty(options, "selectedValue", {
get() {
const track = textTrack();
return track ? getTrackValue(track) : "off";
}
});
return options;
}, [$textTracks]);
}
function getTrackValue(track) {
return track.id + ":" + track.kind + "-" + track.label.toLowerCase();
}
export { AirPlayButton, Button, CaptionButton, ChapterTitle, Chapters, FullscreenButton, Gesture, Img, Item$1 as Item, Items, LiveButton, MuteButton, PIPButton, PlayButton, Portal, Preview, Progress, Root$3 as Root, Root$2 as Root$1, Root as Root$2, Root$1 as Root$3, Root$4, Root$5, SeekButton, Steps, Thumb, Thumbnail, Time, Track, TrackFill, Value, appendParamsToURL, menu, radioGroup, slider, sliderCallbacks, thumbnail, timeSlider, useAudioOptions, useCaptionOptions, useMediaContext, useMediaPlayer, volumeSlider };