UNPKG

@livepeer/react

Version:

React primitives for video apps.

1,113 lines (1,088 loc) 36.1 kB
"use client"; // src/broadcast/AudioEnabled.tsx import { composeEventHandlers } from "@radix-ui/primitive"; import { Presence } from "@radix-ui/react-presence"; import React2, { useMemo } from "react"; import { useStore } from "zustand"; import { useShallow } from "zustand/react/shallow"; // src/shared/primitive.tsx import { Slot } from "@radix-ui/react-slot"; import * as React from "react"; import * as ReactDOM from "react-dom"; var NODES = [ "a", "audio", "button", "div", "form", "h2", "h3", "img", "input", "label", "li", "nav", "ol", "p", "span", "svg", "ul", "video" ]; var Primitive = NODES.reduce((primitive, node) => { const Node = React.forwardRef( // biome-ignore lint/suspicious/noExplicitAny: any (props, forwardedRef) => { const { asChild, ...primitiveProps } = props; const Comp = asChild ? Slot : node; React.useEffect(() => { window[Symbol.for("radix-ui")] = true; }, []); return /* @__PURE__ */ React.createElement(Comp, { ...primitiveProps, ref: forwardedRef }); } ); Node.displayName = `Primitive.${node}`; return { ...primitive, [node]: Node }; }, {}); // src/shared/utils.ts var noPropagate = (cb) => (event) => { event.stopPropagation(); return cb(); }; // src/broadcast/context.tsx import { createContextScope } from "@radix-ui/react-context"; var MEDIA_NAME = "Broadcast"; var [createBroadcastContext, createBroadcastScope] = createContextScope(MEDIA_NAME); var [BroadcastProvider, useBroadcastContext] = createBroadcastContext(MEDIA_NAME); // src/broadcast/AudioEnabled.tsx var AUDIO_ENABLED_TRIGGER_NAME = "AudioEnabledTrigger"; var AudioEnabledTrigger = React2.forwardRef((props, forwardedRef) => { const { __scopeBroadcast, ...audioEnabledProps } = props; const broadcastContext = useBroadcastContext( AUDIO_ENABLED_TRIGGER_NAME, __scopeBroadcast ); const { audio, title, toggleAudio } = useStore( broadcastContext.store, useShallow(({ audio: audio2, aria, __controlsFunctions }) => ({ audio: audio2, title: aria.audioTrigger, toggleAudio: __controlsFunctions.toggleAudio })) ); return /* @__PURE__ */ React2.createElement( Primitive.button, { type: "button", "aria-pressed": audio, "aria-label": title, title, ...audioEnabledProps, onClick: composeEventHandlers(props.onClick, noPropagate(toggleAudio)), ref: forwardedRef, "data-livepeer-controls-audio-enabled-trigger": "", "data-enabled": String(audio) } ); }); AudioEnabledTrigger.displayName = AUDIO_ENABLED_TRIGGER_NAME; var AUDIO_ENABLED_INDICATOR_NAME = "AudioEnabledIndicator"; var AudioEnabledIndicator = React2.forwardRef((props, forwardedRef) => { const { __scopeBroadcast, forceMount, matcher = true, ...audioIndicatorProps } = props; const broadcastContext = useBroadcastContext( AUDIO_ENABLED_INDICATOR_NAME, __scopeBroadcast ); const audio = useStore(broadcastContext.store, ({ audio: audio2 }) => audio2); const isPresent = useMemo( () => typeof matcher === "boolean" ? matcher === audio : matcher(audio), [audio, matcher] ); return /* @__PURE__ */ React2.createElement(Presence, { present: forceMount || isPresent }, /* @__PURE__ */ React2.createElement( Primitive.div, { ...audioIndicatorProps, ref: forwardedRef, "data-livepeer-controls-audio-enabled-indicator": "", "data-enabled": String(audio), "data-visible": String(isPresent) } )); }); AudioEnabledIndicator.displayName = AUDIO_ENABLED_INDICATOR_NAME; // src/broadcast/Broadcast.tsx import { addLegacyMediaMetricsToStore, addMetricsToStore, createControllerStore } from "@livepeer/core/media"; import { createStorage, noopStorage } from "@livepeer/core/storage"; import { version } from "@livepeer/core/version"; import { createBroadcastStore, getBroadcastDeviceInfo } from "@livepeer/core-web/broadcast"; import { getDeviceInfo } from "@livepeer/core-web/browser"; import React3, { useEffect as useEffect2, useRef } from "react"; // src/shared/context.tsx import { createContextScope as createContextScope2 } from "@radix-ui/react-context"; import { useStore as useStoreZustand } from "zustand"; var MEDIA_NAME2 = "Media"; var [createMediaContext, createMediaScope] = createContextScope2(MEDIA_NAME2); var [MediaProvider, useMediaContext] = createMediaContext(MEDIA_NAME2); var useStore2 = useStoreZustand; // src/broadcast/Broadcast.tsx var Broadcast = (props) => { const { aspectRatio = 16 / 9, children, ingestUrl, onError, storage, timeout, videoQuality, onPlaybackEvents, metricsInterval, ...rest } = props; const mediaStore = useRef( createControllerStore({ device: getDeviceInfo(version.react), storage: storage ?? createStorage( storage !== null && typeof window !== "undefined" ? { storage: window.localStorage } : { storage: noopStorage } ), src: null, initialProps: { hotkeys: "broadcast", aspectRatio, volume: 0, onError, timeout, videoQuality } }) ); const broadcastStore = useRef( createBroadcastStore({ device: getBroadcastDeviceInfo(version.react), storage: storage ?? createStorage( storage !== null && typeof window !== "undefined" ? { storage: window.localStorage } : { storage: noopStorage } ), ingestUrl, initialProps: { aspectRatio, ...rest } }) ); useEffect2(() => { return () => { mediaStore?.current?.destroy?.(); broadcastStore?.current?.destroy?.(); }; }, []); useEffect2(() => { if (ingestUrl) { broadcastStore.current.store.getState().__controlsFunctions.setIngestUrl(ingestUrl); } }, [ingestUrl]); useEffect2(() => { const metrics = addLegacyMediaMetricsToStore(mediaStore.current.store); return () => { metrics.destroy(); }; }, []); useEffect2(() => { const metrics = addMetricsToStore(mediaStore.current.store, { onPlaybackEvents, interval: metricsInterval }); return () => { metrics.destroy(); }; }, []); return /* @__PURE__ */ React3.createElement(MediaProvider, { store: mediaStore.current.store, scope: props.__scopeMedia }, /* @__PURE__ */ React3.createElement( BroadcastProvider, { store: broadcastStore.current.store, scope: props.__scopeBroadcast }, children )); }; Broadcast.displayName = "Broadcast"; var Root = Broadcast; // src/broadcast/Controls.tsx import { Presence as Presence2 } from "@radix-ui/react-presence"; import React4, { useEffect as useEffect3, useMemo as useMemo2 } from "react"; import { useStore as useStore3 } from "zustand"; import { useShallow as useShallow2 } from "zustand/react/shallow"; var CONTROLS_NAME = "Controls"; var Controls = React4.forwardRef( (props, forwardedRef) => { const { forceMount, __scopeMedia, __scopeBroadcast, // biome-ignore lint/correctness/noUnusedVariables: ignored using `--suppress` onClick, style, autoHide, ...controlsProps } = props; const context = useMediaContext(CONTROLS_NAME, __scopeMedia); const { hidden, loading, error } = useStore3( context.store, useShallow2(({ hidden: hidden2, loading: loading2, error: error2 }) => ({ hidden: hidden2, loading: loading2, error: error2?.type ?? null })) ); const broadcastContext = useBroadcastContext( CONTROLS_NAME, __scopeBroadcast ); const { isWebRTCSupported } = useStore3( broadcastContext.store, useShallow2(({ enabled, __device }) => ({ enabled, isWebRTCSupported: __device.isMediaDevicesSupported })) ); const shown = useMemo2( () => !hidden && !loading && !error && isWebRTCSupported, [hidden, loading, error, isWebRTCSupported] ); useEffect3(() => { if (autoHide !== void 0) { context.store.getState().__controlsFunctions.setAutohide(autoHide); } }, []); return /* @__PURE__ */ React4.createElement(Presence2, { present: forceMount || shown }, /* @__PURE__ */ React4.createElement( Primitive.div, { ...controlsProps, ref: forwardedRef, "data-livepeer-controls": "", "data-visible": String(shown), style: { ...style, // ensures controls expands in ratio position: "absolute", top: 0, right: 0, bottom: 0, left: 0 } } )); } ); Controls.displayName = CONTROLS_NAME; // src/broadcast/Enabled.tsx import { composeEventHandlers as composeEventHandlers2 } from "@radix-ui/primitive"; import { Presence as Presence3 } from "@radix-ui/react-presence"; import React5, { useMemo as useMemo3 } from "react"; import { useStore as useStore4 } from "zustand"; import { useShallow as useShallow3 } from "zustand/react/shallow"; var ENABLED_TRIGGER_NAME = "EnabledTrigger"; var EnabledTrigger = React5.forwardRef((props, forwardedRef) => { const { __scopeBroadcast, ...playProps } = props; const broadcastContext = useBroadcastContext( ENABLED_TRIGGER_NAME, __scopeBroadcast ); const { enabled, title, toggleEnabled } = useStore4( broadcastContext.store, useShallow3(({ enabled: enabled2, aria, __controlsFunctions }) => ({ enabled: enabled2, title: aria.start, toggleEnabled: __controlsFunctions.toggleEnabled })) ); return /* @__PURE__ */ React5.createElement( Primitive.button, { type: "button", "aria-pressed": enabled, "aria-label": title, title, ...playProps, onClick: composeEventHandlers2(props.onClick, noPropagate(toggleEnabled)), ref: forwardedRef, "data-livepeer-controls-enabled-trigger": "", "data-enabled": String(enabled) } ); }); EnabledTrigger.displayName = ENABLED_TRIGGER_NAME; var ENABLED_INDICATOR_NAME = "EnabledIndicator"; var EnabledIndicator = React5.forwardRef( (props, forwardedRef) => { const { __scopeBroadcast, __scopeMedia, forceMount, matcher = true, ...playPauseIndicatorProps } = props; const context = useMediaContext(ENABLED_INDICATOR_NAME, __scopeMedia); const loading = useStore4(context.store, ({ loading: loading2 }) => loading2); const broadcastContext = useBroadcastContext( ENABLED_INDICATOR_NAME, __scopeBroadcast ); const enabled = useStore4(broadcastContext.store, ({ enabled: enabled2 }) => enabled2); const isPresent = useMemo3( () => !loading && (typeof matcher === "boolean" ? matcher === enabled : matcher(enabled)), [enabled, matcher, loading] ); return /* @__PURE__ */ React5.createElement(Presence3, { present: forceMount || isPresent }, /* @__PURE__ */ React5.createElement( Primitive.div, { ...playPauseIndicatorProps, ref: forwardedRef, "data-livepeer-controls-enabled-indicator": "", "data-enabled": String(enabled), "data-visible": String(isPresent) } )); } ); EnabledIndicator.displayName = ENABLED_INDICATOR_NAME; // src/broadcast/Screenshare.tsx import { composeEventHandlers as composeEventHandlers3 } from "@radix-ui/primitive"; import { Presence as Presence4 } from "@radix-ui/react-presence"; import React6, { useMemo as useMemo4 } from "react"; import { useStore as useStore5 } from "zustand"; import { useShallow as useShallow4 } from "zustand/react/shallow"; var SCREENSHARE_TRIGGER_NAME = "ScreenshareTrigger"; var ScreenshareTrigger = React6.forwardRef((props, forwardedRef) => { const { __scopeBroadcast, forceMount, ...screenshareProps } = props; const broadcastContext = useBroadcastContext( SCREENSHARE_TRIGGER_NAME, __scopeBroadcast ); const { isSupported, isActive, title, toggleDisplayMedia } = useStore5( broadcastContext.store, useShallow4(({ mediaDeviceIds, aria, __device, __controlsFunctions }) => ({ isActive: mediaDeviceIds.videoinput === "screen", title: aria.screenshareTrigger, toggleDisplayMedia: __controlsFunctions.toggleDisplayMedia, isSupported: __device.isDisplayMediaSupported })) ); return /* @__PURE__ */ React6.createElement(Presence4, { present: forceMount || isSupported }, /* @__PURE__ */ React6.createElement( Primitive.button, { type: "button", "aria-pressed": isActive, "aria-label": title, title, ...screenshareProps, onClick: composeEventHandlers3( props.onClick, noPropagate(toggleDisplayMedia) ), ref: forwardedRef, "data-livepeer-controls-screenshare-trigger": "", "data-active": String(isActive), "data-visible": String(isSupported) } )); }); ScreenshareTrigger.displayName = SCREENSHARE_TRIGGER_NAME; var SCREENSHARE_INDICATOR_NAME = "ScreenshareIndicator"; var ScreenshareIndicator = React6.forwardRef((props, forwardedRef) => { const { __scopeBroadcast, forceMount, matcher = true, ...audioIndicatorProps } = props; const broadcastContext = useBroadcastContext( SCREENSHARE_INDICATOR_NAME, __scopeBroadcast ); const { isActive, isSupported } = useStore5( broadcastContext.store, ({ mediaDeviceIds, __device }) => ({ isActive: mediaDeviceIds.videoinput === "screen", isSupported: __device.isDisplayMediaSupported }) ); const isPresent = useMemo4( () => isSupported ? typeof matcher === "boolean" ? matcher === isActive : matcher(isActive) : false, [isSupported, isActive, matcher] ); return /* @__PURE__ */ React6.createElement(Presence4, { present: forceMount || isPresent }, /* @__PURE__ */ React6.createElement( Primitive.div, { ...audioIndicatorProps, ref: forwardedRef, "data-livepeer-controls-screenshare-indicator": "", "data-active": String(isActive), "data-visible": String(isPresent) } )); }); ScreenshareIndicator.displayName = SCREENSHARE_INDICATOR_NAME; // src/broadcast/SourceSelect.tsx import { Presence as Presence5 } from "@radix-ui/react-presence"; import React7, { useCallback } from "react"; import { useStore as useStore6 } from "zustand"; import { useShallow as useShallow5 } from "zustand/react/shallow"; // src/shared/Select.tsx import * as SelectPrimitive from "@radix-ui/react-select"; var SelectRoot = SelectPrimitive.Root; var SelectTrigger2 = SelectPrimitive.SelectTrigger; var SelectValue2 = SelectPrimitive.SelectValue; var SelectIcon2 = SelectPrimitive.SelectIcon; var SelectPortal2 = SelectPrimitive.SelectPortal; var SelectContent2 = SelectPrimitive.SelectContent; var SelectViewport2 = SelectPrimitive.SelectViewport; var SelectGroup2 = SelectPrimitive.SelectGroup; var SelectLabel2 = SelectPrimitive.SelectLabel; var SelectItem2 = SelectPrimitive.SelectItem; var SelectItemText2 = SelectPrimitive.SelectItemText; var SelectItemIndicator2 = SelectPrimitive.SelectItemIndicator; var SelectScrollUpButton2 = SelectPrimitive.SelectScrollUpButton; var SelectScrollDownButton2 = SelectPrimitive.SelectScrollDownButton; var SelectSeparator2 = SelectPrimitive.SelectSeparator; var SelectArrow2 = SelectPrimitive.SelectArrow; // src/broadcast/SourceSelect.tsx var SOURCE_SELECT_NAME = "SourceSelect"; var SourceSelect = (props) => { const { __scopeMedia, __scopeBroadcast, forceMount, type, children, ...controlsProps } = props; const broadcastContext = useBroadcastContext( SOURCE_SELECT_NAME, __scopeBroadcast ); const { video, audio, mediaDevices, isSupported, mediaDeviceIds, requestMediaDeviceId } = useStore6( broadcastContext.store, useShallow5( ({ video: video2, audio: audio2, mediaDevices: mediaDevices2, __device, mediaDeviceIds: mediaDeviceIds2, __controlsFunctions }) => ({ video: video2, audio: audio2, mediaDevices: mediaDevices2?.filter((d) => d.kind === type) ?? null, isSupported: __device.isMediaDevicesSupported, requestMediaDeviceId: __controlsFunctions.requestMediaDeviceId, mediaDeviceIds: mediaDeviceIds2 }) ) ); const setMediaDeviceIdComposed = useCallback( (deviceId) => { requestMediaDeviceId(deviceId, type); }, [requestMediaDeviceId, type] ); const handleValueChange = useCallback( (value) => { if (props.onValueChange) { props.onValueChange(value); } setMediaDeviceIdComposed(value); }, [props.onValueChange, setMediaDeviceIdComposed] ); return /* @__PURE__ */ React7.createElement(Presence5, { present: forceMount || isSupported }, /* @__PURE__ */ React7.createElement( SelectRoot, { disabled: type === "audioinput" ? !audio : !video, ...controlsProps, value: mediaDeviceIds[type] ?? void 0, onValueChange: handleValueChange, "data-livepeer-source-select": "", "data-type": type, "data-visible": String(isSupported) }, children(mediaDevices) )); }; SourceSelect.displayName = SOURCE_SELECT_NAME; // src/broadcast/StatusIndicator.tsx import { Presence as Presence6 } from "@radix-ui/react-presence"; import React8, { useMemo as useMemo5 } from "react"; import { useStore as useStore7 } from "zustand"; var STATUS_INDICATOR_NAME = "StatusIndicator"; var StatusIndicator = React8.forwardRef((props, forwardedRef) => { const { __scopeBroadcast, forceMount, matcher = true, ...statusIndicatorProps } = props; const broadcastContext = useBroadcastContext( STATUS_INDICATOR_NAME, __scopeBroadcast ); const status = useStore7(broadcastContext.store, ({ status: status2 }) => status2); const isPresent = useMemo5( () => typeof matcher === "function" ? matcher(status) : matcher === status, [matcher, status] ); return /* @__PURE__ */ React8.createElement(Presence6, { present: forceMount || isPresent }, /* @__PURE__ */ React8.createElement( Primitive.span, { "aria-label": status, ...statusIndicatorProps, ref: forwardedRef, "data-livepeer-controls-status-indicator": "", "data-status": String(status), "data-visible": String(isPresent) } )); }); StatusIndicator.displayName = STATUS_INDICATOR_NAME; // src/broadcast/Video.tsx import { addBroadcastEventListeners } from "@livepeer/core-web/broadcast"; import { addEventListeners } from "@livepeer/core-web/browser"; import { useComposedRefs } from "@radix-ui/react-compose-refs"; import React9, { useEffect as useEffect4 } from "react"; import { useStore as useStore8 } from "zustand"; var VIDEO_NAME = "Video"; var Video = React9.forwardRef( (props, forwardedRef) => { const { __scopeMedia, __scopeBroadcast, style, muted = true, ...broadcastProps } = props; const context = useMediaContext(VIDEO_NAME, __scopeMedia); const broadcastContext = useBroadcastContext(VIDEO_NAME, __scopeBroadcast); const ref = React9.useRef(null); const composedRefs = useComposedRefs(forwardedRef, ref); const isEnabled = useStore8( broadcastContext.store, ({ enabled }) => enabled ); useEffect4(() => { if (ref.current) { const { destroy } = addEventListeners(ref.current, context.store); return destroy; } }, [context?.store]); useEffect4(() => { if (ref.current) { const { destroy } = addBroadcastEventListeners( ref.current, broadcastContext.store, context.store ); return destroy; } }, []); React9.useEffect(() => { context.store.getState().__controlsFunctions.setMounted(); }, []); return /* @__PURE__ */ React9.createElement( Primitive.video, { playsInline: true, muted, ...broadcastProps, ref: composedRefs, "data-livepeer-video": "", "data-enabled": Boolean(isEnabled), style: { ...style, // ensures video expands in ratio position: "absolute", top: 0, right: 0, bottom: 0, left: 0 } } ); } ); Video.displayName = VIDEO_NAME; // src/broadcast/VideoEnabled.tsx import { composeEventHandlers as composeEventHandlers4 } from "@radix-ui/primitive"; import { Presence as Presence7 } from "@radix-ui/react-presence"; import React10, { useMemo as useMemo6 } from "react"; import { useStore as useStore9 } from "zustand"; import { useShallow as useShallow6 } from "zustand/react/shallow"; var VIDEO_ENABLED_TRIGGER_NAME = "VideoEnabledTrigger"; var VideoEnabledTrigger = React10.forwardRef((props, forwardedRef) => { const { __scopeBroadcast, ...videoEnabledProps } = props; const broadcastContext = useBroadcastContext( VIDEO_ENABLED_TRIGGER_NAME, __scopeBroadcast ); const { video, title, toggleVideo } = useStore9( broadcastContext.store, useShallow6(({ video: video2, aria, __controlsFunctions }) => ({ video: video2, title: aria.videoTrigger, toggleVideo: __controlsFunctions.toggleVideo })) ); return /* @__PURE__ */ React10.createElement( Primitive.button, { type: "button", "aria-pressed": video, "aria-label": title, title, ...videoEnabledProps, onClick: composeEventHandlers4(props.onClick, noPropagate(toggleVideo)), ref: forwardedRef, "data-livepeer-controls-video-enabled-trigger": "", "data-enabled": String(video) } ); }); VideoEnabledTrigger.displayName = VIDEO_ENABLED_TRIGGER_NAME; var VIDEO_ENABLED_INDICATOR_NAME = "VideoEnabledIndicator"; var VideoEnabledIndicator = React10.forwardRef((props, forwardedRef) => { const { __scopeBroadcast, forceMount, matcher = true, ...videoIndicatorProps } = props; const broadcastContext = useBroadcastContext( VIDEO_ENABLED_INDICATOR_NAME, __scopeBroadcast ); const video = useStore9(broadcastContext.store, ({ video: video2 }) => video2); const isPresent = useMemo6( () => typeof matcher === "boolean" ? matcher === video : matcher(video), [video, matcher] ); return /* @__PURE__ */ React10.createElement(Presence7, { present: forceMount || isPresent }, /* @__PURE__ */ React10.createElement( Primitive.div, { ...videoIndicatorProps, ref: forwardedRef, "data-livepeer-controls-video-enabled-indicator": "", "data-enabled": String(video) } )); }); VideoEnabledIndicator.displayName = VIDEO_ENABLED_INDICATOR_NAME; // src/shared/Container.tsx import * as RadixAspectRatio from "@radix-ui/react-aspect-ratio"; import React11 from "react"; import { useStore as useStore10 } from "zustand"; import { useShallow as useShallow7 } from "zustand/react/shallow"; var CONTAINER_NAME = "Container"; var Container = React11.memo( React11.forwardRef( (props, forwardedRef) => { const { __scopeMedia, ...aspectRatioProps } = props; const context = useMediaContext(CONTAINER_NAME, __scopeMedia); const { aspectRatio, fullscreen, playing, canPlay, rate, error, live, hasPlayed, hidden, pictureInPicture, loading, videoQuality } = useStore10( context.store, useShallow7( ({ __initialProps, fullscreen: fullscreen2, playing: playing2, canPlay: canPlay2, playbackRate, error: error2, live: live2, hasPlayed: hasPlayed2, hidden: hidden2, pictureInPicture: pictureInPicture2, loading: loading2, videoQuality: videoQuality2 }) => ({ aspectRatio: __initialProps.aspectRatio, fullscreen: fullscreen2, playing: playing2, canPlay: canPlay2, error: Boolean(error2), rate: playbackRate === "constant" ? "constant" : playbackRate > 1 ? "fast" : playbackRate < 1 ? "slow" : "normal", live: live2, hasPlayed: hasPlayed2, hidden: hidden2, pictureInPicture: pictureInPicture2, loading: loading2, videoQuality: videoQuality2 }) ) ); return aspectRatio ? /* @__PURE__ */ React11.createElement( RadixAspectRatio.Root, { ratio: aspectRatio, ...aspectRatioProps, ref: forwardedRef, "data-livepeer-aspect-ratio": "", "data-fullscreen": String(fullscreen), "data-playing": String(playing), "data-can-play": String(canPlay), "data-playback-rate": rate, "data-error": String(error), "data-loading": String(loading), "data-live": String(live), "data-has-played": String(hasPlayed), "data-controls-hidden": String(hidden), "data-picture-in-picture": String(pictureInPicture), "data-video-quality": String(videoQuality) } ) : /* @__PURE__ */ React11.createElement( Primitive.div, { ...aspectRatioProps, ref: forwardedRef, "data-livepeer-wrapper": "", "data-fullscreen": String(fullscreen), "data-playing": String(playing), "data-can-play": String(canPlay), "data-playback-rate": rate, "data-error": String(error), "data-loading": String(loading), "data-live": String(live), "data-has-played": String(hasPlayed), "data-controls-hidden": String(hidden), "data-picture-in-picture": String(pictureInPicture), "data-video-quality": String(videoQuality) } ); } ) ); Container.displayName = CONTAINER_NAME; // src/shared/ErrorIndicator.tsx import { Presence as Presence8 } from "@radix-ui/react-presence"; import React12, { useMemo as useMemo7 } from "react"; import { useStore as useStore11 } from "zustand"; var ERROR_INDICATOR_NAME = "ErrorIndicator"; var ErrorIndicator = React12.forwardRef((props, forwardedRef) => { const { __scopeMedia, forceMount, matcher, ...offlineErrorProps } = props; const context = useMediaContext(ERROR_INDICATOR_NAME, __scopeMedia); const error = useStore11(context.store, ({ error: error2 }) => error2); const isPresent = useMemo7( () => error ? typeof matcher === "string" ? matcher === "all" ? true : matcher === "not-permissions" ? error.type !== "permissions" : matcher === error.type : matcher(error.type) : false, [error, matcher] ); return /* @__PURE__ */ React12.createElement(Presence8, { present: forceMount || isPresent }, /* @__PURE__ */ React12.createElement( Primitive.div, { ...offlineErrorProps, ref: forwardedRef, "data-livepeer-error-indicator": "", "data-error-state": String(Boolean(error)), "data-error-type": error?.type ?? "none", "data-visible": String(isPresent) } )); }); ErrorIndicator.displayName = ERROR_INDICATOR_NAME; // src/shared/Fullscreen.tsx import { composeEventHandlers as composeEventHandlers5 } from "@radix-ui/primitive"; import { Presence as Presence9 } from "@radix-ui/react-presence"; import React13, { useMemo as useMemo8 } from "react"; import { useStore as useStore12 } from "zustand"; import { useShallow as useShallow8 } from "zustand/react/shallow"; var FULLSCREEN_INDICATOR_NAME = "FullscreenIndicator"; var FullscreenIndicator = React13.forwardRef((props, forwardedRef) => { const { __scopeMedia, forceMount, matcher = true, ...fullscreenIndicatorProps } = props; const context = useMediaContext(FULLSCREEN_INDICATOR_NAME, __scopeMedia); const fullscreen = useStore12( context.store, useShallow8(({ fullscreen: fullscreen2 }) => fullscreen2) ); const isPresent = useMemo8( () => typeof matcher === "function" ? matcher(fullscreen) : matcher === fullscreen, [matcher, fullscreen] ); return /* @__PURE__ */ React13.createElement(Presence9, { present: forceMount || isPresent }, /* @__PURE__ */ React13.createElement( Primitive.div, { ...fullscreenIndicatorProps, ref: forwardedRef, "data-livepeer-controls-fullscreen-indicator": "", "data-fullscreen": String(Boolean(fullscreen)), "data-visible": String(isPresent) } )); }); FullscreenIndicator.displayName = FULLSCREEN_INDICATOR_NAME; var FULLSCREEN_TRIGGER_NAME = "FullscreenTrigger"; var FullscreenTrigger = React13.forwardRef((props, forwardedRef) => { const { __scopeMedia, ...fullscreenProps } = props; const context = useMediaContext(FULLSCREEN_TRIGGER_NAME, __scopeMedia); const { title, fullscreen, requestToggleFullscreen } = useStore12( context.store, useShallow8(({ fullscreen: fullscreen2, __controlsFunctions, aria }) => ({ fullscreen: fullscreen2, requestToggleFullscreen: __controlsFunctions.requestToggleFullscreen, title: aria.fullscreen })) ); return /* @__PURE__ */ React13.createElement( Primitive.button, { type: "button", "aria-pressed": fullscreen, "aria-label": title ?? void 0, title: title ?? void 0, ...fullscreenProps, onClick: composeEventHandlers5( props.onClick, noPropagate(requestToggleFullscreen) ), ref: forwardedRef, "data-livepeer-controls-fullscreen-trigger": "", "data-fullscreen-state": String(Boolean(fullscreen)) } ); }); FullscreenTrigger.displayName = FULLSCREEN_TRIGGER_NAME; // src/shared/LoadingIndicator.tsx import { Presence as Presence10 } from "@radix-ui/react-presence"; import React14, { useMemo as useMemo9 } from "react"; import { useStore as useStore13 } from "zustand"; var LOADING_INDICATOR_NAME = "LoadingIndicator"; var LoadingIndicator = React14.forwardRef((props, forwardedRef) => { const { __scopeMedia, forceMount, matcher = true, ...offlineErrorProps } = props; const context = useMediaContext(LOADING_INDICATOR_NAME, __scopeMedia); const loading = useStore13(context.store, ({ loading: loading2 }) => loading2); const isPresent = useMemo9( () => typeof matcher === "function" ? matcher(loading) : matcher === loading, [matcher, loading] ); return /* @__PURE__ */ React14.createElement(Presence10, { present: forceMount || isPresent }, /* @__PURE__ */ React14.createElement( Primitive.div, { "aria-label": "Loading", ...offlineErrorProps, ref: forwardedRef, "data-livepeer-loading-indicator": "", "data-loading": String(Boolean(loading)), "data-visible": String(isPresent) } )); }); LoadingIndicator.displayName = LOADING_INDICATOR_NAME; // src/shared/PictureInPictureTrigger.tsx import { composeEventHandlers as composeEventHandlers6 } from "@radix-ui/primitive"; import { Presence as Presence11 } from "@radix-ui/react-presence"; import React15 from "react"; import { useStore as useStore14 } from "zustand"; import { useShallow as useShallow9 } from "zustand/react/shallow"; var PICTURE_IN_PICTURE_TRIGGER_NAME = "PictureInPictureTrigger"; var PictureInPictureTrigger = React15.forwardRef((props, forwardedRef) => { const { __scopeMedia, forceMount, ...pictureInPictureProps } = props; const context = useMediaContext( PICTURE_IN_PICTURE_TRIGGER_NAME, __scopeMedia ); const { pictureInPicture, requestTogglePictureInPicture, isPictureInPictureSupported, fullscreen, title } = useStore14( context.store, useShallow9( ({ pictureInPicture: pictureInPicture2, __controlsFunctions, __device, fullscreen: fullscreen2, aria }) => ({ pictureInPicture: pictureInPicture2, requestTogglePictureInPicture: __controlsFunctions.requestTogglePictureInPicture, isPictureInPictureSupported: __device.isPictureInPictureSupported, fullscreen: fullscreen2, title: aria.pictureInPicture }) ) ); return ( // do not show button if it is not supported or if currently fullscreen /* @__PURE__ */ React15.createElement( Presence11, { present: forceMount || isPictureInPictureSupported && !fullscreen }, /* @__PURE__ */ React15.createElement( Primitive.button, { type: "button", "aria-pressed": pictureInPicture, "aria-label": title ?? void 0, title: title ?? void 0, ...pictureInPictureProps, onClick: composeEventHandlers6( props.onClick, noPropagate(requestTogglePictureInPicture) ), ref: forwardedRef, "data-livepeer-controls-picture-in-picture-trigger": "", "data-picture-in-picture": String(Boolean(pictureInPicture)), "data-visible": String(isPictureInPictureSupported && !fullscreen) } ) ) ); }); PictureInPictureTrigger.displayName = PICTURE_IN_PICTURE_TRIGGER_NAME; // src/shared/Portal.tsx import * as RadixPortal from "@radix-ui/react-portal"; import React16 from "react"; var PORTAL_NAME = "Portal"; var Portal = (props) => { return /* @__PURE__ */ React16.createElement(RadixPortal.Root, { ...props }); }; Portal.displayName = PORTAL_NAME; // src/shared/Slider.tsx import * as SliderPrimitive from "@radix-ui/react-slider"; var Track2 = SliderPrimitive.Track; var Range2 = SliderPrimitive.Range; var Thumb2 = SliderPrimitive.Thumb; // src/shared/Time.tsx import React17 from "react"; import { useStore as useStore15 } from "zustand"; import { useShallow as useShallow10 } from "zustand/react/shallow"; var TIME_NAME = "Time"; var Time = React17.forwardRef( (props, forwardedRef) => { const { __scopeMedia, ...timeProps } = props; const context = useMediaContext(TIME_NAME, __scopeMedia); const { progress, duration, live, formattedTime } = useStore15( context.store, useShallow10(({ progress: progress2, duration: duration2, live: live2, aria }) => ({ formattedTime: aria.time, progress: progress2, duration: duration2, live: live2 })) ); return /* @__PURE__ */ React17.createElement( Primitive.span, { "aria-label": formattedTime ?? void 0, title: formattedTime ?? void 0, ...timeProps, ref: forwardedRef, "data-livepeer-controls-time": "", "data-duration": duration, "data-progress": progress, "data-live": String(live) }, formattedTime ); } ); Time.displayName = TIME_NAME; export { AudioEnabledIndicator, AudioEnabledTrigger, BroadcastProvider, Container, Controls, EnabledIndicator, EnabledTrigger, ErrorIndicator, FullscreenIndicator, FullscreenTrigger, LoadingIndicator, MediaProvider, PictureInPictureTrigger, Portal, Range2 as Range, Root, ScreenshareIndicator, ScreenshareTrigger, SelectArrow2 as SelectArrow, SelectContent2 as SelectContent, SelectGroup2 as SelectGroup, SelectIcon2 as SelectIcon, SelectItem2 as SelectItem, SelectItemIndicator2 as SelectItemIndicator, SelectItemText2 as SelectItemText, SelectLabel2 as SelectLabel, SelectPortal2 as SelectPortal, SelectRoot, SelectScrollDownButton2 as SelectScrollDownButton, SelectScrollUpButton2 as SelectScrollUpButton, SelectSeparator2 as SelectSeparator, SelectTrigger2 as SelectTrigger, SelectValue2 as SelectValue, SelectViewport2 as SelectViewport, SourceSelect, StatusIndicator, Thumb2 as Thumb, Time, Track2 as Track, Video, VideoEnabledIndicator, VideoEnabledTrigger, createBroadcastScope, createMediaScope, useBroadcastContext, useMediaContext, useStore2 as useStore }; //# sourceMappingURL=index.js.map