atomsystem 0.1.34 → 0.1.36

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.
@@ -21,13 +21,7 @@ export const ModalContent = ({
21
21
  size = "normal",
22
22
  }: ModalProps) => {
23
23
  useEffect(() => {
24
- let rootElement = document.getElementById("modal-root");
25
- if (!rootElement) {
26
- rootElement = document.createElement("div");
27
- rootElement.id = "modal-root";
28
- document.body.appendChild(rootElement);
29
- }
30
- ReactModal.setAppElement(rootElement); // 접근성 설정
24
+ ReactModal.setAppElement("#modal-root"); // 접근성 설정
31
25
  }, []);
32
26
 
33
27
  return (
@@ -2,7 +2,7 @@
2
2
 
3
3
  import { useEffect, useState } from "react";
4
4
  import { Radio } from "../Form/Form";
5
- import { themes } from "../../../build/typescript/theme";
5
+ import { themes } from "@/build/typescript/theme";
6
6
  import { Button } from "../Button/Button";
7
7
  import { ModalContent } from "../Modal/Modal";
8
8
 
@@ -180,7 +180,12 @@ myStyleDictionary.registerFormat({
180
180
  .join("\n");
181
181
 
182
182
  // global(@theme)인 경우에만 수집해둔 시멘틱 변수(semanticCss)를 추가
183
- return `${selector} {\n${cssVariables}\n${selector === "@theme" ? `\n${semanticCss}\n` : ""}} `;
183
+ // @theme: Tailwind 유틸리티 클래스 생성에 필요 (bg-primary, text-secondary 등)
184
+ // Tailwind CSS v4의 @theme은 빌드 시 자동으로 :root에도 등록되므로 별도 :root 선언 불필요
185
+ if (selector === "@theme") {
186
+ return `@theme {\n${cssVariables}\n\n${semanticCss}\n}`;
187
+ }
188
+ return `${selector} {\n${cssVariables}\n} `;
184
189
  })
185
190
  .join("\n\n");
186
191
  },
@@ -144,6 +144,104 @@
144
144
  --color-border-sidenav: var(--border-sidenav);
145
145
  }
146
146
 
147
+ :root {
148
+ --color-gray-100: #f5f5f5;
149
+ --color-gray-200: #e6e6e6;
150
+ --color-gray-300: #dbdbdb;
151
+ --color-gray-400: #d4d4d4;
152
+ --color-gray-500: #cccccc;
153
+ --color-gray-600: #bfbfbf;
154
+ --color-gray-700: #b3b3b3;
155
+ --color-gray-800: #a6a6a6;
156
+ --color-gray-900: #999999;
157
+ --color-gray-950: #707070;
158
+ --color-dark-100: #111111;
159
+ --color-dark-200: #222222;
160
+ --color-dark-300: #333333;
161
+ --color-dark-400: #444444;
162
+ --color-dark-500: #555555;
163
+ --color-dark-600: #666666;
164
+ --color-dark-700: #777777;
165
+ --color-dark-800: #888888;
166
+ --color-dark-900: #999999;
167
+ --color-dark-950: #b2b2b2;
168
+ --color-blue-100: #e3f2fd;
169
+ --color-blue-200: #bbdefb;
170
+ --color-blue-300: #90caf9;
171
+ --color-blue-400: #64b5f6;
172
+ --color-blue-500: #2196f3;
173
+ --color-blue-600: #1e88e5;
174
+ --color-blue-700: #1976d2;
175
+ --color-blue-800: #1565c0;
176
+ --color-blue-900: #0d47a1;
177
+ --color-blue-950: #0a2f6b;
178
+ --color-indigo-100: #e8eaf6;
179
+ --color-indigo-200: #c5cae9;
180
+ --color-indigo-300: #7986cb;
181
+ --color-indigo-400: #3f51b5;
182
+ --color-indigo-500: #162c4e;
183
+ --color-indigo-600: #122542;
184
+ --color-indigo-700: #0e1d35;
185
+ --color-indigo-800: #0a1628;
186
+ --color-indigo-900: #070f1b;
187
+ --color-indigo-950: #04080e;
188
+ --color-red-100: #ffebee;
189
+ --color-red-200: #ffcdd2;
190
+ --color-red-300: #ef9a9a;
191
+ --color-red-400: #e57373;
192
+ --color-red-500: #f44336;
193
+ --color-red-600: #e53935;
194
+ --color-red-700: #d32f2f;
195
+ --color-red-800: #c62828;
196
+ --color-red-900: #b71c1c;
197
+ --color-red-950: #7f1212;
198
+ --color-yellow-100: #fff8e1;
199
+ --color-yellow-200: #ffecb3;
200
+ --color-yellow-300: #ffe082;
201
+ --color-yellow-400: #ffd54f;
202
+ --color-yellow-500: #ffb300;
203
+ --color-yellow-600: #ffa000;
204
+ --color-yellow-700: #ff8f00;
205
+ --color-yellow-800: #ff6f00;
206
+ --color-yellow-900: #e65100;
207
+ --color-yellow-950: #9e3600;
208
+ --color-green-100: #e8f5e9;
209
+ --color-green-200: #c8e6c9;
210
+ --color-green-300: #a5d6a7;
211
+ --color-green-400: #81c784;
212
+ --color-green-500: #4caf50;
213
+ --color-green-600: #43a047;
214
+ --color-green-700: #388e3c;
215
+ --color-green-800: #2e7d32;
216
+ --color-green-900: #1b5e20;
217
+ --color-green-950: #104015;
218
+ --color-black: #111111;
219
+ --color-white: #fafafa;
220
+ --color-primary: var(--color-blue-500);
221
+ --color-secondary: var(--color-indigo-500);
222
+ --color-danger: var(--color-red-500);
223
+ --color-warning: var(--color-yellow-500);
224
+ --color-info: var(--color-gray-900);
225
+ --color-success: var(--color-green-500);
226
+ --text-h1: 40px;
227
+ --text-h2: 36px;
228
+ --text-h3: 28px;
229
+ --text-h4: 24px;
230
+ --text-h5: 20px;
231
+ --text-h6: 16px;
232
+ --text-body: 16px;
233
+ --text-sm: 12px;
234
+ --font-weight-header: 700;
235
+ --radius-common: 4px;
236
+ --radius-circle: 10000000px;
237
+ --font-spoqaNeo: Spoqa Han Sans Neo;
238
+ --spacing-common-y: 12px;
239
+ --spacing-common-x: 16px;
240
+ --spacing-gap-small: 4px;
241
+ --spacing-sm-y: 8px;
242
+ --spacing-small: 20px;
243
+ }
244
+
147
245
  .white {
148
246
  --bg-card: var(--color-white);
149
247
  --bg-wrapper: var(--color-gray-200);
package/cli/add.js CHANGED
@@ -51,7 +51,7 @@ function addComponent(comp) {
51
51
 
52
52
  // 컴포넌트의 CSS 파일 복제 지원
53
53
  const cssFileName = `${comp}.css`.toLowerCase();
54
- const sourceCssPath = path.join(__dirname, "..", "css", cssFileName);
54
+ const sourceCssPath = path.join(templateDir, comp, cssFileName);
55
55
  const targetCssPath = path.join(targetDir, cssFileName);
56
56
 
57
57
  if (fs.existsSync(componentPath)) {
@@ -65,10 +65,54 @@ function addComponent(comp) {
65
65
  copyFileSync(componentPath, targetPath);
66
66
  console.log(`✅ ${comp} component typescript has been added to ${targetPath}`);
67
67
 
68
- // 2) CSS 복사
68
+ // 2) CSS 복사 + globals.css에 @import 자동 추가
69
69
  if (fs.existsSync(sourceCssPath)) {
70
70
  copyFileSync(sourceCssPath, targetCssPath);
71
71
  console.log(`✅ ${comp} component stylesheet has been added to ${targetCssPath}`);
72
+
73
+ // globals.css에 @import 추가
74
+ const globalsPath = path.join(process.cwd(), "app", "globals.css");
75
+ const importLine = `@import "./components/${comp}/${cssFileName}";`;
76
+
77
+ if (fs.existsSync(globalsPath)) {
78
+ const globalsContent = fs.readFileSync(globalsPath, "utf8");
79
+
80
+ if (!globalsContent.includes(importLine)) {
81
+ // "/* Component Styles */" 섹션 이후에 추가, 없으면 파일 끝에 추가
82
+ let updatedContent;
83
+ const componentSectionMarker = "/* Component Styles */";
84
+
85
+ if (globalsContent.includes(componentSectionMarker)) {
86
+ // 마커 이후의 마지막 @import 뒤에 추가
87
+ const markerIndex = globalsContent.indexOf(componentSectionMarker);
88
+ const afterMarker = globalsContent.slice(markerIndex);
89
+ const lastImportInSection = afterMarker.lastIndexOf("@import");
90
+
91
+ if (lastImportInSection !== -1) {
92
+ const endOfLastImport = markerIndex + lastImportInSection + afterMarker.slice(lastImportInSection).indexOf("\n") + 1;
93
+ updatedContent =
94
+ globalsContent.slice(0, endOfLastImport) +
95
+ importLine + "\n" +
96
+ globalsContent.slice(endOfLastImport);
97
+ } else {
98
+ updatedContent =
99
+ globalsContent.slice(0, markerIndex + componentSectionMarker.length) +
100
+ "\n" + importLine + "\n" +
101
+ globalsContent.slice(markerIndex + componentSectionMarker.length);
102
+ }
103
+ } else {
104
+ // 마커가 없으면 "/* Component Styles */" 섹션과 함께 파일 끝에 추가
105
+ updatedContent = globalsContent.trimEnd() + "\n\n/* Component Styles */\n" + importLine + "\n";
106
+ }
107
+
108
+ fs.writeFileSync(globalsPath, updatedContent, "utf8");
109
+ console.log(`✅ Added @import for ${comp} to globals.css`);
110
+ } else {
111
+ console.log(`ℹ️ ${comp} is already imported in globals.css`);
112
+ }
113
+ } else {
114
+ console.log(`⚠️ globals.css not found at ${globalsPath}. Please add manually:\n ${importLine}`);
115
+ }
72
116
  }
73
117
  // 3) 의존성 컴포넌트 자동 복사 (Recursive Copy)
74
118
  if (dependenciesMap[comp]) {
package/cli/init.js CHANGED
@@ -49,7 +49,7 @@ inquirer
49
49
 
50
50
  try {
51
51
  await execPromise(
52
- "npm install next@latest react@latest react-dom@latest tailwindcss clsx react-modal typescript @types/react @types/node @types/react-dom @types/react-modal"
52
+ "npm install next@latest react@latest react-dom@latest tailwindcss @tailwindcss/postcss postcss clsx react-modal typescript @types/react @types/node @types/react-dom @types/react-modal"
53
53
  );
54
54
  pkgSpinner.succeed("Next.js and React installation complete!");
55
55
  } catch (err) {
@@ -160,6 +160,56 @@ export default function Page() {
160
160
  )
161
161
  }`,
162
162
  },
163
+ // ✅ tsconfig.json: "@/*" 경로 별칭 설정 (예: @/build/typescript/theme)
164
+ {
165
+ path: path.join(projectRoot, "tsconfig.json"),
166
+ content: JSON.stringify({
167
+ compilerOptions: {
168
+ target: "ES2017",
169
+ lib: ["dom", "dom.iterable", "esnext"],
170
+ allowJs: true,
171
+ skipLibCheck: true,
172
+ strict: true,
173
+ noEmit: true,
174
+ esModuleInterop: true,
175
+ module: "esnext",
176
+ moduleResolution: "bundler",
177
+ resolveJsonModule: true,
178
+ isolatedModules: true,
179
+ jsx: "preserve",
180
+ incremental: true,
181
+ plugins: [{ name: "next" }],
182
+ paths: {
183
+ "@/*": ["./*"]
184
+ }
185
+ },
186
+ include: ["next-env.d.ts", "**/*.ts", "**/*.tsx", ".next/types/**/*.ts"],
187
+ exclude: ["node_modules"]
188
+ }, null, 2),
189
+ },
190
+ // ✅ next.config.ts: Next.js 기본 설정
191
+ {
192
+ path: path.join(projectRoot, "next.config.ts"),
193
+ content: `import type { NextConfig } from "next";
194
+
195
+ const nextConfig: NextConfig = {
196
+ reactStrictMode: false,
197
+ };
198
+
199
+ export default nextConfig;`,
200
+ },
201
+ // ✅ postcss.config.mjs: Tailwind CSS v4 PostCSS 플러그인 등록 (@theme, @import "tailwindcss" 인식)
202
+ {
203
+ path: path.join(projectRoot, "postcss.config.mjs"),
204
+ content: `/** @type {import('postcss-load-config').Config} */
205
+ const config = {
206
+ plugins: {
207
+ "@tailwindcss/postcss": {},
208
+ },
209
+ };
210
+
211
+ export default config;`,
212
+ },
163
213
  ];
164
214
 
165
215
  files.forEach(({ path, content }) => {
@@ -167,6 +217,23 @@ export default function Page() {
167
217
  console.log(`✅ Created ${path}`);
168
218
  });
169
219
 
220
+ // ✅ 토큰 빌드 먼저 실행: Theme.tsx가 @/build/typescript/theme를 import하므로
221
+ // 컴포넌트 복사 전에 build-tokens.js를 실행해 theme.ts를 미리 생성해야 합니다.
222
+ const buildTokensPath = path.join(projectRoot, "build", "build-tokens.js");
223
+ if (fs.existsSync(buildTokensPath)) {
224
+ const tokenBuildSpinner = ora("Building design tokens (generating build/typescript/theme.ts)...").start();
225
+ try {
226
+ await execPromise(`node "${buildTokensPath}"`, { cwd: projectRoot });
227
+ tokenBuildSpinner.succeed("Design tokens built successfully!");
228
+ } catch (err) {
229
+ tokenBuildSpinner.fail("Error during token build");
230
+ console.error(err);
231
+ return;
232
+ }
233
+ } else {
234
+ console.warn("⚠️ build-tokens.js not found, skipping token build.");
235
+ }
236
+
170
237
  // add.js를 실행하여 Theme, Card 컴포넌트 및 하위 의존성을 복사합니다.
171
238
  const addScriptPath = path.join(__dirname, "add.js");
172
239
  if (fs.existsSync(addScriptPath)) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "atomsystem",
3
- "version": "0.1.34",
3
+ "version": "0.1.36",
4
4
  "type": "module",
5
5
  "homepage": "https://system.atomground.com",
6
6
  "bin": {
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes