UNPKG

@7sage/vidstack

Version:

UI component library for building high-quality, accessible video and audio experiences on the web.

169 lines (164 loc) 6.2 kB
import { signal, effect, toggleClass, Host, listenEvent } from '../../chunks/vidstack-Bu2kfzUd.js'; import { DefaultLayout, DefaultAnnouncer, DefaultCaptions, DefaultSeekButton, DefaultPlayButton, DefaultTimeSlider, DefaultTimeInvert, DefaultVolumePopup, DefaultCaptionButton, DefaultDownloadButton, DefaultAirPlayButton, DefaultChaptersMenu, DefaultSettingsMenu, useDefaultLayoutContext, DefaultControlsSpacer, i18n, DefaultChapterTitle, setLayoutName, createMenuContainer, DefaultLayoutIconsLoader } from '../../chunks/vidstack-DBy9lvwr.js'; import { useMediaContext, useMediaState } from '../../chunks/vidstack-DFImIcIL.js'; import { useTransitionActive, useResizeObserver, isHTMLElement } from '../../chunks/vidstack-C_l97D5j.js'; import { $signal, SlotManager } from '../../chunks/vidstack-Bcmx8pmK.js'; import { LitElement } from '../../chunks/vidstack-CwTj4H1w.js'; import { html } from 'lit-html'; import { ref } from 'lit-html/directives/ref.js'; import '../../chunks/vidstack-28cU2iGK.js'; import '../../chunks/vidstack-BTM4ERc7.js'; import 'lit-html/directives/if-defined.js'; import '../../chunks/vidstack-zG6PIeGg.js'; import '../../chunks/vidstack-CjhKISI0.js'; import '@floating-ui/dom'; import 'lit-html/directives/unsafe-svg.js'; import 'lit-html/async-directive.js'; let DefaultAudioLayout$1 = class DefaultAudioLayout extends DefaultLayout { static props = { ...super.props, when: ({ viewType }) => viewType === "audio", smallWhen: ({ width }) => width < 576 }; }; function DefaultAudioLayout() { return [ DefaultAnnouncer(), DefaultCaptions(), html` <media-controls class="vds-controls"> <media-controls-group class="vds-controls-group"> ${[ DefaultSeekButton({ backward: true, tooltip: "top start" }), DefaultPlayButton({ tooltip: "top" }), DefaultSeekButton({ tooltip: "top" }), DefaultAudioTitle(), DefaultTimeSlider(), DefaultTimeInvert(), DefaultVolumePopup({ orientation: "vertical", tooltip: "top" }), DefaultCaptionButton({ tooltip: "top" }), DefaultDownloadButton(), DefaultAirPlayButton({ tooltip: "top" }), DefaultAudioMenus() ]} </media-controls-group> </media-controls> ` ]; } function DefaultAudioTitle() { return $signal(() => { let $ref = signal(void 0), $isTextOverflowing = signal(false), media = useMediaContext(), { title, started, currentTime, ended } = useMediaState(), { translations } = useDefaultLayoutContext(), $isTransitionActive = useTransitionActive($ref), $isContinued = () => started() || currentTime() > 0; const $title = () => { const word = ended() ? "Replay" : $isContinued() ? "Continue" : "Play"; return `${i18n(translations, word)}: ${title()}`; }; effect(() => { if ($isTransitionActive() && document.activeElement === document.body) { media.player.el?.focus({ preventScroll: true }); } }); function onResize() { const el = $ref(), isOverflowing = !!el && !$isTransitionActive() && el.clientWidth < el.children[0].clientWidth; el && toggleClass(el, "vds-marquee", isOverflowing); $isTextOverflowing.set(isOverflowing); } function Title() { return html` <span class="vds-title-text"> ${$signal($title)}${$signal(() => $isContinued() ? DefaultChapterTitle() : null)} </span> `; } useResizeObserver($ref, onResize); return title() ? html` <span class="vds-title" title=${$signal($title)} ${ref($ref.set)}> ${[ Title(), $signal(() => $isTextOverflowing() && !$isTransitionActive() ? Title() : null) ]} </span> ` : DefaultControlsSpacer(); }); } function DefaultAudioMenus() { const placement = "top end"; return [ DefaultChaptersMenu({ tooltip: "top", placement, portal: true }), DefaultSettingsMenu({ tooltip: "top end", placement, portal: true }) ]; } class MediaAudioLayoutElement extends Host(LitElement, DefaultAudioLayout$1) { static tagName = "media-audio-layout"; static attrs = { smallWhen: { converter(value) { return value !== "never" && !!value; } } }; #media; #scrubbing = signal(false); onSetup() { this.forwardKeepAlive = false; this.#media = useMediaContext(); this.classList.add("vds-audio-layout"); this.#setupWatchScrubbing(); } onConnect() { setLayoutName("audio", () => this.isMatch); this.#setupMenuContainer(); } render() { return $signal(this.#render.bind(this)); } #render() { return this.isMatch ? DefaultAudioLayout() : null; } #setupMenuContainer() { const { menuPortal } = useDefaultLayoutContext(); effect(() => { if (!this.isMatch) return; const container = createMenuContainer( this, this.menuContainer, "vds-audio-layout", () => this.isSmallLayout ), roots = container ? [this, container] : [this]; const iconsManager = this.$props.customIcons() ? new SlotManager(roots) : new DefaultLayoutIconsLoader(roots); iconsManager.connect(); menuPortal.set(container); return () => { container.remove(); menuPortal.set(null); }; }); } #setupWatchScrubbing() { const { pointer } = this.#media.$state; effect(() => { if (pointer() !== "coarse") return; effect(this.#watchScrubbing.bind(this)); }); } #watchScrubbing() { if (!this.#scrubbing()) { listenEvent(this, "pointerdown", this.#onStartScrubbing.bind(this), { capture: true }); return; } listenEvent(this, "pointerdown", (e) => e.stopPropagation()); listenEvent(window, "pointerdown", this.#onStopScrubbing.bind(this)); } #onStartScrubbing(event) { const { target } = event, hasTimeSlider = !!(isHTMLElement(target) && target.closest(".vds-time-slider")); if (!hasTimeSlider) return; event.stopImmediatePropagation(); this.setAttribute("data-scrubbing", ""); this.#scrubbing.set(true); } #onStopScrubbing() { this.#scrubbing.set(false); this.removeAttribute("data-scrubbing"); } } export { MediaAudioLayoutElement };