66 lines
1.9 KiB
TypeScript
66 lines
1.9 KiB
TypeScript
import React, { memo, useCallback, useMemo } from 'react'
|
|
|
|
interface SentenceInputProps {
|
|
value: string
|
|
onChange: (value: string) => void
|
|
onSubmit: () => void
|
|
disabled?: boolean
|
|
placeholder?: string
|
|
showResult?: boolean
|
|
targetWordLength?: number
|
|
className?: string
|
|
}
|
|
|
|
export const SentenceInput = memo<SentenceInputProps>(({
|
|
value,
|
|
onChange,
|
|
onSubmit,
|
|
disabled = false,
|
|
placeholder = '',
|
|
showResult = false,
|
|
targetWordLength = 0,
|
|
className = ''
|
|
}) => {
|
|
const handleChange = useCallback((e: React.ChangeEvent<HTMLInputElement>) => {
|
|
onChange(e.target.value)
|
|
}, [onChange])
|
|
|
|
const handleKeyDown = useCallback((e: React.KeyboardEvent) => {
|
|
if (e.key === 'Enter' && !showResult && value.trim()) {
|
|
onSubmit()
|
|
}
|
|
}, [onSubmit, showResult, value])
|
|
|
|
const inputWidth = useMemo(() => {
|
|
return Math.max(100, Math.max(targetWordLength * 12, value.length * 12 + 20))
|
|
}, [targetWordLength, value.length])
|
|
|
|
return (
|
|
<span className={`relative inline-block mx-1 ${className}`}>
|
|
<input
|
|
type="text"
|
|
value={value}
|
|
onChange={handleChange}
|
|
onKeyDown={handleKeyDown}
|
|
placeholder={placeholder}
|
|
disabled={disabled || showResult}
|
|
className={`inline-block px-2 py-1 text-center bg-transparent focus:outline-none disabled:bg-gray-100 ${
|
|
value
|
|
? 'border-b-2 border-blue-500'
|
|
: 'border-b-2 border-dashed border-gray-400 focus:border-blue-400 focus:border-solid'
|
|
}`}
|
|
style={{ width: `${inputWidth}px` }}
|
|
/>
|
|
{!value && (
|
|
<span
|
|
className="absolute inset-0 flex items-center justify-center text-gray-400 pointer-events-none"
|
|
style={{ paddingBottom: '8px' }}
|
|
>
|
|
____
|
|
</span>
|
|
)}
|
|
</span>
|
|
)
|
|
})
|
|
|
|
SentenceInput.displayName = 'SentenceInput' |