@aidenlx/vidstack-react
Version:
UI component library for building high-quality, accessible video and audio experiences on the web.
192 lines (185 loc) • 6.08 kB
JavaScript
"use client"
import * as React from 'react';
import { RadioGroupController, useMediaContext, menuContext, MediaRemoteControl, MediaPlayerInstance, sortVideoQualities } from './vidstack-CkT8sP15.js';
import { useMediaContext as useMediaContext$1 } from './vidstack-p9VvwQcz.js';
import { useSignal } from 'maverick.js/react';
import { isString } from 'maverick.js/std';
import { prop, method, Component, hasProvidedContext, useContext, effect } from 'maverick.js';
const DEFAULT_PLAYBACK_RATES = [0.25, 0.5, 0.75, 1, 1.25, 1.5, 1.75, 2];
class SpeedRadioGroup extends Component {
static props = {
normalLabel: "Normal",
rates: DEFAULT_PLAYBACK_RATES
};
#media;
#menu;
#controller;
get value() {
return this.#controller.value;
}
get disabled() {
const { rates } = this.$props, { canSetPlaybackRate } = this.#media.$state;
return !canSetPlaybackRate() || rates().length === 0;
}
constructor() {
super();
this.#controller = new RadioGroupController();
this.#controller.onValueChange = this.#onValueChange.bind(this);
}
onSetup() {
this.#media = useMediaContext();
if (hasProvidedContext(menuContext)) {
this.#menu = useContext(menuContext);
}
}
onConnect(el) {
effect(this.#watchValue.bind(this));
effect(this.#watchHintText.bind(this));
effect(this.#watchControllerDisabled.bind(this));
}
getOptions() {
const { rates, normalLabel } = this.$props;
return rates().map((rate) => ({
label: rate === 1 ? normalLabel : rate + "\xD7",
value: rate.toString()
}));
}
#watchValue() {
this.#controller.value = this.#getValue();
}
#watchHintText() {
const { normalLabel } = this.$props, { playbackRate } = this.#media.$state, rate = playbackRate();
this.#menu?.hint.set(rate === 1 ? normalLabel() : rate + "\xD7");
}
#watchControllerDisabled() {
this.#menu?.disable(this.disabled);
}
#getValue() {
const { playbackRate } = this.#media.$state;
return playbackRate().toString();
}
#onValueChange(value, trigger) {
if (this.disabled) return;
const rate = +value;
this.#media.remote.changePlaybackRate(rate, trigger);
this.dispatch("change", { detail: rate, trigger });
}
}
const speedradiogroup__proto = SpeedRadioGroup.prototype;
prop(speedradiogroup__proto, "value");
prop(speedradiogroup__proto, "disabled");
method(speedradiogroup__proto, "getOptions");
function useMediaRemote(target) {
const media = useMediaContext$1(), remote = React.useRef(null);
if (!remote.current) {
remote.current = new MediaRemoteControl();
}
React.useEffect(() => {
const ref = target && "current" in target ? target.current : target, isPlayerRef = ref instanceof MediaPlayerInstance, player = isPlayerRef ? ref : media?.player;
remote.current.setPlayer(player ?? null);
remote.current.setTarget(ref ?? null);
}, [media, target && "current" in target ? target.current : target]);
return remote.current;
}
function useVideoQualityOptions({
auto = true,
sort = "descending"
} = {}) {
const media = useMediaContext$1(), { qualities, quality, autoQuality, canSetQuality } = media.$state, $qualities = useSignal(qualities);
useSignal(quality);
useSignal(autoQuality);
useSignal(canSetQuality);
return React.useMemo(() => {
const sortedQualities = sortVideoQualities($qualities, sort === "descending"), options = sortedQualities.map((q) => {
return {
quality: q,
label: q.height + "p",
value: getQualityValue(q),
bitrateText: q.bitrate && q.bitrate > 0 ? `${(q.bitrate / 1e6).toFixed(2)} Mbps` : null,
get selected() {
return q === quality();
},
get autoSelected() {
return autoQuality();
},
select(trigger) {
const index = qualities().indexOf(q);
if (index >= 0) media.remote.changeQuality(index, trigger);
}
};
});
if (auto) {
options.unshift({
quality: null,
label: isString(auto) ? auto : "Auto",
value: "auto",
bitrateText: null,
get selected() {
return autoQuality();
},
get autoSelected() {
return autoQuality();
},
select(trigger) {
media.remote.requestAutoQuality(trigger);
}
});
}
Object.defineProperty(options, "disabled", {
get() {
return !canSetQuality() || $qualities.length <= 1;
}
});
Object.defineProperty(options, "selectedQuality", {
get() {
return quality();
}
});
Object.defineProperty(options, "selectedValue", {
get() {
const $quality = quality();
return !autoQuality() && $quality ? getQualityValue($quality) : "auto";
}
});
return options;
}, [$qualities, sort]);
}
function getQualityValue(quality) {
return quality.height + "_" + quality.bitrate;
}
function usePlaybackRateOptions({
rates = DEFAULT_PLAYBACK_RATES,
normalLabel = "Normal"
} = {}) {
const media = useMediaContext$1(), { playbackRate, canSetPlaybackRate } = media.$state;
useSignal(playbackRate);
useSignal(canSetPlaybackRate);
return React.useMemo(() => {
const options = rates.map((opt) => {
const label = typeof opt === "number" ? opt === 1 && normalLabel ? normalLabel : opt + "x" : opt.label, rate = typeof opt === "number" ? opt : opt.rate;
return {
label,
value: rate.toString(),
rate,
get selected() {
return playbackRate() === rate;
},
select(trigger) {
media.remote.changePlaybackRate(rate, trigger);
}
};
});
Object.defineProperty(options, "disabled", {
get() {
return !canSetPlaybackRate() || !options.length;
}
});
Object.defineProperty(options, "selectedValue", {
get() {
return playbackRate().toString();
}
});
return options;
}, [rates]);
}
export { DEFAULT_PLAYBACK_RATES, useMediaRemote, usePlaybackRateOptions, useVideoQualityOptions };