@spectrabrain/eds 0.3.0 → 0.3.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.
@@ -1,19 +1,21 @@
1
1
  # EVA 프론트엔드 컨벤션
2
2
 
3
- EVA 서비스의 Vite + React 프론트엔드가 따르는 구조·라이브러리·코드 패턴·개발 규칙입니다. `eds align`은 프로토타입을 이 문서에 맞추는 일회성 계획(`.eds/align/PLAN.md`)을 만들고, `eds align --check`가 이 문서의 규칙 중 기계로 판정할 수 있는 부분을 점검합니다. EDS 컴포넌트와 token 규칙은 같은 package root의 `QUICKSTART.md`가 기준입니다.
3
+ EVA 서비스의 Vite + React 프론트엔드 규칙입니다. `eds align`은 이 문서를 기준으로 정렬 계획을 만들고, `eds align --check`는 자동 판정할 수 있는 항목을 점검합니다. EDS 컴포넌트와 token 사용은 package root의 `QUICKSTART.md`를 따릅니다.
4
4
 
5
- `.eds/align/PLAN.md`를 따르는 중이면 전체를 읽습니다. 그 밖에는 파일을 만들거나 옮길 때 「FSD 계층」, service·hook·store·component·page를 쓸 때 「코드 패턴」의 해당 절, 화면 문구를 쓸 때 「UI 문구」, 의존성을 추가하거나 바꿀 때 「라이브러리 스택」, 완료 전에 「점검」을 읽습니다.
5
+ 정렬 중에는 전체를 읽습니다. 평소에는 파일 위치를 바꿀 때 「FSD 계층」, service·hook·store·component·page 작업에는 「코드 패턴」, 의존성 변경에는 「라이브러리 스택」, 완료 전에는 「점검」을 읽습니다.
6
6
 
7
7
  ## 적용 범위
8
8
 
9
9
  - 대상은 Vite로 빌드하는 React 단일 페이지 앱의 프론트엔드입니다. Next.js·Remix 같은 framework와 React Native는 대상이 아닙니다.
10
- - 이 문서는 프론트엔드만 다루며 backend 코드, API 계약(요청 URL·method·header·payload, 응답 해석, 인증 흐름), 배포 설정, backend가 읽는 환경 변수 이름은 정하지 않습니다. 정렬 중 이들을 지키는 규칙은 `.eds/align/PLAN.md` 「보호 경로」에 있습니다.
11
- - 테스트 도구, 테스트 파일의 위치와 이름, 테스트 설정은 이 문서가 정하지 않습니다. 프로토타입마다 정책이 바뀔 수 있으므로 새로 쓰는 테스트는 저장소의 기존 방식을 따릅니다. `eds align`은 테스트 파일과 도구를 제자리에 두고, 소스를 옮겨 깨진 import 경로만 고치게 합니다.
10
+ - backend 코드·배포 설정·backend 환경 변수는 이 문서의 범위가 아닙니다. API 계약(요청 URL·method·header·payload, 응답 해석, 인증 흐름)은 수동 보존 기준이며, `eds align --check`는 frontend service의 요청·응답 의미를 검사하지 않습니다.
11
+ - 기존 테스트·mock·다국어 파일과 설정은 원래 위치와 내용대로 둡니다.
12
+ - 자동 감지되지 않는 경로만 `.eds/align/state.json`의 `preservedPaths`에 git 저장소 루트 기준으로 추가하고 `eds align`을 다시 실행합니다.
13
+ - `--check`는 기준선에 있던 보존 파일의 수정·삭제, tsconfig 파일 삭제, 각 설정 파일에서 기준선에 있던 `include`·`exclude`·`compilerOptions.types`·project references 항목의 누락을 `preserved:`로 보고합니다. 새 리소스 파일 추가는 오류가 아닙니다.
12
14
  - 사용자의 명시적 요청이 이 문서보다 우선합니다. 이 문서에 없는 결정은 가장 가까운 기존 코드를 따릅니다.
13
15
 
14
16
  ## 라이브러리 스택
15
17
 
16
- 범주마다 표준 하나를 씁니다. 교체 대상은 프로토타입에서 자주 보이는 예시이며, 전체 목록은 `eds align`이 감지합니다.
18
+ 범주별 표준과 교체 대상 예시입니다. `eds align`은 표보다 넓은 패키지 목록을 감지합니다.
17
19
 
18
20
  | 범주 | 표준 | 교체 대상 예시 | 적용 방법 |
19
21
  | --- | --- | --- | --- |
@@ -29,17 +31,18 @@ EVA 서비스의 Vite + React 프론트엔드가 따르는 구조·라이브러
29
31
  | toast | `sonner` | `react-toastify`, `react-hot-toast` | `app/App.tsx`에 `<Toaster position="top-right" richColors />`를 한 번 둡니다. |
30
32
  | date | `date-fns` | `moment`, `dayjs`, `luxon` | 달력 UI는 `react-day-picker`를 씁니다. |
31
33
  | virtual-list | `react-virtuoso` | `react-window`, `react-virtualized` | 긴 목록에만 씁니다. |
32
- | api-mock | `msw` + `@faker-js/faker` | `miragejs` | `src/mocks`에 domain별 handler를 둡니다. |
33
34
  | lint-format | ESLint 9 flat config + Prettier 3 | `@biomejs/biome`, `oxlint`, `.eslintrc*`(legacy 설정) | 설정은 「개발 규칙」을 따릅니다. |
34
- | build-plugin | `@vitejs/plugin-react` + React Compiler | `@vitejs/plugin-react-swc` | Vite 5–7은 `@vitejs/plugin-react`의 `babel` 옵션에 `babel-plugin-react-compiler`를 넣고, Vite 8 이상은 `@vitejs/plugin-react` 6이 export하는 `reactCompilerPreset()`을 `@rolldown/plugin-babel`의 `presets`로 실행합니다. Tailwind는 `@tailwindcss/vite`로 실행합니다. |
35
+ | build-plugin | `@vitejs/plugin-react` + React Compiler | `@vitejs/plugin-react-swc` | Vite 5.2–7은 `@vitejs/plugin-react@^4`의 `babel` 옵션에 `babel-plugin-react-compiler`를 넣거나 호환되는 `@vitejs/plugin-react@^5`를 씁니다. Vite 8은 `@vitejs/plugin-react@^6.0.1`이 export하는 `reactCompilerPreset()`을 `@rolldown/plugin-babel`의 `presets`로 실행합니다. Tailwind는 `@tailwindcss/vite`로 실행합니다. |
35
36
 
36
37
  - 버전 기준은 React 19입니다.
37
- - i18n 라이브러리는 당분간 새로 추가하지 않습니다. 저장소가 이미 쓰는 i18n 라이브러리와 문구 작성 규칙은 「UI 문구」를 따릅니다.
38
- - Supabase·Firebase·tRPC·GraphQL client·인증·결제 SDK처럼 backend 계약을 정하는 client SDK는 교체하지 않습니다. SDK client 생성과 설정은 `shared/api`에 한 번만 두고, entity service만 그 client를 import합니다. 데이터를 SDK로만 주고받고 `fetch()`·axios 호출이 없으면 axios는 쓰지 않습니다.
38
+ - `eds align`은 Vite 5.2.0–8.x를 지원하며, 선언 범위는 Vite 5.2.0 이상과 단일 major를 보장해야 합니다(예: `^5.2.0`, `^8.0.0`, `>=5.2.0 <6`). 상한이 없거나 여러 major 또는 Vite 9 이상을 허용하는 범위는 지원하지 않습니다. Vite 5.2·6·7의 `@vitejs/plugin-react` 4.x 최소 버전은 각각 4.2.1·4.4.0·4.7.0이며, 이 Vite 버전에서는 5.x도 허용합니다. Vite 8은 6.0.1 이상을 씁니다. Tailwind plugin 버전은 `TAILWIND_V4.md`를 따릅니다.
39
+ - Vite 8 React Compiler 설정은 `@rolldown/plugin-babel`을 사용하므로 Node 22.12.0 이상이 필요합니다.
40
+ - `eds align`은 실행 중인 Node 버전만 검사합니다. Vite 8 계획은 frontend package의 `engines.node` 설정을 안내하며, CI Node 버전은 별도로 맞춥니다. CI 파일이 frontend package 밖에 있으면 align 완료 후 갱신합니다.
41
+ - Supabase·Firebase·tRPC·GraphQL client·인증·결제 SDK는 교체하지 않습니다. SDK client는 `shared/api`에서 한 번 만들고 entity service만 import합니다. 데이터를 SDK로만 가져오면 axios를 추가하지 않습니다.
39
42
 
40
43
  ## FSD 계층
41
44
 
42
- `src/`는 Feature-Sliced Design 계층으로 나누고, 소스는 `.ts`·`.tsx`로 씁니다(테스트 파일 제외). import 방향은 「import」를 따릅니다.
45
+ `src/`는 Feature-Sliced Design 계층으로 나눕니다. 앱 소스는 `.ts`·`.tsx`로 쓰고 import 방향은 「import」를 따릅니다.
43
46
 
44
47
  ```text
45
48
  src/
@@ -49,7 +52,6 @@ src/
49
52
  ├─ features/ <domain>/<feature>/{ui,lib,types} 사용자 행동 · <domain>/{ui,lib,types} domain 안 여러 feature가 공유
50
53
  ├─ entities/ <domain>/{components,hooks,services,stores,types,lib} 도메인 데이터
51
54
  ├─ shared/ {api,assets,hooks,lib,ui} 도메인을 모르는 코드(api/index.ts · api/queryClient.ts · lib/utils/index.ts)
52
- ├─ mocks/ <domain>/index.ts · handlers.ts · browser.ts
53
55
  ├─ types/ 전역 선언 파일(`*.d.ts`)
54
56
  └─ styles/ eds-tokens.css(eds sync가 package root의 src/styles/에 생성합니다. 옮기거나 편집하지 않습니다)
55
57
  ```
@@ -111,12 +113,16 @@ import type { Account, AccountListResponse } from "../types/api";
111
113
 
112
114
  const accountService = {
113
115
  getAccounts: async (): Promise<AccountListResponse> => {
114
- const response = await axiosInstance.get<AccountListResponse>("/api/v1/users/");
116
+ const response = await axiosInstance.get<AccountListResponse>(
117
+ "/api/v1/users/"
118
+ );
115
119
  return response.data;
116
120
  },
117
121
 
118
122
  getAccount: async (userId: string): Promise<Account> => {
119
- const response = await axiosInstance.get<Account>(`/api/v1/users/${userId}`);
123
+ const response = await axiosInstance.get<Account>(
124
+ `/api/v1/users/${userId}`
125
+ );
120
126
  return response.data;
121
127
  },
122
128
 
@@ -172,8 +178,8 @@ export const useAuthStore = create<AuthState>()(
172
178
  {
173
179
  name: "auth-storage",
174
180
  partialize: (state) => ({ isAuthenticated: state.isAuthenticated }),
175
- },
176
- ),
181
+ }
182
+ )
177
183
  );
178
184
  ```
179
185
 
@@ -183,7 +189,6 @@ export const useAuthStore = create<AuthState>()(
183
189
 
184
190
  - 컴포넌트는 named export 함수이고 props는 `interface XxxProps`입니다. `className`은 `@/shared/lib/utils`의 `cn()`으로 합칩니다.
185
191
  - page는 `export default function XxxPage()`이며, widget·feature·entity 컴포넌트를 조합하기만 합니다. `app/router/index.tsx`가 `lazy(() => import("@/pages/<domain>/<action>/page"))`로 불러옵니다.
186
- - 화면에 보이거나 보조기술이 읽는 문자열은 「UI 문구」를 따릅니다. 주석은 한국어로 써도 됩니다.
187
192
  - 되돌리기 어려운 행동은 `shared/ui`의 alert-dialog로 확인받은 뒤 실행합니다.
188
193
 
189
194
  ```tsx
@@ -197,7 +202,9 @@ interface ConfirmDeleteAccountButtonProps {
197
202
  userId: string;
198
203
  }
199
204
 
200
- export function ConfirmDeleteAccountButton({ userId }: ConfirmDeleteAccountButtonProps) {
205
+ export function ConfirmDeleteAccountButton({
206
+ userId,
207
+ }: ConfirmDeleteAccountButtonProps) {
201
208
  const { mutate, isPending } = useDeleteAccount();
202
209
 
203
210
  return (
@@ -219,33 +226,21 @@ export function ConfirmDeleteAccountButton({ userId }: ConfirmDeleteAccountButto
219
226
  }
220
227
  ```
221
228
 
222
- ### UI 문구
223
-
224
- - 다국어 리소스(i18n)는 당분간 적용하지 않습니다. 화면에 보이거나 보조기술이 읽는 문자열(텍스트, `aria-label`, `alt`, `title`, `placeholder`)은 한국어로 컴포넌트에 직접 씁니다. 나중에 다국어 리소스로 옮기는 시점과 방식은 `미결`입니다.
225
- - 나중에 문구를 그대로 옮길 수 있도록 문장은 조각내어 `+`로 잇지 않고 한 문자열로 씁니다. 값이 들어가는 문장은 template literal 하나로 씁니다(예: `` `${count}개를 삭제했습니다` ``).
226
- - 문구는 컴포넌트와 feature의 UI 코드에 두고, service·store·query hook은 문구 대신 데이터와 오류 값을 돌려줍니다. 검증 함수는 표시할 오류 문구를 돌려줍니다.
227
- - 저장소가 이미 i18n 라이브러리를 쓰고 있으면 기존 설정·번역 파일·호출은 지우지 않고 그대로 둡니다. 새 문구는 이 절의 첫 항목대로 한국어로 직접 씁니다.
228
-
229
229
  ### 오류 처리
230
230
 
231
231
  - `app/router/index.tsx`는 route 전체를 `ErrorBoundary`(`app/providers`)로 감쌉니다.
232
232
  - `shared/api`의 axios interceptor는 401·403 응답을 `eventBus.emit("error", error)`로 알리고, `app/providers/ErrorHandler.tsx`가 toast와 session 정리를 처리합니다.
233
233
  - 사용자 행동의 실패는 그 행동을 처리한 feature가 `toast.error("…")`로 알립니다.
234
234
 
235
- ### API mock
236
-
237
- - REST API가 있으면 `src/mocks/<domain>/index.ts`가 `createMockXxx()` faker factory와 `<domain>Handlers`(`http.get`·`HttpResponse.json`)를 export하고, `src/mocks/handlers.ts`가 모두 모읍니다.
238
- - worker(`mockServiceWorker.js`)는 `msw init <Vite root>/public --save`(runner는 저장소 형식)로 Vite root의 `public/`에 만듭니다. `dev:mock` script(`.env.mock`의 `VITE_API_MOCKING=true`)에서만 `app/main.tsx`가 worker를 시작합니다.
239
-
240
235
  ## 개발 규칙
241
236
 
242
- 설정 값의 기준은 저장소의 설정 파일입니다. 정렬 전이면 `eds align`이 대상 저장소의 경로로 채워 `.eds/align/templates/`에 만든 템플릿이 기준입니다. `eds align --check`가 필수 script(`lint`·`format`·`format:check`·`typecheck`·`build`)와 `.prettierignore` 항목을 점검합니다. 다음은 설정 파일만 봐서는 알 수 없는 규칙입니다.
237
+ 저장소의 기존 설정을 유지합니다. 정렬에 필요한 템플릿은 `eds align`이 `.eds/align/templates/`에 만들고, `eds align --check`는 필수 script(`lint`·`format`·`format:check`·`typecheck`·`build`)와 `.prettierignore`를 확인합니다.
243
238
 
244
239
  - `.prettierignore`에 `src/styles/eds-tokens.css`(eds sync 생성물)와 backend 경로를 둡니다. 생성물을 포맷하면 `eds doctor`가 `stale:`로 보고합니다. backend 경로는 ESLint `globalIgnores`에도 둡니다.
245
240
  - React Compiler lint는 `eslint-plugin-react-hooks` 7 recommended로 대신하며 `eslint-plugin-react-compiler`는 설치하지 않습니다.
246
- - backend가 dev server나 build를 맡는 package는 `dev`·`build`의 기존 명령을 유지합니다. mock 실행은 `dev:mock`(`vite --mode mock`)입니다.
241
+ - backend가 dev server나 build를 맡는 package는 기존 `dev`·`build` 명령을 유지합니다.
247
242
  - EVA 기본값은 `strict: false`입니다. 저장소가 이미 더 엄격한 설정으로 typecheck를 통과하면 그 설정을 유지합니다.
248
- - Tailwind는 `@tailwindcss/vite`로 실행합니다(`@tailwindcss/postcss`는 import한 package CSS의 `url()`을 옮기지 않아 EDS font 파일이 번들에 들어가지 않습니다). 기존 `server.proxy`의 API target은 유지합니다.
243
+ - Vite에서는 `@tailwindcss/vite`를 씁니다. 기존 `server.proxy`의 API target은 유지합니다.
249
244
 
250
245
  ## 점검
251
246
 
package/QUICKSTART.md CHANGED
@@ -1,42 +1,33 @@
1
1
  # EDS QUICKSTART
2
2
 
3
- `@spectrabrain/eds` 소비처 AI가 UI 작업 전에 읽는 유일한 필수 문서입니다. 문서는 package root(`require.resolve("@spectrabrain/eds/package.json")`, 보통 `node_modules/@spectrabrain/eds`)에 있으며 설치 버전의 문서·타입을 따릅니다.
3
+ `@spectrabrain/eds` 소비처 AI가 UI 작업 전에 읽는 필수 문서입니다. package root는 `require.resolve("@spectrabrain/eds/package.json")`로 찾습니다(보통 `node_modules/@spectrabrain/eds`). 설치 버전의 문서·타입을 따릅니다.
4
+
5
+ ## 실행 전제
6
+
7
+ - EDS는 `Node.js >=18`과 `react >=18.2 <20` peer dependency를 요구합니다. 기존 React 웹 앱에 추가하며 앱 구성과 `react-dom` 등 렌더링 의존성은 소비처가 관리합니다.
8
+ - Tailwind CSS는 선택 사항입니다. Tailwind를 사용하지 않거나 v3를 쓰면 앱 진입점에서 `@spectrabrain/eds/styles.css`를 import하고 공개 CSS variable 또는 `cssVar()`를 사용합니다. 이때 `eds-*` Tailwind class는 쓰지 않습니다.
9
+ - `eds align`은 Vite + React 앱을 React 19·Tailwind CSS 4 기반의 EVA 프론트엔드 규칙으로 맞출 계획을 만드는 선택 기능이며, EDS 사용에는 필요하지 않습니다.
4
10
 
5
11
  ## 규칙
6
12
 
7
- 1. 사용자의 명시적 요청을 먼저 따르고, 요청 범위의 코드부터 적용합니다. 같은 역할의 EDS 컴포넌트(현재 `Button`)가 있으면 자체 구현이나 소비처 규칙이 지정한 로컬 컴포넌트보다 EDS를 먼저 선택하고, 소비처 규칙이 접근성·보안·제품 요구를 이유로 명시한 경우에만 그것을 우선합니다.
8
- 2. `Button`의 `role`(ARIA role이 아닌 시각 prop)과 `variant`는 행동의 의미로 고릅니다.
9
-
10
- | 행동 | 조합 |
11
- | --- | --- |
12
- | 화면의 핵심 행동(생성·저장·관리·확인) | `brand/solid` |
13
- | 일반 주요 행동(검색·조회) | `neutral/solid` |
14
- | 취소·닫기·수정 같은 보조 작업 | `neutral/outline` |
15
- | 초기화·갱신처럼 부담이 낮은 반복 행동 | `neutral/weak` |
16
- | 툴바·헤더·메뉴의 보조 행동 | `neutral/ghost` |
17
- | 되돌리기 어려운 삭제·초기화 | `critical/weak` |
18
- | 페이지·콘텐츠로 이동 | `neutral/link`(`href` 필수) |
19
- | 비동기 처리 중 | 선택한 조합에 `loading` |
20
-
21
- 3. 화면 요구를 `AI_CONTEXT.json.components` → component `README.md` → `spec.json` → TypeScript contract 순으로 대조합니다. 필요한 prop·variant·state·slot까지 모두 맞으면 EDS component로 판정하고, 목록에 없거나 contract가 맞지 않으면 소비처 로컬 UI로 분기합니다.
22
- 4. 색상·typography·spacing·radius는 공개 token으로 지정합니다. Tailwind는 `text-eds-fg-*`, `bg-eds-bg-*`, `border-eds-stroke-*`, `p-eds-spacing-0-5`, `rounded-eds-radius-1`, 그 밖은 `var(--eds-color-*)`·`var(--eds-typography-*)` 또는 `cssVar("spacing-0.5")`처럼 씁니다.
23
- 5. raw 색상·typography 값, 공개 token이 아닌 CSS variable(내부 `--eds-button-*` 포함), 패키지 비공개 경로는 쓰지 않습니다. EDS component의 `className`은 바깥 배치에만 씁니다.
24
- 6. Tailwind를 쓰는 저장소에서는 EDS 밖 요소도 `className`으로 쓰고, `index.css` 같은 전역 CSS에 컴포넌트별 규칙을 추가하지 않습니다.
13
+ 1. 사용자의 명시적 요청에 따르고 접근성·보안·framework 제약을 지킵니다. 그 안에서 문서화된 소비처 제품 요구를 우선합니다. 이를 충족하는 같은 역할의 EDS component(현재 `Button`)가 있고 공개 contract도 맞으면 쓰고, 아니면 소비처 로컬 UI를 씁니다.
14
+ 2. `AI_CONTEXT.json.components`의 후보를 확인하고, 요청에 맞는지 판단하기 전에 component `README.md`의 사용 맥락·선택 기준을 읽습니다. 필요한 prop·variant·state·slot이 README와 TypeScript contract에 모두 맞아야 합니다. 후보가 없거나 맞지 않으면 로컬 UI를 쓰고, `spec.json`은 아이콘 이름이나 기계 판독 계약 확인에만 씁니다.
15
+ 3. 색상·typography·spacing·radius는 공개 token으로 지정합니다. EDS와 sync한 Tailwind CSS v4 root에서는 `text-eds-fg-*`·`bg-eds-bg-*`·`border-eds-stroke-*`·`p-eds-spacing-0-5`·`rounded-eds-radius-1` 등 EDS class를 쓰고, 그 밖에는 `var(--eds-color-*)`·`var(--eds-typography-*)` 또는 `cssVar("spacing-0.5")`를 씁니다.
16
+ 4. raw 색상·typography 값, 비공개 CSS variable, 패키지 비공개 경로는 쓰지 않습니다. EDS component의 `className`은 바깥 배치에만 씁니다.
17
+ 5. Tailwind를 쓰는 저장소에서는 EDS 밖 요소도 `className`으로 쓰고, `index.css` 같은 전역 CSS에 컴포넌트별 규칙을 추가하지 않습니다.
18
+
19
+ 새 UI의 미결 선택은 사용자에게 묻습니다. 기존 UI는 명시한 변경만 적용하고 나머지 동작을 유지합니다.
25
20
 
26
21
  ## 완료 기준
27
22
 
28
- 1. `npm run eds:doctor`가 `[EDS] synced with` 줄을 출력합니다. 실패하면 `scripts:` → `npm run sync:eds` → 나머지 순서로, 각 줄의 조치(`unknown:` 포함)와 `CONSUMER_AGENT.md` 「`eds:doctor` 점검」 표대로 고칩니다.
29
- 2. 소비처 `typecheck`·`build` script가 exit 0이고, Tailwind 저장소는 `npm run eds:doctor -- --scan`의 `raw:`에 바꾼 파일이 없습니다.
30
- 3. 완료 보고에 변경 파일, 사용한 EDS component·token, typecheck·build·doctor 결과를 적습니다.
23
+ 1. `npm run eds:doctor`가 `[EDS] synced with`를 출력해야 합니다. 실패하면 각 줄의 조치(`unknown:` 포함)를 따라 `scripts:` → sync → 나머지 순서로 고칩니다. 자세한 절차는 `CONSUMER_AGENT.md`의 doctor 표를 따릅니다.
24
+ 2. 있는 `typecheck`·`build` script는 exit 0이어야 합니다. 없는 script는 추가하지 말고 기존 검증 명령을 씁니다. EDS와 sync한 Tailwind CSS v4 root가 있을 때는 `npm run eds:doctor -- --scan`의 `raw:`에 바꾼 파일이 없어야 합니다.
25
+ 3. 완료 보고에 변경 파일, EDS component·token, typecheck·build·doctor 결과를 적습니다. script가 없으면 그렇게 밝힙니다.
31
26
 
32
27
  ## 명령
33
28
 
34
- `npm run eds:doctor`는 읽기 전용 점검, `npm run sync:eds`는 생성 CSS·managed block 갱신, `npx @spectrabrain/eds init`은 script·hook 등록과 첫 sync입니다. runner는 소비처 형식으로 바꿉니다(`pnpm`·`yarn`·`bun run`, init은 `pnpm exec eds init`·`yarn eds init`·`bunx @spectrabrain/eds init`).
29
+ `npm run eds:doctor`는 읽기 전용 점검입니다. `npm run sync:eds`는 `AGENTS.md` managed block을 갱신하며, Tailwind CSS v4 root가 있으면 생성 CSS와 token alias도 갱신합니다. `npx @spectrabrain/eds init`은 기본 script 등록을 시도합니다. `typecheck`·`build` script가 있고 대응 hook이 없으면 `eds doctor` hook을 추가하며, 첫 sync도 실행합니다. runner는 소비처 형식으로 바꿉니다(`pnpm`·`yarn`·`bun run`, init은 `pnpm exec eds init`·`yarn eds init`·`bunx @spectrabrain/eds init`).
35
30
 
36
31
  ## 더 읽을 문서
37
32
 
38
- - `CONSUMER_AGENT.md`: `AGENTS.md`에 `<!-- EDS:BEGIN -->`이 없으면 「첫 setup 절차」, doctor·sync가 exit 2이면 「`eds:doctor` 점검」, EDS 버전을 올렸으면 「버전 업데이트」, 프로토타입 정리를 요청받으면 「프로토타입 정렬」을 읽습니다.
39
- - `TOKEN_CONTEXT.md`: EDS 컴포넌트 prop 밖에서 color·typography·spacing·radius token을 지정하거나 바꿀 때 읽습니다.
40
- - `TAILWIND_V4.md`: Tailwind CSS v4 adapter나 root CSS 배선을 설정하거나 고칠 때 읽습니다.
41
- - `AI.md`: dark theme이나 목록 밖 컴포넌트·Tailwind utility가 필요할 때 읽습니다.
42
- - `dist/components/Button/README.md`: Button을 쓸 때 읽습니다. 이름으로 쓰는 아이콘 목록은 같은 폴더 `spec.json`의 `api.iconNames`입니다.
33
+ 조건별 문서와 읽을 시점은 `AI_CONTEXT.json`의 `readOrder`를 따릅니다.
package/README.md CHANGED
@@ -4,25 +4,27 @@ EVA 서비스의 일관된 UI/UX를 위한 React 웹 디자인 시스템입니
4
4
 
5
5
  ## 설치
6
6
 
7
+ `@spectrabrain/eds`는 `Node.js >=18`과 `react >=18.2 <20` peer dependency를 사용하는 기존 React 웹 앱용입니다. 새 React 앱은 만들지 않으며 Tailwind CSS는 선택 사항입니다. 소비처 AI의 설치·사용 규칙은 [QUICKSTART.md](QUICKSTART.md)를 따릅니다.
8
+
7
9
  ~~~sh
8
10
  npm install @spectrabrain/eds
9
11
  npx @spectrabrain/eds init
10
12
  ~~~
11
13
 
12
- `init`은 소비처 `package.json`에 `sync:eds`·`eds:doctor` script와 doctor hook을 등록하고 첫 동기화를 실행합니다. EDS를 업데이트한 뒤에는 `npm run sync:eds`로 Tailwind root CSS의 EDS import, Tailwind token alias, `AGENTS.md` managed block을 갱신하고, `npm run eds:doctor`로 동기화 상태를 읽기 전용으로 점검합니다. pnpm·yarn·bun의 명령과 동작은 [CONSUMER_AGENT.md](CONSUMER_AGENT.md) 「첫 setup 절차」에 있습니다. `npx`로 실행할 때는 항상 `@spectrabrain/eds`를 적습니다. npm registry의 `eds`는 다른 패키지입니다.
14
+ `init`은 소비처 `package.json`에 `sync:eds`·`eds:doctor` 기본 script 등록을 시도합니다. `typecheck`·`build` script가 있으면 대응하는 doctor hook도 기존 hook이 없을 때만 등록한 뒤 첫 sync를 실행합니다. EDS를 업데이트한 뒤 `npm run sync:eds`로 `AGENTS.md` managed block을 갱신하고, Tailwind CSS v4 root가 있으면 CSS import·token alias도 갱신합니다. `npm run eds:doctor`로 동기화 상태를 확인합니다. pnpm·yarn·bun의 명령은 [CONSUMER_AGENT.md](CONSUMER_AGENT.md) 「첫 setup 절차」를 따릅니다. `npx`에는 항상 `@spectrabrain/eds`를 적습니다. npm의 unscoped `eds`는 다른 패키지입니다.
13
15
 
14
16
  소비처 AI와 자동화 도구는 UI 작업 전에 [QUICKSTART.md](QUICKSTART.md)를 읽습니다. 나머지 문서는 [AI_CONTEXT.json](AI_CONTEXT.json)의 조건에 해당할 때만 읽습니다.
15
17
 
16
- 첫 sync 전에는 소비처 `AGENTS.md`에 EDS managed block이 없습니다. 이 기간에 AI가 설치된 계약을 먼저 읽게 하려면 `CLAUDE.md` 또는 `AGENTS.md` 상단에 다음 한 줄을 넣습니다. pnpm·yarn·bun 저장소에서는 `npm run`을 그 runner로 바꿉니다. sync가 block을 넣은 뒤에는 이 줄을 지웁니다.
18
+ 첫 sync 전에 AI가 `QUICKSTART.md`를 읽게 하려면 사용하는 도구가 읽는 루트 지시 파일에 다음 한 줄을 임시로 넣습니다(Codex는 `AGENTS.md`, Claude Code는 `CLAUDE.md`, Gemini CLI는 `GEMINI.md`). sync가 managed block을 추가하면 임시 줄을 지웁니다. pnpm·yarn·bun에서는 `npm run`을 해당 runner로 바꿉니다.
17
19
 
18
- > package.json에 `@spectrabrain/eds`가 있으면 UI 작업 전에 `node_modules/@spectrabrain/eds/QUICKSTART.md`를 먼저 읽고 그 규칙과 완료 기준을 따릅니다.
20
+ > package.json에 `@spectrabrain/eds`가 있으면 UI 작업 전에 EDS package root의 `QUICKSTART.md`를 읽고 규칙과 완료 기준을 따릅니다. package root는 `require.resolve("@spectrabrain/eds/package.json")`로 찾습니다.
19
21
 
20
22
  `@spectrabrain/eds/styles.css`는 Pretendard font, semantic CSS custom property, `html` 기본 font family, Button CSS를 함께 불러옵니다. 개별 파일(`@spectrabrain/eds/tokens.css`, `@spectrabrain/eds/components.css`, `@spectrabrain/eds/fonts.css`, 선택 파일 `@spectrabrain/eds/base.css`)의 구성 규칙은 [CONSUMER_AGENT.md](CONSUMER_AGENT.md) 「font 정책」에 있습니다.
21
23
 
22
24
  ## 현재 제공 범위
23
25
 
24
26
  - foreground, background, stroke 역할의 semantic color token을 제공합니다.
25
- - 소비처 로컬 UI에서도 사용할 수 있는 spacing·radius semantic scale을 제공합니다. public 이름의 소수점은 유지하며 Tailwind에서는 CSS-safe alias로 연결합니다.
27
+ - 소비처 로컬 UI에서도 사용할 수 있는 spacing·radius semantic scale을 제공합니다. public 이름의 소수점은 유지하며 Tailwind CSS v4에서는 CSS-safe alias를 제공합니다.
26
28
  - Display, Heading, Title, Body, Caption semantic text style을 제공합니다. 각 style은 font family, weight, size, line height, letter spacing token으로 구성합니다.
27
29
  - `styles.css`에서 사용할 수 있는 Pretendard Variable v1.3.9 webfont를 제공합니다.
28
30
  - 자동완성을 지원하는 TypeScript token API와 CSS custom property를 제공합니다.
@@ -61,7 +63,7 @@ const token: SemanticTokenName = "color-fg-brand-contrast";
61
63
  const color = cssVar(token); // var(--eds-color-fg-brand-contrast)
62
64
  ~~~
63
65
 
64
- `spacing-0.5`처럼 소수점이 있는 public 이름은 `cssVar("spacing-0.5")`로 전달합니다. 반환되는 CSS reference는 `var(--eds-spacing-0\.5)`처럼 점을 escape합니다. Tailwind에서는 `p-eds-spacing-0-5`, `rounded-eds-radius-1` 같은 CSS-safe alias를 사용합니다.
66
+ `spacing-0.5`처럼 소수점이 있는 public 이름은 `cssVar("spacing-0.5")`로 전달합니다. 반환되는 CSS reference는 `var(--eds-spacing-0\.5)`처럼 점을 escape합니다. Tailwind CSS v4에서는 `p-eds-spacing-0-5`, `rounded-eds-radius-1` 같은 CSS-safe alias를 사용합니다.
65
67
 
66
68
  TypeScript의 `moduleResolution`이 `node`(node10), `node16` 또는 `bundler`인 소비처에서도 `@spectrabrain/eds/tokens`의 타입을 사용할 수 있습니다.
67
69
 
@@ -71,7 +73,7 @@ TypeScript의 `moduleResolution`이 `node`(node10), `node16` 또는 `bundler`인
71
73
 
72
74
  ## Tailwind CSS v4에서 token 사용
73
75
 
74
- EDS는 Tailwind utility API를 패키지에 포함하지 않습니다. Tailwind CSS v4 저장소에서는 `npm run sync:eds`가 `tokens.json`에서 `src/styles/eds-tokens.css`를 생성해 `@import "tailwindcss"`가 있는 Tailwind root CSS에 연결하며, `text-eds-fg-*`, `bg-eds-bg-*`, `border-eds-stroke-*`, `eds-typography-*`, `p-eds-spacing-0-5`, `rounded-eds-radius-1` class를 사용할 수 있습니다. 생성된 `@theme inline`에는 `--font-sans: var(--eds-typography-body1-fontFamily);`도 들어가므로 Tailwind의 기본 sans font가 Pretendard가 됩니다. 설정 방법은 [Tailwind CSS v4 token 설정 가이드](./TAILWIND_V4.md)를 확인합니다.
76
+ EDS는 Tailwind preset·plugin을 제공하지 않습니다. Tailwind CSS v4 저장소에서는 `npm run sync:eds`가 `tokens.json`에서 `src/styles/eds-tokens.css`를 생성해 `@import "tailwindcss"`가 있는 Tailwind root CSS에 연결합니다. 이 파일에서 `text-eds-fg-*`, `bg-eds-bg-*`, `border-eds-stroke-*`, `eds-typography-*`, `p-eds-spacing-0-5`, `rounded-eds-radius-1` class를 사용할 수 있습니다. 일반 Tailwind utility는 소비처 설정에 따라 함께 쓸 수 있습니다. 생성된 `@theme inline`에는 `--font-sans: var(--eds-typography-body1-fontFamily);`도 들어가므로 Tailwind의 기본 sans font가 Pretendard가 됩니다. 설정 방법은 [Tailwind CSS v4 token 설정 가이드](./TAILWIND_V4.md)를 확인합니다.
75
77
 
76
78
  ## Text style 사용
77
79
 
@@ -87,11 +89,11 @@ EDS는 Tailwind utility API를 패키지에 포함하지 않습니다. Tailwind
87
89
  }
88
90
  ~~~
89
91
 
90
- `styles.css`는 `fonts.css`, `tokens.css`, `base.css`, `components.css`를 순서대로 import하며 Pretendard Variable font에 `font-display: swap`을 사용합니다. `base.css`와 소비처 `html` font-family 선언의 우선순위는 [CONSUMER_AGENT.md](CONSUMER_AGENT.md) 「font 정책」에 있습니다. font의 license와 저작권 고지는 패키지의 [NOTICE](./NOTICE)에서 확인합니다.
92
+ `styles.css`는 `fonts.css`, `tokens.css`, `base.css`, `components.css`를 순서대로 불러옵니다. 개별 CSS 구성과 `base.css`의 우선순위는 [CONSUMER_AGENT.md](CONSUMER_AGENT.md) 「font 정책」을 따릅니다. font license와 저작권 고지는 [NOTICE](./NOTICE)에 있습니다.
91
93
 
92
94
  ## 프로토타입 정렬
93
95
 
94
- AI 바이브코딩으로 만든 Vite + React 프로토타입은 EDS를 설치한 frontend package에서 `npx @spectrabrain/eds align`을 한 번 실행해 [EVA 프론트엔드 컨벤션](./FRONTEND_CONVENTIONS.md)에 맞춥니다. 이 명령은 소스를 바꾸지 않고 `.eds/align/`에 AI 에이전트가 따를 단계(`PLAN.md`)와 이 저장소의 경로로 채운 설정 템플릿을 만듭니다. `npx @spectrabrain/eds align --check`가 컨벤션과 보호 경로를 점검합니다. 동작과 exit code는 [CONSUMER_AGENT.md](./CONSUMER_AGENT.md) 「프로토타입 정렬」에 있습니다.
96
+ 사용자가 Vite + React 프로토타입을 EVA 프론트엔드 구조로 정리해 달라고 요청하면, EDS가 설치된 frontend package에서 `npx @spectrabrain/eds align`을 실행합니다. 이 명령은 소스를 바꾸지 않고 `.eds/align/`에 작업 계획과 설정 템플릿을 씁니다. 사용법·보존 규칙·exit code는 [CONSUMER_AGENT.md](./CONSUMER_AGENT.md) 「프로토타입 정렬」에 있습니다.
95
97
 
96
98
  ## 공개 경로
97
99
 
@@ -113,7 +115,7 @@ AI 바이브코딩으로 만든 Vite + React 프로토타입은 EDS를 설치한
113
115
  | `@spectrabrain/eds/TOKEN_CONTEXT.md` | semantic token의 역할과 화면 맥락입니다. |
114
116
  | `@spectrabrain/eds/TAILWIND_V4.md` | Tailwind CSS v4에서 공개 token을 연결하는 설치 가이드입니다. |
115
117
  | `@spectrabrain/eds/FRONTEND_CONVENTIONS.md` | EVA 프론트엔드의 구조·라이브러리·코드 패턴·개발 규칙입니다. `eds align`의 기준입니다. |
116
- | `eds` CLI (`npx @spectrabrain/eds init`) | 소비처 setup CLI입니다. `init`은 script 등록과 첫 동기화, `npm run sync:eds`는 동기화, `npm run eds:doctor`는 동기화 상태·font import·`eds-*` class 이름의 읽기 전용 점검, `npx @spectrabrain/eds align`은 프로토타입 정렬 계획과 점검을 실행합니다. 모듈로 import하지 않습니다. |
118
+ | `eds` CLI (`npx @spectrabrain/eds init`) | 소비처 setup CLI입니다. `init`은 기본 script 등록을 시도하고 첫 동기화를 실행합니다. `npm run sync:eds`는 동기화합니다. `npm run eds:doctor`는 동기화 상태와 font import를 읽기 전용 점검하고, Tailwind CSS v4 root가 있으면 `eds-*` class 이름도 확인합니다. `npx @spectrabrain/eds align`은 프로토타입 정렬 계획과 점검을 실행합니다. 모듈로 import하지 않습니다. |
117
119
  | `@spectrabrain/eds/components/Button/README.md` | Button 개요·사용 맥락·공개 API 문서입니다. |
118
120
  | `@spectrabrain/eds/components/Button/spec.json` | Button 공개 API와 접근성 계약을 위한 manifest입니다. |
119
121
  | `@spectrabrain/eds/llms.txt` | AI 문서 읽기 순서입니다. |
package/TAILWIND_V4.md CHANGED
@@ -9,7 +9,7 @@ CSS 진입점은 `@spectrabrain/eds/styles.css` 하나를 권장합니다. 개
9
9
  ## 설정 순서
10
10
 
11
11
  1. 「adapter 선택」 표에서 저장소에 맞는 행 하나를 골라 설치하고 연결합니다.
12
- 2. 앱의 전역 CSS 파일 하나에 `@import "tailwindcss";`를 둡니다. 이 파일이 Tailwind root이며, 이미 있으면 새로 만들지 않습니다.
12
+ 2. 기존 앱 전역 CSS를 Tailwind root로 씁니다. 전체 import 구성은 `@import "tailwindcss";`를, 분할 구성은 `@import "tailwindcss/theme.css";`와 `@import "tailwindcss/utilities.css";`를 같은 파일에 둡니다.
13
13
  3. `npm run sync:eds`를 실행합니다. script가 없으면 `npx @spectrabrain/eds init`을 실행합니다(패키지 매니저별 명령은 `CONSUMER_AGENT.md` 「첫 setup 절차」). init을 2단계보다 먼저 실행했다면 2단계 뒤에 sync를 다시 실행합니다.
14
14
  4. 「완료 기준」을 확인합니다.
15
15
 
@@ -24,6 +24,8 @@ CSS가 `@tailwind` 지시어를 쓰는 Tailwind CSS v3 저장소는 이 절차
24
24
  | `vite.config.*`가 있음 | `npm install -D tailwindcss @tailwindcss/vite` | `vite.config`의 `plugins`에 `tailwindcss()`를 추가합니다. `postcss.config.*`에 `@tailwindcss/postcss` 항목이 있으면 그 항목과 devDependency를 지웁니다. |
25
25
  | `vite.config.*` 없이 PostCSS를 씀 | `npm install -D tailwindcss @tailwindcss/postcss postcss` | PostCSS 설정의 `plugins`에 `"@tailwindcss/postcss": {}`를 추가합니다. |
26
26
 
27
+ Vite adapter는 Vite 5.2.0 이상이 필요합니다. `eds align`은 Vite 5.2.0–8.x를 지원합니다. Vite 7에서는 `@tailwindcss/vite` 4.2.0 이상, Vite 8에서는 4.3.2 이상을 설치합니다.
28
+
27
29
  Vite에서 `@tailwindcss/postcss`로 빌드하면 import한 EDS CSS의 상대 `url()`이 옮겨지지 않아 `fonts.css`의 Pretendard 파일이 번들에 들어가지 않습니다. 기존 framework plugin과 Tailwind 외 PostCSS plugin은 유지합니다.
28
30
 
29
31
  ```ts
@@ -86,7 +88,7 @@ sync는 설치된 package의 공개 `@spectrabrain/eds/tokens.json`에서 token
86
88
 
87
89
  ## Tailwind root 지정
88
90
 
89
- `eds sync`와 `eds doctor`는 `@import "tailwindcss"`가 있는 CSS 파일 하나를 Tailwind root로 찾습니다. 후보가 둘 이상이면 둘 다 exit 2로 멈추며, 사용자에게 root를 확인하는 절차는 `CONSUMER_AGENT.md` 「Tailwind root 결정」을 따릅니다. 확인한 root는 다음처럼 한 번 지정하고, sync가 그 경로를 소비처 `package.json`의 `eds.tailwindRoot`에 기록합니다.
91
+ Tailwind root의 자동 감지와 후보 처리 기준은 `CONSUMER_AGENT.md` 「Tailwind root 결정」을 따릅니다. 자동 감지가 어렵거나 후보가 여러 개면 다음처럼 경로를 지정합니다. sync는 이 값을 소비처 `package.json`의 `eds.tailwindRoot`에 기록합니다.
90
92
 
91
93
  ```sh
92
94
  EDS_TAILWIND_ROOT=src/app/styles/index.css npm run sync:eds
package/TOKEN_CONTEXT.md CHANGED
@@ -1,16 +1,16 @@
1
1
  # EVA semantic token 사용 맥락
2
2
 
3
- 이 문서는 `@spectrabrain/eds`의 공개 semantic token을 화면 맥락에 맞춰 고르는 방법을 안내합니다. 필수 규칙은 package root의 `QUICKSTART.md`에 있습니다. class 이름은 `src/styles/eds-tokens.css`에, CSS variable과 `cssVar()`에 쓰는 token 이름은 설치된 버전의 `@spectrabrain/eds/tokens`(`SemanticTokenName`)와 `dist/tokens.json`에 있습니다.
3
+ 이 문서는 `@spectrabrain/eds`의 공개 semantic token을 화면 맥락에 맞춰 고르는 방법을 안내합니다. 필수 규칙은 package root의 `QUICKSTART.md`에 있습니다. Tailwind CSS v4 root를 EDS와 sync한 경우 class 이름은 소비처의 `src/styles/eds-tokens.css`에 있습니다. CSS variable과 `cssVar()`에 쓰는 token 이름은 설치된 버전의 `@spectrabrain/eds/tokens`(`SemanticTokenName`)와 `dist/tokens.json`에 있습니다.
4
4
 
5
5
  ## 색상 역할
6
6
 
7
- | 역할 | 적용 대상 | Tailwind class 패턴 | CSS variable 패턴 |
7
+ | 역할 | 적용 대상 | Tailwind CSS v4 class 패턴 | CSS variable 패턴 |
8
8
  | --- | --- | --- | --- |
9
9
  | `fg` | 제목, 본문, placeholder, 아이콘, inverted content | `text-eds-fg-*`(SVG 아이콘은 `currentColor`로 따라갑니다), `fill-eds-fg-*` | `var(--eds-color-fg-*)` |
10
10
  | `bg` | 페이지, 카드, 입력, 버튼, 상태 surface | `bg-eds-bg-*` | `var(--eds-color-bg-*)` |
11
11
  | `stroke` | border, divider, keyboard focus ring | `border-eds-stroke-*`, `divide-eds-stroke-*`, `outline-eds-stroke-*`, `ring-eds-stroke-*` | `var(--eds-color-stroke-*)` |
12
12
 
13
- Tailwind class는 Tailwind root CSS가 있는 저장소에서 `eds sync`가 생성하며, 그 밖의 저장소에서는 CSS variable 또는 `cssVar()`를 씁니다. class 이름은 token 이름의 대소문자를 그대로 씁니다(예: focus ring은 `focus-visible:outline-eds-stroke-focusRing`). 공개 token이 없는 `eds-*` class는 Tailwind가 오류 없이 버리며 doctor의 `unknown:`으로만 드러납니다.
13
+ `eds sync`는 Tailwind CSS v4 root가 있으면 class utility가 든 `src/styles/eds-tokens.css`를 생성합니다. Tailwind CSS v3 또는 Tailwind 미사용 저장소에서는 CSS variable이나 `cssVar()`를 씁니다. class 이름은 token 이름의 대소문자를 따릅니다(예: focus ring은 `focus-visible:outline-eds-stroke-focusRing`). 공개 token이 없는 `eds-*` class는 Tailwind가 조용히 버립니다.
14
14
 
15
15
  역할을 고른 뒤 의미, 강도, 상태를 아래 표의 이름에서 고릅니다. 의미는 주변 화면의 색이 아니라 콘텐츠가 전달하는 상태로 고릅니다: `critical` 오류·위험, `warning` 주의, `positive` 성공·완료, `informative` 정보·안내, `brand` 제품 강조, `neutral` 그 밖의 모든 것.
16
16
 
@@ -31,7 +31,7 @@ exact token이 없으면 아래 순서로 조건을 하나씩 완화하고, 처
31
31
  3. 강도를 같은 의미 안의 가까운 단계로 바꿉니다(`primary`↔`weak`, `neutral`의 `secondary`·`tertiary`).
32
32
  4. 의미를 `neutral`로 바꿉니다. `critical`·`warning`·`positive`·`informative`를 `neutral`로 바꿔야 한다면 구현을 멈추고 사용자에게 확인합니다.
33
33
 
34
- 버튼은 token을 조합하지 않고 EDS `Button`의 `role`·`variant`를 씁니다. 행동별 조합은 `QUICKSTART.md` 표와 `dist/components/Button/README.md` 「Role과 Variant」에 있습니다.
34
+ 버튼은 token을 조합하지 않고 EDS `Button`의 `role`·`variant`를 씁니다. 행동별 조합은 설치된 패키지의 `dist/components/Button/README.md` 「Role과 Variant」를 따릅니다.
35
35
 
36
36
  ## Typography
37
37
 
@@ -95,9 +95,9 @@ import { cssVar } from "@spectrabrain/eds/tokens";
95
95
  - spacing: `spacing-none`, `spacing-0.5`, `spacing-1`, `spacing-1.5`, `spacing-2`, `spacing-2.5`, `spacing-3`, `spacing-3.5`, `spacing-4`, `spacing-4.5`, `spacing-5`, `spacing-6`, `spacing-7`, `spacing-7.5`, `spacing-8`, `spacing-9`, `spacing-10`, `spacing-11`, `spacing-12`
96
96
  - radius: `radius-none`, `radius-1`, `radius-2`, `radius-3`, `radius-4`, `radius-5`, `radius-6`, `radius-7`, `radius-8`, `radius-9`, `radius-10`
97
97
 
98
- Tailwind에서는 CSS-safe alias를 사용합니다. `spacing-0.5`는 `p-eds-spacing-0-5`, `radius-1`은 `rounded-eds-radius-1`처럼 씁니다. `0.5`·`1.5`·`2.5`·`3.5`·`4.5`·`7.5`의 점은 alias에서 `-`로 바뀝니다.
98
+ EDS와 sync한 Tailwind CSS v4 root가 있는 저장소에서는 CSS-safe alias를 사용합니다. `spacing-0.5`는 `p-eds-spacing-0-5`, `radius-1`은 `rounded-eds-radius-1`처럼 씁니다. `0.5`·`1.5`·`2.5`·`3.5`·`4.5`·`7.5`의 점은 alias에서 `-`로 바뀝니다.
99
99
 
100
- Tailwind가 없으면 `@spectrabrain/eds/tokens`의 `SemanticTokenName` 자동완성과 `cssVar()`를 사용합니다. public 이름은 `spacing-0.5`로 전달하고, CSS reference에서만 점이 escape됩니다.
100
+ Tailwind CSS v4 alias를 사용하지 않는 저장소에서는 `@spectrabrain/eds/tokens`의 `SemanticTokenName` 자동완성과 `cssVar()`를 사용합니다. public 이름은 `spacing-0.5`로 전달하고, CSS reference에서만 점이 escape됩니다.
101
101
 
102
102
  ```tsx
103
103
  import { cssVar } from "@spectrabrain/eds/tokens";
@@ -110,5 +110,5 @@ import { cssVar } from "@spectrabrain/eds/tokens";
110
110
 
111
111
  ## 확인 목록
112
112
 
113
- - 새로 쓴 CSS variable이 `tokens.json`의 `cssVariable` mapping과 일치하는지 확인합니다. dotted public name은 `var(--eds-spacing-0\.5)`처럼 CSS reference에서만 escape합니다. doctor는 Tailwind class를, typecheck는 `cssVar()` 인자를 검사합니다.
113
+ - 새로 쓴 CSS variable이 `tokens.json`의 `cssVariable` mapping과 일치하는지 확인합니다. dotted public name은 `var(--eds-spacing-0\.5)`처럼 CSS reference에서만 escape합니다. `eds doctor`는 Tailwind CSS v4 root가 있을 때만 `eds-*` class를 검사하고, typecheck는 `cssVar()` 인자를 검사합니다.
114
114
  - typography는 preset 하나(`eds-typography-*` class 또는 같은 preset의 변수 다섯 개)로 지정합니다.
@@ -1,6 +1,5 @@
1
1
  {
2
2
  "dev": "vite",
3
- "dev:mock": "vite --mode mock",
4
3
  "build": "vite build",
5
4
  "preview": "vite preview",
6
5
  "lint": "eslint .",
@@ -6,22 +6,12 @@ import { QueryClientProvider } from "@tanstack/react-query";
6
6
  import { queryClient } from "@/shared/api/queryClient";
7
7
  import App from "./App.tsx";
8
8
 
9
- async function main() {
10
- // The dev:mock script loads .env.mock, which sets VITE_API_MOCKING=true.
11
- if (import.meta.env.VITE_API_MOCKING === "true") {
12
- const { worker } = await import("@/mocks/browser");
13
- await worker.start({ onUnhandledRequest: "bypass" });
14
- }
15
-
16
- createRoot(document.getElementById("root")!).render(
17
- <StrictMode>
18
- <BrowserRouter>
19
- <QueryClientProvider client={queryClient}>
20
- <App />
21
- </QueryClientProvider>
22
- </BrowserRouter>
23
- </StrictMode>,
24
- );
25
- }
26
-
27
- main();
9
+ createRoot(document.getElementById("root")!).render(
10
+ <StrictMode>
11
+ <BrowserRouter>
12
+ <QueryClientProvider client={queryClient}>
13
+ <App />
14
+ </QueryClientProvider>
15
+ </BrowserRouter>
16
+ </StrictMode>,
17
+ );
@@ -5,7 +5,7 @@ import babel from "@rolldown/plugin-babel";
5
5
  import svgr from "vite-plugin-svgr";
6
6
  import tailwindcss from "@tailwindcss/vite";
7
7
 
8
- // Vite 8+ with @vitejs/plugin-react 6, which runs the React Compiler through @rolldown/plugin-babel.
8
+ // Vite 8 with @vitejs/plugin-react 6, which runs the React Compiler through @rolldown/plugin-babel.
9
9
  // Merge rules: PLAN.md step 3.
10
10
  export default defineConfig({
11
11
  plugins: [