diff --git a/src/components/input/CardNumberInput.stories.ts b/src/components/input/CardNumberInput.stories.ts index 09c05d1..dd6ebe2 100644 --- a/src/components/input/CardNumberInput.stories.ts +++ b/src/components/input/CardNumberInput.stories.ts @@ -2,8 +2,12 @@ import { Meta, StoryObj } from '@storybook/react'; import CardNumberInput from './CardNumberInput'; const meta = { - title: 'Input/CardNumberInput', + title: 'Components/Input/CardNumberInput', component: CardNumberInput, + parameters: { + layout: 'centered', + }, + tags: ['autodocs'], } satisfies Meta; export default meta; @@ -11,6 +15,7 @@ type Story = StoryObj; export const Default: Story = { args: { - onChange: () => {}, + placeholder: '카드 번호를 입력해주세요', + onChange: (value) => console.log('Changed value:', value), }, }; diff --git a/src/components/input/CvcInput.stories.tsx b/src/components/input/CvcInput.stories.tsx new file mode 100644 index 0000000..0874a4d --- /dev/null +++ b/src/components/input/CvcInput.stories.tsx @@ -0,0 +1,26 @@ +import type { Meta, StoryObj } from '@storybook/react'; +import CvcInput from './CvcInput'; + +const meta = { + title: 'Components/Input/CvcInput', + component: CvcInput, + parameters: { + layout: 'centered', + }, + tags: ['autodocs'], +} satisfies Meta; + +export default meta; +type Story = StoryObj; + +export const Default: Story = { + args: { + onChange: (value: string) => console.log('CVC value:', value), + }, +}; + +export const WithInitialValue: Story = { + args: { + onChange: (value: string) => console.log('CVC value:', value), + }, +}; diff --git a/src/components/input/ExpireDateInput.stories.tsx b/src/components/input/ExpireDateInput.stories.tsx new file mode 100644 index 0000000..0610282 --- /dev/null +++ b/src/components/input/ExpireDateInput.stories.tsx @@ -0,0 +1,35 @@ +import type { Meta, StoryObj } from '@storybook/react'; +import ExpireDateInput from './ExpireDateInput'; + +const meta = { + title: 'Components/Input/ExpireDateInput', + component: ExpireDateInput, + parameters: { + layout: 'centered', + }, + tags: ['autodocs'], +} satisfies Meta; + +export default meta; +type Story = StoryObj; + +export const Default: Story = { + args: { + onChange: (value) => console.log('Changed:', value), + onFull: (e) => console.log('Full:', e), + }, +}; + +export const WithInitialValue: Story = { + args: { + ...Default.args, + defaultValue: '12', + }, +}; + +export const Disabled: Story = { + args: { + ...Default.args, + disabled: true, + }, +}; diff --git a/src/components/input/Input.stories.ts b/src/components/input/Input.stories.ts index 9e5c0c6..aae1039 100644 --- a/src/components/input/Input.stories.ts +++ b/src/components/input/Input.stories.ts @@ -2,8 +2,12 @@ import { Meta, StoryObj } from '@storybook/react'; import Input from './Input'; const meta = { - title: 'Input/Input', + title: 'Components/Input/Input', component: Input, + parameters: { + layout: 'centered', + }, + tags: ['autodocs'], } satisfies Meta; export default meta; diff --git a/src/components/input/InputBox.stories.tsx b/src/components/input/InputBox.stories.tsx new file mode 100644 index 0000000..0d0ba77 --- /dev/null +++ b/src/components/input/InputBox.stories.tsx @@ -0,0 +1,40 @@ +import type { Meta, StoryObj } from '@storybook/react'; +import InputBox from './InputBox'; + +const meta = { + title: 'Components/Input/InputBox', + component: InputBox, + parameters: { + layout: 'centered', + }, + tags: ['autodocs'], +} satisfies Meta; + +export default meta; +type Story = StoryObj; + +export const Default: Story = { + args: { + children: 'Input Box Content', + className: 'p-4', + }, +}; + +export const WithCustomStyle: Story = { + args: { + children: 'Custom Styled Input Box', + className: 'p-6 bg-red-300', + }, +}; + +export const WithNestedContent: Story = { + args: { + children: ( +
+

Nested Content

+

This is nested content inside InputBox

+
+ ), + className: 'p-4', + }, +}; diff --git a/src/components/input/NameInput.stories.tsx b/src/components/input/NameInput.stories.tsx new file mode 100644 index 0000000..c3e41f2 --- /dev/null +++ b/src/components/input/NameInput.stories.tsx @@ -0,0 +1,28 @@ +import type { Meta, StoryObj } from '@storybook/react'; +import NameInput from './NameInput'; + +const meta = { + title: 'Components/Input/NameInput', + component: NameInput, + parameters: { + layout: 'centered', + }, + tags: ['autodocs'], +} satisfies Meta; + +export default meta; +type Story = StoryObj; + +export const Default: Story = { + args: { + onChange: (value) => console.log('Name changed:', value), + maxLength: 30, + }, +}; + +export const CustomMaxLength: Story = { + args: { + onChange: (value) => console.log('Name changed:', value), + maxLength: 10, + }, +}; diff --git a/src/components/input/NameInput.tsx b/src/components/input/NameInput.tsx index cc41e96..fbd73d5 100644 --- a/src/components/input/NameInput.tsx +++ b/src/components/input/NameInput.tsx @@ -1,4 +1,3 @@ -import { useEffect } from 'react'; import Input from './Input'; import InputBox from './InputBox'; import React from 'react'; @@ -9,16 +8,18 @@ interface NameInputProps { } const NameInput = ({ onChange, maxLength = 30 }: NameInputProps) => { const [value, setValue] = React.useState(''); - useEffect(() => { - onChange?.(value); - }, [value]); + + const handleChange = (v: string) => { + setValue(v); + onChange?.(v); + }; return ( setValue(v.target.value)} + onChange={(e) => handleChange(e.target.value)} maxLength={maxLength} /> diff --git a/src/components/input/PasswordInput.stories.tsx b/src/components/input/PasswordInput.stories.tsx new file mode 100644 index 0000000..84767b0 --- /dev/null +++ b/src/components/input/PasswordInput.stories.tsx @@ -0,0 +1,22 @@ +import type { Meta, StoryObj } from '@storybook/react'; +import PasswordInput from './PasswordInput'; + +const meta = { + title: 'Components/Input/PasswordInput', + component: PasswordInput, + parameters: { + layout: 'centered', + }, + tags: ['autodocs'], +} satisfies Meta; + +export default meta; +type Story = StoryObj; + +export const Default: Story = { + args: { + onChange: (value: string) => { + console.log('Password value:', value); + }, + }, +}; diff --git a/src/stories/Button.stories.ts b/src/stories/Button.stories.ts deleted file mode 100644 index 2a05e01..0000000 --- a/src/stories/Button.stories.ts +++ /dev/null @@ -1,53 +0,0 @@ -import type { Meta, StoryObj } from '@storybook/react'; -import { fn } from '@storybook/test'; - -import { Button } from './Button'; - -// More on how to set up stories at: https://storybook.js.org/docs/writing-stories#default-export -const meta = { - title: 'Example/Button', - component: Button, - parameters: { - // Optional parameter to center the component in the Canvas. More info: https://storybook.js.org/docs/configure/story-layout - layout: 'centered', - }, - // This component will have an automatically generated Autodocs entry: https://storybook.js.org/docs/writing-docs/autodocs - tags: ['autodocs'], - // More on argTypes: https://storybook.js.org/docs/api/argtypes - argTypes: { - backgroundColor: { control: 'color' }, - }, - // Use `fn` to spy on the onClick arg, which will appear in the actions panel once invoked: https://storybook.js.org/docs/essentials/actions#action-args - args: { onClick: fn() }, -} satisfies Meta; - -export default meta; -type Story = StoryObj; - -// More on writing stories with args: https://storybook.js.org/docs/writing-stories/args -export const Primary: Story = { - args: { - primary: true, - label: 'Button', - }, -}; - -export const Secondary: Story = { - args: { - label: 'Button', - }, -}; - -export const Large: Story = { - args: { - size: 'large', - label: 'Button', - }, -}; - -export const Small: Story = { - args: { - size: 'small', - label: 'Button', - }, -}; diff --git a/src/stories/Button.tsx b/src/stories/Button.tsx deleted file mode 100644 index f35dafd..0000000 --- a/src/stories/Button.tsx +++ /dev/null @@ -1,37 +0,0 @@ -import React from 'react'; - -import './button.css'; - -export interface ButtonProps { - /** Is this the principal call to action on the page? */ - primary?: boolean; - /** What background color to use */ - backgroundColor?: string; - /** How large should the button be? */ - size?: 'small' | 'medium' | 'large'; - /** Button contents */ - label: string; - /** Optional click handler */ - onClick?: () => void; -} - -/** Primary UI component for user interaction */ -export const Button = ({ - primary = false, - size = 'medium', - backgroundColor, - label, - ...props -}: ButtonProps) => { - const mode = primary ? 'storybook-button--primary' : 'storybook-button--secondary'; - return ( - - ); -}; diff --git a/src/stories/Header.stories.ts b/src/stories/Header.stories.ts deleted file mode 100644 index 80c71d0..0000000 --- a/src/stories/Header.stories.ts +++ /dev/null @@ -1,33 +0,0 @@ -import type { Meta, StoryObj } from '@storybook/react'; -import { fn } from '@storybook/test'; - -import { Header } from './Header'; - -const meta = { - title: 'Example/Header', - component: Header, - // This component will have an automatically generated Autodocs entry: https://storybook.js.org/docs/writing-docs/autodocs - tags: ['autodocs'], - parameters: { - // More on how to position stories at: https://storybook.js.org/docs/configure/story-layout - layout: 'fullscreen', - }, - args: { - onLogin: fn(), - onLogout: fn(), - onCreateAccount: fn(), - }, -} satisfies Meta; - -export default meta; -type Story = StoryObj; - -export const LoggedIn: Story = { - args: { - user: { - name: 'Jane Doe', - }, - }, -}; - -export const LoggedOut: Story = {}; diff --git a/src/stories/Header.tsx b/src/stories/Header.tsx deleted file mode 100644 index 1bf981a..0000000 --- a/src/stories/Header.tsx +++ /dev/null @@ -1,56 +0,0 @@ -import React from 'react'; - -import { Button } from './Button'; -import './header.css'; - -type User = { - name: string; -}; - -export interface HeaderProps { - user?: User; - onLogin?: () => void; - onLogout?: () => void; - onCreateAccount?: () => void; -} - -export const Header = ({ user, onLogin, onLogout, onCreateAccount }: HeaderProps) => ( -
-
-
- - - - - - - -

Acme

-
-
- {user ? ( - <> - - Welcome, {user.name}! - -
-
-
-); diff --git a/src/stories/Page.stories.ts b/src/stories/Page.stories.ts deleted file mode 100644 index 53b9f8f..0000000 --- a/src/stories/Page.stories.ts +++ /dev/null @@ -1,32 +0,0 @@ -import type { Meta, StoryObj } from '@storybook/react'; -import { expect, userEvent, within } from '@storybook/test'; - -import { Page } from './Page'; - -const meta = { - title: 'Example/Page', - component: Page, - parameters: { - // More on how to position stories at: https://storybook.js.org/docs/configure/story-layout - layout: 'fullscreen', - }, -} satisfies Meta; - -export default meta; -type Story = StoryObj; - -export const LoggedOut: Story = {}; - -// More on interaction testing: https://storybook.js.org/docs/writing-tests/interaction-testing -export const LoggedIn: Story = { - play: async ({ canvasElement }) => { - const canvas = within(canvasElement); - const loginButton = canvas.getByRole('button', { name: /Log in/i }); - await expect(loginButton).toBeInTheDocument(); - await userEvent.click(loginButton); - await expect(loginButton).not.toBeInTheDocument(); - - const logoutButton = canvas.getByRole('button', { name: /Log out/i }); - await expect(logoutButton).toBeInTheDocument(); - }, -}; diff --git a/src/stories/Page.tsx b/src/stories/Page.tsx deleted file mode 100644 index e117483..0000000 --- a/src/stories/Page.tsx +++ /dev/null @@ -1,73 +0,0 @@ -import React from 'react'; - -import { Header } from './Header'; -import './page.css'; - -type User = { - name: string; -}; - -export const Page: React.FC = () => { - const [user, setUser] = React.useState(); - - return ( -
-
setUser({ name: 'Jane Doe' })} - onLogout={() => setUser(undefined)} - onCreateAccount={() => setUser({ name: 'Jane Doe' })} - /> - -
-

Pages in Storybook

-

- We recommend building UIs with a{' '} - - component-driven - {' '} - process starting with atomic components and ending with pages. -

-

- Render pages with mock data. This makes it easy to build and review page states without - needing to navigate to them in your app. Here are some handy patterns for managing page - data in Storybook: -

-
    -
  • - Use a higher-level connected component. Storybook helps you compose such data from the - "args" of child component stories -
  • -
  • - Assemble data in the page component from your services. You can mock these services out - using Storybook. -
  • -
-

- Get a guided tutorial on component-driven development at{' '} - - Storybook tutorials - - . Read more in the{' '} - - docs - - . -

-
- Tip Adjust the width of the canvas with the{' '} - - - - - - Viewports addon in the toolbar -
-
-
- ); -}; diff --git a/src/stories/button.css b/src/stories/button.css deleted file mode 100644 index 94d674b..0000000 --- a/src/stories/button.css +++ /dev/null @@ -1,30 +0,0 @@ -.storybook-button { - display: inline-block; - cursor: pointer; - border: 0; - border-radius: 3em; - font-weight: 700; - line-height: 1; - font-family: 'Nunito Sans', 'Helvetica Neue', Helvetica, Arial, sans-serif; -} -.storybook-button--primary { - background-color: #1ea7fd; - color: white; -} -.storybook-button--secondary { - box-shadow: rgba(0, 0, 0, 0.15) 0px 0px 0px 1px inset; - background-color: transparent; - color: #333; -} -.storybook-button--small { - padding: 10px 16px; - font-size: 12px; -} -.storybook-button--medium { - padding: 11px 20px; - font-size: 14px; -} -.storybook-button--large { - padding: 12px 24px; - font-size: 16px; -} diff --git a/src/stories/header.css b/src/stories/header.css deleted file mode 100644 index 5efd46c..0000000 --- a/src/stories/header.css +++ /dev/null @@ -1,32 +0,0 @@ -.storybook-header { - display: flex; - justify-content: space-between; - align-items: center; - border-bottom: 1px solid rgba(0, 0, 0, 0.1); - padding: 15px 20px; - font-family: 'Nunito Sans', 'Helvetica Neue', Helvetica, Arial, sans-serif; -} - -.storybook-header svg { - display: inline-block; - vertical-align: top; -} - -.storybook-header h1 { - display: inline-block; - vertical-align: top; - margin: 6px 0 6px 10px; - font-weight: 700; - font-size: 20px; - line-height: 1; -} - -.storybook-header button + button { - margin-left: 10px; -} - -.storybook-header .welcome { - margin-right: 10px; - color: #333; - font-size: 14px; -} diff --git a/src/stories/page.css b/src/stories/page.css deleted file mode 100644 index 87f7ecb..0000000 --- a/src/stories/page.css +++ /dev/null @@ -1,69 +0,0 @@ -.storybook-page { - margin: 0 auto; - padding: 48px 20px; - max-width: 600px; - color: #333; - font-size: 14px; - line-height: 24px; - font-family: 'Nunito Sans', 'Helvetica Neue', Helvetica, Arial, sans-serif; -} - -.storybook-page h2 { - display: inline-block; - vertical-align: top; - margin: 0 0 4px; - font-weight: 700; - font-size: 32px; - line-height: 1; -} - -.storybook-page p { - margin: 1em 0; -} - -.storybook-page a { - color: #1ea7fd; - text-decoration: none; -} - -.storybook-page ul { - margin: 1em 0; - padding-left: 30px; -} - -.storybook-page li { - margin-bottom: 8px; -} - -.storybook-page .tip { - display: inline-block; - vertical-align: top; - margin-right: 10px; - border-radius: 1em; - background: #e7fdd8; - padding: 4px 12px; - color: #66bf3c; - font-weight: 700; - font-size: 11px; - line-height: 12px; -} - -.storybook-page .tip-wrapper { - margin-top: 40px; - margin-bottom: 40px; - font-size: 13px; - line-height: 20px; -} - -.storybook-page .tip-wrapper svg { - display: inline-block; - vertical-align: top; - margin-top: 3px; - margin-right: 4px; - width: 12px; - height: 12px; -} - -.storybook-page .tip-wrapper svg path { - fill: #1ea7fd; -}