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

DisplayName.tsx 4.8KB

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