@nexus-cross/design-system 2.0.0-beta.1 → 2.0.1
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 +375 -0
- package/claude-rules/nexus/CLAUDE.md +68 -0
- package/cursor-rules/nexus-project-setup.mdc +50 -3
- package/cursor-rules/nexus-ui-api.mdc +374 -9
- package/dist/chunks/{chunk-2T7RUYEK.js → chunk-2BINGHGR.js} +11 -3
- package/dist/chunks/{chunk-QOREDNWO.mjs → chunk-53BHDUID.mjs} +2 -1
- package/dist/chunks/{chunk-QZ4QR3XV.mjs → chunk-ATZE57ZO.mjs} +11 -3
- package/dist/chunks/{chunk-OX5MEJ7B.js → chunk-HU6E2R2T.js} +2 -1
- package/dist/chunks/chunk-KT2WKVF7.mjs +5 -0
- package/dist/chunks/{chunk-5J63FUAS.mjs → chunk-LNC3TV6N.mjs} +53 -2
- package/dist/chunks/{chunk-NZHK76R3.js → chunk-LYPBQI3Y.js} +31 -6
- package/dist/chunks/chunk-MWWQMVXJ.js +7 -0
- package/dist/chunks/{chunk-BJM3NDT2.mjs → chunk-RL5UAEGQ.mjs} +11 -3
- package/dist/chunks/{chunk-LAGQ7J5A.js → chunk-VCN7DMCQ.js} +53 -2
- package/dist/chunks/{chunk-2ZXDXO4I.js → chunk-VDEB5BMT.js} +11 -3
- package/dist/chunks/{chunk-6BWOKTVQ.mjs → chunk-WZFKTTVX.mjs} +31 -6
- package/dist/components/ImageUpload.d.ts +14 -0
- package/dist/components/ImageUpload.d.ts.map +1 -1
- package/dist/components/NumberInput.d.ts +20 -1
- package/dist/components/NumberInput.d.ts.map +1 -1
- package/dist/components/NxImage.d.ts.map +1 -1
- package/dist/components/Select.d.ts +5 -1
- package/dist/components/Select.d.ts.map +1 -1
- package/dist/components/Tab.d.ts +12 -1
- package/dist/components/Tab.d.ts.map +1 -1
- package/dist/image-upload.js +3 -3
- package/dist/image-upload.mjs +1 -1
- package/dist/index.js +18 -18
- package/dist/index.mjs +5 -5
- package/dist/number-input.js +4 -4
- package/dist/number-input.mjs +1 -1
- package/dist/nx-image.js +2 -2
- package/dist/nx-image.mjs +1 -1
- package/dist/schemas/_all.json +48 -10
- package/dist/schemas/image-upload.d.ts +6 -0
- package/dist/schemas/image-upload.d.ts.map +1 -1
- package/dist/schemas/imageUpload.json +19 -1
- package/dist/schemas/number-input.d.ts +9 -3
- package/dist/schemas/number-input.d.ts.map +1 -1
- package/dist/schemas/numberInput.json +10 -3
- package/dist/schemas/spinner.json +2 -2
- package/dist/schemas/tab.d.ts +11 -0
- package/dist/schemas/tab.d.ts.map +1 -1
- package/dist/schemas/tab.json +17 -4
- package/dist/schemas.js +48 -10
- package/dist/schemas.mjs +48 -10
- package/dist/select.js +5 -5
- package/dist/select.mjs +1 -1
- package/dist/styles/.generated/built.d.ts +1 -1
- package/dist/styles/.generated/built.d.ts.map +1 -1
- package/dist/styles/layer.js +2 -2
- package/dist/styles/layer.mjs +1 -1
- package/dist/styles.css +185 -44
- package/dist/styles.js +2 -2
- package/dist/styles.layered.css +185 -44
- package/dist/styles.mjs +1 -1
- package/dist/tab.js +4 -4
- package/dist/tab.mjs +1 -1
- package/dist/tokens/TOKENS.md +13 -0
- package/dist/tokens/company.css +21 -1
- package/dist/tokens/css.css +21 -1
- package/dist/tokens/data/color.json +32 -0
- package/dist/tokens/data/space.json +1 -1
- package/dist/tokens/data/typography.json +55 -1
- package/dist/tokens-domains/data/gamehub/domain.json +258 -0
- package/dist/tokens-domains/data/index.ts +3 -1
- package/dist/tokens-domains/data/prediction/domain.json +0 -12
- package/dist/tokens-domains/gamehub.md +62 -0
- package/dist/tokens-domains/prediction-vars.css +1 -5
- package/dist/tokens-domains/prediction.css +1 -5
- package/dist/tokens-domains/prediction.md +0 -1
- package/package.json +3 -3
- package/dist/chunks/chunk-3SCSND6S.js +0 -7
- package/dist/chunks/chunk-QWK4CLS2.mjs +0 -5
package/README.md
ADDED
|
@@ -0,0 +1,375 @@
|
|
|
1
|
+
# @nexus-cross/design-system
|
|
2
|
+
|
|
3
|
+
NEXUS Design System — UI 컴포넌트 + 디자인 토큰을 한 패키지에 담은 통합 라이브러리.
|
|
4
|
+
|
|
5
|
+
[](https://www.npmjs.com/package/@nexus-cross/design-system)
|
|
6
|
+
[](#-라이선스)
|
|
7
|
+
|
|
8
|
+
- **45+ React 컴포넌트** — Button부터 DataGrid, DatePicker까지 프로덕션-레디
|
|
9
|
+
- **160+ 디자인 토큰** — `@nexus-cross/tokens`를 sub-path(`/tokens`)로 자동 노출
|
|
10
|
+
- **도메인 토큰** — `@nexus-cross/tokens-domains`도 sub-path(`/tokens-domains`)로 옵트인
|
|
11
|
+
- **Tailwind v4 / v3 / Pure CSS** — 모든 환경에서 검증 완료 (`test-apps/`)
|
|
12
|
+
- **AI 규칙 자동 셋업** — `nexus-ds-setup` CLI로 Cursor / Claude Code가 자동 인식
|
|
13
|
+
- **Sub-path 개별 임포트** — `@nexus-cross/design-system/button` 처럼 컴포넌트별 트리쉐이킹
|
|
14
|
+
|
|
15
|
+
> v2.0부터 `@nexus-cross/tokens`와 `@nexus-cross/tokens-domains`를 transitive dependency로 흡수했습니다. **이 패키지 1개만 install 하면 토큰까지 모두 사용할 수 있습니다.**
|
|
16
|
+
|
|
17
|
+
---
|
|
18
|
+
|
|
19
|
+
## 🚀 Quick Start
|
|
20
|
+
|
|
21
|
+
### 1. 설치
|
|
22
|
+
|
|
23
|
+
```bash
|
|
24
|
+
npm install @nexus-cross/design-system
|
|
25
|
+
# 또는: pnpm add / yarn add
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
postinstall에서 `nexus-ds-setup`이 자동 실행되어 Cursor/Claude Code 규칙 파일도 함께 셋업합니다.
|
|
29
|
+
|
|
30
|
+
### 2. CSS 한 줄 셋업 (Tailwind v4 기준)
|
|
31
|
+
|
|
32
|
+
```css
|
|
33
|
+
/* app/globals.css (Next.js) 또는 src/globals.css (Vite) */
|
|
34
|
+
@import 'tailwindcss';
|
|
35
|
+
@import '@nexus-cross/design-system/tailwind-v4.css';
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
이 한 줄 안에 다음이 모두 들어 있습니다:
|
|
39
|
+
- 회사 공통 디자인 토큰 (`/tokens/company.css`) 자동 로드
|
|
40
|
+
- 컴포넌트 CSS를 Tailwind `components` 레이어에 주입
|
|
41
|
+
- Cascade: `base < components(Nexus) < utilities` → `className="bg-red-500"` 같은 utility 오버라이드가 항상 우선
|
|
42
|
+
|
|
43
|
+
### 3. 컴포넌트 사용
|
|
44
|
+
|
|
45
|
+
```tsx
|
|
46
|
+
import { Button, TextInput } from '@nexus-cross/design-system'
|
|
47
|
+
|
|
48
|
+
export default function Hello() {
|
|
49
|
+
return (
|
|
50
|
+
<form className="flex flex-col gap-3 p-6">
|
|
51
|
+
<TextInput placeholder="이메일" />
|
|
52
|
+
<Button semantic="primary" variant="contained">시작하기</Button>
|
|
53
|
+
</form>
|
|
54
|
+
)
|
|
55
|
+
}
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
> Button API: `semantic` ∈ `primary | secondary | tertiary | danger | success | warning | info`,
|
|
59
|
+
> `variant` ∈ `contained | outlined | ghost | text | subtle`.
|
|
60
|
+
|
|
61
|
+
---
|
|
62
|
+
|
|
63
|
+
## 📦 환경별 셋업
|
|
64
|
+
|
|
65
|
+
> 모든 환경은 `test-apps/{tw4, vite-tw4, tw3, pure-css}`에서 Playwright + CDP로 검증됨.
|
|
66
|
+
|
|
67
|
+
### Next.js + Tailwind v4 (Turbopack / Webpack)
|
|
68
|
+
|
|
69
|
+
```css
|
|
70
|
+
/* app/globals.css */
|
|
71
|
+
@import 'tailwindcss';
|
|
72
|
+
@import '@nexus-cross/design-system/tailwind-v4.css';
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
```js
|
|
76
|
+
// next.config.mjs
|
|
77
|
+
const nextConfig = {
|
|
78
|
+
transpilePackages: ['@nexus-cross/design-system'],
|
|
79
|
+
}
|
|
80
|
+
export default nextConfig
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
> **레이어 순서를 직접 선언하지 마세요.** Tailwind v4의 CSS 프로세서는 사용자 영역에서 선언한 `@layer base, nexus, components, utilities;` 같은 statement를 자동 정리/제거합니다. `tailwind-v4.css` 프리셋이 Tailwind 빌트인 `components` 레이어를 활용하므로 별도 layer 선언이 필요 없습니다.
|
|
84
|
+
|
|
85
|
+
### Vite + Tailwind v4
|
|
86
|
+
|
|
87
|
+
```css
|
|
88
|
+
/* src/globals.css */
|
|
89
|
+
@import 'tailwindcss';
|
|
90
|
+
@import '@nexus-cross/design-system/tailwind-v4.css';
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
### Tailwind v3
|
|
94
|
+
|
|
95
|
+
```js
|
|
96
|
+
// tailwind.config.js
|
|
97
|
+
module.exports = {
|
|
98
|
+
presets: [require('@nexus-cross/design-system/tokens/tailwind')],
|
|
99
|
+
// 도메인 토큰 사용 시:
|
|
100
|
+
// presets: [require('@nexus-cross/design-system/tokens-domains/tailwind')],
|
|
101
|
+
content: ['./src/**/*.{js,ts,jsx,tsx}'],
|
|
102
|
+
}
|
|
103
|
+
```
|
|
104
|
+
|
|
105
|
+
```css
|
|
106
|
+
/* globals.css */
|
|
107
|
+
@import '@nexus-cross/design-system/tokens/css';
|
|
108
|
+
@import '@nexus-cross/design-system/styles.css';
|
|
109
|
+
|
|
110
|
+
@tailwind base;
|
|
111
|
+
@tailwind components;
|
|
112
|
+
@tailwind utilities;
|
|
113
|
+
```
|
|
114
|
+
|
|
115
|
+
### 순수 CSS / CSS Modules (Tailwind 미사용)
|
|
116
|
+
|
|
117
|
+
```css
|
|
118
|
+
@import '@nexus-cross/design-system/tokens/css';
|
|
119
|
+
/* 도메인 토큰까지: */
|
|
120
|
+
/* @import '@nexus-cross/design-system/tokens-domains/prediction-vars.css'; */
|
|
121
|
+
```
|
|
122
|
+
|
|
123
|
+
```tsx
|
|
124
|
+
// 앱 entry (main.tsx / _app.tsx)
|
|
125
|
+
import '@nexus-cross/design-system/styles'
|
|
126
|
+
```
|
|
127
|
+
|
|
128
|
+
### 도메인 토큰 추가
|
|
129
|
+
|
|
130
|
+
도메인(예: Prediction) 색을 함께 쓰고 싶다면 한 줄 추가:
|
|
131
|
+
|
|
132
|
+
```css
|
|
133
|
+
@import 'tailwindcss';
|
|
134
|
+
@import '@nexus-cross/design-system/tailwind-v4.css';
|
|
135
|
+
@import '@nexus-cross/design-system/tokens-domains/prediction.css';
|
|
136
|
+
```
|
|
137
|
+
|
|
138
|
+
---
|
|
139
|
+
|
|
140
|
+
## 🔔 전역 셋업: `<Toaster />` · `<ModalContainer />`
|
|
141
|
+
|
|
142
|
+
`Toaster` / `ModalContainer`는 내부적으로 `useState`를 쓰는 **클라이언트 컴포넌트**입니다. 환경에 맞춰 둘 중 한 패턴을 선택하세요.
|
|
143
|
+
|
|
144
|
+
### Pattern A — Next.js App Router (권장)
|
|
145
|
+
|
|
146
|
+
server `layout.tsx`에서 직접 import 하면 `useState only works in Client Components` 에러가 납니다. `"use client"` wrapper로 분리하세요.
|
|
147
|
+
|
|
148
|
+
```tsx
|
|
149
|
+
// app/providers.tsx
|
|
150
|
+
'use client'
|
|
151
|
+
|
|
152
|
+
import { Toaster } from '@nexus-cross/design-system'
|
|
153
|
+
import { ModalContainer } from '@nexus-cross/design-system/modal'
|
|
154
|
+
|
|
155
|
+
export function NexusProviders() {
|
|
156
|
+
return (
|
|
157
|
+
<>
|
|
158
|
+
<ModalContainer />
|
|
159
|
+
<Toaster position="top-right" />
|
|
160
|
+
</>
|
|
161
|
+
)
|
|
162
|
+
}
|
|
163
|
+
```
|
|
164
|
+
|
|
165
|
+
```tsx
|
|
166
|
+
// app/layout.tsx (server component — "use client" 추가 금지)
|
|
167
|
+
import { NexusProviders } from './providers'
|
|
168
|
+
import './globals.css'
|
|
169
|
+
|
|
170
|
+
export default function RootLayout({ children }: { children: React.ReactNode }) {
|
|
171
|
+
return (
|
|
172
|
+
<html lang="ko">
|
|
173
|
+
<body>
|
|
174
|
+
{children}
|
|
175
|
+
<NexusProviders />
|
|
176
|
+
</body>
|
|
177
|
+
</html>
|
|
178
|
+
)
|
|
179
|
+
}
|
|
180
|
+
```
|
|
181
|
+
|
|
182
|
+
### Pattern B — Vite / CRA / 이미 client인 root
|
|
183
|
+
|
|
184
|
+
```tsx
|
|
185
|
+
// App.tsx
|
|
186
|
+
import { Toaster } from '@nexus-cross/design-system'
|
|
187
|
+
import { ModalContainer } from '@nexus-cross/design-system/modal'
|
|
188
|
+
|
|
189
|
+
export default function App() {
|
|
190
|
+
return (
|
|
191
|
+
<>
|
|
192
|
+
{/* routes / pages */}
|
|
193
|
+
<ModalContainer />
|
|
194
|
+
<Toaster position="top-right" />
|
|
195
|
+
</>
|
|
196
|
+
)
|
|
197
|
+
}
|
|
198
|
+
```
|
|
199
|
+
|
|
200
|
+
> ⚠️ `Toaster` / `ModalContainer`는 앱 전체에 1개씩만 마운트하세요. 페이지 단위로 다시 마운트하면 toast/modal이 두 번 뜨는 현상이 생길 수 있습니다.
|
|
201
|
+
|
|
202
|
+
---
|
|
203
|
+
|
|
204
|
+
## 🎨 디자인 토큰 사용
|
|
205
|
+
|
|
206
|
+
토큰은 세 가지 방식으로 노출됩니다 — CSS 변수 / Tailwind 유틸리티 / JS API.
|
|
207
|
+
|
|
208
|
+
### CSS 변수
|
|
209
|
+
|
|
210
|
+
```css
|
|
211
|
+
.card {
|
|
212
|
+
background: var(--color-surface-default);
|
|
213
|
+
color: var(--color-text-primary);
|
|
214
|
+
padding: var(--space-4);
|
|
215
|
+
border: 1px solid var(--color-border-default);
|
|
216
|
+
border-radius: var(--radius-lg);
|
|
217
|
+
box-shadow: var(--shadow-sm);
|
|
218
|
+
}
|
|
219
|
+
```
|
|
220
|
+
|
|
221
|
+
### Tailwind 유틸리티
|
|
222
|
+
|
|
223
|
+
```tsx
|
|
224
|
+
<div className="bg-surface-default text-text-primary p-4 rounded-lg shadow-sm">
|
|
225
|
+
<h2 className="text-text-primary font-semibold">Hello</h2>
|
|
226
|
+
<p className="text-text-secondary mt-2">디자인 토큰으로 만든 카드</p>
|
|
227
|
+
</div>
|
|
228
|
+
```
|
|
229
|
+
|
|
230
|
+
semantic 토큰(`bg-bg-default`, `text-text-primary` 등)은 light/dark 모드별 값을 갖고 있어, 별도 분기 없이 자동 전환됩니다.
|
|
231
|
+
|
|
232
|
+
### JS API (sub-path)
|
|
233
|
+
|
|
234
|
+
```tsx
|
|
235
|
+
import { getTheme } from '@nexus-cross/design-system/tokens'
|
|
236
|
+
import { getPredictionTheme } from '@nexus-cross/design-system/tokens-domains'
|
|
237
|
+
|
|
238
|
+
const { semantic } = getTheme('dark')
|
|
239
|
+
// semantic.bg.default.base → "#1E232E"
|
|
240
|
+
|
|
241
|
+
const { domain } = getPredictionTheme('dark')
|
|
242
|
+
// domain['domain-market'].bullish.base
|
|
243
|
+
|
|
244
|
+
<MyChart
|
|
245
|
+
bg={semantic.bg.default.base}
|
|
246
|
+
series={[
|
|
247
|
+
domain['domain-market'].bullish.base,
|
|
248
|
+
domain['domain-market'].bearish.base,
|
|
249
|
+
]}
|
|
250
|
+
/>
|
|
251
|
+
```
|
|
252
|
+
|
|
253
|
+
---
|
|
254
|
+
|
|
255
|
+
## 🤖 AI 규칙 자동 셋업 — `nexus-ds-setup`
|
|
256
|
+
|
|
257
|
+
postinstall에서 자동 실행되며, 수동으로 다시 돌릴 수도 있습니다. 이미 같은 내용이 있으면 skip 합니다. 사용자의 `CLAUDE.md`는 절대 덮어쓰지 않고 마커 블록만 추가/갱신합니다.
|
|
258
|
+
|
|
259
|
+
```bash
|
|
260
|
+
npx nexus-ds-setup
|
|
261
|
+
```
|
|
262
|
+
|
|
263
|
+
| 위치 | 내용 |
|
|
264
|
+
|---|---|
|
|
265
|
+
| `.cursor/rules/nexus-project-setup.mdc` | 셋업 / 컴포넌트 매핑 / Figma 변환 룰 |
|
|
266
|
+
| `.cursor/rules/nexus-ui-components.mdc` | 컴포넌트 매핑 가이드 |
|
|
267
|
+
| `.cursor/rules/nexus-ui-api.mdc` | 컴포넌트 props 자동 생성 (44개) |
|
|
268
|
+
| `.cursor/rules/nexus-ui-decisions.mdc` | UI 결정 트리 |
|
|
269
|
+
| `.cursor/rules/nexus-tokens.mdc` | Company 토큰 레퍼런스 |
|
|
270
|
+
| `.cursor/rules/nexus-domains.mdc` | Domain 토큰 레퍼런스 (Prediction 등) |
|
|
271
|
+
| `.claude/nexus/CLAUDE.md` | Claude Code용 인덱스 (`@import` 모음) |
|
|
272
|
+
| `.claude/nexus/skills/nexus-design-system/SKILL.md` | 자연어 트리거 |
|
|
273
|
+
| `.claude/nexus/{ui-components,ui-api,ui-decisions,tokens,domains}.md` | mdc → md 변환본 |
|
|
274
|
+
| `.claude/commands/nexus-{audit,token-check,component-map}.md` | 슬래시 커맨드 |
|
|
275
|
+
| 루트 `DESIGN.md` | 디자인 시스템 핵심 결정 사항 |
|
|
276
|
+
| 루트 `CLAUDE.md` | nexus 마커 블록만 삽입/갱신 (사용자 내용 보존) |
|
|
277
|
+
|
|
278
|
+
설치 후엔 자연어로:
|
|
279
|
+
|
|
280
|
+
```text
|
|
281
|
+
"Nexus로 로그인 폼 만들어줘"
|
|
282
|
+
"이 hex(#FF6B6B)를 가장 가까운 Nexus 토큰으로 바꿔줘"
|
|
283
|
+
"이 Figma URL을 Nexus 컴포넌트로 변환해줘"
|
|
284
|
+
|
|
285
|
+
# 슬래시 커맨드
|
|
286
|
+
/nexus-audit # 토큰/컴포넌트 사용 감사
|
|
287
|
+
/nexus-token-check # 하드코딩된 색/스페이스 찾기
|
|
288
|
+
```
|
|
289
|
+
|
|
290
|
+
---
|
|
291
|
+
|
|
292
|
+
## 🧩 컴포넌트 카탈로그 (45+)
|
|
293
|
+
|
|
294
|
+
| 카테고리 | 컴포넌트 |
|
|
295
|
+
|---|---|
|
|
296
|
+
| **Form** | `Button` · `TextInput` · `TextArea` · `NumberInput` · `PriceInput` · `Select` · `Combobox` · `Switch` · `CheckBox` · `RadioGroup` · `Slider` · `ToggleGroup` · `TagInput` · `DatePicker` · `ImageUpload` |
|
|
297
|
+
| **Overlay / Container** | `Modal` · `Drawer` · `Tooltip` · `Popover` · `DropdownMenu` · `Accordion` · `Tab` · `Carousel` |
|
|
298
|
+
| **Feedback** | `Toast` · `Alert` · `Progress` · `Spinner` · `Skeleton` · `Countdown` · `Counter` · `Badge` · `Chip` |
|
|
299
|
+
| **Layout / Navigation** | `Divider` · `EmptyState` · `Stepper` · `Breadcrumb` · `Pagination` |
|
|
300
|
+
| **Data** | `Table` · `DataList` · `DataGrid` · `VirtualScroll` · `InfiniteScroll` · `Marquee` · `Ellipsis` |
|
|
301
|
+
| **Media / Utility** | `Avatar` · `NxImage` · `ClientOnly` · `ErrorBoundary` |
|
|
302
|
+
|
|
303
|
+
### Hooks
|
|
304
|
+
|
|
305
|
+
`useCheckDevice` · `useClickOutside` · `useModal` · `useInView`
|
|
306
|
+
|
|
307
|
+
### Utils
|
|
308
|
+
|
|
309
|
+
`cn` (class merger)
|
|
310
|
+
|
|
311
|
+
---
|
|
312
|
+
|
|
313
|
+
## 📁 Sub-path Imports (트리쉐이킹)
|
|
314
|
+
|
|
315
|
+
배포 사이즈에 민감한 환경에서는 컴포넌트별 sub-path로 직접 import 하세요. 의존하지 않는 컴포넌트는 번들에 포함되지 않습니다.
|
|
316
|
+
|
|
317
|
+
```tsx
|
|
318
|
+
import { Button } from '@nexus-cross/design-system/button'
|
|
319
|
+
import { TextInput } from '@nexus-cross/design-system/text-input'
|
|
320
|
+
import { useModal } from '@nexus-cross/design-system/hooks/useModal'
|
|
321
|
+
import { cn } from '@nexus-cross/design-system/utils/cn'
|
|
322
|
+
```
|
|
323
|
+
|
|
324
|
+
전체 export 경로:
|
|
325
|
+
|
|
326
|
+
| 카테고리 | 경로 |
|
|
327
|
+
|---|---|
|
|
328
|
+
| **Root API** | `@nexus-cross/design-system` |
|
|
329
|
+
| **Styles** | `/styles` · `/styles.css` · `/styles.layered.css` · `/tailwind-v4.css` · `/styles/layer` |
|
|
330
|
+
| **Tokens (sub-path)** | `/tokens` · `/tokens/data` · `/tokens/tailwind` · `/tokens/company.css` · `/tokens/css` |
|
|
331
|
+
| **Domain Tokens** | `/tokens-domains` · `/tokens-domains/data` · `/tokens-domains/tailwind` · `/tokens-domains/prediction.css` · `/tokens-domains/prediction-vars.css` |
|
|
332
|
+
| **Modal / Toast / Table** | `/modal` · `/toast` · `/table` |
|
|
333
|
+
| **Components** | `/button` · `/text-input` · `/text-area` · `/number-input` · `/price-input` · `/select` · `/combobox` · `/switch` · `/checkbox` · `/radio-group` · `/slider` · `/toggle-group` · `/tag-input` · `/date-picker` · `/avatar` · `/badge` · `/chip` · `/progress` · `/alert` · `/spinner` · `/skeleton` · `/countdown` · `/counter` · `/divider` · `/drawer` · `/tooltip` · `/popover` · `/dropdown-menu` · `/accordion` · `/tab` · `/carousel` · `/breadcrumb` · `/pagination` · `/stepper` · `/empty-state` · `/data-list` · `/data-grid` · `/virtual-scroll` · `/infinite-scroll` · `/marquee` · `/ellipsis` · `/nx-image` · `/client-only` · `/error-boundary` |
|
|
334
|
+
| **Hooks** | `/hooks/useCheckDevice` · `/hooks/useClickOutside` · `/hooks/useModal` · `/hooks/useInView` |
|
|
335
|
+
| **Utils / Schemas** | `/utils/cn` · `/schemas` |
|
|
336
|
+
|
|
337
|
+
---
|
|
338
|
+
|
|
339
|
+
## ⚙️ 컴포넌트 오버라이드
|
|
340
|
+
|
|
341
|
+
Nexus 컴포넌트 CSS는 Tailwind `components` 레이어에 들어가 있고, utility class는 그 다음 레이어에 위치합니다. 따라서 utility 오버라이드가 항상 우선합니다.
|
|
342
|
+
|
|
343
|
+
```tsx
|
|
344
|
+
<Button semantic="primary" className="rounded-full px-6">
|
|
345
|
+
알림 받기
|
|
346
|
+
</Button>
|
|
347
|
+
```
|
|
348
|
+
|
|
349
|
+
---
|
|
350
|
+
|
|
351
|
+
## 🔌 호환성
|
|
352
|
+
|
|
353
|
+
- **React** — `^18` / `^19`
|
|
354
|
+
- **TypeScript** — `^5` 권장
|
|
355
|
+
- **Node** — `>=18` (권장 `>=20`)
|
|
356
|
+
- **Tailwind** — v3 / v4 모두 지원, 없어도 사용 가능
|
|
357
|
+
|
|
358
|
+
> `react`와 `react-dom`은 peerDependency 입니다. 호스트 앱이 제공해야 합니다.
|
|
359
|
+
|
|
360
|
+
---
|
|
361
|
+
|
|
362
|
+
## 📚 더 알아보기
|
|
363
|
+
|
|
364
|
+
- [통합 사용 가이드](https://github.com/nexus-cross/nexus-design-system/blob/main/guides/GUIDE.md) — 환경별 가장 상세한 셋업
|
|
365
|
+
- [Designer 가이드](https://github.com/nexus-cross/nexus-design-system/blob/main/guides/DESIGNER.md) — 토큰 시각 편집 도구
|
|
366
|
+
- [파이프라인](https://github.com/nexus-cross/nexus-design-system/blob/main/guides/PIPELINE.md) — 디자이너 → PR → 빌드 → 배포
|
|
367
|
+
- [@nexus-cross/tokens](https://www.npmjs.com/package/@nexus-cross/tokens) — 토큰만 단독 사용
|
|
368
|
+
- [@nexus-cross/tokens-domains](https://www.npmjs.com/package/@nexus-cross/tokens-domains) — 도메인 토큰만 단독 사용
|
|
369
|
+
- [CHANGELOG](./CHANGELOG.md) — 버전 변경 이력
|
|
370
|
+
|
|
371
|
+
---
|
|
372
|
+
|
|
373
|
+
## 📝 라이선스
|
|
374
|
+
|
|
375
|
+
ISC
|
|
@@ -99,6 +99,74 @@ const nextConfig = {
|
|
|
99
99
|
|
|
100
100
|
---
|
|
101
101
|
|
|
102
|
+
## Global Setup — `<Toaster />` / `<ModalContainer />`
|
|
103
|
+
|
|
104
|
+
`Toaster` / `ModalContainer`는 내부적으로 `useState`를 사용하는 **클라이언트 컴포넌트**입니다.
|
|
105
|
+
|
|
106
|
+
| 환경 | 패턴 |
|
|
107
|
+
|---|---|
|
|
108
|
+
| Next.js App Router (root layout이 server component) | **반드시 `"use client"` wrapper로 분리** |
|
|
109
|
+
| Vite, CRA, Pages Router 등 root가 이미 client | 직접 import 가능 |
|
|
110
|
+
|
|
111
|
+
### Pattern A — Next.js App Router (권장)
|
|
112
|
+
|
|
113
|
+
```tsx
|
|
114
|
+
// app/providers.tsx
|
|
115
|
+
"use client";
|
|
116
|
+
|
|
117
|
+
import { Toaster } from '@nexus-cross/design-system';
|
|
118
|
+
import { ModalContainer } from '@nexus-cross/design-system/modal';
|
|
119
|
+
|
|
120
|
+
export function NexusProviders() {
|
|
121
|
+
return (
|
|
122
|
+
<>
|
|
123
|
+
<ModalContainer />
|
|
124
|
+
<Toaster position="top-right" />
|
|
125
|
+
</>
|
|
126
|
+
);
|
|
127
|
+
}
|
|
128
|
+
```
|
|
129
|
+
|
|
130
|
+
```tsx
|
|
131
|
+
// app/layout.tsx (server component — "use client" 추가 금지)
|
|
132
|
+
import { NexusProviders } from './providers';
|
|
133
|
+
import './globals.css';
|
|
134
|
+
|
|
135
|
+
export default function RootLayout({ children }: { children: React.ReactNode }) {
|
|
136
|
+
return (
|
|
137
|
+
<html lang="ko">
|
|
138
|
+
<body>
|
|
139
|
+
{children}
|
|
140
|
+
<NexusProviders />
|
|
141
|
+
</body>
|
|
142
|
+
</html>
|
|
143
|
+
);
|
|
144
|
+
}
|
|
145
|
+
```
|
|
146
|
+
|
|
147
|
+
> ❌ server `layout.tsx`에서 `Toaster` / `ModalContainer`를 직접 import하면
|
|
148
|
+
> `TypeError: useState only works in Client Components.` 에러 발생.
|
|
149
|
+
|
|
150
|
+
### Pattern B — Vite / CRA / 이미 client인 root
|
|
151
|
+
|
|
152
|
+
```tsx
|
|
153
|
+
// App.tsx
|
|
154
|
+
import { Toaster } from '@nexus-cross/design-system';
|
|
155
|
+
import { ModalContainer } from '@nexus-cross/design-system/modal';
|
|
156
|
+
|
|
157
|
+
export default function App() {
|
|
158
|
+
return (
|
|
159
|
+
<>
|
|
160
|
+
{/* routes / pages */}
|
|
161
|
+
<ModalContainer />
|
|
162
|
+
<Toaster position="top-right" />
|
|
163
|
+
</>
|
|
164
|
+
);
|
|
165
|
+
}
|
|
166
|
+
```
|
|
167
|
+
|
|
168
|
+
---
|
|
169
|
+
|
|
102
170
|
## Token Path Convention
|
|
103
171
|
|
|
104
172
|
모든 디자인 토큰은 5-segment 형식: `color.semantic.{namespace}.{slot}.{state}`
|
|
@@ -203,15 +203,62 @@ The following components MUST be placed at the app root (layout.tsx or App.tsx).
|
|
|
203
203
|
| `<ModalContainer />` | `@nexus-cross/design-system/modal` | Using `modal()` or `useModal()` | Modal rendering container |
|
|
204
204
|
| `<Toaster />` | `@nexus-cross/design-system` | Using `toast()` | Toast notification renderer |
|
|
205
205
|
|
|
206
|
+
> Both components use `useState` internally → they are **client components**.
|
|
207
|
+
> In environments where the root layout is a **server component** (e.g. Next.js App Router), import them through a `"use client"` wrapper as shown in **Pattern A**.
|
|
208
|
+
> If the root layout is already a client component (e.g. Vite, CRA, Pages Router with `"use client"` already declared), you can use them directly as in **Pattern B**.
|
|
209
|
+
|
|
210
|
+
### Pattern A — Next.js App Router / RSC (Recommended)
|
|
211
|
+
|
|
212
|
+
Server components cannot directly render client components that use hooks. Wrap providers in a single client file:
|
|
213
|
+
|
|
206
214
|
```tsx
|
|
207
|
-
//
|
|
215
|
+
// app/providers.tsx
|
|
216
|
+
"use client";
|
|
217
|
+
|
|
218
|
+
import { Toaster } from '@nexus-cross/design-system';
|
|
208
219
|
import { ModalContainer } from '@nexus-cross/design-system/modal';
|
|
220
|
+
|
|
221
|
+
export function NexusProviders() {
|
|
222
|
+
return (
|
|
223
|
+
<>
|
|
224
|
+
<ModalContainer />
|
|
225
|
+
<Toaster position="top-right" />
|
|
226
|
+
</>
|
|
227
|
+
);
|
|
228
|
+
}
|
|
229
|
+
```
|
|
230
|
+
|
|
231
|
+
```tsx
|
|
232
|
+
// app/layout.tsx (server component — DO NOT add "use client" here)
|
|
233
|
+
import { NexusProviders } from './providers';
|
|
234
|
+
import './globals.css';
|
|
235
|
+
|
|
236
|
+
export default function RootLayout({ children }: { children: React.ReactNode }) {
|
|
237
|
+
return (
|
|
238
|
+
<html lang="en">
|
|
239
|
+
<body>
|
|
240
|
+
{children}
|
|
241
|
+
<NexusProviders />
|
|
242
|
+
</body>
|
|
243
|
+
</html>
|
|
244
|
+
);
|
|
245
|
+
}
|
|
246
|
+
```
|
|
247
|
+
|
|
248
|
+
> ❌ Importing `Toaster` / `ModalContainer` directly inside a server `layout.tsx` throws:
|
|
249
|
+
> `TypeError: useState only works in Client Components.`
|
|
250
|
+
|
|
251
|
+
### Pattern B — Vite / CRA / Already-client roots
|
|
252
|
+
|
|
253
|
+
```tsx
|
|
254
|
+
// App.tsx (already a client component)
|
|
209
255
|
import { Toaster } from '@nexus-cross/design-system';
|
|
256
|
+
import { ModalContainer } from '@nexus-cross/design-system/modal';
|
|
210
257
|
|
|
211
|
-
export default function
|
|
258
|
+
export default function App() {
|
|
212
259
|
return (
|
|
213
260
|
<>
|
|
214
|
-
{
|
|
261
|
+
{/* ... your routes/pages ... */}
|
|
215
262
|
<ModalContainer />
|
|
216
263
|
<Toaster position="top-right" />
|
|
217
264
|
</>
|