Compare commits

...

1 Commits

Author SHA1 Message Date
robertpin 576d3ed8a7 ref(chat) Convert components to TS 2023-03-01 10:16:36 +02:00
15 changed files with 163 additions and 207 deletions

View File

@ -1,80 +1,76 @@
// @flow import React, { Component, ReactNode } from 'react';
import React, { Component } from 'react';
import { NOTIFY_CLICK_MODE } from '../../../toolbox/constants'; import { NOTIFY_CLICK_MODE } from '../../../toolbox/constants';
import { combineStyles } from '../../styles'; import { combineStyles } from '../../styles/functions.any';
import type { Styles } from './AbstractToolboxItem'; import type { Styles } from './AbstractToolboxItem';
import ToolboxItem from './ToolboxItem'; import ToolboxItem from './ToolboxItem';
export type Props = {| export type Props = {
/** /**
* Function to be called after the click handler has been processed. * Function to be called after the click handler has been processed.
*/ */
afterClick: ?Function, afterClick?: Function;
/** /**
* The button's key. * The button's key.
*/ */
buttonKey?: string, buttonKey?: string;
/** /**
* Whether or not the button is displayed in a context menu. * Whether or not the button is displayed in a context menu.
*/ */
contextMenu?: boolean, contextMenu?: boolean;
/** /**
* An extra class name to be added at the end of the element's class name * An extra class name to be added at the end of the element's class name
* in order to enable custom styling. * in order to enable custom styling.
*/ */
customClass?: string, customClass?: string;
/** /**
* Extra styles which will be applied in conjunction with `styles` or * Extra styles which will be applied in conjunction with `styles` or
* `toggledStyles` when the button is disabled;. * `toggledStyles` when the button is disabled;.
*/ */
disabledStyles: ?Styles, disabledStyles?: Styles;
/** /**
* External handler for click action. * External handler for click action.
*/ */
handleClick?: Function, handleClick?: Function;
/** /**
* Notify mode for `toolbarButtonClicked` event - * Notify mode for `toolbarButtonClicked` event -
* whether to only notify or to also prevent button click routine. * whether to only notify or to also prevent button click routine.
*/ */
notifyMode?: string, notifyMode?: string;
/** /**
* Whether to show the label or not. * Whether to show the label or not.
*/ */
showLabel: boolean, showLabel: boolean;
/** /**
* Collection of styles for the button. * Collection of styles for the button.
*/ */
styles: ?Styles, styles?: Styles;
/** /**
* Collection of styles for the button, when in toggled state. * Collection of styles for the button, when in toggled state.
*/ */
toggledStyles: ?Styles, toggledStyles?: Styles;
/** /**
* From which direction the tooltip should appear, relative to the button. * From which direction the tooltip should appear, relative to the button.
*/ */
tooltipPosition: string, tooltipPosition: string;
/** /**
* Whether this button is visible or not. * Whether this button is visible or not.
*/ */
visible: boolean visible: boolean;
|}; };
declare var APP: Object;
/** /**
* Default style for disabled buttons. * Default style for disabled buttons.
@ -93,7 +89,7 @@ export const defaultDisabledButtonStyles = {
/** /**
* An abstract implementation of a button. * An abstract implementation of a button.
*/ */
export default class AbstractButton<P: Props, S: *> extends Component<P, S> { export default class AbstractButton<P extends Props, S> extends Component<P, S> {
static defaultProps = { static defaultProps = {
afterClick: undefined, afterClick: undefined,
disabledStyles: defaultDisabledButtonStyles, disabledStyles: defaultDisabledButtonStyles,
@ -146,7 +142,9 @@ export default class AbstractButton<P: Props, S: *> extends Component<P, S> {
* *
* @abstract * @abstract
*/ */
tooltip: ?string; get tooltip(): string | undefined {
return undefined;
}
/** /**
* Initializes a new {@code AbstractButton} instance. * Initializes a new {@code AbstractButton} instance.
@ -229,7 +227,7 @@ export default class AbstractButton<P: Props, S: *> extends Component<P, S> {
* @private * @private
* @returns {?Styles} * @returns {?Styles}
*/ */
_getStyles(): ?Styles { _getStyles(): Styles | undefined {
const { disabledStyles, styles, toggledStyles } = this.props; const { disabledStyles, styles, toggledStyles } = this.props;
const buttonStyles const buttonStyles
= (this._isToggled() ? toggledStyles : styles) || styles; = (this._isToggled() ? toggledStyles : styles) || styles;
@ -280,11 +278,9 @@ export default class AbstractButton<P: Props, S: *> extends Component<P, S> {
* @returns {?boolean} * @returns {?boolean}
*/ */
_isToggled() { _isToggled() {
return undefined; return false;
} }
_onClick: (*) => void;
/** /**
* Handles clicking / pressing the button. * Handles clicking / pressing the button.
* *
@ -292,7 +288,7 @@ export default class AbstractButton<P: Props, S: *> extends Component<P, S> {
* @private * @private
* @returns {void} * @returns {void}
*/ */
_onClick(e) { _onClick(e: React.MouseEvent<HTMLElement>) {
const { afterClick, handleClick, notifyMode, buttonKey } = this.props; const { afterClick, handleClick, notifyMode, buttonKey } = this.props;
if (typeof APP !== 'undefined' && notifyMode) { if (typeof APP !== 'undefined' && notifyMode) {
@ -309,9 +305,10 @@ export default class AbstractButton<P: Props, S: *> extends Component<P, S> {
this._handleClick(); this._handleClick();
} }
afterClick && afterClick(e); afterClick?.(e);
// blur after click to release focus from button to allow PTT. // blur after click to release focus from button to allow PTT.
// @ts-ignore
e?.currentTarget?.blur && e.currentTarget.blur(); e?.currentTarget?.blur && e.currentTarget.blur();
} }
@ -321,7 +318,7 @@ export default class AbstractButton<P: Props, S: *> extends Component<P, S> {
* @inheritdoc * @inheritdoc
* @returns {React$Node} * @returns {React$Node}
*/ */
render(): React$Node { render(): ReactNode {
const props = { const props = {
...this.props, ...this.props,
accessibilityLabel: this.accessibilityLabel, accessibilityLabel: this.accessibilityLabel,
@ -337,6 +334,8 @@ export default class AbstractButton<P: Props, S: *> extends Component<P, S> {
return ( return (
<ToolboxItem <ToolboxItem
disabled = { this._isDisabled() } disabled = { this._isDisabled() }
// @ts-ignore
onClick = { this._onClick } onClick = { this._onClick }
onKeyDown = { this._onKeyDown } onKeyDown = { this._onKeyDown }
{ ...props } /> { ...props } />

View File

@ -1,30 +1,29 @@
// @flow import React, { Component, ReactNode } from 'react';
import { GestureResponderEvent } from 'react-native';
import { Component } from 'react'; import { StyleType } from '../../styles/functions.any';
import type { StyleType } from '../../styles';
export type Styles = { export type Styles = {
/** /**
* Style for the item's icon. * Style for the item's icon.
*/ */
iconStyle: StyleType, iconStyle: StyleType;
/** /**
* Style for the item's label. * Style for the item's label.
*/ */
labelStyle: StyleType, labelStyle: StyleType;
/** /**
* Style for the item itself. * Style for the item itself.
*/ */
style: StyleType, style: StyleType;
/** /**
* Color for the item underlay (shows when clicked). * Color for the item underlay (shows when clicked).
*/ */
underlayColor: ?string underlayColor?: string;
}; };
export type Props = { export type Props = {
@ -33,76 +32,78 @@ export type Props = {
* A succinct description of what the item does. Used by accessibility * A succinct description of what the item does. Used by accessibility
* tools and torture tests. * tools and torture tests.
*/ */
accessibilityLabel: string, accessibilityLabel: string;
/** /**
* An extra class name to be added at the end of the element's class name * An extra class name to be added at the end of the element's class name
* in order to enable custom styling. * in order to enable custom styling.
*/ */
customClass?: string, customClass?: string;
/** /**
* Whether this item is disabled or not. When disabled, clicking an the item * Whether this item is disabled or not. When disabled, clicking an the item
* has no effect, and it may reflect on its style. * has no effect, and it may reflect on its style.
*/ */
disabled: boolean, disabled: boolean;
/** /**
* A React Element to display at the end of {@code ToolboxItem}. * A React Element to display at the end of {@code ToolboxItem}.
*/ */
elementAfter?: React$Node, elementAfter?: ReactNode;
/** /**
* The icon to render for this {@code ToolboxItem}. * The icon to render for this {@code ToolboxItem}.
*/ */
icon: Object, icon: Function;
/** /**
* The text associated with this item. When `showLabel` is set to * The text associated with this item. When `showLabel` is set to
* {@code true}, it will be displayed alongside the icon. * {@code true}, it will be displayed alongside the icon.
*/ */
label: string, label: string;
labelProps: any;
/** /**
* On click handler. * On click handler.
*/ */
onClick: Function, onClick: (e?: React.MouseEvent | GestureResponderEvent) => void;
/** /**
* Whether to show the label or not. * Whether to show the label or not.
*/ */
showLabel: boolean, showLabel: boolean;
/** /**
* Collection of styles for the item. Used only on native. * Collection of styles for the item. Used only on native.
*/ */
styles: ?Styles, styles?: Styles;
/** /**
* Invoked to obtain translated strings. * Invoked to obtain translated strings.
*/ */
t: ?Function, t?: Function;
/** /**
* True if the item is toggled, false otherwise. * True if the item is toggled, false otherwise.
*/ */
toggled: ?boolean, toggled?: boolean;
/** /**
* The text to display in the tooltip. Used only on web. * The text to display in the tooltip. Used only on web.
*/ */
tooltip: ?string, tooltip?: string;
/** /**
* From which direction the tooltip should appear, relative to the * From which direction the tooltip should appear, relative to the
* item. Used only on web. * item. Used only on web.
*/ */
tooltipPosition: string, tooltipPosition: string;
/** /**
* Whether this item is visible or not. * Whether this item is visible or not.
*/ */
visible: boolean visible: boolean;
}; };
/** /**
@ -111,7 +112,7 @@ export type Props = {
* *
* @abstract * @abstract
*/ */
export default class AbstractToolboxItem<P : Props> extends Component<P> { export default class AbstractToolboxItem<P extends Props> extends Component<P> {
/** /**
* Default values for {@code AbstractToolboxItem} component's properties. * Default values for {@code AbstractToolboxItem} component's properties.
* *
@ -147,7 +148,7 @@ export default class AbstractToolboxItem<P : Props> extends Component<P> {
* @protected * @protected
* @returns {?string} * @returns {?string}
*/ */
get label(): ?string { get label(): string | undefined {
return this._maybeTranslateAttribute(this.props.label, this.props.labelProps); return this._maybeTranslateAttribute(this.props.label, this.props.labelProps);
} }
@ -158,7 +159,7 @@ export default class AbstractToolboxItem<P : Props> extends Component<P> {
* @protected * @protected
* @returns {?string} * @returns {?string}
*/ */
get tooltip(): ?string { get tooltip(): string | undefined {
return this._maybeTranslateAttribute(this.props.tooltip); return this._maybeTranslateAttribute(this.props.tooltip);
} }
@ -169,7 +170,7 @@ export default class AbstractToolboxItem<P : Props> extends Component<P> {
* @protected * @protected
* @returns {?string} * @returns {?string}
*/ */
get accessibilityLabel(): ?string { get accessibilityLabel(): string | undefined {
return this._maybeTranslateAttribute(this.props.accessibilityLabel); return this._maybeTranslateAttribute(this.props.accessibilityLabel);
} }
@ -182,7 +183,7 @@ export default class AbstractToolboxItem<P : Props> extends Component<P> {
* @private * @private
* @returns {string} * @returns {string}
*/ */
_maybeTranslateAttribute(text, textProps) { _maybeTranslateAttribute(text?: string, textProps?: string) {
const { t } = this.props; const { t } = this.props;
if (textProps) { if (textProps) {
@ -193,8 +194,6 @@ export default class AbstractToolboxItem<P : Props> extends Component<P> {
return typeof t === 'function' ? t(text) : text; return typeof t === 'function' ? t(text) : text;
} }
_onClick: (*) => void;
/** /**
* Handles clicking/pressing this {@code AbstractToolboxItem} by * Handles clicking/pressing this {@code AbstractToolboxItem} by
* forwarding the event to the {@code onClick} prop of this instance if any. * forwarding the event to the {@code onClick} prop of this instance if any.
@ -202,10 +201,10 @@ export default class AbstractToolboxItem<P : Props> extends Component<P> {
* @protected * @protected
* @returns {void} * @returns {void}
*/ */
_onClick(...args) { _onClick(...args: any) {
const { disabled, onClick } = this.props; const { disabled, onClick } = this.props;
disabled || (onClick && onClick(...args)); disabled || onClick?.(...args);
} }
/** /**
@ -218,7 +217,7 @@ export default class AbstractToolboxItem<P : Props> extends Component<P> {
*/ */
_renderItem() { _renderItem() {
// To be implemented by a subclass. // To be implemented by a subclass.
return null; return <></>;
} }
/** /**

View File

@ -1,12 +1,9 @@
// @flow
import React from 'react'; import React from 'react';
import { Text, TouchableHighlight, View } from 'react-native'; import { Text, TouchableHighlight, View } from 'react-native';
import { Icon } from '../../icons'; import Icon from '../../icons/components/Icon';
import AbstractToolboxItem from './AbstractToolboxItem'; import AbstractToolboxItem, { Props } from './AbstractToolboxItem';
import type { Props } from './AbstractToolboxItem';
/** /**
* Native implementation of {@code AbstractToolboxItem}. * Native implementation of {@code AbstractToolboxItem}.
@ -24,7 +21,7 @@ export default class ToolboxItem extends AbstractToolboxItem<Props> {
return ( return (
<Icon <Icon
src = { this.props.icon } src = { this.props.icon }
style = { styles && styles.iconStyle } /> style = { styles?.iconStyle } />
); );
} }
@ -49,7 +46,7 @@ export default class ToolboxItem extends AbstractToolboxItem<Props> {
// XXX When using a wrapper View, apply the style to it instead of // XXX When using a wrapper View, apply the style to it instead of
// applying it to the TouchableHighlight. // applying it to the TouchableHighlight.
let style = styles && styles.style; let style = styles?.style;
if (showLabel) { if (showLabel) {
// XXX TouchableHighlight requires 1 child. If there's a need to // XXX TouchableHighlight requires 1 child. If there's a need to
@ -58,7 +55,7 @@ export default class ToolboxItem extends AbstractToolboxItem<Props> {
children = ( children = (
<View style = { style }> <View style = { style }>
{ children } { children }
<Text style = { styles && styles.labelStyle }> <Text style = { styles?.labelStyle }>
{ this.label } { this.label }
</Text> </Text>
{ elementAfter } { elementAfter }
@ -78,7 +75,7 @@ export default class ToolboxItem extends AbstractToolboxItem<Props> {
disabled = { disabled } disabled = { disabled }
onPress = { onClick } onPress = { onClick }
style = { style } style = { style }
underlayColor = { styles && styles.underlayColor } > underlayColor = { styles?.underlayColor } >
{ children } { children }
</TouchableHighlight> </TouchableHighlight>
); );

View File

@ -1,8 +1,8 @@
// @flow
import React, { Fragment } from 'react'; import React, { Fragment } from 'react';
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';
import ContextMenuItem from '../../ui/components/web/ContextMenuItem'; import ContextMenuItem from '../../ui/components/web/ContextMenuItem';
@ -14,12 +14,12 @@ type Props = AbstractToolboxItemProps & {
/** /**
* Whether or not the item is displayed in a context menu. * Whether or not the item is displayed in a context menu.
*/ */
contextMenu?: boolean, contextMenu?: boolean;
/** /**
* On key down handler. * On key down handler.
*/ */
onKeyDown: Function onKeyDown: (e?: React.KeyboardEvent) => void;
}; };
/** /**
@ -37,8 +37,6 @@ export default class ToolboxItem extends AbstractToolboxItem<Props> {
this._onKeyPress = this._onKeyPress.bind(this); this._onKeyPress = this._onKeyPress.bind(this);
} }
_onKeyPress: (Object) => void;
/** /**
* Handles 'Enter' and Space key on the button to trigger onClick for accessibility. * Handles 'Enter' and Space key on the button to trigger onClick for accessibility.
* *
@ -46,9 +44,9 @@ export default class ToolboxItem extends AbstractToolboxItem<Props> {
* @private * @private
* @returns {void} * @returns {void}
*/ */
_onKeyPress(event) { _onKeyPress(event?: React.KeyboardEvent) {
if (event.key === 'Enter' || event.key === ' ') { if (event?.key === 'Enter' || event?.key === ' ') {
event.preventDefault(); event?.preventDefault();
this.props.onClick(); this.props.onClick();
} }
} }
@ -92,13 +90,13 @@ export default class ToolboxItem extends AbstractToolboxItem<Props> {
if (contextMenu) { if (contextMenu) {
return (<ContextMenuItem return (<ContextMenuItem
accessibilityLabel = { this.accessibilityLabel } accessibilityLabel = { this.accessibilityLabel ?? '' }
disabled = { disabled } disabled = { disabled }
icon = { icon } icon = { icon }
onClick = { onClick } onClick = { onClick }
onKeyDown = { onKeyDown } onKeyDown = { onKeyDown }
onKeyPress = { this._onKeyPress } onKeyPress = { this._onKeyPress }
text = { this.label } />); text = { this.label ?? '' } />);
} }
let children = ( let children = (
<Fragment> <Fragment>

View File

@ -1,103 +1,98 @@
// @flow
import { Component } from 'react'; import { Component } from 'react';
import type { Dispatch } from 'redux'; import { WithTranslation } from 'react-i18next';
import { getLocalParticipant } from '../../base/participants'; import { IReduxState, IStore } from '../../app/types';
import { getLocalParticipant } from '../../base/participants/functions';
import { sendMessage, setIsPollsTabFocused } from '../actions'; import { sendMessage, setIsPollsTabFocused } from '../actions';
import { SMALL_WIDTH_THRESHOLD } from '../constants'; import { SMALL_WIDTH_THRESHOLD } from '../constants';
import { IMessage } from '../reducer';
/** /**
* The type of the React {@code Component} props of {@code AbstractChat}. * The type of the React {@code Component} props of {@code AbstractChat}.
*/ */
export type Props = { export interface IProps extends WithTranslation {
/** /**
* Whether the chat is opened in a modal or not (computed based on window width). * Whether the chat is opened in a modal or not (computed based on window width).
*/ */
_isModal: boolean, _isModal: boolean;
/** /**
* True if the chat window should be rendered. * True if the chat window should be rendered.
*/ */
_isOpen: boolean, _isOpen: boolean;
/** /**
* True if the polls feature is enabled. * True if the polls feature is enabled.
*/ */
_isPollsEnabled: boolean, _isPollsEnabled: boolean;
/** /**
* Whether the poll tab is focused or not. * Whether the poll tab is focused or not.
*/ */
_isPollsTabFocused: boolean, _isPollsTabFocused: boolean;
/** /**
* All the chat messages in the conference. * All the chat messages in the conference.
*/ */
_messages: Array<Object>, _messages: Array<IMessage>;
/** /**
* Number of unread chat messages. * Number of unread chat messages.
*/ */
_nbUnreadMessages: number, _nbUnreadMessages: number;
/** /**
* Number of unread poll messages. * Number of unread poll messages.
*/ */
_nbUnreadPolls: number, _nbUnreadPolls: number;
/** /**
* Function to send a text message. * Function to send a text message.
* *
* @protected * @protected
*/ */
_onSendMessage: Function, _onSendMessage: Function;
/**
* Function to toggle the chat window.
*/
_onToggleChat: Function;
/** /**
* Function to display the chat tab. * Function to display the chat tab.
* *
* @protected * @protected
*/ */
_onToggleChatTab: Function, _onToggleChatTab: Function;
/** /**
* Function to display the polls tab. * Function to display the polls tab.
* *
* @protected * @protected
*/ */
_onTogglePollsTab: Function, _onTogglePollsTab: Function;
/**
* Function to toggle the chat window.
*/
_onToggleChat: Function,
/** /**
* Whether or not to block chat access with a nickname input form. * Whether or not to block chat access with a nickname input form.
*/ */
_showNamePrompt: boolean, _showNamePrompt: boolean;
/** /**
* The Redux dispatch function. * The Redux dispatch function.
*/ */
dispatch: Dispatch<any>, dispatch: IStore['dispatch'];
}
/**
* Function to be used to translate i18n labels.
*/
t: Function,
};
/** /**
* Implements an abstract chat panel. * Implements an abstract chat panel.
*/ */
export default class AbstractChat<P: Props> extends Component<P> { export default class AbstractChat<P extends IProps> extends Component<P> {
/** /**
* Initializes a new {@code AbstractChat} instance. * Initializes a new {@code AbstractChat} instance.
* *
* @param {Props} props - The React {@code Component} props to initialize * @param {IProps} props - The React {@code Component} props to initialize
* the new {@code AbstractChat} instance with. * the new {@code AbstractChat} instance with.
*/ */
constructor(props: P) { constructor(props: P) {
@ -109,8 +104,6 @@ export default class AbstractChat<P: Props> extends Component<P> {
this._onTogglePollsTab = this._onTogglePollsTab.bind(this); this._onTogglePollsTab = this._onTogglePollsTab.bind(this);
} }
_onSendMessage: (string) => void;
/** /**
* Sends a text message. * Sends a text message.
* *
@ -123,8 +116,6 @@ export default class AbstractChat<P: Props> extends Component<P> {
this.props.dispatch(sendMessage(text)); this.props.dispatch(sendMessage(text));
} }
_onToggleChatTab: () => void;
/** /**
* Display the Chat tab. * Display the Chat tab.
* *
@ -135,8 +126,6 @@ export default class AbstractChat<P: Props> extends Component<P> {
this.props.dispatch(setIsPollsTabFocused(false)); this.props.dispatch(setIsPollsTabFocused(false));
} }
_onTogglePollsTab: () => void;
/** /**
* Display the Polls tab. * Display the Polls tab.
* *
@ -160,7 +149,7 @@ export default class AbstractChat<P: Props> extends Component<P> {
* _showNamePrompt: boolean * _showNamePrompt: boolean
* }} * }}
*/ */
export function _mapStateToProps(state: Object) { export function _mapStateToProps(state: IReduxState) {
const { isOpen, isPollsTabFocused, messages, nbUnreadMessages } = state['features/chat']; const { isOpen, isPollsTabFocused, messages, nbUnreadMessages } = state['features/chat'];
const { nbUnreadPolls } = state['features/polls']; const { nbUnreadPolls } = state['features/polls'];
const _localParticipant = getLocalParticipant(state); const _localParticipant = getLocalParticipant(state);

View File

@ -9,7 +9,7 @@ import { connect } from '../../../base/redux';
import { TabBarLabelCounter } from '../../../mobile/navigation/components/TabBarLabelCounter'; import { TabBarLabelCounter } from '../../../mobile/navigation/components/TabBarLabelCounter';
import { closeChat } from '../../actions.native'; import { closeChat } from '../../actions.native';
import AbstractChat, { import AbstractChat, {
type Props as AbstractProps, type IProps as AbstractProps,
_mapStateToProps _mapStateToProps
} from '../AbstractChat'; } from '../AbstractChat';

View File

@ -1,14 +1,14 @@
import clsx from 'clsx'; import clsx from 'clsx';
import React from 'react'; import React, { KeyboardEvent } from 'react';
import { connect } from 'react-redux';
import { translate } from '../../../base/i18n'; import { translate } from '../../../base/i18n/functions';
import { connect } from '../../../base/redux';
import Tabs from '../../../base/ui/components/web/Tabs'; import Tabs from '../../../base/ui/components/web/Tabs';
import { PollsPane } from '../../../polls/components'; import PollsPane from '../../../polls/components/web/PollsPane';
import { toggleChat } from '../../actions.web'; import { toggleChat } from '../../actions.web';
import { CHAT_TABS } from '../../constants'; import { CHAT_TABS } from '../../constants';
import AbstractChat, { import AbstractChat, {
type Props, IProps,
_mapStateToProps _mapStateToProps
} from '../AbstractChat'; } from '../AbstractChat';
@ -19,11 +19,12 @@ import KeyboardAvoider from './KeyboardAvoider';
import MessageContainer from './MessageContainer'; import MessageContainer from './MessageContainer';
import MessageRecipient from './MessageRecipient'; import MessageRecipient from './MessageRecipient';
/** /**
* React Component for holding the chat feature in a side panel that slides in * React Component for holding the chat feature in a side panel that slides in
* and out of view. * and out of view.
*/ */
class Chat extends AbstractChat<Props> { class Chat extends AbstractChat<IProps> {
/** /**
* Reference to the React Component for displaying chat messages. Used for * Reference to the React Component for displaying chat messages. Used for
@ -37,7 +38,7 @@ class Chat extends AbstractChat<Props> {
* @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: Props) { constructor(props: IProps) {
super(props); super(props);
this._messageContainerRef = React.createRef(); this._messageContainerRef = React.createRef();
@ -67,8 +68,7 @@ class Chat extends AbstractChat<Props> {
<ChatHeader <ChatHeader
className = 'chat-header' className = 'chat-header'
id = 'chat-header' id = 'chat-header'
isPollsEnabled = { _isPollsEnabled } isPollsEnabled = { _isPollsEnabled } />
onCancel = { this._onToggleChat } />
{ _showNamePrompt { _showNamePrompt
? <DisplayNameForm isPollsEnabled = { _isPollsEnabled } /> ? <DisplayNameForm isPollsEnabled = { _isPollsEnabled } />
: this._renderChat() } : this._renderChat() }
@ -76,15 +76,13 @@ class Chat extends AbstractChat<Props> {
); );
} }
_onChatTabKeyDown: (KeyboardEvent) => void;
/** /**
* Key press handler for the chat tab. * Key press handler for the chat tab.
* *
* @param {KeyboardEvent} event - The event. * @param {KeyboardEvent} event - The event.
* @returns {void} * @returns {void}
*/ */
_onChatTabKeyDown(event) { _onChatTabKeyDown(event: KeyboardEvent) {
if (event.key === 'Enter' || event.key === ' ') { if (event.key === 'Enter' || event.key === ' ') {
event.preventDefault(); event.preventDefault();
event.stopPropagation(); event.stopPropagation();
@ -92,15 +90,13 @@ class Chat extends AbstractChat<Props> {
} }
} }
_onEscClick: (KeyboardEvent) => void;
/** /**
* Click handler for the chat sidenav. * Click handler for the chat sidenav.
* *
* @param {KeyboardEvent} event - Esc key click to close the popup. * @param {KeyboardEvent} event - Esc key click to close the popup.
* @returns {void} * @returns {void}
*/ */
_onEscClick(event) { _onEscClick(event: KeyboardEvent) {
if (event.key === 'Escape' && this.props._isOpen) { if (event.key === 'Escape' && this.props._isOpen) {
event.preventDefault(); event.preventDefault();
event.stopPropagation(); event.stopPropagation();
@ -108,15 +104,13 @@ class Chat extends AbstractChat<Props> {
} }
} }
_onPollsTabKeyDown: (KeyboardEvent) => void;
/** /**
* Key press handler for the polls tab. * Key press handler for the polls tab.
* *
* @param {KeyboardEvent} event - The event. * @param {KeyboardEvent} event - The event.
* @returns {void} * @returns {void}
*/ */
_onPollsTabKeyDown(event) { _onPollsTabKeyDown(event: KeyboardEvent) {
if (event.key === 'Enter' || event.key === ' ') { if (event.key === 'Enter' || event.key === ' ') {
event.preventDefault(); event.preventDefault();
event.stopPropagation(); event.stopPropagation();
@ -196,10 +190,6 @@ class Chat extends AbstractChat<Props> {
); );
} }
_onSendMessage: (string) => void;
_onToggleChat: () => void;
/** /**
* Toggles the chat window. * Toggles the chat window.
* *
@ -208,9 +198,6 @@ class Chat extends AbstractChat<Props> {
_onToggleChat() { _onToggleChat() {
this.props.dispatch(toggleChat()); this.props.dispatch(toggleChat());
} }
_onTogglePollsTab: () => void;
_onToggleChatTab: () => void;
_onChangeTab: (string) => void;
/** /**
* Change selected tab. * Change selected tab.
@ -218,7 +205,7 @@ class Chat extends AbstractChat<Props> {
* @param {string} id - Id of the clicked tab. * @param {string} id - Id of the clicked tab.
* @returns {void} * @returns {void}
*/ */
_onChangeTab(id) { _onChangeTab(id: string) {
id === CHAT_TABS.CHAT ? this._onToggleChatTab() : this._onTogglePollsTab(); id === CHAT_TABS.CHAT ? this._onToggleChatTab() : this._onTogglePollsTab();
} }
} }

View File

@ -1,29 +1,29 @@
// @flow import React, { ReactNode } from 'react';
import { WithTranslation } from 'react-i18next';
import { connect } from 'react-redux';
import React from 'react'; import { IReduxState } from '../../../app/types';
import { translate } from '../../../base/i18n/functions';
import { translate } from '../../../base/i18n'; import { IconMessage } from '../../../base/icons/svg';
import { IconMessage } from '../../../base/icons'; import AbstractButton, { Props as AbstractButtonProps } from '../../../base/toolbox/components/AbstractButton';
import { connect } from '../../../base/redux';
import { AbstractButton, type AbstractButtonProps } from '../../../base/toolbox/components';
import ChatCounter from './ChatCounter'; import ChatCounter from './ChatCounter';
/** /**
* The type of the React {@code Component} props of {@link ChatButton}. * The type of the React {@code Component} props of {@link ChatButton}.
*/ */
type Props = AbstractButtonProps & { interface IProps extends AbstractButtonProps, WithTranslation {
/** /**
* Whether or not the chat feature is currently displayed. * Whether or not the chat feature is currently displayed.
*/ */
_chatOpen: boolean, _chatOpen: boolean;
}; }
/** /**
* Implementation of a button for accessing chat pane. * Implementation of a button for accessing chat pane.
*/ */
class ChatButton extends AbstractButton<Props, *> { class ChatButton extends AbstractButton<IProps, any> {
accessibilityLabel = 'toolbar.accessibilityLabel.chat'; accessibilityLabel = 'toolbar.accessibilityLabel.chat';
icon = IconMessage; icon = IconMessage;
label = 'toolbar.openChat'; label = 'toolbar.openChat';
@ -67,7 +67,7 @@ class ChatButton extends AbstractButton<Props, *> {
* @protected * @protected
* @returns {boReact$Nodeolean} * @returns {boReact$Nodeolean}
*/ */
render(): React$Node { render(): ReactNode {
return ( return (
<div <div
className = 'toolbar-button-with-badge' className = 'toolbar-button-with-badge'
@ -85,7 +85,7 @@ class ChatButton extends AbstractButton<Props, *> {
* @param {Object} state - Redux state. * @param {Object} state - Redux state.
* @returns {Object} * @returns {Object}
*/ */
const mapStateToProps = state => { const mapStateToProps = (state: IReduxState) => {
return { return {
_chatOpen: state['features/chat'].isOpen _chatOpen: state['features/chat'].isOpen
}; };

View File

@ -1,26 +1,25 @@
// @flow
import React, { Component } from 'react'; import React, { Component } from 'react';
import { connect } from 'react-redux';
import { connect } from '../../../base/redux'; import { IReduxState } from '../../../app/types';
import { getUnreadPollCount } from '../../../polls/functions'; import { getUnreadPollCount } from '../../../polls/functions';
import { getUnreadCount } from '../../functions'; import { getUnreadCount } from '../../functions';
/** /**
* The type of the React {@code Component} props of {@link ChatCounter}. * The type of the React {@code Component} props of {@link ChatCounter}.
*/ */
type Props = { interface IProps {
/** /**
* The value of to display as a count. * The value of to display as a count.
*/ */
_count: number, _count: number;
/** /**
* True if the chat window should be rendered. * True if the chat window should be rendered.
*/ */
_isOpen: boolean _isOpen: boolean;
}; }
/** /**
* Implements a React {@link Component} which displays a count of the number of * Implements a React {@link Component} which displays a count of the number of
@ -28,7 +27,7 @@ type Props = {
* *
* @augments Component * @augments Component
*/ */
class ChatCounter extends Component<Props> { class ChatCounter extends Component<IProps> {
/** /**
* Implements React's {@link Component#render()}. * Implements React's {@link Component#render()}.
@ -61,14 +60,12 @@ class ChatCounter extends Component<Props> {
* _count: number * _count: number
* }} * }}
*/ */
function _mapStateToProps(state) { function _mapStateToProps(state: IReduxState) {
const { isOpen } = state['features/chat']; const { isOpen } = state['features/chat'];
return { return {
_count: getUnreadCount(state) + getUnreadPollCount(state), _count: getUnreadCount(state) + getUnreadPollCount(state),
_isOpen: isOpen _isOpen: isOpen
}; };
} }

View File

@ -1,41 +1,41 @@
// @flow
import React, { useCallback } from 'react'; import React, { useCallback } from 'react';
import { WithTranslation } from 'react-i18next';
import { connect } from 'react-redux';
import { translate } from '../../../base/i18n'; import { translate } from '../../../base/i18n/functions';
import { Icon, IconCloseLarge } from '../../../base/icons'; import Icon from '../../../base/icons/components/Icon';
import { connect } from '../../../base/redux'; import { IconCloseLarge } from '../../../base/icons/svg';
import { toggleChat } from '../../actions.web'; import { toggleChat } from '../../actions.web';
type Props = { interface IProps extends WithTranslation {
/**
* Function to be called when pressing the close button.
*/
onCancel: Function,
/** /**
* An optional class name. * An optional class name.
*/ */
className: string, className: string;
/**
* Optional id.
*/
id?: string;
/** /**
* Whether the polls feature is enabled or not. * Whether the polls feature is enabled or not.
*/ */
isPollsEnabled: boolean, isPollsEnabled: boolean;
/** /**
* Invoked to obtain translated strings. * Function to be called when pressing the close button.
*/ */
t: Function onCancel: Function;
}; }
/** /**
* Custom header of the {@code ChatDialog}. * Custom header of the {@code ChatDialog}.
* *
* @returns {React$Element<any>} * @returns {React$Element<any>}
*/ */
function Header({ onCancel, className, isPollsEnabled, t }: Props) { function Header({ onCancel, className, isPollsEnabled, t }: IProps) {
const onKeyPressHandler = useCallback(e => { const onKeyPressHandler = useCallback(e => {
if (onCancel && (e.key === ' ' || e.key === 'Enter')) { if (onCancel && (e.key === ' ' || e.key === 'Enter')) {

View File

@ -1,11 +1,11 @@
import React, { Component, RefObject } from 'react'; import React, { Component, RefObject } from 'react';
import { WithTranslation } from 'react-i18next'; import { WithTranslation } from 'react-i18next';
import { connect } from 'react-redux';
import { IReduxState, IStore } from '../../../app/types'; import { IReduxState, IStore } from '../../../app/types';
import { isMobileBrowser } from '../../../base/environment/utils'; import { isMobileBrowser } from '../../../base/environment/utils';
import { translate } from '../../../base/i18n/functions'; import { translate } from '../../../base/i18n/functions';
import { IconFaceSmile, IconSend } from '../../../base/icons/svg'; import { IconFaceSmile, IconSend } from '../../../base/icons/svg';
import { connect } from '../../../base/redux/functions';
import Button from '../../../base/ui/components/web/Button'; import Button from '../../../base/ui/components/web/Button';
import Input from '../../../base/ui/components/web/Input'; import Input from '../../../base/ui/components/web/Input';
import { areSmileysDisabled } from '../../functions'; import { areSmileysDisabled } from '../../functions';

View File

@ -1,9 +1,9 @@
import React, { Component } from 'react'; import React, { Component } from 'react';
import { WithTranslation } from 'react-i18next'; import { WithTranslation } from 'react-i18next';
import { connect } from 'react-redux';
import { IStore } from '../../../app/types'; import { IStore } from '../../../app/types';
import { translate } from '../../../base/i18n/functions'; import { translate } from '../../../base/i18n/functions';
import { connect } from '../../../base/redux/functions';
import { updateSettings } from '../../../base/settings/actions'; import { updateSettings } from '../../../base/settings/actions';
import Button from '../../../base/ui/components/web/Button'; import Button from '../../../base/ui/components/web/Button';
import Input from '../../../base/ui/components/web/Input'; import Input from '../../../base/ui/components/web/Input';

View File

@ -1,5 +1,3 @@
// @flow
import React, { useEffect, useState } from 'react'; import React, { useEffect, useState } from 'react';
import { isIosMobileBrowser } from '../../../base/environment/utils'; import { isIosMobileBrowser } from '../../../base/environment/utils';

View File

@ -1,10 +1,10 @@
import { Theme } from '@mui/material'; import { Theme } from '@mui/material';
import { withStyles } from '@mui/styles'; import { withStyles } from '@mui/styles';
import React from 'react'; import React from 'react';
import { connect } from 'react-redux';
import { translate } from '../../../base/i18n/functions'; import { translate } from '../../../base/i18n/functions';
import { IconCloseLarge } from '../../../base/icons/svg'; import { IconCloseLarge } from '../../../base/icons/svg';
import { connect } from '../../../base/redux/functions';
import { withPixelLineHeight } from '../../../base/styles/functions.web'; import { withPixelLineHeight } from '../../../base/styles/functions.web';
import Button from '../../../base/ui/components/web/Button'; import Button from '../../../base/ui/components/web/Button';
import { BUTTON_TYPES } from '../../../base/ui/constants.any'; import { BUTTON_TYPES } from '../../../base/ui/constants.any';

View File

@ -1,5 +1,3 @@
// @flow
import React, { PureComponent } from 'react'; import React, { PureComponent } from 'react';
import Emoji from 'react-emoji-render'; import Emoji from 'react-emoji-render';
@ -14,7 +12,7 @@ type Props = {
* Callback to invoke when a smiley is selected. The smiley will be passed * Callback to invoke when a smiley is selected. The smiley will be passed
* back. * back.
*/ */
onSmileySelect: Function onSmileySelect: Function;
}; };
/** /**
@ -38,8 +36,6 @@ class SmileysPanel extends PureComponent<Props> {
this._onEscKey = this._onEscKey.bind(this); this._onEscKey = this._onEscKey.bind(this);
} }
_onEscKey: (Object) => void;
/** /**
* KeyPress handler for accessibility. * KeyPress handler for accessibility.
* *
@ -47,7 +43,7 @@ class SmileysPanel extends PureComponent<Props> {
* *
* @returns {void} * @returns {void}
*/ */
_onEscKey(e) { _onEscKey(e: React.KeyboardEvent) {
// Escape handling does not work in onKeyPress // Escape handling does not work in onKeyPress
if (e.key === 'Escape') { if (e.key === 'Escape') {
e.preventDefault(); e.preventDefault();
@ -56,8 +52,6 @@ class SmileysPanel extends PureComponent<Props> {
} }
} }
_onKeyPress: (Object) => void;
/** /**
* KeyPress handler for accessibility. * KeyPress handler for accessibility.
* *
@ -65,15 +59,13 @@ class SmileysPanel extends PureComponent<Props> {
* *
* @returns {void} * @returns {void}
*/ */
_onKeyPress(e) { _onKeyPress(e: any) {
if (e.key === ' ') { if (e.key === ' ') {
e.preventDefault(); e.preventDefault();
this.props.onSmileySelect(e.target.id && smileys[e.target.id]); this.props.onSmileySelect(e.target.id && smileys[e.target.id as keyof typeof smileys]);
} }
} }
_onClick: (Object) => void;
/** /**
* Click handler for to select emoji. * Click handler for to select emoji.
* *
@ -81,9 +73,9 @@ class SmileysPanel extends PureComponent<Props> {
* *
* @returns {void} * @returns {void}
*/ */
_onClick(e) { _onClick(e: React.MouseEvent) {
e.preventDefault(); e.preventDefault();
this.props.onSmileySelect(e.currentTarget.id && smileys[e.currentTarget.id]); this.props.onSmileySelect(e.currentTarget.id && smileys[e.currentTarget.id as keyof typeof smileys]);
} }
/** /**
@ -105,7 +97,7 @@ class SmileysPanel extends PureComponent<Props> {
tabIndex = { 0 }> tabIndex = { 0 }>
<Emoji <Emoji
onlyEmojiClassName = 'smiley' onlyEmojiClassName = 'smiley'
text = { smileys[smileyKey] } /> text = { smileys[smileyKey as keyof typeof smileys] } />
</div> </div>
)); ));