dramaling-vocab-learning/frontend/components/review/shared/SentenceInput.tsx

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'