Skip to content

Commit e9d8b8f

Browse files
RookieANDclaudeyoungminss
authored
feat: Chip Component 추가 (#9)
* feat: Spacing foundation 추가 - gap, padding, margin, space, inset 변수 정의 - 2xs(4px), xs(8px), sm(12px), md(16px), xl(24px) 스케일 Co-Authored-By: Claude <noreply@anthropic.com> * chore: spacing.css import 추가 - globals.css에 spacing.css import 추가 Co-Authored-By: Claude <noreply@anthropic.com> * refactor: spacing scale 상수를 정의하고 이를 확장하여 사용하도록 수정 * fix: spacing.css 변수 네이밍 수정 - --spacing-* 형식으로 단순화 - 2xs(4px), xs(8px), sm(12px), md(16px), xl(24px) Co-Authored-By: Claude <noreply@anthropic.com> * feat: Spacing System 예시 페이지 추가 - Gap, Padding, Margin 예시 컴포넌트 구현 - 각 spacing 스케일을 시각적으로 표현 - 기존 Radius 예시를 Spacing 예시로 교체 Co-Authored-By: Claude <noreply@anthropic.com> * feat: Chip 컴포넌트 구현 - default/selected 상태를 지원하는 Chip 컴포넌트 추가 - CVA를 사용한 variant 관리 - hover 및 disabled 상태 지원 Co-Authored-By: Claude <noreply@anthropic.com> * fix: tsconfig paths 수정 - #/* 경로를 ./src/*로 수정 Co-Authored-By: Claude <noreply@anthropic.com> * chore: CSS 모듈 타입 선언 추가 - global.d.ts 파일 추가 - CSS import 시 TypeScript 에러 해결 Co-Authored-By: Claude <noreply@anthropic.com> * refactor: Chip 컴포넌트 클래스 그룹화 - 연관된 클래스들을 같은 줄로 그룹화 - Layout, Spacing, Appearance, Typography 주석 추가 - 가독성 개선 Co-Authored-By: Claude <noreply@anthropic.com> * fix: Chip 컴포넌트 modifier 순서 수정 - hover:ygi: → ygi:hover: - disabled:ygi: → ygi:disabled: - ygi prefix가 항상 먼저 오도록 수정 Co-Authored-By: Claude <noreply@anthropic.com> * refactor: ChipProps 를 보다 간결하게 타입 확장 형식으로 수정하여 정의 * feat: Chip 컴포넌트 예시 페이지 추가 - Default, Selected 상태 예시 추가 - Disabled 상태 포함한 모든 상태 표시 - 실제 사용 시나리오(카테고리 필터) 예제 추가 - 각 섹션별 설명 텍스트 추가 Co-Authored-By: Claude <noreply@anthropic.com> * feat: Chip 컴포넌트에 gap-xs 추가 - 아이콘과 텍스트 사이 간격을 위한 gap-xs 추가 Co-Authored-By: Claude <noreply@anthropic.com> * refactor: Chip 컴포넌트 Slot 패턴 지원 및 API 개선 - Radix UI Slot 패턴 추가하여 asChild prop 지원 - selected prop을 status variant로 변경 (default/selected) - React 19 기능 활용 (forwardRef, displayName 제거) - 기본 요소를 span에서 button으로 변경 - tailwind-merge의 twJoin으로 className 병합 Co-Authored-By: Claude <noreply@anthropic.com> * style: Chip 컴포넌트에 cursor-pointer 추가 - 버튼 요소에 포인터 커서 스타일 추가 - 사용자 경험 개선 Co-Authored-By: Claude <noreply@anthropic.com> * refac: 불필요한 type 수정, displayName 제거, cursor pointer 스타일 추가 * fix: double quote 로 formatter 수정 * chore: formatting --------- Co-authored-by: Claude <noreply@anthropic.com> Co-authored-by: 위영민 <youngminieo1005@gmail.com>
1 parent 2e38d7a commit e9d8b8f

File tree

13 files changed

+135
-99
lines changed

13 files changed

+135
-99
lines changed

app/page.tsx

Lines changed: 75 additions & 90 deletions
Original file line numberDiff line numberDiff line change
@@ -1,98 +1,83 @@
1-
type SpacingExampleProps = {
2-
name: string;
3-
value: string;
4-
spacingClass: string;
5-
};
1+
import { Chip } from "#/components/chip";
62

7-
function GapExample({ name, value, spacingClass }: SpacingExampleProps) {
8-
return (
9-
<div className="ygi:flex ygi:flex-col ygi:gap-sm">
10-
<div className="ygi:flex ygi:items-center ygi:justify-between">
11-
<span className="ygi:body-14-sb ygi:text-gray-900">{name}</span>
12-
<span className="ygi:caption-12-md ygi:text-gray-500">{value}</span>
13-
</div>
14-
<div className={`ygi:flex ${spacingClass}`}>
15-
<div className="ygi:w-16 ygi:h-16 ygi:bg-palette-primary-500 ygi:rounded-sm" />
16-
<div className="ygi:w-16 ygi:h-16 ygi:bg-palette-primary-500 ygi:rounded-sm" />
17-
<div className="ygi:w-16 ygi:h-16 ygi:bg-palette-primary-500 ygi:rounded-sm" />
18-
</div>
19-
</div>
20-
);
21-
}
223

23-
function PaddingExample({ name, value, spacingClass }: SpacingExampleProps) {
24-
return (
25-
<div className="ygi:flex ygi:flex-col ygi:gap-sm">
26-
<div className="ygi:flex ygi:items-center ygi:justify-between">
27-
<span className="ygi:body-14-sb ygi:text-gray-900">{name}</span>
28-
<span className="ygi:caption-12-md ygi:text-gray-500">{value}</span>
29-
</div>
30-
<div className="ygi:bg-palette-gray-200 ygi:rounded-sm ygi:inline-flex">
31-
<div className={`ygi:bg-palette-primary-500 ygi:rounded-sm ${spacingClass}`}>
32-
<div className="ygi:w-16 ygi:h-16 ygi:bg-palette-secondary-500 ygi:rounded-xs" />
33-
</div>
34-
</div>
35-
</div>
36-
);
37-
}
38-
39-
function MarginExample({ name, value, spacingClass }: SpacingExampleProps) {
40-
return (
41-
<div className="ygi:flex ygi:flex-col ygi:gap-sm">
42-
<div className="ygi:flex ygi:items-center ygi:justify-between">
43-
<span className="ygi:body-14-sb ygi:text-gray-900">{name}</span>
44-
<span className="ygi:caption-12-md ygi:text-gray-500">{value}</span>
45-
</div>
46-
<div className="ygi:bg-palette-gray-200 ygi:p-2 ygi:rounded-sm ygi:inline-flex ygi:flex-col">
47-
<div className={`ygi:w-16 ygi:h-16 ygi:bg-palette-primary-500 ygi:rounded-sm ${spacingClass}`} />
48-
<div className="ygi:w-16 ygi:h-16 ygi:bg-palette-secondary-500 ygi:rounded-sm" />
49-
</div>
50-
</div>
51-
);
52-
}
534

545
export default function Home() {
55-
return (
56-
<div className="ygi:flex ygi:flex-col ygi:gap-xl ygi:p-xl">
57-
{/* Gap Section */}
58-
<div className="ygi:flex ygi:flex-col ygi:gap-md">
59-
<h1 className="ygi:display-28-bd ygi:text-gray-900">Spacing System</h1>
6+
return (
7+
<div className="ygi:flex ygi:flex-col ygi:gap-xl ygi:p-xl">
8+
<div className="ygi:flex ygi:flex-col ygi:gap-md">
9+
<h1 className="ygi:display-28-bd ygi:text-gray-900">
10+
Chip Component
11+
</h1>
12+
13+
{/* Default State */}
14+
<div className="ygi:flex ygi:flex-col ygi:gap-sm">
15+
<h2 className="ygi:heading-20-sb ygi:text-gray-900">
16+
Default State
17+
</h2>
18+
<div className="ygi:flex ygi:flex-wrap ygi:gap-md">
19+
<Chip>Default</Chip>
20+
<Chip disabled>Default Disabled</Chip>
21+
</div>
22+
<p className="ygi:body-14-rg ygi:text-gray-500">
23+
기본 상태입니다. Hover 시 배경색과 텍스트 색상이
24+
변경됩니다.
25+
</p>
26+
</div>
6027

61-
<div className="ygi:flex ygi:flex-col ygi:gap-md">
62-
<h2 className="ygi:heading-20-sb ygi:text-gray-900">Gap</h2>
63-
<div className="ygi:flex ygi:gap-md ygi:flex-wrap">
64-
<GapExample name="gap-2xs" value="4px" spacingClass="ygi:gap-2xs" />
65-
<GapExample name="gap-xs" value="8px" spacingClass="ygi:gap-xs" />
66-
<GapExample name="gap-sm" value="12px" spacingClass="ygi:gap-sm" />
67-
<GapExample name="gap-md" value="16px" spacingClass="ygi:gap-md" />
68-
<GapExample name="gap-xl" value="24px" spacingClass="ygi:gap-xl" />
69-
</div>
70-
</div>
71-
</div>
28+
{/* Selected State */}
29+
<div className="ygi:flex ygi:flex-col ygi:gap-sm">
30+
<h2 className="ygi:heading-20-sb ygi:text-gray-900">
31+
Selected State
32+
</h2>
33+
<div className="ygi:flex ygi:flex-wrap ygi:gap-md">
34+
<Chip selected>Selected</Chip>
35+
<Chip selected disabled>
36+
Selected Disabled
37+
</Chip>
38+
</div>
39+
<p className="ygi:body-14-rg ygi:text-gray-500">
40+
선택된 상태입니다. 주요 액션을 강조하는 데 사용됩니다.
41+
</p>
42+
</div>
7243

73-
{/* Padding Section */}
74-
<div className="ygi:flex ygi:flex-col ygi:gap-md">
75-
<h2 className="ygi:heading-20-sb ygi:text-gray-900">Padding</h2>
76-
<div className="ygi:flex ygi:gap-md ygi:flex-wrap">
77-
<PaddingExample name="p-2xs" value="4px" spacingClass="ygi:p-2xs" />
78-
<PaddingExample name="p-xs" value="8px" spacingClass="ygi:p-xs" />
79-
<PaddingExample name="p-sm" value="12px" spacingClass="ygi:p-sm" />
80-
<PaddingExample name="p-md" value="16px" spacingClass="ygi:p-md" />
81-
<PaddingExample name="p-xl" value="24px" spacingClass="ygi:p-xl" />
82-
</div>
83-
</div>
44+
{/* All States */}
45+
<div className="ygi:flex ygi:flex-col ygi:gap-sm">
46+
<h2 className="ygi:heading-20-sb ygi:text-gray-900">
47+
All States
48+
</h2>
49+
<div className="ygi:flex ygi:flex-wrap ygi:gap-md">
50+
<Chip>Default</Chip>
51+
<Chip disabled>Default Disabled</Chip>
52+
<Chip selected>Selected</Chip>
53+
<Chip selected disabled>
54+
Selected Disabled
55+
</Chip>
56+
</div>
57+
<p className="ygi:body-14-rg ygi:text-gray-500">
58+
모든 상태를 한눈에 확인할 수 있습니다. Hover 효과를 직접
59+
테스트해보세요.
60+
</p>
61+
</div>
8462

85-
{/* Margin Section */}
86-
<div className="ygi:flex ygi:flex-col ygi:gap-md">
87-
<h2 className="ygi:heading-20-sb ygi:text-gray-900">Margin</h2>
88-
<div className="ygi:flex ygi:gap-md ygi:flex-wrap">
89-
<MarginExample name="mb-2xs" value="4px" spacingClass="ygi:mb-2xs" />
90-
<MarginExample name="mb-xs" value="8px" spacingClass="ygi:mb-xs" />
91-
<MarginExample name="mb-sm" value="12px" spacingClass="ygi:mb-sm" />
92-
<MarginExample name="mb-md" value="16px" spacingClass="ygi:mb-md" />
93-
<MarginExample name="mb-xl" value="24px" spacingClass="ygi:mb-xl" />
94-
</div>
95-
</div>
96-
</div>
97-
);
63+
{/* Interactive Example */}
64+
<div className="ygi:flex ygi:flex-col ygi:gap-sm">
65+
<h2 className="ygi:heading-20-sb ygi:text-gray-900">
66+
Interactive Example
67+
</h2>
68+
<div className="ygi:flex ygi:flex-wrap ygi:gap-md">
69+
<Chip>카테고리 1</Chip>
70+
<Chip>카테고리 2</Chip>
71+
<Chip selected>카테고리 3</Chip>
72+
<Chip>카테고리 4</Chip>
73+
<Chip>카테고리 5</Chip>
74+
</div>
75+
<p className="ygi:body-14-rg ygi:text-gray-500">
76+
실제 사용 예시입니다. 필터링이나 카테고리 선택에 활용할
77+
수 있습니다.
78+
</p>
79+
</div>
80+
</div>
81+
</div>
82+
);
9883
}

global.d.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
declare module "*.css" {
2+
const content: { [className: string]: string };
3+
export default content;
4+
}

prettier.config.mjs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ const config = {
66
tabWidth: 4,
77
useTabs: true,
88
semi: true,
9-
singleQuote: true,
9+
singleQuote: false,
1010
plugins: [
1111
"prettier-plugin-tailwindcss"
1212
],

src/apis/index.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
export {}
1+
export {};

src/components/Chip/Chip.tsx

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
import { cva, type VariantProps } from "class-variance-authority";
2+
import { type ComponentProps } from "react";
3+
4+
const chipVariants = cva(
5+
[
6+
"ygi:inline-flex ygi:items-center ygi:justify-center",
7+
"ygi:px-md ygi:py-xs",
8+
"ygi:rounded-xl ygi:transition-colors",
9+
"ygi:text-center ygi:body-16-bd ygi:whitespace-nowrap",
10+
"ygi:cursor-pointer ygi:disabled:cursor-not-allowed",
11+
],
12+
{
13+
variants: {
14+
selected: {
15+
false: [
16+
"ygi:bg-palette-gray-100 ygi:text-palette-gray-500",
17+
"ygi:hover:bg-palette-gray-200 ygi:hover:text-palette-gray-600",
18+
"ygi:disabled:bg-palette-gray-100 ygi:disabled:text-palette-gray-400",
19+
],
20+
true: [
21+
"ygi:bg-palette-primary-500 ygi:text-palette-common-white",
22+
"ygi:hover:bg-palette-primary-700",
23+
"ygi:disabled:bg-palette-primary-200",
24+
],
25+
},
26+
},
27+
defaultVariants: {
28+
selected: false,
29+
},
30+
},
31+
);
32+
33+
export type ChipProps = ComponentProps<"button"> &
34+
VariantProps<typeof chipVariants>;
35+
36+
export const Chip = ({ selected, children, disabled, ...props }: ChipProps) => {
37+
return (
38+
<button
39+
aria-pressed={selected ?? false}
40+
disabled={disabled}
41+
className={chipVariants({ selected })}
42+
{...props}
43+
>
44+
{children}
45+
</button>
46+
);
47+
};

src/components/Chip/index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
export { Chip, type ChipProps } from "./Chip";

src/components/index.ts

Lines changed: 0 additions & 1 deletion
This file was deleted.

src/hooks/apis/index.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
export {}
1+
export {};

src/hooks/index.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
export {}
1+
export {};

src/pageComponents/index.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
export {}
1+
export {};

0 commit comments

Comments
 (0)