diff --git a/src/app/preview/input/page.tsx b/src/app/preview/input/page.tsx new file mode 100644 index 0000000..2f9211e --- /dev/null +++ b/src/app/preview/input/page.tsx @@ -0,0 +1,142 @@ +import { Input } from '@/components/ui/Input'; + +export default function ButtonExamples() { + return ( +
+

Normal

+

large normal

+
+ +
+ +

large typing

+
+ +
+ +

large done

+
+ +
+ +

large error

+
+ +
+ +

large disable

+
+ +
+ +

small normal

+
+ +
+ +

small typing

+
+ +
+ +

small done

+
+ +
+ +

small error

+
+ +
+ +

small disable

+
+ +
+ +

Password

+

large normal

+
+ +
+ +

large typing

+
+ +
+ +

large done

+
+ +
+ +

large error

+
+ +
+ +

large disable

+
+ +
+ +

small normal

+
+ +
+ +

small typing

+
+ +
+ +

small done

+
+ +
+ +

small error

+
+ +
+ +

small disable

+
+ +
+ +

width 커스텀

+
+ +
+
+ +
+ + +
+ ); +} diff --git a/src/components/ui/Input.tsx b/src/components/ui/Input.tsx new file mode 100644 index 0000000..4b5067c --- /dev/null +++ b/src/components/ui/Input.tsx @@ -0,0 +1,147 @@ +'use client'; + +import { cn } from '@/util/cn'; +import { VariantProps, cva } from 'class-variance-authority'; +import { Eye, EyeOff } from 'lucide-react'; +import * as React from 'react'; + +interface IInputProps + extends React.InputHTMLAttributes, + VariantProps { + /** + * 입력 필드의 상태 (기본값: `'default'`) + * - `'default'` : 기본 상태 (테두리 없음) + * - `'success'` : 성공 상태 (메인 컬러 테두리 적용) + */ + state?: 'default' | 'success'; + /** + * 입력 필드의 크기 (기본값: `'l'`) + * - `'s'` : 작은 크기 (36px) + * - `'l'` : 기본 크기 (50px) + */ + inputSize?: 'l' | 's'; + /** + * 에러 메시지 (에러 상태일 때 표시) + */ + errorMessage?: string; +} + +const inputVariants = cva( + 'box-border flex w-full rounded-md border-transparent bg-Cgray200 px-3 px-[16px] py-1 py-[14px] text-base text-Cgray700 caret-Cgray500 shadow-sm transition-colors placeholder:text-Cgray400 focus:outline-none focus-visible:outline-none disabled:cursor-not-allowed disabled:bg-disable disabled:text-disable_text md:text-sm', + { + variants: { + state: { + default: '', + success: 'border border-main', + }, + inputSize: { + s: 'typo-button2 h-[36px]', + l: 'typo-button1 h-[50px] py-[10px]', + }, + }, + defaultVariants: { + inputSize: 'l', + }, + }, +); + +const errorTextVariants = cva('px-[10px] text-warning', { + variants: { + inputSize: { + s: 'typo-caption2 mt-[8px]', + l: 'typo-caption1 mt-[10px]', + }, + defaultVariants: { + inputSize: 'l', + }, + }, +}); + +/** + * `Input` 컴포넌트 + * + * 기본적인 입력 필드로, 텍스트 및 비밀번호 입력을 지원하며, + * 에러 상태 및 성공 상태를 지정할 수 있습니다. + * 접근성을 위해 id가 필수적으로 필요합니다. + * + * @example + * // 기본 사용법 + * + * + * @example + * // 에러 상태 + * + * + * @example + * // 성공 상태 + * + * + * @example + * // 비밀번호 입력 필드 (눈 아이콘 포함) + * + * + * @param {IInputProps} props - `Input` 컴포넌트의 속성 + * @returns {JSX.Element} `Input` 요소 + */ +const Input = React.forwardRef( + ( + { + className, + type, + state = 'default', + errorMessage, + inputSize = 'l', + id, + ...props + }, + ref, + ) => { + const [isVisible, setIsVisible] = React.useState(false); + + return ( +
+
+ + +
+ {errorMessage && ( +

+ {errorMessage} +

+ )} +
+ ); + }, +); + +Input.displayName = 'Input'; + +export { Input };