project-name-editable-label.tsx 2.8 KB

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