common.tsx 1.5 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455
  1. import { useEffect, useRef } from 'react'
  2. import cn from '@/utils/classnames'
  3. type AutoHeightTextareaProps =
  4. & React.DetailedHTMLProps<React.TextareaHTMLAttributes<HTMLTextAreaElement>, HTMLTextAreaElement>
  5. & { outerClassName?: string }
  6. const AutoHeightTextarea = (
  7. {
  8. ref: outRef,
  9. outerClassName,
  10. value,
  11. className,
  12. placeholder,
  13. autoFocus,
  14. disabled,
  15. ...rest
  16. }: AutoHeightTextareaProps & {
  17. ref: React.RefObject<HTMLTextAreaElement>;
  18. },
  19. ) => {
  20. const innerRef = useRef<HTMLTextAreaElement>(null)
  21. const ref = outRef || innerRef
  22. useEffect(() => {
  23. if (autoFocus && !disabled && value) {
  24. if (typeof ref !== 'function') {
  25. ref.current?.setSelectionRange(`${value}`.length, `${value}`.length)
  26. ref.current?.focus()
  27. }
  28. }
  29. }, [autoFocus, disabled, ref])
  30. return (
  31. (<div className={outerClassName}>
  32. <div className='relative'>
  33. <div className={cn(className, 'invisible whitespace-pre-wrap break-all')}>
  34. {!value ? placeholder : `${value}`.replace(/\n$/, '\n ')}
  35. </div>
  36. <textarea
  37. ref={ref}
  38. placeholder={placeholder}
  39. className={cn(className, 'absolute inset-0 h-full w-full resize-none appearance-none border-none outline-none disabled:bg-transparent')}
  40. value={value}
  41. disabled={disabled}
  42. {...rest}
  43. />
  44. </div>
  45. </div>)
  46. )
  47. }
  48. AutoHeightTextarea.displayName = 'AutoHeightTextarea'
  49. export default AutoHeightTextarea