diff --git a/react/features/base/label/components/AbstractLabel.js b/react/features/base/label/components/AbstractLabel.tsx similarity index 81% rename from react/features/base/label/components/AbstractLabel.js rename to react/features/base/label/components/AbstractLabel.tsx index 685343ec5..aa04a868f 100644 --- a/react/features/base/label/components/AbstractLabel.js +++ b/react/features/base/label/components/AbstractLabel.tsx @@ -1,5 +1,3 @@ -// @flow - import { Component } from 'react'; export type Props = { @@ -7,7 +5,7 @@ export type Props = { /** * An SVG icon to be rendered as the content of the label. */ - icon: Component, + icon: Function, /** * String or component that will be rendered as the label itself. @@ -18,6 +16,6 @@ export type Props = { /** * Abstract class for the {@code Label} component. */ -export default class Label +export default class Label

extends Component { } diff --git a/react/features/base/label/components/_.native.js b/react/features/base/label/components/_.native.js new file mode 100644 index 000000000..738c4d2b8 --- /dev/null +++ b/react/features/base/label/components/_.native.js @@ -0,0 +1 @@ +export * from './native'; diff --git a/react/features/base/label/components/_.web.js b/react/features/base/label/components/_.web.js new file mode 100644 index 000000000..b80c83af3 --- /dev/null +++ b/react/features/base/label/components/_.web.js @@ -0,0 +1 @@ +export * from './web'; diff --git a/react/features/base/label/components/index.js b/react/features/base/label/components/index.js index 387c352cb..cda61441e 100644 --- a/react/features/base/label/components/index.js +++ b/react/features/base/label/components/index.js @@ -1,2 +1 @@ -export { default as Label } from './Label'; -export { default as ExpandedLabel } from './ExpandedLabel'; +export * from './_'; diff --git a/react/features/base/label/components/ExpandedLabel.native.js b/react/features/base/label/components/native/ExpandedLabel.js similarity index 100% rename from react/features/base/label/components/ExpandedLabel.native.js rename to react/features/base/label/components/native/ExpandedLabel.js diff --git a/react/features/base/label/components/Label.native.js b/react/features/base/label/components/native/Label.js similarity index 96% rename from react/features/base/label/components/Label.native.js rename to react/features/base/label/components/native/Label.js index 5f0d66399..8a8916165 100644 --- a/react/features/base/label/components/Label.native.js +++ b/react/features/base/label/components/native/Label.js @@ -2,12 +2,12 @@ import React from 'react'; import { Animated, Text } from 'react-native'; -import Icon from '../../icons/components/Icon'; -import { combineStyles, type StyleType } from '../../styles'; - +import Icon from '../../../icons/components/Icon'; +import { combineStyles, type StyleType } from '../../../styles'; import AbstractLabel, { type Props as AbstractProps -} from './AbstractLabel'; +} from '../AbstractLabel'; + import styles from './styles'; /** diff --git a/react/features/base/label/components/native/index.js b/react/features/base/label/components/native/index.js new file mode 100644 index 000000000..387c352cb --- /dev/null +++ b/react/features/base/label/components/native/index.js @@ -0,0 +1,2 @@ +export { default as Label } from './Label'; +export { default as ExpandedLabel } from './ExpandedLabel'; diff --git a/react/features/base/label/components/styles.js b/react/features/base/label/components/native/styles.js similarity index 92% rename from react/features/base/label/components/styles.js rename to react/features/base/label/components/native/styles.js index 41bd79fd1..68fb4bff0 100644 --- a/react/features/base/label/components/styles.js +++ b/react/features/base/label/components/native/styles.js @@ -1,7 +1,7 @@ // @flow -import { ColorPalette } from '../../styles'; -import BaseTheme from '../../ui/components/BaseTheme'; +import { ColorPalette } from '../../../styles'; +import BaseTheme from '../../../ui/components/BaseTheme'; /** * The default color of the {@code Label} and {@code ExpandedLabel}. diff --git a/react/features/base/label/components/ExpandedLabel.web.js b/react/features/base/label/components/web/ExpandedLabel.js similarity index 100% rename from react/features/base/label/components/ExpandedLabel.web.js rename to react/features/base/label/components/web/ExpandedLabel.js diff --git a/react/features/base/label/components/Label.web.js b/react/features/base/label/components/web/Label.tsx similarity index 88% rename from react/features/base/label/components/Label.web.js rename to react/features/base/label/components/web/Label.tsx index 42cc5d6ea..a2f44b1eb 100644 --- a/react/features/base/label/components/Label.web.js +++ b/react/features/base/label/components/web/Label.tsx @@ -1,48 +1,46 @@ -// @flow import { withStyles } from '@material-ui/core/styles'; import clsx from 'clsx'; import React from 'react'; -import Icon from '../../icons/components/Icon'; -import { withPixelLineHeight } from '../../styles/functions.web'; -import { COLORS } from '../constants'; - +import Icon from '../../../icons/components/Icon'; +import { withPixelLineHeight } from '../../../styles/functions.web'; +import { COLORS } from '../../constants'; import AbstractLabel, { type Props as AbstractProps -} from './AbstractLabel'; +} from '../AbstractLabel'; type Props = AbstractProps & { - /** - * An object containing the CSS classes. - */ - classes: Object, - /** * Own CSS class name. */ className: string, + /** + * An object containing the CSS classes. + */ + classes: any, + /** * The color of the label. */ color: string, - /** - * HTML ID attribute to add to the root of {@code Label}. - */ - id: string, - /** * Color for the icon. */ iconColor?: string, + /** + * HTML ID attribute to add to the root of {@code Label}. + */ + id: string, + /** * Click handler if any. */ - onClick?: Function, + onClick?: (e?: React.MouseEvent) => void, }; @@ -53,7 +51,7 @@ type Props = AbstractProps & { * * @returns {Object} */ -const styles = theme => { +const styles = (theme: any) => { return { label: { ...withPixelLineHeight(theme.typography.labelRegular), @@ -96,7 +94,7 @@ const styles = theme => { * * @augments Component */ -class Label extends AbstractLabel { +class Label extends AbstractLabel { /** * Implements React's {@link Component#render()}. * diff --git a/react/features/base/label/components/web/index.js b/react/features/base/label/components/web/index.js new file mode 100644 index 000000000..387c352cb --- /dev/null +++ b/react/features/base/label/components/web/index.js @@ -0,0 +1,2 @@ +export { default as Label } from './Label'; +export { default as ExpandedLabel } from './ExpandedLabel'; diff --git a/react/features/base/label/constants.js b/react/features/base/label/constants.ts similarity index 89% rename from react/features/base/label/constants.js rename to react/features/base/label/constants.ts index 4eaf920a0..38623fa06 100644 --- a/react/features/base/label/constants.js +++ b/react/features/base/label/constants.ts @@ -1,5 +1,3 @@ -// @flow - export const COLORS = { white: 'white', green: 'green', diff --git a/react/features/base/participants/actions.ts b/react/features/base/participants/actions.ts index 95996a7e2..93b99839d 100644 --- a/react/features/base/participants/actions.ts +++ b/react/features/base/participants/actions.ts @@ -581,7 +581,7 @@ export function participantKicked(kicker: any, kicked: any) { * } * }} */ -export function pinParticipant(id: string) { +export function pinParticipant(id: string|null) { return { type: PIN_PARTICIPANT, participant: { diff --git a/react/features/base/participants/functions.ts b/react/features/base/participants/functions.ts index 4b15cef27..58cc3c662 100644 --- a/react/features/base/participants/functions.ts +++ b/react/features/base/participants/functions.ts @@ -224,7 +224,7 @@ export function getNormalizedDisplayName(name: string) { * @returns {(Participant|undefined)} */ export function getParticipantById( - stateful: IStore | Function, id: string): Participant|undefined { + stateful: IStore | Function | IState, id: string): Participant|undefined { const state = toState(stateful)['features/base/participants']; const { local, localScreenShare, remote } = state; diff --git a/react/features/base/ui/components/web/Button.tsx b/react/features/base/ui/components/web/Button.tsx index 91491b1b7..95654bae5 100644 --- a/react/features/base/ui/components/web/Button.tsx +++ b/react/features/base/ui/components/web/Button.tsx @@ -177,7 +177,7 @@ const useStyles = makeStyles((theme: Theme) => { }; }); -const Button = ({ +const Button = React.forwardRef(({ accessibilityLabel, className, disabled, @@ -191,7 +191,7 @@ const Button = ({ size = 'medium', testId, type = BUTTON_TYPES.PRIMARY -}: IButtonProps) => { +}: IButtonProps, ref) => { const styles = useStyles(); const { t } = useTranslation(); @@ -206,6 +206,7 @@ const Button = ({ disabled = { disabled } { ...(id ? { id } : {}) } onClick = { onClick } + ref = { ref } title = { accessibilityLabel } type = { isSubmit ? 'submit' : 'button' }> {icon && } ); -}; +}); export default Button; diff --git a/react/features/filmstrip/components/web/Thumbnail.js b/react/features/filmstrip/components/web/Thumbnail.tsx similarity index 95% rename from react/features/filmstrip/components/web/Thumbnail.js rename to react/features/filmstrip/components/web/Thumbnail.tsx index dcb4e1614..e429e0376 100644 --- a/react/features/filmstrip/components/web/Thumbnail.js +++ b/react/features/filmstrip/components/web/Thumbnail.tsx @@ -1,24 +1,29 @@ -// @flow - +/* eslint-disable lines-around-comment */ import { withStyles } from '@material-ui/styles'; import clsx from 'clsx'; import debounce from 'lodash/debounce'; import React, { Component } from 'react'; +// @ts-ignore import { createScreenSharingIssueEvent, sendAnalytics } from '../../../analytics'; +// @ts-ignore import { Avatar } from '../../../base/avatar'; +// @ts-ignore import { getMultipleVideoSupportFeatureFlag, getSourceNameSignalingFeatureFlag } from '../../../base/config'; import { isMobileBrowser } from '../../../base/environment/utils'; import { JitsiTrackEvents } from '../../../base/lib-jitsi-meet'; +// @ts-ignore import { MEDIA_TYPE, VideoTrack } from '../../../base/media'; +import { pinParticipant } from '../../../base/participants/actions'; import { getLocalParticipant, getParticipantByIdOrUndefined, - hasRaisedHand, - pinParticipant -} from '../../../base/participants'; -import { connect } from '../../../base/redux'; + hasRaisedHand +} from '../../../base/participants/functions'; +import { Participant } from '../../../base/participants/reducer'; +import { connect } from '../../../base/redux/functions'; import { ASPECT_RATIO_NARROW } from '../../../base/responsive-ui/constants'; +// @ts-ignore import { isTestModeEnabled } from '../../../base/testing'; import { getLocalAudioTrack, @@ -27,12 +32,19 @@ import { getVirtualScreenshareParticipantTrack, updateLastTrackVideoMediaEvent, trackStreamingStatusChanged + // @ts-ignore } from '../../../base/tracks'; +// @ts-ignore import { getVideoObjectPosition } from '../../../face-landmarks/functions'; +// @ts-ignore import { hideGif, showGif } from '../../../gifs/actions'; +// @ts-ignore import { getGifDisplayMode, getGifForParticipant } from '../../../gifs/functions'; +// @ts-ignore import { PresenceLabel } from '../../../presence-status'; +// @ts-ignore import { getCurrentLayout, LAYOUTS } from '../../../video-layout'; +// @ts-ignore import { togglePinStageParticipant } from '../../actions'; import { DISPLAY_MODE_TO_CLASS_NAME, @@ -50,20 +62,22 @@ import { isVideoPlayable, isStageFilmstripAvailable, showGridInVerticalView + // @ts-ignore } from '../../functions'; +// @ts-ignore import ThumbnailAudioIndicator from './ThumbnailAudioIndicator'; import ThumbnailBottomIndicators from './ThumbnailBottomIndicators'; import ThumbnailTopIndicators from './ThumbnailTopIndicators'; +// @ts-ignore import VirtualScreenshareParticipant from './VirtualScreenshareParticipant'; - -declare var interfaceConfig: Object; +declare let interfaceConfig: any; /** * The type of the React {@code Component} state of {@link Thumbnail}. */ -export type State = {| +export type State = { /** * Indicates that the canplay event has been received. @@ -75,26 +89,26 @@ export type State = {| */ displayMode: number, - /** - * Whether popover is visible or not. - */ - popoverVisible: boolean, - /** * Indicates whether the thumbnail is hovered or not. */ - isHovered: boolean -|}; + isHovered: boolean, + + /** + * Whether popover is visible or not. + */ + popoverVisible: boolean +}; /** * The type of the React {@code Component} props of {@link Thumbnail}. */ -export type Props = {| +export type Props = { /** * The audio track related to the participant. */ - _audioTrack: ?Object, + _audioTrack?: Object, /** * Indicates whether the local video flip feature is disabled or not. @@ -109,7 +123,7 @@ export type Props = {| /** * URL of GIF sent by this participant, null if there's none. */ - _gifSrc ?: string, + _gifSrc?: string, /** * The height of the Thumbnail. @@ -122,11 +136,6 @@ export type Props = {| */ _isActiveParticipant: boolean, - /** - * Indicates whether the thumbnail should be hidden or not. - */ - _isHidden: boolean, - /** * Indicates whether audio only mode is enabled. */ @@ -142,6 +151,11 @@ export type Props = {| */ _isDominantSpeakerDisabled: boolean, + /** + * Indicates whether the thumbnail should be hidden or not. + */ + _isHidden: boolean, + /** * Whether we are currently running in a mobile browser. */ @@ -181,7 +195,7 @@ export type Props = {| /** * An object with information about the participant related to the thumbnail. */ - _participant: Object, + _participant: Participant, /** * Whether or not the participant has the hand raised. @@ -218,7 +232,7 @@ export type Props = {| /** * The video track that will be displayed in the thumbnail. */ - _videoTrack: ?Object, + _videoTrack?: any, /** * The width of the thumbnail. @@ -228,7 +242,7 @@ export type Props = {| /** * An object containing CSS classes. */ - classes: Object, + classes: any, /** * The redux dispatch function. @@ -248,21 +262,21 @@ export type Props = {| /** * The ID of the participant related to the thumbnail. */ - participantID: ?string, + participantID?: string, /** * Styles that will be set to the Thumbnail's main span element. */ - style?: ?Object, + style?: any, - /** + /** * The width of the thumbnail. Used for expanding the width of the thumbnails on last row in case * there is empty space. */ width?: number -|}; +}; -const defaultStyles = theme => { +const defaultStyles = (theme: any) => { return { indicatorsContainer: { position: 'absolute', @@ -372,13 +386,13 @@ class Thumbnail extends Component { /** * The long touch setTimeout handler. */ - timeoutHandle: Object; + timeoutHandle?: number; /** * Timeout used to detect double tapping. * It is active while user has tapped once. */ - _firstTap: ?TimeoutID; + _firstTap?: number; /** * Initializes a new Thumbnail instance. @@ -400,7 +414,7 @@ class Thumbnail extends Component { ...state, displayMode: computeDisplayModeFromInput(getDisplayModeInput(props, state)) }; - this.timeoutHandle = null; + this.timeoutHandle = undefined; this._clearDoubleClickTimeout = this._clearDoubleClickTimeout.bind(this); this._onCanPlay = this._onCanPlay.bind(this); @@ -505,7 +519,7 @@ class Thumbnail extends Component { * @param {JitsiTrackStreamingStatus} streamingStatus - The updated track streaming status. * @returns {void} */ - handleTrackStreamingStatusChanged(jitsiTrack, streamingStatus) { + handleTrackStreamingStatusChanged(jitsiTrack: any, streamingStatus: any) { this.props.dispatch(trackStreamingStatusChanged(jitsiTrack, streamingStatus)); } @@ -526,7 +540,7 @@ class Thumbnail extends Component { * @param {Object} input - The input used to compute the thumbnail display mode. * @returns {void} */ - _maybeSendScreenSharingIssueEvents(input) { + _maybeSendScreenSharingIssueEvents(input: any) { const { _isAudioOnly, _isScreenSharing, @@ -576,8 +590,6 @@ class Thumbnail extends Component { return null; } - _clearDoubleClickTimeout: () => void; - /** * Clears the first click timeout. * @@ -588,8 +600,6 @@ class Thumbnail extends Component { this._firstTap = undefined; } - _showPopover: () => void; - /** * Shows popover. * @@ -602,8 +612,6 @@ class Thumbnail extends Component { }); } - _hidePopover: () => void; - /** * Hides popover. * @@ -628,7 +636,7 @@ class Thumbnail extends Component { * * @returns {Object} - The styles for the thumbnail. */ - _getStyles(): Object { + _getStyles(): any { const { canPlayEventReceived } = this.state; const { _disableTileEnlargement, @@ -652,7 +660,7 @@ class Thumbnail extends Component { let styles: { avatar: Object, - thumbnail: Object, + thumbnail: any, video: Object } = { thumbnail: {}, @@ -667,7 +675,7 @@ class Thumbnail extends Component { left += horizontalOffset; } - let videoStyles = null; + let videoStyles: any = null; const doNotStretchVideo = (isPortraitVideo && isTileType) || _disableTileEnlargement || _isScreenSharing; @@ -709,8 +717,6 @@ class Thumbnail extends Component { return styles; } - _onClick: () => void; - /** * On click handler. * @@ -727,8 +733,6 @@ class Thumbnail extends Component { } } - _onMouseEnter: () => void; - /** * Mouse enter handler. * @@ -752,8 +756,6 @@ class Thumbnail extends Component { } } - _onMouseLeave: () => void; - /** * Mouse leave handler. * @@ -763,15 +765,13 @@ class Thumbnail extends Component { this.setState({ isHovered: false }); } - _onTouchStart: () => void; - /** * Handler for touch start. * * @returns {void} */ _onTouchStart() { - this.timeoutHandle = setTimeout(this._showPopover, SHOW_TOOLBAR_CONTEXT_MENU_AFTER); + this.timeoutHandle = window.setTimeout(this._showPopover, SHOW_TOOLBAR_CONTEXT_MENU_AFTER); if (this._firstTap) { this._clearDoubleClickTimeout(); @@ -780,11 +780,9 @@ class Thumbnail extends Component { return; } - this._firstTap = setTimeout(this._clearDoubleClickTimeout, 300); + this._firstTap = window.setTimeout(this._clearDoubleClickTimeout, 300); } - _onTouchEnd: () => void; - /** * Cancel showing popover context menu after x miliseconds if the no. Of miliseconds is not reached yet, * or just clears the timeout. @@ -795,8 +793,6 @@ class Thumbnail extends Component { clearTimeout(this.timeoutHandle); } - _onTouchMove: () => void; - /** * Cancel showing Context menu after x miliseconds if the number of miliseconds is not reached * before a touch move(drag), or just clears the timeout. @@ -845,7 +841,7 @@ class Thumbnail extends Component { * @param {Object} styles - The styles that will be applied to the avatar. * @returns {ReactElement} */ - _renderAvatar(styles) { + _renderAvatar(styles: Object) { const { _participant } = this.props; const { id } = _participant; @@ -892,8 +888,6 @@ class Thumbnail extends Component { return className; } - _onGifMouseEnter: () => void; - /** * Keep showing the GIF for the current participant. * @@ -905,8 +899,6 @@ class Thumbnail extends Component { dispatch(showGif(id)); } - _onGifMouseLeave: () => void; - /** * Keep showing the GIF for the current participant. * @@ -935,15 +927,13 @@ class Thumbnail extends Component { ); } - _onCanPlay: Object => void; - /** * Canplay event listener. * * @param {SyntheticEvent} event - The event. * @returns {void} */ - _onCanPlay(event) { + _onCanPlay(event: any) { this.setState({ canPlayEventReceived: true }); const { @@ -956,15 +946,13 @@ class Thumbnail extends Component { } } - _onTestingEvent: Object => void; - /** * Event handler for testing events. * * @param {SyntheticEvent} event - The event. * @returns {void} */ - _onTestingEvent(event) { + _onTestingEvent(event: any) { const { _videoTrack, dispatch @@ -1004,7 +992,7 @@ class Thumbnail extends Component { = !_disableLocalVideoFlip && _videoTrack && !_isScreenSharing && _localFlipX ? 'flipVideoX' : ''; const jitsiVideoTrack = _videoTrack?.jitsiTrack; const videoTrackId = jitsiVideoTrack && jitsiVideoTrack.getId(); - const videoEventListeners = {}; + const videoEventListeners: any = {}; if (local) { if (_isMobilePortrait) { @@ -1168,7 +1156,7 @@ class Thumbnail extends Component { * @private * @returns {Props} */ -function _mapStateToProps(state, ownProps): Object { +function _mapStateToProps(state: any, ownProps: any): Object { const { participantID, filmstripType = FILMSTRIP_TYPE.MAIN } = ownProps; const participant = getParticipantByIdOrUndefined(state, participantID); @@ -1188,7 +1176,7 @@ function _mapStateToProps(state, ownProps): Object { const _audioTrack = isLocal ? getLocalAudioTrack(tracks) : getTrackByMediaTypeAndParticipant(tracks, MEDIA_TYPE.AUDIO, participantID); const _currentLayout = getCurrentLayout(state); - let size = {}; + let size: any = {}; let _isMobilePortrait = false; const { defaultLocalDisplayName, @@ -1287,7 +1275,7 @@ function _mapStateToProps(state, ownProps): Object { _defaultLocalDisplayName: defaultLocalDisplayName, _disableLocalVideoFlip: Boolean(disableLocalVideoFlip), _disableTileEnlargement: Boolean(disableTileEnlargement), - _isActiveParticipant: activeParticipants.find(pId => pId === participantId), + _isActiveParticipant: activeParticipants.find((pId: string) => pId === participantId), _isHidden: isLocal && iAmRecorder && !iAmSipGateway, _isAudioOnly: Boolean(state['features/base/audio-only'].enabled), _isCurrentlyOnLargeVideo: state['features/large-video']?.participantId === id, @@ -1313,4 +1301,5 @@ function _mapStateToProps(state, ownProps): Object { }; } +// @ts-ignore export default connect(_mapStateToProps)(withStyles(defaultStyles)(Thumbnail)); diff --git a/react/features/filmstrip/components/web/ThumbnailBottomIndicators.js b/react/features/filmstrip/components/web/ThumbnailBottomIndicators.tsx similarity index 95% rename from react/features/filmstrip/components/web/ThumbnailBottomIndicators.js rename to react/features/filmstrip/components/web/ThumbnailBottomIndicators.tsx index 23566d878..8415ef27a 100644 --- a/react/features/filmstrip/components/web/ThumbnailBottomIndicators.js +++ b/react/features/filmstrip/components/web/ThumbnailBottomIndicators.tsx @@ -1,5 +1,4 @@ -// @flow - +/* eslint-disable lines-around-comment */ import { makeStyles } from '@material-ui/styles'; import React from 'react'; import { useSelector } from 'react-redux'; @@ -8,13 +7,16 @@ import { getMultipleVideoSupportFeatureFlag, isDisplayNameVisible, isNameReadOnly + // @ts-ignore } from '../../../base/config/functions.any'; +// @ts-ignore import DisplayName from '../../../display-name/components/web/DisplayName'; import { THUMBNAIL_TYPE } from '../../constants'; +// @ts-ignore import StatusIndicators from './StatusIndicators'; -declare var interfaceConfig: Object; +declare let interfaceConfig: any; type Props = { @@ -41,7 +43,7 @@ type Props = { /** * Whether or not to show the status indicators. */ - showStatusIndicators: string, + showStatusIndicators?: boolean, /** * The type of thumbnail. diff --git a/react/features/filmstrip/components/web/ThumbnailTopIndicators.js b/react/features/filmstrip/components/web/ThumbnailTopIndicators.tsx similarity index 91% rename from react/features/filmstrip/components/web/ThumbnailTopIndicators.js rename to react/features/filmstrip/components/web/ThumbnailTopIndicators.tsx index 97784a66c..041e5a60b 100644 --- a/react/features/filmstrip/components/web/ThumbnailTopIndicators.js +++ b/react/features/filmstrip/components/web/ThumbnailTopIndicators.tsx @@ -1,22 +1,28 @@ -// @flow - +/* eslint-disable lines-around-comment */ import { makeStyles } from '@material-ui/styles'; import clsx from 'clsx'; import React from 'react'; import { useSelector } from 'react-redux'; +import { IState } from '../../../app/types'; +// @ts-ignore import { getMultipleVideoSupportFeatureFlag } from '../../../base/config'; import { isMobileBrowser } from '../../../base/environment/utils'; +// @ts-ignore import ConnectionIndicator from '../../../connection-indicator/components/web/ConnectionIndicator'; import { STATS_POPOVER_POSITION, THUMBNAIL_TYPE } from '../../constants'; +// @ts-ignore import { getIndicatorsTooltipPosition } from '../../functions.web'; +// @ts-ignore import PinnedIndicator from './PinnedIndicator'; +// @ts-ignore import RaisedHandIndicator from './RaisedHandIndicator'; +// @ts-ignore import StatusIndicators from './StatusIndicators'; import VideoMenuTriggerButton from './VideoMenuTriggerButton'; -declare var interfaceConfig: Object; +declare let interfaceConfig: any; type Props = { @@ -38,7 +44,7 @@ type Props = { /** * Whether or not the thumbnail is a virtual screen share participant. */ - isVirtualScreenshareParticipant: boolean, + isVirtualScreenshareParticipant?: boolean, /** * Whether or not the indicators are for the local participant. @@ -95,9 +101,9 @@ const ThumbnailTopIndicators = ({ const { NORMAL = 16 } = interfaceConfig.INDICATOR_FONT_SIZES || {}; const _indicatorIconSize = NORMAL; const _connectionIndicatorAutoHideEnabled = Boolean( - useSelector(state => state['features/base/config'].connectionIndicators?.autoHide) ?? true); + useSelector((state: IState) => state['features/base/config'].connectionIndicators?.autoHide) ?? true); const _connectionIndicatorDisabled = _isMobile - || Boolean(useSelector(state => state['features/base/config'].connectionIndicators?.disabled)); + || Boolean(useSelector((state: IState) => state['features/base/config'].connectionIndicators?.disabled)); const _isMultiStreamEnabled = useSelector(getMultipleVideoSupportFeatureFlag); const showConnectionIndicator = isHovered || !_connectionIndicatorAutoHideEnabled; diff --git a/react/features/filmstrip/constants.js b/react/features/filmstrip/constants.ts similarity index 99% rename from react/features/filmstrip/constants.js rename to react/features/filmstrip/constants.ts index c901fa7aa..cbe134765 100644 --- a/react/features/filmstrip/constants.js +++ b/react/features/filmstrip/constants.ts @@ -1,5 +1,4 @@ -// @flow - +// @ts-ignore import { BoxModel } from '../base/styles'; /** diff --git a/react/features/gifs/components/web/GifsMenu.js b/react/features/gifs/components/web/GifsMenu.tsx similarity index 83% rename from react/features/gifs/components/web/GifsMenu.js rename to react/features/gifs/components/web/GifsMenu.tsx index d2f8da7bd..108860d58 100644 --- a/react/features/gifs/components/web/GifsMenu.js +++ b/react/features/gifs/components/web/GifsMenu.tsx @@ -1,6 +1,5 @@ -// @flow - -import { GiphyFetch } from '@giphy/js-fetch-api'; +/* eslint-disable lines-around-comment */ +import { GiphyFetch, TrendingOptions } from '@giphy/js-fetch-api'; import { Grid } from '@giphy/react-components'; import { makeStyles } from '@material-ui/core'; import clsx from 'clsx'; @@ -8,21 +7,30 @@ import React, { useCallback, useEffect, useState } from 'react'; import { useTranslation } from 'react-i18next'; import { batch, useDispatch, useSelector } from 'react-redux'; +// @ts-ignore import { createGifSentEvent, sendAnalytics } from '../../../analytics'; +import { IState } from '../../../app/types'; +// @ts-ignore import InputField from '../../../base/premeeting/components/web/InputField'; -import BaseTheme from '../../../base/ui/components/BaseTheme'; +import BaseTheme from '../../../base/ui/components/BaseTheme.web'; +// @ts-ignore import { sendMessage } from '../../../chat/actions.any'; -import { SCROLL_SIZE } from '../../../filmstrip'; +import { SCROLL_SIZE } from '../../../filmstrip/constants'; import { toggleReactionsMenuVisibility } from '../../../reactions/actions.web'; +// @ts-ignore import { setOverflowMenuVisible } from '../../../toolbox/actions.web'; +// @ts-ignore import { Drawer, JitsiPortal } from '../../../toolbox/components/web'; +// @ts-ignore import { showOverflowDrawer } from '../../../toolbox/functions.web'; +// @ts-ignore import { setGifDrawerVisibility } from '../../actions'; +// @ts-ignore import { formatGifUrlMessage, getGifAPIKey, getGifUrl } from '../../functions'; const OVERFLOW_DRAWER_PADDING = BaseTheme.spacing(3); -const useStyles = makeStyles(theme => { +const useStyles = makeStyles((theme: any) => { return { gifsMenu: { width: '100%', @@ -87,17 +95,17 @@ const useStyles = makeStyles(theme => { * @returns {ReactElement} */ function GifsMenu() { - const API_KEY = useSelector(getGifAPIKey); + const API_KEY: string = useSelector(getGifAPIKey); const giphyFetch = new GiphyFetch(API_KEY); - const [ searchKey, setSearchKey ] = useState(); + const [ searchKey, setSearchKey ] = useState(); const styles = useStyles(); const dispatch = useDispatch(); const { t } = useTranslation(); - const overflowDrawer = useSelector(showOverflowDrawer); - const { clientWidth } = useSelector(state => state['features/base/responsive-ui']); + const overflowDrawer: boolean = useSelector(showOverflowDrawer); + const { clientWidth } = useSelector((state: IState) => state['features/base/responsive-ui']); const fetchGifs = useCallback(async (offset = 0) => { - const options = { + const options: TrendingOptions = { rating: 'pg-13', limit: 20, offset @@ -113,7 +121,7 @@ function GifsMenu() { const onDrawerClose = useCallback(() => { dispatch(setGifDrawerVisibility(false)); dispatch(setOverflowMenuVisible(false)); - }); + }, []); const handleGifClick = useCallback((gif, e) => { e?.stopPropagation(); @@ -135,26 +143,37 @@ function GifsMenu() { const handleSearchKeyChange = useCallback(value => { setSearchKey(value); - }); + }, []); const handleKeyDown = useCallback(e => { + if (!document.activeElement) { + return; + } if (e.keyCode === 38) { // up arrow e.preventDefault(); // if the first gif is focused move focus to the input if (document.activeElement.previousElementSibling === null) { - document.querySelector('.gif-input').focus(); + const element = document.querySelector('.gif-input') as HTMLElement; + + element?.focus(); } else { - document.activeElement.previousElementSibling.focus(); + const element = document.activeElement.previousElementSibling as HTMLElement; + + element?.focus(); } } else if (e.keyCode === 40) { // down arrow e.preventDefault(); // if the input is focused move focus to the first gif if (document.activeElement.classList.contains('gif-input')) { - document.querySelector('.giphy-gif').focus(); + const element = document.querySelector('.giphy-gif') as HTMLElement; + + element?.focus(); } else { - document.activeElement.nextElementSibling.focus(); + const element = document.activeElement.nextElementSibling as HTMLElement; + + element?.focus(); } } }, []); diff --git a/react/features/keyboard-shortcuts/components/KeyboardShortcutsDialog.native.js b/react/features/keyboard-shortcuts/components/KeyboardShortcutsDialog.native.js deleted file mode 100644 index e69de29bb..000000000 diff --git a/react/features/keyboard-shortcuts/components/_.native.js b/react/features/keyboard-shortcuts/components/_.native.js new file mode 100644 index 000000000..738c4d2b8 --- /dev/null +++ b/react/features/keyboard-shortcuts/components/_.native.js @@ -0,0 +1 @@ +export * from './native'; diff --git a/react/features/keyboard-shortcuts/components/_.web.js b/react/features/keyboard-shortcuts/components/_.web.js new file mode 100644 index 000000000..b80c83af3 --- /dev/null +++ b/react/features/keyboard-shortcuts/components/_.web.js @@ -0,0 +1 @@ +export * from './web'; diff --git a/react/features/keyboard-shortcuts/components/index.js b/react/features/keyboard-shortcuts/components/index.js index 25f84920e..cda61441e 100644 --- a/react/features/keyboard-shortcuts/components/index.js +++ b/react/features/keyboard-shortcuts/components/index.js @@ -1,2 +1 @@ -export { default as KeyboardShortcutsButton } from './KeyboardShortcutsButton'; -export { default as KeyboardShortcutsDialog } from './KeyboardShortcutsDialog'; +export * from './_'; diff --git a/react/features/keyboard-shortcuts/components/KeyboardShortcutsButton.native.js b/react/features/keyboard-shortcuts/components/native/index.js similarity index 100% rename from react/features/keyboard-shortcuts/components/KeyboardShortcutsButton.native.js rename to react/features/keyboard-shortcuts/components/native/index.js diff --git a/react/features/keyboard-shortcuts/components/KeyboardShortcutsButton.web.js b/react/features/keyboard-shortcuts/components/web/KeyboardShortcutsButton.js similarity index 75% rename from react/features/keyboard-shortcuts/components/KeyboardShortcutsButton.web.js rename to react/features/keyboard-shortcuts/components/web/KeyboardShortcutsButton.js index 2e9056748..9ba5c6847 100644 --- a/react/features/keyboard-shortcuts/components/KeyboardShortcutsButton.web.js +++ b/react/features/keyboard-shortcuts/components/web/KeyboardShortcutsButton.js @@ -1,11 +1,11 @@ // @flow -import { createToolbarEvent, sendAnalytics } from '../../analytics'; -import { translate } from '../../base/i18n'; -import { IconDeviceDocument } from '../../base/icons'; -import { connect } from '../../base/redux'; -import { AbstractButton, type AbstractButtonProps } from '../../base/toolbox/components'; -import { openKeyboardShortcutsDialog } from '../actions'; +import { createToolbarEvent, sendAnalytics } from '../../../analytics'; +import { translate } from '../../../base/i18n'; +import { IconDeviceDocument } from '../../../base/icons'; +import { connect } from '../../../base/redux'; +import { AbstractButton, type AbstractButtonProps } from '../../../base/toolbox/components'; +import { openKeyboardShortcutsDialog } from '../../actions'; /** * The type of the React {@code Component} props of {@link KeyboardShortcutsButton}. diff --git a/react/features/keyboard-shortcuts/components/KeyboardShortcutsDialog.web.js b/react/features/keyboard-shortcuts/components/web/KeyboardShortcutsDialog.tsx similarity index 88% rename from react/features/keyboard-shortcuts/components/KeyboardShortcutsDialog.web.js rename to react/features/keyboard-shortcuts/components/web/KeyboardShortcutsDialog.tsx index 66f9c14f0..e55d9f843 100644 --- a/react/features/keyboard-shortcuts/components/KeyboardShortcutsDialog.web.js +++ b/react/features/keyboard-shortcuts/components/web/KeyboardShortcutsDialog.tsx @@ -1,33 +1,28 @@ -/* @flow */ - import { withStyles } from '@material-ui/core/styles'; import clsx from 'clsx'; import React, { Component } from 'react'; +import { WithTranslation } from 'react-i18next'; -import { Dialog } from '../../base/dialog'; -import { translate } from '../../base/i18n'; +// @ts-ignore +import { Dialog } from '../../../base/dialog'; +import { translate } from '../../../base/i18n/functions'; /** * The type of the React {@code Component} props of * {@link KeyboardShortcutsDialog}. */ -type Props = { +interface Props extends WithTranslation { /** * An object containing the CSS classes. */ - classes: Object, + classes: any, /** * A Map with keyboard keys as keys and translation keys as values. */ - shortcutDescriptions: Object, - - /** - * Invoked to obtain translated strings. - */ - t: Function -}; + shortcutDescriptions: Map +} /** * Creates the styles for the component. @@ -36,7 +31,7 @@ type Props = { * * @returns {Object} */ -const styles = theme => { +const styles = (theme: any) => { return { list: { listStyleType: 'none', @@ -86,7 +81,7 @@ class KeyboardShortcutsDialog extends Component {

@@ -101,7 +96,7 @@ class KeyboardShortcutsDialog extends Component { * @private * @returns {ReactElement} */ - _renderShortcutsListItem(keyboardKey, translationKey) { + _renderShortcutsListItem(keyboardKey: string, translationKey: string) { let modifierKey = 'Alt'; if (window.navigator?.platform) { diff --git a/react/features/keyboard-shortcuts/components/web/index.js b/react/features/keyboard-shortcuts/components/web/index.js new file mode 100644 index 000000000..25f84920e --- /dev/null +++ b/react/features/keyboard-shortcuts/components/web/index.js @@ -0,0 +1,2 @@ +export { default as KeyboardShortcutsButton } from './KeyboardShortcutsButton'; +export { default as KeyboardShortcutsDialog } from './KeyboardShortcutsDialog'; diff --git a/react/features/notifications/components/web/NotificationsContainer.js b/react/features/notifications/components/web/NotificationsContainer.tsx similarity index 90% rename from react/features/notifications/components/web/NotificationsContainer.js rename to react/features/notifications/components/web/NotificationsContainer.tsx index 5ba956d82..5b3727c42 100644 --- a/react/features/notifications/components/web/NotificationsContainer.js +++ b/react/features/notifications/components/web/NotificationsContainer.tsx @@ -1,20 +1,23 @@ -// @flow - +/* eslint-disable lines-around-comment */ import { FlagGroupContext } from '@atlaskit/flag/flag-group'; import { AtlasKitThemeProvider } from '@atlaskit/theme'; import { withStyles } from '@material-ui/styles'; import clsx from 'clsx'; import React, { Component } from 'react'; +import { WithTranslation } from 'react-i18next'; import { CSSTransition, TransitionGroup } from 'react-transition-group'; -import { translate } from '../../../base/i18n'; -import { connect } from '../../../base/redux'; +import { translate } from '../../../base/i18n/functions'; +import { connect } from '../../../base/redux/functions'; +// @ts-ignore import { hideNotification } from '../../actions'; +// @ts-ignore import { areThereNotifications } from '../../functions'; +// @ts-ignore import Notification from './Notification'; -type Props = { +interface Props extends WithTranslation { /** * Whether we are a SIP gateway or not. @@ -30,12 +33,15 @@ type Props = { * The notifications to be displayed, with the first index being the * notification at the top and the rest shown below it in order. */ - _notifications: Array, + _notifications: Array<{ + props: Object; + uid: number; + }>, /** * JSS classes object. */ - classes: Object, + classes: any, /** * Invoked to update the redux store in order to remove notifications. @@ -45,15 +51,10 @@ type Props = { /** * Whether or not the notifications are displayed in a portal. */ - portal?: boolean, + portal?: boolean +} - /** - * Invoked to obtain translated strings. - */ - t: Function -}; - -const useStyles = theme => { +const useStyles = (theme: any) => { return { container: { position: 'absolute', @@ -124,7 +125,7 @@ const useStyles = theme => { */ class NotificationsContainer extends Component { _api: Object; - _timeouts: Map; + _timeouts: Map; /** * Initializes a new {@code NotificationsContainer} instance. @@ -161,6 +162,7 @@ class NotificationsContainer extends Component { return ( + {/* @ts-ignore */}
{ ); } - _onDismissed: number => void; - /** * Emits an action to remove the notification from the redux store so it * stops displaying. @@ -186,12 +186,12 @@ class NotificationsContainer extends Component { * @private * @returns {void} */ - _onDismissed(uid) { - const timeout = this._timeouts.get(uid); + _onDismissed(uid: number) { + const timeout = this._timeouts.get(`${uid}`); if (timeout) { clearTimeout(timeout); - this._timeouts.delete(uid); + this._timeouts.delete(`${uid}`); } this.props.dispatch(hideNotification(uid)); @@ -238,7 +238,7 @@ class NotificationsContainer extends Component { * @private * @returns {Props} */ -function _mapStateToProps(state) { +function _mapStateToProps(state: any) { const { notifications } = state['features/notifications']; const { iAmSipGateway } = state['features/base/config']; const { isOpen: isChatOpen } = state['features/chat']; @@ -251,4 +251,5 @@ function _mapStateToProps(state) { }; } +// @ts-ignore export default translate(connect(_mapStateToProps)(withStyles(useStyles)(NotificationsContainer))); diff --git a/react/features/participants-pane/components/breakout-rooms/components/web/CollapsibleRoom.js b/react/features/participants-pane/components/breakout-rooms/components/web/CollapsibleRoom.tsx similarity index 83% rename from react/features/participants-pane/components/breakout-rooms/components/web/CollapsibleRoom.js rename to react/features/participants-pane/components/breakout-rooms/components/web/CollapsibleRoom.tsx index 659248c4b..ac0ad6a58 100644 --- a/react/features/participants-pane/components/breakout-rooms/components/web/CollapsibleRoom.js +++ b/react/features/participants-pane/components/breakout-rooms/components/web/CollapsibleRoom.tsx @@ -1,18 +1,24 @@ -// @flow - +/* eslint-disable lines-around-comment */ import { makeStyles } from '@material-ui/styles'; import clsx from 'clsx'; -import React, { useCallback, useState } from 'react'; +import React, { ReactElement, useCallback, useState } from 'react'; import { useTranslation } from 'react-i18next'; import { useSelector } from 'react-redux'; +import { IState } from '../../../../../app/types'; +// @ts-ignore import { ListItem } from '../../../../../base/components'; -import { Icon, IconArrowDown, IconArrowUp } from '../../../../../base/icons'; -import { isLocalParticipantModerator } from '../../../../../base/participants'; +import Icon from '../../../../../base/icons/components/Icon'; +import { IconArrowDown, IconArrowUp } from '../../../../../base/icons/svg/index'; +import { isLocalParticipantModerator } from '../../../../../base/participants/functions'; +// @ts-ignore import { showOverflowDrawer } from '../../../../../toolbox/functions.web'; +// @ts-ignore import { ACTION_TRIGGER } from '../../../../constants'; +// @ts-ignore import { participantMatchesSearch } from '../../../../functions'; import ParticipantActionEllipsis from '../../../web/ParticipantActionEllipsis'; +// @ts-ignore import ParticipantItem from '../../../web/ParticipantItem'; type Props = { @@ -25,27 +31,29 @@ type Props = { /** * React children. */ - children: React$Node, + children: ReactElement, /** * Is this item highlighted/raised. */ isHighlighted?: boolean, - /** - * Callback to raise menu. Used to raise menu on mobile long press. - */ - onRaiseMenu: Function, - /** * Callback for when the mouse leaves this component. */ onLeave?: Function, + /** + * Callback to raise menu. Used to raise menu on mobile long press. + */ + onRaiseMenu: Function, + /** * The raise context for the participant menu. */ - participantContextEntity: ?Object, + participantContextEntity?: { + jid: string + }, /** * Callback to raise participant context menu. @@ -55,7 +63,16 @@ type Props = { /** * Room reference. */ - room: Object, + room: { + id: string; + name: string; + participants: { + [jid: string]: { + displayName: string; + jid: string; + } + }; + }, /** * Participants search string. @@ -68,7 +85,7 @@ type Props = { toggleParticipantMenu: Function } -const useStyles = makeStyles(theme => { +const useStyles = makeStyles((theme: any) => { return { container: { boxShadow: 'none' @@ -117,7 +134,7 @@ export const CollapsibleRoom = ({ const raiseMenu = useCallback(target => { onRaiseMenu(target); }, [ onRaiseMenu ]); - const { defaultRemoteDisplayName } = useSelector(state => state['features/base/config']); + const { defaultRemoteDisplayName } = useSelector((state: IState) => state['features/base/config']); const overflowDrawer = useSelector(showOverflowDrawer); const moderator = useSelector(isLocalParticipantModerator); @@ -153,7 +170,7 @@ export const CollapsibleRoom = ({ textChildren = { roomName } trigger = { actionsTrigger } /> {!collapsed && room?.participants - && Object.values(room?.participants || {}).map((p: Object) => + && Object.values(room?.participants || {}).map(p => participantMatchesSearch(p, searchString) && ( {!overflowDrawer && moderator && ( diff --git a/react/features/participants-pane/components/web/FooterContextMenu.js b/react/features/participants-pane/components/web/FooterContextMenu.tsx similarity index 94% rename from react/features/participants-pane/components/web/FooterContextMenu.js rename to react/features/participants-pane/components/web/FooterContextMenu.tsx index c1770e9b1..df14d45fe 100644 --- a/react/features/participants-pane/components/web/FooterContextMenu.js +++ b/react/features/participants-pane/components/web/FooterContextMenu.tsx @@ -1,5 +1,4 @@ -// @flow - +/* eslint-disable lines-around-comment */ import { makeStyles } from '@material-ui/core/styles'; import React, { useCallback } from 'react'; import { useTranslation } from 'react-i18next'; @@ -10,32 +9,39 @@ import { requestDisableVideoModeration, requestEnableAudioModeration, requestEnableVideoModeration + // @ts-ignore } from '../../../av-moderation/actions'; import { isEnabled as isAvModerationEnabled, isSupported as isAvModerationSupported + // @ts-ignore } from '../../../av-moderation/functions'; +// @ts-ignore import { ContextMenu, ContextMenuItemGroup } from '../../../base/components'; +// @ts-ignore import { openDialog } from '../../../base/dialog'; import { IconCheck, IconHorizontalPoints, IconVideoOff -} from '../../../base/icons'; -import { MEDIA_TYPE } from '../../../base/media'; +} from '../../../base/icons/svg'; +import { MEDIA_TYPE } from '../../../base/media/constants'; import { getParticipantCount, isEveryoneModerator -} from '../../../base/participants'; +} from '../../../base/participants/functions'; +// @ts-ignore import { isInBreakoutRoom } from '../../../breakout-rooms/functions'; import { SETTINGS_TABS, openSettingsDialog, shouldShowModeratorSettings + // @ts-ignore } from '../../../settings'; +// @ts-ignore import { MuteEveryonesVideoDialog } from '../../../video-menu/components'; -const useStyles = makeStyles(theme => { +const useStyles = makeStyles((theme: any) => { return { contextMenu: { bottom: 'auto', diff --git a/react/features/participants-pane/components/web/LobbyParticipantItem.js b/react/features/participants-pane/components/web/LobbyParticipantItem.tsx similarity index 90% rename from react/features/participants-pane/components/web/LobbyParticipantItem.js rename to react/features/participants-pane/components/web/LobbyParticipantItem.tsx index d9576ddcd..b732148f4 100644 --- a/react/features/participants-pane/components/web/LobbyParticipantItem.js +++ b/react/features/participants-pane/components/web/LobbyParticipantItem.tsx @@ -1,40 +1,45 @@ -// @flow - +/* eslint-disable lines-around-comment */ import { makeStyles } from '@material-ui/styles'; import React, { useCallback, useState, useRef } from 'react'; import { useTranslation } from 'react-i18next'; import { useSelector } from 'react-redux'; +// @ts-ignore import { ContextMenu, ContextMenuItemGroup } from '../../../base/components'; -import { IconChat, IconCloseCircle, IconHorizontalPoints } from '../../../base/icons'; -import { hasRaisedHand } from '../../../base/participants'; +import { IconChat, IconCloseCircle, IconHorizontalPoints } from '../../../base/icons/svg/index'; +import { hasRaisedHand } from '../../../base/participants/functions'; +import { Participant } from '../../../base/participants/reducer'; import Button from '../../../base/ui/components/web/Button'; import { BUTTON_TYPES } from '../../../base/ui/constants'; +// @ts-ignore import { showLobbyChatButton } from '../../../lobby/functions'; +// @ts-ignore import { ACTION_TRIGGER, MEDIA_STATE } from '../../constants'; +// @ts-ignore import { useLobbyActions } from '../../hooks'; +// @ts-ignore import ParticipantItem from './ParticipantItem'; type Props = { - /** - * If an overflow drawer should be displayed. - */ - overflowDrawer: boolean, - /** * Callback used to open a drawer with admit/reject actions. */ openDrawerForParticipant: Function, + /** + * If an overflow drawer should be displayed. + */ + overflowDrawer: boolean, + /** * Participant reference. */ - participant: Object + participant: Participant }; -const useStyles = makeStyles(theme => { +const useStyles = makeStyles((theme: any) => { return { button: { marginRight: `${theme.spacing(2)}px` @@ -67,8 +72,8 @@ export const LobbyParticipantItem = ({ const moreButtonRef = useRef(); - const openContextMenu = useCallback(() => setIsOpen(true)); - const closeContextMenu = useCallback(() => setIsOpen(false)); + const openContextMenu = useCallback(() => setIsOpen(true), []); + const closeContextMenu = useCallback(() => setIsOpen(false), []); const renderAdmitButton = () => (