import React, { PropsWithoutRef, RefAttributes, useEffect, useImperativeHandle, useMemo, useRef, useState, } from 'react' import useTheme from '../styles/use-theme' import InputLabel from './input-label' import InputBlockLabel from './input-block-label' import InputIcon from './input-icon' import InputClearIcon from './input-icon-clear' import Textarea from '../textarea/textarea' import InputPassword from './password' import { getSizes, getColors } from './styles' import { Props, defaultProps } from './input-props' type NativeAttrs = Omit, keyof Props> export type InputProps = Props & typeof defaultProps & NativeAttrs const simulateChangeEvent = ( el: HTMLInputElement, event: React.MouseEvent, ): React.ChangeEvent => { return { ...event, target: el, currentTarget: el, } } const Input = React.forwardRef>( ( { label, labelRight, size, status, icon, iconRight, iconClickable, onIconClick, initialValue, onChange, readOnly, value, onClearClick, clearable, width, className, onBlur, onFocus, autoComplete, placeholder, children, disabled, ...props }, ref: React.Ref, ) => { const theme = useTheme() const inputRef = useRef(null) useImperativeHandle(ref, () => inputRef.current) const [selfValue, setSelfValue] = useState(initialValue) const [hover, setHover] = useState(false) const { heightRatio, fontSize } = useMemo(() => getSizes(size), [size]) const showClearIcon = useMemo(() => clearable && selfValue !== '', [selfValue, clearable]) const labelClasses = useMemo(() => (labelRight ? 'right-label' : label ? 'left-label' : ''), [ label, labelRight, ]) const iconClasses = useMemo(() => (iconRight ? 'right-icon' : icon ? 'left-icon' : ''), [ icon, iconRight, ]) const { color, borderColor, hoverBorder } = useMemo(() => getColors(theme.palette, status), [ theme.palette, status, ]) const changeHandler = (event: React.ChangeEvent) => { if (disabled || readOnly) return setSelfValue(event.target.value) onChange && onChange(event) } const clearHandler = (event: React.MouseEvent) => { setSelfValue('') onClearClick && onClearClick(event) /* istanbul ignore next */ if (!inputRef.current) return const changeEvent = simulateChangeEvent(inputRef.current, event) changeEvent.target.value = '' onChange && onChange(changeEvent) inputRef.current.focus() } const focusHandler = (e: React.FocusEvent) => { setHover(true) onFocus && onFocus(e) } const blurHandler = (e: React.FocusEvent) => { setHover(false) onBlur && onBlur(e) } const iconClickHandler = (e: React.MouseEvent) => { if (disabled) return onIconClick && onIconClick(e) } const iconProps = useMemo( () => ({ ratio: heightRatio, clickable: iconClickable, onClick: iconClickHandler, }), [heightRatio, iconClickable], ) useEffect(() => { if (value === undefined) return setSelfValue(value) }, [value]) return (
{children && {children}}
{label && {label}}
{icon && } {clearable && ( )} {iconRight && }
{labelRight && ( {labelRight} )}
) }, ) type InputComponent = React.ForwardRefExoticComponent< PropsWithoutRef

& RefAttributes > & { Textarea: typeof Textarea Password: typeof InputPassword } type ComponentProps = Partial & Omit & NativeAttrs Input.defaultProps = defaultProps export default Input as InputComponent