@stream-io/video-react-sdk 1.36.1 → 1.37.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 +17 -0
- package/dist/css/embedded.css +60 -54
- package/dist/css/embedded.css.map +1 -1
- package/dist/css/styles.css +50 -44
- package/dist/css/styles.css.map +1 -1
- package/dist/embedded.cjs.js +40 -24
- package/dist/embedded.cjs.js.map +1 -1
- package/dist/embedded.es.js +41 -25
- package/dist/embedded.es.js.map +1 -1
- package/dist/index.cjs.js +54 -26
- package/dist/index.cjs.js.map +1 -1
- package/dist/index.es.js +54 -26
- package/dist/index.es.js.map +1 -1
- package/dist/src/core/hooks/useTrackElementVisibility.d.ts +2 -3
- package/dist/src/translations/index.d.ts +2 -0
- package/package.json +5 -5
- package/src/components/CallControls/ToggleAudioButton.tsx +32 -5
- package/src/components/CallControls/ToggleVideoButton.tsx +36 -5
- package/src/core/components/CallLayout/LivestreamLayout.tsx +17 -1
- package/src/core/components/CallLayout/PaginatedGridLayout.tsx +1 -1
- package/src/core/components/CallLayout/SpeakerLayout.tsx +1 -1
- package/src/core/components/ParticipantView/ParticipantView.tsx +0 -1
- package/src/core/hooks/useTrackElementVisibility.ts +4 -14
- package/src/translations/en.json +2 -0
package/dist/embedded.cjs.js
CHANGED
|
@@ -665,17 +665,13 @@ const Video$1 = ({ enabled = true, mirror, trackType, participant, className, Vi
|
|
|
665
665
|
};
|
|
666
666
|
Video$1.displayName = 'Video';
|
|
667
667
|
|
|
668
|
-
const useTrackElementVisibility = ({ trackedElement,
|
|
668
|
+
const useTrackElementVisibility = ({ trackedElement, sessionId, trackType, }) => {
|
|
669
669
|
const call = videoReactBindings.useCall();
|
|
670
|
-
const manager = propsDynascaleManager ?? call?.dynascaleManager;
|
|
671
670
|
react.useEffect(() => {
|
|
672
|
-
if (!trackedElement || !
|
|
671
|
+
if (!trackedElement || !call || trackType === 'none')
|
|
673
672
|
return;
|
|
674
|
-
|
|
675
|
-
|
|
676
|
-
unobserve();
|
|
677
|
-
};
|
|
678
|
-
}, [trackedElement, manager, call, sessionId, trackType]);
|
|
673
|
+
return call.trackElementVisibility(trackedElement, sessionId, trackType);
|
|
674
|
+
}, [trackedElement, call, sessionId, trackType]);
|
|
679
675
|
};
|
|
680
676
|
|
|
681
677
|
const Avatar = ({ imageSrc, name, style, className, ...rest }) => {
|
|
@@ -1207,7 +1203,7 @@ const SpeakerTest = (props) => {
|
|
|
1207
1203
|
const audioElementRef = react.useRef(null);
|
|
1208
1204
|
const [isPlaying, setIsPlaying] = react.useState(false);
|
|
1209
1205
|
const { t } = videoReactBindings.useI18n();
|
|
1210
|
-
const { audioUrl = `https://unpkg.com/${"@stream-io/video-react-sdk"}@${"1.
|
|
1206
|
+
const { audioUrl = `https://unpkg.com/${"@stream-io/video-react-sdk"}@${"1.37.1"}/assets/piano.mp3`, } = props;
|
|
1211
1207
|
// Update audio output device when selection changes
|
|
1212
1208
|
react.useEffect(() => {
|
|
1213
1209
|
const audio = audioElementRef.current;
|
|
@@ -1316,25 +1312,31 @@ react.forwardRef(function ToggleDeviceSettingsMenuButton({ menuShown }, ref) {
|
|
|
1316
1312
|
const ToggleAudioPreviewButton = (props) => {
|
|
1317
1313
|
const { caption, Menu = DeviceSelectorAudioInput, menuPlacement = 'top', onMenuToggle, optimisticUpdates, ...restCompositeButtonProps } = props;
|
|
1318
1314
|
const { t } = videoReactBindings.useI18n();
|
|
1319
|
-
const { useMicrophoneState } = videoReactBindings.useCallStateHooks();
|
|
1315
|
+
const { useMicrophoneState, useLocalParticipant } = videoReactBindings.useCallStateHooks();
|
|
1320
1316
|
const { microphone, hasBrowserPermission, isPromptingPermission, optionsAwareIsMute, isTogglePending, } = useMicrophoneState({ optimisticUpdates });
|
|
1317
|
+
const localParticipant = useLocalParticipant();
|
|
1318
|
+
const isSystemMuted = !!localParticipant?.interruptedTracks?.includes(videoClient.SfuModels.TrackType.AUDIO);
|
|
1321
1319
|
const [tooltipDisabled, setTooltipDisabled] = react.useState(false);
|
|
1322
1320
|
const handleClick = createCallControlHandler(props, () => microphone.toggle());
|
|
1323
1321
|
return (jsxRuntime.jsx(WithTooltip, { title: !hasBrowserPermission
|
|
1324
1322
|
? t('Check your browser audio permissions')
|
|
1325
|
-
:
|
|
1323
|
+
: isSystemMuted
|
|
1324
|
+
? t('Microphone is paused by your system')
|
|
1325
|
+
: (caption ?? t('Mic')), tooltipDisabled: tooltipDisabled, children: jsxRuntime.jsxs(CompositeButton, { active: optionsAwareIsMute, caption: caption, className: clsx(!hasBrowserPermission && 'str-video__device-unavailable'), variant: "secondary", disabled: !hasBrowserPermission || (!optimisticUpdates && isTogglePending), "data-testid": optionsAwareIsMute
|
|
1326
1326
|
? 'preview-audio-unmute-button'
|
|
1327
1327
|
: 'preview-audio-mute-button', onClick: handleClick, Menu: Menu, menuPlacement: menuPlacement, ...restCompositeButtonProps, onMenuToggle: (shown) => {
|
|
1328
1328
|
setTooltipDisabled(shown);
|
|
1329
1329
|
onMenuToggle?.(shown);
|
|
1330
|
-
}, children: [jsxRuntime.jsx(Icon, { icon: !optionsAwareIsMute ? 'mic' : 'mic-off' }), !hasBrowserPermission && (jsxRuntime.jsx("span", { className: "str-video__no-media-permission", title: t('Check your browser audio permissions'), children: "!" })), isPromptingPermission && (jsxRuntime.jsx("span", { className: "str-video__pending-permission", title: t('Waiting for permission'), children: "?" }))] }) }));
|
|
1330
|
+
}, children: [jsxRuntime.jsx(Icon, { icon: !optionsAwareIsMute ? 'mic' : 'mic-off' }), !hasBrowserPermission && (jsxRuntime.jsx("span", { className: "str-video__no-media-permission", title: t('Check your browser audio permissions'), children: "!" })), isPromptingPermission && (jsxRuntime.jsx("span", { className: "str-video__pending-permission", title: t('Waiting for permission'), children: "?" })), isSystemMuted && hasBrowserPermission && (jsxRuntime.jsx("span", { className: "str-video__system-muted", title: t('Microphone is paused by your system'), children: "!" }))] }) }));
|
|
1331
1331
|
};
|
|
1332
1332
|
const ToggleAudioPublishingButton = (props) => {
|
|
1333
1333
|
const { t } = videoReactBindings.useI18n();
|
|
1334
1334
|
const { caption, Menu = jsxRuntime.jsx(DeviceSelectorAudioInput, { visualType: "list" }), menuPlacement = 'top', onMenuToggle, optimisticUpdates, ...restCompositeButtonProps } = props;
|
|
1335
1335
|
const { hasPermission, requestPermission, isAwaitingPermission } = useRequestPermission(videoClient.OwnCapability.SEND_AUDIO);
|
|
1336
|
-
const { useMicrophoneState } = videoReactBindings.useCallStateHooks();
|
|
1336
|
+
const { useMicrophoneState, useLocalParticipant } = videoReactBindings.useCallStateHooks();
|
|
1337
1337
|
const { microphone, hasBrowserPermission, isPromptingPermission, isTogglePending, optionsAwareIsMute, } = useMicrophoneState({ optimisticUpdates });
|
|
1338
|
+
const localParticipant = useLocalParticipant();
|
|
1339
|
+
const isSystemMuted = !!localParticipant?.interruptedTracks?.includes(videoClient.SfuModels.TrackType.AUDIO);
|
|
1338
1340
|
const [tooltipDisabled, setTooltipDisabled] = react.useState(false);
|
|
1339
1341
|
const handleClick = createCallControlHandler(props, async () => {
|
|
1340
1342
|
if (!hasPermission) {
|
|
@@ -1348,37 +1350,45 @@ const ToggleAudioPublishingButton = (props) => {
|
|
|
1348
1350
|
? t('You have no permission to share your audio')
|
|
1349
1351
|
: !hasBrowserPermission
|
|
1350
1352
|
? t('Check your browser mic permissions')
|
|
1351
|
-
:
|
|
1353
|
+
: isSystemMuted
|
|
1354
|
+
? t('Microphone is paused by your system')
|
|
1355
|
+
: (caption ?? t('Mic')), tooltipDisabled: tooltipDisabled, children: jsxRuntime.jsxs(CompositeButton, { active: optionsAwareIsMute, caption: caption, variant: "secondary", disabled: !hasBrowserPermission ||
|
|
1352
1356
|
!hasPermission ||
|
|
1353
1357
|
// disable button while the toggle action is pending when not using optimistic updates
|
|
1354
1358
|
(!optimisticUpdates && isTogglePending), "data-testid": optionsAwareIsMute ? 'audio-unmute-button' : 'audio-mute-button', onClick: handleClick, Menu: Menu, menuPlacement: menuPlacement, menuOffset: 16, ...restCompositeButtonProps, onMenuToggle: (shown) => {
|
|
1355
1359
|
setTooltipDisabled(shown);
|
|
1356
1360
|
onMenuToggle?.(shown);
|
|
1357
|
-
}, children: [jsxRuntime.jsx(Icon, { icon: optionsAwareIsMute ? 'mic-off' : 'mic' }), (!hasBrowserPermission || !hasPermission) && (jsxRuntime.jsx("span", { className: "str-video__no-media-permission", children: "!" })), isPromptingPermission && (jsxRuntime.jsx("span", { className: "str-video__pending-permission", title: t('Waiting for permission'), children: "?" }))] }) }) }) }));
|
|
1361
|
+
}, children: [jsxRuntime.jsx(Icon, { icon: optionsAwareIsMute ? 'mic-off' : 'mic' }), (!hasBrowserPermission || !hasPermission) && (jsxRuntime.jsx("span", { className: "str-video__no-media-permission", children: "!" })), isPromptingPermission && (jsxRuntime.jsx("span", { className: "str-video__pending-permission", title: t('Waiting for permission'), children: "?" })), isSystemMuted && hasBrowserPermission && hasPermission && (jsxRuntime.jsx("span", { className: "str-video__system-muted", title: t('Microphone is paused by your system'), children: "!" }))] }) }) }) }));
|
|
1358
1362
|
};
|
|
1359
1363
|
|
|
1360
1364
|
const ToggleVideoPreviewButton = (props) => {
|
|
1361
1365
|
const { caption, Menu = DeviceSelectorVideo, menuPlacement = 'top', onMenuToggle, optimisticUpdates, ...restCompositeButtonProps } = props;
|
|
1362
1366
|
const { t } = videoReactBindings.useI18n();
|
|
1363
|
-
const { useCameraState } = videoReactBindings.useCallStateHooks();
|
|
1367
|
+
const { useCameraState, useLocalParticipant } = videoReactBindings.useCallStateHooks();
|
|
1364
1368
|
const { camera, hasBrowserPermission, isPromptingPermission, isTogglePending, optionsAwareIsMute, } = useCameraState({ optimisticUpdates });
|
|
1369
|
+
const localParticipant = useLocalParticipant();
|
|
1370
|
+
const isSystemMuted = !!localParticipant?.interruptedTracks?.includes(videoClient.SfuModels.TrackType.VIDEO);
|
|
1365
1371
|
const [tooltipDisabled, setTooltipDisabled] = react.useState(false);
|
|
1366
1372
|
const handleClick = createCallControlHandler(props, () => camera.toggle());
|
|
1367
1373
|
return (jsxRuntime.jsx(WithTooltip, { title: !hasBrowserPermission
|
|
1368
1374
|
? t('Check your browser video permissions')
|
|
1369
|
-
:
|
|
1375
|
+
: isSystemMuted
|
|
1376
|
+
? t('Camera is paused by your system')
|
|
1377
|
+
: (caption ?? t('Video')), tooltipDisabled: tooltipDisabled, children: jsxRuntime.jsxs(CompositeButton, { active: optionsAwareIsMute, caption: caption, className: clsx(!hasBrowserPermission && 'str-video__device-unavailable'), variant: "secondary", "data-testid": optionsAwareIsMute
|
|
1370
1378
|
? 'preview-video-unmute-button'
|
|
1371
1379
|
: 'preview-video-mute-button', onClick: handleClick, disabled: !hasBrowserPermission || (!optimisticUpdates && isTogglePending), Menu: Menu, menuPlacement: menuPlacement, ...restCompositeButtonProps, onMenuToggle: (shown) => {
|
|
1372
1380
|
setTooltipDisabled(shown);
|
|
1373
1381
|
onMenuToggle?.(shown);
|
|
1374
|
-
}, children: [jsxRuntime.jsx(Icon, { icon: !optionsAwareIsMute ? 'camera' : 'camera-off' }), !hasBrowserPermission && (jsxRuntime.jsx("span", { className: "str-video__no-media-permission", title: t('Check your browser video permissions'), children: "!" })), isPromptingPermission && (jsxRuntime.jsx("span", { className: "str-video__pending-permission", title: t('Waiting for permission'), children: "?" }))] }) }));
|
|
1382
|
+
}, children: [jsxRuntime.jsx(Icon, { icon: !optionsAwareIsMute ? 'camera' : 'camera-off' }), !hasBrowserPermission && (jsxRuntime.jsx("span", { className: "str-video__no-media-permission", title: t('Check your browser video permissions'), children: "!" })), isPromptingPermission && (jsxRuntime.jsx("span", { className: "str-video__pending-permission", title: t('Waiting for permission'), children: "?" })), isSystemMuted && hasBrowserPermission && (jsxRuntime.jsx("span", { className: "str-video__system-muted", title: t('Camera is paused by your system'), children: "!" }))] }) }));
|
|
1375
1383
|
};
|
|
1376
1384
|
const ToggleVideoPublishingButton = (props) => {
|
|
1377
1385
|
const { t } = videoReactBindings.useI18n();
|
|
1378
1386
|
const { caption, Menu = jsxRuntime.jsx(DeviceSelectorVideo, { visualType: "list" }), menuPlacement = 'top', onMenuToggle, optimisticUpdates, ...restCompositeButtonProps } = props;
|
|
1379
1387
|
const { hasPermission, requestPermission, isAwaitingPermission } = useRequestPermission(videoClient.OwnCapability.SEND_VIDEO);
|
|
1380
|
-
const { useCameraState, useCallSettings } = videoReactBindings.useCallStateHooks();
|
|
1388
|
+
const { useCameraState, useCallSettings, useLocalParticipant } = videoReactBindings.useCallStateHooks();
|
|
1381
1389
|
const { camera, optionsAwareIsMute, hasBrowserPermission, isPromptingPermission, isTogglePending, } = useCameraState({ optimisticUpdates });
|
|
1390
|
+
const localParticipant = useLocalParticipant();
|
|
1391
|
+
const isSystemMuted = !!localParticipant?.interruptedTracks?.includes(videoClient.SfuModels.TrackType.VIDEO);
|
|
1382
1392
|
const callSettings = useCallSettings();
|
|
1383
1393
|
const isPublishingVideoAllowed = callSettings?.video.enabled;
|
|
1384
1394
|
const [tooltipDisabled, setTooltipDisabled] = react.useState(false);
|
|
@@ -1396,7 +1406,9 @@ const ToggleVideoPublishingButton = (props) => {
|
|
|
1396
1406
|
? t('Check your browser video permissions')
|
|
1397
1407
|
: !isPublishingVideoAllowed
|
|
1398
1408
|
? t('Video publishing is disabled by the system')
|
|
1399
|
-
:
|
|
1409
|
+
: isSystemMuted
|
|
1410
|
+
? t('Camera is paused by your system')
|
|
1411
|
+
: caption || t('Video'), tooltipDisabled: tooltipDisabled, children: jsxRuntime.jsxs(CompositeButton, { active: optionsAwareIsMute, caption: caption, variant: "secondary", disabled: !hasBrowserPermission ||
|
|
1400
1412
|
!hasPermission ||
|
|
1401
1413
|
!isPublishingVideoAllowed ||
|
|
1402
1414
|
(!optimisticUpdates && isTogglePending), "data-testid": optionsAwareIsMute ? 'video-unmute-button' : 'video-mute-button', onClick: handleClick, Menu: Menu, menuPlacement: menuPlacement, menuOffset: 16, ...restCompositeButtonProps, onMenuToggle: (shown) => {
|
|
@@ -1404,7 +1416,10 @@ const ToggleVideoPublishingButton = (props) => {
|
|
|
1404
1416
|
onMenuToggle?.(shown);
|
|
1405
1417
|
}, children: [jsxRuntime.jsx(Icon, { icon: optionsAwareIsMute ? 'camera-off' : 'camera' }), (!hasBrowserPermission ||
|
|
1406
1418
|
!hasPermission ||
|
|
1407
|
-
!isPublishingVideoAllowed) && (jsxRuntime.jsx("span", { className: "str-video__no-media-permission", children: "!" })), isPromptingPermission && (jsxRuntime.jsx("span", { className: "str-video__pending-permission", title: t('Waiting for permission'), children: "?" }))
|
|
1419
|
+
!isPublishingVideoAllowed) && (jsxRuntime.jsx("span", { className: "str-video__no-media-permission", children: "!" })), isPromptingPermission && (jsxRuntime.jsx("span", { className: "str-video__pending-permission", title: t('Waiting for permission'), children: "?" })), isSystemMuted &&
|
|
1420
|
+
hasBrowserPermission &&
|
|
1421
|
+
hasPermission &&
|
|
1422
|
+
isPublishingVideoAllowed && (jsxRuntime.jsx("span", { className: "str-video__system-muted", title: t('Camera is paused by your system'), children: "!" }))] }) }) }) }));
|
|
1408
1423
|
};
|
|
1409
1424
|
|
|
1410
1425
|
const EndCallMenu = (props) => {
|
|
@@ -1902,7 +1917,6 @@ const ParticipantView = react.forwardRef(function ParticipantView({ participant,
|
|
|
1902
1917
|
const [trackedElement, setTrackedElement] = react.useState(null);
|
|
1903
1918
|
const [contextVideoElement, setContextVideoElement] = react.useState(null);
|
|
1904
1919
|
const [contextVideoPlaceholderElement, setContextVideoPlaceholderElement] = react.useState(null);
|
|
1905
|
-
// TODO: allow to pass custom ViewportTracker instance from props
|
|
1906
1920
|
useTrackElementVisibility({
|
|
1907
1921
|
sessionId,
|
|
1908
1922
|
trackedElement,
|
|
@@ -2033,8 +2047,10 @@ var en = {
|
|
|
2033
2047
|
Dismiss: Dismiss,
|
|
2034
2048
|
"Microphone on": "Microphone on",
|
|
2035
2049
|
"Microphone off": "Microphone off",
|
|
2050
|
+
"Microphone is paused by your system": "Microphone is paused by your system",
|
|
2036
2051
|
"Camera on": "Camera on",
|
|
2037
2052
|
"Camera off": "Camera off",
|
|
2053
|
+
"Camera is paused by your system": "Camera is paused by your system",
|
|
2038
2054
|
"No camera found": "No camera found",
|
|
2039
2055
|
"Video is disabled": "Video is disabled",
|
|
2040
2056
|
Pinned: Pinned,
|
|
@@ -2421,7 +2437,7 @@ const PaginatedGridLayout = (props) => {
|
|
|
2421
2437
|
if (!paginatedGridLayoutWrapperElement || !call)
|
|
2422
2438
|
return;
|
|
2423
2439
|
const cleanup = call.setViewport(paginatedGridLayoutWrapperElement);
|
|
2424
|
-
return () => cleanup();
|
|
2440
|
+
return () => cleanup?.();
|
|
2425
2441
|
}, [paginatedGridLayoutWrapperElement, call]);
|
|
2426
2442
|
// only used to render video elements
|
|
2427
2443
|
const participantGroups = react.useMemo(() => chunk(participants, groupSize), [participants, groupSize]);
|
|
@@ -2513,7 +2529,7 @@ const SpeakerLayout = ({ ParticipantViewUIBar = DefaultParticipantViewUIBar, Par
|
|
|
2513
2529
|
if (!participantsBarWrapperElement || !call)
|
|
2514
2530
|
return;
|
|
2515
2531
|
const cleanup = call.setViewport(participantsBarWrapperElement);
|
|
2516
|
-
return () => cleanup();
|
|
2532
|
+
return () => cleanup?.();
|
|
2517
2533
|
}, [participantsBarWrapperElement, call]);
|
|
2518
2534
|
const isOneOnOneCall = allParticipants.length === 2;
|
|
2519
2535
|
useSpeakerLayoutSortPreset(call, isOneOnOneCall);
|