@azure/communication-react 1.4.3-alpha-202212070014.0 → 1.4.3-alpha-202212090014.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 +1292 -1285
- 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/DevicePermissions/DomainPermissionsScaffolding.js +1 -1
- package/dist/dist-esm/react-components/src/components/DevicePermissions/DomainPermissionsScaffolding.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/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/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/videoGalleryUtils.js +5 -1
- package/dist/dist-esm/react-components/src/components/VideoGallery/videoGalleryUtils.js.map +1 -1
- package/dist/dist-esm/react-components/src/components/VideoGallery.js +9 -120
- 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 +3 -138
- 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-202212090014.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
|
@@ -8386,133 +8336,6 @@ const _RemoteVideoTile = React__default['default'].memo((props) => {
|
|
8386
8336
|
participantState: props.participantState }));
|
8387
8337
|
});
|
8388
8338
|
|
8389
|
-
// Copyright (c) Microsoft Corporation.
|
8390
|
-
/**
|
8391
|
-
* @private
|
8392
|
-
*/
|
8393
|
-
const videoGalleryOuterDivStyle = react.mergeStyles({ position: 'relative', width: '100%', height: '100%' });
|
8394
|
-
/**
|
8395
|
-
* @private
|
8396
|
-
*/
|
8397
|
-
const videoGalleryContainerStyle = {
|
8398
|
-
root: { position: 'relative', height: '100%', width: '100%', padding: '0.5rem' }
|
8399
|
-
};
|
8400
|
-
/**
|
8401
|
-
* Small floating modal width and height in rem for small screen
|
8402
|
-
*/
|
8403
|
-
const SMALL_FLOATING_MODAL_SIZE_PX$1 = { width: 64, height: 88 };
|
8404
|
-
/**
|
8405
|
-
* Large floating modal width and height in rem for large screen
|
8406
|
-
*/
|
8407
|
-
const LARGE_FLOATING_MODAL_SIZE_PX$1 = { width: 160, height: 120 };
|
8408
|
-
/**
|
8409
|
-
* @private
|
8410
|
-
* z-index to ensure that the local video tile is above the video gallery.
|
8411
|
-
*/
|
8412
|
-
const LOCAL_VIDEO_TILE_ZINDEX = 2;
|
8413
|
-
/**
|
8414
|
-
* @private
|
8415
|
-
*/
|
8416
|
-
const floatingLocalVideoModalStyle = (theme, isNarrow) => {
|
8417
|
-
return react.concatStyleSets({
|
8418
|
-
main: localVideoTileContainerStyle(theme, isNarrow)
|
8419
|
-
}, {
|
8420
|
-
main: {
|
8421
|
-
boxShadow: theme.effects.elevation8,
|
8422
|
-
':focus-within': {
|
8423
|
-
boxShadow: theme.effects.elevation16,
|
8424
|
-
border: `${_pxToRem(2)} solid ${theme.palette.neutralPrimary}`
|
8425
|
-
}
|
8426
|
-
}
|
8427
|
-
}, localVideoModalStyles);
|
8428
|
-
};
|
8429
|
-
/**
|
8430
|
-
* Padding equal to the amount the modal should stay inside the bounds of the container.
|
8431
|
-
* i.e. if this is 8px, the modal should always be at least 8px inside the container at all times on all sides.
|
8432
|
-
* @private
|
8433
|
-
*/
|
8434
|
-
const localVideoTileOuterPaddingPX = 8;
|
8435
|
-
/**
|
8436
|
-
* @private
|
8437
|
-
*/
|
8438
|
-
const localVideoTileContainerStyle = (theme, isNarrow) => {
|
8439
|
-
return Object.assign({ minWidth: isNarrow ? _pxToRem(SMALL_FLOATING_MODAL_SIZE_PX$1.width) : _pxToRem(LARGE_FLOATING_MODAL_SIZE_PX$1.width), minHeight: isNarrow ? _pxToRem(SMALL_FLOATING_MODAL_SIZE_PX$1.height) : _pxToRem(LARGE_FLOATING_MODAL_SIZE_PX$1.height), position: 'absolute', bottom: _pxToRem(localVideoTileOuterPaddingPX), borderRadius: theme.effects.roundedCorner4, overflow: 'hidden' }, (theme.rtl
|
8440
|
-
? { left: _pxToRem(localVideoTileOuterPaddingPX) }
|
8441
|
-
: { right: _pxToRem(localVideoTileOuterPaddingPX) }));
|
8442
|
-
};
|
8443
|
-
/**
|
8444
|
-
* @private
|
8445
|
-
*/
|
8446
|
-
const localVideoTileWithControlsContainerStyle = (theme, isNarrow) => {
|
8447
|
-
return react.concatStyleSets(localVideoTileContainerStyle(theme, isNarrow), {
|
8448
|
-
root: { boxShadow: theme.effects.elevation8 }
|
8449
|
-
});
|
8450
|
-
};
|
8451
|
-
/**
|
8452
|
-
* @private
|
8453
|
-
*/
|
8454
|
-
const floatingLocalVideoTileStyle = {
|
8455
|
-
root: {
|
8456
|
-
position: 'absolute',
|
8457
|
-
zIndex: LOCAL_VIDEO_TILE_ZINDEX,
|
8458
|
-
height: '100%',
|
8459
|
-
width: '100%'
|
8460
|
-
}
|
8461
|
-
};
|
8462
|
-
/**
|
8463
|
-
* @private
|
8464
|
-
*/
|
8465
|
-
const layerHostStyle = {
|
8466
|
-
position: 'absolute',
|
8467
|
-
left: 0,
|
8468
|
-
top: 0,
|
8469
|
-
width: '100%',
|
8470
|
-
height: '100%',
|
8471
|
-
overflow: 'hidden',
|
8472
|
-
// pointer events for layerHost set to none to make descendants interactive
|
8473
|
-
pointerEvents: 'none'
|
8474
|
-
};
|
8475
|
-
/**
|
8476
|
-
* @private
|
8477
|
-
*/
|
8478
|
-
const localVideoCameraCycleButtonStyles = (theme) => {
|
8479
|
-
return {
|
8480
|
-
root: {
|
8481
|
-
position: 'absolute',
|
8482
|
-
width: _pxToRem(32),
|
8483
|
-
height: _pxToRem(32),
|
8484
|
-
right: '0rem',
|
8485
|
-
top: '0rem',
|
8486
|
-
color: '#FFFFFF',
|
8487
|
-
zIndex: 2,
|
8488
|
-
background: 'rgba(0,0,0,0.4)',
|
8489
|
-
borderRadius: theme.effects.roundedCorner2
|
8490
|
-
},
|
8491
|
-
rootFocused: {
|
8492
|
-
// styles to remove the unwanted white highlight and blue colour after tapping on button.
|
8493
|
-
color: '#FFFFFF',
|
8494
|
-
background: 'rgba(0,0,0,0.4)' // sets opacity of background to be visible on all backdrops in video stream.
|
8495
|
-
},
|
8496
|
-
icon: {
|
8497
|
-
paddingLeft: _pxToRem(3),
|
8498
|
-
paddingRight: _pxToRem(3),
|
8499
|
-
margin: 0
|
8500
|
-
},
|
8501
|
-
flexContainer: {
|
8502
|
-
paddingBottom: _pxToRem(8)
|
8503
|
-
}
|
8504
|
-
};
|
8505
|
-
};
|
8506
|
-
/**
|
8507
|
-
* Styles for the local video tile modal when it is focused, will cause keyboard move icon to appear over video
|
8508
|
-
* @private
|
8509
|
-
*/
|
8510
|
-
const localVideoModalStyles = {
|
8511
|
-
keyboardMoveIconContainer: {
|
8512
|
-
zIndex: LOCAL_VIDEO_TILE_ZINDEX + 1 // zIndex to set the keyboard movement Icon above the other layers in the video tile.
|
8513
|
-
}
|
8514
|
-
};
|
8515
|
-
|
8516
8339
|
// Copyright (c) Microsoft Corporation.
|
8517
8340
|
/**
|
8518
8341
|
* @private
|
@@ -8619,1053 +8442,1323 @@ const LoadingSpinner = (props) => {
|
|
8619
8442
|
};
|
8620
8443
|
|
8621
8444
|
// Copyright (c) Microsoft Corporation.
|
8622
|
-
|
8623
|
-
|
8624
|
-
|
8625
|
-
|
8626
|
-
|
8627
|
-
|
8628
|
-
|
8629
|
-
|
8630
|
-
|
8631
|
-
|
8632
|
-
|
8633
|
-
|
8634
|
-
|
8635
|
-
|
8636
|
-
|
8445
|
+
/**
|
8446
|
+
* @private
|
8447
|
+
*/
|
8448
|
+
const videoGalleryOuterDivStyle = react.mergeStyles({ position: 'relative', width: '100%', height: '100%' });
|
8449
|
+
/**
|
8450
|
+
* @private
|
8451
|
+
*/
|
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
|
+
height: 'unset'
|
8637
8478
|
}
|
8638
|
-
}
|
8639
|
-
else if (ev.ctrlKey) {
|
8640
|
-
delta = 1;
|
8641
|
-
}
|
8642
|
-
return delta;
|
8479
|
+
};
|
8643
8480
|
};
|
8644
|
-
|
8645
|
-
|
8646
|
-
|
8647
|
-
|
8648
|
-
|
8481
|
+
|
8482
|
+
// Copyright (c) Microsoft Corporation.
|
8483
|
+
/**
|
8484
|
+
* local video tile camera cycle button - for use on mobile screens only.
|
8485
|
+
* @internal
|
8486
|
+
*/
|
8487
|
+
const LocalVideoCameraCycleButton = (props) => {
|
8488
|
+
const { cameras, selectedCamera, onSelectCamera, label, ariaDescription } = props;
|
8489
|
+
const theme = react.useTheme();
|
8490
|
+
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: () => {
|
8491
|
+
if (cameras && cameras.length > 1 && selectedCamera !== undefined) {
|
8492
|
+
const index = cameras.findIndex((camera) => selectedCamera.id === camera.id);
|
8493
|
+
const newCamera = cameras[(index + 1) % cameras.length];
|
8494
|
+
if (onSelectCamera !== undefined) {
|
8495
|
+
onSelectCamera(newCamera);
|
8496
|
+
}
|
8649
8497
|
}
|
8650
|
-
}
|
8651
|
-
}), [focusTrapZone]);
|
8498
|
+
} }));
|
8652
8499
|
};
|
8653
|
-
|
8654
|
-
|
8655
|
-
|
8656
|
-
|
8657
|
-
|
8658
|
-
|
8659
|
-
|
8660
|
-
|
8661
|
-
const
|
8662
|
-
const
|
8663
|
-
|
8664
|
-
|
8665
|
-
|
8666
|
-
|
8667
|
-
|
8668
|
-
|
8669
|
-
|
8670
|
-
|
8671
|
-
|
8672
|
-
|
8673
|
-
|
8674
|
-
|
8675
|
-
|
8676
|
-
|
8677
|
-
|
8678
|
-
|
8679
|
-
const
|
8680
|
-
//
|
8681
|
-
|
8682
|
-
|
8683
|
-
|
8684
|
-
|
8685
|
-
isOpen,
|
8686
|
-
isVisible,
|
8687
|
-
hasBeenOpened: internalState.hasBeenOpened,
|
8688
|
-
modalRectangleTop,
|
8689
|
-
topOffsetFixed,
|
8690
|
-
isModeless,
|
8691
|
-
layerClassName,
|
8692
|
-
windowInnerHeight: win === null || win === void 0 ? void 0 : win.innerHeight,
|
8693
|
-
isDefaultDragHandle: dragOptions && !dragOptions.dragHandleSelector
|
8694
|
-
});
|
8695
|
-
const mergedLayerProps = Object.assign(Object.assign({ eventBubblingEnabled: false }, layerProps), { onLayerDidMount: layerProps && layerProps.onLayerDidMount ? layerProps.onLayerDidMount : onLayerDidMount, insertFirst: isModeless, className: classNames.layer });
|
8696
|
-
// Allow the user to scroll within the modal but not on the body
|
8697
|
-
const allowScrollOnModal = React__namespace.useCallback((elt) => {
|
8698
|
-
if (elt) {
|
8699
|
-
if (internalState.allowTouchBodyScroll) {
|
8700
|
-
react.allowOverscrollOnElement(elt, internalState.events);
|
8701
|
-
}
|
8702
|
-
else {
|
8703
|
-
react.allowScrollOnElement(elt, internalState.events);
|
8704
|
-
}
|
8705
|
-
}
|
8706
|
-
else {
|
8707
|
-
internalState.events.off(internalState.scrollableContent);
|
8708
|
-
}
|
8709
|
-
internalState.scrollableContent = elt;
|
8710
|
-
}, [internalState]);
|
8711
|
-
const registerInitialModalPosition = () => {
|
8712
|
-
const dialogMain = focusTrapZoneElm.current;
|
8713
|
-
const modalRectangle = dialogMain === null || dialogMain === void 0 ? void 0 : dialogMain.getBoundingClientRect();
|
8714
|
-
if (modalRectangle) {
|
8715
|
-
if (topOffsetFixed) {
|
8716
|
-
setModalRectangleTop(modalRectangle.top);
|
8717
|
-
}
|
8718
|
-
if (keepInBounds) {
|
8719
|
-
// x/y are unavailable in IE, so use the equivalent left/top
|
8720
|
-
internalState.minPosition = minDragPosition !== null && minDragPosition !== void 0 ? minDragPosition : { x: -modalRectangle.left, y: -modalRectangle.top };
|
8721
|
-
internalState.maxPosition = maxDragPosition !== null && maxDragPosition !== void 0 ? maxDragPosition : { x: modalRectangle.left, y: modalRectangle.top };
|
8722
|
-
// Make sure the initial co-ordinates are within clamp bounds.
|
8723
|
-
setCoordinates({
|
8724
|
-
x: getClampedAxis('x', coordinates.x),
|
8725
|
-
y: getClampedAxis('y', coordinates.y)
|
8726
|
-
});
|
8727
|
-
}
|
8728
|
-
}
|
8729
|
-
};
|
8730
|
-
/**
|
8731
|
-
* Clamps an axis to a specified min and max position.
|
8732
|
-
*
|
8733
|
-
* @param axis A string that represents the axis (x/y).
|
8734
|
-
* @param position The position on the axis.
|
8735
|
-
*/
|
8736
|
-
const getClampedAxis = React__namespace.useCallback((axis, position) => {
|
8737
|
-
const { minPosition, maxPosition } = internalState;
|
8738
|
-
if (keepInBounds && minPosition && maxPosition) {
|
8739
|
-
position = Math.max(minPosition[axis], position);
|
8740
|
-
position = Math.min(maxPosition[axis], position);
|
8741
|
-
}
|
8742
|
-
return position;
|
8743
|
-
}, [keepInBounds, internalState]);
|
8744
|
-
const handleModalClose = () => {
|
8745
|
-
var _a;
|
8746
|
-
internalState.lastSetCoordinates = ZERO;
|
8747
|
-
setModalMenuClose();
|
8748
|
-
internalState.isInKeyboardMoveMode = false;
|
8749
|
-
setIsModalOpen(false);
|
8750
|
-
setCoordinates(ZERO);
|
8751
|
-
(_a = internalState.disposeOnKeyUp) === null || _a === void 0 ? void 0 : _a.call(internalState);
|
8752
|
-
onDismissed === null || onDismissed === void 0 ? void 0 : onDismissed();
|
8753
|
-
};
|
8754
|
-
const handleDragStart = React__namespace.useCallback(() => {
|
8755
|
-
setModalMenuClose();
|
8756
|
-
internalState.isInKeyboardMoveMode = false;
|
8757
|
-
}, [internalState, setModalMenuClose]);
|
8758
|
-
const handleDrag = React__namespace.useCallback(
|
8759
|
-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
8760
|
-
(ev, dragData) => {
|
8761
|
-
setCoordinates((prevValue) => ({
|
8762
|
-
x: getClampedAxis('x', prevValue.x + dragData.delta.x),
|
8763
|
-
y: getClampedAxis('y', prevValue.y + dragData.delta.y)
|
8764
|
-
}));
|
8765
|
-
}, [getClampedAxis]);
|
8766
|
-
const handleDragStop = React__namespace.useCallback(() => {
|
8767
|
-
if (focusTrapZone.current) {
|
8768
|
-
focusTrapZone.current.focus();
|
8769
|
-
}
|
8770
|
-
}, []);
|
8771
|
-
const handleEnterKeyboardMoveMode = () => {
|
8772
|
-
// We need a global handleKeyDown event when we are in the move mode so that we can
|
8773
|
-
// handle the key presses and the components inside the modal do not get the events
|
8774
|
-
const handleKeyDown = (ev) => {
|
8775
|
-
if (ev.altKey && ev.ctrlKey && ev.keyCode === react.KeyCodes.space) {
|
8776
|
-
// CTRL + ALT + SPACE is handled during keyUp
|
8777
|
-
ev.preventDefault();
|
8778
|
-
ev.stopPropagation();
|
8779
|
-
return;
|
8780
|
-
}
|
8781
|
-
const newLocal = ev.altKey || ev.keyCode === react.KeyCodes.escape;
|
8782
|
-
if (isModalMenuOpen && newLocal) {
|
8783
|
-
setModalMenuClose();
|
8784
|
-
}
|
8785
|
-
if (internalState.isInKeyboardMoveMode && (ev.keyCode === react.KeyCodes.escape || ev.keyCode === react.KeyCodes.enter)) {
|
8786
|
-
internalState.isInKeyboardMoveMode = false;
|
8787
|
-
ev.preventDefault();
|
8788
|
-
ev.stopPropagation();
|
8789
|
-
}
|
8790
|
-
if (internalState.isInKeyboardMoveMode) {
|
8791
|
-
let handledEvent = true;
|
8792
|
-
const delta = getMoveDelta(ev);
|
8793
|
-
switch (ev.keyCode) {
|
8794
|
-
/* eslint-disable no-fallthrough */
|
8795
|
-
case react.KeyCodes.escape:
|
8796
|
-
setCoordinates(internalState.lastSetCoordinates);
|
8797
|
-
case react.KeyCodes.enter: {
|
8798
|
-
// TODO: determine if fallthrough was intentional
|
8799
|
-
/* eslint-enable no-fallthrough */
|
8800
|
-
internalState.lastSetCoordinates = ZERO;
|
8801
|
-
// setIsInKeyboardMoveMode(false);
|
8802
|
-
break;
|
8803
|
-
}
|
8804
|
-
case react.KeyCodes.up: {
|
8805
|
-
setCoordinates((prevValue) => ({ x: prevValue.x, y: getClampedAxis('y', prevValue.y - delta) }));
|
8806
|
-
break;
|
8807
|
-
}
|
8808
|
-
case react.KeyCodes.down: {
|
8809
|
-
setCoordinates((prevValue) => ({ x: prevValue.x, y: getClampedAxis('y', prevValue.y + delta) }));
|
8810
|
-
break;
|
8811
|
-
}
|
8812
|
-
case react.KeyCodes.left: {
|
8813
|
-
setCoordinates((prevValue) => ({ x: getClampedAxis('x', prevValue.x - delta), y: prevValue.y }));
|
8814
|
-
break;
|
8815
|
-
}
|
8816
|
-
case react.KeyCodes.right: {
|
8817
|
-
setCoordinates((prevValue) => ({ x: getClampedAxis('x', prevValue.x + delta), y: prevValue.y }));
|
8818
|
-
break;
|
8819
|
-
}
|
8820
|
-
default: {
|
8821
|
-
handledEvent = false;
|
8822
|
-
}
|
8823
|
-
}
|
8824
|
-
if (handledEvent) {
|
8825
|
-
ev.preventDefault();
|
8826
|
-
ev.stopPropagation();
|
8827
|
-
}
|
8828
|
-
}
|
8829
|
-
};
|
8830
|
-
internalState.lastSetCoordinates = coordinates;
|
8831
|
-
setModalMenuClose();
|
8832
|
-
internalState.isInKeyboardMoveMode = true;
|
8833
|
-
internalState.events.on(win, 'keydown', handleKeyDown, true /* useCapture */);
|
8834
|
-
internalState.disposeOnKeyDown = () => {
|
8835
|
-
internalState.events.off(win, 'keydown', handleKeyDown, true /* useCapture */);
|
8836
|
-
internalState.disposeOnKeyDown = undefined;
|
8837
|
-
};
|
8838
|
-
};
|
8839
|
-
const handleExitKeyboardMoveMode = () => {
|
8840
|
-
var _a;
|
8841
|
-
internalState.lastSetCoordinates = ZERO;
|
8842
|
-
internalState.isInKeyboardMoveMode = false;
|
8843
|
-
(_a = internalState.disposeOnKeyDown) === null || _a === void 0 ? void 0 : _a.call(internalState);
|
8844
|
-
};
|
8845
|
-
const registerForKeyUp = () => {
|
8846
|
-
const handleKeyUp = (ev) => {
|
8847
|
-
// Needs to handle the CTRL + ALT + SPACE key during keyup due to FireFox bug:
|
8848
|
-
// https://bugzilla.mozilla.org/show_bug.cgi?id=1220143
|
8849
|
-
if (ev.altKey && ev.ctrlKey && ev.keyCode === react.KeyCodes.space) {
|
8850
|
-
if (react.elementContains(internalState.scrollableContent, ev.target)) {
|
8851
|
-
toggleModalMenuOpen();
|
8852
|
-
ev.preventDefault();
|
8853
|
-
ev.stopPropagation();
|
8854
|
-
}
|
8855
|
-
}
|
8856
|
-
};
|
8857
|
-
if (!internalState.disposeOnKeyUp) {
|
8858
|
-
internalState.events.on(win, 'keyup', handleKeyUp, true /* useCapture */);
|
8859
|
-
internalState.disposeOnKeyUp = () => {
|
8860
|
-
internalState.events.off(win, 'keyup', handleKeyUp, true /* useCapture */);
|
8861
|
-
internalState.disposeOnKeyUp = undefined;
|
8862
|
-
};
|
8500
|
+
|
8501
|
+
// Copyright (c) Microsoft Corporation.
|
8502
|
+
/**
|
8503
|
+
* A memoized version of VideoTile for rendering local participant.
|
8504
|
+
*
|
8505
|
+
* @internal
|
8506
|
+
*/
|
8507
|
+
const _LocalVideoTile = React__default['default'].memo((props) => {
|
8508
|
+
const { isAvailable, isMuted, onCreateLocalStreamView, onDisposeLocalStreamView, localVideoViewOptions, renderElement, userId, showLabel, displayName, initialsName, onRenderAvatar, showMuteIndicator, styles, showCameraSwitcherInLocalPreview, localVideoCameraCycleButtonProps, localVideoCameraSwitcherLabel, localVideoSelectedDescription } = props;
|
8509
|
+
const localVideoStreamProps = React.useMemo(() => ({
|
8510
|
+
isMirrored: localVideoViewOptions === null || localVideoViewOptions === void 0 ? void 0 : localVideoViewOptions.isMirrored,
|
8511
|
+
isStreamAvailable: isAvailable,
|
8512
|
+
onCreateLocalStreamView,
|
8513
|
+
onDisposeLocalStreamView,
|
8514
|
+
renderElementExists: !!renderElement,
|
8515
|
+
scalingMode: localVideoViewOptions === null || localVideoViewOptions === void 0 ? void 0 : localVideoViewOptions.scalingMode
|
8516
|
+
}), [
|
8517
|
+
isAvailable,
|
8518
|
+
localVideoViewOptions === null || localVideoViewOptions === void 0 ? void 0 : localVideoViewOptions.isMirrored,
|
8519
|
+
localVideoViewOptions === null || localVideoViewOptions === void 0 ? void 0 : localVideoViewOptions.scalingMode,
|
8520
|
+
onCreateLocalStreamView,
|
8521
|
+
onDisposeLocalStreamView,
|
8522
|
+
renderElement
|
8523
|
+
]);
|
8524
|
+
// Handle creating, destroying and updating the video stream as necessary
|
8525
|
+
useLocalVideoStreamLifecycleMaintainer(localVideoStreamProps);
|
8526
|
+
const renderVideoStreamElement = React.useMemo(() => {
|
8527
|
+
// Checking if renderElement is well defined or not as calling SDK has a number of video streams limitation which
|
8528
|
+
// implies that, after their threshold, all streams have no child (blank video)
|
8529
|
+
if (!renderElement || !renderElement.childElementCount) {
|
8530
|
+
// Returning `undefined` results in the placeholder with avatar being shown
|
8531
|
+
return undefined;
|
8863
8532
|
}
|
8533
|
+
return (React__default['default'].createElement(React__default['default'].Fragment, null,
|
8534
|
+
React__default['default'].createElement(FloatingLocalCameraCycleButton, { showCameraSwitcherInLocalPreview: showCameraSwitcherInLocalPreview !== null && showCameraSwitcherInLocalPreview !== void 0 ? showCameraSwitcherInLocalPreview : false, localVideoCameraCycleButtonProps: localVideoCameraCycleButtonProps, localVideoCameraSwitcherLabel: localVideoCameraSwitcherLabel, localVideoSelectedDescription: localVideoSelectedDescription }),
|
8535
|
+
React__default['default'].createElement(StreamMedia, { videoStreamElement: renderElement, isMirrored: true })));
|
8536
|
+
}, [
|
8537
|
+
localVideoCameraCycleButtonProps,
|
8538
|
+
localVideoCameraSwitcherLabel,
|
8539
|
+
localVideoSelectedDescription,
|
8540
|
+
renderElement,
|
8541
|
+
showCameraSwitcherInLocalPreview
|
8542
|
+
]);
|
8543
|
+
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 }));
|
8544
|
+
});
|
8545
|
+
const FloatingLocalCameraCycleButton = (props) => {
|
8546
|
+
const { showCameraSwitcherInLocalPreview, localVideoCameraCycleButtonProps, localVideoCameraSwitcherLabel, localVideoSelectedDescription } = props;
|
8547
|
+
const ariaDescription = (localVideoCameraCycleButtonProps === null || localVideoCameraCycleButtonProps === void 0 ? void 0 : localVideoCameraCycleButtonProps.selectedCamera) &&
|
8548
|
+
localVideoSelectedDescription &&
|
8549
|
+
_formatString(localVideoSelectedDescription, {
|
8550
|
+
cameraName: localVideoCameraCycleButtonProps.selectedCamera.name
|
8551
|
+
});
|
8552
|
+
return (React__default['default'].createElement(react.Stack, { horizontalAlign: "end" }, showCameraSwitcherInLocalPreview &&
|
8553
|
+
(localVideoCameraCycleButtonProps === null || localVideoCameraCycleButtonProps === void 0 ? void 0 : localVideoCameraCycleButtonProps.cameras) !== undefined &&
|
8554
|
+
(localVideoCameraCycleButtonProps === null || localVideoCameraCycleButtonProps === void 0 ? void 0 : localVideoCameraCycleButtonProps.selectedCamera) !== undefined &&
|
8555
|
+
(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 }))));
|
8556
|
+
};
|
8557
|
+
|
8558
|
+
// Copyright (c) Microsoft Corporation.
|
8559
|
+
// Licensed under the MIT license.
|
8560
|
+
/**
|
8561
|
+
* @private
|
8562
|
+
*/
|
8563
|
+
const rootLayoutStyle$1 = {
|
8564
|
+
root: { position: 'relative', height: '100%', width: '100%', padding: '0.5rem' }
|
8565
|
+
};
|
8566
|
+
|
8567
|
+
// Copyright (c) Microsoft Corporation.
|
8568
|
+
// Licensed under the MIT license.
|
8569
|
+
/**
|
8570
|
+
* Horizontal Gallery button width in rem
|
8571
|
+
*/
|
8572
|
+
const HORIZONTAL_GALLERY_BUTTON_WIDTH = 1.75;
|
8573
|
+
/**
|
8574
|
+
* @private
|
8575
|
+
*/
|
8576
|
+
const leftRightButtonStyles = (theme) => {
|
8577
|
+
return {
|
8578
|
+
background: 'none',
|
8579
|
+
padding: 0,
|
8580
|
+
height: 'auto',
|
8581
|
+
minWidth: `${HORIZONTAL_GALLERY_BUTTON_WIDTH}rem`,
|
8582
|
+
maxWidth: `${HORIZONTAL_GALLERY_BUTTON_WIDTH}rem`,
|
8583
|
+
border: `1px solid ${theme.palette.neutralLight}`,
|
8584
|
+
borderRadius: theme.effects.roundedCorner4
|
8864
8585
|
};
|
8865
|
-
|
8866
|
-
|
8867
|
-
|
8868
|
-
|
8869
|
-
|
8870
|
-
|
8871
|
-
|
8872
|
-
|
8873
|
-
|
8874
|
-
|
8875
|
-
|
8876
|
-
|
8877
|
-
|
8878
|
-
|
8879
|
-
|
8880
|
-
|
8881
|
-
|
8882
|
-
|
8883
|
-
|
8884
|
-
|
8885
|
-
|
8886
|
-
|
8887
|
-
|
8586
|
+
};
|
8587
|
+
/**
|
8588
|
+
* Horizontal Gallery gap size in rem between tiles and buttons
|
8589
|
+
*/
|
8590
|
+
const HORIZONTAL_GALLERY_GAP = 0.5;
|
8591
|
+
/**
|
8592
|
+
* @private
|
8593
|
+
*/
|
8594
|
+
const rootStyle = {
|
8595
|
+
height: '100%',
|
8596
|
+
width: '100%',
|
8597
|
+
gap: `${HORIZONTAL_GALLERY_GAP}rem`
|
8598
|
+
};
|
8599
|
+
/**
|
8600
|
+
* @private
|
8601
|
+
*/
|
8602
|
+
const childrenContainerStyle = {
|
8603
|
+
height: '100%',
|
8604
|
+
gap: `${HORIZONTAL_GALLERY_GAP}rem`
|
8605
|
+
};
|
8606
|
+
|
8607
|
+
// Copyright (c) Microsoft Corporation.
|
8608
|
+
/**
|
8609
|
+
* {@link HorizontalGallery} default children per page
|
8610
|
+
*/
|
8611
|
+
const DEFAULT_CHILDREN_PER_PAGE = 5;
|
8612
|
+
/**
|
8613
|
+
* Renders a horizontal gallery that parents children horizontally. Handles pagination based on the childrenPerPage prop.
|
8614
|
+
* @param props - HorizontalGalleryProps {@link @azure/communication-react#HorizontalGalleryProps}
|
8615
|
+
* @returns
|
8616
|
+
*/
|
8617
|
+
const HorizontalGallery = (props) => {
|
8618
|
+
var _a, _b;
|
8619
|
+
const { children, childrenPerPage = DEFAULT_CHILDREN_PER_PAGE, styles } = props;
|
8620
|
+
const ids = useIdentifiers();
|
8621
|
+
const [page, setPage] = React.useState(0);
|
8622
|
+
const numberOfChildren = React__default['default'].Children.count(children);
|
8623
|
+
const lastPage = Math.ceil(numberOfChildren / childrenPerPage) - 1;
|
8624
|
+
const paginatedChildren = React.useMemo(() => {
|
8625
|
+
return bucketize(React__default['default'].Children.toArray(children), childrenPerPage);
|
8626
|
+
}, [children, childrenPerPage]);
|
8627
|
+
// If children per page is 0 or less return empty element
|
8628
|
+
if (childrenPerPage <= 0) {
|
8629
|
+
return React__default['default'].createElement(React__default['default'].Fragment, null);
|
8630
|
+
}
|
8631
|
+
const firstIndexOfCurrentPage = page * childrenPerPage;
|
8632
|
+
const clippedPage = firstIndexOfCurrentPage < numberOfChildren - 1 ? page : lastPage;
|
8633
|
+
const childrenOnCurrentPage = paginatedChildren[clippedPage];
|
8634
|
+
const showButtons = numberOfChildren > childrenPerPage;
|
8635
|
+
const disablePreviousButton = page === 0;
|
8636
|
+
const disableNextButton = page === lastPage;
|
8637
|
+
return (React__default['default'].createElement(react.Stack, { horizontal: true, className: react.mergeStyles(rootStyle, (_a = props.styles) === null || _a === void 0 ? void 0 : _a.root) },
|
8638
|
+
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 })),
|
8639
|
+
React__default['default'].createElement(react.Stack, { horizontal: true, className: react.mergeStyles(childrenContainerStyle, { '> *': (_b = props.styles) === null || _b === void 0 ? void 0 : _b.children }) }, childrenOnCurrentPage),
|
8640
|
+
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 }))));
|
8641
|
+
};
|
8642
|
+
const HorizontalGalleryNavigationButton = (props) => {
|
8643
|
+
const theme = useTheme();
|
8644
|
+
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));
|
8645
|
+
};
|
8646
|
+
function bucketize(arr, bucketSize) {
|
8647
|
+
const bucketArray = [];
|
8648
|
+
if (bucketSize <= 0) {
|
8649
|
+
return bucketArray;
|
8650
|
+
}
|
8651
|
+
for (let i = 0; i < arr.length; i += bucketSize) {
|
8652
|
+
bucketArray.push(arr.slice(i, i + bucketSize));
|
8653
|
+
}
|
8654
|
+
return bucketArray;
|
8655
|
+
}
|
8656
|
+
|
8657
|
+
// Copyright (c) Microsoft Corporation.
|
8658
|
+
/**
|
8659
|
+
* Wrapped HorizontalGallery that adjusts the number of items per page based on the
|
8660
|
+
* available width obtained from a ResizeObserver, width per child, gap width, and button width
|
8661
|
+
*/
|
8662
|
+
const ResponsiveHorizontalGallery = (props) => {
|
8663
|
+
const { childWidthRem, gapWidthRem, buttonWidthRem = 0 } = props;
|
8664
|
+
const containerRef = React.useRef(null);
|
8665
|
+
const containerWidth = _useContainerWidth(containerRef);
|
8666
|
+
const leftPadding = containerRef.current ? parseFloat(getComputedStyle(containerRef.current).paddingLeft) : 0;
|
8667
|
+
const rightPadding = containerRef.current ? parseFloat(getComputedStyle(containerRef.current).paddingRight) : 0;
|
8668
|
+
const childrenPerPage = calculateChildrenPerPage({
|
8669
|
+
numberOfChildren: React__default['default'].Children.count(props.children),
|
8670
|
+
containerWidth: (containerWidth !== null && containerWidth !== void 0 ? containerWidth : 0) - leftPadding - rightPadding,
|
8671
|
+
childWidthRem,
|
8672
|
+
gapWidthRem,
|
8673
|
+
buttonWidthRem
|
8888
8674
|
});
|
8889
|
-
|
8890
|
-
|
8891
|
-
|
8892
|
-
|
8893
|
-
|
8894
|
-
|
8895
|
-
|
8896
|
-
|
8897
|
-
|
8898
|
-
|
8899
|
-
|
8900
|
-
|
8901
|
-
|
8902
|
-
|
8903
|
-
|
8904
|
-
|
8905
|
-
|
8906
|
-
|
8907
|
-
|
8908
|
-
|
8909
|
-
|
8910
|
-
|
8675
|
+
return (React__default['default'].createElement("div", { ref: containerRef, className: react.mergeStyles(props.containerStyles) },
|
8676
|
+
React__default['default'].createElement(HorizontalGallery, { childrenPerPage: childrenPerPage, styles: props.horizontalGalleryStyles }, props.children)));
|
8677
|
+
};
|
8678
|
+
/**
|
8679
|
+
* Helper function to calculate children per page for HorizontalGallery based on width of container, child, buttons, and
|
8680
|
+
* gaps in between
|
8681
|
+
*/
|
8682
|
+
const calculateChildrenPerPage = (args) => {
|
8683
|
+
const { numberOfChildren, containerWidth, buttonWidthRem, childWidthRem, gapWidthRem } = args;
|
8684
|
+
const childWidth = _convertRemToPx(childWidthRem);
|
8685
|
+
const gapWidth = _convertRemToPx(gapWidthRem);
|
8686
|
+
/** First check how many children can fit in containerWidth.
|
8687
|
+
* __________________________________
|
8688
|
+
* | || |
|
8689
|
+
* | || |
|
8690
|
+
* |________________||________________|
|
8691
|
+
* <-----------containerWidth--------->
|
8692
|
+
* containerWidth = n * childWidth + (n - 1) * gapWidth. Isolate n and take the floor.
|
8693
|
+
*/
|
8694
|
+
const numberOfChildrenInContainer = Math.floor((containerWidth + gapWidth) / (childWidth + gapWidth));
|
8695
|
+
// If all children fit then return numberOfChildrenInContainer
|
8696
|
+
if (numberOfChildren <= numberOfChildrenInContainer) {
|
8697
|
+
return numberOfChildrenInContainer;
|
8698
|
+
}
|
8699
|
+
const buttonWidth = _convertRemToPx(buttonWidthRem);
|
8700
|
+
/** We know we need to paginate. So we need to subtract the buttonWidth twice and gapWidth twice from
|
8701
|
+
* containerWidth to compute childrenSpace
|
8702
|
+
* <-----------containerWidth--------->
|
8703
|
+
* __________________________________
|
8704
|
+
* | || || || |
|
8705
|
+
* |<|| || ||>|
|
8706
|
+
* |_||_____________||_____________||_|
|
8707
|
+
* <-------childrenSpace------>
|
8708
|
+
*/
|
8709
|
+
const childrenSpace = containerWidth - 2 * buttonWidth - 2 * gapWidth;
|
8710
|
+
// Now that we have childrenSpace width we can figure out how many children can fit in childrenSpace.
|
8711
|
+
// childrenSpace = n * childWidth + (n - 1) * gapWidth. Isolate n and take the floor.
|
8712
|
+
return Math.floor((childrenSpace + gapWidth) / (childWidth + gapWidth));
|
8713
|
+
};
|
8714
|
+
|
8715
|
+
// Copyright (c) Microsoft Corporation.
|
8716
|
+
/**
|
8717
|
+
* Small floating modal width and height in rem for small screen
|
8718
|
+
*/
|
8719
|
+
const SMALL_FLOATING_MODAL_SIZE_PX$1 = { width: 64, height: 88 };
|
8720
|
+
/**
|
8721
|
+
* Large floating modal width and height in rem for large screen
|
8722
|
+
*/
|
8723
|
+
const LARGE_FLOATING_MODAL_SIZE_PX$1 = { width: 160, height: 120 };
|
8724
|
+
/**
|
8725
|
+
* @private
|
8726
|
+
*/
|
8727
|
+
const horizontalGalleryContainerStyle = (shouldFloatLocalVideo, isNarrow) => {
|
8911
8728
|
return {
|
8912
|
-
|
8913
|
-
|
8914
|
-
|
8915
|
-
|
8916
|
-
|
8917
|
-
}
|
8918
|
-
|
8919
|
-
|
8729
|
+
minHeight: isNarrow
|
8730
|
+
? `${SMALL_HORIZONTAL_GALLERY_TILE_SIZE_REM.height}rem`
|
8731
|
+
: `${LARGE_HORIZONTAL_GALLERY_TILE_SIZE_REM.height}rem`,
|
8732
|
+
width: shouldFloatLocalVideo
|
8733
|
+
? isNarrow
|
8734
|
+
? `calc(100% - ${_pxToRem(SMALL_FLOATING_MODAL_SIZE_PX$1.width)})`
|
8735
|
+
: `calc(100% - ${_pxToRem(LARGE_FLOATING_MODAL_SIZE_PX$1.width)})`
|
8736
|
+
: '100%',
|
8737
|
+
paddingRight: '0.5rem'
|
8920
8738
|
};
|
8921
|
-
});
|
8922
|
-
const eventMapping = {
|
8923
|
-
touch: {
|
8924
|
-
start: 'touchstart',
|
8925
|
-
move: 'touchmove',
|
8926
|
-
stop: 'touchend'
|
8927
|
-
},
|
8928
|
-
mouse: {
|
8929
|
-
start: 'mousedown',
|
8930
|
-
move: 'mousemove',
|
8931
|
-
stop: 'mouseup'
|
8932
|
-
}
|
8933
8739
|
};
|
8934
|
-
|
8935
|
-
|
8936
|
-
|
8937
|
-
|
8938
|
-
|
8939
|
-
|
8940
|
-
|
8941
|
-
|
8942
|
-
|
8943
|
-
|
8944
|
-
|
8945
|
-
|
8946
|
-
|
8947
|
-
|
8948
|
-
|
8949
|
-
|
8950
|
-
|
8951
|
-
|
8952
|
-
|
8953
|
-
|
8954
|
-
|
8955
|
-
|
8956
|
-
|
8957
|
-
|
8958
|
-
|
8959
|
-
|
8960
|
-
|
8961
|
-
|
8962
|
-
|
8963
|
-
|
8964
|
-
|
8965
|
-
|
8966
|
-
|
8967
|
-
|
8968
|
-
|
8969
|
-
|
8970
|
-
|
8971
|
-
|
8972
|
-
|
8973
|
-
|
8974
|
-
|
8975
|
-
|
8976
|
-
|
8977
|
-
|
8978
|
-
|
8979
|
-
|
8980
|
-
|
8981
|
-
|
8982
|
-
|
8983
|
-
|
8984
|
-
|
8985
|
-
|
8986
|
-
|
8987
|
-
|
8988
|
-
|
8989
|
-
|
8990
|
-
|
8991
|
-
|
8992
|
-
|
8993
|
-
|
8994
|
-
isDragging: true,
|
8995
|
-
lastPosition: position
|
8996
|
-
});
|
8997
|
-
// hook up the appropriate mouse/touch events to the body to ensure
|
8998
|
-
// smooth dragging
|
8999
|
-
this._events = [
|
9000
|
-
react.on(document.body, this._currentEventType.move, this._onDrag, true /* use capture phase */),
|
9001
|
-
react.on(document.body, this._currentEventType.stop, this._onDragStop, true /* use capture phase */)
|
9002
|
-
];
|
9003
|
-
return;
|
9004
|
-
};
|
9005
|
-
this._onDrag = (event) => {
|
9006
|
-
// Prevent scrolling on mobile devices
|
9007
|
-
if (event.type === 'touchmove') {
|
9008
|
-
event.preventDefault();
|
9009
|
-
}
|
9010
|
-
const position = this._getControlPosition(event);
|
9011
|
-
if (!position) {
|
9012
|
-
return;
|
9013
|
-
}
|
9014
|
-
// create the updated drag data from the position data
|
9015
|
-
const updatedData = this._createUpdatedDragData(this._createDragDataFromPosition(position));
|
9016
|
-
const updatedPosition = updatedData.position;
|
9017
|
-
this.props.onDragChange && this.props.onDragChange(event, updatedData);
|
9018
|
-
this.setState({
|
9019
|
-
position: updatedPosition,
|
9020
|
-
lastPosition: position
|
9021
|
-
});
|
9022
|
-
};
|
9023
|
-
this._onDragStop = (event) => {
|
9024
|
-
if (!this.state.isDragging) {
|
9025
|
-
return;
|
9026
|
-
}
|
9027
|
-
const position = this._getControlPosition(event);
|
9028
|
-
if (!position) {
|
9029
|
-
return;
|
9030
|
-
}
|
9031
|
-
const baseDragData = this._createDragDataFromPosition(position);
|
9032
|
-
// Set dragging to false and reset the lastPosition
|
9033
|
-
this.setState({
|
9034
|
-
isDragging: false,
|
9035
|
-
lastPosition: undefined
|
9036
|
-
});
|
9037
|
-
this.props.onStop && this.props.onStop(event, baseDragData);
|
9038
|
-
if (this.props.position) {
|
9039
|
-
this.setState({
|
9040
|
-
position: this.props.position
|
9041
|
-
});
|
9042
|
-
}
|
9043
|
-
// Remove event handlers
|
9044
|
-
this._events.forEach((dispose) => dispose());
|
9045
|
-
};
|
9046
|
-
this.state = {
|
9047
|
-
isDragging: false,
|
9048
|
-
position: this.props.position || { x: 0, y: 0 },
|
9049
|
-
lastPosition: undefined
|
9050
|
-
};
|
8740
|
+
/**
|
8741
|
+
* @private
|
8742
|
+
*/
|
8743
|
+
const horizontalGalleryStyle = (isNarrow) => {
|
8744
|
+
return {
|
8745
|
+
children: isNarrow ? SMALL_HORIZONTAL_GALLERY_TILE_STYLE : LARGE_HORIZONTAL_GALLERY_TILE_STYLE
|
8746
|
+
};
|
8747
|
+
};
|
8748
|
+
/**
|
8749
|
+
* Small horizontal gallery tile size in rem
|
8750
|
+
* @private
|
8751
|
+
*/
|
8752
|
+
const SMALL_HORIZONTAL_GALLERY_TILE_SIZE_REM = { height: 5.5, width: 5.5 };
|
8753
|
+
/**
|
8754
|
+
* Large horizontal gallery tile size in rem
|
8755
|
+
* @private
|
8756
|
+
*/
|
8757
|
+
const LARGE_HORIZONTAL_GALLERY_TILE_SIZE_REM = { height: 7.5, width: 10 };
|
8758
|
+
/**
|
8759
|
+
* @private
|
8760
|
+
*/
|
8761
|
+
const SMALL_HORIZONTAL_GALLERY_TILE_STYLE = {
|
8762
|
+
minHeight: `${SMALL_HORIZONTAL_GALLERY_TILE_SIZE_REM.height}rem`,
|
8763
|
+
minWidth: `${SMALL_HORIZONTAL_GALLERY_TILE_SIZE_REM.width}rem`,
|
8764
|
+
maxHeight: `${SMALL_HORIZONTAL_GALLERY_TILE_SIZE_REM.height}rem`,
|
8765
|
+
maxWidth: `${SMALL_HORIZONTAL_GALLERY_TILE_SIZE_REM.width}rem`
|
8766
|
+
};
|
8767
|
+
/**
|
8768
|
+
* @private
|
8769
|
+
*/
|
8770
|
+
const LARGE_HORIZONTAL_GALLERY_TILE_STYLE = {
|
8771
|
+
minHeight: `${LARGE_HORIZONTAL_GALLERY_TILE_SIZE_REM.height}rem`,
|
8772
|
+
minWidth: `${LARGE_HORIZONTAL_GALLERY_TILE_SIZE_REM.width}rem`,
|
8773
|
+
maxHeight: `${LARGE_HORIZONTAL_GALLERY_TILE_SIZE_REM.height}rem`,
|
8774
|
+
maxWidth: `${LARGE_HORIZONTAL_GALLERY_TILE_SIZE_REM.width}rem`
|
8775
|
+
};
|
8776
|
+
|
8777
|
+
// Copyright (c) Microsoft Corporation.
|
8778
|
+
/**
|
8779
|
+
* A ResponsiveHorizontalGallery styled for the @link{VideoGallery}
|
8780
|
+
*/
|
8781
|
+
const VideoGalleryResponsiveHorizontalGallery = (props) => {
|
8782
|
+
const { shouldFloatLocalVideo = false, isNarrow = false, horizontalGalleryElements, styles } = props;
|
8783
|
+
const containerStyles = React.useMemo(() => horizontalGalleryContainerStyle(shouldFloatLocalVideo, isNarrow), [shouldFloatLocalVideo, isNarrow]);
|
8784
|
+
const galleryStyles = React.useMemo(() => react.concatStyleSets(horizontalGalleryStyle(isNarrow), styles), [isNarrow, styles]);
|
8785
|
+
return (React__default['default'].createElement(react.Stack, { styles: { root: { paddingTop: '0.5rem' } } },
|
8786
|
+
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)));
|
8787
|
+
};
|
8788
|
+
|
8789
|
+
/**
|
8790
|
+
* Calculates the participants that should be rendered based on the list of dominant
|
8791
|
+
* speakers and currently rendered participants in a call.
|
8792
|
+
* @param args - SmartDominantSpeakerParticipantsArgs
|
8793
|
+
* @returns VideoGalleryRemoteParticipant[] {@link @azure/communication-react#VideoGalleryRemoteParticipant}
|
8794
|
+
*/
|
8795
|
+
const smartDominantSpeakerParticipants = (args) => {
|
8796
|
+
const { participants, dominantSpeakers = [], lastVisibleParticipants = [], maxDominantSpeakers } = args;
|
8797
|
+
// Don't apply any logic if total number of video streams is less than max dominant speakers.
|
8798
|
+
if (participants.length <= maxDominantSpeakers) {
|
8799
|
+
return participants;
|
9051
8800
|
}
|
9052
|
-
|
9053
|
-
|
9054
|
-
|
8801
|
+
const participantsMap = participantsById(participants);
|
8802
|
+
// Only use the Max allowed dominant speakers that exist in participants
|
8803
|
+
const dominantSpeakerIds = Array.from(new Set(dominantSpeakers).values())
|
8804
|
+
.filter((id) => !!participantsMap[id])
|
8805
|
+
.slice(0, maxDominantSpeakers);
|
8806
|
+
const lastVisibleParticipantIds = lastVisibleParticipants.map((p) => p.userId);
|
8807
|
+
const newVisibleParticipantIds = lastVisibleParticipants.map((p) => p.userId).slice(0, maxDominantSpeakers);
|
8808
|
+
const newDominantSpeakerIds = dominantSpeakerIds.filter((id) => !newVisibleParticipantIds.includes(id));
|
8809
|
+
// Remove participants that are no longer dominant and replace them with new dominant speakers.
|
8810
|
+
for (let index = 0; index < maxDominantSpeakers; index++) {
|
8811
|
+
const newVisibleParticipantId = newVisibleParticipantIds[index];
|
8812
|
+
if (newVisibleParticipantId === undefined || !dominantSpeakerIds.includes(newVisibleParticipantId)) {
|
8813
|
+
const replacement = newDominantSpeakerIds.shift();
|
8814
|
+
if (!replacement) {
|
8815
|
+
break;
|
8816
|
+
}
|
8817
|
+
newVisibleParticipantIds[index] = replacement;
|
9055
8818
|
}
|
9056
8819
|
}
|
9057
|
-
|
9058
|
-
|
9059
|
-
|
9060
|
-
|
9061
|
-
|
9062
|
-
|
9063
|
-
|
9064
|
-
|
9065
|
-
|
9066
|
-
|
9067
|
-
|
9068
|
-
|
9069
|
-
|
8820
|
+
const removedVisibleParticipantIds = lastVisibleParticipantIds.filter((p) => !newVisibleParticipantIds.includes(p));
|
8821
|
+
removedVisibleParticipantIds.forEach((p) => newVisibleParticipantIds.push(p));
|
8822
|
+
const newVisibleParticipantIdSet = new Set(newVisibleParticipantIds);
|
8823
|
+
const leftoverParticipants = participants.filter((p) => !newVisibleParticipantIdSet.has(p.userId));
|
8824
|
+
leftoverParticipants.forEach((p) => {
|
8825
|
+
newVisibleParticipantIds.push(p.userId);
|
8826
|
+
});
|
8827
|
+
// newVisibleParticipantIds can contain identifiers for participants that are no longer in the call. So we ignore those IDs.
|
8828
|
+
const newVisibleParticipants = newVisibleParticipantIds
|
8829
|
+
.map((participantId) => participantsMap[participantId])
|
8830
|
+
.filter((p) => !!p);
|
8831
|
+
return newVisibleParticipants;
|
8832
|
+
};
|
8833
|
+
const participantsById = (participants) => {
|
8834
|
+
const response = {};
|
8835
|
+
participants.forEach((p) => (response[p.userId] = p));
|
8836
|
+
return response;
|
8837
|
+
};
|
8838
|
+
|
8839
|
+
// Copyright (c) Microsoft Corporation.
|
8840
|
+
const DEFAULT_MAX_REMOTE_VIDEOSTREAMS = 4;
|
8841
|
+
const DEFAULT_MAX_AUDIO_DOMINANT_SPEAKERS = 6;
|
8842
|
+
/**
|
8843
|
+
* @private
|
8844
|
+
*/
|
8845
|
+
const useFloatingLocalVideoLayout = (props) => {
|
8846
|
+
var _a, _b;
|
8847
|
+
const visibleVideoParticipants = React.useRef([]);
|
8848
|
+
const visibleAudioParticipants = React.useRef([]);
|
8849
|
+
const { remoteParticipants, dominantSpeakers, maxRemoteVideoStreams = DEFAULT_MAX_REMOTE_VIDEOSTREAMS, maxAudioDominantSpeakers = DEFAULT_MAX_AUDIO_DOMINANT_SPEAKERS, isScreenShareActive = false } = props;
|
8850
|
+
visibleVideoParticipants.current = smartDominantSpeakerParticipants({
|
8851
|
+
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 : [],
|
8852
|
+
dominantSpeakers,
|
8853
|
+
lastVisibleParticipants: visibleVideoParticipants.current,
|
8854
|
+
maxDominantSpeakers: maxRemoteVideoStreams
|
8855
|
+
}).slice(0, maxRemoteVideoStreams);
|
8856
|
+
const visibleVideoParticipantsSet = new Set(visibleVideoParticipants.current.map((p) => p.userId));
|
8857
|
+
/* @conditional-compile-remove(PSTN-calls) */ /* @conditional-compile-remove(one-to-n-calling) */
|
8858
|
+
const callingParticipants = remoteParticipants.filter((p) => p.state === ('Connecting' ));
|
8859
|
+
/* @conditional-compile-remove(PSTN-calls) */ /* @conditional-compile-remove(one-to-n-calling) */
|
8860
|
+
const callingParticipantsSet = new Set(callingParticipants.map((p) => p.userId));
|
8861
|
+
visibleAudioParticipants.current = smartDominantSpeakerParticipants({
|
8862
|
+
participants: (_b = remoteParticipants === null || remoteParticipants === void 0 ? void 0 : remoteParticipants.filter((p) => !visibleVideoParticipantsSet.has(p.userId) &&
|
8863
|
+
/* @conditional-compile-remove(PSTN-calls) */ /* @conditional-compile-remove(one-to-n-calling) */ !callingParticipantsSet.has(p.userId))) !== null && _b !== void 0 ? _b : [],
|
8864
|
+
dominantSpeakers,
|
8865
|
+
lastVisibleParticipants: visibleAudioParticipants.current,
|
8866
|
+
maxDominantSpeakers: maxAudioDominantSpeakers
|
8867
|
+
});
|
8868
|
+
const getGridParticipants = React.useCallback(() => {
|
8869
|
+
if (isScreenShareActive) {
|
8870
|
+
return [];
|
9070
8871
|
}
|
9071
|
-
|
9072
|
-
|
9073
|
-
|
9074
|
-
|
9075
|
-
|
9076
|
-
|
9077
|
-
|
9078
|
-
|
8872
|
+
/* @conditional-compile-remove(PSTN-calls) */ /* @conditional-compile-remove(one-to-n-calling) */
|
8873
|
+
return visibleVideoParticipants.current.length > 0
|
8874
|
+
? visibleVideoParticipants.current
|
8875
|
+
: visibleAudioParticipants.current.concat(callingParticipants);
|
8876
|
+
}, [
|
8877
|
+
/* @conditional-compile-remove(PSTN-calls) */ /* @conditional-compile-remove(one-to-n-calling) */ callingParticipants,
|
8878
|
+
isScreenShareActive
|
8879
|
+
]);
|
8880
|
+
const gridParticipants = getGridParticipants();
|
8881
|
+
const getHorizontalGalleryRemoteParticipants = React.useCallback(() => {
|
8882
|
+
if (isScreenShareActive) {
|
8883
|
+
// If screen sharing is active, assign video and audio participants as horizontal gallery participants
|
8884
|
+
/* @conditional-compile-remove(PSTN-calls) */ /* @conditional-compile-remove(one-to-n-calling) */
|
8885
|
+
return visibleVideoParticipants.current.concat(visibleAudioParticipants.current.concat(callingParticipants));
|
8886
|
+
}
|
8887
|
+
else {
|
8888
|
+
// If screen sharing is not active, then assign all video tiles as grid tiles.
|
8889
|
+
// If there are no video tiles, then assign audio tiles as grid tiles.
|
8890
|
+
/* @conditional-compile-remove(PSTN-calls) */ /* @conditional-compile-remove(one-to-n-calling) */
|
8891
|
+
return visibleVideoParticipants.current.length > 0
|
8892
|
+
? visibleAudioParticipants.current.concat(callingParticipants)
|
8893
|
+
: [];
|
8894
|
+
}
|
8895
|
+
}, [
|
8896
|
+
/* @conditional-compile-remove(PSTN-calls) */ /* @conditional-compile-remove(one-to-n-calling) */ callingParticipants,
|
8897
|
+
isScreenShareActive
|
8898
|
+
]);
|
8899
|
+
const horizontalGalleryParticipants = getHorizontalGalleryRemoteParticipants();
|
8900
|
+
return { gridParticipants, horizontalGalleryParticipants };
|
8901
|
+
};
|
8902
|
+
|
8903
|
+
// Copyright (c) Microsoft Corporation.
|
8904
|
+
/**
|
8905
|
+
* DefaultLayout displays remote participants, local video component, and screen sharing component in
|
8906
|
+
* a grid and horizontal gallery.
|
8907
|
+
*
|
8908
|
+
* @private
|
8909
|
+
*/
|
8910
|
+
const DefaultLayout = (props) => {
|
8911
|
+
const { remoteParticipants = [], dominantSpeakers, localVideoComponent, screenShareComponent, onRenderRemoteParticipant, styles, maxRemoteVideoStreams, parentWidth } = props;
|
8912
|
+
const isNarrow = parentWidth ? isNarrowWidth(parentWidth) : false;
|
8913
|
+
const floatingLocalVideoLayout = useFloatingLocalVideoLayout({
|
8914
|
+
remoteParticipants,
|
8915
|
+
dominantSpeakers,
|
8916
|
+
maxRemoteVideoStreams,
|
8917
|
+
isScreenShareActive: !!screenShareComponent
|
8918
|
+
});
|
8919
|
+
let activeVideoStreams = 0;
|
8920
|
+
const gridTiles = floatingLocalVideoLayout.gridParticipants.map((p) => {
|
8921
|
+
var _a, _b;
|
8922
|
+
return onRenderRemoteParticipant(p, maxRemoteVideoStreams && maxRemoteVideoStreams >= 0
|
8923
|
+
? ((_a = p.videoStream) === null || _a === void 0 ? void 0 : _a.isAvailable) && activeVideoStreams++ < maxRemoteVideoStreams
|
8924
|
+
: (_b = p.videoStream) === null || _b === void 0 ? void 0 : _b.isAvailable);
|
8925
|
+
});
|
8926
|
+
const horizontalGalleryTiles = floatingLocalVideoLayout.horizontalGalleryParticipants.map((p) => {
|
8927
|
+
var _a, _b;
|
8928
|
+
return onRenderRemoteParticipant(p, maxRemoteVideoStreams && maxRemoteVideoStreams >= 0
|
8929
|
+
? ((_a = p.videoStream) === null || _a === void 0 ? void 0 : _a.isAvailable) && activeVideoStreams++ < maxRemoteVideoStreams
|
8930
|
+
: (_b = p.videoStream) === null || _b === void 0 ? void 0 : _b.isAvailable);
|
8931
|
+
});
|
8932
|
+
if (localVideoComponent) {
|
8933
|
+
gridTiles.push(localVideoComponent);
|
9079
8934
|
}
|
9080
|
-
|
9081
|
-
|
9082
|
-
|
9083
|
-
|
9084
|
-
|
9085
|
-
|
9086
|
-
|
9087
|
-
|
9088
|
-
|
8935
|
+
return (React__default['default'].createElement(react.Stack, { horizontal: false, styles: rootLayoutStyle$1 },
|
8936
|
+
screenShareComponent ? (screenShareComponent) : (React__default['default'].createElement(GridLayout, { key: "grid-layout", styles: styles === null || styles === void 0 ? void 0 : styles.gridLayout }, gridTiles)),
|
8937
|
+
horizontalGalleryTiles.length > 0 && (React__default['default'].createElement(VideoGalleryResponsiveHorizontalGallery, { isNarrow: isNarrow, horizontalGalleryElements: horizontalGalleryTiles, styles: styles === null || styles === void 0 ? void 0 : styles.horizontalGallery }))));
|
8938
|
+
};
|
8939
|
+
|
8940
|
+
// Copyright (c) Microsoft Corporation.
|
8941
|
+
/**
|
8942
|
+
* @private
|
8943
|
+
*/
|
8944
|
+
react.mergeStyles({ position: 'relative', width: '100%', height: '100%' });
|
8945
|
+
/**
|
8946
|
+
* Small floating modal width and height in rem for small screen
|
8947
|
+
*/
|
8948
|
+
const SMALL_FLOATING_MODAL_SIZE_PX = { width: 64, height: 88 };
|
8949
|
+
/**
|
8950
|
+
* Large floating modal width and height in rem for large screen
|
8951
|
+
*/
|
8952
|
+
const LARGE_FLOATING_MODAL_SIZE_PX = { width: 160, height: 120 };
|
8953
|
+
/**
|
8954
|
+
* @private
|
8955
|
+
* z-index to ensure that the local video tile is above the video gallery.
|
8956
|
+
*/
|
8957
|
+
const LOCAL_VIDEO_TILE_ZINDEX = 2;
|
8958
|
+
/**
|
8959
|
+
* @private
|
8960
|
+
*/
|
8961
|
+
const localVideoTileContainerStyle = (theme, isNarrow) => {
|
8962
|
+
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
|
8963
|
+
? { left: _pxToRem(localVideoTileOuterPaddingPX) }
|
8964
|
+
: { right: _pxToRem(localVideoTileOuterPaddingPX) }));
|
8965
|
+
};
|
8966
|
+
/**
|
8967
|
+
* @private
|
8968
|
+
*/
|
8969
|
+
const localVideoTileWithControlsContainerStyle = (theme, isNarrow) => {
|
8970
|
+
return react.concatStyleSets(localVideoTileContainerStyle(theme, isNarrow), {
|
8971
|
+
root: { boxShadow: theme.effects.elevation8 }
|
8972
|
+
});
|
8973
|
+
};
|
8974
|
+
/**
|
8975
|
+
* @private
|
8976
|
+
*/
|
8977
|
+
const floatingLocalVideoModalStyle = (theme, isNarrow) => {
|
8978
|
+
return react.concatStyleSets({
|
8979
|
+
main: localVideoTileContainerStyle(theme, isNarrow)
|
8980
|
+
}, {
|
8981
|
+
main: {
|
8982
|
+
boxShadow: theme.effects.elevation8,
|
8983
|
+
':focus-within': {
|
8984
|
+
boxShadow: theme.effects.elevation16,
|
8985
|
+
border: `${_pxToRem(2)} solid ${theme.palette.neutralPrimary}`
|
8986
|
+
}
|
9089
8987
|
}
|
9090
|
-
|
9091
|
-
|
9092
|
-
|
9093
|
-
|
9094
|
-
|
8988
|
+
}, localVideoModalStyles);
|
8989
|
+
};
|
8990
|
+
/**
|
8991
|
+
* Padding equal to the amount the modal should stay inside the bounds of the container.
|
8992
|
+
* i.e. if this is 8px, the modal should always be at least 8px inside the container at all times on all sides.
|
8993
|
+
* @private
|
8994
|
+
*/
|
8995
|
+
const localVideoTileOuterPaddingPX = 8;
|
8996
|
+
/**
|
8997
|
+
* @private
|
8998
|
+
*/
|
8999
|
+
const floatingLocalVideoTileStyle = {
|
9000
|
+
root: {
|
9001
|
+
position: 'absolute',
|
9002
|
+
zIndex: LOCAL_VIDEO_TILE_ZINDEX,
|
9003
|
+
height: '100%',
|
9004
|
+
width: '100%'
|
9095
9005
|
}
|
9096
|
-
|
9097
|
-
|
9098
|
-
|
9099
|
-
|
9100
|
-
|
9101
|
-
|
9102
|
-
|
9006
|
+
};
|
9007
|
+
/**
|
9008
|
+
* Styles for the local video tile modal when it is focused, will cause keyboard move icon to appear over video
|
9009
|
+
* @private
|
9010
|
+
*/
|
9011
|
+
const localVideoModalStyles = {
|
9012
|
+
keyboardMoveIconContainer: {
|
9013
|
+
zIndex: LOCAL_VIDEO_TILE_ZINDEX + 1 // zIndex to set the keyboard movement Icon above the other layers in the video tile.
|
9103
9014
|
}
|
9104
|
-
|
9105
|
-
|
9106
|
-
|
9107
|
-
|
9108
|
-
|
9109
|
-
|
9110
|
-
|
9111
|
-
|
9015
|
+
};
|
9016
|
+
|
9017
|
+
// Copyright (c) Microsoft Corporation.
|
9018
|
+
const animationDuration = react.AnimationVariables.durationValue2;
|
9019
|
+
const ZERO = { x: 0, y: 0 };
|
9020
|
+
const DEFAULT_PROPS = {
|
9021
|
+
isOpen: false,
|
9022
|
+
isDarkOverlay: true,
|
9023
|
+
className: '',
|
9024
|
+
containerClassName: '',
|
9025
|
+
enableAriaHiddenSiblings: true
|
9026
|
+
};
|
9027
|
+
const getModalClassNames = react.classNamesFunction();
|
9028
|
+
const getMoveDelta = (ev) => {
|
9029
|
+
let delta = 10;
|
9030
|
+
if (ev.shiftKey) {
|
9031
|
+
if (!ev.ctrlKey) {
|
9032
|
+
delta = 50;
|
9112
9033
|
}
|
9113
|
-
return;
|
9114
9034
|
}
|
9115
|
-
|
9116
|
-
|
9117
|
-
|
9118
|
-
|
9119
|
-
|
9120
|
-
|
9035
|
+
else if (ev.ctrlKey) {
|
9036
|
+
delta = 1;
|
9037
|
+
}
|
9038
|
+
return delta;
|
9039
|
+
};
|
9040
|
+
const useComponentRef = (props, focusTrapZone) => {
|
9041
|
+
React__namespace.useImperativeHandle(props.componentRef, () => ({
|
9042
|
+
focus() {
|
9043
|
+
if (focusTrapZone.current) {
|
9044
|
+
focusTrapZone.current.focus();
|
9045
|
+
}
|
9121
9046
|
}
|
9122
|
-
|
9123
|
-
|
9124
|
-
|
9125
|
-
|
9047
|
+
}), [focusTrapZone]);
|
9048
|
+
};
|
9049
|
+
const ModalBase = React__namespace.forwardRef((propsWithoutDefaults, ref) => {
|
9050
|
+
const props = react.getPropsWithDefaults(DEFAULT_PROPS, propsWithoutDefaults);
|
9051
|
+
const { allowTouchBodyScroll, className, children, containerClassName, scrollableContentClassName, elementToFocusOnDismiss, firstFocusableSelector, forceFocusInsideTrap, ignoreExternalFocusing, isBlocking, isAlert, isClickableOutsideFocusTrap, isDarkOverlay, onDismiss, layerProps, overlay, isOpen, titleAriaId, styles, subtitleAriaId, theme, topOffsetFixed, responsiveMode, onLayerDidMount, isModeless, dragOptions, onDismissed, minDragPosition, maxDragPosition } = props;
|
9052
|
+
const rootRef = React__namespace.useRef(null);
|
9053
|
+
const focusTrapZone = React__namespace.useRef(null);
|
9054
|
+
const focusTrapZoneElm = React__namespace.useRef(null);
|
9055
|
+
const mergedRef = reactHooks.useMergedRefs(rootRef, ref);
|
9056
|
+
const modalResponsiveMode = react.useResponsiveMode(mergedRef);
|
9057
|
+
const focusTrapZoneId = reactHooks.useId('ModalFocusTrapZone');
|
9058
|
+
const win = reactWindowProvider.useWindow();
|
9059
|
+
const { setTimeout, clearTimeout } = reactHooks.useSetTimeout();
|
9060
|
+
const [isModalOpen, setIsModalOpen] = React__namespace.useState(isOpen);
|
9061
|
+
const [isVisible, setIsVisible] = React__namespace.useState(isOpen);
|
9062
|
+
const [coordinates, setCoordinates] = React__namespace.useState(ZERO);
|
9063
|
+
const [modalRectangleTop, setModalRectangleTop] = React__namespace.useState();
|
9064
|
+
const [isModalMenuOpen, { toggle: toggleModalMenuOpen, setFalse: setModalMenuClose }] = reactHooks.useBoolean(false);
|
9065
|
+
const internalState = reactHooks.useConst(() => ({
|
9066
|
+
onModalCloseTimer: 0,
|
9067
|
+
allowTouchBodyScroll,
|
9068
|
+
scrollableContent: null,
|
9069
|
+
lastSetCoordinates: ZERO,
|
9070
|
+
events: new react.EventGroup({})
|
9071
|
+
}));
|
9072
|
+
const { keepInBounds } = dragOptions || {};
|
9073
|
+
const isAlertRole = isAlert !== null && isAlert !== void 0 ? isAlert : (isBlocking && !isModeless);
|
9074
|
+
const layerClassName = layerProps === undefined ? '' : layerProps.className;
|
9075
|
+
const classNames = getModalClassNames(styles, {
|
9076
|
+
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
|
9077
|
+
theme: theme,
|
9078
|
+
className,
|
9079
|
+
containerClassName,
|
9080
|
+
scrollableContentClassName,
|
9081
|
+
isOpen,
|
9082
|
+
isVisible,
|
9083
|
+
hasBeenOpened: internalState.hasBeenOpened,
|
9084
|
+
modalRectangleTop,
|
9085
|
+
topOffsetFixed,
|
9086
|
+
isModeless,
|
9087
|
+
layerClassName,
|
9088
|
+
windowInnerHeight: win === null || win === void 0 ? void 0 : win.innerHeight,
|
9089
|
+
isDefaultDragHandle: dragOptions && !dragOptions.dragHandleSelector
|
9090
|
+
});
|
9091
|
+
const mergedLayerProps = Object.assign(Object.assign({ eventBubblingEnabled: false }, layerProps), { onLayerDidMount: layerProps && layerProps.onLayerDidMount ? layerProps.onLayerDidMount : onLayerDidMount, insertFirst: isModeless, className: classNames.layer });
|
9092
|
+
// Allow the user to scroll within the modal but not on the body
|
9093
|
+
const allowScrollOnModal = React__namespace.useCallback((elt) => {
|
9094
|
+
if (elt) {
|
9095
|
+
if (internalState.allowTouchBodyScroll) {
|
9096
|
+
react.allowOverscrollOnElement(elt, internalState.events);
|
9097
|
+
}
|
9098
|
+
else {
|
9099
|
+
react.allowScrollOnElement(elt, internalState.events);
|
9100
|
+
}
|
9126
9101
|
}
|
9127
|
-
|
9128
|
-
|
9129
|
-
/**
|
9130
|
-
* Attempts to find the Touch that matches the identifier we stored in dragStart
|
9131
|
-
* @param touchList The TouchList to look for the stored identifier from dragStart
|
9132
|
-
*/
|
9133
|
-
_findTouchInTouchList(touchList) {
|
9134
|
-
if (this._touchId === undefined) {
|
9135
|
-
return;
|
9102
|
+
else {
|
9103
|
+
internalState.events.off(internalState.scrollableContent);
|
9136
9104
|
}
|
9137
|
-
|
9138
|
-
|
9139
|
-
|
9105
|
+
internalState.scrollableContent = elt;
|
9106
|
+
}, [internalState]);
|
9107
|
+
const registerInitialModalPosition = () => {
|
9108
|
+
const dialogMain = focusTrapZoneElm.current;
|
9109
|
+
const modalRectangle = dialogMain === null || dialogMain === void 0 ? void 0 : dialogMain.getBoundingClientRect();
|
9110
|
+
if (modalRectangle) {
|
9111
|
+
if (topOffsetFixed) {
|
9112
|
+
setModalRectangleTop(modalRectangle.top);
|
9113
|
+
}
|
9114
|
+
if (keepInBounds) {
|
9115
|
+
// x/y are unavailable in IE, so use the equivalent left/top
|
9116
|
+
internalState.minPosition = minDragPosition !== null && minDragPosition !== void 0 ? minDragPosition : { x: -modalRectangle.left, y: -modalRectangle.top };
|
9117
|
+
internalState.maxPosition = maxDragPosition !== null && maxDragPosition !== void 0 ? maxDragPosition : { x: modalRectangle.left, y: modalRectangle.top };
|
9118
|
+
// Make sure the initial co-ordinates are within clamp bounds.
|
9119
|
+
setCoordinates({
|
9120
|
+
x: getClampedAxis('x', coordinates.x),
|
9121
|
+
y: getClampedAxis('y', coordinates.y)
|
9122
|
+
});
|
9140
9123
|
}
|
9141
9124
|
}
|
9142
|
-
|
9143
|
-
}
|
9125
|
+
};
|
9144
9126
|
/**
|
9145
|
-
*
|
9146
|
-
*
|
9127
|
+
* Clamps an axis to a specified min and max position.
|
9128
|
+
*
|
9129
|
+
* @param axis A string that represents the axis (x/y).
|
9130
|
+
* @param position The position on the axis.
|
9147
9131
|
*/
|
9148
|
-
|
9149
|
-
const {
|
9150
|
-
|
9151
|
-
|
9152
|
-
|
9153
|
-
return {
|
9154
|
-
delta: { x: 0, y: 0 },
|
9155
|
-
lastPosition: position,
|
9156
|
-
position
|
9157
|
-
};
|
9132
|
+
const getClampedAxis = React__namespace.useCallback((axis, position) => {
|
9133
|
+
const { minPosition, maxPosition } = internalState;
|
9134
|
+
if (keepInBounds && minPosition && maxPosition) {
|
9135
|
+
position = Math.max(minPosition[axis], position);
|
9136
|
+
position = Math.min(maxPosition[axis], position);
|
9158
9137
|
}
|
9159
|
-
return
|
9160
|
-
|
9161
|
-
|
9162
|
-
|
9163
|
-
|
9164
|
-
|
9165
|
-
|
9138
|
+
return position;
|
9139
|
+
}, [keepInBounds, internalState]);
|
9140
|
+
const handleModalClose = () => {
|
9141
|
+
var _a;
|
9142
|
+
internalState.lastSetCoordinates = ZERO;
|
9143
|
+
setModalMenuClose();
|
9144
|
+
internalState.isInKeyboardMoveMode = false;
|
9145
|
+
setIsModalOpen(false);
|
9146
|
+
setCoordinates(ZERO);
|
9147
|
+
(_a = internalState.disposeOnKeyUp) === null || _a === void 0 ? void 0 : _a.call(internalState);
|
9148
|
+
onDismissed === null || onDismissed === void 0 ? void 0 : onDismissed();
|
9149
|
+
};
|
9150
|
+
const handleDragStart = React__namespace.useCallback(() => {
|
9151
|
+
setModalMenuClose();
|
9152
|
+
internalState.isInKeyboardMoveMode = false;
|
9153
|
+
}, [internalState, setModalMenuClose]);
|
9154
|
+
const handleDrag = React__namespace.useCallback(
|
9155
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
9156
|
+
(ev, dragData) => {
|
9157
|
+
setCoordinates((prevValue) => ({
|
9158
|
+
x: getClampedAxis('x', prevValue.x + dragData.delta.x),
|
9159
|
+
y: getClampedAxis('y', prevValue.y + dragData.delta.y)
|
9160
|
+
}));
|
9161
|
+
}, [getClampedAxis]);
|
9162
|
+
const handleDragStop = React__namespace.useCallback(() => {
|
9163
|
+
if (focusTrapZone.current) {
|
9164
|
+
focusTrapZone.current.focus();
|
9165
|
+
}
|
9166
|
+
}, []);
|
9167
|
+
const handleEnterKeyboardMoveMode = () => {
|
9168
|
+
// We need a global handleKeyDown event when we are in the move mode so that we can
|
9169
|
+
// handle the key presses and the components inside the modal do not get the events
|
9170
|
+
const handleKeyDown = (ev) => {
|
9171
|
+
if (ev.altKey && ev.ctrlKey && ev.keyCode === react.KeyCodes.space) {
|
9172
|
+
// CTRL + ALT + SPACE is handled during keyUp
|
9173
|
+
ev.preventDefault();
|
9174
|
+
ev.stopPropagation();
|
9175
|
+
return;
|
9176
|
+
}
|
9177
|
+
const newLocal = ev.altKey || ev.keyCode === react.KeyCodes.escape;
|
9178
|
+
if (isModalMenuOpen && newLocal) {
|
9179
|
+
setModalMenuClose();
|
9180
|
+
}
|
9181
|
+
if (internalState.isInKeyboardMoveMode && (ev.keyCode === react.KeyCodes.escape || ev.keyCode === react.KeyCodes.enter)) {
|
9182
|
+
internalState.isInKeyboardMoveMode = false;
|
9183
|
+
ev.preventDefault();
|
9184
|
+
ev.stopPropagation();
|
9185
|
+
}
|
9186
|
+
if (internalState.isInKeyboardMoveMode) {
|
9187
|
+
let handledEvent = true;
|
9188
|
+
const delta = getMoveDelta(ev);
|
9189
|
+
switch (ev.keyCode) {
|
9190
|
+
/* eslint-disable no-fallthrough */
|
9191
|
+
case react.KeyCodes.escape:
|
9192
|
+
setCoordinates(internalState.lastSetCoordinates);
|
9193
|
+
case react.KeyCodes.enter: {
|
9194
|
+
// TODO: determine if fallthrough was intentional
|
9195
|
+
/* eslint-enable no-fallthrough */
|
9196
|
+
internalState.lastSetCoordinates = ZERO;
|
9197
|
+
// setIsInKeyboardMoveMode(false);
|
9198
|
+
break;
|
9199
|
+
}
|
9200
|
+
case react.KeyCodes.up: {
|
9201
|
+
setCoordinates((prevValue) => ({ x: prevValue.x, y: getClampedAxis('y', prevValue.y - delta) }));
|
9202
|
+
break;
|
9203
|
+
}
|
9204
|
+
case react.KeyCodes.down: {
|
9205
|
+
setCoordinates((prevValue) => ({ x: prevValue.x, y: getClampedAxis('y', prevValue.y + delta) }));
|
9206
|
+
break;
|
9207
|
+
}
|
9208
|
+
case react.KeyCodes.left: {
|
9209
|
+
setCoordinates((prevValue) => ({ x: getClampedAxis('x', prevValue.x - delta), y: prevValue.y }));
|
9210
|
+
break;
|
9211
|
+
}
|
9212
|
+
case react.KeyCodes.right: {
|
9213
|
+
setCoordinates((prevValue) => ({ x: getClampedAxis('x', prevValue.x + delta), y: prevValue.y }));
|
9214
|
+
break;
|
9215
|
+
}
|
9216
|
+
default: {
|
9217
|
+
handledEvent = false;
|
9218
|
+
}
|
9219
|
+
}
|
9220
|
+
if (handledEvent) {
|
9221
|
+
ev.preventDefault();
|
9222
|
+
ev.stopPropagation();
|
9223
|
+
}
|
9224
|
+
}
|
9166
9225
|
};
|
9167
|
-
|
9168
|
-
|
9169
|
-
|
9170
|
-
|
9171
|
-
|
9172
|
-
|
9173
|
-
|
9174
|
-
return {
|
9175
|
-
position: {
|
9176
|
-
x: position.x + baseDragData.delta.x,
|
9177
|
-
y: position.y + baseDragData.delta.y
|
9178
|
-
},
|
9179
|
-
delta: baseDragData.delta,
|
9180
|
-
lastPosition: position
|
9226
|
+
internalState.lastSetCoordinates = coordinates;
|
9227
|
+
setModalMenuClose();
|
9228
|
+
internalState.isInKeyboardMoveMode = true;
|
9229
|
+
internalState.events.on(win, 'keydown', handleKeyDown, true /* useCapture */);
|
9230
|
+
internalState.disposeOnKeyDown = () => {
|
9231
|
+
internalState.events.off(win, 'keydown', handleKeyDown, true /* useCapture */);
|
9232
|
+
internalState.disposeOnKeyDown = undefined;
|
9181
9233
|
};
|
9182
|
-
}
|
9183
|
-
|
9184
|
-
|
9185
|
-
|
9186
|
-
|
9187
|
-
|
9188
|
-
|
9189
|
-
|
9190
|
-
|
9191
|
-
|
9192
|
-
|
9193
|
-
|
9194
|
-
|
9195
|
-
|
9196
|
-
|
9197
|
-
|
9198
|
-
fonts.medium,
|
9199
|
-
{
|
9200
|
-
backgroundColor: 'transparent',
|
9201
|
-
position: isModeless ? 'absolute' : 'fixed',
|
9202
|
-
height: '100%',
|
9203
|
-
width: '100%',
|
9204
|
-
display: 'flex',
|
9205
|
-
alignItems: 'center',
|
9206
|
-
justifyContent: 'center',
|
9207
|
-
opacity: 0,
|
9208
|
-
pointerEvents: 'none',
|
9209
|
-
transition: `opacity ${animationDuration}`
|
9210
|
-
},
|
9211
|
-
topOffsetFixed &&
|
9212
|
-
typeof modalRectangleTop === 'number' &&
|
9213
|
-
hasBeenOpened && {
|
9214
|
-
alignItems: 'flex-start'
|
9215
|
-
},
|
9216
|
-
isOpen && classNames.isOpen,
|
9217
|
-
isVisible && {
|
9218
|
-
opacity: 1,
|
9219
|
-
pointerEvents: 'auto'
|
9220
|
-
},
|
9221
|
-
className
|
9222
|
-
],
|
9223
|
-
main: [
|
9224
|
-
classNames.main,
|
9225
|
-
{
|
9226
|
-
boxShadow: effects.elevation64,
|
9227
|
-
borderRadius: effects.roundedCorner2,
|
9228
|
-
backgroundColor: palette.white,
|
9229
|
-
boxSizing: 'border-box',
|
9230
|
-
position: 'relative',
|
9231
|
-
textAlign: 'left',
|
9232
|
-
outline: '3px solid transparent',
|
9233
|
-
maxHeight: 'calc(100% - 32px)',
|
9234
|
-
maxWidth: 'calc(100% - 32px)',
|
9235
|
-
minHeight: '176px',
|
9236
|
-
minWidth: '288px',
|
9237
|
-
overflowY: 'auto',
|
9238
|
-
zIndex: isModeless ? react.ZIndexes.Layer : undefined
|
9239
|
-
},
|
9240
|
-
topOffsetFixed &&
|
9241
|
-
typeof modalRectangleTop === 'number' &&
|
9242
|
-
hasBeenOpened && {
|
9243
|
-
top: modalRectangleTop
|
9244
|
-
},
|
9245
|
-
isDefaultDragHandle && {
|
9246
|
-
cursor: 'move'
|
9247
|
-
},
|
9248
|
-
containerClassName
|
9249
|
-
],
|
9250
|
-
scrollableContent: [
|
9251
|
-
classNames.scrollableContent,
|
9252
|
-
{
|
9253
|
-
overflowY: 'auto',
|
9254
|
-
flexGrow: 1,
|
9255
|
-
maxHeight: '100vh',
|
9256
|
-
selectors: {
|
9257
|
-
['@supports (-webkit-overflow-scrolling: touch)']: {
|
9258
|
-
maxHeight: windowInnerHeight
|
9259
|
-
}
|
9234
|
+
};
|
9235
|
+
const handleExitKeyboardMoveMode = () => {
|
9236
|
+
var _a;
|
9237
|
+
internalState.lastSetCoordinates = ZERO;
|
9238
|
+
internalState.isInKeyboardMoveMode = false;
|
9239
|
+
(_a = internalState.disposeOnKeyDown) === null || _a === void 0 ? void 0 : _a.call(internalState);
|
9240
|
+
};
|
9241
|
+
const registerForKeyUp = () => {
|
9242
|
+
const handleKeyUp = (ev) => {
|
9243
|
+
// Needs to handle the CTRL + ALT + SPACE key during keyup due to FireFox bug:
|
9244
|
+
// https://bugzilla.mozilla.org/show_bug.cgi?id=1220143
|
9245
|
+
if (ev.altKey && ev.ctrlKey && ev.keyCode === react.KeyCodes.space) {
|
9246
|
+
if (react.elementContains(internalState.scrollableContent, ev.target)) {
|
9247
|
+
toggleModalMenuOpen();
|
9248
|
+
ev.preventDefault();
|
9249
|
+
ev.stopPropagation();
|
9260
9250
|
}
|
9261
|
-
},
|
9262
|
-
scrollableContentClassName
|
9263
|
-
],
|
9264
|
-
layer: isModeless && [
|
9265
|
-
layerClassName,
|
9266
|
-
classNames.layer,
|
9267
|
-
{
|
9268
|
-
position: 'static',
|
9269
|
-
width: 'unset',
|
9270
|
-
height: 'unset'
|
9271
9251
|
}
|
9272
|
-
|
9273
|
-
|
9274
|
-
|
9275
|
-
|
9276
|
-
|
9277
|
-
|
9278
|
-
|
9279
|
-
},
|
9280
|
-
keyboardMoveIcon: {
|
9281
|
-
fontSize: fonts.xLargePlus.fontSize,
|
9282
|
-
width: '24px'
|
9252
|
+
};
|
9253
|
+
if (!internalState.disposeOnKeyUp) {
|
9254
|
+
internalState.events.on(win, 'keyup', handleKeyUp, true /* useCapture */);
|
9255
|
+
internalState.disposeOnKeyUp = () => {
|
9256
|
+
internalState.events.off(win, 'keyup', handleKeyUp, true /* useCapture */);
|
9257
|
+
internalState.disposeOnKeyUp = undefined;
|
9258
|
+
};
|
9283
9259
|
}
|
9284
9260
|
};
|
9285
|
-
|
9286
|
-
|
9287
|
-
|
9288
|
-
|
9289
|
-
|
9290
|
-
|
9291
|
-
|
9292
|
-
|
9293
|
-
|
9294
|
-
|
9295
|
-
* local video tile camera cycle button - for use on mobile screens only.
|
9296
|
-
* @internal
|
9297
|
-
*/
|
9298
|
-
const LocalVideoCameraCycleButton = (props) => {
|
9299
|
-
const { cameras, selectedCamera, onSelectCamera, label, ariaDescription } = props;
|
9300
|
-
const theme = react.useTheme();
|
9301
|
-
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: () => {
|
9302
|
-
if (cameras && cameras.length > 1 && selectedCamera !== undefined) {
|
9303
|
-
const index = cameras.findIndex((camera) => selectedCamera.id === camera.id);
|
9304
|
-
const newCamera = cameras[(index + 1) % cameras.length];
|
9305
|
-
if (onSelectCamera !== undefined) {
|
9306
|
-
onSelectCamera(newCamera);
|
9307
|
-
}
|
9261
|
+
React__namespace.useEffect(() => {
|
9262
|
+
clearTimeout(internalState.onModalCloseTimer);
|
9263
|
+
// Opening the dialog
|
9264
|
+
if (isOpen) {
|
9265
|
+
// This must be done after the modal content has rendered
|
9266
|
+
requestAnimationFrame(() => setTimeout(registerInitialModalPosition, 0));
|
9267
|
+
setIsModalOpen(true);
|
9268
|
+
// Add a keyUp handler for all key up events once the dialog is open.
|
9269
|
+
if (dragOptions) {
|
9270
|
+
registerForKeyUp();
|
9308
9271
|
}
|
9309
|
-
|
9310
|
-
|
9311
|
-
|
9312
|
-
// Copyright (c) Microsoft Corporation.
|
9313
|
-
/**
|
9314
|
-
* A memoized version of VideoTile for rendering local participant.
|
9315
|
-
*
|
9316
|
-
* @internal
|
9317
|
-
*/
|
9318
|
-
const _LocalVideoTile = React__default['default'].memo((props) => {
|
9319
|
-
const { isAvailable, isMuted, onCreateLocalStreamView, onDisposeLocalStreamView, localVideoViewOptions, renderElement, userId, showLabel, displayName, initialsName, onRenderAvatar, showMuteIndicator, styles, showCameraSwitcherInLocalPreview, localVideoCameraCycleButtonProps, localVideoCameraSwitcherLabel, localVideoSelectedDescription } = props;
|
9320
|
-
const localVideoStreamProps = React.useMemo(() => ({
|
9321
|
-
isMirrored: localVideoViewOptions === null || localVideoViewOptions === void 0 ? void 0 : localVideoViewOptions.isMirrored,
|
9322
|
-
isStreamAvailable: isAvailable,
|
9323
|
-
onCreateLocalStreamView,
|
9324
|
-
onDisposeLocalStreamView,
|
9325
|
-
renderElementExists: !!renderElement,
|
9326
|
-
scalingMode: localVideoViewOptions === null || localVideoViewOptions === void 0 ? void 0 : localVideoViewOptions.scalingMode
|
9327
|
-
}), [
|
9328
|
-
isAvailable,
|
9329
|
-
localVideoViewOptions === null || localVideoViewOptions === void 0 ? void 0 : localVideoViewOptions.isMirrored,
|
9330
|
-
localVideoViewOptions === null || localVideoViewOptions === void 0 ? void 0 : localVideoViewOptions.scalingMode,
|
9331
|
-
onCreateLocalStreamView,
|
9332
|
-
onDisposeLocalStreamView,
|
9333
|
-
renderElement
|
9334
|
-
]);
|
9335
|
-
// Handle creating, destroying and updating the video stream as necessary
|
9336
|
-
useLocalVideoStreamLifecycleMaintainer(localVideoStreamProps);
|
9337
|
-
const renderVideoStreamElement = React.useMemo(() => {
|
9338
|
-
// Checking if renderElement is well defined or not as calling SDK has a number of video streams limitation which
|
9339
|
-
// implies that, after their threshold, all streams have no child (blank video)
|
9340
|
-
if (!renderElement || !renderElement.childElementCount) {
|
9341
|
-
// Returning `undefined` results in the placeholder with avatar being shown
|
9342
|
-
return undefined;
|
9272
|
+
internalState.hasBeenOpened = true;
|
9273
|
+
setIsVisible(true);
|
9343
9274
|
}
|
9344
|
-
|
9345
|
-
|
9346
|
-
|
9347
|
-
|
9348
|
-
|
9349
|
-
|
9350
|
-
|
9351
|
-
|
9352
|
-
|
9353
|
-
|
9354
|
-
|
9275
|
+
// Closing the dialog
|
9276
|
+
if (!isOpen && isModalOpen) {
|
9277
|
+
internalState.onModalCloseTimer = setTimeout(handleModalClose, parseFloat(animationDuration) * 1000);
|
9278
|
+
setIsVisible(false);
|
9279
|
+
}
|
9280
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps -- should only run if isModalOpen or isOpen mutates or if min/max drag bounds are updated.
|
9281
|
+
}, [isModalOpen, isOpen, minDragPosition, maxDragPosition]);
|
9282
|
+
reactHooks.useUnmount(() => {
|
9283
|
+
internalState.events.dispose();
|
9284
|
+
});
|
9285
|
+
useComponentRef(props, focusTrapZone);
|
9286
|
+
const modalContent = (React__namespace.createElement(react.FocusTrapZone, { disabled: true, id: focusTrapZoneId, ref: focusTrapZoneElm, componentRef: focusTrapZone, className: classNames.main, elementToFocusOnDismiss: elementToFocusOnDismiss, isClickableOutsideFocusTrap: isModeless || isClickableOutsideFocusTrap || !isBlocking, ignoreExternalFocusing: ignoreExternalFocusing, forceFocusInsideTrap: forceFocusInsideTrap && !isModeless, firstFocusableSelector: firstFocusableSelector, focusPreviouslyFocusedInnerElement: true, onBlur: internalState.isInKeyboardMoveMode ? handleExitKeyboardMoveMode : undefined },
|
9287
|
+
dragOptions && internalState.isInKeyboardMoveMode && (React__namespace.createElement("div", { className: classNames.keyboardMoveIconContainer }, dragOptions.keyboardMoveIconProps ? (React__namespace.createElement(react.Icon, Object.assign({}, dragOptions.keyboardMoveIconProps))) : (React__namespace.createElement(react.Icon, { iconName: "move", className: classNames.keyboardMoveIcon })))),
|
9288
|
+
React__namespace.createElement("div", { ref: allowScrollOnModal, className: classNames.scrollableContent, "data-is-scrollable": true },
|
9289
|
+
dragOptions && isModalMenuOpen && (React__namespace.createElement(dragOptions.menu, { items: [
|
9290
|
+
{ key: 'move', text: dragOptions.moveMenuItemText, onClick: handleEnterKeyboardMoveMode },
|
9291
|
+
{ key: 'close', text: dragOptions.closeMenuItemText, onClick: handleModalClose }
|
9292
|
+
], onDismiss: setModalMenuClose, alignTargetEdge: true, coverTarget: true, directionalHint: react.DirectionalHint.topLeftEdge, directionalHintFixed: true, shouldFocusOnMount: true, target: internalState.scrollableContent })),
|
9293
|
+
children)));
|
9294
|
+
return (
|
9295
|
+
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
|
9296
|
+
(isModalOpen && modalResponsiveMode >= (responsiveMode || react.ResponsiveMode.small) && (React__namespace.createElement(react.Layer, Object.assign({ ref: mergedRef }, mergedLayerProps),
|
9297
|
+
React__namespace.createElement(react.Popup, { role: isAlertRole ? 'alertdialog' : 'dialog', ariaLabelledBy: titleAriaId, ariaDescribedBy: subtitleAriaId,
|
9298
|
+
// onDismiss={onDismiss}
|
9299
|
+
shouldRestoreFocus: !ignoreExternalFocusing, "aria-modal": !isModeless },
|
9300
|
+
React__namespace.createElement("div", { className: classNames.root, role: !isModeless ? 'document' : undefined },
|
9301
|
+
!isModeless && (React__namespace.createElement(react.Overlay, Object.assign({ "aria-hidden": true, isDarkThemed: isDarkOverlay, onClick: isBlocking ? undefined : onDismiss, allowTouchBodyScroll: allowTouchBodyScroll }, overlay))),
|
9302
|
+
dragOptions ? (React__namespace.createElement(DraggableZone, { handleSelector: dragOptions.dragHandleSelector || `#${focusTrapZoneId}`, preventDragSelector: "button", onStart: handleDragStart, onDragChange: handleDrag, onStop: handleDragStop, position: coordinates }, modalContent)) : (modalContent)))))) ||
|
9303
|
+
null);
|
9355
9304
|
});
|
9356
|
-
|
9357
|
-
|
9358
|
-
const ariaDescription = (localVideoCameraCycleButtonProps === null || localVideoCameraCycleButtonProps === void 0 ? void 0 : localVideoCameraCycleButtonProps.selectedCamera) &&
|
9359
|
-
localVideoSelectedDescription &&
|
9360
|
-
_formatString(localVideoSelectedDescription, {
|
9361
|
-
cameraName: localVideoCameraCycleButtonProps.selectedCamera.name
|
9362
|
-
});
|
9363
|
-
return (React__default['default'].createElement(react.Stack, { horizontalAlign: "end" }, showCameraSwitcherInLocalPreview &&
|
9364
|
-
(localVideoCameraCycleButtonProps === null || localVideoCameraCycleButtonProps === void 0 ? void 0 : localVideoCameraCycleButtonProps.cameras) !== undefined &&
|
9365
|
-
(localVideoCameraCycleButtonProps === null || localVideoCameraCycleButtonProps === void 0 ? void 0 : localVideoCameraCycleButtonProps.selectedCamera) !== undefined &&
|
9366
|
-
(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 }))));
|
9367
|
-
};
|
9368
|
-
|
9369
|
-
// Copyright (c) Microsoft Corporation.
|
9370
|
-
// Licensed under the MIT license.
|
9371
|
-
/**
|
9372
|
-
* @private
|
9373
|
-
*/
|
9374
|
-
const rootLayoutStyle = {
|
9375
|
-
root: { position: 'relative', height: '100%', width: '100%', padding: '0.5rem' }
|
9376
|
-
};
|
9377
|
-
|
9378
|
-
// Copyright (c) Microsoft Corporation.
|
9379
|
-
// Licensed under the MIT license.
|
9380
|
-
/**
|
9381
|
-
* Horizontal Gallery button width in rem
|
9382
|
-
*/
|
9383
|
-
const HORIZONTAL_GALLERY_BUTTON_WIDTH = 1.75;
|
9384
|
-
/**
|
9385
|
-
* @private
|
9386
|
-
*/
|
9387
|
-
const leftRightButtonStyles = (theme) => {
|
9305
|
+
ModalBase.displayName = 'ModalBase';
|
9306
|
+
const getDraggableZoneClassNames = react.memoizeFunction((className, isDragging) => {
|
9388
9307
|
return {
|
9389
|
-
|
9390
|
-
|
9391
|
-
|
9392
|
-
|
9393
|
-
|
9394
|
-
|
9395
|
-
|
9308
|
+
root: react.mergeStyles(className, isDragging && {
|
9309
|
+
touchAction: 'none',
|
9310
|
+
selectors: {
|
9311
|
+
'& *': {
|
9312
|
+
userSelect: 'none'
|
9313
|
+
}
|
9314
|
+
}
|
9315
|
+
})
|
9396
9316
|
};
|
9317
|
+
});
|
9318
|
+
const eventMapping = {
|
9319
|
+
touch: {
|
9320
|
+
start: 'touchstart',
|
9321
|
+
move: 'touchmove',
|
9322
|
+
stop: 'touchend'
|
9323
|
+
},
|
9324
|
+
mouse: {
|
9325
|
+
start: 'mousedown',
|
9326
|
+
move: 'mousemove',
|
9327
|
+
stop: 'mouseup'
|
9328
|
+
}
|
9397
9329
|
};
|
9398
|
-
|
9399
|
-
|
9400
|
-
|
9401
|
-
|
9402
|
-
|
9403
|
-
|
9404
|
-
|
9405
|
-
|
9406
|
-
|
9407
|
-
|
9408
|
-
|
9409
|
-
|
9410
|
-
|
9411
|
-
|
9412
|
-
|
9413
|
-
|
9414
|
-
|
9415
|
-
|
9416
|
-
|
9417
|
-
|
9418
|
-
|
9419
|
-
|
9420
|
-
|
9421
|
-
|
9422
|
-
|
9423
|
-
|
9424
|
-
|
9425
|
-
|
9426
|
-
|
9427
|
-
|
9428
|
-
const
|
9429
|
-
|
9430
|
-
|
9431
|
-
|
9432
|
-
|
9433
|
-
|
9434
|
-
|
9435
|
-
|
9436
|
-
|
9437
|
-
|
9438
|
-
|
9439
|
-
|
9440
|
-
|
9330
|
+
class DraggableZone extends React__namespace.Component {
|
9331
|
+
constructor(props) {
|
9332
|
+
super(props);
|
9333
|
+
this._currentEventType = eventMapping.mouse;
|
9334
|
+
this._events = [];
|
9335
|
+
this._onMouseDown = (event) => {
|
9336
|
+
const onMouseDown = React__namespace.Children.only(this.props.children).props.onMouseDown;
|
9337
|
+
if (onMouseDown) {
|
9338
|
+
onMouseDown(event);
|
9339
|
+
}
|
9340
|
+
this._currentEventType = eventMapping.mouse;
|
9341
|
+
return this._onDragStart(event);
|
9342
|
+
};
|
9343
|
+
this._onMouseUp = (event) => {
|
9344
|
+
const onMouseUp = React__namespace.Children.only(this.props.children).props.onMouseUp;
|
9345
|
+
if (onMouseUp) {
|
9346
|
+
onMouseUp(event);
|
9347
|
+
}
|
9348
|
+
this._currentEventType = eventMapping.mouse;
|
9349
|
+
return this._onDragStop(event);
|
9350
|
+
};
|
9351
|
+
this._onTouchStart = (event) => {
|
9352
|
+
const onTouchStart = React__namespace.Children.only(this.props.children).props.onTouchStart;
|
9353
|
+
if (onTouchStart) {
|
9354
|
+
onTouchStart(event);
|
9355
|
+
}
|
9356
|
+
this._currentEventType = eventMapping.touch;
|
9357
|
+
return this._onDragStart(event);
|
9358
|
+
};
|
9359
|
+
this._onTouchEnd = (event) => {
|
9360
|
+
const onTouchEnd = React__namespace.Children.only(this.props.children).props.onTouchEnd;
|
9361
|
+
if (onTouchEnd) {
|
9362
|
+
onTouchEnd(event);
|
9363
|
+
}
|
9364
|
+
this._currentEventType = eventMapping.touch;
|
9365
|
+
this._onDragStop(event);
|
9366
|
+
};
|
9367
|
+
this._onDragStart = (event) => {
|
9368
|
+
// Only handle left click for dragging
|
9369
|
+
if (typeof event.button === 'number' && event.button !== 0) {
|
9370
|
+
return false;
|
9371
|
+
}
|
9372
|
+
// If the target doesn't match the handleSelector OR
|
9373
|
+
// if the target does match the preventDragSelector, bail out
|
9374
|
+
if ((this.props.handleSelector && !this._matchesSelector(event.target, this.props.handleSelector)) ||
|
9375
|
+
(this.props.preventDragSelector &&
|
9376
|
+
this._matchesSelector(event.target, this.props.preventDragSelector))) {
|
9377
|
+
return;
|
9378
|
+
}
|
9379
|
+
// Remember the touch identifier if this is a touch event so we can
|
9380
|
+
// distinguish between individual touches in multitouch scenarios
|
9381
|
+
// by remembering which touch point we were given
|
9382
|
+
this._touchId = this._getTouchId(event);
|
9383
|
+
const position = this._getControlPosition(event);
|
9384
|
+
if (position === undefined) {
|
9385
|
+
return;
|
9386
|
+
}
|
9387
|
+
const dragData = this._createDragDataFromPosition(position);
|
9388
|
+
this.props.onStart && this.props.onStart(event, dragData);
|
9389
|
+
this.setState({
|
9390
|
+
isDragging: true,
|
9391
|
+
lastPosition: position
|
9392
|
+
});
|
9393
|
+
// hook up the appropriate mouse/touch events to the body to ensure
|
9394
|
+
// smooth dragging
|
9395
|
+
this._events = [
|
9396
|
+
react.on(document.body, this._currentEventType.move, this._onDrag, true /* use capture phase */),
|
9397
|
+
react.on(document.body, this._currentEventType.stop, this._onDragStop, true /* use capture phase */)
|
9398
|
+
];
|
9399
|
+
return;
|
9400
|
+
};
|
9401
|
+
this._onDrag = (event) => {
|
9402
|
+
// Prevent scrolling on mobile devices
|
9403
|
+
if (event.type === 'touchmove') {
|
9404
|
+
event.preventDefault();
|
9405
|
+
}
|
9406
|
+
const position = this._getControlPosition(event);
|
9407
|
+
if (!position) {
|
9408
|
+
return;
|
9409
|
+
}
|
9410
|
+
// create the updated drag data from the position data
|
9411
|
+
const updatedData = this._createUpdatedDragData(this._createDragDataFromPosition(position));
|
9412
|
+
const updatedPosition = updatedData.position;
|
9413
|
+
this.props.onDragChange && this.props.onDragChange(event, updatedData);
|
9414
|
+
this.setState({
|
9415
|
+
position: updatedPosition,
|
9416
|
+
lastPosition: position
|
9417
|
+
});
|
9418
|
+
};
|
9419
|
+
this._onDragStop = (event) => {
|
9420
|
+
if (!this.state.isDragging) {
|
9421
|
+
return;
|
9422
|
+
}
|
9423
|
+
const position = this._getControlPosition(event);
|
9424
|
+
if (!position) {
|
9425
|
+
return;
|
9426
|
+
}
|
9427
|
+
const baseDragData = this._createDragDataFromPosition(position);
|
9428
|
+
// Set dragging to false and reset the lastPosition
|
9429
|
+
this.setState({
|
9430
|
+
isDragging: false,
|
9431
|
+
lastPosition: undefined
|
9432
|
+
});
|
9433
|
+
this.props.onStop && this.props.onStop(event, baseDragData);
|
9434
|
+
if (this.props.position) {
|
9435
|
+
this.setState({
|
9436
|
+
position: this.props.position
|
9437
|
+
});
|
9438
|
+
}
|
9439
|
+
// Remove event handlers
|
9440
|
+
this._events.forEach((dispose) => dispose());
|
9441
|
+
};
|
9442
|
+
this.state = {
|
9443
|
+
isDragging: false,
|
9444
|
+
position: this.props.position || { x: 0, y: 0 },
|
9445
|
+
lastPosition: undefined
|
9446
|
+
};
|
9447
|
+
}
|
9448
|
+
componentDidUpdate(prevProps) {
|
9449
|
+
if (this.props.position && (!prevProps.position || this.props.position !== prevProps.position)) {
|
9450
|
+
this.setState({ position: this.props.position });
|
9451
|
+
}
|
9452
|
+
}
|
9453
|
+
componentWillUnmount() {
|
9454
|
+
this._events.forEach((dispose) => dispose());
|
9455
|
+
}
|
9456
|
+
render() {
|
9457
|
+
const child = React__namespace.Children.only(this.props.children);
|
9458
|
+
const { props } = child;
|
9459
|
+
const { position } = this.props;
|
9460
|
+
const { position: statePosition, isDragging } = this.state;
|
9461
|
+
let x = statePosition.x;
|
9462
|
+
let y = statePosition.y;
|
9463
|
+
if (position && !isDragging) {
|
9464
|
+
x = position.x;
|
9465
|
+
y = position.y;
|
9466
|
+
}
|
9467
|
+
return React__namespace.cloneElement(child, {
|
9468
|
+
style: Object.assign(Object.assign({}, props.style), { transform: `translate(${x}px, ${y}px)` }),
|
9469
|
+
className: getDraggableZoneClassNames(props.className, this.state.isDragging).root,
|
9470
|
+
onMouseDown: this._onMouseDown,
|
9471
|
+
onMouseUp: this._onMouseUp,
|
9472
|
+
onTouchStart: this._onTouchStart,
|
9473
|
+
onTouchEnd: this._onTouchEnd
|
9474
|
+
});
|
9441
9475
|
}
|
9442
|
-
|
9443
|
-
|
9444
|
-
|
9445
|
-
|
9446
|
-
|
9447
|
-
|
9448
|
-
|
9449
|
-
|
9450
|
-
|
9451
|
-
|
9452
|
-
|
9453
|
-
|
9454
|
-
|
9455
|
-
|
9456
|
-
};
|
9457
|
-
function bucketize(arr, bucketSize) {
|
9458
|
-
const bucketArray = [];
|
9459
|
-
if (bucketSize <= 0) {
|
9460
|
-
return bucketArray;
|
9476
|
+
/**
|
9477
|
+
* Get the control position based off the event that fired
|
9478
|
+
* @param event - The event to get offsets from
|
9479
|
+
*/
|
9480
|
+
_getControlPosition(event) {
|
9481
|
+
const touchObj = this._getActiveTouch(event);
|
9482
|
+
// did we get the right touch?
|
9483
|
+
if (this._touchId !== undefined && !touchObj) {
|
9484
|
+
return undefined;
|
9485
|
+
}
|
9486
|
+
const eventToGetOffset = touchObj || event;
|
9487
|
+
return {
|
9488
|
+
x: eventToGetOffset.clientX,
|
9489
|
+
y: eventToGetOffset.clientY
|
9490
|
+
};
|
9461
9491
|
}
|
9462
|
-
|
9463
|
-
|
9492
|
+
/**
|
9493
|
+
* Get the active touch point that we have saved from the event's TouchList
|
9494
|
+
* @param event - The event used to get the TouchList for the active touch point
|
9495
|
+
*/
|
9496
|
+
_getActiveTouch(event) {
|
9497
|
+
return ((event.targetTouches && this._findTouchInTouchList(event.targetTouches)) ||
|
9498
|
+
(event.changedTouches && this._findTouchInTouchList(event.changedTouches)));
|
9464
9499
|
}
|
9465
|
-
|
9466
|
-
|
9467
|
-
|
9468
|
-
// Copyright (c) Microsoft Corporation.
|
9469
|
-
/**
|
9470
|
-
* Wrapped HorizontalGallery that adjusts the number of items per page based on the
|
9471
|
-
* available width obtained from a ResizeObserver, width per child, gap width, and button width
|
9472
|
-
*/
|
9473
|
-
const ResponsiveHorizontalGallery = (props) => {
|
9474
|
-
const { childWidthRem, gapWidthRem, buttonWidthRem = 0 } = props;
|
9475
|
-
const containerRef = React.useRef(null);
|
9476
|
-
const containerWidth = _useContainerWidth(containerRef);
|
9477
|
-
const leftPadding = containerRef.current ? parseFloat(getComputedStyle(containerRef.current).paddingLeft) : 0;
|
9478
|
-
const rightPadding = containerRef.current ? parseFloat(getComputedStyle(containerRef.current).paddingRight) : 0;
|
9479
|
-
const childrenPerPage = calculateChildrenPerPage({
|
9480
|
-
numberOfChildren: React__default['default'].Children.count(props.children),
|
9481
|
-
containerWidth: (containerWidth !== null && containerWidth !== void 0 ? containerWidth : 0) - leftPadding - rightPadding,
|
9482
|
-
childWidthRem,
|
9483
|
-
gapWidthRem,
|
9484
|
-
buttonWidthRem
|
9485
|
-
});
|
9486
|
-
return (React__default['default'].createElement("div", { ref: containerRef, className: react.mergeStyles(props.containerStyles) },
|
9487
|
-
React__default['default'].createElement(HorizontalGallery, { childrenPerPage: childrenPerPage, styles: props.horizontalGalleryStyles }, props.children)));
|
9488
|
-
};
|
9489
|
-
/**
|
9490
|
-
* Helper function to calculate children per page for HorizontalGallery based on width of container, child, buttons, and
|
9491
|
-
* gaps in between
|
9492
|
-
*/
|
9493
|
-
const calculateChildrenPerPage = (args) => {
|
9494
|
-
const { numberOfChildren, containerWidth, buttonWidthRem, childWidthRem, gapWidthRem } = args;
|
9495
|
-
const childWidth = _convertRemToPx(childWidthRem);
|
9496
|
-
const gapWidth = _convertRemToPx(gapWidthRem);
|
9497
|
-
/** First check how many children can fit in containerWidth.
|
9498
|
-
* __________________________________
|
9499
|
-
* | || |
|
9500
|
-
* | || |
|
9501
|
-
* |________________||________________|
|
9502
|
-
* <-----------containerWidth--------->
|
9503
|
-
* containerWidth = n * childWidth + (n - 1) * gapWidth. Isolate n and take the floor.
|
9500
|
+
/**
|
9501
|
+
* Get the initial touch identifier associated with the given event
|
9502
|
+
* @param event - The event that contains the TouchList
|
9504
9503
|
*/
|
9505
|
-
|
9506
|
-
|
9507
|
-
|
9508
|
-
|
9504
|
+
_getTouchId(event) {
|
9505
|
+
const touch = (event.targetTouches && event.targetTouches[0]) || (event.changedTouches && event.changedTouches[0]);
|
9506
|
+
if (touch) {
|
9507
|
+
return touch.identifier;
|
9508
|
+
}
|
9509
|
+
return;
|
9509
9510
|
}
|
9510
|
-
|
9511
|
-
|
9512
|
-
* containerWidth to compute childrenSpace
|
9513
|
-
* <-----------containerWidth--------->
|
9514
|
-
* __________________________________
|
9515
|
-
* | || || || |
|
9516
|
-
* |<|| || ||>|
|
9517
|
-
* |_||_____________||_____________||_|
|
9518
|
-
* <-------childrenSpace------>
|
9511
|
+
/**
|
9512
|
+
* Returns if an element (or any of the element's parents) match the given selector
|
9519
9513
|
*/
|
9520
|
-
|
9521
|
-
|
9522
|
-
|
9523
|
-
|
9514
|
+
_matchesSelector(element, selector) {
|
9515
|
+
if (!element || element === document.body) {
|
9516
|
+
return false;
|
9517
|
+
}
|
9518
|
+
// eslint-disable-next-line @typescript-eslint/ban-types
|
9519
|
+
const matchesSelectorFn = element.matches || element.webkitMatchesSelector || element.msMatchesSelector; /* for IE */
|
9520
|
+
if (!matchesSelectorFn) {
|
9521
|
+
return false;
|
9522
|
+
}
|
9523
|
+
return matchesSelectorFn.call(element, selector) || this._matchesSelector(element.parentElement, selector);
|
9524
|
+
}
|
9525
|
+
/**
|
9526
|
+
* Attempts to find the Touch that matches the identifier we stored in dragStart
|
9527
|
+
* @param touchList The TouchList to look for the stored identifier from dragStart
|
9528
|
+
*/
|
9529
|
+
_findTouchInTouchList(touchList) {
|
9530
|
+
if (this._touchId === undefined) {
|
9531
|
+
return;
|
9532
|
+
}
|
9533
|
+
for (let i = 0; i < touchList.length; i++) {
|
9534
|
+
if (touchList[i].identifier === this._touchId) {
|
9535
|
+
return touchList[i];
|
9536
|
+
}
|
9537
|
+
}
|
9538
|
+
return undefined;
|
9539
|
+
}
|
9540
|
+
/**
|
9541
|
+
* Create DragData based off of the last known position and the new position passed in
|
9542
|
+
* @param position The new position as part of the drag
|
9543
|
+
*/
|
9544
|
+
_createDragDataFromPosition(position) {
|
9545
|
+
const { lastPosition } = this.state;
|
9546
|
+
// If we have no lastPosition, use the given position
|
9547
|
+
// for last position
|
9548
|
+
if (lastPosition === undefined) {
|
9549
|
+
return {
|
9550
|
+
delta: { x: 0, y: 0 },
|
9551
|
+
lastPosition: position,
|
9552
|
+
position
|
9553
|
+
};
|
9554
|
+
}
|
9555
|
+
return {
|
9556
|
+
delta: {
|
9557
|
+
x: position.x - lastPosition.x,
|
9558
|
+
y: position.y - lastPosition.y
|
9559
|
+
},
|
9560
|
+
lastPosition,
|
9561
|
+
position
|
9562
|
+
};
|
9563
|
+
}
|
9564
|
+
/**
|
9565
|
+
* Creates an updated DragData based off the current position and given baseDragData
|
9566
|
+
* @param baseDragData The base DragData (from _createDragDataFromPosition) used to calculate the updated positions
|
9567
|
+
*/
|
9568
|
+
_createUpdatedDragData(baseDragData) {
|
9569
|
+
const { position } = this.state;
|
9570
|
+
return {
|
9571
|
+
position: {
|
9572
|
+
x: position.x + baseDragData.delta.x,
|
9573
|
+
y: position.y + baseDragData.delta.y
|
9574
|
+
},
|
9575
|
+
delta: baseDragData.delta,
|
9576
|
+
lastPosition: position
|
9577
|
+
};
|
9578
|
+
}
|
9579
|
+
}
|
9580
|
+
const globalClassNames = {
|
9581
|
+
root: 'ms-Modal',
|
9582
|
+
main: 'ms-Dialog-main',
|
9583
|
+
scrollableContent: 'ms-Modal-scrollableContent',
|
9584
|
+
isOpen: 'is-open',
|
9585
|
+
layer: 'ms-Modal-Layer'
|
9586
|
+
};
|
9587
|
+
const getStyles = (props) => {
|
9588
|
+
const { className, containerClassName, scrollableContentClassName, isOpen, isVisible, hasBeenOpened, modalRectangleTop, theme, topOffsetFixed, isModeless, layerClassName, isDefaultDragHandle, windowInnerHeight } = props;
|
9589
|
+
const { palette, effects, fonts } = theme;
|
9590
|
+
const classNames = react.getGlobalClassNames(globalClassNames, theme);
|
9591
|
+
return {
|
9592
|
+
root: [
|
9593
|
+
classNames.root,
|
9594
|
+
fonts.medium,
|
9595
|
+
{
|
9596
|
+
backgroundColor: 'transparent',
|
9597
|
+
position: isModeless ? 'absolute' : 'fixed',
|
9598
|
+
height: '100%',
|
9599
|
+
width: '100%',
|
9600
|
+
display: 'flex',
|
9601
|
+
alignItems: 'center',
|
9602
|
+
justifyContent: 'center',
|
9603
|
+
opacity: 0,
|
9604
|
+
pointerEvents: 'none',
|
9605
|
+
transition: `opacity ${animationDuration}`
|
9606
|
+
},
|
9607
|
+
topOffsetFixed &&
|
9608
|
+
typeof modalRectangleTop === 'number' &&
|
9609
|
+
hasBeenOpened && {
|
9610
|
+
alignItems: 'flex-start'
|
9611
|
+
},
|
9612
|
+
isOpen && classNames.isOpen,
|
9613
|
+
isVisible && {
|
9614
|
+
opacity: 1,
|
9615
|
+
pointerEvents: 'auto'
|
9616
|
+
},
|
9617
|
+
className
|
9618
|
+
],
|
9619
|
+
main: [
|
9620
|
+
classNames.main,
|
9621
|
+
{
|
9622
|
+
boxShadow: effects.elevation64,
|
9623
|
+
borderRadius: effects.roundedCorner2,
|
9624
|
+
backgroundColor: palette.white,
|
9625
|
+
boxSizing: 'border-box',
|
9626
|
+
position: 'relative',
|
9627
|
+
textAlign: 'left',
|
9628
|
+
outline: '3px solid transparent',
|
9629
|
+
maxHeight: 'calc(100% - 32px)',
|
9630
|
+
maxWidth: 'calc(100% - 32px)',
|
9631
|
+
minHeight: '176px',
|
9632
|
+
minWidth: '288px',
|
9633
|
+
overflowY: 'auto',
|
9634
|
+
zIndex: isModeless ? react.ZIndexes.Layer : undefined
|
9635
|
+
},
|
9636
|
+
topOffsetFixed &&
|
9637
|
+
typeof modalRectangleTop === 'number' &&
|
9638
|
+
hasBeenOpened && {
|
9639
|
+
top: modalRectangleTop
|
9640
|
+
},
|
9641
|
+
isDefaultDragHandle && {
|
9642
|
+
cursor: 'move'
|
9643
|
+
},
|
9644
|
+
containerClassName
|
9645
|
+
],
|
9646
|
+
scrollableContent: [
|
9647
|
+
classNames.scrollableContent,
|
9648
|
+
{
|
9649
|
+
overflowY: 'auto',
|
9650
|
+
flexGrow: 1,
|
9651
|
+
maxHeight: '100vh',
|
9652
|
+
selectors: {
|
9653
|
+
['@supports (-webkit-overflow-scrolling: touch)']: {
|
9654
|
+
maxHeight: windowInnerHeight
|
9655
|
+
}
|
9656
|
+
}
|
9657
|
+
},
|
9658
|
+
scrollableContentClassName
|
9659
|
+
],
|
9660
|
+
layer: isModeless && [
|
9661
|
+
layerClassName,
|
9662
|
+
classNames.layer,
|
9663
|
+
{
|
9664
|
+
position: 'static',
|
9665
|
+
width: 'unset',
|
9666
|
+
height: 'unset'
|
9667
|
+
}
|
9668
|
+
],
|
9669
|
+
keyboardMoveIconContainer: {
|
9670
|
+
position: 'absolute',
|
9671
|
+
display: 'flex',
|
9672
|
+
justifyContent: 'center',
|
9673
|
+
width: '100%',
|
9674
|
+
padding: '3px 0px'
|
9675
|
+
},
|
9676
|
+
keyboardMoveIcon: {
|
9677
|
+
fontSize: fonts.xLargePlus.fontSize,
|
9678
|
+
width: '24px'
|
9679
|
+
}
|
9680
|
+
};
|
9524
9681
|
};
|
9682
|
+
/** @internal */
|
9683
|
+
const _ModalClone = react.styled(ModalBase, getStyles, undefined, {
|
9684
|
+
scope: 'Modal',
|
9685
|
+
fields: ['theme', 'styles', 'enableAriaHiddenSiblings']
|
9686
|
+
});
|
9687
|
+
_ModalClone.displayName = 'Modal';
|
9525
9688
|
|
9526
9689
|
// Copyright (c) Microsoft Corporation.
|
9527
|
-
|
9528
|
-
|
9529
|
-
|
9530
|
-
|
9531
|
-
|
9532
|
-
* Large floating modal width and height in rem for large screen
|
9533
|
-
*/
|
9534
|
-
const LARGE_FLOATING_MODAL_SIZE_PX = { width: 160, height: 120 };
|
9535
|
-
/**
|
9536
|
-
* @private
|
9537
|
-
*/
|
9538
|
-
const horizontalGalleryContainerStyle = (shouldFloatLocalVideo, isNarrow) => {
|
9539
|
-
return {
|
9540
|
-
minHeight: isNarrow
|
9541
|
-
? `${SMALL_HORIZONTAL_GALLERY_TILE_SIZE_REM.height}rem`
|
9542
|
-
: `${LARGE_HORIZONTAL_GALLERY_TILE_SIZE_REM.height}rem`,
|
9543
|
-
width: shouldFloatLocalVideo
|
9544
|
-
? isNarrow
|
9545
|
-
? `calc(100% - ${_pxToRem(SMALL_FLOATING_MODAL_SIZE_PX.width)})`
|
9546
|
-
: `calc(100% - ${_pxToRem(LARGE_FLOATING_MODAL_SIZE_PX.width)})`
|
9547
|
-
: '100%',
|
9548
|
-
paddingRight: '0.5rem'
|
9549
|
-
};
|
9690
|
+
const DRAG_OPTIONS$1 = {
|
9691
|
+
moveMenuItemText: 'Move',
|
9692
|
+
closeMenuItemText: 'Close',
|
9693
|
+
menu: react.ContextualMenu,
|
9694
|
+
keepInBounds: true
|
9550
9695
|
};
|
9696
|
+
// Manually override the max position used to keep the modal in the bounds of its container.
|
9697
|
+
// This is a workaround for: https://github.com/microsoft/fluentui/issues/20122
|
9698
|
+
// Because our modal starts in the bottom right corner, we can say that this is the max (i.e. rightmost and bottomost)
|
9699
|
+
// position the modal can be dragged to.
|
9700
|
+
const modalMaxDragPosition = { x: localVideoTileOuterPaddingPX, y: localVideoTileOuterPaddingPX };
|
9551
9701
|
/**
|
9552
9702
|
* @private
|
9553
9703
|
*/
|
9554
|
-
const
|
9555
|
-
|
9556
|
-
|
9557
|
-
|
9704
|
+
const FloatingLocalVideo = (props) => {
|
9705
|
+
const { localVideoComponent, layerHostId, isNarrow, parentWidth, parentHeight } = props;
|
9706
|
+
const theme = useTheme();
|
9707
|
+
const modalWidth = isNarrow ? SMALL_FLOATING_MODAL_SIZE_PX.width : LARGE_FLOATING_MODAL_SIZE_PX.width;
|
9708
|
+
const modalHeight = isNarrow ? SMALL_FLOATING_MODAL_SIZE_PX.height : LARGE_FLOATING_MODAL_SIZE_PX.height;
|
9709
|
+
// The minimum drag position is the top left of the video gallery. i.e. the modal (PiP) should not be able
|
9710
|
+
// to be dragged offscreen and these are the top and left bounds of that calculation.
|
9711
|
+
const modalMinDragPosition = React.useMemo(() => parentWidth && parentHeight
|
9712
|
+
? {
|
9713
|
+
// We use -parentWidth/Height because our modal is positioned to start in the bottom right,
|
9714
|
+
// hence (0,0) is the bottom right of the video gallery.
|
9715
|
+
x: -parentWidth + modalWidth + localVideoTileOuterPaddingPX,
|
9716
|
+
y: -parentHeight + modalHeight + localVideoTileOuterPaddingPX
|
9717
|
+
}
|
9718
|
+
: undefined, [parentHeight, parentWidth, modalHeight, modalWidth]);
|
9719
|
+
const modalStyles = React.useMemo(() => floatingLocalVideoModalStyle(theme, isNarrow), [theme, isNarrow]);
|
9720
|
+
const layerProps = React.useMemo(() => ({ hostId: layerHostId }), [layerHostId]);
|
9721
|
+
return (React__default['default'].createElement(_ModalClone, { isOpen: true, isModeless: true, dragOptions: DRAG_OPTIONS$1, styles: modalStyles, layerProps: layerProps, maxDragPosition: modalMaxDragPosition, minDragPosition: modalMinDragPosition }, localVideoComponent));
|
9558
9722
|
};
|
9559
|
-
|
9560
|
-
|
9561
|
-
|
9562
|
-
*/
|
9563
|
-
const SMALL_HORIZONTAL_GALLERY_TILE_SIZE_REM = { height: 5.5, width: 5.5 };
|
9564
|
-
/**
|
9565
|
-
* Large horizontal gallery tile size in rem
|
9566
|
-
* @private
|
9567
|
-
*/
|
9568
|
-
const LARGE_HORIZONTAL_GALLERY_TILE_SIZE_REM = { height: 7.5, width: 10 };
|
9723
|
+
|
9724
|
+
// Copyright (c) Microsoft Corporation.
|
9725
|
+
// Licensed under the MIT license.
|
9569
9726
|
/**
|
9570
9727
|
* @private
|
9571
9728
|
*/
|
9572
|
-
const
|
9573
|
-
|
9574
|
-
minWidth: `${SMALL_HORIZONTAL_GALLERY_TILE_SIZE_REM.width}rem`,
|
9575
|
-
maxHeight: `${SMALL_HORIZONTAL_GALLERY_TILE_SIZE_REM.height}rem`,
|
9576
|
-
maxWidth: `${SMALL_HORIZONTAL_GALLERY_TILE_SIZE_REM.width}rem`
|
9729
|
+
const rootLayoutStyle = {
|
9730
|
+
root: { position: 'relative', height: '100%', width: '100%' }
|
9577
9731
|
};
|
9578
9732
|
/**
|
9579
9733
|
* @private
|
9580
9734
|
*/
|
9581
|
-
const
|
9582
|
-
|
9583
|
-
minWidth: `${LARGE_HORIZONTAL_GALLERY_TILE_SIZE_REM.width}rem`,
|
9584
|
-
maxHeight: `${LARGE_HORIZONTAL_GALLERY_TILE_SIZE_REM.height}rem`,
|
9585
|
-
maxWidth: `${LARGE_HORIZONTAL_GALLERY_TILE_SIZE_REM.width}rem`
|
9586
|
-
};
|
9587
|
-
|
9588
|
-
// Copyright (c) Microsoft Corporation.
|
9589
|
-
/**
|
9590
|
-
* A ResponsiveHorizontalGallery styled for the @link{VideoGallery}
|
9591
|
-
*/
|
9592
|
-
const VideoGalleryResponsiveHorizontalGallery = (props) => {
|
9593
|
-
const { shouldFloatLocalVideo = false, isNarrow = false, horizontalGalleryElements, styles } = props;
|
9594
|
-
const containerStyles = React.useMemo(() => horizontalGalleryContainerStyle(shouldFloatLocalVideo, isNarrow), [shouldFloatLocalVideo, isNarrow]);
|
9595
|
-
const galleryStyles = React.useMemo(() => react.concatStyleSets(horizontalGalleryStyle(isNarrow), styles), [isNarrow, styles]);
|
9596
|
-
return (React__default['default'].createElement(react.Stack, { styles: { root: { paddingTop: '0.5rem' } } },
|
9597
|
-
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)));
|
9735
|
+
const innerLayoutStyle = {
|
9736
|
+
root: { position: 'relative', height: '100%', width: '100%', padding: '0.5rem' }
|
9598
9737
|
};
|
9599
|
-
|
9600
|
-
// Copyright (c) Microsoft Corporation.
|
9601
|
-
const DEFAULT_MAX_REMOTE_VIDEOSTREAMS = 4;
|
9602
|
-
const DEFAULT_MAX_AUDIO_DOMINANT_SPEAKERS = 6;
|
9603
9738
|
/**
|
9604
9739
|
* @private
|
9605
9740
|
*/
|
9606
|
-
const
|
9607
|
-
|
9608
|
-
|
9609
|
-
|
9610
|
-
|
9611
|
-
|
9612
|
-
|
9613
|
-
|
9614
|
-
|
9615
|
-
maxDominantSpeakers: maxRemoteVideoStreams
|
9616
|
-
}).slice(0, maxRemoteVideoStreams);
|
9617
|
-
const visibleVideoParticipantsSet = new Set(visibleVideoParticipants.current.map((p) => p.userId));
|
9618
|
-
/* @conditional-compile-remove(PSTN-calls) */ /* @conditional-compile-remove(one-to-n-calling) */
|
9619
|
-
const callingParticipants = remoteParticipants.filter((p) => p.state === ('Connecting' ));
|
9620
|
-
/* @conditional-compile-remove(PSTN-calls) */ /* @conditional-compile-remove(one-to-n-calling) */
|
9621
|
-
const callingParticipantsSet = new Set(callingParticipants.map((p) => p.userId));
|
9622
|
-
visibleAudioParticipants.current = smartDominantSpeakerParticipants({
|
9623
|
-
participants: (_b = remoteParticipants === null || remoteParticipants === void 0 ? void 0 : remoteParticipants.filter((p) => !visibleVideoParticipantsSet.has(p.userId) &&
|
9624
|
-
/* @conditional-compile-remove(PSTN-calls) */ /* @conditional-compile-remove(one-to-n-calling) */ !callingParticipantsSet.has(p.userId))) !== null && _b !== void 0 ? _b : [],
|
9625
|
-
dominantSpeakers,
|
9626
|
-
lastVisibleParticipants: visibleAudioParticipants.current,
|
9627
|
-
maxDominantSpeakers: maxAudioDominantSpeakers
|
9628
|
-
});
|
9629
|
-
const getGridParticipants = React.useCallback(() => {
|
9630
|
-
/* @conditional-compile-remove(PSTN-calls) */ /* @conditional-compile-remove(one-to-n-calling) */
|
9631
|
-
return visibleVideoParticipants.current.length > 0
|
9632
|
-
? visibleVideoParticipants.current
|
9633
|
-
: visibleAudioParticipants.current.concat(callingParticipants);
|
9634
|
-
}, [
|
9635
|
-
/* @conditional-compile-remove(PSTN-calls) */ /* @conditional-compile-remove(one-to-n-calling) */ callingParticipants
|
9636
|
-
]);
|
9637
|
-
const gridParticipants = getGridParticipants();
|
9638
|
-
const getHorizontalGalleryRemoteParticipants = React.useCallback(() => {
|
9639
|
-
if (isScreenShareActive) {
|
9640
|
-
// If screen sharing is active, assign video and audio participants as horizontal gallery participants
|
9641
|
-
/* @conditional-compile-remove(PSTN-calls) */ /* @conditional-compile-remove(one-to-n-calling) */
|
9642
|
-
return visibleVideoParticipants.current.concat(visibleAudioParticipants.current.concat(callingParticipants));
|
9643
|
-
}
|
9644
|
-
else {
|
9645
|
-
// If screen sharing is not active, then assign all video tiles as grid tiles.
|
9646
|
-
// If there are no video tiles, then assign audio tiles as grid tiles.
|
9647
|
-
/* @conditional-compile-remove(PSTN-calls) */ /* @conditional-compile-remove(one-to-n-calling) */
|
9648
|
-
return visibleVideoParticipants.current.length > 0
|
9649
|
-
? visibleAudioParticipants.current.concat(callingParticipants)
|
9650
|
-
: [];
|
9651
|
-
}
|
9652
|
-
}, [
|
9653
|
-
/* @conditional-compile-remove(PSTN-calls) */ /* @conditional-compile-remove(one-to-n-calling) */ callingParticipants,
|
9654
|
-
isScreenShareActive
|
9655
|
-
]);
|
9656
|
-
const horizontalGalleryParticipants = getHorizontalGalleryRemoteParticipants();
|
9657
|
-
return { gridParticipants, horizontalGalleryParticipants };
|
9741
|
+
const layerHostStyle = {
|
9742
|
+
position: 'absolute',
|
9743
|
+
left: 0,
|
9744
|
+
top: 0,
|
9745
|
+
width: '100%',
|
9746
|
+
height: '100%',
|
9747
|
+
overflow: 'hidden',
|
9748
|
+
// pointer events for layerHost set to none to make descendants interactive
|
9749
|
+
pointerEvents: 'none'
|
9658
9750
|
};
|
9659
9751
|
|
9660
9752
|
// Copyright (c) Microsoft Corporation.
|
9661
9753
|
/**
|
9662
|
-
*
|
9663
|
-
* a grid and horizontal gallery
|
9754
|
+
* FloatingLocalVideoLayout displays remote participants and a screen sharing component in
|
9755
|
+
* a grid and horizontal gallery while floating the local video
|
9664
9756
|
*
|
9665
9757
|
* @private
|
9666
9758
|
*/
|
9667
|
-
const
|
9668
|
-
const { remoteParticipants = [], dominantSpeakers, localVideoComponent, screenShareComponent, onRenderRemoteParticipant, styles, maxRemoteVideoStreams, parentWidth } = props;
|
9759
|
+
const FloatingLocalVideoLayout = (props) => {
|
9760
|
+
const { remoteParticipants = [], dominantSpeakers, localVideoComponent, screenShareComponent, onRenderRemoteParticipant, styles, maxRemoteVideoStreams, showCameraSwitcherInLocalPreview, parentWidth, parentHeight } = props;
|
9761
|
+
const theme = useTheme();
|
9669
9762
|
const isNarrow = parentWidth ? isNarrowWidth(parentWidth) : false;
|
9670
9763
|
const floatingLocalVideoLayout = useFloatingLocalVideoLayout({
|
9671
9764
|
remoteParticipants,
|
@@ -9680,18 +9773,29 @@ const DefaultLayout = (props) => {
|
|
9680
9773
|
? ((_a = p.videoStream) === null || _a === void 0 ? void 0 : _a.isAvailable) && activeVideoStreams++ < maxRemoteVideoStreams
|
9681
9774
|
: (_b = p.videoStream) === null || _b === void 0 ? void 0 : _b.isAvailable);
|
9682
9775
|
});
|
9776
|
+
const shouldFloatLocalVideo = remoteParticipants.length > 0;
|
9777
|
+
if (!shouldFloatLocalVideo && localVideoComponent) {
|
9778
|
+
gridTiles.push(localVideoComponent);
|
9779
|
+
}
|
9683
9780
|
const horizontalGalleryTiles = floatingLocalVideoLayout.horizontalGalleryParticipants.map((p) => {
|
9684
9781
|
var _a, _b;
|
9685
9782
|
return onRenderRemoteParticipant(p, maxRemoteVideoStreams && maxRemoteVideoStreams >= 0
|
9686
9783
|
? ((_a = p.videoStream) === null || _a === void 0 ? void 0 : _a.isAvailable) && activeVideoStreams++ < maxRemoteVideoStreams
|
9687
9784
|
: (_b = p.videoStream) === null || _b === void 0 ? void 0 : _b.isAvailable);
|
9688
9785
|
});
|
9689
|
-
|
9690
|
-
|
9691
|
-
|
9692
|
-
|
9693
|
-
|
9694
|
-
|
9786
|
+
const layerHostId = reactHooks.useId('layerhost');
|
9787
|
+
const wrappedLocalVideoComponent = localVideoComponent && shouldFloatLocalVideo ? (
|
9788
|
+
// When we use showCameraSwitcherInLocalPreview it disables dragging to allow keyboard navigation.
|
9789
|
+
showCameraSwitcherInLocalPreview ? (React__default['default'].createElement(react.Stack, { className: react.mergeStyles(localVideoTileWithControlsContainerStyle(theme, isNarrow), {
|
9790
|
+
boxShadow: theme.effects.elevation8,
|
9791
|
+
zIndex: LOCAL_VIDEO_TILE_ZINDEX
|
9792
|
+
}) }, 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;
|
9793
|
+
return (React__default['default'].createElement(react.Stack, { styles: rootLayoutStyle },
|
9794
|
+
wrappedLocalVideoComponent,
|
9795
|
+
React__default['default'].createElement(react.Stack, { horizontal: false, styles: innerLayoutStyle },
|
9796
|
+
screenShareComponent ? (screenShareComponent) : (React__default['default'].createElement(GridLayout, { key: "grid-layout", styles: styles === null || styles === void 0 ? void 0 : styles.gridLayout }, gridTiles)),
|
9797
|
+
horizontalGalleryTiles.length > 0 && (React__default['default'].createElement(VideoGalleryResponsiveHorizontalGallery, { isNarrow: isNarrow, shouldFloatLocalVideo: true, horizontalGalleryElements: horizontalGalleryTiles, styles: styles === null || styles === void 0 ? void 0 : styles.horizontalGallery })),
|
9798
|
+
React__default['default'].createElement(react.LayerHost, { id: layerHostId, className: react.mergeStyles(layerHostStyle) }))));
|
9695
9799
|
};
|
9696
9800
|
|
9697
9801
|
// Copyright (c) Microsoft Corporation.
|
@@ -9700,22 +9804,6 @@ const DefaultLayout = (props) => {
|
|
9700
9804
|
* Currently the Calling JS SDK supports up to 4 remote video streams
|
9701
9805
|
*/
|
9702
9806
|
const DEFAULT_MAX_REMOTE_VIDEO_STREAMS = 4;
|
9703
|
-
/**
|
9704
|
-
* @private
|
9705
|
-
* Set aside only 6 dominant speakers for remaining audio participants
|
9706
|
-
*/
|
9707
|
-
const MAX_AUDIO_DOMINANT_SPEAKERS = 6;
|
9708
|
-
const DRAG_OPTIONS$1 = {
|
9709
|
-
moveMenuItemText: 'Move',
|
9710
|
-
closeMenuItemText: 'Close',
|
9711
|
-
menu: react.ContextualMenu,
|
9712
|
-
keepInBounds: true
|
9713
|
-
};
|
9714
|
-
// Manually override the max position used to keep the modal in the bounds of its container.
|
9715
|
-
// This is a workaround for: https://github.com/microsoft/fluentui/issues/20122
|
9716
|
-
// Because our modal starts in the bottom right corner, we can say that this is the max (i.e. rightmost and bottomost)
|
9717
|
-
// position the modal can be dragged to.
|
9718
|
-
const modalMaxDragPosition = { x: localVideoTileOuterPaddingPX, y: localVideoTileOuterPaddingPX };
|
9719
9807
|
/**
|
9720
9808
|
* VideoGallery represents a layout of video tiles for a specific call.
|
9721
9809
|
* It displays a {@link VideoTile} for the local user as well as for each remote participant who has joined the call.
|
@@ -9723,53 +9811,17 @@ const modalMaxDragPosition = { x: localVideoTileOuterPaddingPX, y: localVideoTil
|
|
9723
9811
|
* @public
|
9724
9812
|
*/
|
9725
9813
|
const VideoGallery = (props) => {
|
9726
|
-
var _a, _b
|
9814
|
+
var _a, _b;
|
9727
9815
|
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;
|
9728
9816
|
const ids = useIdentifiers();
|
9729
9817
|
const theme = useTheme();
|
9730
9818
|
const localeStrings = useLocale$1().strings.videoGallery;
|
9731
9819
|
const strings = Object.assign(Object.assign({}, localeStrings), props.strings);
|
9732
9820
|
const shouldFloatLocalVideo = !!(layout === 'floatingLocalVideo' && remoteParticipants.length > 0);
|
9733
|
-
const shouldFloatNonDraggableLocalVideo = !!(showCameraSwitcherInLocalPreview && shouldFloatLocalVideo);
|
9734
9821
|
const containerRef = React.useRef(null);
|
9735
9822
|
const containerWidth = _useContainerWidth(containerRef);
|
9736
9823
|
const containerHeight = _useContainerHeight(containerRef);
|
9737
9824
|
const isNarrow = containerWidth ? isNarrowWidth(containerWidth) : false;
|
9738
|
-
const visibleVideoParticipants = React.useRef([]);
|
9739
|
-
const visibleAudioParticipants = React.useRef([]);
|
9740
|
-
/* @conditional-compile-remove(PSTN-calls) */ /* @conditional-compile-remove(one-to-n-calling) */
|
9741
|
-
const visibleCallingParticipants = React.useRef([]);
|
9742
|
-
const modalWidth = isNarrow ? SMALL_FLOATING_MODAL_SIZE_PX$1.width : LARGE_FLOATING_MODAL_SIZE_PX$1.width;
|
9743
|
-
const modalHeight = isNarrow ? SMALL_FLOATING_MODAL_SIZE_PX$1.height : LARGE_FLOATING_MODAL_SIZE_PX$1.height;
|
9744
|
-
// The minimum drag position is the top left of the video gallery. i.e. the modal (PiP) should not be able
|
9745
|
-
// to be dragged offscreen and these are the top and left bounds of that calculation.
|
9746
|
-
const modalMinDragPosition = React.useMemo(() => containerWidth && containerHeight
|
9747
|
-
? {
|
9748
|
-
// We use -containerWidth/Height because our modal is positioned to start in the bottom right,
|
9749
|
-
// hence (0,0) is the bottom right of the video gallery.
|
9750
|
-
x: -containerWidth + modalWidth + localVideoTileOuterPaddingPX,
|
9751
|
-
y: -containerHeight + modalHeight + localVideoTileOuterPaddingPX
|
9752
|
-
}
|
9753
|
-
: undefined, [containerHeight, containerWidth, modalHeight, modalWidth]);
|
9754
|
-
visibleVideoParticipants.current = smartDominantSpeakerParticipants({
|
9755
|
-
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 : [],
|
9756
|
-
dominantSpeakers,
|
9757
|
-
lastVisibleParticipants: visibleVideoParticipants.current,
|
9758
|
-
maxDominantSpeakers: maxRemoteVideoStreams
|
9759
|
-
}).slice(0, maxRemoteVideoStreams);
|
9760
|
-
/* @conditional-compile-remove(PSTN-calls) */ /* @conditional-compile-remove(one-to-n-calling) */
|
9761
|
-
visibleCallingParticipants.current = (_b = remoteParticipants === null || remoteParticipants === void 0 ? void 0 : remoteParticipants.filter((p) => p.state === ('Connecting' ))) !== null && _b !== void 0 ? _b : [];
|
9762
|
-
// This set will be used to filter out participants already in visibleVideoParticipants
|
9763
|
-
const visibleVideoParticipantsSet = new Set(visibleVideoParticipants.current.map((p) => p.userId));
|
9764
|
-
/* @conditional-compile-remove(PSTN-calls) */ /* @conditional-compile-remove(one-to-n-calling) */
|
9765
|
-
const visibleCallingParticipantsSet = new Set(visibleCallingParticipants.current.map((p) => p.userId));
|
9766
|
-
visibleAudioParticipants.current = smartDominantSpeakerParticipants({
|
9767
|
-
participants: (_c = remoteParticipants === null || remoteParticipants === void 0 ? void 0 : remoteParticipants.filter((p) => !visibleVideoParticipantsSet.has(p.userId) &&
|
9768
|
-
/* @conditional-compile-remove(PSTN-calls) */ /* @conditional-compile-remove(one-to-n-calling) */ !visibleCallingParticipantsSet.has(p.userId))) !== null && _c !== void 0 ? _c : [],
|
9769
|
-
dominantSpeakers,
|
9770
|
-
lastVisibleParticipants: visibleAudioParticipants.current,
|
9771
|
-
maxDominantSpeakers: MAX_AUDIO_DOMINANT_SPEAKERS
|
9772
|
-
});
|
9773
9825
|
/* @conditional-compile-remove(rooms) */
|
9774
9826
|
const permissions = _usePermissions();
|
9775
9827
|
/**
|
@@ -9817,73 +9869,16 @@ const VideoGallery = (props) => {
|
|
9817
9869
|
/* @conditional-compile-remove(PSTN-calls) */
|
9818
9870
|
participantState: participant.state })));
|
9819
9871
|
}, [onCreateRemoteStreamView, onDisposeRemoteStreamView, remoteVideoViewOptions, onRenderAvatar, showMuteIndicator]);
|
9820
|
-
const videoTiles = onRenderRemoteVideoTile
|
9821
|
-
? visibleVideoParticipants.current.map((participant) => onRenderRemoteVideoTile(participant))
|
9822
|
-
: visibleVideoParticipants.current.map((participant) => {
|
9823
|
-
return defaultOnRenderVideoTile(participant, true);
|
9824
|
-
});
|
9825
|
-
const audioTiles = onRenderRemoteVideoTile
|
9826
|
-
? visibleAudioParticipants.current.map((participant) => onRenderRemoteVideoTile(participant))
|
9827
|
-
: visibleAudioParticipants.current.map((participant) => {
|
9828
|
-
return defaultOnRenderVideoTile(participant, false);
|
9829
|
-
});
|
9830
|
-
/* @conditional-compile-remove(PSTN-calls) */ /* @conditional-compile-remove(one-to-n-calling) */
|
9831
|
-
const callingTiles = onRenderRemoteVideoTile
|
9832
|
-
? visibleCallingParticipants.current.map((participant) => onRenderRemoteVideoTile(participant))
|
9833
|
-
: visibleCallingParticipants.current.map((participant) => {
|
9834
|
-
return defaultOnRenderVideoTile(participant, false);
|
9835
|
-
});
|
9836
9872
|
const screenShareParticipant = remoteParticipants.find((participant) => { var _a; return (_a = participant.screenShareStream) === null || _a === void 0 ? void 0 : _a.isAvailable; });
|
9837
|
-
const screenShareActive = screenShareParticipant || (localParticipant === null || localParticipant === void 0 ? void 0 : localParticipant.isScreenSharingOn);
|
9838
|
-
const createGridTiles = () => {
|
9839
|
-
/* @conditional-compile-remove(PSTN-calls) */ /* @conditional-compile-remove(one-to-n-calling) */
|
9840
|
-
return videoTiles.length > 0 ? videoTiles : audioTiles.concat(callingTiles);
|
9841
|
-
};
|
9842
|
-
const gridTiles = createGridTiles();
|
9843
|
-
const createHorizontalGalleryTiles = () => {
|
9844
|
-
if (screenShareActive) {
|
9845
|
-
// If screen sharing is active, assign video and audio participants as horizontal gallery participants
|
9846
|
-
/* @conditional-compile-remove(PSTN-calls) */ /* @conditional-compile-remove(one-to-n-calling) */
|
9847
|
-
return videoTiles.concat(audioTiles.concat(callingTiles));
|
9848
|
-
}
|
9849
|
-
else {
|
9850
|
-
// If screen sharing is not active, then assign all video tiles as grid tiles.
|
9851
|
-
// If there are no video tiles, then assign audio tiles as grid tiles.
|
9852
|
-
/* @conditional-compile-remove(PSTN-calls) */ /* @conditional-compile-remove(one-to-n-calling) */
|
9853
|
-
return videoTiles.length > 0 ? audioTiles.concat(callingTiles) : [];
|
9854
|
-
}
|
9855
|
-
};
|
9856
|
-
const horizontalGalleryTiles = createHorizontalGalleryTiles();
|
9857
|
-
if (!shouldFloatLocalVideo && localVideoTile) {
|
9858
|
-
gridTiles.push(localVideoTile);
|
9859
|
-
}
|
9860
9873
|
const localScreenShareStreamComponent = React__default['default'].createElement(LocalScreenShare, { localParticipant: localParticipant });
|
9861
|
-
const remoteScreenShareComponent = screenShareParticipant && (React__default['default'].createElement(RemoteScreenShare, Object.assign({}, screenShareParticipant, { renderElement: (
|
9862
|
-
const horizontalGalleryPresent = horizontalGalleryTiles && horizontalGalleryTiles.length > 0;
|
9863
|
-
const layerHostId = reactHooks.useId('layerhost');
|
9864
|
-
if (layout === 'floatingLocalVideo') {
|
9865
|
-
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) },
|
9866
|
-
shouldFloatLocalVideo &&
|
9867
|
-
!shouldFloatNonDraggableLocalVideo &&
|
9868
|
-
localVideoTile &&
|
9869
|
-
(horizontalGalleryPresent ? (React__default['default'].createElement(react.Stack, { className: react.mergeStyles(localVideoTileContainerStyle(theme, isNarrow)) }, localVideoTile)) : (React__default['default'].createElement(_ModalClone, { isOpen: true, isModeless: true, dragOptions: DRAG_OPTIONS$1, styles: floatingLocalVideoModalStyle(theme, isNarrow), layerProps: { hostId: layerHostId }, maxDragPosition: modalMaxDragPosition, minDragPosition: modalMinDragPosition }, localVideoTile))),
|
9870
|
-
// When we use showCameraSwitcherInLocalPreview it disables dragging to allow keyboard navigation.
|
9871
|
-
shouldFloatNonDraggableLocalVideo && localVideoTile && remoteParticipants.length > 0 && (React__default['default'].createElement(react.Stack, { className: react.mergeStyles(localVideoTileWithControlsContainerStyle(theme, isNarrow), {
|
9872
|
-
boxShadow: theme.effects.elevation8,
|
9873
|
-
zIndex: LOCAL_VIDEO_TILE_ZINDEX
|
9874
|
-
}) }, localVideoTile)),
|
9875
|
-
React__default['default'].createElement(react.Stack, { horizontal: false, styles: videoGalleryContainerStyle },
|
9876
|
-
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)),
|
9877
|
-
horizontalGalleryPresent && (React__default['default'].createElement(VideoGalleryResponsiveHorizontalGallery, { shouldFloatLocalVideo: true, isNarrow: isNarrow, horizontalGalleryElements: horizontalGalleryTiles, styles: styles === null || styles === void 0 ? void 0 : styles.horizontalGallery })),
|
9878
|
-
React__default['default'].createElement(react.LayerHost, { id: layerHostId, className: react.mergeStyles(layerHostStyle) }))));
|
9879
|
-
}
|
9874
|
+
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 })));
|
9880
9875
|
const screenShareComponent = remoteScreenShareComponent
|
9881
9876
|
? remoteScreenShareComponent
|
9882
9877
|
: localParticipant.isScreenSharingOn
|
9883
9878
|
? localScreenShareStreamComponent
|
9884
9879
|
: undefined;
|
9885
|
-
|
9886
|
-
|
9880
|
+
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 }));
|
9881
|
+
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));
|
9887
9882
|
};
|
9888
9883
|
|
9889
9884
|
// Copyright (c) Microsoft Corporation.
|
@@ -10582,7 +10577,7 @@ const DomainPermissionsContainer = (props) => {
|
|
10582
10577
|
var _a, _b;
|
10583
10578
|
const { appName, onTroubleshootingClick, onPrimaryButtonClick, strings } = props;
|
10584
10579
|
const theme = react.useTheme();
|
10585
|
-
return (React__default['default'].createElement(react.Stack, { style: { padding: '2rem', maxWidth: '25.375rem' }, "aria-label": strings === null || strings === void 0 ? void 0 : strings.ariaLabel },
|
10580
|
+
return (React__default['default'].createElement(react.Stack, { style: { padding: '2rem', maxWidth: '25.375rem', alignSelf: 'center' }, "aria-label": strings === null || strings === void 0 ? void 0 : strings.ariaLabel },
|
10586
10581
|
React__default['default'].createElement(react.Stack, { styles: iconBannerContainerStyles, horizontal: true, horizontalAlign: 'center', verticalFill: true, tokens: tokens },
|
10587
10582
|
props.cameraIconName && (React__default['default'].createElement(react.Stack, null,
|
10588
10583
|
React__default['default'].createElement(react.Icon, { styles: iconPrimaryStyles, iconName: props.cameraIconName }))),
|
@@ -11582,6 +11577,14 @@ const DialpadContainer = (props) => {
|
|
11582
11577
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
11583
11578
|
onChange: (e) => {
|
11584
11579
|
setText(e.target.value);
|
11580
|
+
},
|
11581
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
11582
|
+
onClick: (e) => {
|
11583
|
+
const input = e.target;
|
11584
|
+
const end = input.value.length;
|
11585
|
+
// Move focus to end of input field
|
11586
|
+
input.setSelectionRange(end, end);
|
11587
|
+
input.focus();
|
11585
11588
|
}, placeholder: props.strings.placeholderText, "data-test-id": "dialpad-input", onRenderSuffix: () => {
|
11586
11589
|
var _a;
|
11587
11590
|
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' } }))));
|
@@ -11945,6 +11948,21 @@ const convertRemoteVideoStreamToVideoGalleryStream = (stream) => {
|
|
11945
11948
|
scalingMode: (_c = stream.view) === null || _c === void 0 ? void 0 : _c.scalingMode
|
11946
11949
|
};
|
11947
11950
|
};
|
11951
|
+
/** @private */
|
11952
|
+
const memoizeLocalParticipant = memoizeOne__default['default']((identifier, displayName, isMuted, isScreenSharingOn, localVideoStream) => {
|
11953
|
+
var _a, _b;
|
11954
|
+
return ({
|
11955
|
+
userId: identifier,
|
11956
|
+
displayName: displayName !== null && displayName !== void 0 ? displayName : '',
|
11957
|
+
isMuted: isMuted,
|
11958
|
+
isScreenSharingOn: isScreenSharingOn,
|
11959
|
+
videoStream: {
|
11960
|
+
isAvailable: !!localVideoStream,
|
11961
|
+
isMirrored: (_a = localVideoStream === null || localVideoStream === void 0 ? void 0 : localVideoStream.view) === null || _a === void 0 ? void 0 : _a.isMirrored,
|
11962
|
+
renderElement: (_b = localVideoStream === null || localVideoStream === void 0 ? void 0 : localVideoStream.view) === null || _b === void 0 ? void 0 : _b.target
|
11963
|
+
}
|
11964
|
+
});
|
11965
|
+
});
|
11948
11966
|
|
11949
11967
|
// Copyright (c) Microsoft Corporation.
|
11950
11968
|
/**
|
@@ -11961,7 +11979,6 @@ const videoGallerySelector = reselect.createSelector([
|
|
11961
11979
|
getIdentifier,
|
11962
11980
|
getDominantSpeakers
|
11963
11981
|
], (screenShareRemoteParticipantId, remoteParticipants, localVideoStreams, isMuted, isScreenSharingOn, displayName, identifier, dominantSpeakers) => {
|
11964
|
-
var _a, _b;
|
11965
11982
|
const screenShareRemoteParticipant = screenShareRemoteParticipantId && remoteParticipants
|
11966
11983
|
? remoteParticipants[screenShareRemoteParticipantId]
|
11967
11984
|
: undefined;
|
@@ -11973,17 +11990,7 @@ const videoGallerySelector = reselect.createSelector([
|
|
11973
11990
|
screenShareParticipant: screenShareRemoteParticipant
|
11974
11991
|
? convertRemoteParticipantToVideoGalleryRemoteParticipant(toFlatCommunicationIdentifier(screenShareRemoteParticipant.identifier), screenShareRemoteParticipant.isMuted, checkIsSpeaking(screenShareRemoteParticipant), screenShareRemoteParticipant.videoStreams, screenShareRemoteParticipant.state, screenShareRemoteParticipant.displayName)
|
11975
11992
|
: undefined,
|
11976
|
-
localParticipant:
|
11977
|
-
userId: identifier,
|
11978
|
-
displayName: displayName !== null && displayName !== void 0 ? displayName : '',
|
11979
|
-
isMuted: isMuted,
|
11980
|
-
isScreenSharingOn: isScreenSharingOn,
|
11981
|
-
videoStream: {
|
11982
|
-
isAvailable: !!localVideoStream,
|
11983
|
-
isMirrored: (_a = localVideoStream === null || localVideoStream === void 0 ? void 0 : localVideoStream.view) === null || _a === void 0 ? void 0 : _a.isMirrored,
|
11984
|
-
renderElement: (_b = localVideoStream === null || localVideoStream === void 0 ? void 0 : localVideoStream.view) === null || _b === void 0 ? void 0 : _b.target
|
11985
|
-
}
|
11986
|
-
},
|
11993
|
+
localParticipant: memoizeLocalParticipant(identifier, displayName, isMuted, isScreenSharingOn, localVideoStream),
|
11987
11994
|
remoteParticipants: _videoGalleryRemoteParticipantsMemo(updateUserDisplayNamesTrampoline$2(remoteParticipants ? Object.values(remoteParticipants) : noRemoteParticipants)),
|
11988
11995
|
dominantSpeakers: dominantSpeakerIds
|
11989
11996
|
};
|