Skip to content

Conversation

@Bangdayeon
Copy link
Member

@Bangdayeon Bangdayeon commented Jul 18, 2025

필요한 input 컴포넌트 기획 완료 후 진행하겠습니다

관련 이슈

PR 설명

SearchInput.tsx

  • 검색바 UI 제작
  • 검색 아이콘 버튼, enter 입력으로 onSubmit 트리거 구현
props value description
value string 입력값
onChange (e: React.ChangeEvent<HTMLInputElement>) => void 입력값 실시간 변화
onSubmit (e: React.FormEvent) => void 제출
placeholder string placeholder 필요시 지정
size md, lg 검색바 길이

실행 방법

  1. page.tsx에서 SearchInput 컴포넌트, useStateimport
  2. useStatevalue, setValue 선언
  3. SearchInput 컴포넌트 사용
<SearchInput
        value={value}
        onChange={(e)=>setvalue(e.target.value)}
        onSubmit={(e) => {
          e.preventDefault();
          console.log("제출됨:", value);
        }}
      />

npm run dev 실행 결과

image

npm run storybook 실행 결과

2025-07-19.1.55.27.mov

@Bangdayeon Bangdayeon requested a review from Seong-Myeong July 18, 2025 16:56
@Bangdayeon Bangdayeon linked an issue Jul 18, 2025 that may be closed by this pull request
Copy link
Contributor

@Seong-Myeong Seong-Myeong left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

컴포넌트 구현 확인했습니다.

@Bangdayeon Bangdayeon force-pushed the feature/#69-add-searchinput-component branch 3 times, most recently from f1afbeb to 5f53cc3 Compare August 12, 2025 12:52
@Bangdayeon Bangdayeon force-pushed the feature/#69-add-searchinput-component branch from 5f53cc3 to 1f16156 Compare August 28, 2025 10:24
@github-actions
Copy link

@Goder-0
Copy link
Contributor

Goder-0 commented Sep 19, 2025

@Bangdayeon rebase가 필요하다 생각됩니다. image 관련 부분이 코드 변경사항으로 보여지고 있습니다.

@Bangdayeon Bangdayeon force-pushed the feature/#69-add-searchinput-component branch from 1f16156 to 0f77820 Compare September 21, 2025 16:00
@github-actions
Copy link

@coderabbitai
Copy link

coderabbitai bot commented Sep 21, 2025

개요

세 개의 새로운 파일이 추가되었습니다. public/icons/Image.tsx에 표준 img 요소를 렌더링하는 Image 컴포넌트가 추가되었습니다. src/components/wrappers/SearchInput/SearchInput.tsx에 검색 입력 기능을 제공하는 SearchInput 클라이언트 컴포넌트가 추가되었으며, value, onChange, onSubmit, placeholder, size 속성을 지원합니다. 크기는 'md'와 'lg' 두 가지 옵션을 제공하며, 폼 제출 시 기본 동작을 방지합니다. src/stories/SearchInput.stories.tsx에는 Storybook 스토리 파일이 추가되어 SearchInput 컴포넌트의 사용 예시와 size 제어 옵션을 정의합니다.

Pre-merge checks and finishing touches

❌ Failed checks (2 warnings)
Check name Status Explanation Resolution
Linked Issues check ⚠️ Warning PR이 주요 요구사항인 SearchInput 컴포넌트 구현(value, onChange, onSubmit)을 충족하나, 이슈의 필수 속성(radius, variant 스타일링)이 미구현되어 있습니다. 이슈 #69의 radius 및 variant 속성을 구현하거나, 추후 작업으로 명시적으로 남겨두어야 합니다.
Out of Scope Changes check ⚠️ Warning PR에 SearchInput 구현 외에 Image.tsx 아이콘 컴포넌트가 추가되었으며, 이는 연결된 이슈 #69의 범위를 벗어나는 변경입니다. Image.tsx 컴포넌트 추가가 SearchInput 구현에 필수적인지 확인하고, 별도 이슈로 분리하거나 정당성을 명시해야 합니다.
✅ Passed checks (2 passed)
Check name Status Explanation
Title check ✅ Passed PR 제목이 SearchInput 컴포넌트 구현이라는 주요 변경사항을 명확히 반영하고 있습니다.
Description check ✅ Passed PR 설명이 필요한 템플릿 구조(관련 이슈, PR 설명)를 포함하고 있으며, 구현 내용, props 설명, 사용 방법 및 실행 결과가 상세히 기술되어 있습니다.
✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch feature/#69-add-searchinput-component

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.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link

@coderabbitai coderabbitai bot left a 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-actionsaction('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

📥 Commits

Reviewing files that changed from the base of the PR and between 03e486b and 0f77820.

📒 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

Comment on lines +9 to +15
interface SearchInputProps {
value: string;
onChange: (e: React.ChangeEvent<HTMLInputElement>) => void;
onSubmit: (e: React.FormEvent) => void;
placeholder?: string;
size?: 'md' | 'lg';
}
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

이슈 요구사항과 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.

Comment on lines 47 to 51
<IconButton
icon={<CustomImage src="globe.svg" alt="search button" />}
ariaLabel="search button"
radius="full"
/>
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

아이콘 버튼 클릭 시 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.

Suggested change
<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.

@Bangdayeon Bangdayeon changed the title SearchInput 컴포넌트 구현 [WIP] SearchInput 컴포넌트 구현 Oct 19, 2025
@Bangdayeon Bangdayeon force-pushed the feature/#69-add-searchinput-component branch from 0f77820 to 81b6fee Compare November 2, 2025 14:41
@github-actions
Copy link

github-actions bot commented Nov 2, 2025

@Bangdayeon Bangdayeon force-pushed the feature/#69-add-searchinput-component branch from 81b6fee to 695165e Compare November 2, 2025 15:15
@github-actions
Copy link

github-actions bot commented Nov 2, 2025

@Bangdayeon Bangdayeon force-pushed the feature/#69-add-searchinput-component branch from 695165e to 979ea17 Compare November 2, 2025 15:31
@github-actions
Copy link

github-actions bot commented Nov 2, 2025

@Goder-0 Goder-0 added the wontfix This will not be worked on label Nov 2, 2025
@Bangdayeon Bangdayeon force-pushed the feature/#69-add-searchinput-component branch from 979ea17 to 7c4ccde Compare November 20, 2025 06:04
@github-actions
Copy link

Copy link

@coderabbitai coderabbitai bot left a 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, icon props가 여전히 누락되어 있습니다. 이전 리뷰에서 지적된 사항이 반영되지 않았으니 확인이 필요합니다.


47-47: 검색 버튼에 부적합한 아이콘 이름 및 props 미구현.

IC_Chat 아이콘은 검색 버튼의 의미와 맞지 않습니다. 검색/제출 의미를 가진 아이콘(예: IC_Search, IC_Submit)으로 변경해야 합니다. 또한, 이 아이콘을 submitIcon?: React.ReactNode props로 받아 커스터마이징 가능하도록 구현하는 것이 필요합니다.

-      <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.ReactNode props로 받기를 권장합니다. 현재 Line 39의 <CustomImage src="file.svg" alt="img" />를 props로 구성하면 다양한 검색 컨텍스트에서 컴포넌트를 활용할 수 있습니다.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 0f77820 and 7c4ccde.

📒 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도 올바르게 제공되고 있습니다.

Comment on lines +29 to +35
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]);
Copy link

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에서 요구한 재사용성이 떨어집니다. radiusvariant 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.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

wontfix This will not be worked on

Projects

None yet

Development

Successfully merging this pull request may close these issues.

SearchInput 컴포넌트 구현

4 participants