- 면 높이
- 5
- 바닥 · 파임 · 카드 · 솟음 · 뜸
- 글자 단계
- 4
- 강조 · 본문 · 보조 · 흐림
- 상태 톤
- 5
- ok · warn · bad · info · neutral
- 토큰
- 170
- --uyoo-*
@uyoolabs/ui
우유랩스 제품군이 함께 쓰는 디자인 시스템입니다. 카톤 재질의 디자인 토큰 · CSS · React 컴포넌트를 하나의 패키지로 배포합니다.
재질은 카톤입니다. 우유 마크의 문법을 화면 전체로 옮겨, 선 대신 틈으로 나누고 효과 대신 면의 명도 차로 높이를 나타냅니다. 입체감은 모서리 · 두께 · 그늘로만 만듭니다. 빛은 왼쪽 위 하나라 두께는 오른쪽 아래로 떨어지고, 카드처럼 내용을 담는 면은 오른쪽 위를 카톤 지붕처럼 꺾습니다. 반투명 · blur · 배경 블롭 · 그라데이션 · 무늬는 쓰지 않습니다.
원본 저장소는 uyoolabs/ui 하나입니다(v1 때 이름은 uyoolabs/uyooglass). 제품 저장소에서 스타일 값을 직접 수정하지 않습니다. 이 사이트는 패키지의 실제 소스로 렌더링되므로, 여기에 보이는 모습이 제품에 적용되는 모습과 같습니다. 시각 스펙의 정본은 design/canvas 의 보드입니다.
v1 에서 옮기기
v1 의 이름은 @uyoolabs/uyooglass 였습니다. v2 는 패키지 이름과 재질을 한 번에 바꿉니다.
- 패키지
- @uyoolabs/uyooglass → @uyoolabs/ui. 서브패스(./ui · ./menu · ./brand …)는 이름만 바뀌고 그대로입니다. v1 은 v1 유지보수 브랜치에서 중요한 수정만 냅니다.
- 토큰
- 새 이름은 --uyoo-*(면 · 글자 · 선 · 상태 · 두께 · 그늘)입니다. v1 의미 이름(--background · --primary · --muted-foreground …)은 호환 층이 카톤 값으로 돌려 Tailwind 유틸리티가 그대로 동작합니다.
- 재질 클래스
- v1 서피스 클래스 · 배경 블롭 · UyooBackdrop · PretendardFont · DocumentFonts 는 v2.0.0 에서 빠집니다. 화면은 카톤 컴포넌트(Card · Button …)로, 서체는 @uyoolabs/ui/fonts/* 로 바꿉니다.
- 코드모드
- pnpm codemod:v2 <리포 경로> 가 import 경로 · 클래스 이름 · 바뀐 prop 을 옮기고, 손으로 볼 자리에 // v2: 주석을 남깁니다. 바뀐 이름 전체는 docs/migration/v2-*.md 에 있습니다.
설치
패키지는 npmjs 가 아닌 GitHub Packages 에 게시되어 있습니다.
.npmrc
@uyoolabs:registry=https://npm.pkg.github.com
//npm.pkg.github.com/:_authToken=${GITHUB_PACKAGES_TOKEN}GITHUB_PACKAGES_TOKEN 은 read:packages 권한이 있는 토큰입니다. 로컬 셸, Vercel, Railway 환경 변수에 같은 이름으로 등록합니다.
패키지 추가
pnpm add @uyoolabs/ui # latest
pnpm add @uyoolabs/ui@dev # main 최신 커밋next.config.ts
// next.config.ts: 패키지가 소스(.tsx)로 배포되므로 Next 에서 트랜스파일한다.
const nextConfig: NextConfig = {
transpilePackages: ["@uyoolabs/ui"],
};globals.css
/* globals.css: 아래 두 줄만 있으면 된다. 순서를 바꾸지 않는다. */
@import "tailwindcss";
@import "@uyoolabs/ui/css";루트 layout.tsx
import "@uyoolabs/ui/fonts/app"; // UI 고딕. 일본어 화면은 fonts/app-ja 를 더한다
import "@uyoolabs/ui/fonts/doc-ko"; // 문서 명조(uyoo-doc-*)를 쓰는 앱에만 넣는다
import { ThemeProvider } from "@uyoolabs/ui/theme";
<html lang="ko" suppressHydrationWarning>
<body><ThemeProvider>{children}</ThemeProvider></body>
</html>peer 의존성은 react · react-dom ≥ 19, next ≥ 16, tailwindcss ≥ 4, next-themes 입니다. 서체 패키지(Fontsource) · radix-ui · lucide-react 는 그것을 쓰는 진입점(fonts/* · menu · avatar · ThemeToggle 등)을 불러올 때만 필요합니다.
진입점
기능별로 진입점이 나뉘어 있습니다. 필요한 진입점만 import 합니다.
| import | 내보내는 항목 |
|---|---|
| @uyoolabs/ui | cn · useMounted · isComposing · formatDate · formatDateTime · formatRelative |
| @uyoolabs/ui/ui | Button · IconButton · Input · Textarea · Field · LinkProvider · Card · Table · Badge · Stats · TabNav · Pagination · Sidebar · SidebarItem · Breadcrumb · Count · FormRow · InlineEdit · CodeBlock · Snippet · Sparkline · BarList · Meter · Progress · ProgressRing · 버튼·입력 클래스 상수 (Next 없음) |
| @uyoolabs/ui/icons | IconSearch · IconChevronDown 등 내부 아이콘 세트 · icons 이름 맵 (react 만 필요) |
| @uyoolabs/ui/theme | ThemeProvider |
| @uyoolabs/ui/theme-toggle | ThemeToggle (radix · lucide 필요) |
| @uyoolabs/ui/menu | DropdownMenu* · ContextMenu* · MenuItems(항목 정의 하나로 드롭다운 · 컨텍스트 메뉴 · 아래 시트) (radix) |
| @uyoolabs/ui/avatar | Avatar* (radix) |
| @uyoolabs/ui/brand | BrandLogo(<img>, Next 없이) · GoogleIcon · GitHubIcon |
| @uyoolabs/ui/fonts/* | app · app-ja · doc-ko · doc-ja · doc-en 서체(side-effect import, 서체 패키지는 선택 peer) |
| @uyoolabs/ui/form | Checkbox · RadioGroup · Switch · SegmentedControl · Select · Slider · FieldGroup · SubmitBar 등(radix) |
| @uyoolabs/ui/command | CommandPalette · CommandInput · CommandList · CommandGroup · CommandItem · CommandPage · Highlight(radix) — W2 |
| @uyoolabs/ui/overlay | Tooltip · Popover · Dialog · AlertDialog · Sheet · HoverCard · PersonCard · LinkPreviewCard(radix). DropdownMenu · ContextMenu 는 ./menu |
| @uyoolabs/ui/feedback | toast() · ToastRegion · Toast · ToastCard(radix) · PageProgress · UploadList · UploadPanel · StepProgress. Alert · Banner · Progress · ProgressRing 는 ./ui |
| @uyoolabs/ui/nav | AppShell · Topbar · SidebarSection · WorkspaceSwitcher · BreadcrumbOverflow · Tabs · Accordion · Collapsible(radix) |
| @uyoolabs/ui/split | SplitPanel · SplitPane · SplitHandle(react-resizable-panels 필요) |
| @uyoolabs/ui/date | DatePicker · DateRangePicker · DateField · Calendar · TimeField · toUtcIso · fromUtcIso (react-day-picker · date-fns · radix 필요) |
| @uyoolabs/ui/next | NextLinkProvider · next/link 로 그리는 TabNav · Pagination · Breadcrumb |
| @uyoolabs/ui/editor | RichTextEditor comment · message 프리셋(Tiptap · marked · radix 필요, 지연 로드) — W3 · W4 |
| @uyoolabs/ui/editor/document | DocumentEditor · normalizeMarkdown(표 · 이미지 확장을 더한다, 지연 로드) — W5 |
| @uyoolabs/ui/editor/collab | CollaborativeEditor · Participants · createMemoryRoom(yjs · @tiptap/extension-collaboration 필요) — W5 |
| @uyoolabs/ui/meeting | MeetingRoom · MeetingStage · VideoTile · CallControls · PreJoin · RecordingIndicator · 녹화 대화상자 · ConnectionBanner · VoiceChannelMembers · VoiceDock · Captions · Transcript(radix, 미디어 SDK 없음) — W5 |
| @uyoolabs/ui/chat | ChannelSidebar · MessageItem · MessageList · Composer · ThreadPanel · TypingIndicator · PersonCard · FileAttachment · LinkPreview · SearchResults · NotificationPrefs · Reactions · ReactionChip(radix · @tanstack/react-virtual · 반응 추가는 ./emoji 를 지연 로드해 emojibase-data 필요) — W4 |
| @uyoolabs/ui/emoji | EmojiPicker · EmojiPickerPopover · SkinTonePicker · searchEmoji(radix · emojibase-data 선택 peer, 데이터는 지연 로드) — W4 |
| @uyoolabs/ui/ai | AssistantPanel · AISummaryCard · Citation · SourceList · UsageNotice · createStreamQueue(radix). AiLabel · AiMark · UsageMeter 는 ./ui |
| @uyoolabs/ui/board | Board · BoardColumn · BoardGroup · BoardCard · BoardLine — 칸반(radix). 끌기는 모른다 — W3 |
| @uyoolabs/ui/board/dnd | boardDnd — 칸반 끌기 층(pragmatic-drag-and-drop core · auto-scroll 필요) — W3 |
| @uyoolabs/ui/table | TableToolbar · BulkBar · FilterChips · SavedViews · ColumnMenu · SortHeader · ColumnResizer · EditableCell(radix, 표 엔진 없음) |
| @uyoolabs/ui/virtual | VirtualList · VirtualTable(@tanstack/react-virtual 필요) |
| @uyoolabs/ui/markdown | Markdown · splitStableBlocks · closeOpenFences(react-markdown · remark-gfm · remark-breaks 필요) |
| @uyoolabs/ui/css | 전체 CSS. 일부만 필요하면 css/tokens · css/tailwind · css/base · css/animations · css/components · css/utilities · css/carton/* (브랜드 표면은 css/carton/brand) |
레이아웃 규칙
여러 제품의 화면 구성을 맞추기 위한 최소 규칙입니다.
- 셸
- 바닥 면 위에 파인 면 사이드바(240)와 불투명한 상단 바(52)를 둡니다. 본문은 최대 1200, 양옆 24 입니다. 이 사이트의 셸이 예시입니다.
- 페이지
- Card 를 20px 간격으로 나열합니다. h1 은 쓰지 않습니다.
- 화면 이름
- 상단 바의 브레드크럼 마지막 항목이 말합니다.
- 목록
- Table 을 씁니다. 좁은 화면에서는 카드 목록으로 바뀝니다. 표가 아닌 목록은 파인 면 행(rowClass).
- 상태
- Badge 의 5톤(ok · warn · bad · info · neutral)을 씁니다. 색만이 아니라 모양과 글자로 말하고, 빨강은 오류와 되돌릴 수 없는 동작에만 씁니다.
- 버튼 · 입력
- 컴포넌트가 아닌 클래스 문자열입니다. Link 에도 적용할 수 있습니다.
- ID · 날짜
- ID 와 주소는 id 유틸리티(고정폭), 날짜와 수치는 num 유틸리티(tabular-nums)를 씁니다.
- UI 문구
- 합니다체로 씁니다.
이름 규칙
새 클래스와 토큰의 접두어는 uyoo 하나입니다. 변형 · 상태는 클래스가 아니라 data-* 속성(data-tone="ok", radix 의 data-state)으로 나타냅니다. v1 클래스는 기준선에 묶여 있어 늘릴 수 없고, CI 가 접두어와 금지어를 검사합니다.