// frontend\src\components\ui\TextInput.tsx 'use client' import { useRef, useCallback, forwardRef, type InputHTMLAttributes, type Ref, } from 'react' type TextInputSize = 'sm' | 'md' | 'lg' export type TextInputProps = Omit< InputHTMLAttributes, 'size' > & { size?: TextInputSize selectAllOnFocus?: boolean selectAllOnMouseDown?: boolean } const baseClassName = ` block w-full min-w-0 bg-white text-gray-900 shadow-sm ring-1 ring-gray-200 focus:outline-none focus:ring-2 focus:ring-indigo-500 dark:bg-white/10 dark:text-white dark:ring-white/10 dark:[color-scheme:dark] ` const sizeClassName: Record = { sm: 'rounded-md px-3 py-2 text-sm', md: 'rounded-lg px-3 py-2.5 text-sm', lg: 'rounded-lg px-4 py-3 text-base', } function assignRef(ref: Ref | undefined, value: T | null) { if (!ref) return if (typeof ref === 'function') { ref(value) return } ;(ref as { current: T | null }).current = value } const TextInput = forwardRef( ( { className = '', type = 'text', size = 'md', selectAllOnFocus = false, selectAllOnMouseDown = false, onFocus, onMouseDown, ...props }, forwardedRef ) => { const innerRef = useRef(null) const setRefs = useCallback( (node: HTMLInputElement | null) => { innerRef.current = node assignRef(forwardedRef, node) }, [forwardedRef] ) const selectAll = useCallback(() => { const el = innerRef.current if (!el) return el.focus() requestAnimationFrame(() => el.select()) }, []) return ( { onFocus?.(e) if (selectAllOnFocus) { selectAll() } }} onMouseDown={(e) => { onMouseDown?.(e) if (!selectAllOnMouseDown) return if (e.button !== 0) return e.preventDefault() selectAll() }} /> ) } ) TextInput.displayName = 'TextInput' export default TextInput