저장소 밖 앱에 설치
@werft-ai/ui를 tarball로 묶어 다른 React 앱에 설치한다
@werft-ai/ui를 이 저장소 밖의 React 앱에서 쓰는 방법이다. 저장소에서 패키지를 빌드해 tarball로 묶고, 앱에서 그 파일을 npm install한다. 앱에 Tailwind는 없어도 된다.
아직 레지스트리에 게시하지 않았다. 그래서 지금은 아래처럼 tarball 파일로만 설치할 수 있다. @werft-ai/react(hook과 세션 블록)는 배포 대상이 아니라서 저장소 밖 앱에서는 쓸 수 없다.
이 저장소는 PolyForm Small Business License 1.0.0을 따르는 source-available 저장소다. 패키지에도 저장소의 LICENSE가 들어 있다. 직원·독립 계약자 100명 미만이고 직전 과세연도 총매출 100만 달러(2019년 기준, 물가 보정) 미만인 회사는 무료로 쓸 수 있고(회사를 지배하거나 회사가 지배하는 조직, 회사와 같은 지배를 받는 조직도 합쳐서 센다), 그보다 큰 회사는 상용 라이선스가 필요하다. 평가·상용 라이선스 문의: jaesoon@94soon.dev
tarball 만들기
저장소 루트에서 실행한다. 저장소가 고정한 Bun 1.3.14(루트 package.json의 packageManager)와 npm이 필요하다.
bun install
bun run --cwd packages/ui build:package
npm pack ./packages/ui/distbuild:package가 packages/ui/dist에 빌드된 JavaScript와 타입 선언, CSS, 배포용 package.json, LICENSE를 만든다. npm pack은 그 디렉터리를 묶어 현재 디렉터리에 werft-ai-ui-<버전>.tgz를 둔다. 버전은 packages/ui/package.json의 version이다.
앱에 설치하기
Vite + React + TypeScript 앱을 예로 든다. 앱이 없으면 npm create vite@latest my-app -- --template react-ts로 만든다.
@werft-ai/ui는 react와 react-dom ^19.3.0을 peer dependency로 받는다. 앱의 React가 이보다 낮으면 먼저 올리고, 만든 tarball을 설치한다.
npm install react@^19.3.0 react-dom@^19.3.0
npm install <저장소 경로>/werft-ai-ui-0.0.0.tgzRadix, class-variance-authority, clsx, tailwind-merge, lucide-react는 패키지의 dependency라서 함께 설치된다.
CSS 가져오기
미리 빌드한 styles.css를 한 번 import한다. 토큰, 키트 요소의 규칙, 키트가 쓰는 유틸리티 클래스가 모두 들어 있어서 Tailwind 없이 그려진다.
import "@werft-ai/ui/styles.css";
import { Button, Card } from "@werft-ai/ui";styles.css에는 Tailwind의 preflight(전역 리셋)가 없다. 전역에 거는 규칙은 하나뿐이다. 모든 요소의 기본 border-color를 --werft-color-border로 둬서, 앱이 border-width와 border-style만 주고 색을 정하지 않은 요소는 이 색으로 그려진다(border 단축 속성은 색도 정하므로 해당하지 않는다). 키트가 기대하는 리셋(테두리, margin, 버튼 배경, 링크 밑줄 등)은 키트 요소와 그 안쪽에만 specificity 0으로 걸린다. 그래서 키트 안에 넣은 앱 마크업도 브라우저 기본 margin과 밑줄이 빠진다. 키트 규칙은 cascade layer 안에 있어서 layer 밖에 쓴 앱의 CSS가 항상 이긴다.
Tailwind v4 앱
앱의 마크업에서도 키트의 유틸리티 이름(bg-primary, text-control, rounded-control 등)을 쓰려면 앱 CSS에서 styles.css 뒤에 theme.css를 import한다. theme.css가 토큰을 Tailwind 유틸리티에 잇는다.
@import "tailwindcss";
@import "@werft-ai/ui/styles.css";
@import "@werft-ai/ui/theme.css";키트 컴포넌트가 쓰는 클래스는 styles.css에 이미 있어서 node_modules를 @source로 스캔하지 않아도 된다.
폰트
패키지는 폰트를 싣지 않는다. 글꼴 목록은 --werft-font-sans(Geist, Pretendard Variable 순)와 --werft-font-mono(Geist Mono부터)에 있지만, styles.css는 이 변수를 키트의 werft-* 요소에만 건다. 버튼·세그먼트 컨트롤 같은 컨트롤은 앱의 글꼴을 물려받으므로, 앱이 body(또는 :root)에 글꼴을 주지 않으면 브라우저 기본 글꼴(대개 Times 같은 serif)로 그려진다. 앱 CSS에 한 줄을 둔다.
body { font-family: var(--werft-font-sans); }이렇게 두면 앱이 Geist·Pretendard를 로드하지 않아도 목록 끝의 시스템 폰트로 그려진다. 한글을 Pretendard로 보이려면 앱이 직접 로드한다. 이 저장소의 웹 콘솔은 pretendard 패키지의 dynamic subset을 쓴다.
npm install pretendardimport "pretendard/dist/web/variable/pretendardvariable-dynamic-subset.css";테마
라이트가 기본이다. 어두운 테마를 켜는 방법은 테마 적용과 같다.
가져올 수 있는 경로
| 경로 | 내용 |
|---|---|
@werft-ai/ui | 아래 두 층과 foundations(cn 등) 전부 |
@werft-ai/ui/primitives | Button, Card, Dialog, Tabs, Input, Skeleton 등 |
@werft-ai/ui/patterns | ConfirmDialog, EmptyState, ErrorState, PageHeader, Stepper 등 |
@werft-ai/ui/styles.css | 미리 빌드한 CSS. 보통 이것 하나만 import한다 |
@werft-ai/ui/theme.css | Tailwind v4 앱용 토큰 연결 |
@werft-ai/ui/tokens.css | --werft-* 변수만 |
다음 단계
- 테마 적용: 어두운 테마와 덮어쓰기 규칙