bo-ui-kit 0.1.0 → 0.2.0
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.
- package/README.md +54 -95
- package/dist/components/ui/accordion.d.ts +27 -0
- package/dist/components/ui/alert-dialog.d.ts +22 -0
- package/dist/components/ui/alert.d.ts +23 -0
- package/dist/components/ui/avatar-group.d.ts +16 -0
- package/dist/components/ui/avatar.d.ts +23 -0
- package/dist/components/ui/badge.d.ts +19 -0
- package/dist/components/ui/breadcrumb.d.ts +17 -0
- package/dist/components/ui/button.d.ts +5 -2
- package/dist/components/ui/collapsible.d.ts +16 -0
- package/dist/components/ui/dialog.d.ts +22 -0
- package/dist/components/ui/drawer.d.ts +16 -0
- package/dist/components/ui/index.d.ts +46 -0
- package/dist/components/ui/input.d.ts +1 -1
- package/dist/components/ui/number-field.d.ts +22 -0
- package/dist/components/ui/overlay.d.ts +36 -0
- package/dist/components/ui/radio-group.d.ts +19 -0
- package/dist/components/ui/scroll-area.d.ts +13 -0
- package/dist/components/ui/segmented-control.d.ts +29 -0
- package/dist/components/ui/separator.d.ts +15 -0
- package/dist/components/ui/sheet.d.ts +23 -0
- package/dist/components/ui/skeleton.d.ts +13 -0
- package/dist/components/ui/spinner.d.ts +15 -0
- package/dist/components/ui/switch.d.ts +22 -0
- package/dist/components/ui/tabs.d.ts +26 -0
- package/dist/components/ui/textarea.d.ts +17 -0
- package/dist/components/ui/toast.d.ts +19 -0
- package/dist/components/ui/tooltip.d.ts +14 -0
- package/dist/index.cjs +1 -1
- package/dist/index.js +1390 -278
- package/dist/styles.css +16 -5
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -1,32 +1,17 @@
|
|
|
1
1
|
# bo-ui-kit
|
|
2
2
|
|
|
3
|
-
Figma **"BO UI Kit"** 디자인
|
|
4
|
-
|
|
5
|
-
`React 18 · TypeScript · Tailwind v3 · cva` · 컴포넌트 10종 · npm 라이브러리(ESM+CJS) · 5종 CI 게이트
|
|
6
|
-
|
|
7
|
-
---
|
|
8
|
-
|
|
9
|
-
## 이 저장소가 하는 일 (3가지)
|
|
10
|
-
|
|
11
|
-
| | 무엇 | 핵심 |
|
|
12
|
-
|---|---|---|
|
|
13
|
-
| 1. **컴포넌트 라이브러리** | `bo-ui-kit` — 설치해서 쓰는 React UI | ESM+CJS, Tailwind 없이도 동작(프리빌드 CSS), 타입 포함 |
|
|
14
|
-
| 2. **자동 동기화 파이프라인** | Figma 변경 → 감지 → 추출 → PR | 헤드리스 Claude가 변경분만 추출, 사람은 머지만 |
|
|
15
|
-
| 3. **품질 게이트(CI)** | 시각 회귀 + 소비자 스모크 | 컴포넌트/배포물이 깨지면 PR에서 빨강 |
|
|
16
|
-
|
|
17
|
-
> 한 줄 요약: **디자이너가 Figma를 바꾸면 → 코드 PR이 알아서 생기고(증거 스크린샷 첨부) → 라이브러리로 배포 가능**.
|
|
18
|
-
|
|
19
|
-
---
|
|
20
|
-
|
|
21
|
-
## 빠른 시작 — 라이브러리로 쓰기
|
|
3
|
+
Figma **"BO UI Kit"** 디자인 시스템에서 추출한 **React UI 컴포넌트 라이브러리**.
|
|
4
|
+
Tailwind 설정 없이 바로 쓰는 프리빌드 CSS · ESM·CJS 듀얼 번들 · 타입 포함.
|
|
22
5
|
|
|
23
6
|
```bash
|
|
24
|
-
npm i bo-ui-kit # peer: react, react-dom >=18
|
|
7
|
+
npm i bo-ui-kit # peer: react, react-dom >= 18
|
|
25
8
|
```
|
|
26
9
|
|
|
10
|
+
## 사용법
|
|
11
|
+
|
|
27
12
|
```tsx
|
|
28
|
-
import { Button,
|
|
29
|
-
import "bo-ui-kit/styles.css"; //
|
|
13
|
+
import { Button, Field, Input } from "bo-ui-kit";
|
|
14
|
+
import "bo-ui-kit/styles.css"; // 디자인 토큰 + 컴포넌트 스타일 (앱 진입점에서 1회)
|
|
30
15
|
|
|
31
16
|
export default function App() {
|
|
32
17
|
return (
|
|
@@ -37,88 +22,62 @@ export default function App() {
|
|
|
37
22
|
}
|
|
38
23
|
```
|
|
39
24
|
|
|
40
|
-
|
|
41
|
-
- **Tailwind 불필요** — `styles.css` 한 줄이면 토큰·유틸 전부 포함
|
|
42
|
-
- **다크 모드** — 상위 요소에 `class="dark"`
|
|
43
|
-
- **테마 변경** — `styles.css`의 CSS 변수(`--primary` 등)를 덮어쓰기
|
|
44
|
-
- **폰트** — Pretendard 우선, 없으면 시스템 산세리프 폴백
|
|
25
|
+
> `styles.css`는 앱에서 **한 번만** import 하면 됩니다. **Tailwind를 설치하거나 설정할 필요가 없습니다.**
|
|
45
26
|
|
|
46
|
-
|
|
27
|
+
## 특징
|
|
47
28
|
|
|
48
|
-
|
|
29
|
+
- **Tailwind 불필요** — `bo-ui-kit/styles.css` 한 줄에 디자인 토큰 + 컴포넌트 스타일이 모두 들어 있습니다. 전역 리셋(preflight)이 없어 기존 앱 스타일을 건드리지 않습니다.
|
|
30
|
+
- **ESM · CommonJS** — `import` / `require` 모두 지원.
|
|
31
|
+
- **TypeScript** — 타입 선언(`.d.ts`) 포함.
|
|
32
|
+
- **다크 모드** — 상위 요소에 `class="dark"`.
|
|
33
|
+
- **테마 변경** — `styles.css`의 CSS 변수(`--primary`, `--radius` 등)를 앱에서 덮어쓰면 색·반경 등이 바뀝니다.
|
|
34
|
+
- **폰트** — Pretendard 우선, 없으면 시스템 산세리프로 폴백.
|
|
49
35
|
|
|
50
|
-
|
|
51
|
-
|---|---|---|
|
|
52
|
-
| Button | `Button` | 1692:74 |
|
|
53
|
-
| Checkbox | `Checkbox` | 5667:129 |
|
|
54
|
-
| Input | `Input` | 7745:699 |
|
|
55
|
-
| Label | `Label` | 7658:2157 |
|
|
56
|
-
| Field | `Field` | 7745:713 |
|
|
57
|
-
| Input OTP | `InputOTP` `InputOTPSlot` `InputOTPSeparator` | 8060:1580 |
|
|
58
|
-
| Meter | `Meter` | 7664:31 |
|
|
59
|
-
| Toggle | `Toggle` | 5685:204 |
|
|
60
|
-
| Toggle Group | `ToggleGroup` `ToggleGroupItem` | 5686:270 |
|
|
61
|
-
| Select | `Select` | 7751:1561 |
|
|
36
|
+
## 컴포넌트
|
|
62
37
|
|
|
63
|
-
|
|
64
|
-
|
|
38
|
+
| 컴포넌트 | export |
|
|
39
|
+
|---|---|
|
|
40
|
+
| Button | `Button` |
|
|
41
|
+
| Checkbox | `Checkbox` |
|
|
42
|
+
| Input | `Input` |
|
|
43
|
+
| Label | `Label` |
|
|
44
|
+
| Field | `Field` |
|
|
45
|
+
| Input OTP | `InputOTP`, `InputOTPSlot`, `InputOTPSeparator` |
|
|
46
|
+
| Meter | `Meter` |
|
|
47
|
+
| Toggle | `Toggle` |
|
|
48
|
+
| Toggle Group | `ToggleGroup`, `ToggleGroupItem` |
|
|
49
|
+
| Select | `Select` |
|
|
65
50
|
|
|
66
|
-
|
|
51
|
+
모든 컴포넌트는 `className`으로 스타일 합성이 가능하고 `forwardRef`로 ref를 전달받습니다.
|
|
67
52
|
|
|
68
|
-
|
|
53
|
+
### 예시
|
|
69
54
|
|
|
55
|
+
```tsx
|
|
56
|
+
import { Toggle, ToggleGroup, ToggleGroupItem, Select } from "bo-ui-kit";
|
|
57
|
+
|
|
58
|
+
// 제어형 Toggle (2-state 버튼)
|
|
59
|
+
<Toggle pressed={on} onPressedChange={setOn}>굵게</Toggle>
|
|
60
|
+
|
|
61
|
+
// Select (드롭다운)
|
|
62
|
+
<Select
|
|
63
|
+
options={[{ value: "apple", label: "Apple" }, { value: "banana", label: "Banana" }]}
|
|
64
|
+
value={fruit}
|
|
65
|
+
onValueChange={setFruit}
|
|
66
|
+
placeholder="과일 선택…"
|
|
67
|
+
/>
|
|
68
|
+
|
|
69
|
+
// Toggle Group (세그먼티드, 단일 선택)
|
|
70
|
+
<ToggleGroup type="single" value={align} onValueChange={setAlign}>
|
|
71
|
+
<ToggleGroupItem value="left">왼쪽</ToggleGroupItem>
|
|
72
|
+
<ToggleGroupItem value="center">가운데</ToggleGroupItem>
|
|
73
|
+
<ToggleGroupItem value="right">오른쪽</ToggleGroupItem>
|
|
74
|
+
</ToggleGroup>
|
|
70
75
|
```
|
|
71
|
-
Figma (BO UI Kit)
|
|
72
|
-
│ 디자인 변경
|
|
73
|
-
▼
|
|
74
|
-
① 감지 figma-poll.yml (cron) — 파일 버전 + 추적 노드 지문 비교
|
|
75
|
-
│ 실제 컴포넌트가 바뀐 경우에만
|
|
76
|
-
▼
|
|
77
|
-
② 추출 figma-sync.yml — 헤드리스 Claude가 변경분만 추출 → 검증(tsc+build) → PR
|
|
78
|
-
│ (PR에 "Closes #이슈" 연결)
|
|
79
|
-
▼
|
|
80
|
-
③ 검증 visual.yml — 시각 회귀 + Figma/Before/After/Diff 증거 코멘트
|
|
81
|
-
│ smoke.yml — 소비자 설치·렌더 + tarball 검증
|
|
82
|
-
▼
|
|
83
|
-
④ 사람 PR 증거 보고 머지 → 이슈 자동 종료 → baseline 자동 갱신
|
|
84
|
-
```
|
|
85
|
-
|
|
86
|
-
- **autosave는 무시**: 버전만 올라가고 추적 노드(컴포넌트)가 안 바뀌면 헤드리스를 돌리지 않음(`figma.fingerprints.json` 지문 비교).
|
|
87
|
-
- **PR 시각 증거**: 변경된 컴포넌트의 Figma 원본 + 렌더 Before/After/Diff를 PR 코멘트로 자동 첨부.
|
|
88
|
-
- **토큰 점검**: `token-health.yml`이 `FIGMA_TOKEN` 만료를 매일 점검(만료 시 Issue).
|
|
89
|
-
|
|
90
|
-
> 파이프라인 구성·운영·시크릿·함정 상세는 **[docs/CONFLUENCE.md](docs/CONFLUENCE.md)**.
|
|
91
76
|
|
|
92
|
-
|
|
77
|
+
## 요구사항
|
|
93
78
|
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
| 명령 | 설명 |
|
|
97
|
-
|---|---|
|
|
98
|
-
| `npm run dev` | 플레이그라운드(컴포넌트 카탈로그) |
|
|
99
|
-
| `npm run verify` | 타입체크 + 빌드 |
|
|
100
|
-
| `npm run build:lib` | 라이브러리 빌드 → `dist/`(ESM+CJS+타입+styles.css) |
|
|
101
|
-
| `npm run test:visual` | 시각 회귀(로컬은 비교 생략, CI=Linux 기준) |
|
|
102
|
-
| `npm run check:figma` | Figma 변경 감지(exit 10=변경) |
|
|
103
|
-
| `npm run pack:test` | tarball 만들어 `examples/pack-consumer`에 설치(배포물 검증) |
|
|
79
|
+
- **React 18+** — `react`, `react-dom`은 peer dependency.
|
|
104
80
|
|
|
105
|
-
|
|
81
|
+
## 라이선스
|
|
106
82
|
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
## 프로젝트 구조
|
|
110
|
-
|
|
111
|
-
```
|
|
112
|
-
src/
|
|
113
|
-
components/ui/ 컴포넌트 (배럴: index.ts)
|
|
114
|
-
stories/ 플레이그라운드 스토리
|
|
115
|
-
tokens.css 디자인 토큰(단일 소스 — 앱·라이브러리 공유)
|
|
116
|
-
index.css 앱 진입 CSS (tokens 임포트)
|
|
117
|
-
lib/styles.css 라이브러리 CSS 입력(프리빌드용)
|
|
118
|
-
scripts/ 감지/빌드/검증 스크립트
|
|
119
|
-
.github/workflows/ figma-poll · figma-sync · visual · smoke · token-health
|
|
120
|
-
examples/ consumer(링크) · pack-consumer(tarball)
|
|
121
|
-
figma.manifest.json / figma.fingerprints.json 추출 대상 + 노드 지문
|
|
122
|
-
CLAUDE.md 컴포넌트 작성 규칙(★ Variant 매핑)
|
|
123
|
-
docs/CONFLUENCE.md 파이프라인/운영 레퍼런스
|
|
124
|
-
```
|
|
83
|
+
MIT © eromnet
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import * as React from "react";
|
|
2
|
+
type AccordionBase = {
|
|
3
|
+
className?: string;
|
|
4
|
+
children?: React.ReactNode;
|
|
5
|
+
};
|
|
6
|
+
export type AccordionProps = AccordionBase & ({
|
|
7
|
+
type?: "single";
|
|
8
|
+
value?: string;
|
|
9
|
+
defaultValue?: string;
|
|
10
|
+
onValueChange?: (v: string) => void;
|
|
11
|
+
} | {
|
|
12
|
+
type: "multiple";
|
|
13
|
+
value?: string[];
|
|
14
|
+
defaultValue?: string[];
|
|
15
|
+
onValueChange?: (v: string[]) => void;
|
|
16
|
+
});
|
|
17
|
+
declare const Accordion: React.ForwardRefExoticComponent<AccordionProps & React.RefAttributes<HTMLDivElement>>;
|
|
18
|
+
export interface AccordionItemProps extends Omit<React.HTMLAttributes<HTMLDivElement>, "title"> {
|
|
19
|
+
value: string;
|
|
20
|
+
title: React.ReactNode;
|
|
21
|
+
/** 제목 앞 아이콘(선택) */
|
|
22
|
+
icon?: React.ReactNode;
|
|
23
|
+
/** 하단 구분선 표시(기본 true) */
|
|
24
|
+
showSeparator?: boolean;
|
|
25
|
+
}
|
|
26
|
+
declare const AccordionItem: React.ForwardRefExoticComponent<AccordionItemProps & React.RefAttributes<HTMLDivElement>>;
|
|
27
|
+
export { Accordion, AccordionItem };
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import * as React from "react";
|
|
2
|
+
/**
|
|
3
|
+
* AlertDialog — Figma "BO UI Kit" AlertDialog(node 5655:5142). 확인이 필요한 모달.
|
|
4
|
+
*
|
|
5
|
+
* Dialog 프리미티브 재사용 + role=alertdialog + 바깥클릭/X 비활성(명시적 선택 필요).
|
|
6
|
+
* 취소/실행 버튼. `destructive` 시 실행 버튼이 빨간(destructive) Button. 제어/비제어(open).
|
|
7
|
+
*/
|
|
8
|
+
export interface AlertDialogProps {
|
|
9
|
+
open?: boolean;
|
|
10
|
+
defaultOpen?: boolean;
|
|
11
|
+
onOpenChange?: (open: boolean) => void;
|
|
12
|
+
title: React.ReactNode;
|
|
13
|
+
description?: React.ReactNode;
|
|
14
|
+
cancelText?: React.ReactNode;
|
|
15
|
+
actionText?: React.ReactNode;
|
|
16
|
+
onAction?: () => void;
|
|
17
|
+
onCancel?: () => void;
|
|
18
|
+
destructive?: boolean;
|
|
19
|
+
children?: React.ReactNode;
|
|
20
|
+
}
|
|
21
|
+
declare function AlertDialog({ open, defaultOpen, onOpenChange, title, description, cancelText, actionText, onAction, onCancel, destructive, children, }: AlertDialogProps): React.JSX.Element;
|
|
22
|
+
export { AlertDialog };
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import * as React from "react";
|
|
2
|
+
import { type VariantProps } from "class-variance-authority";
|
|
3
|
+
/**
|
|
4
|
+
* Alert — Figma "BO UI Kit" Alert(node 5655:4958). 중요 정보 콜아웃.
|
|
5
|
+
*
|
|
6
|
+
* Type: Default/Info/Success/Warning/Error → 테두리 색@32% + 배경 색@4% + 아이콘 색.
|
|
7
|
+
* 제목=foreground medium, 설명=muted-foreground. 상태색은 통일 토큰(info/success/warning/destructive).
|
|
8
|
+
*/
|
|
9
|
+
declare const alertVariants: (props?: ({
|
|
10
|
+
type?: "default" | "error" | "info" | "success" | "warning" | null | undefined;
|
|
11
|
+
} & import("class-variance-authority/types").ClassProp) | undefined) => string;
|
|
12
|
+
export declare function StatusIcon({ type }: {
|
|
13
|
+
type: NonNullable<VariantProps<typeof alertVariants>["type"]>;
|
|
14
|
+
}): React.JSX.Element;
|
|
15
|
+
export interface AlertProps extends Omit<React.HTMLAttributes<HTMLDivElement>, "title">, VariantProps<typeof alertVariants> {
|
|
16
|
+
title?: React.ReactNode;
|
|
17
|
+
/** 아이콘 직접 지정(미지정 시 type 기본 아이콘). false 면 숨김. */
|
|
18
|
+
icon?: React.ReactNode | false;
|
|
19
|
+
/** 우측 액션(버튼 등) */
|
|
20
|
+
action?: React.ReactNode;
|
|
21
|
+
}
|
|
22
|
+
declare const Alert: React.ForwardRefExoticComponent<AlertProps & React.RefAttributes<HTMLDivElement>>;
|
|
23
|
+
export { Alert, alertVariants };
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import * as React from "react";
|
|
2
|
+
import { type AvatarProps } from "./avatar";
|
|
3
|
+
/**
|
|
4
|
+
* AvatarGroup — Figma "BO UI Kit" AvatarGroup(node 1696:220). Avatar 겹쳐 쌓기.
|
|
5
|
+
*
|
|
6
|
+
* 자식 Avatar 들을 음수 마진으로 겹치고 각자 2px background 테두리(ring)로 분리한다.
|
|
7
|
+
* `size` 를 자식에 주입(자식이 명시하면 우선), `max` 초과분은 "+N" 아바타로 요약.
|
|
8
|
+
*/
|
|
9
|
+
export interface AvatarGroupProps extends React.HTMLAttributes<HTMLDivElement> {
|
|
10
|
+
/** 그룹 공통 아바타 크기(자식에 주입) */
|
|
11
|
+
size?: AvatarProps["size"];
|
|
12
|
+
/** 표시할 최대 개수, 초과분은 +N */
|
|
13
|
+
max?: number;
|
|
14
|
+
}
|
|
15
|
+
declare const AvatarGroup: React.ForwardRefExoticComponent<AvatarGroupProps & React.RefAttributes<HTMLDivElement>>;
|
|
16
|
+
export { AvatarGroup };
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import * as React from "react";
|
|
2
|
+
import { type VariantProps } from "class-variance-authority";
|
|
3
|
+
/**
|
|
4
|
+
* Avatar — Figma "BO UI Kit" Avatar(node 1696:153). 이미지 + 폴백(이니셜).
|
|
5
|
+
*
|
|
6
|
+
* Figma 변형: Circular(True/False) → `shape` circle/square, Size 24/28/32/36/40/48 → `size`.
|
|
7
|
+
* 폴백 배경=Figma `muted`(#e2e8f0)=프로젝트 `secondary`, 텍스트=muted-foreground, medium.
|
|
8
|
+
* `ring`(2px background 색 테두리)은 AvatarGroup 겹침 분리용. 이미지 로드 실패 시 폴백 표시.
|
|
9
|
+
*/
|
|
10
|
+
declare const avatarVariants: (props?: ({
|
|
11
|
+
size?: "xs" | "sm" | "md" | "lg" | "xl" | "2xl" | null | undefined;
|
|
12
|
+
shape?: "square" | "circle" | null | undefined;
|
|
13
|
+
} & import("class-variance-authority/types").ClassProp) | undefined) => string;
|
|
14
|
+
export interface AvatarProps extends React.HTMLAttributes<HTMLDivElement>, VariantProps<typeof avatarVariants> {
|
|
15
|
+
src?: string;
|
|
16
|
+
alt?: string;
|
|
17
|
+
/** 이미지 없음/로드 실패 시 표시할 이니셜 등 */
|
|
18
|
+
fallback?: React.ReactNode;
|
|
19
|
+
/** 2px background 색 테두리(그룹 겹침 분리용) */
|
|
20
|
+
ring?: boolean;
|
|
21
|
+
}
|
|
22
|
+
declare const Avatar: React.ForwardRefExoticComponent<AvatarProps & React.RefAttributes<HTMLDivElement>>;
|
|
23
|
+
export { Avatar, avatarVariants };
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import * as React from "react";
|
|
2
|
+
import { type VariantProps } from "class-variance-authority";
|
|
3
|
+
/**
|
|
4
|
+
* Badge — Figma "BO UI Kit" Badge(node 9929:48567). 상태/카테고리 라벨.
|
|
5
|
+
*
|
|
6
|
+
* Figma 변형: Color(blue/red/orange/green/neutral…) × Type(Fill/Tinted) × Disabled.
|
|
7
|
+
* - Fill : 단색 채움(상태색) + 흰 텍스트
|
|
8
|
+
* - Tinted: 상태색 @8% 배경 + 상태색-foreground 텍스트
|
|
9
|
+
* 색은 상태 토큰으로 매핑: blue→info(=primary), red→destructive, orange→warning,
|
|
10
|
+
* green→success, neutral→foreground. (Figma static/secondary(dark) 변형은 미구현.)
|
|
11
|
+
*/
|
|
12
|
+
declare const badgeVariants: (props?: ({
|
|
13
|
+
color?: "destructive" | "info" | "success" | "warning" | "neutral" | null | undefined;
|
|
14
|
+
variant?: "fill" | "tinted" | null | undefined;
|
|
15
|
+
} & import("class-variance-authority/types").ClassProp) | undefined) => string;
|
|
16
|
+
export interface BadgeProps extends Omit<React.HTMLAttributes<HTMLSpanElement>, "color">, VariantProps<typeof badgeVariants> {
|
|
17
|
+
}
|
|
18
|
+
declare const Badge: React.ForwardRefExoticComponent<BadgeProps & React.RefAttributes<HTMLSpanElement>>;
|
|
19
|
+
export { Badge, badgeVariants };
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import * as React from "react";
|
|
2
|
+
/**
|
|
3
|
+
* Breadcrumb — Figma "BO UI Kit" Breadcrumb(node 5665:4391). 현재 위치 경로 표시.
|
|
4
|
+
*
|
|
5
|
+
* 항목들을 구분자(chevron/slash)로 연결. 링크(href 있음)=muted-foreground, 마지막(현재)=foreground.
|
|
6
|
+
* Type: Chevron(›) / Slash(/). text-sm. items 배열 API.
|
|
7
|
+
*/
|
|
8
|
+
export interface BreadcrumbItemData {
|
|
9
|
+
label: React.ReactNode;
|
|
10
|
+
href?: string;
|
|
11
|
+
}
|
|
12
|
+
export interface BreadcrumbProps extends React.HTMLAttributes<HTMLElement> {
|
|
13
|
+
items: BreadcrumbItemData[];
|
|
14
|
+
separator?: "chevron" | "slash";
|
|
15
|
+
}
|
|
16
|
+
declare const Breadcrumb: React.ForwardRefExoticComponent<BreadcrumbProps & React.RefAttributes<HTMLElement>>;
|
|
17
|
+
export { Breadcrumb };
|
|
@@ -3,14 +3,15 @@ import { type VariantProps } from "class-variance-authority";
|
|
|
3
3
|
/**
|
|
4
4
|
* Button — Figma "BO UI Kit" Button 컴포넌트(node 1692:74)를 옮긴 React 컴포넌트.
|
|
5
5
|
*
|
|
6
|
-
* 7가지 타입 × 5가지 사이즈
|
|
6
|
+
* 7가지 타입(Default/Outline/Secondary/Destructive/DestructiveTinted/Link/Ghost) × 5가지 사이즈
|
|
7
|
+
* 매트릭스를 그대로 재현하며, 모든 색상/간격/타이포는
|
|
7
8
|
* Tailwind config(= Figma 디자인 토큰)에 매핑돼 하드코딩을 최소화했다.
|
|
8
9
|
* 좌/우 아이콘 슬롯(icon, rightIcon)을 지원한다.
|
|
9
10
|
*
|
|
10
11
|
* @see https://coss.com/ui/docs/components/button
|
|
11
12
|
*/
|
|
12
13
|
declare const buttonVariants: (props?: ({
|
|
13
|
-
variant?: "default" | "outline" | "secondary" | "destructive" | "destructive-
|
|
14
|
+
variant?: "link" | "default" | "outline" | "secondary" | "destructive" | "destructive-tinted" | "ghost" | null | undefined;
|
|
14
15
|
size?: "xs" | "sm" | "md" | "lg" | "xl" | null | undefined;
|
|
15
16
|
} & import("class-variance-authority/types").ClassProp) | undefined) => string;
|
|
16
17
|
export interface ButtonProps extends React.ButtonHTMLAttributes<HTMLButtonElement>, VariantProps<typeof buttonVariants> {
|
|
@@ -18,6 +19,8 @@ export interface ButtonProps extends React.ButtonHTMLAttributes<HTMLButtonElemen
|
|
|
18
19
|
icon?: React.ReactNode;
|
|
19
20
|
/** 우측 아이콘 */
|
|
20
21
|
rightIcon?: React.ReactNode;
|
|
22
|
+
/** 알약(rounded-full) 형태 — Figma PillButton 변형 */
|
|
23
|
+
pill?: boolean;
|
|
21
24
|
}
|
|
22
25
|
declare const Button: React.ForwardRefExoticComponent<ButtonProps & React.RefAttributes<HTMLButtonElement>>;
|
|
23
26
|
export { Button, buttonVariants };
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import * as React from "react";
|
|
2
|
+
/**
|
|
3
|
+
* Collapsible — Figma "BO UI Kit" Collapsible(node 5677:165). 버튼으로 여닫는 패널.
|
|
4
|
+
*
|
|
5
|
+
* 트리거 행(제목 + chevron-down, 펼침 시 회전) + 펼침 시 내용. 제어/비제어(open/defaultOpen/onOpenChange).
|
|
6
|
+
*/
|
|
7
|
+
export interface CollapsibleProps extends Omit<React.HTMLAttributes<HTMLDivElement>, "title"> {
|
|
8
|
+
/** 트리거에 표시할 제목 */
|
|
9
|
+
title: React.ReactNode;
|
|
10
|
+
open?: boolean;
|
|
11
|
+
defaultOpen?: boolean;
|
|
12
|
+
onOpenChange?: (open: boolean) => void;
|
|
13
|
+
disabled?: boolean;
|
|
14
|
+
}
|
|
15
|
+
declare const Collapsible: React.ForwardRefExoticComponent<CollapsibleProps & React.RefAttributes<HTMLDivElement>>;
|
|
16
|
+
export { Collapsible };
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import * as React from "react";
|
|
2
|
+
export interface DialogProps {
|
|
3
|
+
open?: boolean;
|
|
4
|
+
defaultOpen?: boolean;
|
|
5
|
+
onOpenChange?: (open: boolean) => void;
|
|
6
|
+
/** 내부용: alertdialog 역할 + 바깥클릭 비활성 */
|
|
7
|
+
role?: "dialog" | "alertdialog";
|
|
8
|
+
dismissable?: boolean;
|
|
9
|
+
children?: React.ReactNode;
|
|
10
|
+
}
|
|
11
|
+
declare function Dialog({ open, defaultOpen, onOpenChange, role, dismissable, children }: DialogProps): React.JSX.Element;
|
|
12
|
+
declare const DialogTrigger: React.ForwardRefExoticComponent<React.ButtonHTMLAttributes<HTMLButtonElement> & React.RefAttributes<HTMLButtonElement>>;
|
|
13
|
+
declare const DialogClose: React.ForwardRefExoticComponent<React.ButtonHTMLAttributes<HTMLButtonElement> & React.RefAttributes<HTMLButtonElement>>;
|
|
14
|
+
export interface DialogContentProps extends React.HTMLAttributes<HTMLDivElement> {
|
|
15
|
+
showClose?: boolean;
|
|
16
|
+
}
|
|
17
|
+
declare const DialogContent: React.ForwardRefExoticComponent<DialogContentProps & React.RefAttributes<HTMLDivElement>>;
|
|
18
|
+
declare const DialogHeader: ({ className, ...props }: React.HTMLAttributes<HTMLDivElement>) => React.JSX.Element;
|
|
19
|
+
declare const DialogTitle: ({ className, id, ...props }: React.HTMLAttributes<HTMLHeadingElement>) => React.JSX.Element;
|
|
20
|
+
declare const DialogDescription: ({ className, id, ...props }: React.HTMLAttributes<HTMLParagraphElement>) => React.JSX.Element;
|
|
21
|
+
declare const DialogFooter: ({ className, ...props }: React.HTMLAttributes<HTMLDivElement>) => React.JSX.Element;
|
|
22
|
+
export { Dialog, DialogTrigger, DialogContent, DialogHeader, DialogTitle, DialogDescription, DialogFooter, DialogClose };
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { type SheetContentProps } from "./sheet";
|
|
2
|
+
/**
|
|
3
|
+
* Drawer — Figma "BO UI Kit" Drawer(node 8046:330). 가장자리 패널(Sheet 기반, 여백 있는 inset 기본).
|
|
4
|
+
*
|
|
5
|
+
* Sheet 를 재사용한 프리셋: 기본 side=bottom + inset(플로팅 rounded-2xl). 제어/비제어(open).
|
|
6
|
+
* 헤더/푸터는 Sheet 의 SheetHeader/SheetTitle/SheetDescription/SheetFooter 를 그대로 사용.
|
|
7
|
+
*/
|
|
8
|
+
export interface DrawerProps extends Omit<SheetContentProps, "side"> {
|
|
9
|
+
open?: boolean;
|
|
10
|
+
defaultOpen?: boolean;
|
|
11
|
+
onOpenChange?: (open: boolean) => void;
|
|
12
|
+
side?: SheetContentProps["side"];
|
|
13
|
+
}
|
|
14
|
+
declare function Drawer({ open, defaultOpen, onOpenChange, side, inset, children, ...contentProps }: DrawerProps): import("react").JSX.Element;
|
|
15
|
+
export { Drawer };
|
|
16
|
+
export { SheetHeader as DrawerHeader, SheetTitle as DrawerTitle, SheetDescription as DrawerDescription, SheetFooter as DrawerFooter, } from "./sheet";
|
|
@@ -18,3 +18,49 @@ export { ToggleGroup, ToggleGroupItem } from "./toggle-group";
|
|
|
18
18
|
export type { ToggleGroupProps, ToggleGroupItemProps } from "./toggle-group";
|
|
19
19
|
export { Select, selectTriggerVariants } from "./select";
|
|
20
20
|
export type { SelectProps, SelectOption } from "./select";
|
|
21
|
+
export { Switch, switchVariants } from "./switch";
|
|
22
|
+
export type { SwitchProps } from "./switch";
|
|
23
|
+
export { Separator } from "./separator";
|
|
24
|
+
export type { SeparatorProps } from "./separator";
|
|
25
|
+
export { Skeleton } from "./skeleton";
|
|
26
|
+
export type { SkeletonProps } from "./skeleton";
|
|
27
|
+
export { Spinner, spinnerVariants } from "./spinner";
|
|
28
|
+
export type { SpinnerProps } from "./spinner";
|
|
29
|
+
export { Textarea, textareaVariants } from "./textarea";
|
|
30
|
+
export type { TextareaProps } from "./textarea";
|
|
31
|
+
export { Avatar, avatarVariants } from "./avatar";
|
|
32
|
+
export type { AvatarProps } from "./avatar";
|
|
33
|
+
export { AvatarGroup } from "./avatar-group";
|
|
34
|
+
export type { AvatarGroupProps } from "./avatar-group";
|
|
35
|
+
export { Badge, badgeVariants } from "./badge";
|
|
36
|
+
export type { BadgeProps } from "./badge";
|
|
37
|
+
export { NumberField, numberFieldVariants } from "./number-field";
|
|
38
|
+
export type { NumberFieldProps } from "./number-field";
|
|
39
|
+
export { RadioGroup, RadioGroupItem } from "./radio-group";
|
|
40
|
+
export type { RadioGroupProps, RadioGroupItemProps } from "./radio-group";
|
|
41
|
+
export { SegmentedControl, segmentVariants } from "./segmented-control";
|
|
42
|
+
export type { SegmentedControlProps, SegmentedOption } from "./segmented-control";
|
|
43
|
+
export { Tabs, TabsList, TabsTrigger, TabsContent } from "./tabs";
|
|
44
|
+
export type { TabsProps, TabsTriggerProps, TabsContentProps } from "./tabs";
|
|
45
|
+
export { Accordion, AccordionItem } from "./accordion";
|
|
46
|
+
export type { AccordionProps, AccordionItemProps } from "./accordion";
|
|
47
|
+
export { Collapsible } from "./collapsible";
|
|
48
|
+
export type { CollapsibleProps } from "./collapsible";
|
|
49
|
+
export { Breadcrumb } from "./breadcrumb";
|
|
50
|
+
export type { BreadcrumbProps, BreadcrumbItemData } from "./breadcrumb";
|
|
51
|
+
export { Alert, alertVariants } from "./alert";
|
|
52
|
+
export type { AlertProps } from "./alert";
|
|
53
|
+
export { Toast } from "./toast";
|
|
54
|
+
export type { ToastProps } from "./toast";
|
|
55
|
+
export { Tooltip } from "./tooltip";
|
|
56
|
+
export type { TooltipProps } from "./tooltip";
|
|
57
|
+
export { ScrollArea } from "./scroll-area";
|
|
58
|
+
export type { ScrollAreaProps } from "./scroll-area";
|
|
59
|
+
export { Dialog, DialogTrigger, DialogContent, DialogHeader, DialogTitle, DialogDescription, DialogFooter, DialogClose, } from "./dialog";
|
|
60
|
+
export type { DialogProps, DialogContentProps } from "./dialog";
|
|
61
|
+
export { AlertDialog } from "./alert-dialog";
|
|
62
|
+
export type { AlertDialogProps } from "./alert-dialog";
|
|
63
|
+
export { Sheet, SheetTrigger, SheetContent, SheetHeader, SheetTitle, SheetDescription, SheetFooter, SheetClose, } from "./sheet";
|
|
64
|
+
export type { SheetProps, SheetContentProps } from "./sheet";
|
|
65
|
+
export { Drawer, DrawerHeader, DrawerTitle, DrawerDescription, DrawerFooter } from "./drawer";
|
|
66
|
+
export type { DrawerProps } from "./drawer";
|
|
@@ -6,7 +6,7 @@ import { type VariantProps } from "class-variance-authority";
|
|
|
6
6
|
* 구조: 테두리 컨테이너 + [leftIcon][prefix][native input][suffix][rightIcon].
|
|
7
7
|
* 상태(Figma Type 변형):
|
|
8
8
|
* - Default : border input-border
|
|
9
|
-
* - Error : border destructive(#
|
|
9
|
+
* - Error : border destructive(#fb2c36 빨강) → `invalid` prop
|
|
10
10
|
* - Disabled: 컨테이너 opacity 64% → input `disabled`
|
|
11
11
|
* - Focus : 테두리가 disabled(#45556c@30%)로 진해지고 3px 회색 글로우 링
|
|
12
12
|
* (Figma Focus 노드 7745:700 Stroke: 3px disabled@30% × opacity23% ≈ @7%, offset 없음).
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import * as React from "react";
|
|
2
|
+
import { type VariantProps } from "class-variance-authority";
|
|
3
|
+
/**
|
|
4
|
+
* NumberField — Figma "BO UI Kit" NumberField(node 7781:5501). 증감 버튼이 달린 숫자 입력.
|
|
5
|
+
*
|
|
6
|
+
* Input 과 동일한 컨테이너 토큰/포커스(회색 3px 링, border-input). 좌(−)·우(+) 스텝퍼 버튼 +
|
|
7
|
+
* 가운데 정렬 숫자 입력. size sm/md/lg(28/32/36). min/max/step·clamp 지원. 제어/비제어.
|
|
8
|
+
* 아이콘은 7일 만료 에셋 대신 인라인 SVG.
|
|
9
|
+
*/
|
|
10
|
+
declare const numberFieldVariants: (props?: ({
|
|
11
|
+
size?: "sm" | "md" | "lg" | null | undefined;
|
|
12
|
+
} & import("class-variance-authority/types").ClassProp) | undefined) => string;
|
|
13
|
+
export interface NumberFieldProps extends Omit<React.InputHTMLAttributes<HTMLInputElement>, "size" | "value" | "defaultValue" | "onChange">, VariantProps<typeof numberFieldVariants> {
|
|
14
|
+
value?: number;
|
|
15
|
+
defaultValue?: number;
|
|
16
|
+
onValueChange?: (value: number) => void;
|
|
17
|
+
min?: number;
|
|
18
|
+
max?: number;
|
|
19
|
+
step?: number;
|
|
20
|
+
}
|
|
21
|
+
declare const NumberField: React.ForwardRefExoticComponent<NumberFieldProps & React.RefAttributes<HTMLInputElement>>;
|
|
22
|
+
export { NumberField, numberFieldVariants };
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import * as React from "react";
|
|
2
|
+
/**
|
|
3
|
+
* 오버레이 공용 내부 유틸 — Dialog / AlertDialog / Sheet / Drawer 가 공유.
|
|
4
|
+
* 포털(body), ESC 닫기 + body 스크롤 잠금, 백드롭(black@32% + blur).
|
|
5
|
+
*/
|
|
6
|
+
export declare function Portal({ children }: {
|
|
7
|
+
children: React.ReactNode;
|
|
8
|
+
}): React.ReactPortal | null;
|
|
9
|
+
/** 열림 동안 ESC 로 닫고 body 스크롤을 잠근다. */
|
|
10
|
+
export declare function useOverlayBehavior(open: boolean, onClose: () => void): void;
|
|
11
|
+
/** 백드롭(검정 #101012 @32% + 배경 블러). Figma Overlay 토큰. */
|
|
12
|
+
export declare const backdropClass = "fixed inset-0 z-50 bg-[rgb(16_16_18_/_0.32)] backdrop-blur-sm";
|
|
13
|
+
/** open/defaultOpen/onOpenChange 를 controlled/uncontrolled 로 다루는 훅. */
|
|
14
|
+
export declare function useControllableOpen(open: boolean | undefined, defaultOpen: boolean, onOpenChange?: (o: boolean) => void): readonly [boolean, (o: boolean) => void];
|
|
15
|
+
/**
|
|
16
|
+
* 열림 시 포커스를 패널로 옮기고 Tab/Shift+Tab 을 패널 안에 가둔다. 닫히면 이전
|
|
17
|
+
* 포커스로 복원. 초기 포커스는 내부 요소가 아니라 패널 자체(tabIndex=-1)로 둬서
|
|
18
|
+
* 포커스 링이 생겨 시각이 바뀌는 것을 막는다(패널엔 outline-none).
|
|
19
|
+
*/
|
|
20
|
+
export declare function useFocusTrap(open: boolean, containerRef: React.RefObject<HTMLElement | null>): void;
|
|
21
|
+
/**
|
|
22
|
+
* Title/Description 존재 여부를 추적해 컨테이너에 붙일 aria-labelledby/describedby 를
|
|
23
|
+
* 만든다. 제목/설명이 실제로 렌더된 경우에만 연결(없는 id 참조 방지).
|
|
24
|
+
*/
|
|
25
|
+
export declare function useA11yIds(): {
|
|
26
|
+
titleId: string;
|
|
27
|
+
descId: string;
|
|
28
|
+
setHasTitle: React.Dispatch<React.SetStateAction<boolean>>;
|
|
29
|
+
setHasDesc: React.Dispatch<React.SetStateAction<boolean>>;
|
|
30
|
+
labelProps: {
|
|
31
|
+
"aria-labelledby"?: string;
|
|
32
|
+
"aria-describedby"?: string;
|
|
33
|
+
};
|
|
34
|
+
};
|
|
35
|
+
/** Title/Description 컴포넌트가 마운트 동안 자신의 존재를 등록한다. */
|
|
36
|
+
export declare function useRegisterPresence(setPresent: (v: boolean) => void): void;
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import * as React from "react";
|
|
2
|
+
export interface RadioGroupProps extends Omit<React.HTMLAttributes<HTMLDivElement>, "onChange"> {
|
|
3
|
+
value?: string;
|
|
4
|
+
defaultValue?: string;
|
|
5
|
+
onValueChange?: (value: string) => void;
|
|
6
|
+
name?: string;
|
|
7
|
+
disabled?: boolean;
|
|
8
|
+
}
|
|
9
|
+
declare const RadioGroup: React.ForwardRefExoticComponent<RadioGroupProps & React.RefAttributes<HTMLDivElement>>;
|
|
10
|
+
export interface RadioGroupItemProps extends Omit<React.LabelHTMLAttributes<HTMLLabelElement>, "title"> {
|
|
11
|
+
value: string;
|
|
12
|
+
title?: React.ReactNode;
|
|
13
|
+
description?: React.ReactNode;
|
|
14
|
+
disabled?: boolean;
|
|
15
|
+
/** 테두리 카드로 감쌈 */
|
|
16
|
+
cardStyle?: boolean;
|
|
17
|
+
}
|
|
18
|
+
declare const RadioGroupItem: React.ForwardRefExoticComponent<RadioGroupItemProps & React.RefAttributes<HTMLLabelElement>>;
|
|
19
|
+
export { RadioGroup, RadioGroupItem };
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import * as React from "react";
|
|
2
|
+
/**
|
|
3
|
+
* ScrollArea — Figma "BO UI Kit" Scroll Area(node 7669:1745). 커스텀 스크롤바 컨테이너.
|
|
4
|
+
*
|
|
5
|
+
* overflow-auto + 얇은 커스텀 스크롤바(thumb=foreground@20%, rounded-full). 테두리/패딩은 기본 제공,
|
|
6
|
+
* 높이는 className(max-h 등)으로 지정. Figma 의 하단 fade 는 선택(scrollFade).
|
|
7
|
+
*/
|
|
8
|
+
export interface ScrollAreaProps extends React.HTMLAttributes<HTMLDivElement> {
|
|
9
|
+
/** 테두리/패딩 박스 스타일 적용(기본 true) */
|
|
10
|
+
bordered?: boolean;
|
|
11
|
+
}
|
|
12
|
+
declare const ScrollArea: React.ForwardRefExoticComponent<ScrollAreaProps & React.RefAttributes<HTMLDivElement>>;
|
|
13
|
+
export { ScrollArea };
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import * as React from "react";
|
|
2
|
+
import { type VariantProps } from "class-variance-authority";
|
|
3
|
+
/**
|
|
4
|
+
* SegmentedControl — Figma "BO UI Kit" Segmented Control(node 9705:88227). 단일 선택 세그먼트.
|
|
5
|
+
*
|
|
6
|
+
* 컨테이너(bg-background, p-0.5) 안에 균등 너비 세그먼트. 선택 세그먼트만 bg-card + shadow(흰 알약),
|
|
7
|
+
* 나머지는 muted-foreground 텍스트. Style: Rounded(rounded-full) / Regular(rounded-radius) / Sharp(rounded-none).
|
|
8
|
+
* 제어/비제어(value/onValueChange). (Figma 의 다층 그림자는 shadow-xs 로 근사.)
|
|
9
|
+
*/
|
|
10
|
+
declare const containerVariants: (props?: ({
|
|
11
|
+
segStyle?: "rounded" | "regular" | "sharp" | null | undefined;
|
|
12
|
+
} & import("class-variance-authority/types").ClassProp) | undefined) => string;
|
|
13
|
+
declare const segmentVariants: (props?: ({
|
|
14
|
+
segStyle?: "rounded" | "regular" | "sharp" | null | undefined;
|
|
15
|
+
active?: boolean | null | undefined;
|
|
16
|
+
} & import("class-variance-authority/types").ClassProp) | undefined) => string;
|
|
17
|
+
export interface SegmentedOption {
|
|
18
|
+
value: string;
|
|
19
|
+
label: React.ReactNode;
|
|
20
|
+
disabled?: boolean;
|
|
21
|
+
}
|
|
22
|
+
export interface SegmentedControlProps extends Omit<React.HTMLAttributes<HTMLDivElement>, "onChange">, VariantProps<typeof containerVariants> {
|
|
23
|
+
options: SegmentedOption[];
|
|
24
|
+
value?: string;
|
|
25
|
+
defaultValue?: string;
|
|
26
|
+
onValueChange?: (value: string) => void;
|
|
27
|
+
}
|
|
28
|
+
declare const SegmentedControl: React.ForwardRefExoticComponent<SegmentedControlProps & React.RefAttributes<HTMLDivElement>>;
|
|
29
|
+
export { SegmentedControl, segmentVariants };
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import * as React from "react";
|
|
2
|
+
/**
|
|
3
|
+
* Separator — Figma "BO UI Kit" Separator(node 3605:3065). 영역 구분선.
|
|
4
|
+
*
|
|
5
|
+
* 1px 라인(`border` 토큰, #0f172b @8%). orientation: horizontal(h-px w-full) / vertical(w-px h-full).
|
|
6
|
+
* 접근성: 의미상 구분이면 `decorative={false}` → role=separator + aria-orientation, 장식이면 기본(role=none).
|
|
7
|
+
* (Figma 의 Spacing 변형은 여백 — 소비자가 className(margin)으로 처리.)
|
|
8
|
+
*/
|
|
9
|
+
export interface SeparatorProps extends React.HTMLAttributes<HTMLDivElement> {
|
|
10
|
+
orientation?: "horizontal" | "vertical";
|
|
11
|
+
/** 장식용(기본 true). false 면 스크린리더에 구분선으로 노출. */
|
|
12
|
+
decorative?: boolean;
|
|
13
|
+
}
|
|
14
|
+
declare const Separator: React.ForwardRefExoticComponent<SeparatorProps & React.RefAttributes<HTMLDivElement>>;
|
|
15
|
+
export { Separator };
|