Skip to content

[Feat/#59] feat(web): migrate Tabs#70

Merged
seungdeok merged 1 commit into
mainfrom
feat/#59
Sep 24, 2025
Merged

[Feat/#59] feat(web): migrate Tabs#70
seungdeok merged 1 commit into
mainfrom
feat/#59

Conversation

@seungdeok

@seungdeok seungdeok commented Sep 23, 2025

Copy link
Copy Markdown
Member

📝 PR 유형

  • 🚀 feature 기능 추가
  • 🐞 버그 발생
  • 🔨 리팩토링
  • 📋 문서작성
  • 🌍 빌드 설정 및 문제
  • ETC

📝 PR 설명

Tabs 컴포넌트 마이그레이션 작업입니다.

관련된 이슈 넘버

close #59

✅ 작업 목록

  • Tabs 컴포넌트 마이그레이션(pure css -> pandacss)
  • Tabs storybook

MR하기 전에 확인해주세요

  • local code lint 검사를 진행하셨나요?
  • loca ci test를 진행하셨나요?

📚 논의사항

📚 ETC

Summary by CodeRabbit

  • New Features

    • 탭 UI 컴포넌트를 추가해 콘텐츠를 탭으로 전환하고 탐색할 수 있습니다. 선택/비선택 상태 스타일과 가로 레이아웃, 기본 선택값 및 너비 설정을 지원합니다.
  • Documentation

    • 탭 컴포넌트의 스토리북 데모를 추가해 사용 예시와 동작을 미리 확인할 수 있습니다.
  • Chores

    • 탭 UI 제공을 위해 런타임 의존성 추가: Radix Tabs 패키지.

@seungdeok seungdeok requested a review from widse September 23, 2025 14:59
@seungdeok seungdeok self-assigned this Sep 23, 2025
@Frieeren Frieeren deleted a comment from coderabbitai Bot Sep 23, 2025
@github-actions

Copy link
Copy Markdown

📚 Storybook is ready for review!
🔗 Preview: https://68ceb72871701a8b3beb1d8f-zvxxuambrr.chromatic.com/

@coderabbitai

coderabbitai Bot commented Sep 24, 2025

Copy link
Copy Markdown

Walkthrough

apps/web에 Radix UI Tabs 의존성을 추가하고, Tabs 컴포넌트와 타입 정의를 신설했으며, 해당 컴포넌트의 Storybook 스토리를 추가했습니다. 컴포넌트는 Radix Tabs 프리미티브를 조합해 리스트/트리거 렌더링과 값 제어를 지원합니다.

Changes

Cohort / File(s) Summary
Dependency update
apps/web/package.json
웹 앱에 @radix-ui/react-tabs(^1.1.13) 런타임 의존성 추가
Tabs component
apps/web/src/shared/components/Tabs/Tabs.tsx, apps/web/src/shared/components/Tabs/Tabs.type.ts
Tabs 컴포넌트 및 타입 신규 추가. Radix Tabs 조합, width/controlled value 지원, tabItems 기반 Trigger 자동 렌더링
Storybook
apps/web/src/shared/components/Tabs/Tabs.stories.tsx
Tabs 스토리 추가. 기본 탭 아이템(아이콘+라벨)과 레이아웃 파라미터 정의, Meta/Story 타입 안전 구성

Sequence Diagram(s)

sequenceDiagram
  autonumber
  actor User as 사용자
  participant Tabs as Tabs 컴포넌트
  participant Radix as Radix Tabs(Root/List/Trigger)
  participant DOM as DOM

  User->>Tabs: 탭 클릭(새 value)
  Tabs->>Radix: value 전달(제어형)
  Radix->>DOM: data-state="active"/"inactive" 반영
  note over DOM: 스타일 상태 전환(활성/비활성)
  DOM-->>User: 활성 탭 표시
Loading

Estimated code review effort

🎯 2 (Simple) | ⏱️ ~10 minutes

Possibly related PRs

Suggested reviewers

  • widse

Pre-merge checks and finishing touches

✅ Passed checks (5 passed)
Check name Status Explanation
Title Check ✅ Passed 제목은 주요 변경사항인 Tabs 컴포넌트 이관을 명확히 요약하고 있으며 관련 이슈 번호와 범위를 적절히 포함하고 있어 PR의 핵심 내용을 잘 전달합니다.
Linked Issues Check ✅ Passed 코드 변경사항이 연관 이슈 #59의 주요 목표인 Tabs 컴포넌트 이관을 충실히 구현하고 Storybook 추가까지 포함하여 요구사항을 모두 만족합니다.
Out of Scope Changes Check ✅ Passed 변경사항은 Tabs 컴포넌트 마이그레이션과 해당 컴포넌트의 Storybook 통합에만 국한되어 있으며 연관 이슈 범위를 벗어나는 불필요한 수정이 포함되지 않았습니다.
Description Check ✅ Passed PR 설명은 템플릿의 모든 필수 섹션을 충족하고 PR 유형, 설명, 관련 이슈, 작업 목록, 사전 확인사항이 모두 적절히 작성되어 있어 전반적으로 완성도가 높습니다.
Docstring Coverage ✅ Passed No functions found in the changes. Docstring coverage check skipped.
✨ Finishing touches
  • 📝 Generate Docstrings
🧪 Generate unit tests
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch feat/#59

Tip

👮 Agentic pre-merge checks are now available in preview!

Pro plan users can now enable pre-merge checks in their settings to enforce checklists before merging PRs.

  • Built-in checks – Quickly apply ready-made checks to enforce title conventions, require pull request descriptions that follow templates, validate linked issues for compliance, and more.
  • Custom agentic checks – Define your own rules using CodeRabbit’s advanced agentic capabilities to enforce organization-specific policies and workflows. For example, you can instruct CodeRabbit’s agent to verify that API documentation is updated whenever API schema files are modified in a PR. Note: Upto 5 custom checks are currently allowed during the preview period. Pricing for this feature will be announced in a few weeks.

Please see the documentation for more information.

Example:

reviews:
  pre_merge_checks:
    custom_checks:
      - name: "Undocumented Breaking Changes"
        mode: "warning"
        instructions: |
          Pass/fail criteria: All breaking changes to public APIs, CLI flags, environment variables, configuration keys, database schemas, or HTTP/GraphQL endpoints must be documented in the "Breaking Change" section of the PR description and in CHANGELOG.md. Exclude purely internal or private changes (e.g., code not exported from package entry points or explicitly marked as internal).

Please share your feedback with us on this Discord post.


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.

@github-actions

Copy link
Copy Markdown

📚 Storybook is ready for review!
🔗 Preview: https://68ceb72871701a8b3beb1d8f-jmnegyltow.chromatic.com/

@seungdeok seungdeok merged commit dd3d06f into main Sep 24, 2025
3 of 4 checks passed
@seungdeok seungdeok deleted the feat/#59 branch September 24, 2025 13:56

@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

🧹 Nitpick comments (3)
apps/web/src/shared/components/Tabs/Tabs.stories.tsx (1)

5-40: 인라인 스타일 대신 CSS-in-JS 사용을 권장합니다.

tabItems의 label에서 인라인 스타일을 사용하고 있습니다. 프로젝트에서 PandaCSS를 사용하고 있으므로, 일관성을 위해 css 헬퍼 함수를 사용하는 것이 좋겠습니다.

+import { css } from "../../../../styled-system/css";

 const tabItems = [
   {
     value: "일일 업무",
     label: (
-      <div style={{ display: "flex", flexDirection: "row", alignItems: "center", gap: "6px" }}>
+      <div className={css({ display: "flex", flexDirection: "row", alignItems: "center", gap: "6px" })}>
         {/* SVG 내용 */}
         <div>일일 업무</div>
       </div>
     ),
   },
   {
     value: "회의 일정", 
     label: (
-      <div style={{ display: "flex", flexDirection: "row", alignItems: "center", gap: "6px" }}>
+      <div className={css({ display: "flex", flexDirection: "row", alignItems: "center", gap: "6px" })}>
         {/* SVG 내용 */}
         <div>회의 일정</div>
       </div>
     ),
   },
 ];
apps/web/src/shared/components/Tabs/Tabs.tsx (2)

8-8: 사용되지 않는 listRef 제거를 고려해보세요.

listRef가 선언되고 할당되지만 실제로는 사용되지 않고 있습니다. UseTabsIndicatorProps 타입도 정의되어 있지만 현재 구현에서는 활용되지 않습니다. 향후 indicator 기능 구현을 위한 준비 작업이라면 주석으로 의도를 명시하는 것이 좋겠습니다.

 export const Tabs = (props: TabsProps) => {
   const { width = "100%", tabItems, value, ...rest } = props;
-  const listRef = useRef<HTMLDivElement>(null);
+  // TODO: indicator 기능 구현 시 활용 예정
+  // const listRef = useRef<HTMLDivElement>(null);

21-32: 접근성을 위한 aria-label 추가를 권장합니다.

TabsBase.List에 적절한 aria-label을 추가하면 스크린 리더 사용자에게 더 나은 경험을 제공할 수 있습니다.

 <TabsBase.List
   ref={listRef}
   data-orientation="horizontal"
+  aria-label="탭 목록"
   className={css({
     position: "relative",
     display: "flex", 
     height: "35px",
     padding: "0 20px",
     backgroundColor: "#fff",
     boxSizing: "border-box",
   })}
 >
📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 95fbe93 and 1d8293f.

⛔ Files ignored due to path filters (1)
  • pnpm-lock.yaml is excluded by !**/pnpm-lock.yaml
📒 Files selected for processing (4)
  • apps/web/package.json (1 hunks)
  • apps/web/src/shared/components/Tabs/Tabs.stories.tsx (1 hunks)
  • apps/web/src/shared/components/Tabs/Tabs.tsx (1 hunks)
  • apps/web/src/shared/components/Tabs/Tabs.type.ts (1 hunks)
🧰 Additional context used
🧬 Code graph analysis (1)
apps/web/src/shared/components/Tabs/Tabs.stories.tsx (2)
apps/web/src/shared/components/Tabs/Tabs.tsx (1)
  • Tabs (6-63)
apps/web/src/shared/components/Tabs/Tabs.type.ts (1)
  • TabsProps (13-16)
🔇 Additional comments (3)
apps/web/package.json (1)

19-19: 추가된 Radix UI Tabs 의존성이 최신 버전이며 안전합니다.

추가된 @radix-ui/react-tabs 버전 1.1.13은 최신 버전이며, 보안 스캔 결과 위험 요소가 탐지되지 않아 안전한 것으로 확인되었습니다. 이 의존성은 새로 추가된 Tabs 컴포넌트 구현에 필요한 라이브러리입니다.

apps/web/src/shared/components/Tabs/Tabs.stories.tsx (1)

81-81: key 속성을 이용한 강제 리마운트 로직이 우아합니다.

defaultValue 변경 시 key를 사용하여 컴포넌트를 강제 리마운트하는 접근 방식이 Storybook 환경에서 초기 상태를 올바르게 반영하기 위한 좋은 해결책입니다.

apps/web/src/shared/components/Tabs/Tabs.tsx (1)

33-59: LGTM! 잘 구조화된 Tabs 구현입니다.

tabItems를 순회하여 동적으로 Trigger를 생성하는 로직과 data-state에 따른 스타일링이 깔끔하게 구현되어 있습니다. Radix UI의 접근성 기능을 활용하면서도 커스텀 스타일링을 잘 적용했습니다.

Comment on lines +4 to +7
interface TabItem {
value: string;
label: ReactNode;
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue

TabItem 인터페이스 export가 누락되었습니다.

TabItem 인터페이스가 다른 인터페이스들과 달리 export되지 않았습니다. Tabs 컴포넌트와 Storybook에서 이 타입을 사용하므로 export가 필요합니다.

-interface TabItem {
+export interface TabItem {
   value: string;
   label: ReactNode;
 }
📝 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
interface TabItem {
value: string;
label: ReactNode;
}
export interface TabItem {
value: string;
label: ReactNode;
}
🤖 Prompt for AI Agents
In apps/web/src/shared/components/Tabs/Tabs.type.ts around lines 4 to 7, the
TabItem interface is declared but not exported; add the export keyword to the
interface declaration (e.g., export interface TabItem { ... }) so Tabs component
and Storybook can import the type, and update any imports if necessary to
reflect the exported name.

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

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Tabs] fireeren-component to Time-align Code 이관

2 participants