@100mslive/roomkit-react 0.2.3 → 0.2.4-alpha.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/{HLSView-2BP4GO3Q.js → HLSView-5I6UAYPZ.js} +6 -6
- package/dist/HLSView-5I6UAYPZ.js.map +7 -0
- package/dist/Prebuilt/common/constants.d.ts +1 -0
- package/dist/Prebuilt/components/Connection/TileConnection.d.ts +2 -3
- package/dist/Prebuilt/components/InsetTile.d.ts +3 -1
- package/dist/Prebuilt/components/LayoutModeSelector.d.ts +2 -0
- package/dist/Prebuilt/components/MoreSettings/ChangeNameContent.d.ts +10 -0
- package/dist/Prebuilt/components/MoreSettings/ChangeNameModal.d.ts +5 -0
- package/dist/Prebuilt/components/Polls/CreatePollQuiz/PollsQuizMenu.d.ts +2 -0
- package/dist/Prebuilt/components/Polls/CreateQuestions/SavedQuestion.d.ts +1 -2
- package/dist/Prebuilt/components/Polls/common/StatusIndicator.d.ts +4 -3
- package/dist/Prebuilt/components/Polls/common/constants.d.ts +5 -0
- package/dist/Prebuilt/components/ScreenshareDisplay.d.ts +2 -0
- package/dist/Prebuilt/components/ScreenshareTile.d.ts +7 -0
- package/dist/Prebuilt/components/SecondaryTiles.d.ts +1 -1
- package/dist/Prebuilt/components/Settings/LayoutSettings.d.ts +11 -0
- package/dist/Prebuilt/components/Settings/NotificationSettings.d.ts +2 -0
- package/dist/Prebuilt/components/Settings/SwitchWithLabel.d.ts +10 -0
- package/dist/Prebuilt/components/Settings/common.d.ts +878 -0
- package/dist/Prebuilt/components/TileMenu/TileMenu.d.ts +14 -0
- package/dist/Prebuilt/components/TileMenu/TileMenuContent.d.ts +7 -7
- package/dist/Prebuilt/components/VideoLayouts/ProminenceLayout.d.ts +4 -2
- package/dist/Prebuilt/components/VideoLayouts/interface.d.ts +1 -0
- package/dist/Prebuilt/components/VideoTile.d.ts +19 -0
- package/dist/Prebuilt/components/hooks/useDropdownList.d.ts +4 -0
- package/dist/{chunk-G25T3EBJ.js → chunk-OGCNZHHH.js} +1328 -1097
- package/dist/chunk-OGCNZHHH.js.map +7 -0
- package/dist/index.cjs.js +1826 -1575
- package/dist/index.cjs.js.map +4 -4
- package/dist/index.js +1 -1
- package/dist/meta.cjs.json +458 -293
- package/dist/meta.esbuild.json +470 -305
- package/package.json +6 -6
- package/src/Pagination/StyledPagination.tsx +1 -0
- package/src/Popover/index.tsx +8 -1
- package/src/Prebuilt/common/constants.ts +1 -0
- package/src/Prebuilt/components/AppData/AppData.tsx +2 -0
- package/src/Prebuilt/components/AppData/useUISettings.js +1 -1
- package/src/Prebuilt/components/Connection/TileConnection.tsx +13 -6
- package/src/Prebuilt/components/HlsStatsOverlay.jsx +2 -2
- package/src/Prebuilt/components/InsetTile.tsx +13 -6
- package/src/Prebuilt/components/LayoutModeSelector.tsx +106 -0
- package/src/Prebuilt/components/MoreSettings/{ChangeNameContent.jsx → ChangeNameContent.tsx} +10 -2
- package/src/Prebuilt/components/MoreSettings/{ChangeNameModal.jsx → ChangeNameModal.tsx} +14 -5
- package/src/Prebuilt/components/MoreSettings/SplitComponents/DesktopOptions.tsx +2 -2
- package/src/Prebuilt/components/MoreSettings/SplitComponents/MwebOptions.tsx +2 -2
- package/src/Prebuilt/components/Notifications/Notifications.tsx +0 -1
- package/src/Prebuilt/components/Playlist/VideoPlayer.jsx +1 -1
- package/src/Prebuilt/components/Polls/CreatePollQuiz/{PollsQuizMenu.jsx → PollsQuizMenu.tsx} +54 -26
- package/src/Prebuilt/components/Polls/CreateQuestions/CreateQuestions.jsx +21 -31
- package/src/Prebuilt/components/Polls/CreateQuestions/SavedQuestion.tsx +3 -17
- package/src/Prebuilt/components/Polls/Voting/LeaderboardSummary.tsx +1 -1
- package/src/Prebuilt/components/Polls/Voting/QuestionCard.jsx +1 -10
- package/src/Prebuilt/components/Polls/Voting/Voting.tsx +1 -3
- package/src/Prebuilt/components/Polls/common/StatusIndicator.tsx +12 -3
- package/src/Prebuilt/components/Polls/common/constants.ts +5 -0
- package/src/Prebuilt/components/Preview/PreviewForm.tsx +2 -2
- package/src/Prebuilt/components/PreviousRoleInMetadata.tsx +1 -1
- package/src/Prebuilt/components/{ScreenshareTile.jsx → ScreenshareTile.tsx} +39 -6
- package/src/Prebuilt/components/SecondaryTiles.tsx +36 -4
- package/src/Prebuilt/components/Settings/DeviceSettings.jsx +1 -1
- package/src/Prebuilt/components/Settings/{LayoutSettings.jsx → LayoutSettings.tsx} +58 -14
- package/src/Prebuilt/components/Settings/{NotificationSettings.jsx → NotificationSettings.tsx} +14 -3
- package/src/Prebuilt/components/Settings/SettingsModal.jsx +32 -6
- package/src/Prebuilt/components/Settings/{SwitchWithLabel.jsx → SwitchWithLabel.tsx} +15 -1
- package/src/Prebuilt/components/Settings/common.ts +16 -0
- package/src/Prebuilt/components/TileMenu/{TileMenu.jsx → TileMenu.tsx} +12 -4
- package/src/Prebuilt/components/TileMenu/TileMenuContent.tsx +12 -10
- package/src/Prebuilt/components/VideoLayouts/ProminenceLayout.tsx +29 -14
- package/src/Prebuilt/components/VideoLayouts/RoleProminence.tsx +12 -2
- package/src/Prebuilt/components/VideoLayouts/ScreenshareLayout.tsx +20 -5
- package/src/Prebuilt/components/VideoLayouts/interface.ts +1 -0
- package/src/Prebuilt/components/{VideoTile.jsx → VideoTile.tsx} +57 -44
- package/src/Prebuilt/components/VirtualBackground/VBPicker.tsx +2 -2
- package/src/Prebuilt/components/hooks/{useDropdownList.jsx → useDropdownList.ts} +2 -1
- package/src/Prebuilt/components/pdfAnnotator/shareScreenOptions.jsx +1 -1
- package/src/Prebuilt/layouts/HLSView.jsx +2 -2
- package/src/Prebuilt/layouts/SidePane.tsx +8 -4
- package/src/Prebuilt/layouts/VideoStreamingSection.tsx +1 -1
- package/src/VideoTile/StyledVideoTile.tsx +4 -4
- package/dist/HLSView-2BP4GO3Q.js.map +0 -7
- package/dist/chunk-G25T3EBJ.js.map +0 -7
- package/src/Prebuilt/components/Settings/common.js +0 -41
- /package/src/Prebuilt/components/{ScreenshareDisplay.jsx → ScreenshareDisplay.tsx} +0 -0
|
@@ -11,30 +11,26 @@ import { usePollViewToggle } from '../../AppData/useSidepane';
|
|
|
11
11
|
import { usePollViewState } from '../../AppData/useUISettings';
|
|
12
12
|
import { POLL_VIEWS } from '../../../common/constants';
|
|
13
13
|
|
|
14
|
+
const getEditableFormat = questions => {
|
|
15
|
+
const editableQuestions = questions.map(question => {
|
|
16
|
+
return { ...question, saved: true, draftID: uuid() };
|
|
17
|
+
});
|
|
18
|
+
return editableQuestions;
|
|
19
|
+
};
|
|
20
|
+
|
|
14
21
|
export function CreateQuestions() {
|
|
15
|
-
const [questions, setQuestions] = useState([{ draftID: uuid() }]);
|
|
16
22
|
const actions = useHMSActions();
|
|
17
23
|
const { isHLSRunning } = useRecordingStreaming();
|
|
18
24
|
const togglePollView = usePollViewToggle();
|
|
19
25
|
const { pollInView: id, setPollView } = usePollViewState();
|
|
20
26
|
const interaction = useHMSStore(selectPollByID(id));
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
() => questions.length > 0 && questions.every(question => isValidQuestion(question)),
|
|
24
|
-
[questions],
|
|
27
|
+
const [questions, setQuestions] = useState(
|
|
28
|
+
interaction.questions?.length ? getEditableFormat(interaction.questions) : [{ draftID: uuid() }],
|
|
25
29
|
);
|
|
26
30
|
|
|
31
|
+
const isValidPoll = useMemo(() => questions.length > 0 && questions.every(isValidQuestion), [questions]);
|
|
32
|
+
|
|
27
33
|
const launchPoll = async () => {
|
|
28
|
-
const validQuestions = questions
|
|
29
|
-
.filter(question => isValidQuestion(question))
|
|
30
|
-
.map(question => ({
|
|
31
|
-
text: question.text,
|
|
32
|
-
type: question.type,
|
|
33
|
-
options: question.options,
|
|
34
|
-
skippable: question.skippable,
|
|
35
|
-
weight: question.weight,
|
|
36
|
-
}));
|
|
37
|
-
await actions.interactivityCenter.addQuestionsToPoll(id, validQuestions);
|
|
38
34
|
await actions.interactivityCenter.startPoll(id);
|
|
39
35
|
await sendTimedMetadata(id);
|
|
40
36
|
setPollView(POLL_VIEWS.VOTE);
|
|
@@ -75,17 +71,17 @@ export function CreateQuestions() {
|
|
|
75
71
|
question={question}
|
|
76
72
|
index={index}
|
|
77
73
|
length={questions.length}
|
|
78
|
-
onSave={questionParams => {
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
74
|
+
onSave={async questionParams => {
|
|
75
|
+
const updatedQuestions = [...questions.slice(0, index), questionParams, ...questions.slice(index + 1)];
|
|
76
|
+
setQuestions(updatedQuestions);
|
|
77
|
+
const validQuestions = updatedQuestions.filter(question => isValidQuestion(question));
|
|
78
|
+
|
|
79
|
+
await actions.interactivityCenter.addQuestionsToPoll(id, validQuestions);
|
|
84
80
|
}}
|
|
85
81
|
isQuiz={isQuiz}
|
|
86
82
|
removeQuestion={questionID =>
|
|
87
83
|
setQuestions(prev => {
|
|
88
|
-
return prev.filter(questionFromSet => questionID !== questionFromSet
|
|
84
|
+
return prev.filter(questionFromSet => questionID !== questionFromSet?.draftID);
|
|
89
85
|
})
|
|
90
86
|
}
|
|
91
87
|
convertToDraft={questionID =>
|
|
@@ -117,8 +113,8 @@ export function CreateQuestions() {
|
|
|
117
113
|
</Text>
|
|
118
114
|
</Flex>
|
|
119
115
|
<Flex css={{ w: '100%' }} justify="end">
|
|
120
|
-
<Button disabled={!isValidPoll} onClick={launchPoll}>
|
|
121
|
-
Launch {interaction
|
|
116
|
+
<Button disabled={!isValidPoll} onClick={async () => launchPoll()}>
|
|
117
|
+
Launch {interaction?.type}
|
|
122
118
|
</Button>
|
|
123
119
|
</Flex>
|
|
124
120
|
</Flex>
|
|
@@ -130,13 +126,7 @@ const QuestionCard = ({ question, onSave, index, length, removeQuestion, isQuiz,
|
|
|
130
126
|
return (
|
|
131
127
|
<Flex direction="column" css={{ p: '$md', bg: '$surface_default', r: '$1', mb: '$sm' }}>
|
|
132
128
|
{question.saved ? (
|
|
133
|
-
<SavedQuestion
|
|
134
|
-
question={question}
|
|
135
|
-
index={index}
|
|
136
|
-
length={length}
|
|
137
|
-
convertToDraft={convertToDraft}
|
|
138
|
-
removeQuestion={removeQuestion}
|
|
139
|
-
/>
|
|
129
|
+
<SavedQuestion question={question} index={index} length={length} convertToDraft={convertToDraft} />
|
|
140
130
|
) : (
|
|
141
131
|
<QuestionForm
|
|
142
132
|
question={question}
|
|
@@ -1,10 +1,7 @@
|
|
|
1
|
-
import React
|
|
1
|
+
import React from 'react';
|
|
2
2
|
import { HMSPollQuestion } from '@100mslive/react-sdk';
|
|
3
|
-
import { CheckCircleIcon
|
|
3
|
+
import { CheckCircleIcon } from '@100mslive/react-icons';
|
|
4
4
|
import { Button, Flex, Text } from '../../../../';
|
|
5
|
-
// @ts-ignore
|
|
6
|
-
import IconButton from '../../../IconButton';
|
|
7
|
-
import { DeleteQuestionModal } from './DeleteQuestionModal';
|
|
8
5
|
import { QUESTION_TYPE_TITLE } from '../../../common/constants';
|
|
9
6
|
|
|
10
7
|
export const SavedQuestion = ({
|
|
@@ -12,15 +9,12 @@ export const SavedQuestion = ({
|
|
|
12
9
|
index,
|
|
13
10
|
length,
|
|
14
11
|
convertToDraft,
|
|
15
|
-
removeQuestion,
|
|
16
12
|
}: {
|
|
17
13
|
question: HMSPollQuestion & { draftID: number };
|
|
18
14
|
index: number;
|
|
19
15
|
length: number;
|
|
20
16
|
convertToDraft: (draftID: number) => void;
|
|
21
|
-
removeQuestion: (draftID: number) => void;
|
|
22
17
|
}) => {
|
|
23
|
-
const [openDeleteModal, setOpenDeleteModal] = useState(false);
|
|
24
18
|
return (
|
|
25
19
|
<>
|
|
26
20
|
<Text variant="overline" css={{ c: '$on_surface_low', textTransform: 'uppercase' }}>
|
|
@@ -48,19 +42,11 @@ export const SavedQuestion = ({
|
|
|
48
42
|
Not required to answer
|
|
49
43
|
</Text>
|
|
50
44
|
) : null}
|
|
51
|
-
<Flex justify="end" css={{ w: '100%', alignItems: 'center'
|
|
52
|
-
<IconButton onClick={() => setOpenDeleteModal(true)} css={{ background: 'none' }}>
|
|
53
|
-
<TrashIcon />
|
|
54
|
-
</IconButton>
|
|
45
|
+
<Flex justify="end" css={{ w: '100%', alignItems: 'center' }}>
|
|
55
46
|
<Button variant="standard" css={{ fontWeight: '$semiBold' }} onClick={() => convertToDraft(question.draftID)}>
|
|
56
47
|
Edit
|
|
57
48
|
</Button>
|
|
58
49
|
</Flex>
|
|
59
|
-
<DeleteQuestionModal
|
|
60
|
-
removeQuestion={() => removeQuestion(question.draftID)}
|
|
61
|
-
open={openDeleteModal}
|
|
62
|
-
setOpen={setOpenDeleteModal}
|
|
63
|
-
/>
|
|
64
50
|
</>
|
|
65
51
|
);
|
|
66
52
|
};
|
|
@@ -44,7 +44,7 @@ export const LeaderboardSummary = ({ pollID }: { pollID: string }) => {
|
|
|
44
44
|
<Text variant="lg" css={{ fontWeight: '$semiBold' }}>
|
|
45
45
|
{quiz.title}
|
|
46
46
|
</Text>
|
|
47
|
-
<StatusIndicator
|
|
47
|
+
<StatusIndicator status={quiz.state} />
|
|
48
48
|
</Flex>
|
|
49
49
|
<Flex
|
|
50
50
|
css={{ color: '$on_surface_medium', '&:hover': { color: '$on_surface_high', cursor: 'pointer' } }}
|
|
@@ -73,16 +73,7 @@ export const QuestionCard = ({
|
|
|
73
73
|
},
|
|
74
74
|
]);
|
|
75
75
|
startTime.current = Date.now();
|
|
76
|
-
}, [
|
|
77
|
-
isValidVote,
|
|
78
|
-
actions.interactivityCenter,
|
|
79
|
-
pollID,
|
|
80
|
-
index,
|
|
81
|
-
singleOptionAnswer,
|
|
82
|
-
multipleOptionAnswer,
|
|
83
|
-
totalQuestions,
|
|
84
|
-
isQuiz,
|
|
85
|
-
]);
|
|
76
|
+
}, [isValidVote, actions.interactivityCenter, pollID, index, singleOptionAnswer, multipleOptionAnswer]);
|
|
86
77
|
|
|
87
78
|
return (
|
|
88
79
|
<Box
|
|
@@ -33,8 +33,6 @@ export const Voting = ({ id, toggleVoting }: { id: string; toggleVoting: () => v
|
|
|
33
33
|
|
|
34
34
|
const canViewLeaderboard = poll.type === 'quiz' && poll.state === 'stopped' && !poll.anonymous;
|
|
35
35
|
|
|
36
|
-
const isLive = poll.state === 'started';
|
|
37
|
-
|
|
38
36
|
return (
|
|
39
37
|
<Container rounded>
|
|
40
38
|
<Flex
|
|
@@ -56,7 +54,7 @@ export const Voting = ({ id, toggleVoting }: { id: string; toggleVoting: () => v
|
|
|
56
54
|
<ChevronLeftIcon />
|
|
57
55
|
</Flex>
|
|
58
56
|
<Text variant="h6">{poll.title}</Text>
|
|
59
|
-
<StatusIndicator
|
|
57
|
+
<StatusIndicator status={poll.state} />
|
|
60
58
|
<Box
|
|
61
59
|
css={{
|
|
62
60
|
marginLeft: 'auto',
|
|
@@ -1,12 +1,21 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
|
+
import { HMSPollState } from '@100mslive/react-sdk';
|
|
2
3
|
import { Flex, Text } from '../../../../';
|
|
4
|
+
import { PollStage } from './constants';
|
|
3
5
|
|
|
4
|
-
|
|
6
|
+
const statusMap: Record<HMSPollState, PollStage> = {
|
|
7
|
+
created: PollStage.DRAFT,
|
|
8
|
+
started: PollStage.LIVE,
|
|
9
|
+
stopped: PollStage.ENDED,
|
|
10
|
+
};
|
|
11
|
+
|
|
12
|
+
export const StatusIndicator = ({ status }: { status?: HMSPollState }) => {
|
|
13
|
+
if (!status) return null;
|
|
5
14
|
return (
|
|
6
15
|
<Flex align="center">
|
|
7
16
|
<Flex
|
|
8
17
|
css={{
|
|
9
|
-
backgroundColor:
|
|
18
|
+
backgroundColor: statusMap[status] === PollStage.LIVE ? '$alert_error_default' : '$secondary_default',
|
|
10
19
|
p: '$2 $4',
|
|
11
20
|
borderRadius: '$0',
|
|
12
21
|
}}
|
|
@@ -18,7 +27,7 @@ export const StatusIndicator = ({ isLive }: { isLive: boolean }) => {
|
|
|
18
27
|
color: '$on_primary_high',
|
|
19
28
|
}}
|
|
20
29
|
>
|
|
21
|
-
{
|
|
30
|
+
{statusMap[status]}
|
|
22
31
|
</Text>
|
|
23
32
|
</Flex>
|
|
24
33
|
</Flex>
|
|
@@ -2,7 +2,7 @@ import React from 'react';
|
|
|
2
2
|
import { useMedia } from 'react-use';
|
|
3
3
|
import { JoinForm_JoinBtnType } from '@100mslive/types-prebuilt/elements/join_form';
|
|
4
4
|
import { useRecordingStreaming } from '@100mslive/react-sdk';
|
|
5
|
-
import {
|
|
5
|
+
import { GoLiveIcon } from '@100mslive/react-icons';
|
|
6
6
|
import { Button, config as cssConfig, Flex, Input, styled } from '../../..';
|
|
7
7
|
import { useRoomLayout } from '../../provider/roomLayoutProvider';
|
|
8
8
|
// @ts-ignore: No implicit Any
|
|
@@ -72,7 +72,7 @@ const PreviewForm = ({
|
|
|
72
72
|
|
|
73
73
|
<Button type="submit" icon disabled={!name || !enableJoin} onClick={onJoin}>
|
|
74
74
|
{/* Conditions to show go live: The first broadcaster joins a streaming kit that is not live */}
|
|
75
|
-
{showGoLive ? <
|
|
75
|
+
{showGoLive ? <GoLiveIcon height={18} width={18} /> : null}
|
|
76
76
|
{showGoLive ? joinForm.go_live_btn_label : joinForm.join_btn_label}
|
|
77
77
|
</Button>
|
|
78
78
|
</Form>
|
|
@@ -10,7 +10,7 @@ export const PreviousRoleInMetadata = () => {
|
|
|
10
10
|
useEffect(() => {
|
|
11
11
|
let previousRole = vanillaStore.getState(selectLocalPeerRoleName);
|
|
12
12
|
const unsubscribe = vanillaStore.subscribe(currentRole => {
|
|
13
|
-
if (previousRole !== currentRole) {
|
|
13
|
+
if (previousRole !== currentRole && currentRole) {
|
|
14
14
|
updateMetaData({ prevRole: previousRole });
|
|
15
15
|
previousRole = currentRole;
|
|
16
16
|
}
|
|
@@ -10,11 +10,16 @@ import {
|
|
|
10
10
|
} from '@100mslive/react-sdk';
|
|
11
11
|
import { ExpandIcon, ShrinkIcon } from '@100mslive/react-icons';
|
|
12
12
|
import TileMenu from './TileMenu/TileMenu';
|
|
13
|
+
import { Box } from '../../Layout';
|
|
13
14
|
import { VideoTileStats } from '../../Stats';
|
|
15
|
+
import { useTheme } from '../../Theme';
|
|
14
16
|
import { Video } from '../../Video';
|
|
15
17
|
import { StyledVideoTile } from '../../VideoTile';
|
|
18
|
+
import { LayoutModeSelector } from './LayoutModeSelector';
|
|
19
|
+
// @ts-ignore: No implicit Any
|
|
16
20
|
import { getVideoTileLabel } from './peerTileUtils';
|
|
17
21
|
import { ScreenshareDisplay } from './ScreenshareDisplay';
|
|
22
|
+
// @ts-ignore: No implicit Any
|
|
18
23
|
import { useUISettings } from './AppData/useUISettings';
|
|
19
24
|
import { UI_SETTINGS } from '../common/constants';
|
|
20
25
|
|
|
@@ -27,14 +32,15 @@ const labelStyles = {
|
|
|
27
32
|
flexShrink: 0,
|
|
28
33
|
};
|
|
29
34
|
|
|
30
|
-
const Tile = ({ peerId, width = '100%', height = '100%' }) => {
|
|
35
|
+
const Tile = ({ peerId, width = '100%', height = '100%' }: { peerId: string; width?: string; height?: string }) => {
|
|
31
36
|
const isLocal = useHMSStore(selectLocalPeerID) === peerId;
|
|
32
37
|
const track = useHMSStore(selectScreenShareByPeerID(peerId));
|
|
38
|
+
const { theme } = useTheme();
|
|
33
39
|
const peer = useHMSStore(selectPeerByID(peerId));
|
|
34
40
|
const isAudioOnly = useUISettings(UI_SETTINGS.isAudioOnly);
|
|
35
41
|
const [isMouseHovered, setIsMouseHovered] = useState(false);
|
|
36
42
|
const showStatsOnTiles = useUISettings(UI_SETTINGS.showStatsOnTiles);
|
|
37
|
-
const fullscreenRef = useRef(null);
|
|
43
|
+
const fullscreenRef = useRef<HTMLDivElement | null>(null);
|
|
38
44
|
// fullscreen is for desired state
|
|
39
45
|
const [fullscreen, setFullscreen] = useState(false);
|
|
40
46
|
// isFullscreen is for true state
|
|
@@ -44,7 +50,7 @@ const Tile = ({ peerId, width = '100%', height = '100%' }) => {
|
|
|
44
50
|
const isFullScreenSupported = screenfull.isEnabled;
|
|
45
51
|
const audioTrack = useHMSStore(selectScreenShareAudioByPeerID(peer?.id));
|
|
46
52
|
|
|
47
|
-
if (isLocal && !['browser', 'window', 'application'].includes(track
|
|
53
|
+
if (isLocal && track?.displaySurface && !['browser', 'window', 'application'].includes(track.displaySurface)) {
|
|
48
54
|
return <ScreenshareDisplay />;
|
|
49
55
|
}
|
|
50
56
|
|
|
@@ -59,7 +65,15 @@ const Tile = ({ peerId, width = '100%', height = '100%' }) => {
|
|
|
59
65
|
});
|
|
60
66
|
|
|
61
67
|
return (
|
|
62
|
-
<StyledVideoTile.Root
|
|
68
|
+
<StyledVideoTile.Root
|
|
69
|
+
css={{
|
|
70
|
+
width,
|
|
71
|
+
height,
|
|
72
|
+
p: 0,
|
|
73
|
+
minHeight: 0,
|
|
74
|
+
}}
|
|
75
|
+
data-testid="screenshare_tile"
|
|
76
|
+
>
|
|
63
77
|
<StyledVideoTile.Container
|
|
64
78
|
transparentBg
|
|
65
79
|
ref={fullscreenRef}
|
|
@@ -73,14 +87,33 @@ const Tile = ({ peerId, width = '100%', height = '100%' }) => {
|
|
|
73
87
|
<VideoTileStats audioTrackID={audioTrack?.id} videoTrackID={track?.id} peerID={peerId} isLocal={isLocal} />
|
|
74
88
|
) : null}
|
|
75
89
|
{isFullScreenSupported && isMouseHovered ? (
|
|
76
|
-
<StyledVideoTile.FullScreenButton
|
|
90
|
+
<StyledVideoTile.FullScreenButton
|
|
91
|
+
css={{ bg: `${theme.colors.background_dim.value}A3` }}
|
|
92
|
+
onClick={() => setFullscreen(!fullscreen)}
|
|
93
|
+
>
|
|
77
94
|
{isFullscreen ? <ShrinkIcon /> : <ExpandIcon />}
|
|
78
95
|
</StyledVideoTile.FullScreenButton>
|
|
79
96
|
) : null}
|
|
97
|
+
{isMouseHovered && (
|
|
98
|
+
<Box
|
|
99
|
+
css={{
|
|
100
|
+
position: 'absolute',
|
|
101
|
+
top: '$2',
|
|
102
|
+
r: '$1',
|
|
103
|
+
h: '$14',
|
|
104
|
+
right: isFullScreenSupported ? '$17' : '$2',
|
|
105
|
+
zIndex: 5,
|
|
106
|
+
bg: `${theme.colors.background_dim.value}A3`,
|
|
107
|
+
}}
|
|
108
|
+
>
|
|
109
|
+
<LayoutModeSelector />
|
|
110
|
+
</Box>
|
|
111
|
+
)}
|
|
112
|
+
|
|
80
113
|
{track ? (
|
|
81
114
|
<Video
|
|
82
115
|
screenShare={true}
|
|
83
|
-
mirror={peer.isLocal
|
|
116
|
+
mirror={peer.isLocal}
|
|
84
117
|
attach={!isAudioOnly}
|
|
85
118
|
trackId={track.id}
|
|
86
119
|
css={{ minHeight: 0 }}
|
|
@@ -1,16 +1,39 @@
|
|
|
1
|
-
import React, { useEffect, useState } from 'react';
|
|
1
|
+
import React, { useEffect, useRef, useState } from 'react';
|
|
2
2
|
import { useMedia } from 'react-use';
|
|
3
|
+
import { selectAppData, selectSessionStore, selectTrackByID, useHMSStore } from '@100mslive/react-sdk';
|
|
3
4
|
import { LayoutProps } from './VideoLayouts/interface';
|
|
4
5
|
import { ProminenceLayout } from './VideoLayouts/ProminenceLayout';
|
|
5
6
|
import { config as cssConfig } from '../../Theme';
|
|
6
7
|
import { Pagination } from './Pagination';
|
|
7
8
|
import { usePagesWithTiles } from './hooks/useTileLayout';
|
|
9
|
+
import { APP_DATA, SESSION_STORE_KEY } from '../common/constants';
|
|
8
10
|
|
|
9
|
-
export const SecondaryTiles = ({ peers, onPageChange, onPageSize, edgeToEdge }: LayoutProps) => {
|
|
11
|
+
export const SecondaryTiles = ({ peers, onPageChange, onPageSize, edgeToEdge, hasSidebar }: LayoutProps) => {
|
|
10
12
|
const isMobile = useMedia(cssConfig.media.md);
|
|
11
13
|
const maxTileCount = isMobile ? 2 : 4;
|
|
12
|
-
const pagesWithTiles = usePagesWithTiles({ peers, maxTileCount });
|
|
13
14
|
const [page, setPage] = useState(0);
|
|
15
|
+
const pinnedTrackId = useHMSStore(selectAppData(APP_DATA.pinnedTrackId));
|
|
16
|
+
const spotlightPeerId = useHMSStore(selectSessionStore(SESSION_STORE_KEY.SPOTLIGHT));
|
|
17
|
+
const activeScreensharePeerId = useHMSStore(selectAppData(APP_DATA.activeScreensharePeerId));
|
|
18
|
+
const pinnedPeer = useHMSStore(selectTrackByID(pinnedTrackId))?.peerId;
|
|
19
|
+
const pageChangedAfterPinning = useRef(false);
|
|
20
|
+
const pagesWithTiles = usePagesWithTiles({
|
|
21
|
+
peers:
|
|
22
|
+
spotlightPeerId || pinnedPeer
|
|
23
|
+
? [...peers].sort((p1, p2) => {
|
|
24
|
+
const peerIdList = [activeScreensharePeerId, pinnedPeer, spotlightPeerId];
|
|
25
|
+
// put active screenshare peer, pinned peer, spotlight peer at first
|
|
26
|
+
if (peerIdList.includes(p1)) {
|
|
27
|
+
return -1;
|
|
28
|
+
}
|
|
29
|
+
if (peerIdList.includes(p2)) {
|
|
30
|
+
return 1;
|
|
31
|
+
}
|
|
32
|
+
return 0;
|
|
33
|
+
})
|
|
34
|
+
: peers,
|
|
35
|
+
maxTileCount,
|
|
36
|
+
});
|
|
14
37
|
const pageSize = pagesWithTiles[0]?.length || 0;
|
|
15
38
|
|
|
16
39
|
useEffect(() => {
|
|
@@ -19,8 +42,17 @@ export const SecondaryTiles = ({ peers, onPageChange, onPageSize, edgeToEdge }:
|
|
|
19
42
|
}
|
|
20
43
|
}, [pageSize, onPageSize]);
|
|
21
44
|
|
|
45
|
+
useEffect(() => {
|
|
46
|
+
if ((pinnedPeer || spotlightPeerId) && page !== 0 && !pageChangedAfterPinning.current) {
|
|
47
|
+
setPage(0);
|
|
48
|
+
pageChangedAfterPinning.current = true;
|
|
49
|
+
} else if (!pinnedPeer && !spotlightPeerId) {
|
|
50
|
+
pageChangedAfterPinning.current = false;
|
|
51
|
+
}
|
|
52
|
+
}, [pinnedPeer, spotlightPeerId, page]);
|
|
53
|
+
|
|
22
54
|
return (
|
|
23
|
-
<ProminenceLayout.SecondarySection tiles={pagesWithTiles[page]} edgeToEdge={edgeToEdge}>
|
|
55
|
+
<ProminenceLayout.SecondarySection tiles={pagesWithTiles[page]} edgeToEdge={edgeToEdge} hasSidebar={hasSidebar}>
|
|
24
56
|
{!edgeToEdge && (
|
|
25
57
|
<Pagination
|
|
26
58
|
page={page}
|
|
@@ -15,7 +15,7 @@ import { config as cssConfig } from '../../../Theme';
|
|
|
15
15
|
import { DialogDropdownTrigger } from '../../primitives/DropdownTrigger';
|
|
16
16
|
import { useUISettings } from '../AppData/useUISettings';
|
|
17
17
|
import { useDropdownSelection } from '../hooks/useDropdownSelection';
|
|
18
|
-
import { settingOverflow } from './common
|
|
18
|
+
import { settingOverflow } from './common';
|
|
19
19
|
import { UI_SETTINGS } from '../../common/constants';
|
|
20
20
|
|
|
21
21
|
/**
|
|
@@ -1,18 +1,34 @@
|
|
|
1
1
|
import React, { useCallback } from 'react';
|
|
2
2
|
import { selectIsLocalScreenShared, selectIsLocalVideoEnabled, useHMSActions, useHMSStore } from '@100mslive/react-sdk';
|
|
3
|
-
import {
|
|
3
|
+
import { GalleryIcon, PersonRectangleIcon, SidebarIcon } from '@100mslive/react-icons';
|
|
4
|
+
import { Box, Flex, Slider, Text } from '../../..';
|
|
4
5
|
import SwitchWithLabel from './SwitchWithLabel';
|
|
6
|
+
// @ts-ignore: No implicit Any
|
|
5
7
|
import { useSetUiSettings } from '../AppData/useUISettings';
|
|
6
|
-
import { settingOverflow } from './common
|
|
8
|
+
import { settingOverflow } from './common';
|
|
7
9
|
import { UI_SETTINGS } from '../../common/constants';
|
|
8
10
|
|
|
11
|
+
export const LayoutMode = {
|
|
12
|
+
SIDEBAR: 'Sidebar',
|
|
13
|
+
GALLERY: 'Gallery',
|
|
14
|
+
SPOTLIGHT: 'Spotlight',
|
|
15
|
+
};
|
|
16
|
+
|
|
17
|
+
export type LayoutModeKeys = keyof typeof LayoutMode;
|
|
18
|
+
|
|
19
|
+
export const LayoutModeIconMapping = {
|
|
20
|
+
[LayoutMode.GALLERY]: <GalleryIcon />,
|
|
21
|
+
[LayoutMode.SIDEBAR]: <SidebarIcon />,
|
|
22
|
+
[LayoutMode.SPOTLIGHT]: <PersonRectangleIcon />,
|
|
23
|
+
};
|
|
24
|
+
|
|
9
25
|
export const LayoutSettings = () => {
|
|
10
26
|
const hmsActions = useHMSActions();
|
|
11
27
|
const isLocalVideoEnabled = useHMSStore(selectIsLocalVideoEnabled);
|
|
12
28
|
const isLocalScreenShared = useHMSStore(selectIsLocalScreenShared);
|
|
13
29
|
const [{ isAudioOnly, maxTileCount, mirrorLocalVideo }, setUISettings] = useSetUiSettings();
|
|
14
30
|
const toggleIsAudioOnly = useCallback(
|
|
15
|
-
async isAudioOnlyModeOn => {
|
|
31
|
+
async (isAudioOnlyModeOn?: boolean) => {
|
|
16
32
|
if (isAudioOnlyModeOn) {
|
|
17
33
|
// turn off video and screen share if user switches to audio only mode
|
|
18
34
|
isLocalVideoEnabled && (await hmsActions.setLocalVideoEnabled(false));
|
|
@@ -25,17 +41,34 @@ export const LayoutSettings = () => {
|
|
|
25
41
|
|
|
26
42
|
return (
|
|
27
43
|
<Box className={settingOverflow()}>
|
|
28
|
-
<
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
44
|
+
<Box>
|
|
45
|
+
{/* <Text variant="md" css={{ fontWeight: '$semiBold' }}>
|
|
46
|
+
Layout Modes
|
|
47
|
+
</Text>
|
|
48
|
+
<RadioGroup.Root
|
|
49
|
+
css={{ flexDirection: 'column', alignItems: 'start', gap: '$10', my: '$2', py: '$8' }}
|
|
50
|
+
value={layoutMode}
|
|
51
|
+
onValueChange={value =>
|
|
52
|
+
setUISettings({
|
|
53
|
+
[UI_SETTINGS.layoutMode]: value,
|
|
54
|
+
})
|
|
55
|
+
}
|
|
56
|
+
>
|
|
57
|
+
{Object.keys(LayoutMode).map(key => {
|
|
58
|
+
return (
|
|
59
|
+
<Flex align="center" key={key} css={{ mr: '$8', gap: '$8' }}>
|
|
60
|
+
<RadioGroup.Item value={LayoutMode[key as LayoutModeKeys]} id={`layoutMode-${key}`} css={{ mr: '$4' }}>
|
|
61
|
+
<RadioGroup.Indicator />
|
|
62
|
+
</RadioGroup.Item>
|
|
63
|
+
<Label htmlFor={`layoutMode-${key}`} css={{ display: 'flex', gap: '$8', cursor: 'pointer' }}>
|
|
64
|
+
{LayoutModeIconMapping[LayoutMode[key as LayoutModeKeys]]}
|
|
65
|
+
{LayoutMode[key as LayoutModeKeys]}
|
|
66
|
+
</Label>
|
|
67
|
+
</Flex>
|
|
68
|
+
);
|
|
69
|
+
})}
|
|
70
|
+
</RadioGroup.Root> */}
|
|
71
|
+
</Box>
|
|
39
72
|
<Flex align="center" css={{ w: '100%', my: '$2', py: '$8', '@md': { display: 'none' } }}>
|
|
40
73
|
<Text variant="md" css={{ fontWeight: '$semiBold' }}>
|
|
41
74
|
Tiles In View({maxTileCount})
|
|
@@ -53,6 +86,17 @@ export const LayoutSettings = () => {
|
|
|
53
86
|
/>
|
|
54
87
|
</Flex>
|
|
55
88
|
</Flex>
|
|
89
|
+
<SwitchWithLabel label="Audio Only Mode" id="audioOnlyMode" checked={isAudioOnly} onChange={toggleIsAudioOnly} />
|
|
90
|
+
<SwitchWithLabel
|
|
91
|
+
label="Mirror Local Video"
|
|
92
|
+
id="mirrorMode"
|
|
93
|
+
checked={mirrorLocalVideo}
|
|
94
|
+
onChange={value => {
|
|
95
|
+
setUISettings({
|
|
96
|
+
[UI_SETTINGS.mirrorLocalVideo]: value,
|
|
97
|
+
});
|
|
98
|
+
}}
|
|
99
|
+
/>
|
|
56
100
|
</Box>
|
|
57
101
|
);
|
|
58
102
|
};
|
package/src/Prebuilt/components/Settings/{NotificationSettings.jsx → NotificationSettings.tsx}
RENAMED
|
@@ -1,12 +1,23 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
2
|
import { AlertOctagonIcon, HandIcon, PeopleAddIcon, PeopleRemoveIcon } from '@100mslive/react-icons';
|
|
3
|
-
import { Box } from '
|
|
3
|
+
import { Box } from '../../..';
|
|
4
4
|
import SwitchWithLabel from './SwitchWithLabel';
|
|
5
|
+
// @ts-ignore: No implicit Any
|
|
5
6
|
import { useSetSubscribedNotifications, useSubscribedNotifications } from '../AppData/useUISettings';
|
|
6
|
-
import { settingOverflow } from './common
|
|
7
|
+
import { settingOverflow } from './common';
|
|
7
8
|
import { SUBSCRIBED_NOTIFICATIONS } from '../../common/constants';
|
|
8
9
|
|
|
9
|
-
const NotificationItem = ({
|
|
10
|
+
const NotificationItem = ({
|
|
11
|
+
type,
|
|
12
|
+
label,
|
|
13
|
+
icon,
|
|
14
|
+
checked,
|
|
15
|
+
}: {
|
|
16
|
+
type: string;
|
|
17
|
+
label: string;
|
|
18
|
+
icon: React.ReactNode;
|
|
19
|
+
checked: boolean;
|
|
20
|
+
}) => {
|
|
10
21
|
const [, setSubscribedNotifications] = useSetSubscribedNotifications(type);
|
|
11
22
|
return (
|
|
12
23
|
<SwitchWithLabel
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import React, { useCallback, useEffect, useState } from 'react';
|
|
2
2
|
import { useMedia } from 'react-use';
|
|
3
|
-
import { ChevronLeftIcon, CrossIcon } from '@100mslive/react-icons';
|
|
3
|
+
import { ChevronLeftIcon, CrossIcon, GridFourIcon, NotificationsIcon, SettingsIcon } from '@100mslive/react-icons';
|
|
4
4
|
import { HorizontalDivider } from '../../../Divider';
|
|
5
5
|
import { IconButton } from '../../../IconButton';
|
|
6
6
|
import { Box, Flex } from '../../../Layout';
|
|
@@ -9,7 +9,31 @@ import { Sheet } from '../../../Sheet';
|
|
|
9
9
|
import { Tabs } from '../../../Tabs';
|
|
10
10
|
import { Text } from '../../../Text';
|
|
11
11
|
import { config as cssConfig } from '../../../Theme';
|
|
12
|
-
import
|
|
12
|
+
import DeviceSettings from './DeviceSettings';
|
|
13
|
+
import { LayoutSettings } from './LayoutSettings';
|
|
14
|
+
import { NotificationSettings } from './NotificationSettings';
|
|
15
|
+
import { settingContent } from './common';
|
|
16
|
+
|
|
17
|
+
const settingsList = [
|
|
18
|
+
{
|
|
19
|
+
tabName: 'devices',
|
|
20
|
+
title: 'Device Settings',
|
|
21
|
+
icon: SettingsIcon,
|
|
22
|
+
content: DeviceSettings,
|
|
23
|
+
},
|
|
24
|
+
{
|
|
25
|
+
tabName: 'notifications',
|
|
26
|
+
title: 'Notifications',
|
|
27
|
+
icon: NotificationsIcon,
|
|
28
|
+
content: NotificationSettings,
|
|
29
|
+
},
|
|
30
|
+
{
|
|
31
|
+
tabName: 'layout',
|
|
32
|
+
title: 'Layout',
|
|
33
|
+
icon: GridFourIcon,
|
|
34
|
+
content: LayoutSettings,
|
|
35
|
+
},
|
|
36
|
+
];
|
|
13
37
|
|
|
14
38
|
const SettingsModal = ({ open, onOpenChange, screenType, children = <></> }) => {
|
|
15
39
|
const mediaQueryLg = cssConfig.media.md;
|
|
@@ -53,8 +77,9 @@ const SettingsModal = ({ open, onOpenChange, screenType, children = <></> }) =>
|
|
|
53
77
|
showSetting={showSetting}
|
|
54
78
|
hideSettingByTabName={hideSettingByTabName}
|
|
55
79
|
resetSelection={resetSelection}
|
|
56
|
-
|
|
57
|
-
|
|
80
|
+
>
|
|
81
|
+
{children}
|
|
82
|
+
</MobileSettingModal>
|
|
58
83
|
) : (
|
|
59
84
|
<DesktopSettingModal
|
|
60
85
|
open={open}
|
|
@@ -64,8 +89,9 @@ const SettingsModal = ({ open, onOpenChange, screenType, children = <></> }) =>
|
|
|
64
89
|
showSetting={showSetting}
|
|
65
90
|
hideSettingByTabName={hideSettingByTabName}
|
|
66
91
|
resetSelection={resetSelection}
|
|
67
|
-
|
|
68
|
-
|
|
92
|
+
>
|
|
93
|
+
{children}
|
|
94
|
+
</DesktopSettingModal>
|
|
69
95
|
);
|
|
70
96
|
};
|
|
71
97
|
|
|
@@ -3,7 +3,21 @@ import { Label } from '../../../Label';
|
|
|
3
3
|
import { Flex } from '../../../Layout';
|
|
4
4
|
import { Switch } from '../../../Switch';
|
|
5
5
|
|
|
6
|
-
const SwitchWithLabel = ({
|
|
6
|
+
const SwitchWithLabel = ({
|
|
7
|
+
label,
|
|
8
|
+
icon,
|
|
9
|
+
id,
|
|
10
|
+
onChange,
|
|
11
|
+
checked,
|
|
12
|
+
hide = false,
|
|
13
|
+
}: {
|
|
14
|
+
label: string;
|
|
15
|
+
icon?: React.ReactNode;
|
|
16
|
+
id: string;
|
|
17
|
+
onChange: (value: boolean) => void;
|
|
18
|
+
checked: boolean;
|
|
19
|
+
hide?: boolean;
|
|
20
|
+
}) => {
|
|
7
21
|
return (
|
|
8
22
|
<Flex
|
|
9
23
|
align="center"
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { css } from '../../..';
|
|
2
|
+
|
|
3
|
+
export const settingOverflow = css({
|
|
4
|
+
flex: '1 1 0',
|
|
5
|
+
pr: '$12',
|
|
6
|
+
mr: '-$12',
|
|
7
|
+
overflowY: 'auto',
|
|
8
|
+
});
|
|
9
|
+
|
|
10
|
+
export const settingContent = css({
|
|
11
|
+
display: 'flex',
|
|
12
|
+
flexDirection: 'column',
|
|
13
|
+
'&[hidden]': {
|
|
14
|
+
display: 'none',
|
|
15
|
+
},
|
|
16
|
+
});
|