import React, { forwardRef, useMemo, useRef, useState } from "react"; import classnames from "classnames"; import { ControlSize, ControlsProps } from "../../common/controls.type"; import Icon, { IconProp } from "../icon"; import IconButton from "../icon-button"; import EyeIcon from "../../icons/eye-icon"; import EyeSlashIcon from "../../icons/eye-slash-icon"; import CloseIcon from "../../icons/close-icon"; import { useCombinedRefs } from "../../hooks/combinedrefs"; type PropPrependAppend = string | React.ReactElement; export interface InputProps extends Omit, "size" | "prefix">, ControlsProps { value?: string; onDebounce?: (value: string) => void; debounceTimeout?: number; prepend?: PropPrependAppend; prefix?: string | React.ReactElement; prefixIcon?: IconProp; prefixText?: string; prefixPlaceholder?: string; suffixPlaceholder?: string; suffixText?: string; suffixIcon?: IconProp; suffix?: string | React.ReactElement; append?: PropPrependAppend; clearable?: boolean; togglePassword?: boolean; htmlSize?: number; fill?: boolean; } const InputIcon = ({ icon, size, focus, success, error, warning, onClick, }: { icon?: IconProp; focus: boolean; onClick?: () => void; } & ControlsProps) => { if (!icon) { return null; } return (
); }; const InputPrefixSuffix = ({ children, onClick, }: { children?: string; onClick?: () => void; }) => { if (!children || children.length == 0) { return null; } return (
{children}
); }; const InputPrefixSuffixPlaceholder = InputPrefixSuffix; const InputPrefixSuffixText = InputPrefixSuffix; const InputPrependAppend = ({ children, type, focus, }: { children?: PropPrependAppend; type: "prepend" | "append"; focus: boolean; }) => { if (!children || (typeof children === "string" && children.length == 0)) { return null; } return (
{children}
); }; interface InputPasswordToggleButtonProps { show: boolean; onChange: (status: boolean) => void; size: ControlSize; } const InputPasswordToggleButton = ({ show, size, onChange, }: InputPasswordToggleButtonProps) => { const toggle = () => { onChange(!show); }; return ( : } onClick={toggle} > ); }; interface InputClearButtonProps { onClear: () => void; size: ControlSize; } const InputClearButton = ({ size, onClear }: InputClearButtonProps) => { return ( } onClick={onClear} > ); }; const Input = forwardRef( ( { value, onChange, onDebounce, debounceTimeout = 200, size = "default", disabled, success, warning, error, prepend, prefix, prefixIcon, prefixText, prefixPlaceholder, suffixPlaceholder, suffixText, suffixIcon, suffix, append, clearable, togglePassword, type, fill, htmlSize, ...restProps }, ref: React.Ref ) => { const handleChange = (e: React.ChangeEvent) => { const value = e.target.value; if (onChange) { onChange(e); } handleDebounce(value); }; let debounceTimer = useRef(); const handleDebounce = (value: string) => { if (!onDebounce) { return; } if (debounceTimer.current) { clearTimeout(debounceTimer.current); } debounceTimer.current = setTimeout(() => { onDebounce(value); }, debounceTimeout); }; const inputZeroPaddingLeft = prefixPlaceholder && prefixPlaceholder.length > 0; const inputZeroPaddingRight = suffixPlaceholder && suffixPlaceholder.length > 0; const inputEl = useRef(null); const combinedRef = useCombinedRefs(inputEl, ref); const focusInput = () => inputEl.current?.focus(); const [focus, setFocus] = useState(false); const handleFocus = (e: React.FocusEvent) => { setFocus(true); if (restProps?.onFocus) { restProps?.onFocus(e); } }; const handleBlur = (e: React.FocusEvent) => { setFocus(false); if (restProps?.onBlur) { restProps?.onBlur(e); } }; const isTogglePasswordButtonVisible = togglePassword && type == "password"; const [currentType, setCurrentType] = useState(type); const isPasswordVisible = useMemo( () => currentType != "password", [currentType] ); const onChangePasswordVisibility = (show: boolean) => { setCurrentType(show ? "text" : "password"); }; const isClearButtonVisible = useMemo(() => { return value != null && value.length > 0 && clearable; }, [value, clearable]); const clear = () => { if (inputEl.current) { inputEl.current.value = ""; inputEl.current.dispatchEvent(new Event("change")); } }; return (
{prepend} {prefix}
{prefixText}
{prefixPlaceholder} {suffixPlaceholder}
{suffixText}
{isClearButtonVisible && ( )} {isTogglePasswordButtonVisible && ( )} {suffix} {append}
); } ); export default Input;