@azure/communication-react 1.4.3-alpha-202212160013.0 → 1.4.3-alpha-202212170012.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 (59) hide show
  1. package/dist/communication-react.d.ts +5 -1
  2. package/dist/dist-cjs/communication-react/index.js +425 -321
  3. package/dist/dist-cjs/communication-react/index.js.map +1 -1
  4. package/dist/dist-esm/acs-ui-common/src/telemetryVersion.js +1 -1
  5. package/dist/dist-esm/acs-ui-common/src/telemetryVersion.js.map +1 -1
  6. package/dist/dist-esm/calling-stateful-client/src/StreamUtils.js +6 -2
  7. package/dist/dist-esm/calling-stateful-client/src/StreamUtils.js.map +1 -1
  8. package/dist/dist-esm/react-components/src/components/UnsupportedBrowserVersion.d.ts +1 -1
  9. package/dist/dist-esm/react-components/src/components/UnsupportedBrowserVersion.js +2 -2
  10. package/dist/dist-esm/react-components/src/components/UnsupportedBrowserVersion.js.map +1 -1
  11. package/dist/dist-esm/react-components/src/components/UnsupportedEnvironment.d.ts +1 -1
  12. package/dist/dist-esm/react-components/src/components/UnsupportedEnvironment.js +2 -2
  13. package/dist/dist-esm/react-components/src/components/UnsupportedEnvironment.js.map +1 -1
  14. package/dist/dist-esm/react-components/src/components/VideoGallery/DefaultLayout.d.ts +2 -27
  15. package/dist/dist-esm/react-components/src/components/VideoGallery/DefaultLayout.js +1 -1
  16. package/dist/dist-esm/react-components/src/components/VideoGallery/DefaultLayout.js.map +1 -1
  17. package/dist/dist-esm/react-components/src/components/VideoGallery/FloatingLocalVideoLayout.d.ts +2 -26
  18. package/dist/dist-esm/react-components/src/components/VideoGallery/FloatingLocalVideoLayout.js +2 -2
  19. package/dist/dist-esm/react-components/src/components/VideoGallery/FloatingLocalVideoLayout.js.map +1 -1
  20. package/dist/dist-esm/react-components/src/components/VideoGallery/Layout.d.ts +34 -0
  21. package/dist/dist-esm/react-components/src/components/VideoGallery/Layout.js +4 -0
  22. package/dist/dist-esm/react-components/src/components/VideoGallery/Layout.js.map +1 -0
  23. package/dist/dist-esm/react-components/src/components/VideoGallery/PinnedParticipantsLayout.d.ts +25 -0
  24. package/dist/dist-esm/react-components/src/components/VideoGallery/PinnedParticipantsLayout.js +62 -0
  25. package/dist/dist-esm/react-components/src/components/VideoGallery/PinnedParticipantsLayout.js.map +1 -0
  26. package/dist/dist-esm/react-components/src/components/VideoGallery/VideoGalleryResponsiveHorizontalGallery.d.ts +3 -1
  27. package/dist/dist-esm/react-components/src/components/VideoGallery/VideoGalleryResponsiveHorizontalGallery.js +3 -1
  28. package/dist/dist-esm/react-components/src/components/VideoGallery/VideoGalleryResponsiveHorizontalGallery.js.map +1 -1
  29. package/dist/dist-esm/react-components/src/components/VideoGallery/styles/FloatingLocalVideo.styles.d.ts +1 -0
  30. package/dist/dist-esm/react-components/src/components/VideoGallery/styles/FloatingLocalVideo.styles.js +2 -1
  31. package/dist/dist-esm/react-components/src/components/VideoGallery/styles/FloatingLocalVideo.styles.js.map +1 -1
  32. package/dist/dist-esm/react-components/src/components/VideoGallery/styles/VideoGalleryResponsiveHorizontalGallery.styles.d.ts +0 -14
  33. package/dist/dist-esm/react-components/src/components/VideoGallery/styles/VideoGalleryResponsiveHorizontalGallery.styles.js +1 -8
  34. package/dist/dist-esm/react-components/src/components/VideoGallery/styles/VideoGalleryResponsiveHorizontalGallery.styles.js.map +1 -1
  35. package/dist/dist-esm/react-components/src/components/VideoGallery/utils/videoGalleryLayoutUtils.d.ts +36 -0
  36. package/dist/dist-esm/react-components/src/components/VideoGallery/{videoGalleryUtils.js → utils/videoGalleryLayoutUtils.js} +46 -2
  37. package/dist/dist-esm/react-components/src/components/VideoGallery/utils/videoGalleryLayoutUtils.js.map +1 -0
  38. package/dist/dist-esm/react-components/src/components/VideoGallery.d.ts +4 -0
  39. package/dist/dist-esm/react-components/src/components/VideoGallery.js +47 -3
  40. package/dist/dist-esm/react-components/src/components/VideoGallery.js.map +1 -1
  41. package/dist/dist-esm/react-composites/src/composites/CallComposite/components/CallArrangement.js +11 -11
  42. package/dist/dist-esm/react-composites/src/composites/CallComposite/components/CallArrangement.js.map +1 -1
  43. package/dist/dist-esm/react-composites/src/composites/CallComposite/components/buttons/Microphone.js +1 -1
  44. package/dist/dist-esm/react-composites/src/composites/CallComposite/components/buttons/Microphone.js.map +1 -1
  45. package/dist/dist-esm/react-composites/src/composites/CallComposite/pages/UnsupportedBrowser.js +1 -1
  46. package/dist/dist-esm/react-composites/src/composites/CallComposite/pages/UnsupportedBrowser.js.map +1 -1
  47. package/dist/dist-esm/react-composites/src/composites/CallComposite/styles/CallPage.styles.d.ts +0 -4
  48. package/dist/dist-esm/react-composites/src/composites/CallComposite/styles/CallPage.styles.js +0 -8
  49. package/dist/dist-esm/react-composites/src/composites/CallComposite/styles/CallPage.styles.js.map +1 -1
  50. package/dist/dist-esm/react-composites/src/composites/CallWithChatComposite/CallWithChatControlBar.js +1 -11
  51. package/dist/dist-esm/react-composites/src/composites/CallWithChatComposite/CallWithChatControlBar.js.map +1 -1
  52. package/dist/dist-esm/react-composites/src/composites/CallWithChatComposite/styles/CallWithChatCompositeStyles.d.ts +0 -2
  53. package/dist/dist-esm/react-composites/src/composites/CallWithChatComposite/styles/CallWithChatCompositeStyles.js +0 -15
  54. package/dist/dist-esm/react-composites/src/composites/CallWithChatComposite/styles/CallWithChatCompositeStyles.js.map +1 -1
  55. package/dist/dist-esm/react-composites/src/composites/common/styles/Pane.styles.js +1 -1
  56. package/dist/dist-esm/react-composites/src/composites/common/styles/Pane.styles.js.map +1 -1
  57. package/package.json +8 -8
  58. package/dist/dist-esm/react-components/src/components/VideoGallery/videoGalleryUtils.d.ts +0 -17
  59. package/dist/dist-esm/react-components/src/components/VideoGallery/videoGalleryUtils.js.map +0 -1
@@ -202,7 +202,7 @@ const _toCommunicationIdentifier = (id) => {
202
202
  // Copyright (c) Microsoft Corporation.
203
203
  // Licensed under the MIT license.
204
204
  // GENERATED FILE. DO NOT EDIT MANUALLY.
205
- var telemetryVersion = '1.4.3-alpha-202212160013.0';
205
+ var telemetryVersion = '1.4.3-alpha-202212170012.0';
206
206
 
207
207
  // Copyright (c) Microsoft Corporation.
208
208
  /**
@@ -2498,7 +2498,9 @@ function createView(context, internalContext, callId, participantId, stream, opt
2498
2498
  }
2499
2499
  else if (!('id' in stream) && !callId) {
2500
2500
  // Render LocalVideoStream that is not part of a Call
2501
- return createViewUnparentedVideo(context, internalContext, stream, options);
2501
+ // Because it is not part of the call we don't tee errors to state naturally (e.g. via a Call Client function such as startVideo).
2502
+ // We do not have a startLocalPreviewVideo function, so as a workaround we ensure any errors are propagated here.
2503
+ return context.withAsyncErrorTeedToState(() => __awaiter$v(this, void 0, void 0, function* () { return yield createViewUnparentedVideo(context, internalContext, stream, options); }), 'Call.startVideo')();
2502
2504
  }
2503
2505
  else {
2504
2506
  _logEvent(callingStatefulLogger, {
@@ -2523,7 +2525,9 @@ function disposeView(context, internalContext, callId, participantId, stream) {
2523
2525
  }
2524
2526
  else if (!('id' in stream) && !callId) {
2525
2527
  // Stop rendering LocalVideoStream that is not part of a Call
2526
- disposeViewUnparentedVideo(context, internalContext, stream);
2528
+ // Because it is not part of the call we don't tee errors to state naturally (e.g. via a Call Client function such as startVideo).
2529
+ // We do not have a stopLocalPreviewVideo function, so as a workaround we ensure any errors are propagated here.
2530
+ context.withErrorTeedToState(() => disposeViewUnparentedVideo(context, internalContext, stream), 'Call.stopVideo')();
2527
2531
  }
2528
2532
  else {
2529
2533
  _logEvent(callingStatefulLogger, {
@@ -8653,6 +8657,164 @@ const rootLayoutStyle$1 = {
8653
8657
  root: { position: 'relative', height: '100%', width: '100%', padding: '0.5rem' }
8654
8658
  };
8655
8659
 
8660
+ /**
8661
+ * Calculates the participants that should be rendered based on the list of dominant
8662
+ * speakers and currently rendered participants in a call.
8663
+ * @param args - SmartDominantSpeakerParticipantsArgs
8664
+ * @returns VideoGalleryRemoteParticipant[] {@link @azure/communication-react#VideoGalleryRemoteParticipant}
8665
+ */
8666
+ const smartDominantSpeakerParticipants = (args) => {
8667
+ const { participants, dominantSpeakers = [], lastVisibleParticipants = [], maxDominantSpeakers } = args;
8668
+ // Don't apply any logic if total number of video streams is less than max dominant speakers.
8669
+ if (participants.length <= maxDominantSpeakers) {
8670
+ return participants;
8671
+ }
8672
+ const participantsMap = participantsById(participants);
8673
+ // Only use the Max allowed dominant speakers that exist in participants
8674
+ const dominantSpeakerIds = Array.from(new Set(dominantSpeakers).values())
8675
+ .filter((id) => !!participantsMap[id])
8676
+ .slice(0, maxDominantSpeakers);
8677
+ const lastVisibleParticipantIds = lastVisibleParticipants.map((p) => p.userId);
8678
+ const newVisibleParticipantIds = lastVisibleParticipants.map((p) => p.userId).slice(0, maxDominantSpeakers);
8679
+ const newDominantSpeakerIds = dominantSpeakerIds.filter((id) => !newVisibleParticipantIds.includes(id));
8680
+ // Remove participants that are no longer dominant and replace them with new dominant speakers.
8681
+ for (let index = 0; index < maxDominantSpeakers; index++) {
8682
+ const newVisibleParticipantId = newVisibleParticipantIds[index];
8683
+ if (newVisibleParticipantId === undefined || !dominantSpeakerIds.includes(newVisibleParticipantId)) {
8684
+ const replacement = newDominantSpeakerIds.shift();
8685
+ if (!replacement) {
8686
+ break;
8687
+ }
8688
+ newVisibleParticipantIds[index] = replacement;
8689
+ }
8690
+ }
8691
+ const removedVisibleParticipantIds = lastVisibleParticipantIds.filter((p) => !newVisibleParticipantIds.includes(p));
8692
+ removedVisibleParticipantIds.forEach((p) => newVisibleParticipantIds.push(p));
8693
+ const newVisibleParticipantIdSet = new Set(newVisibleParticipantIds);
8694
+ const leftoverParticipants = participants.filter((p) => !newVisibleParticipantIdSet.has(p.userId));
8695
+ leftoverParticipants.forEach((p) => {
8696
+ newVisibleParticipantIds.push(p.userId);
8697
+ });
8698
+ // newVisibleParticipantIds can contain identifiers for participants that are no longer in the call. So we ignore those IDs.
8699
+ const newVisibleParticipants = newVisibleParticipantIds
8700
+ .map((participantId) => participantsMap[participantId])
8701
+ .filter((p) => !!p);
8702
+ return newVisibleParticipants;
8703
+ };
8704
+ const participantsById = (participants) => {
8705
+ const response = {};
8706
+ participants.forEach((p) => (response[p.userId] = p));
8707
+ return response;
8708
+ };
8709
+
8710
+ // Copyright (c) Microsoft Corporation.
8711
+ const DEFAULT_MAX_REMOTE_VIDEOSTREAMS = 4;
8712
+ const DEFAULT_MAX_AUDIO_DOMINANT_SPEAKERS = 6;
8713
+ /**
8714
+ * @private
8715
+ */
8716
+ const useFloatingLocalVideoLayout = (props) => {
8717
+ var _a, _b;
8718
+ const visibleVideoParticipants = React.useRef([]);
8719
+ const visibleAudioParticipants = React.useRef([]);
8720
+ const { remoteParticipants, dominantSpeakers, maxRemoteVideoStreams = DEFAULT_MAX_REMOTE_VIDEOSTREAMS, maxAudioDominantSpeakers = DEFAULT_MAX_AUDIO_DOMINANT_SPEAKERS, isScreenShareActive = false } = props;
8721
+ visibleVideoParticipants.current = smartDominantSpeakerParticipants({
8722
+ participants: (_a = remoteParticipants === null || remoteParticipants === void 0 ? void 0 : remoteParticipants.filter((p) => { var _a; return (_a = p.videoStream) === null || _a === void 0 ? void 0 : _a.isAvailable; })) !== null && _a !== void 0 ? _a : [],
8723
+ dominantSpeakers,
8724
+ lastVisibleParticipants: visibleVideoParticipants.current,
8725
+ maxDominantSpeakers: maxRemoteVideoStreams
8726
+ }).slice(0, maxRemoteVideoStreams);
8727
+ const visibleVideoParticipantsSet = new Set(visibleVideoParticipants.current.map((p) => p.userId));
8728
+ /* @conditional-compile-remove(PSTN-calls) */ /* @conditional-compile-remove(one-to-n-calling) */
8729
+ const callingParticipants = remoteParticipants.filter((p) => p.state === ('Connecting' ));
8730
+ /* @conditional-compile-remove(PSTN-calls) */ /* @conditional-compile-remove(one-to-n-calling) */
8731
+ const callingParticipantsSet = new Set(callingParticipants.map((p) => p.userId));
8732
+ visibleAudioParticipants.current = smartDominantSpeakerParticipants({
8733
+ participants: (_b = remoteParticipants === null || remoteParticipants === void 0 ? void 0 : remoteParticipants.filter((p) => !visibleVideoParticipantsSet.has(p.userId) &&
8734
+ /* @conditional-compile-remove(PSTN-calls) */ /* @conditional-compile-remove(one-to-n-calling) */ !callingParticipantsSet.has(p.userId))) !== null && _b !== void 0 ? _b : [],
8735
+ dominantSpeakers,
8736
+ lastVisibleParticipants: visibleAudioParticipants.current,
8737
+ maxDominantSpeakers: maxAudioDominantSpeakers
8738
+ });
8739
+ const getGridParticipants = React.useCallback(() => {
8740
+ if (isScreenShareActive) {
8741
+ return [];
8742
+ }
8743
+ /* @conditional-compile-remove(PSTN-calls) */ /* @conditional-compile-remove(one-to-n-calling) */
8744
+ return visibleVideoParticipants.current.length > 0
8745
+ ? visibleVideoParticipants.current
8746
+ : visibleAudioParticipants.current.concat(callingParticipants);
8747
+ }, [
8748
+ /* @conditional-compile-remove(PSTN-calls) */ /* @conditional-compile-remove(one-to-n-calling) */ callingParticipants,
8749
+ isScreenShareActive
8750
+ ]);
8751
+ const gridParticipants = getGridParticipants();
8752
+ const getHorizontalGalleryRemoteParticipants = React.useCallback(() => {
8753
+ if (isScreenShareActive) {
8754
+ // If screen sharing is active, assign video and audio participants as horizontal gallery participants
8755
+ /* @conditional-compile-remove(PSTN-calls) */ /* @conditional-compile-remove(one-to-n-calling) */
8756
+ return visibleVideoParticipants.current.concat(visibleAudioParticipants.current.concat(callingParticipants));
8757
+ }
8758
+ else {
8759
+ // If screen sharing is not active, then assign all video tiles as grid tiles.
8760
+ // If there are no video tiles, then assign audio tiles as grid tiles.
8761
+ /* @conditional-compile-remove(PSTN-calls) */ /* @conditional-compile-remove(one-to-n-calling) */
8762
+ return visibleVideoParticipants.current.length > 0
8763
+ ? visibleAudioParticipants.current.concat(callingParticipants)
8764
+ : [];
8765
+ }
8766
+ }, [
8767
+ /* @conditional-compile-remove(PSTN-calls) */ /* @conditional-compile-remove(one-to-n-calling) */ callingParticipants,
8768
+ isScreenShareActive
8769
+ ]);
8770
+ const horizontalGalleryParticipants = getHorizontalGalleryRemoteParticipants();
8771
+ return { gridParticipants, horizontalGalleryParticipants };
8772
+ };
8773
+ /**
8774
+ * @private
8775
+ */
8776
+ const usePinnedParticipantLayout = (props) => {
8777
+ // map remote participants by userId
8778
+ const remoteParticipantMap = props.remoteParticipants.reduce((map, remoteParticipant) => {
8779
+ map[remoteParticipant.userId] = remoteParticipant;
8780
+ return map;
8781
+ }, {});
8782
+ // count pinned participants with video
8783
+ let pinnedParticipantsWithVideoOnCount = 0;
8784
+ // get pinned participants in the same order of pinned participant user ids using remoteParticipantMap
8785
+ const pinnedParticipants = [];
8786
+ props.pinnedParticipantUserIds.forEach((id) => {
8787
+ var _a;
8788
+ const pinnedParticipant = remoteParticipantMap[id];
8789
+ if (pinnedParticipant) {
8790
+ pinnedParticipants.push(pinnedParticipant);
8791
+ if ((_a = pinnedParticipant.videoStream) === null || _a === void 0 ? void 0 : _a.isAvailable) {
8792
+ pinnedParticipantsWithVideoOnCount++;
8793
+ }
8794
+ }
8795
+ });
8796
+ // get unpinned participants by filtering all remote participants using a set of pinned participant user ids
8797
+ const pinnedParticipantUserIdSet = new Set(props.pinnedParticipantUserIds);
8798
+ const unpinnedParticipants = props.remoteParticipants.filter((p) => !pinnedParticipantUserIdSet.has(p.userId));
8799
+ const floatingLocalVideoLayoutProps = Object.assign(Object.assign({}, props), {
8800
+ // if there are pinned participants then we should only consider unpinned participants
8801
+ remoteParticipants: unpinnedParticipants,
8802
+ // if there is a maximum of remote video streams we need to subtract pinned participants with video
8803
+ maxRemoteVideoStreams: props.maxRemoteVideoStreams
8804
+ ? props.maxRemoteVideoStreams - pinnedParticipantsWithVideoOnCount
8805
+ : undefined });
8806
+ const floatingLocalVideoLayout = useFloatingLocalVideoLayout(floatingLocalVideoLayoutProps);
8807
+ if (props.pinnedParticipantUserIds.length === 0) {
8808
+ return floatingLocalVideoLayout;
8809
+ }
8810
+ return {
8811
+ gridParticipants: props.isScreenShareActive ? [] : pinnedParticipants,
8812
+ horizontalGalleryParticipants: props.isScreenShareActive
8813
+ ? pinnedParticipants.concat(floatingLocalVideoLayout.horizontalGalleryParticipants)
8814
+ : floatingLocalVideoLayout.gridParticipants.concat(floatingLocalVideoLayout.horizontalGalleryParticipants)
8815
+ };
8816
+ };
8817
+
8656
8818
  // Copyright (c) Microsoft Corporation.
8657
8819
  // Licensed under the MIT license.
8658
8820
  /**
@@ -8787,243 +8949,18 @@ const calculateChildrenPerPage = (args) => {
8787
8949
  }
8788
8950
  const buttonWidth = _convertRemToPx(buttonWidthRem);
8789
8951
  /** We know we need to paginate. So we need to subtract the buttonWidth twice and gapWidth twice from
8790
- * containerWidth to compute childrenSpace
8791
- * <-----------containerWidth--------->
8792
- * __________________________________
8793
- * | || || || |
8794
- * |<|| || ||>|
8795
- * |_||_____________||_____________||_|
8796
- * <-------childrenSpace------>
8797
- */
8798
- const childrenSpace = containerWidth - 2 * buttonWidth - 2 * gapWidth;
8799
- // Now that we have childrenSpace width we can figure out how many children can fit in childrenSpace.
8800
- // childrenSpace = n * childWidth + (n - 1) * gapWidth. Isolate n and take the floor.
8801
- return Math.floor((childrenSpace + gapWidth) / (childWidth + gapWidth));
8802
- };
8803
-
8804
- // Copyright (c) Microsoft Corporation.
8805
- /**
8806
- * Small floating modal width and height in rem for small screen
8807
- */
8808
- const SMALL_FLOATING_MODAL_SIZE_PX$1 = { width: 64, height: 88 };
8809
- /**
8810
- * Large floating modal width and height in rem for large screen
8811
- */
8812
- const LARGE_FLOATING_MODAL_SIZE_PX$1 = { width: 160, height: 120 };
8813
- /**
8814
- * @private
8815
- */
8816
- const horizontalGalleryContainerStyle = (shouldFloatLocalVideo, isNarrow) => {
8817
- return {
8818
- minHeight: isNarrow
8819
- ? `${SMALL_HORIZONTAL_GALLERY_TILE_SIZE_REM.height}rem`
8820
- : `${LARGE_HORIZONTAL_GALLERY_TILE_SIZE_REM.height}rem`,
8821
- width: shouldFloatLocalVideo
8822
- ? isNarrow
8823
- ? `calc(100% - ${_pxToRem(SMALL_FLOATING_MODAL_SIZE_PX$1.width)})`
8824
- : `calc(100% - ${_pxToRem(LARGE_FLOATING_MODAL_SIZE_PX$1.width)})`
8825
- : '100%',
8826
- paddingRight: '0.5rem'
8827
- };
8828
- };
8829
- /**
8830
- * @private
8831
- */
8832
- const horizontalGalleryStyle = (isNarrow) => {
8833
- return {
8834
- children: isNarrow ? SMALL_HORIZONTAL_GALLERY_TILE_STYLE : LARGE_HORIZONTAL_GALLERY_TILE_STYLE
8835
- };
8836
- };
8837
- /**
8838
- * Small horizontal gallery tile size in rem
8839
- * @private
8840
- */
8841
- const SMALL_HORIZONTAL_GALLERY_TILE_SIZE_REM = { height: 5.5, width: 5.5 };
8842
- /**
8843
- * Large horizontal gallery tile size in rem
8844
- * @private
8845
- */
8846
- const LARGE_HORIZONTAL_GALLERY_TILE_SIZE_REM = { height: 7.5, width: 10 };
8847
- /**
8848
- * @private
8849
- */
8850
- const SMALL_HORIZONTAL_GALLERY_TILE_STYLE = {
8851
- minHeight: `${SMALL_HORIZONTAL_GALLERY_TILE_SIZE_REM.height}rem`,
8852
- minWidth: `${SMALL_HORIZONTAL_GALLERY_TILE_SIZE_REM.width}rem`,
8853
- maxHeight: `${SMALL_HORIZONTAL_GALLERY_TILE_SIZE_REM.height}rem`,
8854
- maxWidth: `${SMALL_HORIZONTAL_GALLERY_TILE_SIZE_REM.width}rem`
8855
- };
8856
- /**
8857
- * @private
8858
- */
8859
- const LARGE_HORIZONTAL_GALLERY_TILE_STYLE = {
8860
- minHeight: `${LARGE_HORIZONTAL_GALLERY_TILE_SIZE_REM.height}rem`,
8861
- minWidth: `${LARGE_HORIZONTAL_GALLERY_TILE_SIZE_REM.width}rem`,
8862
- maxHeight: `${LARGE_HORIZONTAL_GALLERY_TILE_SIZE_REM.height}rem`,
8863
- maxWidth: `${LARGE_HORIZONTAL_GALLERY_TILE_SIZE_REM.width}rem`
8864
- };
8865
-
8866
- // Copyright (c) Microsoft Corporation.
8867
- /**
8868
- * A ResponsiveHorizontalGallery styled for the @link{VideoGallery}
8869
- */
8870
- const VideoGalleryResponsiveHorizontalGallery = (props) => {
8871
- const { shouldFloatLocalVideo = false, isNarrow = false, horizontalGalleryElements, styles } = props;
8872
- const containerStyles = React.useMemo(() => horizontalGalleryContainerStyle(shouldFloatLocalVideo, isNarrow), [shouldFloatLocalVideo, isNarrow]);
8873
- const galleryStyles = React.useMemo(() => react.concatStyleSets(horizontalGalleryStyle(isNarrow), styles), [isNarrow, styles]);
8874
- return (React__default['default'].createElement(react.Stack, { styles: { root: { paddingTop: '0.5rem' } } },
8875
- React__default['default'].createElement(ResponsiveHorizontalGallery, { key: "responsive-horizontal-gallery", containerStyles: containerStyles, horizontalGalleryStyles: galleryStyles, childWidthRem: isNarrow ? SMALL_HORIZONTAL_GALLERY_TILE_SIZE_REM.width : LARGE_HORIZONTAL_GALLERY_TILE_SIZE_REM.width, buttonWidthRem: HORIZONTAL_GALLERY_BUTTON_WIDTH, gapWidthRem: HORIZONTAL_GALLERY_GAP }, horizontalGalleryElements)));
8876
- };
8877
-
8878
- /**
8879
- * Calculates the participants that should be rendered based on the list of dominant
8880
- * speakers and currently rendered participants in a call.
8881
- * @param args - SmartDominantSpeakerParticipantsArgs
8882
- * @returns VideoGalleryRemoteParticipant[] {@link @azure/communication-react#VideoGalleryRemoteParticipant}
8883
- */
8884
- const smartDominantSpeakerParticipants = (args) => {
8885
- const { participants, dominantSpeakers = [], lastVisibleParticipants = [], maxDominantSpeakers } = args;
8886
- // Don't apply any logic if total number of video streams is less than max dominant speakers.
8887
- if (participants.length <= maxDominantSpeakers) {
8888
- return participants;
8889
- }
8890
- const participantsMap = participantsById(participants);
8891
- // Only use the Max allowed dominant speakers that exist in participants
8892
- const dominantSpeakerIds = Array.from(new Set(dominantSpeakers).values())
8893
- .filter((id) => !!participantsMap[id])
8894
- .slice(0, maxDominantSpeakers);
8895
- const lastVisibleParticipantIds = lastVisibleParticipants.map((p) => p.userId);
8896
- const newVisibleParticipantIds = lastVisibleParticipants.map((p) => p.userId).slice(0, maxDominantSpeakers);
8897
- const newDominantSpeakerIds = dominantSpeakerIds.filter((id) => !newVisibleParticipantIds.includes(id));
8898
- // Remove participants that are no longer dominant and replace them with new dominant speakers.
8899
- for (let index = 0; index < maxDominantSpeakers; index++) {
8900
- const newVisibleParticipantId = newVisibleParticipantIds[index];
8901
- if (newVisibleParticipantId === undefined || !dominantSpeakerIds.includes(newVisibleParticipantId)) {
8902
- const replacement = newDominantSpeakerIds.shift();
8903
- if (!replacement) {
8904
- break;
8905
- }
8906
- newVisibleParticipantIds[index] = replacement;
8907
- }
8908
- }
8909
- const removedVisibleParticipantIds = lastVisibleParticipantIds.filter((p) => !newVisibleParticipantIds.includes(p));
8910
- removedVisibleParticipantIds.forEach((p) => newVisibleParticipantIds.push(p));
8911
- const newVisibleParticipantIdSet = new Set(newVisibleParticipantIds);
8912
- const leftoverParticipants = participants.filter((p) => !newVisibleParticipantIdSet.has(p.userId));
8913
- leftoverParticipants.forEach((p) => {
8914
- newVisibleParticipantIds.push(p.userId);
8915
- });
8916
- // newVisibleParticipantIds can contain identifiers for participants that are no longer in the call. So we ignore those IDs.
8917
- const newVisibleParticipants = newVisibleParticipantIds
8918
- .map((participantId) => participantsMap[participantId])
8919
- .filter((p) => !!p);
8920
- return newVisibleParticipants;
8921
- };
8922
- const participantsById = (participants) => {
8923
- const response = {};
8924
- participants.forEach((p) => (response[p.userId] = p));
8925
- return response;
8926
- };
8927
-
8928
- // Copyright (c) Microsoft Corporation.
8929
- const DEFAULT_MAX_REMOTE_VIDEOSTREAMS = 4;
8930
- const DEFAULT_MAX_AUDIO_DOMINANT_SPEAKERS = 6;
8931
- /**
8932
- * @private
8933
- */
8934
- const useFloatingLocalVideoLayout = (props) => {
8935
- var _a, _b;
8936
- const visibleVideoParticipants = React.useRef([]);
8937
- const visibleAudioParticipants = React.useRef([]);
8938
- const { remoteParticipants, dominantSpeakers, maxRemoteVideoStreams = DEFAULT_MAX_REMOTE_VIDEOSTREAMS, maxAudioDominantSpeakers = DEFAULT_MAX_AUDIO_DOMINANT_SPEAKERS, isScreenShareActive = false } = props;
8939
- visibleVideoParticipants.current = smartDominantSpeakerParticipants({
8940
- participants: (_a = remoteParticipants === null || remoteParticipants === void 0 ? void 0 : remoteParticipants.filter((p) => { var _a; return (_a = p.videoStream) === null || _a === void 0 ? void 0 : _a.isAvailable; })) !== null && _a !== void 0 ? _a : [],
8941
- dominantSpeakers,
8942
- lastVisibleParticipants: visibleVideoParticipants.current,
8943
- maxDominantSpeakers: maxRemoteVideoStreams
8944
- }).slice(0, maxRemoteVideoStreams);
8945
- const visibleVideoParticipantsSet = new Set(visibleVideoParticipants.current.map((p) => p.userId));
8946
- /* @conditional-compile-remove(PSTN-calls) */ /* @conditional-compile-remove(one-to-n-calling) */
8947
- const callingParticipants = remoteParticipants.filter((p) => p.state === ('Connecting' ));
8948
- /* @conditional-compile-remove(PSTN-calls) */ /* @conditional-compile-remove(one-to-n-calling) */
8949
- const callingParticipantsSet = new Set(callingParticipants.map((p) => p.userId));
8950
- visibleAudioParticipants.current = smartDominantSpeakerParticipants({
8951
- participants: (_b = remoteParticipants === null || remoteParticipants === void 0 ? void 0 : remoteParticipants.filter((p) => !visibleVideoParticipantsSet.has(p.userId) &&
8952
- /* @conditional-compile-remove(PSTN-calls) */ /* @conditional-compile-remove(one-to-n-calling) */ !callingParticipantsSet.has(p.userId))) !== null && _b !== void 0 ? _b : [],
8953
- dominantSpeakers,
8954
- lastVisibleParticipants: visibleAudioParticipants.current,
8955
- maxDominantSpeakers: maxAudioDominantSpeakers
8956
- });
8957
- const getGridParticipants = React.useCallback(() => {
8958
- if (isScreenShareActive) {
8959
- return [];
8960
- }
8961
- /* @conditional-compile-remove(PSTN-calls) */ /* @conditional-compile-remove(one-to-n-calling) */
8962
- return visibleVideoParticipants.current.length > 0
8963
- ? visibleVideoParticipants.current
8964
- : visibleAudioParticipants.current.concat(callingParticipants);
8965
- }, [
8966
- /* @conditional-compile-remove(PSTN-calls) */ /* @conditional-compile-remove(one-to-n-calling) */ callingParticipants,
8967
- isScreenShareActive
8968
- ]);
8969
- const gridParticipants = getGridParticipants();
8970
- const getHorizontalGalleryRemoteParticipants = React.useCallback(() => {
8971
- if (isScreenShareActive) {
8972
- // If screen sharing is active, assign video and audio participants as horizontal gallery participants
8973
- /* @conditional-compile-remove(PSTN-calls) */ /* @conditional-compile-remove(one-to-n-calling) */
8974
- return visibleVideoParticipants.current.concat(visibleAudioParticipants.current.concat(callingParticipants));
8975
- }
8976
- else {
8977
- // If screen sharing is not active, then assign all video tiles as grid tiles.
8978
- // If there are no video tiles, then assign audio tiles as grid tiles.
8979
- /* @conditional-compile-remove(PSTN-calls) */ /* @conditional-compile-remove(one-to-n-calling) */
8980
- return visibleVideoParticipants.current.length > 0
8981
- ? visibleAudioParticipants.current.concat(callingParticipants)
8982
- : [];
8983
- }
8984
- }, [
8985
- /* @conditional-compile-remove(PSTN-calls) */ /* @conditional-compile-remove(one-to-n-calling) */ callingParticipants,
8986
- isScreenShareActive
8987
- ]);
8988
- const horizontalGalleryParticipants = getHorizontalGalleryRemoteParticipants();
8989
- return { gridParticipants, horizontalGalleryParticipants };
8990
- };
8991
-
8992
- // Copyright (c) Microsoft Corporation.
8993
- /**
8994
- * DefaultLayout displays remote participants, local video component, and screen sharing component in
8995
- * a grid and horizontal gallery.
8996
- *
8997
- * @private
8998
- */
8999
- const DefaultLayout = (props) => {
9000
- const { remoteParticipants = [], dominantSpeakers, localVideoComponent, screenShareComponent, onRenderRemoteParticipant, styles, maxRemoteVideoStreams, parentWidth } = props;
9001
- const isNarrow = parentWidth ? isNarrowWidth(parentWidth) : false;
9002
- const floatingLocalVideoLayout = useFloatingLocalVideoLayout({
9003
- remoteParticipants,
9004
- dominantSpeakers,
9005
- maxRemoteVideoStreams,
9006
- isScreenShareActive: !!screenShareComponent
9007
- });
9008
- let activeVideoStreams = 0;
9009
- const gridTiles = floatingLocalVideoLayout.gridParticipants.map((p) => {
9010
- var _a, _b;
9011
- return onRenderRemoteParticipant(p, maxRemoteVideoStreams && maxRemoteVideoStreams >= 0
9012
- ? ((_a = p.videoStream) === null || _a === void 0 ? void 0 : _a.isAvailable) && activeVideoStreams++ < maxRemoteVideoStreams
9013
- : (_b = p.videoStream) === null || _b === void 0 ? void 0 : _b.isAvailable);
9014
- });
9015
- const horizontalGalleryTiles = floatingLocalVideoLayout.horizontalGalleryParticipants.map((p) => {
9016
- var _a, _b;
9017
- return onRenderRemoteParticipant(p, maxRemoteVideoStreams && maxRemoteVideoStreams >= 0
9018
- ? ((_a = p.videoStream) === null || _a === void 0 ? void 0 : _a.isAvailable) && activeVideoStreams++ < maxRemoteVideoStreams
9019
- : (_b = p.videoStream) === null || _b === void 0 ? void 0 : _b.isAvailable);
9020
- });
9021
- if (localVideoComponent) {
9022
- gridTiles.push(localVideoComponent);
9023
- }
9024
- return (React__default['default'].createElement(react.Stack, { horizontal: false, styles: rootLayoutStyle$1 },
9025
- screenShareComponent ? (screenShareComponent) : (React__default['default'].createElement(GridLayout, { key: "grid-layout", styles: styles === null || styles === void 0 ? void 0 : styles.gridLayout }, gridTiles)),
9026
- horizontalGalleryTiles.length > 0 && (React__default['default'].createElement(VideoGalleryResponsiveHorizontalGallery, { isNarrow: isNarrow, horizontalGalleryElements: horizontalGalleryTiles, styles: styles === null || styles === void 0 ? void 0 : styles.horizontalGallery }))));
8952
+ * containerWidth to compute childrenSpace
8953
+ * <-----------containerWidth--------->
8954
+ * __________________________________
8955
+ * | || || || |
8956
+ * |<|| || ||>|
8957
+ * |_||_____________||_____________||_|
8958
+ * <-------childrenSpace------>
8959
+ */
8960
+ const childrenSpace = containerWidth - 2 * buttonWidth - 2 * gapWidth;
8961
+ // Now that we have childrenSpace width we can figure out how many children can fit in childrenSpace.
8962
+ // childrenSpace = n * childWidth + (n - 1) * gapWidth. Isolate n and take the floor.
8963
+ return Math.floor((childrenSpace + gapWidth) / (childWidth + gapWidth));
9027
8964
  };
9028
8965
 
9029
8966
  // Copyright (c) Microsoft Corporation.
@@ -9037,8 +8974,9 @@ react.mergeStyles({ position: 'relative', width: '100%', height: '100%' });
9037
8974
  const SMALL_FLOATING_MODAL_SIZE_PX = { width: 64, height: 88 };
9038
8975
  /**
9039
8976
  * Large floating modal width and height in rem for large screen
8977
+ * Aspect ratio: 16:9
9040
8978
  */
9041
- const LARGE_FLOATING_MODAL_SIZE_PX = { width: 160, height: 120 };
8979
+ const LARGE_FLOATING_MODAL_SIZE_PX = { width: 215, height: 120 };
9042
8980
  /**
9043
8981
  * @private
9044
8982
  * z-index to ensure that the local video tile is above the video gallery.
@@ -9103,6 +9041,111 @@ const localVideoModalStyles = {
9103
9041
  }
9104
9042
  };
9105
9043
 
9044
+ // Copyright (c) Microsoft Corporation.
9045
+ /**
9046
+ * @private
9047
+ */
9048
+ const horizontalGalleryContainerStyle = (shouldFloatLocalVideo, isNarrow) => {
9049
+ return {
9050
+ minHeight: isNarrow
9051
+ ? `${SMALL_HORIZONTAL_GALLERY_TILE_SIZE_REM.height}rem`
9052
+ : `${LARGE_HORIZONTAL_GALLERY_TILE_SIZE_REM.height}rem`,
9053
+ width: shouldFloatLocalVideo
9054
+ ? isNarrow
9055
+ ? `calc(100% - ${_pxToRem(SMALL_FLOATING_MODAL_SIZE_PX.width)})`
9056
+ : `calc(100% - ${_pxToRem(LARGE_FLOATING_MODAL_SIZE_PX.width)})`
9057
+ : '100%',
9058
+ paddingRight: '0.5rem'
9059
+ };
9060
+ };
9061
+ /**
9062
+ * @private
9063
+ */
9064
+ const horizontalGalleryStyle = (isNarrow) => {
9065
+ return {
9066
+ children: isNarrow ? SMALL_HORIZONTAL_GALLERY_TILE_STYLE : LARGE_HORIZONTAL_GALLERY_TILE_STYLE
9067
+ };
9068
+ };
9069
+ /**
9070
+ * Small horizontal gallery tile size in rem
9071
+ * @private
9072
+ */
9073
+ const SMALL_HORIZONTAL_GALLERY_TILE_SIZE_REM = { height: 5.5, width: 5.5 };
9074
+ /**
9075
+ * Large horizontal gallery tile size in rem
9076
+ * @private
9077
+ */
9078
+ const LARGE_HORIZONTAL_GALLERY_TILE_SIZE_REM = { height: 7.5, width: 10 };
9079
+ /**
9080
+ * @private
9081
+ */
9082
+ const SMALL_HORIZONTAL_GALLERY_TILE_STYLE = {
9083
+ minHeight: `${SMALL_HORIZONTAL_GALLERY_TILE_SIZE_REM.height}rem`,
9084
+ minWidth: `${SMALL_HORIZONTAL_GALLERY_TILE_SIZE_REM.width}rem`,
9085
+ maxHeight: `${SMALL_HORIZONTAL_GALLERY_TILE_SIZE_REM.height}rem`,
9086
+ maxWidth: `${SMALL_HORIZONTAL_GALLERY_TILE_SIZE_REM.width}rem`
9087
+ };
9088
+ /**
9089
+ * @private
9090
+ */
9091
+ const LARGE_HORIZONTAL_GALLERY_TILE_STYLE = {
9092
+ minHeight: `${LARGE_HORIZONTAL_GALLERY_TILE_SIZE_REM.height}rem`,
9093
+ minWidth: `${LARGE_HORIZONTAL_GALLERY_TILE_SIZE_REM.width}rem`,
9094
+ maxHeight: `${LARGE_HORIZONTAL_GALLERY_TILE_SIZE_REM.height}rem`,
9095
+ maxWidth: `${LARGE_HORIZONTAL_GALLERY_TILE_SIZE_REM.width}rem`
9096
+ };
9097
+
9098
+ // Copyright (c) Microsoft Corporation.
9099
+ /**
9100
+ * A ResponsiveHorizontalGallery styled for the {@link VideoGallery}
9101
+ *
9102
+ * @private
9103
+ */
9104
+ const VideoGalleryResponsiveHorizontalGallery = (props) => {
9105
+ const { shouldFloatLocalVideo = false, isNarrow = false, horizontalGalleryElements, styles } = props;
9106
+ const containerStyles = React.useMemo(() => horizontalGalleryContainerStyle(shouldFloatLocalVideo, isNarrow), [shouldFloatLocalVideo, isNarrow]);
9107
+ const galleryStyles = React.useMemo(() => react.concatStyleSets(horizontalGalleryStyle(isNarrow), styles), [isNarrow, styles]);
9108
+ return (React__default['default'].createElement(react.Stack, { styles: { root: { paddingTop: '0.5rem' } } },
9109
+ React__default['default'].createElement(ResponsiveHorizontalGallery, { key: "responsive-horizontal-gallery", containerStyles: containerStyles, horizontalGalleryStyles: galleryStyles, childWidthRem: isNarrow ? SMALL_HORIZONTAL_GALLERY_TILE_SIZE_REM.width : LARGE_HORIZONTAL_GALLERY_TILE_SIZE_REM.width, buttonWidthRem: HORIZONTAL_GALLERY_BUTTON_WIDTH, gapWidthRem: HORIZONTAL_GALLERY_GAP }, horizontalGalleryElements)));
9110
+ };
9111
+
9112
+ // Copyright (c) Microsoft Corporation.
9113
+ /**
9114
+ * DefaultLayout displays remote participants, local video component, and screen sharing component in
9115
+ * a grid and horizontal gallery.
9116
+ *
9117
+ * @private
9118
+ */
9119
+ const DefaultLayout = (props) => {
9120
+ const { remoteParticipants = [], dominantSpeakers, localVideoComponent, screenShareComponent, onRenderRemoteParticipant, styles, maxRemoteVideoStreams, parentWidth } = props;
9121
+ const isNarrow = parentWidth ? isNarrowWidth(parentWidth) : false;
9122
+ const floatingLocalVideoLayout = useFloatingLocalVideoLayout({
9123
+ remoteParticipants,
9124
+ dominantSpeakers,
9125
+ maxRemoteVideoStreams,
9126
+ isScreenShareActive: !!screenShareComponent
9127
+ });
9128
+ let activeVideoStreams = 0;
9129
+ const gridTiles = floatingLocalVideoLayout.gridParticipants.map((p) => {
9130
+ var _a, _b;
9131
+ return onRenderRemoteParticipant(p, maxRemoteVideoStreams && maxRemoteVideoStreams >= 0
9132
+ ? ((_a = p.videoStream) === null || _a === void 0 ? void 0 : _a.isAvailable) && activeVideoStreams++ < maxRemoteVideoStreams
9133
+ : (_b = p.videoStream) === null || _b === void 0 ? void 0 : _b.isAvailable);
9134
+ });
9135
+ const horizontalGalleryTiles = floatingLocalVideoLayout.horizontalGalleryParticipants.map((p) => {
9136
+ var _a, _b;
9137
+ return onRenderRemoteParticipant(p, maxRemoteVideoStreams && maxRemoteVideoStreams >= 0
9138
+ ? ((_a = p.videoStream) === null || _a === void 0 ? void 0 : _a.isAvailable) && activeVideoStreams++ < maxRemoteVideoStreams
9139
+ : (_b = p.videoStream) === null || _b === void 0 ? void 0 : _b.isAvailable);
9140
+ });
9141
+ if (localVideoComponent) {
9142
+ gridTiles.push(localVideoComponent);
9143
+ }
9144
+ return (React__default['default'].createElement(react.Stack, { horizontal: false, styles: rootLayoutStyle$1 },
9145
+ screenShareComponent ? (screenShareComponent) : (React__default['default'].createElement(GridLayout, { key: "grid-layout", styles: styles === null || styles === void 0 ? void 0 : styles.gridLayout }, gridTiles)),
9146
+ horizontalGalleryTiles.length > 0 && (React__default['default'].createElement(VideoGalleryResponsiveHorizontalGallery, { isNarrow: isNarrow, horizontalGalleryElements: horizontalGalleryTiles, styles: styles === null || styles === void 0 ? void 0 : styles.horizontalGallery }))));
9147
+ };
9148
+
9106
9149
  // Copyright (c) Microsoft Corporation.
9107
9150
  const animationDuration = react.AnimationVariables.durationValue2;
9108
9151
  const ZERO = { x: 0, y: 0 };
@@ -9887,6 +9930,56 @@ const FloatingLocalVideoLayout = (props) => {
9887
9930
  React__default['default'].createElement(react.LayerHost, { id: layerHostId, className: react.mergeStyles(layerHostStyle) }))));
9888
9931
  };
9889
9932
 
9933
+ // Copyright (c) Microsoft Corporation.
9934
+ /**
9935
+ * PinnedParticipantsLayout displays remote participants and a screen sharing component in
9936
+ * a grid and horizontal gallery while floating the local video
9937
+ *
9938
+ * @private
9939
+ */
9940
+ const PinnedParticipantsLayout = (props) => {
9941
+ const { remoteParticipants = [], pinnedParticipants = [], dominantSpeakers, localVideoComponent, screenShareComponent, onRenderRemoteParticipant, styles, maxRemoteVideoStreams, showCameraSwitcherInLocalPreview, parentWidth, parentHeight, isLocalVideoFloating } = props;
9942
+ const theme = useTheme();
9943
+ const isNarrow = parentWidth ? isNarrowWidth(parentWidth) : false;
9944
+ const pinnedParticipantsLayout = usePinnedParticipantLayout({
9945
+ remoteParticipants,
9946
+ pinnedParticipantUserIds: pinnedParticipants,
9947
+ dominantSpeakers,
9948
+ maxRemoteVideoStreams,
9949
+ isScreenShareActive: !!screenShareComponent
9950
+ });
9951
+ let activeVideoStreams = 0;
9952
+ const shouldFloatLocalVideo = isLocalVideoFloating && remoteParticipants.length > 0;
9953
+ const gridTiles = pinnedParticipantsLayout.gridParticipants.map((p) => {
9954
+ var _a, _b;
9955
+ return onRenderRemoteParticipant(p, maxRemoteVideoStreams && maxRemoteVideoStreams >= 0
9956
+ ? ((_a = p.videoStream) === null || _a === void 0 ? void 0 : _a.isAvailable) && activeVideoStreams++ < maxRemoteVideoStreams
9957
+ : (_b = p.videoStream) === null || _b === void 0 ? void 0 : _b.isAvailable);
9958
+ });
9959
+ if (localVideoComponent && !shouldFloatLocalVideo) {
9960
+ gridTiles.push(localVideoComponent);
9961
+ }
9962
+ const horizontalGalleryTiles = pinnedParticipantsLayout.horizontalGalleryParticipants.map((p) => {
9963
+ var _a, _b;
9964
+ return onRenderRemoteParticipant(p, maxRemoteVideoStreams && maxRemoteVideoStreams >= 0
9965
+ ? ((_a = p.videoStream) === null || _a === void 0 ? void 0 : _a.isAvailable) && activeVideoStreams++ < maxRemoteVideoStreams
9966
+ : (_b = p.videoStream) === null || _b === void 0 ? void 0 : _b.isAvailable);
9967
+ });
9968
+ const layerHostId = reactHooks.useId('layerhost');
9969
+ const wrappedLocalVideoComponent = localVideoComponent && shouldFloatLocalVideo ? (
9970
+ // When we use showCameraSwitcherInLocalPreview it disables dragging to allow keyboard navigation.
9971
+ showCameraSwitcherInLocalPreview ? (React__default['default'].createElement(react.Stack, { className: react.mergeStyles(localVideoTileWithControlsContainerStyle(theme, isNarrow), {
9972
+ boxShadow: theme.effects.elevation8,
9973
+ zIndex: LOCAL_VIDEO_TILE_ZINDEX
9974
+ }) }, localVideoComponent)) : horizontalGalleryTiles.length > 0 ? (React__default['default'].createElement(react.Stack, { className: react.mergeStyles(localVideoTileContainerStyle(theme, isNarrow)) }, localVideoComponent)) : (React__default['default'].createElement(FloatingLocalVideo, { localVideoComponent: localVideoComponent, layerHostId: layerHostId, isNarrow: isNarrow, parentWidth: parentWidth, parentHeight: parentHeight }))) : undefined;
9975
+ return (React__default['default'].createElement(react.Stack, { styles: rootLayoutStyle },
9976
+ wrappedLocalVideoComponent,
9977
+ React__default['default'].createElement(react.Stack, { horizontal: false, styles: innerLayoutStyle },
9978
+ screenShareComponent ? (screenShareComponent) : (React__default['default'].createElement(GridLayout, { key: "grid-layout", styles: styles === null || styles === void 0 ? void 0 : styles.gridLayout }, gridTiles)),
9979
+ horizontalGalleryTiles.length > 0 && (React__default['default'].createElement(VideoGalleryResponsiveHorizontalGallery, { isNarrow: isNarrow, shouldFloatLocalVideo: true, horizontalGalleryElements: horizontalGalleryTiles, styles: styles === null || styles === void 0 ? void 0 : styles.horizontalGallery })),
9980
+ React__default['default'].createElement(react.LayerHost, { id: layerHostId, className: react.mergeStyles(layerHostStyle) }))));
9981
+ };
9982
+
9890
9983
  // Copyright (c) Microsoft Corporation.
9891
9984
  /**
9892
9985
  * @private
@@ -9900,7 +9993,7 @@ const DEFAULT_MAX_REMOTE_VIDEO_STREAMS = 4;
9900
9993
  * @public
9901
9994
  */
9902
9995
  const VideoGallery = (props) => {
9903
- var _a, _b;
9996
+ var _a, _b, _c;
9904
9997
  const { localParticipant, remoteParticipants = [], localVideoViewOptions, remoteVideoViewOptions, dominantSpeakers, onRenderLocalVideoTile, onRenderRemoteVideoTile, onCreateLocalStreamView, onDisposeLocalStreamView, onCreateRemoteStreamView, onDisposeRemoteStreamView, styles, layout, onRenderAvatar, showMuteIndicator, maxRemoteVideoStreams = DEFAULT_MAX_REMOTE_VIDEO_STREAMS, showCameraSwitcherInLocalPreview, localVideoCameraCycleButtonProps } = props;
9905
9998
  const ids = useIdentifiers();
9906
9999
  const theme = useTheme();
@@ -9911,6 +10004,11 @@ const VideoGallery = (props) => {
9911
10004
  const containerWidth = _useContainerWidth(containerRef);
9912
10005
  const containerHeight = _useContainerHeight(containerRef);
9913
10006
  const isNarrow = containerWidth ? isNarrowWidth(containerWidth) : false;
10007
+ /* @conditional-compile-remove(pinned-participants) */
10008
+ const [pinnedParticipantsState, _] = React__default['default'].useState([]);
10009
+ /* @conditional-compile-remove(pinned-participants) */
10010
+ // Use pinnedParticipants from props but if it is not defined use the maintained state of pinned participants
10011
+ const pinnedParticipants = (_a = props.pinnedParticipants) !== null && _a !== void 0 ? _a : pinnedParticipantsState;
9914
10012
  /* @conditional-compile-remove(rooms) */
9915
10013
  const permissions = _usePermissions();
9916
10014
  /**
@@ -9971,13 +10069,50 @@ const VideoGallery = (props) => {
9971
10069
  ]);
9972
10070
  const screenShareParticipant = remoteParticipants.find((participant) => { var _a; return (_a = participant.screenShareStream) === null || _a === void 0 ? void 0 : _a.isAvailable; });
9973
10071
  const localScreenShareStreamComponent = React__default['default'].createElement(LocalScreenShare, { localParticipant: localParticipant });
9974
- const remoteScreenShareComponent = screenShareParticipant && (React__default['default'].createElement(RemoteScreenShare, Object.assign({}, screenShareParticipant, { renderElement: (_a = screenShareParticipant.screenShareStream) === null || _a === void 0 ? void 0 : _a.renderElement, onCreateRemoteStreamView: onCreateRemoteStreamView, onDisposeRemoteStreamView: onDisposeRemoteStreamView, isReceiving: (_b = screenShareParticipant.screenShareStream) === null || _b === void 0 ? void 0 : _b.isReceiving })));
10072
+ const remoteScreenShareComponent = screenShareParticipant && (React__default['default'].createElement(RemoteScreenShare, Object.assign({}, screenShareParticipant, { renderElement: (_b = screenShareParticipant.screenShareStream) === null || _b === void 0 ? void 0 : _b.renderElement, onCreateRemoteStreamView: onCreateRemoteStreamView, onDisposeRemoteStreamView: onDisposeRemoteStreamView, isReceiving: (_c = screenShareParticipant.screenShareStream) === null || _c === void 0 ? void 0 : _c.isReceiving })));
9975
10073
  const screenShareComponent = remoteScreenShareComponent
9976
10074
  ? remoteScreenShareComponent
9977
10075
  : localParticipant.isScreenSharingOn
9978
10076
  ? localScreenShareStreamComponent
9979
10077
  : undefined;
9980
- const videoGalleryLayout = layout === 'floatingLocalVideo' ? (React__default['default'].createElement(FloatingLocalVideoLayout, { remoteParticipants: remoteParticipants, onRenderRemoteParticipant: onRenderRemoteVideoTile !== null && onRenderRemoteVideoTile !== void 0 ? onRenderRemoteVideoTile : defaultOnRenderVideoTile, localVideoComponent: localVideoTile, screenShareComponent: screenShareComponent, showCameraSwitcherInLocalPreview: showCameraSwitcherInLocalPreview, maxRemoteVideoStreams: maxRemoteVideoStreams, dominantSpeakers: dominantSpeakers, parentWidth: containerWidth, parentHeight: containerHeight, styles: styles })) : (React__default['default'].createElement(DefaultLayout, { remoteParticipants: remoteParticipants, onRenderRemoteParticipant: onRenderRemoteVideoTile !== null && onRenderRemoteVideoTile !== void 0 ? onRenderRemoteVideoTile : defaultOnRenderVideoTile, localVideoComponent: localVideoTile, screenShareComponent: screenShareComponent, maxRemoteVideoStreams: maxRemoteVideoStreams, dominantSpeakers: dominantSpeakers, parentWidth: containerWidth, styles: styles }));
10078
+ const layoutProps = React.useMemo(() => ({
10079
+ remoteParticipants,
10080
+ /* @conditional-compile-remove(pinned-participants) */ pinnedParticipants,
10081
+ screenShareComponent,
10082
+ showCameraSwitcherInLocalPreview,
10083
+ maxRemoteVideoStreams,
10084
+ dominantSpeakers,
10085
+ styles,
10086
+ onRenderRemoteParticipant: onRenderRemoteVideoTile !== null && onRenderRemoteVideoTile !== void 0 ? onRenderRemoteVideoTile : defaultOnRenderVideoTile,
10087
+ localVideoComponent: localVideoTile,
10088
+ parentWidth: containerWidth,
10089
+ parentHeight: containerHeight,
10090
+ isLocalVideoFloating: layout === 'floatingLocalVideo'
10091
+ }), [
10092
+ remoteParticipants,
10093
+ screenShareComponent,
10094
+ showCameraSwitcherInLocalPreview,
10095
+ maxRemoteVideoStreams,
10096
+ dominantSpeakers,
10097
+ styles,
10098
+ localVideoTile,
10099
+ containerWidth,
10100
+ containerHeight,
10101
+ onRenderRemoteVideoTile,
10102
+ defaultOnRenderVideoTile,
10103
+ layout,
10104
+ /* @conditional-compile-remove(pinned-participants) */ pinnedParticipants
10105
+ ]);
10106
+ const videoGalleryLayout = React.useMemo(() => {
10107
+ /* @conditional-compile-remove(pinned-participants) */
10108
+ if (layoutProps.pinnedParticipants.length > 0) {
10109
+ return React__default['default'].createElement(PinnedParticipantsLayout, Object.assign({}, layoutProps));
10110
+ }
10111
+ if (layout === 'floatingLocalVideo') {
10112
+ return React__default['default'].createElement(FloatingLocalVideoLayout, Object.assign({}, layoutProps));
10113
+ }
10114
+ return React__default['default'].createElement(DefaultLayout, Object.assign({}, layoutProps));
10115
+ }, [layout, layoutProps]);
9981
10116
  return (React__default['default'].createElement("div", { "data-ui-id": ids.videoGallery, ref: containerRef, className: react.mergeStyles(videoGalleryOuterDivStyle, styles === null || styles === void 0 ? void 0 : styles.root) }, videoGalleryLayout));
9982
10117
  };
9983
10118
 
@@ -11847,7 +11982,7 @@ const continueAnywayButtonStyles = (theme) => {
11847
11982
  // Copyright (c) Microsoft Corporation.
11848
11983
  /* @conditional-compile-remove(unsupported-browser) */
11849
11984
  const UnsupportedEnvironmentContainer = (props) => {
11850
- const { onTroubleshootingClick, strings, onContinueClick } = props;
11985
+ const { onTroubleshootingClick, strings, onContinueAnywayClick } = props;
11851
11986
  const theme = useTheme();
11852
11987
  return (React__default['default'].createElement(react.Stack, { styles: containerStyles$2, tokens: { childrenGap: '2rem' } },
11853
11988
  React__default['default'].createElement(react.Icon, { iconName: "UnsupportedEnvironmentWarning", "data-ui-id": "unsupported-environment-icon" }),
@@ -11855,7 +11990,7 @@ const UnsupportedEnvironmentContainer = (props) => {
11855
11990
  React__default['default'].createElement(react.Text, { styles: mainTextStyles }, strings === null || strings === void 0 ? void 0 : strings.primaryText),
11856
11991
  React__default['default'].createElement(react.Text, { styles: secondaryTextStyles }, strings === null || strings === void 0 ? void 0 : strings.secondaryText)),
11857
11992
  onTroubleshootingClick && (React__default['default'].createElement(react.Link, { styles: linkTextStyles, onClick: onTroubleshootingClick, "data-ui-id": "unsupported-environment-link" }, strings === null || strings === void 0 ? void 0 : strings.moreHelpLinkText)),
11858
- onContinueClick && (React__default['default'].createElement(react.DefaultButton, { "data-ui-id": "allowUnsupportedBrowserButton", styles: continueAnywayButtonStyles(theme), onClick: onContinueClick }, strings === null || strings === void 0 ? void 0 : strings.continueAnywayButtonText))));
11993
+ onContinueAnywayClick && (React__default['default'].createElement(react.DefaultButton, { "data-ui-id": "allowUnsupportedBrowserButton", styles: continueAnywayButtonStyles(theme), onClick: onContinueAnywayClick }, strings === null || strings === void 0 ? void 0 : strings.continueAnywayButtonText))));
11859
11994
  };
11860
11995
  /**
11861
11996
  * UI to display to the user that the environment they are using is not supported by calling application.
@@ -11886,8 +12021,8 @@ const UnsupportedBrowser = (props) => {
11886
12021
  * @beta
11887
12022
  */
11888
12023
  const UnsupportedBrowserVersion = (props) => {
11889
- const { onTroubleshootingClick, strings, onContinueClick } = props;
11890
- return (React__default['default'].createElement(UnsupportedEnvironment, { onTroubleshootingClick: onTroubleshootingClick, strings: strings, onContinueClick: onContinueClick }));
12024
+ const { onTroubleshootingClick, strings, onContinueAnywayClick } = props;
12025
+ return (React__default['default'].createElement(UnsupportedEnvironment, { onTroubleshootingClick: onTroubleshootingClick, strings: strings, onContinueAnywayClick: onContinueAnywayClick }));
11891
12026
  };
11892
12027
 
11893
12028
  // Copyright (c) Microsoft Corporation.
@@ -16744,7 +16879,7 @@ const Microphone = (props) => {
16744
16879
  : {};
16745
16880
  const styles = React.useMemo(() => { var _a; return concatButtonBaseStyles((_a = props.styles) !== null && _a !== void 0 ? _a : {}); }, [props.styles]);
16746
16881
  // tab focus on MicrophoneButton on page load
16747
- return (React__default['default'].createElement(MicrophoneButton, Object.assign({ "data-ui-id": "call-composite-microphone-button" }, microphoneButtonProps, { showLabel: props.displayType !== 'compact', styles: styles }, microphoneButtonStrings, { enableDeviceSelectionMenu: props.splitButtonsForDeviceSelection, disabled: microphoneButtonProps.disabled || props.disabled })));
16882
+ return (React__default['default'].createElement(MicrophoneButton, Object.assign({ autoFocus: true, "data-ui-id": "call-composite-microphone-button" }, microphoneButtonProps, { showLabel: props.displayType !== 'compact', styles: styles }, microphoneButtonStrings, { enableDeviceSelectionMenu: props.splitButtonsForDeviceSelection, disabled: microphoneButtonProps.disabled || props.disabled })));
16748
16883
  };
16749
16884
 
16750
16885
  // Copyright (c) Microsoft Corporation.
@@ -17175,14 +17310,6 @@ const bannerNotificationStyles = {
17175
17310
  pointerEvents: 'auto' // to allow the dismissal or error and warning bars in the notification container
17176
17311
  }
17177
17312
  };
17178
- /**
17179
- * @private
17180
- */
17181
- const callArrangementContainerStyles = {
17182
- root: {
17183
- flexDirection: 'column-reverse' // to allow first initial keyboard focus on ControlBar
17184
- }
17185
- };
17186
17313
 
17187
17314
  // Copyright (c) Microsoft Corporation.
17188
17315
  /**
@@ -17947,7 +18074,7 @@ const hiddenStyles = {
17947
18074
  */
17948
18075
  const sidePaneStyles = {
17949
18076
  root: {
17950
- height: '100%',
18077
+ height: 'auto',
17951
18078
  padding: '0.5rem 0.25rem',
17952
18079
  maxWidth: '21.5rem'
17953
18080
  }
@@ -18182,25 +18309,25 @@ const CallArrangement = (props) => {
18182
18309
  }
18183
18310
  return (React__default['default'].createElement("div", { ref: containerRef, className: react.mergeStyles(containerDivStyles) },
18184
18311
  React__default['default'].createElement(react.Stack, { verticalFill: true, horizontalAlign: "stretch", className: containerClassName, "data-ui-id": props.dataUiId },
18185
- React__default['default'].createElement(react.Stack, { horizontal: true, grow: true, styles: callArrangementContainerStyles },
18312
+ React__default['default'].createElement(react.Stack, { horizontal: true, grow: true },
18186
18313
  React__default['default'].createElement(react.Stack.Item, { styles: notificationsContainerStyles },
18187
18314
  React__default['default'].createElement(react.Stack, { styles: bannerNotificationStyles },
18188
18315
  React__default['default'].createElement(_ComplianceBanner, Object.assign({}, props.complianceBannerProps))),
18189
18316
  errorBarProps !== false && (React__default['default'].createElement(react.Stack, { styles: bannerNotificationStyles },
18190
18317
  React__default['default'].createElement(ErrorBar, Object.assign({}, errorBarProps)))),
18191
18318
  canUnmute && !!props.mutedNotificationProps && React__default['default'].createElement(MutedNotification, Object.assign({}, props.mutedNotificationProps))),
18192
- ((_b = props.callControlProps) === null || _b === void 0 ? void 0 : _b.options) !== false &&
18193
- /* @conditional-compile-remove(one-to-n-calling) @conditional-compile-remove(PSTN-calls) */
18194
- !isMobileWithActivePane && (React__default['default'].createElement(react.Stack.Item, { className: callControlsContainerStyles },
18195
- React__default['default'].createElement(CallControls, Object.assign({}, props.callControlProps, { containerWidth: containerWidth, containerHeight: containerHeight, isMobile: props.mobileView,
18196
- /* @conditional-compile-remove(one-to-n-calling) */
18197
- peopleButtonChecked: activePane === 'people',
18198
- /* @conditional-compile-remove(one-to-n-calling) */
18199
- onPeopleButtonClicked: togglePeoplePane })))),
18200
18319
  React__default['default'].createElement(react.Stack.Item, { grow: true, style: callCompositeContainerFlex() },
18201
18320
  React__default['default'].createElement(react.Stack.Item, { styles: callGalleryStyles, grow: true }, props.onRenderGalleryContent && (React__default['default'].createElement(react.Stack, { verticalFill: true, styles: mediaGalleryContainerStyles }, props.onRenderGalleryContent())))),
18202
18321
  /* @conditional-compile-remove(one-to-n-calling) @conditional-compile-remove(PSTN-calls) */
18203
- callPaneContent()))));
18322
+ callPaneContent()),
18323
+ ((_b = props.callControlProps) === null || _b === void 0 ? void 0 : _b.options) !== false &&
18324
+ /* @conditional-compile-remove(one-to-n-calling) @conditional-compile-remove(PSTN-calls) */
18325
+ !isMobileWithActivePane && (React__default['default'].createElement(react.Stack.Item, { className: callControlsContainerStyles },
18326
+ React__default['default'].createElement(CallControls, Object.assign({}, props.callControlProps, { containerWidth: containerWidth, containerHeight: containerHeight, isMobile: props.mobileView,
18327
+ /* @conditional-compile-remove(one-to-n-calling) */
18328
+ peopleButtonChecked: activePane === 'people',
18329
+ /* @conditional-compile-remove(one-to-n-calling) */
18330
+ onPeopleButtonClicked: togglePeoplePane })))))));
18204
18331
  };
18205
18332
  /* @conditional-compile-remove(one-to-n-calling) @conditional-compile-remove(PSTN-calls) */
18206
18333
  const showShowPeopleTabHeaderButton$1 = (callControls) => {
@@ -19899,7 +20026,7 @@ const UnsupportedBrowserPage = (props) => {
19899
20026
  pageElement = (React__default['default'].createElement(UnsupportedBrowser, { onTroubleshootingClick: onTroubleshootingClick, strings: unsupportedBrowserStrings }));
19900
20027
  }
19901
20028
  else if (!(environmentInfo === null || environmentInfo === void 0 ? void 0 : environmentInfo.isSupportedBrowserVersion)) {
19902
- pageElement = (React__default['default'].createElement(UnsupportedBrowserVersion, { onTroubleshootingClick: onTroubleshootingClick, strings: unsupportedBrowserVersionStrings, onContinueClick: onContinueClick }));
20029
+ pageElement = (React__default['default'].createElement(UnsupportedBrowserVersion, { onTroubleshootingClick: onTroubleshootingClick, strings: unsupportedBrowserVersionStrings, onContinueAnywayClick: onContinueClick }));
19903
20030
  }
19904
20031
  else {
19905
20032
  throw new Error('There was a problem with your environment info');
@@ -21242,50 +21369,6 @@ const DesktopMoreButton = (props) => {
21242
21369
  strings: moreButtonStrings, menuIconProps: { hidden: true }, menuProps: { items: moreButtonContextualMenuItems() } })));
21243
21370
  };
21244
21371
 
21245
- // Copyright (c) Microsoft Corporation.
21246
- // Licensed under the MIT license.
21247
- /**
21248
- * @private
21249
- */
21250
- const compositeOuterContainerStyles = {
21251
- root: {
21252
- width: '100%',
21253
- // Create a new stacking context so that DrawerMenu can be positioned absolutely.
21254
- position: 'relative'
21255
- }
21256
- };
21257
- /** @private */
21258
- const callCompositeContainerStyles = {
21259
- root: {
21260
- // Start a new stacking context so that any `position:absolute` elements
21261
- // inside the call composite do not compete with its siblings.
21262
- position: 'relative'
21263
- }
21264
- };
21265
- /** @private */
21266
- const controlBarContainerStyles = {
21267
- root: {
21268
- // Start a new stacking context so that any `position:absolute` elements
21269
- // inside the control bar do not compete with its siblings.
21270
- position: 'relative'
21271
- }
21272
- };
21273
- /** @private */
21274
- const hiddenAutoFocusButtonStyles = {
21275
- root: {
21276
- width: '0',
21277
- height: '0',
21278
- margin: '0',
21279
- minHeight: '0',
21280
- minWidth: '0',
21281
- maxHeight: '0',
21282
- maxWidth: '0',
21283
- outline: 'none',
21284
- padding: '0',
21285
- position: 'absolute'
21286
- }
21287
- };
21288
-
21289
21372
  // Copyright (c) Microsoft Corporation.
21290
21373
  const inferCallWithChatControlOptions$1 = (mobileView, callWithChatControls) => {
21291
21374
  if (callWithChatControls === false) {
@@ -21308,13 +21391,6 @@ const inferCallWithChatControlOptions$1 = (mobileView, callWithChatControls) =>
21308
21391
  */
21309
21392
  const CallWithChatControlBar = (props) => {
21310
21393
  var _a, _b;
21311
- React.useEffect(() => {
21312
- var _a;
21313
- // On mount, button used for initial focus is hidden to prevent screen readers from announcing the initial focus
21314
- if (document.querySelector('[data-ui-id=call-with-chat-autofocus-hidden-button]') === document.activeElement) {
21315
- (_a = document.activeElement) === null || _a === void 0 ? void 0 : _a.setAttribute('hidden', 'true');
21316
- }
21317
- }, []);
21318
21394
  const theme = react.useTheme();
21319
21395
  const callWithChatStrings = useCallWithChatCompositeStrings();
21320
21396
  const options = inferCallWithChatControlOptions$1(props.mobileView, props.callControls);
@@ -21355,7 +21431,6 @@ const CallWithChatControlBar = (props) => {
21355
21431
  React__default['default'].createElement(react.Stack.Item, { grow: true },
21356
21432
  React__default['default'].createElement(CallAdapterProvider, { adapter: props.callAdapter },
21357
21433
  React__default['default'].createElement(react.Stack, { horizontalAlign: "center" },
21358
- React__default['default'].createElement(ControlBarButton, { autoFocus: true, ariaHidden: true, "data-ui-id": 'call-with-chat-autofocus-hidden-button', styles: hiddenAutoFocusButtonStyles, tabIndex: -1 }),
21359
21434
  React__default['default'].createElement(react.Stack.Item, null,
21360
21435
  React__default['default'].createElement(ControlBar, { layout: "horizontal", styles: centerContainerStyles },
21361
21436
  isEnabled$1(options.microphoneButton) && (React__default['default'].createElement(Microphone, { displayType: options.displayType, styles: commonButtonStyles, splitButtonsForDeviceSelection: !props.mobileView,
@@ -21462,6 +21537,35 @@ const getDesktopEndCallButtonStyles = (theme) => {
21462
21537
  };
21463
21538
  const isEnabled$1 = (option) => option !== false;
21464
21539
 
21540
+ // Copyright (c) Microsoft Corporation.
21541
+ // Licensed under the MIT license.
21542
+ /**
21543
+ * @private
21544
+ */
21545
+ const compositeOuterContainerStyles = {
21546
+ root: {
21547
+ width: '100%',
21548
+ // Create a new stacking context so that DrawerMenu can be positioned absolutely.
21549
+ position: 'relative'
21550
+ }
21551
+ };
21552
+ /** @private */
21553
+ const callCompositeContainerStyles = {
21554
+ root: {
21555
+ // Start a new stacking context so that any `position:absolute` elements
21556
+ // inside the call composite do not compete with its siblings.
21557
+ position: 'relative'
21558
+ }
21559
+ };
21560
+ /** @private */
21561
+ const controlBarContainerStyles = {
21562
+ root: {
21563
+ // Start a new stacking context so that any `position:absolute` elements
21564
+ // inside the control bar do not compete with its siblings.
21565
+ position: 'relative'
21566
+ }
21567
+ };
21568
+
21465
21569
  // Copyright (c) Microsoft Corporation.
21466
21570
  // Licensed under the MIT license.
21467
21571
  var __awaiter$3 = (window && window.__awaiter) || function (thisArg, _arguments, P, generator) {