From 474f41270aa095effc3b593cec14d87ad4f5b078 Mon Sep 17 00:00:00 2001 From: dbswl701 Date: Fri, 14 Feb 2025 14:47:36 +0900 Subject: [PATCH 1/9] =?UTF-8?q?feat(DEVING-34):=20=EC=9D=B8=ED=92=8B=20?= =?UTF-8?q?=EA=B8=B0=EB=B3=B8=20=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/app/preview/input/page.tsx | 11 +++++++++++ src/components/ui/input.tsx | 23 +++++++++++++++++++++++ 2 files changed, 34 insertions(+) create mode 100644 src/app/preview/input/page.tsx create mode 100644 src/components/ui/input.tsx diff --git a/src/app/preview/input/page.tsx b/src/app/preview/input/page.tsx new file mode 100644 index 0000000..54139aa --- /dev/null +++ b/src/app/preview/input/page.tsx @@ -0,0 +1,11 @@ +import { Input } from '@/components/ui/Input'; + +export default function ButtonExamples() { + return ( +
+
+ +
+
+ ); +} diff --git a/src/components/ui/input.tsx b/src/components/ui/input.tsx new file mode 100644 index 0000000..61a46d9 --- /dev/null +++ b/src/components/ui/input.tsx @@ -0,0 +1,23 @@ +import { cn } from '@/util/cn'; +import * as React from 'react'; + +const Input = React.forwardRef>( + ({ className, type, ...props }, ref) => { + // 기본 fill, + return ( + + ); + }, +); +Input.displayName = 'Input'; + +export { Input }; From beeda2a27fe2290a434c52befe3e6eb3a808fa35 Mon Sep 17 00:00:00 2001 From: dbswl701 Date: Fri, 14 Feb 2025 15:16:35 +0900 Subject: [PATCH 2/9] =?UTF-8?q?feat(DEVING-34):=20disabled,=20success,=20e?= =?UTF-8?q?rror=20=EC=83=81=ED=83=9C=20=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/app/preview/input/page.tsx | 16 ++++++++++++- src/components/ui/input.tsx | 41 ++++++++++++++++++++++++---------- 2 files changed, 44 insertions(+), 13 deletions(-) diff --git a/src/app/preview/input/page.tsx b/src/app/preview/input/page.tsx index 54139aa..c905435 100644 --- a/src/app/preview/input/page.tsx +++ b/src/app/preview/input/page.tsx @@ -3,9 +3,23 @@ import { Input } from '@/components/ui/Input'; export default function ButtonExamples() { return (
-
+
+ +
+ +
+ +
+
+
+ +
); } diff --git a/src/components/ui/input.tsx b/src/components/ui/input.tsx index 61a46d9..67101fa 100644 --- a/src/components/ui/input.tsx +++ b/src/components/ui/input.tsx @@ -1,20 +1,37 @@ import { cn } from '@/util/cn'; import * as React from 'react'; -const Input = React.forwardRef>( - ({ className, type, ...props }, ref) => { - // 기본 fill, +interface IInputProps extends React.ComponentProps<'input'> { + isValid?: boolean; + errorMessage?: string; +} + +const Input = React.forwardRef( + ({ className, type, isValid, errorMessage, ...props }, ref) => { return ( - + + {errorMessage && ( +

+ {errorMessage} +

)} - ref={ref} - {...props} - /> +
); }, ); From dd268edb4d38d288f6a9badb1b4c0e7c3246965c Mon Sep 17 00:00:00 2001 From: dbswl701 Date: Fri, 14 Feb 2025 15:22:24 +0900 Subject: [PATCH 3/9] =?UTF-8?q?style(DEVING-34):=20caret=20=EC=83=89?= =?UTF-8?q?=EC=83=81=20=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/components/ui/input.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/components/ui/input.tsx b/src/components/ui/input.tsx index 67101fa..21b406d 100644 --- a/src/components/ui/input.tsx +++ b/src/components/ui/input.tsx @@ -15,12 +15,12 @@ const Input = React.forwardRef( className={cn( 'flex w-full rounded-md border-input bg-transparent px-3 py-1 text-base shadow-sm transition-colors file:border-0 file:bg-transparent file:text-sm file:font-medium file:text-foreground placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring md:text-sm', 'typo-button1 box-border h-[50px] bg-Cgray200 px-[16px] py-[14px] text-Cgray700 placeholder:text-Cgray400', - 'disabled:cursor-not-allowed disabled:bg-disable disabled:text-disable_text', + 'caret-Cgray500 disabled:cursor-not-allowed disabled:bg-disable disabled:text-disable_text', isValid === undefined ? '' : isValid ? 'border border-main' - : 'border border-warning text-warning', + : 'border border-warning text-warning caret-warning', className, )} ref={ref} From bd8f320acc5ce26be6363835c85b77f04aa524b0 Mon Sep 17 00:00:00 2001 From: dbswl701 Date: Fri, 14 Feb 2025 15:38:42 +0900 Subject: [PATCH 4/9] =?UTF-8?q?feat(DEVING-34):=20input=20=EC=82=AC?= =?UTF-8?q?=EC=9D=B4=EC=A6=88=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/app/preview/input/page.tsx | 13 +++++++++++++ src/components/ui/input.tsx | 20 ++++++++++++++++---- 2 files changed, 29 insertions(+), 4 deletions(-) diff --git a/src/app/preview/input/page.tsx b/src/app/preview/input/page.tsx index c905435..3d8e632 100644 --- a/src/app/preview/input/page.tsx +++ b/src/app/preview/input/page.tsx @@ -3,6 +3,19 @@ import { Input } from '@/components/ui/Input'; export default function ButtonExamples() { return (
+
+ +
+ +
+ +
+
diff --git a/src/components/ui/input.tsx b/src/components/ui/input.tsx index 21b406d..9bb9f76 100644 --- a/src/components/ui/input.tsx +++ b/src/components/ui/input.tsx @@ -4,30 +4,42 @@ import * as React from 'react'; interface IInputProps extends React.ComponentProps<'input'> { isValid?: boolean; errorMessage?: string; + inputSize?: 's' | 'l'; } const Input = React.forwardRef( - ({ className, type, isValid, errorMessage, ...props }, ref) => { + ( + { className, type, isValid, errorMessage, inputSize = 'l', ...props }, + ref, + ) => { return (
{errorMessage && ( -

+

{errorMessage}

)} From 198bd5a3a3da19541d22f2d662ea44113d42f7c5 Mon Sep 17 00:00:00 2001 From: dbswl701 Date: Fri, 14 Feb 2025 17:14:41 +0900 Subject: [PATCH 5/9] =?UTF-8?q?refactor(DEVING-34):=20=EC=8A=A4=ED=83=80?= =?UTF-8?q?=EC=9D=BC=20=ED=81=B4=EB=9E=98=EC=8A=A4=20=EC=A1=B0=ED=95=A9=20?= =?UTF-8?q?cn=EC=97=90=EC=84=9C=20cva=EB=A1=9C=20=EB=A6=AC=ED=8E=99?= =?UTF-8?q?=ED=86=A0=EB=A7=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/components/ui/input.tsx | 66 ++++++++++++++++++++++--------------- 1 file changed, 39 insertions(+), 27 deletions(-) diff --git a/src/components/ui/input.tsx b/src/components/ui/input.tsx index 9bb9f76..d161e78 100644 --- a/src/components/ui/input.tsx +++ b/src/components/ui/input.tsx @@ -1,45 +1,56 @@ import { cn } from '@/util/cn'; +import { VariantProps, cva } from 'class-variance-authority'; import * as React from 'react'; -interface IInputProps extends React.ComponentProps<'input'> { - isValid?: boolean; +interface IInputProps + extends React.InputHTMLAttributes, + VariantProps { errorMessage?: string; - inputSize?: 's' | 'l'; } +const inputVariants = cva( + 'box-border flex w-full rounded-md border-input bg-Cgray200 px-3 px-[16px] py-1 py-[14px] text-base text-Cgray700 caret-Cgray500 shadow-sm transition-colors file:border-0 file:bg-transparent file:text-sm file:font-medium file:text-foreground placeholder:text-Cgray400 placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring disabled:cursor-not-allowed disabled:bg-disable disabled:text-disable_text md:text-sm', + { + variants: { + isValid: { + true: 'border border-main', + false: 'border border-warning text-warning caret-warning', + }, + 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', + }, + }, +}); + const Input = React.forwardRef( - ( - { className, type, isValid, errorMessage, inputSize = 'l', ...props }, - ref, - ) => { + ({ className, type, isValid, errorMessage, inputSize, ...props }, ref) => { return (
{errorMessage && ( -

+

{errorMessage}

)} @@ -47,6 +58,7 @@ const Input = React.forwardRef( ); }, ); + Input.displayName = 'Input'; export { Input }; From 685f9b1f110d6f22a7ded98d63b3e5617ab1de74 Mon Sep 17 00:00:00 2001 From: dbswl701 Date: Mon, 17 Feb 2025 14:32:12 +0900 Subject: [PATCH 6/9] =?UTF-8?q?feat(DEVING-34):=20=EB=B9=84=EB=B0=80?= =?UTF-8?q?=EB=B2=88=ED=98=B8=20=ED=83=80=EC=9E=85=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/components/ui/input.tsx | 32 ++++++++++++++++++++++++++------ 1 file changed, 26 insertions(+), 6 deletions(-) diff --git a/src/components/ui/input.tsx b/src/components/ui/input.tsx index d161e78..a4c5d4c 100644 --- a/src/components/ui/input.tsx +++ b/src/components/ui/input.tsx @@ -1,5 +1,8 @@ +'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 @@ -41,14 +44,31 @@ const errorTextVariants = cva('px-[10px] text-warning', { const Input = React.forwardRef( ({ className, type, isValid, errorMessage, inputSize, ...props }, ref) => { + const [isVisible, setIsVisible] = React.useState(false); + return (
- +
+ + +
{errorMessage && (

{errorMessage} From 157519eaea036cf83134221d6ee569615bce0393 Mon Sep 17 00:00:00 2001 From: dbswl701 Date: Wed, 19 Feb 2025 10:50:15 +0900 Subject: [PATCH 7/9] =?UTF-8?q?feat(DEVING-34):=20=EC=84=A4=EB=AA=85=20?= =?UTF-8?q?=EC=B6=94=EA=B0=80=20=EB=B0=8F=20=EC=97=90=EB=9F=AC=EC=8B=9C=20?= =?UTF-8?q?=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/app/preview/input/page.tsx | 120 ++++++++++++++++++++++++++++++--- src/components/ui/input.tsx | 76 ++++++++++++++++++--- 2 files changed, 178 insertions(+), 18 deletions(-) diff --git a/src/app/preview/input/page.tsx b/src/app/preview/input/page.tsx index 3d8e632..2f9211e 100644 --- a/src/app/preview/input/page.tsx +++ b/src/app/preview/input/page.tsx @@ -2,37 +2,141 @@ 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 index a4c5d4c..e028595 100644 --- a/src/components/ui/input.tsx +++ b/src/components/ui/input.tsx @@ -8,16 +8,33 @@ import * as React from 'react'; interface IInputProps extends React.InputHTMLAttributes, VariantProps { + /** + * 입력 필드의 상태 (기본값: `'default'`) + * - `'default'` : 기본 상태 (테두리 없음) + * - `'success'` : 성공 상태 (메인 컬러 테두리 적용) + * - `'error'` : 에러 상태 (경고 컬러 테두리 및 텍스트 적용) + */ + state?: 'default' | 'success' | 'error'; + /** + * 입력 필드의 크기 (기본값: `'l'`) + * - `'s'` : 작은 크기 (36px) + * - `'l'` : 기본 크기 (50px) + */ + inputSize?: 'l' | 's'; + /** + * 에러 메시지 (에러 상태일 때 표시) + */ errorMessage?: string; } const inputVariants = cva( - 'box-border flex w-full rounded-md border-input bg-Cgray200 px-3 px-[16px] py-1 py-[14px] text-base text-Cgray700 caret-Cgray500 shadow-sm transition-colors file:border-0 file:bg-transparent file:text-sm file:font-medium file:text-foreground placeholder:text-Cgray400 placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring disabled:cursor-not-allowed disabled:bg-disable disabled:text-disable_text md:text-sm', + '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: { - isValid: { - true: 'border border-main', - false: 'border border-warning text-warning caret-warning', + state: { + default: '', + success: 'border border-main', + error: 'border border-warning text-warning caret-warning', }, inputSize: { s: 'typo-button2 h-[36px]', @@ -42,30 +59,69 @@ const errorTextVariants = cva('px-[10px] text-warning', { }, }); +/** + * `Input` 컴포넌트 + * + * 기본적인 입력 필드로, 텍스트 및 비밀번호 입력을 지원하며, + * 에러 상태 및 성공 상태를 지정할 수 있습니다. + * + * @example + * // 기본 사용법 + * + * + * @example + * // 에러 상태 + * + * + * @example + * // 성공 상태 + * + * + * @example + * // 비밀번호 입력 필드 (눈 아이콘 포함) + * + * + * @param {IInputProps} props - `Input` 컴포넌트의 속성 + * @returns {JSX.Element} `Input` 요소 + */ const Input = React.forwardRef( - ({ className, type, isValid, errorMessage, inputSize, ...props }, ref) => { + ( + { + className, + type, + state = 'default', + errorMessage, + inputSize = 'l', + ...props + }, + ref, + ) => { const [isVisible, setIsVisible] = React.useState(false); return ( -
+
From 344177ee0fb12803af01819b4464b22c8e4f2a6b Mon Sep 17 00:00:00 2001 From: dbswl701 <73208914+dbswl701@users.noreply.github.com> Date: Wed, 19 Feb 2025 11:08:31 +0900 Subject: [PATCH 8/9] =?UTF-8?q?fix(DEVING-34):=20input=20=ED=8C=8C?= =?UTF-8?q?=EC=9D=BC=EB=AA=85=20=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/components/ui/{input.tsx => Input.tsx} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename src/components/ui/{input.tsx => Input.tsx} (100%) diff --git a/src/components/ui/input.tsx b/src/components/ui/Input.tsx similarity index 100% rename from src/components/ui/input.tsx rename to src/components/ui/Input.tsx From ee0b64482d3e424781092ccace102cac3e0d53a2 Mon Sep 17 00:00:00 2001 From: dbswl701 Date: Wed, 19 Feb 2025 13:02:34 +0900 Subject: [PATCH 9/9] =?UTF-8?q?refactor(DEVING-34):=20=EC=9B=B9=20?= =?UTF-8?q?=EC=A0=91=EA=B7=BC=EC=84=B1=20=EA=B3=A0=EB=A0=A4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/components/ui/Input.tsx | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/src/components/ui/Input.tsx b/src/components/ui/Input.tsx index e028595..4b5067c 100644 --- a/src/components/ui/Input.tsx +++ b/src/components/ui/Input.tsx @@ -12,9 +12,8 @@ interface IInputProps * 입력 필드의 상태 (기본값: `'default'`) * - `'default'` : 기본 상태 (테두리 없음) * - `'success'` : 성공 상태 (메인 컬러 테두리 적용) - * - `'error'` : 에러 상태 (경고 컬러 테두리 및 텍스트 적용) */ - state?: 'default' | 'success' | 'error'; + state?: 'default' | 'success'; /** * 입력 필드의 크기 (기본값: `'l'`) * - `'s'` : 작은 크기 (36px) @@ -34,7 +33,6 @@ const inputVariants = cva( state: { default: '', success: 'border border-main', - error: 'border border-warning text-warning caret-warning', }, inputSize: { s: 'typo-button2 h-[36px]', @@ -64,6 +62,7 @@ const errorTextVariants = cva('px-[10px] text-warning', { * * 기본적인 입력 필드로, 텍스트 및 비밀번호 입력을 지원하며, * 에러 상태 및 성공 상태를 지정할 수 있습니다. + * 접근성을 위해 id가 필수적으로 필요합니다. * * @example * // 기본 사용법 @@ -92,6 +91,7 @@ const Input = React.forwardRef( state = 'default', errorMessage, inputSize = 'l', + id, ...props }, ref, @@ -105,6 +105,7 @@ const Input = React.forwardRef( type={ type === 'password' ? (isVisible ? 'text' : 'password') : 'text' } + aria-invalid={!!errorMessage} className={cn( inputVariants({ state, inputSize }), !!errorMessage && @@ -115,6 +116,9 @@ const Input = React.forwardRef( />
{errorMessage && ( -

+

{errorMessage}

)}