@stream-io/video-react-sdk 1.36.1 → 1.37.0
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 +13 -0
- package/dist/css/embedded.css +6 -0
- package/dist/css/embedded.css.map +1 -1
- package/dist/css/styles.css +6 -0
- 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 +41 -25
- package/dist/index.cjs.js.map +1 -1
- package/dist/index.es.js +41 -25
- 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/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/index.es.js
CHANGED
|
@@ -807,17 +807,13 @@ const Video$1 = ({ enabled = true, mirror, trackType, participant, className, Vi
|
|
|
807
807
|
};
|
|
808
808
|
Video$1.displayName = 'Video';
|
|
809
809
|
|
|
810
|
-
const useTrackElementVisibility = ({ trackedElement,
|
|
810
|
+
const useTrackElementVisibility = ({ trackedElement, sessionId, trackType, }) => {
|
|
811
811
|
const call = useCall();
|
|
812
|
-
const manager = propsDynascaleManager ?? call?.dynascaleManager;
|
|
813
812
|
useEffect(() => {
|
|
814
|
-
if (!trackedElement || !
|
|
813
|
+
if (!trackedElement || !call || trackType === 'none')
|
|
815
814
|
return;
|
|
816
|
-
|
|
817
|
-
|
|
818
|
-
unobserve();
|
|
819
|
-
};
|
|
820
|
-
}, [trackedElement, manager, call, sessionId, trackType]);
|
|
815
|
+
return call.trackElementVisibility(trackedElement, sessionId, trackType);
|
|
816
|
+
}, [trackedElement, call, sessionId, trackType]);
|
|
821
817
|
};
|
|
822
818
|
|
|
823
819
|
const Avatar = ({ imageSrc, name, style, className, ...rest }) => {
|
|
@@ -1403,7 +1399,7 @@ const SpeakerTest = (props) => {
|
|
|
1403
1399
|
const audioElementRef = useRef(null);
|
|
1404
1400
|
const [isPlaying, setIsPlaying] = useState(false);
|
|
1405
1401
|
const { t } = useI18n();
|
|
1406
|
-
const { audioUrl = `https://unpkg.com/${"@stream-io/video-react-sdk"}@${"1.
|
|
1402
|
+
const { audioUrl = `https://unpkg.com/${"@stream-io/video-react-sdk"}@${"1.37.0"}/assets/piano.mp3`, } = props;
|
|
1407
1403
|
// Update audio output device when selection changes
|
|
1408
1404
|
useEffect(() => {
|
|
1409
1405
|
const audio = audioElementRef.current;
|
|
@@ -1519,25 +1515,31 @@ const ToggleDeviceSettingsMenuButton = forwardRef(function ToggleDeviceSettingsM
|
|
|
1519
1515
|
const ToggleAudioPreviewButton = (props) => {
|
|
1520
1516
|
const { caption, Menu = DeviceSelectorAudioInput, menuPlacement = 'top', onMenuToggle, optimisticUpdates, ...restCompositeButtonProps } = props;
|
|
1521
1517
|
const { t } = useI18n();
|
|
1522
|
-
const { useMicrophoneState } = useCallStateHooks();
|
|
1518
|
+
const { useMicrophoneState, useLocalParticipant } = useCallStateHooks();
|
|
1523
1519
|
const { microphone, hasBrowserPermission, isPromptingPermission, optionsAwareIsMute, isTogglePending, } = useMicrophoneState({ optimisticUpdates });
|
|
1520
|
+
const localParticipant = useLocalParticipant();
|
|
1521
|
+
const isSystemMuted = !!localParticipant?.interruptedTracks?.includes(SfuModels.TrackType.AUDIO);
|
|
1524
1522
|
const [tooltipDisabled, setTooltipDisabled] = useState(false);
|
|
1525
1523
|
const handleClick = createCallControlHandler(props, () => microphone.toggle());
|
|
1526
1524
|
return (jsx(WithTooltip, { title: !hasBrowserPermission
|
|
1527
1525
|
? t('Check your browser audio permissions')
|
|
1528
|
-
:
|
|
1526
|
+
: isSystemMuted
|
|
1527
|
+
? t('Microphone is paused by your system')
|
|
1528
|
+
: (caption ?? t('Mic')), tooltipDisabled: tooltipDisabled, children: jsxs(CompositeButton, { active: optionsAwareIsMute, caption: caption, className: clsx(!hasBrowserPermission && 'str-video__device-unavailable'), variant: "secondary", disabled: !hasBrowserPermission || (!optimisticUpdates && isTogglePending), "data-testid": optionsAwareIsMute
|
|
1529
1529
|
? 'preview-audio-unmute-button'
|
|
1530
1530
|
: 'preview-audio-mute-button', onClick: handleClick, Menu: Menu, menuPlacement: menuPlacement, ...restCompositeButtonProps, onMenuToggle: (shown) => {
|
|
1531
1531
|
setTooltipDisabled(shown);
|
|
1532
1532
|
onMenuToggle?.(shown);
|
|
1533
|
-
}, children: [jsx(Icon, { icon: !optionsAwareIsMute ? 'mic' : 'mic-off' }), !hasBrowserPermission && (jsx("span", { className: "str-video__no-media-permission", title: t('Check your browser audio permissions'), children: "!" })), isPromptingPermission && (jsx("span", { className: "str-video__pending-permission", title: t('Waiting for permission'), children: "?" }))] }) }));
|
|
1533
|
+
}, children: [jsx(Icon, { icon: !optionsAwareIsMute ? 'mic' : 'mic-off' }), !hasBrowserPermission && (jsx("span", { className: "str-video__no-media-permission", title: t('Check your browser audio permissions'), children: "!" })), isPromptingPermission && (jsx("span", { className: "str-video__pending-permission", title: t('Waiting for permission'), children: "?" })), isSystemMuted && hasBrowserPermission && (jsx("span", { className: "str-video__system-muted", title: t('Microphone is paused by your system'), children: "!" }))] }) }));
|
|
1534
1534
|
};
|
|
1535
1535
|
const ToggleAudioPublishingButton = (props) => {
|
|
1536
1536
|
const { t } = useI18n();
|
|
1537
1537
|
const { caption, Menu = jsx(DeviceSelectorAudioInput, { visualType: "list" }), menuPlacement = 'top', onMenuToggle, optimisticUpdates, ...restCompositeButtonProps } = props;
|
|
1538
1538
|
const { hasPermission, requestPermission, isAwaitingPermission } = useRequestPermission(OwnCapability.SEND_AUDIO);
|
|
1539
|
-
const { useMicrophoneState } = useCallStateHooks();
|
|
1539
|
+
const { useMicrophoneState, useLocalParticipant } = useCallStateHooks();
|
|
1540
1540
|
const { microphone, hasBrowserPermission, isPromptingPermission, isTogglePending, optionsAwareIsMute, } = useMicrophoneState({ optimisticUpdates });
|
|
1541
|
+
const localParticipant = useLocalParticipant();
|
|
1542
|
+
const isSystemMuted = !!localParticipant?.interruptedTracks?.includes(SfuModels.TrackType.AUDIO);
|
|
1541
1543
|
const [tooltipDisabled, setTooltipDisabled] = useState(false);
|
|
1542
1544
|
const handleClick = createCallControlHandler(props, async () => {
|
|
1543
1545
|
if (!hasPermission) {
|
|
@@ -1551,37 +1553,45 @@ const ToggleAudioPublishingButton = (props) => {
|
|
|
1551
1553
|
? t('You have no permission to share your audio')
|
|
1552
1554
|
: !hasBrowserPermission
|
|
1553
1555
|
? t('Check your browser mic permissions')
|
|
1554
|
-
:
|
|
1556
|
+
: isSystemMuted
|
|
1557
|
+
? t('Microphone is paused by your system')
|
|
1558
|
+
: (caption ?? t('Mic')), tooltipDisabled: tooltipDisabled, children: jsxs(CompositeButton, { active: optionsAwareIsMute, caption: caption, variant: "secondary", disabled: !hasBrowserPermission ||
|
|
1555
1559
|
!hasPermission ||
|
|
1556
1560
|
// disable button while the toggle action is pending when not using optimistic updates
|
|
1557
1561
|
(!optimisticUpdates && isTogglePending), "data-testid": optionsAwareIsMute ? 'audio-unmute-button' : 'audio-mute-button', onClick: handleClick, Menu: Menu, menuPlacement: menuPlacement, menuOffset: 16, ...restCompositeButtonProps, onMenuToggle: (shown) => {
|
|
1558
1562
|
setTooltipDisabled(shown);
|
|
1559
1563
|
onMenuToggle?.(shown);
|
|
1560
|
-
}, children: [jsx(Icon, { icon: optionsAwareIsMute ? 'mic-off' : 'mic' }), (!hasBrowserPermission || !hasPermission) && (jsx("span", { className: "str-video__no-media-permission", children: "!" })), isPromptingPermission && (jsx("span", { className: "str-video__pending-permission", title: t('Waiting for permission'), children: "?" }))] }) }) }) }));
|
|
1564
|
+
}, children: [jsx(Icon, { icon: optionsAwareIsMute ? 'mic-off' : 'mic' }), (!hasBrowserPermission || !hasPermission) && (jsx("span", { className: "str-video__no-media-permission", children: "!" })), isPromptingPermission && (jsx("span", { className: "str-video__pending-permission", title: t('Waiting for permission'), children: "?" })), isSystemMuted && hasBrowserPermission && hasPermission && (jsx("span", { className: "str-video__system-muted", title: t('Microphone is paused by your system'), children: "!" }))] }) }) }) }));
|
|
1561
1565
|
};
|
|
1562
1566
|
|
|
1563
1567
|
const ToggleVideoPreviewButton = (props) => {
|
|
1564
1568
|
const { caption, Menu = DeviceSelectorVideo, menuPlacement = 'top', onMenuToggle, optimisticUpdates, ...restCompositeButtonProps } = props;
|
|
1565
1569
|
const { t } = useI18n();
|
|
1566
|
-
const { useCameraState } = useCallStateHooks();
|
|
1570
|
+
const { useCameraState, useLocalParticipant } = useCallStateHooks();
|
|
1567
1571
|
const { camera, hasBrowserPermission, isPromptingPermission, isTogglePending, optionsAwareIsMute, } = useCameraState({ optimisticUpdates });
|
|
1572
|
+
const localParticipant = useLocalParticipant();
|
|
1573
|
+
const isSystemMuted = !!localParticipant?.interruptedTracks?.includes(SfuModels.TrackType.VIDEO);
|
|
1568
1574
|
const [tooltipDisabled, setTooltipDisabled] = useState(false);
|
|
1569
1575
|
const handleClick = createCallControlHandler(props, () => camera.toggle());
|
|
1570
1576
|
return (jsx(WithTooltip, { title: !hasBrowserPermission
|
|
1571
1577
|
? t('Check your browser video permissions')
|
|
1572
|
-
:
|
|
1578
|
+
: isSystemMuted
|
|
1579
|
+
? t('Camera is paused by your system')
|
|
1580
|
+
: (caption ?? t('Video')), tooltipDisabled: tooltipDisabled, children: jsxs(CompositeButton, { active: optionsAwareIsMute, caption: caption, className: clsx(!hasBrowserPermission && 'str-video__device-unavailable'), variant: "secondary", "data-testid": optionsAwareIsMute
|
|
1573
1581
|
? 'preview-video-unmute-button'
|
|
1574
1582
|
: 'preview-video-mute-button', onClick: handleClick, disabled: !hasBrowserPermission || (!optimisticUpdates && isTogglePending), Menu: Menu, menuPlacement: menuPlacement, ...restCompositeButtonProps, onMenuToggle: (shown) => {
|
|
1575
1583
|
setTooltipDisabled(shown);
|
|
1576
1584
|
onMenuToggle?.(shown);
|
|
1577
|
-
}, children: [jsx(Icon, { icon: !optionsAwareIsMute ? 'camera' : 'camera-off' }), !hasBrowserPermission && (jsx("span", { className: "str-video__no-media-permission", title: t('Check your browser video permissions'), children: "!" })), isPromptingPermission && (jsx("span", { className: "str-video__pending-permission", title: t('Waiting for permission'), children: "?" }))] }) }));
|
|
1585
|
+
}, children: [jsx(Icon, { icon: !optionsAwareIsMute ? 'camera' : 'camera-off' }), !hasBrowserPermission && (jsx("span", { className: "str-video__no-media-permission", title: t('Check your browser video permissions'), children: "!" })), isPromptingPermission && (jsx("span", { className: "str-video__pending-permission", title: t('Waiting for permission'), children: "?" })), isSystemMuted && hasBrowserPermission && (jsx("span", { className: "str-video__system-muted", title: t('Camera is paused by your system'), children: "!" }))] }) }));
|
|
1578
1586
|
};
|
|
1579
1587
|
const ToggleVideoPublishingButton = (props) => {
|
|
1580
1588
|
const { t } = useI18n();
|
|
1581
1589
|
const { caption, Menu = jsx(DeviceSelectorVideo, { visualType: "list" }), menuPlacement = 'top', onMenuToggle, optimisticUpdates, ...restCompositeButtonProps } = props;
|
|
1582
1590
|
const { hasPermission, requestPermission, isAwaitingPermission } = useRequestPermission(OwnCapability.SEND_VIDEO);
|
|
1583
|
-
const { useCameraState, useCallSettings } = useCallStateHooks();
|
|
1591
|
+
const { useCameraState, useCallSettings, useLocalParticipant } = useCallStateHooks();
|
|
1584
1592
|
const { camera, optionsAwareIsMute, hasBrowserPermission, isPromptingPermission, isTogglePending, } = useCameraState({ optimisticUpdates });
|
|
1593
|
+
const localParticipant = useLocalParticipant();
|
|
1594
|
+
const isSystemMuted = !!localParticipant?.interruptedTracks?.includes(SfuModels.TrackType.VIDEO);
|
|
1585
1595
|
const callSettings = useCallSettings();
|
|
1586
1596
|
const isPublishingVideoAllowed = callSettings?.video.enabled;
|
|
1587
1597
|
const [tooltipDisabled, setTooltipDisabled] = useState(false);
|
|
@@ -1599,7 +1609,9 @@ const ToggleVideoPublishingButton = (props) => {
|
|
|
1599
1609
|
? t('Check your browser video permissions')
|
|
1600
1610
|
: !isPublishingVideoAllowed
|
|
1601
1611
|
? t('Video publishing is disabled by the system')
|
|
1602
|
-
:
|
|
1612
|
+
: isSystemMuted
|
|
1613
|
+
? t('Camera is paused by your system')
|
|
1614
|
+
: caption || t('Video'), tooltipDisabled: tooltipDisabled, children: jsxs(CompositeButton, { active: optionsAwareIsMute, caption: caption, variant: "secondary", disabled: !hasBrowserPermission ||
|
|
1603
1615
|
!hasPermission ||
|
|
1604
1616
|
!isPublishingVideoAllowed ||
|
|
1605
1617
|
(!optimisticUpdates && isTogglePending), "data-testid": optionsAwareIsMute ? 'video-unmute-button' : 'video-mute-button', onClick: handleClick, Menu: Menu, menuPlacement: menuPlacement, menuOffset: 16, ...restCompositeButtonProps, onMenuToggle: (shown) => {
|
|
@@ -1607,7 +1619,10 @@ const ToggleVideoPublishingButton = (props) => {
|
|
|
1607
1619
|
onMenuToggle?.(shown);
|
|
1608
1620
|
}, children: [jsx(Icon, { icon: optionsAwareIsMute ? 'camera-off' : 'camera' }), (!hasBrowserPermission ||
|
|
1609
1621
|
!hasPermission ||
|
|
1610
|
-
!isPublishingVideoAllowed) && (jsx("span", { className: "str-video__no-media-permission", children: "!" })), isPromptingPermission && (jsx("span", { className: "str-video__pending-permission", title: t('Waiting for permission'), children: "?" }))
|
|
1622
|
+
!isPublishingVideoAllowed) && (jsx("span", { className: "str-video__no-media-permission", children: "!" })), isPromptingPermission && (jsx("span", { className: "str-video__pending-permission", title: t('Waiting for permission'), children: "?" })), isSystemMuted &&
|
|
1623
|
+
hasBrowserPermission &&
|
|
1624
|
+
hasPermission &&
|
|
1625
|
+
isPublishingVideoAllowed && (jsx("span", { className: "str-video__system-muted", title: t('Camera is paused by your system'), children: "!" }))] }) }) }) }));
|
|
1611
1626
|
};
|
|
1612
1627
|
|
|
1613
1628
|
const EndCallMenu = (props) => {
|
|
@@ -2398,7 +2413,6 @@ const ParticipantView = forwardRef(function ParticipantView({ participant, track
|
|
|
2398
2413
|
const [trackedElement, setTrackedElement] = useState(null);
|
|
2399
2414
|
const [contextVideoElement, setContextVideoElement] = useState(null);
|
|
2400
2415
|
const [contextVideoPlaceholderElement, setContextVideoPlaceholderElement] = useState(null);
|
|
2401
|
-
// TODO: allow to pass custom ViewportTracker instance from props
|
|
2402
2416
|
useTrackElementVisibility({
|
|
2403
2417
|
sessionId,
|
|
2404
2418
|
trackedElement,
|
|
@@ -2529,8 +2543,10 @@ var en = {
|
|
|
2529
2543
|
Dismiss: Dismiss,
|
|
2530
2544
|
"Microphone on": "Microphone on",
|
|
2531
2545
|
"Microphone off": "Microphone off",
|
|
2546
|
+
"Microphone is paused by your system": "Microphone is paused by your system",
|
|
2532
2547
|
"Camera on": "Camera on",
|
|
2533
2548
|
"Camera off": "Camera off",
|
|
2549
|
+
"Camera is paused by your system": "Camera is paused by your system",
|
|
2534
2550
|
"No camera found": "No camera found",
|
|
2535
2551
|
"Video is disabled": "Video is disabled",
|
|
2536
2552
|
Pinned: Pinned,
|
|
@@ -2937,7 +2953,7 @@ const PaginatedGridLayout = (props) => {
|
|
|
2937
2953
|
if (!paginatedGridLayoutWrapperElement || !call)
|
|
2938
2954
|
return;
|
|
2939
2955
|
const cleanup = call.setViewport(paginatedGridLayoutWrapperElement);
|
|
2940
|
-
return () => cleanup();
|
|
2956
|
+
return () => cleanup?.();
|
|
2941
2957
|
}, [paginatedGridLayoutWrapperElement, call]);
|
|
2942
2958
|
// only used to render video elements
|
|
2943
2959
|
const participantGroups = useMemo(() => chunk(participants, groupSize), [participants, groupSize]);
|
|
@@ -3029,7 +3045,7 @@ const SpeakerLayout = ({ ParticipantViewUIBar = DefaultParticipantViewUIBar, Par
|
|
|
3029
3045
|
if (!participantsBarWrapperElement || !call)
|
|
3030
3046
|
return;
|
|
3031
3047
|
const cleanup = call.setViewport(participantsBarWrapperElement);
|
|
3032
|
-
return () => cleanup();
|
|
3048
|
+
return () => cleanup?.();
|
|
3033
3049
|
}, [participantsBarWrapperElement, call]);
|
|
3034
3050
|
const isOneOnOneCall = allParticipants.length === 2;
|
|
3035
3051
|
useSpeakerLayoutSortPreset(call, isOneOnOneCall);
|
|
@@ -3236,7 +3252,7 @@ const checkCanJoinEarly = (startsAt, joinAheadTimeSeconds) => {
|
|
|
3236
3252
|
return Date.now() >= +startsAt - (joinAheadTimeSeconds ?? 0) * 1000;
|
|
3237
3253
|
};
|
|
3238
3254
|
|
|
3239
|
-
const [major, minor, patch] = ("1.
|
|
3255
|
+
const [major, minor, patch] = ("1.37.0").split('.');
|
|
3240
3256
|
setSdkInfo({
|
|
3241
3257
|
type: SfuModels.SdkType.REACT,
|
|
3242
3258
|
major,
|