@stream-io/video-react-sdk 1.33.4 → 1.34.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +29 -0
- package/dist/{background-filters-Zu84SkRR.cjs.js → background-filters-DdQqSx4T.cjs.js} +7 -3
- package/dist/background-filters-DdQqSx4T.cjs.js.map +1 -0
- package/dist/{background-filters-RdXfNf6_.es.js → background-filters-g6ozIvlN.es.js} +7 -3
- package/dist/background-filters-g6ozIvlN.es.js.map +1 -0
- package/dist/css/embedded.css +5 -0
- package/dist/css/embedded.css.map +1 -1
- package/dist/css/styles.css +5 -0
- package/dist/css/styles.css.map +1 -1
- package/dist/{embedded-BackgroundFilters-Zu84SkRR.cjs.js → embedded-BackgroundFilters-DdQqSx4T.cjs.js} +7 -3
- package/dist/embedded-BackgroundFilters-DdQqSx4T.cjs.js.map +1 -0
- package/dist/{embedded-BackgroundFilters-RdXfNf6_.es.js → embedded-BackgroundFilters-g6ozIvlN.es.js} +7 -3
- package/dist/embedded-BackgroundFilters-g6ozIvlN.es.js.map +1 -0
- package/dist/embedded.cjs.js +64 -35
- package/dist/embedded.cjs.js.map +1 -1
- package/dist/embedded.es.js +64 -35
- package/dist/embedded.es.js.map +1 -1
- package/dist/index.cjs.js +70 -39
- package/dist/index.cjs.js.map +1 -1
- package/dist/index.es.js +70 -39
- package/dist/index.es.js.map +1 -1
- package/dist/src/components/BackgroundFilters/types.d.ts +6 -1
- package/dist/src/components/CallControls/RecordCallButton.d.ts +6 -5
- package/dist/src/translations/index.d.ts +1 -0
- package/package.json +5 -5
- package/src/components/BackgroundFilters/BackgroundFilters.tsx +6 -0
- package/src/components/BackgroundFilters/types.ts +7 -0
- package/src/components/CallControls/CallControls.tsx +4 -9
- package/src/components/CallControls/RecordCallButton.tsx +26 -13
- package/src/core/components/ParticipantView/DefaultParticipantViewUI.tsx +44 -4
- package/src/translations/en.json +1 -0
- package/dist/background-filters-RdXfNf6_.es.js.map +0 -1
- package/dist/background-filters-Zu84SkRR.cjs.js.map +0 -1
- package/dist/embedded-BackgroundFilters-RdXfNf6_.es.js.map +0 -1
- package/dist/embedded-BackgroundFilters-Zu84SkRR.cjs.js.map +0 -1
package/dist/index.cjs.js
CHANGED
|
@@ -828,7 +828,7 @@ const AvatarFallback = ({ className, names, style, }) => {
|
|
|
828
828
|
return (jsxRuntime.jsx("div", { className: clsx('str-video__avatar--initials-fallback', className), style: style, children: jsxRuntime.jsxs("div", { children: [names[0][0], names[1]?.[0]] }) }));
|
|
829
829
|
};
|
|
830
830
|
|
|
831
|
-
const BackgroundFiltersProviderImpl = react.lazy(() => Promise.resolve().then(function () { return require('./background-filters-
|
|
831
|
+
const BackgroundFiltersProviderImpl = react.lazy(() => Promise.resolve().then(function () { return require('./background-filters-DdQqSx4T.cjs.js'); }).then((m) => ({
|
|
832
832
|
default: m.BackgroundFiltersProvider,
|
|
833
833
|
})));
|
|
834
834
|
/**
|
|
@@ -1042,23 +1042,53 @@ const WithTooltip = ({ title, tooltipClassName, tooltipPlacement, tooltipDisable
|
|
|
1042
1042
|
return (jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [jsxRuntime.jsx(Tooltip, { referenceElement: tooltipAnchor, visible: tooltipActuallyVisible, tooltipClassName: tooltipClassName, tooltipPlacement: tooltipPlacement, children: title || '' }), jsxRuntime.jsx("div", { ref: setTooltipAnchor, onMouseEnter: handleMouseEnter, onMouseLeave: handleMouseLeave, ...props })] }));
|
|
1043
1043
|
};
|
|
1044
1044
|
|
|
1045
|
-
|
|
1045
|
+
/**
|
|
1046
|
+
* Wraps an event handler, silencing and logging exceptions (excluding the NotAllowedError
|
|
1047
|
+
* DOMException, which is a normal situation handled by the SDK)
|
|
1048
|
+
*
|
|
1049
|
+
* @param props component props, including the onError callback
|
|
1050
|
+
* @param handler event handler to wrap
|
|
1051
|
+
*/
|
|
1052
|
+
const createCallControlHandler = (props, handler) => {
|
|
1053
|
+
return async () => {
|
|
1054
|
+
try {
|
|
1055
|
+
await handler();
|
|
1056
|
+
}
|
|
1057
|
+
catch (error) {
|
|
1058
|
+
if (props.onError) {
|
|
1059
|
+
props.onError(error);
|
|
1060
|
+
return;
|
|
1061
|
+
}
|
|
1062
|
+
if (!isNotAllowedError(error)) {
|
|
1063
|
+
console.error('Call control handler failed', error);
|
|
1064
|
+
}
|
|
1065
|
+
}
|
|
1066
|
+
};
|
|
1067
|
+
};
|
|
1068
|
+
function isNotAllowedError(error) {
|
|
1069
|
+
return error instanceof DOMException && error.name === 'NotAllowedError';
|
|
1070
|
+
}
|
|
1071
|
+
|
|
1072
|
+
const RecordEndConfirmation = (props) => {
|
|
1046
1073
|
const { t } = videoReactBindings.useI18n();
|
|
1047
1074
|
const { toggleCallRecording, isAwaitingResponse } = videoReactBindings.useToggleCallRecording();
|
|
1048
1075
|
const { close } = useMenuContext();
|
|
1049
|
-
|
|
1076
|
+
const handleClick = createCallControlHandler(props, toggleCallRecording);
|
|
1077
|
+
return (jsxRuntime.jsxs("div", { className: "str-video__end-recording__confirmation", children: [jsxRuntime.jsxs("div", { className: "str-video__end-recording__header", children: [jsxRuntime.jsx(Icon, { icon: "recording-on" }), jsxRuntime.jsx("h2", { className: "str-video__end-recording__heading", children: t('End recording') })] }), jsxRuntime.jsx("p", { className: "str-video__end-recording__description", children: t('Are you sure you want end the recording?') }), jsxRuntime.jsxs("div", { className: "str-video__end-recording__actions", children: [jsxRuntime.jsx(CompositeButton, { variant: "secondary", onClick: close, children: t('Cancel') }), jsxRuntime.jsx(CompositeButton, { variant: "primary", onClick: isAwaitingResponse ? undefined : handleClick, children: isAwaitingResponse ? jsxRuntime.jsx(LoadingIndicator, {}) : t('End recording') })] })] }));
|
|
1050
1078
|
};
|
|
1051
1079
|
const ToggleEndRecordingMenuButton = react.forwardRef(function ToggleEndRecordingMenuButton(props, ref) {
|
|
1052
1080
|
return (jsxRuntime.jsx(CompositeButton, { ref: ref, active: true, variant: "secondary", "data-testid": "recording-stop-button", children: jsxRuntime.jsx(Icon, { icon: "recording-off" }) }));
|
|
1053
1081
|
});
|
|
1054
|
-
const RecordCallConfirmationButton = (
|
|
1082
|
+
const RecordCallConfirmationButton = (props) => {
|
|
1083
|
+
const { caption } = props;
|
|
1055
1084
|
const { t } = videoReactBindings.useI18n();
|
|
1056
1085
|
const { toggleCallRecording, isAwaitingResponse, isCallRecordingInProgress } = videoReactBindings.useToggleCallRecording();
|
|
1086
|
+
const handleClick = createCallControlHandler(props, toggleCallRecording);
|
|
1057
1087
|
if (isCallRecordingInProgress) {
|
|
1058
1088
|
return (jsxRuntime.jsx(videoReactBindings.Restricted, { requiredGrants: [
|
|
1059
1089
|
videoClient.OwnCapability.START_RECORD_CALL,
|
|
1060
1090
|
videoClient.OwnCapability.STOP_RECORD_CALL,
|
|
1061
|
-
], children: jsxRuntime.jsx(MenuToggle, { ToggleButton: ToggleEndRecordingMenuButton, visualType: exports.MenuVisualType.PORTAL, children: jsxRuntime.jsx(RecordEndConfirmation, {}) }) }));
|
|
1091
|
+
], children: jsxRuntime.jsx(MenuToggle, { ToggleButton: ToggleEndRecordingMenuButton, visualType: exports.MenuVisualType.PORTAL, children: jsxRuntime.jsx(RecordEndConfirmation, { onError: props.onError }) }) }));
|
|
1062
1092
|
}
|
|
1063
1093
|
const title = isAwaitingResponse
|
|
1064
1094
|
? t('Waiting for recording to start...')
|
|
@@ -1066,11 +1096,13 @@ const RecordCallConfirmationButton = ({ caption, }) => {
|
|
|
1066
1096
|
return (jsxRuntime.jsx(videoReactBindings.Restricted, { requiredGrants: [
|
|
1067
1097
|
videoClient.OwnCapability.START_RECORD_CALL,
|
|
1068
1098
|
videoClient.OwnCapability.STOP_RECORD_CALL,
|
|
1069
|
-
], children: jsxRuntime.jsx(WithTooltip, { title: title, children: jsxRuntime.jsx(CompositeButton, { active: isCallRecordingInProgress, caption: caption, variant: "secondary", "data-testid": "recording-start-button", onClick: isAwaitingResponse ? undefined :
|
|
1099
|
+
], children: jsxRuntime.jsx(WithTooltip, { title: title, children: jsxRuntime.jsx(CompositeButton, { active: isCallRecordingInProgress, caption: caption, variant: "secondary", "data-testid": "recording-start-button", onClick: isAwaitingResponse ? undefined : handleClick, children: isAwaitingResponse ? (jsxRuntime.jsx(LoadingIndicator, {})) : (jsxRuntime.jsx(Icon, { icon: "recording-off" })) }) }) }));
|
|
1070
1100
|
};
|
|
1071
|
-
const RecordCallButton = (
|
|
1101
|
+
const RecordCallButton = (props) => {
|
|
1102
|
+
const { caption } = props;
|
|
1072
1103
|
const { t } = videoReactBindings.useI18n();
|
|
1073
1104
|
const { toggleCallRecording, isAwaitingResponse, isCallRecordingInProgress } = videoReactBindings.useToggleCallRecording();
|
|
1105
|
+
const handleClick = createCallControlHandler(props, toggleCallRecording);
|
|
1074
1106
|
let title = caption ?? t('Record call');
|
|
1075
1107
|
if (isAwaitingResponse) {
|
|
1076
1108
|
title = isCallRecordingInProgress
|
|
@@ -1082,7 +1114,7 @@ const RecordCallButton = ({ caption }) => {
|
|
|
1082
1114
|
videoClient.OwnCapability.STOP_RECORD_CALL,
|
|
1083
1115
|
], children: jsxRuntime.jsx(CompositeButton, { active: isCallRecordingInProgress, caption: caption, variant: "secondary", "data-testid": isCallRecordingInProgress
|
|
1084
1116
|
? 'recording-stop-button'
|
|
1085
|
-
: 'recording-start-button', title: title, onClick: isAwaitingResponse ? undefined :
|
|
1117
|
+
: 'recording-start-button', title: title, onClick: isAwaitingResponse ? undefined : handleClick, children: isAwaitingResponse ? (jsxRuntime.jsx(LoadingIndicator, {})) : (jsxRuntime.jsx(Icon, { icon: isCallRecordingInProgress ? 'recording-on' : 'recording-off' })) }) }));
|
|
1086
1118
|
};
|
|
1087
1119
|
|
|
1088
1120
|
const defaultEmojiReactionMap = {
|
|
@@ -1157,33 +1189,6 @@ const DefaultReactionsMenu = ({ reactions, layout = 'horizontal', }) => {
|
|
|
1157
1189
|
}, children: reaction.emoji_code && defaultEmojiReactionMap[reaction.emoji_code] }, reaction.emoji_code))) }));
|
|
1158
1190
|
};
|
|
1159
1191
|
|
|
1160
|
-
/**
|
|
1161
|
-
* Wraps an event handler, silencing and logging exceptions (excluding the NotAllowedError
|
|
1162
|
-
* DOMException, which is a normal situation handled by the SDK)
|
|
1163
|
-
*
|
|
1164
|
-
* @param props component props, including the onError callback
|
|
1165
|
-
* @param handler event handler to wrap
|
|
1166
|
-
*/
|
|
1167
|
-
const createCallControlHandler = (props, handler) => {
|
|
1168
|
-
return async () => {
|
|
1169
|
-
try {
|
|
1170
|
-
await handler();
|
|
1171
|
-
}
|
|
1172
|
-
catch (error) {
|
|
1173
|
-
if (props.onError) {
|
|
1174
|
-
props.onError(error);
|
|
1175
|
-
return;
|
|
1176
|
-
}
|
|
1177
|
-
if (!isNotAllowedError(error)) {
|
|
1178
|
-
console.error('Call control handler failed', error);
|
|
1179
|
-
}
|
|
1180
|
-
}
|
|
1181
|
-
};
|
|
1182
|
-
};
|
|
1183
|
-
function isNotAllowedError(error) {
|
|
1184
|
-
return error instanceof DOMException && error.name === 'NotAllowedError';
|
|
1185
|
-
}
|
|
1186
|
-
|
|
1187
1192
|
const ScreenShareButton = (props) => {
|
|
1188
1193
|
const { t } = videoReactBindings.useI18n();
|
|
1189
1194
|
const { caption, optimisticUpdates } = props;
|
|
@@ -1347,7 +1352,7 @@ const SpeakerTest = (props) => {
|
|
|
1347
1352
|
const audioElementRef = react.useRef(null);
|
|
1348
1353
|
const [isPlaying, setIsPlaying] = react.useState(false);
|
|
1349
1354
|
const { t } = videoReactBindings.useI18n();
|
|
1350
|
-
const { audioUrl = `https://unpkg.com/${"@stream-io/video-react-sdk"}@${"1.
|
|
1355
|
+
const { audioUrl = `https://unpkg.com/${"@stream-io/video-react-sdk"}@${"1.34.1"}/assets/piano.mp3`, } = props;
|
|
1351
1356
|
// Update audio output device when selection changes
|
|
1352
1357
|
react.useEffect(() => {
|
|
1353
1358
|
const audio = audioElementRef.current;
|
|
@@ -1582,7 +1587,7 @@ const CancelCallButton = ({ disabled, caption, onClick, onLeave, }) => {
|
|
|
1582
1587
|
return (jsxRuntime.jsx(IconButton, { disabled: disabled, icon: "call-end", variant: "danger", title: caption ?? t('Leave call'), "data-testid": "cancel-call-button", onClick: handleClick }));
|
|
1583
1588
|
};
|
|
1584
1589
|
|
|
1585
|
-
const CallControls = ({ onLeave }) => (jsxRuntime.jsxs("div", { className: "str-video__call-controls", children: [jsxRuntime.jsx(videoReactBindings.Restricted, { requiredGrants: [videoClient.OwnCapability.SEND_AUDIO], children: jsxRuntime.jsx(
|
|
1590
|
+
const CallControls = ({ onLeave }) => (jsxRuntime.jsxs("div", { className: "str-video__call-controls", children: [jsxRuntime.jsx(videoReactBindings.Restricted, { requiredGrants: [videoClient.OwnCapability.SEND_AUDIO], children: jsxRuntime.jsx(SpeakingWhileMutedNotification, { children: jsxRuntime.jsx(ToggleAudioPublishingButton, {}) }) }), jsxRuntime.jsx(videoReactBindings.Restricted, { requiredGrants: [videoClient.OwnCapability.SEND_VIDEO], children: jsxRuntime.jsx(ToggleVideoPublishingButton, {}) }), jsxRuntime.jsx(videoReactBindings.Restricted, { requiredGrants: [videoClient.OwnCapability.CREATE_REACTION], children: jsxRuntime.jsx(ReactionsButton, {}) }), jsxRuntime.jsx(videoReactBindings.Restricted, { requiredGrants: [videoClient.OwnCapability.SCREENSHARE], children: jsxRuntime.jsx(ScreenShareButton, {}) }), jsxRuntime.jsx(videoReactBindings.Restricted, { requiredGrants: [
|
|
1586
1591
|
videoClient.OwnCapability.START_RECORD_CALL,
|
|
1587
1592
|
videoClient.OwnCapability.STOP_RECORD_CALL,
|
|
1588
1593
|
], children: jsxRuntime.jsx(RecordCallButton, {}) }), jsxRuntime.jsx(CancelCallButton, { onLeave: onLeave })] }));
|
|
@@ -2288,7 +2293,9 @@ const ParticipantDetails = ({ indicatorsVisible = true, }) => {
|
|
|
2288
2293
|
const hasVideoTrack = videoClient.hasVideo(participant);
|
|
2289
2294
|
const canUnpin = !!pin && pin.isLocalPin;
|
|
2290
2295
|
const isTrackPaused = trackType !== 'none' ? videoClient.hasPausedTrack(participant, trackType) : false;
|
|
2291
|
-
|
|
2296
|
+
const isAudioTrackUnmuted = useIsTrackUnmuted(participant);
|
|
2297
|
+
const isAudioConnecting = hasAudioTrack && !isAudioTrackUnmuted;
|
|
2298
|
+
return (jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [jsxRuntime.jsx("div", { className: "str-video__participant-details", children: jsxRuntime.jsxs("div", { className: "str-video__participant-details__name", children: [name || userId, indicatorsVisible && isAudioConnecting && (jsxRuntime.jsx(LoadingIndicator, { className: "str-video__participant-details__name--audio-connecting", tooltip: t('Audio is connecting...') })), indicatorsVisible && !hasAudioTrack && (jsxRuntime.jsx("span", { className: "str-video__participant-details__name--audio-muted" })), indicatorsVisible && !hasVideoTrack && (jsxRuntime.jsx("span", { className: "str-video__participant-details__name--video-muted" })), indicatorsVisible && isTrackPaused && (jsxRuntime.jsx("span", { title: t('Video paused due to insufficient bandwidth'), className: "str-video__participant-details__name--track-paused" })), indicatorsVisible && canUnpin && (
|
|
2292
2299
|
// TODO: remove this monstrosity once we have a proper design
|
|
2293
2300
|
jsxRuntime.jsx("span", { title: t('Unpin'), onClick: () => call?.unpin(sessionId), className: "str-video__participant-details__name--pinned" })), indicatorsVisible && jsxRuntime.jsx(SpeechIndicator, {})] }) }), indicatorsVisible && (jsxRuntime.jsx(Notification, { isVisible: isLocalParticipant &&
|
|
2294
2301
|
connectionQuality === videoClient.SfuModels.ConnectionQuality.POOR, message: t('Poor connection quality'), children: connectionQualityAsString && (jsxRuntime.jsx("span", { className: clsx('str-video__participant-details__connection-quality', `str-video__participant-details__connection-quality--${connectionQualityAsString}`), title: connectionQualityAsString })) }))] }));
|
|
@@ -2298,6 +2305,29 @@ const SpeechIndicator = () => {
|
|
|
2298
2305
|
const { isSpeaking, isDominantSpeaker } = participant;
|
|
2299
2306
|
return (jsxRuntime.jsxs("span", { className: clsx('str-video__speech-indicator', isSpeaking && 'str-video__speech-indicator--speaking', isDominantSpeaker && 'str-video__speech-indicator--dominant'), children: [jsxRuntime.jsx("span", { className: "str-video__speech-indicator__bar" }), jsxRuntime.jsx("span", { className: "str-video__speech-indicator__bar" }), jsxRuntime.jsx("span", { className: "str-video__speech-indicator__bar" })] }));
|
|
2300
2307
|
};
|
|
2308
|
+
const useIsTrackUnmuted = (participant) => {
|
|
2309
|
+
const audioStream = participant.audioStream;
|
|
2310
|
+
const [unmuted, setUnmuted] = react.useState(() => {
|
|
2311
|
+
const track = audioStream?.getAudioTracks()[0];
|
|
2312
|
+
return !!track && !track.muted;
|
|
2313
|
+
});
|
|
2314
|
+
react.useEffect(() => {
|
|
2315
|
+
const track = audioStream?.getAudioTracks()[0];
|
|
2316
|
+
if (!track)
|
|
2317
|
+
return;
|
|
2318
|
+
setUnmuted(!track.muted);
|
|
2319
|
+
const handler = () => {
|
|
2320
|
+
setUnmuted(!track.muted);
|
|
2321
|
+
};
|
|
2322
|
+
track.addEventListener('mute', handler);
|
|
2323
|
+
track.addEventListener('unmute', handler);
|
|
2324
|
+
return () => {
|
|
2325
|
+
track.removeEventListener('mute', handler);
|
|
2326
|
+
track.removeEventListener('unmute', handler);
|
|
2327
|
+
};
|
|
2328
|
+
}, [audioStream]);
|
|
2329
|
+
return unmuted;
|
|
2330
|
+
};
|
|
2301
2331
|
|
|
2302
2332
|
const ParticipantView = react.forwardRef(function ParticipantView({ participant, trackType = 'videoTrack', mirror, muteAudio, refs: { setVideoElement, setVideoPlaceholderElement } = {}, className, VideoPlaceholder, PictureInPicturePlaceholder, ParticipantViewUI = DefaultParticipantViewUI, }, ref) {
|
|
2303
2333
|
const { isLocalParticipant, isSpeaking, isDominantSpeaker, sessionId } = participant;
|
|
@@ -2468,6 +2498,7 @@ var en = {
|
|
|
2468
2498
|
"Dominant Speaker": "Dominant Speaker",
|
|
2469
2499
|
"Poor connection quality": "Poor connection quality. Please check your internet connection.",
|
|
2470
2500
|
"Video paused due to insufficient bandwidth": "Video paused due to insufficient bandwidth",
|
|
2501
|
+
"Audio is connecting...": "Audio is connecting...",
|
|
2471
2502
|
Participants: Participants,
|
|
2472
2503
|
Anonymous: Anonymous,
|
|
2473
2504
|
"No participants found": "No participants found",
|
|
@@ -3144,7 +3175,7 @@ const checkCanJoinEarly = (startsAt, joinAheadTimeSeconds) => {
|
|
|
3144
3175
|
return Date.now() >= +startsAt - (joinAheadTimeSeconds ?? 0) * 1000;
|
|
3145
3176
|
};
|
|
3146
3177
|
|
|
3147
|
-
const [major, minor, patch] = ("1.
|
|
3178
|
+
const [major, minor, patch] = ("1.34.1").split('.');
|
|
3148
3179
|
videoClient.setSdkInfo({
|
|
3149
3180
|
type: videoClient.SfuModels.SdkType.REACT,
|
|
3150
3181
|
major,
|