2025-07-25 19:37:25 +04:00

110 lines
2.6 KiB
TypeScript

import {
cloneElement,
isValidElement,
useId,
type ReactElement,
type ReactNode,
} from "react";
import type { BaseProps, HTMLProps } from "../../shared/types";
import { cn } from "../../shared/utils/cn";
import { Typography } from "../typography/Typography";
import { cloneIcon } from "../../shared/utils/clone-icon";
export type InputProps = Omit<
HTMLProps<"input">,
"label" | "aria-invalid" | "checked"
> & {
label: string;
start?: ReactElement<HTMLProps<"svg">>;
end?: ReactElement<HTMLProps<"svg">>;
error?: string;
hint?: string;
} & BaseProps;
export const Input = ({
className,
label,
id: propId,
disabled,
value,
onChange,
start,
end,
error,
type,
hint,
readOnly,
testId,
...props
}: InputProps) => {
const generatedId = useId();
const id = propId ?? generatedId;
const iconCss = cn(
"w-6 h-6 text-light-neutral-300",
error && " text-red-400"
);
return (
<label
htmlFor={id}
data-testid={testId}
className={cn(
"flex flex-col gap-y-2",
disabled ? "cursor-not-allowed opacity-50" : "cursor-pointer"
)}
>
<Typography.Text fontSize="s" className="text-light-neutral-200">
{label}
</Typography.Text>
<div
className={cn(
"flex flex-row items-center gap-x-2.5",
"py-4.25 px-4",
"border-light-neutral-500 border-1 rounded-2xl",
// base
"bg-light-neutral-950",
// hover modifier
"hover:bg-light-neutral-900",
// focus modifier
"focus-within:bg-light-neutral-900",
// error state
error && " border-red-400 bg-light-neutral-970",
readOnly &&
"bg-light-neutral-985 border-none hover:bg-light-neutral-985 cursor-auto",
// disabled modifier
disabled && "hover:bg-light-neutral-950"
)}
>
{cloneIcon(start, {
className: iconCss,
})}
<input
id={id}
type={type}
value={value}
onChange={onChange}
disabled={disabled}
aria-invalid={error ? "true" : "false"}
readOnly={readOnly}
className={cn(
"flex-1 outline-none caret-primary-500 text-white",
"placeholder:text-light-neutral-300",
error && "text-red-400"
)}
{...props}
/>
{cloneIcon(end, {
className: iconCss,
})}
</div>
<Typography.Text
fontSize="xs"
className={cn("text-light-neutral-600 ml-4", error && "text-red-400")}
>
{error ?? hint}
</Typography.Text>
</label>
);
};