wwf
3 天以前 a430284aa21e3ae1f0d5654e55b2ad2852519cc2
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
import React, { useEffect, useState } from 'react'
import type { FC } from 'react'
import cn from '@/utils/classnames'
 
type AutoWidthInputProps = {
  value: string
  placeholder: string
  onChange: (event: React.ChangeEvent<HTMLInputElement>) => void
  onBlur: () => void
  minWidth?: number
  maxWidth?: number
} & Omit<React.InputHTMLAttributes<HTMLInputElement>, 'onChange'>
 
const AutoWidthInput: FC<AutoWidthInputProps> = ({
  value,
  placeholder,
  onChange,
  onBlur,
  minWidth = 60,
  maxWidth = 300,
  className,
  ...props
}) => {
  const [width, setWidth] = useState(minWidth)
  const textRef = React.useRef<HTMLSpanElement>(null)
 
  useEffect(() => {
    if (textRef.current) {
      textRef.current.textContent = value || placeholder
      const textWidth = textRef.current.offsetWidth
      const newWidth = Math.max(minWidth, Math.min(textWidth + 16, maxWidth))
      if (width !== newWidth)
        setWidth(newWidth)
    }
  }, [value, placeholder, minWidth, maxWidth, width])
 
  // Handle Enter key
  const handleKeyUp = (e: React.KeyboardEvent<HTMLInputElement>) => {
    if (e.key === 'Enter' && e.currentTarget.blur)
      e.currentTarget.blur()
    if (props.onKeyUp)
      props.onKeyUp(e)
  }
 
  return (
    <div className='relative inline-flex items-center'>
      {/* Hidden measurement span */}
      <span
        ref={textRef}
        className='system-sm-semibold invisible absolute left-0 top-0 -z-10 whitespace-pre px-1'
        aria-hidden="true"
      >
        {value || placeholder}
      </span>
 
      {/* Actual input element */}
      <input
        value={value}
        className={cn(
          'system-sm-semibold placeholder:system-sm-semibold h-5 rounded-[5px] border border-transparent px-1',
          'py-px text-text-primary caret-[#295EFF] shadow-shadow-shadow-3 outline-none',
          'placeholder:text-text-placeholder hover:bg-state-base-hover focus:border-components-input-border-active focus:bg-components-input-bg-active focus:shadow-xs',
          className,
        )}
        style={{
          width: `${width}px`,
          minWidth: `${minWidth}px`,
          maxWidth: `${maxWidth}px`,
          transition: 'width 100ms ease-out',
        }}
        placeholder={placeholder}
        onChange={onChange}
        onBlur={onBlur}
        onKeyUp={handleKeyUp}
        {...props}
      />
    </div>
  )
}
 
export default React.memo(AutoWidthInput)