@gunjo/ui 0.0.1-alpha.1 → 0.0.1-alpha.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (224) hide show
  1. package/LICENSE +21 -0
  2. package/README.ja.md +90 -0
  3. package/README.md +52 -91
  4. package/package.json +47 -6
  5. package/src/components/display/Accordion.tsx +185 -0
  6. package/src/components/display/AccordionGroup.tsx +155 -0
  7. package/src/components/display/ActionDataTable.tsx +413 -0
  8. package/src/components/display/ActivityTimelineCard.tsx +483 -0
  9. package/src/components/display/AnalyticsCard.tsx +167 -0
  10. package/src/components/display/AssetCard.tsx +242 -0
  11. package/src/components/display/AssetGrid.tsx +164 -0
  12. package/src/components/display/Avatar.tsx +127 -0
  13. package/src/components/display/AvatarGroup.tsx +131 -0
  14. package/src/components/{atoms → display}/Badge.tsx +3 -3
  15. package/src/components/display/BarChart.tsx +247 -0
  16. package/src/components/{molecules → display}/Card.tsx +1 -1
  17. package/src/components/display/Carousel.tsx +593 -0
  18. package/src/components/display/ChartLegend.tsx +124 -0
  19. package/src/components/display/ChatMessage.tsx +382 -0
  20. package/src/components/display/ChoroplethMap.tsx +613 -0
  21. package/src/components/display/Code.tsx +42 -0
  22. package/src/components/display/CodeBlock.tsx +338 -0
  23. package/src/components/display/ColorSwatch.tsx +71 -0
  24. package/src/components/display/ConcentricProgressCard.tsx +545 -0
  25. package/src/components/display/DataTable.tsx +522 -0
  26. package/src/components/display/DistributionBar.tsx +102 -0
  27. package/src/components/display/DocNote.tsx +36 -0
  28. package/src/components/display/DonutChart.tsx +257 -0
  29. package/src/components/display/EmptyState.tsx +44 -0
  30. package/src/components/display/FileTree.tsx +180 -0
  31. package/src/components/display/GaugeChart.tsx +219 -0
  32. package/src/components/display/HeatmapChart.tsx +266 -0
  33. package/src/components/display/Icon.tsx +66 -0
  34. package/src/components/display/ImagePreview.tsx +140 -0
  35. package/src/components/{atoms → display}/Img.tsx +46 -12
  36. package/src/components/display/LabeledDonutCard.tsx +475 -0
  37. package/src/components/display/LineChart.tsx +464 -0
  38. package/src/components/{molecules → display}/List.tsx +20 -13
  39. package/src/components/display/MarkdownRenderer.tsx +157 -0
  40. package/src/components/display/MetadataList.tsx +81 -0
  41. package/src/components/display/MiniDistributionBarCard.tsx +314 -0
  42. package/src/components/display/PieChart.tsx +234 -0
  43. package/src/components/display/QuadrantMatrix.tsx +330 -0
  44. package/src/components/display/RadarChart.tsx +335 -0
  45. package/src/components/display/RadialBarChart.tsx +264 -0
  46. package/src/components/display/RetentionCohortCard.tsx +350 -0
  47. package/src/components/display/RibbonChart.tsx +618 -0
  48. package/src/components/display/SearchableAccordion.tsx +270 -0
  49. package/src/components/display/SegmentTimelineCard.tsx +452 -0
  50. package/src/components/display/SegmentedGaugeCard.tsx +607 -0
  51. package/src/components/display/Spacer.tsx +51 -0
  52. package/src/components/display/SparklineChart.tsx +394 -0
  53. package/src/components/display/StackedBarChart.tsx +393 -0
  54. package/src/components/display/Statistic.tsx +70 -0
  55. package/src/components/{molecules → display}/Table.tsx +22 -7
  56. package/src/components/display/Tag.tsx +80 -0
  57. package/src/components/display/TagEditor.tsx +141 -0
  58. package/src/components/display/Timeline.tsx +121 -0
  59. package/src/components/{atoms → display}/ToolPill.tsx +42 -18
  60. package/src/components/display/TreeView.tsx +226 -0
  61. package/src/components/display/chart-tooltip.tsx +423 -0
  62. package/src/components/display/chart-utils.ts +71 -0
  63. package/src/components/display/circular-chart-utils.ts +147 -0
  64. package/src/components/display/generated/default-variant-keys.ts +90 -0
  65. package/src/components/display/generated/variant-keys.ts +169 -0
  66. package/src/components/{atoms → feedback}/Alert.tsx +12 -5
  67. package/src/components/feedback/Banner.tsx +90 -0
  68. package/src/components/{molecules → feedback}/NotificationCenter.tsx +64 -31
  69. package/src/components/feedback/ProgressWidget.tsx +44 -0
  70. package/src/components/{atoms → feedback}/Spinner.tsx +2 -2
  71. package/src/components/{molecules → feedback}/StatusBar.tsx +4 -4
  72. package/src/components/feedback/StatusScreen.tsx +148 -0
  73. package/src/components/{molecules → feedback}/Stepper.tsx +10 -5
  74. package/src/components/feedback/Toast.tsx +108 -0
  75. package/src/components/feedback/ToastProvider.tsx +78 -0
  76. package/src/components/feedback/generated/default-variant-keys.ts +16 -0
  77. package/src/components/feedback/generated/variant-keys.ts +21 -0
  78. package/src/components/generated/component-manifest.ts +1568 -454
  79. package/src/components/generated/component-style-hints.ts +1958 -718
  80. package/src/components/{atoms → inputs}/ButtonVariants.ts +13 -3
  81. package/src/components/inputs/Calendar.tsx +212 -0
  82. package/src/components/inputs/ChatComposer.tsx +75 -0
  83. package/src/components/inputs/ChatInput.tsx +528 -0
  84. package/src/components/{atoms → inputs}/Checkbox.tsx +2 -2
  85. package/src/components/inputs/Combobox.tsx +175 -0
  86. package/src/components/inputs/CopyButton.tsx +187 -0
  87. package/src/components/inputs/DatePicker.tsx +519 -0
  88. package/src/components/inputs/DateRangePicker.tsx +878 -0
  89. package/src/components/inputs/EditableField.tsx +182 -0
  90. package/src/components/{organisms → inputs}/FileUploader.tsx +24 -9
  91. package/src/components/inputs/FilterButton.tsx +163 -0
  92. package/src/components/{molecules → inputs}/Form.tsx +20 -3
  93. package/src/components/{atoms → inputs}/Input.tsx +2 -0
  94. package/src/components/inputs/InputOTP.tsx +75 -0
  95. package/src/components/inputs/Mention.tsx +279 -0
  96. package/src/components/inputs/NumberInput.tsx +109 -0
  97. package/src/components/inputs/PasswordGroup.tsx +138 -0
  98. package/src/components/inputs/PasswordInput.tsx +74 -0
  99. package/src/components/inputs/PasswordRequirementList.tsx +96 -0
  100. package/src/components/inputs/PasswordStrengthMeter.tsx +93 -0
  101. package/src/components/inputs/PhoneInput.tsx +99 -0
  102. package/src/components/inputs/PostalCodeInput.tsx +98 -0
  103. package/src/components/inputs/RangeSlider.tsx +129 -0
  104. package/src/components/inputs/SearchInput.tsx +76 -0
  105. package/src/components/inputs/Select.tsx +39 -0
  106. package/src/components/{atoms → inputs}/Slider.tsx +18 -5
  107. package/src/components/{molecules → inputs}/SortButton.tsx +5 -2
  108. package/src/components/{atoms → inputs}/Switch.tsx +15 -4
  109. package/src/components/inputs/TagInput.tsx +114 -0
  110. package/src/components/{atoms → inputs}/Textarea.tsx +1 -0
  111. package/src/components/inputs/TimePicker.tsx +150 -0
  112. package/src/components/inputs/Toggle.tsx +48 -0
  113. package/src/components/{atoms → inputs}/ToggleGroup.tsx +2 -2
  114. package/src/components/inputs/TooltipButton.tsx +148 -0
  115. package/src/components/inputs/VoiceInputButton.tsx +317 -0
  116. package/src/components/inputs/calendar-holidays.ts +56 -0
  117. package/src/components/inputs/generated/default-variant-keys.ts +32 -0
  118. package/src/components/{atoms → inputs}/generated/variant-keys.ts +19 -27
  119. package/src/components/layout/AspectRatio.tsx +12 -0
  120. package/src/components/layout/AssetInspectorPanel.tsx +416 -0
  121. package/src/components/layout/Cluster.tsx +56 -0
  122. package/src/components/layout/CollapsiblePanelToggle.tsx +94 -0
  123. package/src/components/layout/Container.tsx +43 -0
  124. package/src/components/layout/DeviceFrame.tsx +227 -0
  125. package/src/components/layout/Grid.tsx +65 -0
  126. package/src/components/layout/HStack.tsx +73 -0
  127. package/src/components/{organisms → layout}/InspectorPanel.tsx +6 -5
  128. package/src/components/layout/MarqueeFrame.tsx +158 -0
  129. package/src/components/layout/Resizable.tsx +94 -0
  130. package/src/components/layout/ScrollArea.tsx +71 -0
  131. package/src/components/{organisms → layout}/SpatialCanvas.tsx +12 -7
  132. package/src/components/layout/VStack.tsx +69 -0
  133. package/src/components/layout/generated/default-variant-keys.ts +16 -0
  134. package/src/components/layout/generated/variant-keys.ts +21 -0
  135. package/src/components/{molecules → navigation}/Breadcrumb.tsx +5 -4
  136. package/src/components/navigation/Command.tsx +266 -0
  137. package/src/components/navigation/CommandPalette.tsx +83 -0
  138. package/src/components/navigation/DocumentPager.tsx +171 -0
  139. package/src/components/navigation/Footer.tsx +88 -0
  140. package/src/components/navigation/Header.tsx +80 -0
  141. package/src/components/{molecules → navigation}/Menubar.tsx +45 -12
  142. package/src/components/navigation/NavigationMenu.tsx +128 -0
  143. package/src/components/navigation/PageAside.tsx +84 -0
  144. package/src/components/{molecules → navigation}/Pagination.tsx +60 -7
  145. package/src/components/{organisms → navigation}/RightRail.tsx +1 -1
  146. package/src/components/navigation/Sidebar.tsx +223 -0
  147. package/src/components/navigation/SidebarItem.tsx +160 -0
  148. package/src/components/{molecules → navigation}/Tabs.tsx +2 -2
  149. package/src/components/navigation/TextLink.tsx +71 -0
  150. package/src/components/navigation/generated/default-variant-keys.ts +12 -0
  151. package/src/components/navigation/generated/variant-keys.ts +13 -0
  152. package/src/components/overlay/AIChatInput.tsx +5 -0
  153. package/src/components/overlay/AIChatMessage.tsx +6 -0
  154. package/src/components/overlay/AlertDialog.tsx +145 -0
  155. package/src/components/overlay/ChatPanel.tsx +180 -0
  156. package/src/components/{molecules → overlay}/ContextMenu.tsx +65 -29
  157. package/src/components/{molecules → overlay}/Dialog.tsx +21 -13
  158. package/src/components/overlay/Drawer.tsx +131 -0
  159. package/src/components/{molecules → overlay}/DropdownMenu.tsx +52 -17
  160. package/src/components/overlay/FloatingPanel.tsx +90 -0
  161. package/src/components/overlay/HoverCard.tsx +36 -0
  162. package/src/components/overlay/MediaLightbox.tsx +403 -0
  163. package/src/components/overlay/MediaPickerDialog.tsx +198 -0
  164. package/src/components/overlay/Modal.tsx +103 -0
  165. package/src/components/overlay/OnboardingFlow.tsx +172 -0
  166. package/src/components/overlay/Popover.tsx +36 -0
  167. package/src/components/overlay/ShareModal.tsx +324 -0
  168. package/src/components/{molecules → overlay}/Sheet.tsx +76 -19
  169. package/src/components/overlay/Tooltip.tsx +130 -0
  170. package/src/components/overlay/generated/default-variant-keys.ts +14 -0
  171. package/src/components/overlay/generated/variant-keys.ts +17 -0
  172. package/src/components/patterns/BlogTemplate.tsx +46 -0
  173. package/src/components/{templates → patterns}/DashboardTemplate.tsx +2 -2
  174. package/src/components/patterns/DocsTemplate.tsx +41 -0
  175. package/src/components/{templates → patterns}/MediaLibraryTemplate.tsx +1 -1
  176. package/src/components/patterns/OnboardingTemplate.tsx +32 -0
  177. package/src/components/patterns/PricingTemplate.tsx +106 -0
  178. package/src/globals.css +173 -22
  179. package/src/index.ts +177 -76
  180. package/tailwind-theme-extend.cjs +48 -3
  181. package/design/atoms-metadata.json +0 -82
  182. package/design/molecules-metadata.json +0 -130
  183. package/design/organisms-metadata.json +0 -38
  184. package/design/templates-metadata.json +0 -38
  185. package/src/components/atoms/Avatar.tsx +0 -57
  186. package/src/components/atoms/Select.tsx +0 -28
  187. package/src/components/atoms/generated/default-variant-keys.ts +0 -36
  188. package/src/components/molecules/AIChatInput.tsx +0 -140
  189. package/src/components/molecules/AIChatMessage.tsx +0 -109
  190. package/src/components/molecules/Accordion.tsx +0 -99
  191. package/src/components/molecules/Calendar.tsx +0 -60
  192. package/src/components/molecules/Carousel.tsx +0 -261
  193. package/src/components/molecules/Command.tsx +0 -152
  194. package/src/components/molecules/FilterButton.tsx +0 -133
  195. package/src/components/molecules/HoverCard.tsx +0 -29
  196. package/src/components/molecules/Modal.tsx +0 -66
  197. package/src/components/molecules/Popover.tsx +0 -31
  198. package/src/components/molecules/ProgressWidget.tsx +0 -40
  199. package/src/components/molecules/Resizable.tsx +0 -47
  200. package/src/components/molecules/ScrollArea.tsx +0 -48
  201. package/src/components/molecules/SidebarItem.tsx +0 -134
  202. package/src/components/molecules/Toast.tsx +0 -57
  203. package/src/components/molecules/Tooltip.tsx +0 -30
  204. package/src/components/molecules/generated/default-variant-keys.ts +0 -22
  205. package/src/components/molecules/generated/variant-keys.ts +0 -33
  206. package/src/components/organisms/CommandPalette.tsx +0 -58
  207. package/src/components/organisms/FloatingPanel.tsx +0 -46
  208. package/src/components/organisms/ShareModal.tsx +0 -182
  209. package/src/components/organisms/ToastProvider.tsx +0 -49
  210. /package/src/components/{atoms → display}/Kbd.tsx +0 -0
  211. /package/src/components/{atoms → display}/Separator.tsx +0 -0
  212. /package/src/components/{atoms → display}/Skeleton.tsx +0 -0
  213. /package/src/components/{atoms → feedback}/Progress.tsx +0 -0
  214. /package/src/components/{atoms → inputs}/Button.tsx +0 -0
  215. /package/src/components/{atoms → inputs}/Label.tsx +0 -0
  216. /package/src/components/{atoms → inputs}/RadioGroup.tsx +0 -0
  217. /package/src/components/{organisms → navigation}/AppRail.tsx +0 -0
  218. /package/src/components/{templates → patterns}/AuthTemplate.tsx +0 -0
  219. /package/src/components/{templates → patterns}/BannalyzeTemplate.tsx +0 -0
  220. /package/src/components/{templates → patterns}/ChatTemplate.tsx +0 -0
  221. /package/src/components/{templates → patterns}/EditorTemplate.tsx +0 -0
  222. /package/src/components/{templates → patterns}/KanbanTemplate.tsx +0 -0
  223. /package/src/components/{templates → patterns}/LandingTemplate.tsx +0 -0
  224. /package/src/components/{templates → patterns}/SettingsTemplate.tsx +0 -0
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 4px LLC
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.ja.md ADDED
@@ -0,0 +1,90 @@
1
+ # @gunjo/ui
2
+
3
+ [![npm version](https://img.shields.io/npm/v/@gunjo/ui.svg)](https://www.npmjs.com/package/@gunjo/ui)
4
+ [![License: MIT](https://img.shields.io/badge/License-MIT-blue.svg)](./LICENSE)
5
+
6
+ [English](./README.md) · **日本語**
7
+
8
+ *[UIXHERO](https://www.uixhero.com) が手がけるデザインシステム — ライブの [コンポーネントギャラリー](https://www.uixhero.com/resources/ui-components) もどうぞ。*
9
+
10
+ > ⚠️ **1.0 未満。** 現在の `0.0.1-alpha.x` は名前確保とリリース工程の試運転です。`1.0.0` stable まで public API は変わる可能性があります——バージョンを固定し、アップグレード前に [CHANGELOG](./CHANGELOG.md) を確認してください。
11
+
12
+ **Gunjo(群青)** は SSOT 駆動の React + Tailwind デザインシステムです。**pen デザインソース・React ソース・ドキュメントの 3 軸が常に同期している**ことを検証された 150+ コンポーネントを提供し、人だけでなく AI エージェントからも快適に使えるよう設計しています。
13
+
14
+ ## 「becoming」── 名前について
15
+
16
+ **群青(ぐんじょう)** は、伝統的な日本の色名に連なる深い青。けれどこの名が指すのは、**まだ青ならず、青になりつつある色**です。夜明け前の空、まだ乾かない墨。完成された青ではなく、これから青になる色──成長と、開かれた可能性の象徴。この *becoming* が、プロジェクトそのものの姿勢でもあります。AI 時代に作られ、完成を急がず、いまも到着し続けているデザインシステム。主役の **群青** を、温かい **媚茶(こびちゃ)** のアクセントが「土」として支えます。
17
+
18
+ ## なぜ Gunjo か
19
+
20
+ - **単一の正(SSOT)を強制する。** すべての公開コンポーネントは、デザインソース(`.pen`)・実装(`src/`)・ドキュメントの 3 軸で、自動ドリフト検査(`npm run design:verify`)により突合されます。トークン・バリアント・見た目が黙ってズレることがありません。
21
+ - **「何を作るか」で整理。** コンポーネントは機能別に分類されています──Inputs · Display · Charts · Feedback · Navigation · Overlay · Layout。抽象的な階層ではなく、用途で引けます。すべて Radix ベースで、アクセシビリティ(ARIA・キーボード)とダークモードを内包。
22
+
23
+ ## AI から使える設計
24
+
25
+ Gunjo は「エージェントがこれを読んで使う」を後付けではなく第一級の要件として扱います:
26
+
27
+ - **単一の型付きエントリ** — すべての公開 API を `src/index.ts` から re-export。`import { Button, Card } from '@gunjo/ui'` だけで、エージェント(や人)が API 全体を発見できます。
28
+ - **SSOT パイプライン** — 機械可読のコンポーネントメタデータ(`design/*-metadata.json`)が各コンポーネントのバリアントとトークンを記述。
29
+ - **AI ハンドオフ面** — 専用のハンドオフ面(docs サイトの `/ai-handoff`、MCP・Figma ガイドを含む)でエージェントがシステムを把握できます。*(公開 Figma ライブラリと MCP サーバは roadmap)*
30
+
31
+ ## クイックスタート
32
+
33
+ ```bash
34
+ npm install @gunjo/ui
35
+ ```
36
+
37
+ ```typescript
38
+ // コンポーネント
39
+ import { Button, Input, Card } from '@gunjo/ui';
40
+ // スタイル
41
+ import '@gunjo/ui/styles';
42
+ // Tailwind プリセット
43
+ import gunjoPreset from '@gunjo/ui/tailwind-preset';
44
+ ```
45
+
46
+ > **Next.js:** `next.config.ts` に `transpilePackages: ["@gunjo/ui"]` を追加してください(本パッケージは TypeScript ソースを直接配布します)。詳細は [docs/adoption.md](./docs/adoption.md)。
47
+
48
+ **別プロジェクトへ導入する**
49
+
50
+ - [docs/adoption.md](./docs/adoption.md) — 5 分インストール(ここから)
51
+ - [docs/adoption-strategy.md](./docs/adoption-strategy.md) — 配布形態の決定書
52
+ - [docs/migration-playbook.md](./docs/migration-playbook.md) — 既存アプリの段階移行
53
+ - [docs/dependencies.md](./docs/dependencies.md) — peer dependency 範囲とテスト済みの組み合わせ
54
+ - [docs/versioning.md](./docs/versioning.md) — semver 運用と破壊的変更ポリシー
55
+
56
+ **Gunjo を拡張する**
57
+
58
+ - [docs/component-addition.md](./docs/component-addition.md) — SSOT 三軸(pen + source + docs)でコンポーネントを追加する手順
59
+
60
+ ## ドキュメントサイト
61
+
62
+ ```bash
63
+ npm install
64
+ npm run dev # http://localhost:13030
65
+ ```
66
+
67
+ ドキュメントサイトは `@gunjo/ui` を自ら使って(ドッグフーディング)構築されており、全コンポーネント・トークン・パターンの正式リファレンスです。
68
+
69
+ ## Gunjo の作り方
70
+
71
+ Gunjo は、近い将来あたりまえになっていくと考える、シンプルな役割分担の上に作られています:
72
+
73
+ - **人が思想と方向を定める** — 何を作るか、何を大事にするか、美意識、すべての判断。
74
+ - **Claude と協働して作る** — 実装、網羅的な監査(アクセシビリティ・デザイントークン・全コンポーネントの視覚ドリフト)、そして速い反復。
75
+ - **そして AI から使えるよう設計する** — 単一の型付きエントリ、SSOT パイプライン、AI ハンドオフ面。エージェントが人と同じくらい簡単に読んで使えるように。
76
+
77
+ これは「AI がコンポーネントライブラリを作った」ではありません。一人の人間がビジョンを定め、AI をパートナーに、短いループで試行錯誤を重ねたものです。そしてそれを隠さず明示します——それが誠実で、そして次第に当たり前になっていく、ソフトウェアの作られ方だと考えるからです。
78
+
79
+ ## 貢献・セキュリティ
80
+
81
+ - [CONTRIBUTING.md](./CONTRIBUTING.md) — 開発参加の手引き、PR、SSOT 三軸ワークフロー
82
+ - [SECURITY.md](./SECURITY.md) — 脆弱性報告手順、サポート対象バージョン
83
+ - [CHANGELOG.md](./CHANGELOG.md) — リリース履歴
84
+ - [CLAUDE.md](./CLAUDE.md) — issue 駆動の working agreement(非自明な作業は issue を切ってから)
85
+
86
+ タスクは [GitHub Issues](https://github.com/uixhero/gunjo/issues) に集約しています。
87
+
88
+ ## ライセンス
89
+
90
+ [MIT](./LICENSE) © 2026 4px LLC · built by [UIXHERO](https://www.uixhero.com)
package/README.md CHANGED
@@ -1,129 +1,90 @@
1
1
  # @gunjo/ui
2
2
 
3
3
  [![npm version](https://img.shields.io/npm/v/@gunjo/ui.svg)](https://www.npmjs.com/package/@gunjo/ui)
4
+ [![License: MIT](https://img.shields.io/badge/License-MIT-blue.svg)](./LICENSE)
4
5
 
5
- > ⚠️ **Early alpha** `0.0.1-alpha.0` は名前確保とドライラン目的の初回 publish です。API は今後変更される可能性があります。本格採用は `1.0.0` stable リリース以降を推奨。
6
+ **English** · [日本語](./README.ja.md)
6
7
 
7
- SSOT-driven React + Tailwind デザインシステム。Pen / source / docs の 3 軸で整合性検証された 70 コンポーネントを提供。
8
+ *A design system from [UIXHERO](https://www.uixhero.com) see the live [component gallery](https://www.uixhero.com/resources/ui-components).*
8
9
 
9
- ## 📘 デザイン仕様(正式)
10
+ > ⚠️ **Pre-1.0.** The current `0.0.1-alpha.x` publish reserves the name and exercises the release pipeline. Until the `1.0.0` stable release the public API may change — pin your version and check the [CHANGELOG](./CHANGELOG.md) before upgrading.
10
11
 
11
- - UI デザイン仕様の正式ドキュメントは [DESIGN.md](./DESIGN.md) を参照してください。
12
- - SSOT 運用・同期手順は [design/README.md](./design/README.md) を参照してください。
13
- - 今回対応の概要と運用 RUNBOOK は [SSOT_RUNBOOK.md](./SSOT_RUNBOOK.md) を参照してください。
14
- - コンポーネント突合表(Source / Docs / Pen)は [COMPONENT_COVERAGE_MATRIX.md](./COMPONENT_COVERAGE_MATRIX.md) を参照してください。
15
- - 視覚監査台帳(docs vs pen)は [COMPONENT_VISUAL_AUDIT.md](./COMPONENT_VISUAL_AUDIT.md) を参照してください。
12
+ **Gunjo (群青)** is an SSOT-driven React + Tailwind design system — 150+ components whose **pen design source, React source, and docs are verified to stay in sync**, and which are built to be used as comfortably by AI agents as by people.
16
13
 
17
- ## 🚀 採用ガイド(他プロジェクトから使う)
14
+ ## "Becoming" — about the name
18
15
 
19
- GunjoUI を別アプリに導入したい場合:
16
+ *Gunjo (群青)* is a deep ultramarine from the traditional palette of Japanese color names. But the name points at a color **not yet blue — becoming blue**: the sky before dawn, ink before it dries. Not a finished blue, but one on its way there — a symbol of growth and open possibility. That *becoming* is the stance of the whole project: built in the age of AI, never quite finished, always arriving. The primary **群青 (ultramarine)** is grounded by a warm **媚茶 (kobicha)** accent — the earth that supports the becoming.
20
17
 
21
- - [docs/adoption.md](./docs/adoption.md) — **5 分インストール**(ここから始める)
22
- - [docs/adoption-strategy.md](./docs/adoption-strategy.md) — 配布形態の決定書
23
- - [docs/migration-playbook.md](./docs/migration-playbook.md) — 既存アプリの段階移行
24
- - [docs/dependencies.md](./docs/dependencies.md) — peer dependency 範囲とテスト済み組み合わせ
25
- - [docs/versioning.md](./docs/versioning.md) — semver 運用と破壊的変更ポリシー
18
+ ## Why Gunjo
26
19
 
27
- GunjoUI に新規コンポーネントを足したい場合:
20
+ - **One source of truth, enforced.** Every shipped component is checked across three axes — design source (`.pen`), implementation (`src/`), and documentation — by an automated drift pipeline (`npm run design:verify`). Tokens, variants, and visuals can't silently diverge.
21
+ - **Organized by what you build.** Components are grouped by function — Inputs · Display · Charts · Feedback · Navigation · Overlay · Layout — not by abstract tiers. All Radix-based, with accessibility (ARIA, keyboard) and dark mode built in.
28
22
 
29
- - [docs/component-addition.md](./docs/component-addition.md) SSOT 三軸(pen + source + docs)で追加する手順
23
+ ## AI-consumable by design
30
24
 
31
- ## 📦 セットアップ
25
+ Gunjo treats "an agent will read and use this" as a first-class requirement, not an afterthought:
32
26
 
33
- ### 依存関係のインストール
27
+ - **Single typed entry point** — every public API is re-exported from `src/index.ts`, so `import { Button, Card } from '@gunjo/ui'` is all an agent (or a person) needs to discover the surface.
28
+ - **SSOT pipeline** — machine-readable component metadata (`design/*-metadata.json`) describes every component's variants and tokens.
29
+ - **AI-handoff surface** — a dedicated handoff section (`/ai-handoff` in the docs, with MCP and Figma guides) for agents to pick up the system. *(A published Figma library and an MCP server are on the roadmap.)*
34
30
 
35
- ```bash
36
- cd gunjo
37
- npm install
38
- ```
39
-
40
- ### 型チェック
31
+ ## Quick start
41
32
 
42
33
  ```bash
43
- npm run type-check
34
+ npm install @gunjo/ui
44
35
  ```
45
36
 
46
- ## 🚀 ドキュメントサイトの起動
47
-
48
- ```bash
49
- npm run dev
37
+ ```typescript
38
+ // components
39
+ import { Button, Input, Card } from '@gunjo/ui';
40
+ // styles
41
+ import '@gunjo/ui/styles';
42
+ // tailwind preset
43
+ import gunjoPreset from '@gunjo/ui/tailwind-preset';
50
44
  ```
51
45
 
52
- ドキュメントサイトは `http://localhost:13030` で起動します。
46
+ > **Next.js:** add `transpilePackages: ["@gunjo/ui"]` to `next.config.ts` — the package ships TypeScript source directly. See [docs/adoption.md](./docs/adoption.md).
53
47
 
54
- ## 📚 使用方法(ライブラリとして)
48
+ **Adopting Gunjo in another project**
55
49
 
56
- ### インストール(他のプロジェクトから)
50
+ - [docs/adoption.md](./docs/adoption.md) — 5-minute install (start here)
51
+ - [docs/adoption-strategy.md](./docs/adoption-strategy.md) — distribution-format decision record
52
+ - [docs/migration-playbook.md](./docs/migration-playbook.md) — staged migration for existing apps
53
+ - [docs/dependencies.md](./docs/dependencies.md) — peer-dependency ranges and tested combinations
54
+ - [docs/versioning.md](./docs/versioning.md) — semver policy and breaking-change rules
57
55
 
58
- ```bash
59
- # npm から(推奨)
60
- npm install @gunjo/ui
56
+ **Extending Gunjo**
61
57
 
62
- # ローカルパスで(開発時)
63
- npm install file:../gunjo
64
- ```
65
-
66
- > **重要**:採用先 Next.js では `next.config.ts` に `transpilePackages: ["@gunjo/ui"]` を追加してください(本パッケージは TypeScript ソースを直接配布するため)。詳細は [docs/adoption.md §2](./docs/adoption.md#2-nextjs-設定必須)。
67
-
68
- ### インポート
69
-
70
- ```typescript
71
- // コンポーネント
72
- import { Button, Input, Card } from '@gunjo/ui';
58
+ - [docs/component-addition.md](./docs/component-addition.md) — add a component across the SSOT three axes (pen + source + docs)
73
59
 
74
- // スタイル
75
- import '@gunjo/ui/styles';
60
+ ## Documentation site
76
61
 
77
- // Tailwindプリセット
78
- import gunjoPreset from '@gunjo/ui/tailwind-preset';
62
+ ```bash
63
+ npm install
64
+ npm run dev # http://localhost:13030
79
65
  ```
80
66
 
81
- ## 完全独立
67
+ The docs site dogfoods `@gunjo/ui` and is the canonical reference for every component, token, and pattern.
82
68
 
83
- - 他のパッケージへの依存なし
84
- - ✅ 相対パスはすべて `gunjo/` ディレクトリ内
85
- - ✅ どこに移動しても動作します
86
- - ✅ `npm install` で依存関係をインストール可能
87
- - ✅ ドキュメントサイトも含まれています
69
+ ## How Gunjo was built
88
70
 
89
- ## 🤖 AIエディタでの利用
71
+ Gunjo is built on a simple division of labor — the kind we expect to become commonplace before long:
90
72
 
91
- コンポーネントは **AI エディタ(Cursor 等)で読み出して使いやすい** 構成にしています。
73
+ - **A human sets the philosophy and direction** — what to build, what matters, the aesthetic, every judgment call.
74
+ - **The system is built in collaboration with Claude** — implementation, exhaustive audits (accessibility, design tokens, visual drift across every component), and fast iteration.
75
+ - **And it is designed to be consumed by AI** — a single typed entry point, an SSOT pipeline, and an AI-handoff surface, so agents can read and use it as easily as people can.
92
76
 
93
- - **単一エントリ**: すべての公開 API `src/index.ts` から re-export しているため、`import { Button, Card } from '@gunjo/ui'` の形で一覧・利用しやすい
94
- - **TypeScript**: 各コンポーネントの props が型付けされており、補完・推論がしやすい
95
- - **Atomic Design**: Atoms / Molecules / Organisms / Templates で整理され、役割ごとに検索しやすい
96
- - **Radix UI ベース**: アクセシビリティ(ARIA・キーボード操作)を考慮した構造で、意味の読み取りがしやすい
77
+ This is not "an AI made a component library." It is one person setting the vision and iterating, in tight loops, with an AI partner — and being transparent about it, because we think that's the honest (and increasingly normal) way software gets made.
97
78
 
98
- 利用時は `@gunjo/ui` から必要なコンポーネントを import し、`@gunjo/ui/styles` と Tailwind プリセットを併用してください。
79
+ ## Contributing & security
99
80
 
100
- ## 📁 構造
81
+ - [CONTRIBUTING.md](./CONTRIBUTING.md) — workflow, PRs, the SSOT three-axis flow
82
+ - [SECURITY.md](./SECURITY.md) — vulnerability reporting and supported versions
83
+ - [CHANGELOG.md](./CHANGELOG.md) — release history
84
+ - [CLAUDE.md](./CLAUDE.md) — issue-driven working agreement (open an issue before non-trivial work)
101
85
 
102
- ```
103
- gunjo/
104
- ├── src/ # コンポーネントライブラリ
105
- │ ├── components/
106
- │ │ ├── atoms/ # 原子コンポーネント
107
- │ │ ├── molecules/ # 分子コンポーネント
108
- │ │ ├── organisms/ # 有機体コンポーネント
109
- │ │ └── templates/ # テンプレート
110
- │ ├── lib/ # ユーティリティ
111
- │ ├── globals.css # グローバルスタイル
112
- │ └── index.ts # エクスポート
113
- ├── docs/ # ドキュメントサイト(Next.js)
114
- │ ├── app/ # Next.jsアプリ
115
- │ ├── components/ # ドキュメント用コンポーネント
116
- │ └── lib/ # ドキュメント用ユーティリティ
117
- ├── public/ # 静的ファイル
118
- ├── tailwind-preset.js # Tailwindプリセット
119
- ├── next.config.ts # Next.js設定
120
- ├── postcss.config.mjs # PostCSS設定
121
- ├── package.json
122
- └── tsconfig.json
123
- ```
86
+ Work is tracked on [GitHub Issues](https://github.com/uixhero/gunjo/issues).
124
87
 
125
- ## 📝 注意事項
88
+ ## License
126
89
 
127
- - ライブラリとして使用する場合: `src/` からコンポーネントをインポート
128
- - ドキュメントサイトを起動する場合: `npm run dev` で起動
129
- - すべての依存関係は `package.json` に含まれています
90
+ [MIT](./LICENSE) © 2026 4px LLC · built by [UIXHERO](https://www.uixhero.com)
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@gunjo/ui",
3
- "version": "0.0.1-alpha.1",
3
+ "version": "0.0.1-alpha.2",
4
4
  "description": "GunjoUI — SSOT-driven React + Tailwind design system. Pen / source / docs three-axis verified. Early alpha: API may change. See docs/adoption.md to consume from another project.",
5
5
  "keywords": [
6
6
  "design-system",
@@ -12,6 +12,13 @@
12
12
  ],
13
13
  "main": "src/index.ts",
14
14
  "types": "src/index.ts",
15
+ "repository": {
16
+ "type": "git",
17
+ "url": "git+https://github.com/uixhero/gunjo.git"
18
+ },
19
+ "homepage": "https://github.com/uixhero/gunjo#readme",
20
+ "bugs": "https://github.com/uixhero/gunjo/issues",
21
+ "author": "4px LLC (https://www.uixhero.com)",
15
22
  "license": "MIT",
16
23
  "private": false,
17
24
  "publishConfig": {
@@ -38,6 +45,9 @@
38
45
  "build": "next build",
39
46
  "start": "next start",
40
47
  "lint": "eslint",
48
+ "showcase:thumbs": "node scripts/showcase-capture-thumbs.mjs && node scripts/sync-thumb-manifest.mjs",
49
+ "patterns:thumbs": "node scripts/patterns-capture-thumbs.mjs && node scripts/sync-thumb-manifest.mjs",
50
+ "thumbs:manifest": "node scripts/sync-thumb-manifest.mjs",
41
51
  "prepare": "npm run hooks:install",
42
52
  "hooks:install": "node scripts/install-git-hooks.mjs",
43
53
  "design:sync": "node scripts/design-sync.mjs",
@@ -45,6 +55,7 @@
45
55
  "design:sync:metadata": "node scripts/design-sync.mjs --metadata",
46
56
  "design:sync:components": "node scripts/design-sync.mjs --components",
47
57
  "design:sync:docs-navigation": "node scripts/design-sync.mjs --docs-navigation",
58
+ "design:sync:docs-embeds": "node scripts/sync-docs-embeds.mjs",
48
59
  "design:sync:docs-pages": "node scripts/design-sync.mjs --docs-pages",
49
60
  "design:sync:docs-pages:refresh": "node scripts/design-sync.mjs --docs-pages --refresh-generated",
50
61
  "design:sync:stubs": "node scripts/design-sync.mjs --stubs",
@@ -63,10 +74,8 @@
63
74
  "design:verify:node-snapshots": "node scripts/design-verify-node-snapshot-coverage.mjs",
64
75
  "design:verify:slot-nodes": "node scripts/design-verify-slot-node-coverage.mjs",
65
76
  "design:verify:atom-variant-keys": "node scripts/design-verify-atom-variant-key-coverage.mjs",
66
- "design:verify:atom-generated-variant-keys": "node scripts/design-verify-atom-generated-variant-key-coverage.mjs",
67
- "design:verify:atom-generated-variant-key-usage": "node scripts/design-verify-atom-generated-variant-key-usage.mjs",
68
- "design:verify:molecule-variant-keys": "node scripts/design-verify-molecule-variant-key-coverage.mjs",
69
- "design:verify:molecule-generated-variant-key-usage": "node scripts/design-verify-molecule-generated-variant-key-usage.mjs",
77
+ "design:verify:generated-variant-keys": "node scripts/design-verify-generated-variant-key-coverage.mjs",
78
+ "design:verify:generated-variant-key-usage": "node scripts/design-verify-generated-variant-key-usage.mjs",
70
79
  "design:verify:default-variant-keys": "node scripts/design-verify-default-variant-key-coverage.mjs",
71
80
  "design:verify:default-variant-key-usage": "node scripts/design-verify-default-variant-key-usage.mjs",
72
81
  "design:verify:component-style-hints": "node scripts/design-verify-component-style-hints-coverage.mjs",
@@ -79,6 +88,7 @@
79
88
  "design:verify:tailwind-theme-ssot": "node scripts/design-verify-tailwind-theme-ssot.mjs",
80
89
  "design:verify:tailwind-preset-plugins": "node scripts/design-verify-tailwind-preset-plugins.mjs",
81
90
  "design:verify:css-vars": "node scripts/design-verify-css-variable-coverage.mjs",
91
+ "design:verify:color-contrast": "node scripts/design-verify-color-contrast.mjs",
82
92
  "design:verify:app-globals": "node scripts/design-verify-app-globals-sync.mjs",
83
93
  "design:verify:generated-stubs": "node scripts/design-verify-generated-stub-coverage.mjs",
84
94
  "design:verify:generated-stubs:report": "node scripts/design-verify-generated-stub-coverage.mjs --report",
@@ -95,9 +105,30 @@
95
105
  "design:verify:ssot-progress-thresholds": "node scripts/design-verify-ssot-progress-thresholds.mjs",
96
106
  "design:verify:ssot-pr-comment-docs": "node scripts/design-verify-ssot-pr-comment-docs.mjs",
97
107
  "design:report:component-coverage": "node scripts/design-generate-component-coverage-matrix.mjs",
108
+ "design:report:figma-library": "node scripts/generate-figma-library-discovery.mjs",
109
+ "design:report:figma-foundations": "node scripts/generate-figma-foundations-payload.mjs",
98
110
  "design:audit:docs-capture": "node scripts/design-capture-doc-component-screenshots.mjs",
99
111
  "design:audit:checklist": "node scripts/design-generate-visual-audit-checklist.mjs",
100
112
  "design:audit:refresh": "npm run -s design:audit:docs-capture && npm run -s design:audit:checklist",
113
+ "docs:audit:components": "node scripts/audit-component-docs.mjs",
114
+ "docs:crawl:components": "node scripts/crawl-component-doc-pages.mjs",
115
+ "docs:audit:foundation-tokens": "npm run docs:audit:component-foundation-tokens && npm run docs:audit:runtime-foundation-tokens && npm run docs:audit:site-foundation-tokens",
116
+ "docs:audit:component-foundation-tokens": "node scripts/audit-component-foundation-tokens.mjs",
117
+ "docs:audit:runtime-foundation-tokens": "node scripts/audit-runtime-foundation-tokens.mjs",
118
+ "docs:audit:site-foundation-tokens": "node scripts/audit-site-foundation-tokens.mjs",
119
+ "docs:audit:extended-tokens": "npm run docs:audit:component-extended-tokens && npm run docs:audit:runtime-extended-tokens && npm run docs:audit:site-extended-tokens",
120
+ "docs:audit:component-extended-tokens": "node scripts/audit-component-extended-tokens.mjs",
121
+ "docs:audit:runtime-extended-tokens": "node scripts/audit-runtime-extended-tokens.mjs",
122
+ "docs:audit:site-extended-tokens": "node scripts/audit-site-extended-tokens.mjs",
123
+ "docs:audit:colors": "npm run docs:audit:component-colors && npm run docs:audit:runtime-colors && npm run docs:audit:site-colors",
124
+ "docs:audit:component-colors": "node scripts/audit-component-colors.mjs",
125
+ "docs:audit:runtime-colors": "node scripts/audit-runtime-colors.mjs",
126
+ "docs:audit:site-colors": "node scripts/audit-site-colors.mjs",
127
+ "docs:audit:mobile-disabled-feedback": "node scripts/audit-mobile-disabled-feedback.mjs",
128
+ "docs:audit:public-contrast": "node scripts/audit-public-contrast.mjs",
129
+ "docs:audit:en-locale-sweep": "node scripts/audit-en-locale-sweep.mjs",
130
+ "docs:audit:command-palette": "node scripts/audit-command-palette.mjs",
131
+ "docs:audit:lighthouse-public": "node scripts/audit-public-lighthouse.mjs",
101
132
  "design:verify:components": "node scripts/design-verify-components.mjs",
102
133
  "design:verify:molecules": "node scripts/design-verify-molecule-drift.mjs",
103
134
  "design:verify:organisms": "node scripts/design-verify-organism-drift.mjs",
@@ -109,13 +140,17 @@
109
140
  "tailwindcss": "^3.0.0 || ^4.0.0"
110
141
  },
111
142
  "dependencies": {
143
+ "@next/third-parties": "^16.2.9",
112
144
  "@radix-ui/react-accordion": "^1.2.12",
145
+ "@radix-ui/react-alert-dialog": "^1.1.15",
146
+ "@radix-ui/react-aspect-ratio": "^1.1.8",
113
147
  "@radix-ui/react-avatar": "^1.1.11",
114
148
  "@radix-ui/react-context-menu": "^2.2.16",
115
149
  "@radix-ui/react-dialog": "^1.1.15",
116
150
  "@radix-ui/react-dropdown-menu": "^2.1.16",
117
151
  "@radix-ui/react-hover-card": "^1.1.15",
118
152
  "@radix-ui/react-menubar": "^1.1.16",
153
+ "@radix-ui/react-navigation-menu": "^1.2.14",
119
154
  "@radix-ui/react-popover": "^1.1.15",
120
155
  "@radix-ui/react-scroll-area": "^1.2.10",
121
156
  "@radix-ui/react-slot": "^1.2.4",
@@ -123,12 +158,16 @@
123
158
  "@radix-ui/react-toggle-group": "^1.1.11",
124
159
  "@radix-ui/react-tooltip": "^1.2.8",
125
160
  "@radix-ui/react-visually-hidden": "^1.2.4",
161
+ "@tabler/icons-react": "^3.44.0",
162
+ "@tanstack/react-table": "^8.21.3",
163
+ "@vercel/analytics": "^2.0.1",
126
164
  "class-variance-authority": "^0.7.1",
127
165
  "clsx": "^2.1.1",
128
166
  "cmdk": "^1.1.1",
129
167
  "date-fns": "^4.1.0",
130
168
  "embla-carousel-react": "^8.6.0",
131
169
  "framer-motion": "^12.0.0",
170
+ "input-otp": "^1.4.2",
132
171
  "lucide-react": "^0.562.0",
133
172
  "next": "16.1.0",
134
173
  "next-themes": "^0.4.6",
@@ -140,7 +179,8 @@
140
179
  "remark-gfm": "^4.0.1",
141
180
  "shiki": "^3.20.0",
142
181
  "tailwind-merge": "^3.4.0",
143
- "tailwindcss-animate": "^1.0.7"
182
+ "tailwindcss-animate": "^1.0.7",
183
+ "vaul": "^1.1.2"
144
184
  },
145
185
  "devDependencies": {
146
186
  "@tailwindcss/postcss": "^4.1.18",
@@ -150,6 +190,7 @@
150
190
  "@types/react-syntax-highlighter": "^15.5.13",
151
191
  "eslint": "^9",
152
192
  "eslint-config-next": "16.1.0",
193
+ "lighthouse": "^12.8.2",
153
194
  "postcss": "^8.5.6",
154
195
  "puppeteer": "^24.41.0",
155
196
  "tailwindcss": "^4",
@@ -0,0 +1,185 @@
1
+ "use client"
2
+
3
+ import * as React from "react"
4
+ import * as AccordionPrimitive from "@radix-ui/react-accordion"
5
+ import {
6
+ IconChevronDown as ChevronDown,
7
+ IconPlus as Plus,
8
+ } from "@tabler/icons-react";
9
+
10
+ import { cn } from "../../lib/utils"
11
+ import { Icon } from "./Icon"
12
+ import { Tooltip, TooltipContent, TooltipTrigger } from "../overlay/Tooltip"
13
+ import type { AccordionVariantKey } from "./generated/variant-keys"
14
+ import { accordionDefaultVariantKey } from "./generated/default-variant-keys"
15
+
16
+ function buildVariantStateMap(
17
+ defaultVariantKey: AccordionVariantKey,
18
+ defaultStateClass: string,
19
+ alternateStateClass: string
20
+ ): Record<AccordionVariantKey, string> {
21
+ return defaultVariantKey === "collapsed"
22
+ ? { collapsed: defaultStateClass, expanded: alternateStateClass }
23
+ : { collapsed: alternateStateClass, expanded: defaultStateClass }
24
+ }
25
+
26
+ const expandedAccordionVariantKey: AccordionVariantKey =
27
+ accordionDefaultVariantKey === "collapsed" ? "expanded" : "collapsed"
28
+
29
+ const contentStateClasses = buildVariantStateMap(
30
+ accordionDefaultVariantKey,
31
+ "data-[state=closed]:animate-accordion-up",
32
+ "data-[state=open]:animate-accordion-down"
33
+ )
34
+
35
+ const Accordion = React.forwardRef<
36
+ React.ElementRef<typeof AccordionPrimitive.Root>,
37
+ React.ComponentPropsWithoutRef<typeof AccordionPrimitive.Root>
38
+ >(({ className, ...props }, ref) => (
39
+ <AccordionPrimitive.Root
40
+ ref={ref}
41
+ className={cn("flex flex-col w-[400px] border", className)}
42
+ {...props}
43
+ />
44
+ ))
45
+ Accordion.displayName = AccordionPrimitive.Root.displayName
46
+
47
+ const AccordionItem = React.forwardRef<
48
+ React.ElementRef<typeof AccordionPrimitive.Item>,
49
+ React.ComponentPropsWithoutRef<typeof AccordionPrimitive.Item>
50
+ >(({ className, ...props }, ref) => (
51
+ <AccordionPrimitive.Item
52
+ ref={ref}
53
+ className={cn("border-b", className)}
54
+ {...props}
55
+ />
56
+ ))
57
+ AccordionItem.displayName = "AccordionItem"
58
+
59
+ type AccordionTriggerIndicator = "chevron" | "plus" | "none"
60
+
61
+ interface AccordionTriggerProps
62
+ extends React.ComponentPropsWithoutRef<typeof AccordionPrimitive.Trigger> {
63
+ /**
64
+ * Visual indicator shown at the trailing edge of the trigger.
65
+ * `chevron` is the default navigation-style affordance. `plus` is useful
66
+ * for FAQ and disclosure lists where open/close reads as add/remove.
67
+ */
68
+ indicator?: AccordionTriggerIndicator
69
+ /** Tooltip label shown when the item is closed. */
70
+ openLabel?: string
71
+ /** Tooltip label shown when the item is open. */
72
+ closeLabel?: string
73
+ }
74
+
75
+ function AccordionTriggerIndicator({
76
+ indicator,
77
+ openLabel,
78
+ closeLabel,
79
+ }: {
80
+ indicator: AccordionTriggerIndicator
81
+ openLabel: string
82
+ closeLabel: string
83
+ }) {
84
+ const indicatorRef = React.useRef<HTMLSpanElement | null>(null)
85
+ const [tooltipLabel, setTooltipLabel] = React.useState(openLabel)
86
+
87
+ const updateTooltipLabel = React.useCallback(() => {
88
+ const trigger = indicatorRef.current?.closest("button[data-state]")
89
+ const isOpen = trigger?.getAttribute("data-state") === "open"
90
+ setTooltipLabel(isOpen ? closeLabel : openLabel)
91
+ }, [closeLabel, openLabel])
92
+
93
+ React.useEffect(() => {
94
+ const trigger = indicatorRef.current?.closest("button[data-state]")
95
+ if (!trigger) return
96
+
97
+ updateTooltipLabel()
98
+
99
+ const observer = new MutationObserver(updateTooltipLabel)
100
+ observer.observe(trigger, {
101
+ attributes: true,
102
+ attributeFilter: ["data-state"],
103
+ })
104
+
105
+ return () => observer.disconnect()
106
+ }, [updateTooltipLabel])
107
+
108
+ if (indicator === "none") return null
109
+
110
+ const indicatorNode = indicator === "plus"
111
+ ? (
112
+ <Icon
113
+ icon={Plus}
114
+ size="sm"
115
+ className="h-4 w-4 shrink-0 transition-transform duration-200 group-data-[state=open]:rotate-45"
116
+ />
117
+ )
118
+ : (
119
+ <Icon
120
+ icon={ChevronDown}
121
+ size="sm"
122
+ className="h-4 w-4 shrink-0 transition-transform duration-200 group-data-[state=open]:rotate-180"
123
+ />
124
+ )
125
+
126
+ return (
127
+ <Tooltip>
128
+ <TooltipTrigger asChild>
129
+ <span
130
+ ref={indicatorRef}
131
+ className="inline-flex h-6 w-6 shrink-0 items-center justify-center rounded-sm"
132
+ onFocus={updateTooltipLabel}
133
+ onMouseEnter={updateTooltipLabel}
134
+ >
135
+ {indicatorNode}
136
+ </span>
137
+ </TooltipTrigger>
138
+ <TooltipContent>{tooltipLabel}</TooltipContent>
139
+ </Tooltip>
140
+ )
141
+ }
142
+
143
+ const AccordionTrigger = React.forwardRef<
144
+ React.ElementRef<typeof AccordionPrimitive.Trigger>,
145
+ AccordionTriggerProps
146
+ >(({ className, children, indicator = "chevron", openLabel = "Open", closeLabel = "Close", ...props }, ref) => (
147
+ <AccordionPrimitive.Header className="flex">
148
+ <AccordionPrimitive.Trigger
149
+ ref={ref}
150
+ className={cn(
151
+ "group flex flex-1 items-center justify-between px-4 py-4 text-sm font-medium transition-all hover:underline disabled:cursor-not-allowed disabled:opacity-55 disabled:hover:no-underline [&[data-state=open]>svg]:rotate-180",
152
+ className
153
+ )}
154
+ {...props}
155
+ >
156
+ {children}
157
+ <AccordionTriggerIndicator
158
+ indicator={indicator}
159
+ openLabel={openLabel}
160
+ closeLabel={closeLabel}
161
+ />
162
+ </AccordionPrimitive.Trigger>
163
+ </AccordionPrimitive.Header>
164
+ ))
165
+ AccordionTrigger.displayName = AccordionPrimitive.Trigger.displayName
166
+
167
+ const AccordionContent = React.forwardRef<
168
+ React.ElementRef<typeof AccordionPrimitive.Content>,
169
+ React.ComponentPropsWithoutRef<typeof AccordionPrimitive.Content>
170
+ >(({ className, children, ...props }, ref) => (
171
+ <AccordionPrimitive.Content
172
+ ref={ref}
173
+ className={cn(
174
+ "overflow-hidden text-sm text-muted-foreground transition-all",
175
+ contentStateClasses[accordionDefaultVariantKey],
176
+ contentStateClasses[expandedAccordionVariantKey]
177
+ )}
178
+ {...props}
179
+ >
180
+ <div className={cn("px-4 pb-4 pt-0", className)}>{children}</div>
181
+ </AccordionPrimitive.Content>
182
+ ))
183
+ AccordionContent.displayName = AccordionPrimitive.Content.displayName
184
+
185
+ export { Accordion, AccordionItem, AccordionTrigger, AccordionContent }