134 lines
2.8 KiB
TypeScript
Raw Normal View History

2024-08-28 10:04:50 +02:00
import {
ChangeEvent,
ComponentType,
CSSProperties,
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";
import { SimpleText } from "../SimpleText/SimpleText";
export interface InputCustomStyleCSS extends CSSProperties {
"--codex-input-background"?: string;
"--codex-color"?: string;
"--codex-border-radius"?: string;
"--codex-input-border"?: string;
"--codex-color-primary"?: string;
"--codex-input-background-disabled"?: string;
}
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 (
<>
{label && (
<label className="input-label" htmlFor={id}>
{label}
</label>
2024-08-20 15:57:58 +02:00
)}
2024-08-28 10:04:50 +02:00
2024-10-25 18:01:37 +02:00
<div
className={classnames(
["input-icon", !!Icon],
[inputContainerClassName]
)}
>
2024-08-28 10:04:50 +02:00
{Icon && (
<div className="input-iconElement">
<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}
className={classnames(
["input"],
2024-10-14 20:36:12 +02:00
["input--invalid", invalid || isInvalid],
2024-08-28 10:04:50 +02:00
["input-icon-input", !!Icon],
[inputClassName || ""]
2024-08-28 10:04:50 +02:00
)}
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-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
{helper && (
<div>
2024-10-14 20:36:12 +02:00
<SimpleText
className="input-helper-text"
variant={invalid || isInvalid ? "error" : "light"}
>
2024-08-28 10:04:50 +02:00
{helper}
</SimpleText>
</div>
)}
</>
);
}
);