@godxjp/ui 28.9.0 → 28.12.0

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 (244) hide show
  1. package/agent/START-HERE.md +193 -0
  2. package/agent/anti-ai-tells.json +158 -0
  3. package/agent/components/Accordion.json +60 -0
  4. package/agent/components/AccountChip.json +59 -0
  5. package/agent/components/Actions.json +78 -0
  6. package/agent/components/Activity.json +80 -0
  7. package/agent/components/Affix.json +78 -0
  8. package/agent/components/Alert.json +65 -0
  9. package/agent/components/AlertDialog.json +109 -0
  10. package/agent/components/AlertDialogRoot.json +52 -0
  11. package/agent/components/Anchor.json +119 -0
  12. package/agent/components/AppLauncher.json +95 -0
  13. package/agent/components/AppProvider.json +105 -0
  14. package/agent/components/AppSettingPicker.json +88 -0
  15. package/agent/components/AppSettingToggle.json +70 -0
  16. package/agent/components/AppShell.json +159 -0
  17. package/agent/components/AreaChart.json +105 -0
  18. package/agent/components/AspectRatio.json +38 -0
  19. package/agent/components/Attachments.json +77 -0
  20. package/agent/components/AuthAccountSummary.json +64 -0
  21. package/agent/components/AuthDivider.json +35 -0
  22. package/agent/components/AuthFooter.json +48 -0
  23. package/agent/components/AuthIdentity.json +42 -0
  24. package/agent/components/AuthShell.json +108 -0
  25. package/agent/components/AuthStack.json +21 -0
  26. package/agent/components/Avatar.json +89 -0
  27. package/agent/components/Badge.json +96 -0
  28. package/agent/components/Banner.json +48 -0
  29. package/agent/components/BarChart.json +108 -0
  30. package/agent/components/BranchScopePicker.json +89 -0
  31. package/agent/components/Breadcrumb.json +54 -0
  32. package/agent/components/Button.json +133 -0
  33. package/agent/components/Calendar.json +259 -0
  34. package/agent/components/Callout.json +46 -0
  35. package/agent/components/Card.json +112 -0
  36. package/agent/components/CardBar.json +49 -0
  37. package/agent/components/CardContent.json +51 -0
  38. package/agent/components/Carousel.json +50 -0
  39. package/agent/components/Cascader.json +209 -0
  40. package/agent/components/CenteredShell.json +66 -0
  41. package/agent/components/ChatBubble.json +100 -0
  42. package/agent/components/ChatBubbleList.json +64 -0
  43. package/agent/components/ChatComposer.json +160 -0
  44. package/agent/components/ChatSuggestion.json +86 -0
  45. package/agent/components/Checkbox.json +68 -0
  46. package/agent/components/CheckboxGroup.json +96 -0
  47. package/agent/components/CodeBlock.json +64 -0
  48. package/agent/components/Collapsible.json +74 -0
  49. package/agent/components/ColorPicker.json +87 -0
  50. package/agent/components/Command.json +168 -0
  51. package/agent/components/CommandPalette.json +84 -0
  52. package/agent/components/CompactBarTrend.json +101 -0
  53. package/agent/components/Conversations.json +82 -0
  54. package/agent/components/CredentialReveal.json +93 -0
  55. package/agent/components/DataState.json +79 -0
  56. package/agent/components/DataTable.json +268 -0
  57. package/agent/components/DatePicker.json +275 -0
  58. package/agent/components/Descriptions.json +67 -0
  59. package/agent/components/Dialog.json +78 -0
  60. package/agent/components/DraggablePanel.json +106 -0
  61. package/agent/components/DropdownMenu.json +102 -0
  62. package/agent/components/EmptyState.json +83 -0
  63. package/agent/components/ErrorSurface.json +128 -0
  64. package/agent/components/FeatureList.json +43 -0
  65. package/agent/components/Field.json +64 -0
  66. package/agent/components/FilterBar.json +99 -0
  67. package/agent/components/Flex.json +153 -0
  68. package/agent/components/FloatButton.json +91 -0
  69. package/agent/components/Form.json +87 -0
  70. package/agent/components/FormErrors.json +51 -0
  71. package/agent/components/FormField.json +137 -0
  72. package/agent/components/FormFieldArray.json +39 -0
  73. package/agent/components/FormFieldControl.json +129 -0
  74. package/agent/components/FormRoot.json +122 -0
  75. package/agent/components/Heading.json +61 -0
  76. package/agent/components/HoverCard.json +55 -0
  77. package/agent/components/Icon.json +60 -0
  78. package/agent/components/InfiniteQueryState.json +58 -0
  79. package/agent/components/Input.json +122 -0
  80. package/agent/components/InputOTP.json +106 -0
  81. package/agent/components/Label.json +43 -0
  82. package/agent/components/LegalDocumentShell.json +102 -0
  83. package/agent/components/Legend.json +42 -0
  84. package/agent/components/LineChart.json +103 -0
  85. package/agent/components/Link.json +41 -0
  86. package/agent/components/ListRow.json +92 -0
  87. package/agent/components/Logo.json +85 -0
  88. package/agent/components/Marquee.json +91 -0
  89. package/agent/components/Masonry.json +82 -0
  90. package/agent/components/MasterDetail.json +95 -0
  91. package/agent/components/MegaMenu.json +120 -0
  92. package/agent/components/MobileShell.json +73 -0
  93. package/agent/components/NavList.json +63 -0
  94. package/agent/components/NumberInput.json +158 -0
  95. package/agent/components/OrgSwitcher.json +89 -0
  96. package/agent/components/OverlayPortalProvider.json +42 -0
  97. package/agent/components/PageContainer.json +181 -0
  98. package/agent/components/Pagination.json +132 -0
  99. package/agent/components/Paragraph.json +40 -0
  100. package/agent/components/PasswordInput.json +79 -0
  101. package/agent/components/PasswordStrength.json +51 -0
  102. package/agent/components/PermissionMatrix.json +81 -0
  103. package/agent/components/PieChart.json +99 -0
  104. package/agent/components/Popover.json +110 -0
  105. package/agent/components/PrefetchLink.json +65 -0
  106. package/agent/components/Progress.json +79 -0
  107. package/agent/components/Prose.json +57 -0
  108. package/agent/components/QrCode.json +62 -0
  109. package/agent/components/Radio.json +98 -0
  110. package/agent/components/RadioGroup.json +91 -0
  111. package/agent/components/RangeTimeline.json +80 -0
  112. package/agent/components/Rating.json +92 -0
  113. package/agent/components/ResizablePanel.json +69 -0
  114. package/agent/components/ResponsiveGrid.json +77 -0
  115. package/agent/components/Reveal.json +70 -0
  116. package/agent/components/ScrollArea.json +104 -0
  117. package/agent/components/SearchInput.json +98 -0
  118. package/agent/components/Segmented.json +96 -0
  119. package/agent/components/Select.json +397 -0
  120. package/agent/components/Separator.json +86 -0
  121. package/agent/components/ServiceCatalogCta.json +46 -0
  122. package/agent/components/ServiceLauncherCard.json +93 -0
  123. package/agent/components/ServiceRolePanel.json +83 -0
  124. package/agent/components/Sheet.json +85 -0
  125. package/agent/components/Sidebar.json +118 -0
  126. package/agent/components/Skeleton.json +57 -0
  127. package/agent/components/SkeletonArticle.json +71 -0
  128. package/agent/components/SkeletonAvatar.json +50 -0
  129. package/agent/components/SkeletonButton.json +57 -0
  130. package/agent/components/SkeletonForm.json +52 -0
  131. package/agent/components/SkeletonImage.json +37 -0
  132. package/agent/components/SkeletonInput.json +51 -0
  133. package/agent/components/SkeletonNode.json +42 -0
  134. package/agent/components/SkeletonRows.json +49 -0
  135. package/agent/components/SkeletonTable.json +45 -0
  136. package/agent/components/Slider.json +160 -0
  137. package/agent/components/SplitPane.json +66 -0
  138. package/agent/components/StatCard.json +83 -0
  139. package/agent/components/Steps.json +95 -0
  140. package/agent/components/Swatch.json +41 -0
  141. package/agent/components/Switch.json +81 -0
  142. package/agent/components/Table.json +112 -0
  143. package/agent/components/Tabs.json +158 -0
  144. package/agent/components/TagInput.json +105 -0
  145. package/agent/components/Text.json +201 -0
  146. package/agent/components/Textarea.json +126 -0
  147. package/agent/components/ThoughtChain.json +76 -0
  148. package/agent/components/Thumbnail.json +70 -0
  149. package/agent/components/TimePicker.json +200 -0
  150. package/agent/components/TimeRangePicker.json +90 -0
  151. package/agent/components/Timeline.json +47 -0
  152. package/agent/components/TimelineGrid.json +92 -0
  153. package/agent/components/Title.json +67 -0
  154. package/agent/components/Toaster.json +42 -0
  155. package/agent/components/Toggle.json +90 -0
  156. package/agent/components/ToggleGroup.json +102 -0
  157. package/agent/components/Toolbar.json +120 -0
  158. package/agent/components/Tooltip.json +110 -0
  159. package/agent/components/Topbar.json +83 -0
  160. package/agent/components/TopbarItem.json +79 -0
  161. package/agent/components/Transfer.json +141 -0
  162. package/agent/components/Tree.json +185 -0
  163. package/agent/components/TreeSelect.json +232 -0
  164. package/agent/components/TwoFactorSetup.json +79 -0
  165. package/agent/components/Typography.json +42 -0
  166. package/agent/components/Upload.json +221 -0
  167. package/agent/components/UploadCropDialog.json +60 -0
  168. package/agent/components/VisuallyHidden.json +20 -0
  169. package/agent/components/Welcome.json +65 -0
  170. package/agent/components/formatDate.json +46 -0
  171. package/agent/components/inertiaUpload.json +32 -0
  172. package/agent/components/useZodForm.json +39 -0
  173. package/agent/components-index.json +884 -0
  174. package/agent/components.json +15515 -0
  175. package/agent/index.json +56 -0
  176. package/agent/llms.txt +32 -0
  177. package/agent/patterns/account-recovery-settings.json +19 -0
  178. package/agent/patterns/async-data-state.json +20 -0
  179. package/agent/patterns/auth-recovery-panels.json +29 -0
  180. package/agent/patterns/badge-coloring.json +14 -0
  181. package/agent/patterns/common-fixes.json +16 -0
  182. package/agent/patterns/confirm-destructive.json +11 -0
  183. package/agent/patterns/data-table-page.json +18 -0
  184. package/agent/patterns/deferred-loading.json +12 -0
  185. package/agent/patterns/error-pages.json +28 -0
  186. package/agent/patterns/inertia-detail-page.json +13 -0
  187. package/agent/patterns/inertia-list-page.json +15 -0
  188. package/agent/patterns/inertia-persistent-layout.json +14 -0
  189. package/agent/patterns/organization-memberships.json +19 -0
  190. package/agent/patterns/page-sections.json +18 -0
  191. package/agent/patterns/settings-page-responsive.json +18 -0
  192. package/agent/patterns/settings-section-rows.json +23 -0
  193. package/agent/patterns/signup-form.json +13 -0
  194. package/agent/patterns/topbar-account-chip.json +18 -0
  195. package/agent/patterns/transactional-email.json +22 -0
  196. package/agent/patterns-index.json +323 -0
  197. package/agent/patterns.json +342 -0
  198. package/agent/rules.json +237 -0
  199. package/agent/tokens.json +8427 -0
  200. package/agent/vocabulary.json +198 -0
  201. package/dist/components/data-display/service-launcher-card.d.ts +19 -0
  202. package/dist/components/data-display/service-launcher-card.js +14 -1
  203. package/dist/components/data-entry/attachments.js +77 -33
  204. package/dist/components/data-entry/input.js +8 -1
  205. package/dist/components/layout/flex.d.ts +2 -2
  206. package/dist/components/layout/flex.js +2 -0
  207. package/dist/components/ui/avatar.d.ts +1 -18
  208. package/dist/components/ui/avatar.js +1 -36
  209. package/dist/components/ui/tag-input.d.ts +10 -0
  210. package/dist/components/ui/tag-input.js +35 -2
  211. package/dist/contracts/measurement.json +1 -1
  212. package/dist/i18n/messages/en.json +190 -1
  213. package/dist/i18n/messages/ja.json +188 -1
  214. package/dist/i18n/messages/vi.json +188 -1
  215. package/dist/lib/image-loading-status.d.ts +25 -0
  216. package/dist/lib/image-loading-status.js +41 -0
  217. package/dist/props/components/data-entry.prop.d.ts +21 -2
  218. package/dist/props/components/layout.prop.d.ts +42 -0
  219. package/dist/props/registry.d.ts +14 -1
  220. package/dist/props/registry.js +18 -1
  221. package/dist/styles/card-layout.css +10 -4
  222. package/dist/styles/control.css +33 -4
  223. package/dist/styles/data-display-layout.css +1 -1
  224. package/dist/styles/data-entry-layout.css +245 -2
  225. package/dist/styles/layout.css +17 -0
  226. package/dist/styles/navigation-layout.css +3 -1
  227. package/dist/styles/shell-layout.css +2 -0
  228. package/dist/styles/table-layout.css +50 -9
  229. package/dist/tokens/components/attachments.css +18 -9
  230. package/dist/tokens/components/segmented.css +7 -3
  231. package/dist/tokens/components/table.css +2 -1
  232. package/docs/COMPOSITION-VS-COMPONENT.md +41 -0
  233. package/docs/DESIGN-AUTHORITY.md +52 -0
  234. package/docs/DEVELOPMENT.md +81 -6
  235. package/docs/assets/service-mark-rose.svg +6 -0
  236. package/docs/assets/service-mark-teal.svg +5 -0
  237. package/docs/data-display/service-launcher-card.tsx +232 -92
  238. package/docs/data-entry/tag-input.tsx +37 -0
  239. package/docs/layout/flex.tsx +40 -0
  240. package/docs/roadmap/website-components.md +34 -0
  241. package/docs/showcase/marketing-page.tsx +54 -45
  242. package/docs/showcase/table-pagination.tsx +99 -18
  243. package/docs/showcase/theme-customization.tsx +25 -2
  244. package/package.json +8 -5
@@ -19,8 +19,20 @@ import {
19
19
  ServiceLauncherCardSkeleton,
20
20
  } from "@godxjp/ui/data-display";
21
21
  import { Button, Text } from "@godxjp/ui/general";
22
+ import { useTranslation } from "@godxjp/ui/i18n";
22
23
  import { Flex, PageContainer, ResponsiveGrid } from "@godxjp/ui/layout";
23
24
 
25
+ /* Committed SVGs, imported so the bundler rewrites each URL against PREVIEW_BASE. A docs page must
26
+ * never fetch a third-party image: offline it cannot render, and on CI the request never settles,
27
+ * `networkidle` never fires and `page.goto` times out. */
28
+ import serviceMarkRose from "../assets/service-mark-rose.svg";
29
+ import serviceMarkTeal from "../assets/service-mark-teal.svg";
30
+
31
+ /* A URL that is GUARANTEED to fail, with no network round-trip to hang on: the bytes are not an
32
+ * image, so the browser's decode fails locally. That is the production case this section exists to
33
+ * show — `logo_path` in the database outlives the file on disk. */
34
+ const BROKEN_LOGO_URL = "data:image/svg+xml,not-an-image";
35
+
24
36
  /**
25
37
  * ServiceLauncherCard — one tile for one application in an organization's launcher.
26
38
  *
@@ -36,6 +48,10 @@ import { Flex, PageContainer, ResponsiveGrid } from "@godxjp/ui/layout";
36
48
  * own entitlement contract. There is no `href`, no `available`, no `entitlement` prop to find.
37
49
  *
38
50
  * ResponsiveGrid owns the 3 → 2 → 1 ladder. The page writes no grid tracks and no page-local CSS.
51
+ *
52
+ * All copy is localized through useTranslation() — see docs/showcase/table-pagination.tsx for the
53
+ * pattern this follows. `metadata` (hostnames, version strings, pixel dimensions) is domain DATA
54
+ * and stays literal; it is what the gate does not scan and what localizing would be wrong for.
39
55
  */
40
56
 
41
57
  /** A section heading. Headings are headings, not Cards — a Card here would nest borders. */
@@ -62,240 +78,364 @@ function Section({
62
78
  }
63
79
 
64
80
  export default function Demo() {
81
+ const { t } = useTranslation();
82
+
83
+ // Status-tone labels are consumer copy, not the component's — shared across the tiles that
84
+ // reuse the same real-world status (e.g. "stopped" appears on both the data-sync and analytics
85
+ // tiles). `attentionRequired` / `openServiceEnglish` stay identical across locales on purpose:
86
+ // section 5's third tile is deliberately an English-named service in a JP admin portal.
87
+ const status = {
88
+ available: t("serviceLauncherShowcase.status.available"),
89
+ active: t("serviceLauncherShowcase.status.active"),
90
+ maintenance: t("serviceLauncherShowcase.status.maintenance"),
91
+ stopped: t("serviceLauncherShowcase.status.stopped"),
92
+ adminOnly: t("serviceLauncherShowcase.status.adminOnly"),
93
+ preparing: t("serviceLauncherShowcase.status.preparing"),
94
+ archived: t("serviceLauncherShowcase.status.archived"),
95
+ unapplied: t("serviceLauncherShowcase.status.unapplied"),
96
+ noPermission: t("serviceLauncherShowcase.status.noPermission"),
97
+ attentionRequired: t("serviceLauncherShowcase.status.attentionRequired"),
98
+ };
99
+
100
+ const action = {
101
+ openService: t("serviceLauncherShowcase.action.openService"),
102
+ open: t("serviceLauncherShowcase.action.open"),
103
+ viewStatus: t("serviceLauncherShowcase.action.viewStatus"),
104
+ viewHistory: t("serviceLauncherShowcase.action.viewHistory"),
105
+ checkPermissions: t("serviceLauncherShowcase.action.checkPermissions"),
106
+ openSettings: t("serviceLauncherShowcase.action.openSettings"),
107
+ viewArchive: t("serviceLauncherShowcase.action.viewArchive"),
108
+ openRequestForm: t("serviceLauncherShowcase.action.openRequestForm"),
109
+ openList: t("serviceLauncherShowcase.action.openList"),
110
+ openServiceEnglish: t("serviceLauncherShowcase.action.openServiceEnglish"),
111
+ };
112
+
65
113
  return (
66
114
  <PageContainer
67
- title="ServiceLauncherCard"
68
- subtitle="社内アプリケーション一覧のタイル — 利用可能・制限・停止・アーカイブ・読み込み中・カタログ導線"
115
+ title={t("serviceLauncherShowcase.page.title")}
116
+ subtitle={t("serviceLauncherShowcase.page.subtitle")}
69
117
  >
70
118
  <Flex direction="col" gap="lg">
71
119
  <Section
72
- title="1 · 基本 · 利用できるサービス"
73
- why="アイコン・名称・ステータス・説明・識別子・操作。ステータスの文言は常に利用側のコピーで、コンポーネントが決めるのは tone に対応する Badge の意味づけだけです。"
120
+ title={t("serviceLauncherShowcase.sections.basics.heading")}
121
+ why={t("serviceLauncherShowcase.sections.basics.why")}
74
122
  >
75
123
  <ResponsiveGrid columns={{ sm: 1, md: 2, lg: 3 }}>
76
124
  <ServiceLauncherCard
77
125
  icon={Clock3}
78
- title="勤怠管理"
79
- statusLabel="利用可能"
126
+ title={t("serviceLauncherShowcase.sections.basics.attendance.title")}
127
+ statusLabel={status.available}
80
128
  statusTone="success"
81
- description="打刻、シフト、休暇申請を一つのワークスペースで管理します。"
129
+ description={t("serviceLauncherShowcase.sections.basics.attendance.description")}
82
130
  metadata="attend.corp.example.jp · v4.2"
83
- action={<Button>サービスを開く</Button>}
131
+ action={<Button>{action.openService}</Button>}
84
132
  />
85
133
  <ServiceLauncherCard
86
134
  icon={ReceiptText}
87
- title="経費精算"
88
- statusLabel="利用可能"
135
+ title={t("serviceLauncherShowcase.sections.basics.expense.title")}
136
+ statusLabel={status.available}
89
137
  statusTone="success"
90
- description="領収書の提出から承認、仕訳連携までを扱います。"
138
+ description={t("serviceLauncherShowcase.sections.basics.expense.description")}
91
139
  metadata="keihi.corp.example.jp · v2.8"
92
- action={<Button>サービスを開く</Button>}
140
+ action={<Button>{action.openService}</Button>}
93
141
  />
94
142
  <ServiceLauncherCard
95
143
  icon={Calendar}
96
- title="会議室予約"
97
- statusLabel="利用可能"
144
+ title={t("serviceLauncherShowcase.sections.basics.meetingRoom.title")}
145
+ statusLabel={status.available}
98
146
  statusTone="success"
99
- description="拠点ごとの会議室と備品を予約します。"
147
+ description={t("serviceLauncherShowcase.sections.basics.meetingRoom.description")}
100
148
  metadata="rooms.corp.example.jp · v1.9"
101
- action={<Button>サービスを開く</Button>}
149
+ action={<Button>{action.openService}</Button>}
102
150
  />
103
151
  </ResponsiveGrid>
104
152
  </Section>
105
153
 
106
154
  <Section
107
- title="2 · statusTone の 6 値すべて"
108
- why="success / warning / destructive / info / neutral / muted。tone は Badge の意味づけだけを決め、文言・判定・操作の可否はすべて利用側が渡します。"
155
+ title={t("serviceLauncherShowcase.sections.statusTones.heading")}
156
+ why={t("serviceLauncherShowcase.sections.statusTones.why")}
109
157
  >
110
158
  <ResponsiveGrid columns={{ sm: 1, md: 2, lg: 3 }}>
111
159
  <ServiceLauncherCard
112
160
  icon={Mail}
113
161
  titleLevel={3}
114
- title="社内メール"
115
- statusLabel="稼働中"
162
+ title={t("serviceLauncherShowcase.sections.statusTones.mail.title")}
163
+ statusLabel={status.active}
116
164
  statusTone="success"
117
- description="メールボックス、配布リスト、共有署名を管理します。"
165
+ description={t("serviceLauncherShowcase.sections.statusTones.mail.description")}
118
166
  metadata="mail.corp.example.jp"
119
- action={<Button>サービスを開く</Button>}
167
+ action={<Button>{action.openService}</Button>}
120
168
  />
121
169
  <ServiceLauncherCard
122
170
  icon={Server}
123
171
  titleLevel={3}
124
- title="ファイル共有"
125
- statusLabel="メンテナンス中"
172
+ title={t("serviceLauncherShowcase.sections.statusTones.fileShare.title")}
173
+ statusLabel={status.maintenance}
126
174
  statusTone="warning"
127
- description="部門フォルダと外部共有リンクを扱います。"
175
+ description={t("serviceLauncherShowcase.sections.statusTones.fileShare.description")}
128
176
  metadata="files.corp.example.jp"
129
- action={<Button variant="outline">状況を見る</Button>}
177
+ action={<Button variant="outline">{action.viewStatus}</Button>}
130
178
  />
131
179
  <ServiceLauncherCard
132
180
  icon={Database}
133
181
  titleLevel={3}
134
- title="データ連携基盤"
135
- statusLabel="停止中"
182
+ title={t("serviceLauncherShowcase.sections.statusTones.dataSync.title")}
183
+ statusLabel={status.stopped}
136
184
  statusTone="destructive"
137
- description="外部システムとのデータ同期ジョブを管理します。"
185
+ description={t("serviceLauncherShowcase.sections.statusTones.dataSync.description")}
138
186
  metadata="sync.corp.example.jp"
139
- action={<Button variant="outline">履歴を見る</Button>}
187
+ action={<Button variant="outline">{action.viewHistory}</Button>}
140
188
  />
141
189
  <ServiceLauncherCard
142
190
  icon={ShieldCheck}
143
191
  titleLevel={3}
144
- title="権限管理"
145
- statusLabel="管理者限定"
192
+ title={t("serviceLauncherShowcase.sections.statusTones.iam.title")}
193
+ statusLabel={status.adminOnly}
146
194
  statusTone="info"
147
- description="ロール、二要素認証ポリシー、監査イベントを確認します。"
195
+ description={t("serviceLauncherShowcase.sections.statusTones.iam.description")}
148
196
  metadata="iam.corp.example.jp"
149
- action={<Button variant="outline">権限を確認</Button>}
197
+ action={<Button variant="outline">{action.checkPermissions}</Button>}
150
198
  />
151
199
  <ServiceLauncherCard
152
200
  icon={PlugZap}
153
201
  titleLevel={3}
154
- title="連携アプリ"
155
- statusLabel="準備中"
202
+ title={t("serviceLauncherShowcase.sections.statusTones.integrations.title")}
203
+ statusLabel={status.preparing}
156
204
  statusTone="neutral"
157
- description="サードパーティ連携の接続とスコープを設定します。"
205
+ description={t(
206
+ "serviceLauncherShowcase.sections.statusTones.integrations.description",
207
+ )}
158
208
  metadata="connect.corp.example.jp"
159
- action={<Button variant="outline">設定を開く</Button>}
209
+ action={<Button variant="outline">{action.openSettings}</Button>}
160
210
  />
161
211
  <ServiceLauncherCard
162
212
  icon={BookOpen}
163
213
  titleLevel={3}
164
- title="旧ナレッジベース"
165
- statusLabel="アーカイブ"
214
+ title={t("serviceLauncherShowcase.sections.statusTones.legacyKb.title")}
215
+ statusLabel={status.archived}
166
216
  statusTone="muted"
167
- description="2024 年度までの運用手順を読み取り専用で保管しています。"
217
+ description={t("serviceLauncherShowcase.sections.statusTones.legacyKb.description")}
168
218
  metadata="kb-archive.corp.example.jp"
169
- action={<Button variant="outline">アーカイブを見る</Button>}
219
+ action={<Button variant="outline">{action.viewArchive}</Button>}
170
220
  />
171
221
  </ResponsiveGrid>
172
222
  </Section>
173
223
 
174
224
  <Section
175
- title="3 · disabledReason · 操作が効かない理由は操作より先に置かれる"
176
- why="無効化されたボタンは「なぜ」を一切伝えません。だから理由は DOM 順で操作より先に置かれ(WCAG 2.2 · 1.3.2)、タイルは data-unavailable を帯びてメダリオンが沈みます。disabledReason はボタンを無効化しません — それは利用側の Button prop のままです。"
225
+ title={t("serviceLauncherShowcase.sections.disabledReason.heading")}
226
+ why={t("serviceLauncherShowcase.sections.disabledReason.why")}
177
227
  >
178
228
  <ResponsiveGrid columns={{ sm: 1, md: 2, lg: 3 }}>
179
229
  <ServiceLauncherCard
180
230
  icon={Boxes}
181
231
  titleLevel={3}
182
- title="在庫管理"
183
- statusLabel="未申請"
232
+ title={t("serviceLauncherShowcase.sections.disabledReason.inventory.title")}
233
+ statusLabel={status.unapplied}
184
234
  statusTone="warning"
185
- description="拠点別の在庫、入出庫、棚卸を管理します。"
235
+ description={t(
236
+ "serviceLauncherShowcase.sections.disabledReason.inventory.description",
237
+ )}
186
238
  metadata="zaiko.corp.example.jp"
187
- disabledReason="この部門ではまだ利用申請が承認されていません。"
188
- action={<Button disabled>サービスを開く</Button>}
239
+ disabledReason={t("serviceLauncherShowcase.sections.disabledReason.inventory.reason")}
240
+ action={<Button disabled>{action.openService}</Button>}
189
241
  />
190
242
  <ServiceLauncherCard
191
243
  icon={FileText}
192
244
  titleLevel={3}
193
- title="契約書管理"
194
- statusLabel="権限なし"
245
+ title={t("serviceLauncherShowcase.sections.disabledReason.contracts.title")}
246
+ statusLabel={status.noPermission}
195
247
  statusTone="info"
196
- description="契約書の保管、期限通知、電子署名の依頼を扱います。"
248
+ description={t(
249
+ "serviceLauncherShowcase.sections.disabledReason.contracts.description",
250
+ )}
197
251
  metadata="keiyaku.corp.example.jp"
198
- disabledReason="閲覧には法務部門のロールが必要です。IT ヘルプデスクへ申請してください。"
199
- action={<Button disabled>サービスを開く</Button>}
252
+ disabledReason={t("serviceLauncherShowcase.sections.disabledReason.contracts.reason")}
253
+ action={<Button disabled>{action.openService}</Button>}
200
254
  />
201
255
  <ServiceLauncherCard
202
256
  icon={Database}
203
257
  titleLevel={3}
204
- title="分析基盤"
205
- statusLabel="停止中"
258
+ title={t("serviceLauncherShowcase.sections.disabledReason.analytics.title")}
259
+ statusLabel={status.stopped}
206
260
  statusTone="destructive"
207
- description="全社ダッシュボードとデータマートを提供します。"
261
+ description={t(
262
+ "serviceLauncherShowcase.sections.disabledReason.analytics.description",
263
+ )}
208
264
  metadata="bi.corp.example.jp"
209
- disabledReason="このサービスは組織の管理者によって停止されています。"
210
- action={<Button disabled>サービスを開く</Button>}
265
+ disabledReason={t("serviceLauncherShowcase.sections.disabledReason.analytics.reason")}
266
+ action={<Button disabled>{action.openService}</Button>}
211
267
  />
212
268
  </ResponsiveGrid>
213
269
  </Section>
214
270
 
215
271
  <Section
216
- title="4 · 読み込み中とカタログ導線"
217
- why="ServiceLauncherCardSkeleton は同じ骨格の初期プレースホルダーで、label が必須・aria-busy を持ち、ライブリージョンは意図的に開きません。ServiceCatalogCta は実在する追加導線がある場合にだけ並べる相棒タイルで、既定の Plus 以外のグリフも受け取ります。"
272
+ title={t("serviceLauncherShowcase.sections.loadingCatalog.heading")}
273
+ why={t("serviceLauncherShowcase.sections.loadingCatalog.why")}
218
274
  >
219
275
  <ResponsiveGrid columns={{ sm: 1, md: 2, lg: 3 }}>
220
- <ServiceLauncherCardSkeleton label="サービスを読み込み中" />
276
+ <ServiceLauncherCardSkeleton
277
+ label={t("serviceLauncherShowcase.sections.loadingCatalog.skeletonLabel")}
278
+ />
221
279
  <ServiceCatalogCta
222
- title="アプリを追加"
223
- action={<Button variant="outline">申請フォームを開く</Button>}
280
+ title={t("serviceLauncherShowcase.sections.loadingCatalog.addApp.title")}
281
+ action={<Button variant="outline">{action.openRequestForm}</Button>}
224
282
  />
225
283
  <ServiceCatalogCta
226
284
  icon={LayoutGrid}
227
- title="すべての社内アプリを見る"
228
- action={<Button variant="ghost">一覧を開く</Button>}
285
+ title={t("serviceLauncherShowcase.sections.loadingCatalog.allApps.title")}
286
+ action={<Button variant="ghost">{action.openList}</Button>}
229
287
  />
230
288
  </ResponsiveGrid>
231
289
  </Section>
232
290
 
233
291
  <Section
234
- title="5 · 端に触れる · 3 行の名称、説明なし、切れない長いホスト名"
235
- why="整った例はタイルが崩れる場所を何も見せません。ここは崩れる側です:3 行になる名称と 2 語の名称が同じ行に並び、説明のないタイルが説明のあるタイルの隣に置かれ、空白のないホスト名が列幅を広げようとします。見苦しく見えるなら、このセクションは仕事をしています — 耐えるのはサンプルデータではなくコンポーネントの側です。"
292
+ title={t("serviceLauncherShowcase.sections.edgeCases.heading")}
293
+ why={t("serviceLauncherShowcase.sections.edgeCases.why")}
236
294
  >
237
295
  <ResponsiveGrid columns={{ sm: 1, md: 2, lg: 3 }}>
238
296
  <ServiceLauncherCard
239
297
  icon={ShieldCheck}
240
298
  titleLevel={3}
241
- title="グローバル人事情報基盤・従業員セルフサービスポータル(アジア太平洋地域)"
242
- statusLabel="利用可能"
299
+ title={t("serviceLauncherShowcase.sections.edgeCases.hrPortal.title")}
300
+ statusLabel={status.available}
243
301
  statusTone="success"
244
- description="人事マスタ、勤怠、給与、評価を一元管理する統合ワークスペースです。"
302
+ description={t("serviceLauncherShowcase.sections.edgeCases.hrPortal.description")}
245
303
  metadata="workforce-identity-administration.ap-northeast-1.corp.example.jp · v11.0"
246
- action={<Button>サービスを開く</Button>}
304
+ action={<Button>{action.openService}</Button>}
247
305
  />
248
306
  <ServiceLauncherCard
249
307
  icon={Clock3}
250
308
  titleLevel={3}
251
- title="日報"
252
- statusLabel="利用可能"
309
+ title={t("serviceLauncherShowcase.sections.edgeCases.dailyReport.title")}
310
+ statusLabel={status.available}
253
311
  statusTone="success"
254
312
  metadata="nippo.corp.example.jp"
255
- action={<Button>サービスを開く</Button>}
313
+ action={<Button>{action.openService}</Button>}
256
314
  />
257
315
  <ServiceLauncherCard
258
316
  icon={Server}
259
317
  titleLevel={3}
260
- title="Global Workforce Identity & Entitlement Administration Console"
261
- statusLabel="Attention required"
318
+ title={t("serviceLauncherShowcase.sections.edgeCases.warningConsole.title")}
319
+ statusLabel={status.attentionRequired}
262
320
  statusTone="warning"
263
- description="Review pending entitlement requests before the next access certification."
321
+ description={t(
322
+ "serviceLauncherShowcase.sections.edgeCases.warningConsole.description",
323
+ )}
264
324
  metadata="workforce-identity-administration.ap-southeast-1.corp.example.com"
265
- disabledReason="Your organization has no approved request for this service yet."
266
- action={<Button disabled>Open service</Button>}
325
+ disabledReason={t("serviceLauncherShowcase.sections.edgeCases.warningConsole.reason")}
326
+ action={<Button disabled>{action.openServiceEnglish}</Button>}
267
327
  />
268
328
  </ResponsiveGrid>
269
329
  </Section>
270
330
 
271
331
  <Section
272
- title="6 · 最小のタイル"
273
- why="必須は icon・title・action の 3 つだけです。statusLabel を省けば Badge の行ごと消え、description と metadata を省いても骨格は保たれます — 隣の満載のタイルと高さを比べてください。"
332
+ title={t("serviceLauncherShowcase.sections.minimalTiles.heading")}
333
+ why={t("serviceLauncherShowcase.sections.minimalTiles.why")}
274
334
  >
275
335
  <ResponsiveGrid columns={{ sm: 1, md: 2, lg: 3 }}>
276
336
  <ServiceLauncherCard
277
337
  icon={BookOpen}
278
338
  titleLevel={3}
279
- title="社内 Wiki"
280
- action={<Button variant="outline">開く</Button>}
339
+ title={t("serviceLauncherShowcase.sections.minimalTiles.wiki.title")}
340
+ action={<Button variant="outline">{action.open}</Button>}
281
341
  />
282
342
  <ServiceLauncherCard
283
343
  icon={Mail}
284
344
  titleLevel={3}
285
- title="問い合わせ窓口"
286
- description="社内のシステム相談はこちらで受け付けています。"
287
- action={<Button variant="outline">開く</Button>}
345
+ title={t("serviceLauncherShowcase.sections.minimalTiles.contact.title")}
346
+ description={t("serviceLauncherShowcase.sections.minimalTiles.contact.description")}
347
+ action={<Button variant="outline">{action.open}</Button>}
288
348
  />
289
349
  <ServiceLauncherCard
290
350
  icon={Calendar}
291
351
  titleLevel={3}
292
- title="全社カレンダー"
293
- statusLabel="利用可能"
352
+ title={t("serviceLauncherShowcase.sections.minimalTiles.calendar.title")}
353
+ statusLabel={status.available}
294
354
  statusTone="success"
295
- description="全社行事、休業日、拠点別の予定を共有します。"
355
+ description={t("serviceLauncherShowcase.sections.minimalTiles.calendar.description")}
296
356
  metadata="calendar.corp.example.jp · v3.1"
297
- disabledReason="読み取り専用で公開されています。"
298
- action={<Button variant="outline">開く</Button>}
357
+ disabledReason={t("serviceLauncherShowcase.sections.minimalTiles.calendar.reason")}
358
+ action={<Button variant="outline">{action.open}</Button>}
359
+ />
360
+ </ResponsiveGrid>
361
+ </Section>
362
+
363
+ <Section
364
+ title={t("serviceLauncherShowcase.sections.logo.heading")}
365
+ why={t("serviceLauncherShowcase.sections.logo.why")}
366
+ >
367
+ <ResponsiveGrid columns={{ sm: 1, md: 2, lg: 3 }}>
368
+ {/* 1 · a real uploaded mark, square */}
369
+ <ServiceLauncherCard
370
+ icon={Clock3}
371
+ logo={serviceMarkTeal}
372
+ titleLevel={3}
373
+ title={t("serviceLauncherShowcase.sections.logo.uploaded.title")}
374
+ statusLabel={status.available}
375
+ statusTone="success"
376
+ description={t("serviceLauncherShowcase.sections.logo.uploaded.description")}
377
+ metadata="attend.corp.example.jp · v4.2"
378
+ action={<Button>{action.openService}</Button>}
379
+ />
380
+ {/* 2 · the SAME tile with no upload yet — the fallback, side by side */}
381
+ <ServiceLauncherCard
382
+ icon={Clock3}
383
+ titleLevel={3}
384
+ title={t("serviceLauncherShowcase.sections.logo.missing.title")}
385
+ statusLabel={status.available}
386
+ statusTone="success"
387
+ description={t("serviceLauncherShowcase.sections.logo.missing.description")}
388
+ metadata="attend.corp.example.jp · v4.2"
389
+ action={<Button>{action.openService}</Button>}
390
+ />
391
+ {/* 3 · the URL is set but the file is gone — the state that reaches production */}
392
+ <ServiceLauncherCard
393
+ icon={Database}
394
+ logo={BROKEN_LOGO_URL}
395
+ titleLevel={3}
396
+ title={t("serviceLauncherShowcase.sections.logo.broken.title")}
397
+ statusLabel={status.available}
398
+ statusTone="success"
399
+ description={t("serviceLauncherShowcase.sections.logo.broken.description")}
400
+ metadata="sync.corp.example.jp"
401
+ action={<Button>{action.openService}</Button>}
402
+ />
403
+ {/* 4 · a WIDE wordmark — contain letterboxes it, never crops it */}
404
+ <ServiceLauncherCard
405
+ icon={ReceiptText}
406
+ logo={serviceMarkRose}
407
+ titleLevel={3}
408
+ title={t("serviceLauncherShowcase.sections.logo.wideMark.title")}
409
+ statusLabel={status.available}
410
+ statusTone="success"
411
+ description={t("serviceLauncherShowcase.sections.logo.wideMark.description")}
412
+ metadata="keihi.corp.example.jp · v2.8"
413
+ action={<Button>{action.openService}</Button>}
414
+ />
415
+ {/* 5 · logo + disabledReason — the medallion mutes, the mark stays the mark */}
416
+ <ServiceLauncherCard
417
+ icon={ShieldCheck}
418
+ logo={serviceMarkTeal}
419
+ titleLevel={3}
420
+ title={t("serviceLauncherShowcase.sections.logo.withReason.title")}
421
+ statusLabel={status.noPermission}
422
+ statusTone="info"
423
+ description={t("serviceLauncherShowcase.sections.logo.withReason.description")}
424
+ metadata="iam.corp.example.jp"
425
+ disabledReason={t("serviceLauncherShowcase.sections.logo.withReason.reason")}
426
+ action={<Button disabled>{action.openService}</Button>}
427
+ />
428
+ {/* 6 · logo="" — an empty projection value is the same as no logo */}
429
+ <ServiceLauncherCard
430
+ icon={Mail}
431
+ logo=""
432
+ titleLevel={3}
433
+ title={t("serviceLauncherShowcase.sections.logo.emptyString.title")}
434
+ statusLabel={status.active}
435
+ statusTone="success"
436
+ description={t("serviceLauncherShowcase.sections.logo.emptyString.description")}
437
+ metadata="mail.corp.example.jp"
438
+ action={<Button>{action.openService}</Button>}
299
439
  />
300
440
  </ResponsiveGrid>
301
441
  </Section>
@@ -2,6 +2,7 @@ import { useState } from "react";
2
2
 
3
3
  import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "@godxjp/ui/data-display";
4
4
  import { FormField, TagInput } from "@godxjp/ui/data-entry";
5
+ import { useTranslation } from "@godxjp/ui/i18n";
5
6
  import { Flex, PageContainer } from "@godxjp/ui/layout";
6
7
 
7
8
  /**
@@ -11,9 +12,17 @@ import { Flex, PageContainer } from "@godxjp/ui/layout";
11
12
  * Composed only from real @godxjp/ui components.
12
13
  */
13
14
  export default function Demo() {
15
+ const { t } = useTranslation();
14
16
  const [invoiceTags, setInvoiceTags] = useState<string[]>(["営業部", "Q1"]);
15
17
  const [skillTags, setSkillTags] = useState<string[]>(["経理", "仕訳入力"]);
16
18
  const [recipientEmails, setRecipientEmails] = useState<string[]>([]);
19
+ /* The reporter's exact 71-character string, held FIRST so the truncated chip is one of the two
20
+ that render rather than one of the ones `+N` hides (gh#840). */
21
+ const [ledgerTags, setLedgerTags] = useState<string[]>([
22
+ "THEME_SEED_LEDGER_0007_CONTRAST_VERIFIED_AGAINST_CANVAS_AND_LABEL_00042",
23
+ "本番",
24
+ "ổn định",
25
+ ]);
17
26
 
18
27
  return (
19
28
  <PageContainer
@@ -87,6 +96,34 @@ export default function Demo() {
87
96
  </CardContent>
88
97
  </Card>
89
98
 
99
+ <Card>
100
+ <CardHeader>
101
+ <CardTitle level={2}>{t("showcase.tagInput.longIdTitle")}</CardTitle>
102
+ <CardDescription>
103
+ maxTagTextLength cuts the chip TEXT only — the whole value stays in the chip&apos;s
104
+ title and in the remove button&apos;s accessible name. maxTagCount collapses the rest
105
+ into a +N that names, in its own title and aria-label, exactly which tags it hides.
106
+ Neither may swallow a value silently (gh#840).
107
+ </CardDescription>
108
+ </CardHeader>
109
+ <CardContent>
110
+ <FormField
111
+ id="ledger-tags"
112
+ label={t("showcase.tagInput.ledgerLabel")}
113
+ helper={t("showcase.tagInput.ledgerHelper")}
114
+ >
115
+ <TagInput
116
+ id="ledger-tags"
117
+ value={ledgerTags}
118
+ onValueChange={setLedgerTags}
119
+ maxTagCount={2}
120
+ maxTagTextLength={16}
121
+ aria-label={t("showcase.tagInput.ledgerLabel")}
122
+ />
123
+ </FormField>
124
+ </CardContent>
125
+ </Card>
126
+
90
127
  <Card>
91
128
  <CardHeader>
92
129
  <CardTitle level={2}>無効状態</CardTitle>
@@ -8,6 +8,7 @@ import {
8
8
  ListRow,
9
9
  } from "@godxjp/ui/data-display";
10
10
  import { Button, Text } from "@godxjp/ui/general";
11
+ import { useTranslation } from "@godxjp/ui/i18n";
11
12
  import { Flex, PageContainer } from "@godxjp/ui/layout";
12
13
 
13
14
  /**
@@ -20,6 +21,7 @@ import { Flex, PageContainer } from "@godxjp/ui/layout";
20
21
  * @godxjp/ui components.
21
22
  */
22
23
  export default function Demo() {
24
+ const { t } = useTranslation();
23
25
  return (
24
26
  <PageContainer
25
27
  title="Flex"
@@ -398,6 +400,44 @@ export default function Demo() {
398
400
  </Flex>
399
401
  </CardContent>
400
402
  </Card>
403
+
404
+ <Card>
405
+ <CardHeader>
406
+ <CardTitle level={2}>{t("showcase.flexMeasure.title")}</CardTitle>
407
+ <CardDescription>{t("showcase.flexMeasure.lead")}</CardDescription>
408
+ </CardHeader>
409
+ <CardContent>
410
+ <Flex direction="col" gap="sm">
411
+ <Flex
412
+ id="measure-narrow"
413
+ measure="narrow"
414
+ surface="muted"
415
+ pad={{ block: 2, inline: 6 }}
416
+ justify="center"
417
+ >
418
+ <Text tone="muted">measure=&quot;narrow&quot; · 42rem</Text>
419
+ </Flex>
420
+ <Flex
421
+ id="measure-medium"
422
+ measure="medium"
423
+ surface="muted"
424
+ pad={{ block: 2, inline: 6 }}
425
+ justify="center"
426
+ >
427
+ <Text tone="muted">measure=&quot;medium&quot; · 48rem</Text>
428
+ </Flex>
429
+ <Flex
430
+ id="measure-wide"
431
+ measure="wide"
432
+ surface="muted"
433
+ pad={{ block: 2, inline: 6 }}
434
+ justify="center"
435
+ >
436
+ <Text tone="muted">measure=&quot;wide&quot; · 72rem</Text>
437
+ </Flex>
438
+ </Flex>
439
+ </CardContent>
440
+ </Card>
401
441
  </Flex>
402
442
  </PageContainer>
403
443
  );