import classnames from 'classnames'; import type { HTMLAttributes, ReactNode } from 'react'; import { useCallback, useMemo, useState } from 'react'; import type { EditorProps } from './Editor'; import { Editor } from './Editor'; import { IconButton } from './IconButton'; import { HStack, VStack } from './Stacks'; export type InputProps = Omit, 'onChange' | 'onFocus'> & Pick & { name: string; type?: 'text' | 'password'; label: string; hideLabel?: boolean; labelClassName?: string; containerClassName?: string; onChange?: (value: string) => void; onFocus?: () => void; defaultValue?: string; leftSlot?: ReactNode; rightSlot?: ReactNode; size?: 'sm' | 'md'; className?: string; placeholder?: string; autoFocus?: boolean; validate?: (v: string) => boolean; require?: boolean; }; export function Input({ label, type = 'text', hideLabel, className, containerClassName, labelClassName, onChange, placeholder, size = 'md', name, leftSlot, rightSlot, defaultValue, validate, require, forceUpdateKey, ...props }: InputProps) { const [obscured, setObscured] = useState(type === 'password'); const [currentValue, setCurrentValue] = useState(defaultValue ?? ''); const id = `input-${name}`; const inputClassName = classnames( className, '!bg-transparent min-w-0 h-full w-full focus:outline-none placeholder:text-placeholder', // Bump things over if the slots are occupied leftSlot && 'pl-0.5 -ml-2', rightSlot && 'pr-0.5 -mr-2', ); const isValid = useMemo(() => { if (require && !validateRequire(currentValue)) return false; if (validate && !validate(currentValue)) return false; return true; }, [currentValue, validate, require]); const handleChange = useCallback((value: string) => { setCurrentValue(value); onChange?.(value); }, []); return ( {leftSlot} {type === 'password' && ( setObscured((o) => !o)} /> )} {rightSlot} ); } function validateRequire(v: string) { return v.length > 0; }