@stream-io/video-react-sdk 1.37.7 → 1.39.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.
Files changed (33) hide show
  1. package/CHANGELOG.md +4409 -0
  2. package/dist/css/embedded.css +1 -0
  3. package/dist/css/embedded.css.map +1 -1
  4. package/dist/css/styles.css +1 -0
  5. package/dist/css/styles.css.map +1 -1
  6. package/dist/embedded.cjs.js +60 -39
  7. package/dist/embedded.cjs.js.map +1 -1
  8. package/dist/embedded.es.js +62 -41
  9. package/dist/embedded.es.js.map +1 -1
  10. package/dist/index.cjs.js +60 -40
  11. package/dist/index.cjs.js.map +1 -1
  12. package/dist/index.es.js +62 -42
  13. package/dist/index.es.js.map +1 -1
  14. package/dist/src/components/CallParticipantsList/CallParticipantListingItem.d.ts +1 -1
  15. package/dist/src/core/components/Audio/Audio.d.ts +1 -4
  16. package/dist/src/core/components/ParticipantView/ParticipantView.d.ts +1 -1
  17. package/dist/src/translations/index.d.ts +1 -0
  18. package/package.json +9 -7
  19. package/src/components/CallParticipantsList/CallParticipantListingItem.tsx +50 -46
  20. package/src/components/CallParticipantsList/CallParticipantsList.tsx +17 -6
  21. package/src/components/DeviceSettings/AudioVolumeIndicator.tsx +8 -4
  22. package/src/components/Search/SearchInput.tsx +4 -2
  23. package/src/core/components/Audio/Audio.tsx +4 -4
  24. package/src/core/components/ParticipantView/DefaultParticipantViewUI.tsx +8 -0
  25. package/src/core/components/ParticipantView/ParticipantView.tsx +4 -3
  26. package/src/core/components/Video/BaseVideo.tsx +3 -1
  27. package/src/core/components/Video/Video.tsx +5 -2
  28. package/src/embedded/hooks/useWakeLock.ts +1 -0
  29. package/src/embedded/livestream/viewer/ViewerLobby.tsx +5 -6
  30. package/src/hooks/useDragToScroll.ts +9 -4
  31. package/src/hooks/useScrollPosition.ts +2 -2
  32. package/src/translations/en.json +1 -0
  33. package/src/wrappers/LivestreamPlayer/LivestreamPlayer.tsx +5 -6
@@ -7,7 +7,7 @@ var videoClient = require('@stream-io/video-client');
7
7
  var react$1 = require('@floating-ui/react');
8
8
  var clsx = require('clsx');
9
9
 
10
- const Audio = ({ participant, trackType = 'audioTrack', ...rest }) => {
10
+ const Audio = react.memo(function Audio({ participant, trackType = 'audioTrack', ...rest }) {
11
11
  const call = videoReactBindings.useCall();
12
12
  const [audioElement, setAudioElement] = react.useState(null);
13
13
  const { userId, sessionId } = participant;
@@ -20,7 +20,7 @@ const Audio = ({ participant, trackType = 'audioTrack', ...rest }) => {
20
20
  };
21
21
  }, [call, sessionId, audioElement, trackType]);
22
22
  return (jsxRuntime.jsx("audio", { autoPlay: true, ...rest, ref: setAudioElement, "data-user-id": userId, "data-session-id": sessionId, "data-track-type": trackType }));
23
- };
23
+ });
24
24
  Audio.displayName = 'Audio';
25
25
 
26
26
  const ParticipantsAudio = (props) => {
@@ -96,7 +96,7 @@ const useVerticalScrollPosition = (scrollElement, threshold = SCROLL_THRESHOLD)
96
96
  };
97
97
  const resizeObserver = new ResizeObserver(scrollHandler);
98
98
  resizeObserver.observe(scrollElement);
99
- scrollElement.addEventListener('scroll', scrollHandler);
99
+ scrollElement.addEventListener('scroll', scrollHandler, { passive: true });
100
100
  return () => {
101
101
  scrollElement.removeEventListener('scroll', scrollHandler);
102
102
  resizeObserver.disconnect();
@@ -124,7 +124,7 @@ const useHorizontalScrollPosition = (scrollElement, threshold = SCROLL_THRESHOLD
124
124
  };
125
125
  const resizeObserver = new ResizeObserver(scrollHandler);
126
126
  resizeObserver.observe(scrollElement);
127
- scrollElement.addEventListener('scroll', scrollHandler);
127
+ scrollElement.addEventListener('scroll', scrollHandler, { passive: true });
128
128
  return () => {
129
129
  scrollElement.removeEventListener('scroll', scrollHandler);
130
130
  resizeObserver.disconnect();
@@ -215,6 +215,7 @@ function useDeviceList(devices, selectedDeviceId) {
215
215
  * @param options - Options for customizing the drag-to-scroll behavior.
216
216
  */
217
217
  function useDragToScroll(element, options = {}) {
218
+ const { enabled, decay = 0.95, minVelocity = 0.5, dragThreshold = 5, } = options;
218
219
  const stateRef = react.useRef({
219
220
  isDragging: false,
220
221
  isPointerActive: false,
@@ -227,9 +228,8 @@ function useDragToScroll(element, options = {}) {
227
228
  startY: 0,
228
229
  });
229
230
  react.useEffect(() => {
230
- if (!element || !options.enabled)
231
+ if (!element || !enabled)
231
232
  return;
232
- const { decay = 0.95, minVelocity = 0.5, dragThreshold = 5 } = options;
233
233
  const state = stateRef.current;
234
234
  const stopMomentum = () => {
235
235
  if (state.rafId) {
@@ -313,7 +313,7 @@ function useDragToScroll(element, options = {}) {
313
313
  window.removeEventListener('pointercancel', onPointerUpOrCancel);
314
314
  stopMomentum();
315
315
  };
316
- }, [element, options]);
316
+ }, [element, enabled, decay, minVelocity, dragThreshold]);
317
317
  }
318
318
 
319
319
  var MenuVisualType;
@@ -543,9 +543,10 @@ const BaseVideo = react.forwardRef(function BaseVideo({ stream, ...rest }, ref)
543
543
  if (stream === videoElement.srcObject)
544
544
  return;
545
545
  videoElement.srcObject = stream;
546
+ let timeoutId;
546
547
  if (videoClient.Browsers.isSafari() || videoClient.Browsers.isFirefox()) {
547
548
  // Firefox and Safari have some timing issue
548
- setTimeout(() => {
549
+ timeoutId = setTimeout(() => {
549
550
  videoElement.srcObject = stream;
550
551
  videoElement.play().catch((e) => {
551
552
  console.error(`Failed to play stream`, e);
@@ -553,6 +554,7 @@ const BaseVideo = react.forwardRef(function BaseVideo({ stream, ...rest }, ref)
553
554
  }, 0);
554
555
  }
555
556
  return () => {
557
+ clearTimeout(timeoutId);
556
558
  videoElement.pause();
557
559
  videoElement.srcObject = null;
558
560
  };
@@ -589,6 +591,7 @@ const DefaultPictureInPicturePlaceholder = react.forwardRef(function DefaultPict
589
591
  return (jsxRuntime.jsx(BaseVideoPlaceholder, { ref: ref, ...props, children: t('Video is playing in a popup') }));
590
592
  });
591
593
 
594
+ const ABSOLUTE_POSITION_STYLE = { position: 'absolute' };
592
595
  const Video$1 = ({ enabled = true, mirror, trackType, participant, className, VideoPlaceholder = DefaultVideoPlaceholder, PictureInPicturePlaceholder = DefaultPictureInPicturePlaceholder, refs, ...rest }) => {
593
596
  const { sessionId, videoStream, screenShareStream, viewportVisibilityState, isLocalParticipant, userId, } = participant;
594
597
  const call = videoReactBindings.useCall();
@@ -661,7 +664,7 @@ const Video$1 = ({ enabled = true, mirror, trackType, participant, className, Vi
661
664
  }), "data-user-id": userId, "data-session-id": sessionId, ref: (element) => {
662
665
  setVideoElement(element);
663
666
  refs?.setVideoElement?.(element);
664
- } })), isPiP && PictureInPicturePlaceholder && (jsxRuntime.jsx(PictureInPicturePlaceholder, { style: { position: 'absolute' }, participant: participant })), (hasNoVideoOrInvisible || isVideoPaused) && VideoPlaceholder && (jsxRuntime.jsx(VideoPlaceholder, { style: { position: 'absolute' }, participant: participant, ref: refs?.setVideoPlaceholderElement }))] }));
667
+ } })), isPiP && PictureInPicturePlaceholder && (jsxRuntime.jsx(PictureInPicturePlaceholder, { style: ABSOLUTE_POSITION_STYLE, participant: participant })), (hasNoVideoOrInvisible || isVideoPaused) && VideoPlaceholder && (jsxRuntime.jsx(VideoPlaceholder, { style: ABSOLUTE_POSITION_STYLE, participant: participant, ref: refs?.setVideoPlaceholderElement }))] }));
665
668
  };
666
669
  Video$1.displayName = 'Video';
667
670
 
@@ -1020,16 +1023,20 @@ const ScreenShareButton = (props) => {
1020
1023
  const AudioVolumeIndicator = () => {
1021
1024
  const { useMicrophoneState } = videoReactBindings.useCallStateHooks();
1022
1025
  const { isEnabled, mediaStream } = useMicrophoneState();
1023
- const [audioLevel, setAudioLevel] = react.useState(0);
1026
+ const barRef = react.useRef(null);
1024
1027
  react.useEffect(() => {
1025
1028
  if (!isEnabled || !mediaStream)
1026
1029
  return;
1027
- const disposeSoundDetector = videoClient.createSoundDetector(mediaStream, ({ audioLevel: al }) => setAudioLevel(al), { detectionFrequencyInMs: 80, destroyStreamOnStop: false });
1030
+ const disposeSoundDetector = videoClient.createSoundDetector(mediaStream, ({ audioLevel: al }) => {
1031
+ if (barRef.current) {
1032
+ barRef.current.style.transform = `scaleX(${al / 100})`;
1033
+ }
1034
+ }, { detectionFrequencyInMs: 80, destroyStreamOnStop: false });
1028
1035
  return () => {
1029
1036
  disposeSoundDetector().catch(console.error);
1030
1037
  };
1031
1038
  }, [isEnabled, mediaStream]);
1032
- return (jsxRuntime.jsxs("div", { className: "str-video__audio-volume-indicator", children: [jsxRuntime.jsx(Icon, { icon: isEnabled ? 'mic' : 'mic-off' }), jsxRuntime.jsx("div", { className: "str-video__audio-volume-indicator__bar", children: jsxRuntime.jsx("div", { className: "str-video__audio-volume-indicator__bar-value", style: { transform: `scaleX(${audioLevel / 100})` } }) })] }));
1039
+ return (jsxRuntime.jsxs("div", { className: "str-video__audio-volume-indicator", children: [jsxRuntime.jsx(Icon, { icon: isEnabled ? 'mic' : 'mic-off' }), jsxRuntime.jsx("div", { className: "str-video__audio-volume-indicator__bar", children: jsxRuntime.jsx("div", { ref: barRef, className: "str-video__audio-volume-indicator__bar-value" }) })] }));
1033
1040
  };
1034
1041
 
1035
1042
  const LEVEL_BARS = 5;
@@ -1203,7 +1210,7 @@ const SpeakerTest = (props) => {
1203
1210
  const audioElementRef = react.useRef(null);
1204
1211
  const [isPlaying, setIsPlaying] = react.useState(false);
1205
1212
  const { t } = videoReactBindings.useI18n();
1206
- const { audioUrl = `https://unpkg.com/${"@stream-io/video-react-sdk"}@${"1.37.7"}/assets/piano.mp3`, } = props;
1213
+ const { audioUrl = `https://unpkg.com/${"@stream-io/video-react-sdk"}@${"1.39.0"}/assets/piano.mp3`, } = props;
1207
1214
  // Update audio output device when selection changes
1208
1215
  react.useEffect(() => {
1209
1216
  const audio = audioElementRef.current;
@@ -1502,13 +1509,14 @@ const CallParticipantListHeader = ({ onClose, }) => {
1502
1509
  return (jsxRuntime.jsxs("div", { className: "str-video__participant-list-header", children: [jsxRuntime.jsxs("div", { className: "str-video__participant-list-header__title", children: [t('Participants'), ' ', jsxRuntime.jsxs("span", { className: "str-video__participant-list-header__title-count", children: ["[", participants.length, "]"] }), anonymousParticipantCount > 0 && (jsxRuntime.jsx("span", { className: "str-video__participant-list-header__title-anonymous", children: t('Anonymous', { count: anonymousParticipantCount }) }))] }), jsxRuntime.jsx(IconButton, { onClick: onClose, className: "str-video__participant-list-header__close-button", icon: "close" })] }));
1503
1510
  };
1504
1511
 
1505
- const CallParticipantListingItem = ({ participant, DisplayName = DefaultDisplayName, }) => {
1512
+ const CallParticipantListingItem = react.memo(function CallParticipantListingItem({ participant, DisplayName = DefaultDisplayName, }) {
1506
1513
  const isAudioOn = videoClient.hasAudio(participant);
1507
1514
  const isVideoOn = videoClient.hasVideo(participant);
1508
1515
  const isPinnedOn = videoClient.isPinned(participant);
1509
1516
  const { t } = videoReactBindings.useI18n();
1510
1517
  return (jsxRuntime.jsxs("div", { className: "str-video__participant-listing-item", children: [jsxRuntime.jsx(Avatar, { name: participant.name, imageSrc: participant.image }), jsxRuntime.jsx(DisplayName, { participant: participant }), jsxRuntime.jsxs("div", { className: "str-video__participant-listing-item__media-indicator-group", children: [jsxRuntime.jsx(MediaIndicator, { title: isAudioOn ? t('Microphone on') : t('Microphone off'), className: clsx('str-video__participant-listing-item__icon', `str-video__participant-listing-item__icon-${isAudioOn ? 'mic' : 'mic-off'}`) }), jsxRuntime.jsx(MediaIndicator, { title: isVideoOn ? t('Camera on') : t('Camera off'), className: clsx('str-video__participant-listing-item__icon', `str-video__participant-listing-item__icon-${isVideoOn ? 'camera' : 'camera-off'}`) }), isPinnedOn && (jsxRuntime.jsx(MediaIndicator, { title: t('Pinned'), className: clsx('str-video__participant-listing-item__icon', 'str-video__participant-listing-item__icon-pinned') })), jsxRuntime.jsx(MenuToggle, { placement: "bottom-end", ToggleButton: ToggleButton$2, children: jsxRuntime.jsx(ParticipantViewContext.Provider, { value: { participant, trackType: 'none' }, children: jsxRuntime.jsx(ParticipantActionsContextMenu, {}) }) })] })] }));
1511
- };
1518
+ });
1519
+ CallParticipantListingItem.displayName = 'CallParticipantListingItem';
1512
1520
  const MediaIndicator = (props) => (jsxRuntime.jsx(WithTooltip, { ...props }));
1513
1521
  const DefaultDisplayName = ({ participant }) => {
1514
1522
  const connectedUser = videoReactBindings.useConnectedUser();
@@ -1540,18 +1548,19 @@ const EmptyParticipantSearchList = () => {
1540
1548
 
1541
1549
  const SearchInput = ({ exitSearch, isActive, ...rest }) => {
1542
1550
  const [inputElement, setInputElement] = react.useState(null);
1551
+ const onExitSearch = videoReactBindings.useEffectEvent(exitSearch);
1543
1552
  react.useEffect(() => {
1544
1553
  if (!inputElement)
1545
1554
  return;
1546
1555
  const handleKeyDown = (e) => {
1547
1556
  if (e.key.toLowerCase() === 'escape')
1548
- exitSearch();
1557
+ onExitSearch();
1549
1558
  };
1550
1559
  inputElement.addEventListener('keydown', handleKeyDown);
1551
1560
  return () => {
1552
1561
  inputElement.removeEventListener('keydown', handleKeyDown);
1553
1562
  };
1554
- }, [exitSearch, inputElement]);
1563
+ }, [inputElement]);
1555
1564
  return (jsxRuntime.jsxs("div", { className: clsx('str-video__search-input__container', {
1556
1565
  'str-video__search-input__container--active': isActive,
1557
1566
  }), children: [jsxRuntime.jsx("input", { placeholder: "Search", ...rest, ref: setInputElement }), isActive ? (jsxRuntime.jsx("button", { className: "str-video__search-input__clear-btn", onClick: exitSearch, children: jsxRuntime.jsx("span", { className: "str-video__search-input__icon--active" }) })) : (jsxRuntime.jsx("span", { className: "str-video__search-input__icon" }))] }));
@@ -1622,10 +1631,19 @@ const CallParticipantListContentHeader = ({ userListType, setUserListType, }) =>
1622
1631
  const ActiveUsersSearchResults = ({ searchQuery, activeUsersSearchFn: activeUsersSearchFnFromProps, debounceSearchInterval, }) => {
1623
1632
  const { useParticipants } = videoReactBindings.useCallStateHooks();
1624
1633
  const participants = useParticipants({ sortBy: videoClient.name });
1634
+ // cache: each distinct name is normalized once
1635
+ const normalizedNameCache = react.useRef(null);
1625
1636
  const activeUsersSearchFn = react.useCallback(async (queryString) => {
1626
1637
  const normalizedQuery = normalizeString(queryString);
1627
- const queryRegExp = new RegExp(normalizedQuery, 'i');
1628
- return participants.filter((p) => normalizeString(p.name).match(queryRegExp));
1638
+ const cache = (normalizedNameCache.current ??= new Map());
1639
+ return participants.filter((p) => {
1640
+ let normalizedName = cache.get(p.name);
1641
+ if (normalizedName === undefined) {
1642
+ normalizedName = normalizeString(p.name);
1643
+ cache.set(p.name, normalizedName);
1644
+ }
1645
+ return normalizedName.includes(normalizedQuery);
1646
+ });
1629
1647
  }, [participants]);
1630
1648
  const { searchQueryInProgress, searchResults } = useSearch({
1631
1649
  searchFn: activeUsersSearchFnFromProps ?? activeUsersSearchFn,
@@ -1638,8 +1656,8 @@ const BlockedUsersSearchResults = ({ blockedUsersSearchFn: blockedUsersSearchFnF
1638
1656
  const { useCallBlockedUserIds } = videoReactBindings.useCallStateHooks();
1639
1657
  const blockedUsers = useCallBlockedUserIds();
1640
1658
  const blockedUsersSearchFn = react.useCallback(async (queryString) => {
1641
- const queryRegExp = new RegExp(queryString, 'i');
1642
- return blockedUsers.filter((userId) => userId.match(queryRegExp));
1659
+ const normalizedQuery = queryString.toLowerCase();
1660
+ return blockedUsers.filter((userId) => userId.toLowerCase().includes(normalizedQuery));
1643
1661
  }, [blockedUsers]);
1644
1662
  const { searchQueryInProgress, searchResults } = useSearch({
1645
1663
  searchFn: blockedUsersSearchFnFromProps ?? blockedUsersSearchFn,
@@ -1900,7 +1918,8 @@ const ParticipantDetails = ({ indicatorsVisible = true, }) => {
1900
1918
  const canUnpin = !!pin && pin.isLocalPin;
1901
1919
  const isTrackPaused = trackType !== 'none' ? videoClient.hasPausedTrack(participant, trackType) : false;
1902
1920
  const isAudioConnecting = videoReactBindings.useIsAudioConnecting(participant);
1903
- 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 && pin && (jsxRuntime.jsx("span", { title: canUnpin ? t('Unpin') : t('Pinned'), onClick: canUnpin ? () => call?.unpin(sessionId) : undefined, className: "str-video__participant-details__name--pinned" })), indicatorsVisible && jsxRuntime.jsx(SpeechIndicator, {})] }) }), indicatorsVisible && (jsxRuntime.jsx(Notification, { isVisible: isLocalParticipant &&
1921
+ const isVideoConnecting = videoReactBindings.useIsVideoConnecting(participant);
1922
+ 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 && isVideoConnecting && (jsxRuntime.jsx(LoadingIndicator, { className: "str-video__participant-details__name--video-connecting", tooltip: t('Video is connecting...') })), 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 && pin && (jsxRuntime.jsx("span", { title: canUnpin ? t('Unpin') : t('Pinned'), onClick: canUnpin ? () => call?.unpin(sessionId) : undefined, className: "str-video__participant-details__name--pinned" })), indicatorsVisible && jsxRuntime.jsx(SpeechIndicator, {})] }) }), indicatorsVisible && (jsxRuntime.jsx(Notification, { isVisible: isLocalParticipant &&
1904
1923
  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 })) }))] }));
1905
1924
  };
1906
1925
  const SpeechIndicator = () => {
@@ -1909,7 +1928,7 @@ const SpeechIndicator = () => {
1909
1928
  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" })] }));
1910
1929
  };
1911
1930
 
1912
- const ParticipantView = react.forwardRef(function ParticipantView({ participant, trackType = 'videoTrack', mirror, muteAudio, refs: { setVideoElement, setVideoPlaceholderElement } = {}, className, VideoPlaceholder, PictureInPicturePlaceholder, ParticipantViewUI = DefaultParticipantViewUI, }, ref) {
1931
+ const ParticipantView = react.memo(react.forwardRef(function ParticipantView({ participant, trackType = 'videoTrack', mirror, muteAudio, refs: { setVideoElement, setVideoPlaceholderElement } = {}, className, VideoPlaceholder, PictureInPicturePlaceholder, ParticipantViewUI = DefaultParticipantViewUI, }, ref) {
1913
1932
  const { isLocalParticipant, isSpeaking, isDominantSpeaker, sessionId } = participant;
1914
1933
  const hasAudioTrack = videoClient.hasAudio(participant);
1915
1934
  const hasVideoTrack = videoClient.hasVideo(participant);
@@ -1953,7 +1972,7 @@ const ParticipantView = react.forwardRef(function ParticipantView({ participant,
1953
1972
  }, className: clsx('str-video__participant-view', isDominantSpeaker && 'str-video__participant-view--dominant-speaker', isSpeaking && 'str-video__participant-view--speaking', !hasVideoTrack && 'str-video__participant-view--no-video', !hasAudioTrack && 'str-video__participant-view--no-audio', className), children: jsxRuntime.jsxs(ParticipantViewContext.Provider, { value: participantViewContextValue, children: [!isLocalParticipant && !muteAudio && (jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [hasAudioTrack && (jsxRuntime.jsx(Audio, { participant: participant, trackType: "audioTrack" })), hasScreenShareAudioTrack && (jsxRuntime.jsx(Audio, { participant: participant, trackType: "screenShareAudioTrack" }))] })), jsxRuntime.jsx(Video$1, { VideoPlaceholder: VideoPlaceholder, PictureInPicturePlaceholder: PictureInPicturePlaceholder, participant: participant, trackType: trackType, refs: videoRefs, enabled: isLocalParticipant ||
1954
1973
  trackType !== 'videoTrack' ||
1955
1974
  isParticipantVideoEnabled(participant.sessionId), mirror: mirror, autoPlay: true }), isComponentType(ParticipantViewUI) ? (jsxRuntime.jsx(ParticipantViewUI, {})) : (ParticipantViewUI)] }) }));
1956
- });
1975
+ }));
1957
1976
  ParticipantView.displayName = 'ParticipantView';
1958
1977
 
1959
1978
  // re-exporting the StreamCallProvider as StreamCall
@@ -2080,6 +2099,7 @@ var en = {
2080
2099
  "Poor connection quality": "Poor connection quality. Please check your internet connection.",
2081
2100
  "Video paused due to insufficient bandwidth": "Video paused due to insufficient bandwidth",
2082
2101
  "Audio is connecting...": "Audio is connecting...",
2102
+ "Video is connecting...": "Video is connecting...",
2083
2103
  Participants: Participants,
2084
2104
  Anonymous: Anonymous,
2085
2105
  "No participants found": "No participants found",
@@ -2170,20 +2190,20 @@ function checkConditions(obj, conditions) {
2170
2190
  const eqOperatorValue = isDateString(eqOperator.$eq)
2171
2191
  ? new Date(eqOperator.$eq).getTime()
2172
2192
  : eqOperator.$eq;
2173
- match && (match = eqOperatorValue === value);
2193
+ match &&= eqOperatorValue === value;
2174
2194
  }
2175
2195
  else if (maybeOperator && '$neq' in operator) {
2176
2196
  const neqOperator = operator;
2177
- match && (match = neqOperator.$neq !== value);
2197
+ match &&= neqOperator.$neq !== value;
2178
2198
  }
2179
2199
  else if (maybeOperator && '$in' in operator) {
2180
2200
  const inOperator = operator;
2181
- match && (match = inOperator.$in.includes(value));
2201
+ match &&= inOperator.$in.includes(value);
2182
2202
  }
2183
2203
  else if (maybeOperator && '$contains' in operator) {
2184
2204
  if (Array.isArray(value)) {
2185
2205
  const containsOperator = operator;
2186
- match && (match = value.includes(containsOperator.$contains));
2206
+ match &&= value.includes(containsOperator.$contains);
2187
2207
  }
2188
2208
  else {
2189
2209
  match = false;
@@ -2194,35 +2214,35 @@ function checkConditions(obj, conditions) {
2194
2214
  const gtOperatorValue = isDateString(gtOperator.$gt)
2195
2215
  ? new Date(gtOperator.$gt).getTime()
2196
2216
  : gtOperator.$gt;
2197
- match && (match = value > gtOperatorValue);
2217
+ match &&= value > gtOperatorValue;
2198
2218
  }
2199
2219
  else if (maybeOperator && '$gte' in operator) {
2200
2220
  const gteOperator = operator;
2201
2221
  const gteOperatorValue = isDateString(gteOperator.$gte)
2202
2222
  ? new Date(gteOperator.$gte).getTime()
2203
2223
  : gteOperator.$gte;
2204
- match && (match = value >= gteOperatorValue);
2224
+ match &&= value >= gteOperatorValue;
2205
2225
  }
2206
2226
  else if (maybeOperator && '$lt' in operator) {
2207
2227
  const ltOperator = operator;
2208
2228
  const ltOperatorValue = isDateString(ltOperator.$lt)
2209
2229
  ? new Date(ltOperator.$lt).getTime()
2210
2230
  : ltOperator.$lt;
2211
- match && (match = value < ltOperatorValue);
2231
+ match &&= value < ltOperatorValue;
2212
2232
  }
2213
2233
  else if (maybeOperator && '$lte' in operator) {
2214
2234
  const lteOperator = operator;
2215
2235
  const lteOperatorValue = isDateString(lteOperator.$lte)
2216
2236
  ? new Date(lteOperator.$lte).getTime()
2217
2237
  : lteOperator.$lte;
2218
- match && (match = value <= lteOperatorValue);
2238
+ match &&= value <= lteOperatorValue;
2219
2239
  // } else if (maybeOperator && '$autocomplete' in operator) {
2220
2240
  // TODO: regexp solution maybe?
2221
2241
  // match &&= false;
2222
2242
  }
2223
2243
  else {
2224
2244
  const eqValue = operator;
2225
- match && (match = eqValue === value);
2245
+ match &&= eqValue === value;
2226
2246
  }
2227
2247
  if (!match) {
2228
2248
  return false;
@@ -3061,6 +3081,7 @@ const useWakeLock = () => {
3061
3081
  if (interrupted)
3062
3082
  return wls.release();
3063
3083
  wakeLockSentinel = wls;
3084
+ return undefined;
3064
3085
  })
3065
3086
  .catch((error) => console.debug(`Couldn't setup WakeLock due to: ${error}`));
3066
3087
  return () => {
@@ -3395,12 +3416,12 @@ const ViewerLobby = ({ onJoin }) => {
3395
3416
  }
3396
3417
  }, [canJoin, autoJoin, onJoin]);
3397
3418
  react.useEffect(() => {
3398
- if (!canJoinEarly) {
3399
- const handle = setInterval(() => {
3400
- setCanJoinEarly(checkCanJoinEarly(startsAt, joinAheadTimeSeconds));
3401
- }, 1000);
3402
- return () => clearInterval(handle);
3403
- }
3419
+ if (canJoinEarly)
3420
+ return;
3421
+ const handle = setInterval(() => {
3422
+ setCanJoinEarly(checkCanJoinEarly(startsAt, joinAheadTimeSeconds));
3423
+ }, 1000);
3424
+ return () => clearInterval(handle);
3404
3425
  }, [canJoinEarly, startsAt, joinAheadTimeSeconds]);
3405
3426
  react.useEffect(() => {
3406
3427
  if (!startsAt || startsAtPassed)