@x-plat/design-system 0.5.0 → 0.5.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,57 @@
1
+ # @x-plat/design-system Guidelines
2
+
3
+ React 기반 디자인 시스템 라이브러리이다. Figma Make Kit과 1:1 대응한다.
4
+
5
+ ---
6
+
7
+ ## 핵심 규칙
8
+
9
+ 1. **컴포넌트에 `color`, `className`, `style` prop이 없다.** 색상과 스타일은 내부 semantic 토큰으로 고정한다.
10
+ 2. **레이아웃 조절은 래퍼 `<div>`로 감싸서 래퍼에만 스타일을 적용한다.**
11
+ 3. **CSS로 DS 컴포넌트 스타일을 오버라이드하지 않는다.**
12
+
13
+ ```tsx
14
+ // 올바른 방법
15
+ <div className="button-wrapper">
16
+ <Button type="primary">저장</Button>
17
+ </div>
18
+
19
+ // 금지
20
+ <Button style={{ marginBottom: "1rem" }}>저장</Button>
21
+ ```
22
+
23
+ ---
24
+
25
+ ## 읽기 순서
26
+
27
+ 아래 순서로 읽는다.
28
+
29
+ 1. **[설치 및 설정](./setup.md)** - CSS/컴포넌트 import, ToastProvider 설정
30
+ 2. **파운데이션**
31
+ - [컬러](./foundations/color.md) - 4레이어 semantic 토큰
32
+ - [스페이싱](./foundations/spacing.md) - space, radius, stroke
33
+ - [타이포그래피](./foundations/typography.md) - font, size, weight
34
+ - [아이콘](./foundations/icons.md) - import, 크기/색상, 카테고리
35
+ 3. **컴포넌트**
36
+ - [Button](./components/button.md)
37
+ - [Input](./components/input.md) - Input, PasswordInput, TextArea
38
+ - [Select](./components/select.md)
39
+ - [Table](./components/table.md)
40
+ - [피드백](./components/feedback.md) - Alert, Toast, Badge
41
+ - [오버레이](./components/overlay.md) - Modal, Drawer, PopOver, Tooltip
42
+ - [폼 컨트롤](./components/form.md) - CheckBox, Radio, Switch
43
+ - [Chip & Tag](./components/chip-tag.md)
44
+ - [내비게이션](./components/navigation.md) - Tab, CardTab, Breadcrumb, Pagination, Steps
45
+ - [DatePicker](./components/datepicker.md) - Calendar, DatePicker 4종
46
+ - [Accordion](./components/accordion.md)
47
+ - [Avatar](./components/avatar.md)
48
+ - [Card](./components/card.md)
49
+ - [Chart](./components/chart.md)
50
+ - [데이터 표시](./components/data-display.md) - Divider, EmptyState, Skeleton, Spinner
51
+ - [Dropdown](./components/dropdown.md)
52
+ - [파일 & 미디어](./components/file-media.md) - FileUpload, ImageSelector, Video
53
+ - [Swiper](./components/swiper.md)
54
+ - [HtmlTypeWriter](./components/html-typewriter.md)
55
+ 4. **컴포지션**
56
+ - [Grid](./composition/grid.md) - Grid 시스템, 위젯 패턴
57
+ - [Layout](./composition/layout.md) - Layout, Header, SideBar
@@ -0,0 +1,72 @@
1
+ # Accordion
2
+
3
+ 접이식 패널을 표시한다. 단일/다중 모드를 지원하며, controlled/uncontrolled 모두 가능하다.
4
+
5
+ ```tsx
6
+ import { Accordion } from "@xplat/design-system";
7
+ ```
8
+
9
+ ## Props
10
+
11
+ ### 공통
12
+
13
+ | Prop | 타입 | 기본값 | 설명 |
14
+ |------|------|--------|------|
15
+ | items `*` | `AccordionItemData[]` | — | 아코디언 아이템 배열 |
16
+ | multiple | `boolean` | `false` | 다중 열기 허용 |
17
+
18
+ ### AccordionItemData
19
+
20
+ | 필드 | 타입 | 설명 |
21
+ |------|------|------|
22
+ | key `*` | `string` | 고유 식별자 |
23
+ | title `*` | `ReactNode` | 헤더 영역 |
24
+ | content `*` | `ReactNode` | 본문 영역 |
25
+
26
+ ### 단일 모드 (multiple 미지정 또는 false)
27
+
28
+ | Prop | 타입 | 설명 |
29
+ |------|------|------|
30
+ | activeKey | `string \| null` | 열린 아이템 key (controlled) |
31
+ | defaultActiveKey | `string` | 초기 열린 아이템 key (uncontrolled) |
32
+ | onChange | `(key: string \| null) => void` | 변경 콜백 |
33
+
34
+ ### 다중 모드 (multiple={true})
35
+
36
+ | Prop | 타입 | 설명 |
37
+ |------|------|------|
38
+ | activeKeys | `string[]` | 열린 아이템 key 목록 (controlled) |
39
+ | defaultActiveKeys | `string[]` | 초기 열린 아이템 key 목록 (uncontrolled) |
40
+ | onChange | `(keys: string[]) => void` | 변경 콜백 |
41
+
42
+ ---
43
+
44
+ ## 사용 예시
45
+
46
+ ### 단일 모드 (uncontrolled)
47
+
48
+ ```tsx
49
+ <Accordion
50
+ defaultActiveKey="faq-1"
51
+ items={[
52
+ { key: "faq-1", title: "질문 1", content: "답변 1" },
53
+ { key: "faq-2", title: "질문 2", content: "답변 2" },
54
+ ]}
55
+ />
56
+ ```
57
+
58
+ ### 다중 모드 (controlled)
59
+
60
+ ```tsx
61
+ const [openKeys, setOpenKeys] = useState<string[]>([]);
62
+
63
+ <Accordion
64
+ multiple
65
+ activeKeys={openKeys}
66
+ onChange={setOpenKeys}
67
+ items={[
68
+ { key: "a", title: "섹션 A", content: <div>내용 A</div> },
69
+ { key: "b", title: "섹션 B", content: <div>내용 B</div> },
70
+ ]}
71
+ />
72
+ ```
@@ -0,0 +1,35 @@
1
+ # Avatar
2
+
3
+ 프로필 이미지 또는 이니셜을 표시한다. `src`가 있으면 이미지를 렌더하고, 없으면 `name` 기반 이니셜을 표시한다. 둘 다 없으면 기본 사람 아이콘을 표시한다.
4
+
5
+ ```tsx
6
+ import { Avatar } from "@xplat/design-system";
7
+ ```
8
+
9
+ ## Props
10
+
11
+ | Prop | 타입 | 기본값 | 설명 |
12
+ |------|------|--------|------|
13
+ | src | `string` | — | 이미지 URL |
14
+ | alt | `string` | name 또는 `"avatar"` | 이미지 alt 텍스트 |
15
+ | name | `string` | — | 이니셜 생성용 이름 (예: `"홍 길동"` → `"홍길"`) |
16
+ | size | `"sm" \| "md" \| "lg"` | `"md"` | 크기 |
17
+
18
+ ## 색상 자동 배정
19
+
20
+ `name`의 첫 글자 charCode 기반으로 8가지 categorical color 중 하나를 자동 배정한다. 같은 이름은 항상 같은 색상이 된다.
21
+
22
+ ---
23
+
24
+ ## 사용 예시
25
+
26
+ ```tsx
27
+ // 이미지
28
+ <Avatar src="/profile.jpg" name="김철수" size="lg" />
29
+
30
+ // 이니셜 (이미지 없음)
31
+ <Avatar name="홍 길동" size="md" />
32
+
33
+ // 기본 아이콘 (이름도 없음)
34
+ <Avatar size="sm" />
35
+ ```
@@ -0,0 +1,58 @@
1
+ # Button
2
+
3
+ ## Type
4
+
5
+ | type | 용도 |
6
+ |------|------|
7
+ | primary | 주요 액션 |
8
+ | secondary | 보조 액션 |
9
+ | danger | 삭제/위험 액션 |
10
+ | ghost | 텍스트만 표시 |
11
+
12
+ ## Size
13
+
14
+ | size | 높이 |
15
+ |------|------|
16
+ | sm | 32px |
17
+ | md | 40px |
18
+ | lg | 48px |
19
+
20
+ ## 상태
21
+
22
+ | 상태 | 설명 |
23
+ |------|------|
24
+ | default | 기본 |
25
+ | hover | 마우스 오버 |
26
+ | pressed (`:active`) | 클릭 중 |
27
+ | focused (`:focus-visible`) | 키보드 포커스 |
28
+ | disabled | 비활성화 |
29
+
30
+ ---
31
+
32
+ ## 올바른 예시
33
+
34
+ ```tsx
35
+ <Button type="primary" size="md">확인</Button>
36
+ <Button type="secondary" size="lg">취소</Button>
37
+ <Button type="danger">삭제</Button>
38
+ <Button type="primary" disabled>비활성</Button>
39
+ ```
40
+
41
+ ## 잘못된 예시
42
+
43
+ ```tsx
44
+ // 금지: style prop 사용
45
+ <Button style={{ backgroundColor: "red" }}>삭제</Button>
46
+
47
+ // 금지: className 사용
48
+ <Button className="custom-btn">확인</Button>
49
+ ```
50
+
51
+ ---
52
+
53
+ ## 유사 컴포넌트 구분
54
+
55
+ | 목적 | 사용할 것 |
56
+ |------|----------|
57
+ | 페이지/외부 링크 이동 | `<a>` 또는 라우터 Link |
58
+ | 액션 실행 | Button |
@@ -0,0 +1,28 @@
1
+ # Card
2
+
3
+ 콘텐츠를 카드 형태로 감싸는 컨테이너이다.
4
+
5
+ ```tsx
6
+ import { Card } from "@xplat/design-system";
7
+ ```
8
+
9
+ ## Props
10
+
11
+ | Prop | 타입 | 기본값 | 설명 |
12
+ |------|------|--------|------|
13
+ | children `*` | `ReactNode` | — | 카드 본문 |
14
+ | title | `string` | — | 카드 상단 제목 |
15
+
16
+ ---
17
+
18
+ ## 사용 예시
19
+
20
+ ```tsx
21
+ <Card title="매출 현황">
22
+ <p>이번 달 매출: 1,200만원</p>
23
+ </Card>
24
+
25
+ <Card>
26
+ <p>제목 없는 카드</p>
27
+ </Card>
28
+ ```
@@ -0,0 +1,58 @@
1
+ # Chart
2
+
3
+ SVG 기반 차트를 렌더한다. line, bar, pie, doughnut 4가지 타입을 지원한다.
4
+
5
+ ```tsx
6
+ import { Chart } from "@xplat/design-system";
7
+ ```
8
+
9
+ ## Props
10
+
11
+ | Prop | 타입 | 기본값 | 설명 |
12
+ |------|------|--------|------|
13
+ | type `*` | `"line" \| "bar" \| "pie" \| "doughnut"` | — | 차트 타입 |
14
+ | data `*` | `Record<string, number[]>` | — | 데이터셋 (key: 시리즈 이름, value: 값 배열) |
15
+ | labels `*` | `string[]` | — | x축 라벨 배열 |
16
+ | tooltip | `boolean` | `true` | 호버 시 툴팁 표시 |
17
+
18
+ ## 색상
19
+
20
+ primitive 팔레트 기반으로 시리즈별 색상을 자동 배정한다. line/bar는 `LINE_BAR_PALETTES`, pie/doughnut는 `PIE_PALETTES`를 사용한다.
21
+
22
+ ---
23
+
24
+ ## 사용 예시
25
+
26
+ ### Line
27
+
28
+ ```tsx
29
+ <Chart
30
+ type="line"
31
+ labels={["1월", "2월", "3월", "4월"]}
32
+ data={{
33
+ 매출: [100, 200, 150, 300],
34
+ 비용: [80, 120, 100, 200],
35
+ }}
36
+ />
37
+ ```
38
+
39
+ ### Bar
40
+
41
+ ```tsx
42
+ <Chart
43
+ type="bar"
44
+ labels={["서울", "부산", "대구"]}
45
+ data={{ 방문자: [500, 300, 200] }}
46
+ />
47
+ ```
48
+
49
+ ### Pie / Doughnut
50
+
51
+ ```tsx
52
+ <Chart
53
+ type="doughnut"
54
+ labels={["모바일", "데스크톱", "태블릿"]}
55
+ data={{ 점유율: [60, 30, 10] }}
56
+ tooltip={false}
57
+ />
58
+ ```
@@ -0,0 +1,49 @@
1
+ # Chip & Tag
2
+
3
+ ## Chip
4
+
5
+ 읽기 전용 라벨이다. 삭제 기능이 없다.
6
+
7
+ ```tsx
8
+ <Chip type="primary">진행중</Chip>
9
+ <Chip type="success">완료</Chip>
10
+ <Chip type="error">실패</Chip>
11
+ ```
12
+
13
+ | type | 용도 |
14
+ |------|------|
15
+ | primary | 기본 강조 |
16
+ | secondary | 보조 |
17
+ | neutral | 중립 |
18
+ | success | 성공 |
19
+ | error | 에러 |
20
+ | warning | 경고 |
21
+ | info | 정보 |
22
+
23
+ ---
24
+
25
+ ## Tag
26
+
27
+ 제거 가능한 태그이다. `onClose`로 삭제를 처리한다.
28
+
29
+ ```tsx
30
+ <Tag onClose={() => handleRemove("react")}>React</Tag>
31
+ <Tag type="categorical" colorIndex={1} onClose={handleRemove}>TypeScript</Tag>
32
+ <Tag disabled>삭제 불가</Tag>
33
+ ```
34
+
35
+ | Prop | 설명 |
36
+ |------|------|
37
+ | type | `"neutral" \| "categorical"` |
38
+ | onClose | 삭제 콜백 |
39
+ | colorIndex | categorical 타입의 색상 인덱스 |
40
+ | disabled | 비활성화 |
41
+
42
+ ---
43
+
44
+ ## 의사결정
45
+
46
+ | 상황 | 사용할 것 |
47
+ |------|----------|
48
+ | 상태/분류 라벨 (삭제 불필요) | Chip |
49
+ | 사용자가 제거할 수 있는 태그 | Tag |
@@ -0,0 +1,96 @@
1
+ # 데이터 표시: Divider / EmptyState / Skeleton / Spinner
2
+
3
+ ## Divider
4
+
5
+ 구분선을 표시한다.
6
+
7
+ ```tsx
8
+ import { Divider } from "@xplat/design-system";
9
+ ```
10
+
11
+ | Prop | 타입 | 기본값 | 설명 |
12
+ |------|------|--------|------|
13
+ | orientation | `"horizontal" \| "vertical"` | `"horizontal"` | 방향 |
14
+
15
+ ```tsx
16
+ <Divider />
17
+ <Divider orientation="vertical" />
18
+ ```
19
+
20
+ ---
21
+
22
+ ## EmptyState
23
+
24
+ 빈 상태 안내를 표시한다.
25
+
26
+ ```tsx
27
+ import { EmptyState } from "@xplat/design-system";
28
+ ```
29
+
30
+ | Prop | 타입 | 기본값 | 설명 |
31
+ |------|------|--------|------|
32
+ | icon | `ReactNode` | 기본 폴더 아이콘 | 상단 아이콘 |
33
+ | title | `string` | `"데이터가 없습니다"` | 제목 |
34
+ | description | `string` | — | 부가 설명 |
35
+ | action | `ReactNode` | — | 하단 액션 영역 (버튼 등) |
36
+
37
+ ```tsx
38
+ <EmptyState
39
+ title="검색 결과가 없습니다"
40
+ description="다른 키워드로 검색해 보세요."
41
+ action={<Button type="primary">전체 목록</Button>}
42
+ />
43
+ ```
44
+
45
+ ---
46
+
47
+ ## Skeleton
48
+
49
+ 로딩 플레이스홀더를 표시한다.
50
+
51
+ ```tsx
52
+ import { Skeleton } from "@xplat/design-system";
53
+ ```
54
+
55
+ | Prop | 타입 | 기본값 | 설명 |
56
+ |------|------|--------|------|
57
+ | variant | `"text" \| "circular" \| "rectangular"` | `"text"` | 형태 |
58
+ | width | `string \| number` | — | 너비 |
59
+ | height | `string \| number` | — | 높이 |
60
+
61
+ ```tsx
62
+ <Skeleton variant="text" width="200px" />
63
+ <Skeleton variant="circular" width={48} height={48} />
64
+ <Skeleton variant="rectangular" width="100%" height={120} />
65
+ ```
66
+
67
+ ---
68
+
69
+ ## Spinner
70
+
71
+ 로딩 인디케이터를 표시한다.
72
+
73
+ ```tsx
74
+ import { Spinner } from "@xplat/design-system";
75
+ ```
76
+
77
+ | Prop | 타입 | 기본값 | 설명 |
78
+ |------|------|--------|------|
79
+ | size | `"sm" \| "md" \| "lg"` | `"md"` | 크기 |
80
+ | type | `"brand" \| "success" \| "error" \| "warning" \| "info"` | `"brand"` | 색상 타입 |
81
+
82
+ ```tsx
83
+ <Spinner />
84
+ <Spinner size="lg" type="success" />
85
+ ```
86
+
87
+ ---
88
+
89
+ ## 의사결정
90
+
91
+ | 상황 | 사용할 것 |
92
+ |------|----------|
93
+ | 영역 구분선 | Divider |
94
+ | 데이터가 없는 상태 안내 | EmptyState |
95
+ | 콘텐츠 로딩 전 자리 차지 | Skeleton |
96
+ | 로딩 중 표시 (인디케이터) | Spinner |
@@ -0,0 +1,60 @@
1
+ # DatePicker: Calendar / DatePicker 4종
2
+
3
+ ## Calendar
4
+
5
+ 달력을 표시한다. 이벤트 표시와 `renderDay` 커스텀을 지원한다.
6
+
7
+ ```tsx
8
+ <Calendar
9
+ events={[{ date: "2026-03-15", type: "success" }]}
10
+ renderDay={(date) => <span>{date.getDate()}</span>}
11
+ />
12
+ ```
13
+
14
+ ---
15
+
16
+ ## SingleDatePicker
17
+
18
+ 단일 날짜를 선택한다.
19
+
20
+ ```tsx
21
+ <SingleDatePicker value={date} onChange={(d) => setDate(d)} />
22
+ ```
23
+
24
+ ## RangeDatePicker
25
+
26
+ 날짜 범위를 선택한다.
27
+
28
+ ```tsx
29
+ <RangeDatePicker startDate={start} endDate={end} onChange={handleRange} />
30
+ ```
31
+
32
+ ## InputDatePicker
33
+
34
+ Input + 드롭다운 형태이다.
35
+
36
+ ```tsx
37
+ <InputDatePicker value={date} onChange={(d) => setDate(d)} />
38
+ ```
39
+
40
+ ## PopupDatePicker
41
+
42
+ 버튼 + 모달 형태이다.
43
+
44
+ ```tsx
45
+ <PopupDatePicker
46
+ type="single"
47
+ component={<Button>날짜 선택</Button>}
48
+ value={date}
49
+ onChange={(d) => setDate(d)}
50
+ />
51
+ ```
52
+
53
+ ---
54
+
55
+ ## 의사결정
56
+
57
+ | 상황 | 사용할 것 |
58
+ |------|----------|
59
+ | 달력 표시 / 이벤트 | Calendar |
60
+ | 날짜 선택 | DatePicker (Single/Range/Input/Popup) |
@@ -0,0 +1,49 @@
1
+ # Dropdown
2
+
3
+ 액션 메뉴를 표시한다. `children`이 트리거 역할을 하며, 클릭 시 메뉴가 열린다.
4
+
5
+ ```tsx
6
+ import { Dropdown } from "@xplat/design-system";
7
+ ```
8
+
9
+ ## Props
10
+
11
+ | Prop | 타입 | 기본값 | 설명 |
12
+ |------|------|--------|------|
13
+ | items `*` | `DropdownItem[]` | — | 메뉴 아이템 배열 |
14
+ | children `*` | `ReactNode` | — | 트리거 요소 |
15
+
16
+ ### DropdownItem
17
+
18
+ | 필드 | 타입 | 설명 |
19
+ |------|------|------|
20
+ | key `*` | `string` | 고유 식별자 |
21
+ | label `*` | `ReactNode` | 표시 텍스트 |
22
+ | onClick | `() => void` | 클릭 콜백 |
23
+ | disabled | `boolean` | 비활성화 |
24
+ | danger | `boolean` | 위험 액션 스타일 (빨간색) |
25
+
26
+ ---
27
+
28
+ ## 사용 예시
29
+
30
+ ```tsx
31
+ <Dropdown
32
+ items={[
33
+ { key: "edit", label: "수정", onClick: () => handleEdit() },
34
+ { key: "copy", label: "복사", onClick: () => handleCopy() },
35
+ { key: "delete", label: "삭제", onClick: () => handleDelete(), danger: true },
36
+ ]}
37
+ >
38
+ <Button type="ghost">더보기</Button>
39
+ </Dropdown>
40
+ ```
41
+
42
+ ---
43
+
44
+ ## 유사 컴포넌트 구분
45
+
46
+ | 목적 | 사용할 것 |
47
+ |------|----------|
48
+ | 값 선택 (폼 필드) | Select |
49
+ | 액션 실행 (메뉴) | Dropdown |
@@ -0,0 +1,64 @@
1
+ # 피드백: Alert / Toast / Badge
2
+
3
+ ## Alert
4
+
5
+ 인라인 알림을 표시한다.
6
+
7
+ ```tsx
8
+ <Alert type="info">정보 메시지</Alert>
9
+ <Alert type="success">성공</Alert>
10
+ <Alert type="warning">경고</Alert>
11
+ <Alert type="error" onClose={() => {}}>에러 (닫기 가능)</Alert>
12
+ ```
13
+
14
+ | Prop | 설명 |
15
+ |------|------|
16
+ | type | `"info" \| "success" \| "warning" \| "error"` |
17
+ | onClose | 닫기 버튼 콜백 (전달 시 닫기 버튼 표시) |
18
+
19
+ ---
20
+
21
+ ## Toast
22
+
23
+ 일시적 알림을 표시한다. **ToastProvider가 앱 최상위에 필수이다.**
24
+
25
+ ```tsx
26
+ // 앱 루트
27
+ <ToastProvider position="top-right">
28
+ <App />
29
+ </ToastProvider>
30
+
31
+ // 컴포넌트 내
32
+ const { toast } = useToast();
33
+ toast("success", "저장 완료");
34
+ toast("error", "오류 발생", 5000);
35
+ ```
36
+
37
+ `toast(type, message, duration?)` 형태로 호출한다.
38
+
39
+ ---
40
+
41
+ ## Badge
42
+
43
+ 카운트 또는 도트를 표시한다.
44
+
45
+ ```tsx
46
+ <Badge type="error" count={5}><BellIcon /></Badge>
47
+ <Badge type="success" dot><UserIcon /></Badge>
48
+ ```
49
+
50
+ | Prop | 설명 |
51
+ |------|------|
52
+ | type | `"error" \| "success" \| "warning" \| "info" \| "brand"` |
53
+ | count | 숫자 표시 |
54
+ | dot | 도트만 표시 |
55
+
56
+ ---
57
+
58
+ ## 의사결정
59
+
60
+ | 상황 | 사용할 것 |
61
+ |------|----------|
62
+ | 인라인 알림 (페이지 내 고정) | Alert |
63
+ | 일시적 알림 (자동 사라짐) | Toast |
64
+ | 카운트/상태 표시 | Badge |