@whereby.com/browser-sdk 3.31.2 → 3.32.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/cdn/v3-react.js +10 -10
- package/dist/react/index.cjs +525 -87
- package/dist/react/index.d.ts +197 -5
- package/dist/react/index.esm.js +508 -90
- package/package.json +3 -3
package/dist/react/index.esm.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import * as React from 'react';
|
|
2
|
-
import { WherebyClient, CURRENT_SPEAKER_CHANGED, debounce } from '@whereby.com/core';
|
|
3
|
-
export { ACCEPTED_FILE_TYPES, MAX_FILES_PER_UPLOAD, MAX_FILE_SIZE, getUsableCameraEffectPresets, isAudioDenoiserSupported } from '@whereby.com/core';
|
|
2
|
+
import { WherebyClient, CURRENT_SPEAKER_CHANGED, debounce, ROOM_INTEGRATION_PICKER_MESSAGES, roomIntegrationPickerUrl } from '@whereby.com/core';
|
|
3
|
+
export { ACCEPTED_FILE_TYPES, MAX_FILES_PER_UPLOAD, MAX_FILE_SIZE, ROOM_INTEGRATION_PICKER_MESSAGES, getUsableCameraEffectPresets, isAudioDenoiserSupported, roomIntegrationContent, roomIntegrationContentTagName, roomIntegrationPickerUrl } from '@whereby.com/core';
|
|
4
4
|
import runes from 'runes';
|
|
5
5
|
import * as PopoverPrimitive from '@radix-ui/react-popover';
|
|
6
6
|
|
|
@@ -151,7 +151,7 @@ const VideoView = React.forwardRef((_a, ref) => {
|
|
|
151
151
|
});
|
|
152
152
|
VideoView.displayName = "VideoView";
|
|
153
153
|
|
|
154
|
-
const browserSdkVersion = "3.
|
|
154
|
+
const browserSdkVersion = "3.32.0";
|
|
155
155
|
|
|
156
156
|
const initialState$1 = {
|
|
157
157
|
chatMessages: [],
|
|
@@ -182,6 +182,14 @@ const initialState$1 = {
|
|
|
182
182
|
isMicrophoneEnabled: false,
|
|
183
183
|
localParticipant: undefined,
|
|
184
184
|
remoteParticipants: [],
|
|
185
|
+
roomIntegrations: {
|
|
186
|
+
hasFetched: false,
|
|
187
|
+
isFetching: false,
|
|
188
|
+
error: null,
|
|
189
|
+
embeddable: [],
|
|
190
|
+
enabled: [],
|
|
191
|
+
running: [],
|
|
192
|
+
},
|
|
185
193
|
screenshares: [],
|
|
186
194
|
connectionStatus: "ready",
|
|
187
195
|
connectionError: null,
|
|
@@ -268,6 +276,9 @@ function useRoomConnection(roomUrl, roomConnectionOptions = defaultRoomConnectio
|
|
|
268
276
|
const endMeeting = React.useCallback((stayBehind) => client.endMeeting(stayBehind), [client]);
|
|
269
277
|
const joinBreakoutGroup = React.useCallback((group) => client.joinBreakoutGroup(group), [client]);
|
|
270
278
|
const joinBreakoutMainRoom = React.useCallback(() => client.joinBreakoutMainRoom(), [client]);
|
|
279
|
+
const startRoomIntegration = React.useCallback((options) => client.startRoomIntegration(options), [client]);
|
|
280
|
+
const stopRoomIntegration = React.useCallback((options) => client.stopRoomIntegration(options), [client]);
|
|
281
|
+
const updateRoomIntegrationProps = React.useCallback((options) => client.updateRoomIntegrationProps(options), [client]);
|
|
271
282
|
const startBreakoutSession = React.useCallback((options) => client.startBreakoutSession(options), [client]);
|
|
272
283
|
const updateBreakoutSession = React.useCallback((options) => client.updateBreakoutSession(options), [client]);
|
|
273
284
|
const stopBreakoutSession = React.useCallback(() => client.stopBreakoutSession(), [client]);
|
|
@@ -338,6 +349,9 @@ function useRoomConnection(roomUrl, roomConnectionOptions = defaultRoomConnectio
|
|
|
338
349
|
removeSpotlight,
|
|
339
350
|
joinBreakoutGroup,
|
|
340
351
|
joinBreakoutMainRoom,
|
|
352
|
+
startRoomIntegration,
|
|
353
|
+
stopRoomIntegration,
|
|
354
|
+
updateRoomIntegrationProps,
|
|
341
355
|
startBreakoutSession,
|
|
342
356
|
updateBreakoutSession,
|
|
343
357
|
stopBreakoutSession,
|
|
@@ -534,6 +548,9 @@ function VideoCell(_a) {
|
|
|
534
548
|
React.createElement("div", Object.assign({ style: contentStyle }, rest), React.cloneElement(children, { contentWidth, contentHeight, withRoundedCorners, withShadow }))));
|
|
535
549
|
}
|
|
536
550
|
|
|
551
|
+
const IntegrationCell = ({ cellId, children, isHiddenCell = false }) => (React.createElement("div", { "data-cell-id": cellId, "aria-hidden": isHiddenCell || undefined, style: { height: "100%", width: "100%" } }, children));
|
|
552
|
+
IntegrationCell.displayName = "IntegrationCell";
|
|
553
|
+
|
|
537
554
|
function generateStylesFromFrame({ origin, bounds }) {
|
|
538
555
|
return {
|
|
539
556
|
top: Math.round(origin.top),
|
|
@@ -549,7 +566,10 @@ function renderVideoCell({ cell, child, clientId, style = {}, withRoundedCorners
|
|
|
549
566
|
function renderSubgridVideoCells({ content, stageLayout, withRoundedCorners, withShadow, }) {
|
|
550
567
|
const cells = stageLayout.subgrid.cells;
|
|
551
568
|
return content.map((child, index) => {
|
|
552
|
-
var _a, _b, _c, _d;
|
|
569
|
+
var _a, _b, _c, _d, _e;
|
|
570
|
+
if (!child) {
|
|
571
|
+
return null;
|
|
572
|
+
}
|
|
553
573
|
const cell = cells[index];
|
|
554
574
|
const style = { height: Math.round(cell.bounds.height), width: Math.round(cell.bounds.width), transform: "" };
|
|
555
575
|
const origin = {
|
|
@@ -557,9 +577,9 @@ function renderSubgridVideoCells({ content, stageLayout, withRoundedCorners, wit
|
|
|
557
577
|
left: stageLayout.subgrid.origin.left + cell.origin.left,
|
|
558
578
|
};
|
|
559
579
|
style.transform = `translate3d(${Math.round(origin.left)}px, ${Math.round(origin.top)}px, 0)`;
|
|
560
|
-
const clientId = (
|
|
561
|
-
const leftPaddings = ((
|
|
562
|
-
const rightPaddings = ((
|
|
580
|
+
const clientId = ((_a = child === null || child === void 0 ? void 0 : child.props) === null || _a === void 0 ? void 0 : _a.cellId) || ((_c = (_b = child === null || child === void 0 ? void 0 : child.props) === null || _b === void 0 ? void 0 : _b.participant) === null || _c === void 0 ? void 0 : _c.id);
|
|
581
|
+
const leftPaddings = ((_d = cell.paddings) === null || _d === void 0 ? void 0 : _d.left) || 0;
|
|
582
|
+
const rightPaddings = ((_e = cell.paddings) === null || _e === void 0 ? void 0 : _e.right) || 0;
|
|
563
583
|
const childWithProps = React.cloneElement(child, {
|
|
564
584
|
avatarSize: cell.bounds.width - leftPaddings - rightPaddings,
|
|
565
585
|
canZoom: false,
|
|
@@ -583,8 +603,8 @@ function renderPresentationGridVideoCells({ content, isConstrained, stageLayout,
|
|
|
583
603
|
var _a;
|
|
584
604
|
const cells = ((_a = stageLayout.presentationGrid) === null || _a === void 0 ? void 0 : _a.cells) || [];
|
|
585
605
|
return content.map((child, index) => {
|
|
586
|
-
var _a, _b;
|
|
587
|
-
if (!stageLayout.presentationGrid) {
|
|
606
|
+
var _a, _b, _c, _d;
|
|
607
|
+
if (!child || !stageLayout.presentationGrid) {
|
|
588
608
|
return null;
|
|
589
609
|
}
|
|
590
610
|
const cell = cells[index];
|
|
@@ -599,10 +619,10 @@ function renderPresentationGridVideoCells({ content, isConstrained, stageLayout,
|
|
|
599
619
|
height: Math.round(cell.bounds.height),
|
|
600
620
|
transform: `translate3d(${Math.round(origin.left)}px, ${Math.round(origin.top)}px, 0)`,
|
|
601
621
|
};
|
|
602
|
-
const clientId = (
|
|
622
|
+
const clientId = ((_a = child === null || child === void 0 ? void 0 : child.props) === null || _a === void 0 ? void 0 : _a.cellId) || ((_c = (_b = child === null || child === void 0 ? void 0 : child.props) === null || _b === void 0 ? void 0 : _b.participant) === null || _c === void 0 ? void 0 : _c.id);
|
|
603
623
|
const childWithProps = React.cloneElement(child, {
|
|
604
624
|
isSmallCell: cell.isSmallCell,
|
|
605
|
-
isZoomedByDefault: !!isConstrained &&
|
|
625
|
+
isZoomedByDefault: !!isConstrained && !!((_d = child === null || child === void 0 ? void 0 : child.props) === null || _d === void 0 ? void 0 : _d.participant) && !child.props.participant.isPresentation,
|
|
606
626
|
canZoom: !!isConstrained,
|
|
607
627
|
key: clientId || `presentation-${index}`,
|
|
608
628
|
});
|
|
@@ -620,8 +640,8 @@ function renderGridVideoCells({ content, isConstrained, stageLayout, withRounded
|
|
|
620
640
|
var _a;
|
|
621
641
|
const cells = ((_a = stageLayout.videoGrid) === null || _a === void 0 ? void 0 : _a.cells) || [];
|
|
622
642
|
const gridVideoCells = content.map((child, index) => {
|
|
623
|
-
var _a, _b;
|
|
624
|
-
if (!stageLayout.videoGrid) {
|
|
643
|
+
var _a, _b, _c, _d;
|
|
644
|
+
if (!child || !stageLayout.videoGrid) {
|
|
625
645
|
return null;
|
|
626
646
|
}
|
|
627
647
|
const cell = cells[index];
|
|
@@ -634,10 +654,10 @@ function renderGridVideoCells({ content, isConstrained, stageLayout, withRounded
|
|
|
634
654
|
height: Math.round(cell.bounds.height),
|
|
635
655
|
transform: `translate3d(${Math.round(origin.left)}px, ${Math.round(origin.top)}px, 0)`,
|
|
636
656
|
};
|
|
637
|
-
const clientId = (
|
|
657
|
+
const clientId = ((_a = child === null || child === void 0 ? void 0 : child.props) === null || _a === void 0 ? void 0 : _a.cellId) || ((_c = (_b = child === null || child === void 0 ? void 0 : child.props) === null || _b === void 0 ? void 0 : _b.participant) === null || _c === void 0 ? void 0 : _c.id);
|
|
638
658
|
const childWithProps = React.cloneElement(child, {
|
|
639
659
|
isSmallCell: cell.isSmallCell,
|
|
640
|
-
isZoomedByDefault: !!isConstrained &&
|
|
660
|
+
isZoomedByDefault: !!isConstrained && !!((_d = child === null || child === void 0 ? void 0 : child.props) === null || _d === void 0 ? void 0 : _d.participant) && !child.props.participant.isPresentation,
|
|
641
661
|
canZoom: !!isConstrained,
|
|
642
662
|
key: clientId || `video-${index}`,
|
|
643
663
|
});
|
|
@@ -685,7 +705,33 @@ function renderFloatingVideoCell({ content, containerFrame, stageLayout, withRou
|
|
|
685
705
|
withShadow: false,
|
|
686
706
|
});
|
|
687
707
|
}
|
|
688
|
-
|
|
708
|
+
const HIDDEN_CELL_STYLE = {
|
|
709
|
+
width: 1,
|
|
710
|
+
height: 1,
|
|
711
|
+
opacity: 0,
|
|
712
|
+
overflow: "hidden",
|
|
713
|
+
pointerEvents: "none",
|
|
714
|
+
};
|
|
715
|
+
function renderHiddenCells({ content }) {
|
|
716
|
+
const cell = { bounds: { width: 1, height: 1 }, aspectRatio: 1 };
|
|
717
|
+
return content.map((child, index) => {
|
|
718
|
+
var _a;
|
|
719
|
+
if (!child) {
|
|
720
|
+
return null;
|
|
721
|
+
}
|
|
722
|
+
const clientId = ((_a = child.props) === null || _a === void 0 ? void 0 : _a.cellId) || `hidden-${index}`;
|
|
723
|
+
const childWithProps = React.cloneElement(child, { isHiddenCell: true, key: clientId });
|
|
724
|
+
return renderVideoCell({ cell, child: childWithProps, clientId, style: HIDDEN_CELL_STYLE });
|
|
725
|
+
});
|
|
726
|
+
}
|
|
727
|
+
function withIntegrationCellsFirst(cells) {
|
|
728
|
+
const isIntegrationCell = (cell) => { var _a, _b; return ((_b = (_a = cell === null || cell === void 0 ? void 0 : cell.props) === null || _a === void 0 ? void 0 : _a.children) === null || _b === void 0 ? void 0 : _b.type) === IntegrationCell; };
|
|
729
|
+
const integrationCells = cells
|
|
730
|
+
.filter(isIntegrationCell)
|
|
731
|
+
.sort((a, b) => String(a === null || a === void 0 ? void 0 : a.key).localeCompare(String(b === null || b === void 0 ? void 0 : b.key)));
|
|
732
|
+
return [...integrationCells, ...cells.filter((cell) => !isIntegrationCell(cell))];
|
|
733
|
+
}
|
|
734
|
+
function VideoStageLayout({ containerFrame, debug = false, featureRoundedCornersOff = false, floatingContent, gridContent = [], isConstrained = false, layoutOverflowBackdropFrame = makeFrame(), layoutVideoStage: stageLayout, presentationGridContent = [], subgridContent = [], hiddenContent = [], }) {
|
|
689
735
|
const withRoundedCorners = !featureRoundedCornersOff && !isConstrained;
|
|
690
736
|
const cells = [];
|
|
691
737
|
if (gridContent.length) {
|
|
@@ -722,16 +768,221 @@ function VideoStageLayout({ containerFrame, debug = false, featureRoundedCorners
|
|
|
722
768
|
withShadow: true,
|
|
723
769
|
}));
|
|
724
770
|
}
|
|
771
|
+
if (hiddenContent.length) {
|
|
772
|
+
cells.push(...renderHiddenCells({ content: hiddenContent }));
|
|
773
|
+
}
|
|
725
774
|
return (React.createElement("div", { key: "video-stage-layout", style: {
|
|
726
775
|
width: "100%",
|
|
727
776
|
height: "100%",
|
|
728
777
|
position: "relative",
|
|
729
778
|
} },
|
|
730
779
|
hasBounds(layoutOverflowBackdropFrame.bounds) && (React.createElement("div", { style: generateStylesFromFrame(layoutOverflowBackdropFrame) })),
|
|
731
|
-
cells,
|
|
780
|
+
withIntegrationCellsFirst(cells),
|
|
732
781
|
debug && (React.createElement(React.Fragment, null))));
|
|
733
782
|
}
|
|
734
783
|
|
|
784
|
+
function useIframeContract(ref, hookName, enabled) {
|
|
785
|
+
React.useEffect(() => {
|
|
786
|
+
if (!enabled) {
|
|
787
|
+
return;
|
|
788
|
+
}
|
|
789
|
+
const timer = setTimeout(() => {
|
|
790
|
+
const frame = ref.current;
|
|
791
|
+
if (!frame) {
|
|
792
|
+
console.warn(`${hookName}: iframeProps.ref was never attached. Spread iframeProps onto the ` +
|
|
793
|
+
`<iframe> you render — without the ref the hook cannot tell which window is ` +
|
|
794
|
+
`answering, so nothing will ever arrive.`);
|
|
795
|
+
return;
|
|
796
|
+
}
|
|
797
|
+
if (frame.hasAttribute("sandbox")) {
|
|
798
|
+
console.warn(`${hookName}: the iframe has a sandbox attribute. Some integrations open their ` +
|
|
799
|
+
`own window to sign in, which a sandbox without allow-popups blocks silently.`);
|
|
800
|
+
}
|
|
801
|
+
}, 0);
|
|
802
|
+
return () => clearTimeout(timer);
|
|
803
|
+
}, [ref, hookName, enabled]);
|
|
804
|
+
}
|
|
805
|
+
|
|
806
|
+
const HOST_TO_FRAME = {
|
|
807
|
+
PROPS: "whereby:props",
|
|
808
|
+
SET_VOLUME: "whereby:setVolume",
|
|
809
|
+
GET_VOLUME: "whereby:getVolume",
|
|
810
|
+
};
|
|
811
|
+
const FRAME_TO_HOST = {
|
|
812
|
+
FRAME_READY: "whereby:frameReady",
|
|
813
|
+
UPDATE_PROPS: "whereby:updateProps",
|
|
814
|
+
CONTENT_READY: "whereby:contentReady",
|
|
815
|
+
CLOSE: "whereby:close",
|
|
816
|
+
AUDIO_OVERRIDE: "whereby:audioOverride",
|
|
817
|
+
VOLUME: "whereby:volume",
|
|
818
|
+
};
|
|
819
|
+
const DEFAULT_ALLOW$1 = "autoplay; fullscreen; encrypted-media; picture-in-picture";
|
|
820
|
+
const VOLUME_REQUEST_TIMEOUT = 2000;
|
|
821
|
+
function outboundProps(session) {
|
|
822
|
+
return Object.assign(Object.assign({}, session.props), { ispresenter: session.isPresenter, presenterdisplayname: session.presenterDisplayName, roomintegrationsessionid: session.roomIntegrationSessionId, breakoutgroupid: session.breakoutGroupId });
|
|
823
|
+
}
|
|
824
|
+
function diffProps(next, previous) {
|
|
825
|
+
if (!previous) {
|
|
826
|
+
return next;
|
|
827
|
+
}
|
|
828
|
+
return Object.keys(next).reduce((patch, key) => {
|
|
829
|
+
if (previous[key] !== next[key]) {
|
|
830
|
+
patch[key] = next[key];
|
|
831
|
+
}
|
|
832
|
+
return patch;
|
|
833
|
+
}, {});
|
|
834
|
+
}
|
|
835
|
+
function useRoomIntegrationView({ session, onAudioOverride, onContentReady, allow = DEFAULT_ALLOW$1, title, }) {
|
|
836
|
+
var _a;
|
|
837
|
+
const client = (_a = React.useContext(WherebyContext)) === null || _a === void 0 ? void 0 : _a.getRoomConnection();
|
|
838
|
+
const iframeRef = React.useRef(null);
|
|
839
|
+
const lastSentRef = React.useRef(null);
|
|
840
|
+
const isFrameReadyRef = React.useRef(false);
|
|
841
|
+
const volumeRequestsRef = React.useRef(new Map());
|
|
842
|
+
const nextRequestIdRef = React.useRef(0);
|
|
843
|
+
const sessionRef = React.useRef(session);
|
|
844
|
+
const onAudioOverrideRef = React.useRef(onAudioOverride);
|
|
845
|
+
const onContentReadyRef = React.useRef(onContentReady);
|
|
846
|
+
sessionRef.current = session;
|
|
847
|
+
onAudioOverrideRef.current = onAudioOverride;
|
|
848
|
+
onContentReadyRef.current = onContentReady;
|
|
849
|
+
const { webview } = session.integration;
|
|
850
|
+
const { roomIntegrationSessionId } = session;
|
|
851
|
+
const frameOrigin = React.useMemo(() => {
|
|
852
|
+
try {
|
|
853
|
+
return new URL(webview).origin;
|
|
854
|
+
}
|
|
855
|
+
catch (_a) {
|
|
856
|
+
console.warn(`useRoomIntegrationView: unusable webview url ${webview}`);
|
|
857
|
+
return null;
|
|
858
|
+
}
|
|
859
|
+
}, [webview]);
|
|
860
|
+
const src = React.useMemo(() => {
|
|
861
|
+
if (!frameOrigin) {
|
|
862
|
+
return null;
|
|
863
|
+
}
|
|
864
|
+
const url = new URL(webview);
|
|
865
|
+
url.searchParams.set("parentOrigin", window.location.origin);
|
|
866
|
+
url.searchParams.set("roomintegrationsessionid", roomIntegrationSessionId);
|
|
867
|
+
return url.href;
|
|
868
|
+
}, [webview, frameOrigin, roomIntegrationSessionId]);
|
|
869
|
+
const post = React.useCallback((type, payload) => {
|
|
870
|
+
var _a;
|
|
871
|
+
const frameWindow = (_a = iframeRef.current) === null || _a === void 0 ? void 0 : _a.contentWindow;
|
|
872
|
+
if (!frameWindow || !frameOrigin) {
|
|
873
|
+
return;
|
|
874
|
+
}
|
|
875
|
+
frameWindow.postMessage({ type, payload }, frameOrigin);
|
|
876
|
+
}, [frameOrigin]);
|
|
877
|
+
React.useEffect(() => {
|
|
878
|
+
isFrameReadyRef.current = false;
|
|
879
|
+
lastSentRef.current = null;
|
|
880
|
+
}, [src]);
|
|
881
|
+
React.useEffect(() => {
|
|
882
|
+
if (!frameOrigin) {
|
|
883
|
+
return;
|
|
884
|
+
}
|
|
885
|
+
const handleMessage = (event) => {
|
|
886
|
+
var _a, _b, _c, _d;
|
|
887
|
+
if (event.origin !== frameOrigin || event.source !== ((_a = iframeRef.current) === null || _a === void 0 ? void 0 : _a.contentWindow)) {
|
|
888
|
+
return;
|
|
889
|
+
}
|
|
890
|
+
const { type, payload } = event.data || {};
|
|
891
|
+
const currentSession = sessionRef.current;
|
|
892
|
+
switch (type) {
|
|
893
|
+
case FRAME_TO_HOST.FRAME_READY: {
|
|
894
|
+
const props = outboundProps(currentSession);
|
|
895
|
+
isFrameReadyRef.current = true;
|
|
896
|
+
lastSentRef.current = props;
|
|
897
|
+
post(HOST_TO_FRAME.PROPS, props);
|
|
898
|
+
break;
|
|
899
|
+
}
|
|
900
|
+
case FRAME_TO_HOST.UPDATE_PROPS: {
|
|
901
|
+
if (payload === null || payload === void 0 ? void 0 : payload.props) {
|
|
902
|
+
client === null || client === void 0 ? void 0 : client.updateRoomIntegrationProps({
|
|
903
|
+
roomIntegrationSessionId: currentSession.roomIntegrationSessionId,
|
|
904
|
+
props: payload.props,
|
|
905
|
+
});
|
|
906
|
+
}
|
|
907
|
+
break;
|
|
908
|
+
}
|
|
909
|
+
case FRAME_TO_HOST.CLOSE: {
|
|
910
|
+
if (currentSession.canStop) {
|
|
911
|
+
client === null || client === void 0 ? void 0 : client.stopRoomIntegration({
|
|
912
|
+
roomIntegrationSessionId: currentSession.roomIntegrationSessionId,
|
|
913
|
+
intent: "end",
|
|
914
|
+
});
|
|
915
|
+
}
|
|
916
|
+
break;
|
|
917
|
+
}
|
|
918
|
+
case FRAME_TO_HOST.AUDIO_OVERRIDE: {
|
|
919
|
+
(_b = onAudioOverrideRef.current) === null || _b === void 0 ? void 0 : _b.call(onAudioOverrideRef, (_c = payload === null || payload === void 0 ? void 0 : payload.enabled) !== null && _c !== void 0 ? _c : null);
|
|
920
|
+
break;
|
|
921
|
+
}
|
|
922
|
+
case FRAME_TO_HOST.CONTENT_READY: {
|
|
923
|
+
(_d = onContentReadyRef.current) === null || _d === void 0 ? void 0 : _d.call(onContentReadyRef);
|
|
924
|
+
break;
|
|
925
|
+
}
|
|
926
|
+
case FRAME_TO_HOST.VOLUME: {
|
|
927
|
+
const resolve = volumeRequestsRef.current.get(payload === null || payload === void 0 ? void 0 : payload.requestId);
|
|
928
|
+
if (resolve) {
|
|
929
|
+
volumeRequestsRef.current.delete(payload.requestId);
|
|
930
|
+
resolve(payload.volume);
|
|
931
|
+
}
|
|
932
|
+
break;
|
|
933
|
+
}
|
|
934
|
+
}
|
|
935
|
+
};
|
|
936
|
+
window.addEventListener("message", handleMessage);
|
|
937
|
+
return () => window.removeEventListener("message", handleMessage);
|
|
938
|
+
}, [frameOrigin, client, post]);
|
|
939
|
+
const serializedProps = JSON.stringify(outboundProps(session));
|
|
940
|
+
React.useEffect(() => {
|
|
941
|
+
if (!isFrameReadyRef.current) {
|
|
942
|
+
return;
|
|
943
|
+
}
|
|
944
|
+
const props = outboundProps(sessionRef.current);
|
|
945
|
+
const patch = diffProps(props, lastSentRef.current);
|
|
946
|
+
lastSentRef.current = props;
|
|
947
|
+
if (Object.keys(patch).length) {
|
|
948
|
+
post(HOST_TO_FRAME.PROPS, patch);
|
|
949
|
+
}
|
|
950
|
+
}, [serializedProps, post]);
|
|
951
|
+
const setVolume = React.useCallback((volume) => post(HOST_TO_FRAME.SET_VOLUME, { volume }), [post]);
|
|
952
|
+
const getVolume = React.useCallback(() => new Promise((resolve, reject) => {
|
|
953
|
+
const requestId = ++nextRequestIdRef.current;
|
|
954
|
+
const requests = volumeRequestsRef.current;
|
|
955
|
+
const timer = setTimeout(() => {
|
|
956
|
+
requests.delete(requestId);
|
|
957
|
+
reject(new Error("Timed out reading volume from the room integration"));
|
|
958
|
+
}, VOLUME_REQUEST_TIMEOUT);
|
|
959
|
+
requests.set(requestId, (volume) => {
|
|
960
|
+
clearTimeout(timer);
|
|
961
|
+
resolve(volume);
|
|
962
|
+
});
|
|
963
|
+
post(HOST_TO_FRAME.GET_VOLUME, { requestId });
|
|
964
|
+
}), [post]);
|
|
965
|
+
useIframeContract(iframeRef, "useRoomIntegrationView", !!src);
|
|
966
|
+
return {
|
|
967
|
+
iframeProps: src
|
|
968
|
+
? {
|
|
969
|
+
ref: iframeRef,
|
|
970
|
+
src,
|
|
971
|
+
title: title || session.integration.title,
|
|
972
|
+
allow,
|
|
973
|
+
}
|
|
974
|
+
: null,
|
|
975
|
+
getVolume,
|
|
976
|
+
setVolume,
|
|
977
|
+
};
|
|
978
|
+
}
|
|
979
|
+
|
|
980
|
+
const IFRAME_STYLE = { border: "none", width: "100%", height: "100%" };
|
|
981
|
+
function DefaultIntegrationView({ session }) {
|
|
982
|
+
const { iframeProps } = useRoomIntegrationView({ session });
|
|
983
|
+
return iframeProps ? React.createElement("iframe", Object.assign({}, iframeProps, { allowFullScreen: true, style: IFRAME_STYLE })) : null;
|
|
984
|
+
}
|
|
985
|
+
|
|
735
986
|
const WIDE_AR = 16 / 9;
|
|
736
987
|
const NORMAL_AR = 4 / 3;
|
|
737
988
|
const clamp = ({ value, min, max }) => Math.min(Math.max(value, min), max);
|
|
@@ -1787,6 +2038,7 @@ function makeVideoCellView({ aspectRatio, avatarSize, cellPaddings, client = und
|
|
|
1787
2038
|
avatarSize,
|
|
1788
2039
|
cellPaddings,
|
|
1789
2040
|
client,
|
|
2041
|
+
cellId: (client === null || client === void 0 ? void 0 : client.id) || "",
|
|
1790
2042
|
clientId: (client === null || client === void 0 ? void 0 : client.id) || "",
|
|
1791
2043
|
isDraggable,
|
|
1792
2044
|
isPlaceholder,
|
|
@@ -1794,20 +2046,38 @@ function makeVideoCellView({ aspectRatio, avatarSize, cellPaddings, client = und
|
|
|
1794
2046
|
type: "video",
|
|
1795
2047
|
};
|
|
1796
2048
|
}
|
|
2049
|
+
function integrationAspectRatio(session) {
|
|
2050
|
+
var _a;
|
|
2051
|
+
const reported = Number((_a = session.props) === null || _a === void 0 ? void 0 : _a.aspectratio);
|
|
2052
|
+
return isFinite(reported) && reported > 0 ? reported : undefined;
|
|
2053
|
+
}
|
|
2054
|
+
function roomIntegrationCellId(session) {
|
|
2055
|
+
return `room-integration:${session.roomIntegrationSessionId}`;
|
|
2056
|
+
}
|
|
2057
|
+
function makeIntegrationCellView({ session, isDraggable = false, isSubgrid = false, }) {
|
|
2058
|
+
const cellId = roomIntegrationCellId(session);
|
|
2059
|
+
return {
|
|
2060
|
+
aspectRatio: integrationAspectRatio(session) || 16 / 9,
|
|
2061
|
+
cellId,
|
|
2062
|
+
clientId: cellId,
|
|
2063
|
+
isDraggable,
|
|
2064
|
+
isSubgrid,
|
|
2065
|
+
session,
|
|
2066
|
+
type: "integration",
|
|
2067
|
+
};
|
|
2068
|
+
}
|
|
1797
2069
|
|
|
1798
2070
|
const STAGE_PARTICIPANT_LIMIT = 12;
|
|
1799
2071
|
const ACTIVE_VIDEO_SUBGRID_TRIGGER = 12;
|
|
1800
2072
|
const ACTIVE_VIDEOS_PHONE_LIMIT = 24;
|
|
1801
2073
|
|
|
1802
|
-
function calculateSubgridViews({ clientViews, activeVideosSubgridTrigger, shouldShowSubgrid, spotlightedParticipants,
|
|
2074
|
+
function calculateSubgridViews({ clientViews, activeVideosSubgridTrigger, shouldShowSubgrid, spotlightedParticipants, maximizedCellId, hasStagedIntegration = false, isPhoneResolution, }) {
|
|
1803
2075
|
if (!shouldShowSubgrid) {
|
|
1804
2076
|
return [];
|
|
1805
2077
|
}
|
|
1806
2078
|
const hasSpotlights = spotlightedParticipants.length > 0;
|
|
1807
|
-
const hasPresentationStage = hasSpotlights;
|
|
1808
|
-
const notMaximized =
|
|
1809
|
-
? clientViews.filter((client) => client.id !== maximizedParticipant.id)
|
|
1810
|
-
: clientViews;
|
|
2079
|
+
const hasPresentationStage = hasSpotlights || hasStagedIntegration;
|
|
2080
|
+
const notMaximized = maximizedCellId ? clientViews.filter((client) => client.id !== maximizedCellId) : clientViews;
|
|
1811
2081
|
const notSpotlighted = notMaximized.filter((client) => !client.isPresentation && !spotlightedParticipants.includes(client));
|
|
1812
2082
|
const noVideoViews = notSpotlighted.filter((client) => !client.isVideoEnabled);
|
|
1813
2083
|
const videoLimitReached = notSpotlighted.filter((client) => client.isVideoEnabled).length > activeVideosSubgridTrigger;
|
|
@@ -1838,7 +2108,8 @@ function calculateSubgridViews({ clientViews, activeVideosSubgridTrigger, should
|
|
|
1838
2108
|
}
|
|
1839
2109
|
return noVideoViews;
|
|
1840
2110
|
}
|
|
1841
|
-
|
|
2111
|
+
const NO_INTEGRATIONS = [];
|
|
2112
|
+
function useGridParticipants({ activeVideosSubgridTrigger = ACTIVE_VIDEO_SUBGRID_TRIGGER, stageParticipantLimit = STAGE_PARTICIPANT_LIMIT, forceSubgrid = true, enableSubgrid = true, maximizedCellId, floatingCellId, isConstrained = false, includeIntegrations = false, } = {}) {
|
|
1842
2113
|
var _a;
|
|
1843
2114
|
const client = (_a = React.useContext(WherebyContext)) === null || _a === void 0 ? void 0 : _a.getGrid();
|
|
1844
2115
|
if (!client) {
|
|
@@ -1851,6 +2122,9 @@ function useGridParticipants({ activeVideosSubgridTrigger = ACTIVE_VIDEO_SUBGRID
|
|
|
1851
2122
|
const handleSpotlightedParticipantsChanged = React.useCallback((spotlighted) => {
|
|
1852
2123
|
setState((prevState) => (Object.assign(Object.assign({}, prevState), { spotlightedParticipants: spotlighted })));
|
|
1853
2124
|
}, [setState]);
|
|
2125
|
+
const handleRunningRoomIntegrationsChanged = React.useCallback((runningRoomIntegrations) => {
|
|
2126
|
+
setState((prevState) => (Object.assign(Object.assign({}, prevState), { runningRoomIntegrations })));
|
|
2127
|
+
}, [setState]);
|
|
1854
2128
|
const handleNumParticipantsChanged = React.useCallback((num) => {
|
|
1855
2129
|
setState((prevState) => (Object.assign(Object.assign({}, prevState), { numParticipants: num })));
|
|
1856
2130
|
}, [setState]);
|
|
@@ -1858,19 +2132,21 @@ function useGridParticipants({ activeVideosSubgridTrigger = ACTIVE_VIDEO_SUBGRID
|
|
|
1858
2132
|
const unsubscribeClientViews = client.subscribeClientViews(handleClientViewChanged);
|
|
1859
2133
|
const unsubscribeSpotlighted = client.subscribeSpotlightedParticipants(handleSpotlightedParticipantsChanged);
|
|
1860
2134
|
const unsubscribeNumParticipants = client.subscribeNumberOfClientViews(handleNumParticipantsChanged);
|
|
2135
|
+
const unsubscribeRunningRoomIntegrations = client.subscribeRunningRoomIntegrations(handleRunningRoomIntegrationsChanged);
|
|
1861
2136
|
setState(client.getState());
|
|
1862
2137
|
return () => {
|
|
1863
2138
|
unsubscribeClientViews();
|
|
1864
2139
|
unsubscribeSpotlighted();
|
|
1865
2140
|
unsubscribeNumParticipants();
|
|
2141
|
+
unsubscribeRunningRoomIntegrations();
|
|
1866
2142
|
};
|
|
1867
2143
|
}, [client]);
|
|
1868
2144
|
const allClientViews = React.useMemo(() => state.allClientViews, [state.allClientViews]);
|
|
1869
2145
|
const spotlightedParticipants = React.useMemo(() => state.spotlightedParticipants, [state.spotlightedParticipants]);
|
|
1870
2146
|
const numParticipants = React.useMemo(() => state.numParticipants, [state.numParticipants]);
|
|
1871
|
-
const
|
|
1872
|
-
|
|
1873
|
-
|
|
2147
|
+
const runningRoomIntegrations = React.useMemo(() => (includeIntegrations ? state.runningRoomIntegrations : NO_INTEGRATIONS), [includeIntegrations, state.runningRoomIntegrations]);
|
|
2148
|
+
const maximizedClientView = React.useMemo(() => (maximizedCellId ? allClientViews.find((client) => client.id === maximizedCellId) || null : null), [allClientViews, maximizedCellId]);
|
|
2149
|
+
const floatingClientView = React.useMemo(() => (floatingCellId ? allClientViews.find((client) => client.id === floatingCellId) || null : null), [allClientViews, floatingCellId]);
|
|
1874
2150
|
const clientViewsNotFloating = React.useMemo(() => {
|
|
1875
2151
|
if (floatingClientView) {
|
|
1876
2152
|
return allClientViews.filter((c) => c.id !== floatingClientView.id);
|
|
@@ -1883,51 +2159,84 @@ function useGridParticipants({ activeVideosSubgridTrigger = ACTIVE_VIDEO_SUBGRID
|
|
|
1883
2159
|
}
|
|
1884
2160
|
return forceSubgrid ? true : numParticipants > stageParticipantLimit;
|
|
1885
2161
|
}, [forceSubgrid, numParticipants, stageParticipantLimit, enableSubgrid]);
|
|
2162
|
+
const integrationsInPresentationGrid = React.useMemo(() => {
|
|
2163
|
+
if (!runningRoomIntegrations.length || maximizedClientView) {
|
|
2164
|
+
return [];
|
|
2165
|
+
}
|
|
2166
|
+
return [runningRoomIntegrations[0]];
|
|
2167
|
+
}, [runningRoomIntegrations, maximizedClientView]);
|
|
2168
|
+
const integrationsInSubgrid = React.useMemo(() => {
|
|
2169
|
+
if (!shouldShowSubgrid) {
|
|
2170
|
+
return [];
|
|
2171
|
+
}
|
|
2172
|
+
return runningRoomIntegrations.filter((session) => !integrationsInPresentationGrid.some((staged) => staged.roomIntegrationSessionId === session.roomIntegrationSessionId));
|
|
2173
|
+
}, [runningRoomIntegrations, integrationsInPresentationGrid, shouldShowSubgrid]);
|
|
2174
|
+
const integrationsHidden = React.useMemo(() => {
|
|
2175
|
+
const visible = [...integrationsInPresentationGrid, ...integrationsInSubgrid];
|
|
2176
|
+
return runningRoomIntegrations.filter((session) => !visible.some((shown) => shown.roomIntegrationSessionId === session.roomIntegrationSessionId));
|
|
2177
|
+
}, [runningRoomIntegrations, integrationsInPresentationGrid, integrationsInSubgrid]);
|
|
1886
2178
|
const clientViewsInSubgrid = React.useMemo(() => {
|
|
1887
2179
|
return calculateSubgridViews({
|
|
1888
2180
|
clientViews: clientViewsNotFloating,
|
|
1889
2181
|
activeVideosSubgridTrigger,
|
|
1890
2182
|
shouldShowSubgrid,
|
|
1891
2183
|
spotlightedParticipants,
|
|
1892
|
-
|
|
2184
|
+
maximizedCellId,
|
|
2185
|
+
hasStagedIntegration: integrationsInPresentationGrid.length > 0,
|
|
1893
2186
|
isPhoneResolution: isConstrained,
|
|
1894
2187
|
});
|
|
1895
|
-
}, [
|
|
2188
|
+
}, [
|
|
2189
|
+
clientViewsNotFloating,
|
|
2190
|
+
shouldShowSubgrid,
|
|
2191
|
+
activeVideosSubgridTrigger,
|
|
2192
|
+
spotlightedParticipants,
|
|
2193
|
+
maximizedCellId,
|
|
2194
|
+
integrationsInPresentationGrid,
|
|
2195
|
+
isConstrained,
|
|
2196
|
+
]);
|
|
1896
2197
|
const clientViewsOnStage = React.useMemo(() => {
|
|
1897
2198
|
return clientViewsNotFloating.filter((client) => !clientViewsInSubgrid.includes(client));
|
|
1898
2199
|
}, [clientViewsNotFloating, clientViewsInSubgrid]);
|
|
1899
2200
|
const clientViewsInPresentationGrid = React.useMemo(() => {
|
|
1900
|
-
if (
|
|
1901
|
-
return [
|
|
2201
|
+
if (maximizedClientView) {
|
|
2202
|
+
return [maximizedClientView];
|
|
2203
|
+
}
|
|
2204
|
+
if (integrationsInPresentationGrid.length) {
|
|
2205
|
+
return [];
|
|
1902
2206
|
}
|
|
1903
|
-
return spotlightedParticipants;
|
|
1904
|
-
}, [spotlightedParticipants,
|
|
2207
|
+
return spotlightedParticipants.filter((client) => clientViewsOnStage.includes(client));
|
|
2208
|
+
}, [spotlightedParticipants, maximizedClientView, integrationsInPresentationGrid, clientViewsOnStage]);
|
|
1905
2209
|
const clientViewsInGrid = React.useMemo(() => {
|
|
1906
2210
|
return clientViewsOnStage.filter((client) => !clientViewsInPresentationGrid.includes(client));
|
|
1907
2211
|
}, [clientViewsOnStage, clientViewsInPresentationGrid]);
|
|
1908
2212
|
return {
|
|
1909
2213
|
floatingClientView,
|
|
2214
|
+
maximizedClientView,
|
|
1910
2215
|
clientViewsInGrid,
|
|
1911
2216
|
clientViewsInPresentationGrid,
|
|
1912
2217
|
clientViewsInSubgrid,
|
|
2218
|
+
integrationsInPresentationGrid,
|
|
2219
|
+
integrationsInSubgrid,
|
|
2220
|
+
integrationsHidden,
|
|
1913
2221
|
spotlightedParticipants,
|
|
1914
2222
|
};
|
|
1915
2223
|
}
|
|
1916
2224
|
|
|
1917
|
-
function useGrid({ activeVideosSubgridTrigger, forceSubgrid, stageParticipantLimit = STAGE_PARTICIPANT_LIMIT, gridGap = 8, videoGridGap = 8, enableSubgrid = true, enableConstrainedGrid = true, } = {}) {
|
|
2225
|
+
function useGrid({ activeVideosSubgridTrigger, forceSubgrid, stageParticipantLimit = STAGE_PARTICIPANT_LIMIT, gridGap = 8, videoGridGap = 8, enableSubgrid = true, enableConstrainedGrid = true, includeIntegrations = false, } = {}) {
|
|
1918
2226
|
const [containerBounds, setContainerBounds] = React.useState({ width: 0, height: 0 });
|
|
1919
2227
|
const [isConstrained, setIsConstrained] = React.useState(false);
|
|
1920
2228
|
const [clientAspectRatios, setClientAspectRatios] = React.useState({});
|
|
1921
|
-
const [
|
|
1922
|
-
const [
|
|
1923
|
-
const { clientViewsInGrid, clientViewsInPresentationGrid, clientViewsInSubgrid, floatingClientView } = useGridParticipants({
|
|
2229
|
+
const [maximizedCellId, setMaximizedCellId] = React.useState(null);
|
|
2230
|
+
const [floatingCellId, setFloatingCellId] = React.useState(null);
|
|
2231
|
+
const { clientViewsInGrid, clientViewsInPresentationGrid, clientViewsInSubgrid, floatingClientView, maximizedClientView, integrationsInPresentationGrid, integrationsInSubgrid, integrationsHidden, } = useGridParticipants({
|
|
1924
2232
|
activeVideosSubgridTrigger,
|
|
1925
2233
|
forceSubgrid,
|
|
1926
2234
|
stageParticipantLimit,
|
|
1927
2235
|
enableSubgrid,
|
|
1928
|
-
|
|
1929
|
-
|
|
2236
|
+
maximizedCellId,
|
|
2237
|
+
floatingCellId,
|
|
1930
2238
|
isConstrained: !!enableConstrainedGrid && !!isConstrained,
|
|
2239
|
+
includeIntegrations,
|
|
1931
2240
|
});
|
|
1932
2241
|
const cellViewsFloating = React.useMemo(() => {
|
|
1933
2242
|
return floatingClientView
|
|
@@ -1952,26 +2261,35 @@ function useGrid({ activeVideosSubgridTrigger, forceSubgrid, stageParticipantLim
|
|
|
1952
2261
|
});
|
|
1953
2262
|
}, [clientViewsInGrid, clientAspectRatios]);
|
|
1954
2263
|
const cellViewsInPresentationGrid = React.useMemo(() => {
|
|
1955
|
-
return
|
|
1956
|
-
|
|
1957
|
-
|
|
1958
|
-
|
|
1959
|
-
|
|
1960
|
-
|
|
1961
|
-
|
|
1962
|
-
|
|
1963
|
-
|
|
2264
|
+
return [
|
|
2265
|
+
...integrationsInPresentationGrid.map((session) => makeIntegrationCellView({ session })),
|
|
2266
|
+
...clientViewsInPresentationGrid.map((client) => {
|
|
2267
|
+
return makeVideoCellView({
|
|
2268
|
+
client,
|
|
2269
|
+
aspectRatio: clientAspectRatios[client.id],
|
|
2270
|
+
avatarSize: 0,
|
|
2271
|
+
cellPaddings: { top: 0, right: 0 },
|
|
2272
|
+
});
|
|
2273
|
+
}),
|
|
2274
|
+
];
|
|
2275
|
+
}, [clientViewsInPresentationGrid, integrationsInPresentationGrid, clientAspectRatios]);
|
|
1964
2276
|
const cellViewsInSubgrid = React.useMemo(() => {
|
|
1965
|
-
return
|
|
1966
|
-
|
|
1967
|
-
|
|
1968
|
-
|
|
1969
|
-
|
|
1970
|
-
|
|
1971
|
-
|
|
1972
|
-
|
|
1973
|
-
|
|
1974
|
-
|
|
2277
|
+
return [
|
|
2278
|
+
...clientViewsInSubgrid.map((client) => {
|
|
2279
|
+
return makeVideoCellView({
|
|
2280
|
+
client,
|
|
2281
|
+
aspectRatio: clientAspectRatios[client.id],
|
|
2282
|
+
avatarSize: 0,
|
|
2283
|
+
cellPaddings: { top: 0, right: 0 },
|
|
2284
|
+
isSubgrid: true,
|
|
2285
|
+
});
|
|
2286
|
+
}),
|
|
2287
|
+
...integrationsInSubgrid.map((session) => makeIntegrationCellView({ session, isSubgrid: true })),
|
|
2288
|
+
];
|
|
2289
|
+
}, [clientViewsInSubgrid, integrationsInSubgrid, clientAspectRatios]);
|
|
2290
|
+
const cellViewsHidden = React.useMemo(() => {
|
|
2291
|
+
return integrationsHidden.map((session) => makeIntegrationCellView({ session }));
|
|
2292
|
+
}, [integrationsHidden]);
|
|
1975
2293
|
const containerFrame = React.useMemo(() => {
|
|
1976
2294
|
return makeFrame(containerBounds);
|
|
1977
2295
|
}, [containerBounds]);
|
|
@@ -2008,14 +2326,17 @@ function useGrid({ activeVideosSubgridTrigger, forceSubgrid, stageParticipantLim
|
|
|
2008
2326
|
cellViewsVideoGrid,
|
|
2009
2327
|
cellViewsInPresentationGrid,
|
|
2010
2328
|
cellViewsInSubgrid,
|
|
2329
|
+
cellViewsHidden,
|
|
2011
2330
|
clientAspectRatios,
|
|
2012
2331
|
videoStage,
|
|
2013
2332
|
setContainerBounds,
|
|
2014
2333
|
setClientAspectRatios,
|
|
2015
|
-
|
|
2016
|
-
|
|
2017
|
-
|
|
2018
|
-
|
|
2334
|
+
maximizedCellId,
|
|
2335
|
+
setMaximizedCellId,
|
|
2336
|
+
maximizedParticipant: maximizedClientView,
|
|
2337
|
+
floatingCellId,
|
|
2338
|
+
setFloatingCellId,
|
|
2339
|
+
floatingParticipant: floatingClientView,
|
|
2019
2340
|
isConstrained,
|
|
2020
2341
|
};
|
|
2021
2342
|
}
|
|
@@ -2129,22 +2450,17 @@ ParticipantMenuTrigger.displayName = PopoverTrigger.displayName;
|
|
|
2129
2450
|
const ParticipantMenuItem = React.forwardRef((_a, ref) => {
|
|
2130
2451
|
var _b;
|
|
2131
2452
|
var { children, style, participantAction } = _a, props = __rest(_a, ["children", "style", "participantAction"]);
|
|
2132
|
-
const { participant, setOpen,
|
|
2453
|
+
const { participant, setOpen, maximizedCellId, setMaximizedCellId, floatingCellId, setFloatingCellId } = useParticipantMenu();
|
|
2133
2454
|
const client = (_b = React.useContext(WherebyContext)) === null || _b === void 0 ? void 0 : _b.getGrid();
|
|
2134
2455
|
const { spotlightedParticipants } = useGridParticipants();
|
|
2135
2456
|
const isSpotlighted = spotlightedParticipants.find((p) => p.id === participant.id);
|
|
2136
|
-
const isMaximized =
|
|
2137
|
-
const isFloating =
|
|
2457
|
+
const isMaximized = maximizedCellId === participant.id;
|
|
2458
|
+
const isFloating = floatingCellId === participant.id;
|
|
2138
2459
|
let onClick;
|
|
2139
2460
|
switch (participantAction) {
|
|
2140
2461
|
case "maximize":
|
|
2141
2462
|
onClick = () => {
|
|
2142
|
-
|
|
2143
|
-
setMaximizedParticipant(null);
|
|
2144
|
-
}
|
|
2145
|
-
else {
|
|
2146
|
-
setMaximizedParticipant(participant);
|
|
2147
|
-
}
|
|
2463
|
+
setMaximizedCellId(isMaximized ? null : participant.id);
|
|
2148
2464
|
setOpen(false);
|
|
2149
2465
|
};
|
|
2150
2466
|
break;
|
|
@@ -2161,12 +2477,7 @@ const ParticipantMenuItem = React.forwardRef((_a, ref) => {
|
|
|
2161
2477
|
break;
|
|
2162
2478
|
case "float":
|
|
2163
2479
|
onClick = () => {
|
|
2164
|
-
|
|
2165
|
-
setFloatingParticipant(null);
|
|
2166
|
-
}
|
|
2167
|
-
else {
|
|
2168
|
-
setFloatingParticipant(participant);
|
|
2169
|
-
}
|
|
2480
|
+
setFloatingCellId(isFloating ? null : participant.id);
|
|
2170
2481
|
setOpen(false);
|
|
2171
2482
|
};
|
|
2172
2483
|
break;
|
|
@@ -2283,28 +2594,35 @@ const GridVideoView = React.forwardRef((_a, ref) => {
|
|
|
2283
2594
|
return (React.createElement(VideoView, Object.assign({ ref: videoEl, style: Object.assign(Object.assign({ borderRadius: isConstrained ? 0 : "8px" }, (isConstrained ? { objectFit: "cover" } : {})), style), muted: participant.isLocalClient }, rest, { stream: s, onVideoResize: handleResize })));
|
|
2284
2595
|
});
|
|
2285
2596
|
GridVideoView.displayName = "GridVideoView";
|
|
2286
|
-
function renderCellView({ cellView, enableParticipantMenu, render }) {
|
|
2287
|
-
|
|
2288
|
-
if (!participant) {
|
|
2597
|
+
function renderCellView({ cellView, enableParticipantMenu, render, renderIntegration }) {
|
|
2598
|
+
if (!cellView) {
|
|
2289
2599
|
return undefined;
|
|
2290
2600
|
}
|
|
2291
2601
|
switch (cellView.type) {
|
|
2292
|
-
case "video":
|
|
2293
|
-
|
|
2602
|
+
case "video": {
|
|
2603
|
+
const participant = cellView.client;
|
|
2604
|
+
if (!participant) {
|
|
2605
|
+
return undefined;
|
|
2606
|
+
}
|
|
2607
|
+
return (React.createElement(GridCell, { participant: participant, cellId: cellView.cellId },
|
|
2294
2608
|
React.createElement(React.Fragment, null, render ? (render({ participant })) : (React.createElement(React.Fragment, null,
|
|
2295
2609
|
React.createElement(GridVideoView, null),
|
|
2296
2610
|
enableParticipantMenu ? React.createElement(DefaultParticipantMenu, { participant: participant }) : null)))));
|
|
2611
|
+
}
|
|
2612
|
+
case "integration":
|
|
2613
|
+
return (React.createElement(IntegrationCell, { cellId: cellView.cellId }, renderIntegration ? (renderIntegration({ session: cellView.session })) : (React.createElement(DefaultIntegrationView, { session: cellView.session }))));
|
|
2297
2614
|
}
|
|
2298
2615
|
}
|
|
2299
|
-
function Grid({ renderParticipant, renderSubgridParticipant, renderFloatingParticipant, stageParticipantLimit, gridGap, videoGridGap, enableSubgrid, enableParticipantMenu, enableConstrainedGrid, }) {
|
|
2616
|
+
function Grid({ renderParticipant, renderSubgridParticipant, renderFloatingParticipant, renderIntegration, stageParticipantLimit, gridGap, videoGridGap, enableSubgrid, enableParticipantMenu, enableConstrainedGrid, enableIntegrations = true, }) {
|
|
2300
2617
|
const gridRef = React.useRef(null);
|
|
2301
|
-
const { containerFrame, cellViewsFloating, cellViewsVideoGrid, cellViewsInPresentationGrid, cellViewsInSubgrid, clientAspectRatios, videoStage, setContainerBounds, setClientAspectRatios,
|
|
2618
|
+
const { containerFrame, cellViewsFloating, cellViewsVideoGrid, cellViewsInPresentationGrid, cellViewsInSubgrid, cellViewsHidden, clientAspectRatios, videoStage, setContainerBounds, setClientAspectRatios, maximizedCellId, setMaximizedCellId, maximizedParticipant, isConstrained, floatingCellId, setFloatingCellId, floatingParticipant, } = useGrid({
|
|
2302
2619
|
activeVideosSubgridTrigger: 12,
|
|
2303
2620
|
stageParticipantLimit,
|
|
2304
2621
|
gridGap,
|
|
2305
2622
|
videoGridGap,
|
|
2306
2623
|
enableSubgrid,
|
|
2307
2624
|
enableConstrainedGrid,
|
|
2625
|
+
includeIntegrations: enableIntegrations,
|
|
2308
2626
|
});
|
|
2309
2627
|
const handleSetClientAspectRatio = React.useCallback(({ aspectRatio, clientId }) => {
|
|
2310
2628
|
setClientAspectRatios((prev) => (Object.assign(Object.assign({}, prev), { [clientId]: aspectRatio })));
|
|
@@ -2315,13 +2633,16 @@ function Grid({ renderParticipant, renderSubgridParticipant, renderFloatingParti
|
|
|
2315
2633
|
: {})));
|
|
2316
2634
|
}, [cellViewsFloating]);
|
|
2317
2635
|
const presentationGridContent = React.useMemo(() => cellViewsInPresentationGrid.map((cellView) => renderCellView(Object.assign({ cellView,
|
|
2318
|
-
enableParticipantMenu
|
|
2636
|
+
enableParticipantMenu,
|
|
2637
|
+
renderIntegration }, (renderParticipant ? { render: ({ participant }) => renderParticipant({ participant }) } : {})))), [cellViewsInPresentationGrid, renderIntegration]);
|
|
2319
2638
|
const gridContent = React.useMemo(() => cellViewsVideoGrid.map((cellView) => renderCellView(Object.assign({ cellView,
|
|
2320
2639
|
enableParticipantMenu }, (renderParticipant ? { render: ({ participant }) => renderParticipant({ participant }) } : {})))), [cellViewsVideoGrid]);
|
|
2321
2640
|
const subgridContent = React.useMemo(() => cellViewsInSubgrid.map((cellView) => renderCellView(Object.assign({ cellView,
|
|
2322
|
-
enableParticipantMenu
|
|
2641
|
+
enableParticipantMenu,
|
|
2642
|
+
renderIntegration }, (renderSubgridParticipant
|
|
2323
2643
|
? { render: ({ participant }) => renderSubgridParticipant({ participant }) }
|
|
2324
|
-
: {})))), [cellViewsInSubgrid]);
|
|
2644
|
+
: {})))), [cellViewsInSubgrid, renderIntegration]);
|
|
2645
|
+
const hiddenContent = React.useMemo(() => cellViewsHidden.map((cellView) => renderCellView({ cellView, renderIntegration })), [cellViewsHidden, renderIntegration]);
|
|
2325
2646
|
React.useEffect(() => {
|
|
2326
2647
|
if (!gridRef.current) {
|
|
2327
2648
|
return;
|
|
@@ -2344,10 +2665,12 @@ function Grid({ renderParticipant, renderSubgridParticipant, renderFloatingParti
|
|
|
2344
2665
|
cellViewsInPresentationGrid,
|
|
2345
2666
|
cellViewsInSubgrid,
|
|
2346
2667
|
clientAspectRatios,
|
|
2668
|
+
maximizedCellId,
|
|
2669
|
+
setMaximizedCellId,
|
|
2347
2670
|
maximizedParticipant,
|
|
2348
|
-
|
|
2671
|
+
floatingCellId,
|
|
2672
|
+
setFloatingCellId,
|
|
2349
2673
|
floatingParticipant,
|
|
2350
|
-
setFloatingParticipant,
|
|
2351
2674
|
isConstrained,
|
|
2352
2675
|
} },
|
|
2353
2676
|
React.createElement("div", { ref: gridRef, style: {
|
|
@@ -2355,7 +2678,102 @@ function Grid({ renderParticipant, renderSubgridParticipant, renderFloatingParti
|
|
|
2355
2678
|
height: "100%",
|
|
2356
2679
|
position: "relative",
|
|
2357
2680
|
} },
|
|
2358
|
-
React.createElement(VideoStageLayout, { containerFrame: containerFrame, floatingContent: floatingContent, layoutVideoStage: videoStage, presentationGridContent: presentationGridContent, gridContent: gridContent, subgridContent: subgridContent }))));
|
|
2681
|
+
React.createElement(VideoStageLayout, { containerFrame: containerFrame, floatingContent: floatingContent, layoutVideoStage: videoStage, presentationGridContent: presentationGridContent, gridContent: gridContent, subgridContent: subgridContent, hiddenContent: hiddenContent }))));
|
|
2682
|
+
}
|
|
2683
|
+
|
|
2684
|
+
function subscribeToRoomIntegrationPicker({ pickerOrigin, getSource, onOutcome, }) {
|
|
2685
|
+
let settled = false;
|
|
2686
|
+
function handleMessage(event) {
|
|
2687
|
+
if (settled || event.origin !== pickerOrigin || !event.source || event.source !== getSource()) {
|
|
2688
|
+
return;
|
|
2689
|
+
}
|
|
2690
|
+
const { type, payload } = event.data || {};
|
|
2691
|
+
if (type === ROOM_INTEGRATION_PICKER_MESSAGES.FORM_SUBMIT) {
|
|
2692
|
+
settle({ type: "submitted", content: payload });
|
|
2693
|
+
}
|
|
2694
|
+
else if (type === ROOM_INTEGRATION_PICKER_MESSAGES.FORM_CLOSE) {
|
|
2695
|
+
settle({ type: "cancelled" });
|
|
2696
|
+
}
|
|
2697
|
+
else if (type === ROOM_INTEGRATION_PICKER_MESSAGES.ERROR) {
|
|
2698
|
+
settle({
|
|
2699
|
+
type: "error",
|
|
2700
|
+
error: new Error((payload === null || payload === void 0 ? void 0 : payload.message) || "The room integration picker failed"),
|
|
2701
|
+
});
|
|
2702
|
+
}
|
|
2703
|
+
}
|
|
2704
|
+
const unsubscribe = () => {
|
|
2705
|
+
settled = true;
|
|
2706
|
+
window.removeEventListener("message", handleMessage);
|
|
2707
|
+
};
|
|
2708
|
+
const settle = (outcome) => {
|
|
2709
|
+
unsubscribe();
|
|
2710
|
+
onOutcome(outcome);
|
|
2711
|
+
};
|
|
2712
|
+
window.addEventListener("message", handleMessage);
|
|
2713
|
+
return unsubscribe;
|
|
2714
|
+
}
|
|
2715
|
+
|
|
2716
|
+
const DEFAULT_ALLOW = "clipboard-read; clipboard-write; fullscreen";
|
|
2717
|
+
function useRoomIntegrationPicker({ integration, onPicked, onCancel, onError, featureSource, allow = DEFAULT_ALLOW, title, }) {
|
|
2718
|
+
const iframeRef = React.useRef(null);
|
|
2719
|
+
const onPickedRef = React.useRef(onPicked);
|
|
2720
|
+
const onCancelRef = React.useRef(onCancel);
|
|
2721
|
+
const onErrorRef = React.useRef(onError);
|
|
2722
|
+
onPickedRef.current = onPicked;
|
|
2723
|
+
onCancelRef.current = onCancel;
|
|
2724
|
+
onErrorRef.current = onError;
|
|
2725
|
+
const { webview } = integration;
|
|
2726
|
+
const pickerOrigin = React.useMemo(() => {
|
|
2727
|
+
try {
|
|
2728
|
+
return new URL(webview).origin;
|
|
2729
|
+
}
|
|
2730
|
+
catch (_a) {
|
|
2731
|
+
console.warn(`useRoomIntegrationPicker: unusable webview url ${webview}`);
|
|
2732
|
+
return null;
|
|
2733
|
+
}
|
|
2734
|
+
}, [webview]);
|
|
2735
|
+
const src = React.useMemo(() => {
|
|
2736
|
+
if (!pickerOrigin) {
|
|
2737
|
+
return null;
|
|
2738
|
+
}
|
|
2739
|
+
return roomIntegrationPickerUrl({
|
|
2740
|
+
integration: { webview },
|
|
2741
|
+
parentOrigin: window.location.origin,
|
|
2742
|
+
featureSource,
|
|
2743
|
+
});
|
|
2744
|
+
}, [pickerOrigin, webview, featureSource]);
|
|
2745
|
+
React.useEffect(() => {
|
|
2746
|
+
if (!pickerOrigin) {
|
|
2747
|
+
return;
|
|
2748
|
+
}
|
|
2749
|
+
return subscribeToRoomIntegrationPicker({
|
|
2750
|
+
pickerOrigin,
|
|
2751
|
+
getSource: () => { var _a; return (_a = iframeRef.current) === null || _a === void 0 ? void 0 : _a.contentWindow; },
|
|
2752
|
+
onOutcome: (outcome) => {
|
|
2753
|
+
var _a, _b;
|
|
2754
|
+
if (outcome.type === "submitted") {
|
|
2755
|
+
onPickedRef.current(outcome.content || {});
|
|
2756
|
+
return;
|
|
2757
|
+
}
|
|
2758
|
+
if (outcome.type === "cancelled") {
|
|
2759
|
+
(_a = onCancelRef.current) === null || _a === void 0 ? void 0 : _a.call(onCancelRef);
|
|
2760
|
+
return;
|
|
2761
|
+
}
|
|
2762
|
+
(_b = onErrorRef.current) === null || _b === void 0 ? void 0 : _b.call(onErrorRef, outcome.error);
|
|
2763
|
+
},
|
|
2764
|
+
});
|
|
2765
|
+
}, [pickerOrigin, src]);
|
|
2766
|
+
useIframeContract(iframeRef, "useRoomIntegrationPicker", !!src);
|
|
2767
|
+
return {
|
|
2768
|
+
iframeProps: src
|
|
2769
|
+
? {
|
|
2770
|
+
ref: iframeRef,
|
|
2771
|
+
src,
|
|
2772
|
+
title: title || `${integration.title} picker`,
|
|
2773
|
+
allow,
|
|
2774
|
+
}
|
|
2775
|
+
: null,
|
|
2776
|
+
};
|
|
2359
2777
|
}
|
|
2360
2778
|
|
|
2361
|
-
export { GridCell, GridVideoView, ParticipantMenu, ParticipantMenuContent, ParticipantMenuItem, ParticipantMenuTrigger, Grid as VideoGrid, VideoView, Provider as WherebyProvider, useLocalMedia, useRoomConnection };
|
|
2779
|
+
export { GridCell, GridVideoView, ParticipantMenu, ParticipantMenuContent, ParticipantMenuItem, ParticipantMenuTrigger, Grid as VideoGrid, VideoView, Provider as WherebyProvider, subscribeToRoomIntegrationPicker, useGrid, useLocalMedia, useRoomConnection, useRoomIntegrationPicker, useRoomIntegrationView };
|