project-name-editable-label.tsx 2.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899
  1. import { useEffect, useState, useRef } from 'react'
  2. import { useTranslation } from 'react-i18next'
  3. import classNames from 'classnames'
  4. import Tooltip from '../../../shared/components/tooltip'
  5. import Icon from '../../../shared/components/icon'
  6. type ProjectNameEditableLabelProps = {
  7. projectName: string
  8. onChange: (value: string) => void
  9. hasRenamePermissions?: boolean
  10. className?: string
  11. }
  12. function ProjectNameEditableLabel({
  13. projectName,
  14. hasRenamePermissions,
  15. onChange,
  16. className,
  17. }: ProjectNameEditableLabelProps) {
  18. const { t } = useTranslation()
  19. const [isRenaming, setIsRenaming] = useState(false)
  20. const canRename = hasRenamePermissions && !isRenaming
  21. const [inputContent, setInputContent] = useState(projectName)
  22. const inputRef = useRef<HTMLInputElement | null>(null)
  23. useEffect(() => {
  24. if (isRenaming) {
  25. inputRef.current?.select()
  26. }
  27. }, [isRenaming])
  28. function startRenaming() {
  29. if (canRename) {
  30. setInputContent(projectName)
  31. setIsRenaming(true)
  32. }
  33. }
  34. function finishRenaming() {
  35. setIsRenaming(false)
  36. onChange(inputContent)
  37. }
  38. function handleKeyDown(event: React.KeyboardEvent) {
  39. if (event.key === 'Enter') {
  40. event.preventDefault()
  41. finishRenaming()
  42. }
  43. }
  44. function handleOnChange(event: React.ChangeEvent<HTMLInputElement>) {
  45. setInputContent(event.target.value)
  46. }
  47. function handleBlur() {
  48. if (isRenaming) {
  49. finishRenaming()
  50. }
  51. }
  52. return (
  53. <div className={classNames('project-name', className)}>
  54. {!isRenaming && (
  55. <span className="name" onDoubleClick={startRenaming}>
  56. {projectName}
  57. </span>
  58. )}
  59. {isRenaming && (
  60. <input
  61. ref={inputRef}
  62. type="text"
  63. className="form-control"
  64. onKeyDown={handleKeyDown}
  65. onChange={handleOnChange}
  66. onBlur={handleBlur}
  67. value={inputContent}
  68. />
  69. )}
  70. {canRename && (
  71. <Tooltip
  72. id="online-user"
  73. description={t('rename')}
  74. overlayProps={{ placement: 'bottom', trigger: ['hover', 'focus'] }}
  75. >
  76. {/* eslint-disable-next-line jsx-a11y/anchor-is-valid, jsx-a11y/click-events-have-key-events, jsx-a11y/interactive-supports-focus */}
  77. <a className="rename" role="button" onClick={startRenaming}>
  78. <Icon type="pencil" fw />
  79. </a>
  80. </Tooltip>
  81. )}
  82. </div>
  83. )
  84. }
  85. export default ProjectNameEditableLabel