Conversation
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.
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.
이슈 요구사항과 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.
아이콘 버튼 클릭 시 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.
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.
🛠️ 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