"use client"; import { useTranslator } from "../../i18n/context.js"; import { usePlayer } from "../../player/context.js"; import { renderElement } from "../../utils/use-render.js"; import { useButton } from "../hooks/use-button.js"; import { useOptionalTooltipContext } from "../tooltip/context.js"; import { logMissingFeature, selectBuffer, selectLive, selectTime } from "@videojs/core/dom"; import { translateText } from "@videojs/core/i18n"; import { forwardRef, useLayoutEffect, useState } from "react"; import { LiveButtonCore, LiveButtonDataAttrs } from "@videojs/core"; //#region src/ui/live-button/live-button.tsx const DISPLAY_NAME = "LiveButton"; /** * A button that indicates live status and seeks to the live edge when * pressed. Exposes `data-live` while the stream is live (or DVR) and * `data-live-edge` while playing at the live edge so skins can style a * red-dot ↔ grey-dot treatment. * * Selects from `live`, `time`, and `buffer` features and composes them * itself rather than going through `createMediaButton`, since the LiveButton * needs three feature slices to detect the live edge and seek. * * Displays the translated live badge when no children are provided. * * @example * ```tsx * * ``` * * @see https://github.com/video-dev/media-ui-extensions/blob/main/proposals/0007-live-edge.md */ const LiveButton = forwardRef(function LiveButton(componentProps, forwardedRef) { const { children, render, className, style, label, disabled, ...elementProps } = componentProps; const live = usePlayer(selectLive); const time = usePlayer(selectTime); const buffer = usePlayer(selectBuffer); const media = live && time && buffer ? { currentTime: time.currentTime, seek: time.seek, seekable: buffer.seekable, liveEdgeStart: live.liveEdgeStart, targetLiveWindow: live.targetLiveWindow } : null; const tooltipCtx = useOptionalTooltipContext(); const translator = useTranslator(); const [core] = useState(() => new LiveButtonCore()); core.setProps({ label, disabled }); const { getButtonProps, buttonRef } = useButton({ displayName: DISPLAY_NAME, onActivate: () => { if (media) core.seekToLive(media); }, isDisabled: () => !!disabled || !media }); if (media) core.setMedia(media); const state = media ? core.getState() : null; const labelText = state ? translateText(core.getLabel(state), translator) : void 0; useLayoutEffect(() => { if (!tooltipCtx) return; tooltipCtx.setContent(labelText ? { label: labelText } : void 0); return () => tooltipCtx.setContent(void 0); }, [tooltipCtx, labelText]); if (!media || !state) { logMissingFeature(DISPLAY_NAME, selectLive.displayName ?? "live"); return null; } const attrs = core.getAttrs(state); const labelAttr = attrs["aria-label"]; const content = children ?? translateText(LiveButtonCore.defaultText, translator); return renderElement("button", { render, className, style }, { state, stateAttrMap: LiveButtonDataAttrs, ref: [forwardedRef, buttonRef], props: [ attrs, { children: content, ...elementProps, "aria-label": labelAttr ? translateText(labelAttr, translator) : labelAttr }, getButtonProps() ] }); }); LiveButton.displayName = DISPLAY_NAME; //#endregion export { LiveButton }; //# sourceMappingURL=live-button.js.map