-
Notifications
You must be signed in to change notification settings - Fork 0
[WIP] SearchInput 컴포넌트 구현 #94
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
base: main
Are you sure you want to change the base?
Conversation
Seong-Myeong
left a comment
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.
컴포넌트 구현 확인했습니다.
f1afbeb to
5f53cc3
Compare
5f53cc3 to
1f16156
Compare
|
🚀 storybook url: https://689bfce92a7bd08f5aa1edbe-zcnpmlqfcd.chromatic.com/ |
|
@Bangdayeon rebase가 필요하다 생각됩니다. image 관련 부분이 코드 변경사항으로 보여지고 있습니다. |
1f16156 to
0f77820
Compare
|
🚀 storybook url: https://689bfce92a7bd08f5aa1edbe-rjkqmidqjo.chromatic.com/ |
개요세 개의 새로운 파일이 추가되었습니다. Pre-merge checks and finishing touches❌ Failed checks (2 warnings)
✅ Passed checks (2 passed)
✨ Finishing touches
🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
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.
Actionable comments posted: 2
🧹 Nitpick comments (8)
public/icons/Image.tsx (2)
14-16: 컴포넌트명Image는 혼동 유발 가능(브라우저Image,next/image등).이미
src/components/Icons/CustomImage.tsx가 존재합니다. 중복/혼동을 피하기 위해 이 파일은 제거하거나 명확한 이름(예:PlainImg)으로 변경하고 사용하는 쪽을 일관화하세요.
4-7: 접근성/타입 정합성 소소한 개선 (alt).장식용 이미지라면
alt를 선택 속성으로 두고 기본값''이면 충분합니다.적용 예:
-type ImageProps = React.ImgHTMLAttributes<HTMLImageElement> & { - src: string; - alt: string; -}; +type ImageProps = React.ImgHTMLAttributes<HTMLImageElement> & { + src: string; + alt?: string; +}; -export default function Image({ src, alt = "", ...rest }: ImageProps) { +export default function Image({ src, alt = '', ...rest }: ImageProps) { return <img src={src} alt={alt} {...rest} />; }Also applies to: 14-16
src/components/SearchInput/SearchInput.tsx (3)
29-36: Tailwind 클래스/접근성 개선(placeholder 색 적용 위치, 유효하지 않을 수 있는w-70, role/label).
placeholder-*는 input에 적용해야 합니다.- Tailwind 기본 스케일에
w-70은 없습니다.w-72또는 임의값(w-[280px])로 교체하세요.- 세로 정렬을 위한
items-center권장, 간격은gap-2.- 검색 폼은
role="search", input은type="search"와 접근성 이름(예:aria-label)을 제공하세요.적용 예:
- const baseStyle = - 'flex justify-between pl-4 h-10 text-gray-800 bg-white placeholder-gray-400 rounded-full'; + const baseStyle = + 'flex items-center gap-2 justify-between pl-4 h-10 text-gray-800 bg-white rounded-full'; const sizes = { - md: 'w-70', + md: 'w-72', // or: w-[280px] lg: 'w-full', }; @@ - return ( - <form onSubmit={handleSubmit} className={classes}> + return ( + <form onSubmit={handleSubmit} role="search" className={classes}> @@ - <input - type="text" + <input + type="search" value={value} onChange={onChange} placeholder={placeholder} - className="flex-1 bg-transparent outline-none ml-1" + aria-label={placeholder || '검색'} + className="flex-1 bg-transparent outline-none ml-1 placeholder-gray-400" />Also applies to: 38-46
21-27: onSubmit 시 전달값 UX: 이벤트 대신 현재 입력값을 넘기는 API도 고려.폼 이벤트 대신
onSubmit(value: string)시그니처를 제공하면 상위 사용처에서 바로 검색어를 받는 패턴이 단순해집니다(이벤트 필요 시 별도 prop 유지).현재 이 컴포넌트를 소비하는 곳에서 어떤 시그니처를 선호하는지 확인 부탁드립니다.
49-50: 문구 일관성(i18n):ariaLabel이 영문, placeholder는 한글.한 언어로 통일(예:
ariaLabel="검색")을 권장합니다.- ariaLabel="search button" + ariaLabel="검색"src/components/SearchInput/SearchInput.stories.tsx (3)
22-24: args 타입 단순화 가능.조건부 타입 대신
React.ComponentProps<typeof SearchInput>로 간단히 표현하세요.-function ControlledSearchInput( - args: typeof SearchInput extends React.ComponentType<infer P> ? P : never -) { +type Props = React.ComponentProps<typeof SearchInput>; +function ControlledSearchInput(args: Props) {
32-35: 스토리 상호작용 로깅은 actions 애드온 사용 권장.
console.log대신@storybook/addon-actions의action('submit')을 사용하면 Docs/Controls에서 추적이 용이합니다.- onSubmit={e => { - e.preventDefault(); - console.log('Submit:', value); - }} + onSubmit={e => { + e.preventDefault(); + // import { action } from '@storybook/addon-actions'; + action('submit')(value); + }}
40-46: 사이즈 바리에이션 스토리 추가 제안.
lg케이스도 별도 스토리로 제공하면 시각적 회귀 테스트에 유용합니다.export const Default: Story = { render: args => <ControlledSearchInput {...args} />, args: { placeholder: '검색하세요', size: 'md', }, }; + +export const Large: Story = { + render: args => <ControlledSearchInput {...args} />, + args: { + placeholder: '검색하세요', + size: 'lg', + }, +};
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (3)
public/icons/Image.tsx(1 hunks)src/components/SearchInput/SearchInput.stories.tsx(1 hunks)src/components/SearchInput/SearchInput.tsx(1 hunks)
🧰 Additional context used
🧬 Code graph analysis (2)
src/components/SearchInput/SearchInput.tsx (1)
src/components/Icons/CustomImage.tsx (1)
CustomImage(16-24)
src/components/SearchInput/SearchInput.stories.tsx (1)
src/components/SearchInput/SearchInput.tsx (1)
SearchInput(17-54)
🔇 Additional comments (2)
src/components/SearchInput/SearchInput.tsx (1)
39-49: 아이콘 경로/ALT 텍스트 정리 필요정적 자산은 public/ 루트 기준 절대경로(/...)로 사용하고, 장식 아이콘은 보조기기에서 숨김. 리포지토리에서 public/*.svg 검색 결과 없음 — 아이콘 파일 존재 여부 직접 확인 필요.
파일: src/components/SearchInput/SearchInput.tsx (Lines 39–49)
- 경로를 절대경로로 변경: "file.svg" → "/icons/file.svg" 등 (public/ 루트 기준)
- 장식 아이콘: alt="" 및 aria-hidden 추가
- 버튼 아이콘: alt="" 및 aria-hidden (버튼 레이블은 ariaLabel로 유지)
- IconButton에 type="submit" 추가(폼 내 사용 시)
적용 예:
- <CustomImage src="file.svg" alt="img" /> + <CustomImage src="/icons/file.svg" alt="" aria-hidden /> - <IconButton - icon={<CustomImage src="globe.svg" alt="search button" />} + <IconButton + icon={<CustomImage src="/icons/globe.svg" alt="" aria-hidden />} ariaLabel="search button" radius="full" + type="submit" />public/icons/Image.tsx (1)
1-16: public/ 폴더에 TSX(컴포넌트) 파일 존재 — 사용 여부 확인 후 이동 또는 삭제 필요public/는 정적 자산 전용입니다. public/icons/Image.tsx는 컴포넌트로 보이므로 src/components/ 등으로 옮기거나 사용하지 않으면 제거하세요. 제출된 스크립트가 출력 없이 종료되어 리포지토리 내 사용처/파일 존재를 확인하지 못했습니다. 로컬에서 아래 명령을 실행해 파일 존재와 사용처를 확인하고 결과를 코멘트로 남기세요:
- find public -type f -name '*.tsx' -print
- rg -n "public/icons/Image" -S || true
- rg -n "icons/Image" -S || true
| interface SearchInputProps { | ||
| value: string; | ||
| onChange: (e: React.ChangeEvent<HTMLInputElement>) => void; | ||
| onSubmit: (e: React.FormEvent) => void; | ||
| placeholder?: string; | ||
| size?: 'md' | 'lg'; | ||
| } |
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.
이슈 요구사항과 props 미스매치(size, radius, variant, icon).
Linked issue(#69)에 정의된 radius, variant, icon이 누락되었습니다. 재사용성을 위해 API를 정합화하세요(현 PR에 포함하거나 후속 PR로 트래킹).
간단한 방향:
radius?: 'none'|'sm'|'md'|'lg'|'full'→ 클래스 매핑variant?: 'classic'|'surface'|'soft'→ 배경/테두리 클래스 매핑leftIcon?: React.ReactNode,submitIcon?: React.ReactNode→ 현재 하드코딩된 SVG 대체
원하시면 최소 구현 패치(diff) 제안 드리겠습니다.
🤖 Prompt for AI Agents
In src/components/SearchInput/SearchInput.tsx around lines 9 to 15, the
component props are missing radius, variant and icon options required by issue
#69; add the following props to the interface: radius?: 'none' | 'sm' | 'md' |
'lg' | 'full'; variant?: 'classic' | 'surface' | 'soft'; leftIcon?:
React.ReactNode; submitIcon?: React.ReactNode; then update the component to map
radius to corresponding border-radius utility classes, map variant to
background/border/hover classes, and replace the hardcoded SVGs with the
supplied leftIcon and submitIcon (fall back to existing SVGs if icons are
undefined); ensure className composition includes the mapped classes and
existing size prop behavior and update any usage/tests or note a follow-up PR if
you prefer to add consumers later.
| <IconButton | ||
| icon={<CustomImage src="globe.svg" alt="search button" />} | ||
| ariaLabel="search button" | ||
| radius="full" | ||
| /> |
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.
아이콘 버튼 클릭 시 submit 보장되지 않을 수 있음 — type="submit" 명시 필요.
많은 UI 버튼 컴포넌트가 기본 type="button"을 사용합니다. 명시적으로 제출 버튼으로 지정해 주세요.
적용 예:
- <IconButton
+ <IconButton
icon={<CustomImage src="globe.svg" alt="search button" />}
ariaLabel="search button"
radius="full"
+ type="submit"
/>📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| <IconButton | |
| icon={<CustomImage src="globe.svg" alt="search button" />} | |
| ariaLabel="search button" | |
| radius="full" | |
| /> | |
| <IconButton | |
| icon={<CustomImage src="globe.svg" alt="search button" />} | |
| ariaLabel="search button" | |
| radius="full" | |
| type="submit" | |
| /> |
🤖 Prompt for AI Agents
In src/components/SearchInput/SearchInput.tsx around lines 47 to 51, the
IconButton is missing an explicit type so it may default to "button" and not
submit the form; update the IconButton usage to include type="submit" (and if
IconButton is a wrapper component, ensure it forwards the type prop to the
underlying <button> element) so clicking the icon reliably triggers form
submission.
0f77820 to
81b6fee
Compare
|
🚀 storybook url: https://689bfce92a7bd08f5aa1edbe-urqubcblxn.chromatic.com/ |
81b6fee to
695165e
Compare
|
🚀 storybook url: https://689bfce92a7bd08f5aa1edbe-ambfmwjluf.chromatic.com/ |
695165e to
979ea17
Compare
|
🚀 storybook url: https://689bfce92a7bd08f5aa1edbe-qkidcyvhfm.chromatic.com/ |
979ea17 to
7c4ccde
Compare
|
🚀 storybook url: https://689bfce92a7bd08f5aa1edbe-epsxsgsosy.chromatic.com/ |
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.
Actionable comments posted: 1
♻️ Duplicate comments (2)
src/components/wrappers/SearchInput/SearchInput.tsx (2)
9-15: 이슈 요구사항과 props 불일치 (이전 리뷰 재확인).Issue #69에서 요구한
radius,variant,iconprops가 여전히 누락되어 있습니다. 이전 리뷰에서 지적된 사항이 반영되지 않았으니 확인이 필요합니다.
47-47: 검색 버튼에 부적합한 아이콘 이름 및 props 미구현.
IC_Chat아이콘은 검색 버튼의 의미와 맞지 않습니다. 검색/제출 의미를 가진 아이콘(예:IC_Search,IC_Submit)으로 변경해야 합니다. 또한, 이 아이콘을submitIcon?: React.ReactNodeprops로 받아 커스터마이징 가능하도록 구현하는 것이 필요합니다.- <IconButton icon="IC_Chat" ariaLabel="search button" /> + <IconButton icon="IC_Search" ariaLabel="search button" />
🧹 Nitpick comments (3)
src/stories/SearchInput.stories.tsx (2)
21-22: 타입 추출 로직 단순화 제안.
infer를 사용한 타입 추출이 복잡합니다. SearchInput의 props 타입을 직접 import하여 사용하면 더 명확합니다:+import type { SearchInputProps } from '@/components/wrappers/SearchInput/SearchInput'; + -function ControlledSearchInput( - args: typeof SearchInput extends React.ComponentType<infer P> ? P : never -) { +function ControlledSearchInput(args: SearchInputProps) {참고: 이를 위해 SearchInput.tsx에서
SearchInputProps를 export해야 합니다.
31-34: 중복된 preventDefault 호출 제거 가능.
SearchInput컴포넌트의handleSubmit에서 이미e.preventDefault()를 호출하고 있으므로(SearchInput.tsx Line 25), 여기서의 호출은 불필요합니다.onSubmit={e => { - e.preventDefault(); console.log('Submit:', value); }}src/components/wrappers/SearchInput/SearchInput.tsx (1)
39-39: 경로는 정확하며, 좌측 아이콘을 props로 구성하기를 제안합니다.
public/file.svg파일이 존재하여 경로는 유효합니다. CustomImage 컴포넌트가 NextImage 래퍼이므로 "file.svg"로 public 루트 상대 경로를 정상 처리합니다.다만 재사용성 향상을 위해 좌측 아이콘을 하드코딩하지 말고
leftIcon?: React.ReactNodeprops로 받기를 권장합니다. 현재 Line 39의<CustomImage src="file.svg" alt="img" />를 props로 구성하면 다양한 검색 컨텍스트에서 컴포넌트를 활용할 수 있습니다.
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (3)
public/icons/Image.tsx(1 hunks)src/components/wrappers/SearchInput/SearchInput.tsx(1 hunks)src/stories/SearchInput.stories.tsx(1 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
- public/icons/Image.tsx
🧰 Additional context used
🧬 Code graph analysis (2)
src/stories/SearchInput.stories.tsx (1)
src/components/wrappers/SearchInput/SearchInput.tsx (1)
SearchInput(17-50)
src/components/wrappers/SearchInput/SearchInput.tsx (1)
src/components/Icons/CustomImage.tsx (1)
CustomImage(16-24)
🔇 Additional comments (3)
src/components/wrappers/SearchInput/SearchInput.tsx (1)
17-27: LGTM!컴포넌트 함수 시그니처와 handleSubmit 로직이 올바르게 구현되어 있습니다.
src/stories/SearchInput.stories.tsx (2)
6-19: LGTM!Storybook 메타 설정이 올바르게 구성되어 있습니다.
argTypes에서size컨트롤도 적절히 정의되어 있습니다.
39-45: LGTM!Default story 설정이 적절하며, 초기 args도 올바르게 제공되고 있습니다.
| const baseStyle = | ||
| 'flex justify-between pl-4 h-10 text-gray-800 bg-white placeholder-gray-400 rounded-full'; | ||
| const sizes = { | ||
| md: 'w-70', | ||
| lg: 'w-full', | ||
| }; | ||
| const classes = clsx(baseStyle, sizes[size]); |
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.
🛠️ Refactor suggestion | 🟠 Major
하드코딩된 스타일을 props로 제어 가능하게 리팩토링 필요.
baseStyle에서 rounded-full, bg-white, text-gray-800 등이 하드코딩되어 있어 Issue #69에서 요구한 재사용성이 떨어집니다. radius와 variant props를 추가하여 다음과 같이 매핑하는 것을 권장합니다:
radius:'none' | 'sm' | 'md' | 'lg' | 'full'→rounded-*클래스variant:'classic' | 'surface' | 'soft'→ 배경/테두리 클래스 조합
🤖 Prompt for AI Agents
In src/components/wrappers/SearchInput/SearchInput.tsx around lines 29 to 35,
the baseStyle currently hardcodes rounded-full, bg-white and text-gray-800 which
reduces reusability; add two new props to the component: radius:
'none'|'sm'|'md'|'lg'|'full' and variant: 'classic'|'surface'|'soft', remove the
hardcoded rounded/bg/text classes from baseStyle and instead map radius values
to the corresponding rounded-* Tailwind classes and map variant values to the
appropriate background/border/text class combinations (e.g. classic -> bg-white
text-gray-800, surface -> bg-gray-50 border border-gray-200, soft -> bg-gray-100
text-gray-800), then compute classes via clsx(baseStyleWithoutHardcodedBits,
sizes[size], radiusClass, variantClass), provide sensible defaults for radius
and variant in the props/type definitions, and update any usages/tests to pass
or rely on the new defaults.
필요한 input 컴포넌트 기획 완료 후 진행하겠습니다
관련 이슈
PR 설명
✅
SearchInput.tsxonSubmit트리거 구현valuestringonChange(e: React.ChangeEvent<HTMLInputElement>) => voidonSubmit(e: React.FormEvent) => voidplaceholderstringsizemd,lg실행 방법
page.tsx에서SearchInput컴포넌트,useState를importuseState로value,setValue선언SearchInput컴포넌트 사용npm run dev실행 결과npm run storybook실행 결과2025-07-19.1.55.27.mov