@livepeer/react
Version:
React primitives for video apps.
1,188 lines (1,162 loc) • 41.5 kB
JavaScript
"use client";
;
var __create = Object.create;
var __defProp = Object.defineProperty;
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
var __getOwnPropNames = Object.getOwnPropertyNames;
var __getProtoOf = Object.getPrototypeOf;
var __hasOwnProp = Object.prototype.hasOwnProperty;
var __export = (target, all) => {
for (var name in all)
__defProp(target, name, { get: all[name], enumerable: true });
};
var __copyProps = (to, from, except, desc) => {
if (from && typeof from === "object" || typeof from === "function") {
for (let key of __getOwnPropNames(from))
if (!__hasOwnProp.call(to, key) && key !== except)
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
}
return to;
};
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
// If the importer is in node compatibility mode or this is not an ESM
// file that has been converted to a CommonJS file using a Babel-
// compatible transform (i.e. "__esModule" has not been set), then set
// "default" to the CommonJS "module.exports" for node compatibility.
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
mod
));
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
// src/broadcast.tsx
var broadcast_exports = {};
__export(broadcast_exports, {
AudioEnabledIndicator: () => AudioEnabledIndicator,
AudioEnabledTrigger: () => AudioEnabledTrigger,
BroadcastProvider: () => BroadcastProvider,
Container: () => Container,
Controls: () => Controls,
EnabledIndicator: () => EnabledIndicator,
EnabledTrigger: () => EnabledTrigger,
ErrorIndicator: () => ErrorIndicator,
FullscreenIndicator: () => FullscreenIndicator,
FullscreenTrigger: () => FullscreenTrigger,
LoadingIndicator: () => LoadingIndicator,
MediaProvider: () => MediaProvider,
PictureInPictureTrigger: () => PictureInPictureTrigger,
Portal: () => Portal,
Range: () => Range2,
Root: () => Root,
ScreenshareIndicator: () => ScreenshareIndicator,
ScreenshareTrigger: () => ScreenshareTrigger,
SelectArrow: () => SelectArrow2,
SelectContent: () => SelectContent2,
SelectGroup: () => SelectGroup2,
SelectIcon: () => SelectIcon2,
SelectItem: () => SelectItem2,
SelectItemIndicator: () => SelectItemIndicator2,
SelectItemText: () => SelectItemText2,
SelectLabel: () => SelectLabel2,
SelectPortal: () => SelectPortal2,
SelectRoot: () => SelectRoot,
SelectScrollDownButton: () => SelectScrollDownButton2,
SelectScrollUpButton: () => SelectScrollUpButton2,
SelectSeparator: () => SelectSeparator2,
SelectTrigger: () => SelectTrigger2,
SelectValue: () => SelectValue2,
SelectViewport: () => SelectViewport2,
SourceSelect: () => SourceSelect,
StatusIndicator: () => StatusIndicator,
Thumb: () => Thumb2,
Time: () => Time,
Track: () => Track2,
Video: () => Video,
VideoEnabledIndicator: () => VideoEnabledIndicator,
VideoEnabledTrigger: () => VideoEnabledTrigger,
createBroadcastScope: () => createBroadcastScope,
createMediaScope: () => createMediaScope,
useBroadcastContext: () => useBroadcastContext,
useMediaContext: () => useMediaContext,
useStore: () => useStore2
});
module.exports = __toCommonJS(broadcast_exports);
// src/broadcast/AudioEnabled.tsx
var import_primitive = require("@radix-ui/primitive");
var import_react_presence = require("@radix-ui/react-presence");
var import_react = __toESM(require("react"), 1);
var import_zustand = require("zustand");
var import_shallow = require("zustand/react/shallow");
// src/shared/primitive.tsx
var import_react_slot = require("@radix-ui/react-slot");
var React = __toESM(require("react"), 1);
var ReactDOM = __toESM(require("react-dom"), 1);
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 ? import_react_slot.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
var import_react_context = require("@radix-ui/react-context");
var MEDIA_NAME = "Broadcast";
var [createBroadcastContext, createBroadcastScope] = (0, import_react_context.createContextScope)(MEDIA_NAME);
var [BroadcastProvider, useBroadcastContext] = createBroadcastContext(MEDIA_NAME);
// src/broadcast/AudioEnabled.tsx
var AUDIO_ENABLED_TRIGGER_NAME = "AudioEnabledTrigger";
var AudioEnabledTrigger = import_react.default.forwardRef((props, forwardedRef) => {
const { __scopeBroadcast, ...audioEnabledProps } = props;
const broadcastContext = useBroadcastContext(
AUDIO_ENABLED_TRIGGER_NAME,
__scopeBroadcast
);
const { audio, title, toggleAudio } = (0, import_zustand.useStore)(
broadcastContext.store,
(0, import_shallow.useShallow)(({ audio: audio2, aria, __controlsFunctions }) => ({
audio: audio2,
title: aria.audioTrigger,
toggleAudio: __controlsFunctions.toggleAudio
}))
);
return /* @__PURE__ */ import_react.default.createElement(
Primitive.button,
{
type: "button",
"aria-pressed": audio,
"aria-label": title,
title,
...audioEnabledProps,
onClick: (0, import_primitive.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 = import_react.default.forwardRef((props, forwardedRef) => {
const {
__scopeBroadcast,
forceMount,
matcher = true,
...audioIndicatorProps
} = props;
const broadcastContext = useBroadcastContext(
AUDIO_ENABLED_INDICATOR_NAME,
__scopeBroadcast
);
const audio = (0, import_zustand.useStore)(broadcastContext.store, ({ audio: audio2 }) => audio2);
const isPresent = (0, import_react.useMemo)(
() => typeof matcher === "boolean" ? matcher === audio : matcher(audio),
[audio, matcher]
);
return /* @__PURE__ */ import_react.default.createElement(import_react_presence.Presence, { present: forceMount || isPresent }, /* @__PURE__ */ import_react.default.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
var import_media = require("@livepeer/core/media");
var import_storage = require("@livepeer/core/storage");
var import_version = require("@livepeer/core/version");
var import_broadcast = require("@livepeer/core-web/broadcast");
var import_browser = require("@livepeer/core-web/browser");
var import_react2 = __toESM(require("react"), 1);
// src/shared/context.tsx
var import_react_context2 = require("@radix-ui/react-context");
var import_zustand2 = require("zustand");
var MEDIA_NAME2 = "Media";
var [createMediaContext, createMediaScope] = (0, import_react_context2.createContextScope)(MEDIA_NAME2);
var [MediaProvider, useMediaContext] = createMediaContext(MEDIA_NAME2);
var useStore2 = import_zustand2.useStore;
// src/broadcast/Broadcast.tsx
var Broadcast = (props) => {
const {
aspectRatio = 16 / 9,
children,
ingestUrl,
onError,
storage,
timeout,
videoQuality,
onPlaybackEvents,
metricsInterval,
...rest
} = props;
const mediaStore = (0, import_react2.useRef)(
(0, import_media.createControllerStore)({
device: (0, import_browser.getDeviceInfo)(import_version.version.react),
storage: storage ?? (0, import_storage.createStorage)(
storage !== null && typeof window !== "undefined" ? {
storage: window.localStorage
} : {
storage: import_storage.noopStorage
}
),
src: null,
initialProps: {
hotkeys: "broadcast",
aspectRatio,
volume: 0,
onError,
timeout,
videoQuality
}
})
);
const broadcastStore = (0, import_react2.useRef)(
(0, import_broadcast.createBroadcastStore)({
device: (0, import_broadcast.getBroadcastDeviceInfo)(import_version.version.react),
storage: storage ?? (0, import_storage.createStorage)(
storage !== null && typeof window !== "undefined" ? {
storage: window.localStorage
} : {
storage: import_storage.noopStorage
}
),
ingestUrl,
initialProps: {
aspectRatio,
...rest
}
})
);
(0, import_react2.useEffect)(() => {
return () => {
mediaStore?.current?.destroy?.();
broadcastStore?.current?.destroy?.();
};
}, []);
(0, import_react2.useEffect)(() => {
if (ingestUrl) {
broadcastStore.current.store.getState().__controlsFunctions.setIngestUrl(ingestUrl);
}
}, [ingestUrl]);
(0, import_react2.useEffect)(() => {
const metrics = (0, import_media.addLegacyMediaMetricsToStore)(mediaStore.current.store);
return () => {
metrics.destroy();
};
}, []);
(0, import_react2.useEffect)(() => {
const metrics = (0, import_media.addMetricsToStore)(mediaStore.current.store, {
onPlaybackEvents,
interval: metricsInterval
});
return () => {
metrics.destroy();
};
}, []);
return /* @__PURE__ */ import_react2.default.createElement(MediaProvider, { store: mediaStore.current.store, scope: props.__scopeMedia }, /* @__PURE__ */ import_react2.default.createElement(
BroadcastProvider,
{
store: broadcastStore.current.store,
scope: props.__scopeBroadcast
},
children
));
};
Broadcast.displayName = "Broadcast";
var Root = Broadcast;
// src/broadcast/Controls.tsx
var import_react_presence2 = require("@radix-ui/react-presence");
var import_react3 = __toESM(require("react"), 1);
var import_zustand3 = require("zustand");
var import_shallow2 = require("zustand/react/shallow");
var CONTROLS_NAME = "Controls";
var Controls = import_react3.default.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 } = (0, import_zustand3.useStore)(
context.store,
(0, import_shallow2.useShallow)(({ hidden: hidden2, loading: loading2, error: error2 }) => ({
hidden: hidden2,
loading: loading2,
error: error2?.type ?? null
}))
);
const broadcastContext = useBroadcastContext(
CONTROLS_NAME,
__scopeBroadcast
);
const { isWebRTCSupported } = (0, import_zustand3.useStore)(
broadcastContext.store,
(0, import_shallow2.useShallow)(({ enabled, __device }) => ({
enabled,
isWebRTCSupported: __device.isMediaDevicesSupported
}))
);
const shown = (0, import_react3.useMemo)(
() => !hidden && !loading && !error && isWebRTCSupported,
[hidden, loading, error, isWebRTCSupported]
);
(0, import_react3.useEffect)(() => {
if (autoHide !== void 0) {
context.store.getState().__controlsFunctions.setAutohide(autoHide);
}
}, []);
return /* @__PURE__ */ import_react3.default.createElement(import_react_presence2.Presence, { present: forceMount || shown }, /* @__PURE__ */ import_react3.default.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
var import_primitive2 = require("@radix-ui/primitive");
var import_react_presence3 = require("@radix-ui/react-presence");
var import_react4 = __toESM(require("react"), 1);
var import_zustand4 = require("zustand");
var import_shallow3 = require("zustand/react/shallow");
var ENABLED_TRIGGER_NAME = "EnabledTrigger";
var EnabledTrigger = import_react4.default.forwardRef((props, forwardedRef) => {
const { __scopeBroadcast, ...playProps } = props;
const broadcastContext = useBroadcastContext(
ENABLED_TRIGGER_NAME,
__scopeBroadcast
);
const { enabled, title, toggleEnabled } = (0, import_zustand4.useStore)(
broadcastContext.store,
(0, import_shallow3.useShallow)(({ enabled: enabled2, aria, __controlsFunctions }) => ({
enabled: enabled2,
title: aria.start,
toggleEnabled: __controlsFunctions.toggleEnabled
}))
);
return /* @__PURE__ */ import_react4.default.createElement(
Primitive.button,
{
type: "button",
"aria-pressed": enabled,
"aria-label": title,
title,
...playProps,
onClick: (0, import_primitive2.composeEventHandlers)(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 = import_react4.default.forwardRef(
(props, forwardedRef) => {
const {
__scopeBroadcast,
__scopeMedia,
forceMount,
matcher = true,
...playPauseIndicatorProps
} = props;
const context = useMediaContext(ENABLED_INDICATOR_NAME, __scopeMedia);
const loading = (0, import_zustand4.useStore)(context.store, ({ loading: loading2 }) => loading2);
const broadcastContext = useBroadcastContext(
ENABLED_INDICATOR_NAME,
__scopeBroadcast
);
const enabled = (0, import_zustand4.useStore)(broadcastContext.store, ({ enabled: enabled2 }) => enabled2);
const isPresent = (0, import_react4.useMemo)(
() => !loading && (typeof matcher === "boolean" ? matcher === enabled : matcher(enabled)),
[enabled, matcher, loading]
);
return /* @__PURE__ */ import_react4.default.createElement(import_react_presence3.Presence, { present: forceMount || isPresent }, /* @__PURE__ */ import_react4.default.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
var import_primitive3 = require("@radix-ui/primitive");
var import_react_presence4 = require("@radix-ui/react-presence");
var import_react5 = __toESM(require("react"), 1);
var import_zustand5 = require("zustand");
var import_shallow4 = require("zustand/react/shallow");
var SCREENSHARE_TRIGGER_NAME = "ScreenshareTrigger";
var ScreenshareTrigger = import_react5.default.forwardRef((props, forwardedRef) => {
const { __scopeBroadcast, forceMount, ...screenshareProps } = props;
const broadcastContext = useBroadcastContext(
SCREENSHARE_TRIGGER_NAME,
__scopeBroadcast
);
const { isSupported, isActive, title, toggleDisplayMedia } = (0, import_zustand5.useStore)(
broadcastContext.store,
(0, import_shallow4.useShallow)(({ mediaDeviceIds, aria, __device, __controlsFunctions }) => ({
isActive: mediaDeviceIds.videoinput === "screen",
title: aria.screenshareTrigger,
toggleDisplayMedia: __controlsFunctions.toggleDisplayMedia,
isSupported: __device.isDisplayMediaSupported
}))
);
return /* @__PURE__ */ import_react5.default.createElement(import_react_presence4.Presence, { present: forceMount || isSupported }, /* @__PURE__ */ import_react5.default.createElement(
Primitive.button,
{
type: "button",
"aria-pressed": isActive,
"aria-label": title,
title,
...screenshareProps,
onClick: (0, import_primitive3.composeEventHandlers)(
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 = import_react5.default.forwardRef((props, forwardedRef) => {
const {
__scopeBroadcast,
forceMount,
matcher = true,
...audioIndicatorProps
} = props;
const broadcastContext = useBroadcastContext(
SCREENSHARE_INDICATOR_NAME,
__scopeBroadcast
);
const { isActive, isSupported } = (0, import_zustand5.useStore)(
broadcastContext.store,
({ mediaDeviceIds, __device }) => ({
isActive: mediaDeviceIds.videoinput === "screen",
isSupported: __device.isDisplayMediaSupported
})
);
const isPresent = (0, import_react5.useMemo)(
() => isSupported ? typeof matcher === "boolean" ? matcher === isActive : matcher(isActive) : false,
[isSupported, isActive, matcher]
);
return /* @__PURE__ */ import_react5.default.createElement(import_react_presence4.Presence, { present: forceMount || isPresent }, /* @__PURE__ */ import_react5.default.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
var import_react_presence5 = require("@radix-ui/react-presence");
var import_react6 = __toESM(require("react"), 1);
var import_zustand6 = require("zustand");
var import_shallow5 = require("zustand/react/shallow");
// src/shared/Select.tsx
var SelectPrimitive = __toESM(require("@radix-ui/react-select"), 1);
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
} = (0, import_zustand6.useStore)(
broadcastContext.store,
(0, import_shallow5.useShallow)(
({
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 = (0, import_react6.useCallback)(
(deviceId) => {
requestMediaDeviceId(deviceId, type);
},
[requestMediaDeviceId, type]
);
const handleValueChange = (0, import_react6.useCallback)(
(value) => {
if (props.onValueChange) {
props.onValueChange(value);
}
setMediaDeviceIdComposed(value);
},
[props.onValueChange, setMediaDeviceIdComposed]
);
return /* @__PURE__ */ import_react6.default.createElement(import_react_presence5.Presence, { present: forceMount || isSupported }, /* @__PURE__ */ import_react6.default.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
var import_react_presence6 = require("@radix-ui/react-presence");
var import_react7 = __toESM(require("react"), 1);
var import_zustand7 = require("zustand");
var STATUS_INDICATOR_NAME = "StatusIndicator";
var StatusIndicator = import_react7.default.forwardRef((props, forwardedRef) => {
const {
__scopeBroadcast,
forceMount,
matcher = true,
...statusIndicatorProps
} = props;
const broadcastContext = useBroadcastContext(
STATUS_INDICATOR_NAME,
__scopeBroadcast
);
const status = (0, import_zustand7.useStore)(broadcastContext.store, ({ status: status2 }) => status2);
const isPresent = (0, import_react7.useMemo)(
() => typeof matcher === "function" ? matcher(status) : matcher === status,
[matcher, status]
);
return /* @__PURE__ */ import_react7.default.createElement(import_react_presence6.Presence, { present: forceMount || isPresent }, /* @__PURE__ */ import_react7.default.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
var import_broadcast3 = require("@livepeer/core-web/broadcast");
var import_browser2 = require("@livepeer/core-web/browser");
var import_react_compose_refs = require("@radix-ui/react-compose-refs");
var import_react8 = __toESM(require("react"), 1);
var import_zustand8 = require("zustand");
var VIDEO_NAME = "Video";
var Video = import_react8.default.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 = import_react8.default.useRef(null);
const composedRefs = (0, import_react_compose_refs.useComposedRefs)(forwardedRef, ref);
const isEnabled = (0, import_zustand8.useStore)(
broadcastContext.store,
({ enabled }) => enabled
);
(0, import_react8.useEffect)(() => {
if (ref.current) {
const { destroy } = (0, import_browser2.addEventListeners)(ref.current, context.store);
return destroy;
}
}, [context?.store]);
(0, import_react8.useEffect)(() => {
if (ref.current) {
const { destroy } = (0, import_broadcast3.addBroadcastEventListeners)(
ref.current,
broadcastContext.store,
context.store
);
return destroy;
}
}, []);
import_react8.default.useEffect(() => {
context.store.getState().__controlsFunctions.setMounted();
}, []);
return /* @__PURE__ */ import_react8.default.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
var import_primitive4 = require("@radix-ui/primitive");
var import_react_presence7 = require("@radix-ui/react-presence");
var import_react9 = __toESM(require("react"), 1);
var import_zustand9 = require("zustand");
var import_shallow6 = require("zustand/react/shallow");
var VIDEO_ENABLED_TRIGGER_NAME = "VideoEnabledTrigger";
var VideoEnabledTrigger = import_react9.default.forwardRef((props, forwardedRef) => {
const { __scopeBroadcast, ...videoEnabledProps } = props;
const broadcastContext = useBroadcastContext(
VIDEO_ENABLED_TRIGGER_NAME,
__scopeBroadcast
);
const { video, title, toggleVideo } = (0, import_zustand9.useStore)(
broadcastContext.store,
(0, import_shallow6.useShallow)(({ video: video2, aria, __controlsFunctions }) => ({
video: video2,
title: aria.videoTrigger,
toggleVideo: __controlsFunctions.toggleVideo
}))
);
return /* @__PURE__ */ import_react9.default.createElement(
Primitive.button,
{
type: "button",
"aria-pressed": video,
"aria-label": title,
title,
...videoEnabledProps,
onClick: (0, import_primitive4.composeEventHandlers)(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 = import_react9.default.forwardRef((props, forwardedRef) => {
const {
__scopeBroadcast,
forceMount,
matcher = true,
...videoIndicatorProps
} = props;
const broadcastContext = useBroadcastContext(
VIDEO_ENABLED_INDICATOR_NAME,
__scopeBroadcast
);
const video = (0, import_zustand9.useStore)(broadcastContext.store, ({ video: video2 }) => video2);
const isPresent = (0, import_react9.useMemo)(
() => typeof matcher === "boolean" ? matcher === video : matcher(video),
[video, matcher]
);
return /* @__PURE__ */ import_react9.default.createElement(import_react_presence7.Presence, { present: forceMount || isPresent }, /* @__PURE__ */ import_react9.default.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
var RadixAspectRatio = __toESM(require("@radix-ui/react-aspect-ratio"), 1);
var import_react10 = __toESM(require("react"), 1);
var import_zustand10 = require("zustand");
var import_shallow7 = require("zustand/react/shallow");
var CONTAINER_NAME = "Container";
var Container = import_react10.default.memo(
import_react10.default.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
} = (0, import_zustand10.useStore)(
context.store,
(0, import_shallow7.useShallow)(
({
__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__ */ import_react10.default.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__ */ import_react10.default.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
var import_react_presence8 = require("@radix-ui/react-presence");
var import_react11 = __toESM(require("react"), 1);
var import_zustand11 = require("zustand");
var ERROR_INDICATOR_NAME = "ErrorIndicator";
var ErrorIndicator = import_react11.default.forwardRef((props, forwardedRef) => {
const { __scopeMedia, forceMount, matcher, ...offlineErrorProps } = props;
const context = useMediaContext(ERROR_INDICATOR_NAME, __scopeMedia);
const error = (0, import_zustand11.useStore)(context.store, ({ error: error2 }) => error2);
const isPresent = (0, import_react11.useMemo)(
() => error ? typeof matcher === "string" ? matcher === "all" ? true : matcher === "not-permissions" ? error.type !== "permissions" : matcher === error.type : matcher(error.type) : false,
[error, matcher]
);
return /* @__PURE__ */ import_react11.default.createElement(import_react_presence8.Presence, { present: forceMount || isPresent }, /* @__PURE__ */ import_react11.default.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
var import_primitive5 = require("@radix-ui/primitive");
var import_react_presence9 = require("@radix-ui/react-presence");
var import_react12 = __toESM(require("react"), 1);
var import_zustand12 = require("zustand");
var import_shallow8 = require("zustand/react/shallow");
var FULLSCREEN_INDICATOR_NAME = "FullscreenIndicator";
var FullscreenIndicator = import_react12.default.forwardRef((props, forwardedRef) => {
const {
__scopeMedia,
forceMount,
matcher = true,
...fullscreenIndicatorProps
} = props;
const context = useMediaContext(FULLSCREEN_INDICATOR_NAME, __scopeMedia);
const fullscreen = (0, import_zustand12.useStore)(
context.store,
(0, import_shallow8.useShallow)(({ fullscreen: fullscreen2 }) => fullscreen2)
);
const isPresent = (0, import_react12.useMemo)(
() => typeof matcher === "function" ? matcher(fullscreen) : matcher === fullscreen,
[matcher, fullscreen]
);
return /* @__PURE__ */ import_react12.default.createElement(import_react_presence9.Presence, { present: forceMount || isPresent }, /* @__PURE__ */ import_react12.default.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 = import_react12.default.forwardRef((props, forwardedRef) => {
const { __scopeMedia, ...fullscreenProps } = props;
const context = useMediaContext(FULLSCREEN_TRIGGER_NAME, __scopeMedia);
const { title, fullscreen, requestToggleFullscreen } = (0, import_zustand12.useStore)(
context.store,
(0, import_shallow8.useShallow)(({ fullscreen: fullscreen2, __controlsFunctions, aria }) => ({
fullscreen: fullscreen2,
requestToggleFullscreen: __controlsFunctions.requestToggleFullscreen,
title: aria.fullscreen
}))
);
return /* @__PURE__ */ import_react12.default.createElement(
Primitive.button,
{
type: "button",
"aria-pressed": fullscreen,
"aria-label": title ?? void 0,
title: title ?? void 0,
...fullscreenProps,
onClick: (0, import_primitive5.composeEventHandlers)(
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
var import_react_presence10 = require("@radix-ui/react-presence");
var import_react13 = __toESM(require("react"), 1);
var import_zustand13 = require("zustand");
var LOADING_INDICATOR_NAME = "LoadingIndicator";
var LoadingIndicator = import_react13.default.forwardRef((props, forwardedRef) => {
const {
__scopeMedia,
forceMount,
matcher = true,
...offlineErrorProps
} = props;
const context = useMediaContext(LOADING_INDICATOR_NAME, __scopeMedia);
const loading = (0, import_zustand13.useStore)(context.store, ({ loading: loading2 }) => loading2);
const isPresent = (0, import_react13.useMemo)(
() => typeof matcher === "function" ? matcher(loading) : matcher === loading,
[matcher, loading]
);
return /* @__PURE__ */ import_react13.default.createElement(import_react_presence10.Presence, { present: forceMount || isPresent }, /* @__PURE__ */ import_react13.default.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
var import_primitive6 = require("@radix-ui/primitive");
var import_react_presence11 = require("@radix-ui/react-presence");
var import_react14 = __toESM(require("react"), 1);
var import_zustand14 = require("zustand");
var import_shallow9 = require("zustand/react/shallow");
var PICTURE_IN_PICTURE_TRIGGER_NAME = "PictureInPictureTrigger";
var PictureInPictureTrigger = import_react14.default.forwardRef((props, forwardedRef) => {
const { __scopeMedia, forceMount, ...pictureInPictureProps } = props;
const context = useMediaContext(
PICTURE_IN_PICTURE_TRIGGER_NAME,
__scopeMedia
);
const {
pictureInPicture,
requestTogglePictureInPicture,
isPictureInPictureSupported,
fullscreen,
title
} = (0, import_zustand14.useStore)(
context.store,
(0, import_shallow9.useShallow)(
({
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__ */ import_react14.default.createElement(
import_react_presence11.Presence,
{
present: forceMount || isPictureInPictureSupported && !fullscreen
},
/* @__PURE__ */ import_react14.default.createElement(
Primitive.button,
{
type: "button",
"aria-pressed": pictureInPicture,
"aria-label": title ?? void 0,
title: title ?? void 0,
...pictureInPictureProps,
onClick: (0, import_primitive6.composeEventHandlers)(
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
var RadixPortal = __toESM(require("@radix-ui/react-portal"), 1);
var import_react15 = __toESM(require("react"), 1);
var PORTAL_NAME = "Portal";
var Portal = (props) => {
return /* @__PURE__ */ import_react15.default.createElement(RadixPortal.Root, { ...props });
};
Portal.displayName = PORTAL_NAME;
// src/shared/Slider.tsx
var SliderPrimitive = __toESM(require("@radix-ui/react-slider"), 1);
var Track2 = SliderPrimitive.Track;
var Range2 = SliderPrimitive.Range;
var Thumb2 = SliderPrimitive.Thumb;
// src/shared/Time.tsx
var import_react16 = __toESM(require("react"), 1);
var import_zustand15 = require("zustand");
var import_shallow10 = require("zustand/react/shallow");
var TIME_NAME = "Time";
var Time = import_react16.default.forwardRef(
(props, forwardedRef) => {
const { __scopeMedia, ...timeProps } = props;
const context = useMediaContext(TIME_NAME, __scopeMedia);
const { progress, duration, live, formattedTime } = (0, import_zustand15.useStore)(
context.store,
(0, import_shallow10.useShallow)(({ progress: progress2, duration: duration2, live: live2, aria }) => ({
formattedTime: aria.time,
progress: progress2,
duration: duration2,
live: live2
}))
);
return /* @__PURE__ */ import_react16.default.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;
// Annotate the CommonJS export names for ESM import in node:
0 && (module.exports = {
AudioEnabledIndicator,
AudioEnabledTrigger,
BroadcastProvider,
Container,
Controls,
EnabledIndicator,
EnabledTrigger,
ErrorIndicator,
FullscreenIndicator,
FullscreenTrigger,
LoadingIndicator,
MediaProvider,
PictureInPictureTrigger,
Portal,
Range,
Root,
ScreenshareIndicator,
ScreenshareTrigger,
SelectArrow,
SelectContent,
SelectGroup,
SelectIcon,
SelectItem,
SelectItemIndicator,
SelectItemText,
SelectLabel,
SelectPortal,
SelectRoot,
SelectScrollDownButton,
SelectScrollUpButton,
SelectSeparator,
SelectTrigger,
SelectValue,
SelectViewport,
SourceSelect,
StatusIndicator,
Thumb,
Time,
Track,
Video,
VideoEnabledIndicator,
VideoEnabledTrigger,
createBroadcastScope,
createMediaScope,
useBroadcastContext,
useMediaContext,
useStore
});
//# sourceMappingURL=index.cjs.map