@squadbase/vantage 0.6.2-dev1.54bde93 → 0.6.2-dev1.56da87f

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 (89) hide show
  1. package/dist/{build-A23M4GCH.js → build-U7GO26HR.js} +3 -3
  2. package/dist/{build-A23M4GCH.js.map → build-U7GO26HR.js.map} +1 -1
  3. package/dist/{check-FBHT6W6J.js → check-MRVAIHG5.js} +3 -3
  4. package/dist/{check-FBHT6W6J.js.map → check-MRVAIHG5.js.map} +1 -1
  5. package/dist/{chunk-57GHR5LN.js → chunk-3RJEOP3J.js} +29 -18
  6. package/dist/chunk-3RJEOP3J.js.map +1 -0
  7. package/dist/{chunk-QOXXOFGL.js → chunk-77CISBMG.js} +994 -464
  8. package/dist/chunk-77CISBMG.js.map +1 -0
  9. package/dist/{chunk-JXFCSF3K.js → chunk-EG4PX726.js} +12 -7
  10. package/dist/chunk-EG4PX726.js.map +1 -0
  11. package/dist/{chunk-2N72FKLB.js → chunk-NZ5QIIG4.js} +33 -11
  12. package/dist/chunk-NZ5QIIG4.js.map +1 -0
  13. package/dist/{chunk-5C2SEDPH.js → chunk-PJ4SPXHS.js} +4 -4
  14. package/dist/{chunk-5C2SEDPH.js.map → chunk-PJ4SPXHS.js.map} +1 -1
  15. package/dist/{chunk-7S52M2SL.js → chunk-QNOX7WLZ.js} +3 -3
  16. package/dist/{chunk-7S52M2SL.js.map → chunk-QNOX7WLZ.js.map} +1 -1
  17. package/dist/{chunk-PDOBHMUQ.js → chunk-ROHNXP7J.js} +72 -3
  18. package/dist/chunk-ROHNXP7J.js.map +1 -0
  19. package/dist/{chunk-6OTTGAPO.js → chunk-TRMHNMMZ.js} +24 -7
  20. package/dist/chunk-TRMHNMMZ.js.map +1 -0
  21. package/dist/cli.js +4 -4
  22. package/dist/components/index.d.ts +49 -29
  23. package/dist/components/index.js +5 -5
  24. package/dist/{delta-text-CvwBGJ95.d.ts → delta-text-CbrOaW83.d.ts} +4 -2
  25. package/dist/{dev-H4I2JL63.js → dev-O42JFQ64.js} +3 -3
  26. package/dist/{dev-H4I2JL63.js.map → dev-O42JFQ64.js.map} +1 -1
  27. package/dist/doc/index.d.ts +14 -14
  28. package/dist/doc/index.js +198 -84
  29. package/dist/doc/index.js.map +1 -1
  30. package/dist/{doctor-B2O3GJDU.js → doctor-YD3XAAOT.js} +3 -3
  31. package/dist/{doctor-B2O3GJDU.js.map → doctor-YD3XAAOT.js.map} +1 -1
  32. package/dist/{format-U0cQl069.d.ts → format-DihQkL1N.d.ts} +17 -11
  33. package/dist/slide/index.d.ts +2 -2
  34. package/dist/slide/index.js +95 -44
  35. package/dist/slide/index.js.map +1 -1
  36. package/dist/table/index.js +6 -6
  37. package/dist/ui/index.d.ts +1 -1
  38. package/dist/ui/index.js +5 -5
  39. package/docs/en/agent-skills.md +1 -1
  40. package/docs/ja/agent-skills.md +1 -1
  41. package/package.json +2 -2
  42. package/registry/ui/app-shell.tsx +138 -1
  43. package/registry/ui/area-chart.tsx +344 -85
  44. package/registry/ui/attention-list.tsx +177 -15
  45. package/registry/ui/bar-chart.tsx +341 -85
  46. package/registry/ui/bar-list.tsx +332 -77
  47. package/registry/ui/box-plot-chart.tsx +405 -97
  48. package/registry/ui/category-bar.tsx +248 -40
  49. package/registry/ui/chart-frame.tsx +257 -46
  50. package/registry/ui/data-table.tsx +229 -37
  51. package/registry/ui/date-range-picker.tsx +190 -36
  52. package/registry/ui/delta.tsx +171 -12
  53. package/registry/ui/donut-chart.tsx +339 -84
  54. package/registry/ui/echart.tsx +142 -4
  55. package/registry/ui/filter-bar.tsx +179 -20
  56. package/registry/ui/funnel-steps.tsx +354 -80
  57. package/registry/ui/heatmap.tsx +293 -52
  58. package/registry/ui/histogram-chart.tsx +395 -97
  59. package/registry/ui/kpi-card.tsx +245 -44
  60. package/registry/ui/legend.tsx +330 -76
  61. package/registry/ui/line-chart.tsx +344 -85
  62. package/registry/ui/multi-select.tsx +159 -9
  63. package/registry/ui/page-shell.tsx +141 -3
  64. package/registry/ui/paired-chart.tsx +349 -90
  65. package/registry/ui/progress-circle.tsx +205 -39
  66. package/registry/ui/sample-data.tsx +153 -9
  67. package/registry/ui/scatter-chart.tsx +391 -100
  68. package/registry/ui/searchable-select.tsx +145 -7
  69. package/registry/ui/states.tsx +170 -13
  70. package/registry/ui/status-badge.tsx +193 -28
  71. package/registry/ui/tracker.tsx +205 -39
  72. package/registry/ui/trend-indicator.tsx +149 -6
  73. package/registry/ui/updated-at.tsx +170 -16
  74. package/registry/ui/waterfall-chart.tsx +415 -102
  75. package/skills/vantage-add-feature/SKILL.md +5 -0
  76. package/skills/vantage-design/SKILL.md +25 -27
  77. package/skills/vantage-design/references/extract.md +10 -13
  78. package/skills/vantage-design/references/format.md +12 -173
  79. package/skills/vantage-design/references/presets.md +0 -10
  80. package/templates/AGENTS.md +29 -15
  81. package/templates/agents/api.md +7 -0
  82. package/templates/agents/page.md +37 -1
  83. package/templates/agents/slide.md +7 -1
  84. package/dist/chunk-2N72FKLB.js.map +0 -1
  85. package/dist/chunk-57GHR5LN.js.map +0 -1
  86. package/dist/chunk-6OTTGAPO.js.map +0 -1
  87. package/dist/chunk-JXFCSF3K.js.map +0 -1
  88. package/dist/chunk-PDOBHMUQ.js.map +0 -1
  89. package/dist/chunk-QOXXOFGL.js.map +0 -1
@@ -1,10 +1,10 @@
1
- import { DeltaText } from '../chunk-6OTTGAPO.js';
2
- export { DeltaText } from '../chunk-6OTTGAPO.js';
1
+ import { DeltaText } from '../chunk-TRMHNMMZ.js';
2
+ export { DeltaText } from '../chunk-TRMHNMMZ.js';
3
3
  import { useSearchState } from '../chunk-ZO62C6T4.js';
4
4
  import '../chunk-6S4BAIGV.js';
5
- import { EChart } from '../chunk-JXFCSF3K.js';
6
- import { formatValue, EMPTY_VALUE } from '../chunk-57GHR5LN.js';
7
- import '../chunk-PDOBHMUQ.js';
5
+ import { EChart } from '../chunk-EG4PX726.js';
6
+ import { formatValue, EMPTY_VALUE } from '../chunk-3RJEOP3J.js';
7
+ import { uiLanguage, useLocale } from '../chunk-ROHNXP7J.js';
8
8
  import '../chunk-U736PVHY.js';
9
9
  import { createContext, useRef, useState, useLayoutEffect, useContext, createElement, Children, isValidElement, useCallback, cloneElement, useMemo, useEffect } from 'react';
10
10
  import { jsx, Fragment, jsxs } from 'react/jsx-runtime';
@@ -1700,8 +1700,13 @@ function SlideHeading({ title, eyebrow }) {
1700
1700
  heading
1701
1701
  ] });
1702
1702
  }
1703
+ var TEXT = {
1704
+ ja: { asOf: (asOf) => `${asOf} \u6642\u70B9`, source: (source) => `\u51FA\u5178: ${source}` },
1705
+ en: { asOf: (asOf) => `As of ${asOf}`, source: (source) => `Source: ${source}` }
1706
+ };
1703
1707
  function SlideSourceLine({ asOf, source, page }) {
1704
- const text = [asOf ? `${asOf} \u6642\u70B9` : null, source ? `\u51FA\u5178: ${source}` : null].filter(Boolean).join(" / ");
1708
+ const t = TEXT[uiLanguage(useLocale())];
1709
+ const text = [asOf ? t.asOf(asOf) : null, source ? t.source(source) : null].filter(Boolean).join(" / ");
1705
1710
  if (!text && !page) return null;
1706
1711
  return /* @__PURE__ */ jsx(
1707
1712
  "p",
@@ -1725,7 +1730,7 @@ var MAX_INSIGHTS = 3;
1725
1730
  var MAX_INSIGHT_CHARS = 40;
1726
1731
  var LINE_TYPES = ["solid", "dashed", "dotted"];
1727
1732
  var SYMBOLS = ["circle", "rect", "triangle", "diamond"];
1728
- function buildSlideChartOption(chart) {
1733
+ function buildSlideChartOption(chart, locale) {
1729
1734
  return {
1730
1735
  animation: false,
1731
1736
  textStyle: { fontSize: SLIDE_SPEC.fontSize.caption },
@@ -1761,7 +1766,7 @@ function buildSlideChartOption(chart) {
1761
1766
  axisLabel: {
1762
1767
  fontSize: SLIDE_SPEC.fontSize.caption,
1763
1768
  hideOverlap: true,
1764
- formatter: (v) => formatValue(v, "compact")
1769
+ formatter: (v) => formatValue(v, "compact", locale)
1765
1770
  }
1766
1771
  },
1767
1772
  ...chart.type === "bar" && chart.series.length > 1 ? { aria: { enabled: true, decal: { show: true } } } : {},
@@ -1782,7 +1787,8 @@ function SlideChartInsight({ title, chart, insights, chartSide = "left", asOf, s
1782
1787
  const hasSource = Boolean(asOf || source);
1783
1788
  if (insights.some((t) => t.length > MAX_INSIGHT_CHARS)) console.warn(`SlideChartInsight: an insight is over ${MAX_INSIGHT_CHARS} characters; the column is narrow. Shorten it.`);
1784
1789
  if (insights.length > MAX_INSIGHTS) console.warn(`SlideChartInsight: ${insights.length} insights; ${MAX_INSIGHTS} fit beside the chart. Split the slide.`);
1785
- const option = useMemo(() => buildSlideChartOption(chart), [chart]);
1790
+ const locale = useLocale();
1791
+ const option = useMemo(() => buildSlideChartOption(chart, locale), [chart, locale]);
1786
1792
  const chartFirst = chartSide === "left";
1787
1793
  const chartColumn = /* @__PURE__ */ jsx(SlideColumn, { span: 7, children: /* @__PURE__ */ jsx("div", { "data-waitfor": "canvas", style: { minHeight: 0, height: "100%" }, children: /* @__PURE__ */ jsx(EChart, { option, height: "100%", ariaLabel: title }) }) });
1788
1794
  const insightsColumn = /* @__PURE__ */ jsx(SlideColumn, { span: 5, children: /* @__PURE__ */ jsx(
@@ -1843,11 +1849,16 @@ function SlideChartInsight({ title, chart, insights, chartSide = "left", asOf, s
1843
1849
  }
1844
1850
  );
1845
1851
  }
1852
+ var TEXT2 = {
1853
+ ja: { asOf: (asOf) => `${asOf} \u6642\u70B9`, source: (source) => `\u51FA\u5178: ${source}`, separator: "\u3000|\u3000" },
1854
+ en: { asOf: (asOf) => `As of ${asOf}`, source: (source) => `Source: ${source}`, separator: " | " }
1855
+ };
1846
1856
  function SlideCover({ title, subtitle, period, author, asOf, source }) {
1857
+ const t = TEXT2[uiLanguage(useLocale())];
1847
1858
  const meta = [
1848
1859
  period,
1849
1860
  author,
1850
- [asOf ? `${asOf} \u6642\u70B9` : null, source ? `\u51FA\u5178: ${source}` : null].filter(Boolean).join(" / ") || void 0
1861
+ [asOf ? t.asOf(asOf) : null, source ? t.source(source) : null].filter(Boolean).join(" / ") || void 0
1851
1862
  ].filter(Boolean);
1852
1863
  return /* @__PURE__ */ jsxs(
1853
1864
  "section",
@@ -1909,7 +1920,7 @@ function SlideCover({ title, subtitle, period, author, asOf, source }) {
1909
1920
  lineHeight: SLIDE_SPEC.lineHeight.body,
1910
1921
  color: "var(--slide-muted)"
1911
1922
  },
1912
- children: meta.join("\u3000|\u3000")
1923
+ children: meta.join(t.separator)
1913
1924
  }
1914
1925
  )
1915
1926
  ]
@@ -2014,21 +2025,38 @@ function SlideExecSummary({ title, points, layout = "rows", asOf, source }) {
2014
2025
  }
2015
2026
  var MAX_ITEMS = 4;
2016
2027
  var ARROW = { up: "\u25B2", down: "\u25BC", flat: "\u25AC" };
2017
- var WORD = { up: "\u5897", down: "\u6E1B", flat: "\u6A2A\u3070\u3044" };
2018
- function deltaView(delta, betterWhen) {
2028
+ var TEXT3 = {
2029
+ ja: {
2030
+ up: "\u5897",
2031
+ down: "\u6E1B",
2032
+ flat: "\u6A2A\u3070\u3044",
2033
+ target: (target) => `\u76EE\u6A19 ${target}`,
2034
+ attainment: (shown, rate) => `${shown}(\u9054\u6210\u7387 ${rate})`
2035
+ },
2036
+ en: {
2037
+ up: "Up",
2038
+ down: "Down",
2039
+ flat: "Flat",
2040
+ target: (target) => `Target ${target}`,
2041
+ attainment: (shown, rate) => `${shown} (${rate} attained)`
2042
+ }
2043
+ };
2044
+ function deltaView(delta, betterWhen, locale) {
2019
2045
  const direction = delta.value > 0 ? "up" : delta.value < 0 ? "down" : "flat";
2020
2046
  const color = direction === "flat" ? "var(--slide-muted)" : direction === betterWhen ? "var(--positive)" : "var(--negative)";
2021
- const amount = formatValue(delta.value, delta.format, void 0, { signDisplay: "exceptZero" });
2022
- return { color, text: `${ARROW[direction]} ${WORD[direction]} ${amount}` };
2047
+ const amount = formatValue(delta.value, delta.format, locale, { signDisplay: "exceptZero" });
2048
+ return { color, text: `${ARROW[direction]} ${TEXT3[uiLanguage(locale)][direction]} ${amount}` };
2023
2049
  }
2024
- function targetText(item) {
2050
+ function targetText(item, locale) {
2025
2051
  if (item.target === void 0) return void 0;
2052
+ const t = TEXT3[uiLanguage(locale)];
2026
2053
  const { value, target, betterWhen = "up" } = item;
2027
2054
  const rate = value === null ? void 0 : betterWhen === "down" ? target / value : value / target;
2028
- const shown = `\u76EE\u6A19 ${formatValue(target, item.format)}`;
2029
- return rate === void 0 || !Number.isFinite(rate) ? shown : `${shown}(\u9054\u6210\u7387 ${formatValue(rate, { type: "percent", digits: 0 })})`;
2055
+ const shown = t.target(formatValue(target, item.format, locale));
2056
+ return rate === void 0 || !Number.isFinite(rate) ? shown : t.attainment(shown, formatValue(rate, { type: "percent", digits: 0 }, locale));
2030
2057
  }
2031
2058
  function SlideKpiGrid({ title, items, asOf, source }) {
2059
+ const locale = useLocale();
2032
2060
  const hasSource = Boolean(asOf || source);
2033
2061
  if (items.length > MAX_ITEMS) console.warn(`SlideKpiGrid: ${items.length} items; ${MAX_ITEMS} fit the canvas. Split the slide.`);
2034
2062
  return /* @__PURE__ */ jsxs(
@@ -2062,8 +2090,8 @@ function SlideKpiGrid({ title, items, asOf, source }) {
2062
2090
  alignItems: "center"
2063
2091
  },
2064
2092
  children: items.map((item, i) => {
2065
- const delta = item.delta ? deltaView({ value: item.delta.value, format: item.delta.format ?? item.format }, item.betterWhen ?? "up") : void 0;
2066
- const target = targetText(item);
2093
+ const delta = item.delta ? deltaView({ value: item.delta.value, format: item.delta.format ?? item.format }, item.betterWhen ?? "up", locale) : void 0;
2094
+ const target = targetText(item, locale);
2067
2095
  return /* @__PURE__ */ jsxs(
2068
2096
  "div",
2069
2097
  {
@@ -2089,7 +2117,7 @@ function SlideKpiGrid({ title, items, asOf, source }) {
2089
2117
  fontWeight: 700,
2090
2118
  fontVariantNumeric: "tabular-nums"
2091
2119
  },
2092
- children: item.display ?? formatValue(item.value, item.format)
2120
+ children: item.display ?? formatValue(item.value, item.format, locale)
2093
2121
  }
2094
2122
  ),
2095
2123
  delta && /* @__PURE__ */ jsxs("span", { style: { fontSize: "var(--slide-size-body)", lineHeight: SLIDE_SPEC.lineHeight.heading, fontWeight: 700, color: delta.color }, children: [
@@ -2113,16 +2141,21 @@ function SlideKpiGrid({ title, items, asOf, source }) {
2113
2141
  );
2114
2142
  }
2115
2143
  var ARROW2 = { up: "\u25B2", down: "\u25BC", flat: "\u25AC" };
2116
- var WORD2 = { up: "\u5897", down: "\u6E1B", flat: "\u6A2A\u3070\u3044" };
2117
- function deltaView2(delta, betterWhen) {
2144
+ var TEXT4 = {
2145
+ ja: { up: "\u5897", down: "\u6E1B", flat: "\u6A2A\u3070\u3044", trend: (label) => `${label}\u306E\u63A8\u79FB` },
2146
+ en: { up: "Up", down: "Down", flat: "Flat", trend: (label) => `${label} trend` }
2147
+ };
2148
+ function deltaView2(delta, betterWhen, locale) {
2118
2149
  const direction = delta.value > 0 ? "up" : delta.value < 0 ? "down" : "flat";
2119
2150
  const color = direction === "flat" ? "var(--slide-muted)" : direction === betterWhen ? "var(--positive)" : "var(--negative)";
2120
- const amount = formatValue(delta.value, delta.format, void 0, { signDisplay: "exceptZero" });
2121
- return { color, text: `${ARROW2[direction]} ${WORD2[direction]} ${amount}` };
2151
+ const amount = formatValue(delta.value, delta.format, locale, { signDisplay: "exceptZero" });
2152
+ return { color, text: `${ARROW2[direction]} ${TEXT4[uiLanguage(locale)][direction]} ${amount}` };
2122
2153
  }
2123
2154
  function SlideKpiHero({ title, label, value, format, display, delta, betterWhen = "up", comparisonLabel, trend, asOf, source }) {
2155
+ const locale = useLocale();
2156
+ const t = TEXT4[uiLanguage(locale)];
2124
2157
  const hasSource = Boolean(asOf || source);
2125
- const deltaShown = delta ? deltaView2({ value: delta.value, format: delta.format ?? format }, betterWhen) : void 0;
2158
+ const deltaShown = delta ? deltaView2({ value: delta.value, format: delta.format ?? format }, betterWhen, locale) : void 0;
2126
2159
  const option = useMemo(() => {
2127
2160
  if (!trend || trend.length === 0) return void 0;
2128
2161
  return {
@@ -2140,7 +2173,7 @@ function SlideKpiHero({ title, label, value, format, display, delta, betterWhen
2140
2173
  yAxis: {
2141
2174
  type: "value",
2142
2175
  scale: true,
2143
- axisLabel: { fontSize: SLIDE_SPEC.fontSize.caption, hideOverlap: true, formatter: (v) => formatValue(v, "compact") }
2176
+ axisLabel: { fontSize: SLIDE_SPEC.fontSize.caption, hideOverlap: true, formatter: (v) => formatValue(v, "compact", locale) }
2144
2177
  },
2145
2178
  series: [
2146
2179
  {
@@ -2153,7 +2186,7 @@ function SlideKpiHero({ title, label, value, format, display, delta, betterWhen
2153
2186
  }
2154
2187
  ]
2155
2188
  };
2156
- }, [trend]);
2189
+ }, [trend, locale]);
2157
2190
  return /* @__PURE__ */ jsxs(
2158
2191
  "section",
2159
2192
  {
@@ -2198,7 +2231,7 @@ function SlideKpiHero({ title, label, value, format, display, delta, betterWhen
2198
2231
  fontWeight: 700,
2199
2232
  fontVariantNumeric: "tabular-nums"
2200
2233
  },
2201
- children: display ?? formatValue(value, format)
2234
+ children: display ?? formatValue(value, format, locale)
2202
2235
  }
2203
2236
  ),
2204
2237
  (deltaShown || comparisonLabel) && /* @__PURE__ */ jsxs("span", { style: { display: "flex", flexWrap: "wrap", alignItems: "baseline", gap: SLIDE_SPEC.space.sm, fontSize: "var(--slide-size-body)", lineHeight: SLIDE_SPEC.lineHeight.heading }, children: [
@@ -2208,7 +2241,7 @@ function SlideKpiHero({ title, label, value, format, display, delta, betterWhen
2208
2241
  ]
2209
2242
  }
2210
2243
  ) }),
2211
- option && /* @__PURE__ */ jsx(SlideColumn, { span: 6, children: /* @__PURE__ */ jsx("div", { "data-waitfor": "canvas", style: { minHeight: 0, height: "100%" }, children: /* @__PURE__ */ jsx(EChart, { option, height: "100%", ariaLabel: `${label}\u306E\u63A8\u79FB` }) }) })
2244
+ option && /* @__PURE__ */ jsx(SlideColumn, { span: 6, children: /* @__PURE__ */ jsx("div", { "data-waitfor": "canvas", style: { minHeight: 0, height: "100%" }, children: /* @__PURE__ */ jsx(EChart, { option, height: "100%", ariaLabel: t.trend(label) }) }) })
2212
2245
  ] }),
2213
2246
  hasSource && /* @__PURE__ */ jsx(SlideSourceLine, { asOf, source })
2214
2247
  ]
@@ -2217,14 +2250,19 @@ function SlideKpiHero({ title, label, value, format, display, delta, betterWhen
2217
2250
  }
2218
2251
  var MAX_ITEMS2 = 5;
2219
2252
  var MAX_DUE_CHARS = 10;
2253
+ var HEADS = {
2254
+ ja: { owner: "\u62C5\u5F53", due: "\u671F\u9650", metric: "\u78BA\u8A8D\u3059\u308B\u6307\u6A19" },
2255
+ en: { owner: "Owner", due: "Due", metric: "Metric to watch" }
2256
+ };
2220
2257
  function SlideNextActions({ title, items, asOf, source }) {
2258
+ const head = HEADS[uiLanguage(useLocale())];
2221
2259
  const hasSource = Boolean(asOf || source);
2222
2260
  if (items.length > MAX_ITEMS2) console.warn(`SlideNextActions: ${items.length} items; ${MAX_ITEMS2} fit the canvas. Split the slide.`);
2223
2261
  if (items.some((it) => (it.due?.length ?? 0) > MAX_DUE_CHARS)) console.warn(`SlideNextActions: a due date is over ${MAX_DUE_CHARS} characters; the column is one line wide. Shorten it.`);
2224
2262
  const cols = [
2225
- { key: "owner", head: "\u62C5\u5F53", fr: 2 },
2226
- { key: "due", head: "\u671F\u9650", fr: 2 },
2227
- { key: "metric", head: "\u78BA\u8A8D\u3059\u308B\u6307\u6A19", fr: 3 }
2263
+ { key: "owner", head: head.owner, fr: 2 },
2264
+ { key: "due", head: head.due, fr: 2 },
2265
+ { key: "metric", head: head.metric, fr: 3 }
2228
2266
  ];
2229
2267
  const shown = cols.filter((c) => items.some((it) => it[c.key]));
2230
2268
  const template = [`${SLIDE_SPEC.grid.columnWidth}px`, "minmax(0, 6fr)", ...shown.map((c) => `minmax(0, ${c.fr}fr)`)].join(" ");
@@ -2300,10 +2338,20 @@ function SlideNextActions({ title, items, asOf, source }) {
2300
2338
  }
2301
2339
  var MAX_ROWS = 8;
2302
2340
  var DENSE_ROWS = 6;
2303
- var STATUS = {
2304
- on: { label: "\u9806\u8ABF", color: "var(--positive)" },
2305
- risk: { label: "\u8981\u6CE8\u610F", color: "var(--warning)" },
2306
- off: { label: "\u9045\u5EF6", color: "var(--negative)" }
2341
+ var STATUS_COLOR = {
2342
+ on: "var(--positive)",
2343
+ risk: "var(--warning)",
2344
+ off: "var(--negative)"
2345
+ };
2346
+ var TEXT5 = {
2347
+ ja: {
2348
+ status: { on: "\u9806\u8ABF", risk: "\u8981\u6CE8\u610F", off: "\u9045\u5EF6" },
2349
+ head: { metric: "\u6307\u6A19", target: "\u76EE\u6A19", actual: "\u5B9F\u7E3E", attainment: "\u9054\u6210\u7387", status: "\u72B6\u614B" }
2350
+ },
2351
+ en: {
2352
+ status: { on: "On track", risk: "At risk", off: "Off track" },
2353
+ head: { metric: "Metric", target: "Target", actual: "Actual", attainment: "Attainment", status: "Status" }
2354
+ }
2307
2355
  };
2308
2356
  function attainment(row) {
2309
2357
  if (row.value === null || row.target === void 0) return void 0;
@@ -2311,9 +2359,11 @@ function attainment(row) {
2311
2359
  return Number.isFinite(rate) ? rate : void 0;
2312
2360
  }
2313
2361
  function SlideScorecardTable({ title, rows, columns, asOf, source }) {
2362
+ const locale = useLocale();
2363
+ const t = TEXT5[uiLanguage(locale)];
2314
2364
  const hasSource = Boolean(asOf || source);
2315
2365
  if (rows.length > MAX_ROWS) console.warn(`SlideScorecardTable: ${rows.length} rows; ${MAX_ROWS} fit the canvas. Split the slide.`);
2316
- const head = { metric: "\u6307\u6A19", target: "\u76EE\u6A19", actual: "\u5B9F\u7E3E", attainment: "\u9054\u6210\u7387", status: "\u72B6\u614B", ...columns };
2366
+ const head = { ...t.head, ...columns };
2317
2367
  const showAttainment = rows.some((r) => attainment(r) !== void 0);
2318
2368
  const cellSize = rows.length > DENSE_ROWS ? SLIDE_SPEC.fontSize.caption : "var(--slide-size-body)";
2319
2369
  const cell = {
@@ -2353,13 +2403,13 @@ function SlideScorecardTable({ title, rows, columns, asOf, source }) {
2353
2403
  ] }) }),
2354
2404
  /* @__PURE__ */ jsx("tbody", { children: rows.map((r, i) => /* @__PURE__ */ jsxs("tr", { children: [
2355
2405
  /* @__PURE__ */ jsx("th", { scope: "row", style: { ...cell, fontWeight: 700 }, children: r.metric }),
2356
- /* @__PURE__ */ jsx("td", { style: num, children: r.target === void 0 ? EMPTY_VALUE : formatValue(r.target, r.format) }),
2357
- /* @__PURE__ */ jsx("td", { style: { ...num, fontWeight: 700 }, children: r.display ?? formatValue(r.value, r.format) }),
2358
- showAttainment && /* @__PURE__ */ jsx("td", { style: num, children: attainment(r) === void 0 ? EMPTY_VALUE : formatValue(attainment(r), { type: "percent", digits: 0 }) }),
2406
+ /* @__PURE__ */ jsx("td", { style: num, children: r.target === void 0 ? EMPTY_VALUE : formatValue(r.target, r.format, locale) }),
2407
+ /* @__PURE__ */ jsx("td", { style: { ...num, fontWeight: 700 }, children: r.display ?? formatValue(r.value, r.format, locale) }),
2408
+ showAttainment && /* @__PURE__ */ jsx("td", { style: num, children: attainment(r) === void 0 ? EMPTY_VALUE : formatValue(attainment(r), { type: "percent", digits: 0 }, locale) }),
2359
2409
  /* @__PURE__ */ jsxs("td", { style: cell, children: [
2360
- /* @__PURE__ */ jsx("span", { "aria-hidden": true, style: { color: STATUS[r.status].color }, children: "\u25CF" }),
2410
+ /* @__PURE__ */ jsx("span", { "aria-hidden": true, style: { color: STATUS_COLOR[r.status] }, children: "\u25CF" }),
2361
2411
  " ",
2362
- STATUS[r.status].label
2412
+ t.status[r.status]
2363
2413
  ] })
2364
2414
  ] }, i)) })
2365
2415
  ] }) }),
@@ -2400,6 +2450,7 @@ function SlideChartFull({ title, chart, note, asOf, source }) {
2400
2450
  var MAX_POINTS2 = 3;
2401
2451
  var MAX_POINT_CHARS = 24;
2402
2452
  function SlideComparison({ title, columns, verdict, asOf, source }) {
2453
+ const locale = useLocale();
2403
2454
  const hasSource = Boolean(asOf || source);
2404
2455
  if (columns.length < 2 || columns.length > 3) console.warn(`SlideComparison: ${columns.length} columns; 2\u20133 fit. Split the slide.`);
2405
2456
  if (columns.some((c) => c.points.length > MAX_POINTS2 || c.points.some((t) => t.length > MAX_POINT_CHARS)))
@@ -2425,7 +2476,7 @@ function SlideComparison({ title, columns, verdict, asOf, source }) {
2425
2476
  children: [
2426
2477
  /* @__PURE__ */ jsx(SlideHeading, { title }),
2427
2478
  /* @__PURE__ */ jsx(SlideColumns, { children: columns.map((col, i) => {
2428
- const main = col.display ?? (col.value === void 0 ? void 0 : col.value === null ? "\u2014" : formatValue(col.value, col.format));
2479
+ const main = col.display ?? (col.value === void 0 ? void 0 : col.value === null ? "\u2014" : formatValue(col.value, col.format, locale));
2429
2480
  return /* @__PURE__ */ jsx(SlideColumn, { span, children: /* @__PURE__ */ jsxs(
2430
2481
  "div",
2431
2482
  {