개인적으로 가장 만들고 싶었던 UI컴포넌트~ InputBox는 기본적으로 대응해야 할 케이스가 아주 다양하기 때문에 그걸 한번 유연하게 처리해보고 싶었다. 특히나 이렇게 state가 존재하는 inputbox는 또 분기 처리하는 게 까탈스럽기 때문에...! 잘 해보고 싶은 욕심이 들었다.
type InputTextProp = {
label?: string;
textHelper?: string;
placeholder?: string;
disabled?: boolean;
state?: "default" | "error" | "success";
value: string;
onChange: (event: React.ChangeEvent<HTMLInputElement>) => void;
};
const InputText = ({
label,
textHelper,
placeholder,
disabled,
state = "default",
value,
onChange,
}: InputTextProp) => {
const inputShape =
"caption-bold border-m1 apperance-none outline-none text-black " +
"tablet:border-t1 desktop:border-d1 " +
(state === "default" && value === ""
? "border-lightgray "
: "border-black ") +
(state === "error"
? "border-error text-error placeholder:text-error "
: "") +
(state === "success"
? "border-success text-success placeholder:text-success "
: "");
const inputLayout =
"w-full px-m16 py-m12 mb-m8 " +
"tablet:p-t16 tablet:mb-t8 desktop:p-d16 desktop:mb-d8 ";
const inputState =
"disabled:bg-extralight disabled:placeholder:text-lightgray " +
(value === "" && state === "default"
? "pointerhover:hover:border-gray disabled:pointerhover:hover:border-lightgray "
: "");
// + "focus-within:shadow-[0px_0px_2px_2px_#0D69D4] ";
const inputStyle = inputShape + inputLayout + inputState;
return (
<label className="w-full">
<p className="heading6 mb-m12 tablet:mb-t12 desktop:mb-d12">{label}</p>
<input
className={inputStyle}
disabled={disabled}
type="text"
placeholder={placeholder}
value={value}
onChange={onChange}
/>
{state === "default" && (
<p className="caption-small text-gray">{textHelper}</p>
)}
{state === "error" && (
<p className="caption-small flex items-center text-error">
<ErrorIcon className="inline-block h-m16 w-m16 fill-error tablet:h-t16 tablet:w-t16 desktop:h-d16 desktop:w-d16" />
{textHelper}
</p>
)}
{state === "success" && (
<p className="caption-small text-success">
<CorrectIcon className="fill-succeess inline-block h-m16 w-m16 tablet:h-t16 tablet:w-t16 desktop:h-d16 desktop:w-d16" />
{textHelper}
</p>
)}
</label>
);
};
아~ tailwind 이번에 프로젝트 끝나면 진짜 안 써야지😇 한 번 거슬리니까 계속 거슬리네
...를 하고 싶어서 input 태그의 pseudo-class를 알아보았지만 별 소득은 없었다. (사실은 내가 잘 활용을 못한 것 같다ㅋㅋ)
valid, invalid
.*
, .+
const inputShape = "border "
const inputState =
"valid:border-blue-500 " +
"invalid:border-red-500 "
const inputStyle = inputShape + inputState
<input type="text" className={inputStyle} required />
blank, empty
placeholder-shown
import plugin from "tailwindcss/plugin";
/** @type {import('tailwindcss').Config} */
export default {
plugins: [
plugin(function ({ addVariant }) {
addVariant("not-placeholder-shown", "&:not(:placeholder-shown)");
}),
],
}
아참, 여담으로 tailwind plugin이 안 먹히는 이유를 알아냈다. plugin을 import할 때 tailwindcss가 아닌 tailwindcss/plugin으로 했어야 했다😇
const inputShape = "border "
const inputState =
"not-placeholder-shown:border-blue-500 " +
"placeholder-shown:border-red-500 "
const inputStyle = inputShape + inputState
<input type="text" className={inputStyle} required />