import debounce from 'lodash/debounce.js'; import type { CSSProperties, ChangeEvent, ForwardedRef, ReactElement, } from 'react'; import { forwardRef, useEffect, useMemo, useRef, useState } from 'react'; import useCombinedRefs from '../hooks/useCombinedRefs.js'; const styles: Record<'input' | 'inputWrapper' | 'clearButton', CSSProperties> = { inputWrapper: { borderRadius: '5px', borderWidth: '0.55px', borderColor: '#c7c7c7', borderStyle: 'solid', display: 'flex', flexDirection: 'row', alignItems: 'center', overflow: 'hidden', }, input: { outline: 'none', flex: 1, height: '100%', width: '100%', }, clearButton: { height: 'calc(100% - 4px)', borderRadius: '50%', backgroundColor: 'gray', color: 'white', aspectRatio: '1', fontSize: '60%', padding: 0, }, }; function mapValue(value: any) { return typeof value === 'number' && value === 0 ? value : value || ''; } export interface InputStyle { input?: CSSProperties; inputWrapper?: CSSProperties; } interface InputProps extends Omit< React.InputHTMLAttributes, 'style' > { style?: InputStyle; autoSelect?: boolean; checkValue?: (element: number | string) => boolean; format?: () => (element: string) => number | string; renderIcon?: (() => ReactElement) | null; canClear?: boolean; onClear?: () => void; datalist?: string[]; debounceTime?: number; small?: boolean; } const Input = forwardRef( (props: InputProps, ref: ForwardedRef) => { const { value: externalValue = undefined, name, style = { input: {}, inputWrapper: {}, }, onChange, checkValue = () => true, type = 'text', autoSelect = false, className, renderIcon, canClear = false, onClear, datalist = [], debounceTime = 0, small = false, ...otherProps } = props; const [internalValue, setInternalValue] = useState['value']>(); const value = debounceTime ? internalValue : externalValue; const localRef = useRef(null); const combinedRef = useCombinedRefs([ref, localRef]); const [isDebounced, setDebouncedStatus] = useState(false); const debounceOnChange = useMemo( () => debounce((e: any) => { onChange?.(e); setDebouncedStatus(true); }, debounceTime), [debounceTime, onChange], ); useEffect(() => { if (autoSelect) { combinedRef?.current?.select(); } }, [autoSelect, combinedRef]); useEffect(() => { if (debounceTime) { setInternalValue(externalValue); } }, [debounceTime, externalValue]); function onChangeHandler(e: ChangeEvent) { e.stopPropagation(); e.preventDefault(); const val = e.target.value; setDebouncedStatus(false); if (checkValue(val)) { if (debounceTime) { setInternalValue(val); debounceOnChange(e); } else { onChange?.(e); } } } function clearHandler() { localRef.current?.setAttribute('value', ''); onClear?.(); } return (
{renderIcon?.()} {canClear && value && ( )} {datalist.map((value) => (
); }, ); export default Input;