sparkle-design-cli 2.0.2 → 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
 
@@ -131,6 +131,7 @@ sparkle-design-cli check --help
131
131
  - disabled を isDisabled の代わりに使わない
132
132
  - Button の prefixIcon に JSX を渡さない
133
133
  - Icon の children にテキストを渡さない
134
+ - クリック可能な Card を `<button>` / `<a>` / `role="button"` でラップせず、`ClickableCard` を使う
134
135
 
135
136
  #### Manual Review Reminders
136
137
 
@@ -159,7 +160,7 @@ AI エージェントや CI からこの `lint:sparkle` を呼ぶ運用にする
159
160
 
160
161
  1. **パッケージマネージャーの検出**(pnpm / yarn / bun / npm)
161
162
  2. **パッケージのインストール** — `sparkle-design`(dependencies)、`tailwindcss` + `@tailwindcss/postcss`(devDependencies)
162
- 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`)が無い場合のみ作成
163
164
  4. **AI ガード設定** — `CLAUDE.md` などに Sparkle Design Guard ブロックと `lint:sparkle` script を追加
164
165
  5. **`generate` の実行** — `sparkle-design.css` と `SparkleHead.tsx` を生成
165
166
 
@@ -178,7 +179,7 @@ npx --yes sparkle-design-cli setup --assistant claude --skip-install --skip-scaf
178
179
  ```
179
180
 
180
181
  既存ファイルは上書きされません:
181
- - `sparkle.config.json` / `postcss.config.*` / `globals.css` が存在する場合はそのまま保持
182
+ - `sparkle.config.json` / `postcss.config.*` / Tailwind エントリ CSS が存在する場合はそのまま保持
182
183
  - 既に依存関係に入っているパッケージはインストールをスキップ
183
184
  - `package.json` の既存の `lint:sparkle*` 独自 script は保持(`--force-script-update` で上書き)
184
185
 
@@ -267,11 +268,11 @@ Figma プラグインが出力する基本4項目に加えて、プロジェク
267
268
 
268
269
  #### extend.source-packages
269
270
 
270
- `sparkle-design` を npm パッケージとして利用する場合に必須。`globals.css` に `@source` ディレクティブを自動挿入します。`sparkle-design` は常にデフォルトで含まれます。
271
+ `sparkle-design` を npm パッケージとして利用する場合に必須。Tailwind エントリ CSS(自動検出)に `@source` ディレクティブを自動挿入します。`sparkle-design` は常にデフォルトで含まれます。
271
272
 
272
273
  #### extend.custom-css
273
274
 
274
- プロジェクト固有のカスタムトークンの CSS ファイルパス。`globals.css` に `@import` が自動挿入されます。`sparkle-design.css` に直接追加すると `generate` 実行時に上書きされるため、必ず別ファイルに分離してください。
275
+ プロジェクト固有のカスタムトークンの CSS ファイルパス。Tailwind エントリ CSS に `@import` が自動挿入されます。`sparkle-design.css` に直接追加すると `generate` 実行時に上書きされるため、必ず別ファイルに分離してください。
275
276
 
276
277
  ## 出力
277
278
 
@@ -286,7 +287,7 @@ Figma プラグインが出力する基本4項目に加えて、プロジェク
286
287
  CLI は自動的にフォント管理を行います:
287
288
 
288
289
  1. **フォント検出**: `sparkle-design.css` から Google Fonts の `@import` 文を検出
289
- 2. **globals.css への移動**: フォントの `@import` を `globals.css` の先頭に移動
290
+ 2. **エントリ CSS への移動**: フォントの `@import` を Tailwind エントリ CSS(`globals.css` / `index.css` 等、自動検出)の先頭に移動
290
291
  3. **sparkle-design.css から削除**: 元のファイルからフォント `@import` を削除
291
292
 
292
293
  ### なぜこの処理が必要なのか?
@@ -301,15 +302,15 @@ CSS の仕様では、`@import` 文は `@charset` と `@layer` 以外のすべ
301
302
 
302
303
  ### 動作条件
303
304
 
304
- - `globals.css` が `sparkle-design.css` と同じディレクトリに存在する場合のみ実行されます
305
- - `globals.css` が存在しない場合は、フォント管理処理はスキップされます
305
+ - Tailwind エントリ CSS(`@import "tailwindcss"` を含む CSS ファイル)が `sparkle-design.css` と同じディレクトリに存在する場合のみ実行されます(ファイル名に依存しません)
306
+ - エントリ CSS が存在しない場合は、フォント管理処理はスキップされます
306
307
 
307
308
  ### 出力例
308
309
 
309
310
  ```text
310
311
  📦 フォント管理処理を開始します...
311
312
  📝 3個のフォントimportを検出しました
312
- ✅ globals.css にフォントimportを追加しました
313
+ ✅ エントリ CSS にフォントimportを追加しました
313
314
  ✅ sparkle-design.css からフォントimportを削除しました
314
315
  ```
315
316
 
@@ -202,13 +202,14 @@ Setup options:
202
202
  --instructions-path <path> AI 指示ファイルの出力先パス (default: アシスタント別のデフォルト)
203
203
  --force-script-update 既存の lint:sparkle 系 script も上書きする
204
204
  --skip-install パッケージインストール(sparkle-design, tailwindcss)をスキップ
205
- --skip-scaffold 初期ファイル(sparkle.config.json, postcss.config, globals.css)生成をスキップ
205
+ --skip-scaffold 初期ファイル(sparkle.config.json, postcss.config, エントリ CSS)生成をスキップ
206
206
  --skip-generate generate 実行をスキップ
207
207
 
208
208
  Setup の動作:
209
209
  1. パッケージマネージャー検出(pnpm / npm / yarn / bun)
210
210
  2. sparkle-design を dependencies に追加、tailwindcss + @tailwindcss/postcss を devDependencies に追加
211
- 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 等)が無ければ初期ファイルを生成
212
213
  4. AI アシスタントのガードブロックを指定ファイルに挿入(存在しなければ新規作成)
213
214
  5. sparkle-design-cli generate を実行し、sparkle-design.css と SparkleHead.tsx を生成
214
215
 
@@ -226,7 +227,8 @@ Check で検出する主なパターン:
226
227
  - disabled を isDisabled の代わりに使っている
227
228
  - Button の prefixIcon に JSX を渡している
228
229
  - Icon の children にテキストを渡している
229
- - globals.css にフォント @import が残っている(SparkleHead への移行が必要)
230
+ - <Card> を <button> / <a> / role="button" でラップしている(ClickableCard を使う)
231
+ - エントリ CSS にフォント @import が残っている(SparkleHead への移行が必要)
230
232
  - CSP ヘッダーで Google Fonts がブロックされている可能性
231
233
 
232
234
  JSON 出力では manualReviewReminders も返すため、AI から実行する場合は --format json を推奨
@@ -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.2",
3
+ "version": "2.0.4",
4
4
  "description": "Sparkle Design CSS Generator - デザインシステムCSSを設定ファイルから生成するツール",
5
5
  "publishConfig": {
6
6
  "registry": "https://registry.npmjs.org",