From c864c202ba5c8cf540fb8038f7d696b9f0851d0b Mon Sep 17 00:00:00 2001 From: masuP9 Date: Mon, 11 May 2026 19:30:17 +0900 Subject: [PATCH 1/8] refactor(tabs): split DemoSection into framework-specific files with shared demo data Apply the PR #169 framework-split convention to the tabs pattern, plus extract shared variant data (demoTabs / manualTabs / verticalTabs) into a dedicated `tabs-demo-data.ts` to avoid duplicating ~20 lines of data across the four framework files. The shared data rule (per the migration plan): - 4 frameworks reference the data identically (8+ lines, pure data only) - framework-specific prop name differences (e.g. `activationMode` vs `activation`, `label` vs `defaultSelectedId`) stay in each per-framework DemoSection file Verified: - /patterns/tabs/{react,vue,svelte,astro}/ return 200 (en) - /ja/patterns/tabs/{react,vue,svelte,astro}/ return 200 (ja) Co-Authored-By: Claude Opus 4.7 (1M context) --- src/patterns/tabs/DemoSection.astro | 162 ------------------ src/patterns/tabs/DemoSection.react.astro | 58 +++++++ src/patterns/tabs/DemoSection.svelte.astro | 63 +++++++ src/patterns/tabs/DemoSection.vue.astro | 58 +++++++ .../tabs/DemoSection.web-component.astro | 58 +++++++ src/patterns/tabs/tabs-demo-data.ts | 38 ++++ 6 files changed, 275 insertions(+), 162 deletions(-) delete mode 100644 src/patterns/tabs/DemoSection.astro create mode 100644 src/patterns/tabs/DemoSection.react.astro create mode 100644 src/patterns/tabs/DemoSection.svelte.astro create mode 100644 src/patterns/tabs/DemoSection.vue.astro create mode 100644 src/patterns/tabs/DemoSection.web-component.astro create mode 100644 src/patterns/tabs/tabs-demo-data.ts diff --git a/src/patterns/tabs/DemoSection.astro b/src/patterns/tabs/DemoSection.astro deleted file mode 100644 index f9e351cb..00000000 --- a/src/patterns/tabs/DemoSection.astro +++ /dev/null @@ -1,162 +0,0 @@ ---- -/** - * Tabs Demo Section - * - * Renders the tabs demo for each framework variant. - * Each framework's component is statically imported to support - * Astro's client:load directive for hydration. - * - * The tabs pattern has three demo variants: - * - Automatic Activation (default) - * - Manual Activation - * - Vertical Orientation - */ -import type { Framework } from '@/lib/frameworks'; -import type { Locale } from '@/i18n/ui'; -import TabsReact from './Tabs'; -import TabsVue from './Tabs.vue'; -import TabsSvelte from './Tabs.svelte'; -import TabsAstro from './Tabs.astro'; - -interface Props { - framework: Framework; - locale?: Locale; -} - -const { framework, locale = 'en' } = Astro.props; -const isJa = locale === 'ja'; - -const demoTabs = [ - { - id: 'tab1', - label: 'Overview', - content: - 'This is the overview panel content. It provides a general introduction to the product or service.', - }, - { - id: 'tab2', - label: 'Features', - content: 'Keyboard navigation support, ARIA compliant, Automatic and manual activation modes.', - }, - { id: 'tab3', label: 'Pricing', content: 'Pricing information would be displayed here.' }, -]; - -const manualTabs = [ - { - id: 'manual1', - label: 'Tab One', - content: 'Content for tab one. Press Enter or Space to activate tabs.', - }, - { id: 'manual2', label: 'Tab Two', content: 'Content for tab two.' }, - { id: 'manual3', label: 'Tab Three', content: 'Content for tab three.' }, -]; - -const verticalTabs = [ - { id: 'vert1', label: 'Settings', content: 'Configure your application settings here.' }, - { id: 'vert2', label: 'Profile', content: 'Manage your profile information.' }, - { id: 'vert3', label: 'Notifications', content: 'Set your notification preferences.' }, -]; ---- - - -
-

- {isJa ? '自動アクティベーション(デフォルト)' : 'Automatic Activation (Default)'} -

-

- { - isJa - ? '矢印キーでフォーカスすると、タブが自動的にアクティブになります。' - : 'Tabs are activated automatically when focused with arrow keys.' - } -

-
- {framework === 'react' && } - {framework === 'vue' && } - {framework === 'svelte' && } - {framework === 'astro' && } -
-
- - -
-

{isJa ? '手動アクティベーション' : 'Manual Activation'}

-

- { - isJa - ? 'フォーカス後に Enter または Space キーでタブをアクティブにします。' - : 'Tabs require Enter or Space to activate after focusing.' - } -

-
- { - framework === 'react' && ( - - ) - } - { - framework === 'vue' && ( - - ) - } - { - framework === 'svelte' && ( - - ) - } - { - framework === 'astro' && ( - - ) - } -
-
- - -
-

{isJa ? '垂直方向' : 'Vertical Orientation'}

-

- { - isJa - ? '上下矢印キーで操作する縦並びのタブ。' - : 'Tabs arranged vertically with Up/Down arrow navigation.' - } -

-
- { - framework === 'react' && ( - - ) - } - { - framework === 'vue' && ( - - ) - } - { - framework === 'svelte' && ( - - ) - } - { - framework === 'astro' && ( - - ) - } -
-
diff --git a/src/patterns/tabs/DemoSection.react.astro b/src/patterns/tabs/DemoSection.react.astro new file mode 100644 index 00000000..b2cac468 --- /dev/null +++ b/src/patterns/tabs/DemoSection.react.astro @@ -0,0 +1,58 @@ +--- +import type { Framework } from '@/lib/frameworks'; +import type { Locale } from '@/i18n/ui'; +import TabsReact from './Tabs'; +import { demoTabs, manualTabs, verticalTabs } from './tabs-demo-data'; + +interface Props { + framework?: Framework; + locale?: Locale; +} + +const { locale = 'en' } = Astro.props; +const isJa = locale === 'ja'; +--- + +
+

+ {isJa ? '自動アクティベーション(デフォルト)' : 'Automatic Activation (Default)'} +

+

+ { + isJa + ? '矢印キーでフォーカスすると、タブが自動的にアクティブになります。' + : 'Tabs are activated automatically when focused with arrow keys.' + } +

+
+ +
+
+ +
+

{isJa ? '手動アクティベーション' : 'Manual Activation'}

+

+ { + isJa + ? 'フォーカス後に Enter または Space キーでタブをアクティブにします。' + : 'Tabs require Enter or Space to activate after focusing.' + } +

+
+ +
+
+ +
+

{isJa ? '垂直方向' : 'Vertical Orientation'}

+

+ { + isJa + ? '上下矢印キーで操作する縦並びのタブ。' + : 'Tabs arranged vertically with Up/Down arrow navigation.' + } +

+
+ +
+
diff --git a/src/patterns/tabs/DemoSection.svelte.astro b/src/patterns/tabs/DemoSection.svelte.astro new file mode 100644 index 00000000..f922ef25 --- /dev/null +++ b/src/patterns/tabs/DemoSection.svelte.astro @@ -0,0 +1,63 @@ +--- +import type { Framework } from '@/lib/frameworks'; +import type { Locale } from '@/i18n/ui'; +import TabsSvelte from './Tabs.svelte'; +import { demoTabs, manualTabs, verticalTabs } from './tabs-demo-data'; + +interface Props { + framework?: Framework; + locale?: Locale; +} + +const { locale = 'en' } = Astro.props; +const isJa = locale === 'ja'; +--- + +
+

+ {isJa ? '自動アクティベーション(デフォルト)' : 'Automatic Activation (Default)'} +

+

+ { + isJa + ? '矢印キーでフォーカスすると、タブが自動的にアクティブになります。' + : 'Tabs are activated automatically when focused with arrow keys.' + } +

+
+ +
+
+ +
+

{isJa ? '手動アクティベーション' : 'Manual Activation'}

+

+ { + isJa + ? 'フォーカス後に Enter または Space キーでタブをアクティブにします。' + : 'Tabs require Enter or Space to activate after focusing.' + } +

+
+ +
+
+ +
+

{isJa ? '垂直方向' : 'Vertical Orientation'}

+

+ { + isJa + ? '上下矢印キーで操作する縦並びのタブ。' + : 'Tabs arranged vertically with Up/Down arrow navigation.' + } +

+
+ +
+
diff --git a/src/patterns/tabs/DemoSection.vue.astro b/src/patterns/tabs/DemoSection.vue.astro new file mode 100644 index 00000000..ee1648e9 --- /dev/null +++ b/src/patterns/tabs/DemoSection.vue.astro @@ -0,0 +1,58 @@ +--- +import type { Framework } from '@/lib/frameworks'; +import type { Locale } from '@/i18n/ui'; +import TabsVue from './Tabs.vue'; +import { demoTabs, manualTabs, verticalTabs } from './tabs-demo-data'; + +interface Props { + framework?: Framework; + locale?: Locale; +} + +const { locale = 'en' } = Astro.props; +const isJa = locale === 'ja'; +--- + +
+

+ {isJa ? '自動アクティベーション(デフォルト)' : 'Automatic Activation (Default)'} +

+

+ { + isJa + ? '矢印キーでフォーカスすると、タブが自動的にアクティブになります。' + : 'Tabs are activated automatically when focused with arrow keys.' + } +

+
+ +
+
+ +
+

{isJa ? '手動アクティベーション' : 'Manual Activation'}

+

+ { + isJa + ? 'フォーカス後に Enter または Space キーでタブをアクティブにします。' + : 'Tabs require Enter or Space to activate after focusing.' + } +

+
+ +
+
+ +
+

{isJa ? '垂直方向' : 'Vertical Orientation'}

+

+ { + isJa + ? '上下矢印キーで操作する縦並びのタブ。' + : 'Tabs arranged vertically with Up/Down arrow navigation.' + } +

+
+ +
+
diff --git a/src/patterns/tabs/DemoSection.web-component.astro b/src/patterns/tabs/DemoSection.web-component.astro new file mode 100644 index 00000000..6357a3ae --- /dev/null +++ b/src/patterns/tabs/DemoSection.web-component.astro @@ -0,0 +1,58 @@ +--- +import type { Framework } from '@/lib/frameworks'; +import type { Locale } from '@/i18n/ui'; +import TabsAstro from './Tabs.astro'; +import { demoTabs, manualTabs, verticalTabs } from './tabs-demo-data'; + +interface Props { + framework?: Framework; + locale?: Locale; +} + +const { locale = 'en' } = Astro.props; +const isJa = locale === 'ja'; +--- + +
+

+ {isJa ? '自動アクティベーション(デフォルト)' : 'Automatic Activation (Default)'} +

+

+ { + isJa + ? '矢印キーでフォーカスすると、タブが自動的にアクティブになります。' + : 'Tabs are activated automatically when focused with arrow keys.' + } +

+
+ +
+
+ +
+

{isJa ? '手動アクティベーション' : 'Manual Activation'}

+

+ { + isJa + ? 'フォーカス後に Enter または Space キーでタブをアクティブにします。' + : 'Tabs require Enter or Space to activate after focusing.' + } +

+
+ +
+
+ +
+

{isJa ? '垂直方向' : 'Vertical Orientation'}

+

+ { + isJa + ? '上下矢印キーで操作する縦並びのタブ。' + : 'Tabs arranged vertically with Up/Down arrow navigation.' + } +

+
+ +
+
diff --git a/src/patterns/tabs/tabs-demo-data.ts b/src/patterns/tabs/tabs-demo-data.ts new file mode 100644 index 00000000..c4bbbc28 --- /dev/null +++ b/src/patterns/tabs/tabs-demo-data.ts @@ -0,0 +1,38 @@ +/** + * Shared demo data for the Tabs pattern. + * + * Pure data shared across all four framework-specific DemoSection files. + * Framework-specific prop names and rendering live in the per-framework + * `DemoSection.{react,vue,svelte,web-component}.astro` files. + */ + +export const demoTabs = [ + { + id: 'tab1', + label: 'Overview', + content: + 'This is the overview panel content. It provides a general introduction to the product or service.', + }, + { + id: 'tab2', + label: 'Features', + content: 'Keyboard navigation support, ARIA compliant, Automatic and manual activation modes.', + }, + { id: 'tab3', label: 'Pricing', content: 'Pricing information would be displayed here.' }, +]; + +export const manualTabs = [ + { + id: 'manual1', + label: 'Tab One', + content: 'Content for tab one. Press Enter or Space to activate tabs.', + }, + { id: 'manual2', label: 'Tab Two', content: 'Content for tab two.' }, + { id: 'manual3', label: 'Tab Three', content: 'Content for tab three.' }, +]; + +export const verticalTabs = [ + { id: 'vert1', label: 'Settings', content: 'Configure your application settings here.' }, + { id: 'vert2', label: 'Profile', content: 'Manage your profile information.' }, + { id: 'vert3', label: 'Notifications', content: 'Set your notification preferences.' }, +]; From f7a8973ee91d4ee0b20b910b183aab8795b3d35f Mon Sep 17 00:00:00 2001 From: masuP9 Date: Mon, 11 May 2026 19:31:51 +0900 Subject: [PATCH 2/8] refactor(treegrid): split DemoSection with bilingual demo data The treegrid pattern has the largest shared demo data: 130 lines covering columnsEn / columnsJa / nodesEn / nodesJa for the Astro Web Component variant (the React/Vue/Svelte variants use locale-specific wrapper components TreeGridDemo / TreeGridDemoJa with their own internal data). Extract the Astro variant's data to treegrid-demo-data.ts and split the DemoSection into four framework files. Also switch the locale check from \`Astro.url.pathname.startsWith('/ja/')\` to the \`locale\` prop, matching the convention established by PR #169. Verified: - /patterns/treegrid/{react,vue,svelte,astro}/ return 200 (en) - /ja/patterns/treegrid/{react,vue,svelte,astro}/ return 200 (ja) Co-Authored-By: Claude Opus 4.7 (1M context) --- src/patterns/treegrid/DemoSection.react.astro | 25 +++++++ .../treegrid/DemoSection.svelte.astro | 25 +++++++ src/patterns/treegrid/DemoSection.vue.astro | 25 +++++++ .../treegrid/DemoSection.web-component.astro | 36 ++++++++++ ...emoSection.astro => treegrid-demo-data.ts} | 67 +++---------------- 5 files changed, 120 insertions(+), 58 deletions(-) create mode 100644 src/patterns/treegrid/DemoSection.react.astro create mode 100644 src/patterns/treegrid/DemoSection.svelte.astro create mode 100644 src/patterns/treegrid/DemoSection.vue.astro create mode 100644 src/patterns/treegrid/DemoSection.web-component.astro rename src/patterns/treegrid/{DemoSection.astro => treegrid-demo-data.ts} (62%) diff --git a/src/patterns/treegrid/DemoSection.react.astro b/src/patterns/treegrid/DemoSection.react.astro new file mode 100644 index 00000000..7d6e3b7f --- /dev/null +++ b/src/patterns/treegrid/DemoSection.react.astro @@ -0,0 +1,25 @@ +--- +import type { Framework } from '@/lib/frameworks'; +import type { Locale } from '@/i18n/ui'; +import TreeGridDemoReact from './TreeGridDemo'; +import { TreeGridDemoJa as TreeGridDemoJaReact } from './TreeGridDemoJa'; + +interface Props { + framework?: Framework; + locale?: Locale; +} + +const { locale = 'en' } = Astro.props; +const isJa = locale === 'ja'; + +const demoDescription = isJa + ? '矢印キーで移動。rowheaderでArrowRight/Leftで展開/折りたたみ。Spaceで行を選択。' + : 'Navigate with arrow keys. At rowheader, use ArrowRight/Left to expand/collapse. Press Space to select rows.'; +--- + +
+

+ {demoDescription} +

+ {isJa ? : } +
diff --git a/src/patterns/treegrid/DemoSection.svelte.astro b/src/patterns/treegrid/DemoSection.svelte.astro new file mode 100644 index 00000000..59f8c9c3 --- /dev/null +++ b/src/patterns/treegrid/DemoSection.svelte.astro @@ -0,0 +1,25 @@ +--- +import type { Framework } from '@/lib/frameworks'; +import type { Locale } from '@/i18n/ui'; +import TreeGridDemoSvelte from './TreeGridDemo.svelte'; +import TreeGridDemoJaSvelte from './TreeGridDemoJa.svelte'; + +interface Props { + framework?: Framework; + locale?: Locale; +} + +const { locale = 'en' } = Astro.props; +const isJa = locale === 'ja'; + +const demoDescription = isJa + ? '矢印キーで移動。rowheaderでArrowRight/Leftで展開/折りたたみ。Spaceで行を選択。' + : 'Navigate with arrow keys. At rowheader, use ArrowRight/Left to expand/collapse. Press Space to select rows.'; +--- + +
+

+ {demoDescription} +

+ {isJa ? : } +
diff --git a/src/patterns/treegrid/DemoSection.vue.astro b/src/patterns/treegrid/DemoSection.vue.astro new file mode 100644 index 00000000..b874463f --- /dev/null +++ b/src/patterns/treegrid/DemoSection.vue.astro @@ -0,0 +1,25 @@ +--- +import type { Framework } from '@/lib/frameworks'; +import type { Locale } from '@/i18n/ui'; +import TreeGridDemoVue from './TreeGridDemo.vue'; +import TreeGridDemoJaVue from './TreeGridDemoJa.vue'; + +interface Props { + framework?: Framework; + locale?: Locale; +} + +const { locale = 'en' } = Astro.props; +const isJa = locale === 'ja'; + +const demoDescription = isJa + ? '矢印キーで移動。rowheaderでArrowRight/Leftで展開/折りたたみ。Spaceで行を選択。' + : 'Navigate with arrow keys. At rowheader, use ArrowRight/Left to expand/collapse. Press Space to select rows.'; +--- + +
+

+ {demoDescription} +

+ {isJa ? : } +
diff --git a/src/patterns/treegrid/DemoSection.web-component.astro b/src/patterns/treegrid/DemoSection.web-component.astro new file mode 100644 index 00000000..e78a0071 --- /dev/null +++ b/src/patterns/treegrid/DemoSection.web-component.astro @@ -0,0 +1,36 @@ +--- +import type { Framework } from '@/lib/frameworks'; +import type { Locale } from '@/i18n/ui'; +import TreeGridAstro from './TreeGrid.astro'; +import { columnsEn, columnsJa, nodesEn, nodesJa } from './treegrid-demo-data'; + +interface Props { + framework?: Framework; + locale?: Locale; +} + +const { locale = 'en' } = Astro.props; +const isJa = locale === 'ja'; + +const demoDescription = isJa + ? '矢印キーで移動。rowheaderでArrowRight/Leftで展開/折りたたみ。Spaceで行を選択。' + : 'Navigate with arrow keys. At rowheader, use ArrowRight/Left to expand/collapse. Press Space to select rows.'; + +const columns = isJa ? columnsJa : columnsEn; +const nodes = isJa ? nodesJa : nodesEn; +const ariaLabel = isJa ? 'ファイルブラウザ' : 'File browser'; +--- + +
+

+ {demoDescription} +

+ +
diff --git a/src/patterns/treegrid/DemoSection.astro b/src/patterns/treegrid/treegrid-demo-data.ts similarity index 62% rename from src/patterns/treegrid/DemoSection.astro rename to src/patterns/treegrid/treegrid-demo-data.ts index 7db3ba27..da5c92d4 100644 --- a/src/patterns/treegrid/DemoSection.astro +++ b/src/patterns/treegrid/treegrid-demo-data.ts @@ -1,38 +1,19 @@ ---- /** - * TreeGrid Demo Section + * Shared demo data for the TreeGrid pattern (Astro Web Component variant). * - * Renders the treegrid demo for each framework variant. - * Uses locale-specific demo components for Japanese pages. + * The React / Vue / Svelte demos use locale-specific wrapper components + * (`TreeGridDemo` / `TreeGridDemoJa`); only the Astro Web Component variant + * consumes the raw data, but exposing both locales here keeps demo data + * colocated and avoids inlining ~130 lines into a single .astro file. */ -import type { Framework } from '@/lib/frameworks'; -import TreeGridDemoReact from './TreeGridDemo'; -import { TreeGridDemoJa as TreeGridDemoJaReact } from './TreeGridDemoJa'; -import TreeGridDemoVue from './TreeGridDemo.vue'; -import TreeGridDemoJaVue from './TreeGridDemoJa.vue'; -import TreeGridDemoSvelte from './TreeGridDemo.svelte'; -import TreeGridDemoJaSvelte from './TreeGridDemoJa.svelte'; -import TreeGridAstro from './TreeGrid.astro'; -interface Props { - framework: Framework; -} - -const { framework } = Astro.props; -const isJa = Astro.url.pathname.startsWith('/ja/'); - -const demoDescription = isJa - ? '矢印キーで移動。rowheaderでArrowRight/Leftで展開/折りたたみ。Spaceで行を選択。' - : 'Navigate with arrow keys. At rowheader, use ArrowRight/Left to expand/collapse. Press Space to select rows.'; - -// Astro demo data (English) -const columnsEn = [ +export const columnsEn = [ { id: 'name', header: 'Name', isRowHeader: true }, { id: 'size', header: 'Size' }, { id: 'date', header: 'Date Modified' }, ]; -const nodesEn = [ +export const nodesEn = [ { id: 'docs', cells: [ @@ -71,14 +52,13 @@ const nodesEn = [ }, ]; -// Astro demo data (Japanese) -const columnsJa = [ +export const columnsJa = [ { id: 'name', header: '名前', isRowHeader: true }, { id: 'size', header: 'サイズ' }, { id: 'date', header: '更新日' }, ]; -const nodesJa = [ +export const nodesJa = [ { id: 'docs', cells: [ @@ -160,32 +140,3 @@ const nodesJa = [ ], }, ]; - -const columns = isJa ? columnsJa : columnsEn; -const nodes = isJa ? nodesJa : nodesEn; -const ariaLabel = isJa ? 'ファイルブラウザ' : 'File browser'; ---- - -
-

- {demoDescription} -

- {framework === 'react' && !isJa && } - {framework === 'react' && isJa && } - {framework === 'vue' && !isJa && } - {framework === 'vue' && isJa && } - {framework === 'svelte' && !isJa && } - {framework === 'svelte' && isJa && } - { - framework === 'astro' && ( - - ) - } -
From 11dc59d6d89c0d3c553555fd01e3761e98080682 Mon Sep 17 00:00:00 2001 From: masuP9 Date: Mon, 11 May 2026 19:33:16 +0900 Subject: [PATCH 3/8] refactor(accordion): split DemoSection with shared variant data Extract defaultItems / multipleItems / disabledItems to accordion-demo-data.ts and split DemoSection into four framework files. Verified: /patterns/accordion/{react,vue,svelte,astro}/ and the /ja/ variants all return 200. Co-Authored-By: Claude Opus 4.7 (1M context) --- src/patterns/accordion/DemoSection.astro | 166 ------------------ .../accordion/DemoSection.react.astro | 61 +++++++ .../accordion/DemoSection.svelte.astro | 61 +++++++ src/patterns/accordion/DemoSection.vue.astro | 61 +++++++ .../accordion/DemoSection.web-component.astro | 61 +++++++ src/patterns/accordion/accordion-demo-data.ts | 64 +++++++ 6 files changed, 308 insertions(+), 166 deletions(-) delete mode 100644 src/patterns/accordion/DemoSection.astro create mode 100644 src/patterns/accordion/DemoSection.react.astro create mode 100644 src/patterns/accordion/DemoSection.svelte.astro create mode 100644 src/patterns/accordion/DemoSection.vue.astro create mode 100644 src/patterns/accordion/DemoSection.web-component.astro create mode 100644 src/patterns/accordion/accordion-demo-data.ts diff --git a/src/patterns/accordion/DemoSection.astro b/src/patterns/accordion/DemoSection.astro deleted file mode 100644 index fbede0bb..00000000 --- a/src/patterns/accordion/DemoSection.astro +++ /dev/null @@ -1,166 +0,0 @@ ---- -/** - * Accordion Demo Section - * - * Renders the accordion demo for each framework variant. - * Includes three demos: single expansion, multiple expansion, and disabled items. - */ -import type { Framework } from '@/lib/frameworks'; -import type { Locale } from '@/i18n/ui'; -import { Accordion as AccordionReact } from './Accordion'; -import AccordionVue from './Accordion.vue'; -import AccordionSvelte from './Accordion.svelte'; -import AccordionAstro from './Accordion.astro'; - -interface Props { - framework: Framework; - locale?: Locale; -} - -const { framework, locale = 'en' } = Astro.props; -const isJa = locale === 'ja'; - -const defaultItems = [ - { - id: 'section1', - header: 'What is an Accordion?', - content: - 'An accordion is a vertically stacked set of interactive headings that each reveal a section of content. They are commonly used to reduce the need to scroll when presenting multiple sections of content on a single page.', - defaultExpanded: true, - }, - { - id: 'section2', - header: 'When to use an Accordion?', - content: - 'Use accordions when you need to organize content into collapsible sections. This helps reduce visual clutter while keeping information accessible. They are particularly useful for FAQs, settings panels, and navigation menus.', - }, - { - id: 'section3', - header: 'Accessibility Considerations', - content: - 'Accordions must be keyboard accessible and properly announce their expanded/collapsed state to screen readers. Each header should be a proper heading element, and the panel should be associated with its header via aria-controls and aria-labelledby.', - }, -]; - -const multipleItems = [ - { - id: 'multi1', - header: 'Section One', - content: - 'Content for section one. With allowMultiple enabled, multiple sections can be open at the same time.', - }, - { - id: 'multi2', - header: 'Section Two', - content: 'Content for section two. Try opening this while section one is still open.', - }, - { - id: 'multi3', - header: 'Section Three', - content: 'Content for section three. All three sections can be expanded simultaneously.', - }, -]; - -const disabledItems = [ - { - id: 'dis1', - header: 'Available Section', - content: 'This section can be expanded and collapsed normally.', - }, - { - id: 'dis2', - header: 'Disabled Section', - content: 'This content is not accessible because the section is disabled.', - disabled: true, - }, - { - id: 'dis3', - header: 'Another Available Section', - content: - 'This section can also be expanded. Notice that arrow key navigation skips the disabled section.', - }, -]; ---- - -
- -
-

- {isJa ? '単一展開(デフォルト)' : 'Single Expansion (Default)'} -

-

- { - isJa - ? '同時に1つのパネルのみ展開できます。新しいパネルを開くと、前に開いていたパネルが閉じます。' - : 'Only one panel can be expanded at a time. Opening a new panel closes the previously open one.' - } -

- {framework === 'react' && } - {framework === 'vue' && } - { - framework === 'svelte' && ( - - ) - } - {framework === 'astro' && } -
- - -
-

{isJa ? '複数展開' : 'Multiple Expansion'}

-

- { - isJa ? ( - - allowMultiple プロパティを使用して、複数のパネルを同時に展開できます。 - - ) : ( - - Multiple panels can be expanded simultaneously using the allowMultiple{' '} - prop. - - ) - } -

- { - framework === 'react' && ( - - ) - } - { - framework === 'vue' && ( - - ) - } - { - framework === 'svelte' && ( - - ) - } - { - framework === 'astro' && ( - - ) - } -
- - -
-

{isJa ? '無効な項目あり' : 'With Disabled Items'}

-

- { - isJa - ? '個別のアコーディオン項目を無効にできます。キーボードナビゲーションは無効な項目を自動的にスキップします。' - : 'Individual accordion items can be disabled. Keyboard navigation automatically skips disabled items.' - } -

- {framework === 'react' && } - {framework === 'vue' && } - { - framework === 'svelte' && ( - - ) - } - {framework === 'astro' && } -
-
diff --git a/src/patterns/accordion/DemoSection.react.astro b/src/patterns/accordion/DemoSection.react.astro new file mode 100644 index 00000000..3a26500a --- /dev/null +++ b/src/patterns/accordion/DemoSection.react.astro @@ -0,0 +1,61 @@ +--- +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; +} + +const { locale = 'en' } = Astro.props; +const isJa = locale === 'ja'; +--- + +
+
+

+ {isJa ? '単一展開(デフォルト)' : 'Single Expansion (Default)'} +

+

+ { + isJa + ? '同時に1つのパネルのみ展開できます。新しいパネルを開くと、前に開いていたパネルが閉じます。' + : 'Only one panel can be expanded at a time. Opening a new panel closes the previously open one.' + } +

+ +
+ +
+

{isJa ? '複数展開' : 'Multiple Expansion'}

+

+ { + isJa ? ( + + allowMultiple プロパティを使用して、複数のパネルを同時に展開できます。 + + ) : ( + + Multiple panels can be expanded simultaneously using the allowMultiple{' '} + prop. + + ) + } +

+ +
+ +
+

{isJa ? '無効な項目あり' : 'With Disabled Items'}

+

+ { + isJa + ? '個別のアコーディオン項目を無効にできます。キーボードナビゲーションは無効な項目を自動的にスキップします。' + : 'Individual accordion items can be disabled. Keyboard navigation automatically skips disabled items.' + } +

+ +
+
diff --git a/src/patterns/accordion/DemoSection.svelte.astro b/src/patterns/accordion/DemoSection.svelte.astro new file mode 100644 index 00000000..9a108bf7 --- /dev/null +++ b/src/patterns/accordion/DemoSection.svelte.astro @@ -0,0 +1,61 @@ +--- +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; +} + +const { locale = 'en' } = Astro.props; +const isJa = locale === 'ja'; +--- + +
+
+

+ {isJa ? '単一展開(デフォルト)' : 'Single Expansion (Default)'} +

+

+ { + isJa + ? '同時に1つのパネルのみ展開できます。新しいパネルを開くと、前に開いていたパネルが閉じます。' + : 'Only one panel can be expanded at a time. Opening a new panel closes the previously open one.' + } +

+ +
+ +
+

{isJa ? '複数展開' : 'Multiple Expansion'}

+

+ { + isJa ? ( + + allowMultiple プロパティを使用して、複数のパネルを同時に展開できます。 + + ) : ( + + Multiple panels can be expanded simultaneously using the allowMultiple{' '} + prop. + + ) + } +

+ +
+ +
+

{isJa ? '無効な項目あり' : 'With Disabled Items'}

+

+ { + isJa + ? '個別のアコーディオン項目を無効にできます。キーボードナビゲーションは無効な項目を自動的にスキップします。' + : 'Individual accordion items can be disabled. Keyboard navigation automatically skips disabled items.' + } +

+ +
+
diff --git a/src/patterns/accordion/DemoSection.vue.astro b/src/patterns/accordion/DemoSection.vue.astro new file mode 100644 index 00000000..4ec734e9 --- /dev/null +++ b/src/patterns/accordion/DemoSection.vue.astro @@ -0,0 +1,61 @@ +--- +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; +} + +const { locale = 'en' } = Astro.props; +const isJa = locale === 'ja'; +--- + +
+
+

+ {isJa ? '単一展開(デフォルト)' : 'Single Expansion (Default)'} +

+

+ { + isJa + ? '同時に1つのパネルのみ展開できます。新しいパネルを開くと、前に開いていたパネルが閉じます。' + : 'Only one panel can be expanded at a time. Opening a new panel closes the previously open one.' + } +

+ +
+ +
+

{isJa ? '複数展開' : 'Multiple Expansion'}

+

+ { + isJa ? ( + + allowMultiple プロパティを使用して、複数のパネルを同時に展開できます。 + + ) : ( + + Multiple panels can be expanded simultaneously using the allowMultiple{' '} + prop. + + ) + } +

+ +
+ +
+

{isJa ? '無効な項目あり' : 'With Disabled Items'}

+

+ { + isJa + ? '個別のアコーディオン項目を無効にできます。キーボードナビゲーションは無効な項目を自動的にスキップします。' + : 'Individual accordion items can be disabled. Keyboard navigation automatically skips disabled items.' + } +

+ +
+
diff --git a/src/patterns/accordion/DemoSection.web-component.astro b/src/patterns/accordion/DemoSection.web-component.astro new file mode 100644 index 00000000..6caf6371 --- /dev/null +++ b/src/patterns/accordion/DemoSection.web-component.astro @@ -0,0 +1,61 @@ +--- +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; +} + +const { locale = 'en' } = Astro.props; +const isJa = locale === 'ja'; +--- + +
+
+

+ {isJa ? '単一展開(デフォルト)' : 'Single Expansion (Default)'} +

+

+ { + isJa + ? '同時に1つのパネルのみ展開できます。新しいパネルを開くと、前に開いていたパネルが閉じます。' + : 'Only one panel can be expanded at a time. Opening a new panel closes the previously open one.' + } +

+ +
+ +
+

{isJa ? '複数展開' : 'Multiple Expansion'}

+

+ { + isJa ? ( + + allowMultiple プロパティを使用して、複数のパネルを同時に展開できます。 + + ) : ( + + Multiple panels can be expanded simultaneously using the allowMultiple{' '} + prop. + + ) + } +

+ +
+ +
+

{isJa ? '無効な項目あり' : 'With Disabled Items'}

+

+ { + isJa + ? '個別のアコーディオン項目を無効にできます。キーボードナビゲーションは無効な項目を自動的にスキップします。' + : 'Individual accordion items can be disabled. Keyboard navigation automatically skips disabled items.' + } +

+ +
+
diff --git a/src/patterns/accordion/accordion-demo-data.ts b/src/patterns/accordion/accordion-demo-data.ts new file mode 100644 index 00000000..8a177868 --- /dev/null +++ b/src/patterns/accordion/accordion-demo-data.ts @@ -0,0 +1,64 @@ +/** + * Shared demo data for the Accordion pattern. + */ + +export const defaultItems = [ + { + id: 'section1', + header: 'What is an Accordion?', + content: + 'An accordion is a vertically stacked set of interactive headings that each reveal a section of content. They are commonly used to reduce the need to scroll when presenting multiple sections of content on a single page.', + defaultExpanded: true, + }, + { + id: 'section2', + header: 'When to use an Accordion?', + content: + 'Use accordions when you need to organize content into collapsible sections. This helps reduce visual clutter while keeping information accessible. They are particularly useful for FAQs, settings panels, and navigation menus.', + }, + { + id: 'section3', + header: 'Accessibility Considerations', + content: + 'Accordions must be keyboard accessible and properly announce their expanded/collapsed state to screen readers. Each header should be a proper heading element, and the panel should be associated with its header via aria-controls and aria-labelledby.', + }, +]; + +export const multipleItems = [ + { + id: 'multi1', + header: 'Section One', + content: + 'Content for section one. With allowMultiple enabled, multiple sections can be open at the same time.', + }, + { + id: 'multi2', + header: 'Section Two', + content: 'Content for section two. Try opening this while section one is still open.', + }, + { + id: 'multi3', + header: 'Section Three', + content: 'Content for section three. All three sections can be expanded simultaneously.', + }, +]; + +export const disabledItems = [ + { + id: 'dis1', + header: 'Available Section', + content: 'This section can be expanded and collapsed normally.', + }, + { + id: 'dis2', + header: 'Disabled Section', + content: 'This content is not accessible because the section is disabled.', + disabled: true, + }, + { + id: 'dis3', + header: 'Another Available Section', + content: + 'This section can also be expanded. Notice that arrow key navigation skips the disabled section.', + }, +]; From 7b8641ab1c4e61ec468c831ef35cb943a921439f Mon Sep 17 00:00:00 2001 From: masuP9 Date: Mon, 11 May 2026 19:34:42 +0900 Subject: [PATCH 4/8] refactor(listbox): split DemoSection with shared options data Extract fruitOptions / colorOptions to listbox-demo-data.ts (used by Vue/Svelte/Astro variants; the React variant has its own wrapper components with internal data) and split DemoSection into four framework files. Verified: /patterns/listbox/{react,vue,svelte,astro}/ and the /ja/ variants all return 200. Co-Authored-By: Claude Opus 4.7 (1M context) --- src/patterns/listbox/DemoSection.astro | 283 ------------------ src/patterns/listbox/DemoSection.react.astro | 57 ++++ src/patterns/listbox/DemoSection.svelte.astro | 70 +++++ src/patterns/listbox/DemoSection.vue.astro | 70 +++++ .../listbox/DemoSection.web-component.astro | 77 +++++ src/patterns/listbox/listbox-demo-data.ts | 26 ++ 6 files changed, 300 insertions(+), 283 deletions(-) delete mode 100644 src/patterns/listbox/DemoSection.astro create mode 100644 src/patterns/listbox/DemoSection.react.astro create mode 100644 src/patterns/listbox/DemoSection.svelte.astro create mode 100644 src/patterns/listbox/DemoSection.vue.astro create mode 100644 src/patterns/listbox/DemoSection.web-component.astro create mode 100644 src/patterns/listbox/listbox-demo-data.ts diff --git a/src/patterns/listbox/DemoSection.astro b/src/patterns/listbox/DemoSection.astro deleted file mode 100644 index d91afe88..00000000 --- a/src/patterns/listbox/DemoSection.astro +++ /dev/null @@ -1,283 +0,0 @@ ---- -/** - * Listbox Demo Section - * - * Renders the listbox demo for each framework variant. - * React uses wrapper demo components with built-in data. - * Vue/Svelte use the ListboxDemo component with props. - * Astro uses the Listbox component directly. - */ -import type { Framework } from '@/lib/frameworks'; -import type { Locale } from '@/i18n/ui'; -import { - SingleSelectListboxDemo, - MultiSelectListboxDemo, - HorizontalListboxDemo, -} from './ListboxDemo'; -import ListboxDemoVue from './ListboxDemo.vue'; -import ListboxDemoSvelte from './ListboxDemo.svelte'; -import Listbox from './Listbox.astro'; - -interface Props { - framework: Framework; - locale?: Locale; -} - -const { framework, locale = 'en' } = Astro.props; -const isJa = locale === 'ja'; - -const fruitOptions = [ - { id: 'apple', label: 'Apple' }, - { id: 'banana', label: 'Banana' }, - { id: 'cherry', label: 'Cherry' }, - { id: 'date', label: 'Date' }, - { id: 'elderberry', label: 'Elderberry' }, - { id: 'fig', label: 'Fig' }, - { id: 'grape', label: 'Grape' }, -]; - -const colorOptions = [ - { id: 'red', label: 'Red' }, - { id: 'orange', label: 'Orange' }, - { id: 'yellow', label: 'Yellow' }, - { id: 'green', label: 'Green', disabled: true }, - { id: 'blue', label: 'Blue' }, - { id: 'indigo', label: 'Indigo' }, - { id: 'purple', label: 'Purple' }, -]; ---- - -{ - framework === 'react' && ( - <> - {/* Single-Select */} -
-

- {isJa ? '単一選択(デフォルト)' : 'Single-Select (Default)'} -

-

- {isJa - ? '選択がフォーカスに追従します。矢印キーで移動・選択できます。' - : 'Selection follows focus. Use arrow keys to navigate and select.'} -

-
- -
-
- - {/* Multi-Select */} -
-

{isJa ? '複数選択' : 'Multi-Select'}

-

- {isJa - ? 'フォーカスと選択は独立しています。Spaceで切り替え、Shift+矢印キーで選択を拡張します。' - : 'Focus and selection are independent. Use Space to toggle, Shift+Arrow to extend selection.'} -

-
- -
-
- - {/* Horizontal Orientation */} -
-

{isJa ? '水平方向' : 'Horizontal Orientation'}

-

- {isJa ? '左右の矢印キーで移動します。' : 'Use Left/Right arrow keys for navigation.'} -

-
- -
-
- - ) -} - -{ - framework === 'vue' && ( - <> - {/* Single-Select */} -
-

- {isJa ? '単一選択(デフォルト)' : 'Single-Select (Default)'} -

-

- {isJa - ? '選択がフォーカスに追従します。矢印キーで移動・選択できます。' - : 'Selection follows focus. Use arrow keys to navigate and select.'} -

-
- -
-
- - {/* Multi-Select */} -
-

{isJa ? '複数選択' : 'Multi-Select'}

-

- {isJa - ? 'フォーカスと選択は独立しています。Spaceで切り替え、Shift+矢印キーで選択を拡張します。' - : 'Focus and selection are independent. Use Space to toggle, Shift+Arrow to extend selection.'} -

-
- -
-
- - {/* Horizontal Orientation */} -
-

{isJa ? '水平方向' : 'Horizontal Orientation'}

-

- {isJa ? '左右の矢印キーで移動します。' : 'Use Left/Right arrow keys for navigation.'} -

-
- -
-
- - ) -} - -{ - framework === 'svelte' && ( - <> - {/* Single-Select */} -
-

- {isJa ? '単一選択(デフォルト)' : 'Single-Select (Default)'} -

-

- {isJa - ? '選択がフォーカスに追従します。矢印キーで移動・選択できます。' - : 'Selection follows focus. Use arrow keys to navigate and select.'} -

-
- -
-
- - {/* Multi-Select */} -
-

{isJa ? '複数選択' : 'Multi-Select'}

-

- {isJa - ? 'フォーカスと選択は独立しています。Spaceで切り替え、Shift+矢印キーで選択を拡張します。' - : 'Focus and selection are independent. Use Space to toggle, Shift+Arrow to extend selection.'} -

-
- -
-
- - {/* Horizontal Orientation */} -
-

{isJa ? '水平方向' : 'Horizontal Orientation'}

-

- {isJa ? '左右の矢印キーで移動します。' : 'Use Left/Right arrow keys for navigation.'} -

-
- -
-
- - ) -} - -{ - framework === 'astro' && ( - <> - {/* Single-Select */} -
-

- {isJa ? '単一選択(デフォルト)' : 'Single-Select (Default)'} -

-

- {isJa - ? '選択がフォーカスに追従します。矢印キーで移動・選択できます。' - : 'Selection follows focus. Use arrow keys to navigate and select.'} -

-
- - -
-
- - {/* Multi-Select */} -
-

{isJa ? '複数選択' : 'Multi-Select'}

-

- {isJa - ? 'フォーカスと選択は独立しています。Spaceで切り替え、Shift+矢印キーで選択を拡張します。' - : 'Focus and selection are independent. Use Space to toggle, Shift+Arrow to extend selection.'} -

-
- - -

- {isJa - ? 'ヒント: Spaceで切り替え、Shift+矢印キーで選択を拡張、Ctrl+Aで全選択' - : 'Tip: Use Space to toggle, Shift+Arrow to extend selection, Ctrl+A to select all'} -

-
-
- - {/* Horizontal Orientation */} -
-

{isJa ? '水平方向' : 'Horizontal Orientation'}

-

- {isJa ? '左右の矢印キーで移動します。' : 'Use Left/Right arrow keys for navigation.'} -

-
- - -
-
- - ) -} diff --git a/src/patterns/listbox/DemoSection.react.astro b/src/patterns/listbox/DemoSection.react.astro new file mode 100644 index 00000000..6b9efb0a --- /dev/null +++ b/src/patterns/listbox/DemoSection.react.astro @@ -0,0 +1,57 @@ +--- +import type { Framework } from '@/lib/frameworks'; +import type { Locale } from '@/i18n/ui'; +import { + SingleSelectListboxDemo, + MultiSelectListboxDemo, + HorizontalListboxDemo, +} from './ListboxDemo'; + +interface Props { + framework?: Framework; + locale?: Locale; +} + +const { locale = 'en' } = Astro.props; +const isJa = locale === 'ja'; +--- + +
+

+ {isJa ? '単一選択(デフォルト)' : 'Single-Select (Default)'} +

+

+ { + isJa + ? '選択がフォーカスに追従します。矢印キーで移動・選択できます。' + : 'Selection follows focus. Use arrow keys to navigate and select.' + } +

+
+ +
+
+ +
+

{isJa ? '複数選択' : 'Multi-Select'}

+

+ { + isJa + ? 'フォーカスと選択は独立しています。Spaceで切り替え、Shift+矢印キーで選択を拡張します。' + : 'Focus and selection are independent. Use Space to toggle, Shift+Arrow to extend selection.' + } +

+
+ +
+
+ +
+

{isJa ? '水平方向' : 'Horizontal Orientation'}

+

+ {isJa ? '左右の矢印キーで移動します。' : 'Use Left/Right arrow keys for navigation.'} +

+
+ +
+
diff --git a/src/patterns/listbox/DemoSection.svelte.astro b/src/patterns/listbox/DemoSection.svelte.astro new file mode 100644 index 00000000..328a591d --- /dev/null +++ b/src/patterns/listbox/DemoSection.svelte.astro @@ -0,0 +1,70 @@ +--- +import type { Framework } from '@/lib/frameworks'; +import type { Locale } from '@/i18n/ui'; +import ListboxDemoSvelte from './ListboxDemo.svelte'; +import { fruitOptions, colorOptions } from './listbox-demo-data'; + +interface Props { + framework?: Framework; + locale?: Locale; +} + +const { locale = 'en' } = Astro.props; +const isJa = locale === 'ja'; +--- + +
+

+ {isJa ? '単一選択(デフォルト)' : 'Single-Select (Default)'} +

+

+ { + isJa + ? '選択がフォーカスに追従します。矢印キーで移動・選択できます。' + : 'Selection follows focus. Use arrow keys to navigate and select.' + } +

+
+ +
+
+ +
+

{isJa ? '複数選択' : 'Multi-Select'}

+

+ { + isJa + ? 'フォーカスと選択は独立しています。Spaceで切り替え、Shift+矢印キーで選択を拡張します。' + : 'Focus and selection are independent. Use Space to toggle, Shift+Arrow to extend selection.' + } +

+
+ +
+
+ +
+

{isJa ? '水平方向' : 'Horizontal Orientation'}

+

+ {isJa ? '左右の矢印キーで移動します。' : 'Use Left/Right arrow keys for navigation.'} +

+
+ +
+
diff --git a/src/patterns/listbox/DemoSection.vue.astro b/src/patterns/listbox/DemoSection.vue.astro new file mode 100644 index 00000000..cbe5cc39 --- /dev/null +++ b/src/patterns/listbox/DemoSection.vue.astro @@ -0,0 +1,70 @@ +--- +import type { Framework } from '@/lib/frameworks'; +import type { Locale } from '@/i18n/ui'; +import ListboxDemoVue from './ListboxDemo.vue'; +import { fruitOptions, colorOptions } from './listbox-demo-data'; + +interface Props { + framework?: Framework; + locale?: Locale; +} + +const { locale = 'en' } = Astro.props; +const isJa = locale === 'ja'; +--- + +
+

+ {isJa ? '単一選択(デフォルト)' : 'Single-Select (Default)'} +

+

+ { + isJa + ? '選択がフォーカスに追従します。矢印キーで移動・選択できます。' + : 'Selection follows focus. Use arrow keys to navigate and select.' + } +

+
+ +
+
+ +
+

{isJa ? '複数選択' : 'Multi-Select'}

+

+ { + isJa + ? 'フォーカスと選択は独立しています。Spaceで切り替え、Shift+矢印キーで選択を拡張します。' + : 'Focus and selection are independent. Use Space to toggle, Shift+Arrow to extend selection.' + } +

+
+ +
+
+ +
+

{isJa ? '水平方向' : 'Horizontal Orientation'}

+

+ {isJa ? '左右の矢印キーで移動します。' : 'Use Left/Right arrow keys for navigation.'} +

+
+ +
+
diff --git a/src/patterns/listbox/DemoSection.web-component.astro b/src/patterns/listbox/DemoSection.web-component.astro new file mode 100644 index 00000000..615eeb68 --- /dev/null +++ b/src/patterns/listbox/DemoSection.web-component.astro @@ -0,0 +1,77 @@ +--- +import type { Framework } from '@/lib/frameworks'; +import type { Locale } from '@/i18n/ui'; +import Listbox from './Listbox.astro'; +import { fruitOptions, colorOptions } from './listbox-demo-data'; + +interface Props { + framework?: Framework; + locale?: Locale; +} + +const { locale = 'en' } = Astro.props; +const isJa = locale === 'ja'; +--- + +
+

+ {isJa ? '単一選択(デフォルト)' : 'Single-Select (Default)'} +

+

+ { + isJa + ? '選択がフォーカスに追従します。矢印キーで移動・選択できます。' + : 'Selection follows focus. Use arrow keys to navigate and select.' + } +

+
+ + +
+
+ +
+

{isJa ? '複数選択' : 'Multi-Select'}

+

+ { + isJa + ? 'フォーカスと選択は独立しています。Spaceで切り替え、Shift+矢印キーで選択を拡張します。' + : 'Focus and selection are independent. Use Space to toggle, Shift+Arrow to extend selection.' + } +

+
+ + +

+ { + isJa + ? 'ヒント: Spaceで切り替え、Shift+矢印キーで選択を拡張、Ctrl+Aで全選択' + : 'Tip: Use Space to toggle, Shift+Arrow to extend selection, Ctrl+A to select all' + } +

+
+
+ +
+

{isJa ? '水平方向' : 'Horizontal Orientation'}

+

+ {isJa ? '左右の矢印キーで移動します。' : 'Use Left/Right arrow keys for navigation.'} +

+
+ + +
+
diff --git a/src/patterns/listbox/listbox-demo-data.ts b/src/patterns/listbox/listbox-demo-data.ts new file mode 100644 index 00000000..ea9693ab --- /dev/null +++ b/src/patterns/listbox/listbox-demo-data.ts @@ -0,0 +1,26 @@ +/** + * Shared demo data for the Listbox pattern. + * + * Used by the Vue / Svelte / Astro Web Component variants. The React variant + * uses wrapper demo components with their own internal data. + */ + +export const fruitOptions = [ + { id: 'apple', label: 'Apple' }, + { id: 'banana', label: 'Banana' }, + { id: 'cherry', label: 'Cherry' }, + { id: 'date', label: 'Date' }, + { id: 'elderberry', label: 'Elderberry' }, + { id: 'fig', label: 'Fig' }, + { id: 'grape', label: 'Grape' }, +]; + +export const colorOptions = [ + { id: 'red', label: 'Red' }, + { id: 'orange', label: 'Orange' }, + { id: 'yellow', label: 'Yellow' }, + { id: 'green', label: 'Green', disabled: true }, + { id: 'blue', label: 'Blue' }, + { id: 'indigo', label: 'Indigo' }, + { id: 'purple', label: 'Purple' }, +]; From 8710d19c85a5d95352f12c8e546793769a17cd1c Mon Sep 17 00:00:00 2001 From: masuP9 Date: Mon, 11 May 2026 19:36:07 +0900 Subject: [PATCH 5/8] refactor(radio-group): split DemoSection with shared options data Extract colorOptions / sizeOptions / planOptions / ratingOptions to radio-group-demo-data.ts and split DemoSection into four framework files. Framework prop name differences (e.g. Vue \`ariaLabel\` vs React/Svelte/Astro \`aria-label\`) are kept in each per-framework file rather than in the shared data, per the migration convention. Verified: /patterns/radio-group/{react,vue,svelte,astro}/ and /ja/ variants all return 200. Co-Authored-By: Claude Opus 4.7 (1M context) --- src/patterns/radio-group/DemoSection.astro | 270 ------------------ .../radio-group/DemoSection.react.astro | 96 +++++++ .../radio-group/DemoSection.svelte.astro | 101 +++++++ .../radio-group/DemoSection.vue.astro | 96 +++++++ .../DemoSection.web-component.astro | 94 ++++++ .../radio-group/radio-group-demo-data.ts | 29 ++ 6 files changed, 416 insertions(+), 270 deletions(-) delete mode 100644 src/patterns/radio-group/DemoSection.astro create mode 100644 src/patterns/radio-group/DemoSection.react.astro create mode 100644 src/patterns/radio-group/DemoSection.svelte.astro create mode 100644 src/patterns/radio-group/DemoSection.vue.astro create mode 100644 src/patterns/radio-group/DemoSection.web-component.astro create mode 100644 src/patterns/radio-group/radio-group-demo-data.ts diff --git a/src/patterns/radio-group/DemoSection.astro b/src/patterns/radio-group/DemoSection.astro deleted file mode 100644 index 506d982c..00000000 --- a/src/patterns/radio-group/DemoSection.astro +++ /dev/null @@ -1,270 +0,0 @@ ---- -/** - * Radio Group Demo Section - * - * Renders the radio group demo for each framework variant. - * Each framework's component is statically imported to support - * Astro's client:load directive for hydration. - */ -import type { Framework } from '@/lib/frameworks'; -import type { Locale } from '@/i18n/ui'; -import { RadioGroup as RadioGroupReact } from './RadioGroup'; -import RadioGroupVue from './RadioGroup.vue'; -import RadioGroupSvelte from './RadioGroup.svelte'; -import RadioGroupAstro from './RadioGroup.astro'; - -interface Props { - framework: Framework; - locale?: Locale; -} - -const { framework, locale = 'en' } = Astro.props; -const isJa = locale === 'ja'; - -const colorOptions = [ - { id: 'red', label: 'Red', value: 'red' }, - { id: 'blue', label: 'Blue', value: 'blue' }, - { id: 'green', label: 'Green', value: 'green' }, -]; - -const sizeOptions = [ - { id: 'small', label: 'Small', value: 'small' }, - { id: 'medium', label: 'Medium', value: 'medium' }, - { id: 'large', label: 'Large', value: 'large' }, -]; - -const planOptions = [ - { id: 'free', label: 'Free', value: 'free' }, - { id: 'pro', label: 'Pro', value: 'pro' }, - { id: 'enterprise', label: 'Enterprise (Coming Soon)', value: 'enterprise', disabled: true }, -]; - -const ratingOptions = [ - { id: 'r1', label: '1', value: '1' }, - { id: 'r2', label: '2', value: '2' }, - { id: 'r3', label: '3', value: '3' }, - { id: 'r4', label: '4', value: '4' }, - { id: 'r5', label: '5', value: '5' }, -]; ---- - - -
-

{isJa ? '基本的なラジオグループ' : 'Basic Radio Group'}

-

- { - isJa - ? '矢印キーで移動・選択します。Tabでグループの内外にフォーカスを移動します。' - : 'Use arrow keys to navigate and select. Tab moves focus in/out of the group.' - } -

-
- { - framework === 'react' && ( - - ) - } - { - framework === 'vue' && ( - - ) - } - { - framework === 'svelte' && ( - - ) - } - { - framework === 'astro' && ( - - ) - } -
-
- - -
-

{isJa ? 'デフォルト値あり' : 'With Default Value'}

-

- { - isJa ? ( - <> - defaultValue propで事前に選択されたオプション。 - - ) : ( - <> - Pre-selected option using the defaultValue prop. - - ) - } -

-
- { - framework === 'react' && ( - - ) - } - { - framework === 'vue' && ( - - ) - } - { - framework === 'svelte' && ( - - ) - } - { - framework === 'astro' && ( - - ) - } -
-
- - -
-

- {isJa ? '無効なオプションを含む場合' : 'With Disabled Option'} -

-

- { - isJa - ? '無効なオプションはキーボード操作時にスキップされます。' - : 'Disabled options are skipped during keyboard navigation.' - } -

-
- { - framework === 'react' && ( - - ) - } - { - framework === 'vue' && ( - - ) - } - { - framework === 'svelte' && ( - - ) - } - { - framework === 'astro' && ( - - ) - } -
-
- - -
-

{isJa ? '水平方向' : 'Horizontal Orientation'}

-

- { - isJa ? ( - <> - orientation="horizontal" による水平レイアウト。 - - ) : ( - <> - Horizontal layout with orientation="horizontal". - - ) - } -

-
- { - framework === 'react' && ( - - ) - } - { - framework === 'vue' && ( - - ) - } - { - framework === 'svelte' && ( - - ) - } - { - framework === 'astro' && ( - - ) - } -
-
diff --git a/src/patterns/radio-group/DemoSection.react.astro b/src/patterns/radio-group/DemoSection.react.astro new file mode 100644 index 00000000..55f2da77 --- /dev/null +++ b/src/patterns/radio-group/DemoSection.react.astro @@ -0,0 +1,96 @@ +--- +import type { Framework } from '@/lib/frameworks'; +import type { Locale } from '@/i18n/ui'; +import { RadioGroup as RadioGroupReact } from './RadioGroup'; +import { colorOptions, sizeOptions, planOptions, ratingOptions } from './radio-group-demo-data'; + +interface Props { + framework?: Framework; + locale?: Locale; +} + +const { locale = 'en' } = Astro.props; +const isJa = locale === 'ja'; +--- + +
+

{isJa ? '基本的なラジオグループ' : 'Basic Radio Group'}

+

+ { + isJa + ? '矢印キーで移動・選択します。Tabでグループの内外にフォーカスを移動します。' + : 'Use arrow keys to navigate and select. Tab moves focus in/out of the group.' + } +

+
+ +
+
+ +
+

{isJa ? 'デフォルト値あり' : 'With Default Value'}

+

+ { + isJa ? ( + + defaultValue propで事前に選択されたオプション。 + + ) : ( + + Pre-selected option using the defaultValue prop. + + ) + } +

+
+ +
+
+ +
+

+ {isJa ? '無効なオプションを含む場合' : 'With Disabled Option'} +

+

+ { + isJa + ? '無効なオプションはキーボード操作時にスキップされます。' + : 'Disabled options are skipped during keyboard navigation.' + } +

+
+ +
+
+ +
+

{isJa ? '水平方向' : 'Horizontal Orientation'}

+

+ { + isJa ? ( + + orientation="horizontal" による水平レイアウト。 + + ) : ( + + Horizontal layout with orientation="horizontal". + + ) + } +

+
+ +
+
diff --git a/src/patterns/radio-group/DemoSection.svelte.astro b/src/patterns/radio-group/DemoSection.svelte.astro new file mode 100644 index 00000000..585fb8a8 --- /dev/null +++ b/src/patterns/radio-group/DemoSection.svelte.astro @@ -0,0 +1,101 @@ +--- +import type { Framework } from '@/lib/frameworks'; +import type { Locale } from '@/i18n/ui'; +import RadioGroupSvelte from './RadioGroup.svelte'; +import { colorOptions, sizeOptions, planOptions, ratingOptions } from './radio-group-demo-data'; + +interface Props { + framework?: Framework; + locale?: Locale; +} + +const { locale = 'en' } = Astro.props; +const isJa = locale === 'ja'; +--- + +
+

{isJa ? '基本的なラジオグループ' : 'Basic Radio Group'}

+

+ { + isJa + ? '矢印キーで移動・選択します。Tabでグループの内外にフォーカスを移動します。' + : 'Use arrow keys to navigate and select. Tab moves focus in/out of the group.' + } +

+
+ +
+
+ +
+

{isJa ? 'デフォルト値あり' : 'With Default Value'}

+

+ { + isJa ? ( + + defaultValue propで事前に選択されたオプション。 + + ) : ( + + Pre-selected option using the defaultValue prop. + + ) + } +

+
+ +
+
+ +
+

+ {isJa ? '無効なオプションを含む場合' : 'With Disabled Option'} +

+

+ { + isJa + ? '無効なオプションはキーボード操作時にスキップされます。' + : 'Disabled options are skipped during keyboard navigation.' + } +

+
+ +
+
+ +
+

{isJa ? '水平方向' : 'Horizontal Orientation'}

+

+ { + isJa ? ( + + orientation="horizontal" による水平レイアウト。 + + ) : ( + + Horizontal layout with orientation="horizontal". + + ) + } +

+
+ +
+
diff --git a/src/patterns/radio-group/DemoSection.vue.astro b/src/patterns/radio-group/DemoSection.vue.astro new file mode 100644 index 00000000..270e9d1e --- /dev/null +++ b/src/patterns/radio-group/DemoSection.vue.astro @@ -0,0 +1,96 @@ +--- +import type { Framework } from '@/lib/frameworks'; +import type { Locale } from '@/i18n/ui'; +import RadioGroupVue from './RadioGroup.vue'; +import { colorOptions, sizeOptions, planOptions, ratingOptions } from './radio-group-demo-data'; + +interface Props { + framework?: Framework; + locale?: Locale; +} + +const { locale = 'en' } = Astro.props; +const isJa = locale === 'ja'; +--- + +
+

{isJa ? '基本的なラジオグループ' : 'Basic Radio Group'}

+

+ { + isJa + ? '矢印キーで移動・選択します。Tabでグループの内外にフォーカスを移動します。' + : 'Use arrow keys to navigate and select. Tab moves focus in/out of the group.' + } +

+
+ +
+
+ +
+

{isJa ? 'デフォルト値あり' : 'With Default Value'}

+

+ { + isJa ? ( + + defaultValue propで事前に選択されたオプション。 + + ) : ( + + Pre-selected option using the defaultValue prop. + + ) + } +

+
+ +
+
+ +
+

+ {isJa ? '無効なオプションを含む場合' : 'With Disabled Option'} +

+

+ { + isJa + ? '無効なオプションはキーボード操作時にスキップされます。' + : 'Disabled options are skipped during keyboard navigation.' + } +

+
+ +
+
+ +
+

{isJa ? '水平方向' : 'Horizontal Orientation'}

+

+ { + isJa ? ( + + orientation="horizontal" による水平レイアウト。 + + ) : ( + + Horizontal layout with orientation="horizontal". + + ) + } +

+
+ +
+
diff --git a/src/patterns/radio-group/DemoSection.web-component.astro b/src/patterns/radio-group/DemoSection.web-component.astro new file mode 100644 index 00000000..c8fed468 --- /dev/null +++ b/src/patterns/radio-group/DemoSection.web-component.astro @@ -0,0 +1,94 @@ +--- +import type { Framework } from '@/lib/frameworks'; +import type { Locale } from '@/i18n/ui'; +import RadioGroupAstro from './RadioGroup.astro'; +import { colorOptions, sizeOptions, planOptions, ratingOptions } from './radio-group-demo-data'; + +interface Props { + framework?: Framework; + locale?: Locale; +} + +const { locale = 'en' } = Astro.props; +const isJa = locale === 'ja'; +--- + +
+

{isJa ? '基本的なラジオグループ' : 'Basic Radio Group'}

+

+ { + isJa + ? '矢印キーで移動・選択します。Tabでグループの内外にフォーカスを移動します。' + : 'Use arrow keys to navigate and select. Tab moves focus in/out of the group.' + } +

+
+ +
+
+ +
+

{isJa ? 'デフォルト値あり' : 'With Default Value'}

+

+ { + isJa ? ( + + defaultValue propで事前に選択されたオプション。 + + ) : ( + + Pre-selected option using the defaultValue prop. + + ) + } +

+
+ +
+
+ +
+

+ {isJa ? '無効なオプションを含む場合' : 'With Disabled Option'} +

+

+ { + isJa + ? '無効なオプションはキーボード操作時にスキップされます。' + : 'Disabled options are skipped during keyboard navigation.' + } +

+
+ +
+
+ +
+

{isJa ? '水平方向' : 'Horizontal Orientation'}

+

+ { + isJa ? ( + + orientation="horizontal" による水平レイアウト。 + + ) : ( + + Horizontal layout with orientation="horizontal". + + ) + } +

+
+ +
+
diff --git a/src/patterns/radio-group/radio-group-demo-data.ts b/src/patterns/radio-group/radio-group-demo-data.ts new file mode 100644 index 00000000..ebb1dc8d --- /dev/null +++ b/src/patterns/radio-group/radio-group-demo-data.ts @@ -0,0 +1,29 @@ +/** + * Shared demo data for the Radio Group pattern. + */ + +export const colorOptions = [ + { id: 'red', label: 'Red', value: 'red' }, + { id: 'blue', label: 'Blue', value: 'blue' }, + { id: 'green', label: 'Green', value: 'green' }, +]; + +export const sizeOptions = [ + { id: 'small', label: 'Small', value: 'small' }, + { id: 'medium', label: 'Medium', value: 'medium' }, + { id: 'large', label: 'Large', value: 'large' }, +]; + +export const planOptions = [ + { id: 'free', label: 'Free', value: 'free' }, + { id: 'pro', label: 'Pro', value: 'pro' }, + { id: 'enterprise', label: 'Enterprise (Coming Soon)', value: 'enterprise', disabled: true }, +]; + +export const ratingOptions = [ + { id: 'r1', label: '1', value: '1' }, + { id: 'r2', label: '2', value: '2' }, + { id: 'r3', label: '3', value: '3' }, + { id: 'r4', label: '4', value: '4' }, + { id: 'r5', label: '5', value: '5' }, +]; From 9b97e8d84b4f1cdbacaaec335b27781d1eac12b0 Mon Sep 17 00:00:00 2001 From: masuP9 Date: Mon, 11 May 2026 19:37:54 +0900 Subject: [PATCH 6/8] refactor(tree-view): split DemoSection with shared nodes data Extract fileSystemNodes / disabledNodes to tree-view-demo-data.ts and split DemoSection into four framework files. The inline \` diff --git a/src/patterns/tree-view/DemoSection.react.astro b/src/patterns/tree-view/DemoSection.react.astro new file mode 100644 index 00000000..eb7fa332 --- /dev/null +++ b/src/patterns/tree-view/DemoSection.react.astro @@ -0,0 +1,59 @@ +--- +import type { Framework } from '@/lib/frameworks'; +import type { Locale } from '@/i18n/ui'; +import { TreeView as TreeViewReact } from './TreeView'; +import { TreeViewActivationDemo as TreeViewActivationDemoReact } from './TreeViewActivationDemo'; +import { fileSystemNodes, disabledNodes } from './tree-view-demo-data'; + +interface Props { + framework?: Framework; + locale?: Locale; +} + +const { locale = 'en' } = Astro.props; +const isJa = locale === 'ja'; + +const singleSelectLabel = isJa ? '単一選択 + アクティベーション' : 'Single-Select with Activation'; +const multiSelectLabel = isJa ? '複数選択' : 'Multi-Select'; +const disabledLabel = isJa ? '無効化されたノード' : 'With Disabled Nodes'; +const fileExplorerAriaLabel = isJa ? 'ファイルエクスプローラー' : 'File Explorer'; +const multiSelectAriaLabel = isJa + ? '複数選択ファイルエクスプローラー' + : 'Multi-select File Explorer'; +const restrictedAriaLabel = isJa + ? 'アクセス制限付きファイルエクスプローラー' + : 'File Explorer with Restricted Access'; +--- + +
+
+
+

{singleSelectLabel}

+ +
+
+

{multiSelectLabel}

+ +
+
+

{disabledLabel}

+ +
+
+
diff --git a/src/patterns/tree-view/DemoSection.svelte.astro b/src/patterns/tree-view/DemoSection.svelte.astro new file mode 100644 index 00000000..5d9f8643 --- /dev/null +++ b/src/patterns/tree-view/DemoSection.svelte.astro @@ -0,0 +1,59 @@ +--- +import type { Framework } from '@/lib/frameworks'; +import type { Locale } from '@/i18n/ui'; +import TreeViewSvelte from './TreeView.svelte'; +import TreeViewActivationDemoSvelte from './TreeViewActivationDemo.svelte'; +import { fileSystemNodes, disabledNodes } from './tree-view-demo-data'; + +interface Props { + framework?: Framework; + locale?: Locale; +} + +const { locale = 'en' } = Astro.props; +const isJa = locale === 'ja'; + +const singleSelectLabel = isJa ? '単一選択 + アクティベーション' : 'Single-Select with Activation'; +const multiSelectLabel = isJa ? '複数選択' : 'Multi-Select'; +const disabledLabel = isJa ? '無効化されたノード' : 'With Disabled Nodes'; +const fileExplorerAriaLabel = isJa ? 'ファイルエクスプローラー' : 'File Explorer'; +const multiSelectAriaLabel = isJa + ? '複数選択ファイルエクスプローラー' + : 'Multi-select File Explorer'; +const restrictedAriaLabel = isJa + ? 'アクセス制限付きファイルエクスプローラー' + : 'File Explorer with Restricted Access'; +--- + +
+
+
+

{singleSelectLabel}

+ +
+
+

{multiSelectLabel}

+ +
+
+

{disabledLabel}

+ +
+
+
diff --git a/src/patterns/tree-view/DemoSection.vue.astro b/src/patterns/tree-view/DemoSection.vue.astro new file mode 100644 index 00000000..a9bcf7d1 --- /dev/null +++ b/src/patterns/tree-view/DemoSection.vue.astro @@ -0,0 +1,59 @@ +--- +import type { Framework } from '@/lib/frameworks'; +import type { Locale } from '@/i18n/ui'; +import TreeViewVue from './TreeView.vue'; +import TreeViewActivationDemoVue from './TreeViewActivationDemo.vue'; +import { fileSystemNodes, disabledNodes } from './tree-view-demo-data'; + +interface Props { + framework?: Framework; + locale?: Locale; +} + +const { locale = 'en' } = Astro.props; +const isJa = locale === 'ja'; + +const singleSelectLabel = isJa ? '単一選択 + アクティベーション' : 'Single-Select with Activation'; +const multiSelectLabel = isJa ? '複数選択' : 'Multi-Select'; +const disabledLabel = isJa ? '無効化されたノード' : 'With Disabled Nodes'; +const fileExplorerAriaLabel = isJa ? 'ファイルエクスプローラー' : 'File Explorer'; +const multiSelectAriaLabel = isJa + ? '複数選択ファイルエクスプローラー' + : 'Multi-select File Explorer'; +const restrictedAriaLabel = isJa + ? 'アクセス制限付きファイルエクスプローラー' + : 'File Explorer with Restricted Access'; +--- + +
+
+
+

{singleSelectLabel}

+ +
+
+

{multiSelectLabel}

+ +
+
+

{disabledLabel}

+ +
+
+
diff --git a/src/patterns/tree-view/DemoSection.web-component.astro b/src/patterns/tree-view/DemoSection.web-component.astro new file mode 100644 index 00000000..9f203a97 --- /dev/null +++ b/src/patterns/tree-view/DemoSection.web-component.astro @@ -0,0 +1,131 @@ +--- +import type { Framework } from '@/lib/frameworks'; +import type { Locale } from '@/i18n/ui'; +import TreeViewAstro from './TreeView.astro'; +import { fileSystemNodes, disabledNodes } from './tree-view-demo-data'; + +interface Props { + framework?: Framework; + locale?: Locale; +} + +const { locale = 'en' } = Astro.props; +const isJa = locale === 'ja'; + +const singleSelectLabel = isJa ? '単一選択 + アクティベーション' : 'Single-Select with Activation'; +const multiSelectLabel = isJa ? '複数選択' : 'Multi-Select'; +const disabledLabel = isJa ? '無効化されたノード' : 'With Disabled Nodes'; +const fileExplorerAriaLabel = isJa ? 'ファイルエクスプローラー' : 'File Explorer'; +const multiSelectAriaLabel = isJa + ? '複数選択ファイルエクスプローラー' + : 'Multi-select File Explorer'; +const restrictedAriaLabel = isJa + ? 'アクセス制限付きファイルエクスプローラー' + : 'File Explorer with Restricted Access'; +const activatedPlaceholder = isJa + ? 'Enter、Space、またはクリックでノードを選択してください' + : 'Select a node with Enter, Space, or Click'; +const activatedPrefix = isJa ? 'アクティベート: ' : 'Activated: '; +--- + +
+
+
+

{singleSelectLabel}

+
+ +
+
+ {activatedPrefix} + + {activatedPlaceholder} + +
+ +
+
+
+
+

{multiSelectLabel}

+ +
+
+

{disabledLabel}

+ +
+
+
+ + diff --git a/src/patterns/tree-view/tree-view-demo-data.ts b/src/patterns/tree-view/tree-view-demo-data.ts new file mode 100644 index 00000000..4be6d6f2 --- /dev/null +++ b/src/patterns/tree-view/tree-view-demo-data.ts @@ -0,0 +1,49 @@ +/** + * Shared demo data for the Tree View pattern. + */ + +export const fileSystemNodes = [ + { + id: 'documents', + label: 'Documents', + children: [ + { id: 'report', label: 'report.pdf' }, + { id: 'notes', label: 'notes.txt' }, + { + id: 'projects', + label: 'Projects', + children: [ + { id: 'project-a', label: 'Project A' }, + { id: 'project-b', label: 'Project B' }, + ], + }, + ], + }, + { + id: 'images', + label: 'Images', + children: [ + { id: 'vacation', label: 'vacation.jpg' }, + { id: 'profile', label: 'profile.png' }, + ], + }, + { id: 'readme', label: 'readme.md' }, +]; + +export const disabledNodes = [ + { + id: 'folder1', + label: 'Accessible Folder', + children: [ + { id: 'file1', label: 'file1.txt' }, + { id: 'file2', label: 'file2.txt', disabled: true }, + ], + }, + { + id: 'folder2', + label: 'Restricted Folder', + disabled: true, + children: [{ id: 'secret', label: 'secret.txt' }], + }, + { id: 'public', label: 'public.txt' }, +]; From 72419ae5462d23a35ca7d00d4d98353514ef8d2a Mon Sep 17 00:00:00 2001 From: masuP9 Date: Mon, 11 May 2026 19:39:50 +0900 Subject: [PATCH 7/8] refactor(table): split DemoSection with shared columns/rows data Extract pure data (basicColumns/Rows, rowHeaderRows, virtualizedRows, spanningColumns/Rows) used by the Astro Web Component variant to table-demo-data.ts. The React / Vue / Svelte variants use wrapper demo components with their own internal data. The sortable demo, even for the Astro page, uses the React SortableTableDemo via \`client:load\`. Note: the previously declared but unused \`sortableColumns\` is dropped, clearing the existing astro check warning at DemoSection.astro:45. Verified: /patterns/table/{react,vue,svelte,astro}/ and /ja/ variants all return 200. Co-Authored-By: Claude Opus 4.7 (1M context) --- src/patterns/table/DemoSection.astro | 406 ------------------ src/patterns/table/DemoSection.react.astro | 107 +++++ src/patterns/table/DemoSection.svelte.astro | 101 +++++ src/patterns/table/DemoSection.vue.astro | 101 +++++ .../table/DemoSection.web-component.astro | 128 ++++++ src/patterns/table/table-demo-data.ts | 53 +++ 6 files changed, 490 insertions(+), 406 deletions(-) delete mode 100644 src/patterns/table/DemoSection.astro create mode 100644 src/patterns/table/DemoSection.react.astro create mode 100644 src/patterns/table/DemoSection.svelte.astro create mode 100644 src/patterns/table/DemoSection.vue.astro create mode 100644 src/patterns/table/DemoSection.web-component.astro create mode 100644 src/patterns/table/table-demo-data.ts diff --git a/src/patterns/table/DemoSection.astro b/src/patterns/table/DemoSection.astro deleted file mode 100644 index f420dc33..00000000 --- a/src/patterns/table/DemoSection.astro +++ /dev/null @@ -1,406 +0,0 @@ ---- -/** - * Table Demo Section - * - * Renders the table demo for each framework variant. - * Each framework has multiple demo variants (basic, sortable, row headers, - * virtualized, spanning cells) shown together. - */ -import type { Framework } from '@/lib/frameworks'; -import type { Locale } from '@/i18n/ui'; -import { - BasicTableDemo, - SortableTableDemo, - RowHeaderTableDemo, - VirtualizedTableDemo, - SpanningCellsTableDemo, -} from './TableDemo'; -import TableDemoVue from './TableDemo.vue'; -import TableDemoSvelte from './TableDemo.svelte'; -import Table from './Table.astro'; - -interface Props { - framework: Framework; - locale?: Locale; -} - -const { framework, locale = 'en' } = Astro.props; -const isJa = locale === 'ja'; - -// Data for Astro framework demo -const basicColumns = [ - { id: 'name', header: 'Name' }, - { id: 'age', header: 'Age' }, - { id: 'city', header: 'City' }, -]; - -const basicRows = [ - { id: '1', cells: ['Alice', '30', 'Tokyo'] }, - { id: '2', cells: ['Bob', '25', 'Osaka'] }, - { id: '3', cells: ['Charlie', '35', 'Kyoto'] }, - { id: '4', cells: ['Diana', '28', 'Nagoya'] }, - { id: '5', cells: ['Edward', '42', 'Sapporo'] }, -]; - -const sortableColumns = [ - { id: 'name', header: 'Name', sortable: true, sort: 'ascending' as const }, - { id: 'age', header: 'Age', sortable: true }, - { id: 'city', header: 'City', sortable: true }, -]; - -const rowHeaderRows = [ - { id: '1', cells: ['Alice', '30', 'Tokyo'], hasRowHeader: true }, - { id: '2', cells: ['Bob', '25', 'Osaka'], hasRowHeader: true }, - { id: '3', cells: ['Charlie', '35', 'Kyoto'], hasRowHeader: true }, -]; - -const virtualizedRows = [ - { id: '5', cells: ['Alice', '30', 'Tokyo'], rowIndex: 5 }, - { id: '6', cells: ['Bob', '25', 'Osaka'], rowIndex: 6 }, - { id: '7', cells: ['Charlie', '35', 'Kyoto'], rowIndex: 7 }, - { id: '8', cells: ['Diana', '28', 'Nagoya'], rowIndex: 8 }, - { id: '9', cells: ['Edward', '42', 'Sapporo'], rowIndex: 9 }, -]; - -const spanningColumns = [ - { id: 'product', header: 'Product' }, - { id: 'q1', header: 'Q1' }, - { id: 'q2', header: 'Q2' }, - { id: 'q3', header: 'Q3' }, - { id: 'q4', header: 'Q4' }, -]; - -const spanningRows = [ - { - id: 'electronics', - cells: [{ content: 'Electronics', rowspan: 2 }, '150', '180', '200', '220'], - }, - { id: 'electronics-sub', cells: ['175', '190', '210', '240'] }, - { id: 'clothing', cells: ['Clothing', { content: 'N/A', colspan: 2 }, '90', '120'] }, - { id: 'summary', cells: [{ content: 'Total', colspan: 4 }, '1775'] }, -]; ---- - -{/* React demos */} -{ - framework === 'react' && ( - <> -
-

{isJa ? '基本テーブル' : 'Basic Table'}

-

- {isJa - ? 'データを表示するシンプルな静的テーブル。インタラクティブな機能はありません。' - : 'A simple static table displaying data. No interactive features.'} -

-
- -
-
-
-

{isJa ? 'ソート可能なテーブル' : 'Sortable Table'}

-

- {isJa ? '列ヘッダーをクリックしてソートします。' : 'Click column headers to sort.'} Uses{' '} - aria-sort {isJa ? 'でソート方向を示します。' : 'to indicate sort direction.'} -

-
- -
-
-
-

{isJa ? '行ヘッダー付き' : 'With Row Headers'}

-

- {isJa ? '各行の最初のセルが' : 'First cell in each row uses'}{' '} - role="rowheader"{' '} - {isJa - ? 'を使用し、スクリーンリーダーのナビゲーションを改善します。' - : 'for better screen reader navigation.'} -

-
- -
-
-
-

{isJa ? '仮想化対応' : 'Virtualization Support'}

-

- {isJa ? '大規模なデータセットでは、' : 'For large datasets, use'}{' '} - aria-rowcount - {isJa ? '、' : ','} aria-colcount - {isJa ? '、' : ', and'} aria-rowindex{' '} - {isJa - ? 'を使用してテーブル全体の構造を伝えます。' - : 'to communicate the full table structure.'} -

-
- -
-
-
-

{isJa ? 'セル結合' : 'Spanning Cells'}

-

- {isJa - ? 'セルは複数の列や行にまたがることができます。この実装では、視覚的な結合に CSS Grid の' - : 'Cells can span multiple columns or rows using'}{' '} - colspan {isJa ? 'と' : 'and'} rowspan - {isJa ? ' を使用し、CSS Grid の' : '. This implementation uses CSS Grid with'}{' '} - grid-column: span N {isJa ? 'と' : 'and'} grid-row: span N{' '} - {isJa - ? 'で視覚的な結合を行い、スクリーンリーダーのアクセシビリティのために' - : 'for visual spanning, plus'}{' '} - aria-colspan {isJa ? 'と' : 'and'} aria-rowspan{' '} - {isJa ? 'を使用しています。' : 'for screen reader accessibility.'} -

-
- -
-
- - ) -} - -{/* Vue demos */} -{ - framework === 'vue' && ( - <> -
-

{isJa ? '基本テーブル' : 'Basic Table'}

-

- {isJa - ? 'データを表示するシンプルな静的テーブル。インタラクティブな機能はありません。' - : 'A simple static table displaying data. No interactive features.'} -

-
- -
-
-
-

{isJa ? 'ソート可能なテーブル' : 'Sortable Table'}

-

- {isJa ? '列ヘッダーをクリックしてソートします。' : 'Click column headers to sort.'} Uses{' '} - aria-sort {isJa ? 'でソート方向を示します。' : 'to indicate sort direction.'} -

-
- -
-
-
-

{isJa ? '行ヘッダー付き' : 'With Row Headers'}

-

- {isJa ? '各行の最初のセルが' : 'First cell in each row uses'}{' '} - role="rowheader"{' '} - {isJa - ? 'を使用し、スクリーンリーダーのナビゲーションを改善します。' - : 'for better screen reader navigation.'} -

-
- -
-
-
-

{isJa ? '仮想化対応' : 'Virtualization Support'}

-

- {isJa ? '大規模なデータセットでは、' : 'For large datasets, use'}{' '} - aria-rowcount - {isJa ? '、' : ','} aria-colcount - {isJa ? '、' : ', and'} aria-rowindex{' '} - {isJa - ? 'を使用してテーブル全体の構造を伝えます。' - : 'to communicate the full table structure.'} -

-
- -
-
-
-

{isJa ? 'セル結合' : 'Spanning Cells'}

-

- {isJa - ? 'セルは複数の列や行にまたがることができます。この実装では、視覚的な結合に CSS Grid の' - : 'Cells can span multiple columns or rows using'}{' '} - colspan {isJa ? 'と' : 'and'} rowspan - {isJa ? ' を使用し、CSS Grid の' : '. This implementation uses CSS Grid with'}{' '} - grid-column: span N {isJa ? 'と' : 'and'} grid-row: span N{' '} - {isJa - ? 'で視覚的な結合を行い、スクリーンリーダーのアクセシビリティのために' - : 'for visual spanning, plus'}{' '} - aria-colspan {isJa ? 'と' : 'and'} aria-rowspan{' '} - {isJa ? 'を使用しています。' : 'for screen reader accessibility.'} -

-
- -
-
- - ) -} - -{/* Svelte demos */} -{ - framework === 'svelte' && ( - <> -
-

{isJa ? '基本テーブル' : 'Basic Table'}

-

- {isJa - ? 'データを表示するシンプルな静的テーブル。インタラクティブな機能はありません。' - : 'A simple static table displaying data. No interactive features.'} -

-
- -
-
-
-

{isJa ? 'ソート可能なテーブル' : 'Sortable Table'}

-

- {isJa ? '列ヘッダーをクリックしてソートします。' : 'Click column headers to sort.'} Uses{' '} - aria-sort {isJa ? 'でソート方向を示します。' : 'to indicate sort direction.'} -

-
- -
-
-
-

{isJa ? '行ヘッダー付き' : 'With Row Headers'}

-

- {isJa ? '各行の最初のセルが' : 'First cell in each row uses'}{' '} - role="rowheader"{' '} - {isJa - ? 'を使用し、スクリーンリーダーのナビゲーションを改善します。' - : 'for better screen reader navigation.'} -

-
- -
-
-
-

{isJa ? '仮想化対応' : 'Virtualization Support'}

-

- {isJa ? '大規模なデータセットでは、' : 'For large datasets, use'}{' '} - aria-rowcount - {isJa ? '、' : ','} aria-colcount - {isJa ? '、' : ', and'} aria-rowindex{' '} - {isJa - ? 'を使用してテーブル全体の構造を伝えます。' - : 'to communicate the full table structure.'} -

-
- -
-
-
-

{isJa ? 'セル結合' : 'Spanning Cells'}

-

- {isJa - ? 'セルは複数の列や行にまたがることができます。この実装では、視覚的な結合に CSS Grid の' - : 'Cells can span multiple columns or rows using'}{' '} - colspan {isJa ? 'と' : 'and'} rowspan - {isJa ? ' を使用し、CSS Grid の' : '. This implementation uses CSS Grid with'}{' '} - grid-column: span N {isJa ? 'と' : 'and'} grid-row: span N{' '} - {isJa - ? 'で視覚的な結合を行い、スクリーンリーダーのアクセシビリティのために' - : 'for visual spanning, plus'}{' '} - aria-colspan {isJa ? 'と' : 'and'} aria-rowspan{' '} - {isJa ? 'を使用しています。' : 'for screen reader accessibility.'} -

-
- -
-
- - ) -} - -{/* Astro demos */} -{ - framework === 'astro' && ( - <> -
-

{isJa ? '基本テーブル' : 'Basic Table'}

-

- {isJa - ? 'データを表示するシンプルな静的テーブル。インタラクティブな機能はありません。' - : 'A simple static table displaying data. No interactive features.'} -

-
- - - -
-

{isJa ? 'ソート可能なテーブル' : 'Sortable Table'}

-

- {isJa ? '列ヘッダーをクリックしてソートします。' : 'Click column headers to sort.'} Uses{' '} - aria-sort{' '} - {isJa - ? 'でソート方向を示します。このデモではインタラクティブなソートのために' - : 'to indicate sort direction. This demo uses a'}{' '} - React {isJa ? 'コンポーネントを' : 'component with'} client:load{' '} - {isJa ? 'で使用しています。' : 'for interactive sorting.'} -

-
- -
-
-
-

{isJa ? '行ヘッダー付き' : 'With Row Headers'}

-

- {isJa ? '各行の最初のセルが' : 'First cell in each row uses'}{' '} - role="rowheader"{' '} - {isJa - ? 'を使用し、スクリーンリーダーのナビゲーションを改善します。' - : 'for better screen reader navigation.'} -

-
-
- - -
-

{isJa ? '仮想化対応' : 'Virtualization Support'}

-

- {isJa ? '大規模なデータセットでは、' : 'For large datasets, use'}{' '} - aria-rowcount - {isJa ? '、' : ','} aria-colcount - {isJa ? '、' : ', and'} aria-rowindex{' '} - {isJa - ? 'を使用してテーブル全体の構造を伝えます。' - : 'to communicate the full table structure.'} -

-
-
- - -
-

{isJa ? 'セル結合' : 'Spanning Cells'}

-

- {isJa - ? 'セルは複数の列や行にまたがることができます。この実装では、視覚的な結合に CSS Grid の' - : 'Cells can span multiple columns or rows using'}{' '} - colspan {isJa ? 'と' : 'and'} rowspan - {isJa ? ' を使用し、CSS Grid の' : '. This implementation uses CSS Grid with'}{' '} - grid-column: span N {isJa ? 'と' : 'and'} grid-row: span N{' '} - {isJa - ? 'で視覚的な結合を行い、スクリーンリーダーのアクセシビリティのために' - : 'for visual spanning, plus'}{' '} - aria-colspan {isJa ? 'と' : 'and'} aria-rowspan{' '} - {isJa ? 'を使用しています。' : 'for screen reader accessibility.'} -

-
-
- - - - ) -} diff --git a/src/patterns/table/DemoSection.react.astro b/src/patterns/table/DemoSection.react.astro new file mode 100644 index 00000000..c7a44a4e --- /dev/null +++ b/src/patterns/table/DemoSection.react.astro @@ -0,0 +1,107 @@ +--- +import type { Framework } from '@/lib/frameworks'; +import type { Locale } from '@/i18n/ui'; +import { + BasicTableDemo, + SortableTableDemo, + RowHeaderTableDemo, + VirtualizedTableDemo, + SpanningCellsTableDemo, +} from './TableDemo'; + +interface Props { + framework?: Framework; + locale?: Locale; +} + +const { locale = 'en' } = Astro.props; +const isJa = locale === 'ja'; +--- + +
+

{isJa ? '基本テーブル' : 'Basic Table'}

+

+ { + isJa + ? 'データを表示するシンプルな静的テーブル。インタラクティブな機能はありません。' + : 'A simple static table displaying data. No interactive features.' + } +

+
+ +
+
+ +
+

{isJa ? 'ソート可能なテーブル' : 'Sortable Table'}

+

+ {isJa ? '列ヘッダーをクリックしてソートします。' : 'Click column headers to sort.'} Uses{' '} + aria-sort + {isJa ? 'でソート方向を示します。' : 'to indicate sort direction.'} +

+
+ +
+
+ +
+

{isJa ? '行ヘッダー付き' : 'With Row Headers'}

+

+ {isJa ? '各行の最初のセルが' : 'First cell in each row uses'} + role="rowheader"{' '} + { + isJa + ? 'を使用し、スクリーンリーダーのナビゲーションを改善します。' + : 'for better screen reader navigation.' + } +

+
+ +
+
+ +
+

{isJa ? '仮想化対応' : 'Virtualization Support'}

+

+ {isJa ? '大規模なデータセットでは、' : 'For large datasets, use'} + aria-rowcount + {isJa ? '、' : ','} + aria-colcount + {isJa ? '、' : ', and'} + aria-rowindex{' '} + {isJa ? 'を使用してテーブル全体の構造を伝えます。' : 'to communicate the full table structure.'} +

+
+ +
+
+ +
+

{isJa ? 'セル結合' : 'Spanning Cells'}

+

+ { + isJa + ? 'セルは複数の列や行にまたがることができます。この実装では、視覚的な結合に CSS Grid の' + : 'Cells can span multiple columns or rows using' + }{' '} + colspan + {isJa ? 'と' : 'and'} + rowspan + {isJa ? ' を使用し、CSS Grid の' : '. This implementation uses CSS Grid with'}{' '} + grid-column: span N + {isJa ? 'と' : 'and'} + grid-row: span N{' '} + { + isJa + ? 'で視覚的な結合を行い、スクリーンリーダーのアクセシビリティのために' + : 'for visual spanning, plus' + }{' '} + aria-colspan + {isJa ? 'と' : 'and'} + aria-rowspan{' '} + {isJa ? 'を使用しています。' : 'for screen reader accessibility.'} +

+
+ +
+
diff --git a/src/patterns/table/DemoSection.svelte.astro b/src/patterns/table/DemoSection.svelte.astro new file mode 100644 index 00000000..6d130932 --- /dev/null +++ b/src/patterns/table/DemoSection.svelte.astro @@ -0,0 +1,101 @@ +--- +import type { Framework } from '@/lib/frameworks'; +import type { Locale } from '@/i18n/ui'; +import TableDemoSvelte from './TableDemo.svelte'; + +interface Props { + framework?: Framework; + locale?: Locale; +} + +const { locale = 'en' } = Astro.props; +const isJa = locale === 'ja'; +--- + +
+

{isJa ? '基本テーブル' : 'Basic Table'}

+

+ { + isJa + ? 'データを表示するシンプルな静的テーブル。インタラクティブな機能はありません。' + : 'A simple static table displaying data. No interactive features.' + } +

+
+ +
+
+ +
+

{isJa ? 'ソート可能なテーブル' : 'Sortable Table'}

+

+ {isJa ? '列ヘッダーをクリックしてソートします。' : 'Click column headers to sort.'} Uses{' '} + aria-sort + {isJa ? 'でソート方向を示します。' : 'to indicate sort direction.'} +

+
+ +
+
+ +
+

{isJa ? '行ヘッダー付き' : 'With Row Headers'}

+

+ {isJa ? '各行の最初のセルが' : 'First cell in each row uses'} + role="rowheader"{' '} + { + isJa + ? 'を使用し、スクリーンリーダーのナビゲーションを改善します。' + : 'for better screen reader navigation.' + } +

+
+ +
+
+ +
+

{isJa ? '仮想化対応' : 'Virtualization Support'}

+

+ {isJa ? '大規模なデータセットでは、' : 'For large datasets, use'} + aria-rowcount + {isJa ? '、' : ','} + aria-colcount + {isJa ? '、' : ', and'} + aria-rowindex{' '} + {isJa ? 'を使用してテーブル全体の構造を伝えます。' : 'to communicate the full table structure.'} +

+
+ +
+
+ +
+

{isJa ? 'セル結合' : 'Spanning Cells'}

+

+ { + isJa + ? 'セルは複数の列や行にまたがることができます。この実装では、視覚的な結合に CSS Grid の' + : 'Cells can span multiple columns or rows using' + }{' '} + colspan + {isJa ? 'と' : 'and'} + rowspan + {isJa ? ' を使用し、CSS Grid の' : '. This implementation uses CSS Grid with'}{' '} + grid-column: span N + {isJa ? 'と' : 'and'} + grid-row: span N{' '} + { + isJa + ? 'で視覚的な結合を行い、スクリーンリーダーのアクセシビリティのために' + : 'for visual spanning, plus' + }{' '} + aria-colspan + {isJa ? 'と' : 'and'} + aria-rowspan{' '} + {isJa ? 'を使用しています。' : 'for screen reader accessibility.'} +

+
+ +
+
diff --git a/src/patterns/table/DemoSection.vue.astro b/src/patterns/table/DemoSection.vue.astro new file mode 100644 index 00000000..e7160734 --- /dev/null +++ b/src/patterns/table/DemoSection.vue.astro @@ -0,0 +1,101 @@ +--- +import type { Framework } from '@/lib/frameworks'; +import type { Locale } from '@/i18n/ui'; +import TableDemoVue from './TableDemo.vue'; + +interface Props { + framework?: Framework; + locale?: Locale; +} + +const { locale = 'en' } = Astro.props; +const isJa = locale === 'ja'; +--- + +
+

{isJa ? '基本テーブル' : 'Basic Table'}

+

+ { + isJa + ? 'データを表示するシンプルな静的テーブル。インタラクティブな機能はありません。' + : 'A simple static table displaying data. No interactive features.' + } +

+
+ +
+
+ +
+

{isJa ? 'ソート可能なテーブル' : 'Sortable Table'}

+

+ {isJa ? '列ヘッダーをクリックしてソートします。' : 'Click column headers to sort.'} Uses{' '} + aria-sort + {isJa ? 'でソート方向を示します。' : 'to indicate sort direction.'} +

+
+ +
+
+ +
+

{isJa ? '行ヘッダー付き' : 'With Row Headers'}

+

+ {isJa ? '各行の最初のセルが' : 'First cell in each row uses'} + role="rowheader"{' '} + { + isJa + ? 'を使用し、スクリーンリーダーのナビゲーションを改善します。' + : 'for better screen reader navigation.' + } +

+
+ +
+
+ +
+

{isJa ? '仮想化対応' : 'Virtualization Support'}

+

+ {isJa ? '大規模なデータセットでは、' : 'For large datasets, use'} + aria-rowcount + {isJa ? '、' : ','} + aria-colcount + {isJa ? '、' : ', and'} + aria-rowindex{' '} + {isJa ? 'を使用してテーブル全体の構造を伝えます。' : 'to communicate the full table structure.'} +

+
+ +
+
+ +
+

{isJa ? 'セル結合' : 'Spanning Cells'}

+

+ { + isJa + ? 'セルは複数の列や行にまたがることができます。この実装では、視覚的な結合に CSS Grid の' + : 'Cells can span multiple columns or rows using' + }{' '} + colspan + {isJa ? 'と' : 'and'} + rowspan + {isJa ? ' を使用し、CSS Grid の' : '. This implementation uses CSS Grid with'}{' '} + grid-column: span N + {isJa ? 'と' : 'and'} + grid-row: span N{' '} + { + isJa + ? 'で視覚的な結合を行い、スクリーンリーダーのアクセシビリティのために' + : 'for visual spanning, plus' + }{' '} + aria-colspan + {isJa ? 'と' : 'and'} + aria-rowspan{' '} + {isJa ? 'を使用しています。' : 'for screen reader accessibility.'} +

+
+ +
+
diff --git a/src/patterns/table/DemoSection.web-component.astro b/src/patterns/table/DemoSection.web-component.astro new file mode 100644 index 00000000..62cfb726 --- /dev/null +++ b/src/patterns/table/DemoSection.web-component.astro @@ -0,0 +1,128 @@ +--- +import type { Framework } from '@/lib/frameworks'; +import type { Locale } from '@/i18n/ui'; +import { SortableTableDemo } from './TableDemo'; +import Table from './Table.astro'; +import { + basicColumns, + basicRows, + rowHeaderRows, + virtualizedRows, + spanningColumns, + spanningRows, +} from './table-demo-data'; + +interface Props { + framework?: Framework; + locale?: Locale; +} + +const { locale = 'en' } = Astro.props; +const isJa = locale === 'ja'; +--- + +
+

{isJa ? '基本テーブル' : 'Basic Table'}

+

+ { + isJa + ? 'データを表示するシンプルな静的テーブル。インタラクティブな機能はありません。' + : 'A simple static table displaying data. No interactive features.' + } +

+
+
+ + + +
+

{isJa ? 'ソート可能なテーブル' : 'Sortable Table'}

+

+ {isJa ? '列ヘッダーをクリックしてソートします。' : 'Click column headers to sort.'} Uses{' '} + aria-sort{' '} + { + isJa + ? 'でソート方向を示します。このデモではインタラクティブなソートのために' + : 'to indicate sort direction. This demo uses a' + }{' '} + React {isJa ? 'コンポーネントを' : 'component with'} + client:load{' '} + {isJa ? 'で使用しています。' : 'for interactive sorting.'} +

+
+ +
+
+ +
+

{isJa ? '行ヘッダー付き' : 'With Row Headers'}

+

+ {isJa ? '各行の最初のセルが' : 'First cell in each row uses'} + role="rowheader"{' '} + { + isJa + ? 'を使用し、スクリーンリーダーのナビゲーションを改善します。' + : 'for better screen reader navigation.' + } +

+
+
+ + + +
+

{isJa ? '仮想化対応' : 'Virtualization Support'}

+

+ {isJa ? '大規模なデータセットでは、' : 'For large datasets, use'} + aria-rowcount + {isJa ? '、' : ','} + aria-colcount + {isJa ? '、' : ', and'} + aria-rowindex{' '} + {isJa ? 'を使用してテーブル全体の構造を伝えます。' : 'to communicate the full table structure.'} +

+
+
+ + + +
+

{isJa ? 'セル結合' : 'Spanning Cells'}

+

+ { + isJa + ? 'セルは複数の列や行にまたがることができます。この実装では、視覚的な結合に CSS Grid の' + : 'Cells can span multiple columns or rows using' + }{' '} + colspan + {isJa ? 'と' : 'and'} + rowspan + {isJa ? ' を使用し、CSS Grid の' : '. This implementation uses CSS Grid with'}{' '} + grid-column: span N + {isJa ? 'と' : 'and'} + grid-row: span N{' '} + { + isJa + ? 'で視覚的な結合を行い、スクリーンリーダーのアクセシビリティのために' + : 'for visual spanning, plus' + }{' '} + aria-colspan + {isJa ? 'と' : 'and'} + aria-rowspan{' '} + {isJa ? 'を使用しています。' : 'for screen reader accessibility.'} +

+
+
+ + diff --git a/src/patterns/table/table-demo-data.ts b/src/patterns/table/table-demo-data.ts new file mode 100644 index 00000000..974af649 --- /dev/null +++ b/src/patterns/table/table-demo-data.ts @@ -0,0 +1,53 @@ +/** + * Shared demo data for the Table pattern (Astro Web Component variant). + * + * The React / Vue / Svelte variants use wrapper demo components + * (TableDemo / SortableTableDemo / etc.) with their own internal data. + * The Astro Web Component variant consumes the raw rows/columns from here. + */ + +export const basicColumns = [ + { id: 'name', header: 'Name' }, + { id: 'age', header: 'Age' }, + { id: 'city', header: 'City' }, +]; + +export const basicRows = [ + { id: '1', cells: ['Alice', '30', 'Tokyo'] }, + { id: '2', cells: ['Bob', '25', 'Osaka'] }, + { id: '3', cells: ['Charlie', '35', 'Kyoto'] }, + { id: '4', cells: ['Diana', '28', 'Nagoya'] }, + { id: '5', cells: ['Edward', '42', 'Sapporo'] }, +]; + +export const rowHeaderRows = [ + { id: '1', cells: ['Alice', '30', 'Tokyo'], hasRowHeader: true }, + { id: '2', cells: ['Bob', '25', 'Osaka'], hasRowHeader: true }, + { id: '3', cells: ['Charlie', '35', 'Kyoto'], hasRowHeader: true }, +]; + +export const virtualizedRows = [ + { id: '5', cells: ['Alice', '30', 'Tokyo'], rowIndex: 5 }, + { id: '6', cells: ['Bob', '25', 'Osaka'], rowIndex: 6 }, + { id: '7', cells: ['Charlie', '35', 'Kyoto'], rowIndex: 7 }, + { id: '8', cells: ['Diana', '28', 'Nagoya'], rowIndex: 8 }, + { id: '9', cells: ['Edward', '42', 'Sapporo'], rowIndex: 9 }, +]; + +export const spanningColumns = [ + { id: 'product', header: 'Product' }, + { id: 'q1', header: 'Q1' }, + { id: 'q2', header: 'Q2' }, + { id: 'q3', header: 'Q3' }, + { id: 'q4', header: 'Q4' }, +]; + +export const spanningRows = [ + { + id: 'electronics', + cells: [{ content: 'Electronics', rowspan: 2 }, '150', '180', '200', '220'], + }, + { id: 'electronics-sub', cells: ['175', '190', '210', '240'] }, + { id: 'clothing', cells: ['Clothing', { content: 'N/A', colspan: 2 }, '90', '120'] }, + { id: 'summary', cells: [{ content: 'Total', colspan: 4 }, '1775'] }, +]; From 16f4caf65c1031e2cf1225bf577f68fcb7b5ed62 Mon Sep 17 00:00:00 2001 From: masuP9 Date: Mon, 11 May 2026 19:42:26 +0900 Subject: [PATCH 8/8] docs: note transitional state for 16 framework-split patterns After PR #169 (9 patterns) and PR-A (7 patterns), 16 of 32 patterns now use the framework-split DemoSection format. CLAUDE.md is updated to: - describe the new \`{pattern}-demo-data.ts\` convention (introduced in PR-A for variant-heavy patterns) - list the currently migrated patterns - note that the legacy format and dispatcher fallback will be removed in PR-B once all 32 patterns are split Co-Authored-By: Claude Opus 4.7 (1M context) --- CLAUDE.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CLAUDE.md b/CLAUDE.md index ec1f0517..4f0ff45f 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -84,7 +84,9 @@ src/ - **`meta.ts`**: タイトル、説明、TOC、リソース、フレームワーク別メタデータ(ソースファイル、API Props/Events/Slots)を `PatternMeta` 型で定義。全テキストは `Record` で 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 `