Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 11 additions & 4 deletions .internal/page-template.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

このテンプレートは、APG パターンページの構成を統一するためのガイドラインです。

> **Note**: ページは動的ルーティング(`[pattern]/[framework]/index.astro`)で自動生成される。個別のページファイル作成は不要。新しいパターンを追加するには `meta.ts` と `DemoSection.astro` を作成すればよい
> **Note**: ページは動的ルーティング(`[pattern]/[framework]/index.astro`)で自動生成される。個別のページファイル作成は不要。新しいパターンを追加するには `meta.ts` と framework 別の `DemoSection.{react,vue,svelte,web-component}.astro` 4 ファイルを作成すればよい

## 章構成 (tocItems)

Expand Down Expand Up @@ -49,7 +49,8 @@ const tocItems = [
| ファイル | 役割 | 検出パターン |
|---------|------|-------------|
| `meta.ts` | メタデータ定義 | `/src/patterns/*/meta.ts` |
| `DemoSection.astro` | デモ表示 | `/src/patterns/*/DemoSection.astro` |
| `DemoSection.{react,vue,svelte,web-component}.astro` | framework 別デモ表示 | `/src/patterns/*/DemoSection.{react,vue,svelte,web-component}.astro` |
| `{pattern}-demo-data.ts` | 共通 demo data(任意) | `/src/patterns/{pattern}/{pattern}-demo-data.ts` |
| `TestingDocs.astro` | テスト解説 | `/src/patterns/*/TestingDocs.astro` |
| `{Component}.{tsx,vue,svelte,astro}` | ソースコード表示 | `/src/patterns/**/*.{tsx,vue,svelte,astro}` (`?raw`) |
| `{Component}.test.*` | テストコード表示 | `/src/patterns/**/*.test.*` (`?raw`) |
Expand All @@ -58,7 +59,9 @@ const tocItems = [
## 章の説明

### 1. Demo
- `DemoSection.astro` コンポーネントが `framework` prop に基づいて適切なフレームワーク実装を表示
- ページ側 dispatcher が `framework` 値から `DemoSection.{react,vue,svelte,web-component}.astro` の該当ファイルを動的 import して呼ぶ(`Astro Web Component` は `web-component` キー)
- 各 framework 別ファイルは `locale` prop だけを受け取り、自分の framework の実装ファイルだけを静的 import する
- 4 framework で内容が完全に同一かつ概ね 8 行以上の純 data は `{pattern}-demo-data.ts` に切り出して全 4 ファイルから import する
- 複数のバリエーションがある場合は DemoSection 内で `<h3>` 小見出しで分割

### 2. Native HTML(条件付き)
Expand Down Expand Up @@ -108,7 +111,10 @@ const tocItems = [

### 必須ファイル
- [ ] `src/patterns/{pattern}/meta.ts` - パターンメタデータ(`PatternMeta` 型)
- [ ] `src/patterns/{pattern}/DemoSection.astro` - 全フレームワーク統合デモ
- [ ] `src/patterns/{pattern}/DemoSection.react.astro` - React 用デモ
- [ ] `src/patterns/{pattern}/DemoSection.vue.astro` - Vue 用デモ
- [ ] `src/patterns/{pattern}/DemoSection.svelte.astro` - Svelte 用デモ
- [ ] `src/patterns/{pattern}/DemoSection.web-component.astro` - Astro Web Component 用デモ
- [ ] `src/patterns/{pattern}/{Component}.tsx` - React 実装
- [ ] `src/patterns/{pattern}/{Component}.vue` - Vue 実装
- [ ] `src/patterns/{pattern}/{Component}.svelte` - Svelte 実装
Expand All @@ -119,6 +125,7 @@ const tocItems = [
- [ ] `src/content/accessibility-docs/{pattern}/ja.mdx` - アクセシビリティ解説(日本語)
- [ ] `src/patterns/{pattern}/{pattern}.md` - AI 向けガイド
- [ ] `src/patterns/{pattern}/NativeHtmlNotice.astro` - Native HTML 説明(該当パターンのみ)
- [ ] `src/patterns/{pattern}/{pattern}-demo-data.ts` - 共通 demo data(4 framework で完全一致する 8 行以上の純 data がある場合のみ)

### meta.ts 構成確認
- [ ] `PatternMeta` 型に準拠している
Expand Down
13 changes: 9 additions & 4 deletions .internal/pattern-planning-prompt.md
Original file line number Diff line number Diff line change
Expand Up @@ -137,7 +137,8 @@ Phase 1 で llm.md とテストを先に作成し、その後実装に進みま

### Phase 3: メタデータ・ドキュメント
- [ ] `meta.ts` - パターンメタデータ(`PatternMeta` 型)
- [ ] `DemoSection.astro` - 全フレームワーク統合デモ
- [ ] `DemoSection.react.astro` / `DemoSection.vue.astro` / `DemoSection.svelte.astro` / `DemoSection.web-component.astro` - framework 別デモ
- [ ] `{pattern}-demo-data.ts` - 共通 demo data(4 framework で完全一致する 8 行以上の純 data がある場合のみ)
- [ ] `TestingDocs.astro` - テスト解説 ※ `.internal/TestingDocs-template.astro` を参照
- [ ] `NativeHtmlNotice.astro` - ネイティブ HTML 注記(該当パターンのみ)
- [ ] `src/content/accessibility-docs/{pattern}/en.mdx` - ARIA 仕様解説(英語)
Expand Down Expand Up @@ -689,8 +690,8 @@ export interface {ComponentName}Props extends Omit<
# meta.ts の存在確認
ls -la src/patterns/{pattern}/meta.ts

# DemoSection の存在確認
ls -la src/patterns/{pattern}/DemoSection.astro
# DemoSection の存在確認(framework 別 4 ファイル)
ls -la src/patterns/{pattern}/DemoSection.{react,vue,svelte,web-component}.astro

# アクセシビリティドキュメントの確認
ls -la src/content/accessibility-docs/{pattern}/en.mdx
Expand All @@ -713,7 +714,11 @@ export interface {ComponentName}Props extends Omit<

### メタデータ・デモ
- [ ] meta.ts(PatternMeta 型)
- [ ] DemoSection.astro
- [ ] DemoSection.react.astro
- [ ] DemoSection.vue.astro
- [ ] DemoSection.svelte.astro
- [ ] DemoSection.web-component.astro
- [ ] {pattern}-demo-data.ts(共通 data がある場合のみ)

### ドキュメント
- [ ] src/content/accessibility-docs/{pattern}/en.mdx
Expand Down
9 changes: 7 additions & 2 deletions .internal/site-specification.md
Original file line number Diff line number Diff line change
Expand Up @@ -221,7 +221,11 @@ src/
├── patterns/ # APG パターン実装
│ └── button/ # 例: button パターン
│ ├── meta.ts # パターンメタデータ(単一の真実源)
│ ├── DemoSection.astro # 全フレームワーク統合デモ
│ ├── DemoSection.react.astro # React 用デモ
│ ├── DemoSection.vue.astro # Vue 用デモ
│ ├── DemoSection.svelte.astro # Svelte 用デモ
│ ├── DemoSection.web-component.astro # Astro Web Component 用デモ
│ ├── {pattern}-demo-data.ts # 共通 demo data(必要なときのみ)
│ ├── TestingDocs.astro # テストドキュメント
│ ├── Button.tsx # React 実装
│ ├── Button.vue # Vue 実装
Expand Down Expand Up @@ -266,7 +270,8 @@ src/
各パターンの `meta.ts` が `PatternMeta` 型でメタデータを一元定義する。動的ルーティング(`[pattern]/[framework]/index.astro`)が `import.meta.glob()` で全パターンの `meta.ts` を検出し、`getStaticPaths()` で 4フレームワーク × 2言語 のページをビルド時に生成する。

- **`meta.ts`**: タイトル、説明、TOC、リソース、フレームワーク別 API ドキュメント。全テキストは `Record<Locale, string>` で i18n 対応
- **`DemoSection.astro`**: 4フレームワークの実装を静的 import し、`framework` prop で切り替え表示
- **`DemoSection.{react,vue,svelte,web-component}.astro`**: framework ごとに分割した薄い Astro。それぞれ自分の framework の実装ファイルだけを静的 import する。ページ側 dispatcher が `framework` から該当ファイルを選んで動的 import で呼ぶ
- **`{pattern}-demo-data.ts`** (任意): 4 framework で内容が完全に同一かつ概ね 8 行以上の純 data を切り出した共通ファイル
- **`content/accessibility-docs/`**: MDX でアクセシビリティ解説を記述。frontmatter は `pattern` と `locale` のみ

---
Expand Down
19 changes: 8 additions & 11 deletions CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -43,12 +43,11 @@ src/
├── patterns/ # APG パターン実装
│ └── button/ # 例: button パターン
│ ├── meta.ts # パターンメタデータ(単一の真実源)
│ ├── DemoSection.astro # 全フレームワーク統合デモ(legacy)
│ │ # ↓ または framework 別に分割(後述)
│ ├── DemoSection.react.astro # React 用デモ(split 後)
│ ├── DemoSection.vue.astro # Vue 用デモ(split 後)
│ ├── DemoSection.svelte.astro # Svelte 用デモ(split 後)
│ ├── DemoSection.web-component.astro # Astro Web Component 用(split 後)
│ ├── DemoSection.react.astro # React 用デモ
│ ├── DemoSection.vue.astro # Vue 用デモ
│ ├── DemoSection.svelte.astro # Svelte 用デモ
│ ├── DemoSection.web-component.astro # Astro Web Component 用デモ
│ ├── {pattern}-demo-data.ts # 共通 demo data(必要なときのみ。後述)
│ ├── TestingDocs.astro # テストドキュメント
│ ├── Button.tsx # React 実装
│ ├── Button.vue # Vue 実装
Expand Down Expand Up @@ -83,11 +82,9 @@ src/
各パターンの `meta.ts` が単一の真実源(Single Source of Truth)となる。1つの `meta.ts` から 4フレームワーク × 2言語 = 8ページが動的に生成される。

- **`meta.ts`**: タイトル、説明、TOC、リソース、フレームワーク別メタデータ(ソースファイル、API Props/Events/Slots)を `PatternMeta` 型で定義。全テキストは `Record<Locale, string>` で i18n 対応
- **`DemoSection.*.astro`** (推奨): framework ごとに分割した薄い Astro。`DemoSection.{react,vue,svelte,web-component}.astro` が、それぞれ自分の framework の実装ファイルだけを静的 import する。ページ側 dispatcher が `framework` から該当ファイルを選んで呼ぶ
- **`{pattern}-demo-data.ts`** (任意): 4 framework で内容が完全に同一かつ概ね 8 行以上の純 data (配列/オブジェクトリテラル) を切り出した共通ファイル。framework 固有の prop 名 (Vue `ariaLabel` ↔ React/Astro `aria-label`) や関数 (`renderCell` など) は含めず、各 `DemoSection.{framework}.astro` 側で吸収する
- **`DemoSection.astro`** (legacy): 4 framework の実装を 1 ファイルで静的 import する旧形式。dispatcher にフォールバックとして残してあり、まだ移行していない pattern で使われている。**注意**: legacy 形式は `@vitejs/plugin-react v6` + Vite 8 + Vue SFC `<script setup lang="ts">` の組み合わせで dev 限定の `$RefreshSig$` エラーを引き起こすことがあるため、Vue SFC を含むパターンは新形式に移行することを推奨
- **移行状況** (transitional): PR #169 で 9 pattern (alert / checkbox / combobox / disclosure / menu-button / menubar / slider / slider-multithumb / toolbar)、PR-A で 7 pattern (accordion / listbox / radio-group / tabs / tree-view / table / treegrid) を分割済み。残り 16 pattern は legacy のまま (PR-B で対応予定)。最終的に legacy 形式と dispatcher fallback は撤去する
- **動的ルーティング**: `[pattern]/[framework]/index.astro` が `import.meta.glob()` で全パターンの `meta.ts` を検出し、`getStaticPaths()` でビルド時にページ生成。同じファイル内の dispatcher が `DemoSection.{framework}.astro` を優先し、無ければ legacy `DemoSection.astro` にフォールバック
- **`DemoSection.{react,vue,svelte,web-component}.astro`**: framework ごとに分割した薄い Astro。それぞれ自分の framework の実装ファイルだけを静的 import する。`Astro.props` から `locale` のみを受け取り、`framework` prop は持たない。pages 側 dispatcher が `framework` から該当ファイルを選んで呼ぶ
- **`{pattern}-demo-data.ts`** (任意): 4 framework で内容が完全に同一かつ概ね 8 行以上の純 data (配列/オブジェクトリテラル) を切り出した共通ファイル。framework 固有の prop 名 (Vue `ariaLabel` ↔ React/Astro `aria-label`) や関数 (`renderCell` など) は含めず、各 `DemoSection.{framework}.astro` 側で吸収する。共有 data が小さい (8 行未満) または framework 間で差があるパターンでは作らない
- **動的ルーティング**: `[pattern]/[framework]/index.astro` が `import.meta.glob()` で全パターンの `meta.ts` を検出し、`getStaticPaths()` でビルド時にページ生成。同じファイル内の dispatcher が `DemoSection.${framework}.astro` (Astro Web Component は `web-component`) を `import.meta.glob` 経由で動的 import する。loader 欠落時は `throw` する設計(`getStaticPaths` が valid な組み合わせのみ生成する前提)

**パスエイリアス**(tsconfig.json):

Expand Down
10 changes: 7 additions & 3 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -183,9 +183,13 @@ Each pattern should include:

```
src/patterns/{pattern}/
├── meta.ts # Pattern metadata (single source of truth)
├── DemoSection.astro # Unified demo for all frameworks
├── TestingDocs.astro # Test documentation
├── meta.ts # Pattern metadata (single source of truth)
├── DemoSection.react.astro # React demo
├── DemoSection.vue.astro # Vue demo
├── DemoSection.svelte.astro # Svelte demo
├── DemoSection.web-component.astro # Astro Web Component demo
├── {pattern}-demo-data.ts # Shared demo data (optional)
├── TestingDocs.astro # Test documentation
├── {Pattern}.tsx # React implementation
├── {Pattern}.vue # Vue implementation
├── {Pattern}.svelte # Svelte implementation
Expand Down
19 changes: 7 additions & 12 deletions src/pages/ja/patterns/[pattern]/[framework]/index.astro
Original file line number Diff line number Diff line change
Expand Up @@ -24,11 +24,10 @@
import type { PatternMeta } from '@/lib/pattern-meta-types';

// Glob imports for dynamic content loading
const demoModules = import.meta.glob<{ default: any }>('/src/patterns/*/DemoSection.astro');
const demoReactModules = import.meta.glob<{ default: any }>(

Check warning on line 27 in src/pages/ja/patterns/[pattern]/[framework]/index.astro

View workflow job for this annotation

GitHub Actions / lint

Unexpected any. Specify a different type
'/src/patterns/*/DemoSection.react.astro'
);
const demoVueModules = import.meta.glob<{ default: any }>('/src/patterns/*/DemoSection.vue.astro');

Check warning on line 30 in src/pages/ja/patterns/[pattern]/[framework]/index.astro

View workflow job for this annotation

GitHub Actions / lint

Unexpected any. Specify a different type
const demoSvelteModules = import.meta.glob<{ default: any }>(
'/src/patterns/*/DemoSection.svelte.astro'
);
Expand Down Expand Up @@ -100,16 +99,12 @@
const fwInfo = FRAMEWORK_INFO[framework];

// Load dynamic components
// Prefer framework-specific DemoSection (DemoSection.{framework}.astro) if present,
// fall back to the legacy unified DemoSection.astro during migration.
const newDemoLoader =
frameworkDemoModules[framework][
`/src/patterns/${pattern}/DemoSection.${frameworkDemoKey[framework]}.astro`
];
const legacyDemoLoader = demoModules[`/src/patterns/${pattern}/DemoSection.astro`];
const DemoSection = newDemoLoader
? ((await newDemoLoader()).default as any)
: ((await legacyDemoLoader?.())?.default as any);
const demoLoaderPath = `/src/patterns/${pattern}/DemoSection.${frameworkDemoKey[framework]}.astro`;
const demoLoader = frameworkDemoModules[framework][demoLoaderPath];
if (!demoLoader) {
throw new Error(`DemoSection not found: ${demoLoaderPath}`);
}
const DemoSection = (await demoLoader()).default as any;
const TestingDocs = (await testingModules[`/src/patterns/${pattern}/TestingDocs.astro`]?.())
?.default as any;
const NativeHtmlNotice = meta.hasNativeHtmlNotice
Expand Down Expand Up @@ -166,7 +161,7 @@
<!-- Demo Section -->
<section class="mb-12">
<Heading level={2} id="demo" class="mb-4 text-xl font-semibold">{t('pattern.demo')}</Heading>
{DemoSection && <DemoSection framework={framework} locale={locale} />}
<DemoSection locale={locale} />
<p class="text-muted-foreground mt-2 text-sm">
<a href="./demo/" class="text-primary hover:underline">デモのみ表示 →</a>
</p>
Expand Down
19 changes: 7 additions & 12 deletions src/pages/patterns/[pattern]/[framework]/index.astro
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,6 @@ import { getPatterns } from '@/lib/patterns';
import type { PatternMeta } from '@/lib/pattern-meta-types';

// Glob imports for dynamic content loading
const demoModules = import.meta.glob<{ default: any }>('/src/patterns/*/DemoSection.astro');
const demoReactModules = import.meta.glob<{ default: any }>(
'/src/patterns/*/DemoSection.react.astro'
);
Expand Down Expand Up @@ -101,16 +100,12 @@ if (!fwMeta) {
const fwInfo = FRAMEWORK_INFO[framework];

// Load dynamic components
// Prefer framework-specific DemoSection (DemoSection.{framework}.astro) if present,
// fall back to the legacy unified DemoSection.astro during migration.
const newDemoLoader =
frameworkDemoModules[framework][
`/src/patterns/${pattern}/DemoSection.${frameworkDemoKey[framework]}.astro`
];
const legacyDemoLoader = demoModules[`/src/patterns/${pattern}/DemoSection.astro`];
const DemoSection = newDemoLoader
? ((await newDemoLoader()).default as any)
: ((await legacyDemoLoader?.())?.default as any);
const demoLoaderPath = `/src/patterns/${pattern}/DemoSection.${frameworkDemoKey[framework]}.astro`;
const demoLoader = frameworkDemoModules[framework][demoLoaderPath];
if (!demoLoader) {
throw new Error(`DemoSection not found: ${demoLoaderPath}`);
}
const DemoSection = (await demoLoader()).default as any;
const TestingDocs = (await testingModules[`/src/patterns/${pattern}/TestingDocs.astro`]?.())
?.default as any;
const NativeHtmlNotice = meta.hasNativeHtmlNotice
Expand Down Expand Up @@ -166,7 +161,7 @@ const { Content: AccessibilityContent } = await getAccessibilityContent(pattern,
<!-- Demo Section -->
<section class="mb-12">
<Heading level={2} class="mb-4 text-xl font-semibold">Demo</Heading>
{DemoSection && <DemoSection framework={framework} locale={locale} />}
<DemoSection locale={locale} />
<p class="text-muted-foreground mt-2 text-sm">
<a href="./demo/" class="text-primary hover:underline">Open demo only →</a>
</p>
Expand Down
2 changes: 0 additions & 2 deletions src/patterns/accordion/DemoSection.react.astro
Original file line number Diff line number Diff line change
@@ -1,11 +1,9 @@
---
import type { Framework } from '@/lib/frameworks';
import type { Locale } from '@/i18n/ui';
import { Accordion as AccordionReact } from './Accordion';
import { defaultItems, multipleItems, disabledItems } from './accordion-demo-data';

interface Props {
framework?: Framework;
locale?: Locale;
}

Expand Down
2 changes: 0 additions & 2 deletions src/patterns/accordion/DemoSection.svelte.astro
Original file line number Diff line number Diff line change
@@ -1,11 +1,9 @@
---
import type { Framework } from '@/lib/frameworks';
import type { Locale } from '@/i18n/ui';
import AccordionSvelte from './Accordion.svelte';
import { defaultItems, multipleItems, disabledItems } from './accordion-demo-data';

interface Props {
framework?: Framework;
locale?: Locale;
}

Expand Down
2 changes: 0 additions & 2 deletions src/patterns/accordion/DemoSection.vue.astro
Original file line number Diff line number Diff line change
@@ -1,11 +1,9 @@
---
import type { Framework } from '@/lib/frameworks';
import type { Locale } from '@/i18n/ui';
import AccordionVue from './Accordion.vue';
import { defaultItems, multipleItems, disabledItems } from './accordion-demo-data';

interface Props {
framework?: Framework;
locale?: Locale;
}

Expand Down
2 changes: 0 additions & 2 deletions src/patterns/accordion/DemoSection.web-component.astro
Original file line number Diff line number Diff line change
@@ -1,11 +1,9 @@
---
import type { Framework } from '@/lib/frameworks';
import type { Locale } from '@/i18n/ui';
import AccordionAstro from './Accordion.astro';
import { defaultItems, multipleItems, disabledItems } from './accordion-demo-data';

interface Props {
framework?: Framework;
locale?: Locale;
}

Expand Down
Loading
Loading