ref: Convert files to TS (#12007)

Convert files that use material-ui to TS (needed for material-ui upgrade)
This commit is contained in:
Robert Pintilii 2022-08-26 12:54:03 +03:00 committed by GitHub
parent fc60ab8383
commit 3bd3be4df0
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
30 changed files with 534 additions and 518 deletions

19
package-lock.json generated
View File

@ -143,6 +143,7 @@
"@types/react": "17.0.14", "@types/react": "17.0.14",
"@types/react-native": "0.68.1", "@types/react-native": "0.68.1",
"@types/react-redux": "7.1.24", "@types/react-redux": "7.1.24",
"@types/react-window": "1.8.5",
"@types/unorm": "1.3.28", "@types/unorm": "1.3.28",
"@types/uuid": "8.3.4", "@types/uuid": "8.3.4",
"@types/zxcvbn": "4.4.1", "@types/zxcvbn": "4.4.1",
@ -5534,6 +5535,15 @@
"@types/react": "*" "@types/react": "*"
} }
}, },
"node_modules/@types/react-window": {
"version": "1.8.5",
"resolved": "https://registry.npmjs.org/@types/react-window/-/react-window-1.8.5.tgz",
"integrity": "sha512-V9q3CvhC9Jk9bWBOysPGaWy/Z0lxYcTXLtLipkt2cnRj1JOSFNF7wqGpkScSXMgBwC+fnVRg/7shwgddBG5ICw==",
"dev": true,
"dependencies": {
"@types/react": "*"
}
},
"node_modules/@types/retry": { "node_modules/@types/retry": {
"version": "0.12.1", "version": "0.12.1",
"resolved": "https://registry.npmjs.org/@types/retry/-/retry-0.12.1.tgz", "resolved": "https://registry.npmjs.org/@types/retry/-/retry-0.12.1.tgz",
@ -23993,6 +24003,15 @@
"@types/react": "*" "@types/react": "*"
} }
}, },
"@types/react-window": {
"version": "1.8.5",
"resolved": "https://registry.npmjs.org/@types/react-window/-/react-window-1.8.5.tgz",
"integrity": "sha512-V9q3CvhC9Jk9bWBOysPGaWy/Z0lxYcTXLtLipkt2cnRj1JOSFNF7wqGpkScSXMgBwC+fnVRg/7shwgddBG5ICw==",
"dev": true,
"requires": {
"@types/react": "*"
}
},
"@types/retry": { "@types/retry": {
"version": "0.12.1", "version": "0.12.1",
"resolved": "https://registry.npmjs.org/@types/retry/-/retry-0.12.1.tgz", "resolved": "https://registry.npmjs.org/@types/retry/-/retry-0.12.1.tgz",

View File

@ -148,6 +148,7 @@
"@types/react": "17.0.14", "@types/react": "17.0.14",
"@types/react-native": "0.68.1", "@types/react-native": "0.68.1",
"@types/react-redux": "7.1.24", "@types/react-redux": "7.1.24",
"@types/react-window": "1.8.5",
"@types/unorm": "1.3.28", "@types/unorm": "1.3.28",
"@types/uuid": "8.3.4", "@types/uuid": "8.3.4",
"@types/zxcvbn": "4.4.1", "@types/zxcvbn": "4.4.1",

View File

@ -1,5 +1,3 @@
// @flow
import { PureComponent } from 'react'; import { PureComponent } from 'react';
export type Props = { export type Props = {
@ -32,21 +30,21 @@ export type Props = {
/** /**
* The URL of the avatar to render. * The URL of the avatar to render.
*/ */
url?: ?string | Object url?: string|Function
}; };
/** /**
* Implements an abstract stateless avatar component that renders an avatar purely from what gets passed through * Implements an abstract stateless avatar component that renders an avatar purely from what gets passed through
* props. * props.
*/ */
export default class AbstractStatelessAvatar<P: Props> extends PureComponent<P> { export default class AbstractStatelessAvatar<P extends Props> extends PureComponent<P> {
/** /**
* Checks if the passed prop is a loaded icon or not. * Checks if the passed prop is a loaded icon or not.
* *
* @param {string? | Object?} iconProp - The prop to check. * @param {string? | Object?} iconProp - The prop to check.
* @returns {boolean} * @returns {boolean}
*/ */
_isIcon(iconProp: ?string | ?Object): boolean { _isIcon(iconProp?: string | Function): iconProp is Function {
return Boolean(iconProp) && (typeof iconProp === 'object' || typeof iconProp === 'function'); return Boolean(iconProp) && (typeof iconProp === 'object' || typeof iconProp === 'function');
} }
} }

View File

@ -1,25 +1,23 @@
// @flow
import { withStyles } from '@material-ui/core/styles'; import { withStyles } from '@material-ui/core/styles';
import clsx from 'clsx'; import clsx from 'clsx';
import React from 'react'; import React from 'react';
import { Icon } from '../../../icons'; import Icon from '../../../icons/components/Icon';
import AbstractStatelessAvatar, { type Props as AbstractProps } from '../AbstractStatelessAvatar'; import AbstractStatelessAvatar, { type Props as AbstractProps } from '../AbstractStatelessAvatar';
import { PRESENCE_AVAILABLE_COLOR, PRESENCE_AWAY_COLOR, PRESENCE_BUSY_COLOR, PRESENCE_IDLE_COLOR } from '../styles'; import { PRESENCE_AVAILABLE_COLOR, PRESENCE_AWAY_COLOR, PRESENCE_BUSY_COLOR, PRESENCE_IDLE_COLOR } from '../styles';
type Props = AbstractProps & { type Props = AbstractProps & {
/**
* An object containing the CSS classes.
*/
classes: Object,
/** /**
* External class name passed through props. * External class name passed through props.
*/ */
className?: string, className?: string,
/**
* An object containing the CSS classes.
*/
classes: any,
/** /**
* The default avatar URL if we want to override the app bundled one (e.g. AlwaysOnTop). * The default avatar URL if we want to override the app bundled one (e.g. AlwaysOnTop).
*/ */
@ -33,7 +31,7 @@ type Props = AbstractProps & {
/** /**
* One of the expected status strings (e.g. 'available') to render a badge on the avatar, if necessary. * One of the expected status strings (e.g. 'available') to render a badge on the avatar, if necessary.
*/ */
status?: ?string, status?: string,
/** /**
* TestId of the element, if any. * TestId of the element, if any.
@ -43,7 +41,7 @@ type Props = AbstractProps & {
/** /**
* Indicates whether to load the avatar using CORS or not. * Indicates whether to load the avatar using CORS or not.
*/ */
useCORS?: ?boolean useCORS?: boolean
}; };
/** /**
@ -211,10 +209,10 @@ class StatelessAvatar extends AbstractStatelessAvatar<Props> {
/** /**
* Constructs a style object to be used on the avatars. * Constructs a style object to be used on the avatars.
* *
* @param {string?} color - The desired background color. * @param {string} color - The desired background color.
* @returns {Object} * @returns {Object}
*/ */
_getAvatarStyle(color) { _getAvatarStyle(color?: string) {
const { size } = this.props; const { size } = this.props;
return { return {
@ -231,7 +229,7 @@ class StatelessAvatar extends AbstractStatelessAvatar<Props> {
* @param {string} additional - Any additional class to add. * @param {string} additional - Any additional class to add.
* @returns {string} * @returns {string}
*/ */
_getAvatarClassName(additional) { _getAvatarClassName(additional?: string) {
return clsx('avatar', additional, this.props.className, this.props.classes.avatar); return clsx('avatar', additional, this.props.className, this.props.classes.avatar);
} }
@ -250,10 +248,6 @@ class StatelessAvatar extends AbstractStatelessAvatar<Props> {
return ''; return '';
} }
_isIcon: (?string | ?Object) => boolean;
_onAvatarLoadError: () => void;
/** /**
* Handles avatar load errors. * Handles avatar load errors.
* *
@ -268,4 +262,5 @@ class StatelessAvatar extends AbstractStatelessAvatar<Props> {
} }
} }
// @ts-ignore
export default withStyles(styles)(StatelessAvatar); export default withStyles(styles)(StatelessAvatar);

View File

@ -1,17 +1,15 @@
// @flow
/* eslint-disable react/jsx-no-bind */ /* eslint-disable react/jsx-no-bind */
import { withStyles } from '@material-ui/styles'; import { withStyles } from '@material-ui/styles';
import clsx from 'clsx'; import clsx from 'clsx';
import React, { useEffect, useState } from 'react'; import React, { useEffect, useState } from 'react';
import { Icon, IconCheck, IconCopy } from '../../base/icons'; import Icon from '../icons/components/Icon';
import { IconCheck, IconCopy } from '../icons/svg/index';
import { withPixelLineHeight } from '../styles/functions.web'; import { withPixelLineHeight } from '../styles/functions.web';
import { copyText } from '../util'; import { Theme } from '../ui/types';
import { copyText } from '../util/helpers';
const styles = (theme: Theme) => {
const styles = theme => {
return { return {
copyButton: { copyButton: {
...withPixelLineHeight(theme.typography.bodyLongRegular), ...withPixelLineHeight(theme.typography.bodyLongRegular),
@ -54,34 +52,29 @@ const styles = theme => {
}; };
}; };
let mounted; let mounted: boolean;
type Props = { type Props = {
/**
* An object containing the CSS classes.
*/
classes: Object,
/** /**
* Css class to apply on container. * Css class to apply on container.
*/ */
className: string, className: string,
/**
* An object containing the CSS classes.
*/
classes: any,
/** /**
* The displayed text. * The displayed text.
*/ */
displayedText: string, displayedText: string,
/** /**
* The text that needs to be copied (might differ from the displayedText). * The id of the button.
*/ */
textToCopy: string, id?: string,
/**
* The text displayed on mouse hover.
*/
textOnHover: string,
/** /**
* The text displayed on copy success. * The text displayed on copy success.
@ -89,9 +82,14 @@ type Props = {
textOnCopySuccess: string, textOnCopySuccess: string,
/** /**
* The id of the button. * The text displayed on mouse hover.
*/ */
id?: string, textOnHover: string,
/**
* The text that needs to be copied (might differ from the displayedText).
*/
textToCopy: string
}; };
/** /**
@ -160,7 +158,7 @@ function CopyButton({ classes, className, displayedText, textToCopy, textOnHover
* *
* @returns {void} * @returns {void}
*/ */
function onKeyPress(e) { function onKeyPress(e: React.KeyboardEvent) {
if (onClick && (e.key === ' ' || e.key === 'Enter')) { if (onClick && (e.key === ' ' || e.key === 'Enter')) {
e.preventDefault(); e.preventDefault();
onClick(); onClick();
@ -216,4 +214,5 @@ CopyButton.defaultProps = {
className: '' className: ''
}; };
// @ts-ignore
export default withStyles(styles)(CopyButton); export default withStyles(styles)(CopyButton);

View File

@ -1,11 +1,14 @@
// @flow /* eslint-disable lines-around-comment */
import { makeStyles } from '@material-ui/core'; import { makeStyles } from '@material-ui/core';
import clsx from 'clsx'; import clsx from 'clsx';
import React, { useEffect, useLayoutEffect, useRef, useState } from 'react'; import React, { ReactNode, useEffect, useLayoutEffect, useRef, useState } from 'react';
import { useSelector } from 'react-redux'; import { useSelector } from 'react-redux';
// @ts-ignore
import { getComputedOuterHeight } from '../../../participants-pane/functions'; import { getComputedOuterHeight } from '../../../participants-pane/functions';
// @ts-ignore
import { Drawer, JitsiPortal } from '../../../toolbox/components/web'; import { Drawer, JitsiPortal } from '../../../toolbox/components/web';
// @ts-ignore
import { showOverflowDrawer } from '../../../toolbox/functions.web'; import { showOverflowDrawer } from '../../../toolbox/functions.web';
import participantsPaneTheme from '../themes/participantsPaneTheme.json'; import participantsPaneTheme from '../themes/participantsPaneTheme.json';
@ -19,12 +22,12 @@ type Props = {
/** /**
* Children of the context menu. * Children of the context menu.
*/ */
children: React$Node, children: ReactNode,
/** /**
* Class name for context menu. Used to overwrite default styles. * Class name for context menu. Used to overwrite default styles.
*/ */
className?: ?string, className?: string,
/** /**
* The entity for which the context menu is displayed. * The entity for which the context menu is displayed.
@ -39,7 +42,7 @@ type Props = {
/** /**
* Whether or not the menu is already in a drawer. * Whether or not the menu is already in a drawer.
*/ */
inDrawer?: ?boolean, inDrawer?: boolean,
/** /**
* Whether or not drawer should be open. * Whether or not drawer should be open.
@ -54,32 +57,32 @@ type Props = {
/** /**
* Callback for click on an item in the menu. * Callback for click on an item in the menu.
*/ */
onClick?: Function, onClick?: (e?: React.MouseEvent) => void,
/**
* Keydown handler.
*/
onKeyDown?: Function,
/** /**
* Callback for drawer close. * Callback for drawer close.
*/ */
onDrawerClose?: Function, onDrawerClose?: (e?: React.MouseEvent) => void,
/**
* Keydown handler.
*/
onKeyDown?: (e?: React.KeyboardEvent) => void,
/** /**
* Callback for the mouse entering the component. * Callback for the mouse entering the component.
*/ */
onMouseEnter?: Function, onMouseEnter?: (e?: React.MouseEvent) => void,
/** /**
* Callback for the mouse leaving the component. * Callback for the mouse leaving the component.
*/ */
onMouseLeave?: Function onMouseLeave?: (e?: React.MouseEvent) => void
}; };
const MAX_HEIGHT = 400; const MAX_HEIGHT = 400;
const useStyles = makeStyles(theme => { const useStyles = makeStyles((theme: any) => {
return { return {
contextMenu: { contextMenu: {
backgroundColor: theme.palette.ui02, backgroundColor: theme.palette.ui02,

View File

@ -1,12 +1,11 @@
// @flow
import { makeStyles } from '@material-ui/styles'; import { makeStyles } from '@material-ui/styles';
import clsx from 'clsx'; import clsx from 'clsx';
import React from 'react'; import React, { ReactNode } from 'react';
import { useSelector } from 'react-redux'; import { useSelector } from 'react-redux';
// @ts-ignore
import { showOverflowDrawer } from '../../../toolbox/functions.web'; import { showOverflowDrawer } from '../../../toolbox/functions.web';
import { Icon } from '../../icons'; import Icon from '../../icons/components/Icon';
export type Props = { export type Props = {
@ -24,37 +23,37 @@ export type Props = {
* Custom icon. If used, the icon prop is ignored. * Custom icon. If used, the icon prop is ignored.
* Used to allow custom children instead of just the default icons. * Used to allow custom children instead of just the default icons.
*/ */
customIcon?: React$Node, customIcon?: ReactNode,
/** /**
* Whether or not the action is disabled. * Whether or not the action is disabled.
*/ */
disabled?: boolean, disabled?: boolean,
/**
* Id of the action container.
*/
id?: string,
/** /**
* Default icon for action. * Default icon for action.
*/ */
icon?: Function, icon?: Function,
/**
* Id of the action container.
*/
id?: string,
/** /**
* Click handler. * Click handler.
*/ */
onClick?: Function, onClick?: (e?: React.MouseEvent) => void,
/** /**
* Keydown handler. * Keydown handler.
*/ */
onKeyDown?: Function, onKeyDown?: (e?: React.KeyboardEvent) => void,
/** /**
* Keypress handler. * Keypress handler.
*/ */
onKeyPress?: Function, onKeyPress?: (e?: React.KeyboardEvent) => void,
/** /**
* TestId of the element, if any. * TestId of the element, if any.
@ -72,7 +71,7 @@ export type Props = {
textClassName?: string textClassName?: string
} }
const useStyles = makeStyles(theme => { const useStyles = makeStyles((theme: any) => {
return { return {
contextMenuItem: { contextMenuItem: {
alignItems: 'center', alignItems: 'center',
@ -121,7 +120,7 @@ const ContextMenuItem = ({
text, text,
textClassName }: Props) => { textClassName }: Props) => {
const styles = useStyles(); const styles = useStyles();
const _overflowDrawer = useSelector(showOverflowDrawer); const _overflowDrawer: boolean = useSelector(showOverflowDrawer);
return ( return (
<div <div

View File

@ -1,8 +1,7 @@
// @flow
import { makeStyles } from '@material-ui/core'; import { makeStyles } from '@material-ui/core';
import React from 'react'; import React, { ReactNode } from 'react';
import ContextMenuItem from './ContextMenuItem'; import ContextMenuItem, { Props as ItemProps } from './ContextMenuItem';
type Props = { type Props = {
@ -10,15 +9,15 @@ type Props = {
/** /**
* List of actions in this group. * List of actions in this group.
*/ */
actions?: Array<Object>, actions?: Array<ItemProps>,
/** /**
* The children of the component. * The children of the component.
*/ */
children?: React$Node, children?: ReactNode,
}; };
const useStyles = makeStyles(theme => { const useStyles = makeStyles((theme: any) => {
return { return {
contextMenuItemGroup: { contextMenuItemGroup: {
'&:not(:empty)': { '&:not(:empty)': {

View File

@ -1,9 +1,8 @@
// @flow
import { makeStyles } from '@material-ui/styles'; import { makeStyles } from '@material-ui/styles';
import clsx from 'clsx'; import clsx from 'clsx';
import React from 'react'; import React, { ReactNode } from 'react';
// @ts-ignore
import { ACTION_TRIGGER } from '../../../participants-pane/constants'; import { ACTION_TRIGGER } from '../../../participants-pane/constants';
import { isMobileBrowser } from '../../environment/utils'; import { isMobileBrowser } from '../../environment/utils';
import participantsPaneTheme from '../themes/participantsPaneTheme.json'; import participantsPaneTheme from '../themes/participantsPaneTheme.json';
@ -13,32 +12,32 @@ type Props = {
/** /**
* List item actions. * List item actions.
*/ */
actions: React$Node, actions: ReactNode,
/** /**
* List item container class name. * List item container class name.
*/ */
className: string, className: string,
/**
* Whether or not the actions should be hidden.
*/
hideActions?: boolean,
/** /**
* Icon to be displayed on the list item. (Avatar for participants). * Icon to be displayed on the list item. (Avatar for participants).
*/ */
icon: React$Node, icon: ReactNode,
/** /**
* Id of the container. * Id of the container.
*/ */
id: string, id: string,
/**
* Whether or not the actions should be hidden.
*/
hideActions?: Boolean,
/** /**
* Indicators to be displayed on the list item. * Indicators to be displayed on the list item.
*/ */
indicators?: React$Node, indicators?: ReactNode,
/** /**
* Whether or not the item is highlighted. * Whether or not the item is highlighted.
@ -48,17 +47,17 @@ type Props = {
/** /**
* Click handler. * Click handler.
*/ */
onClick: Function, onClick: (e?: React.MouseEvent) => void,
/** /**
* Long press handler. * Long press handler.
*/ */
onLongPress: Function, onLongPress: (e?: EventTarget) => void,
/** /**
* Mouse leave handler. * Mouse leave handler.
*/ */
onMouseLeave: Function, onMouseLeave: (e?: React.MouseEvent) => void,
/** /**
* Data test id. * Data test id.
@ -68,7 +67,7 @@ type Props = {
/** /**
* Text children to be displayed on the list item. * Text children to be displayed on the list item.
*/ */
textChildren: React$Node | string, textChildren: ReactNode | string,
/** /**
* The actions trigger. Can be Hover or Permanent. * The actions trigger. Can be Hover or Permanent.
@ -77,7 +76,7 @@ type Props = {
} }
const useStyles = makeStyles(theme => { const useStyles = makeStyles((theme: any) => {
return { return {
container: { container: {
alignItems: 'center', alignItems: 'center',
@ -194,7 +193,7 @@ const ListItem = ({
}: Props) => { }: Props) => {
const styles = useStyles(); const styles = useStyles();
const _isMobile = isMobileBrowser(); const _isMobile = isMobileBrowser();
let timeoutHandler; let timeoutHandler: number;
/** /**
* Set calling long press handler after x milliseconds. * Set calling long press handler after x milliseconds.
@ -202,10 +201,10 @@ const ListItem = ({
* @param {TouchEvent} e - Touch start event. * @param {TouchEvent} e - Touch start event.
* @returns {void} * @returns {void}
*/ */
function _onTouchStart(e) { function _onTouchStart(e: React.TouchEvent) {
const target = e.touches[0].target; const target = e.touches[0].target;
timeoutHandler = setTimeout(() => onLongPress(target), 600); timeoutHandler = window.setTimeout(() => onLongPress(target), 600);
} }
/** /**

View File

@ -1,4 +1,4 @@
// @flow /* eslint-disable lines-around-comment */
/* eslint-disable react/no-multi-comp */ /* eslint-disable react/no-multi-comp */
import ErrorIcon from '@atlaskit/icon/glyph/error'; import ErrorIcon from '@atlaskit/icon/glyph/error';
import WarningIcon from '@atlaskit/icon/glyph/warning'; import WarningIcon from '@atlaskit/icon/glyph/warning';
@ -7,12 +7,15 @@ import {
Title, Title,
titleIconWrapperStyles, titleIconWrapperStyles,
TitleText TitleText
// @ts-ignore
} from '@atlaskit/modal-dialog/dist/es2019/styled/Content'; } from '@atlaskit/modal-dialog/dist/es2019/styled/Content';
import { withStyles } from '@material-ui/core/styles'; import { withStyles } from '@material-ui/core/styles';
import React from 'react'; import React from 'react';
import { WithTranslation } from 'react-i18next';
import { translate } from '../../../i18n'; import { translate } from '../../../i18n/functions';
import { IconClose } from '../../../icons/svg/index'; import { IconClose } from '../../../icons/svg/index';
// @ts-ignore
import { withPixelLineHeight } from '../../../styles/functions'; import { withPixelLineHeight } from '../../../styles/functions';
import Button from '../../../ui/components/web/Button'; import Button from '../../../ui/components/web/Button';
import { BUTTON_TYPES } from '../../../ui/constants'; import { BUTTON_TYPES } from '../../../ui/constants';
@ -31,17 +34,16 @@ const TitleIcon = ({ appearance }: { appearance?: 'danger' | 'warning' }) => {
); );
}; };
type Props = { interface Props extends WithTranslation {
id: string,
appearance?: 'danger' | 'warning', appearance?: 'danger' | 'warning',
classes: Object, classes: any,
heading: string, heading: string,
hideCloseIconButton: boolean, hideCloseIconButton: boolean,
onClose: Function, id?: string,
showKeyline: boolean,
isHeadingMultiline: boolean, isHeadingMultiline: boolean,
testId: string, onClose: (e?: any) => void,
t: Function showKeyline: boolean,
testId?: string
} }
/** /**
@ -51,7 +53,7 @@ type Props = {
* *
* @returns {Object} * @returns {Object}
*/ */
const styles = theme => { const styles = (theme: any) => {
return { return {
closeButton: { closeButton: {
borderRadius: theme.shape.borderRadius, borderRadius: theme.shape.borderRadius,
@ -95,15 +97,13 @@ class ModalHeader extends React.Component<Props> {
* @param {*} props - The read-only properties with which the new instance * @param {*} props - The read-only properties with which the new instance
* is to be initialized. * is to be initialized.
*/ */
constructor(props) { constructor(props: Props) {
super(props); super(props);
// Bind event handler so it is only bound once for every instance. // Bind event handler so it is only bound once for every instance.
this._onKeyPress = this._onKeyPress.bind(this); this._onKeyPress = this._onKeyPress.bind(this);
} }
_onKeyPress: (Object) => void;
/** /**
* KeyPress handler for accessibility. * KeyPress handler for accessibility.
* *
@ -111,7 +111,7 @@ class ModalHeader extends React.Component<Props> {
* *
* @returns {void} * @returns {void}
*/ */
_onKeyPress(e) { _onKeyPress(e: React.KeyboardEvent) {
if (this.props.onClose && (e.key === ' ' || e.key === 'Enter')) { if (this.props.onClose && (e.key === ' ' || e.key === 'Enter')) {
e.preventDefault(); e.preventDefault();
this.props.onClose(); this.props.onClose();

View File

@ -1,9 +1,8 @@
// @flow /* eslint-disable lines-around-comment */
import Modal, { ModalFooter } from '@atlaskit/modal-dialog'; import Modal, { ModalFooter } from '@atlaskit/modal-dialog';
import { withStyles } from '@material-ui/core/styles'; import { withStyles } from '@material-ui/core/styles';
import _ from 'lodash'; import React, { Component, ReactElement } from 'react';
import React, { Component } from 'react'; import { WithTranslation } from 'react-i18next';
import { translate } from '../../../i18n/functions'; import { translate } from '../../../i18n/functions';
import Button from '../../../ui/components/web/Button'; import Button from '../../../ui/components/web/Button';
@ -31,17 +30,23 @@ const OK_BUTTON_ID = 'modal-dialog-ok-button';
* *
* @static * @static
*/ */
type Props = DialogProps & { interface Props extends DialogProps, WithTranslation {
/** /**
* An object containing the CSS classes. * An object containing the CSS classes.
*/ */
classes: Object, classes: any,
/** /**
* Custom dialog header that replaces the standard heading. * Custom dialog header that replaces the standard heading.
*/ */
customHeader?: React$Element<any> | Function, customHeader?: ReactElement<any> | Function,
/**
* Disables dismissing the dialog when the blanket is clicked. Enabled
* by default.
*/
disableBlanketClickDismiss: boolean,
/* /*
* True if listening for the Enter key should be disabled. * True if listening for the Enter key should be disabled.
@ -49,10 +54,9 @@ type Props = DialogProps & {
disableEnter: boolean, disableEnter: boolean,
/** /**
* Disables dismissing the dialog when the blanket is clicked. Enabled * If true, no footer will be displayed.
* by default.
*/ */
disableBlanketClickDismiss: boolean, disableFooter?: boolean,
/** /**
* If true, the cancel button will not display but cancel actions, like * If true, the cancel button will not display but cancel actions, like
@ -65,13 +69,6 @@ type Props = DialogProps & {
*/ */
hideCloseIconButton: boolean, hideCloseIconButton: boolean,
/**
* If true, no footer will be displayed.
*/
disableFooter?: boolean,
i18n: Object,
/** /**
* Whether the dialog is modal. This means clicking on the blanket will * Whether the dialog is modal. This means clicking on the blanket will
* leave the dialog open. No cancel button. * leave the dialog open. No cancel button.
@ -82,7 +79,7 @@ type Props = DialogProps & {
* The handler for the event when clicking the 'confirmNo' button. * The handler for the event when clicking the 'confirmNo' button.
* Defaults to onCancel if absent. * Defaults to onCancel if absent.
*/ */
onDecline?: Function, onDecline?: () => void,
/** /**
* Callback invoked when setting the ref of the Dialog. * Callback invoked when setting the ref of the Dialog.
@ -94,11 +91,6 @@ type Props = DialogProps & {
*/ */
submitDisabled: boolean, submitDisabled: boolean,
/**
* Function to be used to retrieve translated i18n labels.
*/
t: Function,
/** /**
* Width of the dialog, can be: * Width of the dialog, can be:
* - 'small' (400px), 'medium' (600px), 'large' (800px), * - 'small' (400px), 'medium' (600px), 'large' (800px),
@ -107,7 +99,7 @@ type Props = DialogProps & {
* - string value for percentage. * - string value for percentage.
*/ */
width: string width: string
}; }
/** /**
* Creates the styles for the component. * Creates the styles for the component.
@ -115,7 +107,7 @@ type Props = DialogProps & {
* @param {Object} theme - The theme. * @param {Object} theme - The theme.
* @returns {Object} * @returns {Object}
*/ */
const styles = theme => { const styles = (theme: any) => {
return { return {
footer: { footer: {
boxShadow: 'none' boxShadow: 'none'
@ -139,20 +131,13 @@ class StatelessDialog extends Component<Props> {
hideCloseIconButton: false hideCloseIconButton: false
}; };
/**
* The functional component to be used for rendering the modal footer.
*/
_Footer: ?Function;
_dialogElement: ?HTMLElement;
/** /**
* Initializes a new {@code StatelessDialog} instance. * Initializes a new {@code StatelessDialog} instance.
* *
* @param {Object} props - The read-only properties with which the new * @param {Object} props - The read-only properties with which the new
* instance is to be initialized. * instance is to be initialized.
*/ */
constructor(props) { constructor(props: Props) {
super(props); super(props);
// Bind event handlers so they are only bound once for every instance. // Bind event handlers so they are only bound once for every instance.
@ -175,7 +160,7 @@ class StatelessDialog extends Component<Props> {
customHeader, customHeader,
children, children,
hideCloseIconButton, hideCloseIconButton,
t /* The following fixes a flow error: */ = _.identity, t,
titleString, titleString,
titleKey, titleKey,
width width
@ -185,10 +170,12 @@ class StatelessDialog extends Component<Props> {
<Modal <Modal
autoFocus = { true } autoFocus = { true }
components = {{ components = {{
// @ts-ignore
Header: customHeader ? customHeader : props => ( Header: customHeader ? customHeader : props => (
// @ts-ignore
<ModalHeader <ModalHeader
{ ...props } { ...props }
heading = { titleString || t(titleKey) } heading = { titleString || t(titleKey ?? '') }
hideCloseIconButton = { hideCloseIconButton } /> hideCloseIconButton = { hideCloseIconButton } />
) )
}} }}
@ -212,8 +199,6 @@ class StatelessDialog extends Component<Props> {
); );
} }
_renderFooter: () => React$Node;
/** /**
* Returns a ReactElement to display buttons for closing the modal. * Returns a ReactElement to display buttons for closing the modal.
* *
@ -222,7 +207,7 @@ class StatelessDialog extends Component<Props> {
* @private * @private
* @returns {ReactElement} * @returns {ReactElement}
*/ */
_renderFooter(propsFromModalFooter) { _renderFooter(propsFromModalFooter: any) {
// Filter out falsy (null) values because {@code ButtonGroup} will error // Filter out falsy (null) values because {@code ButtonGroup} will error
// if passed in anything but buttons with valid type props. // if passed in anything but buttons with valid type props.
const buttons = [ const buttons = [
@ -252,8 +237,6 @@ class StatelessDialog extends Component<Props> {
); );
} }
_onCancel: () => void;
/** /**
* Dispatches action to hide the dialog. * Dispatches action to hide the dialog.
* *
@ -267,8 +250,6 @@ class StatelessDialog extends Component<Props> {
} }
} }
_onDialogDismissed: () => void;
/** /**
* Handles click on the blanket area. * Handles click on the blanket area.
* *
@ -280,8 +261,6 @@ class StatelessDialog extends Component<Props> {
} }
} }
_onSubmit: (?string) => void;
/** /**
* Dispatches the action when submitting the dialog. * Dispatches the action when submitting the dialog.
* *
@ -289,7 +268,7 @@ class StatelessDialog extends Component<Props> {
* @param {string} value - The submitted value if any. * @param {string} value - The submitted value if any.
* @returns {void} * @returns {void}
*/ */
_onSubmit(value) { _onSubmit(value?: any) {
const { onSubmit } = this.props; const { onSubmit } = this.props;
onSubmit && onSubmit(value); onSubmit && onSubmit(value);
@ -310,12 +289,13 @@ class StatelessDialog extends Component<Props> {
} }
const { const {
t /* The following fixes a flow error: */ = _.identity, t,
onDecline onDecline
} = this.props; } = this.props;
return ( return (
<Button <Button
accessibilityLabel = { t(this.props.cancelKey || 'dialog.Cancel') }
id = { CANCEL_BUTTON_ID } id = { CANCEL_BUTTON_ID }
key = { CANCEL_BUTTON_ID } key = { CANCEL_BUTTON_ID }
label = { t(this.props.cancelKey || 'dialog.Cancel') } label = { t(this.props.cancelKey || 'dialog.Cancel') }
@ -332,16 +312,18 @@ class StatelessDialog extends Component<Props> {
* @returns {ReactElement|null} The OK button if enabled. * @returns {ReactElement|null} The OK button if enabled.
*/ */
_renderOKButton() { _renderOKButton() {
if (this.props.submitDisabled) { const {
submitDisabled,
t
} = this.props;
if (submitDisabled) {
return null; return null;
} }
const {
t /* The following fixes a flow error: */ = _.identity
} = this.props;
return ( return (
<Button <Button
accessibilityLabel = { t(this.props.okKey || 'dialog.Ok') }
disabled = { this.props.okDisabled } disabled = { this.props.okDisabled }
id = { OK_BUTTON_ID } id = { OK_BUTTON_ID }
key = { OK_BUTTON_ID } key = { OK_BUTTON_ID }
@ -351,8 +333,6 @@ class StatelessDialog extends Component<Props> {
); );
} }
_onDialogRef: (?Element) => void;
/** /**
* Callback invoked when setting the ref of the dialog's child passing the Modal ref. * Callback invoked when setting the ref of the dialog's child passing the Modal ref.
* It is done this way because we cannot directly access the ref of the Modal component. * It is done this way because we cannot directly access the ref of the Modal component.
@ -361,12 +341,10 @@ class StatelessDialog extends Component<Props> {
* @private * @private
* @returns {void} * @returns {void}
*/ */
_onDialogRef(element: ?Element) { _onDialogRef(element?: any) {
this.props.onDialogRef && this.props.onDialogRef(element && element.parentNode); this.props.onDialogRef && this.props.onDialogRef(element && element.parentNode);
} }
_onKeyPress: (Object) => void;
/** /**
* Handles 'Enter' key in the dialog to submit/hide dialog depending on * Handles 'Enter' key in the dialog to submit/hide dialog depending on
* the available buttons and their disabled state. * the available buttons and their disabled state.
@ -375,7 +353,7 @@ class StatelessDialog extends Component<Props> {
* @private * @private
* @returns {void} * @returns {void}
*/ */
_onKeyPress(event) { _onKeyPress(event: React.KeyboardEvent) {
// If the event coming to the dialog has been subject to preventDefault // If the event coming to the dialog has been subject to preventDefault
// we don't handle it here. // we don't handle it here.
if (event.defaultPrevented) { if (event.defaultPrevented) {

View File

@ -1,31 +1,31 @@
// @flow import { ReactNode } from 'react';
export type DialogProps = { export type DialogProps = {
/** /**
* Whether cancel button is disabled. Enabled by default. * Whether cancel button is disabled. Enabled by default.
*/ */
cancelDisabled: ?boolean, cancelDisabled?: boolean,
/** /**
* Optional i18n key to change the cancel button title. * Optional i18n key to change the cancel button title.
*/ */
cancelKey: ?string, cancelKey?: string,
/** /**
* The React {@code Component} children which represents the dialog's body. * The React {@code Component} children which represents the dialog's body.
*/ */
children: ?React$Node, children?: ReactNode,
/** /**
* Is ok button enabled/disabled. Enabled by default. * Is ok button enabled/disabled. Enabled by default.
*/ */
okDisabled: ?boolean, okDisabled?: boolean,
/** /**
* Optional i18n key to change the ok button title. * Optional i18n key to change the ok button title.
*/ */
okKey: ?string, okKey?: string,
/** /**
* The handler for onCancel event. * The handler for onCancel event.
@ -47,14 +47,14 @@ export type DialogProps = {
/** /**
* Key to use for showing a title. * Key to use for showing a title.
*/ */
titleKey: ?string, titleKey?: string,
/** /**
* The string to use as a title instead of {@code titleKey}. If a truthy * The string to use as a title instead of {@code titleKey}. If a truthy
* value is specified, it takes precedence over {@code titleKey} i.e. * value is specified, it takes precedence over {@code titleKey} i.e.
* The latter is unused. * The latter is unused.
*/ */
titleString: ?string titleString?: string
}; };
/** /**

View File

@ -159,7 +159,7 @@ export function getFirstLoadableAvatarUrl(participant: Participant, store: IStor
* features/base/participants. * features/base/participants.
* @returns {(Participant|undefined)} * @returns {(Participant|undefined)}
*/ */
export function getLocalParticipant(stateful: IStore | Function) { export function getLocalParticipant(stateful: IStore | Function | IState) {
const state = toState(stateful)['features/base/participants']; const state = toState(stateful)['features/base/participants'];
return state.local; return state.local;
@ -342,7 +342,7 @@ export function getParticipantCountWithFake(stateful: IStore | Function) {
* @param {string} id - The ID of the participant's display name to retrieve. * @param {string} id - The ID of the participant's display name to retrieve.
* @returns {string} * @returns {string}
*/ */
export function getParticipantDisplayName(stateful: IStore | Function, id: string): string { export function getParticipantDisplayName(stateful: IStore | Function | IState, id: string): string {
const participant = getParticipantById(stateful, id); const participant = getParticipantById(stateful, id);
const { const {
defaultLocalDisplayName, defaultLocalDisplayName,
@ -374,7 +374,7 @@ export function getParticipantDisplayName(stateful: IStore | Function, id: strin
* @param {string} id - The ID of the screenshare participant's display name to retrieve. * @param {string} id - The ID of the screenshare participant's display name to retrieve.
* @returns {string} * @returns {string}
*/ */
export function getScreenshareParticipantDisplayName(stateful: IStore | Function, id: string) { export function getScreenshareParticipantDisplayName(stateful: IStore | Function| IState, id: string) {
const ownerDisplayName = getParticipantDisplayName(stateful, getVirtualScreenshareParticipantOwnerId(id)); const ownerDisplayName = getParticipantDisplayName(stateful, getVirtualScreenshareParticipantOwnerId(id));
return i18next.t('screenshareDisplayName', { name: ownerDisplayName }); return i18next.t('screenshareDisplayName', { name: ownerDisplayName });
@ -648,6 +648,6 @@ export function getRaiseHandsQueue(stateful: IStore | Function): Array<Object> {
* @param {Object} participant - The participant. * @param {Object} participant - The participant.
* @returns {boolean} - Whether participant has raise hand or not. * @returns {boolean} - Whether participant has raise hand or not.
*/ */
export function hasRaisedHand(participant: Participant): boolean { export function hasRaisedHand(participant?: Participant): boolean {
return Boolean(participant && participant.raisedHandTimestamp); return Boolean(participant?.raisedHandTimestamp);
} }

View File

@ -1,29 +1,48 @@
// @flow
import { withStyles } from '@material-ui/styles'; import { withStyles } from '@material-ui/styles';
import clsx from 'clsx'; import clsx from 'clsx';
import React, { useCallback } from 'react'; import React, { ReactNode, useCallback } from 'react';
import { Icon, IconArrowDown } from '../../../icons'; import Icon from '../../../icons/components/Icon';
import { IconArrowDown } from '../../../icons/svg/index';
import { withPixelLineHeight } from '../../../styles/functions.web'; import { withPixelLineHeight } from '../../../styles/functions.web';
type Props = { type Props = {
/** /**
* Text of the button. * Icon to display in the options section.
*/ */
children: React$Node, OptionsIcon?: Function,
/** /**
* An object containing the CSS classes. * The Label of the child element.
*/ */
classes: Object, ariaDropDownLabel?: string,
/**
* The Label of the current element.
*/
ariaLabel?: string,
/**
* To give a aria-pressed to the icon.
*/
ariaPressed?: boolean,
/**
* Text of the button.
*/
children: ReactNode,
/** /**
* Text css class of the button. * Text css class of the button.
*/ */
className?: string, className?: string,
/**
* An object containing the CSS classes.
*/
classes: any,
/** /**
* If the button is disabled or not. * If the button is disabled or not.
*/ */
@ -34,10 +53,26 @@ type Props = {
*/ */
hasOptions?: boolean, hasOptions?: boolean,
/** /**
* Icon to display in the options section. * OnClick button handler.
*/ */
OptionsIcon?: React$Node, onClick?: (e?: React.MouseEvent) => void,
/**
* Click handler for options.
*/
onOptionsClick?: (e?: React.KeyboardEvent | React.MouseEvent) => void,
/**
* To give a role to the icon.
*/
role?: string,
/**
* To navigate with the keyboard.
*/
tabIndex?: number,
/** /**
* TestId of the button. Can be used to locate element when testing UI. * TestId of the button. Can be used to locate element when testing UI.
@ -47,43 +82,7 @@ type Props = {
/** /**
* The type of th button: primary, secondary, text. * The type of th button: primary, secondary, text.
*/ */
type: string, type: string
/**
* OnClick button handler.
*/
onClick: Function,
/**
* Click handler for options.
*/
onOptionsClick?: Function,
/**
* To navigate with the keyboard.
*/
tabIndex?: number,
/**
* To give a role to the icon.
*/
role?: string,
/**
* To give a aria-pressed to the icon.
*/
ariaPressed?: boolean,
/**
* The Label of the current element.
*/
ariaLabel?: string,
/**
* The Label of the child element.
*/
ariaDropDownLabel?: string
}; };
/** /**
@ -93,7 +92,7 @@ type Props = {
* *
* @returns {Object} * @returns {Object}
*/ */
const styles = theme => { const styles = (theme: any) => {
return { return {
actionButton: { actionButton: {
...withPixelLineHeight(theme.typography.bodyLongBold), ...withPixelLineHeight(theme.typography.bodyLongBold),
@ -254,4 +253,5 @@ function ActionButton({
); );
} }
// @ts-ignore
export default withStyles(styles)(ActionButton); export default withStyles(styles)(ActionButton);

View File

@ -1,16 +1,21 @@
// @flow /* eslint-disable lines-around-comment */
import { makeStyles } from '@material-ui/styles'; import { makeStyles } from '@material-ui/styles';
import React, { useCallback, useState } from 'react'; import React, { useCallback, useState } from 'react';
import { WithTranslation } from 'react-i18next';
import { translate } from '../../../i18n'; import { IState } from '../../../../app/types';
import { Icon, IconArrowDownSmall, IconWifi1Bar, IconWifi2Bars, IconWifi3Bars } from '../../../icons'; import { translate } from '../../../i18n/functions';
import { connect } from '../../../redux'; import Icon from '../../../icons/components/Icon';
import { IconArrowDownSmall, IconWifi1Bar, IconWifi2Bars, IconWifi3Bars } from '../../../icons/svg/index';
import { connect } from '../../../redux/functions';
// @ts-ignore
import { PREJOIN_DEFAULT_CONTENT_WIDTH } from '../../../ui/components/variables'; import { PREJOIN_DEFAULT_CONTENT_WIDTH } from '../../../ui/components/variables';
// @ts-ignore
import { CONNECTION_TYPE } from '../../constants'; import { CONNECTION_TYPE } from '../../constants';
// @ts-ignore
import { getConnectionData } from '../../functions'; import { getConnectionData } from '../../functions';
type Props = { interface Props extends WithTranslation {
/** /**
* List of strings with details about the connection. * List of strings with details about the connection.
@ -20,15 +25,10 @@ type Props = {
/** /**
* The type of the connection. Can be: 'none', 'poor', 'nonOptimal' or 'good'. * The type of the connection. Can be: 'none', 'poor', 'nonOptimal' or 'good'.
*/ */
connectionType: string, connectionType: string
/**
* Used for translation.
*/
t: Function
} }
const useStyles = makeStyles(theme => { const useStyles = makeStyles((theme: any) => {
return { return {
connectionStatus: { connectionStatus: {
borderRadius: '6px', borderRadius: '6px',
@ -121,7 +121,7 @@ const useStyles = makeStyles(theme => {
}; };
}); });
const CONNECTION_TYPE_MAP = { const CONNECTION_TYPE_MAP: any = {
[CONNECTION_TYPE.POOR]: { [CONNECTION_TYPE.POOR]: {
connectionClass: 'con-status--poor', connectionClass: 'con-status--poor',
icon: IconWifi1Bar, icon: IconWifi1Bar,
@ -152,7 +152,7 @@ function ConnectionStatus({ connectionDetails, t, connectionType }: Props) {
const arrowClassName = showDetails const arrowClassName = showDetails
? 'con-status-arrow con-status-arrow--up' ? 'con-status-arrow con-status-arrow--up'
: 'con-status-arrow'; : 'con-status-arrow';
const detailsText = connectionDetails.map(t).join(' '); const detailsText = connectionDetails.map(d => t(d)).join(' ');
const detailsClassName = showDetails const detailsClassName = showDetails
? 'con-status-details-visible' ? 'con-status-details-visible'
: 'con-status-details-hidden'; : 'con-status-details-hidden';
@ -202,7 +202,7 @@ function ConnectionStatus({ connectionDetails, t, connectionType }: Props) {
tabIndex = { 0 } /> tabIndex = { 0 } />
</div> </div>
<div <div
aria-level = '2' aria-level = { 2 }
className = { `con-status-details ${detailsClassName}` } className = { `con-status-details ${detailsClassName}` }
role = 'heading'> role = 'heading'>
{detailsText}</div> {detailsText}</div>
@ -216,7 +216,7 @@ function ConnectionStatus({ connectionDetails, t, connectionType }: Props) {
* @param {Object} state - The redux state. * @param {Object} state - The redux state.
* @returns {Object} * @returns {Object}
*/ */
function mapStateToProps(state): Object { function mapStateToProps(state: IState): Object {
const { connectionDetails, connectionType } = getConnectionData(state); const { connectionDetails, connectionType } = getConnectionData(state);
return { return {

View File

@ -1,36 +1,37 @@
/* @flow */
import { makeStyles } from '@material-ui/core'; import { makeStyles } from '@material-ui/core';
import React from 'react'; import React from 'react';
import { WithTranslation } from 'react-i18next';
import { translate } from '../../../i18n'; import { translate } from '../../../i18n/functions';
import { Icon } from '../../../icons'; import Icon from '../../../icons/components/Icon';
// eslint-disable-next-line lines-around-comment
// @ts-ignore
import { Tooltip } from '../../../tooltip'; import { Tooltip } from '../../../tooltip';
/** /**
* The type of the React {@code Component} props of {@link BaseIndicator}. * The type of the React {@code Component} props of {@link BaseIndicator}.
*/ */
type Props = { interface Props extends WithTranslation {
/** /**
* Additional CSS class name. * Additional CSS class name.
*/ */
className: string, className?: string,
/** /**
* The icon component to use. * The icon component to use.
*/ */
icon: Object, icon: Function,
/** /**
* The CSS classnames to set on the icon element of the component. * The CSS classnames to set on the icon element of the component.
*/ */
iconClassName: string, iconClassName?: string,
/** /**
* The color of the icon. * The color of the icon.
*/ */
iconColor: ?string, iconColor?: string,
/** /**
* Id of the icon to be rendered. * Id of the icon to be rendered.
@ -45,12 +46,7 @@ type Props = {
/** /**
* The ID attribute to set on the root element of the component. * The ID attribute to set on the root element of the component.
*/ */
id: string, id?: string,
/**
* Invoked to obtain translated strings.
*/
t: Function,
/** /**
* The translation key to use for displaying a tooltip when hovering over * The translation key to use for displaying a tooltip when hovering over
@ -63,7 +59,7 @@ type Props = {
* defaulting to "top". * defaulting to "top".
*/ */
tooltipPosition: string tooltipPosition: string
}; }
const useStyles = makeStyles(() => { const useStyles = makeStyles(() => {
return { return {
@ -95,7 +91,7 @@ const BaseIndicator = ({
tooltipPosition = 'top' tooltipPosition = 'top'
}: Props) => { }: Props) => {
const styles = useStyles(); const styles = useStyles();
const style = {}; const style: any = {};
if (iconSize) { if (iconSize) {
style.fontSize = iconSize; style.fontSize = iconSize;

View File

@ -1,8 +1,8 @@
// @flow
import { createStyles, makeStyles } from '@material-ui/core'; import { createStyles, makeStyles } from '@material-ui/core';
import { commonStyles, getGlobalStyles } from '../constants'; import { commonStyles, getGlobalStyles } from '../constants';
// eslint-disable-next-line lines-around-comment
// @ts-ignore
import { formatCommonClasses } from '../functions'; import { formatCommonClasses } from '../functions';
/** /**
@ -12,7 +12,7 @@ import { formatCommonClasses } from '../functions';
* *
* @returns {Object} * @returns {Object}
*/ */
const useStyles = makeStyles(theme => const useStyles = makeStyles((theme: any) =>
createStyles({ createStyles({
'@global': { '@global': {
...formatCommonClasses(commonStyles(theme)), ...formatCommonClasses(commonStyles(theme)),

View File

@ -1,5 +1,3 @@
// @flow
import { makeStyles } from '@material-ui/styles'; import { makeStyles } from '@material-ui/styles';
import React from 'react'; import React from 'react';

View File

@ -1,8 +1,6 @@
// @flow
import { makeStyles } from '@material-ui/core/styles'; import { makeStyles } from '@material-ui/core/styles';
import clsx from 'clsx'; import clsx from 'clsx';
import React, { useEffect, useRef } from 'react'; import React, { ReactElement, useEffect, useRef } from 'react';
import { isMobileBrowser } from '../../../base/environment/utils'; import { isMobileBrowser } from '../../../base/environment/utils';
@ -11,7 +9,7 @@ type Props = {
/** /**
* The component(s) that need to be scrollable on mobile. * The component(s) that need to be scrollable on mobile.
*/ */
children: React$Node, children: ReactElement,
/** /**
* Whether the component should be flex container or not. * Whether the component should be flex container or not.
@ -48,7 +46,7 @@ function TouchmoveHack({ children, isModal, flex }: Props) {
return children; return children;
} }
const touchMoveElementRef = useRef(null); const touchMoveElementRef = useRef<HTMLDivElement>(null);
/** /**
* Atlaskit's {@code Modal} uses a third party library to disable touchmove events * Atlaskit's {@code Modal} uses a third party library to disable touchmove events

View File

@ -1,15 +1,20 @@
/* eslint-disable lines-around-comment */
import { makeStyles } from '@material-ui/styles'; import { makeStyles } from '@material-ui/styles';
import React, { useCallback } from 'react'; import React, { useCallback } from 'react';
import { useTranslation } from 'react-i18next'; import { useTranslation } from 'react-i18next';
import { useDispatch, useSelector } from 'react-redux'; import { useDispatch, useSelector } from 'react-redux';
import { IconRaisedHand } from '../../../base/icons'; import { IState } from '../../../app/types';
import { IconRaisedHand } from '../../../base/icons/svg/index';
// @ts-ignore
import { Label } from '../../../base/label'; import { Label } from '../../../base/label';
// @ts-ignore
import { Tooltip } from '../../../base/tooltip'; import { Tooltip } from '../../../base/tooltip';
import BaseTheme from '../../../base/ui/components/BaseTheme'; import BaseTheme from '../../../base/ui/components/BaseTheme.web';
// @ts-ignore
import { open as openParticipantsPane } from '../../../participants-pane/actions'; import { open as openParticipantsPane } from '../../../participants-pane/actions';
const useStyles = makeStyles(theme => { const useStyles = makeStyles((theme: any) => {
return { return {
label: { label: {
backgroundColor: theme.palette.warning02, backgroundColor: theme.palette.warning02,
@ -22,7 +27,7 @@ const useStyles = makeStyles(theme => {
const RaisedHandsCountLabel = () => { const RaisedHandsCountLabel = () => {
const styles = useStyles(); const styles = useStyles();
const dispatch = useDispatch(); const dispatch = useDispatch();
const raisedHandsCount = useSelector(state => const raisedHandsCount = useSelector((state: IState) =>
(state['features/base/participants'].raisedHandsQueue || []).length); (state['features/base/participants'].raisedHandsQueue || []).length);
const { t } = useTranslation(); const { t } = useTranslation();
const onClick = useCallback(() => { const onClick = useCallback(() => {
@ -38,7 +43,7 @@ const RaisedHandsCountLabel = () => {
iconColor = { BaseTheme.palette.uiBackground } iconColor = { BaseTheme.palette.uiBackground }
id = 'raisedHandsCountLabel' id = 'raisedHandsCountLabel'
onClick = { onClick } onClick = { onClick }
text = { raisedHandsCount } /> text = { `${raisedHandsCount}` } />
</Tooltip>); </Tooltip>);
}; };

View File

@ -1,33 +1,40 @@
// @flow /* eslint-disable lines-around-comment */
import { withStyles } from '@material-ui/styles'; import { withStyles } from '@material-ui/styles';
import clsx from 'clsx'; import clsx from 'clsx';
import React from 'react'; import React from 'react';
import { WithTranslation } from 'react-i18next';
import { connect } from 'react-redux';
import type { Dispatch } from 'redux'; import type { Dispatch } from 'redux';
import { IState } from '../../../app/types';
// @ts-ignore
import { getSourceNameSignalingFeatureFlag } from '../../../base/config'; import { getSourceNameSignalingFeatureFlag } from '../../../base/config';
import { translate } from '../../../base/i18n'; import { translate } from '../../../base/i18n/functions';
import { MEDIA_TYPE } from '../../../base/media'; import { MEDIA_TYPE } from '../../../base/media/constants';
import { getLocalParticipant, getParticipantById } from '../../../base/participants'; import { getLocalParticipant, getParticipantById } from '../../../base/participants/functions';
// @ts-ignore
import { Popover } from '../../../base/popover'; import { Popover } from '../../../base/popover';
import { connect } from '../../../base/redux';
import { import {
getVirtualScreenshareParticipantTrack, getVirtualScreenshareParticipantTrack,
getSourceNameByParticipantId, getSourceNameByParticipantId, // @ts-ignore
getTrackByMediaTypeAndParticipant } from '../../../base/tracks'; getTrackByMediaTypeAndParticipant } from '../../../base/tracks';
import { import {
isParticipantConnectionStatusInactive, isParticipantConnectionStatusInactive,
isParticipantConnectionStatusInterrupted, isParticipantConnectionStatusInterrupted,
isTrackStreamingStatusInactive, isTrackStreamingStatusInactive,
isTrackStreamingStatusInterrupted isTrackStreamingStatusInterrupted
// @ts-ignore
} from '../../functions'; } from '../../functions';
import AbstractConnectionIndicator, { import AbstractConnectionIndicator, {
INDICATOR_DISPLAY_THRESHOLD, INDICATOR_DISPLAY_THRESHOLD,
type Props as AbstractProps, type Props as AbstractProps,
type State as AbstractState type State as AbstractState
// @ts-ignore
} from '../AbstractConnectionIndicator'; } from '../AbstractConnectionIndicator';
// @ts-ignore
import ConnectionIndicatorContent from './ConnectionIndicatorContent'; import ConnectionIndicatorContent from './ConnectionIndicatorContent';
// @ts-ignore
import { ConnectionIndicatorIcon } from './ConnectionIndicatorIcon'; import { ConnectionIndicatorIcon } from './ConnectionIndicatorIcon';
/** /**
@ -37,7 +44,11 @@ import { ConnectionIndicatorIcon } from './ConnectionIndicatorIcon';
* *
* @type {Object[]} * @type {Object[]}
*/ */
const QUALITY_TO_WIDTH: Array<Object> = [ const QUALITY_TO_WIDTH: Array<{
colorClass: string;
percent: number;
tip: string;
}> = [
// Full (3 bars) // Full (3 bars)
{ {
@ -66,7 +77,12 @@ const QUALITY_TO_WIDTH: Array<Object> = [
/** /**
* The type of the React {@code Component} props of {@link ConnectionIndicator}. * The type of the React {@code Component} props of {@link ConnectionIndicator}.
*/ */
type Props = AbstractProps & { type Props = AbstractProps & WithTranslation & {
/**
* Disable/enable inactive indicator.
*/
_connectionIndicatorInactiveDisabled: boolean,
/** /**
* The current condition of the user's connection, matching one of the * The current condition of the user's connection, matching one of the
@ -74,16 +90,21 @@ type Props = AbstractProps & {
*/ */
_connectionStatus: string, _connectionStatus: string,
/**
* Disable/enable inactive indicator.
*/
_connectionIndicatorInactiveDisabled: boolean,
/** /**
* Whether the indicator popover is disabled. * Whether the indicator popover is disabled.
*/ */
_popoverDisabled: boolean, _popoverDisabled: boolean,
/**
* The source name of the track.
*/
_sourceName: string,
/**
* Whether source name signaling is enabled.
*/
_sourceNameSignalingEnabled: boolean,
/** /**
* Whether or not the component should ignore setting a visibility class for * Whether or not the component should ignore setting a visibility class for
* hiding the component when the connection quality is not strong. * hiding the component when the connection quality is not strong.
@ -95,6 +116,7 @@ type Props = AbstractProps & {
*/ */
audioSsrc: number, audioSsrc: number,
/** /**
* An object containing the CSS classes. * An object containing the CSS classes.
*/ */
@ -105,7 +127,6 @@ type Props = AbstractProps & {
*/ */
dispatch: Dispatch<any>, dispatch: Dispatch<any>,
/** /**
* Whether or not clicking the indicator should display a popover for more * Whether or not clicking the indicator should display a popover for more
* details. * details.
@ -121,22 +142,7 @@ type Props = AbstractProps & {
* Relative to the icon from where the popover for more connection details * Relative to the icon from where the popover for more connection details
* should display. * should display.
*/ */
statsPopoverPosition: string, statsPopoverPosition: string
/**
* Invoked to obtain translated strings.
*/
t: Function,
/**
* The source name of the track.
*/
_sourceName: string,
/**
* Whether source name signaling is enabled.
*/
_sourceNameSignalingEnabled: boolean
}; };
type State = AbstractState & { type State = AbstractState & {
@ -147,7 +153,7 @@ type State = AbstractState & {
popoverVisible: boolean popoverVisible: boolean
} }
const styles = theme => { const styles = (theme: any) => {
return { return {
container: { container: {
display: 'inline-block' display: 'inline-block'
@ -209,6 +215,7 @@ class ConnectionIndicator extends AbstractConnectionIndicator<Props, State> {
constructor(props: Props) { constructor(props: Props) {
super(props); super(props);
// @ts-ignore
this.state = { this.state = {
showIndicator: false, showIndicator: false,
stats: {}, stats: {},
@ -225,9 +232,11 @@ class ConnectionIndicator extends AbstractConnectionIndicator<Props, State> {
* @returns {ReactElement} * @returns {ReactElement}
*/ */
render() { render() {
// @ts-ignore
const { enableStatsDisplay, participantId, statsPopoverPosition, classes } = this.props; const { enableStatsDisplay, participantId, statsPopoverPosition, classes } = this.props;
const visibilityClass = this._getVisibilityClass(); const visibilityClass = this._getVisibilityClass();
// @ts-ignore
if (this.props._popoverDisabled) { if (this.props._popoverDisabled) {
return this._renderIndicator(); return this._renderIndicator();
} }
@ -236,6 +245,7 @@ class ConnectionIndicator extends AbstractConnectionIndicator<Props, State> {
<Popover <Popover
className = { clsx(classes.container, visibilityClass) } className = { clsx(classes.container, visibilityClass) }
content = { <ConnectionIndicatorContent content = { <ConnectionIndicatorContent
// @ts-ignore
inheritedStats = { this.state.stats } inheritedStats = { this.state.stats }
participantId = { participantId } /> } participantId = { participantId } /> }
disablePopover = { !enableStatsDisplay } disablePopover = { !enableStatsDisplay }
@ -244,6 +254,7 @@ class ConnectionIndicator extends AbstractConnectionIndicator<Props, State> {
onPopoverClose = { this._onHidePopover } onPopoverClose = { this._onHidePopover }
onPopoverOpen = { this._onShowPopover } onPopoverOpen = { this._onShowPopover }
position = { statsPopoverPosition } position = { statsPopoverPosition }
// @ts-ignore
visible = { this.state.popoverVisible }> visible = { this.state.popoverVisible }>
{ this._renderIndicator() } { this._renderIndicator() }
</Popover> </Popover>
@ -259,12 +270,14 @@ class ConnectionIndicator extends AbstractConnectionIndicator<Props, State> {
*/ */
_getConnectionColorClass() { _getConnectionColorClass() {
// TODO We currently do not have logic to emit and handle stats changes for tracks. // TODO We currently do not have logic to emit and handle stats changes for tracks.
// @ts-ignore
const { percent } = this.state.stats; const { percent } = this.state.stats;
const { const {
_isConnectionStatusInactive, _isConnectionStatusInactive,
_isConnectionStatusInterrupted, _isConnectionStatusInterrupted,
_connectionIndicatorInactiveDisabled _connectionIndicatorInactiveDisabled
// @ts-ignore
} = this.props; } = this.props;
if (_isConnectionStatusInactive) { if (_isConnectionStatusInactive) {
@ -293,7 +306,7 @@ class ConnectionIndicator extends AbstractConnectionIndicator<Props, State> {
* @private * @private
* @returns {Object} * @returns {Object}
*/ */
_getDisplayConfiguration(percent: number): Object { _getDisplayConfiguration(percent: number): any {
return QUALITY_TO_WIDTH.find(x => percent >= x.percent) || {}; return QUALITY_TO_WIDTH.find(x => percent >= x.percent) || {};
} }
@ -305,17 +318,18 @@ class ConnectionIndicator extends AbstractConnectionIndicator<Props, State> {
* @returns {string} * @returns {string}
*/ */
_getVisibilityClass() { _getVisibilityClass() {
// @ts-ignore
const { _isConnectionStatusInactive, _isConnectionStatusInterrupted, classes } = this.props; const { _isConnectionStatusInactive, _isConnectionStatusInterrupted, classes } = this.props;
// @ts-ignore
return this.state.showIndicator return this.state.showIndicator
// @ts-ignore
|| this.props.alwaysVisible || this.props.alwaysVisible
|| _isConnectionStatusInterrupted || _isConnectionStatusInterrupted
|| _isConnectionStatusInactive || _isConnectionStatusInactive
? '' : classes.hidden; ? '' : classes.hidden;
} }
_onHidePopover: () => void;
/** /**
* Hides popover. * Hides popover.
* *
@ -323,12 +337,10 @@ class ConnectionIndicator extends AbstractConnectionIndicator<Props, State> {
* @returns {void} * @returns {void}
*/ */
_onHidePopover() { _onHidePopover() {
// @ts-ignore
this.setState({ popoverVisible: false }); this.setState({ popoverVisible: false });
} }
_onShowPopover: () => void;
/** /**
* Shows popover. * Shows popover.
* *
@ -336,6 +348,7 @@ class ConnectionIndicator extends AbstractConnectionIndicator<Props, State> {
* @returns {void} * @returns {void}
*/ */
_onShowPopover() { _onShowPopover() {
// @ts-ignore
this.setState({ popoverVisible: true }); this.setState({ popoverVisible: true });
} }
@ -353,6 +366,7 @@ class ConnectionIndicator extends AbstractConnectionIndicator<Props, State> {
_videoTrack, _videoTrack,
classes, classes,
iconSize iconSize
// @ts-ignore
} = this.props; } = this.props;
return ( return (
@ -377,7 +391,7 @@ class ConnectionIndicator extends AbstractConnectionIndicator<Props, State> {
* @param {Props} ownProps - The own props of the component. * @param {Props} ownProps - The own props of the component.
* @returns {Props} * @returns {Props}
*/ */
export function _mapStateToProps(state: Object, ownProps: Props) { export function _mapStateToProps(state: IState, ownProps: Props) {
const { participantId } = ownProps; const { participantId } = ownProps;
const tracks = state['features/base/tracks']; const tracks = state['features/base/tracks'];
const sourceNameSignalingEnabled = getSourceNameSignalingFeatureFlag(state); const sourceNameSignalingEnabled = getSourceNameSignalingFeatureFlag(state);
@ -411,4 +425,5 @@ export function _mapStateToProps(state: Object, ownProps: Props) {
}; };
} }
export default translate(connect(_mapStateToProps)( export default translate(connect(_mapStateToProps)(
// @ts-ignore
withStyles(styles)(ConnectionIndicator))); withStyles(styles)(ConnectionIndicator)));

View File

@ -1,18 +1,22 @@
/* @flow */
import { withStyles } from '@material-ui/styles'; import { withStyles } from '@material-ui/styles';
import clsx from 'clsx'; import clsx from 'clsx';
import React, { Component } from 'react'; import React, { Component } from 'react';
import { WithTranslation } from 'react-i18next';
import { isMobileBrowser } from '../../../features/base/environment/utils';
import ContextMenu from '../../base/components/context-menu/ContextMenu'; import ContextMenu from '../../base/components/context-menu/ContextMenu';
import { translate } from '../../base/i18n'; import { isMobileBrowser } from '../../base/environment/utils';
import { translate } from '../../base/i18n/functions';
type DownloadUpload = {
download: number;
upload: number;
}
/** /**
* The type of the React {@code Component} props of * The type of the React {@code Component} props of
* {@link ConnectionStatsTable}. * {@link ConnectionStatsTable}.
*/ */
type Props = { interface Props extends WithTranslation {
/** /**
* The audio SSRC of this client. * The audio SSRC of this client.
@ -26,7 +30,7 @@ type Props = {
* upload: Number * upload: Number
* }}. * }}.
*/ */
bandwidth: Object, bandwidth: DownloadUpload,
/** /**
* Statistics related to bitrate. * Statistics related to bitrate.
@ -35,7 +39,7 @@ type Props = {
* upload: Number * upload: Number
* }}. * }}.
*/ */
bitrate: Object, bitrate: DownloadUpload,
/** /**
* The number of bridges (aka media servers) currently used in the * The number of bridges (aka media servers) currently used in the
@ -46,18 +50,28 @@ type Props = {
/** /**
* An object containing the CSS classes. * An object containing the CSS classes.
*/ */
classes: Object, classes: any,
/** /**
* Audio/video codecs in use for the connection. * Audio/video codecs in use for the connection.
*/ */
codec: Object, codec: {
[key: string]: {
audio: string;
video: string;
}
},
/** /**
* A message describing the connection quality. * A message describing the connection quality.
*/ */
connectionSummary: string, connectionSummary: string,
/**
* Whether or not should display the "Show More" link.
*/
disableShowMoreStats: boolean,
/** /**
* The end-to-end round-trip-time. * The end-to-end round-trip-time.
*/ */
@ -68,16 +82,6 @@ type Props = {
*/ */
enableSaveLogs: boolean, enableSaveLogs: boolean,
/**
* Whether or not should display the "Show More" link.
*/
disableShowMoreStats: boolean,
/**
* The endpoint id of this client.
*/
participantId: string,
/** /**
* Statistics related to frame rates for each ssrc. * Statistics related to frame rates for each ssrc.
* {{ * {{
@ -105,12 +109,12 @@ type Props = {
/** /**
* Callback to invoke when the user clicks on the download logs link. * Callback to invoke when the user clicks on the download logs link.
*/ */
onSaveLogs: Function, onSaveLogs: () => void,
/** /**
* Callback to invoke when the show additional stats link is clicked. * Callback to invoke when the show additional stats link is clicked.
*/ */
onShowMore: Function, onShowMore: (e?: React.MouseEvent) => void,
/** /**
* Statistics related to packet loss. * Statistics related to packet loss.
@ -119,7 +123,12 @@ type Props = {
* upload: Number * upload: Number
* }}. * }}.
*/ */
packetLoss: Object, packetLoss: DownloadUpload,
/**
* The endpoint id of this client.
*/
participantId: string,
/** /**
* The region that we think the client is in. * The region that we think the client is in.
@ -135,7 +144,12 @@ type Props = {
* } * }
* }}. * }}.
*/ */
resolution: Object, resolution: {
[ssrc: string]: {
height: number;
width: number;
}
},
/** /**
* The region of the media server that we are connected to. * The region of the media server that we are connected to.
@ -149,25 +163,28 @@ type Props = {
shouldShowMore: boolean, shouldShowMore: boolean,
/** /**
* Invoked to obtain translated strings. * Whether source name signaling is enabled.
*/ */
t: Function, sourceNameSignalingEnabled: boolean,
/**
* The video SSRC of this client.
*/
videoSsrc: number,
/** /**
* Statistics related to transports. * Statistics related to transports.
*/ */
transport: Array<Object>, transport: Array<{
ip: string;
localCandidateType: string;
localip: string;
p2p: boolean;
remoteCandidateType: string;
transportType: string;
type: string;
}>,
/** /**
* Whether source name signaling is enabled. * The video SSRC of this client.
*/ */
sourceNameSignalingEnabled: boolean videoSsrc: number
}; }
/** /**
* Click handler. * Click handler.
@ -175,13 +192,13 @@ type Props = {
* @param {SyntheticEvent} event - The click event. * @param {SyntheticEvent} event - The click event.
* @returns {void} * @returns {void}
*/ */
function onClick(event) { function onClick(event: React.MouseEvent) {
// If the event is propagated to the thumbnail container the participant will be pinned. That's why the propagation // If the event is propagated to the thumbnail container the participant will be pinned. That's why the propagation
// needs to be stopped. // needs to be stopped.
event.stopPropagation(); event.stopPropagation();
} }
const styles = theme => { const styles = (theme: any) => {
return { return {
actions: { actions: {
margin: '10px auto', margin: '10px auto',
@ -599,7 +616,7 @@ class ConnectionStatsTable extends Component<Props> {
frameRateString = framerate || 'N/A'; frameRateString = framerate || 'N/A';
} else { } else {
frameRateString = Object.keys(framerate || {}) frameRateString = Object.keys(framerate || {})
.map(ssrc => framerate[ssrc]) .map(ssrc => framerate[ssrc as keyof typeof framerate])
.join(', ') || 'N/A'; .join(', ') || 'N/A';
} }
@ -791,7 +808,13 @@ class ConnectionStatsTable extends Component<Props> {
return [ NA ]; return [ NA ];
} }
const data = { const data: {
localIP: string[],
localPort: string[],
remoteIP: string[],
remotePort: string[],
transportType: string[]
} = {
localIP: [], localIP: [],
localPort: [], localPort: [],
remoteIP: [], remoteIP: [],
@ -897,7 +920,7 @@ class ConnectionStatsTable extends Component<Props> {
* @private * @private
* @returns {ReactElement} * @returns {ReactElement}
*/ */
_renderTransportTableRow(config: Object) { _renderTransportTableRow(config: any) {
const { additionalData, data, key, label } = config; const { additionalData, data, key, label } = config;
return ( return (
@ -924,7 +947,7 @@ class ConnectionStatsTable extends Component<Props> {
* @private * @private
* @returns {string} * @returns {string}
*/ */
function getIP(value) { function getIP(value: string) {
if (!value) { if (!value) {
return ''; return '';
} }
@ -940,7 +963,7 @@ function getIP(value) {
* @private * @private
* @returns {string} * @returns {string}
*/ */
function getPort(value) { function getPort(value: string) {
if (!value) { if (!value) {
return ''; return '';
} }
@ -955,7 +978,7 @@ function getPort(value) {
* @private * @private
* @returns {string} * @returns {string}
*/ */
function getStringFromArray(array) { function getStringFromArray(array: string[]) {
let res = ''; let res = '';
for (let i = 0; i < array.length; i++) { for (let i = 0; i < array.length; i++) {
@ -965,4 +988,5 @@ function getStringFromArray(array) {
return res; return res;
} }
// @ts-ignore
export default translate(withStyles(styles)(ConnectionStatsTable)); export default translate(withStyles(styles)(ConnectionStatsTable));

View File

@ -1,24 +1,28 @@
/* @flow */ /* eslint-disable lines-around-comment */
import { withStyles } from '@material-ui/styles'; import { withStyles } from '@material-ui/styles';
import React, { Component } from 'react'; import React, { Component } from 'react';
import { WithTranslation } from 'react-i18next';
import { connect } from 'react-redux';
import type { Dispatch } from 'redux'; import type { Dispatch } from 'redux';
import { translate } from '../../../base/i18n'; import { IState } from '../../../app/types';
import { translate } from '../../../base/i18n/functions';
import { import {
getParticipantDisplayName, getParticipantDisplayName,
getParticipantById getParticipantById
} from '../../../base/participants'; } from '../../../base/participants/functions';
import { connect } from '../../../base/redux'; // @ts-ignore
import { updateSettings } from '../../../base/settings'; import { updateSettings } from '../../../base/settings';
// @ts-ignore
import { Tooltip } from '../../../base/tooltip'; import { Tooltip } from '../../../base/tooltip';
// @ts-ignore
import { getIndicatorsTooltipPosition } from '../../../filmstrip/functions.web'; import { getIndicatorsTooltipPosition } from '../../../filmstrip/functions.web';
import { appendSuffix } from '../../functions'; import { appendSuffix } from '../../functions';
/** /**
* The type of the React {@code Component} props of {@link DisplayName}. * The type of the React {@code Component} props of {@link DisplayName}.
*/ */
type Props = { interface Props extends WithTranslation {
/** /**
* The participant's current display name which should be shown when in * The participant's current display name which should be shown when in
@ -36,6 +40,11 @@ type Props = {
*/ */
allowEditing: boolean, allowEditing: boolean,
/**
* An object containing the CSS classes.
*/
classes: any,
/** /**
* Invoked to update the participant's display name. * Invoked to update the participant's display name.
*/ */
@ -46,11 +55,6 @@ type Props = {
*/ */
displayNameSuffix: string, displayNameSuffix: string,
/**
* An object containing the CSS classes.
*/
classes: Object,
/** /**
* The ID attribute to add to the component. Useful for global querying for * The ID attribute to add to the component. Useful for global querying for
* the component by legacy components and torture tests. * the component by legacy components and torture tests.
@ -62,16 +66,11 @@ type Props = {
*/ */
participantID: string, participantID: string,
/**
* Invoked to obtain translated strings.
*/
t: Function,
/** /**
* The type of thumbnail. * The type of thumbnail.
*/ */
thumbnailType: string thumbnailType: string
}; }
/** /**
* The type of the React {@code Component} state of {@link DisplayName}. * The type of the React {@code Component} state of {@link DisplayName}.
@ -89,7 +88,7 @@ type State = {
isEditing: boolean isEditing: boolean
}; };
const styles = theme => { const styles = (theme: any) => {
return { return {
displayName: { displayName: {
...theme.typography.labelBold, ...theme.typography.labelBold,
@ -119,7 +118,7 @@ const styles = theme => {
* @augments Component * @augments Component
*/ */
class DisplayName extends Component<Props, State> { class DisplayName extends Component<Props, State> {
_nameInput: ?HTMLInputElement; _nameInput?: HTMLInputElement;
static defaultProps = { static defaultProps = {
_configuredDisplayName: '' _configuredDisplayName: ''
@ -148,7 +147,7 @@ class DisplayName extends Component<Props, State> {
* @private * @private
* @type {HTMLInputElement} * @type {HTMLInputElement}
*/ */
this._nameInput = null; this._nameInput = undefined;
// Bind event handlers so they are only bound once for every instance. // Bind event handlers so they are only bound once for every instance.
this._onChange = this._onChange.bind(this); this._onChange = this._onChange.bind(this);
@ -165,7 +164,7 @@ class DisplayName extends Component<Props, State> {
* @inheritdoc * @inheritdoc
* @returns {void} * @returns {void}
*/ */
componentDidUpdate(previousProps, previousState) { componentDidUpdate(previousProps: Props, previousState: State) {
if (!previousState.isEditing if (!previousState.isEditing
&& this.state.isEditing && this.state.isEditing
&& this._nameInput) { && this._nameInput) {
@ -229,12 +228,10 @@ class DisplayName extends Component<Props, State> {
* @private * @private
* @returns {void} * @returns {void}
*/ */
_onClick(e) { _onClick(e: React.MouseEvent) {
e.stopPropagation(); e.stopPropagation();
} }
_onChange: () => void;
/** /**
* Updates the internal state of the display name entered into the edit * Updates the internal state of the display name entered into the edit
* field. * field.
@ -243,14 +240,12 @@ class DisplayName extends Component<Props, State> {
* @private * @private
* @returns {void} * @returns {void}
*/ */
_onChange(event) { _onChange(event: React.ChangeEvent<HTMLInputElement>) {
this.setState({ this.setState({
editDisplayNameValue: event.target.value editDisplayNameValue: event.target.value
}); });
} }
_onKeyDown: () => void;
/** /**
* Submits the edited display name update if the enter key is pressed. * Submits the edited display name update if the enter key is pressed.
* *
@ -258,14 +253,12 @@ class DisplayName extends Component<Props, State> {
* @private * @private
* @returns {void} * @returns {void}
*/ */
_onKeyDown(event) { _onKeyDown(event: React.KeyboardEvent) {
if (event.key === 'Enter') { if (event.key === 'Enter') {
this._onSubmit(); this._onSubmit();
} }
} }
_onStartEditing: () => void;
/** /**
* Updates the component to display an editable input field and sets the * Updates the component to display an editable input field and sets the
* initial value to the current display name. * initial value to the current display name.
@ -274,7 +267,7 @@ class DisplayName extends Component<Props, State> {
* @private * @private
* @returns {void} * @returns {void}
*/ */
_onStartEditing(e) { _onStartEditing(e: React.MouseEvent) {
if (this.props.allowEditing) { if (this.props.allowEditing) {
e.stopPropagation(); e.stopPropagation();
this.setState({ this.setState({
@ -284,8 +277,6 @@ class DisplayName extends Component<Props, State> {
} }
} }
_onSubmit: () => void;
/** /**
* Dispatches an action to update the display name if any change has * Dispatches an action to update the display name if any change has
* occurred after editing. Clears any temporary state used to keep track * occurred after editing. Clears any temporary state used to keep track
@ -309,11 +300,9 @@ class DisplayName extends Component<Props, State> {
editDisplayNameValue: '' editDisplayNameValue: ''
}); });
this._nameInput = null; this._nameInput = undefined;
} }
_setNameInputRef: (HTMLInputElement | null) => void;
/** /**
* Sets the internal reference to the HTML element backing the React * Sets the internal reference to the HTML element backing the React
* {@code Component} input with id {@code editDisplayName}. * {@code Component} input with id {@code editDisplayName}.
@ -323,7 +312,7 @@ class DisplayName extends Component<Props, State> {
* @private * @private
* @returns {void} * @returns {void}
*/ */
_setNameInputRef(element) { _setNameInputRef(element: HTMLInputElement) {
this._nameInput = element; this._nameInput = element;
} }
} }
@ -339,13 +328,13 @@ class DisplayName extends Component<Props, State> {
* _nameToDisplay: string * _nameToDisplay: string
* }} * }}
*/ */
function _mapStateToProps(state, ownProps) { function _mapStateToProps(state: IState, ownProps: Partial<Props>) {
const { participantID } = ownProps; const { participantID } = ownProps;
const participant = getParticipantById(state, participantID); const participant = getParticipantById(state, participantID ?? '');
return { return {
_configuredDisplayName: participant && participant.name, _configuredDisplayName: participant && participant.name,
_nameToDisplay: getParticipantDisplayName(state, participantID) _nameToDisplay: getParticipantDisplayName(state, participantID ?? '')
}; };
} }

View File

@ -1,20 +1,25 @@
// @flow /* eslint-disable lines-around-comment */
import { makeStyles } from '@material-ui/core/styles'; import { makeStyles } from '@material-ui/core/styles';
import clsx from 'clsx'; import clsx from 'clsx';
import React from 'react'; import React from 'react';
import { useSelector } from 'react-redux'; import { useSelector } from 'react-redux';
import { IState } from '../../../app/types';
// @ts-ignore
import { isDisplayNameVisible } from '../../../base/config/functions.any'; import { isDisplayNameVisible } from '../../../base/config/functions.any';
import { getLocalParticipant, getParticipantDisplayName } from '../../../base/participants'; import { getLocalParticipant, getParticipantDisplayName } from '../../../base/participants/functions';
import { Participant } from '../../../base/participants/reducer';
import { withPixelLineHeight } from '../../../base/styles/functions.web'; import { withPixelLineHeight } from '../../../base/styles/functions.web';
// @ts-ignore
import { getLargeVideoParticipant } from '../../../large-video/functions'; import { getLargeVideoParticipant } from '../../../large-video/functions';
// @ts-ignore
import { isToolboxVisible } from '../../../toolbox/functions.web'; import { isToolboxVisible } from '../../../toolbox/functions.web';
// @ts-ignore
import { isLayoutTileView } from '../../../video-layout'; import { isLayoutTileView } from '../../../video-layout';
import DisplayNameBadge from './DisplayNameBadge'; import DisplayNameBadge from './DisplayNameBadge';
const useStyles = makeStyles(theme => { const useStyles = makeStyles((theme: any) => {
return { return {
badgeContainer: { badgeContainer: {
...withPixelLineHeight(theme.typography.bodyShortRegularLarge), ...withPixelLineHeight(theme.typography.bodyShortRegularLarge),
@ -43,15 +48,15 @@ const useStyles = makeStyles(theme => {
*/ */
const StageParticipantNameLabel = () => { const StageParticipantNameLabel = () => {
const classes = useStyles(); const classes = useStyles();
const largeVideoParticipant = useSelector(getLargeVideoParticipant); const largeVideoParticipant: Participant = useSelector(getLargeVideoParticipant);
const selectedId = largeVideoParticipant?.id; const selectedId = largeVideoParticipant?.id;
const nameToDisplay = useSelector(state => getParticipantDisplayName(state, selectedId)); const nameToDisplay = useSelector((state: IState) => getParticipantDisplayName(state, selectedId));
const localParticipant = useSelector(getLocalParticipant); const localParticipant = useSelector(getLocalParticipant);
const localId = localParticipant?.id; const localId = localParticipant?.id;
const isTileView = useSelector(isLayoutTileView); const isTileView = useSelector(isLayoutTileView);
const toolboxVisible = useSelector(isToolboxVisible); const toolboxVisible: boolean = useSelector(isToolboxVisible);
const showDisplayName = useSelector(isDisplayNameVisible); const showDisplayName = useSelector(isDisplayNameVisible);
if (showDisplayName && nameToDisplay && selectedId !== localId && !isTileView) { if (showDisplayName && nameToDisplay && selectedId !== localId && !isTileView) {

View File

@ -1,5 +1,3 @@
// @flow
import { createMuiTheme } from '@material-ui/core/styles'; import { createMuiTheme } from '@material-ui/core/styles';
import { font, colors, colorMap, spacing, shape, typography, breakpoints } from '../base/ui/Tokens'; import { font, colors, colorMap, spacing, shape, typography, breakpoints } from '../base/ui/Tokens';
@ -11,7 +9,7 @@ import { createColorTokens } from '../base/ui/utils';
* @param {Object} customTheme - The branded custom theme. * @param {Object} customTheme - The branded custom theme.
* @returns {Object} - The MUI theme. * @returns {Object} - The MUI theme.
*/ */
export function createMuiBrandingTheme(customTheme: Object) { export function createMuiBrandingTheme(customTheme: any) {
const { const {
palette: customPalette, palette: customPalette,
shape: customShape, shape: customShape,
@ -82,9 +80,10 @@ export function createMuiBrandingTheme(customTheme: Object) {
function overwriteRecurrsive(obj1: Object, obj2: Object) { function overwriteRecurrsive(obj1: Object, obj2: Object) {
Object.keys(obj2).forEach(key => { Object.keys(obj2).forEach(key => {
if (obj1.hasOwnProperty(key)) { if (obj1.hasOwnProperty(key)) {
if (typeof obj1[key] === 'object') { if (typeof obj1[key as keyof typeof obj1] === 'object') {
overwriteRecurrsive(obj1[key], obj2[key]); overwriteRecurrsive(obj1[key as keyof typeof obj1], obj2[key as keyof typeof obj2]);
} else { } else {
// @ts-ignore
obj1[key] = obj2[key]; obj1[key] = obj2[key];
} }
} }

View File

@ -1,9 +1,9 @@
/* @flow */ /* eslint-disable lines-around-comment */
import { withStyles } from '@material-ui/styles'; import { withStyles } from '@material-ui/styles';
import clsx from 'clsx'; import clsx from 'clsx';
import _ from 'lodash'; import _ from 'lodash';
import React, { PureComponent } from 'react'; import React, { PureComponent } from 'react';
import { WithTranslation } from 'react-i18next';
import { FixedSizeList, FixedSizeGrid } from 'react-window'; import { FixedSizeList, FixedSizeGrid } from 'react-window';
import type { Dispatch } from 'redux'; import type { Dispatch } from 'redux';
@ -11,15 +11,23 @@ import {
createShortcutEvent, createShortcutEvent,
createToolbarEvent, createToolbarEvent,
sendAnalytics sendAnalytics
// @ts-ignore
} from '../../../analytics'; } from '../../../analytics';
// @ts-ignore
import { getSourceNameSignalingFeatureFlag, getToolbarButtons } from '../../../base/config'; import { getSourceNameSignalingFeatureFlag, getToolbarButtons } from '../../../base/config';
import { isMobileBrowser } from '../../../base/environment/utils'; import { isMobileBrowser } from '../../../base/environment/utils';
import { translate } from '../../../base/i18n'; import { translate } from '../../../base/i18n/functions';
import { Icon, IconMenuDown, IconMenuUp } from '../../../base/icons'; import Icon from '../../../base/icons/components/Icon';
import { connect } from '../../../base/redux'; import { IconMenuDown, IconMenuUp } from '../../../base/icons/svg/index';
import { Participant } from '../../../base/participants/reducer';
import { connect } from '../../../base/redux/functions';
// @ts-ignore
import { shouldHideSelfView } from '../../../base/settings/functions.any'; import { shouldHideSelfView } from '../../../base/settings/functions.any';
// @ts-ignore
import { showToolbox } from '../../../toolbox/actions.web'; import { showToolbox } from '../../../toolbox/actions.web';
// @ts-ignore
import { isButtonEnabled, isToolboxVisible } from '../../../toolbox/functions.web'; import { isButtonEnabled, isToolboxVisible } from '../../../toolbox/functions.web';
// @ts-ignore
import { getCurrentLayout, LAYOUTS } from '../../../video-layout'; import { getCurrentLayout, LAYOUTS } from '../../../video-layout';
import { import {
setFilmstripVisible, setFilmstripVisible,
@ -28,6 +36,7 @@ import {
setUserIsResizing, setUserIsResizing,
setTopPanelVisible, setTopPanelVisible,
setVisibleRemoteParticipants setVisibleRemoteParticipants
// @ts-ignore
} from '../../actions'; } from '../../actions';
import { import {
ASPECT_RATIO_BREAKPOINT, ASPECT_RATIO_BREAKPOINT,
@ -43,51 +52,55 @@ import {
getVerticalViewMaxWidth, getVerticalViewMaxWidth,
shouldRemoteVideosBeVisible, shouldRemoteVideosBeVisible,
isStageFilmstripTopPanel isStageFilmstripTopPanel
// @ts-ignore
} from '../../functions'; } from '../../functions';
// @ts-ignore
import AudioTracksContainer from './AudioTracksContainer'; import AudioTracksContainer from './AudioTracksContainer';
// @ts-ignore
import Thumbnail from './Thumbnail'; import Thumbnail from './Thumbnail';
// @ts-ignore
import ThumbnailWrapper from './ThumbnailWrapper'; import ThumbnailWrapper from './ThumbnailWrapper';
// @ts-ignore
import { styles } from './styles'; import { styles } from './styles';
declare var APP: Object; declare let APP: any;
declare var interfaceConfig: Object;
/** /**
* The type of the React {@code Component} props of {@link Filmstrip}. * The type of the React {@code Component} props of {@link Filmstrip}.
*/ */
type Props = { interface Props extends WithTranslation {
/** /**
* Additional CSS class names top add to the root. * Additional CSS class names top add to the root.
*/ */
_className: string, _className: string,
/**
* The current layout of the filmstrip.
*/
_currentLayout: string,
/** /**
* The number of columns in tile view. * The number of columns in tile view.
*/ */
_columns: number, _columns: number,
/**
* The current layout of the filmstrip.
*/
_currentLayout: string,
/** /**
* Whether or not to hide the self view. * Whether or not to hide the self view.
*/ */
_disableSelfView: boolean, _disableSelfView: boolean,
/**
* The width of the filmstrip.
*/
_filmstripWidth: number,
/** /**
* The height of the filmstrip. * The height of the filmstrip.
*/ */
_filmstripHeight: number, _filmstripHeight: number,
/**
* The width of the filmstrip.
*/
_filmstripWidth: number,
/** /**
* Whether or not we have scroll on the filmstrip. * Whether or not we have scroll on the filmstrip.
*/ */
@ -116,7 +129,7 @@ type Props = {
/** /**
* The local screen share participant. This prop is behind the sourceNameSignaling feature flag. * The local screen share participant. This prop is behind the sourceNameSignaling feature flag.
*/ */
_localScreenShare: Object, _localScreenShare: Participant,
/** /**
* Whether or not the filmstrip videos should currently be displayed. * Whether or not the filmstrip videos should currently be displayed.
@ -173,16 +186,16 @@ type Props = {
*/ */
_topPanelFilmstrip: boolean, _topPanelFilmstrip: boolean,
/**
* The height of the top panel (user resized).
*/
_topPanelHeight?: number,
/** /**
* The max height of the top panel. * The max height of the top panel.
*/ */
_topPanelMaxHeight: number, _topPanelMaxHeight: number,
/**
* The height of the top panel (user resized).
*/
_topPanelHeight: ?number,
/** /**
* Whether or not the top panel is visible. * Whether or not the top panel is visible.
*/ */
@ -191,7 +204,7 @@ type Props = {
/** /**
* The width of the vertical filmstrip (user resized). * The width of the vertical filmstrip (user resized).
*/ */
_verticalFilmstripWidth: ?number, _verticalFilmstripWidth?: number,
/** /**
* Whether or not the vertical filmstrip should have a background color. * Whether or not the vertical filmstrip should have a background color.
@ -216,7 +229,7 @@ type Props = {
/** /**
* An object containing the CSS classes. * An object containing the CSS classes.
*/ */
classes: Object, classes: any,
/** /**
* The redux {@code dispatch} function. * The redux {@code dispatch} function.
@ -226,16 +239,21 @@ type Props = {
/** /**
* The type of filmstrip to be displayed. * The type of filmstrip to be displayed.
*/ */
filmstripType: string, filmstripType: string
}
/**
* Invoked to obtain translated strings.
*/
t: Function
};
type State = { type State = {
/**
* Initial top panel height on drag handle mouse down.
*/
dragFilmstripHeight?: number,
/**
* Initial filmstrip width on drag handle mouse down.
*/
dragFilmstripWidth?: number|null,
/** /**
* Whether or not the mouse is pressed. * Whether or not the mouse is pressed.
*/ */
@ -244,17 +262,7 @@ type State = {
/** /**
* Initial mouse position on drag handle mouse down. * Initial mouse position on drag handle mouse down.
*/ */
mousePosition: ?number, mousePosition?: number|null
/**
* Initial filmstrip width on drag handle mouse down.
*/
dragFilmstripWidth: ?number,
/**
* Initial top panel height on drag handle mouse down.
*/
dragFilmstripHeight: ?number
} }
/** /**
@ -317,6 +325,7 @@ class Filmstrip extends PureComponent <Props, State> {
'keyboardShortcuts.toggleFilmstrip' 'keyboardShortcuts.toggleFilmstrip'
); );
document.addEventListener('mouseup', this._onDragMouseUp); document.addEventListener('mouseup', this._onDragMouseUp);
// @ts-ignore
document.addEventListener('mousemove', this._throttledResize); document.addEventListener('mousemove', this._throttledResize);
} }
@ -328,6 +337,7 @@ class Filmstrip extends PureComponent <Props, State> {
componentWillUnmount() { componentWillUnmount() {
APP.keyboardshortcut.unregisterShortcut('F'); APP.keyboardshortcut.unregisterShortcut('F');
document.removeEventListener('mouseup', this._onDragMouseUp); document.removeEventListener('mouseup', this._onDragMouseUp);
// @ts-ignore
document.removeEventListener('mousemove', this._throttledResize); document.removeEventListener('mousemove', this._throttledResize);
} }
@ -338,7 +348,7 @@ class Filmstrip extends PureComponent <Props, State> {
* @returns {ReactElement} * @returns {ReactElement}
*/ */
render() { render() {
const filmstripStyle = { }; const filmstripStyle: any = { };
const { const {
_currentLayout, _currentLayout,
_disableSelfView, _disableSelfView,
@ -466,15 +476,13 @@ class Filmstrip extends PureComponent <Props, State> {
); );
} }
_onDragHandleMouseDown: (MouseEvent) => void;
/** /**
* Handles mouse down on the drag handle. * Handles mouse down on the drag handle.
* *
* @param {MouseEvent} e - The mouse down event. * @param {MouseEvent} e - The mouse down event.
* @returns {void} * @returns {void}
*/ */
_onDragHandleMouseDown(e) { _onDragHandleMouseDown(e: React.MouseEvent) {
const { _topPanelFilmstrip, _topPanelHeight, _verticalFilmstripWidth } = this.props; const { _topPanelFilmstrip, _topPanelHeight, _verticalFilmstripWidth } = this.props;
this.setState({ this.setState({
@ -486,8 +494,6 @@ class Filmstrip extends PureComponent <Props, State> {
this.props.dispatch(setUserIsResizing(true)); this.props.dispatch(setUserIsResizing(true));
} }
_onDragMouseUp: () => void;
/** /**
* Drag handle mouse up handler. * Drag handle mouse up handler.
* *
@ -502,15 +508,13 @@ class Filmstrip extends PureComponent <Props, State> {
} }
} }
_onFilmstripResize: (MouseEvent) => void;
/** /**
* Handles drag handle mouse move. * Handles drag handle mouse move.
* *
* @param {MouseEvent} e - The mousemove event. * @param {MouseEvent} e - The mousemove event.
* @returns {void} * @returns {void}
*/ */
_onFilmstripResize(e) { _onFilmstripResize(e: React.MouseEvent) {
if (this.state.isMouseDown) { if (this.state.isMouseDown) {
const { const {
dispatch, dispatch,
@ -523,9 +527,9 @@ class Filmstrip extends PureComponent <Props, State> {
const { dragFilmstripWidth, dragFilmstripHeight, mousePosition } = this.state; const { dragFilmstripWidth, dragFilmstripHeight, mousePosition } = this.state;
if (_topPanelFilmstrip) { if (_topPanelFilmstrip) {
const diff = e.clientY - mousePosition; const diff = e.clientY - (mousePosition ?? 0);
const height = Math.max( const height = Math.max(
Math.min(dragFilmstripHeight + diff, _maxTopPanelHeight), Math.min((dragFilmstripHeight ?? 0) + diff, _maxTopPanelHeight),
TOP_FILMSTRIP_HEIGHT TOP_FILMSTRIP_HEIGHT
); );
@ -533,9 +537,9 @@ class Filmstrip extends PureComponent <Props, State> {
dispatch(setUserFilmstripHeight(height)); dispatch(setUserFilmstripHeight(height));
} }
} else { } else {
const diff = mousePosition - e.clientX; const diff = (mousePosition ?? 0) - e.clientX;
const width = Math.max( const width = Math.max(
Math.min(dragFilmstripWidth + diff, _maxFilmstripWidth), Math.min((dragFilmstripWidth ?? 0) + diff, _maxFilmstripWidth),
DEFAULT_FILMSTRIP_WIDTH DEFAULT_FILMSTRIP_WIDTH
); );
@ -553,7 +557,7 @@ class Filmstrip extends PureComponent <Props, State> {
* @param {number} stopIndex - The stop index. * @param {number} stopIndex - The stop index.
* @returns {Object} * @returns {Object}
*/ */
_calculateIndices(startIndex, stopIndex) { _calculateIndices(startIndex: number, stopIndex: number) {
const { _currentLayout, _iAmRecorder, _thumbnailsReordered, _disableSelfView } = this.props; const { _currentLayout, _iAmRecorder, _thumbnailsReordered, _disableSelfView } = this.props;
let start = startIndex; let start = startIndex;
let stop = stopIndex; let stop = stopIndex;
@ -573,8 +577,6 @@ class Filmstrip extends PureComponent <Props, State> {
}; };
} }
_onTabIn: () => void;
/** /**
* Toggle the toolbar visibility when tabbing into it. * Toggle the toolbar visibility when tabbing into it.
* *
@ -586,15 +588,13 @@ class Filmstrip extends PureComponent <Props, State> {
} }
} }
_listItemKey: number => string;
/** /**
* The key to be used for every ThumbnailWrapper element in stage view. * The key to be used for every ThumbnailWrapper element in stage view.
* *
* @param {number} index - The index of the ThumbnailWrapper instance. * @param {number} index - The index of the ThumbnailWrapper instance.
* @returns {string} - The key. * @returns {string} - The key.
*/ */
_listItemKey(index) { _listItemKey(index: number) {
const { _remoteParticipants, _remoteParticipantsLength } = this.props; const { _remoteParticipants, _remoteParticipantsLength } = this.props;
if (typeof index !== 'number' || _remoteParticipantsLength <= index) { if (typeof index !== 'number' || _remoteParticipantsLength <= index) {
@ -604,15 +604,13 @@ class Filmstrip extends PureComponent <Props, State> {
return _remoteParticipants[index]; return _remoteParticipants[index];
} }
_gridItemKey: Object => string;
/** /**
* The key to be used for every ThumbnailWrapper element in tile views. * The key to be used for every ThumbnailWrapper element in tile views.
* *
* @param {Object} data - An object with the indexes identifying the ThumbnailWrapper instance. * @param {Object} data - An object with the indexes identifying the ThumbnailWrapper instance.
* @returns {string} - The key. * @returns {string} - The key.
*/ */
_gridItemKey({ columnIndex, rowIndex }) { _gridItemKey({ columnIndex, rowIndex }: {columnIndex: number, rowIndex: number}) {
const { const {
_disableSelfView, _disableSelfView,
_columns, _columns,
@ -638,23 +636,20 @@ class Filmstrip extends PureComponent <Props, State> {
return _remoteParticipants[remoteIndex]; return _remoteParticipants[remoteIndex];
} }
_onListItemsRendered: Object => void;
/** /**
* Handles items rendered changes in stage view. * Handles items rendered changes in stage view.
* *
* @param {Object} data - Information about the rendered items. * @param {Object} data - Information about the rendered items.
* @returns {void} * @returns {void}
*/ */
_onListItemsRendered({ visibleStartIndex, visibleStopIndex }) { _onListItemsRendered({ visibleStartIndex, visibleStopIndex }
: { visibleStartIndex: number, visibleStopIndex: number }) {
const { dispatch } = this.props; const { dispatch } = this.props;
const { startIndex, stopIndex } = this._calculateIndices(visibleStartIndex, visibleStopIndex); const { startIndex, stopIndex } = this._calculateIndices(visibleStartIndex, visibleStopIndex);
dispatch(setVisibleRemoteParticipants(startIndex, stopIndex)); dispatch(setVisibleRemoteParticipants(startIndex, stopIndex));
} }
_onGridItemsRendered: Object => void;
/** /**
* Handles items rendered changes in tile view. * Handles items rendered changes in tile view.
* *
@ -666,6 +661,11 @@ class Filmstrip extends PureComponent <Props, State> {
visibleColumnStopIndex, visibleColumnStopIndex,
visibleRowStartIndex, visibleRowStartIndex,
visibleRowStopIndex visibleRowStopIndex
}: {
visibleColumnStartIndex: number,
visibleColumnStopIndex: number,
visibleRowStartIndex: number,
visibleRowStopIndex: number
}) { }) {
const { _columns, dispatch } = this.props; const { _columns, dispatch } = this.props;
const start = (visibleRowStartIndex * _columns) + visibleColumnStartIndex; const start = (visibleRowStartIndex * _columns) + visibleColumnStartIndex;
@ -713,6 +713,7 @@ class Filmstrip extends PureComponent <Props, State> {
initialScrollLeft = { 0 } initialScrollLeft = { 0 }
initialScrollTop = { 0 } initialScrollTop = { 0 }
itemData = {{ filmstripType }} itemData = {{ filmstripType }}
// @ts-ignore
itemKey = { this._gridItemKey } itemKey = { this._gridItemKey }
onItemsRendered = { this._onGridItemsRendered } onItemsRendered = { this._onGridItemsRendered }
overscanRowCount = { 1 } overscanRowCount = { 1 }
@ -727,7 +728,7 @@ class Filmstrip extends PureComponent <Props, State> {
} }
const props = { const props: any = {
itemCount: _remoteParticipantsLength, itemCount: _remoteParticipantsLength,
className: `filmstrip__videos remote-videos ${_resizableFilmstrip ? '' : 'height-transition'}`, className: `filmstrip__videos remote-videos ${_resizableFilmstrip ? '' : 'height-transition'}`,
height: _filmstripHeight, height: _filmstripHeight,
@ -746,8 +747,6 @@ class Filmstrip extends PureComponent <Props, State> {
const isNotOverflowing = !_hasScroll; const isNotOverflowing = !_hasScroll;
props.itemSize = itemSize; props.itemSize = itemSize;
// $FlowFixMe
props.layout = 'horizontal'; props.layout = 'horizontal';
if (isNotOverflowing) { if (isNotOverflowing) {
props.className += ' is-not-overflowing'; props.className += ' is-not-overflowing';
@ -787,8 +786,6 @@ class Filmstrip extends PureComponent <Props, State> {
: dispatch(setFilmstripVisible(!_mainFilmstripVisible)); : dispatch(setFilmstripVisible(!_mainFilmstripVisible));
} }
_onShortcutToggleFilmstrip: () => void;
/** /**
* Creates an analytics keyboard shortcut event and dispatches an action for * Creates an analytics keyboard shortcut event and dispatches an action for
* toggling filmstrip visibility. * toggling filmstrip visibility.
@ -806,8 +803,6 @@ class Filmstrip extends PureComponent <Props, State> {
this._doToggleFilmstrip(); this._doToggleFilmstrip();
} }
_onToolbarToggleFilmstrip: () => void;
/** /**
* Creates an analytics toolbar event and dispatches an action for opening * Creates an analytics toolbar event and dispatches an action for opening
* the speaker stats modal. * the speaker stats modal.
@ -825,8 +820,6 @@ class Filmstrip extends PureComponent <Props, State> {
this._doToggleFilmstrip(); this._doToggleFilmstrip();
} }
_onToggleButtonTouch: (SyntheticEvent<HTMLButtonElement>) => void;
/** /**
* Handler for touch start event of the 'toggle button'. * Handler for touch start event of the 'toggle button'.
* *
@ -834,7 +827,7 @@ class Filmstrip extends PureComponent <Props, State> {
* @param {Object} e - The synthetic event. * @param {Object} e - The synthetic event.
* @returns {void} * @returns {void}
*/ */
_onToggleButtonTouch(e: SyntheticEvent<HTMLButtonElement>) { _onToggleButtonTouch(e: React.TouchEvent) {
// Don't propagate the touchStart event so the toolbar doesn't get toggled. // Don't propagate the touchStart event so the toolbar doesn't get toggled.
e.stopPropagation(); e.stopPropagation();
this._onToolbarToggleFilmstrip(); this._onToolbarToggleFilmstrip();
@ -893,7 +886,7 @@ class Filmstrip extends PureComponent <Props, State> {
* @private * @private
* @returns {Props} * @returns {Props}
*/ */
function _mapStateToProps(state, ownProps) { function _mapStateToProps(state: any, ownProps: any) {
const { _hasScroll = false, filmstripType, _topPanelFilmstrip, _remoteParticipants } = ownProps; const { _hasScroll = false, filmstripType, _topPanelFilmstrip, _remoteParticipants } = ownProps;
const toolbarButtons = getToolbarButtons(state); const toolbarButtons = getToolbarButtons(state);
const { testing = {}, iAmRecorder } = state['features/base/config']; const { testing = {}, iAmRecorder } = state['features/base/config'];

View File

@ -1,12 +1,13 @@
/* @flow */
import { makeStyles } from '@material-ui/styles'; import { makeStyles } from '@material-ui/styles';
import React from 'react'; import React from 'react';
import { useSelector } from 'react-redux'; import { useSelector } from 'react-redux';
import { IconPinParticipant } from '../../../base/icons'; import { IState } from '../../../app/types';
import { getParticipantById } from '../../../base/participants'; import { IconPinParticipant } from '../../../base/icons/svg/index';
import { BaseIndicator } from '../../../base/react'; import { getParticipantById } from '../../../base/participants/functions';
import BaseIndicator from '../../../base/react/components/web/BaseIndicator';
// eslint-disable-next-line lines-around-comment
// @ts-ignore
import { getPinnedActiveParticipants, isStageFilmstripAvailable } from '../../functions.web'; import { getPinnedActiveParticipants, isStageFilmstripAvailable } from '../../functions.web';
/** /**
@ -55,8 +56,10 @@ const PinnedIndicator = ({
tooltipPosition tooltipPosition
}: Props) => { }: Props) => {
const stageFilmstrip = useSelector(isStageFilmstripAvailable); const stageFilmstrip = useSelector(isStageFilmstripAvailable);
const pinned = useSelector(state => getParticipantById(state, participantId))?.pinned; const pinned = useSelector((state: IState) => getParticipantById(state, participantId))?.pinned;
const isPinned = useSelector(getPinnedActiveParticipants).find(p => p.participantId === participantId); const activePinnedParticipants: Array<{participantId: string; pinned: boolean}>
= useSelector(getPinnedActiveParticipants);
const isPinned = activePinnedParticipants.find(p => p.participantId === participantId);
const styles = useStyles(); const styles = useStyles();
if ((stageFilmstrip && !isPinned) || (!stageFilmstrip && !pinned)) { if ((stageFilmstrip && !isPinned) || (!stageFilmstrip && !pinned)) {

View File

@ -1,13 +1,13 @@
/* @flow */
import { makeStyles } from '@material-ui/styles'; import { makeStyles } from '@material-ui/styles';
import React from 'react'; import React from 'react';
import { useSelector } from 'react-redux'; import { useSelector } from 'react-redux';
import { IconRaisedHand } from '../../../base/icons'; import { IState } from '../../../app/types';
import { getParticipantById, hasRaisedHand } from '../../../base/participants'; import { IconRaisedHand } from '../../../base/icons/svg/index';
import { BaseIndicator } from '../../../base/react'; import { getParticipantById, hasRaisedHand } from '../../../base/participants/functions';
import BaseTheme from '../../../base/ui/components/BaseTheme'; import { Participant } from '../../../base/participants/reducer';
import BaseIndicator from '../../../base/react/components/web/BaseIndicator';
import BaseTheme from '../../../base/ui/components/BaseTheme.web';
/** /**
* The type of the React {@code Component} props of {@link RaisedHandIndicator}. * The type of the React {@code Component} props of {@link RaisedHandIndicator}.
@ -31,7 +31,7 @@ type Props = {
tooltipPosition: string tooltipPosition: string
}; };
const useStyles = makeStyles(theme => { const useStyles = makeStyles((theme: any) => {
return { return {
raisedHandIndicator: { raisedHandIndicator: {
backgroundColor: theme.palette.warning02, backgroundColor: theme.palette.warning02,
@ -54,8 +54,9 @@ const RaisedHandIndicator = ({
participantId, participantId,
tooltipPosition tooltipPosition
}: Props) => { }: Props) => {
const _raisedHand = hasRaisedHand(useSelector(state => const participant: Participant|undefined = useSelector((state: IState) =>
getParticipantById(state, participantId))); getParticipantById(state, participantId));
const _raisedHand = hasRaisedHand(participant);
const styles = useStyles(); const styles = useStyles();
if (!_raisedHand) { if (!_raisedHand) {

View File

@ -67,7 +67,7 @@ type Props = {
/** /**
* Closes a drawer if open. * Closes a drawer if open.
*/ */
closeDrawer?: Function, closeDrawer?: () => void,
/** /**
* The participant for which the drawer is open. * The participant for which the drawer is open.
@ -91,17 +91,17 @@ type Props = {
/** /**
* Callback for the mouse entering the component. * Callback for the mouse entering the component.
*/ */
onEnter?: Function, onEnter?: (e?: React.MouseEvent) => void,
/** /**
* Callback for the mouse leaving the component. * Callback for the mouse leaving the component.
*/ */
onLeave?: Function, onLeave?: (e?: React.MouseEvent) => void,
/** /**
* Callback for making a selection in the menu. * Callback for making a selection in the menu.
*/ */
onSelect: Function, onSelect: (value?: boolean | React.MouseEvent) => void,
/** /**
* Participant reference. * Participant reference.
@ -157,7 +157,7 @@ const ParticipantContextMenu = ({
const _isVideoForceMuted = useSelector(state => const _isVideoForceMuted = useSelector(state =>
isForceMuted(participant, MEDIA_TYPE.VIDEO, state)); isForceMuted(participant, MEDIA_TYPE.VIDEO, state));
const _isAudioMuted = useSelector(state => isParticipantAudioMuted(participant, state)); const _isAudioMuted = useSelector(state => isParticipantAudioMuted(participant, state));
const _overflowDrawer = useSelector(showOverflowDrawer); const _overflowDrawer: boolean = useSelector(showOverflowDrawer);
const { remoteVideoMenu = {}, disableRemoteMute, startSilent } const { remoteVideoMenu = {}, disableRemoteMute, startSilent }
= useSelector((state: IState) => state['features/base/config']); = useSelector((state: IState) => state['features/base/config']);
const { disableKick, disableGrantModerator, disablePrivateChat } = remoteVideoMenu; const { disableKick, disableGrantModerator, disablePrivateChat } = remoteVideoMenu;
@ -315,7 +315,7 @@ const ParticipantContextMenu = ({
entity = { participant } entity = { participant }
hidden = { thumbnailMenu ? false : undefined } hidden = { thumbnailMenu ? false : undefined }
inDrawer = { thumbnailMenu && _overflowDrawer } inDrawer = { thumbnailMenu && _overflowDrawer }
isDrawerOpen = { drawerParticipant } isDrawerOpen = { Boolean(drawerParticipant) }
offsetTarget = { offsetTarget } offsetTarget = { offsetTarget }
onClick = { onSelect } onClick = { onSelect }
onDrawerClose = { thumbnailMenu ? onSelect : closeDrawer } onDrawerClose = { thumbnailMenu ? onSelect : closeDrawer }