Вы не можете выбрать более 25 тем Темы должны начинаться с буквы или цифры, могут содержать дефисы(-) и должны содержать не более 35 символов.

DisplayName.tsx 4.9KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163
  1. /* eslint-disable lines-around-comment */
  2. import { Theme } from '@mui/material';
  3. import React, { useCallback, useEffect, useRef, useState } from 'react';
  4. import { useTranslation } from 'react-i18next';
  5. import { useDispatch, useSelector } from 'react-redux';
  6. import { makeStyles } from 'tss-react/mui';
  7. import { IReduxState } from '../../../app/types';
  8. import {
  9. getParticipantById,
  10. getParticipantDisplayName
  11. } from '../../../base/participants/functions';
  12. import { updateSettings } from '../../../base/settings/actions';
  13. import { withPixelLineHeight } from '../../../base/styles/functions.web';
  14. // @ts-ignore
  15. import { Tooltip } from '../../../base/tooltip';
  16. // @ts-ignore
  17. import { getIndicatorsTooltipPosition } from '../../../filmstrip/functions.web';
  18. import { appendSuffix } from '../../functions';
  19. /**
  20. * The type of the React {@code Component} props of {@link DisplayName}.
  21. */
  22. interface IProps {
  23. /**
  24. * Whether or not the display name should be editable on click.
  25. */
  26. allowEditing: boolean;
  27. /**
  28. * A string to append to the displayName, if provided.
  29. */
  30. displayNameSuffix: string;
  31. /**
  32. * The ID attribute to add to the component. Useful for global querying for
  33. * the component by legacy components and torture tests.
  34. */
  35. elementID: string;
  36. /**
  37. * The ID of the participant whose name is being displayed.
  38. */
  39. participantID: string;
  40. /**
  41. * The type of thumbnail.
  42. */
  43. thumbnailType: string;
  44. }
  45. const useStyles = makeStyles()((theme: Theme) => {
  46. return {
  47. displayName: {
  48. ...withPixelLineHeight(theme.typography.labelBold),
  49. color: theme.palette.text01,
  50. overflow: 'hidden',
  51. textOverflow: 'ellipsis',
  52. whiteSpace: 'nowrap'
  53. },
  54. editDisplayName: {
  55. outline: 'none',
  56. border: 'none',
  57. background: 'none',
  58. boxShadow: 'none',
  59. padding: 0,
  60. ...withPixelLineHeight(theme.typography.labelBold),
  61. color: theme.palette.text01
  62. }
  63. };
  64. });
  65. const DisplayName = ({
  66. allowEditing,
  67. displayNameSuffix,
  68. elementID,
  69. participantID,
  70. thumbnailType
  71. }: IProps) => {
  72. const { classes } = useStyles();
  73. const configuredDisplayName = useSelector((state: IReduxState) =>
  74. getParticipantById(state, participantID))?.name ?? '';
  75. const nameToDisplay = useSelector((state: IReduxState) => getParticipantDisplayName(state, participantID));
  76. const [ editDisplayNameValue, setEditDisplayNameValue ] = useState('');
  77. const [ isEditing, setIsEditing ] = useState(false);
  78. const dispatch = useDispatch();
  79. const { t } = useTranslation();
  80. const nameInputRef = useRef<HTMLInputElement | null>(null);
  81. useEffect(() => {
  82. if (isEditing && nameInputRef.current) {
  83. nameInputRef.current.select();
  84. }
  85. }, [ isEditing ]);
  86. const onClick = useCallback((e: React.MouseEvent) => {
  87. e.stopPropagation();
  88. }, []);
  89. const onChange = useCallback((event: React.ChangeEvent<HTMLInputElement>) => {
  90. setEditDisplayNameValue(event.target.value);
  91. }, []);
  92. const onSubmit = useCallback(() => {
  93. dispatch(updateSettings({
  94. displayName: editDisplayNameValue
  95. }));
  96. setEditDisplayNameValue('');
  97. setIsEditing(false);
  98. nameInputRef.current = null;
  99. }, [ editDisplayNameValue, nameInputRef ]);
  100. const onKeyDown = useCallback((event: React.KeyboardEvent) => {
  101. if (event.key === 'Enter') {
  102. onSubmit();
  103. }
  104. }, [ onSubmit ]);
  105. const onStartEditing = useCallback((e: React.MouseEvent) => {
  106. if (allowEditing) {
  107. e.stopPropagation();
  108. setIsEditing(true);
  109. setEditDisplayNameValue(configuredDisplayName);
  110. }
  111. }, [ allowEditing ]);
  112. if (allowEditing && isEditing) {
  113. return (
  114. <input
  115. autoFocus = { true }
  116. className = { classes.editDisplayName }
  117. id = 'editDisplayName'
  118. onBlur = { onSubmit }
  119. onChange = { onChange }
  120. onClick = { onClick }
  121. onKeyDown = { onKeyDown }
  122. placeholder = { t('defaultNickname') }
  123. ref = { nameInputRef }
  124. spellCheck = { 'false' }
  125. type = 'text'
  126. value = { editDisplayNameValue } />
  127. );
  128. }
  129. return (
  130. <Tooltip
  131. content = { appendSuffix(nameToDisplay, displayNameSuffix) }
  132. position = { getIndicatorsTooltipPosition(thumbnailType) }>
  133. <span
  134. className = { `displayname ${classes.displayName}` }
  135. id = { elementID }
  136. onClick = { onStartEditing }>
  137. {appendSuffix(nameToDisplay, displayNameSuffix)}
  138. </span>
  139. </Tooltip>
  140. );
  141. };
  142. export default DisplayName;