From 0435c3cc64f5e311c3284b97bee9bf50d5de2279 Mon Sep 17 00:00:00 2001 From: Robert Pintilii Date: Thu, 11 Aug 2022 16:32:44 +0300 Subject: [PATCH] ref(ui-components) Use new input and button in chat (#12000) --- css/_chat.scss | 66 +----- .../features/base/ui/components/web/Input.tsx | 79 +++++-- .../web/{ChatInput.js => ChatInput.tsx} | 197 +++++------------- 3 files changed, 119 insertions(+), 223 deletions(-) rename react/features/chat/components/web/{ChatInput.js => ChatInput.tsx} (53%) diff --git a/css/_chat.scss b/css/_chat.scss index 6821c363cd..2ecc31bf56 100644 --- a/css/_chat.scss +++ b/css/_chat.scss @@ -119,63 +119,18 @@ .chat-input-container { padding: 0 16px 16px; - - &.populated { - #chat-input { - .send-button { - background: #1B67EC; - cursor: pointer; - margin-left: 0.3rem; - - @media (hover: hover) and (pointer: fine) { - &:hover { - background: #3D82FB; - } - } - - &:active { - background: #0852D4; - } - - path { - fill: #fff; - } - } - } - } } #chat-input { - border: 1px solid $chatInputSeparatorColor; display: flex; + align-items: flex-end; padding: 4px; - border-radius: 3px; - - &:focus-within { - border: 1px solid #619CF4; - } - - * { - background-color: transparent; - } -} - -.send-button-container { - display: flex; - align-items: center; + position: relative; } -.send-button { - display: flex; - align-items: center; - justify-content: center; - height: 40px; - width: 40px; - border-radius: 3px; - - path { - fill: $chatInputSeparatorColor; - } +.chat-input { + flex: 1; + margin-right: 8px; } .smiley-button { @@ -395,7 +350,9 @@ .smiley-input { display: flex; - position: relative; + position: absolute; + top: 0; + left: 0; } .smileys-panel { @@ -403,7 +360,7 @@ box-sizing: border-box; background-color: rgba(0, 0, 0, .6) !important; height: auto; - display: none; + display: flex; overflow: hidden; position: absolute; width: calc(#{$sidebarWidth} - 32px); @@ -418,11 +375,6 @@ */ transition: max-height 0.3s; - &.show-smileys { - display: flex; - max-height: 500%; - } - #smileysContainer { background-color: $chatBackgroundColor; border-top: 1px solid $chatInputSeparatorColor; diff --git a/react/features/base/ui/components/web/Input.tsx b/react/features/base/ui/components/web/Input.tsx index 702f65d734..98f34c856c 100644 --- a/react/features/base/ui/components/web/Input.tsx +++ b/react/features/base/ui/components/web/Input.tsx @@ -1,6 +1,7 @@ import { makeStyles } from '@material-ui/core'; import clsx from 'clsx'; import React, { useCallback } from 'react'; +import TextareaAutosize from 'react-textarea-autosize'; import { isMobileBrowser } from '../../../environment/utils'; import Icon from '../../../icons/components/Icon'; @@ -14,10 +15,14 @@ interface IInputProps extends InputProps { autoFocus?: boolean; bottomLabel?: string; className?: string; + iconClick?: () => void; id?: string; maxLength?: number; + maxRows?: number; + minRows?: number; name?: string; onKeyPress?: (e: React.KeyboardEvent) => void; + textarea?: boolean; type?: 'text' | 'email' | 'number' | 'password'; } @@ -73,6 +78,10 @@ const useStyles = makeStyles((theme: Theme) => { ...withPixelLineHeight(theme.typography.bodyShortRegularLarge) }, + '&.icon-input': { + paddingLeft: '46px' + }, + '&.error': { boxShadow: `0px 0px 0px 2px ${theme.palette.textError}` } @@ -80,12 +89,13 @@ const useStyles = makeStyles((theme: Theme) => { icon: { position: 'absolute', - top: '10px', + top: '50%', + transform: 'translateY(-50%)', left: '16px' }, - iconInput: { - paddingLeft: '46px' + iconClickable: { + cursor: 'pointer' }, clearableInput: { @@ -118,7 +128,7 @@ const useStyles = makeStyles((theme: Theme) => { }; }); -const Input = ({ +const Input = React.forwardRef(({ accessibilityLabel, autoFocus, bottomLabel, @@ -127,20 +137,24 @@ const Input = ({ disabled, error, icon, + iconClick, id, label, maxLength, + maxRows, + minRows, name, onChange, onKeyPress, placeholder, + textarea = false, type = 'text', value -}: IInputProps) => { +}: IInputProps, ref) => { const styles = useStyles(); const isMobile = isMobileBrowser(); - const handleChange = useCallback((e: React.ChangeEvent) => + const handleChange = useCallback((e: React.ChangeEvent) => onChange(e.target.value), []); const clearInput = useCallback(() => onChange(''), []); @@ -149,23 +163,44 @@ const Input = ({ {label && {label}}
{icon && } - + {textarea ? ( + + ) : ( + + )} {clearable && !disabled && value !== '' &&
); -}; +}); export default Input; diff --git a/react/features/chat/components/web/ChatInput.js b/react/features/chat/components/web/ChatInput.tsx similarity index 53% rename from react/features/chat/components/web/ChatInput.js rename to react/features/chat/components/web/ChatInput.tsx index 3a40c76c17..ef70df72b9 100644 --- a/react/features/chat/components/web/ChatInput.js +++ b/react/features/chat/components/web/ChatInput.tsx @@ -1,21 +1,30 @@ -// @flow - +/* eslint-disable lines-around-comment */ import React, { Component } from 'react'; -import TextareaAutosize from 'react-textarea-autosize'; +import { WithTranslation } from 'react-i18next'; import type { Dispatch } from 'redux'; +import { IState } from '../../../app/types'; import { isMobileBrowser } from '../../../base/environment/utils'; -import { translate } from '../../../base/i18n'; -import { Icon, IconPlane, IconSmile } from '../../../base/icons'; -import { connect } from '../../../base/redux'; +import { translate } from '../../../base/i18n/functions'; +import { IconPlane, IconSmile } from '../../../base/icons/svg/index'; +import { connect } from '../../../base/redux/functions'; +import Button from '../../../base/ui/components/web/Button'; +import Input from '../../../base/ui/components/web/Input'; +// @ts-ignore import { areSmileysDisabled } from '../../functions'; +// @ts-ignore import SmileysPanel from './SmileysPanel'; /** * The type of the React {@code Component} props of {@link ChatInput}. */ -type Props = { +interface Props extends WithTranslation { + + /** + * Whether chat emoticons are disabled. + */ + _areSmileysDisabled: boolean, /** * Invoked to send chat messages. @@ -26,24 +35,14 @@ type Props = { * Optional callback to invoke when the chat textarea has auto-resized to * fit overflowing text. */ - onResize: ?Function, + onResize?: Function, /** * Callback to invoke on message send. */ - onSend: Function, - - /** - * Invoked to obtain translated strings. - */ - t: Function, + onSend: Function - /** - * Whether chat emoticons are disabled. - */ - _areSmileysDisabled: boolean - -}; +} /** * The type of the React {@code Component} state of {@link ChatInput}. @@ -67,7 +66,7 @@ type State = { * @augments Component */ class ChatInput extends Component { - _textArea: ?HTMLTextAreaElement; + _textArea?: HTMLTextAreaElement; state = { message: '', @@ -83,17 +82,14 @@ class ChatInput extends Component { constructor(props: Props) { super(props); - this._textArea = null; + this._textArea = undefined; // Bind event handlers so they are only bound once for every instance. this._onDetectSubmit = this._onDetectSubmit.bind(this); this._onMessageChange = this._onMessageChange.bind(this); this._onSmileySelect = this._onSmileySelect.bind(this); this._onSubmitMessage = this._onSubmitMessage.bind(this); - this._onToggleSmileysPanel = this._onToggleSmileysPanel.bind(this); - this._onEscHandler = this._onEscHandler.bind(this); - this._onToggleSmileysPanelKeyPress = this._onToggleSmileysPanelKeyPress.bind(this); - this._onSubmitMessageKeyPress = this._onSubmitMessageKeyPress.bind(this); + this._toggleSmileysPanel = this._toggleSmileysPanel.bind(this); this._setTextAreaRef = this._setTextAreaRef.bind(this); } @@ -116,62 +112,37 @@ class ChatInput extends Component { * @returns {ReactElement} */ render() { - const smileysPanelClassName = `${this.state.showSmileysPanel - ? 'show-smileys' : 'hide-smileys'} smileys-panel`; - return (
- { this.props._areSmileysDisabled ? null : ( -
-
-
-
- -
-
-
+ {!this.props._areSmileysDisabled && this.state.showSmileysPanel && ( +
+ className = 'smileys-panel' >
- ) } -
- -
-
-
- -
-
+ )} + +
); @@ -187,9 +158,6 @@ class ChatInput extends Component { this._textArea && this._textArea.focus(); } - - _onSubmitMessage: () => void; - /** * Submits the message to the chat window. * @@ -208,7 +176,6 @@ class ChatInput extends Component { } } - _onDetectSubmit: (Object) => void; /** * Detects if enter has been pressed. If so, submit the message in the chat @@ -218,7 +185,7 @@ class ChatInput extends Component { * @private * @returns {void} */ - _onDetectSubmit(event) { + _onDetectSubmit(event: any) { // Composition events used to add accents to characters // despite their absence from standard US keyboards, // to build up logograms of many Asian languages @@ -241,37 +208,17 @@ class ChatInput extends Component { } } - _onSubmitMessageKeyPress: (Object) => void; - - /** - * KeyPress handler for accessibility. - * - * @param {Object} e - The key event to handle. - * - * @returns {void} - */ - _onSubmitMessageKeyPress(e) { - if (e.key === ' ' || e.key === 'Enter') { - e.preventDefault(); - this._onSubmitMessage(); - } - } - - _onMessageChange: (Object) => void; - /** * Updates the known message the user is drafting. * - * @param {string} event - Keyboard event. + * @param {string} value - Keyboard event. * @private * @returns {void} */ - _onMessageChange(event) { - this.setState({ message: event.target.value }); + _onMessageChange(value: string) { + this.setState({ message: value }); } - _onSmileySelect: (string) => void; - /** * Appends a selected smileys to the chat message draft. * @@ -280,7 +227,7 @@ class ChatInput extends Component { * @private * @returns {void} */ - _onSmileySelect(smileyText) { + _onSmileySelect(smileyText: string) { if (smileyText) { this.setState({ message: `${this.state.message} ${smileyText}`, @@ -295,57 +242,19 @@ class ChatInput extends Component { this._focus(); } - _onToggleSmileysPanel: () => void; - /** * Callback invoked to hide or show the smileys selector. * * @private * @returns {void} */ - _onToggleSmileysPanel() { + _toggleSmileysPanel() { if (this.state.showSmileysPanel) { this._focus(); } this.setState({ showSmileysPanel: !this.state.showSmileysPanel }); } - _onEscHandler: (Object) => void; - - /** - * KeyPress handler for accessibility. - * - * @param {Object} e - The key event to handle. - * - * @returns {void} - */ - _onEscHandler(e) { - // Escape handling does not work in onKeyPress - if (this.state.showSmileysPanel && e.key === 'Escape') { - e.preventDefault(); - e.stopPropagation(); - this._onToggleSmileysPanel(); - } - } - - _onToggleSmileysPanelKeyPress: (Object) => void; - - /** - * KeyPress handler for accessibility. - * - * @param {Object} e - The key event to handle. - * - * @returns {void} - */ - _onToggleSmileysPanelKeyPress(e) { - if (e.key === ' ' || e.key === 'Enter') { - e.preventDefault(); - this._onToggleSmileysPanel(); - } - } - - _setTextAreaRef: (?HTMLTextAreaElement) => void; - /** * Sets the reference to the HTML TextArea. * @@ -353,7 +262,7 @@ class ChatInput extends Component { * @private * @returns {void} */ - _setTextAreaRef(textAreaElement: ?HTMLTextAreaElement) { + _setTextAreaRef(textAreaElement?: HTMLTextAreaElement) { this._textArea = textAreaElement; } } @@ -367,7 +276,7 @@ class ChatInput extends Component { * _areSmileysDisabled: boolean * }} */ -const mapStateToProps = state => { +const mapStateToProps = (state: IState) => { return { _areSmileysDisabled: areSmileysDisabled(state) };