@100mslive/roomkit-react 0.2.1 → 0.2.2-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.
Files changed (33) hide show
  1. package/dist/{HLSView-U7FQ2YLK.js → HLSView-4TLGLPKO.js} +19 -4
  2. package/dist/HLSView-4TLGLPKO.js.map +7 -0
  3. package/dist/Prebuilt/components/Polls/Voting/LeaderboardEntry.d.ts +2 -1
  4. package/dist/Prebuilt/components/RoleChangeRequest/RequestPrompt.d.ts +2 -1
  5. package/dist/Prebuilt/components/VirtualBackground/VBHandler.d.ts +1 -0
  6. package/dist/{chunk-GNQAOG73.js → chunk-ARSLHHAZ.js} +176 -159
  7. package/dist/{chunk-GNQAOG73.js.map → chunk-ARSLHHAZ.js.map} +3 -3
  8. package/dist/index.cjs.js +159 -124
  9. package/dist/index.cjs.js.map +3 -3
  10. package/dist/index.js +1 -1
  11. package/dist/meta.cjs.json +41 -41
  12. package/dist/meta.esbuild.json +50 -50
  13. package/package.json +6 -6
  14. package/src/Button/Button.tsx +2 -2
  15. package/src/Prebuilt/components/Notifications/PermissionErrorModal.tsx +8 -1
  16. package/src/Prebuilt/components/Polls/Voting/LeaderboardEntry.tsx +17 -5
  17. package/src/Prebuilt/components/Polls/Voting/LeaderboardSummary.tsx +1 -0
  18. package/src/Prebuilt/components/Polls/Voting/PeerParticipationSummary.tsx +4 -2
  19. package/src/Prebuilt/components/Polls/Voting/QuestionCard.jsx +38 -81
  20. package/src/Prebuilt/components/Polls/Voting/StandardVoting.tsx +0 -1
  21. package/src/Prebuilt/components/Polls/Voting/TimedVoting.tsx +2 -3
  22. package/src/Prebuilt/components/Polls/Voting/Voting.tsx +3 -3
  23. package/src/Prebuilt/components/Polls/common/MultipleChoiceOptions.jsx +1 -2
  24. package/src/Prebuilt/components/Polls/common/SingleChoiceOptions.jsx +6 -4
  25. package/src/Prebuilt/components/Polls/common/StatusIndicator.tsx +1 -1
  26. package/src/Prebuilt/components/Preview/PreviewJoin.tsx +4 -14
  27. package/src/Prebuilt/components/RoleChangeRequest/RequestPrompt.tsx +15 -5
  28. package/src/Prebuilt/components/RoleChangeRequest/RoleChangeRequestModal.tsx +3 -0
  29. package/src/Prebuilt/components/VirtualBackground/VBHandler.tsx +11 -1
  30. package/src/Prebuilt/components/VirtualBackground/VBPicker.tsx +16 -2
  31. package/src/Prebuilt/layouts/HLSView.jsx +16 -1
  32. package/src/Sheet/Sheet.tsx +1 -1
  33. package/dist/HLSView-U7FQ2YLK.js.map +0 -7
@@ -1,14 +1,8 @@
1
1
  // @ts-check
2
- import React, { useCallback, useMemo, useState } from 'react';
2
+ import React, { useCallback, useMemo, useRef, useState } from 'react';
3
3
  import { selectLocalPeer, selectLocalPeerRoleName, useHMSActions, useHMSStore } from '@100mslive/react-sdk';
4
- import {
5
- CheckCircleIcon,
6
- ChevronDownIcon,
7
- ChevronLeftIcon,
8
- ChevronRightIcon,
9
- CrossCircleIcon,
10
- } from '@100mslive/react-icons';
11
- import { Box, Button, Flex, IconButton, Text } from '../../../../';
4
+ import { CheckCircleIcon, ChevronDownIcon, CrossCircleIcon } from '@100mslive/react-icons';
5
+ import { Box, Button, Flex, Text } from '../../../../';
12
6
  import { checkCorrectAnswer } from '../../../common/utils';
13
7
  import { MultipleChoiceOptions } from '../common/MultipleChoiceOptions';
14
8
  import { SingleChoiceOptions } from '../common/SingleChoiceOptions';
@@ -27,9 +21,7 @@ export const QuestionCard = ({
27
21
  options = [],
28
22
  answer,
29
23
  setCurrentIndex,
30
- skippable = false,
31
24
  responses = [],
32
- isTimed = false,
33
25
  rolesThatCanViewResponses,
34
26
  }) => {
35
27
  const actions = useHMSActions();
@@ -37,6 +29,7 @@ export const QuestionCard = ({
37
29
  const localPeerResponse = responses?.find(
38
30
  response => response.peer?.peerid === localPeer?.id || response.peer?.userid === localPeer?.customerUserId,
39
31
  );
32
+
40
33
  const isLocalPeerCreator = localPeer?.id === startedBy;
41
34
  const localPeerRoleName = useHMSStore(selectLocalPeerRoleName);
42
35
  const roleCanViewResponse =
@@ -48,27 +41,13 @@ export const QuestionCard = ({
48
41
 
49
42
  const isLive = pollState === 'started';
50
43
  const canRespond = isLive && !localPeerResponse;
51
-
44
+ const startTime = useRef(Date.now());
52
45
  const isCorrectAnswer = checkCorrectAnswer(answer, localPeerResponse, type);
53
46
 
54
- const prev = index !== 1;
55
- const next = index !== totalQuestions && (skippable || localPeerResponse);
56
-
57
- const moveNext = useCallback(() => {
58
- setCurrentIndex(curr => Math.min(totalQuestions, curr + 1));
59
- }, [setCurrentIndex, totalQuestions]);
60
-
61
- const movePrev = () => {
62
- setCurrentIndex(curr => Math.max(1, curr - 1));
63
- };
64
-
65
- // const [textAnswer, setTextAnswer] = useState('');
66
47
  const [singleOptionAnswer, setSingleOptionAnswer] = useState();
67
48
  const [multipleOptionAnswer, setMultipleOptionAnswer] = useState(new Set());
68
49
  const [showOptions, setShowOptions] = useState(true);
69
50
 
70
- // const stringAnswerExpected = [QUESTION_TYPE.LONG_ANSWER, QUESTION_TYPE.SHORT_ANSWER].includes(type);
71
-
72
51
  const respondedToQuiz = isQuiz && localPeerResponse && !localPeerResponse.skipped;
73
52
 
74
53
  const isValidVote = useMemo(() => {
@@ -83,24 +62,31 @@ export const QuestionCard = ({
83
62
  if (!isValidVote) {
84
63
  return;
85
64
  }
65
+
86
66
  await actions.interactivityCenter.addResponsesToPoll(pollID, [
87
67
  {
88
68
  questionIndex: index,
89
69
  option: singleOptionAnswer,
90
70
  options: Array.from(multipleOptionAnswer),
71
+ duration: Date.now() - startTime.current,
91
72
  },
92
73
  ]);
93
- }, [actions, index, pollID, isValidVote, singleOptionAnswer, multipleOptionAnswer]);
74
+ startTime.current = Date.now();
94
75
 
95
- const handleSkip = useCallback(async () => {
96
- await actions.interactivityCenter.addResponsesToPoll(pollID, [
97
- {
98
- questionIndex: index,
99
- skipped: true,
100
- },
101
- ]);
102
- moveNext();
103
- }, [actions, index, pollID, moveNext]);
76
+ if (isQuiz && index !== totalQuestions) {
77
+ setSingleOptionAnswer(undefined);
78
+ setMultipleOptionAnswer(new Set());
79
+ }
80
+ }, [
81
+ isValidVote,
82
+ actions.interactivityCenter,
83
+ pollID,
84
+ index,
85
+ singleOptionAnswer,
86
+ multipleOptionAnswer,
87
+ totalQuestions,
88
+ isQuiz,
89
+ ]);
104
90
 
105
91
  return (
106
92
  <Box
@@ -135,39 +121,6 @@ export const QuestionCard = ({
135
121
  {respondedToQuiz && !isCorrectAnswer ? <CrossCircleIcon height={20} width={20} /> : null}
136
122
  QUESTION {index} OF {totalQuestions}: {type.toUpperCase()}
137
123
  </Text>
138
-
139
- {isTimed ? (
140
- <Flex align="center" css={{ gap: '$4' }}>
141
- <IconButton
142
- disabled={!prev}
143
- onClick={movePrev}
144
- css={
145
- prev
146
- ? { color: '$on_surface_high', cursor: 'pointer' }
147
- : {
148
- color: '$on_surface_low',
149
- cursor: 'not-allowed',
150
- }
151
- }
152
- >
153
- <ChevronLeftIcon height={16} width={16} />
154
- </IconButton>
155
- <IconButton
156
- disabled={!next}
157
- onClick={moveNext}
158
- css={
159
- next
160
- ? { color: '$on_surface_high', cursor: 'pointer' }
161
- : {
162
- color: '$on_surface_low',
163
- cursor: 'not-allowed',
164
- }
165
- }
166
- >
167
- <ChevronRightIcon height={16} width={16} />
168
- </IconButton>
169
- </Flex>
170
- ) : null}
171
124
  </Flex>
172
125
 
173
126
  <Flex justify="between" css={{ my: '$md' }}>
@@ -185,10 +138,10 @@ export const QuestionCard = ({
185
138
  <Box css={{ maxHeight: showOptions ? '$80' : '0', transition: 'max-height 0.3s ease', overflowY: 'hidden' }}>
186
139
  {type === QUESTION_TYPE.SINGLE_CHOICE ? (
187
140
  <SingleChoiceOptions
141
+ key={index}
188
142
  questionIndex={index}
189
143
  isQuiz={isQuiz}
190
144
  canRespond={canRespond}
191
- response={localPeerResponse}
192
145
  correctOptionIndex={answer?.option}
193
146
  options={options}
194
147
  setAnswer={setSingleOptionAnswer}
@@ -196,14 +149,15 @@ export const QuestionCard = ({
196
149
  showVoteCount={showVoteCount}
197
150
  localPeerResponse={localPeerResponse}
198
151
  isStopped={pollState === 'stopped'}
152
+ answer={singleOptionAnswer}
199
153
  />
200
154
  ) : null}
155
+
201
156
  {type === QUESTION_TYPE.MULTIPLE_CHOICE ? (
202
157
  <MultipleChoiceOptions
203
158
  questionIndex={index}
204
159
  isQuiz={isQuiz}
205
160
  canRespond={canRespond}
206
- response={localPeerResponse}
207
161
  correctOptionIndexes={answer?.options}
208
162
  options={options}
209
163
  selectedOptions={multipleOptionAnswer}
@@ -214,14 +168,16 @@ export const QuestionCard = ({
214
168
  isStopped={pollState === 'stopped'}
215
169
  />
216
170
  ) : null}
171
+
217
172
  {isLive && (
218
173
  <QuestionActions
219
174
  isValidVote={isValidVote}
220
- skippable={skippable}
221
- onSkip={handleSkip}
222
175
  onVote={handleVote}
223
176
  response={localPeerResponse}
224
177
  isQuiz={isQuiz}
178
+ incrementIndex={() => {
179
+ setCurrentIndex(curr => Math.min(totalQuestions, curr + 1));
180
+ }}
225
181
  />
226
182
  )}
227
183
  </Box>
@@ -229,15 +185,9 @@ export const QuestionCard = ({
229
185
  );
230
186
  };
231
187
 
232
- const QuestionActions = ({ isValidVote, skippable, response, isQuiz, onVote, onSkip }) => {
188
+ const QuestionActions = ({ isValidVote, response, isQuiz, onVote, incrementIndex }) => {
233
189
  return (
234
190
  <Flex align="center" justify="end" css={{ gap: '$4', w: '100%' }}>
235
- {skippable && !response ? (
236
- <Button variant="standard" onClick={onSkip} css={{ p: '$xs $10', fontWeight: '$semiBold' }}>
237
- Skip
238
- </Button>
239
- ) : null}
240
-
241
191
  {response ? (
242
192
  <Text css={{ fontWeight: '$semiBold', color: '$on_surface_medium' }}>
243
193
  {response.skipped ? 'Skipped' : null}
@@ -245,7 +195,14 @@ const QuestionActions = ({ isValidVote, skippable, response, isQuiz, onVote, onS
245
195
  {!isQuiz && !response.skipped ? 'Voted' : null}
246
196
  </Text>
247
197
  ) : (
248
- <Button css={{ p: '$xs $10', fontWeight: '$semiBold' }} disabled={!isValidVote} onClick={onVote}>
198
+ <Button
199
+ css={{ p: '$xs $10', fontWeight: '$semiBold' }}
200
+ disabled={!isValidVote}
201
+ onClick={() => {
202
+ onVote();
203
+ incrementIndex();
204
+ }}
205
+ >
249
206
  {isQuiz ? 'Answer' : 'Vote'}
250
207
  </Button>
251
208
  )}
@@ -28,7 +28,6 @@ export const StandardView = ({ poll }: { poll: HMSPoll }) => {
28
28
  result={question.result}
29
29
  totalQuestions={poll.questions?.length || 0}
30
30
  options={question.options}
31
- skippable={question.skippable}
32
31
  responses={question.responses}
33
32
  answer={question.answer}
34
33
  setCurrentIndex={() => {
@@ -4,9 +4,10 @@ import { HMSPoll } from '@100mslive/react-sdk';
4
4
  import { QuestionCard } from './QuestionCard';
5
5
 
6
6
  export const TimedView = ({ poll }: { poll: HMSPoll }) => {
7
- // backend question index starts at 1
7
+ // Backend question index starts at 1
8
8
  const [currentIndex, setCurrentIndex] = useState(1);
9
9
  const activeQuestion = poll.questions?.find(question => question.index === currentIndex);
10
+
10
11
  if (!activeQuestion) {
11
12
  return null;
12
13
  }
@@ -23,12 +24,10 @@ export const TimedView = ({ poll }: { poll: HMSPoll }) => {
23
24
  result={activeQuestion?.result}
24
25
  totalQuestions={poll.questions?.length || 0}
25
26
  options={activeQuestion.options}
26
- skippable={activeQuestion.skippable || false}
27
27
  responses={activeQuestion.responses}
28
28
  answer={activeQuestion.answer}
29
29
  setCurrentIndex={setCurrentIndex}
30
30
  rolesThatCanViewResponses={poll.rolesThatCanViewResponses}
31
- isTimed
32
31
  />
33
32
  );
34
33
  };
@@ -23,6 +23,8 @@ export const Voting = ({ id, toggleVoting }: { id: string; toggleVoting: () => v
23
23
  const pollCreatorName = useHMSStore(selectPeerNameByID(poll?.createdBy));
24
24
  const isLocalPeerCreator = useHMSStore(selectLocalPeerID) === poll?.createdBy;
25
25
  const { setPollView } = usePollViewState();
26
+ // Sets view - linear or vertical, toggles timer indicator
27
+ const showSingleView = poll?.type === 'quiz' && poll.state === 'started';
26
28
 
27
29
  if (!poll) {
28
30
  return null;
@@ -30,8 +32,6 @@ export const Voting = ({ id, toggleVoting }: { id: string; toggleVoting: () => v
30
32
 
31
33
  const canViewLeaderboard = poll.type === 'quiz' && poll.state === 'stopped' && !poll.anonymous;
32
34
 
33
- // Sets view - linear or vertical, toggles timer indicator
34
- const isTimed = (poll.duration || 0) > 0;
35
35
  const isLive = poll.state === 'started';
36
36
 
37
37
  return (
@@ -74,7 +74,7 @@ export const Voting = ({ id, toggleVoting }: { id: string; toggleVoting: () => v
74
74
  </Text>
75
75
  ) : null}
76
76
 
77
- {isTimed ? <TimedView poll={poll} /> : <StandardView poll={poll} />}
77
+ {showSingleView ? <TimedView poll={poll} /> : <StandardView poll={poll} />}
78
78
 
79
79
  {poll.state === 'started' && isLocalPeerCreator && (
80
80
  <Button
@@ -10,7 +10,6 @@ export const MultipleChoiceOptions = ({
10
10
  questionIndex,
11
11
  options,
12
12
  canRespond,
13
- response,
14
13
  totalResponses,
15
14
  selectedOptions,
16
15
  setSelectedOptions,
@@ -39,7 +38,7 @@ export const MultipleChoiceOptions = ({
39
38
  <Checkbox.Root
40
39
  id={`${questionIndex}-${option.index}`}
41
40
  disabled={!canRespond}
42
- checked={response?.options?.includes(option.index)}
41
+ checked={localPeerResponse?.options?.includes(option.index)}
43
42
  onCheckedChange={checked => handleCheckedChange(checked, option.index)}
44
43
  css={{
45
44
  cursor: canRespond ? 'pointer' : 'not-allowed',
@@ -9,7 +9,6 @@ import { VoteProgress } from './VoteProgress';
9
9
  export const SingleChoiceOptions = ({
10
10
  questionIndex,
11
11
  options,
12
- response,
13
12
  canRespond,
14
13
  setAnswer,
15
14
  totalResponses,
@@ -18,9 +17,10 @@ export const SingleChoiceOptions = ({
18
17
  isStopped,
19
18
  isQuiz,
20
19
  localPeerResponse,
20
+ answer,
21
21
  }) => {
22
22
  return (
23
- <RadioGroup.Root value={response?.option} onValueChange={value => setAnswer(value)}>
23
+ <RadioGroup.Root value={answer || null} onValueChange={value => setAnswer(value)}>
24
24
  <Flex direction="column" css={{ gap: '$md', w: '100%', mb: '$md' }}>
25
25
  {options.map(option => {
26
26
  return (
@@ -65,8 +65,10 @@ export const SingleChoiceOptions = ({
65
65
 
66
66
  <Flex direction="column" css={{ flexGrow: '1' }}>
67
67
  <Flex css={{ w: '100%' }}>
68
- <Text css={{ display: 'flex', flexGrow: '1' }}>
69
- <Label htmlFor={`${questionIndex}-${option.index}`}>{option.text}</Label>
68
+ <Text css={{ display: 'flex', flexGrow: '1', color: '$on_surface_high' }}>
69
+ <Label style={{ color: 'inherit' }} htmlFor={`${questionIndex}-${option.index}`}>
70
+ {option.text}
71
+ </Label>
70
72
  </Text>
71
73
  {showVoteCount && <VoteCount voteCount={option.voteCount} />}
72
74
  </Flex>
@@ -15,7 +15,7 @@ export const StatusIndicator = ({ isLive }: { isLive: boolean }) => {
15
15
  variant="caption"
16
16
  css={{
17
17
  fontWeight: '$semiBold',
18
- color: '$on_surface_high',
18
+ color: '$on_primary_high',
19
19
  }}
20
20
  >
21
21
  {isLive ? 'LIVE' : 'ENDED'}
@@ -160,20 +160,7 @@ const PreviewJoin = ({
160
160
  <Chip content={getParticipantChipContent(peerCount)} hideIfNoContent />
161
161
  </Flex>
162
162
  </Flex>
163
- {toggleVideo ? (
164
- <Flex
165
- align="center"
166
- justify="center"
167
- css={{
168
- mt: '$14',
169
- '@md': { mt: 0 },
170
- '@sm': { width: '100%' },
171
- flexDirection: 'column',
172
- }}
173
- >
174
- <PreviewTile name={name} error={previewError} />
175
- </Flex>
176
- ) : null}
163
+ {toggleVideo ? <PreviewTile name={name} error={previewError} /> : null}
177
164
  <Box css={{ w: '100%', maxWidth: `${Math.max(aspectRatio, 1) * 360}px` }}>
178
165
  <PreviewControls hideSettings={!toggleVideo && !toggleAudio} vbEnabled={!!virtual_background} />
179
166
  <PreviewForm
@@ -225,9 +212,12 @@ export const PreviewTile = ({ name, error }: { name: string; error?: boolean })
225
212
  bg: '$surface_default',
226
213
  aspectRatio,
227
214
  height: 'min(360px, 70vh)',
215
+ width: 'auto',
228
216
  maxWidth: '640px',
229
217
  overflow: 'clip',
218
+ mt: '$14',
230
219
  '@md': {
220
+ mt: 0,
231
221
  width: 'min(220px, 70vw)',
232
222
  maxWidth: '100%',
233
223
  my: '$4',
@@ -10,6 +10,7 @@ export const RequestPrompt = ({
10
10
  body,
11
11
  actionText = 'Accept',
12
12
  onAction,
13
+ disableActions = false,
13
14
  }: {
14
15
  open?: boolean;
15
16
  onOpenChange: (value: boolean) => void;
@@ -17,6 +18,7 @@ export const RequestPrompt = ({
17
18
  body: React.ReactNode;
18
19
  actionText?: string;
19
20
  onAction: () => void;
21
+ disableActions?: boolean;
20
22
  }) => {
21
23
  const isMobile = useMedia(cssConfig.media.md);
22
24
 
@@ -26,7 +28,7 @@ export const RequestPrompt = ({
26
28
  <Sheet.Content css={{ py: '$8' }}>
27
29
  <Text css={{ fontWeight: '$semiBold', c: '$on_surface_high', '@md': { px: '$8' } }}>{title}</Text>
28
30
  {body}
29
- <RequestActions actionText={actionText} onAction={onAction} />
31
+ <RequestActions actionText={actionText} onAction={onAction} disabled={disableActions} />
30
32
  </Sheet.Content>
31
33
  </Sheet.Root>
32
34
  );
@@ -40,24 +42,32 @@ export const RequestPrompt = ({
40
42
  <Text variant="h6">{title}</Text>
41
43
  </Dialog.Title>
42
44
  <Box css={{ mt: '$4', mb: '$10' }}>{body}</Box>
43
- <RequestActions actionText={actionText} onAction={onAction} />
45
+ <RequestActions actionText={actionText} onAction={onAction} disabled={disableActions} />
44
46
  </Dialog.Content>
45
47
  </Dialog.Portal>
46
48
  </Dialog.Root>
47
49
  );
48
50
  };
49
51
 
50
- const RequestActions = ({ onAction, actionText }: { actionText?: string; onAction: () => void }) => (
52
+ const RequestActions = ({
53
+ onAction,
54
+ actionText,
55
+ disabled = false,
56
+ }: {
57
+ actionText?: string;
58
+ onAction: () => void;
59
+ disabled?: boolean;
60
+ }) => (
51
61
  <Flex justify="center" align="center" css={{ width: '100%', gap: '$md', '@md': { mt: '$8', px: '$8' } }}>
52
62
  <Box css={{ width: '50%' }}>
53
63
  <Dialog.Close css={{ width: '100%' }}>
54
- <Button variant="standard" outlined css={{ width: '100%' }}>
64
+ <Button variant="standard" outlined css={{ width: '100%' }} disabled={disabled}>
55
65
  Decline
56
66
  </Button>
57
67
  </Dialog.Close>
58
68
  </Box>
59
69
  <Box css={{ width: '50%' }}>
60
- <Button variant="primary" css={{ width: '100%' }} onClick={onAction}>
70
+ <Button variant="primary" css={{ width: '100%' }} onClick={onAction} disabled={disabled}>
61
71
  {actionText}
62
72
  </Button>
63
73
  </Box>
@@ -1,5 +1,6 @@
1
1
  import React, { useEffect } from 'react';
2
2
  import {
3
+ selectIsInPreview,
3
4
  selectLocalPeerName,
4
5
  selectLocalPeerRoleName,
5
6
  selectRoleChangeRequest,
@@ -20,6 +21,7 @@ import { ROLE_CHANGE_DECLINED } from '../../common/constants';
20
21
  export const RoleChangeRequestModal = () => {
21
22
  const hmsActions = useHMSActions();
22
23
  const { updateMetaData } = useMyMetadata();
24
+ const isPreview = useHMSStore(selectIsInPreview);
23
25
  const currentRole = useHMSStore(selectLocalPeerRoleName);
24
26
  const roleChangeRequest = useHMSStore(selectRoleChangeRequest);
25
27
  const name = useHMSStore(selectLocalPeerName);
@@ -87,6 +89,7 @@ export const RoleChangeRequestModal = () => {
87
89
  await hmsActions.lowerLocalPeerHand();
88
90
  }}
89
91
  actionText="Accept"
92
+ disableActions={!isPreview}
90
93
  />
91
94
  );
92
95
  };
@@ -19,8 +19,18 @@ export class VBPlugin {
19
19
  if (this.effectsPlugin) {
20
20
  return this.effectsPlugin?.getBackground();
21
21
  } else {
22
+ const background = this.hmsPlugin?.getBackground();
22
23
  // @ts-ignore
23
- return this.hmsPlugin?.background?.src || this.hmsPlugin?.background;
24
+ return background?.src || background;
25
+ }
26
+ };
27
+
28
+ getBlurAmount = () => {
29
+ if (this.effectsPlugin) {
30
+ return this.effectsPlugin.getBlurAmount();
31
+ } else {
32
+ // Treating HMS VB intensity as a fixed value
33
+ return this.hmsPlugin?.getBackground() === HMSVirtualBackgroundTypes.BLUR ? 1 : 0;
24
34
  }
25
35
  };
26
36
 
@@ -14,7 +14,7 @@ import {
14
14
  useHMSStore,
15
15
  } from '@100mslive/react-sdk';
16
16
  import { BlurPersonHighIcon, CloseIcon, CrossCircleIcon } from '@100mslive/react-icons';
17
- import { Box, Flex, Video } from '../../../index';
17
+ import { Box, Flex, Slider, Video } from '../../../index';
18
18
  import { Text } from '../../../Text';
19
19
  import { VBCollection } from './VBCollection';
20
20
  import { VBHandler } from './VBHandler';
@@ -36,6 +36,7 @@ export const VBPicker = ({ backgroundMedia = [] }: { backgroundMedia: VirtualBac
36
36
  const mirrorLocalVideo = useUISettings(UI_SETTINGS.mirrorLocalVideo);
37
37
  const trackSelector = selectVideoTrackByID(localPeer?.videoTrack);
38
38
  const track = useHMSStore(trackSelector);
39
+ const [blurAmount, setBlurAmount] = useState(VBHandler.getBlurAmount() || 0.5);
39
40
  const roomState = useHMSStore(selectRoomState);
40
41
  const isLargeRoom = useHMSStore(selectIsLargeRoom);
41
42
  const isEffectsEnabled = useHMSStore(selectIsEffectsEnabled);
@@ -127,7 +128,7 @@ export const VBPicker = ({ backgroundMedia = [] }: { backgroundMedia: VirtualBac
127
128
  icon: <BlurPersonHighIcon style={iconDims} />,
128
129
  value: HMSVirtualBackgroundTypes.BLUR,
129
130
  onClick: async () => {
130
- await VBHandler?.setBlur(0.5);
131
+ await VBHandler?.setBlur(blurAmount);
131
132
  setActiveBackground(HMSVirtualBackgroundTypes.BLUR);
132
133
  },
133
134
  },
@@ -135,6 +136,19 @@ export const VBPicker = ({ backgroundMedia = [] }: { backgroundMedia: VirtualBac
135
136
  activeBackground={activeBackground}
136
137
  />
137
138
 
139
+ {activeBackground === HMSVirtualBackgroundTypes.BLUR ? (
140
+ <Slider
141
+ value={[blurAmount]}
142
+ onValueChange={async e => {
143
+ setBlurAmount(e[0]);
144
+ await VBHandler.setBlur(e[0]);
145
+ }}
146
+ step={0.1}
147
+ min={0.1}
148
+ max={1}
149
+ />
150
+ ) : null}
151
+
138
152
  <VBCollection
139
153
  title="Backgrounds"
140
154
  options={mediaList.map(mediaURL => ({
@@ -3,11 +3,13 @@ import { useFullscreen, useMedia, usePrevious, useToggle } from 'react-use';
3
3
  import { HLSPlaybackState, HMSHLSPlayer, HMSHLSPlayerEvents } from '@100mslive/hls-player';
4
4
  import screenfull from 'screenfull';
5
5
  import {
6
+ HMSNotificationTypes,
6
7
  selectAppData,
7
8
  selectHLSState,
8
9
  selectPeerNameByID,
9
10
  selectPollByID,
10
11
  useHMSActions,
12
+ useHMSNotifications,
11
13
  useHMSStore,
12
14
  useHMSVanillaStore,
13
15
  } from '@100mslive/react-sdk';
@@ -30,12 +32,14 @@ import { usePollViewToggle } from '../components/AppData/useSidepane';
30
32
  import { APP_DATA, EMOJI_REACTION_TYPE } from '../common/constants';
31
33
 
32
34
  let hlsPlayer;
35
+ const toastMap = {};
33
36
 
34
37
  const HLSView = () => {
35
38
  const videoRef = useRef(null);
36
39
  const hlsViewRef = useRef(null);
37
40
  const hlsState = useHMSStore(selectHLSState);
38
41
  const enablHlsStats = useHMSStore(selectAppData(APP_DATA.hlsStats));
42
+ const notification = useHMSNotifications(HMSNotificationTypes.POLL_STOPPED);
39
43
  const hmsActions = useHMSActions();
40
44
  const { themeType, theme } = useTheme();
41
45
  const [streamEnded, setStreamEnded] = useState(false);
@@ -85,6 +89,15 @@ const HLSView = () => {
85
89
  }
86
90
  }, [hlsUrl, streamEnded, lastHlsUrl]);
87
91
 
92
+ useEffect(() => {
93
+ if (!notification) return;
94
+ const toastID = toastMap?.[notification.data.id];
95
+ if (toastID) {
96
+ ToastManager.removeToast(toastMap[notification.data.id]);
97
+ delete toastMap[notification.data.id];
98
+ }
99
+ }, [notification]);
100
+
88
101
  useEffect(() => {
89
102
  const videoElem = videoRef.current;
90
103
  const setStreamEndedCallback = () => {
@@ -126,7 +139,7 @@ const HLSView = () => {
126
139
  const poll = vanillaStore.getState(selectPollByID(pollId));
127
140
  const pollStartedBy = vanillaStore.getState(selectPeerNameByID(poll.startedBy)) || 'Participant';
128
141
  // launch poll
129
- ToastManager.addToast({
142
+ const toastID = ToastManager.addToast({
130
143
  title: `${pollStartedBy} started a ${poll.type}: ${poll.title}`,
131
144
  action: (
132
145
  <Button
@@ -142,7 +155,9 @@ const HLSView = () => {
142
155
  {poll.type === 'quiz' ? 'Answer' : 'Vote'}
143
156
  </Button>
144
157
  ),
158
+ duration: Infinity,
145
159
  });
160
+ toastMap[pollId] = toastID;
146
161
  return;
147
162
  }
148
163
  switch (parsedPayload.type) {
@@ -35,7 +35,7 @@ const StyledContent = styled(DialogPrimitive.Content, {
35
35
  borderTopRightRadius: '$3',
36
36
  boxShadow: '0 10px 20px rgba(0,0,0,0.19), 0 6px 6px rgba(0,0,0,0.23)',
37
37
  position: 'fixed',
38
- zIndex: 1001,
38
+ zIndex: 22,
39
39
  top: 0,
40
40
  right: 0,
41
41
  left: 0,