sparkle-design-cli 2.0.1 → 2.0.4

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 CHANGED
@@ -17,7 +17,7 @@ setup は次を自動で行います:
17
17
  3. 未作成の場合のみ初期ファイルを生成:
18
18
  - `sparkle.config.json`(デフォルトは blue / Inter / JetBrains Mono / md)
19
19
  - `postcss.config.mjs`
20
- - `src/app/globals.css`(または `src/globals.css`)
20
+ - Tailwind エントリ CSS — Next.js App Router なら `src/app/globals.css`、Vite なら `src/index.css`、それ以外は `src/globals.css`(プロジェクト構成から自動判定)
21
21
  4. AI 指示ファイル(`CLAUDE.md` / `AGENTS.md` / Cursor rules)に Sparkle Design Guard ブロックを追加
22
22
  5. `sparkle-design-cli generate` を実行し、`sparkle-design.css` と `SparkleHead.tsx` を生成
23
23
 
@@ -49,11 +49,6 @@ npx sparkle-design-cli check src --strict
49
49
  npx sparkle-design-cli check src --format json
50
50
  ```
51
51
 
52
- ### 後方互換モード
53
-
54
- 既存の `npx sparkle-design-cli` も引き続き動作し、内部的には `generate` として扱われます。
55
- ただし後方互換のための動作なので、新規利用やドキュメント上の案内では `sparkle-design-cli generate` を使用してください。
56
-
57
52
  ### generate: 基本的な使用方法
58
53
 
59
54
  1. プロジェクトのルートディレクトリに `sparkle.config.json` ファイルを作成または配置します:
@@ -73,12 +68,6 @@ npx sparkle-design-cli check src --format json
73
68
  npx sparkle-design-cli generate
74
69
  ```
75
70
 
76
- 既存プロジェクトでサブコマンドなしの呼び出しを使っている場合も、後方互換として次の実行方法を継続利用できます:
77
-
78
- ```bash
79
- npx sparkle-design-cli
80
- ```
81
-
82
71
  3. `src/app/sparkle-design.css` に CSS ファイルが生成されます。
83
72
 
84
73
  ### generate: コマンドオプション
@@ -142,6 +131,7 @@ sparkle-design-cli check --help
142
131
  - disabled を isDisabled の代わりに使わない
143
132
  - Button の prefixIcon に JSX を渡さない
144
133
  - Icon の children にテキストを渡さない
134
+ - クリック可能な Card を `<button>` / `<a>` / `role="button"` でラップせず、`ClickableCard` を使う
145
135
 
146
136
  #### Manual Review Reminders
147
137
 
@@ -170,7 +160,7 @@ AI エージェントや CI からこの `lint:sparkle` を呼ぶ運用にする
170
160
 
171
161
  1. **パッケージマネージャーの検出**(pnpm / yarn / bun / npm)
172
162
  2. **パッケージのインストール** — `sparkle-design`(dependencies)、`tailwindcss` + `@tailwindcss/postcss`(devDependencies)
173
- 3. **初期ファイルの生成** — `sparkle.config.json` / `postcss.config.mjs` / `globals.css` が無い場合のみ作成
163
+ 3. **初期ファイルの生成** — `sparkle.config.json` / `postcss.config.mjs` / Tailwind エントリ CSS(Next.js は `src/app/globals.css`、Vite は `src/index.css`)が無い場合のみ作成
174
164
  4. **AI ガード設定** — `CLAUDE.md` などに Sparkle Design Guard ブロックと `lint:sparkle` script を追加
175
165
  5. **`generate` の実行** — `sparkle-design.css` と `SparkleHead.tsx` を生成
176
166
 
@@ -189,7 +179,7 @@ npx --yes sparkle-design-cli setup --assistant claude --skip-install --skip-scaf
189
179
  ```
190
180
 
191
181
  既存ファイルは上書きされません:
192
- - `sparkle.config.json` / `postcss.config.*` / `globals.css` が存在する場合はそのまま保持
182
+ - `sparkle.config.json` / `postcss.config.*` / Tailwind エントリ CSS が存在する場合はそのまま保持
193
183
  - 既に依存関係に入っているパッケージはインストールをスキップ
194
184
  - `package.json` の既存の `lint:sparkle*` 独自 script は保持(`--force-script-update` で上書き)
195
185
 
@@ -278,11 +268,11 @@ Figma プラグインが出力する基本4項目に加えて、プロジェク
278
268
 
279
269
  #### extend.source-packages
280
270
 
281
- `sparkle-design` を npm パッケージとして利用する場合に必須。`globals.css` に `@source` ディレクティブを自動挿入します。`sparkle-design` は常にデフォルトで含まれます。
271
+ `sparkle-design` を npm パッケージとして利用する場合に必須。Tailwind エントリ CSS(自動検出)に `@source` ディレクティブを自動挿入します。`sparkle-design` は常にデフォルトで含まれます。
282
272
 
283
273
  #### extend.custom-css
284
274
 
285
- プロジェクト固有のカスタムトークンの CSS ファイルパス。`globals.css` に `@import` が自動挿入されます。`sparkle-design.css` に直接追加すると `generate` 実行時に上書きされるため、必ず別ファイルに分離してください。
275
+ プロジェクト固有のカスタムトークンの CSS ファイルパス。Tailwind エントリ CSS に `@import` が自動挿入されます。`sparkle-design.css` に直接追加すると `generate` 実行時に上書きされるため、必ず別ファイルに分離してください。
286
276
 
287
277
  ## 出力
288
278
 
@@ -297,7 +287,7 @@ Figma プラグインが出力する基本4項目に加えて、プロジェク
297
287
  CLI は自動的にフォント管理を行います:
298
288
 
299
289
  1. **フォント検出**: `sparkle-design.css` から Google Fonts の `@import` 文を検出
300
- 2. **globals.css への移動**: フォントの `@import` を `globals.css` の先頭に移動
290
+ 2. **エントリ CSS への移動**: フォントの `@import` を Tailwind エントリ CSS(`globals.css` / `index.css` 等、自動検出)の先頭に移動
301
291
  3. **sparkle-design.css から削除**: 元のファイルからフォント `@import` を削除
302
292
 
303
293
  ### なぜこの処理が必要なのか?
@@ -312,15 +302,15 @@ CSS の仕様では、`@import` 文は `@charset` と `@layer` 以外のすべ
312
302
 
313
303
  ### 動作条件
314
304
 
315
- - `globals.css` が `sparkle-design.css` と同じディレクトリに存在する場合のみ実行されます
316
- - `globals.css` が存在しない場合は、フォント管理処理はスキップされます
305
+ - Tailwind エントリ CSS(`@import "tailwindcss"` を含む CSS ファイル)が `sparkle-design.css` と同じディレクトリに存在する場合のみ実行されます(ファイル名に依存しません)
306
+ - エントリ CSS が存在しない場合は、フォント管理処理はスキップされます
317
307
 
318
308
  ### 出力例
319
309
 
320
310
  ```text
321
311
  📦 フォント管理処理を開始します...
322
312
  📝 3個のフォントimportを検出しました
323
- ✅ globals.css にフォントimportを追加しました
313
+ ✅ エントリ CSS にフォントimportを追加しました
324
314
  ✅ sparkle-design.css からフォントimportを削除しました
325
315
  ```
326
316
 
@@ -364,10 +354,8 @@ npm run format:check
364
354
  # CSS生成
365
355
  sparkle-design-cli generate
366
356
 
367
- # 既存呼び出しの後方互換モード
368
- sparkle-design-cli
369
-
370
357
  # ヘルプ表示
358
+ sparkle-design-cli --help
371
359
  sparkle-design-cli generate --help
372
360
 
373
361
  # 検査
@@ -133,11 +133,6 @@ Commands:
133
133
  check Sparkle Design のアンチパターンを検査
134
134
  setup Sparkle Design プロジェクトをセットアップ(パッケージ導入 + 初期ファイル + AI ガード + generate)
135
135
 
136
- 後方互換:
137
- sparkle-design-cli [generate options]
138
- サブコマンドなしの実行は現在も generate として動作しますが、
139
- 正式リリース時に削除予定です。今後は sparkle-design-cli generate を使ってください。
140
-
141
136
  Generate:
142
137
  sparkle-design-cli generate
143
138
  sparkle-design-cli generate --config ./config/design.json
@@ -207,13 +202,14 @@ Setup options:
207
202
  --instructions-path <path> AI 指示ファイルの出力先パス (default: アシスタント別のデフォルト)
208
203
  --force-script-update 既存の lint:sparkle 系 script も上書きする
209
204
  --skip-install パッケージインストール(sparkle-design, tailwindcss)をスキップ
210
- --skip-scaffold 初期ファイル(sparkle.config.json, postcss.config, globals.css)生成をスキップ
205
+ --skip-scaffold 初期ファイル(sparkle.config.json, postcss.config, エントリ CSS)生成をスキップ
211
206
  --skip-generate generate 実行をスキップ
212
207
 
213
208
  Setup の動作:
214
209
  1. パッケージマネージャー検出(pnpm / npm / yarn / bun)
215
210
  2. sparkle-design を dependencies に追加、tailwindcss + @tailwindcss/postcss を devDependencies に追加
216
- 3. sparkle.config.json / postcss.config.mjs / globals.css が無ければ初期ファイルを生成
211
+ 3. sparkle.config.json / postcss.config.mjs / Tailwind エントリ CSS(Next.js は
212
+ src/app/globals.css、Vite は src/index.css 等)が無ければ初期ファイルを生成
217
213
  4. AI アシスタントのガードブロックを指定ファイルに挿入(存在しなければ新規作成)
218
214
  5. sparkle-design-cli generate を実行し、sparkle-design.css と SparkleHead.tsx を生成
219
215
 
@@ -231,7 +227,8 @@ Check で検出する主なパターン:
231
227
  - disabled を isDisabled の代わりに使っている
232
228
  - Button の prefixIcon に JSX を渡している
233
229
  - Icon の children にテキストを渡している
234
- - globals.css にフォント @import が残っている(SparkleHead への移行が必要)
230
+ - <Card> を <button> / <a> / role="button" でラップしている(ClickableCard を使う)
231
+ - エントリ CSS にフォント @import が残っている(SparkleHead への移行が必要)
235
232
  - CSP ヘッダーで Google Fonts がブロックされている可能性
236
233
 
237
234
  JSON 出力では manualReviewReminders も返すため、AI から実行する場合は --format json を推奨
@@ -242,28 +239,16 @@ generate で生成されるファイル:
242
239
  `);
243
240
  }
244
241
 
245
- function showGenerateDeprecationNotice() {
246
- console.warn(
247
- '[sparkle-design-cli] Running without a subcommand defaults to `generate`. ' +
248
- 'Use `sparkle-design-cli generate` instead. This compatibility mode will be removed at the formal release.'
249
- );
250
- }
251
-
252
242
  function main() {
253
243
  const args = process.argv.slice(2);
254
244
  const command = args[0];
255
245
 
256
246
  try {
257
- if (args.length === 0) {
258
- showGenerateDeprecationNotice();
259
- generateCSS();
260
- return;
261
- }
262
-
263
- if (command === '-h' || command === '--help') {
247
+ if (args.length === 0 || command === '-h' || command === '--help') {
264
248
  showHelp();
265
249
  process.exit(0);
266
250
  }
251
+
267
252
  if (command === 'generate') {
268
253
  const options = parseGenerateOptions(args.slice(1));
269
254
 
@@ -306,22 +291,14 @@ function main() {
306
291
  return;
307
292
  }
308
293
 
309
- if (!SUBCOMMANDS.has(command) && command.startsWith('-')) {
310
- showGenerateDeprecationNotice();
311
- const options = parseGenerateOptions(args);
312
-
313
- if (options.help) {
314
- showHelp();
315
- process.exit(0);
316
- }
317
-
318
- generateCSS(options.configPath, options.outputPath, options.globalsPath);
319
- return;
320
- }
321
-
322
- if (!SUBCOMMANDS.has(command)) {
323
- throw new Error(`Unknown command: ${command}`);
324
- }
294
+ // 未知のコマンド: エラー終了ではなく note + help 表示にする(typo 時の迷子を防ぐ)
295
+ // en: Unknown command: show a short note + help instead of throwing
296
+ console.warn(
297
+ `⚠️ Unknown command: ${command}. 次のいずれかを指定してください: ${[...SUBCOMMANDS].join(', ')}`
298
+ );
299
+ console.warn('');
300
+ showHelp();
301
+ process.exit(0);
325
302
  } catch (error) {
326
303
  console.error('❌ エラーが発生しました:', error.message);
327
304
  process.exit(1);
@@ -489,6 +489,62 @@ const ANTI_PATTERN_GROUPS = [
489
489
  },
490
490
  ],
491
491
  },
492
+ {
493
+ id: 'card-clickable-wrap',
494
+ check: {
495
+ description: 'クリック可能な Card は ClickableCard を使う(button / a / role="button" でラップしない)',
496
+ recommendation:
497
+ '`<Card>` を `<button>` / `<a>` / `role="button"` を持つ要素で包まず、`ClickableCard` を使ってください。`ClickableCard` が適切な role / keyboard 対応 / focus ring を担保します。',
498
+ // <button> / <a> / role="button" が直接 <Card> を子に持つケース
499
+ // en: <button> / <a> / role="button" wrapping a <Card> directly
500
+ pattern:
501
+ /<(?:button\b|a\b|[A-Za-z][A-Za-z0-9]*\b[^>]*\brole\s*=\s*["']button["'])[^>]*>\s*<Card\b/g,
502
+ },
503
+ featureSection: lines([
504
+ '### クリック可能な Card: ClickableCard を使う',
505
+ '',
506
+ '```tsx',
507
+ '// ✅ Correct',
508
+ '<ClickableCard onClick={handle}>',
509
+ ' <CardHeader><CardTitle>タイトル</CardTitle></CardHeader>',
510
+ '</ClickableCard>',
511
+ '',
512
+ '// ❌ Wrong - <button> / <a> で Card を包まない',
513
+ '<button type="button" onClick={handle}>',
514
+ ' <Card>',
515
+ ' <CardHeader><CardTitle>タイトル</CardTitle></CardHeader>',
516
+ ' </Card>',
517
+ '</button>',
518
+ '```',
519
+ '',
520
+ '`ClickableCard` はクリック可能な Card のパターンとして必要な `role` / キーボード操作 / focus ring を提供する。`<button>` / `<a>` / `role="button"` でラップすると、ボタンの内側に対話型要素(リンクやフォーム要素)を置いたときにネストされた interactive 要素になりアクセシビリティ違反になる。',
521
+ ]),
522
+ jsdocTargets: [
523
+ {
524
+ file: 'src/components/ui/card/index.tsx',
525
+ targetName: 'Card',
526
+ section: {
527
+ bullets: [
528
+ {
529
+ ja: '`<Card>` を `<button>` / `<a>` / `role="button"` で包まないでください。クリック可能な Card には専用の `ClickableCard` を使ってください。',
530
+ en: 'Do not wrap `<Card>` with `<button>` / `<a>` / `role="button"`. Use the dedicated `ClickableCard` component for clickable cards.',
531
+ },
532
+ ],
533
+ example: lines([
534
+ '// ✅ Correct',
535
+ '<ClickableCard onClick={handle}>',
536
+ ' <CardHeader><CardTitle>タイトル</CardTitle></CardHeader>',
537
+ '</ClickableCard>',
538
+ '',
539
+ '// ❌ Wrong',
540
+ '<button type="button" onClick={handle}>',
541
+ ' <Card>...</Card>',
542
+ '</button>',
543
+ ]),
544
+ },
545
+ },
546
+ ],
547
+ },
492
548
  {
493
549
  id: 'icon-scale',
494
550
  featureSection: lines([
package/lib/setup.js CHANGED
@@ -309,12 +309,33 @@ function ensurePackagesInstalled(cwd, packageManager, candidates, { dev = false,
309
309
  return { ran: true, reason: 'installed', packages: missing, packageManager, dev };
310
310
  }
311
311
 
312
+ // Vite の設定ファイル候補(プロジェクト種別の判定に使う)
313
+ // en: Vite config files used to detect a Vite project
314
+ const VITE_CONFIG_FILES = [
315
+ 'vite.config.ts',
316
+ 'vite.config.js',
317
+ 'vite.config.mjs',
318
+ 'vite.config.cjs',
319
+ 'vite.config.mts',
320
+ 'vite.config.cts',
321
+ ];
322
+
323
+ function isViteProject(cwd) {
324
+ return VITE_CONFIG_FILES.some((name) => fs.existsSync(path.join(cwd, name)));
325
+ }
326
+
312
327
  /**
313
- * src/app → src/app/globals.css、src 直下があれば src/globals.css を優先
314
- * en: Prefer src/app/globals.css when src/app exists, otherwise src/globals.css
328
+ * エントリポイント CSS の新規作成先を決定する。
329
+ * - Next.js App Router (src/app あり) → src/app/globals.css
330
+ * - Vite プロジェクト → src/index.css(Vite の慣習に合わせる)
331
+ * - それ以外で src/ がある → src/globals.css
332
+ * - フォールバック → src/app/globals.css
333
+ * en: Pick the scaffold target for the entry CSS. Vite projects get src/index.css
334
+ * to match the common convention, Next.js App Router gets src/app/globals.css.
315
335
  */
316
336
  function defaultGlobalsCssTarget(cwd) {
317
337
  if (fs.existsSync(path.join(cwd, 'src/app'))) return 'src/app/globals.css';
338
+ if (isViteProject(cwd)) return 'src/index.css';
318
339
  if (fs.existsSync(path.join(cwd, 'src'))) return 'src/globals.css';
319
340
  return 'src/app/globals.css';
320
341
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "sparkle-design-cli",
3
- "version": "2.0.1",
3
+ "version": "2.0.4",
4
4
  "description": "Sparkle Design CSS Generator - デザインシステムCSSを設定ファイルから生成するツール",
5
5
  "publishConfig": {
6
6
  "registry": "https://registry.npmjs.org",