@squadbase/vantage 0.6.2-dev1.9365dcd → 0.6.2-dev1.9d7130b

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 (230) hide show
  1. package/dist/{build-X5NVCQKT.js → build-U7GO26HR.js} +7 -7
  2. package/dist/{build-X5NVCQKT.js.map → build-U7GO26HR.js.map} +1 -1
  3. package/dist/{check-ZBIH422T.js → check-MRVAIHG5.js} +5 -5
  4. package/dist/{check-ZBIH422T.js.map → check-MRVAIHG5.js.map} +1 -1
  5. package/dist/chunk-2IAPIOPS.js +152 -0
  6. package/dist/chunk-2IAPIOPS.js.map +1 -0
  7. package/dist/chunk-3RJEOP3J.js +174 -0
  8. package/dist/chunk-3RJEOP3J.js.map +1 -0
  9. package/dist/{chunk-HKSVYMYJ.js → chunk-77CISBMG.js} +1049 -1387
  10. package/dist/chunk-77CISBMG.js.map +1 -0
  11. package/dist/{chunk-V3LF7BE7.js → chunk-ANZLVSEP.js} +4 -5
  12. package/dist/chunk-ANZLVSEP.js.map +1 -0
  13. package/dist/{chunk-XQUSGIDG.js → chunk-CKWPK4RO.js} +10 -3
  14. package/dist/chunk-CKWPK4RO.js.map +1 -0
  15. package/dist/chunk-EG4PX726.js +678 -0
  16. package/dist/chunk-EG4PX726.js.map +1 -0
  17. package/dist/{chunk-2N72FKLB.js → chunk-NZ5QIIG4.js} +33 -11
  18. package/dist/chunk-NZ5QIIG4.js.map +1 -0
  19. package/dist/{chunk-7DZGJQ3P.js → chunk-PJ4SPXHS.js} +23 -6
  20. package/dist/chunk-PJ4SPXHS.js.map +1 -0
  21. package/dist/{chunk-XPQSTZUU.js → chunk-QNOX7WLZ.js} +5 -4
  22. package/dist/chunk-QNOX7WLZ.js.map +1 -0
  23. package/dist/{chunk-PDOBHMUQ.js → chunk-ROHNXP7J.js} +72 -3
  24. package/dist/chunk-ROHNXP7J.js.map +1 -0
  25. package/dist/{chunk-CEXAQQ5W.js → chunk-S5MDTHH7.js} +180 -18
  26. package/dist/chunk-S5MDTHH7.js.map +1 -0
  27. package/dist/{chunk-2ICNHUG6.js → chunk-SDJTTMLK.js} +64 -7
  28. package/dist/chunk-SDJTTMLK.js.map +1 -0
  29. package/dist/{chunk-WAMZWZJB.js → chunk-SHZM3EXB.js} +19 -8
  30. package/dist/chunk-SHZM3EXB.js.map +1 -0
  31. package/dist/chunk-TRMHNMMZ.js +61 -0
  32. package/dist/chunk-TRMHNMMZ.js.map +1 -0
  33. package/dist/{chunk-JKLLFVEU.js → chunk-UWSQUHX6.js} +4 -99
  34. package/dist/chunk-UWSQUHX6.js.map +1 -0
  35. package/dist/cli.js +6 -6
  36. package/dist/client/index.d.ts +2 -0
  37. package/dist/client/index.js +8 -2
  38. package/dist/client/index.js.map +1 -1
  39. package/dist/components/index.d.ts +57 -273
  40. package/dist/components/index.js +6 -3
  41. package/dist/delta-text-CbrOaW83.d.ts +17 -0
  42. package/dist/{dev-4XEDTELV.js → dev-O42JFQ64.js} +7 -7
  43. package/dist/{dev-4XEDTELV.js.map → dev-O42JFQ64.js.map} +1 -1
  44. package/dist/doc/index.d.ts +215 -2
  45. package/dist/doc/index.js +422 -4
  46. package/dist/doc/index.js.map +1 -1
  47. package/dist/{doctor-5E2VEZPK.js → doctor-YD3XAAOT.js} +5 -5
  48. package/dist/{doctor-5E2VEZPK.js.map → doctor-YD3XAAOT.js.map} +1 -1
  49. package/dist/format-DihQkL1N.d.ts +249 -0
  50. package/dist/query/index.js +2 -2
  51. package/dist/{routes-3SGAFDMC.js → routes-PVKNT777.js} +4 -4
  52. package/dist/{routes-3SGAFDMC.js.map → routes-PVKNT777.js.map} +1 -1
  53. package/dist/slide/index.d.ts +272 -1
  54. package/dist/slide/index.js +1023 -2
  55. package/dist/slide/index.js.map +1 -1
  56. package/dist/table/index.js +9 -6
  57. package/dist/table/index.js.map +1 -1
  58. package/dist/ui/index.d.ts +5 -2
  59. package/dist/ui/index.js +6 -6
  60. package/dist/ui/index.js.map +1 -1
  61. package/dist/{upgrade-JHXZBGQS.js → upgrade-6DT7ADRP.js} +4 -4
  62. package/dist/{upgrade-JHXZBGQS.js.map → upgrade-6DT7ADRP.js.map} +1 -1
  63. package/dist/vite/index.js +3 -3
  64. package/docs/en/agent-skills.md +1 -1
  65. package/docs/en/changelog.md +2 -0
  66. package/docs/en/components.md +13 -2
  67. package/docs/en/doc/delta-text.md +40 -0
  68. package/docs/en/doc/doc-action-items.md +49 -0
  69. package/docs/en/doc/doc-callout.md +38 -0
  70. package/docs/en/doc/doc-data-table.md +60 -0
  71. package/docs/en/doc/doc-executive-summary.md +64 -0
  72. package/docs/en/doc/doc-figure.md +56 -0
  73. package/docs/en/doc/doc-key-findings.md +61 -0
  74. package/docs/en/doc/doc-kpi-scorecard.md +80 -0
  75. package/docs/en/doc/doc-notes-and-sources.md +43 -0
  76. package/docs/en/doc/doc-report-header.md +46 -0
  77. package/docs/en/pages-and-metadata.md +15 -0
  78. package/docs/en/parts/area-chart.md +99 -0
  79. package/docs/en/parts/bar-chart.md +91 -0
  80. package/docs/en/parts/bar-list.md +50 -0
  81. package/docs/en/parts/category-bar.md +37 -0
  82. package/docs/en/parts/chart-frame.md +39 -0
  83. package/docs/en/parts/delta.md +4 -3
  84. package/docs/en/parts/donut-chart.md +72 -0
  85. package/docs/en/parts/funnel-steps.md +2 -1
  86. package/docs/en/parts/heatmap.md +53 -0
  87. package/docs/en/parts/kpi-card.md +2 -1
  88. package/docs/en/parts/legend.md +35 -0
  89. package/docs/en/parts/line-chart.md +94 -0
  90. package/docs/en/parts/progress-circle.md +33 -0
  91. package/docs/en/parts/sample-data.md +39 -0
  92. package/docs/en/parts/scatter-chart.md +56 -0
  93. package/docs/en/parts/tracker.md +36 -0
  94. package/docs/en/parts/updated-at.md +30 -0
  95. package/docs/en/parts/waterfall-chart.md +56 -0
  96. package/docs/en/slide/slide-chart-full.md +48 -0
  97. package/docs/en/slide/slide-chart-insight.md +52 -0
  98. package/docs/en/slide/slide-columns.md +46 -0
  99. package/docs/en/slide/slide-comparison.md +68 -0
  100. package/docs/en/slide/slide-cover.md +39 -0
  101. package/docs/en/slide/slide-exec-summary.md +47 -0
  102. package/docs/en/slide/slide-heading.md +38 -0
  103. package/docs/en/slide/slide-kpi-grid.md +55 -0
  104. package/docs/en/slide/slide-kpi-hero.md +58 -0
  105. package/docs/en/slide/slide-next-actions.md +49 -0
  106. package/docs/en/slide/slide-scorecard-table.md +54 -0
  107. package/docs/en/slide/slide-section.md +44 -0
  108. package/docs/en/slide/slide-source-line.md +34 -0
  109. package/docs/en/ui/alert-dialog.md +42 -0
  110. package/docs/en/ui/avatar.md +31 -0
  111. package/docs/en/ui/combobox.md +74 -0
  112. package/docs/en/ui/drawer.md +41 -0
  113. package/docs/en/ui/empty.md +1 -1
  114. package/docs/en/ui/error-state.md +4 -3
  115. package/docs/en/ui/field.md +42 -0
  116. package/docs/en/ui/hover-card.md +21 -0
  117. package/docs/en/ui/kbd.md +17 -0
  118. package/docs/en/ui/loading.md +1 -1
  119. package/docs/en/ui/pagination.md +36 -0
  120. package/docs/en/ui/radio-group.md +21 -0
  121. package/docs/en/ui/toast.md +44 -0
  122. package/docs/en/ui/toggle-group.md +4 -3
  123. package/docs/index.json +857 -77
  124. package/docs/ja/agent-skills.md +1 -1
  125. package/docs/ja/changelog.md +2 -0
  126. package/docs/ja/components.md +12 -1
  127. package/docs/ja/doc/delta-text.md +40 -0
  128. package/docs/ja/doc/doc-action-items.md +49 -0
  129. package/docs/ja/doc/doc-callout.md +38 -0
  130. package/docs/ja/doc/doc-data-table.md +60 -0
  131. package/docs/ja/doc/doc-executive-summary.md +64 -0
  132. package/docs/ja/doc/doc-figure.md +56 -0
  133. package/docs/ja/doc/doc-key-findings.md +61 -0
  134. package/docs/ja/doc/doc-kpi-scorecard.md +80 -0
  135. package/docs/ja/doc/doc-notes-and-sources.md +43 -0
  136. package/docs/ja/doc/doc-report-header.md +46 -0
  137. package/docs/ja/page-types/slide.md +1 -0
  138. package/docs/ja/pages-and-metadata.md +15 -0
  139. package/docs/ja/parts/area-chart.md +49 -25
  140. package/docs/ja/parts/bar-chart.md +50 -24
  141. package/docs/ja/parts/bar-list.md +31 -8
  142. package/docs/ja/parts/chart-frame.md +36 -0
  143. package/docs/ja/parts/delta.md +5 -4
  144. package/docs/ja/parts/donut-chart.md +45 -26
  145. package/docs/ja/parts/funnel-steps.md +27 -8
  146. package/docs/ja/parts/heatmap.md +45 -0
  147. package/docs/ja/parts/kpi-card.md +2 -1
  148. package/docs/ja/parts/legend.md +36 -0
  149. package/docs/ja/parts/line-chart.md +48 -22
  150. package/docs/ja/parts/sample-data.md +61 -0
  151. package/docs/ja/parts/scatter-chart.md +69 -0
  152. package/docs/ja/parts/updated-at.md +27 -0
  153. package/docs/ja/parts/waterfall-chart.md +61 -0
  154. package/docs/ja/slide/slide-chart-full.md +48 -0
  155. package/docs/ja/slide/slide-chart-insight.md +52 -0
  156. package/docs/ja/slide/slide-columns.md +46 -0
  157. package/docs/ja/slide/slide-comparison.md +68 -0
  158. package/docs/ja/slide/slide-cover.md +39 -0
  159. package/docs/ja/slide/slide-exec-summary.md +47 -0
  160. package/docs/ja/slide/slide-heading.md +38 -0
  161. package/docs/ja/slide/slide-kpi-grid.md +55 -0
  162. package/docs/ja/slide/slide-kpi-hero.md +58 -0
  163. package/docs/ja/slide/slide-next-actions.md +49 -0
  164. package/docs/ja/slide/slide-scorecard-table.md +54 -0
  165. package/docs/ja/slide/slide-section.md +44 -0
  166. package/docs/ja/slide/slide-source-line.md +34 -0
  167. package/docs/ja/ui/empty.md +1 -1
  168. package/docs/ja/ui/error-state.md +4 -3
  169. package/docs/ja/ui/loading.md +1 -1
  170. package/docs/ja/ui/toggle-group.md +4 -3
  171. package/package.json +2 -2
  172. package/registry/ui/app-shell.tsx +138 -1
  173. package/registry/ui/area-chart.tsx +389 -104
  174. package/registry/ui/attention-list.tsx +177 -15
  175. package/registry/ui/bar-chart.tsx +386 -104
  176. package/registry/ui/bar-list.tsx +376 -94
  177. package/registry/ui/box-plot-chart.tsx +450 -116
  178. package/registry/ui/category-bar.tsx +292 -57
  179. package/registry/ui/chart-frame.tsx +301 -63
  180. package/registry/ui/data-table.tsx +229 -37
  181. package/registry/ui/date-range-picker.tsx +190 -36
  182. package/registry/ui/delta.tsx +181 -19
  183. package/registry/ui/donut-chart.tsx +385 -103
  184. package/registry/ui/echart.tsx +313 -58
  185. package/registry/ui/filter-bar.tsx +179 -20
  186. package/registry/ui/funnel-steps.tsx +354 -80
  187. package/registry/ui/heatmap.tsx +338 -71
  188. package/registry/ui/histogram-chart.tsx +440 -116
  189. package/registry/ui/kpi-card.tsx +254 -48
  190. package/registry/ui/legend.tsx +374 -93
  191. package/registry/ui/line-chart.tsx +389 -104
  192. package/registry/ui/multi-select.tsx +159 -9
  193. package/registry/ui/page-shell.tsx +148 -10
  194. package/registry/ui/paired-chart.tsx +394 -109
  195. package/registry/ui/progress-circle.tsx +205 -39
  196. package/registry/ui/sample-data.tsx +154 -10
  197. package/registry/ui/scatter-chart.tsx +436 -119
  198. package/registry/ui/searchable-select.tsx +145 -7
  199. package/registry/ui/slider.tsx +1 -1
  200. package/registry/ui/states.tsx +170 -13
  201. package/registry/ui/status-badge.tsx +201 -36
  202. package/registry/ui/tooltip.tsx +6 -2
  203. package/registry/ui/tracker.tsx +214 -42
  204. package/registry/ui/trend-indicator.tsx +151 -8
  205. package/registry/ui/updated-at.tsx +170 -16
  206. package/registry/ui/waterfall-chart.tsx +460 -121
  207. package/skills/vantage-add-feature/SKILL.md +5 -0
  208. package/skills/vantage-design/SKILL.md +54 -54
  209. package/skills/vantage-design/references/extract.md +26 -27
  210. package/skills/vantage-design/references/format.md +12 -172
  211. package/skills/vantage-design/references/presets.md +50 -110
  212. package/skills/vantage-pitfalls/SKILL.md +5 -0
  213. package/skills/vantage-slide/SKILL.md +54 -36
  214. package/templates/AGENTS.md +35 -18
  215. package/templates/agents/api.md +7 -0
  216. package/templates/agents/doc.md +48 -0
  217. package/templates/agents/page.md +59 -2
  218. package/templates/agents/slide.md +77 -3
  219. package/theme.css +23 -19
  220. package/dist/chunk-2ICNHUG6.js.map +0 -1
  221. package/dist/chunk-2N72FKLB.js.map +0 -1
  222. package/dist/chunk-7DZGJQ3P.js.map +0 -1
  223. package/dist/chunk-CEXAQQ5W.js.map +0 -1
  224. package/dist/chunk-HKSVYMYJ.js.map +0 -1
  225. package/dist/chunk-JKLLFVEU.js.map +0 -1
  226. package/dist/chunk-PDOBHMUQ.js.map +0 -1
  227. package/dist/chunk-V3LF7BE7.js.map +0 -1
  228. package/dist/chunk-WAMZWZJB.js.map +0 -1
  229. package/dist/chunk-XPQSTZUU.js.map +0 -1
  230. package/dist/chunk-XQUSGIDG.js.map +0 -1
@@ -12,50 +12,214 @@
12
12
  * `gray` are still accepted and map to positive / negative / warning / info /
13
13
  * neutral. Unknown statuses and tones fall back to `neutral`.
14
14
  *
15
- * The default label comes from `STATUS_VOCABULARY` (one table of status, 日本語ラベル and tone), so the same
16
- * state is worded the same everywhere (Tracker legends import it too):
15
+ * The default label comes from `STATUS_VOCABULARY` (one table of status, label and tone; the label follows the
16
+ * page's language, `<html lang>`), so the same state is worded the same everywhere (Tracker legends import it too):
17
17
  *
18
- * | status | ラベル | 色調 |
18
+ * | status | ラベル(ja / en) | 色調 |
19
19
  * |---|---|---|
20
- * | `success` | 正常 | positive |
21
- * | `partial` | 一部失敗 | warning |
22
- * | `failed` | 失敗 | negative |
23
- * | `delayed` | 遅延 | warning |
24
- * | `running` | 実行中 | info |
25
- * | `stopped` | 停止中 | neutral |
26
- * | `active` / `inactive` | 有効 / 無効 | positive / neutral |
27
- * | `warning` / `error` / `pending` | 警告 / エラー / 保留中 | warning / negative / info |
20
+ * | `success` | 正常 / Healthy | positive |
21
+ * | `partial` | 一部失敗 / Partially failed | warning |
22
+ * | `failed` | 失敗 / Failed | negative |
23
+ * | `delayed` | 遅延 / Delayed | warning |
24
+ * | `running` | 実行中 / Running | info |
25
+ * | `stopped` | 停止中 / Stopped | neutral |
26
+ * | `active` / `inactive` | 有効 / 無効、Active / Inactive | positive / neutral |
27
+ * | `warning` / `error` / `pending` | 警告 / エラー / 保留中、Warning / Error / Pending | warning / negative / info |
28
28
  */
29
29
  import { forwardRef } from "react"
30
30
 
31
31
  import { cn } from "@squadbase/vantage/ui"
32
32
  import { Badge } from "@squadbase/vantage/ui"
33
+ import { useSyncExternalStore } from "react"
34
+
35
+ /* ---------- inlined from @squadbase/squadkit registry/lib/locale.ts (internal to @squadbase/vantage) ---------- */
36
+
37
+ /**
38
+ * The display language of the parts and the defaults that follow it.
39
+ *
40
+ * The language comes from `<html lang>`: a tag starting with `ja` reads Japanese, anything else English.
41
+ * Without a usable `lang` (missing, invalid, or no `document` — SSR, Node) the locale is `FALLBACK_LOCALE`
42
+ * (`en-US`). A `locale` passed explicitly (a prop, an argument) always wins.
43
+ *
44
+ * Parts read the locale through `useLocale` (`hooks/use-locale`) and pass it down; the pure helpers here
45
+ * and in `format` / `comparison` / `chart-*` take it as an argument and fall back to `documentLocale()`.
46
+ */
47
+
48
+ /** The language of the built-in wording: Japanese or English. */
49
+ type UiLanguage = "ja" | "en"
50
+
51
+ /** The locale used when `<html lang>` gives none (and on the server). */
52
+ const FALLBACK_LOCALE = "en-US"
53
+
54
+ /** `"ja"` when `locale` starts with `ja` (`ja`, `ja-JP`), else `"en"`. A missing locale is `"en"`. */
55
+ function uiLanguage(locale: string | null | undefined): UiLanguage {
56
+ return typeof locale === "string" && locale.trim().toLowerCase().startsWith("ja") ? "ja" : "en"
57
+ }
58
+
59
+ /** A BCP 47 tag in its canonical form (`en-gb` → `en-GB`), or `FALLBACK_LOCALE` when it is empty or invalid. */
60
+ function normalizeLocale(tag: string | null | undefined): string {
61
+ const value = tag?.trim()
62
+ if (!value) return FALLBACK_LOCALE
63
+ try {
64
+ return Intl.getCanonicalLocales(value)[0] ?? FALLBACK_LOCALE
65
+ } catch {
66
+ return FALLBACK_LOCALE
67
+ }
68
+ }
69
+
70
+ /**
71
+ * The locale of the page: `document.documentElement.lang`, canonicalized. `FALLBACK_LOCALE` when it is empty or
72
+ * invalid, or there is no `document`. Parts read it through `useLocale`, never while rendering.
73
+ */
74
+ function documentLocale(): string {
75
+ if (typeof document === "undefined") return FALLBACK_LOCALE
76
+ return normalizeLocale(document.documentElement?.getAttribute("lang"))
77
+ }
78
+
79
+ /** `locale` when given, else the page's locale (`documentLocale()`). */
80
+ function resolveLocale(locale?: string | null): string {
81
+ return locale || documentLocale()
82
+ }
83
+
84
+ /** Picks the wording table of the locale's language. */
85
+ function pickLocale<T>(table: { ja: T; en: T }, locale?: string | null): T {
86
+ return table[uiLanguage(resolveLocale(locale))]
87
+ }
88
+
89
+ /** The currency `format="currency"` uses without a `currency`: JPY for Japanese, USD otherwise. */
90
+ function defaultCurrency(locale?: string | null): string {
91
+ return uiLanguage(resolveLocale(locale)) === "ja" ? "JPY" : "USD"
92
+ }
93
+
94
+ /** The month a fiscal year starts in (1–12) when none is given: April for Japanese, January otherwise. */
95
+ function defaultFiscalYearStartMonth(locale?: string | null): number {
96
+ return uiLanguage(resolveLocale(locale)) === "ja" ? 4 : 1
97
+ }
98
+
99
+ /** A day of the week, 0 = Sunday … 6 = Saturday (the `Date#getDay` / date-fns numbering). */
100
+ type WeekDay = 0 | 1 | 2 | 3 | 4 | 5 | 6
101
+
102
+ /** Locales whose week starts on Sunday when the runtime has no week data. */
103
+ const SUNDAY_FIRST = new Set(["en", "en-US", "en-CA"])
104
+
105
+ /**
106
+ * The first day of the week: Monday for Japanese; otherwise the locale's convention from `Intl.Locale`
107
+ * (`en-US` Sunday, `en-GB` Monday). Without week data in the runtime: Sunday for `en` / `en-US` / `en-CA`,
108
+ * Monday for the rest.
109
+ */
110
+ function weekStartsOn(locale?: string | null): WeekDay {
111
+ const tag = normalizeLocale(resolveLocale(locale))
112
+ if (uiLanguage(tag) === "ja") return 1
113
+ try {
114
+ const info = new Intl.Locale(tag) as Intl.Locale & {
115
+ getWeekInfo?: () => { firstDay: number }
116
+ weekInfo?: { firstDay: number }
117
+ }
118
+ const firstDay = info.getWeekInfo?.().firstDay ?? info.weekInfo?.firstDay
119
+ if (typeof firstDay === "number" && firstDay >= 1 && firstDay <= 7) return (firstDay % 7) as WeekDay
120
+ } catch {
121
+ // Fall through to the table below.
122
+ }
123
+ return SUNDAY_FIRST.has(tag) ? 0 : 1
124
+ }
125
+
126
+ /* ---------- inlined from @squadbase/squadkit registry/hooks/use-locale.ts (internal to @squadbase/vantage) ---------- */
127
+
128
+ const listeners = new Set<() => void>()
129
+ let observer: MutationObserver | null = null
130
+
131
+ /** One observer on `<html lang>` for every subscribed part. */
132
+ function subscribe(onChange: () => void): () => void {
133
+ if (typeof document === "undefined" || typeof MutationObserver === "undefined") return () => {}
134
+ listeners.add(onChange)
135
+ if (!observer) {
136
+ observer = new MutationObserver(() => {
137
+ for (const listener of [...listeners]) listener()
138
+ })
139
+ observer.observe(document.documentElement, { attributes: true, attributeFilter: ["lang"] })
140
+ }
141
+ return () => {
142
+ listeners.delete(onChange)
143
+ if (listeners.size === 0 && observer) {
144
+ observer.disconnect()
145
+ observer = null
146
+ }
147
+ }
148
+ }
149
+
150
+ const serverLocale = () => FALLBACK_LOCALE
151
+
152
+ /**
153
+ * The page's locale (`<html lang>`), following changes made while the page runs. On the server and during
154
+ * hydration it is `FALLBACK_LOCALE` (`en-US`), so the markup matches; it switches right after.
155
+ */
156
+ function useDocumentLocale(): string {
157
+ return useSyncExternalStore(subscribe, documentLocale, serverLocale)
158
+ }
159
+
160
+ /** The locale a part renders in: its `locale` prop when given, else the page's (`useDocumentLocale`). */
161
+ function useLocale(locale?: string | null): string {
162
+ const page = useDocumentLocale()
163
+ return locale || page
164
+ }
165
+
166
+ /* ---------- end of inlined code ---------- */
33
167
 
34
168
  type StatusTone = "positive" | "negative" | "warning" | "info" | "neutral"
35
169
 
170
+ const STATUS_LABELS = {
171
+ ja: {
172
+ success: "正常",
173
+ partial: "一部失敗",
174
+ failed: "失敗",
175
+ delayed: "遅延",
176
+ running: "実行中",
177
+ stopped: "停止中",
178
+ active: "有効",
179
+ inactive: "無効",
180
+ warning: "警告",
181
+ error: "エラー",
182
+ pending: "保留中",
183
+ },
184
+ en: {
185
+ success: "Healthy",
186
+ partial: "Partially failed",
187
+ failed: "Failed",
188
+ delayed: "Delayed",
189
+ running: "Running",
190
+ stopped: "Stopped",
191
+ active: "Active",
192
+ inactive: "Inactive",
193
+ warning: "Warning",
194
+ error: "Error",
195
+ pending: "Pending",
196
+ },
197
+ } as const
198
+
36
199
  /**
37
- * 状態の語彙の正本: status → 日本語ラベルと色調。StatusBadge の既定の表示と、Tracker の凡例など
38
- * 同じ状態を語る他の場所が、同じ語を使うためにここから参照する。
200
+ * 状態の語彙の正本: status → ラベルと色調。StatusBadge の既定の表示と、Tracker の凡例など
201
+ * 同じ状態を語る他の場所が、同じ語を使うためにここから参照する。`label` は英語(フォールバック)で、
202
+ * ページの言語に合わせた語は `statusLabel(status, locale)` で引く。
39
203
  */
40
204
  export const STATUS_VOCABULARY = {
41
- success: { label: "正常", tone: "positive" },
42
- partial: { label: "一部失敗", tone: "warning" },
43
- failed: { label: "失敗", tone: "negative" },
44
- delayed: { label: "遅延", tone: "warning" },
45
- running: { label: "実行中", tone: "info" },
46
- stopped: { label: "停止中", tone: "neutral" },
47
- active: { label: "有効", tone: "positive" },
48
- inactive: { label: "無効", tone: "neutral" },
49
- warning: { label: "警告", tone: "warning" },
50
- error: { label: "エラー", tone: "negative" },
51
- pending: { label: "保留中", tone: "info" },
205
+ success: { label: STATUS_LABELS.en.success, tone: "positive" },
206
+ partial: { label: STATUS_LABELS.en.partial, tone: "warning" },
207
+ failed: { label: STATUS_LABELS.en.failed, tone: "negative" },
208
+ delayed: { label: STATUS_LABELS.en.delayed, tone: "warning" },
209
+ running: { label: STATUS_LABELS.en.running, tone: "info" },
210
+ stopped: { label: STATUS_LABELS.en.stopped, tone: "neutral" },
211
+ active: { label: STATUS_LABELS.en.active, tone: "positive" },
212
+ inactive: { label: STATUS_LABELS.en.inactive, tone: "neutral" },
213
+ warning: { label: STATUS_LABELS.en.warning, tone: "warning" },
214
+ error: { label: STATUS_LABELS.en.error, tone: "negative" },
215
+ pending: { label: STATUS_LABELS.en.pending, tone: "info" },
52
216
  } as const satisfies Record<string, { label: string; tone: StatusTone }>
53
217
 
54
218
  export type StatusKey = keyof typeof STATUS_VOCABULARY
55
219
 
56
- /** 状態の日本語ラベル。語彙に無い status は渡された文字列のまま返す。 */
57
- export function statusLabel(status: string): string {
58
- return Object.hasOwn(STATUS_VOCABULARY, status) ? STATUS_VOCABULARY[status as StatusKey].label : status
220
+ /** 状態のラベル(`locale` の言語。既定はページのロケール)。語彙に無い status は渡された文字列のまま返す。 */
221
+ export function statusLabel(status: string, locale?: string): string {
222
+ return Object.hasOwn(STATUS_VOCABULARY, status) ? STATUS_LABELS[uiLanguage(resolveLocale(locale))][status as StatusKey] : status
59
223
  }
60
224
 
61
225
  const defaultColorMap: Record<string, string> = Object.fromEntries(
@@ -75,12 +239,12 @@ const legacyColorTones: Record<string, StatusTone> = {
75
239
  * One literal class set per tone — Tailwind only emits classes it can see
76
240
  * literally in the source.
77
241
  */
78
- const toneStyles: Record<StatusTone, { dot: string; bg: string; text: string }> = {
79
- positive: { dot: "bg-positive", bg: "bg-positive-subtle", text: "text-positive" },
80
- negative: { dot: "bg-negative", bg: "bg-negative-subtle", text: "text-negative" },
81
- warning: { dot: "bg-warning", bg: "bg-warning-subtle", text: "text-warning" },
82
- info: { dot: "bg-info", bg: "bg-info-subtle", text: "text-info" },
83
- neutral: { dot: "bg-neutral", bg: "bg-neutral-subtle", text: "text-neutral" },
242
+ const toneStyles: Record<StatusTone, { dot: string; bg: string; text: string; border: string }> = {
243
+ positive: { dot: "bg-positive", bg: "bg-positive-subtle", text: "text-positive", border: "border-positive/20 dark:border-positive/25" },
244
+ negative: { dot: "bg-negative", bg: "bg-negative-subtle", text: "text-negative", border: "border-negative/20 dark:border-negative/25" },
245
+ warning: { dot: "bg-warning", bg: "bg-warning-subtle", text: "text-warning", border: "border-warning/20 dark:border-warning/25" },
246
+ info: { dot: "bg-info", bg: "bg-info-subtle", text: "text-info", border: "border-info/20 dark:border-info/25" },
247
+ neutral: { dot: "bg-neutral", bg: "bg-neutral-subtle", text: "text-neutral", border: "border-neutral/20 dark:border-neutral/25" },
84
248
  }
85
249
 
86
250
  const resolveTone = (color: string | undefined): StatusTone => {
@@ -101,19 +265,20 @@ export const StatusBadge = forwardRef<HTMLSpanElement, StatusBadgeProps>(functio
101
265
  { status, label, colorMap, className },
102
266
  ref,
103
267
  ) {
268
+ const locale = useLocale()
104
269
  const mergedColorMap = { ...defaultColorMap, ...colorMap }
105
270
  const style = toneStyles[resolveTone(mergedColorMap[status])]
106
- const displayLabel = label ?? statusLabel(status)
271
+ const displayLabel = label ?? statusLabel(status, locale)
107
272
 
108
273
  return (
109
274
  <Badge
110
275
  ref={ref}
111
276
  data-slot="status-badge"
112
277
  variant="outline"
113
- className={cn("gap-1.5 border-transparent", style.bg, style.text, className)}
278
+ className={cn("gap-1.5 rounded-md", style.border, style.bg, style.text, className)}
114
279
  aria-label={displayLabel}
115
280
  >
116
- <span className={cn("inline-block size-2 rounded-full", style.dot)} aria-hidden="true" />
281
+ <span className={cn("inline-block size-1.5 rounded-full", style.dot)} aria-hidden="true" />
117
282
  {displayLabel}
118
283
  </Badge>
119
284
  )
@@ -34,14 +34,18 @@ function TooltipContent({
34
34
  align = "center",
35
35
  alignOffset = 0,
36
36
  children,
37
+ container,
37
38
  ...props
38
39
  }: TooltipPrimitive.Popup.Props &
39
40
  Pick<
40
41
  TooltipPrimitive.Positioner.Props,
41
42
  "align" | "alignOffset" | "side" | "sideOffset"
42
- >) {
43
+ > & {
44
+ /** ポータルの親要素。ローカルテーマ内の要素を渡すと、その CSS 変数を継承する。省略時は body。 */
45
+ container?: TooltipPrimitive.Portal.Props["container"]
46
+ }) {
43
47
  return (
44
- <TooltipPrimitive.Portal>
48
+ <TooltipPrimitive.Portal container={container} className={container ? "contents" : undefined}>
45
49
  <TooltipPrimitive.Positioner
46
50
  align={align}
47
51
  alignOffset={alignOffset}