108 lines
2.2 KiB
TypeScript
Raw Normal View History

2024-08-28 10:04:50 +02:00
import {
ChangeEvent,
ComponentType,
forwardRef,
2024-10-14 20:36:12 +02:00
InputHTMLAttributes,
useState,
2024-08-28 10:04:50 +02:00
} from "react";
import { attributes } from "../utils/attributes";
import { classnames } from "../utils/classnames";
2024-08-20 15:57:58 +02:00
import "./input.css";
type Props = {
id: string;
2024-10-14 20:36:12 +02:00
label?: string;
2024-08-20 15:57:58 +02:00
/**
* Helper text to add indication about your input.
*/
helper?: string;
/**
* Add an icon on the left.
*/
Icon?: ComponentType;
/**
2024-10-14 20:36:12 +02:00
* If the mode is "auto", the component will check the invalid state
* on change and add an invalid state if it is invalid.
*/
2024-10-14 20:36:12 +02:00
mode?: "auto";
isInvalid?: boolean;
2024-08-20 15:57:58 +02:00
/**
2024-10-14 20:36:12 +02:00
* Apply a class to the input element
2024-08-20 15:57:58 +02:00
*/
2024-10-14 20:36:12 +02:00
inputClassName?: string;
2024-10-25 18:01:37 +02:00
inputContainerClassName?: string;
2024-10-14 20:36:12 +02:00
} & InputHTMLAttributes<HTMLInputElement>;
2024-08-20 15:57:58 +02:00
2024-08-28 10:04:50 +02:00
export const Input = forwardRef<HTMLInputElement, Props>(
(
{
id,
label,
helper,
style,
Icon,
inputClassName,
2024-10-25 18:01:37 +02:00
inputContainerClassName = "",
2024-10-14 20:36:12 +02:00
disabled = false,
onChange,
mode,
isInvalid = false,
...rest
2024-08-28 10:04:50 +02:00
},
ref
) => {
2024-10-14 20:36:12 +02:00
const [invalid, setInvalid] = useState(isInvalid);
const onInternalChange = (e: ChangeEvent<HTMLInputElement>) => {
if (mode === "auto") {
setInvalid(e.currentTarget.checkValidity() !== true);
}
onChange?.(e);
};
2024-08-28 10:04:50 +02:00
return (
2024-10-30 19:20:43 +01:00
<div
className={classnames(
["input"],
["input--invalid", invalid || isInvalid],
["input--icon", !!Icon],
[inputClassName || ""]
2024-08-20 15:57:58 +02:00
)}
2024-10-30 19:20:43 +01:00
>
{label && <label htmlFor={id}>{label}</label>}
2024-08-28 10:04:50 +02:00
2024-10-30 19:20:43 +01:00
<div className={classnames([inputContainerClassName])}>
2024-08-28 10:04:50 +02:00
{Icon && (
2024-10-30 19:20:43 +01:00
<div>
2024-08-28 10:04:50 +02:00
<Icon />
</div>
2024-08-20 15:57:58 +02:00
)}
2024-08-28 10:04:50 +02:00
<input
2024-09-16 19:06:51 +02:00
id={id}
2024-08-28 10:04:50 +02:00
ref={ref}
2024-10-30 19:20:43 +01:00
className={classnames([inputClassName || ""])}
2024-10-14 20:36:12 +02:00
onChange={onInternalChange}
2024-08-28 10:04:50 +02:00
style={style}
{...attributes({
disabled,
"aria-disabled": disabled,
2024-10-30 19:20:43 +01:00
"aria-invalid": invalid || isInvalid,
2024-08-28 10:04:50 +02:00
})}
2024-10-14 20:36:12 +02:00
{...rest}
2024-08-28 10:04:50 +02:00
/>
2024-08-20 15:57:58 +02:00
</div>
2024-08-28 10:04:50 +02:00
2024-10-30 19:20:43 +01:00
{helper && <small>{helper}</small>}
</div>
2024-08-28 10:04:50 +02:00
);
}
);