-
Notifications
You must be signed in to change notification settings - Fork 0
[feat/input] - input 컴포넌트 구현 #6
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from 1 commit
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,2 @@ | ||
| ignoredBuiltDependencies: | ||
| - unrs-resolver |
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| @@ -0,0 +1,85 @@ | ||||||||||||||||||||||||||||||||||||||||||
| @use '../../styles/index' as s; | ||||||||||||||||||||||||||||||||||||||||||
| @use 'sass:map'; | ||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||
| .input_wrapper { | ||||||||||||||||||||||||||||||||||||||||||
| position: relative; | ||||||||||||||||||||||||||||||||||||||||||
| cursor: pointer; | ||||||||||||||||||||||||||||||||||||||||||
| box-shadow: | ||||||||||||||||||||||||||||||||||||||||||
| inset 1px 1px 0 0 s.color(white), | ||||||||||||||||||||||||||||||||||||||||||
| 1px 1px 0 0 s.color(gray-600), | ||||||||||||||||||||||||||||||||||||||||||
| 2px 2px 0 0 s.color(gray-900); | ||||||||||||||||||||||||||||||||||||||||||
| transition: | ||||||||||||||||||||||||||||||||||||||||||
| background-color 0.12s, | ||||||||||||||||||||||||||||||||||||||||||
| color 0.12s, | ||||||||||||||||||||||||||||||||||||||||||
| box-shadow 0.12s; | ||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||
| // 인풋 필드 | ||||||||||||||||||||||||||||||||||||||||||
| .input_field { | ||||||||||||||||||||||||||||||||||||||||||
| width: 100%; | ||||||||||||||||||||||||||||||||||||||||||
| padding: 10px; | ||||||||||||||||||||||||||||||||||||||||||
| box-sizing: border-box; | ||||||||||||||||||||||||||||||||||||||||||
| border: none; | ||||||||||||||||||||||||||||||||||||||||||
| background: s.color(gray-300); | ||||||||||||||||||||||||||||||||||||||||||
| color: s.color(gray-900); | ||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||
| box-shadow: | ||||||||||||||||||||||||||||||||||||||||||
| inset 1px 1px 0 0 s.color(white), | ||||||||||||||||||||||||||||||||||||||||||
| 1px 1px 0 0 s.color(gray-600), | ||||||||||||||||||||||||||||||||||||||||||
| 2px 2px 0 0 s.color(gray-900); | ||||||||||||||||||||||||||||||||||||||||||
| transition: | ||||||||||||||||||||||||||||||||||||||||||
| background-color 0.12s, | ||||||||||||||||||||||||||||||||||||||||||
| color 0.12s, | ||||||||||||||||||||||||||||||||||||||||||
| box-shadow 0.12s; | ||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||
| &:hover, | ||||||||||||||||||||||||||||||||||||||||||
| &:focus { | ||||||||||||||||||||||||||||||||||||||||||
| outline: none; | ||||||||||||||||||||||||||||||||||||||||||
| background: s.color(gray-300); | ||||||||||||||||||||||||||||||||||||||||||
| color: s.color(gray-900); | ||||||||||||||||||||||||||||||||||||||||||
| box-shadow: | ||||||||||||||||||||||||||||||||||||||||||
| inset 1px 1px 0 0 s.color(white), | ||||||||||||||||||||||||||||||||||||||||||
| 2px 2px 0 0 s.color(gray-900); | ||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||
| &:active { | ||||||||||||||||||||||||||||||||||||||||||
| background: #bbbbbb; | ||||||||||||||||||||||||||||||||||||||||||
| color: s.color(gray-900); | ||||||||||||||||||||||||||||||||||||||||||
| box-shadow: | ||||||||||||||||||||||||||||||||||||||||||
| inset 1px 1px 0 0 s.color(white), | ||||||||||||||||||||||||||||||||||||||||||
| 1px 1px 0 0 #868686, | ||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||
| background: #bbbbbb; | |
| color: s.color(gray-900); | |
| box-shadow: | |
| inset 1px 1px 0 0 s.color(white), | |
| 1px 1px 0 0 #868686, | |
| background: s.color(gray-300); | |
| color: s.color(gray-900); | |
| box-shadow: | |
| inset 1px 1px 0 0 s.color(white), | |
| 1px 1px 0 0 s.color(gray-600), |
Outdated
Copilot
AI
Sep 16, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hardcoded color values should be replaced with design system tokens for consistency. Use s.color(gray-300) instead of #bbbbbb and s.color(gray-600) instead of #868686 to match the pattern used in other parts of the codebase.
| background: #bbbbbb; | |
| color: s.color(gray-900); | |
| box-shadow: | |
| inset 1px 1px 0 0 s.color(white), | |
| 1px 1px 0 0 #868686, | |
| background: s.color(gray-300); | |
| color: s.color(gray-900); | |
| box-shadow: | |
| inset 1px 1px 0 0 s.color(white), | |
| 1px 1px 0 0 s.color(gray-600), |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
:active 상태에서 색상 값이 하드코딩되어 있습니다. 디자인 시스템의 일관성을 유지하고 유지보수를 용이하게 하기 위해 s.color() 함수를 사용하여 색상 변수를 참조하는 것이 좋습니다. Button.scss 파일에서 유사한 변경이 이루어진 것을 참고할 수 있습니다.
| &:active { | |
| background: #bbbbbb; | |
| color: s.color(gray-900); | |
| box-shadow: | |
| inset 1px 1px 0 0 s.color(white), | |
| 1px 1px 0 0 #868686, | |
| 0px 0px 0 0 s.color(gray-900); | |
| } | |
| &:active { | |
| background: s.color(gray-300); | |
| color: s.color(gray-900); | |
| box-shadow: | |
| inset 1px 1px 0 0 s.color(white), | |
| 1px 1px 0 0 s.color(gray-600), | |
| 0px 0px 0 0 s.color(gray-900); | |
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
| Original file line number | Diff line number | Diff line change | ||||
|---|---|---|---|---|---|---|
| @@ -0,0 +1,21 @@ | ||||||
| import type { Meta, StoryObj } from '@storybook/react-vite'; | ||||||
| import Input from './Input'; | ||||||
|
|
||||||
| const meta: Meta<typeof Input> = { | ||||||
| title: 'Components/Input', | ||||||
| component: Input, | ||||||
| argTypes: { onClick: { action: 'changed' } } | ||||||
|
||||||
| argTypes: { onClick: { action: 'changed' } } | |
| argTypes: { onChange: { action: 'changed' } } |
Outdated
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Outdated
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,26 @@ | ||
| import { render, screen } from '@testing-library/react'; | ||
| import userEvent from '@testing-library/user-event'; | ||
| import { test, expect, vi } from 'vitest'; | ||
|
|
||
| import Input from './Input'; | ||
|
|
||
| test('Input 렌더링 및 label(플레이스홀더) 확인', () => { | ||
| render(<Input label="테스트라벨" />); | ||
| expect(screen.getByText('테스트라벨')).toBeInTheDocument(); | ||
| expect(screen.getByRole('textbox')).toBeInTheDocument(); | ||
| }); | ||
|
|
||
| test('Input에 placeholder, value props 전달 확인', () => { | ||
| render(<Input label="테스트라벨" placeholder="여기에 입력" value="abc" />); | ||
| const input = screen.getByRole('textbox'); | ||
| expect(input).toHaveAttribute('placeholder', '여기에 입력'); | ||
| expect(input).toHaveValue('abc'); | ||
| }); | ||
|
|
||
| test('Input 입력 시 onChange 이벤트 발생', async () => { | ||
| const handleChange = vi.fn(); | ||
| render(<Input label="테스트라벨" onChange={handleChange} />); | ||
| const input = screen.getByRole('textbox'); | ||
| await userEvent.type(input, 'hello'); | ||
| expect(handleChange).toHaveBeenCalled(); | ||
| }); |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,18 @@ | ||
| import React from 'react'; | ||
| import './Input.scss'; | ||
|
|
||
| export interface InputProps | ||
| extends React.InputHTMLAttributes<HTMLInputElement> { | ||
| label: string; | ||
| } | ||
|
|
||
| const Input: React.FC<InputProps> = ({ label, id, ...rest }) => { | ||
| return ( | ||
| <div className="input_wrapper"> | ||
| <input type="text" className="input_field" id={id} {...rest} /> | ||
| <label htmlFor={id} className="input_placeholder">{label}</label> | ||
|
||
| </div> | ||
| ); | ||
| }; | ||
|
|
||
| export default Input; | ||
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
pnpm-lock.yaml에 따르면@types/testing-library__user-event패키지는 더 이상 사용되지 않으며(deprecated),testing-library__user-event가 자체적으로 타입을 제공하므로 설치할 필요가 없습니다. 이 불필요한 의존성을 제거해주세요.