@azure/communication-react 1.4.3-alpha-202212060013.0 → 1.4.3-alpha-202212080013.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/dist/dist-cjs/communication-react/index.js +664 -522
- package/dist/dist-cjs/communication-react/index.js.map +1 -1
- package/dist/dist-esm/acs-ui-common/src/telemetryVersion.js +1 -1
- package/dist/dist-esm/acs-ui-common/src/telemetryVersion.js.map +1 -1
- package/dist/dist-esm/calling-component-bindings/src/utils/videoGalleryUtils.d.ts +12 -0
- package/dist/dist-esm/calling-component-bindings/src/utils/videoGalleryUtils.js +16 -0
- package/dist/dist-esm/calling-component-bindings/src/utils/videoGalleryUtils.js.map +1 -1
- package/dist/dist-esm/calling-component-bindings/src/videoGallerySelector.js +2 -13
- package/dist/dist-esm/calling-component-bindings/src/videoGallerySelector.js.map +1 -1
- package/dist/dist-esm/react-components/src/components/Dialpad/Dialpad.js +8 -0
- package/dist/dist-esm/react-components/src/components/Dialpad/Dialpad.js.map +1 -1
- package/dist/dist-esm/react-components/src/components/VideoGallery/DefaultLayout.d.ts +41 -0
- package/dist/dist-esm/react-components/src/components/VideoGallery/DefaultLayout.js +45 -0
- package/dist/dist-esm/react-components/src/components/VideoGallery/DefaultLayout.js.map +1 -0
- package/dist/dist-esm/react-components/src/components/VideoGallery/FloatingLocalVideo.d.ts +12 -0
- package/dist/dist-esm/react-components/src/components/VideoGallery/FloatingLocalVideo.js +41 -0
- package/dist/dist-esm/react-components/src/components/VideoGallery/FloatingLocalVideo.js.map +1 -0
- package/dist/dist-esm/react-components/src/components/VideoGallery/FloatingLocalVideoLayout.d.ts +49 -0
- package/dist/dist-esm/react-components/src/components/VideoGallery/FloatingLocalVideoLayout.js +61 -0
- package/dist/dist-esm/react-components/src/components/VideoGallery/FloatingLocalVideoLayout.js.map +1 -0
- package/dist/dist-esm/react-components/src/components/VideoGallery/VideoGalleryResponsiveHorizontalGallery.d.ts +12 -0
- package/dist/dist-esm/react-components/src/components/VideoGallery/VideoGalleryResponsiveHorizontalGallery.js +18 -0
- package/dist/dist-esm/react-components/src/components/VideoGallery/VideoGalleryResponsiveHorizontalGallery.js.map +1 -0
- package/dist/dist-esm/react-components/src/components/VideoGallery/styles/DefaultLayout.styles.d.ts +6 -0
- package/dist/dist-esm/react-components/src/components/VideoGallery/styles/DefaultLayout.styles.js +9 -0
- package/dist/dist-esm/react-components/src/components/VideoGallery/styles/DefaultLayout.styles.js.map +1 -0
- package/dist/dist-esm/react-components/src/components/VideoGallery/styles/FloatingLocalVideo.styles.d.ts +61 -0
- package/dist/dist-esm/react-components/src/components/VideoGallery/styles/FloatingLocalVideo.styles.js +117 -0
- package/dist/dist-esm/react-components/src/components/VideoGallery/styles/FloatingLocalVideo.styles.js.map +1 -0
- package/dist/dist-esm/react-components/src/components/VideoGallery/styles/FloatingLocalVideoLayout.styles.d.ts +14 -0
- package/dist/dist-esm/react-components/src/components/VideoGallery/styles/FloatingLocalVideoLayout.styles.js +28 -0
- package/dist/dist-esm/react-components/src/components/VideoGallery/styles/FloatingLocalVideoLayout.styles.js.map +1 -0
- package/dist/dist-esm/react-components/src/components/VideoGallery/styles/VideoGalleryResponsiveHorizontalGallery.styles.d.ts +59 -0
- package/dist/dist-esm/react-components/src/components/VideoGallery/styles/VideoGalleryResponsiveHorizontalGallery.styles.js +64 -0
- package/dist/dist-esm/react-components/src/components/VideoGallery/styles/VideoGalleryResponsiveHorizontalGallery.styles.js.map +1 -0
- package/dist/dist-esm/react-components/src/components/VideoGallery/videoGalleryUtils.d.ts +17 -0
- package/dist/dist-esm/react-components/src/components/VideoGallery/videoGalleryUtils.js +72 -0
- package/dist/dist-esm/react-components/src/components/VideoGallery/videoGalleryUtils.js.map +1 -0
- package/dist/dist-esm/react-components/src/components/VideoGallery.js +15 -118
- package/dist/dist-esm/react-components/src/components/VideoGallery.js.map +1 -1
- package/dist/dist-esm/react-components/src/components/styles/VideoGallery.styles.d.ts +1 -95
- package/dist/dist-esm/react-components/src/components/styles/VideoGallery.styles.js +1 -137
- package/dist/dist-esm/react-components/src/components/styles/VideoGallery.styles.js.map +1 -1
- package/package.json +8 -8
@@ -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-
|
205
|
+
var telemetryVersion = '1.4.3-alpha-202212080013.0';
|
206
206
|
|
207
207
|
// Copyright (c) Microsoft Corporation.
|
208
208
|
/**
|
@@ -7828,56 +7828,6 @@ const ParticipantList = (props) => {
|
|
7828
7828
|
: onRenderParticipantDefault(participant, strings, myUserId, onRenderAvatar, createParticipantMenuItems, participantItemStyles, props.onParticipantClick, showParticipantOverflowTooltip))));
|
7829
7829
|
};
|
7830
7830
|
|
7831
|
-
/**
|
7832
|
-
* Calculates the participants that should be rendered based on the list of dominant
|
7833
|
-
* speakers and currently rendered participants in a call.
|
7834
|
-
* @param args - SmartDominantSpeakerParticipantsArgs
|
7835
|
-
* @returns VideoGalleryRemoteParticipant[] {@link @azure/communication-react#VideoGalleryRemoteParticipant}
|
7836
|
-
*/
|
7837
|
-
const smartDominantSpeakerParticipants = (args) => {
|
7838
|
-
const { participants, dominantSpeakers = [], lastVisibleParticipants = [], maxDominantSpeakers } = args;
|
7839
|
-
// Don't apply any logic if total number of video streams is less than max dominant speakers.
|
7840
|
-
if (participants.length <= maxDominantSpeakers) {
|
7841
|
-
return participants;
|
7842
|
-
}
|
7843
|
-
const participantsMap = participantsById(participants);
|
7844
|
-
// Only use the Max allowed dominant speakers that exist in participants
|
7845
|
-
const dominantSpeakerIds = Array.from(new Set(dominantSpeakers).values())
|
7846
|
-
.filter((id) => !!participantsMap[id])
|
7847
|
-
.slice(0, maxDominantSpeakers);
|
7848
|
-
const lastVisibleParticipantIds = lastVisibleParticipants.map((p) => p.userId);
|
7849
|
-
const newVisibleParticipantIds = lastVisibleParticipants.map((p) => p.userId).slice(0, maxDominantSpeakers);
|
7850
|
-
const newDominantSpeakerIds = dominantSpeakerIds.filter((id) => !newVisibleParticipantIds.includes(id));
|
7851
|
-
// Remove participants that are no longer dominant and replace them with new dominant speakers.
|
7852
|
-
for (let index = 0; index < maxDominantSpeakers; index++) {
|
7853
|
-
const newVisibleParticipantId = newVisibleParticipantIds[index];
|
7854
|
-
if (newVisibleParticipantId === undefined || !dominantSpeakerIds.includes(newVisibleParticipantId)) {
|
7855
|
-
const replacement = newDominantSpeakerIds.shift();
|
7856
|
-
if (!replacement) {
|
7857
|
-
break;
|
7858
|
-
}
|
7859
|
-
newVisibleParticipantIds[index] = replacement;
|
7860
|
-
}
|
7861
|
-
}
|
7862
|
-
const removedVisibleParticipantIds = lastVisibleParticipantIds.filter((p) => !newVisibleParticipantIds.includes(p));
|
7863
|
-
removedVisibleParticipantIds.forEach((p) => newVisibleParticipantIds.push(p));
|
7864
|
-
const newVisibleParticipantIdSet = new Set(newVisibleParticipantIds);
|
7865
|
-
const leftoverParticipants = participants.filter((p) => !newVisibleParticipantIdSet.has(p.userId));
|
7866
|
-
leftoverParticipants.forEach((p) => {
|
7867
|
-
newVisibleParticipantIds.push(p.userId);
|
7868
|
-
});
|
7869
|
-
// newVisibleParticipantIds can contain identifiers for participants that are no longer in the call. So we ignore those IDs.
|
7870
|
-
const newVisibleParticipants = newVisibleParticipantIds
|
7871
|
-
.map((participantId) => participantsMap[participantId])
|
7872
|
-
.filter((p) => !!p);
|
7873
|
-
return newVisibleParticipants;
|
7874
|
-
};
|
7875
|
-
const participantsById = (participants) => {
|
7876
|
-
const response = {};
|
7877
|
-
participants.forEach((p) => (response[p.userId] = p));
|
7878
|
-
return response;
|
7879
|
-
};
|
7880
|
-
|
7881
7831
|
// Copyright (c) Microsoft Corporation.
|
7882
7832
|
/**
|
7883
7833
|
* Helper hook to maintain the video stream lifecycle. This calls onCreateStreamView and onDisposeStreamView
|
@@ -8387,151 +8337,108 @@ const _RemoteVideoTile = React__default['default'].memo((props) => {
|
|
8387
8337
|
});
|
8388
8338
|
|
8389
8339
|
// Copyright (c) Microsoft Corporation.
|
8390
|
-
// Licensed under the MIT license.
|
8391
8340
|
/**
|
8392
|
-
*
|
8341
|
+
* @private
|
8393
8342
|
*/
|
8394
|
-
const
|
8343
|
+
const screenSharingContainerStyle = react.mergeStyles({
|
8344
|
+
width: '100%',
|
8345
|
+
height: '100%'
|
8346
|
+
});
|
8395
8347
|
/**
|
8396
8348
|
* @private
|
8397
8349
|
*/
|
8398
|
-
const
|
8399
|
-
|
8400
|
-
|
8401
|
-
|
8402
|
-
|
8403
|
-
|
8404
|
-
|
8405
|
-
border: `1px solid ${theme.palette.neutralLight}`,
|
8406
|
-
borderRadius: theme.effects.roundedCorner4
|
8407
|
-
};
|
8408
|
-
};
|
8350
|
+
const screenSharingNotificationContainerStyle = (theme) => react.mergeStyles({
|
8351
|
+
backgroundColor: 'inherit',
|
8352
|
+
padding: '1rem',
|
8353
|
+
maxWidth: '95%',
|
8354
|
+
borderRadius: theme.effects.roundedCorner4,
|
8355
|
+
color: theme.palette.neutralSecondary
|
8356
|
+
});
|
8409
8357
|
/**
|
8410
|
-
*
|
8358
|
+
* @private
|
8411
8359
|
*/
|
8412
|
-
const
|
8360
|
+
const screenSharingNotificationIconContainerStyle = react.mergeStyles({
|
8361
|
+
height: '2rem',
|
8362
|
+
lineHeight: 0
|
8363
|
+
});
|
8413
8364
|
/**
|
8414
8365
|
* @private
|
8415
8366
|
*/
|
8416
|
-
const
|
8417
|
-
|
8418
|
-
|
8419
|
-
|
8420
|
-
};
|
8367
|
+
const screenSharingNotificationIconStyle = (theme) => react.mergeStyles({
|
8368
|
+
// svg is (20px x 20px) but path is only (16px x 12px), so need to scale at 2.5 to get 40px
|
8369
|
+
transform: 'scale(2.5)',
|
8370
|
+
color: theme.palette.neutralTertiary
|
8371
|
+
});
|
8421
8372
|
/**
|
8422
8373
|
* @private
|
8423
8374
|
*/
|
8424
|
-
const
|
8425
|
-
|
8426
|
-
|
8427
|
-
|
8375
|
+
const screenSharingNotificationTextStyle = react.mergeStyles({
|
8376
|
+
fontSize: '1rem',
|
8377
|
+
// Text component will take body color by default (white in Dark Mode), so forcing it to be parent container color
|
8378
|
+
color: 'inherit'
|
8379
|
+
});
|
8428
8380
|
|
8429
8381
|
// Copyright (c) Microsoft Corporation.
|
8430
8382
|
/**
|
8431
|
-
*
|
8432
|
-
|
8433
|
-
|
8434
|
-
/**
|
8435
|
-
* Renders a horizontal gallery that parents children horizontally. Handles pagination based on the childrenPerPage prop.
|
8436
|
-
* @param props - HorizontalGalleryProps {@link @azure/communication-react#HorizontalGalleryProps}
|
8437
|
-
* @returns
|
8383
|
+
* A memoized version of local screen share component. React.memo is used for a performance
|
8384
|
+
* boost by memoizing the same rendered component to avoid rerendering this when the parent component rerenders.
|
8385
|
+
* https://reactjs.org/docs/react-api.html#reactmemo
|
8438
8386
|
*/
|
8439
|
-
const
|
8440
|
-
|
8441
|
-
const { children, childrenPerPage = DEFAULT_CHILDREN_PER_PAGE, styles } = props;
|
8442
|
-
const ids = useIdentifiers();
|
8443
|
-
const [page, setPage] = React.useState(0);
|
8444
|
-
const numberOfChildren = React__default['default'].Children.count(children);
|
8445
|
-
const lastPage = Math.ceil(numberOfChildren / childrenPerPage) - 1;
|
8446
|
-
const paginatedChildren = React.useMemo(() => {
|
8447
|
-
return bucketize(React__default['default'].Children.toArray(children), childrenPerPage);
|
8448
|
-
}, [children, childrenPerPage]);
|
8449
|
-
// If children per page is 0 or less return empty element
|
8450
|
-
if (childrenPerPage <= 0) {
|
8451
|
-
return React__default['default'].createElement(React__default['default'].Fragment, null);
|
8452
|
-
}
|
8453
|
-
const firstIndexOfCurrentPage = page * childrenPerPage;
|
8454
|
-
const clippedPage = firstIndexOfCurrentPage < numberOfChildren - 1 ? page : lastPage;
|
8455
|
-
const childrenOnCurrentPage = paginatedChildren[clippedPage];
|
8456
|
-
const showButtons = numberOfChildren > childrenPerPage;
|
8457
|
-
const disablePreviousButton = page === 0;
|
8458
|
-
const disableNextButton = page === lastPage;
|
8459
|
-
return (React__default['default'].createElement(react.Stack, { horizontal: true, className: react.mergeStyles(rootStyle, (_a = props.styles) === null || _a === void 0 ? void 0 : _a.root) },
|
8460
|
-
showButtons && (React__default['default'].createElement(HorizontalGalleryNavigationButton, { key: "previous-nav-button", icon: React__default['default'].createElement(react.Icon, { iconName: "HorizontalGalleryLeftButton" }), styles: styles === null || styles === void 0 ? void 0 : styles.previousButton, onClick: () => setPage(Math.max(0, Math.min(lastPage, page - 1))), disabled: disablePreviousButton, identifier: ids.horizontalGalleryLeftNavButton })),
|
8461
|
-
React__default['default'].createElement(react.Stack, { horizontal: true, className: react.mergeStyles(childrenContainerStyle, { '> *': (_b = props.styles) === null || _b === void 0 ? void 0 : _b.children }) }, childrenOnCurrentPage),
|
8462
|
-
showButtons && (React__default['default'].createElement(HorizontalGalleryNavigationButton, { key: "next-nav-button", icon: React__default['default'].createElement(react.Icon, { iconName: "HorizontalGalleryRightButton" }), styles: styles === null || styles === void 0 ? void 0 : styles.nextButton, onClick: () => setPage(Math.min(lastPage, page + 1)), disabled: disableNextButton, identifier: ids.horizontalGalleryRightNavButton }))));
|
8463
|
-
};
|
8464
|
-
const HorizontalGalleryNavigationButton = (props) => {
|
8387
|
+
const LocalScreenShare = React__default['default'].memo((props) => {
|
8388
|
+
const { localParticipant } = props;
|
8465
8389
|
const theme = useTheme();
|
8466
|
-
|
8467
|
-
|
8468
|
-
|
8469
|
-
const bucketArray = [];
|
8470
|
-
if (bucketSize <= 0) {
|
8471
|
-
return bucketArray;
|
8472
|
-
}
|
8473
|
-
for (let i = 0; i < arr.length; i += bucketSize) {
|
8474
|
-
bucketArray.push(arr.slice(i, i + bucketSize));
|
8390
|
+
const locale = useLocale$1();
|
8391
|
+
if (!localParticipant || !localParticipant.isScreenSharingOn) {
|
8392
|
+
return null;
|
8475
8393
|
}
|
8476
|
-
|
8477
|
-
}
|
8394
|
+
const localScreenSharingNotification = (React__default['default'].createElement(react.Stack, { horizontalAlign: "center", verticalAlign: "center", className: screenSharingContainerStyle },
|
8395
|
+
React__default['default'].createElement(react.Stack, { horizontalAlign: "center", verticalAlign: "center", className: screenSharingNotificationContainerStyle(theme), tokens: { childrenGap: '1rem' } },
|
8396
|
+
React__default['default'].createElement(react.Stack, { horizontal: true, verticalAlign: "center", className: screenSharingNotificationIconContainerStyle },
|
8397
|
+
React__default['default'].createElement(react.Icon, { iconName: "ControlButtonScreenShareStart", className: screenSharingNotificationIconStyle(theme) })),
|
8398
|
+
React__default['default'].createElement(react.Text, { className: screenSharingNotificationTextStyle, "aria-live": "polite" }, locale.strings.videoGallery.screenIsBeingSharedMessage))));
|
8399
|
+
const displayName = !(localParticipant === null || localParticipant === void 0 ? void 0 : localParticipant.displayName)
|
8400
|
+
? locale.strings.videoGallery.displayNamePlaceholder
|
8401
|
+
: localParticipant === null || localParticipant === void 0 ? void 0 : localParticipant.displayName;
|
8402
|
+
return (React__default['default'].createElement(VideoTile, { displayName: displayName, isMuted: localParticipant === null || localParticipant === void 0 ? void 0 : localParticipant.isMuted, onRenderPlaceholder: () => React__default['default'].createElement(React__default['default'].Fragment, null) }, localScreenSharingNotification));
|
8403
|
+
});
|
8478
8404
|
|
8479
8405
|
// Copyright (c) Microsoft Corporation.
|
8480
8406
|
/**
|
8481
|
-
*
|
8482
|
-
* available width obtained from a ResizeObserver, width per child, gap width, and button width
|
8407
|
+
* @private
|
8483
8408
|
*/
|
8484
|
-
const
|
8485
|
-
|
8486
|
-
|
8487
|
-
|
8488
|
-
|
8489
|
-
|
8490
|
-
const childrenPerPage = calculateChildrenPerPage({
|
8491
|
-
numberOfChildren: React__default['default'].Children.count(props.children),
|
8492
|
-
containerWidth: (containerWidth !== null && containerWidth !== void 0 ? containerWidth : 0) - leftPadding - rightPadding,
|
8493
|
-
childWidthRem,
|
8494
|
-
gapWidthRem,
|
8495
|
-
buttonWidthRem
|
8496
|
-
});
|
8497
|
-
return (React__default['default'].createElement("div", { ref: containerRef, className: react.mergeStyles(props.containerStyles) },
|
8498
|
-
React__default['default'].createElement(HorizontalGallery, { childrenPerPage: childrenPerPage, styles: props.horizontalGalleryStyles }, props.children)));
|
8499
|
-
};
|
8409
|
+
const loadingStyle = react.mergeStyles({
|
8410
|
+
height: '100%',
|
8411
|
+
width: '100%'
|
8412
|
+
});
|
8413
|
+
|
8414
|
+
// Copyright (c) Microsoft Corporation.
|
8500
8415
|
/**
|
8501
|
-
*
|
8502
|
-
*
|
8416
|
+
* A memoized version of VideoTile for rendering the remote screen share stream. React.memo is used for a performance
|
8417
|
+
* boost by memoizing the same rendered component to avoid rerendering this when the parent component rerenders.
|
8418
|
+
* https://reactjs.org/docs/react-api.html#reactmemo
|
8503
8419
|
*/
|
8504
|
-
const
|
8505
|
-
const {
|
8506
|
-
const
|
8507
|
-
|
8508
|
-
|
8509
|
-
* __________________________________
|
8510
|
-
* | || |
|
8511
|
-
* | || |
|
8512
|
-
* |________________||________________|
|
8513
|
-
* <-----------containerWidth--------->
|
8514
|
-
* containerWidth = n * childWidth + (n - 1) * gapWidth. Isolate n and take the floor.
|
8515
|
-
*/
|
8516
|
-
const numberOfChildrenInContainer = Math.floor((containerWidth + gapWidth) / (childWidth + gapWidth));
|
8517
|
-
// If all children fit then return numberOfChildrenInContainer
|
8518
|
-
if (numberOfChildren <= numberOfChildrenInContainer) {
|
8519
|
-
return numberOfChildrenInContainer;
|
8420
|
+
const RemoteScreenShare = React__default['default'].memo((props) => {
|
8421
|
+
const { userId, displayName, isMuted, renderElement, onCreateRemoteStreamView, onDisposeRemoteStreamView, isReceiving } = props;
|
8422
|
+
const locale = useLocale$1();
|
8423
|
+
if (!renderElement) {
|
8424
|
+
onCreateRemoteStreamView && onCreateRemoteStreamView(userId);
|
8520
8425
|
}
|
8521
|
-
|
8522
|
-
|
8523
|
-
|
8524
|
-
|
8525
|
-
|
8526
|
-
|
8527
|
-
|
8528
|
-
|
8529
|
-
|
8530
|
-
|
8531
|
-
|
8532
|
-
|
8533
|
-
|
8534
|
-
|
8426
|
+
React.useEffect(() => {
|
8427
|
+
return () => {
|
8428
|
+
// TODO: Isolate disposing behaviors for screenShare and videoStream
|
8429
|
+
onDisposeRemoteStreamView && onDisposeRemoteStreamView(userId);
|
8430
|
+
};
|
8431
|
+
}, [onDisposeRemoteStreamView, userId]);
|
8432
|
+
const loadingMessage = displayName
|
8433
|
+
? _formatString(locale.strings.videoGallery.screenShareLoadingMessage, {
|
8434
|
+
participant: displayName
|
8435
|
+
})
|
8436
|
+
: '';
|
8437
|
+
return (React__default['default'].createElement(VideoTile, { displayName: displayName, isMuted: isMuted, renderElement: renderElement ? (React__default['default'].createElement(StreamMedia, { videoStreamElement: renderElement, loadingState: isReceiving === false ? 'loading' : 'none' })) : undefined, onRenderPlaceholder: () => React__default['default'].createElement(LoadingSpinner, { loadingMessage: loadingMessage }) }));
|
8438
|
+
});
|
8439
|
+
const LoadingSpinner = (props) => {
|
8440
|
+
return (React__default['default'].createElement(react.Stack, { verticalAlign: "center", className: loadingStyle },
|
8441
|
+
React__default['default'].createElement(react.Spinner, { label: props.loadingMessage, size: react.SpinnerSize.xSmall, "aria-live": 'assertive' })));
|
8535
8442
|
};
|
8536
8443
|
|
8537
8444
|
// Copyright (c) Microsoft Corporation.
|
@@ -8542,71 +8449,277 @@ const videoGalleryOuterDivStyle = react.mergeStyles({ position: 'relative', widt
|
|
8542
8449
|
/**
|
8543
8450
|
* @private
|
8544
8451
|
*/
|
8545
|
-
const
|
8546
|
-
|
8547
|
-
|
8548
|
-
|
8549
|
-
|
8550
|
-
|
8551
|
-
|
8552
|
-
|
8553
|
-
|
8554
|
-
|
8555
|
-
|
8556
|
-
|
8557
|
-
|
8558
|
-
|
8559
|
-
|
8560
|
-
|
8452
|
+
const localVideoCameraCycleButtonStyles = (theme) => {
|
8453
|
+
return {
|
8454
|
+
root: {
|
8455
|
+
position: 'absolute',
|
8456
|
+
width: _pxToRem(32),
|
8457
|
+
height: _pxToRem(32),
|
8458
|
+
right: '0rem',
|
8459
|
+
top: '0rem',
|
8460
|
+
color: '#FFFFFF',
|
8461
|
+
zIndex: 2,
|
8462
|
+
background: 'rgba(0,0,0,0.4)',
|
8463
|
+
borderRadius: theme.effects.roundedCorner2
|
8464
|
+
},
|
8465
|
+
rootFocused: {
|
8466
|
+
// styles to remove the unwanted white highlight and blue colour after tapping on button.
|
8467
|
+
color: '#FFFFFF',
|
8468
|
+
background: 'rgba(0,0,0,0.4)' // sets opacity of background to be visible on all backdrops in video stream.
|
8469
|
+
},
|
8470
|
+
icon: {
|
8471
|
+
paddingLeft: _pxToRem(3),
|
8472
|
+
paddingRight: _pxToRem(3),
|
8473
|
+
margin: 0
|
8474
|
+
},
|
8475
|
+
flexContainer: {
|
8476
|
+
paddingBottom: _pxToRem(8)
|
8477
|
+
}
|
8478
|
+
};
|
8479
|
+
};
|
8480
|
+
|
8481
|
+
// Copyright (c) Microsoft Corporation.
|
8561
8482
|
/**
|
8562
|
-
*
|
8483
|
+
* local video tile camera cycle button - for use on mobile screens only.
|
8484
|
+
* @internal
|
8563
8485
|
*/
|
8564
|
-
const
|
8565
|
-
|
8566
|
-
|
8567
|
-
}, {
|
8568
|
-
|
8569
|
-
|
8570
|
-
|
8571
|
-
|
8572
|
-
|
8486
|
+
const LocalVideoCameraCycleButton = (props) => {
|
8487
|
+
const { cameras, selectedCamera, onSelectCamera, label, ariaDescription } = props;
|
8488
|
+
const theme = react.useTheme();
|
8489
|
+
return (React__default['default'].createElement(react.IconButton, { "data-ui-id": 'local-camera-switcher-button', styles: localVideoCameraCycleButtonStyles(theme), iconProps: { iconName: 'LocalCameraSwitch' }, ariaLabel: label, ariaDescription: ariaDescription, "aria-live": 'polite', onClick: () => {
|
8490
|
+
if (cameras && cameras.length > 1 && selectedCamera !== undefined) {
|
8491
|
+
const index = cameras.findIndex((camera) => selectedCamera.id === camera.id);
|
8492
|
+
const newCamera = cameras[(index + 1) % cameras.length];
|
8493
|
+
if (onSelectCamera !== undefined) {
|
8494
|
+
onSelectCamera(newCamera);
|
8495
|
+
}
|
8573
8496
|
}
|
8497
|
+
} }));
|
8498
|
+
};
|
8499
|
+
|
8500
|
+
// Copyright (c) Microsoft Corporation.
|
8501
|
+
/**
|
8502
|
+
* A memoized version of VideoTile for rendering local participant.
|
8503
|
+
*
|
8504
|
+
* @internal
|
8505
|
+
*/
|
8506
|
+
const _LocalVideoTile = React__default['default'].memo((props) => {
|
8507
|
+
const { isAvailable, isMuted, onCreateLocalStreamView, onDisposeLocalStreamView, localVideoViewOptions, renderElement, userId, showLabel, displayName, initialsName, onRenderAvatar, showMuteIndicator, styles, showCameraSwitcherInLocalPreview, localVideoCameraCycleButtonProps, localVideoCameraSwitcherLabel, localVideoSelectedDescription } = props;
|
8508
|
+
const localVideoStreamProps = React.useMemo(() => ({
|
8509
|
+
isMirrored: localVideoViewOptions === null || localVideoViewOptions === void 0 ? void 0 : localVideoViewOptions.isMirrored,
|
8510
|
+
isStreamAvailable: isAvailable,
|
8511
|
+
onCreateLocalStreamView,
|
8512
|
+
onDisposeLocalStreamView,
|
8513
|
+
renderElementExists: !!renderElement,
|
8514
|
+
scalingMode: localVideoViewOptions === null || localVideoViewOptions === void 0 ? void 0 : localVideoViewOptions.scalingMode
|
8515
|
+
}), [
|
8516
|
+
isAvailable,
|
8517
|
+
localVideoViewOptions === null || localVideoViewOptions === void 0 ? void 0 : localVideoViewOptions.isMirrored,
|
8518
|
+
localVideoViewOptions === null || localVideoViewOptions === void 0 ? void 0 : localVideoViewOptions.scalingMode,
|
8519
|
+
onCreateLocalStreamView,
|
8520
|
+
onDisposeLocalStreamView,
|
8521
|
+
renderElement
|
8522
|
+
]);
|
8523
|
+
// Handle creating, destroying and updating the video stream as necessary
|
8524
|
+
useLocalVideoStreamLifecycleMaintainer(localVideoStreamProps);
|
8525
|
+
const renderVideoStreamElement = React.useMemo(() => {
|
8526
|
+
// Checking if renderElement is well defined or not as calling SDK has a number of video streams limitation which
|
8527
|
+
// implies that, after their threshold, all streams have no child (blank video)
|
8528
|
+
if (!renderElement || !renderElement.childElementCount) {
|
8529
|
+
// Returning `undefined` results in the placeholder with avatar being shown
|
8530
|
+
return undefined;
|
8574
8531
|
}
|
8575
|
-
|
8532
|
+
return (React__default['default'].createElement(React__default['default'].Fragment, null,
|
8533
|
+
React__default['default'].createElement(FloatingLocalCameraCycleButton, { showCameraSwitcherInLocalPreview: showCameraSwitcherInLocalPreview !== null && showCameraSwitcherInLocalPreview !== void 0 ? showCameraSwitcherInLocalPreview : false, localVideoCameraCycleButtonProps: localVideoCameraCycleButtonProps, localVideoCameraSwitcherLabel: localVideoCameraSwitcherLabel, localVideoSelectedDescription: localVideoSelectedDescription }),
|
8534
|
+
React__default['default'].createElement(StreamMedia, { videoStreamElement: renderElement, isMirrored: true })));
|
8535
|
+
}, [
|
8536
|
+
localVideoCameraCycleButtonProps,
|
8537
|
+
localVideoCameraSwitcherLabel,
|
8538
|
+
localVideoSelectedDescription,
|
8539
|
+
renderElement,
|
8540
|
+
showCameraSwitcherInLocalPreview
|
8541
|
+
]);
|
8542
|
+
return (React__default['default'].createElement(VideoTile, { key: userId !== null && userId !== void 0 ? userId : 'local-video-tile', userId: userId, renderElement: renderVideoStreamElement, showLabel: showLabel, displayName: displayName, initialsName: initialsName, styles: styles, onRenderPlaceholder: onRenderAvatar, isMuted: isMuted, showMuteIndicator: showMuteIndicator, personaMinSize: props.personaMinSize }));
|
8543
|
+
});
|
8544
|
+
const FloatingLocalCameraCycleButton = (props) => {
|
8545
|
+
const { showCameraSwitcherInLocalPreview, localVideoCameraCycleButtonProps, localVideoCameraSwitcherLabel, localVideoSelectedDescription } = props;
|
8546
|
+
const ariaDescription = (localVideoCameraCycleButtonProps === null || localVideoCameraCycleButtonProps === void 0 ? void 0 : localVideoCameraCycleButtonProps.selectedCamera) &&
|
8547
|
+
localVideoSelectedDescription &&
|
8548
|
+
_formatString(localVideoSelectedDescription, {
|
8549
|
+
cameraName: localVideoCameraCycleButtonProps.selectedCamera.name
|
8550
|
+
});
|
8551
|
+
return (React__default['default'].createElement(react.Stack, { horizontalAlign: "end" }, showCameraSwitcherInLocalPreview &&
|
8552
|
+
(localVideoCameraCycleButtonProps === null || localVideoCameraCycleButtonProps === void 0 ? void 0 : localVideoCameraCycleButtonProps.cameras) !== undefined &&
|
8553
|
+
(localVideoCameraCycleButtonProps === null || localVideoCameraCycleButtonProps === void 0 ? void 0 : localVideoCameraCycleButtonProps.selectedCamera) !== undefined &&
|
8554
|
+
(localVideoCameraCycleButtonProps === null || localVideoCameraCycleButtonProps === void 0 ? void 0 : localVideoCameraCycleButtonProps.onSelectCamera) !== undefined && (React__default['default'].createElement(LocalVideoCameraCycleButton, { cameras: localVideoCameraCycleButtonProps.cameras, selectedCamera: localVideoCameraCycleButtonProps.selectedCamera, onSelectCamera: localVideoCameraCycleButtonProps.onSelectCamera, label: localVideoCameraSwitcherLabel, ariaDescription: ariaDescription }))));
|
8576
8555
|
};
|
8556
|
+
|
8557
|
+
// Copyright (c) Microsoft Corporation.
|
8558
|
+
// Licensed under the MIT license.
|
8577
8559
|
/**
|
8578
|
-
* Padding equal to the amount the modal should stay inside the bounds of the container.
|
8579
|
-
* i.e. if this is 8px, the modal should always be at least 8px inside the container at all times on all sides.
|
8580
8560
|
* @private
|
8581
8561
|
*/
|
8582
|
-
const
|
8562
|
+
const rootLayoutStyle$1 = {
|
8563
|
+
root: { position: 'relative', height: '100%', width: '100%', padding: '0.5rem' }
|
8564
|
+
};
|
8565
|
+
|
8566
|
+
// Copyright (c) Microsoft Corporation.
|
8567
|
+
// Licensed under the MIT license.
|
8568
|
+
/**
|
8569
|
+
* Horizontal Gallery button width in rem
|
8570
|
+
*/
|
8571
|
+
const HORIZONTAL_GALLERY_BUTTON_WIDTH = 1.75;
|
8583
8572
|
/**
|
8584
8573
|
* @private
|
8585
8574
|
*/
|
8586
|
-
const
|
8587
|
-
return
|
8588
|
-
|
8589
|
-
:
|
8575
|
+
const leftRightButtonStyles = (theme) => {
|
8576
|
+
return {
|
8577
|
+
background: 'none',
|
8578
|
+
padding: 0,
|
8579
|
+
height: 'auto',
|
8580
|
+
minWidth: `${HORIZONTAL_GALLERY_BUTTON_WIDTH}rem`,
|
8581
|
+
maxWidth: `${HORIZONTAL_GALLERY_BUTTON_WIDTH}rem`,
|
8582
|
+
border: `1px solid ${theme.palette.neutralLight}`,
|
8583
|
+
borderRadius: theme.effects.roundedCorner4
|
8584
|
+
};
|
8590
8585
|
};
|
8586
|
+
/**
|
8587
|
+
* Horizontal Gallery gap size in rem between tiles and buttons
|
8588
|
+
*/
|
8589
|
+
const HORIZONTAL_GALLERY_GAP = 0.5;
|
8591
8590
|
/**
|
8592
8591
|
* @private
|
8593
8592
|
*/
|
8594
|
-
const
|
8595
|
-
|
8596
|
-
|
8597
|
-
}
|
8593
|
+
const rootStyle = {
|
8594
|
+
height: '100%',
|
8595
|
+
width: '100%',
|
8596
|
+
gap: `${HORIZONTAL_GALLERY_GAP}rem`
|
8598
8597
|
};
|
8599
8598
|
/**
|
8600
8599
|
* @private
|
8601
8600
|
*/
|
8602
|
-
const
|
8603
|
-
|
8604
|
-
|
8605
|
-
|
8606
|
-
|
8607
|
-
|
8601
|
+
const childrenContainerStyle = {
|
8602
|
+
height: '100%',
|
8603
|
+
gap: `${HORIZONTAL_GALLERY_GAP}rem`
|
8604
|
+
};
|
8605
|
+
|
8606
|
+
// Copyright (c) Microsoft Corporation.
|
8607
|
+
/**
|
8608
|
+
* {@link HorizontalGallery} default children per page
|
8609
|
+
*/
|
8610
|
+
const DEFAULT_CHILDREN_PER_PAGE = 5;
|
8611
|
+
/**
|
8612
|
+
* Renders a horizontal gallery that parents children horizontally. Handles pagination based on the childrenPerPage prop.
|
8613
|
+
* @param props - HorizontalGalleryProps {@link @azure/communication-react#HorizontalGalleryProps}
|
8614
|
+
* @returns
|
8615
|
+
*/
|
8616
|
+
const HorizontalGallery = (props) => {
|
8617
|
+
var _a, _b;
|
8618
|
+
const { children, childrenPerPage = DEFAULT_CHILDREN_PER_PAGE, styles } = props;
|
8619
|
+
const ids = useIdentifiers();
|
8620
|
+
const [page, setPage] = React.useState(0);
|
8621
|
+
const numberOfChildren = React__default['default'].Children.count(children);
|
8622
|
+
const lastPage = Math.ceil(numberOfChildren / childrenPerPage) - 1;
|
8623
|
+
const paginatedChildren = React.useMemo(() => {
|
8624
|
+
return bucketize(React__default['default'].Children.toArray(children), childrenPerPage);
|
8625
|
+
}, [children, childrenPerPage]);
|
8626
|
+
// If children per page is 0 or less return empty element
|
8627
|
+
if (childrenPerPage <= 0) {
|
8628
|
+
return React__default['default'].createElement(React__default['default'].Fragment, null);
|
8608
8629
|
}
|
8630
|
+
const firstIndexOfCurrentPage = page * childrenPerPage;
|
8631
|
+
const clippedPage = firstIndexOfCurrentPage < numberOfChildren - 1 ? page : lastPage;
|
8632
|
+
const childrenOnCurrentPage = paginatedChildren[clippedPage];
|
8633
|
+
const showButtons = numberOfChildren > childrenPerPage;
|
8634
|
+
const disablePreviousButton = page === 0;
|
8635
|
+
const disableNextButton = page === lastPage;
|
8636
|
+
return (React__default['default'].createElement(react.Stack, { horizontal: true, className: react.mergeStyles(rootStyle, (_a = props.styles) === null || _a === void 0 ? void 0 : _a.root) },
|
8637
|
+
showButtons && (React__default['default'].createElement(HorizontalGalleryNavigationButton, { key: "previous-nav-button", icon: React__default['default'].createElement(react.Icon, { iconName: "HorizontalGalleryLeftButton" }), styles: styles === null || styles === void 0 ? void 0 : styles.previousButton, onClick: () => setPage(Math.max(0, Math.min(lastPage, page - 1))), disabled: disablePreviousButton, identifier: ids.horizontalGalleryLeftNavButton })),
|
8638
|
+
React__default['default'].createElement(react.Stack, { horizontal: true, className: react.mergeStyles(childrenContainerStyle, { '> *': (_b = props.styles) === null || _b === void 0 ? void 0 : _b.children }) }, childrenOnCurrentPage),
|
8639
|
+
showButtons && (React__default['default'].createElement(HorizontalGalleryNavigationButton, { key: "next-nav-button", icon: React__default['default'].createElement(react.Icon, { iconName: "HorizontalGalleryRightButton" }), styles: styles === null || styles === void 0 ? void 0 : styles.nextButton, onClick: () => setPage(Math.min(lastPage, page + 1)), disabled: disableNextButton, identifier: ids.horizontalGalleryRightNavButton }))));
|
8609
8640
|
};
|
8641
|
+
const HorizontalGalleryNavigationButton = (props) => {
|
8642
|
+
const theme = useTheme();
|
8643
|
+
return (React__default['default'].createElement(react.DefaultButton, { className: react.mergeStyles(leftRightButtonStyles(theme), props.styles), onClick: props.onClick, disabled: props.disabled, "data-ui-id": props.identifier }, props.icon));
|
8644
|
+
};
|
8645
|
+
function bucketize(arr, bucketSize) {
|
8646
|
+
const bucketArray = [];
|
8647
|
+
if (bucketSize <= 0) {
|
8648
|
+
return bucketArray;
|
8649
|
+
}
|
8650
|
+
for (let i = 0; i < arr.length; i += bucketSize) {
|
8651
|
+
bucketArray.push(arr.slice(i, i + bucketSize));
|
8652
|
+
}
|
8653
|
+
return bucketArray;
|
8654
|
+
}
|
8655
|
+
|
8656
|
+
// Copyright (c) Microsoft Corporation.
|
8657
|
+
/**
|
8658
|
+
* Wrapped HorizontalGallery that adjusts the number of items per page based on the
|
8659
|
+
* available width obtained from a ResizeObserver, width per child, gap width, and button width
|
8660
|
+
*/
|
8661
|
+
const ResponsiveHorizontalGallery = (props) => {
|
8662
|
+
const { childWidthRem, gapWidthRem, buttonWidthRem = 0 } = props;
|
8663
|
+
const containerRef = React.useRef(null);
|
8664
|
+
const containerWidth = _useContainerWidth(containerRef);
|
8665
|
+
const leftPadding = containerRef.current ? parseFloat(getComputedStyle(containerRef.current).paddingLeft) : 0;
|
8666
|
+
const rightPadding = containerRef.current ? parseFloat(getComputedStyle(containerRef.current).paddingRight) : 0;
|
8667
|
+
const childrenPerPage = calculateChildrenPerPage({
|
8668
|
+
numberOfChildren: React__default['default'].Children.count(props.children),
|
8669
|
+
containerWidth: (containerWidth !== null && containerWidth !== void 0 ? containerWidth : 0) - leftPadding - rightPadding,
|
8670
|
+
childWidthRem,
|
8671
|
+
gapWidthRem,
|
8672
|
+
buttonWidthRem
|
8673
|
+
});
|
8674
|
+
return (React__default['default'].createElement("div", { ref: containerRef, className: react.mergeStyles(props.containerStyles) },
|
8675
|
+
React__default['default'].createElement(HorizontalGallery, { childrenPerPage: childrenPerPage, styles: props.horizontalGalleryStyles }, props.children)));
|
8676
|
+
};
|
8677
|
+
/**
|
8678
|
+
* Helper function to calculate children per page for HorizontalGallery based on width of container, child, buttons, and
|
8679
|
+
* gaps in between
|
8680
|
+
*/
|
8681
|
+
const calculateChildrenPerPage = (args) => {
|
8682
|
+
const { numberOfChildren, containerWidth, buttonWidthRem, childWidthRem, gapWidthRem } = args;
|
8683
|
+
const childWidth = _convertRemToPx(childWidthRem);
|
8684
|
+
const gapWidth = _convertRemToPx(gapWidthRem);
|
8685
|
+
/** First check how many children can fit in containerWidth.
|
8686
|
+
* __________________________________
|
8687
|
+
* | || |
|
8688
|
+
* | || |
|
8689
|
+
* |________________||________________|
|
8690
|
+
* <-----------containerWidth--------->
|
8691
|
+
* containerWidth = n * childWidth + (n - 1) * gapWidth. Isolate n and take the floor.
|
8692
|
+
*/
|
8693
|
+
const numberOfChildrenInContainer = Math.floor((containerWidth + gapWidth) / (childWidth + gapWidth));
|
8694
|
+
// If all children fit then return numberOfChildrenInContainer
|
8695
|
+
if (numberOfChildren <= numberOfChildrenInContainer) {
|
8696
|
+
return numberOfChildrenInContainer;
|
8697
|
+
}
|
8698
|
+
const buttonWidth = _convertRemToPx(buttonWidthRem);
|
8699
|
+
/** We know we need to paginate. So we need to subtract the buttonWidth twice and gapWidth twice from
|
8700
|
+
* containerWidth to compute childrenSpace
|
8701
|
+
* <-----------containerWidth--------->
|
8702
|
+
* __________________________________
|
8703
|
+
* | || || || |
|
8704
|
+
* |<|| || ||>|
|
8705
|
+
* |_||_____________||_____________||_|
|
8706
|
+
* <-------childrenSpace------>
|
8707
|
+
*/
|
8708
|
+
const childrenSpace = containerWidth - 2 * buttonWidth - 2 * gapWidth;
|
8709
|
+
// Now that we have childrenSpace width we can figure out how many children can fit in childrenSpace.
|
8710
|
+
// childrenSpace = n * childWidth + (n - 1) * gapWidth. Isolate n and take the floor.
|
8711
|
+
return Math.floor((childrenSpace + gapWidth) / (childWidth + gapWidth));
|
8712
|
+
};
|
8713
|
+
|
8714
|
+
// Copyright (c) Microsoft Corporation.
|
8715
|
+
/**
|
8716
|
+
* Small floating modal width and height in rem for small screen
|
8717
|
+
*/
|
8718
|
+
const SMALL_FLOATING_MODAL_SIZE_PX$1 = { width: 64, height: 88 };
|
8719
|
+
/**
|
8720
|
+
* Large floating modal width and height in rem for large screen
|
8721
|
+
*/
|
8722
|
+
const LARGE_FLOATING_MODAL_SIZE_PX$1 = { width: 160, height: 120 };
|
8610
8723
|
/**
|
8611
8724
|
* @private
|
8612
8725
|
*/
|
@@ -8617,8 +8730,8 @@ const horizontalGalleryContainerStyle = (shouldFloatLocalVideo, isNarrow) => {
|
|
8617
8730
|
: `${LARGE_HORIZONTAL_GALLERY_TILE_SIZE_REM.height}rem`,
|
8618
8731
|
width: shouldFloatLocalVideo
|
8619
8732
|
? isNarrow
|
8620
|
-
? `calc(100% - ${_pxToRem(SMALL_FLOATING_MODAL_SIZE_PX.width)})`
|
8621
|
-
: `calc(100% - ${_pxToRem(LARGE_FLOATING_MODAL_SIZE_PX.width)})`
|
8733
|
+
? `calc(100% - ${_pxToRem(SMALL_FLOATING_MODAL_SIZE_PX$1.width)})`
|
8734
|
+
: `calc(100% - ${_pxToRem(LARGE_FLOATING_MODAL_SIZE_PX$1.width)})`
|
8622
8735
|
: '100%',
|
8623
8736
|
paddingRight: '0.5rem'
|
8624
8737
|
};
|
@@ -8659,163 +8772,245 @@ const LARGE_HORIZONTAL_GALLERY_TILE_STYLE = {
|
|
8659
8772
|
maxHeight: `${LARGE_HORIZONTAL_GALLERY_TILE_SIZE_REM.height}rem`,
|
8660
8773
|
maxWidth: `${LARGE_HORIZONTAL_GALLERY_TILE_SIZE_REM.width}rem`
|
8661
8774
|
};
|
8775
|
+
|
8776
|
+
// Copyright (c) Microsoft Corporation.
|
8662
8777
|
/**
|
8663
|
-
* @
|
8778
|
+
* A ResponsiveHorizontalGallery styled for the @link{VideoGallery}
|
8664
8779
|
*/
|
8665
|
-
const
|
8666
|
-
|
8667
|
-
|
8668
|
-
|
8669
|
-
|
8670
|
-
|
8671
|
-
overflow: 'hidden',
|
8672
|
-
// pointer events for layerHost set to none to make descendants interactive
|
8673
|
-
pointerEvents: 'none'
|
8780
|
+
const VideoGalleryResponsiveHorizontalGallery = (props) => {
|
8781
|
+
const { shouldFloatLocalVideo = false, isNarrow = false, horizontalGalleryElements, styles } = props;
|
8782
|
+
const containerStyles = React.useMemo(() => horizontalGalleryContainerStyle(shouldFloatLocalVideo, isNarrow), [shouldFloatLocalVideo, isNarrow]);
|
8783
|
+
const galleryStyles = React.useMemo(() => react.concatStyleSets(horizontalGalleryStyle(isNarrow), styles), [isNarrow, styles]);
|
8784
|
+
return (React__default['default'].createElement(react.Stack, { styles: { root: { paddingTop: '0.5rem' } } },
|
8785
|
+
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)));
|
8674
8786
|
};
|
8787
|
+
|
8788
|
+
/**
|
8789
|
+
* Calculates the participants that should be rendered based on the list of dominant
|
8790
|
+
* speakers and currently rendered participants in a call.
|
8791
|
+
* @param args - SmartDominantSpeakerParticipantsArgs
|
8792
|
+
* @returns VideoGalleryRemoteParticipant[] {@link @azure/communication-react#VideoGalleryRemoteParticipant}
|
8793
|
+
*/
|
8794
|
+
const smartDominantSpeakerParticipants = (args) => {
|
8795
|
+
const { participants, dominantSpeakers = [], lastVisibleParticipants = [], maxDominantSpeakers } = args;
|
8796
|
+
// Don't apply any logic if total number of video streams is less than max dominant speakers.
|
8797
|
+
if (participants.length <= maxDominantSpeakers) {
|
8798
|
+
return participants;
|
8799
|
+
}
|
8800
|
+
const participantsMap = participantsById(participants);
|
8801
|
+
// Only use the Max allowed dominant speakers that exist in participants
|
8802
|
+
const dominantSpeakerIds = Array.from(new Set(dominantSpeakers).values())
|
8803
|
+
.filter((id) => !!participantsMap[id])
|
8804
|
+
.slice(0, maxDominantSpeakers);
|
8805
|
+
const lastVisibleParticipantIds = lastVisibleParticipants.map((p) => p.userId);
|
8806
|
+
const newVisibleParticipantIds = lastVisibleParticipants.map((p) => p.userId).slice(0, maxDominantSpeakers);
|
8807
|
+
const newDominantSpeakerIds = dominantSpeakerIds.filter((id) => !newVisibleParticipantIds.includes(id));
|
8808
|
+
// Remove participants that are no longer dominant and replace them with new dominant speakers.
|
8809
|
+
for (let index = 0; index < maxDominantSpeakers; index++) {
|
8810
|
+
const newVisibleParticipantId = newVisibleParticipantIds[index];
|
8811
|
+
if (newVisibleParticipantId === undefined || !dominantSpeakerIds.includes(newVisibleParticipantId)) {
|
8812
|
+
const replacement = newDominantSpeakerIds.shift();
|
8813
|
+
if (!replacement) {
|
8814
|
+
break;
|
8815
|
+
}
|
8816
|
+
newVisibleParticipantIds[index] = replacement;
|
8817
|
+
}
|
8818
|
+
}
|
8819
|
+
const removedVisibleParticipantIds = lastVisibleParticipantIds.filter((p) => !newVisibleParticipantIds.includes(p));
|
8820
|
+
removedVisibleParticipantIds.forEach((p) => newVisibleParticipantIds.push(p));
|
8821
|
+
const newVisibleParticipantIdSet = new Set(newVisibleParticipantIds);
|
8822
|
+
const leftoverParticipants = participants.filter((p) => !newVisibleParticipantIdSet.has(p.userId));
|
8823
|
+
leftoverParticipants.forEach((p) => {
|
8824
|
+
newVisibleParticipantIds.push(p.userId);
|
8825
|
+
});
|
8826
|
+
// newVisibleParticipantIds can contain identifiers for participants that are no longer in the call. So we ignore those IDs.
|
8827
|
+
const newVisibleParticipants = newVisibleParticipantIds
|
8828
|
+
.map((participantId) => participantsMap[participantId])
|
8829
|
+
.filter((p) => !!p);
|
8830
|
+
return newVisibleParticipants;
|
8831
|
+
};
|
8832
|
+
const participantsById = (participants) => {
|
8833
|
+
const response = {};
|
8834
|
+
participants.forEach((p) => (response[p.userId] = p));
|
8835
|
+
return response;
|
8836
|
+
};
|
8837
|
+
|
8838
|
+
// Copyright (c) Microsoft Corporation.
|
8839
|
+
const DEFAULT_MAX_REMOTE_VIDEOSTREAMS = 4;
|
8840
|
+
const DEFAULT_MAX_AUDIO_DOMINANT_SPEAKERS = 6;
|
8675
8841
|
/**
|
8676
8842
|
* @private
|
8677
8843
|
*/
|
8678
|
-
const
|
8679
|
-
|
8680
|
-
|
8681
|
-
|
8682
|
-
|
8683
|
-
|
8684
|
-
|
8685
|
-
|
8686
|
-
|
8687
|
-
|
8688
|
-
|
8689
|
-
|
8690
|
-
|
8691
|
-
|
8692
|
-
|
8693
|
-
|
8694
|
-
|
8695
|
-
|
8696
|
-
|
8697
|
-
|
8698
|
-
|
8699
|
-
|
8700
|
-
|
8701
|
-
|
8702
|
-
|
8844
|
+
const useFloatingLocalVideoLayout = (props) => {
|
8845
|
+
var _a, _b;
|
8846
|
+
const visibleVideoParticipants = React.useRef([]);
|
8847
|
+
const visibleAudioParticipants = React.useRef([]);
|
8848
|
+
const { remoteParticipants, dominantSpeakers, maxRemoteVideoStreams = DEFAULT_MAX_REMOTE_VIDEOSTREAMS, maxAudioDominantSpeakers = DEFAULT_MAX_AUDIO_DOMINANT_SPEAKERS, isScreenShareActive = false } = props;
|
8849
|
+
visibleVideoParticipants.current = smartDominantSpeakerParticipants({
|
8850
|
+
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 : [],
|
8851
|
+
dominantSpeakers,
|
8852
|
+
lastVisibleParticipants: visibleVideoParticipants.current,
|
8853
|
+
maxDominantSpeakers: maxRemoteVideoStreams
|
8854
|
+
}).slice(0, maxRemoteVideoStreams);
|
8855
|
+
const visibleVideoParticipantsSet = new Set(visibleVideoParticipants.current.map((p) => p.userId));
|
8856
|
+
/* @conditional-compile-remove(PSTN-calls) */ /* @conditional-compile-remove(one-to-n-calling) */
|
8857
|
+
const callingParticipants = remoteParticipants.filter((p) => p.state === ('Connecting' ));
|
8858
|
+
/* @conditional-compile-remove(PSTN-calls) */ /* @conditional-compile-remove(one-to-n-calling) */
|
8859
|
+
const callingParticipantsSet = new Set(callingParticipants.map((p) => p.userId));
|
8860
|
+
visibleAudioParticipants.current = smartDominantSpeakerParticipants({
|
8861
|
+
participants: (_b = remoteParticipants === null || remoteParticipants === void 0 ? void 0 : remoteParticipants.filter((p) => !visibleVideoParticipantsSet.has(p.userId) &&
|
8862
|
+
/* @conditional-compile-remove(PSTN-calls) */ /* @conditional-compile-remove(one-to-n-calling) */ !callingParticipantsSet.has(p.userId))) !== null && _b !== void 0 ? _b : [],
|
8863
|
+
dominantSpeakers,
|
8864
|
+
lastVisibleParticipants: visibleAudioParticipants.current,
|
8865
|
+
maxDominantSpeakers: maxAudioDominantSpeakers
|
8866
|
+
});
|
8867
|
+
const getGridParticipants = React.useCallback(() => {
|
8868
|
+
if (isScreenShareActive) {
|
8869
|
+
return [];
|
8703
8870
|
}
|
8704
|
-
|
8871
|
+
/* @conditional-compile-remove(PSTN-calls) */ /* @conditional-compile-remove(one-to-n-calling) */
|
8872
|
+
return visibleVideoParticipants.current.length > 0
|
8873
|
+
? visibleVideoParticipants.current
|
8874
|
+
: visibleAudioParticipants.current.concat(callingParticipants);
|
8875
|
+
}, [
|
8876
|
+
/* @conditional-compile-remove(PSTN-calls) */ /* @conditional-compile-remove(one-to-n-calling) */ callingParticipants,
|
8877
|
+
isScreenShareActive
|
8878
|
+
]);
|
8879
|
+
const gridParticipants = getGridParticipants();
|
8880
|
+
const getHorizontalGalleryRemoteParticipants = React.useCallback(() => {
|
8881
|
+
if (isScreenShareActive) {
|
8882
|
+
// If screen sharing is active, assign video and audio participants as horizontal gallery participants
|
8883
|
+
/* @conditional-compile-remove(PSTN-calls) */ /* @conditional-compile-remove(one-to-n-calling) */
|
8884
|
+
return visibleVideoParticipants.current.concat(visibleAudioParticipants.current.concat(callingParticipants));
|
8885
|
+
}
|
8886
|
+
else {
|
8887
|
+
// If screen sharing is not active, then assign all video tiles as grid tiles.
|
8888
|
+
// If there are no video tiles, then assign audio tiles as grid tiles.
|
8889
|
+
/* @conditional-compile-remove(PSTN-calls) */ /* @conditional-compile-remove(one-to-n-calling) */
|
8890
|
+
return visibleVideoParticipants.current.length > 0
|
8891
|
+
? visibleAudioParticipants.current.concat(callingParticipants)
|
8892
|
+
: [];
|
8893
|
+
}
|
8894
|
+
}, [
|
8895
|
+
/* @conditional-compile-remove(PSTN-calls) */ /* @conditional-compile-remove(one-to-n-calling) */ callingParticipants,
|
8896
|
+
isScreenShareActive
|
8897
|
+
]);
|
8898
|
+
const horizontalGalleryParticipants = getHorizontalGalleryRemoteParticipants();
|
8899
|
+
return { gridParticipants, horizontalGalleryParticipants };
|
8705
8900
|
};
|
8901
|
+
|
8902
|
+
// Copyright (c) Microsoft Corporation.
|
8706
8903
|
/**
|
8707
|
-
*
|
8904
|
+
* DefaultLayout displays remote participants, local video component, and screen sharing component in
|
8905
|
+
* a grid and horizontal gallery.
|
8906
|
+
*
|
8708
8907
|
* @private
|
8709
8908
|
*/
|
8710
|
-
const
|
8711
|
-
|
8712
|
-
|
8909
|
+
const DefaultLayout = (props) => {
|
8910
|
+
const { remoteParticipants = [], dominantSpeakers, localVideoComponent, screenShareComponent, onRenderRemoteParticipant, styles, maxRemoteVideoStreams, parentWidth } = props;
|
8911
|
+
const isNarrow = parentWidth ? isNarrowWidth(parentWidth) : false;
|
8912
|
+
const floatingLocalVideoLayout = useFloatingLocalVideoLayout({
|
8913
|
+
remoteParticipants,
|
8914
|
+
dominantSpeakers,
|
8915
|
+
maxRemoteVideoStreams,
|
8916
|
+
isScreenShareActive: !!screenShareComponent
|
8917
|
+
});
|
8918
|
+
let activeVideoStreams = 0;
|
8919
|
+
const gridTiles = floatingLocalVideoLayout.gridParticipants.map((p) => {
|
8920
|
+
var _a, _b;
|
8921
|
+
return onRenderRemoteParticipant(p, maxRemoteVideoStreams && maxRemoteVideoStreams >= 0
|
8922
|
+
? ((_a = p.videoStream) === null || _a === void 0 ? void 0 : _a.isAvailable) && activeVideoStreams++ < maxRemoteVideoStreams
|
8923
|
+
: (_b = p.videoStream) === null || _b === void 0 ? void 0 : _b.isAvailable);
|
8924
|
+
});
|
8925
|
+
const horizontalGalleryTiles = floatingLocalVideoLayout.horizontalGalleryParticipants.map((p) => {
|
8926
|
+
var _a, _b;
|
8927
|
+
return onRenderRemoteParticipant(p, maxRemoteVideoStreams && maxRemoteVideoStreams >= 0
|
8928
|
+
? ((_a = p.videoStream) === null || _a === void 0 ? void 0 : _a.isAvailable) && activeVideoStreams++ < maxRemoteVideoStreams
|
8929
|
+
: (_b = p.videoStream) === null || _b === void 0 ? void 0 : _b.isAvailable);
|
8930
|
+
});
|
8931
|
+
if (localVideoComponent) {
|
8932
|
+
gridTiles.push(localVideoComponent);
|
8713
8933
|
}
|
8934
|
+
return (React__default['default'].createElement(react.Stack, { horizontal: false, styles: rootLayoutStyle$1 },
|
8935
|
+
screenShareComponent ? (screenShareComponent) : (React__default['default'].createElement(GridLayout, { key: "grid-layout", styles: styles === null || styles === void 0 ? void 0 : styles.gridLayout }, gridTiles)),
|
8936
|
+
horizontalGalleryTiles.length > 0 && (React__default['default'].createElement(VideoGalleryResponsiveHorizontalGallery, { isNarrow: isNarrow, horizontalGalleryElements: horizontalGalleryTiles, styles: styles === null || styles === void 0 ? void 0 : styles.horizontalGallery }))));
|
8714
8937
|
};
|
8715
8938
|
|
8716
8939
|
// Copyright (c) Microsoft Corporation.
|
8717
8940
|
/**
|
8718
8941
|
* @private
|
8719
8942
|
*/
|
8720
|
-
|
8721
|
-
|
8722
|
-
|
8723
|
-
|
8943
|
+
react.mergeStyles({ position: 'relative', width: '100%', height: '100%' });
|
8944
|
+
/**
|
8945
|
+
* Small floating modal width and height in rem for small screen
|
8946
|
+
*/
|
8947
|
+
const SMALL_FLOATING_MODAL_SIZE_PX = { width: 64, height: 88 };
|
8948
|
+
/**
|
8949
|
+
* Large floating modal width and height in rem for large screen
|
8950
|
+
*/
|
8951
|
+
const LARGE_FLOATING_MODAL_SIZE_PX = { width: 160, height: 120 };
|
8724
8952
|
/**
|
8725
8953
|
* @private
|
8954
|
+
* z-index to ensure that the local video tile is above the video gallery.
|
8726
8955
|
*/
|
8727
|
-
const
|
8728
|
-
backgroundColor: 'inherit',
|
8729
|
-
padding: '1rem',
|
8730
|
-
maxWidth: '95%',
|
8731
|
-
borderRadius: theme.effects.roundedCorner4,
|
8732
|
-
color: theme.palette.neutralSecondary
|
8733
|
-
});
|
8956
|
+
const LOCAL_VIDEO_TILE_ZINDEX = 2;
|
8734
8957
|
/**
|
8735
8958
|
* @private
|
8736
8959
|
*/
|
8737
|
-
const
|
8738
|
-
height: '
|
8739
|
-
|
8740
|
-
});
|
8960
|
+
const localVideoTileContainerStyle = (theme, isNarrow) => {
|
8961
|
+
return Object.assign({ minWidth: isNarrow ? _pxToRem(SMALL_FLOATING_MODAL_SIZE_PX.width) : _pxToRem(LARGE_FLOATING_MODAL_SIZE_PX.width), minHeight: isNarrow ? _pxToRem(SMALL_FLOATING_MODAL_SIZE_PX.height) : _pxToRem(LARGE_FLOATING_MODAL_SIZE_PX.height), position: 'absolute', bottom: _pxToRem(localVideoTileOuterPaddingPX), borderRadius: theme.effects.roundedCorner4, overflow: 'hidden' }, (theme.rtl
|
8962
|
+
? { left: _pxToRem(localVideoTileOuterPaddingPX) }
|
8963
|
+
: { right: _pxToRem(localVideoTileOuterPaddingPX) }));
|
8964
|
+
};
|
8741
8965
|
/**
|
8742
8966
|
* @private
|
8743
8967
|
*/
|
8744
|
-
const
|
8745
|
-
|
8746
|
-
|
8747
|
-
|
8748
|
-
}
|
8968
|
+
const localVideoTileWithControlsContainerStyle = (theme, isNarrow) => {
|
8969
|
+
return react.concatStyleSets(localVideoTileContainerStyle(theme, isNarrow), {
|
8970
|
+
root: { boxShadow: theme.effects.elevation8 }
|
8971
|
+
});
|
8972
|
+
};
|
8749
8973
|
/**
|
8750
8974
|
* @private
|
8751
8975
|
*/
|
8752
|
-
const
|
8753
|
-
|
8754
|
-
|
8755
|
-
|
8756
|
-
|
8757
|
-
|
8758
|
-
|
8976
|
+
const floatingLocalVideoModalStyle = (theme, isNarrow) => {
|
8977
|
+
return react.concatStyleSets({
|
8978
|
+
main: localVideoTileContainerStyle(theme, isNarrow)
|
8979
|
+
}, {
|
8980
|
+
main: {
|
8981
|
+
boxShadow: theme.effects.elevation8,
|
8982
|
+
':focus-within': {
|
8983
|
+
boxShadow: theme.effects.elevation16,
|
8984
|
+
border: `${_pxToRem(2)} solid ${theme.palette.neutralPrimary}`
|
8985
|
+
}
|
8986
|
+
}
|
8987
|
+
}, localVideoModalStyles);
|
8988
|
+
};
|
8759
8989
|
/**
|
8760
|
-
*
|
8761
|
-
*
|
8762
|
-
*
|
8990
|
+
* Padding equal to the amount the modal should stay inside the bounds of the container.
|
8991
|
+
* i.e. if this is 8px, the modal should always be at least 8px inside the container at all times on all sides.
|
8992
|
+
* @private
|
8763
8993
|
*/
|
8764
|
-
const
|
8765
|
-
const { localParticipant } = props;
|
8766
|
-
const theme = useTheme();
|
8767
|
-
const locale = useLocale$1();
|
8768
|
-
if (!localParticipant || !localParticipant.isScreenSharingOn) {
|
8769
|
-
return null;
|
8770
|
-
}
|
8771
|
-
const localScreenSharingNotification = (React__default['default'].createElement(react.Stack, { horizontalAlign: "center", verticalAlign: "center", className: screenSharingContainerStyle },
|
8772
|
-
React__default['default'].createElement(react.Stack, { horizontalAlign: "center", verticalAlign: "center", className: screenSharingNotificationContainerStyle(theme), tokens: { childrenGap: '1rem' } },
|
8773
|
-
React__default['default'].createElement(react.Stack, { horizontal: true, verticalAlign: "center", className: screenSharingNotificationIconContainerStyle },
|
8774
|
-
React__default['default'].createElement(react.Icon, { iconName: "ControlButtonScreenShareStart", className: screenSharingNotificationIconStyle(theme) })),
|
8775
|
-
React__default['default'].createElement(react.Text, { className: screenSharingNotificationTextStyle, "aria-live": "polite" }, locale.strings.videoGallery.screenIsBeingSharedMessage))));
|
8776
|
-
const displayName = !(localParticipant === null || localParticipant === void 0 ? void 0 : localParticipant.displayName)
|
8777
|
-
? locale.strings.videoGallery.displayNamePlaceholder
|
8778
|
-
: localParticipant === null || localParticipant === void 0 ? void 0 : localParticipant.displayName;
|
8779
|
-
return (React__default['default'].createElement(VideoTile, { displayName: displayName, isMuted: localParticipant === null || localParticipant === void 0 ? void 0 : localParticipant.isMuted, onRenderPlaceholder: () => React__default['default'].createElement(React__default['default'].Fragment, null) }, localScreenSharingNotification));
|
8780
|
-
});
|
8781
|
-
|
8782
|
-
// Copyright (c) Microsoft Corporation.
|
8994
|
+
const localVideoTileOuterPaddingPX = 8;
|
8783
8995
|
/**
|
8784
8996
|
* @private
|
8785
8997
|
*/
|
8786
|
-
const
|
8787
|
-
|
8788
|
-
|
8789
|
-
|
8790
|
-
|
8791
|
-
|
8998
|
+
const floatingLocalVideoTileStyle = {
|
8999
|
+
root: {
|
9000
|
+
position: 'absolute',
|
9001
|
+
zIndex: LOCAL_VIDEO_TILE_ZINDEX,
|
9002
|
+
height: '100%',
|
9003
|
+
width: '100%'
|
9004
|
+
}
|
9005
|
+
};
|
8792
9006
|
/**
|
8793
|
-
*
|
8794
|
-
*
|
8795
|
-
* https://reactjs.org/docs/react-api.html#reactmemo
|
9007
|
+
* Styles for the local video tile modal when it is focused, will cause keyboard move icon to appear over video
|
9008
|
+
* @private
|
8796
9009
|
*/
|
8797
|
-
const
|
8798
|
-
|
8799
|
-
|
8800
|
-
if (!renderElement) {
|
8801
|
-
onCreateRemoteStreamView && onCreateRemoteStreamView(userId);
|
9010
|
+
const localVideoModalStyles = {
|
9011
|
+
keyboardMoveIconContainer: {
|
9012
|
+
zIndex: LOCAL_VIDEO_TILE_ZINDEX + 1 // zIndex to set the keyboard movement Icon above the other layers in the video tile.
|
8802
9013
|
}
|
8803
|
-
React.useEffect(() => {
|
8804
|
-
return () => {
|
8805
|
-
// TODO: Isolate disposing behaviors for screenShare and videoStream
|
8806
|
-
onDisposeRemoteStreamView && onDisposeRemoteStreamView(userId);
|
8807
|
-
};
|
8808
|
-
}, [onDisposeRemoteStreamView, userId]);
|
8809
|
-
const loadingMessage = displayName
|
8810
|
-
? _formatString(locale.strings.videoGallery.screenShareLoadingMessage, {
|
8811
|
-
participant: displayName
|
8812
|
-
})
|
8813
|
-
: '';
|
8814
|
-
return (React__default['default'].createElement(VideoTile, { displayName: displayName, isMuted: isMuted, renderElement: renderElement ? (React__default['default'].createElement(StreamMedia, { videoStreamElement: renderElement, loadingState: isReceiving === false ? 'loading' : 'none' })) : undefined, onRenderPlaceholder: () => React__default['default'].createElement(LoadingSpinner, { loadingMessage: loadingMessage }) }));
|
8815
|
-
});
|
8816
|
-
const LoadingSpinner = (props) => {
|
8817
|
-
return (React__default['default'].createElement(react.Stack, { verticalAlign: "center", className: loadingStyle },
|
8818
|
-
React__default['default'].createElement(react.Spinner, { label: props.loadingMessage, size: react.SpinnerSize.xSmall, "aria-live": 'assertive' })));
|
8819
9014
|
};
|
8820
9015
|
|
8821
9016
|
// Copyright (c) Microsoft Corporation.
|
@@ -9491,103 +9686,123 @@ const _ModalClone = react.styled(ModalBase, getStyles, undefined, {
|
|
9491
9686
|
_ModalClone.displayName = 'Modal';
|
9492
9687
|
|
9493
9688
|
// Copyright (c) Microsoft Corporation.
|
9689
|
+
const DRAG_OPTIONS$1 = {
|
9690
|
+
moveMenuItemText: 'Move',
|
9691
|
+
closeMenuItemText: 'Close',
|
9692
|
+
menu: react.ContextualMenu,
|
9693
|
+
keepInBounds: true
|
9694
|
+
};
|
9695
|
+
// Manually override the max position used to keep the modal in the bounds of its container.
|
9696
|
+
// This is a workaround for: https://github.com/microsoft/fluentui/issues/20122
|
9697
|
+
// Because our modal starts in the bottom right corner, we can say that this is the max (i.e. rightmost and bottomost)
|
9698
|
+
// position the modal can be dragged to.
|
9699
|
+
const modalMaxDragPosition = { x: localVideoTileOuterPaddingPX, y: localVideoTileOuterPaddingPX };
|
9494
9700
|
/**
|
9495
|
-
*
|
9496
|
-
* @internal
|
9701
|
+
* @private
|
9497
9702
|
*/
|
9498
|
-
const
|
9499
|
-
const {
|
9500
|
-
const theme =
|
9501
|
-
|
9502
|
-
|
9503
|
-
|
9504
|
-
|
9505
|
-
|
9506
|
-
|
9507
|
-
|
9508
|
-
|
9509
|
-
|
9703
|
+
const FloatingLocalVideo = (props) => {
|
9704
|
+
const { localVideoComponent, layerHostId, isNarrow, parentWidth, parentHeight } = props;
|
9705
|
+
const theme = useTheme();
|
9706
|
+
const modalWidth = isNarrow ? SMALL_FLOATING_MODAL_SIZE_PX.width : LARGE_FLOATING_MODAL_SIZE_PX.width;
|
9707
|
+
const modalHeight = isNarrow ? SMALL_FLOATING_MODAL_SIZE_PX.height : LARGE_FLOATING_MODAL_SIZE_PX.height;
|
9708
|
+
// The minimum drag position is the top left of the video gallery. i.e. the modal (PiP) should not be able
|
9709
|
+
// to be dragged offscreen and these are the top and left bounds of that calculation.
|
9710
|
+
const modalMinDragPosition = React.useMemo(() => parentWidth && parentHeight
|
9711
|
+
? {
|
9712
|
+
// We use -parentWidth/Height because our modal is positioned to start in the bottom right,
|
9713
|
+
// hence (0,0) is the bottom right of the video gallery.
|
9714
|
+
x: -parentWidth + modalWidth + localVideoTileOuterPaddingPX,
|
9715
|
+
y: -parentHeight + modalHeight + localVideoTileOuterPaddingPX
|
9716
|
+
}
|
9717
|
+
: undefined, [parentHeight, parentWidth, modalHeight, modalWidth]);
|
9718
|
+
const modalStyles = React.useMemo(() => floatingLocalVideoModalStyle(theme, isNarrow), [theme, isNarrow]);
|
9719
|
+
const layerProps = React.useMemo(() => ({ hostId: layerHostId }), [layerHostId]);
|
9720
|
+
return (React__default['default'].createElement(_ModalClone, { isOpen: true, isModeless: true, dragOptions: DRAG_OPTIONS$1, styles: modalStyles, layerProps: layerProps, maxDragPosition: modalMaxDragPosition, minDragPosition: modalMinDragPosition }, localVideoComponent));
|
9510
9721
|
};
|
9511
9722
|
|
9512
9723
|
// Copyright (c) Microsoft Corporation.
|
9724
|
+
// Licensed under the MIT license.
|
9513
9725
|
/**
|
9514
|
-
*
|
9515
|
-
*
|
9516
|
-
* @internal
|
9726
|
+
* @private
|
9517
9727
|
*/
|
9518
|
-
const
|
9519
|
-
|
9520
|
-
|
9521
|
-
|
9522
|
-
|
9523
|
-
|
9524
|
-
|
9525
|
-
|
9526
|
-
|
9527
|
-
|
9528
|
-
|
9529
|
-
|
9530
|
-
|
9531
|
-
|
9532
|
-
|
9533
|
-
|
9534
|
-
|
9535
|
-
|
9536
|
-
|
9537
|
-
|
9538
|
-
|
9539
|
-
// implies that, after their threshold, all streams have no child (blank video)
|
9540
|
-
if (!renderElement || !renderElement.childElementCount) {
|
9541
|
-
// Returning `undefined` results in the placeholder with avatar being shown
|
9542
|
-
return undefined;
|
9543
|
-
}
|
9544
|
-
return (React__default['default'].createElement(React__default['default'].Fragment, null,
|
9545
|
-
React__default['default'].createElement(FloatingLocalCameraCycleButton, { showCameraSwitcherInLocalPreview: showCameraSwitcherInLocalPreview !== null && showCameraSwitcherInLocalPreview !== void 0 ? showCameraSwitcherInLocalPreview : false, localVideoCameraCycleButtonProps: localVideoCameraCycleButtonProps, localVideoCameraSwitcherLabel: localVideoCameraSwitcherLabel, localVideoSelectedDescription: localVideoSelectedDescription }),
|
9546
|
-
React__default['default'].createElement(StreamMedia, { videoStreamElement: renderElement, isMirrored: true })));
|
9547
|
-
}, [
|
9548
|
-
localVideoCameraCycleButtonProps,
|
9549
|
-
localVideoCameraSwitcherLabel,
|
9550
|
-
localVideoSelectedDescription,
|
9551
|
-
renderElement,
|
9552
|
-
showCameraSwitcherInLocalPreview
|
9553
|
-
]);
|
9554
|
-
return (React__default['default'].createElement(VideoTile, { key: userId !== null && userId !== void 0 ? userId : 'local-video-tile', userId: userId, renderElement: renderVideoStreamElement, showLabel: showLabel, displayName: displayName, initialsName: initialsName, styles: styles, onRenderPlaceholder: onRenderAvatar, isMuted: isMuted, showMuteIndicator: showMuteIndicator, personaMinSize: props.personaMinSize }));
|
9555
|
-
});
|
9556
|
-
const FloatingLocalCameraCycleButton = (props) => {
|
9557
|
-
const { showCameraSwitcherInLocalPreview, localVideoCameraCycleButtonProps, localVideoCameraSwitcherLabel, localVideoSelectedDescription } = props;
|
9558
|
-
const ariaDescription = (localVideoCameraCycleButtonProps === null || localVideoCameraCycleButtonProps === void 0 ? void 0 : localVideoCameraCycleButtonProps.selectedCamera) &&
|
9559
|
-
localVideoSelectedDescription &&
|
9560
|
-
_formatString(localVideoSelectedDescription, {
|
9561
|
-
cameraName: localVideoCameraCycleButtonProps.selectedCamera.name
|
9562
|
-
});
|
9563
|
-
return (React__default['default'].createElement(react.Stack, { horizontalAlign: "end" }, showCameraSwitcherInLocalPreview &&
|
9564
|
-
(localVideoCameraCycleButtonProps === null || localVideoCameraCycleButtonProps === void 0 ? void 0 : localVideoCameraCycleButtonProps.cameras) !== undefined &&
|
9565
|
-
(localVideoCameraCycleButtonProps === null || localVideoCameraCycleButtonProps === void 0 ? void 0 : localVideoCameraCycleButtonProps.selectedCamera) !== undefined &&
|
9566
|
-
(localVideoCameraCycleButtonProps === null || localVideoCameraCycleButtonProps === void 0 ? void 0 : localVideoCameraCycleButtonProps.onSelectCamera) !== undefined && (React__default['default'].createElement(LocalVideoCameraCycleButton, { cameras: localVideoCameraCycleButtonProps.cameras, selectedCamera: localVideoCameraCycleButtonProps.selectedCamera, onSelectCamera: localVideoCameraCycleButtonProps.onSelectCamera, label: localVideoCameraSwitcherLabel, ariaDescription: ariaDescription }))));
|
9728
|
+
const rootLayoutStyle = {
|
9729
|
+
root: { position: 'relative', height: '100%', width: '100%' }
|
9730
|
+
};
|
9731
|
+
/**
|
9732
|
+
* @private
|
9733
|
+
*/
|
9734
|
+
const innerLayoutStyle = {
|
9735
|
+
root: { position: 'relative', height: '100%', width: '100%', padding: '0.5rem' }
|
9736
|
+
};
|
9737
|
+
/**
|
9738
|
+
* @private
|
9739
|
+
*/
|
9740
|
+
const layerHostStyle = {
|
9741
|
+
position: 'absolute',
|
9742
|
+
left: 0,
|
9743
|
+
top: 0,
|
9744
|
+
width: '100%',
|
9745
|
+
height: '100%',
|
9746
|
+
overflow: 'hidden',
|
9747
|
+
// pointer events for layerHost set to none to make descendants interactive
|
9748
|
+
pointerEvents: 'none'
|
9567
9749
|
};
|
9568
9750
|
|
9569
9751
|
// Copyright (c) Microsoft Corporation.
|
9570
9752
|
/**
|
9753
|
+
* FloatingLocalVideoLayout displays remote participants and a screen sharing component in
|
9754
|
+
* a grid and horizontal gallery while floating the local video
|
9755
|
+
*
|
9571
9756
|
* @private
|
9572
|
-
* Currently the Calling JS SDK supports up to 4 remote video streams
|
9573
9757
|
*/
|
9574
|
-
const
|
9758
|
+
const FloatingLocalVideoLayout = (props) => {
|
9759
|
+
const { remoteParticipants = [], dominantSpeakers, localVideoComponent, screenShareComponent, onRenderRemoteParticipant, styles, maxRemoteVideoStreams, showCameraSwitcherInLocalPreview, parentWidth, parentHeight } = props;
|
9760
|
+
const theme = useTheme();
|
9761
|
+
const isNarrow = parentWidth ? isNarrowWidth(parentWidth) : false;
|
9762
|
+
const floatingLocalVideoLayout = useFloatingLocalVideoLayout({
|
9763
|
+
remoteParticipants,
|
9764
|
+
dominantSpeakers,
|
9765
|
+
maxRemoteVideoStreams,
|
9766
|
+
isScreenShareActive: !!screenShareComponent
|
9767
|
+
});
|
9768
|
+
let activeVideoStreams = 0;
|
9769
|
+
const gridTiles = floatingLocalVideoLayout.gridParticipants.map((p) => {
|
9770
|
+
var _a, _b;
|
9771
|
+
return onRenderRemoteParticipant(p, maxRemoteVideoStreams && maxRemoteVideoStreams >= 0
|
9772
|
+
? ((_a = p.videoStream) === null || _a === void 0 ? void 0 : _a.isAvailable) && activeVideoStreams++ < maxRemoteVideoStreams
|
9773
|
+
: (_b = p.videoStream) === null || _b === void 0 ? void 0 : _b.isAvailable);
|
9774
|
+
});
|
9775
|
+
const shouldFloatLocalVideo = remoteParticipants.length > 0;
|
9776
|
+
if (!shouldFloatLocalVideo && localVideoComponent) {
|
9777
|
+
gridTiles.push(localVideoComponent);
|
9778
|
+
}
|
9779
|
+
const horizontalGalleryTiles = floatingLocalVideoLayout.horizontalGalleryParticipants.map((p) => {
|
9780
|
+
var _a, _b;
|
9781
|
+
return onRenderRemoteParticipant(p, maxRemoteVideoStreams && maxRemoteVideoStreams >= 0
|
9782
|
+
? ((_a = p.videoStream) === null || _a === void 0 ? void 0 : _a.isAvailable) && activeVideoStreams++ < maxRemoteVideoStreams
|
9783
|
+
: (_b = p.videoStream) === null || _b === void 0 ? void 0 : _b.isAvailable);
|
9784
|
+
});
|
9785
|
+
const layerHostId = reactHooks.useId('layerhost');
|
9786
|
+
const wrappedLocalVideoComponent = localVideoComponent && shouldFloatLocalVideo ? (
|
9787
|
+
// When we use showCameraSwitcherInLocalPreview it disables dragging to allow keyboard navigation.
|
9788
|
+
showCameraSwitcherInLocalPreview ? (React__default['default'].createElement(react.Stack, { className: react.mergeStyles(localVideoTileWithControlsContainerStyle(theme, isNarrow), {
|
9789
|
+
boxShadow: theme.effects.elevation8,
|
9790
|
+
zIndex: LOCAL_VIDEO_TILE_ZINDEX
|
9791
|
+
}) }, 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;
|
9792
|
+
return (React__default['default'].createElement(react.Stack, { styles: rootLayoutStyle },
|
9793
|
+
wrappedLocalVideoComponent,
|
9794
|
+
React__default['default'].createElement(react.Stack, { horizontal: false, styles: innerLayoutStyle },
|
9795
|
+
screenShareComponent ? (screenShareComponent) : (React__default['default'].createElement(GridLayout, { key: "grid-layout", styles: styles === null || styles === void 0 ? void 0 : styles.gridLayout }, gridTiles)),
|
9796
|
+
horizontalGalleryTiles.length > 0 && (React__default['default'].createElement(VideoGalleryResponsiveHorizontalGallery, { isNarrow: isNarrow, shouldFloatLocalVideo: true, horizontalGalleryElements: horizontalGalleryTiles, styles: styles === null || styles === void 0 ? void 0 : styles.horizontalGallery })),
|
9797
|
+
React__default['default'].createElement(react.LayerHost, { id: layerHostId, className: react.mergeStyles(layerHostStyle) }))));
|
9798
|
+
};
|
9799
|
+
|
9800
|
+
// Copyright (c) Microsoft Corporation.
|
9575
9801
|
/**
|
9576
9802
|
* @private
|
9577
|
-
*
|
9803
|
+
* Currently the Calling JS SDK supports up to 4 remote video streams
|
9578
9804
|
*/
|
9579
|
-
const
|
9580
|
-
const DRAG_OPTIONS$1 = {
|
9581
|
-
moveMenuItemText: 'Move',
|
9582
|
-
closeMenuItemText: 'Close',
|
9583
|
-
menu: react.ContextualMenu,
|
9584
|
-
keepInBounds: true
|
9585
|
-
};
|
9586
|
-
// Manually override the max position used to keep the modal in the bounds of its container.
|
9587
|
-
// This is a workaround for: https://github.com/microsoft/fluentui/issues/20122
|
9588
|
-
// Because our modal starts in the bottom right corner, we can say that this is the max (i.e. rightmost and bottomost)
|
9589
|
-
// position the modal can be dragged to.
|
9590
|
-
const modalMaxDragPosition = { x: localVideoTileOuterPaddingPX, y: localVideoTileOuterPaddingPX };
|
9805
|
+
const DEFAULT_MAX_REMOTE_VIDEO_STREAMS = 4;
|
9591
9806
|
/**
|
9592
9807
|
* VideoGallery represents a layout of video tiles for a specific call.
|
9593
9808
|
* It displays a {@link VideoTile} for the local user as well as for each remote participant who has joined the call.
|
@@ -9595,53 +9810,17 @@ const modalMaxDragPosition = { x: localVideoTileOuterPaddingPX, y: localVideoTil
|
|
9595
9810
|
* @public
|
9596
9811
|
*/
|
9597
9812
|
const VideoGallery = (props) => {
|
9598
|
-
var _a, _b
|
9813
|
+
var _a, _b;
|
9599
9814
|
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;
|
9600
9815
|
const ids = useIdentifiers();
|
9601
9816
|
const theme = useTheme();
|
9602
9817
|
const localeStrings = useLocale$1().strings.videoGallery;
|
9603
9818
|
const strings = Object.assign(Object.assign({}, localeStrings), props.strings);
|
9604
9819
|
const shouldFloatLocalVideo = !!(layout === 'floatingLocalVideo' && remoteParticipants.length > 0);
|
9605
|
-
const shouldFloatNonDraggableLocalVideo = !!(showCameraSwitcherInLocalPreview && shouldFloatLocalVideo);
|
9606
9820
|
const containerRef = React.useRef(null);
|
9607
9821
|
const containerWidth = _useContainerWidth(containerRef);
|
9608
9822
|
const containerHeight = _useContainerHeight(containerRef);
|
9609
9823
|
const isNarrow = containerWidth ? isNarrowWidth(containerWidth) : false;
|
9610
|
-
const visibleVideoParticipants = React.useRef([]);
|
9611
|
-
const visibleAudioParticipants = React.useRef([]);
|
9612
|
-
/* @conditional-compile-remove(PSTN-calls) */ /* @conditional-compile-remove(one-to-n-calling) */
|
9613
|
-
const visibleCallingParticipants = React.useRef([]);
|
9614
|
-
const modalWidth = isNarrow ? SMALL_FLOATING_MODAL_SIZE_PX.width : LARGE_FLOATING_MODAL_SIZE_PX.width;
|
9615
|
-
const modalHeight = isNarrow ? SMALL_FLOATING_MODAL_SIZE_PX.height : LARGE_FLOATING_MODAL_SIZE_PX.height;
|
9616
|
-
// The minimum drag position is the top left of the video gallery. i.e. the modal (PiP) should not be able
|
9617
|
-
// to be dragged offscreen and these are the top and left bounds of that calculation.
|
9618
|
-
const modalMinDragPosition = React.useMemo(() => containerWidth && containerHeight
|
9619
|
-
? {
|
9620
|
-
// We use -containerWidth/Height because our modal is positioned to start in the bottom right,
|
9621
|
-
// hence (0,0) is the bottom right of the video gallery.
|
9622
|
-
x: -containerWidth + modalWidth + localVideoTileOuterPaddingPX,
|
9623
|
-
y: -containerHeight + modalHeight + localVideoTileOuterPaddingPX
|
9624
|
-
}
|
9625
|
-
: undefined, [containerHeight, containerWidth, modalHeight, modalWidth]);
|
9626
|
-
visibleVideoParticipants.current = smartDominantSpeakerParticipants({
|
9627
|
-
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 : [],
|
9628
|
-
dominantSpeakers,
|
9629
|
-
lastVisibleParticipants: visibleVideoParticipants.current,
|
9630
|
-
maxDominantSpeakers: maxRemoteVideoStreams
|
9631
|
-
}).slice(0, maxRemoteVideoStreams);
|
9632
|
-
/* @conditional-compile-remove(PSTN-calls) */ /* @conditional-compile-remove(one-to-n-calling) */
|
9633
|
-
visibleCallingParticipants.current = (_b = remoteParticipants === null || remoteParticipants === void 0 ? void 0 : remoteParticipants.filter((p) => p.state === ('Connecting' ))) !== null && _b !== void 0 ? _b : [];
|
9634
|
-
// This set will be used to filter out participants already in visibleVideoParticipants
|
9635
|
-
const visibleVideoParticipantsSet = new Set(visibleVideoParticipants.current.map((p) => p.userId));
|
9636
|
-
/* @conditional-compile-remove(PSTN-calls) */ /* @conditional-compile-remove(one-to-n-calling) */
|
9637
|
-
const visibleCallingParticipantsSet = new Set(visibleCallingParticipants.current.map((p) => p.userId));
|
9638
|
-
visibleAudioParticipants.current = smartDominantSpeakerParticipants({
|
9639
|
-
participants: (_c = remoteParticipants === null || remoteParticipants === void 0 ? void 0 : remoteParticipants.filter((p) => !visibleVideoParticipantsSet.has(p.userId) &&
|
9640
|
-
/* @conditional-compile-remove(PSTN-calls) */ /* @conditional-compile-remove(one-to-n-calling) */ !visibleCallingParticipantsSet.has(p.userId))) !== null && _c !== void 0 ? _c : [],
|
9641
|
-
dominantSpeakers,
|
9642
|
-
lastVisibleParticipants: visibleAudioParticipants.current,
|
9643
|
-
maxDominantSpeakers: MAX_AUDIO_DOMINANT_SPEAKERS
|
9644
|
-
});
|
9645
9824
|
/* @conditional-compile-remove(rooms) */
|
9646
9825
|
const permissions = _usePermissions();
|
9647
9826
|
/**
|
@@ -9689,65 +9868,16 @@ const VideoGallery = (props) => {
|
|
9689
9868
|
/* @conditional-compile-remove(PSTN-calls) */
|
9690
9869
|
participantState: participant.state })));
|
9691
9870
|
}, [onCreateRemoteStreamView, onDisposeRemoteStreamView, remoteVideoViewOptions, onRenderAvatar, showMuteIndicator]);
|
9692
|
-
const videoTiles = onRenderRemoteVideoTile
|
9693
|
-
? visibleVideoParticipants.current.map((participant) => onRenderRemoteVideoTile(participant))
|
9694
|
-
: visibleVideoParticipants.current.map((participant) => {
|
9695
|
-
return defaultOnRenderVideoTile(participant, true);
|
9696
|
-
});
|
9697
|
-
const audioTiles = onRenderRemoteVideoTile
|
9698
|
-
? visibleAudioParticipants.current.map((participant) => onRenderRemoteVideoTile(participant))
|
9699
|
-
: visibleAudioParticipants.current.map((participant) => {
|
9700
|
-
return defaultOnRenderVideoTile(participant, false);
|
9701
|
-
});
|
9702
|
-
/* @conditional-compile-remove(PSTN-calls) */ /* @conditional-compile-remove(one-to-n-calling) */
|
9703
|
-
const callingTiles = onRenderRemoteVideoTile
|
9704
|
-
? visibleCallingParticipants.current.map((participant) => onRenderRemoteVideoTile(participant))
|
9705
|
-
: visibleCallingParticipants.current.map((participant) => {
|
9706
|
-
return defaultOnRenderVideoTile(participant, false);
|
9707
|
-
});
|
9708
9871
|
const screenShareParticipant = remoteParticipants.find((participant) => { var _a; return (_a = participant.screenShareStream) === null || _a === void 0 ? void 0 : _a.isAvailable; });
|
9709
|
-
const screenShareActive = screenShareParticipant || (localParticipant === null || localParticipant === void 0 ? void 0 : localParticipant.isScreenSharingOn);
|
9710
|
-
const createGridTiles = () => {
|
9711
|
-
/* @conditional-compile-remove(PSTN-calls) */ /* @conditional-compile-remove(one-to-n-calling) */
|
9712
|
-
return videoTiles.length > 0 ? videoTiles : audioTiles.concat(callingTiles);
|
9713
|
-
};
|
9714
|
-
const gridTiles = createGridTiles();
|
9715
|
-
const createHorizontalGalleryTiles = () => {
|
9716
|
-
if (screenShareActive) {
|
9717
|
-
// If screen sharing is active, assign video and audio participants as horizontal gallery participants
|
9718
|
-
/* @conditional-compile-remove(PSTN-calls) */ /* @conditional-compile-remove(one-to-n-calling) */
|
9719
|
-
return videoTiles.concat(audioTiles.concat(callingTiles));
|
9720
|
-
}
|
9721
|
-
else {
|
9722
|
-
// If screen sharing is not active, then assign all video tiles as grid tiles.
|
9723
|
-
// If there are no video tiles, then assign audio tiles as grid tiles.
|
9724
|
-
/* @conditional-compile-remove(PSTN-calls) */ /* @conditional-compile-remove(one-to-n-calling) */
|
9725
|
-
return videoTiles.length > 0 ? audioTiles.concat(callingTiles) : [];
|
9726
|
-
}
|
9727
|
-
};
|
9728
|
-
const horizontalGalleryTiles = createHorizontalGalleryTiles();
|
9729
|
-
if (!shouldFloatLocalVideo && localVideoTile) {
|
9730
|
-
gridTiles.push(localVideoTile);
|
9731
|
-
}
|
9732
9872
|
const localScreenShareStreamComponent = React__default['default'].createElement(LocalScreenShare, { localParticipant: localParticipant });
|
9733
|
-
const remoteScreenShareComponent = screenShareParticipant && (React__default['default'].createElement(RemoteScreenShare, Object.assign({}, screenShareParticipant, { renderElement: (
|
9734
|
-
const
|
9735
|
-
|
9736
|
-
|
9737
|
-
|
9738
|
-
|
9739
|
-
|
9740
|
-
|
9741
|
-
// When we use showCameraSwitcherInLocalPreview it disables dragging to allow keyboard navigation.
|
9742
|
-
shouldFloatNonDraggableLocalVideo && localVideoTile && remoteParticipants.length > 0 && (React__default['default'].createElement(react.Stack, { className: react.mergeStyles(localVideoTileWithControlsContainerStyle(theme, isNarrow), {
|
9743
|
-
boxShadow: theme.effects.elevation8,
|
9744
|
-
zIndex: LOCAL_VIDEO_TILE_ZINDEX
|
9745
|
-
}) }, localVideoTile)),
|
9746
|
-
React__default['default'].createElement(react.Stack, { horizontal: false, styles: videoGalleryContainerStyle },
|
9747
|
-
screenShareParticipant ? (remoteScreenShareComponent) : (localParticipant === null || localParticipant === void 0 ? void 0 : localParticipant.isScreenSharingOn) ? (localScreenShareStreamComponent) : (React__default['default'].createElement(GridLayout, { key: "grid-layout", styles: styles === null || styles === void 0 ? void 0 : styles.gridLayout }, gridTiles)),
|
9748
|
-
horizontalGalleryPresent && (React__default['default'].createElement("div", { style: { paddingTop: '0.5rem' } },
|
9749
|
-
React__default['default'].createElement(ResponsiveHorizontalGallery, { key: "responsive-horizontal-gallery", containerStyles: horizontalGalleryContainerStyle(shouldFloatLocalVideo, isNarrow), horizontalGalleryStyles: react.concatStyleSets(horizontalGalleryStyle(isNarrow), styles === null || styles === void 0 ? void 0 : styles.horizontalGallery), 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 }, horizontalGalleryTiles))),
|
9750
|
-
React__default['default'].createElement(react.LayerHost, { id: layerHostId, className: react.mergeStyles(layerHostStyle) }))));
|
9873
|
+
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 })));
|
9874
|
+
const screenShareComponent = remoteScreenShareComponent
|
9875
|
+
? remoteScreenShareComponent
|
9876
|
+
: localParticipant.isScreenSharingOn
|
9877
|
+
? localScreenShareStreamComponent
|
9878
|
+
: undefined;
|
9879
|
+
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 }));
|
9880
|
+
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));
|
9751
9881
|
};
|
9752
9882
|
|
9753
9883
|
// Copyright (c) Microsoft Corporation.
|
@@ -11446,6 +11576,14 @@ const DialpadContainer = (props) => {
|
|
11446
11576
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
11447
11577
|
onChange: (e) => {
|
11448
11578
|
setText(e.target.value);
|
11579
|
+
},
|
11580
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
11581
|
+
onClick: (e) => {
|
11582
|
+
const input = e.target;
|
11583
|
+
const end = input.value.length;
|
11584
|
+
// Move focus to end of input field
|
11585
|
+
input.setSelectionRange(end, end);
|
11586
|
+
input.focus();
|
11449
11587
|
}, placeholder: props.strings.placeholderText, "data-test-id": "dialpad-input", onRenderSuffix: () => {
|
11450
11588
|
var _a;
|
11451
11589
|
return (React__default['default'].createElement(React__default['default'].Fragment, null, showDeleteButton && plainTextValue.length !== 0 && (React__default['default'].createElement(react.IconButton, { ariaLabel: props.strings.deleteButtonAriaLabel, onClick: deleteNumbers, styles: react.concatStyleSets(iconButtonStyles(theme), (_a = props.styles) === null || _a === void 0 ? void 0 : _a.deleteIcon), iconProps: { iconName: 'DialpadBackspace' } }))));
|
@@ -11809,6 +11947,21 @@ const convertRemoteVideoStreamToVideoGalleryStream = (stream) => {
|
|
11809
11947
|
scalingMode: (_c = stream.view) === null || _c === void 0 ? void 0 : _c.scalingMode
|
11810
11948
|
};
|
11811
11949
|
};
|
11950
|
+
/** @private */
|
11951
|
+
const memoizeLocalParticipant = memoizeOne__default['default']((identifier, displayName, isMuted, isScreenSharingOn, localVideoStream) => {
|
11952
|
+
var _a, _b;
|
11953
|
+
return ({
|
11954
|
+
userId: identifier,
|
11955
|
+
displayName: displayName !== null && displayName !== void 0 ? displayName : '',
|
11956
|
+
isMuted: isMuted,
|
11957
|
+
isScreenSharingOn: isScreenSharingOn,
|
11958
|
+
videoStream: {
|
11959
|
+
isAvailable: !!localVideoStream,
|
11960
|
+
isMirrored: (_a = localVideoStream === null || localVideoStream === void 0 ? void 0 : localVideoStream.view) === null || _a === void 0 ? void 0 : _a.isMirrored,
|
11961
|
+
renderElement: (_b = localVideoStream === null || localVideoStream === void 0 ? void 0 : localVideoStream.view) === null || _b === void 0 ? void 0 : _b.target
|
11962
|
+
}
|
11963
|
+
});
|
11964
|
+
});
|
11812
11965
|
|
11813
11966
|
// Copyright (c) Microsoft Corporation.
|
11814
11967
|
/**
|
@@ -11825,7 +11978,6 @@ const videoGallerySelector = reselect.createSelector([
|
|
11825
11978
|
getIdentifier,
|
11826
11979
|
getDominantSpeakers
|
11827
11980
|
], (screenShareRemoteParticipantId, remoteParticipants, localVideoStreams, isMuted, isScreenSharingOn, displayName, identifier, dominantSpeakers) => {
|
11828
|
-
var _a, _b;
|
11829
11981
|
const screenShareRemoteParticipant = screenShareRemoteParticipantId && remoteParticipants
|
11830
11982
|
? remoteParticipants[screenShareRemoteParticipantId]
|
11831
11983
|
: undefined;
|
@@ -11837,17 +11989,7 @@ const videoGallerySelector = reselect.createSelector([
|
|
11837
11989
|
screenShareParticipant: screenShareRemoteParticipant
|
11838
11990
|
? convertRemoteParticipantToVideoGalleryRemoteParticipant(toFlatCommunicationIdentifier(screenShareRemoteParticipant.identifier), screenShareRemoteParticipant.isMuted, checkIsSpeaking(screenShareRemoteParticipant), screenShareRemoteParticipant.videoStreams, screenShareRemoteParticipant.state, screenShareRemoteParticipant.displayName)
|
11839
11991
|
: undefined,
|
11840
|
-
localParticipant:
|
11841
|
-
userId: identifier,
|
11842
|
-
displayName: displayName !== null && displayName !== void 0 ? displayName : '',
|
11843
|
-
isMuted: isMuted,
|
11844
|
-
isScreenSharingOn: isScreenSharingOn,
|
11845
|
-
videoStream: {
|
11846
|
-
isAvailable: !!localVideoStream,
|
11847
|
-
isMirrored: (_a = localVideoStream === null || localVideoStream === void 0 ? void 0 : localVideoStream.view) === null || _a === void 0 ? void 0 : _a.isMirrored,
|
11848
|
-
renderElement: (_b = localVideoStream === null || localVideoStream === void 0 ? void 0 : localVideoStream.view) === null || _b === void 0 ? void 0 : _b.target
|
11849
|
-
}
|
11850
|
-
},
|
11992
|
+
localParticipant: memoizeLocalParticipant(identifier, displayName, isMuted, isScreenSharingOn, localVideoStream),
|
11851
11993
|
remoteParticipants: _videoGalleryRemoteParticipantsMemo(updateUserDisplayNamesTrampoline$2(remoteParticipants ? Object.values(remoteParticipants) : noRemoteParticipants)),
|
11852
11994
|
dominantSpeakers: dominantSpeakerIds
|
11853
11995
|
};
|