import React, { forwardRef, InputHTMLAttributes, ReactNode, useEffect, useRef, useState, } from "react"; import classNames from "classnames"; import { randomString } from ":/utils"; import { Field, FieldProps } from ":/components/Forms/Field"; import { LabelledBox } from ":/components/Forms/LabelledBox"; export type InputOnlyProps = { label?: string; icon?: ReactNode; rightIcon?: ReactNode; charCounter?: boolean; charCounterMax?: number; }; export type InputProps = InputHTMLAttributes & FieldProps & InputOnlyProps; export const Input = forwardRef( ( { className, defaultValue, label, id, icon, rightIcon, charCounter, charCounterMax, ...props }: InputProps, ref, ) => { const classes = ["c__input"]; if (className) { classes.push(className); } const inputRef = useRef(null); const [inputFocus, setInputFocus] = useState(false); const [value, setValue] = useState(defaultValue || props.value || ""); const [labelAsPlaceholder, setLabelAsPlaceholder] = useState(!value); const idToUse = useRef(id || randomString()); const rightTextToUse = charCounter ? `${value.toString().length}/${charCounterMax}` : props.rightText; const updateLabel = () => { if (inputFocus) { setLabelAsPlaceholder(false); return; } setLabelAsPlaceholder(!value); }; useEffect(() => { updateLabel(); }, [inputFocus, value]); // If the input is used as a controlled component, we need to update the local value. useEffect(() => { if (defaultValue !== undefined) { return; } setValue(props.value || ""); }, [props.value]); const { compact, fullWidth, rightText, state, text, textItems, ...inputProps } = props; return ( {/* We disabled linting for this specific line because we consider that the onClick props is only used for */} {/* mouse users, so this do not engender any issue for accessibility. */} {/* eslint-disable-next-line jsx-a11y/no-static-element-interactions */}
{ inputRef.current?.focus(); }} > {!!icon &&
{icon}
} { setInputFocus(true); props.onFocus?.(e); }} onBlur={(e) => { setInputFocus(false); props.onBlur?.(e); }} onChange={(e) => { setValue(e.target.value); props.onChange?.(e); }} ref={(inputTextRef) => { if (ref) { if (typeof ref === "function") { ref(inputTextRef); } else { ref.current = inputTextRef; } } inputRef.current = inputTextRef; }} /> {!!rightIcon && (
{rightIcon}
)}
); }, );