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

DisplayName.tsx 4.8KB

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