import React, { PropsWithoutRef, RefAttributes, useEffect, useImperativeHandle, useMemo, useRef, useState, } from 'react' import useTheme from '../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 isControlledComponent = useMemo(() => value !== undefined, [value]) 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, iconClickHandler], ) useEffect(() => { if (isControlledComponent) { setSelfValue(value as string) } }) const controlledValue = isControlledComponent ? { value: selfValue } : { defaultValue: initialValue } const inputProps = { ...props, ...controlledValue, } 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