ref(display-name) Change to function component (#12402)

Use makeStyles instead of withStyles
This commit is contained in:
Robert Pintilii 2022-10-19 10:19:40 +03:00 committed by GitHub
parent dbb0a953c6
commit 440339dea8
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
1 changed files with 81 additions and 258 deletions

View File

@ -1,12 +1,11 @@
/* eslint-disable lines-around-comment */ /* eslint-disable lines-around-comment */
import { Theme } from '@mui/material'; import { Theme } from '@mui/material';
import { withStyles } from '@mui/styles'; import React, { useCallback, useEffect, useRef, useState } from 'react';
import React, { Component } from 'react'; import { useTranslation } from 'react-i18next';
import { WithTranslation } from 'react-i18next'; import { useDispatch, useSelector } from 'react-redux';
import { connect } from 'react-redux'; import { makeStyles } from 'tss-react/mui';
import { IState, IStore } from '../../../app/types'; import { IState } from '../../../app/types';
import { translate } from '../../../base/i18n/functions';
import { import {
getParticipantById, getParticipantById,
getParticipantDisplayName getParticipantDisplayName
@ -22,34 +21,13 @@ import { appendSuffix } from '../../functions';
/** /**
* The type of the React {@code Component} props of {@link DisplayName}. * The type of the React {@code Component} props of {@link DisplayName}.
*/ */
interface Props extends WithTranslation { interface Props {
/**
* The participant's current display name which should be shown when in
* edit mode. Can be different from what is shown when not editing.
*/
_configuredDisplayName: string;
/**
* The participant's current display name which should be shown.
*/
_nameToDisplay: string;
/** /**
* Whether or not the display name should be editable on click. * Whether or not the display name should be editable on click.
*/ */
allowEditing: boolean; allowEditing: boolean;
/**
* An object containing the CSS classes.
*/
classes: any;
/**
* Invoked to update the participant's display name.
*/
dispatch: IStore['dispatch'];
/** /**
* A string to append to the displayName, if provided. * A string to append to the displayName, if provided.
*/ */
@ -72,23 +50,7 @@ interface Props extends WithTranslation {
thumbnailType: string; thumbnailType: string;
} }
/** const useStyles = makeStyles()((theme: Theme) => {
* The type of the React {@code Component} state of {@link DisplayName}.
*/
type State = {
/**
* The current value of the display name in the edit field.
*/
editDisplayNameValue: string;
/**
* Whether or not the component should be displaying an editable input.
*/
isEditing: boolean;
};
const styles = (theme: Theme) => {
return { return {
displayName: { displayName: {
...withPixelLineHeight(theme.typography.labelBold), ...withPixelLineHeight(theme.typography.labelBold),
@ -108,232 +70,93 @@ const styles = (theme: Theme) => {
color: theme.palette.text01 color: theme.palette.text01
} }
}; };
}; });
/** const DisplayName = ({
* React {@code Component} for displaying and editing a participant's name. allowEditing,
* displayNameSuffix,
* @augments Component elementID,
*/ participantID,
class DisplayName extends Component<Props, State> { thumbnailType
_nameInput?: HTMLInputElement; }: Props) => {
const { classes } = useStyles();
const configuredDisplayName = useSelector((state: IState) => getParticipantById(state, participantID))?.name ?? '';
const nameToDisplay = useSelector((state: IState) => getParticipantDisplayName(state, participantID));
const [ editDisplayNameValue, setEditDisplayNameValue ] = useState('');
const [ isEditing, setIsEditing ] = useState(false);
const dispatch = useDispatch();
const { t } = useTranslation();
const nameInputRef = useRef<HTMLInputElement | null>(null);
static defaultProps = { useEffect(() => {
_configuredDisplayName: '' if (isEditing && nameInputRef.current) {
}; nameInputRef.current.select();
/**
* Initializes a new {@code DisplayName} instance.
*
* @param {Object} props - The read-only properties with which the new
* instance is to be initialized.
*/
constructor(props: Props) {
super(props);
this.state = {
editDisplayNameValue: '',
isEditing: false
};
/**
* The internal reference to the HTML element backing the React
* {@code Component} input with id {@code editDisplayName}. It is
* necessary for automatically selecting the display name input field
* when starting to edit the display name.
*
* @private
* @type {HTMLInputElement}
*/
this._nameInput = undefined;
// Bind event handlers so they are only bound once for every instance.
this._onChange = this._onChange.bind(this);
this._onKeyDown = this._onKeyDown.bind(this);
this._onStartEditing = this._onStartEditing.bind(this);
this._onSubmit = this._onSubmit.bind(this);
this._setNameInputRef = this._setNameInputRef.bind(this);
}
/**
* Automatically selects the input field's value after starting to edit the
* display name.
*
* @inheritdoc
* @returns {void}
*/
componentDidUpdate(previousProps: Props, previousState: State) {
if (!previousState.isEditing
&& this.state.isEditing
&& this._nameInput) {
this._nameInput.select();
} }
} }, [ isEditing ]);
/** const onClick = useCallback((e: React.MouseEvent) => {
* Implements React's {@link Component#render()}.
*
* @inheritdoc
* @returns {ReactElement}
*/
render() {
const {
_nameToDisplay,
allowEditing,
displayNameSuffix,
classes,
elementID,
t,
thumbnailType
} = this.props;
if (allowEditing && this.state.isEditing) {
return (
<input
autoFocus = { true }
className = { classes.editDisplayName }
id = 'editDisplayName'
onBlur = { this._onSubmit }
onChange = { this._onChange }
onClick = { this._onClick }
onKeyDown = { this._onKeyDown }
placeholder = { t('defaultNickname') }
ref = { this._setNameInputRef }
spellCheck = { 'false' }
type = 'text'
value = { this.state.editDisplayNameValue } />
);
}
return (
<Tooltip
content = { appendSuffix(_nameToDisplay, displayNameSuffix) }
position = { getIndicatorsTooltipPosition(thumbnailType) }>
<span
className = { `displayname ${classes.displayName}` }
id = { elementID }
onClick = { this._onStartEditing }>
{ appendSuffix(_nameToDisplay, displayNameSuffix) }
</span>
</Tooltip>
);
}
/**
* Stop click event propagation.
*
* @param {MouseEvent} e - The click event.
* @private
* @returns {void}
*/
_onClick(e: React.MouseEvent) {
e.stopPropagation(); e.stopPropagation();
} }, []);
/** const onChange = useCallback((event: React.ChangeEvent<HTMLInputElement>) => {
* Updates the internal state of the display name entered into the edit setEditDisplayNameValue(event.target.value);
* field. }, []);
*
* @param {Object} event - DOM Event for value change.
* @private
* @returns {void}
*/
_onChange(event: React.ChangeEvent<HTMLInputElement>) {
this.setState({
editDisplayNameValue: event.target.value
});
}
/** const onSubmit = useCallback(() => {
* Submits the edited display name update if the enter key is pressed.
*
* @param {Event} event - Key down event object.
* @private
* @returns {void}
*/
_onKeyDown(event: React.KeyboardEvent) {
if (event.key === 'Enter') {
this._onSubmit();
}
}
/**
* Updates the component to display an editable input field and sets the
* initial value to the current display name.
*
* @param {MouseEvent} e - The click event.
* @private
* @returns {void}
*/
_onStartEditing(e: React.MouseEvent) {
if (this.props.allowEditing) {
e.stopPropagation();
this.setState({
isEditing: true,
editDisplayNameValue: this.props._configuredDisplayName
});
}
}
/**
* Dispatches an action to update the display name if any change has
* occurred after editing. Clears any temporary state used to keep track
* of pending display name changes and exits editing mode.
*
* @param {Event} event - Key down event object.
* @private
* @returns {void}
*/
_onSubmit() {
const { editDisplayNameValue } = this.state;
const { dispatch } = this.props;
// Store display name in settings
dispatch(updateSettings({ dispatch(updateSettings({
displayName: editDisplayNameValue displayName: editDisplayNameValue
})); }));
this.setState({ setEditDisplayNameValue('');
isEditing: false, setIsEditing(false);
editDisplayNameValue: '' nameInputRef.current = null;
}); }, [ editDisplayNameValue, nameInputRef ]);
this._nameInput = undefined; const onKeyDown = useCallback((event: React.KeyboardEvent) => {
if (event.key === 'Enter') {
onSubmit();
}
}, [ onSubmit ]);
const onStartEditing = useCallback((e: React.MouseEvent) => {
if (allowEditing) {
e.stopPropagation();
setIsEditing(true);
setEditDisplayNameValue(configuredDisplayName);
}
}, [ allowEditing ]);
if (allowEditing && isEditing) {
return (
<input
autoFocus = { true }
className = { classes.editDisplayName }
id = 'editDisplayName'
onBlur = { onSubmit }
onChange = { onChange }
onClick = { onClick }
onKeyDown = { onKeyDown }
placeholder = { t('defaultNickname') }
ref = { nameInputRef }
spellCheck = { 'false' }
type = 'text'
value = { editDisplayNameValue } />
);
} }
/** return (
* Sets the internal reference to the HTML element backing the React <Tooltip
* {@code Component} input with id {@code editDisplayName}. content = { appendSuffix(nameToDisplay, displayNameSuffix) }
* position = { getIndicatorsTooltipPosition(thumbnailType) }>
* @param {HTMLInputElement} element - The DOM/HTML element for this <span
* {@code Component}'s input. className = { `displayname ${classes.displayName}` }
* @private id = { elementID }
* @returns {void} onClick = { onStartEditing }>
*/ {appendSuffix(nameToDisplay, displayNameSuffix)}
_setNameInputRef(element: HTMLInputElement) { </span>
this._nameInput = element; </Tooltip>
} );
} };
/**
* Maps (parts of) the redux state to the props of this component.
*
* @param {Object} state - The redux store/state.
* @param {Props} ownProps - The own props of the component.
* @private
* @returns {{
* _configuredDisplayName: string,
* _nameToDisplay: string
* }}
*/
function _mapStateToProps(state: IState, ownProps: Partial<Props>) {
const { participantID } = ownProps;
const participant = getParticipantById(state, participantID ?? '');
return { export default DisplayName;
_configuredDisplayName: participant?.name,
_nameToDisplay: getParticipantDisplayName(state, participantID ?? '')
};
}
export default translate(connect(_mapStateToProps)(withStyles(styles)(DisplayName)));