diff --git a/src/shared/ui/icons/index.tsx b/src/shared/ui/icons/index.tsx index 74f9284..9dc836d 100644 --- a/src/shared/ui/icons/index.tsx +++ b/src/shared/ui/icons/index.tsx @@ -143,3 +143,178 @@ export const ArrowRightIcon: React.FC = ({ size = 20, ...props }) => /> ); + +// Eye (Password Show) 아이콘 +export const EyeIcon: React.FC = ({ size = 20, ...props }) => ( + + + + +); + +// Eye Off (Password Hide) 아이콘 +export const EyeOffIcon: React.FC = ({ size = 20, ...props }) => ( + + + +); + +// Chevron Down (Select) 아이콘 +export const ChevronDownIcon: React.FC = ({ size = 20, ...props }) => ( + + + +); + +// X Circle (Clear Search) 아이콘 +export const XCircleIcon: React.FC = ({ size = 20, ...props }) => ( + + + + +); + +// User 아이콘 (예제용) +export const UserIcon: React.FC = ({ size = 20, ...props }) => ( + + + + +); + +// Mail 아이콘 (예제용) +export const MailIcon: React.FC = ({ size = 20, ...props }) => ( + + + + +); + +// Lock 아이콘 (예제용) +export const LockIcon: React.FC = ({ size = 20, ...props }) => ( + + + + +); diff --git a/src/shared/ui/inputBox/inputBox.stories.tsx b/src/shared/ui/inputBox/inputBox.stories.tsx new file mode 100644 index 0000000..1c3cc95 --- /dev/null +++ b/src/shared/ui/inputBox/inputBox.stories.tsx @@ -0,0 +1,162 @@ +import React from "react"; +import type { Meta, StoryObj } from "@storybook/react-vite"; +import { Input, Textarea, Select } from "./inputBox"; +// 아이콘 임포트 +import { UserIcon, MailIcon, LockIcon, XCircleIcon } from "@/shared/ui/icons"; + +const meta = { + title: "Shared/UI/InputBox", + component: Input, + parameters: { + layout: "padded", + docs: { + description: { + component: "공통 입력 컴포넌트입니다. Input, Textarea, Select를 포함합니다.", + }, + }, + }, + tags: ["autodocs"], + argTypes: { + // 1. Size + size: { + control: "radio", + options: ["medium", "large"], + description: "입력창 크기 조절", + table: { defaultValue: { summary: "large" } }, + }, + // 2. Boolean States + hasError: { + control: "boolean", + description: "에러 상태 표시 (Red Border)", + }, + isFullWidth: { + control: "boolean", + description: "부모 컨테이너 너비 100% 차지 여부", + table: { defaultValue: { summary: "true" } }, + }, + disabled: { + control: "boolean", + description: "비활성화 상태", + }, + // 3. Icons + leftIcon: { control: false, description: "좌측 아이콘 (ReactNode)" }, + rightIcon: { control: false, description: "우측 아이콘 (ReactNode)" }, + }, +} satisfies Meta; + +export default meta; +type Story = StoryObj; + +// 기본 텍스트 입력 +export const Default: Story = { + args: { + placeholder: "텍스트를 입력해주세요", + size: "large", + isFullWidth: true, + }, +}; + +// 아이콘 포함 (User, Mail 아이콘 예시) +export const WithIcons: Story = { + args: { + placeholder: "이메일 입력", + leftIcon: , // 아이콘 크기 지정 권장 + rightIcon: , + isFullWidth: true, + }, +}; + +// 비밀번호 입력 (강도 표시 포함) +export const Password: Story = { + args: { + type: "password", + placeholder: "비밀번호를 입력하세요", + leftIcon: , + passwordStrength: 2, // 0~3 단계 + isFullWidth: true, + }, +}; + +// 검색 입력 (Rounded Pill Shape) +export const Search: Story = { + args: { + type: "search", + placeholder: "검색어를 입력하세요...", + size: "medium", + isFullWidth: true, + // onClear가 전달되면 값이 있을 때 X 버튼이 자동으로 노출됨 + onClear: () => alert("Clear Clicked!"), + }, +}; + +// 에러 상태 +export const ErrorState: Story = { + args: { + placeholder: "잘못된 입력", + defaultValue: "유효하지 않은 값", + hasError: true, + isFullWidth: true, + rightIcon: , + }, +}; + +export const TextareaField: StoryObj = { + render: (args) =>