Conversation
|
Warning Rate limit exceeded@jllee000 has exceeded the limit for the number of commits or files that can be reviewed per hour. Please wait 25 minutes and 51 seconds before requesting another review. ⌛ How to resolve this issue?After the wait time has elapsed, a review can be triggered using the We recommend that you space out your commits to avoid hitting the rate limit. 🚦 How do rate limits work?CodeRabbit enforces hourly rate limits for each developer per organization. Our paid plans have higher rate limits than the trial, open-source and free plans. In all cases, we re-allow further reviews after a brief timeout. Please see our FAQ for further information. 📒 Files selected for processing (3)
Walkthroughdesign-system 패키지에 새로운 Chip 컴포넌트를 추가하고 components 인덱스에 재수출했습니다. 또한 Storybook 및 Vitest 관련 구성(.storybook, vitest.config 등)과 여러 데모/스토리 파일이 추가되었습니다. Changes
Sequence Diagram(s)sequenceDiagram
autonumber
actor Consumer as 소비자
participant Index as components/index
participant Chip as Chip 컴포넌트
participant CVA as class-variance-authority
Consumer->>Index: import { Chip } from 'design-system/components'
Consumer->>Chip: <Chip color="red" category="프론트엔드" />
Chip->>CVA: variants({ color })
CVA-->>Chip: className
Chip-->>Consumer: <span class="...">프론트엔드</span>
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~20 minutes Assessment against linked issues
Out-of-scope changes
Possibly related PRs
Suggested labels
Suggested reviewers
Poem
✨ Finishing Touches
🧪 Generate unit tests
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. 🪧 TipsChatThere are 3 ways to chat with CodeRabbit:
SupportNeed help? Create a ticket on our support page for assistance with any issues or questions. CodeRabbit Commands (Invoked using PR/Issue comments)Type Other keywords and placeholders
Status, Documentation and Community
|
|
✅ Storybook chromatic 배포 확인: |
There was a problem hiding this comment.
Actionable comments posted: 5
🧹 Nitpick comments (4)
packages/design-system/src/components/chip/Chip.tsx (3)
18-39: defaultVariants 사용성과 prop 요구사항 정렬
defaultVariants.color = 'red'가 설정되어 있는데, 기존에는color가 필수라 디폴트가 의미가 없었습니다. 위 코멘트대로color?:로 바꾸면 디폴트가 실제로 의미를 가집니다. 만약color를 필수로 유지하려면defaultVariants를 제거해 혼란을 줄이는 것을 권장합니다.디자인 의도(디폴트 레드 허용 vs 항상 명시 필요)에 따라 최종 방향을 확인해 주세요.
40-44: 문자 콘텐츠 확장성(children 지원) 검토향후 아이콘+텍스트 등 복합 콘텐츠(예: 카테고리 아이콘)를 담으려면
category문자열 전용 대신children을 기본으로 하고category는 deprecated 또는 fallback으로 두는 전략이 유연합니다.원한다면
children ?? category패턴으로의 마이그레이션 diff 제공 가능합니다.
46-46: 타입도 공개 export하여 DX 향상소비자가 색상 토큰/프롭 타입을 재사용할 수 있도록 타입 export를 권장합니다.
적용 diff:
export default Chip; +export type { ChipProps, ChipColor };packages/design-system/src/components/index.ts (1)
4-4: 타입 재export로 소비자 편의 증대
ChipProps,ChipColor타입도 함께 re-export하면 외부에서 타입을 쉽게 참조할 수 있습니다. (Chip.tsx에서 타입들을 export하도록 변경이 선행되어야 합니다.)적용 diff:
export { default as Chip } from './chip/Chip'; +export type { ChipProps, ChipColor } from './chip/Chip';
📜 Review details
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro
💡 Knowledge Base configuration:
- MCP integration is disabled by default for public repositories
- Jira integration is disabled by default for public repositories
- Linear integration is disabled by default for public repositories
You can enable these sources in your CodeRabbit configuration.
📒 Files selected for processing (2)
packages/design-system/src/components/chip/Chip.tsx(1 hunks)packages/design-system/src/components/index.ts(1 hunks)
🔇 Additional comments (2)
packages/design-system/src/components/chip/Chip.tsx (1)
40-44: 접근성 가이드(빈 콘텐츠 처리)
category가 전달되지 않으면 빈<span>이 렌더링됩니다. 이 경우는aria-hidden="true"로 장식적 요소임을 명시하거나, 시각적으로만 표시한다면aria-label을 제공하는 방안을 검토해 주세요.필요 시 역할/레이블 설계를 함께 정의해 드립니다.
packages/design-system/src/components/index.ts (1)
4-4: Chip 공개 export 추가 확인컴포넌트 인덱스에서
Chip공개가 적절히 이루어졌습니다. 소비자 입장에서도 사용성이 좋아집니다.
| @@ -0,0 +1,46 @@ | |||
| import { cva } from 'class-variance-authority'; | |||
There was a problem hiding this comment.
🛠️ Refactor suggestion
유틸 및 타입 임포트 보강: cx(클래스 병합)와 HTMLAttributes 임포트
className 합성을 위해 cx를 같이 쓰고, React 타입은 네임스페이스 접근 대신 타입 임포트를 권장합니다.
적용 diff:
-import { cva } from 'class-variance-authority';
+import { cva, cx } from 'class-variance-authority';
+import type { HTMLAttributes } from 'react';📝 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.
| import { cva } from 'class-variance-authority'; | |
| import { cva, cx } from 'class-variance-authority'; | |
| import type { HTMLAttributes } from 'react'; |
🤖 Prompt for AI Agents
In packages/design-system/src/components/chip/Chip.tsx around line 1, the file
only imports cva but the review requests strengthening imports: add cx from
'class-variance-authority' to use for className merging and import the React
HTMLAttributes type as a type import (import type { HTMLAttributes } from
'react') instead of using the React namespace; update the component props to use
HTMLAttributes<HTMLDivElement> (or the appropriate element) and replace any
React.HTMLAttributes usages with the imported HTMLAttributes, and use cx(...)
when combining className strings to ensure correct class merging.
| interface ChipProps extends React.ButtonHTMLAttributes<HTMLButtonElement> { | ||
| color: ChipColor; | ||
| category?: string; | ||
| } |
There was a problem hiding this comment.
🛠️ Refactor suggestion
DOM 요소와 props 타입 불일치(Span 렌더링 + ButtonHTMLAttributes) — 타입 및 시맨틱 정정 제안
렌더링은 <span>인데 React.ButtonHTMLAttributes<HTMLButtonElement>를 확장하고 있어 시맨틱과 타입이 어긋납니다. 또한 React 네임스페이스 타입 사용 시 별도 타입 임포트가 없으면 TS 구성에 따라 오류가 날 수 있습니다. Span 용으로 맞추고 color를 optional로 두면 defaultVariants('red')도 자연스럽게 작동합니다.
적용 diff:
-interface ChipProps extends React.ButtonHTMLAttributes<HTMLButtonElement> {
- color: ChipColor;
+interface ChipProps extends HTMLAttributes<HTMLSpanElement> {
+ color?: ChipColor;
category?: string;
}Committable suggestion skipped: line range outside the PR's diff.
🤖 Prompt for AI Agents
In packages/design-system/src/components/chip/Chip.tsx around lines 14 to 17,
the component currently extends React.ButtonHTMLAttributes<HTMLButtonElement>
while rendering a <span>, causing a semantic and type mismatch and potential
React namespace issues; change the props to extend
React.HTMLAttributes<HTMLSpanElement> (or import HTMLAttributes and use
HTMLAttributes<HTMLSpanElement>) and make the color prop optional (color?:
ChipColor) so the component can rely on its defaultVariants('red') fallback;
keep category optional as-is and ensure any downstream usages/type imports are
updated accordingly.
| const Chip = ({ color, category }: ChipProps) => { | ||
| return ( | ||
| <span className={ChipColorVariants({ color: color })}>{category}</span> | ||
| ); | ||
| }; |
There was a problem hiding this comment.
🛠️ Refactor suggestion
className 합성 및 나머지 props 전달 누락 — 구성 가능성 향상
현재 className 오버라이드/확장과 이벤트/데이터 속성 전달이 불가능합니다. 디자인 시스템 컴포넌트로서 구성 가능성을 높이기 위해 전달/병합을 추가하세요.
적용 diff:
-const Chip = ({ color, category }: ChipProps) => {
- return (
- <span className={ChipColorVariants({ color: color })}>{category}</span>
- );
-};
+const Chip = ({ color, category, className, ...rest }: ChipProps) => {
+ return (
+ <span
+ className={cx(ChipColorVariants({ color }), className)}
+ {...rest}
+ >
+ {category}
+ </span>
+ );
+};📝 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.
| const Chip = ({ color, category }: ChipProps) => { | |
| return ( | |
| <span className={ChipColorVariants({ color: color })}>{category}</span> | |
| ); | |
| }; | |
| const Chip = ({ color, category, className, ...rest }: ChipProps) => { | |
| return ( | |
| <span | |
| className={cx(ChipColorVariants({ color }), className)} | |
| {...rest} | |
| > | |
| {category} | |
| </span> | |
| ); | |
| }; |
🤖 Prompt for AI Agents
In packages/design-system/src/components/chip/Chip.tsx around lines 40 to 44,
the component currently ignores incoming className and other DOM/event/data
props; update ChipProps to extend React.HTMLAttributes<HTMLSpanElement> (or
include a rest props bag), accept ...props in the component signature, and merge
incoming props.className with ChipColorVariants({ color }) using the project's
class-merge utility (clsx/twMerge/clsx) before passing to the span; finally
spread the remaining props onto the span so event handlers and data attributes
are forwarded.
There was a problem hiding this comment.
Actionable comments posted: 4
🧹 Nitpick comments (20)
vitest.shims.d.ts (1)
1-1: Vitest 전역 타입 선언 누락 확인 및 보강 제안아래 tsconfig.json 파일들에서
compilerOptions.types에"vitest"가 모두 누락된 것이 확인되었습니다:
- apps/client/tsconfig.json: ✖ vitest types missing
- apps/extension/tsconfig.json: ✖ vitest types missing
- apps/landing/tsconfig.json: ✖ vitest types missing
- packages/design-system/tsconfig.json: ✖ vitest types missing
따라서 전역으로
describe/it/expect등을 안전하게 인식시키기 위해, 다음 중 한 가지 방법을 선택하여 적용해 주세요:• Shim 파일에 선언 추가
파일vitest.shims.d.ts상단을 아래와 같이 수정+/// <reference types="vitest" /> /// <reference types="@vitest/browser/providers/playwright" />• tsconfig.json 수정
각 프로젝트의tsconfig*.json에서{ "compilerOptions": { "types": [ /* 기존 항목들 */, "vitest" ] } }위 중 편한 방식을 선택해 적용해 주시면 전역 타입 인식 문제가 해소됩니다.
.storybook/preview.ts (2)
1-1: Preview 타입 import 경로를 '@storybook/react'로 교체 권장Storybook 9.x에서는
Preview타입을@storybook/react에서 가져오는 것이 표준입니다.@storybook/react-vite에서 타입을 가져오면 IDE/빌드에서 타입 해석 오류가 발생할 수 있습니다.-import type { Preview } from '@storybook/react-vite'; +import type { Preview } from '@storybook/react';
12-17: a11y 설정의test: 'todo'는 표준 옵션이 아닙니다
@storybook/addon-a11y는disable,manual,config등의 옵션을 지원합니다. 현재test: 'todo'는 무시될 가능성이 높습니다. “UI에만 표시하고 CI 실패는 원치 않음”이라면manual: true로 명시하거나 테스트 러너 측에서 임계치를 제어하는 편이 명확합니다.a11y: { - // 'todo' - show a11y violations in the test UI only - // 'error' - fail CI on a11y violations - // 'off' - skip a11y checks entirely - test: 'todo', + // 개발 중에만 a11y 패널에서 확인하고, 자동 스캔은 비활성화 + manual: true, },위 변경 후
pnpm storybook실행 시 a11y 패널이 기대대로 동작하는지 확인해 주세요(자동 스캔 비활성화, 수동 검사만 노출).package.json (1)
10-12: 도구 체인 버전 호환성 확인 결과
@storybook/react-vite@9.1.3의 peerDependencies(vite: ^5.0.0 ∥ ^6.0.0 ∥ ^7.0.0)가 프로젝트의vite@7.1.2와 호환됩니다.storybook@9.1.3는 peerDependencies로prettier:^2 ∥ ^3만 요구하므로 별도 버전 충돌 우려가 없습니다.vitest@3.2.4및@vitest/browser@3.2.4는 상호 매칭되는 peerDependencies(jsdom, happy-dom, @vitest/ui@3.2.4, @types/node 등)를 가지며, 설치된 버전과 호환됩니다.추가로, MDX에서
@storybook/blocks를 사용하실 경우
@storybook/addon-docs@9.1.3는@storybook/blocks를 자동 설치하지 않으므로- 필요 시
npm install --save-dev @storybook/blocks@latest또는pnpm add -D @storybook/blocks@latest를 통해 직접 추가해주세요.stories/Configure.mdx (3)
199-205: 문구 오탈자 수정 제안“Follow guided walkthroughs on for key workflows.”에서 “on”이 중복된 것으로 보입니다.
- <p>Follow guided walkthroughs on for key workflows.</p> + <p>Follow guided walkthroughs for key workflows.</p>
253-257: grid-gap 대신 gap 사용 권장
grid-gap은 구문 유지되지만gap으로 대체되었습니다. 최신 속성 사용을 권장합니다..sb-features-grid { display: grid; grid-template-columns: repeat(2, 1fr); - grid-gap: 32px 20px; + gap: 32px 20px; }
354-361: 중복된margin-left선언 정리서로 다른 값으로 두 번 선언되어 있어 마지막 값만 적용됩니다. 불필요한 선언을 제거하세요.
.sb-addon-img img { width: 1200px; transform: rotate(-12deg); - margin-left: 0; margin-top: 48px; margin-bottom: -40px; margin-left: -24px; }packages/design-system/src/components/chip/Chip.stories.tsx (3)
4-12: 메타 타입 표기는satisfies로 전환 권장Storybook CSF8 권장 패턴에 맞춰
const meta = { ... } satisfies Meta<typeof Chip>로 작성하면 과잉 속성 탐지와 추론 품질이 좋아집니다.-const meta: Meta<typeof Chip> = { +const meta = { title: 'UI/Chip', component: Chip, tags: ['autodocs'], args: { category: 'Frontend', color: 'red', }, -}; +} satisfies Meta<typeof Chip>;
79-83: AllColors 스토리에서color컨트롤 비활성화루프에서
color를 강제 설정하므로 Controls 패널에서color를 노출하면 사용자가 바꿔도 즉시 덮어써져 혼란을 줄 수 있습니다. 컨트롤 제외를 권장합니다.parameters: { docs: { description: { story: '팔레트 뷰: 모든 색상 변형을 한 번에 미리보기' }, }, + controls: { exclude: ['color'] }, },
17-32: 색상 옵션 하드코딩 중복 제거 및 재사용
Chip.stories.tsx의argTypes.color.options와AllColors스토리 내colors배열이 동일한 색상 목록을 하드코딩하고 있으며, 이 목록은Chip.tsx의ChipColor타입 및 cva variants 정의와도 중복됩니다. 이로 인해 토큰 드리프트 위험이 있으므로, 한 곳에서만 관리하도록 리팩터링을 권장합니다.주요 변경 제안:
packages/design-system/src/components/chip/Chip.tsx
- 색상 목록을 상수로 추출하여 내보내기
ChipColor타입을 해당 상수를 기반으로 재정의import { cva } from 'class-variance-authority'; - type ChipColor = 'red' | 'purple' | … ; + export const CHIP_COLORS = [ + 'red', + 'purple', + 'navyblue', + 'skyblue', + 'emerald', + 'navygreen', + 'khaki', + 'orange', + 'amber', + 'maroon', + ] as const; + export type ChipColor = typeof CHIP_COLORS[number]; interface ChipProps extends React.ButtonHTMLAttributes<HTMLButtonElement> { color: ChipColor; category?: string; } const ChipColorVariants = cva( /* … */ );packages/design-system/src/components/chip/Chip.stories.tsx
argTypes.color.options와AllColors스토리의colors배열에서 하드코딩된 목록을 삭제하고,CHIP_COLORS를 import하여 재사용argTypes: { color: { control: { type: 'select' }, - options: [ - 'red', 'purple', /* … */ 'maroon', - ], + options: CHIP_COLORS, description: '카테고리 색상', }, }, export const AllColors: Story = { args: { category: 'Category' }, render: (args) => { - const colors = [ 'red', 'purple', /* … */ 'maroon' ] as const; + const colors = CHIP_COLORS; /* … */ }, };이렇게 하면 색상 토큰이 한 곳에서 정의되어 컴포넌트–스토리 간에 항상 동기화되며, 향후 색상 추가·삭제 시 유지보수 부담을 줄일 수 있습니다. 필요하시면 패치 작성도 도와드리겠습니다.
stories/Page.tsx (1)
10-11: React.FC 사용 지양 및 상태 타입 명시화
React.FC는 암묵적 children, 제네릭 제약 등으로 비추천 경향입니다. 단순 함수 컴포넌트로 전환하고useState<User | undefined>를 명시하면 의도가 더 선명합니다.-export const Page: React.FC = () => { - const [user, setUser] = React.useState<User>(); +export function Page() { + const [user, setUser] = React.useState<User | undefined>(undefined);stories/Button.tsx (1)
5-16: 표준 버튼 속성 수용을 위해 HTMLButtonAttributes 확장 권장
disabled,aria-*,onFocus등 표준 속성을 자연스럽게 받도록 타입을 확장하면 재사용성이 좋아집니다. 현재도...props를 전달하지만 타입 선언이 좁아 에디터 지원이 제한됩니다.-export interface ButtonProps { +export interface ButtonProps extends React.ButtonHTMLAttributes<HTMLButtonElement> { /** Is this the principal call to action on the page? */ primary?: boolean; /** What background color to use */ backgroundColor?: string; /** How large should the button be? */ size?: 'small' | 'medium' | 'large'; /** Button contents */ label: string; - /** Optional click handler */ - onClick?: () => void; }stories/Button.stories.ts (3)
9-9: 스토리 타이틀 네이밍 컨벤션 정렬디자인 시스템 내 문서화를 고려하면
"Example/Button"대신"Components/Button"혹은"Design System/Button"처럼 실서비스 컨벤션을 따르는 그룹핑이 탐색성에 유리합니다.
예:- title: 'Example/Button', + title: 'Components/Button',
18-23: 컨트롤/도큐멘트 품질 개선: size/primary 컨트롤 노출현재
backgroundColor만 컨트롤로 노출됩니다. 소비자가 컴포넌트 API를 빠르게 이해할 수 있도록size와primary도 컨트롤로 추가하는 것을 권장합니다.argTypes: { - backgroundColor: { control: 'color' }, + backgroundColor: { control: 'color' }, + size: { + control: { type: 'select' }, + options: ['small', 'medium', 'large'], + description: 'Button size', + }, + primary: { + control: 'boolean', + description: 'Use primary variant', + }, }, // Use `fn` to spy on the onClick arg, which will appear in the actions panel once invoked: https://storybook.js.org/docs/essentials/actions#action-args args: { onClick: fn() },
7-24: 스토리 구성 검토: Chip 컴포넌트 색상 분기 분리 및 Storybook 트리 정렬 요청
packages/design-system/src/components/chip/Chip.stories.tsx파일이 존재하지만, meta.title이 Storybook 사이드바에서Components/Chip로 노출되는지 확인이 필요합니다.- 현재 단일 스토리만 정의되어 있고, 색상 분기(예:
success,warning,info등)에 대한 개별 스토리가 없습니다.
• 각 variant별로 별도 스토리(예:)를 추가하면 회귀 테스트 및 시각 검증에 유리합니다.export const Success = { args: { variant: 'success' } }; export const Warning = { args: { variant: 'warning' } }; // …- Vitest 연동(스토리 기반 테스트)이 이미 설정되어 있다면, 색상 토큰·클래스 바인딩에 대한 상호작용 테스트 케이스도 보강해 주세요.
vitest.config.ts (1)
16-36: Vitest 프로젝트 정의 방식 정교화: defineProject 사용 제안현 구성도 동작 가능하나, Vitest가 권장하는
defineProject를 사용하면 타입 지원과 병렬 프로젝트 구성이 더 명확해집니다. 또한 플러그인을 루트 레벨에 배치하면 중복 구성을 줄일 수 있습니다.-import { defineConfig } from 'vitest/config'; +import { defineConfig, defineProject } from 'vitest/config'; export default defineConfig({ - test: { - projects: [ - { - extends: true, - plugins: [ - // The plugin will run tests for the stories defined in your Storybook config - // See options at: https://storybook.js.org/docs/next/writing-tests/integrations/vitest-addon#storybooktest - storybookTest({ configDir: path.join(dirname, '.storybook') }), - ], - test: { - name: 'storybook', - browser: { - enabled: true, - headless: true, - provider: 'playwright', - instances: [{ browser: 'chromium' }], - }, - setupFiles: ['.storybook/vitest.setup.ts'], - }, - }, - ], - }, + plugins: [storybookTest({ configDir: path.join(dirname, '.storybook') })], + test: { + projects: [ + defineProject({ + name: 'storybook', + browser: { + enabled: true, + headless: true, + provider: 'playwright', + instances: [{ browser: 'chromium' }], + }, + setupFiles: ['.storybook/vitest.setup.ts'], + }), + ], + }, });stories/Header.tsx (2)
21-36: 장식용 SVG 접근성 개선: 스크린 리더에서 숨기기현재 SVG는 순수 장식 요소로 보입니다. 스크린 리더 노이즈를 줄이기 위해
aria-hidden과focusable="false"를 추가하는 것을 권장합니다.- <svg width="32" height="32" viewBox="0 0 32 32" xmlns="http://www.w3.org/2000/svg"> + <svg + width="32" + height="32" + viewBox="0 0 32 32" + xmlns="http://www.w3.org/2000/svg" + aria-hidden="true" + focusable="false" + >
17-17: onClick 핸들러 기본값 제공으로 안정성 소폭 개선
Button이onClick?: () => void일 가능성이 높지만, 기본 no-op을 제공하면 스토리/데모에서 핸들러 미지정 시에도 의도를 명확히 할 수 있습니다.-export const Header = ({ user, onLogin, onLogout, onCreateAccount }: HeaderProps) => ( +export const Header = ({ + user, + onLogin = () => {}, + onLogout = () => {}, + onCreateAccount = () => {}, +}: HeaderProps) => (stories/Page.stories.ts (2)
22-33: 플레이 테스트 안정성 향상: 쿼리 재조회 및 findByRole 사용클릭 직후 DOM 업데이트 타이밍에 따른 간헐적 실패를 줄이기 위해, 사라짐 검증은
queryByRole재조회로, 등장 검증은findByRole로 대기하는 패턴을 권장합니다.export const LoggedIn: Story = { play: async ({ canvasElement }) => { const canvas = within(canvasElement); const loginButton = canvas.getByRole('button', { name: /Log in/i }); await expect(loginButton).toBeInTheDocument(); - await userEvent.click(loginButton); - await expect(loginButton).not.toBeInTheDocument(); + await userEvent.click(loginButton); + // 업데이트 이후 재조회로 부재 검증 + await expect(canvas.queryByRole('button', { name: /Log in/i })).not.toBeInTheDocument(); - const logoutButton = canvas.getByRole('button', { name: /Log out/i }); - await expect(logoutButton).toBeInTheDocument(); + // 등장 대기 후 검증 + const logoutButton = await canvas.findByRole('button', { name: /Log out/i }); + await expect(logoutButton).toBeInTheDocument(); }, };
8-14: 스토리 네임스페이스 정비디자인 시스템 카탈로그와의 일관성을 위해
"Example/Page"대신"Components/Page"또는"Foundations/Page"같은 그룹 사용을 제안드립니다.- title: 'Example/Page', + title: 'Components/Page',
📜 Review details
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro
💡 Knowledge Base configuration:
- MCP integration is disabled by default for public repositories
- Jira integration is disabled by default for public repositories
- Linear integration is disabled by default for public repositories
You can enable these sources in your CodeRabbit configuration.
⛔ Files ignored due to path filters (16)
pnpm-lock.yamlis excluded by!**/pnpm-lock.yamlstories/assets/accessibility.pngis excluded by!**/*.pngstories/assets/accessibility.svgis excluded by!**/*.svgstories/assets/addon-library.pngis excluded by!**/*.pngstories/assets/assets.pngis excluded by!**/*.pngstories/assets/context.pngis excluded by!**/*.pngstories/assets/discord.svgis excluded by!**/*.svgstories/assets/docs.pngis excluded by!**/*.pngstories/assets/figma-plugin.pngis excluded by!**/*.pngstories/assets/github.svgis excluded by!**/*.svgstories/assets/share.pngis excluded by!**/*.pngstories/assets/styling.pngis excluded by!**/*.pngstories/assets/testing.pngis excluded by!**/*.pngstories/assets/theming.pngis excluded by!**/*.pngstories/assets/tutorials.svgis excluded by!**/*.svgstories/assets/youtube.svgis excluded by!**/*.svg
📒 Files selected for processing (18)
.storybook/main.ts(1 hunks).storybook/preview.ts(1 hunks).storybook/vitest.setup.ts(1 hunks)package.json(1 hunks)packages/design-system/src/components/chip/Chip.stories.tsx(1 hunks)packages/design-system/src/components/chip/Chip.tsx(1 hunks)stories/Button.stories.ts(1 hunks)stories/Button.tsx(1 hunks)stories/Configure.mdx(1 hunks)stories/Header.stories.ts(1 hunks)stories/Header.tsx(1 hunks)stories/Page.stories.ts(1 hunks)stories/Page.tsx(1 hunks)stories/button.css(1 hunks)stories/header.css(1 hunks)stories/page.css(1 hunks)vitest.config.ts(1 hunks)vitest.shims.d.ts(1 hunks)
✅ Files skipped from review due to trivial changes (3)
- stories/button.css
- stories/header.css
- stories/page.css
🚧 Files skipped from review as they are similar to previous changes (1)
- packages/design-system/src/components/chip/Chip.tsx
🧰 Additional context used
🧠 Learnings (1)
📚 Learning: 2025-08-23T18:42:42.797Z
Learnt from: jjangminii
PR: Pinback-Team/pinback-client#22
File: packages/design-system/package.json:32-35
Timestamp: 2025-08-23T18:42:42.797Z
Learning: Storybook packages have different release cycles and stable versions. As of 2025, storybook/test and storybook/blocks have their latest stable versions in the 8.x line (8.6.14), while other packages like storybook/react-vite are stable in 9.x line (9.1.3). Mixed major versions across Storybook packages can be intentional and correct when using the latest stable version of each package.
Applied to files:
package.json
🧬 Code graph analysis (5)
stories/Header.stories.ts (1)
stories/Header.tsx (1)
Header(17-56)
stories/Page.tsx (1)
stories/Header.tsx (1)
Header(17-56)
stories/Button.stories.ts (1)
stories/Button.tsx (1)
Button(19-37)
stories/Header.tsx (1)
stories/Button.tsx (1)
Button(19-37)
stories/Page.stories.ts (2)
stories/Page.tsx (1)
Page(10-73)stories/Header.stories.ts (2)
LoggedOut(34-34)LoggedIn(26-32)
🔇 Additional comments (9)
stories/Configure.mdx (1)
1-1: MDX 블록 import 경로 최신화:@storybook/blocks사용 권장Storybook 8/9에서는
@storybook/addon-docs/blocks대신@storybook/blocks사용이 권장됩니다. 구 경로는 제거/호환 중단 가능성이 있습니다.-import { Meta } from "@storybook/addon-docs/blocks"; +import { Meta } from "@storybook/blocks";⛔ Skipped due to learnings
Learnt from: jjangminii PR: Pinback-Team/pinback-client#22 File: packages/design-system/package.json:32-35 Timestamp: 2025-08-23T18:42:42.797Z Learning: Storybook packages have different release cycles and stable versions. As of 2025, storybook/test and storybook/blocks have their latest stable versions in the 8.x line (8.6.14), while other packages like storybook/react-vite are stable in 9.x line (9.1.3). Mixed major versions across Storybook packages can be intentional and correct when using the latest stable version of each package..storybook/vitest.setup.ts (1)
1-7: ✅ Vitest + Portable Stories 설정 반영 확인됨
- vitest.config.ts에서
setupFiles: ['.storybook/vitest.setup.ts']로.storybook/vitest.setup.ts가 정상 포함됨 (32번 줄)storybookTest({ configDir: path.join(dirname, '.storybook') })호출로 Storybook 테스트 플러그인 및configDir옵션이 올바르게 설정됨 (22번 줄)추가 검토 및 조치 불필요합니다.
stories/Page.tsx (1)
15-21: 헤더 상호작용 핸들러는 데모 목적에 적합(LGTM)스토리 데모 용도로 로그인/로그아웃 상태 전환 로직이 간결하고 충분합니다.
stories/Header.stories.ts (1)
7-21: 메타 구성, 타입 세이프티, 테스트 훅 사용이 적절합니다
satisfies Meta<typeof Header>와fn()활용으로 스토리/테스트 작성 준비가 잘 되어 있습니다. 추가 조치는 없어 보입니다.stories/Button.tsx (1)
28-36:type="button"지정과 클래스 구성 적절(LGTM)폼 내 기본 submit 방지 목적의
type="button"지정과 모드 클래스 구성 방식이 명확합니다.stories/Button.stories.ts (1)
1-1: 타입 임포트 경로 유지 권장현재 프로젝트는 Vite 빌더용 Storybook 패키지(
@storybook/react-vite@^9.1.3)를 사용하고 있으며, 공식 문서에서도 “Replace your-framework with the framework you are using, e.g. react-vite” 예시처럼 Vite 빌더를 쓸 경우import type { Meta, StoryObj } from '@storybook/react-vite';를 권장합니다 (storybook.js.org).
@storybook/react패키지가 devDependencies에 존재하지 않아 해당 경로로 타입을 임포트할 경우 모듈을 찾을 수 없어 빌드 에러가 발생합니다.따라서 기존
@storybook/react-vite경로를 그대로 유지하시는 것이 맞습니다.Likely an incorrect or invalid review comment.
vitest.config.ts (2)
8-12: ESM/CJS 환경 가드 처리 좋습니다
__dirname유무에 따른 분기와fileURLToPath사용으로 런타임 환경 차이를 안전하게 흡수하고 있습니다. 유지보수 관점에서도 가독성이 좋습니다.
26-31: Playwright 인스턴스 설정 호환성 확인 완료현재
package.json의 devDependencies에 Vitest^3.2.4와 Playwright^1.55.0가 명시되어 있으며, Vitest 3 이상에서browser.instances옵션을 공식 지원합니다.
또한.storybook/vitest.setup.ts및.storybook디렉터리도 정상 존재하므로, 제안된 폴백(name: 'chromium')을 적용하지 않고도instances: [{ browser: 'chromium' }]구성을 그대로 사용하셔도 문제 없습니다.stories/Header.tsx (1)
17-56: 구성/타이핑 전반적으로 안정적입니다Props를 명시적으로 모델링하고 상태를 외부에서 주입받는 구조가 스토리/테스트 친화적입니다. 버튼 라벨도 명확하여 접근성 측면에서도 기본 요건을 충족합니다.
| @@ -0,0 +1,28 @@ | |||
| import type { StorybookConfig } from '@storybook/react-vite'; | |||
|
|
|||
| import { join, dirname } from "path" | |||
There was a problem hiding this comment.
ESM 환경에서 require 미정의 오류 가능 — createRequire 사용 필요
현재 파일은 ESM(Top-level import) 문법을 사용하고 있어 require가 정의되지 않았을 수 있습니다. createRequire(import.meta.url)로 require.resolve를 안전하게 사용하도록 보완해 주세요. 또한 getAbsolutePath의 반환 타입을 string으로 명시하면 타입 안정성이 좋아집니다.
import { join, dirname } from "path"
+import { createRequire } from "module"
/**
* This function is used to resolve the absolute path of a package.
* It is needed in projects that use Yarn PnP or are set up within a monorepo.
*/
-function getAbsolutePath(value: string): any {
- return dirname(require.resolve(join(value, 'package.json')))
-}
+const require = createRequire(import.meta.url)
+function getAbsolutePath(value: string): string {
+ return dirname(require.resolve(join(value, "package.json")))
+}Also applies to: 9-11
🤖 Prompt for AI Agents
In .storybook/main.ts around lines 3 and 9-11, the file uses ESM imports so
using require.resolve may fail; replace direct require usage by importing
createRequire from "module" and create a require via
createRequire(import.meta.url) to call require.resolve safely in ESM, and
annotate the getAbsolutePath function to return string (not implicit any) to
improve type safety; update any callers accordingly to accept a string return
and remove reliance on global require.
| "stories": [ | ||
| "../stories/**/*.mdx", | ||
| "../stories/**/*.stories.@(js|jsx|mjs|ts|tsx)" | ||
| ], |
There was a problem hiding this comment.
💡 Verification agent
🧩 Analysis chain
디자인 시스템 스토리 경로 누락 — 패키지 내부 스토리도 로드되도록 확장 권장
현재 stories 글롭이 루트 stories/만 가리켜 packages/design-system 하위의 *.stories.*가 로드되지 않을 수 있습니다. 카테고리 칩(Chip) 스토리를 Storybook에서 확인하려면 경로를 확장해 주세요.
"stories": [
"../stories/**/*.mdx",
- "../stories/**/*.stories.@(js|jsx|mjs|ts|tsx)"
+ "../stories/**/*.stories.@(js|jsx|mjs|ts|tsx)",
+ "../packages/**/*.mdx",
+ "../packages/**/*.stories.@(js|jsx|mjs|ts|tsx)"
],변경 후 pnpm storybook을 실행하여 Chip 스토리가 탐색기에 노출되는지 확인해 주세요.
🏁 Script executed:
#!/usr/bin/env bash
# Display the first 50 lines of the Storybook config to confirm current glob patterns
echo "== .storybook/main.ts (lines 1–50) =="
sed -n '1,50p' .storybook/main.ts || echo "Unable to read .storybook/main.ts"
# List any MDX or .stories.* files under packages/design-system to confirm their existence
echo
echo "== Story files in packages/design-system/ =="
find packages/design-system -type f \( -iname "*.mdx" -o -iname "*.stories.*" \) || echo "No story files found under packages/design-system/"Length of output: 1362
스토리 glob 패턴 확장 필요 — 패키지 내부 스토리 로드
현재 .storybook/main.ts의 stories 설정에 루트 stories/만 포함되어 있어 packages/design-system 하위의 스토리가 로드되지 않습니다. Chip 컴포넌트 등의 패키지 내 스토리를 불러오기 위해 glob 패턴을 확장해주세요.
• 파일: .storybook/main.ts
• 위치: stories 배열
"stories": [
"../stories/**/*.mdx",
- "../stories/**/*.stories.@(js|jsx|mjs|ts|tsx)"
+ "../stories/**/*.stories.@(js|jsx|mjs|ts|tsx)",
+ "../packages/**/*.mdx",
+ "../packages/**/*.stories.@(js|jsx|mjs|ts|tsx)"
],변경 후 pnpm storybook 실행 시 탐색기에서 packages/design-system/src/components/chip/Chip.stories.tsx가 노출되는지 확인 부탁드립니다.
📝 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.
| "stories": [ | |
| "../stories/**/*.mdx", | |
| "../stories/**/*.stories.@(js|jsx|mjs|ts|tsx)" | |
| ], | |
| "stories": [ | |
| "../stories/**/*.mdx", | |
| "../stories/**/*.stories.@(js|jsx|mjs|ts|tsx)", | |
| "../packages/**/*.mdx", | |
| "../packages/**/*.stories.@(js|jsx|mjs|ts|tsx)" | |
| ], |
🤖 Prompt for AI Agents
In .storybook/main.ts around lines 13 to 16, the stories glob only includes
"../stories/**" so it misses component stories inside packages (e.g.,
packages/design-system); update the stories array to include package-level globs
that match nested package story files (for example add
"../packages/**/src/**/*.stories.@(js|jsx|mjs|ts|tsx)" or
"../packages/**/stories/**/*.@(mdx|@(js|jsx|mjs|ts|tsx))") so pnpm storybook
will discover packages/design-system/src/components/chip/Chip.stories.tsx;
ensure patterns are relative to the .storybook folder and include the same
extensions as existing entries.
stories/Configure.mdx
Outdated
| href="https://storybook.js.org/docs/configure/styling-and-css/?renderer=react&ref=configure" | ||
| target="_blank" | ||
| >Learn more<RightArrow /></a> |
There was a problem hiding this comment.
🛠️ Refactor suggestion
외부 링크에 rel="noopener noreferrer" 추가
target="_blank" 사용 시 탭 간 window.opener를 통한 보안/성능 이슈를 방지하기 위해 rel="noopener noreferrer"를 추가하세요.
패턴 예시(다른 앵커에도 동일 적용):
- <a
- href="https://storybook.js.org/docs/configure/styling-and-css/?renderer=react&ref=configure"
- target="_blank"
- >Learn more<RightArrow /></a>
+ <a
+ href="https://storybook.js.org/docs/configure/styling-and-css/?renderer=react&ref=configure"
+ target="_blank"
+ rel="noopener noreferrer"
+ >Learn more<RightArrow /></a>Also applies to: 63-65, 75-78, 97-100, 106-109, 116-119, 126-129, 135-138, 144-147, 156-159, 171-174, 181-184, 192-195, 202-205
🤖 Prompt for AI Agents
In stories/Configure.mdx around lines 51-53 (and similarly at 63-65, 75-78,
97-100, 106-109, 116-119, 126-129, 135-138, 144-147, 156-159, 171-174, 181-184,
192-195, 202-205), anchors that use target="_blank" are missing rel="noopener
noreferrer"; update each external <a> tag that opens a new tab to include
rel="noopener noreferrer" alongside target="_blank" to prevent window.opener
security/performance issues.
constantly-dev
left a comment
There was a problem hiding this comment.
수고하셨습니다!! 간단한 코멘트 남겼으니 확인해주세요~
| | 'amber' | ||
| | 'maroon'; | ||
|
|
||
| interface ChipProps extends React.ButtonHTMLAttributes<HTMLButtonElement> { |
There was a problem hiding this comment.
버튼 속성을 확장하고 있는데 아래 span을 사용하고 있네요. 특별하게 button을 쓸 이유가 있다면 아래 span태그도 바꿔야 할 것 같아요! 통일하기!!
There was a problem hiding this comment.
아 헉.! 네 이부분 놓쳤네요! 수정해두겠습니다 :)
| | 'amber' | ||
| | 'maroon'; | ||
|
|
||
| interface ChipProps extends React.ButtonHTMLAttributes<HTMLButtonElement> { |
There was a problem hiding this comment.
그리고
| interface ChipProps extends React.ButtonHTMLAttributes<HTMLButtonElement> { | |
| interface ChipProps extends ButtonHTMLAttributes<HTMLButtonElement> { |
로만 써도 될 것 같아요 👍
There was a problem hiding this comment.
추가적으로 찾아보니, 최신 버전부터는 표준이 바뀌었군요 ㅎㅎ! 감사합니다!
|
|
||
| interface ChipProps extends React.ButtonHTMLAttributes<HTMLButtonElement> { | ||
| color: ChipColor; | ||
| category?: string; |
There was a problem hiding this comment.
확인해보니 말씀대로 카테고리 명은 필수인 것 같아서! 수정해두었습니다 :)
| import Chip from './Chip'; | ||
|
|
||
| const meta: Meta<typeof Chip> = { | ||
| title: 'UI/Chip', |
There was a problem hiding this comment.
title: 'Components/Chip', 로 통일하기!
| parameters: { | ||
| docs: { | ||
| description: { |
There was a problem hiding this comment.
| parameters: { | |
| docs: { | |
| description: { | |
| parameters: { | |
| layout: 'centered', | |
| docs: { | |
| description: { |
로 중앙 정렬 하는 것은 어떤가요?
There was a problem hiding this comment.
중앙 정렬 UI 가 따로 가능하군요? 와우 하나 새로 알아갑니다!
|
|
||
| return ( | ||
| <div style={{ display: 'grid', gap: '8px' }}> | ||
| {colors.map((c) => ( |
There was a problem hiding this comment.
사소하지만 c보다는 color로 네이밍하는 것이 좋을 것 같아요 👍
너무 좋습니다~~~ 👍 |
jjangminii
left a comment
There was a problem hiding this comment.
타입을 명확히 정의해 유지보수성이 높아진 점이 특히 좋습니다. 불필요한 렌더링을 막아 안정성을 끌어올린 부분도 인상적이에요.
색상 케이스가 많아 손이 많이 갔을 텐데 꼼꼼히 반영해 주셔서 고생하셨습니다!
📌 Related Issues
✅ 체크 리스트
📄 Tasks
⭐ PR Point (To Reviewer)
색상 코드값(#000000 같은) 기준으로 color 분기해서 작업할까 하다가, 어차피 색상 코드 받은 걸로 그거에 맞는 텍스트 색상도 세트로 바뀌는 거라서, 색상 코드값을 props로 받지 않고 하나의 색상 세트 네이밍으로 받아 관리했어요. ex. red면 이에 맞는 배경색과 텍스트 적용
++ 서버 리드와 이 색상값 전달 타입에 대해서 논의 후 결정했습니다!
📷 Screenshot
📷 CodeRabbit