cvsa/packages/next/components/ui/TextField.tsx

108 lines
2.9 KiB
TypeScript

"use client";
import React, { useState } from "react";
interface InputProps extends React.HTMLAttributes<HTMLDivElement> {
labelText?: string;
type?: React.HTMLInputTypeAttribute;
inputText?: string;
onInputTextChange?: (value: string) => void;
maxChar?: number;
supportingText?: string;
variant: "filled" | "outlined" | "standard";
}
const OutlineTextField: React.FC<InputProps> = ({
labelText = "",
type = "text",
inputText: initialInputText = "",
onInputTextChange,
maxChar,
supportingText,
...rest
}) => {
const [focus, setFocus] = useState(false);
const [inputText, setInputText] = useState(initialInputText);
const handleValueChange = (event: React.ChangeEvent<HTMLInputElement>) => {
const { value } = event.target;
setInputText(value);
onInputTextChange?.(value);
};
return (
<div {...rest}>
<div className="relative h-14 px-4">
<div className="absolute flex top-0 left-0 h-full w-full">
<div
className={`w-3 rounded-l-sm border-outline dark:border-dark-outline
${
focus
? "border-primary dark:border-dark-primary border-l-2 border-y-2"
: "border-l-[1px] border-y-[1px] "
}
`}
></div>
<div
className={`px-1 border-outline dark:border-dark-outline transition-none
${!focus && !inputText ? "border-y-[1px]" : ""}
${!focus && inputText ? "border-y-[1px] border-t-0" : ""}
${focus ? "border-primary dark:border-dark-primary border-y-2 border-t-0" : ""}
`}
>
<span
className={`
relative leading-6 text-base text-on-surface-variant
dark:text-dark-on-surface-variant duration-150
${focus || inputText ? "-top-3 text-xs leading-4" : "top-4"}
${focus ? "text-primary dark:text-dark-primary" : ""}
`}
>
{labelText}
</span>
</div>
<div
className={`flex-grow rounded-r-sm border-outline dark:border-dark-outline
${focus ?
"border-primary dark:border-dark-primary border-r-2 border-y-2" :
"border-r-[1px] border-y-[1px] "}
`}
></div>
</div>
<input
className="relative focus:outline-none h-full w-full"
onFocus={() => setFocus(true)}
onBlur={() => setFocus(false)}
onChange={handleValueChange}
type={type}
value={inputText}
/>
</div>
{(supportingText || maxChar) && (
<div
className="w-full relative mt-1 text-on-surface-variant
dark:text-dark-on-surface-variant text-xs leading-4 h-4"
>
{supportingText && <span className="absolute left-4">{supportingText}</span>}
{maxChar && (
<span className={`absolute right-4 ${inputText.length > maxChar ? "text-red-500" : ""}`}>
{inputText.length}/{maxChar}
</span>
)}
</div>
)}
</div>
);
};
const TextField: React.FC<InputProps> = (props) => {
if (!props.variant || props.variant === "outlined") {
return <OutlineTextField {...props} />;
}
};
export default TextField;