@selfcommunity/react-ui 0.11.0-alpha.22 → 0.11.0-alpha.24

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 (26) hide show
  1. package/lib/cjs/components/CreateLiveStreamDialog/CreateLiveStreamDialog.js +5 -5
  2. package/lib/cjs/components/EventForm/EventForm.js +7 -5
  3. package/lib/cjs/components/LiveStreamForm/LiveStreamForm.js +6 -4
  4. package/lib/cjs/components/LiveStreamRoom/LiveStreamVideoConference/ControlBar.js +3 -1
  5. package/lib/cjs/components/LiveStreamRoom/LiveStreamVideoConference/LiveStreamSettingsMenu.d.ts +8 -0
  6. package/lib/cjs/components/LiveStreamRoom/LiveStreamVideoConference/LiveStreamSettingsMenu.js +69 -0
  7. package/lib/cjs/components/LiveStreamRoom/LiveStreamVideoConference/PreJoin.d.ts +3 -2
  8. package/lib/cjs/components/LiveStreamRoom/LiveStreamVideoConference/PreJoin.js +31 -2
  9. package/lib/cjs/components/LiveStreamRoom/LiveStreamVideoConference/VideoConference.js +43 -4
  10. package/lib/cjs/constants/LiveStream.d.ts +1 -0
  11. package/lib/cjs/constants/LiveStream.js +2 -1
  12. package/lib/esm/components/CreateLiveStreamDialog/CreateLiveStreamDialog.js +5 -5
  13. package/lib/esm/components/EventForm/EventForm.js +8 -6
  14. package/lib/esm/components/LiveStreamForm/LiveStreamForm.js +6 -4
  15. package/lib/esm/components/LiveStreamRoom/LiveStreamVideoConference/ControlBar.js +3 -1
  16. package/lib/esm/components/LiveStreamRoom/LiveStreamVideoConference/LiveStreamSettingsMenu.d.ts +8 -0
  17. package/lib/esm/components/LiveStreamRoom/LiveStreamVideoConference/LiveStreamSettingsMenu.js +66 -0
  18. package/lib/esm/components/LiveStreamRoom/LiveStreamVideoConference/PreJoin.d.ts +3 -2
  19. package/lib/esm/components/LiveStreamRoom/LiveStreamVideoConference/PreJoin.js +31 -2
  20. package/lib/esm/components/LiveStreamRoom/LiveStreamVideoConference/VideoConference.js +45 -6
  21. package/lib/esm/constants/LiveStream.d.ts +1 -0
  22. package/lib/esm/constants/LiveStream.js +1 -0
  23. package/lib/umd/{653.js → 212.js} +2 -2
  24. package/lib/umd/react-ui.js +1 -1
  25. package/package.json +6 -5
  26. /package/lib/umd/{653.js.LICENSE.txt → 212.js.LICENSE.txt} +0 -0
@@ -77,7 +77,7 @@ const messages = defineMessages({
77
77
  * @param inProps
78
78
  */
79
79
  export default function LiveStreamForm(inProps) {
80
- var _a, _b, _c;
80
+ var _a, _b, _c, _d;
81
81
  //PROPS
82
82
  const props = useThemeProps({
83
83
  props: inProps,
@@ -100,6 +100,7 @@ export default function LiveStreamForm(inProps) {
100
100
  SCPreferences.STATIC_ENVIRONMENT in preferences &&
101
101
  preferences[SCPreferences.STATIC_ENVIRONMENT].value === SCCommunityEnvironment.STAGE, [preferences]);
102
102
  const communityStackId = useMemo(() => preferences && SCPreferences.STATIC_ENVIRONMENT in preferences && preferences[SCPreferences.STATIC_STACKID].value, [preferences]);
103
+ const canCreateLiveStream = useMemo(() => { var _a, _b; return (_b = (_a = scUserContext === null || scUserContext === void 0 ? void 0 : scUserContext.user) === null || _a === void 0 ? void 0 : _a.permission) === null || _b === void 0 ? void 0 : _b.create_live_stream; }, [(_a = scUserContext === null || scUserContext === void 0 ? void 0 : scUserContext.user) === null || _a === void 0 ? void 0 : _a.permission]);
103
104
  const intl = useIntl();
104
105
  // eslint-disable-next-line @typescript-eslint/ban-ts-comment
105
106
  // @ts-ignore
@@ -236,11 +237,12 @@ export default function LiveStreamForm(inProps) {
236
237
  }, error: Boolean(field.title.length > LIVE_STREAM_TITLE_MAX_LENGTH) || Boolean(error['titleError']), helperText: field.title.length > LIVE_STREAM_TITLE_MAX_LENGTH ? (_jsx(FormattedMessage, { id: "ui.liveStreamForm.title.error.maxLength", defaultMessage: "ui.liveStreamForm.title.error.maxLength" })) : error['titleError'] ? (error['titleError']) : null }), _jsx(TextField, { required: true, className: classes.slug, placeholder: `${intl.formatMessage(messages.slug)}`, margin: "normal", value: field.slug, name: "slug", onChange: handleChange, InputProps: {
237
238
  endAdornment: _jsx(Typography, Object.assign({ variant: "body2" }, { children: LIVE_STREAM_SLUG_MAX_LENGTH - field.slug.length }))
238
239
  }, error: Boolean(field.slug.length > LIVE_STREAM_SLUG_MAX_LENGTH) || Boolean(error['slugError']), helperText: field.title.length > LIVE_STREAM_SLUG_MAX_LENGTH ? (_jsx(FormattedMessage, { id: "ui.liveStreamForm.slug.error.maxLength", defaultMessage: "ui.liveStreamForm.slug.error.maxLength" })) : error['slugError'] ? (error['slugError']) : null }), _jsx(TextField, { multiline: true, rows: 4, className: classes.description, placeholder: `${intl.formatMessage(messages.description)}`, margin: "normal", value: field.description, name: "description", onChange: handleChange, InputProps: {
239
- endAdornment: (_jsx(Typography, Object.assign({ variant: "body2" }, { children: ((_a = field.description) === null || _a === void 0 ? void 0 : _a.length) ? LIVE_STREAM_DESCRIPTION_MAX_LENGTH - field.description.length : LIVE_STREAM_DESCRIPTION_MAX_LENGTH })))
240
- }, error: Boolean(((_b = field.description) === null || _b === void 0 ? void 0 : _b.length) > LIVE_STREAM_DESCRIPTION_MAX_LENGTH), helperText: ((_c = field.description) === null || _c === void 0 ? void 0 : _c.length) > LIVE_STREAM_DESCRIPTION_MAX_LENGTH ? (_jsx(FormattedMessage, { id: "ui.liveStreamForm.description.error.maxLength", defaultMessage: "ui.liveStreamForm.description.error.maxLength" })) : null }), _jsx(LiveStreamSettingsForm, { settings: field.settings, onChange: handleChangeSettings }), genericError && (_jsx(Box, Object.assign({ className: classes.genericError }, { children: _jsx(Alert, Object.assign({ variant: "filled", severity: "error" }, { children: genericError })) }))), _jsx(Box, Object.assign({ className: classes.actions }, { children: _jsx(LoadingButton, Object.assign({ loading: field.isSubmitting, disabled: !field.title ||
240
+ endAdornment: (_jsx(Typography, Object.assign({ variant: "body2" }, { children: ((_b = field.description) === null || _b === void 0 ? void 0 : _b.length) ? LIVE_STREAM_DESCRIPTION_MAX_LENGTH - field.description.length : LIVE_STREAM_DESCRIPTION_MAX_LENGTH })))
241
+ }, error: Boolean(((_c = field.description) === null || _c === void 0 ? void 0 : _c.length) > LIVE_STREAM_DESCRIPTION_MAX_LENGTH), helperText: ((_d = field.description) === null || _d === void 0 ? void 0 : _d.length) > LIVE_STREAM_DESCRIPTION_MAX_LENGTH ? (_jsx(FormattedMessage, { id: "ui.liveStreamForm.description.error.maxLength", defaultMessage: "ui.liveStreamForm.description.error.maxLength" })) : null }), _jsx(LiveStreamSettingsForm, { settings: field.settings, onChange: handleChangeSettings }), genericError && (_jsx(Box, Object.assign({ className: classes.genericError }, { children: _jsx(Alert, Object.assign({ variant: "filled", severity: "error" }, { children: genericError })) }))), _jsx(Box, Object.assign({ className: classes.actions }, { children: _jsx(LoadingButton, Object.assign({ loading: field.isSubmitting, disabled: !field.title ||
241
242
  field.isSubmitting ||
242
243
  field.title.length > LIVE_STREAM_TITLE_MAX_LENGTH ||
243
244
  field.description.length > LIVE_STREAM_DESCRIPTION_MAX_LENGTH ||
244
245
  isFreeTrialTier ||
245
- timeRemaining <= WARNING_THRESHOLD_EXPIRING_SOON, variant: "contained", onClick: handleSubmit, color: "secondary" }, { children: liveStream ? (_jsx(FormattedMessage, { id: "ui.liveStreamForm.button.edit", defaultMessage: "ui.liveStreamForm.button.edit" })) : (_jsx(FormattedMessage, { id: "ui.liveStreamForm.button.create", defaultMessage: "ui.liveStreamForm.button.create" })) })) }))] }))] })));
246
+ timeRemaining <= WARNING_THRESHOLD_EXPIRING_SOON ||
247
+ !canCreateLiveStream, variant: "contained", onClick: handleSubmit, color: "secondary" }, { children: liveStream ? (_jsx(FormattedMessage, { id: "ui.liveStreamForm.button.edit", defaultMessage: "ui.liveStreamForm.button.edit" })) : (_jsx(FormattedMessage, { id: "ui.liveStreamForm.button.create", defaultMessage: "ui.liveStreamForm.button.create" })) })) }))] }))] })));
246
248
  }
@@ -9,6 +9,7 @@ import { useMediaQuery } from '@mui/material';
9
9
  import { SettingsMenuToggle } from './SettingsMenuToggle';
10
10
  import { DisconnectButton } from './DisconnectButton';
11
11
  import { mergeProps } from './utils';
12
+ import { FormattedMessage } from 'react-intl';
12
13
  /**
13
14
  * The `ControlBar` prefab gives the user the basic user interface to control their
14
15
  * media devices (camera, microphone and screen share), open the `Chat` and leave the room.
@@ -54,5 +55,6 @@ export function ControlBar(_a) {
54
55
  });
55
56
  const microphoneOnChange = React.useCallback((enabled, isUserInitiated) => (isUserInitiated ? saveAudioInputEnabled(enabled) : null), [saveAudioInputEnabled]);
56
57
  const cameraOnChange = React.useCallback((enabled, isUserInitiated) => (isUserInitiated ? saveVideoInputEnabled(enabled) : null), [saveVideoInputEnabled]);
57
- return (_jsxs("div", Object.assign({}, htmlProps, { children: [visibleControls.microphone && (_jsxs("div", Object.assign({ className: "lk-button-group" }, { children: [_jsx(_Fragment, { children: _jsx(TrackToggle, Object.assign({ source: Track.Source.Microphone, showIcon: showIcon, onChange: microphoneOnChange, onDeviceError: (error) => onDeviceError === null || onDeviceError === void 0 ? void 0 : onDeviceError({ source: Track.Source.Microphone, error }) }, { children: showText && 'Microphone' })) }), _jsx("div", Object.assign({ className: "lk-button-group-menu" }, { children: _jsx(MediaDeviceMenu, { kind: "audioinput", onActiveDeviceChange: (_kind, deviceId) => saveAudioInputDeviceId(deviceId !== null && deviceId !== void 0 ? deviceId : '') }) }))] }))), visibleControls.camera && (_jsxs("div", Object.assign({ className: "lk-button-group" }, { children: [_jsx(_Fragment, { children: _jsx(TrackToggle, Object.assign({ source: Track.Source.Camera, showIcon: showIcon, onChange: cameraOnChange, onDeviceError: (error) => onDeviceError === null || onDeviceError === void 0 ? void 0 : onDeviceError({ source: Track.Source.Camera, error }) }, { children: showText && 'Camera' })) }), _jsx("div", Object.assign({ className: "lk-button-group-menu" }, { children: _jsx(MediaDeviceMenu, { kind: "videoinput", onActiveDeviceChange: (_kind, deviceId) => saveVideoInputDeviceId(deviceId !== null && deviceId !== void 0 ? deviceId : '') }) }))] }))), visibleControls.screenShare && browserSupportsScreenSharing && (_jsx(_Fragment, { children: _jsx(TrackToggle, Object.assign({ source: Track.Source.ScreenShare, captureOptions: { audio: true, selfBrowserSurface: 'include', surfaceSwitching: 'exclude' }, showIcon: showIcon, onChange: onScreenShareChange, onDeviceError: (error) => onDeviceError === null || onDeviceError === void 0 ? void 0 : onDeviceError({ source: Track.Source.ScreenShare, error }) }, { children: showText && (isScreenShareEnabled ? 'Stop screen share' : 'Share screen') })) })), visibleControls.chat && (_jsx(_Fragment, { children: _jsxs(ChatToggle, { children: [showIcon && _jsx(ChatIcon, {}), showText && 'Chat'] }) })), visibleControls.settings && (_jsx(_Fragment, { children: _jsxs(SettingsMenuToggle, { children: [showIcon && _jsx(GearIcon, {}), showText && 'Settings'] }) })), visibleControls.leave && (_jsx(_Fragment, { children: _jsxs(DisconnectButton, { children: [showIcon && _jsx(LeaveIcon, {}), showText && 'Leave'] }) })), _jsx(StartMediaButton, {})] })));
58
+ return (_jsxs("div", Object.assign({}, htmlProps, { children: [visibleControls.microphone && (_jsxs("div", Object.assign({ className: "lk-button-group" }, { children: [_jsx(_Fragment, { children: _jsx(TrackToggle, Object.assign({ source: Track.Source.Microphone, showIcon: showIcon, onChange: microphoneOnChange, onDeviceError: (error) => onDeviceError === null || onDeviceError === void 0 ? void 0 : onDeviceError({ source: Track.Source.Microphone, error }) }, { children: showText && _jsx(FormattedMessage, { id: "ui.liveStreamRoom.controlBar.microphone", defaultMessage: "ui.liveStreamRoom.controlBar.microphone" }) })) }), _jsx("div", Object.assign({ className: "lk-button-group-menu" }, { children: _jsx(MediaDeviceMenu, { kind: "audioinput", onActiveDeviceChange: (_kind, deviceId) => saveAudioInputDeviceId(deviceId !== null && deviceId !== void 0 ? deviceId : '') }) }))] }))), visibleControls.camera && (_jsxs("div", Object.assign({ className: "lk-button-group" }, { children: [_jsx(_Fragment, { children: _jsx(TrackToggle, Object.assign({ source: Track.Source.Camera, showIcon: showIcon, onChange: cameraOnChange, onDeviceError: (error) => onDeviceError === null || onDeviceError === void 0 ? void 0 : onDeviceError({ source: Track.Source.Camera, error }) }, { children: showText && _jsx(FormattedMessage, { id: "ui.liveStreamRoom.controlBar.camera", defaultMessage: "ui.liveStreamRoom.controlBar.camera" }) })) }), _jsx("div", Object.assign({ className: "lk-button-group-menu" }, { children: _jsx(MediaDeviceMenu, { kind: "videoinput", onActiveDeviceChange: (_kind, deviceId) => saveVideoInputDeviceId(deviceId !== null && deviceId !== void 0 ? deviceId : '') }) }))] }))), visibleControls.screenShare && browserSupportsScreenSharing && (_jsx(_Fragment, { children: _jsx(TrackToggle, Object.assign({ source: Track.Source.ScreenShare, captureOptions: { audio: true, selfBrowserSurface: 'include', surfaceSwitching: 'exclude' }, showIcon: showIcon, onChange: onScreenShareChange, onDeviceError: (error) => onDeviceError === null || onDeviceError === void 0 ? void 0 : onDeviceError({ source: Track.Source.ScreenShare, error }) }, { children: showText &&
59
+ (isScreenShareEnabled ? (_jsx(FormattedMessage, { id: "ui.liveStreamRoom.controlBar.stopShareScreen", defaultMessage: "ui.liveStreamRoom.controlBar.stopShareScreen" })) : (_jsx(FormattedMessage, { id: "ui.liveStreamRoom.controlBar.shareScreen", defaultMessage: "ui.liveStreamRoom.controlBar.shareScreen" }))) })) })), visibleControls.chat && (_jsx(_Fragment, { children: _jsxs(ChatToggle, { children: [showIcon && _jsx(ChatIcon, {}), showText && _jsx(FormattedMessage, { id: "ui.liveStreamRoom.controlBar.chat", defaultMessage: "ui.liveStreamRoom.controlBar.chat" })] }) })), visibleControls.settings && (_jsx(_Fragment, { children: _jsxs(SettingsMenuToggle, { children: [showIcon && _jsx(GearIcon, {}), showText && _jsx(FormattedMessage, { id: "ui.liveStreamRoom.controlBar.settings", defaultMessage: "ui.liveStreamRoom.controlBar.settings" })] }) })), visibleControls.leave && (_jsx(_Fragment, { children: _jsxs(DisconnectButton, { children: [showIcon && _jsx(LeaveIcon, {}), showText && _jsx(FormattedMessage, { id: "ui.liveStreamRoom.controlBar.leave", defaultMessage: "ui.liveStreamRoom.controlBar.leave" })] }) })), _jsx(StartMediaButton, {})] })));
58
60
  }
@@ -0,0 +1,8 @@
1
+ export interface LiveStreamSettingsMenuProps {
2
+ className?: string;
3
+ blurEnabled?: boolean;
4
+ handleBlur?: (event: any) => void;
5
+ actionBlurDisabled?: boolean;
6
+ onlyContentMenu?: boolean;
7
+ }
8
+ export default function LiveStreamSettingsMenu(inProps: LiveStreamSettingsMenuProps): JSX.Element;
@@ -0,0 +1,66 @@
1
+ import { __rest } from "tslib";
2
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
3
+ import * as React from 'react';
4
+ import Button from '@mui/material/Button';
5
+ import Menu from '@mui/material/Menu';
6
+ import { Box, FormControlLabel, Icon, Switch, Typography } from '@mui/material';
7
+ import { styled } from '@mui/material/styles';
8
+ import { useThemeProps } from '@mui/system';
9
+ import classNames from 'classnames';
10
+ import { Fragment, useMemo } from 'react';
11
+ import { FormattedMessage } from 'react-intl';
12
+ const PREFIX = 'SCLiveStreamSettingsMenu';
13
+ const classes = {
14
+ root: `${PREFIX}-root`,
15
+ menuRoot: `${PREFIX}-menu-root`
16
+ };
17
+ const Root = styled(Button, {
18
+ name: PREFIX,
19
+ slot: 'Root',
20
+ overridesResolver: (props, styles) => styles.root
21
+ })(({ theme }) => ({
22
+ borderRadius: 7,
23
+ color: theme.palette.common.white,
24
+ paddingLeft: theme.spacing(),
25
+ paddingRight: theme.spacing(),
26
+ minWidth: 45
27
+ }));
28
+ const MenuRoot = styled(Menu, {
29
+ name: PREFIX,
30
+ slot: 'Root',
31
+ overridesResolver: (props, styles) => styles.menuRoot
32
+ })(({ theme }) => ({
33
+ '& .MuiPaper-root': {
34
+ minWidth: 120,
35
+ paddingRight: theme.spacing(2),
36
+ '& div.MuiTypography-body1': {
37
+ paddingLeft: theme.spacing(2)
38
+ },
39
+ '& .MuiFormControlLabel-label.Mui-disabled': {
40
+ color: theme.palette.text.primary
41
+ }
42
+ }
43
+ }));
44
+ export default function LiveStreamSettingsMenu(inProps) {
45
+ // PROPS
46
+ const props = useThemeProps({
47
+ props: inProps,
48
+ name: PREFIX
49
+ });
50
+ const { className, actionBlurDisabled = false, blurEnabled = false, handleBlur, onlyContentMenu = false } = props, rest = __rest(props, ["className", "actionBlurDisabled", "blurEnabled", "handleBlur", "onlyContentMenu"]);
51
+ const [anchorEl, setAnchorEl] = React.useState(null);
52
+ const open = Boolean(anchorEl);
53
+ const handleClick = (event) => {
54
+ setAnchorEl(event.currentTarget);
55
+ };
56
+ const handleClose = () => {
57
+ setAnchorEl(null);
58
+ };
59
+ const MenuContent = useMemo(() => (_jsxs(Box, { children: [_jsx(Typography, Object.assign({ variant: "body1", component: "div" }, { children: _jsx("b", { children: _jsx(FormattedMessage, { id: "ui.liveStreamRoom.settingsMenu.visualEffect", defaultMessage: "ui.liveStreamRoom.settingsMenu.visualEffect" }) }) })), _jsx(FormControlLabel, { labelPlacement: "start", control: _jsx(Switch, { checked: blurEnabled, disabled: actionBlurDisabled, onChange: handleBlur, inputProps: { 'aria-label': 'controlled' } }), label: _jsx(FormattedMessage, { id: "ui.liveStreamRoom.settingsMenu.visualEffect.blurEffect", defaultMessage: "ui.liveStreamRoom.settingsMenu.visualEffect.blurEffect" }) })] })), [blurEnabled, actionBlurDisabled, handleBlur]);
60
+ if (onlyContentMenu) {
61
+ return MenuContent;
62
+ }
63
+ return (_jsxs(Fragment, { children: [_jsx(Root, Object.assign({ className: classNames(className, classes.root, 'lk-button'), "aria-controls": open ? 'live-stream-settings-menu' : undefined, "aria-haspopup": "true", "aria-expanded": open ? 'true' : undefined, onClick: handleClick }, rest, { children: _jsx(Icon, { children: "more_vert" }) })), _jsx(MenuRoot, Object.assign({ id: "live-stream-settings-menu", anchorEl: anchorEl, open: open, onClose: handleClose, MenuListProps: {
64
+ 'aria-labelledby': 'basic-button'
65
+ } }, { children: MenuContent }))] }));
66
+ }
@@ -1,5 +1,5 @@
1
1
  import type { CreateLocalTracksOptions, LocalAudioTrack, LocalTrack, LocalVideoTrack } from 'livekit-client';
2
- import { Track } from 'livekit-client';
2
+ import { Track, TrackProcessor } from 'livekit-client';
3
3
  import * as React from 'react';
4
4
  import type { LocalUserChoices } from '@livekit/components-core';
5
5
  /**
@@ -28,6 +28,7 @@ export interface PreJoinProps extends Omit<React.HTMLAttributes<HTMLDivElement>,
28
28
  * @alpha
29
29
  */
30
30
  persistUserChoices?: boolean;
31
+ videoProcessor?: TrackProcessor<Track.Kind.Video>;
31
32
  }
32
33
  /** @alpha */
33
34
  export declare function usePreviewTracks(options: CreateLocalTracksOptions, onError?: (err: Error) => void): {
@@ -55,4 +56,4 @@ export declare function usePreviewDevice<T extends LocalVideoTrack | LocalAudioT
55
56
  * ```
56
57
  * @public
57
58
  */
58
- export declare function PreJoin({ defaults, onValidate, onSubmit, onError, debug, joinLabel, micLabel, camLabel, userLabel, persistUserChoices, ...htmlProps }: PreJoinProps): JSX.Element;
59
+ export declare function PreJoin({ defaults, onValidate, onSubmit, onError, debug, joinLabel, micLabel, camLabel, userLabel, persistUserChoices, videoProcessor, ...htmlProps }: PreJoinProps): JSX.Element;
@@ -10,6 +10,10 @@ import ParticipantTileAvatar from './ParticipantTileAvatar';
10
10
  import { useEffect, useMemo } from 'react';
11
11
  import { TrackToggle } from './TrackToggle';
12
12
  import { useLiveStream } from './LiveStreamProvider';
13
+ import { BackgroundBlur } from '@livekit/track-processors';
14
+ import LiveStreamSettingsMenu from './LiveStreamSettingsMenu';
15
+ import { isClientSideRendering } from '@selfcommunity/utils';
16
+ import { CHOICE_VIDEO_BLUR_EFFECT } from '../../../constants/LiveStream';
13
17
  /** @alpha */
14
18
  export function usePreviewTracks(options, onError) {
15
19
  const [tracks, setTracks] = React.useState();
@@ -152,7 +156,8 @@ export function usePreviewDevice(enabled, deviceId, kind) {
152
156
  * @public
153
157
  */
154
158
  export function PreJoin(_a) {
155
- var { defaults = {}, onValidate, onSubmit, onError, debug, joinLabel = 'Join Room', micLabel = 'Microphone', camLabel = 'Camera', userLabel = 'Username', persistUserChoices = true } = _a, htmlProps = __rest(_a, ["defaults", "onValidate", "onSubmit", "onError", "debug", "joinLabel", "micLabel", "camLabel", "userLabel", "persistUserChoices"]);
159
+ var _b;
160
+ var { defaults = {}, onValidate, onSubmit, onError, debug, joinLabel = 'Join Room', micLabel = 'Microphone', camLabel = 'Camera', userLabel = 'Username', persistUserChoices = true, videoProcessor } = _a, htmlProps = __rest(_a, ["defaults", "onValidate", "onSubmit", "onError", "debug", "joinLabel", "micLabel", "camLabel", "userLabel", "persistUserChoices", "videoProcessor"]);
156
161
  const { liveStream } = useLiveStream();
157
162
  const scUserContext = useSCUser();
158
163
  const [userChoices, setUserChoices] = React.useState(defaultUserChoices);
@@ -171,6 +176,9 @@ export function PreJoin(_a) {
171
176
  const [audioDeviceId, setAudioDeviceId] = React.useState(initialUserChoices.audioDeviceId);
172
177
  const [videoDeviceId, setVideoDeviceId] = React.useState(initialUserChoices.videoDeviceId);
173
178
  const [username, setUsername] = React.useState(initialUserChoices.username);
179
+ // Processors
180
+ const [blurEnabled, setBlurEnabled] = React.useState(isClientSideRendering() ? Boolean((_b = window === null || window === void 0 ? void 0 : window.localStorage) === null || _b === void 0 ? void 0 : _b.getItem(CHOICE_VIDEO_BLUR_EFFECT)) || false : false);
181
+ const [processorPending, setProcessorPending] = React.useState(false);
174
182
  // Save user choices to persistent storage.
175
183
  React.useEffect(() => {
176
184
  saveAudioInputEnabled(audioEnabled && canUseAudio);
@@ -225,6 +233,11 @@ export function PreJoin(_a) {
225
233
  ((values.videoEnabled && values.videoDeviceId) || !values.videoEnabled));
226
234
  }
227
235
  }, [onValidate]);
236
+ const handleBlur = React.useCallback(() => {
237
+ var _a;
238
+ setBlurEnabled((enabled) => !enabled);
239
+ (_a = window === null || window === void 0 ? void 0 : window.localStorage) === null || _a === void 0 ? void 0 : _a.setItem(CHOICE_VIDEO_BLUR_EFFECT, (!blurEnabled).toString());
240
+ }, [setBlurEnabled, blurEnabled]);
228
241
  useEffect(() => {
229
242
  const newUserChoices = {
230
243
  username,
@@ -236,6 +249,22 @@ export function PreJoin(_a) {
236
249
  setUserChoices(newUserChoices);
237
250
  setIsValid(handleValidation(newUserChoices));
238
251
  }, [username, scUserContext.user, videoEnabled, handleValidation, audioEnabled, audioDeviceId, videoDeviceId]);
252
+ useEffect(() => {
253
+ if (videoTrack && videoEnabled) {
254
+ setProcessorPending(true);
255
+ try {
256
+ if (blurEnabled && !videoTrack.getProcessor()) {
257
+ videoTrack.setProcessor(BackgroundBlur(20));
258
+ }
259
+ else if (!blurEnabled) {
260
+ videoTrack.stopProcessor();
261
+ }
262
+ }
263
+ finally {
264
+ setProcessorPending(false);
265
+ }
266
+ }
267
+ }, [blurEnabled, videoTrack, videoEnabled]);
239
268
  function handleSubmit(event) {
240
269
  event.preventDefault();
241
270
  if (handleValidation(userChoices)) {
@@ -247,5 +276,5 @@ export function PreJoin(_a) {
247
276
  log.warn('Validation failed with: ', userChoices);
248
277
  }
249
278
  }
250
- return (_jsxs("div", Object.assign({ className: "lk-prejoin" }, htmlProps, { children: [_jsxs("div", Object.assign({ className: "lk-video-container" }, { children: [videoTrack && _jsx("video", { ref: videoEl, width: "1280", height: "720", "data-lk-facing-mode": facingMode }), (!videoTrack || !videoEnabled) && (_jsx("div", Object.assign({ className: "lk-camera-off-note" }, { children: _jsx(ParticipantTileAvatar, { user: scUserContext.user }) })))] })), _jsxs("div", Object.assign({ className: "lk-button-group-container" }, { children: [_jsxs("div", Object.assign({ className: "lk-button-group audio" }, { children: [_jsx(TrackToggle, Object.assign({ disabled: !canUseAudio, initialState: audioEnabled, source: Track.Source.Microphone, onChange: (enabled) => setAudioEnabled(enabled) }, { children: micLabel })), _jsx("div", Object.assign({ className: "lk-button-group-menu" }, { children: _jsx(MediaDeviceMenu, { initialSelection: audioDeviceId, kind: "audioinput", disabled: !audioTrack || !canUseAudio || !audioEnabled, tracks: { audioinput: audioTrack }, onActiveDeviceChange: (_, id) => setAudioDeviceId(id) }) }))] })), _jsxs("div", Object.assign({ className: "lk-button-group video" }, { children: [_jsx(TrackToggle, Object.assign({ disabled: !canUseVideo, initialState: videoEnabled, source: Track.Source.Camera, onChange: (enabled) => setVideoEnabled(enabled) }, { children: camLabel })), _jsx("div", Object.assign({ className: "lk-button-group-menu" }, { children: _jsx(MediaDeviceMenu, { initialSelection: videoDeviceId, kind: "videoinput", disabled: !videoTrack || !canUseVideo || !videoEnabled, tracks: { videoinput: videoTrack }, onActiveDeviceChange: (_, id) => setVideoDeviceId(id) }) }))] }))] })), _jsx("form", Object.assign({ className: "lk-username-container" }, { children: _jsx("button", Object.assign({ className: "lk-button lk-join-button", type: "submit", onClick: handleSubmit, disabled: !isValid || error }, { children: joinLabel })) })), debug && (_jsxs(_Fragment, { children: [_jsx("strong", { children: "User Choices:" }), _jsxs("ul", Object.assign({ className: "lk-list", style: { overflow: 'hidden', maxWidth: '15rem' } }, { children: [_jsxs("li", { children: ["Username: ", `${userChoices.username}`] }), _jsxs("li", { children: ["Video Enabled: ", `${userChoices.videoEnabled}`] }), _jsxs("li", { children: ["Audio Enabled: ", `${userChoices.audioEnabled}`] }), _jsxs("li", { children: ["Video Device: ", `${userChoices.videoDeviceId}`] }), _jsxs("li", { children: ["Audio Device: ", `${userChoices.audioDeviceId}`] })] }))] }))] })));
279
+ return (_jsxs("div", Object.assign({ className: "lk-prejoin" }, htmlProps, { children: [_jsxs("div", Object.assign({ className: "lk-video-container" }, { children: [videoTrack && _jsx("video", { ref: videoEl, width: "1280", height: "720", "data-lk-facing-mode": facingMode }), (!videoTrack || !videoEnabled) && (_jsx("div", Object.assign({ className: "lk-camera-off-note" }, { children: _jsx(ParticipantTileAvatar, { user: scUserContext.user }) })))] })), _jsxs("div", Object.assign({ className: "lk-button-group-container" }, { children: [_jsxs("div", Object.assign({ className: "lk-button-group audio" }, { children: [_jsx(TrackToggle, Object.assign({ disabled: !canUseAudio, initialState: audioEnabled, source: Track.Source.Microphone, onChange: (enabled) => setAudioEnabled(enabled) }, { children: micLabel })), _jsx("div", Object.assign({ className: "lk-button-group-menu" }, { children: _jsx(MediaDeviceMenu, { initialSelection: audioDeviceId, kind: "audioinput", disabled: !audioTrack || !canUseAudio || !audioEnabled, tracks: { audioinput: audioTrack }, onActiveDeviceChange: (_, id) => setAudioDeviceId(id) }) }))] })), _jsxs("div", Object.assign({ className: "lk-button-group video" }, { children: [_jsx(TrackToggle, Object.assign({ disabled: !canUseVideo, initialState: videoEnabled, source: Track.Source.Camera, onChange: (enabled) => setVideoEnabled(enabled) }, { children: camLabel })), _jsx("div", Object.assign({ className: "lk-button-group-menu" }, { children: _jsx(MediaDeviceMenu, { initialSelection: videoDeviceId, kind: "videoinput", disabled: !videoTrack || !canUseVideo || !videoEnabled, tracks: { videoinput: videoTrack }, onActiveDeviceChange: (_, id) => setVideoDeviceId(id) }) }))] })), _jsx(LiveStreamSettingsMenu, { actionBlurDisabled: !canUseVideo || !videoEnabled, blurEnabled: blurEnabled, handleBlur: handleBlur })] })), _jsx("form", Object.assign({ className: "lk-username-container" }, { children: _jsx("button", Object.assign({ className: "lk-button lk-join-button", type: "submit", onClick: handleSubmit, disabled: !isValid || error }, { children: joinLabel })) })), debug && (_jsxs(_Fragment, { children: [_jsx("strong", { children: "User Choices:" }), _jsxs("ul", Object.assign({ className: "lk-list", style: { overflow: 'hidden', maxWidth: '15rem' } }, { children: [_jsxs("li", { children: ["Username: ", `${userChoices.username}`] }), _jsxs("li", { children: ["Video Enabled: ", `${userChoices.videoEnabled}`] }), _jsxs("li", { children: ["Audio Enabled: ", `${userChoices.audioEnabled}`] }), _jsxs("li", { children: ["Video Device: ", `${userChoices.videoDeviceId}`] }), _jsxs("li", { children: ["Audio Device: ", `${userChoices.audioDeviceId}`] })] }))] }))] })));
251
280
  }
@@ -1,9 +1,9 @@
1
1
  import { __rest } from "tslib";
2
- import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
3
3
  import * as React from 'react';
4
4
  import { isEqualTrackRef, isTrackReference, isWeb, log } from '@livekit/components-core';
5
5
  import { RoomEvent, Track } from 'livekit-client';
6
- import { CarouselLayout, Chat, ConnectionStateToast, GridLayout, LayoutContextProvider, RoomAudioRenderer, useCreateLayoutContext, useParticipants, usePinnedTracks, useTracks } from '@livekit/components-react';
6
+ import { CarouselLayout, Chat, ConnectionStateToast, GridLayout, LayoutContextProvider, RoomAudioRenderer, useCreateLayoutContext, useLocalParticipant, useParticipants, usePinnedTracks, useTracks } from '@livekit/components-react';
7
7
  import { ParticipantTile } from './ParticipantTile';
8
8
  import { ControlBar } from './ControlBar';
9
9
  import { useEffect, useMemo } from 'react';
@@ -15,6 +15,10 @@ import { styled } from '@mui/material/styles';
15
15
  import { Box } from '@mui/material';
16
16
  import { useThemeProps } from '@mui/system';
17
17
  import NoParticipants from './NoParticipants';
18
+ import LiveStreamSettingsMenu from './LiveStreamSettingsMenu';
19
+ import { BackgroundBlur } from '@livekit/track-processors';
20
+ import { isClientSideRendering } from '@selfcommunity/utils';
21
+ import { CHOICE_VIDEO_BLUR_EFFECT } from '../../../constants/LiveStream';
18
22
  const PREFIX = 'SCVideoConference';
19
23
  const classes = {
20
24
  root: `${PREFIX}-root`
@@ -35,7 +39,7 @@ const Root = styled(Box, {
35
39
  *
36
40
  */
37
41
  export function VideoConference(inProps) {
38
- var _a, _b;
42
+ var _a, _b, _c;
39
43
  // PROPS
40
44
  const props = useThemeProps({
41
45
  props: inProps,
@@ -52,16 +56,34 @@ export function VideoConference(inProps) {
52
56
  const lastAutoFocusedScreenShareTrack = React.useRef(null);
53
57
  // HOOKS
54
58
  const scUserContext = useSCUser();
59
+ const [blurEnabled, setBlurEnabled] = React.useState(isClientSideRendering() ? Boolean((_a = window === null || window === void 0 ? void 0 : window.localStorage) === null || _a === void 0 ? void 0 : _a.getItem(CHOICE_VIDEO_BLUR_EFFECT)) || false : false);
60
+ const [processorPending, setProcessorPending] = React.useState(false);
55
61
  const tracks = useTracks([
56
62
  { source: Track.Source.Camera, withPlaceholder: true },
57
63
  { source: Track.Source.ScreenShare, withPlaceholder: false }
58
64
  ], { updateOnlyOn: [RoomEvent.ActiveSpeakersChanged], onlySubscribed: false });
59
65
  const tracksNoParticipants = useMemo(() => tracks.filter((t) => t.participant.name === scUserContext.user.username || t.participant.name === speakerFocused.username || t.source === 'screen_share'), [tracks, scUserContext.user]);
66
+ const handleBlur = React.useCallback((event) => {
67
+ var _a, _b;
68
+ if (event.target) {
69
+ if ('checked' in event.target) {
70
+ setBlurEnabled((_a = event.target) === null || _a === void 0 ? void 0 : _a.checked);
71
+ }
72
+ else {
73
+ setBlurEnabled((enabled) => !enabled);
74
+ }
75
+ }
76
+ else {
77
+ setBlurEnabled((enabled) => !enabled);
78
+ }
79
+ (_b = window === null || window === void 0 ? void 0 : window.localStorage) === null || _b === void 0 ? void 0 : _b.setItem(CHOICE_VIDEO_BLUR_EFFECT, (!blurEnabled).toString());
80
+ }, [setBlurEnabled, blurEnabled]);
60
81
  const participants = useParticipants();
61
82
  const layoutContext = useCreateLayoutContext();
62
83
  const screenShareTracks = tracks.filter(isTrackReference).filter((track) => track.publication.source === Track.Source.ScreenShare);
63
- const focusTrack = (_a = usePinnedTracks(layoutContext)) === null || _a === void 0 ? void 0 : _a[0];
84
+ const focusTrack = (_b = usePinnedTracks(layoutContext)) === null || _b === void 0 ? void 0 : _b[0];
64
85
  const carouselTracks = tracks.filter((track) => !isEqualTrackRef(track, focusTrack));
86
+ const { cameraTrack } = useLocalParticipant();
65
87
  useLivestreamCheck();
66
88
  /**
67
89
  * widgetUpdate
@@ -117,7 +139,7 @@ export function VideoConference(inProps) {
117
139
  }
118
140
  }, [
119
141
  screenShareTracks.map((ref) => `${ref.publication.trackSid}_${ref.publication.isSubscribed}`).join(),
120
- (_b = focusTrack === null || focusTrack === void 0 ? void 0 : focusTrack.publication) === null || _b === void 0 ? void 0 : _b.trackSid,
142
+ (_c = focusTrack === null || focusTrack === void 0 ? void 0 : focusTrack.publication) === null || _c === void 0 ? void 0 : _c.trackSid,
121
143
  tracks,
122
144
  participants,
123
145
  speakerFocused
@@ -140,10 +162,27 @@ export function VideoConference(inProps) {
140
162
  }
141
163
  }
142
164
  }, [tracks, participants, speakerFocused]);
165
+ useEffect(() => {
166
+ const localCamTrack = cameraTrack === null || cameraTrack === void 0 ? void 0 : cameraTrack.track;
167
+ if (localCamTrack) {
168
+ setProcessorPending(true);
169
+ try {
170
+ if (blurEnabled && !localCamTrack.getProcessor()) {
171
+ localCamTrack.setProcessor(BackgroundBlur(20));
172
+ }
173
+ else if (!blurEnabled) {
174
+ localCamTrack.stopProcessor();
175
+ }
176
+ }
177
+ finally {
178
+ setProcessorPending(false);
179
+ }
180
+ }
181
+ }, [blurEnabled, cameraTrack]);
143
182
  return (_jsxs(Root, Object.assign({ className: classNames(className, classes.root, 'lk-video-conference') }, rest, { children: [isWeb() && (_jsxs(LayoutContextProvider, Object.assign({ value: layoutContext, onPinChange: handleFocusStateChange, onWidgetChange: widgetUpdate }, { children: [_jsxs("div", Object.assign({ className: "lk-video-conference-inner" }, { children: [!focusTrack ? (_jsx("div", Object.assign({ className: "lk-grid-layout-wrapper" }, { children: _jsx(GridLayout, Object.assign({ tracks: hideParticipantsList ? tracksNoParticipants : tracks }, { children: _jsx(ParticipantTile, {}) })) }))) : (_jsx("div", Object.assign({ className: "lk-focus-layout-wrapper" }, { children: hideParticipantsList ? (_jsx(FocusLayoutContainerNoParticipants, { children: focusTrack && _jsx(FocusLayout, { trackRef: focusTrack }) })) : (_jsxs(FocusLayoutContainer, { children: [carouselTracks.length ? (_jsx(CarouselLayout, Object.assign({ tracks: carouselTracks }, { children: _jsx(ParticipantTile, {}) }))) : (_jsx(NoParticipants, {})), focusTrack && _jsx(FocusLayout, { trackRef: focusTrack })] })) }))), _jsx(ControlBar, { controls: Object.assign({
144
183
  chat: !disableChat,
145
184
  microphone: !disableMicrophone,
146
185
  camera: !disableCamera,
147
186
  screenShare: !disableShareScreen
148
- }, { settings: !!SettingsComponent }) })] })), !disableChat && (_jsx(Chat, { style: { display: widgetState.showChat ? 'grid' : 'none' }, messageFormatter: chatMessageFormatter, messageEncoder: chatMessageEncoder, messageDecoder: chatMessageDecoder })), SettingsComponent && (_jsx("div", Object.assign({ className: "lk-settings-menu-modal", style: { display: widgetState.showSettings ? 'block' : 'none' } }, { children: _jsx(SettingsComponent, {}) })))] }))), _jsx(RoomAudioRenderer, {}), _jsx(ConnectionStateToast, {})] })));
187
+ }, { settings: true }) })] })), !disableChat && (_jsx(Chat, { style: { display: widgetState.showChat ? 'grid' : 'none' }, messageFormatter: chatMessageFormatter, messageEncoder: chatMessageEncoder, messageDecoder: chatMessageDecoder })), _jsx("div", Object.assign({ className: "lk-settings-menu-modal", style: { display: widgetState.showSettings ? 'block' : 'none' } }, { children: SettingsComponent ? (_jsx(SettingsComponent, {})) : (_jsx(_Fragment, { children: _jsx(LiveStreamSettingsMenu, { onlyContentMenu: true, actionBlurDisabled: !cameraTrack && !disableCamera, blurEnabled: blurEnabled, handleBlur: handleBlur }) })) }))] }))), _jsx(RoomAudioRenderer, {}), _jsx(ConnectionStateToast, {})] })));
149
188
  }
@@ -1,3 +1,4 @@
1
1
  export declare const LIVE_STREAM_TITLE_MAX_LENGTH = 100;
2
2
  export declare const LIVE_STREAM_SLUG_MAX_LENGTH = 50;
3
3
  export declare const LIVE_STREAM_DESCRIPTION_MAX_LENGTH = 500;
4
+ export declare const CHOICE_VIDEO_BLUR_EFFECT = "lk-video-blur";
@@ -1,3 +1,4 @@
1
1
  export const LIVE_STREAM_TITLE_MAX_LENGTH = 100;
2
2
  export const LIVE_STREAM_SLUG_MAX_LENGTH = 50;
3
3
  export const LIVE_STREAM_DESCRIPTION_MAX_LENGTH = 500;
4
+ export const CHOICE_VIDEO_BLUR_EFFECT = 'lk-video-blur';