-
Notifications
You must be signed in to change notification settings - Fork 0
[FEAT] Table 컴포넌트 제작 #72
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
Walkthrough새로운 Table UI 컴포넌트 세트( Changes
Sequence Diagram(s)sequenceDiagram
autonumber
actor Dev as 스토리북 사용자
participant SB as Storybook
participant Story as Basic Story
participant UI as Table 컴포넌트군
Dev->>SB: Basic 스토리 선택
SB->>Story: render()
Story->>UI: Compose: <Table> -> <TableHeader/> + <TableBody/>
UI->>UI: TableHeader -> TableRow -> TableHead (헤더 렌더)
UI->>UI: TableBody -> TableRow* -> TableCell* (데이터 렌더)
UI-->>SB: DOM 반환
SB-->>Dev: 미리보기 표시
note right of UI: 각 컴포넌트는 props 전달 및 클래스 병합만 수행
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~20 minutes 추가로 주의할 파일/영역:
Suggested reviewers
Pre-merge checks and finishing touches✅ Passed checks (5 passed)
✨ Finishing touches
🧪 Generate unit tests (beta)
📜 Recent review detailsConfiguration used: Path: .coderabbit.yaml Review profile: ASSERTIVE Plan: Pro 📒 Files selected for processing (1)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
🔇 Additional comments (1)
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 |
|
Update: 2025년 11월 17일 14시 36분 50초 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 5
📜 Review details
Configuration used: Path: .coderabbit.yaml
Review profile: ASSERTIVE
Plan: Pro
📒 Files selected for processing (6)
src/shared/ui/Table/Table.stories.tsx(1 hunks)src/shared/ui/Table/Table.tsx(1 hunks)src/shared/ui/Table/TableBody.tsx(1 hunks)src/shared/ui/Table/TableHead.tsx(1 hunks)src/shared/ui/Table/index.ts(1 hunks)src/shared/ui/Table/types.ts(1 hunks)
🧰 Additional context used
🧬 Code graph analysis (4)
src/shared/ui/Table/TableBody.tsx (1)
src/shared/ui/Table/types.ts (1)
Column(3-7)
src/shared/ui/Table/TableHead.tsx (1)
src/shared/ui/Table/types.ts (1)
Column(3-7)
src/shared/ui/Table/Table.tsx (4)
src/shared/ui/Table/types.ts (1)
Column(3-7)src/shared/ui/Table/index.ts (1)
Table(1-1)src/shared/ui/Table/TableHead.tsx (1)
TableHead(10-20)src/shared/ui/Table/TableBody.tsx (1)
TableBody(11-37)
src/shared/ui/Table/Table.stories.tsx (2)
src/shared/ui/Table/Table.tsx (1)
Table(14-31)src/shared/ui/Table/types.ts (1)
Column(3-7)
🔇 Additional comments (4)
src/shared/ui/Table/index.ts (1)
1-1: 깔끔한 배럴 익스포트 구현입니다.표준적인 모듈 재export 패턴을 따르고 있습니다.
src/shared/ui/Table/types.ts (1)
3-7: 타입 정의가 올바르게 구현되었습니다.제네릭 타입 제약과 optional render 함수가 적절하게 정의되어 있습니다.
src/shared/ui/Table/TableHead.tsx (1)
10-20: 헤더 컴포넌트가 올바르게 구현되었습니다.sticky 포지셔닝과 key 생성 로직이 적절합니다.
src/shared/ui/Table/Table.tsx (1)
14-31: Table 컴포넌트가 깔끔하게 구현되었습니다.TableHead와 TableBody를 적절하게 조합하고 있으며, hideHead prop을 통한 조건부 렌더링이 올바릅니다.
src/shared/ui/Table/TableBody.tsx
Outdated
| {data.map((row, rIdx) => ( | ||
| <Flex key={rIdx} className="items-center gap-4 border-b border-gray-200 px-4 py-2"> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
행 키로 배열 인덱스 사용 시 주의가 필요합니다.
현재 rIdx를 키로 사용하고 있는데, 데이터 배열의 순서가 변경되거나 항목이 추가/삭제될 경우 React의 렌더링 최적화가 제대로 동작하지 않을 수 있습니다. 가능하다면 각 행 데이터에서 고유 식별자(예: id)를 추출하여 키로 사용하는 것을 권장합니다.
다음과 같이 개선할 수 있습니다:
- {data.map((row, rIdx) => (
- <Flex key={rIdx} className="items-center gap-4 border-b border-gray-200 px-4 py-2">
+ {data.map((row, rIdx) => {
+ // row에 id 같은 고유 속성이 있다면 사용, 없으면 index 폴백
+ const rowKey = 'id' in row ? String(row.id) : rIdx;
+ return (
+ <Flex key={rowKey} className="items-center gap-4 border-b border-gray-200 px-4 py-2">또는 Props에 getRowKey?: (row: T, index: number) => string | number 같은 prop을 추가하여 사용자가 키 생성 방식을 제어할 수 있도록 할 수 있습니다.
📝 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.
| {data.map((row, rIdx) => ( | |
| <Flex key={rIdx} className="items-center gap-4 border-b border-gray-200 px-4 py-2"> | |
| {data.map((row, rIdx) => { | |
| // row에 id 같은 고유 속성이 있다면 사용, 없으면 index 폴백 | |
| const rowKey = 'id' in row ? String(row.id) : rIdx; | |
| return ( | |
| <Flex key={rowKey} className="items-center gap-4 border-b border-gray-200 px-4 py-2"> |
🤖 Prompt for AI Agents
In src/shared/ui/Table/TableBody.tsx around lines 18 to 19, the code uses the
array index (rIdx) as the React key which can break rendering when rows are
reordered/added/removed; change the component to derive a stable key from the
row (e.g., row.id or another unique field) and fallback only if absent, or add a
getRowKey?: (row: T, index: number) => string | number prop so callers can
supply a stable key generator; update the map to call getRowKey(row, rIdx) or
use row.id (or a configured unique property) instead of rIdx and ensure the prop
type and default fallback are added to the component props.
src/shared/ui/Table/TableBody.tsx
Outdated
| {columns.map((col, cIdx) => { | ||
| const value = row[col.key]; | ||
| const content = col.render ? col.render(value, row) : (value as React.ReactNode); | ||
| return ( | ||
| <Body3 | ||
| key={cIdx} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🧹 Nitpick | 🔵 Trivial
열 키를 개선할 수 있습니다.
현재 cIdx를 열 키로 사용하고 있습니다. 열 순서는 일반적으로 변경되지 않으므로 큰 문제는 아니지만, col.key를 사용하면 더 명시적이고 안정적입니다.
- key={cIdx}
+ key={String(col.key)}📝 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.
| {columns.map((col, cIdx) => { | |
| const value = row[col.key]; | |
| const content = col.render ? col.render(value, row) : (value as React.ReactNode); | |
| return ( | |
| <Body3 | |
| key={cIdx} | |
| {columns.map((col, cIdx) => { | |
| const value = row[col.key]; | |
| const content = col.render ? col.render(value, row) : (value as React.ReactNode); | |
| return ( | |
| <Body3 | |
| key={String(col.key)} |
🤖 Prompt for AI Agents
In src/shared/ui/Table/TableBody.tsx around lines 20 to 25, the column elements
use cIdx as the React key which is less explicit; change the key to use col.key
(or `${col.key}-${cIdx}` as a safe fallback) so keys are stable and meaningful;
ensure col.key is a string/unique identifier and fall back to the index only if
col.key is undefined to avoid warnings.
src/shared/ui/Table/TableBody.tsx
Outdated
| <Flex key={rIdx} className="items-center gap-4 border-b border-gray-200 px-4 py-2"> | ||
| {columns.map((col, cIdx) => { | ||
| const value = row[col.key]; | ||
| const content = col.render ? col.render(value, row) : (value as React.ReactNode); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
타입 단언의 안전성을 검토해주세요.
value를 React.ReactNode로 단언하고 있지만, 실제로 모든 타입의 값이 유효한 ReactNode는 아닙니다. 예를 들어 객체, 함수, Symbol 등은 렌더링 시 에러를 발생시킬 수 있습니다.
다음과 같이 개선할 수 있습니다:
- const content = col.render ? col.render(value, row) : (value as React.ReactNode);
+ const content = col.render
+ ? col.render(value, row)
+ : (typeof value === 'string' || typeof value === 'number' || typeof value === 'boolean' || value === null || value === undefined)
+ ? value
+ : String(value);또는 Column 타입 정의에서 render가 없을 때는 value가 기본적으로 렌더링 가능한 타입이어야 한다는 제약을 추가할 수 있습니다.
📝 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 content = col.render ? col.render(value, row) : (value as React.ReactNode); | |
| // Before: | |
| // const content = col.render ? col.render(value, row) : (value as React.ReactNode); | |
| // After: | |
| const content = col.render | |
| ? col.render(value, row) | |
| : (typeof value === 'string' | |
| || typeof value === 'number' | |
| || typeof value === 'boolean' | |
| || value === null | |
| || value === undefined) | |
| ? value | |
| : String(value); |
🤖 Prompt for AI Agents
In src/shared/ui/Table/TableBody.tsx around line 22, the code unsafely asserts
value as React.ReactNode when col.render is absent; validate and handle
non-renderable types instead of blind assertion. Update logic to detect
renderable primitives/React elements (string, number, boolean, null, undefined,
React.isValidElement) and return them directly; for objects/functions/symbols
either call a safe formatter (e.g., JSON.stringify with try/catch or a toString
fallback) or render a placeholder; alternatively tighten the Column type to
require a render function when the value type is not guaranteed to be renderable
so TypeScript enforces safe usage.
There was a problem hiding this 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 (1)
src/shared/ui/Table/Table.stories.tsx (1)
44-117: 데이터 중복이 여전히 존재합니다.
- Lines 81-86과 100-104가 동일합니다
- Lines 87-92와 105-110이 동일합니다
- Lines 93-98과 111-116이 동일합니다
스크롤 테스트를 위한 의도적인 중복이라면 문제없지만, 실수라면 중복 항목을 제거해 주세요.
📜 Review details
Configuration used: Path: .coderabbit.yaml
Review profile: ASSERTIVE
Plan: Pro
📒 Files selected for processing (1)
src/shared/ui/Table/Table.stories.tsx(1 hunks)
🧰 Additional context used
🧬 Code graph analysis (1)
src/shared/ui/Table/Table.stories.tsx (2)
src/shared/ui/Table/Table.tsx (1)
Table(14-31)src/shared/ui/Table/types.ts (1)
Column(3-7)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
- GitHub Check: preview-storybook
🔇 Additional comments (1)
src/shared/ui/Table/Table.stories.tsx (1)
133-139: 이전 리뷰의 hideHead 누락 이슈가 해결되었습니다.
NoHeader스토리에hideHead: trueprop이 올바르게 추가되어 헤더 없는 테이블이 정상적으로 렌더링됩니다.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 4
📜 Review details
Configuration used: Path: .coderabbit.yaml
Review profile: ASSERTIVE
Plan: Pro
📒 Files selected for processing (9)
src/shared/index.ts(1 hunks)src/shared/ui/Table/Table.stories.tsx(1 hunks)src/shared/ui/Table/Table.tsx(1 hunks)src/shared/ui/Table/TableBody.tsx(1 hunks)src/shared/ui/Table/TableCell.tsx(1 hunks)src/shared/ui/Table/TableHead.tsx(1 hunks)src/shared/ui/Table/TableHeader.tsx(1 hunks)src/shared/ui/Table/TableRow.tsx(1 hunks)src/shared/ui/Table/index.ts(1 hunks)
🧰 Additional context used
🧬 Code graph analysis (7)
src/shared/ui/Table/TableHeader.tsx (7)
src/shared/ui/Table/Table.tsx (1)
Props(5-15)src/shared/ui/Table/TableBody.tsx (1)
Props(5-8)src/shared/ui/Table/TableCell.tsx (1)
Props(7-10)src/shared/ui/Table/TableHead.tsx (1)
Props(7-10)src/shared/ui/Table/TableRow.tsx (1)
Props(5-8)src/shared/index.ts (2)
TableHeader(25-25)cn(30-30)src/shared/ui/Table/index.ts (1)
TableHeader(2-2)
src/shared/ui/Table/TableRow.tsx (7)
src/shared/ui/Table/Table.tsx (1)
Props(5-15)src/shared/ui/Table/TableBody.tsx (1)
Props(5-8)src/shared/ui/Table/TableCell.tsx (1)
Props(7-10)src/shared/ui/Table/TableHead.tsx (1)
Props(7-10)src/shared/ui/Table/TableHeader.tsx (1)
Props(5-8)src/shared/index.ts (2)
TableRow(25-25)cn(30-30)src/shared/ui/Table/index.ts (1)
TableRow(4-4)
src/shared/ui/Table/TableBody.tsx (7)
src/shared/ui/Table/Table.tsx (1)
Props(5-15)src/shared/ui/Table/TableCell.tsx (1)
Props(7-10)src/shared/ui/Table/TableHead.tsx (1)
Props(7-10)src/shared/ui/Table/TableHeader.tsx (1)
Props(5-8)src/shared/ui/Table/TableRow.tsx (1)
Props(5-8)src/shared/index.ts (2)
TableBody(25-25)cn(30-30)src/shared/ui/Table/index.ts (1)
TableBody(3-3)
src/shared/ui/Table/TableHead.tsx (7)
src/shared/ui/Table/Table.tsx (1)
Props(5-15)src/shared/ui/Table/TableBody.tsx (1)
Props(5-8)src/shared/ui/Table/TableCell.tsx (1)
Props(7-10)src/shared/ui/Table/TableHeader.tsx (1)
Props(5-8)src/shared/ui/Table/TableRow.tsx (1)
Props(5-8)src/shared/index.ts (3)
TableHead(25-25)cn(30-30)Body2(24-24)src/shared/ui/Table/index.ts (1)
TableHead(5-5)
src/shared/ui/Table/TableCell.tsx (7)
src/shared/ui/Table/Table.tsx (1)
Props(5-15)src/shared/ui/Table/TableBody.tsx (1)
Props(5-8)src/shared/ui/Table/TableHead.tsx (1)
Props(7-10)src/shared/ui/Table/TableHeader.tsx (1)
Props(5-8)src/shared/ui/Table/TableRow.tsx (1)
Props(5-8)src/shared/index.ts (3)
TableCell(25-25)cn(30-30)Body2(24-24)src/shared/ui/Table/index.ts (1)
TableCell(6-6)
src/shared/ui/Table/Table.stories.tsx (8)
src/shared/index.ts (6)
Table(25-25)TableHeader(25-25)TableRow(25-25)TableHead(25-25)TableBody(25-25)TableCell(25-25)src/shared/ui/Table/Table.tsx (1)
Table(16-26)src/shared/ui/Table/index.ts (6)
Table(1-1)TableHeader(2-2)TableRow(4-4)TableHead(5-5)TableBody(3-3)TableCell(6-6)src/shared/ui/Table/TableHeader.tsx (1)
TableHeader(10-16)src/shared/ui/Table/TableRow.tsx (1)
TableRow(10-16)src/shared/ui/Table/TableHead.tsx (1)
TableHead(12-21)src/shared/ui/Table/TableBody.tsx (1)
TableBody(10-16)src/shared/ui/Table/TableCell.tsx (1)
TableCell(12-20)
src/shared/ui/Table/Table.tsx (7)
src/shared/ui/Table/TableBody.tsx (1)
Props(5-8)src/shared/ui/Table/TableCell.tsx (1)
Props(7-10)src/shared/ui/Table/TableHead.tsx (1)
Props(7-10)src/shared/ui/Table/TableHeader.tsx (1)
Props(5-8)src/shared/ui/Table/TableRow.tsx (1)
Props(5-8)src/shared/index.ts (2)
Table(25-25)cn(30-30)src/shared/ui/Table/index.ts (1)
Table(1-1)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
- GitHub Check: preview-storybook
🔇 Additional comments (9)
src/shared/ui/Table/TableCell.tsx (1)
15-15: 텍스트 색상이 너무 연해 가독성이 떨어질 수 있습니다.
text-gray-400은 상당히 밝은 색상으로, 일반 텍스트 콘텐츠에 사용하기에는 대비가 부족할 수 있습니다. 접근성 가이드라인(WCAG)에서는 일반 텍스트에 대해 최소 4.5:1의 명암비를 권장합니다.
text-gray-600이상의 더 어두운 색상을 사용하는 것을 고려해주세요:- <Body2 className="whitespace-pre-wrap text-gray-400" weight="normal"> + <Body2 className="whitespace-pre-wrap text-gray-600" weight="normal">src/shared/ui/Table/TableHead.tsx (1)
12-20: LGTM!헤더 셀 구현이 적절합니다.
text-gray-700을 사용하여 헤더와 데이터 셀을 시각적으로 구분하고,whitespace-nowrap으로 헤더 텍스트가 줄바꿈되지 않도록 처리한 것이 좋습니다.src/shared/index.ts (1)
25-25: LGTM!모든 Table 컴포넌트가 올바르게 export되었습니다.
src/shared/ui/Table/Table.tsx (2)
21-21:table-fixed레이아웃으로 인한 콘텐츠 오버플로우를 검토해주세요.
table-fixed를 사용하면 모든 열이 동일한 너비를 가지게 되어, 콘텐츠 길이가 불균등할 경우 텍스트가 잘리거나 보기 불편할 수 있습니다. 현재 조회용으로만 사용된다고 하셨지만, 향후 다양한 데이터 형식에 대응하기 어려울 수 있습니다.다음을 확인해주세요:
- 실제 사용 시나리오에서 모든 열의 콘텐츠 길이가 비슷한지
- 긴 텍스트가 있을 경우
whitespace-pre-wrap이나 말줄임 처리가 적절히 동작하는지필요하다면
table-auto로 변경하거나, Props에layout?: 'auto' | 'fixed'를 추가하여 상황에 맞게 선택할 수 있도록 하는 것을 고려해주세요.
19-19:no-scrollbar유틸리티 클래스 정의 확인 완료
src/index.css에서.no-scrollbar가 정의되어 있음을 확인했습니다.src/shared/ui/Table/TableHeader.tsx (1)
10-15: LGTM!테이블 헤더 영역을 깔끔하게 구분하는 간단하고 효과적인 구현입니다.
src/shared/ui/Table/TableRow.tsx (1)
10-15: LGTM!행 사이의 구분선을 적절하게 처리하고,
last:border-0으로 마지막 행의 불필요한 테두리를 제거한 깔끔한 구현입니다.src/shared/ui/Table/index.ts (1)
1-6: LGTM!모든 Table 컴포넌트가 올바르게 export되었으며, 논리적인 계층 구조 순서를 따르고 있습니다.
src/shared/ui/Table/TableBody.tsx (1)
10-15: LGTM!테이블 본문 영역을 감싸는 간단하고 명확한 구현입니다.
bg-white를 사용하여 헤더(bg-gray-50)와 시각적으로 구분되도록 했습니다.참고: 이전 리뷰 코멘트들은 데이터 렌더링 로직이 포함된 다른 버전에 대한 것으로, 현재의 단순한 래퍼 컴포넌트 구현과는 관련이 없습니다.
| export const Basic: StoryObj<typeof PrimitiveMeta> = { | ||
| render: () => ( | ||
| <Table> | ||
| <TableHeader> | ||
| <TableRow> | ||
| <TableHead>날짜</TableHead> | ||
| <TableHead>카테고리</TableHead> | ||
| <TableHead>점수</TableHead> | ||
| </TableRow> | ||
| </TableHeader> | ||
| <TableBody> | ||
| {data.map((row, i) => ( | ||
| <TableRow key={i}> | ||
| <TableCell>{row.createdAt}</TableCell> | ||
| <TableCell>{row.scoreCategory}</TableCell> | ||
| <TableCell>{row.amount.toFixed(3)}점</TableCell> | ||
| </TableRow> | ||
| ))} | ||
| </TableBody> | ||
| </Table> | ||
| ), | ||
| }; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🧹 Nitpick | 🔵 Trivial
스토리를 더 인터랙티브하게 만들 수 있습니다.
현재 Basic 스토리는 render 함수에 데이터가 하드코딩되어 있어 Storybook의 Controls 패널을 통해 수정할 수 없습니다. 데이터를 args로 받도록 하면 사용자가 다양한 데이터 조합을 테스트할 수 있습니다.
다음과 같이 개선할 수 있습니다:
+type StoryArgs = {
+ data: typeof data;
+};
+
-export const Basic: StoryObj<typeof PrimitiveMeta> = {
+export const Basic: StoryObj<StoryArgs> = {
+ args: {
+ data,
+ },
- render: () => (
+ render: ({ data }) => (
<Table>
<TableHeader>
<TableRow>📝 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.
| export const Basic: StoryObj<typeof PrimitiveMeta> = { | |
| render: () => ( | |
| <Table> | |
| <TableHeader> | |
| <TableRow> | |
| <TableHead>날짜</TableHead> | |
| <TableHead>카테고리</TableHead> | |
| <TableHead>점수</TableHead> | |
| </TableRow> | |
| </TableHeader> | |
| <TableBody> | |
| {data.map((row, i) => ( | |
| <TableRow key={i}> | |
| <TableCell>{row.createdAt}</TableCell> | |
| <TableCell>{row.scoreCategory}</TableCell> | |
| <TableCell>{row.amount.toFixed(3)}점</TableCell> | |
| </TableRow> | |
| ))} | |
| </TableBody> | |
| </Table> | |
| ), | |
| }; | |
| type StoryArgs = { | |
| data: typeof data; | |
| }; | |
| export const Basic: StoryObj<StoryArgs> = { | |
| args: { | |
| data, | |
| }, | |
| render: ({ data }) => ( | |
| <Table> | |
| <TableHeader> | |
| <TableRow> | |
| <TableHead>날짜</TableHead> | |
| <TableHead>카테고리</TableHead> | |
| <TableHead>점수</TableHead> | |
| </TableRow> | |
| </TableHeader> | |
| <TableBody> | |
| {data.map((row, i) => ( | |
| <TableRow key={i}> | |
| <TableCell>{row.createdAt}</TableCell> | |
| <TableCell>{row.scoreCategory}</TableCell> | |
| <TableCell>{row.amount.toFixed(3)}점</TableCell> | |
| </TableRow> | |
| ))} | |
| </TableBody> | |
| </Table> | |
| ), | |
| }; |
🤖 Prompt for AI Agents
In src/shared/ui/Table/Table.stories.tsx around lines 52-73, the Basic story
uses hardcoded data inside render which prevents Storybook Controls from
modifying it; refactor the story to accept args (e.g., render: (args) => ...)
and use args.data (with a sensible default via Basic.args) for the rows so users
can edit the dataset from Controls; update the StoryObj generic if needed to
reflect the arg type and add Basic.args = { data: [...] } providing the original
sample so backwards compatibility is preserved.
| </TableHeader> | ||
| <TableBody> | ||
| {data.map((row, i) => ( | ||
| <TableRow key={i}> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🧹 Nitpick | 🔵 Trivial
배열 인덱스를 key로 사용하고 있습니다.
정적 데모 데이터의 경우 허용되지만, 안정적인 고유 식별자를 key로 사용하는 것이 더 좋은 관행입니다. 예를 들어, createdAt과 scoreCategory를 조합하여 사용할 수 있습니다.
- {data.map((row, i) => (
- <TableRow key={i}>
+ {data.map((row) => (
+ <TableRow key={`${row.createdAt}-${row.scoreCategory}`}>🤖 Prompt for AI Agents
In src/shared/ui/Table/Table.stories.tsx around line 64, the story currently
uses the array index as the React key which can cause unstable identity; replace
the index with a stable unique key built from the row data (e.g., combine
createdAt and scoreCategory into a single string) and ensure it’s deterministic
(stringify or format timestamps) and falls back to a safe unique value if either
field is missing.
There was a problem hiding this 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
📜 Review details
Configuration used: Path: .coderabbit.yaml
Review profile: ASSERTIVE
Plan: Pro
📒 Files selected for processing (1)
src/shared/ui/Table/TableCell.tsx(1 hunks)
🧰 Additional context used
🧬 Code graph analysis (1)
src/shared/ui/Table/TableCell.tsx (7)
src/shared/ui/Table/Table.tsx (1)
Props(5-15)src/shared/ui/Table/TableBody.tsx (1)
Props(5-8)src/shared/ui/Table/TableHead.tsx (1)
Props(7-10)src/shared/ui/Table/TableHeader.tsx (1)
Props(5-8)src/shared/ui/Table/TableRow.tsx (1)
Props(5-8)src/shared/index.ts (3)
TableCell(25-25)cn(30-30)Body2(24-24)src/shared/ui/Table/index.ts (1)
TableCell(6-6)
🔇 Additional comments (1)
src/shared/ui/Table/TableCell.tsx (1)
1-10: Props 타입 정의와 import가 적절합니다.타입 정의가 다른 Table 컴포넌트들과 일관성 있게 구현되어 있고, 필요한 import만 포함하고 있습니다.
| export function TableCell({ className, children, ...props }: Props) { | ||
| return ( | ||
| <td className={cn('px-4 py-2 align-middle md:px-4', className)} {...props}> | ||
| <Body2 className="whitespace-pre-wrap text-gray-400" weight="normal"> | ||
| {children} | ||
| </Body2> | ||
| </td> | ||
| ); | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🧹 Nitpick | 🔵 Trivial
중복된 md:px-4 클래스를 제거하세요.
px-4는 모든 화면 크기에 이미 적용되므로, md:px-4는 중복됩니다. Tailwind의 mobile-first 접근 방식에서 기본 클래스는 모든 브레이크포인트에 적용되며, md: 접두사는 해당 브레이크포인트 이상에서 값을 재정의할 때만 의미가 있습니다.
참고: Body2에서 패딩을 제거하여 이전 리뷰의 중복 패딩 문제가 해결된 점은 좋습니다.
다음과 같이 수정하여 중복을 제거하세요:
- <td className={cn('px-4 py-2 align-middle md:px-4', className)} {...props}>
+ <td className={cn('px-4 py-2 align-middle', className)} {...props}>만약 모바일과 데스크톱에서 다른 패딩을 의도했다면, 다음과 같은 패턴을 사용하세요:
- <td className={cn('px-4 py-2 align-middle md:px-4', className)} {...props}>
+ <td className={cn('px-2 py-2 align-middle md:px-4', className)} {...props}>📝 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.
| export function TableCell({ className, children, ...props }: Props) { | |
| return ( | |
| <td className={cn('px-4 py-2 align-middle md:px-4', className)} {...props}> | |
| <Body2 className="whitespace-pre-wrap text-gray-400" weight="normal"> | |
| {children} | |
| </Body2> | |
| </td> | |
| ); | |
| } | |
| export function TableCell({ className, children, ...props }: Props) { | |
| return ( | |
| <td className={cn('px-4 py-2 align-middle', className)} {...props}> | |
| <Body2 className="whitespace-pre-wrap text-gray-400" weight="normal"> | |
| {children} | |
| </Body2> | |
| </td> | |
| ); | |
| } |
🤖 Prompt for AI Agents
In src/shared/ui/Table/TableCell.tsx around lines 12 to 20, remove the redundant
Tailwind class `md:px-4` from the td class list because `px-4` already applies
to all breakpoints; update the class string to only include `px-4 py-2
align-middle` (plus the incoming className) so you don't duplicate padding; if
you actually intended different padding on md and up, replace `md:px-4` with the
desired `md:px-{value}` instead of duplicating the same value.
🔥 연관 이슈
🚀 작업 내용
🤔 고민했던 내용
Table, TableBody, TableCell, TableHead, TableHeader, TableRow를 조합하여 사용할 수 있도록 하였습니다💬 리뷰 중점사항
Summary by CodeRabbit