import classNames from 'classnames'; import type { HTMLAttributes } from 'react'; import { useCallback, useMemo, useRef, useState } from 'react'; import { useStateWithDeps } from '../../hooks/useStateWithDeps'; import { IconButton } from './IconButton'; import type { InputProps } from './Input'; import { HStack } from './Stacks'; export type PlainInputProps = Omit & Pick, 'onKeyDownCapture'> & { type?: 'text' | 'password' | 'number'; step?: number; }; export function PlainInput({ className, containerClassName, defaultValue, forceUpdateKey, hideLabel, label, labelClassName, labelPosition = 'top', leftSlot, name, onBlur, onChange, onFocus, onPaste, placeholder, require, rightSlot, size = 'md', type = 'text', validate, autoSelect, step, autoFocus, readOnly, }: PlainInputProps) { const [obscured, setObscured] = useStateWithDeps(type === 'password', [type]); const [currentValue, setCurrentValue] = useState(defaultValue ?? ''); const [focused, setFocused] = useState(false); const inputRef = useRef(null); const textareaRef = useRef(null); const handleFocus = useCallback(() => { setFocused(true); if (autoSelect) { inputRef.current?.select(); textareaRef.current?.select(); } onFocus?.(); }, [autoSelect, onFocus]); const handleBlur = useCallback(() => { setFocused(false); onBlur?.(); }, [onBlur]); const id = `input-${name}`; const commonClassName = classNames( className, '!bg-transparent min-w-0 w-full focus:outline-none placeholder:text-placeholder', 'px-2 text-xs font-mono cursor-text', ); const isValid = useMemo(() => { if (require && !validateRequire(currentValue)) return false; if (typeof validate === 'boolean') return validate; if (typeof validate === 'function' && !validate(currentValue)) return false; return true; }, [require, currentValue, validate]); const handleChange = useCallback( (value: string) => { setCurrentValue(value); onChange?.(value); }, [onChange], ); const wrapperRef = useRef(null); return (
{leftSlot} handleChange(e.target.value)} onPaste={(e) => onPaste?.(e.clipboardData.getData('Text'))} className={classNames(commonClassName, 'h-auto')} onFocus={handleFocus} onBlur={handleBlur} autoFocus={autoFocus} step={step} readOnly={readOnly} /> {type === 'password' && ( setObscured((o) => !o)} /> )} {rightSlot}
); } function validateRequire(v: string) { return v.length > 0; }