Skip to content

[✨ Feat/#41] Input 공통 컴포넌트 구현#42

Merged
Lseojeong merged 13 commits into
devfrom
feat/#41
Jun 21, 2026
Merged

[✨ Feat/#41] Input 공통 컴포넌트 구현#42
Lseojeong merged 13 commits into
devfrom
feat/#41

Conversation

@Lseojeong

@Lseojeong Lseojeong commented Jun 21, 2026

Copy link
Copy Markdown
Member

#️⃣연관된 이슈

체크 사항

  • UI 동작 및 레이아웃 확인
  • 불필요한 console 제거
  • 기능 정상 동작
  • 팀 컨벤션에 맞게 구현했는지
  • 관련 문서 또는 주석을 갱신했는지

📝작업 내용

Input 공통 컴포넌트 구현

  • Compound Pattern 기반의 Input 컴포넌트를 구현했습니다.
  • Input.Label, Input.Field, Input.Control, Input.ErrorMessage를 조합할 수 있습니다.
  • text, number, url 타입을 지원합니다.
  • required, disabled, invalid 상태를 Root에서 관리합니다.
  • Label과 Field의 htmlFor, id를 자동으로 연결했습니다.
  • Field 내부에 버튼을 배치할 수 있도록 Input.Control을 구현했습니다.
  • Root와 하위 컴포넌트의 className 확장을 지원합니다.
  • 포커스, 오류, disabled 및 브라우저 autofill 스타일을 적용했습니다.

React Hook Form 연동

  • React Hook Form의 Controller를 공통 UI와 연결하는 FormField를 구현했습니다.
  • field, fieldState, formState와 함께 invalid, errorMessage를 제공합니다.
  • Input의 오류 상태와 에러 메시지가 React Hook Form 유효성 검증 결과에 연동되도록 구성했습니다.

readonly 미지원

  • 최종 확인 화면처럼 수정할 수 없는 정보를 보여주는 경우에는 form control보다 dl, dt, dd를 사용하는 것이 의미상 적절하다고 판단했습니다.
  • readonly Input은 여전히 키보드 포커스를 받고 입력값 선택과 복사가 가능한 실제 form control이므로 단순 정보 표시 목적과 차이가 있습니다.
  • 표시 전용 화면은 dt를 Label과 같은 스타일로, dd를 Input과 같은 스타일로 구현할 수 있습니다.
  • 이에 따라 Input 공통 컴포넌트에서는 readonly를 지원하지 않으며, 실질적인 입력 차단이 필요한 경우에는 disabled를 사용합니다.

named export 적용

  • 공통 컴포넌트와 Provider를 named export 방식으로 통일했습니다.
  • 컴포넌트 이름이 import 위치에서 고정되어 자동 완성, 코드 검색 및 리팩터링 시 추적하기 쉬워 선택했습니다.
  • index.ts에서도 원본 컴포넌트의 이름을 그대로 명시적으로 재export하도록 변경했습니다.
  • Next.js 규약상 default export가 필요한 page.tsx, layout.tsx는 예외로 유지했습니다.
  • named export와 default export를 모두 생성할 수 있도록 컨벤션 문서 및 VS Code 코드 스니펫을 정리했습니다.

스타일 및 디자인 토큰

  • 오류 상태 색상으로 #FF5656 토큰을 추가했습니다.
  • 포커스 시 테두리와 확산형 그림자를 적용했습니다.
  • URL 입력의 브라우저 autofill 배경과 텍스트 스타일이 기존 Input 디자인을 유지하도록 수정했습니다.

Storybook 및 문서화

  • Input 타입과 상태별 Storybook 예제를 작성했습니다.
  • Storybook Controls에서 타입, 상태, Label, placeholder, 오류 메시지 등을 변경할 수 있습니다.
  • 버튼 포함 Input과 React Hook Form 연동 예제를 추가했습니다.
  • 공통 컴포넌트 TSDoc과 export 컨벤션 문서를 갱신했습니다.

스크린샷 (선택)

image image image image image

추가한 라이브러리 (선택)

  • react-hook-form
    • 폼 상태와 유효성 검증을 관리하고 공통 Input과 연결하기 위해 추가했습니다.

💬리뷰 요구사항(선택)

  • Compound Pattern의 구성이 실제 폼 사용 사례에 적절한지 확인 필요
  • 표시 전용 데이터는 readonly Input 대신 dl, dt, dd를 사용하도록 구분한 기준을 확인 필요
  • 공통 컴포넌트의 named export 컨벤션과 Next.js 특수 파일의 default export 예외가 적절한지 확인 필요

Summary by CodeRabbit

Release Notes

  • New Features
    • 합성 Input 컴포넌트 시스템(라벨/필드/에러) 추가
    • React Hook Form 연동을 위한 FormField 추가
    • Storybook에 Input 예시 및 검증 시나리오 추가
  • Chores
    • 컴포넌트/Provider 내보내기 방식을 named export로 통일
    • VSCode 코드 스니펫 템플릿 업데이트
  • Style
    • 의미론적 에러 컬러 토큰 추가
  • Documentation
    • 컴포넌트/Provider export 규칙 문서화 추가

@Lseojeong Lseojeong linked an issue Jun 21, 2026 that may be closed by this pull request
22 tasks
@Lseojeong Lseojeong self-assigned this Jun 21, 2026
@vercel

vercel Bot commented Jun 21, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
rewrite Ready Ready Preview, Comment Jun 21, 2026 6:43pm

@Lseojeong Lseojeong added the ✨Feature 새로운 기능 구현 label Jun 21, 2026
@github-actions

github-actions Bot commented Jun 21, 2026

Copy link
Copy Markdown

🧪 테스트 결과

항목 결과
✅ Jest 테스트 success

@coderabbitai

coderabbitai Bot commented Jun 21, 2026

Copy link
Copy Markdown

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 478ec69b-7034-4d3e-8a70-a5e79e505809

📥 Commits

Reviewing files that changed from the base of the PR and between bb62caf and 6f50608.

📒 Files selected for processing (1)
  • src/shared/ui/input/Input.stories.tsx
🚧 Files skipped from review as they are similar to previous changes (1)
  • src/shared/ui/input/Input.stories.tsx

Walkthrough

기존 공유 UI 컴포넌트(Badge, Button, Logo, Title, Spinner, PageHeader, QueryProvider 등) 전반의 export 방식을 default export에서 named export로 일괄 전환했습니다. 동시에 react-hook-form을 신규 의존성으로 추가하고, Compound Pattern 기반의 Input 컴포넌트와 FormField 어댑터 컴포넌트를 새로 구현했습니다.

Changes

Named Export 리팩토링

Layer / File(s) Summary
Export 규칙 문서화 및 VSCode 스니펫 갱신
docs/CONVENTIONS.md, .vscode/project.code-snippets
CONVENTIONS.md에 컴포넌트/Provider의 named export 규칙과 Next.js 파일 예외를 추가했습니다. VSCode 스니펫에서 기존 2개를 export function으로 수정하고, export default function 템플릿 스니펫 2개를 신규 추가했습니다.
Badge / BadgeTitle / BadgeGroup named export 전환
src/shared/ui/badge/Badge.tsx, src/shared/ui/badge/BadgeGroup.tsx, src/shared/ui/badge-title/BadgeTitle.tsx, src/shared/ui/badge*/index.ts, src/shared/ui/badge*/*.stories.tsx
Badge, BadgeGroup, BadgeTitle 컴포넌트를 named export로 전환하고 index.ts 배럴 파일 및 Storybook import를 일괄 수정했습니다.
Button / ButtonContent / LinkButton named export 전환
src/shared/ui/button/Button.tsx, src/shared/ui/button/ButtonContent.tsx, src/shared/ui/button/LinkButton.tsx, src/shared/ui/button/index.ts
ButtonContent를 named export로 전환하고, 이를 내부에서 import하는 Button/LinkButton도 named export로 변경했으며 배럴 파일도 갱신했습니다.
Spinner / Title / Logo / PageHeader / QueryProvider named export 전환
src/shared/ui/spinner/..., src/shared/ui/title/..., src/shared/ui/logo/..., src/shared/ui/page-header/..., src/shared/providers/QueryProviders.tsx
나머지 공유 컴포넌트들을 named export로 일괄 변경하고 각 index.ts 배럴 및 Storybook import를 동기화했습니다.

Input 컴파운드 컴포넌트 및 FormField 어댑터 추가

Layer / File(s) Summary
Input 타입 계약, Context, 에러 색상 토큰
src/shared/ui/input/Input.types.ts, src/shared/ui/input/InputContext.ts, src/shared/styles/base/colors.css, package.json
Input 컴파운드 컴포넌트 전반에 사용할 타입(InputType, InputProps, InputFieldProps, InputContextValue 등)과 InputContext/useInputContext 훅을 정의했습니다. --color-error-500 CSS 변수와 react-hook-form 의존성도 추가했습니다.
InputRoot 및 하위 컴포넌트 구현
src/shared/ui/input/Input.tsx, src/shared/ui/input/InputLabel.tsx, src/shared/ui/input/InputField.tsx, src/shared/ui/input/InputControl.tsx, src/shared/ui/input/InputErrorMessage.tsx, src/shared/ui/input/index.ts
InputRoot가 useId로 fieldId를 생성하여 Context에 주입하고, Label(htmlFor 연결, 필수 \* 표시), Field(aria-\* 조건부 매핑), Control(버튼 절대 배치), ErrorMessage(조건부 alert 렌더링)를 각각 구현했습니다.
FormField 어댑터 타입 및 구현
src/shared/ui/form-field/FormField.types.ts, src/shared/ui/form-field/FormField.tsx, src/shared/ui/form-field/index.ts
react-hook-form Controller를 감싸는 FormField 제네릭 어댑터를 구현했습니다. render 콜백에서 invaliderrorMessage를 파생하여 사용자 render 함수에 전달합니다.
Input Storybook 스토리 및 ReactHookForm 연동 예제
src/shared/ui/input/Input.stories.tsx
Default/Required/Disabled/WithError/WithButton/CustomClassName 등 다양한 시나리오 스토리와, title·jobUrl 필드의 onBlur 검증을 보여주는 ReactHookForm 연동 예제 스토리를 추가했습니다.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Possibly related PRs

  • Rewrite-Team/Rewrite-FE#32: Title 컴포넌트 구현 PR로, 이번 PR에서 해당 컴포넌트의 export 방식을 default에서 named로 전환합니다.
  • Rewrite-Team/Rewrite-FE#38: Badge/BadgeGroup/BadgeTitle 컴포넌트를 추가한 PR로, 이번 PR에서 해당 컴포넌트들의 export 방식이 일괄 변경됩니다.
  • Rewrite-Team/Rewrite-FE#40: Button/LinkButton 컴포넌트를 추가한 PR로, 이번 PR에서 동일 파일들의 export 방식이 named export로 전환됩니다.
🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed PR 제목이 주요 변경 사항인 Input 공통 컴포넌트 구현을 명확하게 나타내고 있습니다.
Linked Issues check ✅ Passed PR은 #41의 모든 주요 요구사항을 충족합니다: Input 컴포넌트 구현, Compound Pattern, 세 가지 입력 타입 지원, disabled 상태, className 확장, FormField를 통한 React Hook Form 통합, 포괄적인 Storybook 문서화가 모두 포함되어 있습니다.
Out of Scope Changes check ✅ Passed PR은 Input 컴포넌트 구현에 집중하면서, 관련된 named export 규칙 적용, 색상 토큰 추가, VSCode 스니펫 업데이트 등의 보조적 변경도 포함합니다. 이러한 변경들은 모두 일관된 export 규칙 도입 및 개발자 경험 개선을 위한 것으로 범위 내 입니다.
Docstring Coverage ✅ Passed Docstring coverage is 80.95% which is sufficient. The required threshold is 80.00%.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/#41

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

@github-actions

github-actions Bot commented Jun 21, 2026

Copy link
Copy Markdown

🚦 CI 검증 결과

항목 결과
🧠 TypeScript 타입 체크 success
🧹 ESLint 검사 success
🎨 Prettier 검사 success
🏗️ Build 검증 success

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@src/shared/ui/input/Input.stories.tsx`:
- Around line 250-257: The Button component in the WithButton story does not
have an explicit type attribute specified, which could cause unintended form
submission when the component is reused within a form context since buttons
default to type="submit". Add the type attribute with the value "button" to the
Button component in the WithButton story render function to ensure it does not
trigger form submission and serves as a safe example in documentation.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 8b795081-8f70-4723-9fb8-a46c427450df

📥 Commits

Reviewing files that changed from the base of the PR and between c6813e1 and bb62caf.

⛔ Files ignored due to path filters (1)
  • pnpm-lock.yaml is excluded by !**/pnpm-lock.yaml
📒 Files selected for processing (42)
  • .vscode/project.code-snippets
  • docs/CONVENTIONS.md
  • package.json
  • src/shared/providers/QueryProviders.tsx
  • src/shared/styles/base/colors.css
  • src/shared/ui/badge-title/BadgeTitle.stories.tsx
  • src/shared/ui/badge-title/BadgeTitle.tsx
  • src/shared/ui/badge-title/index.ts
  • src/shared/ui/badge/Badge.stories.tsx
  • src/shared/ui/badge/Badge.tsx
  • src/shared/ui/badge/BadgeGroup.stories.tsx
  • src/shared/ui/badge/BadgeGroup.tsx
  • src/shared/ui/badge/index.ts
  • src/shared/ui/button/Button.tsx
  • src/shared/ui/button/ButtonContent.tsx
  • src/shared/ui/button/LinkButton.tsx
  • src/shared/ui/button/index.ts
  • src/shared/ui/form-field/FormField.tsx
  • src/shared/ui/form-field/FormField.types.ts
  • src/shared/ui/form-field/index.ts
  • src/shared/ui/input/Input.stories.tsx
  • src/shared/ui/input/Input.tsx
  • src/shared/ui/input/Input.types.ts
  • src/shared/ui/input/InputContext.ts
  • src/shared/ui/input/InputControl.tsx
  • src/shared/ui/input/InputErrorMessage.tsx
  • src/shared/ui/input/InputField.tsx
  • src/shared/ui/input/InputLabel.tsx
  • src/shared/ui/input/index.ts
  • src/shared/ui/logo/SymbolLogo.stories.tsx
  • src/shared/ui/logo/SymbolLogo.tsx
  • src/shared/ui/logo/TextLogo.stories.tsx
  • src/shared/ui/logo/TextLogo.tsx
  • src/shared/ui/logo/index.ts
  • src/shared/ui/page-header/PageHeader.stories.tsx
  • src/shared/ui/page-header/PageHeader.tsx
  • src/shared/ui/page-header/index.ts
  • src/shared/ui/spinner/Spinner.tsx
  • src/shared/ui/spinner/index.ts
  • src/shared/ui/title/Title.stories.tsx
  • src/shared/ui/title/Title.tsx
  • src/shared/ui/title/index.ts

Comment thread src/shared/ui/input/Input.stories.tsx
@Lseojeong Lseojeong merged commit 98afbdf into dev Jun 21, 2026
5 checks passed
@Lseojeong Lseojeong deleted the feat/#41 branch June 21, 2026 18:47
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

✨Feature 새로운 기능 구현

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[✨Feature] Input 공통 컴포너트 구현

1 participant