@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
@@ -1,179 +1,23 @@
1
- import { Tooltip, TooltipTrigger, TooltipContent, Badge, SidebarProvider, Sidebar, SidebarContent, SidebarGroup, SidebarGroupLabel, SidebarMenu, SidebarFooter, SidebarRail, SidebarInset, SidebarTrigger, Separator, Input, Table, TableHeader, TableRow, TableHead, TableBody, TableCell, Skeleton, Select, SelectTrigger, SelectValue, SelectContent, SelectItem, DropdownMenu, DropdownMenuTrigger, DropdownMenuContent, DropdownMenuCheckboxItem, useIsMobile, Popover, PopoverTrigger, PopoverContent, Calendar, ToggleGroup, ToggleGroupItem, SelectGroup, SelectLabel, Collapsible, CollapsibleTrigger, SidebarMenuButton, SidebarMenuBadge, CollapsibleContent, SidebarMenuSub, SidebarMenuSubItem, SidebarMenuSubButton, SidebarMenuItem, Command, CommandInput, CommandList, CommandEmpty, CommandGroup, CommandItem, Checkbox, Card, CardHeader, CardDescription, CardTitle, CardAction, CardFooter } from './chunk-XPQSTZUU.js';
2
- import { Button } from './chunk-PDOBHMUQ.js';
1
+ import { ChartFrameContext, useChartSurface, resolveChartColors, CHART_OTHER_COLOR, EChart, resolveFillColors } from './chunk-EG4PX726.js';
2
+ import { Sparkline } from './chunk-2IAPIOPS.js';
3
+ import { formatDateRange, EMPTY_VALUE, formatDate, toValueFormatter, formatValue, formatPoints, formatKind, formatDelta, MINUS_SIGN, formatDatesInText, DEFAULT_LOCALE } from './chunk-3RJEOP3J.js';
4
+ import { Tooltip, TooltipTrigger, TooltipContent, Badge, SidebarProvider, Sidebar, SidebarContent, SidebarGroup, SidebarGroupLabel, SidebarMenu, SidebarFooter, SidebarRail, SidebarInset, SidebarTrigger, Separator, Input, Table, TableHeader, TableRow, TableHead, TableBody, TableCell, Skeleton, Select, SelectTrigger, SelectValue, SelectContent, SelectItem, DropdownMenu, DropdownMenuTrigger, DropdownMenuContent, DropdownMenuCheckboxItem, useIsMobile, Popover, PopoverTrigger, PopoverContent, Calendar, ToggleGroup, ToggleGroupItem, SelectGroup, SelectLabel, Collapsible, CollapsibleTrigger, SidebarMenuButton, SidebarMenuBadge, CollapsibleContent, SidebarMenuSub, SidebarMenuSubItem, SidebarMenuSubButton, SidebarMenuItem, Command, CommandInput, CommandList, CommandEmpty, CommandGroup, CommandItem, Checkbox, Card, CardHeader, CardDescription, CardTitle, CardAction, CardFooter } from './chunk-QNOX7WLZ.js';
5
+ import { useLocale, uiLanguage, Button, weekStartsOn, resolveLocale, defaultFiscalYearStartMonth, FALLBACK_LOCALE } from './chunk-ROHNXP7J.js';
3
6
  import { cn } from './chunk-U736PVHY.js';
4
- import { forwardRef, useState, useEffect, createContext, useId, useRef, useMemo, useCallback, useContext, Fragment as Fragment$1 } from 'react';
7
+ import { forwardRef, useState, useEffect, createContext, useId, useMemo, useRef, useCallback, Fragment as Fragment$1, useContext } from 'react';
5
8
  import { cva } from 'class-variance-authority';
6
9
  import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
7
- import { Check, Copy, Download, Search, Columns3, CalendarIcon, ChevronDownIcon, ArrowUp, ArrowDown, ArrowRight, Minus, ChevronRight, ArrowUpDown, XIcon, LoaderIcon, CheckIcon, ChevronDown, X, CircleX, TriangleAlert, CircleCheck } from 'lucide-react';
8
- import { use, init } from 'echarts/core';
9
- import { BarChart, CustomChart, LineChart, PieChart, ScatterChart as ScatterChart$1, HeatmapChart } from 'echarts/charts';
10
- import { GridComponent, LegendComponent, MarkAreaComponent, MarkLineComponent, MarkPointComponent, TooltipComponent, GraphicComponent, VisualMapComponent } from 'echarts/components';
11
- import { CanvasRenderer } from 'echarts/renderers';
10
+ import { Search, Columns3, CalendarIcon, ChevronDownIcon, ArrowUp, ArrowDown, ArrowRight, Minus, ChevronRight, ArrowUpDown, XIcon, LoaderIcon, CheckIcon, Download, ChevronDown, X, CircleX, TriangleAlert, CircleCheck } from 'lucide-react';
11
+ import { use } from 'echarts/core';
12
+ import { GraphicComponent, VisualMapComponent } from 'echarts/components';
13
+ import { ScatterChart as ScatterChart$1, HeatmapChart } from 'echarts/charts';
12
14
  import 'echarts';
13
15
  import { flexRender, useReactTable, getPaginationRowModel, getFilteredRowModel, getSortedRowModel, getCoreRowModel } from '@tanstack/react-table';
14
- import { subMonths, subDays, endOfDay, startOfDay, startOfWeek, subWeeks, endOfWeek, startOfMonth, endOfMonth, isSameDay, format, addMonths } from 'date-fns';
16
+ import { subMonths, subDays, endOfDay, startOfDay, startOfWeek, subWeeks, endOfWeek, startOfMonth, endOfMonth, isSameDay, addMonths } from 'date-fns';
15
17
  import { ja } from 'date-fns/locale';
16
18
 
17
19
  // @squadbase/vantage — generated build. Do not edit.
18
20
 
19
- // ../squadkit/registry/lib/format.ts
20
- var DEFAULT_LOCALE = "ja-JP";
21
- var EMPTY_VALUE = "\u2014";
22
- var MINUS_SIGN = "\u2212";
23
- var PERCENT_DIGITS = 1;
24
- var DEFAULT_CURRENCY = "JPY";
25
- var MULTIPLE_SUFFIX = "\xD7";
26
- var POINTS_SUFFIX = "pt";
27
- function normalize(format2) {
28
- if (format2 === void 0) return { type: "compact" };
29
- return typeof format2 === "string" ? { type: format2 } : format2;
30
- }
31
- function formatKind(format2) {
32
- return normalize(format2).type;
33
- }
34
- function digitOptions(digits, defaultMax, significantDigits) {
35
- if (significantDigits !== void 0) return { maximumSignificantDigits: significantDigits };
36
- if (digits !== void 0) return { minimumFractionDigits: digits, maximumFractionDigits: digits };
37
- return defaultMax === void 0 ? {} : { maximumFractionDigits: defaultMax };
38
- }
39
- function formatParts(locale, options, value) {
40
- if (options.notation === "compact") {
41
- const compact = new Intl.NumberFormat(locale, {
42
- ...options,
43
- useGrouping: "always"
44
- }).formatToParts(value);
45
- if (!compact.some((p) => p.type === "compact")) return formatParts(locale, { ...options, notation: "standard" }, value);
46
- return joinParts(compact);
47
- }
48
- return joinParts(new Intl.NumberFormat(locale, options).formatToParts(value));
49
- }
50
- var joinParts = (parts) => parts.map((p) => p.type === "currency" ? p.value.normalize("NFKC") : p.type === "minusSign" ? MINUS_SIGN : p.value).join("");
51
- function formatValue(value, format2, locale = DEFAULT_LOCALE, options) {
52
- if (value === null || value === void 0 || Number.isNaN(value)) return EMPTY_VALUE;
53
- const { type, digits, currency, notation, unit, divisor, durationUnit } = normalize(format2);
54
- if (divisor !== void 0 && Number.isFinite(divisor) && divisor !== 0) value = value / divisor;
55
- const signDisplay = options?.signDisplay ?? "auto";
56
- const sig = options?.significantDigits;
57
- const withUnit = (s) => unit ? `${s}${unit}` : s;
58
- switch (type) {
59
- case "number":
60
- return withUnit(formatParts(locale, { ...digitOptions(digits, 2, sig), signDisplay }, value));
61
- case "percent":
62
- return formatParts(locale, { style: "percent", ...digitOptions(digits ?? PERCENT_DIGITS, void 0, sig), signDisplay }, value);
63
- case "currency":
64
- return withUnit(
65
- formatParts(
66
- locale,
67
- {
68
- style: "currency",
69
- currency: currency ?? DEFAULT_CURRENCY,
70
- notation: notation ?? "compact",
71
- ...digitOptions(digits, notation === "standard" ? void 0 : 1, sig),
72
- signDisplay
73
- },
74
- value
75
- )
76
- );
77
- case "multiple":
78
- return `${formatParts(locale, { ...digitOptions(digits, 2, sig), signDisplay }, value)}${unit || MULTIPLE_SUFFIX}`;
79
- case "compact":
80
- return withUnit(formatParts(locale, { ...digitOptions(digits, 1, sig), signDisplay, notation: "compact" }, value));
81
- case "duration":
82
- return formatDuration(value, durationUnit ?? "second", locale, digits, signDisplay);
83
- }
84
- }
85
- var SECONDS_PER = { second: 1, minute: 60, hour: 3600, day: 86400 };
86
- function durationWords(locale) {
87
- return locale.toLowerCase().startsWith("ja") ? { day: "\u65E5", hour: "\u6642\u9593", minute: "\u5206", second: "\u79D2", sep: "" } : { day: "d", hour: "h", minute: "min", second: "s", sep: " " };
88
- }
89
- function formatDuration(value, unit, locale, digits, signDisplay) {
90
- const w = durationWords(locale);
91
- const abs = Math.round(Math.abs(value) * SECONDS_PER[unit]);
92
- const join = (...parts) => parts.filter(([n]) => n !== 0).map(([n, u]) => `${n}${w.sep}${u}`).join(w.sep) || `0${w.sep}${parts.at(-1)?.[1] ?? w.second}`;
93
- let body;
94
- let zero = false;
95
- if (abs >= 86400) {
96
- const days = new Intl.NumberFormat(locale, { maximumFractionDigits: digits ?? 1, minimumFractionDigits: digits ?? 0 });
97
- body = `${days.format(abs / 86400)}${w.sep}${w.day}`;
98
- } else if (abs >= 3600) {
99
- const minutes = Math.round(abs / 60);
100
- body = join([Math.floor(minutes / 60), w.hour], [minutes % 60, w.minute]);
101
- } else if (abs >= 60) {
102
- body = join([Math.floor(abs / 60), w.minute], [abs % 60, w.second]);
103
- } else {
104
- zero = abs === 0;
105
- body = `${abs}${w.sep}${w.second}`;
106
- }
107
- const sign = zero ? "" : value < 0 ? MINUS_SIGN : signDisplay === "exceptZero" ? "+" : "";
108
- return `${sign}${body}`;
109
- }
110
- function formatDelta(value, format2, locale = DEFAULT_LOCALE) {
111
- return formatValue(value, format2, locale, { signDisplay: "exceptZero" });
112
- }
113
- function formatPoints(difference, locale = DEFAULT_LOCALE, options) {
114
- if (difference === null || difference === void 0 || Number.isNaN(difference)) return EMPTY_VALUE;
115
- const digits = options?.digits ?? PERCENT_DIGITS;
116
- const number = formatParts(
117
- locale,
118
- { minimumFractionDigits: digits, maximumFractionDigits: digits, signDisplay: options?.signDisplay ?? "exceptZero" },
119
- difference * 100
120
- );
121
- return `${number}${POINTS_SUFFIX}`;
122
- }
123
- function toValueFormatter(format2, locale = DEFAULT_LOCALE) {
124
- return (value) => formatValue(value, format2, locale);
125
- }
126
- var DATE_STYLE_OPTIONS = {
127
- date: { year: "numeric", month: "2-digit", day: "2-digit" },
128
- datetime: { year: "numeric", month: "2-digit", day: "2-digit", hour: "2-digit", minute: "2-digit", hourCycle: "h23" },
129
- month: { month: "short" },
130
- "year-month": { year: "numeric", month: "long" },
131
- year: { year: "numeric" }
132
- };
133
- var CALENDAR_DATE = /^\d{4}-\d{2}(-\d{2})?$/;
134
- function formatDate(value, style = "date", locale = DEFAULT_LOCALE, options) {
135
- if (value === null || value === void 0 || value === "") return EMPTY_VALUE;
136
- const calendar = typeof value === "string" && CALENDAR_DATE.test(value);
137
- const date = value instanceof Date ? value : new Date(value);
138
- if (!Number.isFinite(date.getTime())) return EMPTY_VALUE;
139
- return new Intl.DateTimeFormat(locale, {
140
- ...DATE_STYLE_OPTIONS[style],
141
- timeZone: calendar ? "UTC" : options?.timeZone
142
- }).format(date);
143
- }
144
- function formatDateRange(start, end, options) {
145
- const locale = options?.locale ?? DEFAULT_LOCALE;
146
- const parse = (value) => {
147
- if (value === null || value === void 0 || value === "") return null;
148
- const calendar = typeof value === "string" && CALENDAR_DATE.test(value);
149
- const date = value instanceof Date ? value : new Date(value);
150
- if (!Number.isFinite(date.getTime())) return null;
151
- return { date, timeZone: calendar ? "UTC" : options?.timeZone };
152
- };
153
- const a = parse(start);
154
- const b = parse(end);
155
- if (!a || !b) return EMPTY_VALUE;
156
- const full = (x, withYear) => new Intl.DateTimeFormat(locale, {
157
- ...withYear ? { year: "numeric" } : {},
158
- month: "numeric",
159
- day: "numeric",
160
- timeZone: x.timeZone
161
- }).format(x.date);
162
- const year = (x) => new Intl.DateTimeFormat("en-US", { year: "numeric", timeZone: x.timeZone }).format(x.date);
163
- const startText = full(a, true);
164
- const sameYear = year(a) === year(b);
165
- const endFull = full(b, true);
166
- if (startText === endFull) return startText;
167
- const separator = locale.toLowerCase().startsWith("ja") ? "\u301C" : " \u2013 ";
168
- return `${startText}${separator}${sameYear ? full(b, false) : endFull}`;
169
- }
170
- function formatDatesInText(text, locale = DEFAULT_LOCALE) {
171
- return text.replace(
172
- /(?<![\d-])(\d{4})-(0[1-9]|1[0-2])(-(0[1-9]|[12]\d|3[01]))?(?![\d-])/g,
173
- (match, _y, _m, day) => formatDate(match, day ? "date" : "year-month", locale)
174
- );
175
- }
176
-
177
21
  // ../squadkit/registry/lib/relative-time.ts
178
22
  var SECOND = 1e3;
179
23
  var MINUTE = 60 * SECOND;
@@ -197,36 +41,50 @@ function formatRelativeTime(date, options) {
197
41
  const now = nowValue instanceof Date ? nowValue.getTime() : nowValue;
198
42
  if (!Number.isFinite(time) || !Number.isFinite(now)) return EMPTY_VALUE;
199
43
  const diff = time - now;
200
- const rtf = new Intl.RelativeTimeFormat(options?.locale ?? DEFAULT_LOCALE, { numeric: "always" });
44
+ const rtf = new Intl.RelativeTimeFormat(resolveLocale(options?.locale), { numeric: "always" });
201
45
  for (const [unit, size] of UNITS) {
202
46
  if (Math.abs(diff) >= size) return rtf.format(Math.trunc(diff / size), unit);
203
47
  }
204
48
  return rtf.format(Math.trunc(diff / SECOND), "second");
205
49
  }
206
50
  var REFRESH_MS = 6e4;
51
+ var TEXT = {
52
+ ja: {
53
+ justNow: "\u305F\u3063\u305F\u4ECA",
54
+ relative: (relative2) => `${relative2}\u306B\u66F4\u65B0`,
55
+ absoluteFirst: (shown, relative2) => `${shown} \u66F4\u65B0\uFF08${relative2}\uFF09`
56
+ },
57
+ en: {
58
+ justNow: "just now",
59
+ relative: (relative2) => `Updated ${relative2}`,
60
+ absoluteFirst: (shown, relative2) => `Updated ${shown} (${relative2})`
61
+ }
62
+ };
207
63
  var toMs = (value) => value instanceof Date ? value.getTime() : new Date(value).getTime();
208
- function relative(at, now) {
209
- if (now - at < REFRESH_MS && now - at > -REFRESH_MS) return "\u305F\u3063\u305F\u4ECA";
210
- return formatRelativeTime(at, { now });
64
+ function relative(at, now, locale) {
65
+ if (now - at < REFRESH_MS && now - at > -REFRESH_MS) return TEXT[uiLanguage(locale)].justNow;
66
+ return formatRelativeTime(at, { now, locale });
211
67
  }
212
- function absolute(at, timeZone) {
68
+ function absolute(at, locale, timeZone) {
213
69
  if (!Number.isFinite(at)) return void 0;
214
- const zone = new Intl.DateTimeFormat("ja-JP", { timeZone, timeZoneName: "short" }).formatToParts(at).find((part) => part.type === "timeZoneName")?.value;
215
- const text = formatDate(at, "datetime", "ja-JP", { timeZone });
70
+ const zone = new Intl.DateTimeFormat(locale, { timeZone, timeZoneName: "short" }).formatToParts(at).find((part) => part.type === "timeZoneName")?.value;
71
+ const text = formatDate(at, "datetime", locale, { timeZone });
216
72
  return zone ? `${text} ${zone}` : text;
217
73
  }
218
- function label(at, now, variant, timeZone) {
74
+ function label(at, now, variant, locale, timeZone) {
219
75
  if (!Number.isFinite(at) || !Number.isFinite(now)) return EMPTY_VALUE;
76
+ const t = TEXT[uiLanguage(locale)];
220
77
  if (variant === "relative") {
221
- return now - at < REFRESH_MS && now - at > -REFRESH_MS ? "\u305F\u3063\u305F\u4ECA" : `${relative(at, now)}\u306B\u66F4\u65B0`;
78
+ return now - at < REFRESH_MS && now - at > -REFRESH_MS ? uiLanguage(locale) === "ja" ? t.justNow : t.relative(t.justNow) : t.relative(relative(at, now, locale));
222
79
  }
223
- const today = formatDate(at, "date", "ja-JP", { timeZone }) === formatDate(now, "date", "ja-JP", { timeZone });
224
- const when = formatDate(at, "datetime", "ja-JP", { timeZone });
80
+ const today = formatDate(at, "date", locale, { timeZone }) === formatDate(now, "date", locale, { timeZone });
81
+ const when = formatDate(at, "datetime", locale, { timeZone });
225
82
  const shown = today ? when.slice(-5) : when;
226
- return `${shown} \u66F4\u65B0\uFF08${relative(at, now)}\uFF09`;
83
+ return t.absoluteFirst(shown, relative(at, now, locale));
227
84
  }
228
85
  var UpdatedAt = forwardRef(
229
86
  ({ at, variant = "relative", timeZone, prefix, now, className }, ref) => {
87
+ const locale = useLocale();
230
88
  const atMs = toMs(at);
231
89
  const [current, setCurrent] = useState(null);
232
90
  const fixed = now === void 0 ? void 0 : toMs(now);
@@ -239,9 +97,9 @@ var UpdatedAt = forwardRef(
239
97
  const clock = fixed ?? current;
240
98
  const ready = clock !== null;
241
99
  const dateTime = Number.isFinite(atMs) ? new Date(atMs).toISOString() : void 0;
242
- const full = ready ? absolute(atMs, timeZone) : void 0;
100
+ const full = ready ? absolute(atMs, locale, timeZone) : void 0;
243
101
  const classes = cn("text-sm text-muted-foreground tabular-nums", className);
244
- const text = ready ? `${prefix ?? ""}${label(atMs, clock, variant, timeZone)}` : null;
102
+ const text = ready ? `${prefix ?? ""}${label(atMs, clock, variant, locale, timeZone)}` : null;
245
103
  if (!full) {
246
104
  return /* @__PURE__ */ jsx("time", { ref, "data-slot": "updated-at", dateTime, className: classes, suppressHydrationWarning: true, children: text });
247
105
  }
@@ -272,9 +130,11 @@ var PageShell = forwardRef(
272
130
  ({ className, ...props }, ref) => /* @__PURE__ */ jsx("div", { ref, "data-slot": "page-shell", className: cn("flex flex-col", className), ...props })
273
131
  );
274
132
  PageShell.displayName = "PageShell";
133
+ var SOURCE_PREFIX = { ja: "\u51FA\u5178\uFF1A", en: "Source: " };
275
134
  var PageShellHeader = forwardRef(
276
135
  ({ className, updatedAt, updatedAtVariant, timeZone, source, period, status, children, ...props }, ref) => {
277
- const periodText = period ? formatDateRange(period.start, period.end, { timeZone }) : void 0;
136
+ const locale = useLocale();
137
+ const periodText = period ? formatDateRange(period.start, period.end, { timeZone, locale }) : void 0;
278
138
  const hasChips = Boolean(source) || periodText !== void 0 && periodText !== EMPTY_VALUE;
279
139
  const hasStatus = status !== void 0 && status !== null && status !== false && status !== "";
280
140
  return /* @__PURE__ */ jsxs(
@@ -288,11 +148,11 @@ var PageShellHeader = forwardRef(
288
148
  children,
289
149
  updatedAt !== void 0 && updatedAt !== null ? /* @__PURE__ */ jsx("div", { "data-slot": "page-shell-updated-at", className: "ml-auto max-w-full shrink-0 text-right", children: /* @__PURE__ */ jsx(UpdatedAt, { at: updatedAt, variant: updatedAtVariant, timeZone }) }) : null,
290
150
  hasChips ? /* @__PURE__ */ jsxs("div", { "data-slot": "page-shell-chips", className: "order-1 flex basis-full flex-wrap gap-1.5", children: [
291
- source ? /* @__PURE__ */ jsxs(Badge, { variant: "outline", className: "h-auto max-w-full whitespace-normal", children: [
292
- "\u51FA\u5178\uFF1A",
151
+ source ? /* @__PURE__ */ jsxs(Badge, { variant: "outline", className: "h-auto max-w-full whitespace-normal text-muted-foreground", children: [
152
+ SOURCE_PREFIX[uiLanguage(locale)],
293
153
  source
294
154
  ] }) : null,
295
- periodText && periodText !== EMPTY_VALUE ? /* @__PURE__ */ jsx(Badge, { variant: "outline", className: "tabular-nums", children: periodText }) : null
155
+ periodText && periodText !== EMPTY_VALUE ? /* @__PURE__ */ jsx(Badge, { variant: "outline", className: "tabular-nums text-muted-foreground", children: periodText }) : null
296
156
  ] }) : null,
297
157
  hasStatus ? /* @__PURE__ */ jsx("div", { "data-slot": "page-shell-status", className: "order-2 min-w-0 basis-full", children: status }) : null
298
158
  ]
@@ -389,11 +249,11 @@ var PageShellSummary = forwardRef(
389
249
  );
390
250
  PageShellSummary.displayName = "PageShellSummary";
391
251
  var summaryCardTones = {
392
- positive: "border-positive/30 bg-positive-subtle [&>svg]:text-positive",
393
- negative: "border-negative/30 bg-negative-subtle [&>svg]:text-negative",
394
- warning: "border-warning/30 bg-warning-subtle [&>svg]:text-warning",
395
- info: "border-info/30 bg-info-subtle [&>svg]:text-info",
396
- neutral: "border-neutral/30 bg-neutral-subtle [&>svg]:text-neutral",
252
+ positive: "border-positive/20 dark:border-positive/25 bg-positive-subtle [&>svg]:text-positive",
253
+ negative: "border-negative/20 dark:border-negative/25 bg-negative-subtle [&>svg]:text-negative",
254
+ warning: "border-warning/20 dark:border-warning/25 bg-warning-subtle [&>svg]:text-warning",
255
+ info: "border-info/20 dark:border-info/25 bg-info-subtle [&>svg]:text-info",
256
+ neutral: "border-neutral/20 dark:border-neutral/25 bg-neutral-subtle [&>svg]:text-neutral",
397
257
  violet: "border-chart-4/30 bg-chart-4/5 [&>svg]:text-chart-4",
398
258
  pink: "border-chart-5/30 bg-chart-5/5 [&>svg]:text-chart-5"
399
259
  };
@@ -457,6 +317,7 @@ var PageShellContent = forwardRef(
457
317
  )
458
318
  );
459
319
  PageShellContent.displayName = "PageShellContent";
320
+ var PAGE_PLACEHOLDER = { ja: "\u30DA\u30FC\u30B8\u3092\u9078\u629E", en: "Select a page" };
460
321
  function flattenItems(item) {
461
322
  if (item.children && item.children.length > 0) {
462
323
  return item.children.flatMap(flattenItems);
@@ -470,6 +331,7 @@ function NavSelect({
470
331
  const allItems = groups.flatMap((g) => g.items.flatMap(flattenItems));
471
332
  const currentValue = allItems.find((item) => item.isActive)?.href ?? "";
472
333
  const selectItems = allItems.map((item) => ({ value: item.href, label: item.label }));
334
+ const placeholder = PAGE_PLACEHOLDER[uiLanguage(useLocale())];
473
335
  return /* @__PURE__ */ jsxs(
474
336
  Select,
475
337
  {
@@ -479,7 +341,7 @@ function NavSelect({
479
341
  if (href !== null) onNavigate(href);
480
342
  },
481
343
  children: [
482
- /* @__PURE__ */ jsx(SelectTrigger, { size: "sm", className: "w-48", children: /* @__PURE__ */ jsx(SelectValue, { placeholder: "\u30DA\u30FC\u30B8\u3092\u9078\u629E" }) }),
344
+ /* @__PURE__ */ jsx(SelectTrigger, { size: "sm", className: "w-48", children: /* @__PURE__ */ jsx(SelectValue, { placeholder }) }),
483
345
  /* @__PURE__ */ jsx(
484
346
  SelectContent,
485
347
  {
@@ -652,8 +514,11 @@ var SectionHeader = forwardRef(
652
514
  )
653
515
  );
654
516
  SectionHeader.displayName = "SectionHeader";
655
- var DEFAULT_SAMPLE_LABEL = "\u898B\u672C\u306E\u5024";
656
- var SAMPLE_TITLE = "\u5B9F\u30C7\u30FC\u30BF\u306B\u307E\u3060\u3064\u306A\u304C\u3063\u3066\u3044\u306A\u3044\u898B\u672C\u306E\u5024\u3067\u3059";
517
+ var TEXT2 = {
518
+ ja: { label: "\u898B\u672C\u306E\u5024", title: "\u5B9F\u30C7\u30FC\u30BF\u306B\u307E\u3060\u3064\u306A\u304C\u3063\u3066\u3044\u306A\u3044\u898B\u672C\u306E\u5024\u3067\u3059" },
519
+ en: { label: "Sample data", title: "Sample values, not connected to real data yet" }
520
+ };
521
+ var DEFAULT_SAMPLE_LABEL = TEXT2.en.label;
657
522
  var SampleContext = createContext(null);
658
523
  function useSampleMark() {
659
524
  return useContext(SampleContext);
@@ -661,20 +526,22 @@ function useSampleMark() {
661
526
  function SampleClaim({ children }) {
662
527
  return /* @__PURE__ */ jsx(SampleContext.Provider, { value: null, children });
663
528
  }
664
- function SampleBadge({ label: label2 = DEFAULT_SAMPLE_LABEL, className, ...props }) {
529
+ function SampleBadge({ label: label2, className, ...props }) {
530
+ const t = TEXT2[uiLanguage(useLocale())];
665
531
  return /* @__PURE__ */ jsx(
666
532
  Badge,
667
533
  {
668
534
  "data-slot": "sample-badge",
669
- title: SAMPLE_TITLE,
670
- className: cn("border-warning/30 bg-warning-subtle text-warning align-middle", className),
535
+ title: t.title,
536
+ className: cn("border-warning/20 dark:border-warning/25 bg-warning-subtle text-warning align-middle", className),
671
537
  ...props,
672
- children: label2
538
+ children: label2 ?? t.label
673
539
  }
674
540
  );
675
541
  }
676
- function SampleData({ label: label2 = DEFAULT_SAMPLE_LABEL, children }) {
677
- const state = useMemo(() => ({ label: label2 }), [label2]);
542
+ function SampleData({ label: label2, children }) {
543
+ const shown = label2 ?? TEXT2[uiLanguage(useLocale())].label;
544
+ const state = useMemo(() => ({ label: shown }), [shown]);
678
545
  return /* @__PURE__ */ jsx("div", { "data-slot": "sample-data", style: { display: "contents" }, children: /* @__PURE__ */ jsx(SampleContext.Provider, { value: state, children }) });
679
546
  }
680
547
  var SUBGRID_CLASS = {
@@ -807,230 +674,11 @@ function DashboardCardPreset({
807
674
  footer && /* @__PURE__ */ jsx(DashboardCardFooter, { className: cn(subgrid === 3 && "row-start-3", footerClassName), children: footer })
808
675
  ] }) });
809
676
  }
810
- var CHART_OTHER_COLOR = "color-mix(in oklab, var(--neutral) 50%, var(--background))";
811
- var ChartFrameContext = createContext(false);
812
- var SERIES_TOKENS = ["--chart-1", "--chart-2", "--chart-3", "--chart-4", "--chart-5"];
813
- var normalizeContext;
814
- var ZRENDER_COLOR_RE = /^(?:#[0-9a-f]{6}|rgba?\()/i;
815
- function toCanvasColor(value) {
816
- const raw = value.trim();
817
- if (!raw) return null;
818
- if (normalizeContext === void 0) {
819
- const canvas = document.createElement("canvas");
820
- canvas.width = 1;
821
- canvas.height = 1;
822
- normalizeContext = canvas.getContext("2d", { willReadFrequently: true });
823
- }
824
- const ctx = normalizeContext;
825
- if (!ctx) return raw;
826
- ctx.fillStyle = "#000000";
827
- ctx.fillStyle = raw;
828
- const onBlack = ctx.fillStyle;
829
- ctx.fillStyle = "#ffffff";
830
- ctx.fillStyle = raw;
831
- if (onBlack !== ctx.fillStyle || typeof onBlack !== "string") return null;
832
- if (ZRENDER_COLOR_RE.test(onBlack)) return onBlack;
833
- ctx.clearRect(0, 0, 1, 1);
834
- ctx.fillRect(0, 0, 1, 1);
835
- const [r = 0, g = 0, b = 0, a = 0] = ctx.getImageData(0, 0, 1, 1).data;
836
- return a === 255 ? `rgb(${r}, ${g}, ${b})` : `rgba(${r}, ${g}, ${b}, ${Math.round(a / 255 * 1e3) / 1e3})`;
837
- }
838
- function readChartTokens(el) {
839
- if (typeof document === "undefined") return null;
840
- const target = document.documentElement;
841
- if (!target) return null;
842
- const styles = getComputedStyle(target);
843
- const read = (name) => toCanvasColor(styles.getPropertyValue(name));
844
- const series = [];
845
- for (const token of SERIES_TOKENS) {
846
- const color = read(token);
847
- if (color) series.push(color);
848
- }
849
- return {
850
- series,
851
- ...styles.fontFamily ? { fontFamily: styles.fontFamily } : {},
852
- foreground: read("--foreground"),
853
- mutedForeground: read("--muted-foreground"),
854
- border: read("--border"),
855
- popover: read("--popover"),
856
- popoverForeground: read("--popover-foreground")
857
- };
858
- }
859
- function sameChartTokens(a, b) {
860
- if (a === b) return true;
861
- if (!a || !b) return false;
862
- return a.series.length === b.series.length && a.series.every((color, i) => color === b.series[i]) && a.fontFamily === b.fontFamily && a.foreground === b.foreground && a.mutedForeground === b.mutedForeground && a.border === b.border && a.popover === b.popover && a.popoverForeground === b.popoverForeground;
863
- }
864
- function watchChartTokens(onChange) {
865
- if (typeof document === "undefined") return () => {
866
- };
867
- let frame = 0;
868
- const schedule = () => {
869
- if (frame) return;
870
- frame = requestAnimationFrame(() => {
871
- frame = 0;
872
- onChange();
873
- });
874
- };
875
- const themeObserver = new MutationObserver(schedule);
876
- const attributeFilter = ["class", "style", "data-theme"];
877
- themeObserver.observe(document.documentElement, { attributes: true, attributeFilter });
878
- if (document.body) themeObserver.observe(document.body, { attributes: true, attributeFilter });
879
- const styleObserver = new MutationObserver(schedule);
880
- if (document.head) {
881
- styleObserver.observe(document.head, {
882
- childList: true,
883
- subtree: true,
884
- characterData: true,
885
- attributes: true,
886
- attributeFilter: ["href", "media", "disabled"]
887
- });
888
- }
889
- const onLoad = (event) => {
890
- if (event.target instanceof HTMLLinkElement) schedule();
891
- };
892
- document.addEventListener("load", onLoad, true);
893
- const media = window.matchMedia("(prefers-color-scheme: dark)");
894
- media.addEventListener("change", schedule);
895
- return () => {
896
- if (frame) cancelAnimationFrame(frame);
897
- themeObserver.disconnect();
898
- styleObserver.disconnect();
899
- document.removeEventListener("load", onLoad, true);
900
- media.removeEventListener("change", schedule);
901
- };
902
- }
903
- function axisTheme(tokens, splitLine) {
904
- const line = tokens.border ?? void 0;
905
- return {
906
- axisLine: { show: false },
907
- axisTick: { show: false },
908
- axisLabel: { show: true, color: tokens.mutedForeground ?? void 0, fontSize: 12 },
909
- // Faint horizontal rules only: the border colour at low opacity.
910
- splitLine: { show: splitLine, lineStyle: { color: line ? [line] : void 0, opacity: 0.5, width: 1 } },
911
- splitArea: { show: false }
912
- };
913
- }
914
- function buildChartTheme(tokens) {
915
- const text = tokens.foreground ?? void 0;
916
- const muted = tokens.mutedForeground ?? void 0;
917
- const line = tokens.border ?? void 0;
918
- return {
919
- // Let the page background show through: charts sit on cards, not on a canvas.
920
- backgroundColor: "transparent",
921
- ...tokens.series.length > 0 ? { color: tokens.series } : {},
922
- textStyle: { color: text, ...tokens.fontFamily ? { fontFamily: tokens.fontFamily } : {} },
923
- title: { textStyle: { color: text }, subtextStyle: { color: muted } },
924
- legend: { textStyle: { color: muted } },
925
- categoryAxis: axisTheme(tokens, false),
926
- valueAxis: axisTheme(tokens, true),
927
- logAxis: axisTheme(tokens, true),
928
- timeAxis: axisTheme(tokens, true),
929
- tooltip: {
930
- // ECharts' default 0.4s transform lags the tooltip ~300ms behind the cursor.
931
- transitionDuration: 0,
932
- backgroundColor: tokens.popover ?? void 0,
933
- borderColor: line,
934
- borderWidth: 1,
935
- padding: [8, 12],
936
- // Rounded card with a soft shadow; in dark mode the shadow barely shows, so the border carries the edge.
937
- extraCssText: "border-radius:8px;box-shadow:var(--shadow-card, 0 4px 12px rgb(0 0 0 / 0.08));",
938
- textStyle: {
939
- color: tokens.popoverForeground ?? void 0,
940
- fontSize: 12,
941
- ...tokens.fontFamily ? { fontFamily: tokens.fontFamily } : {}
942
- },
943
- axisPointer: { lineStyle: { color: line }, crossStyle: { color: line } }
944
- }
945
- };
946
- }
947
- function useChartTokens() {
948
- const [tokens, setTokens] = useState(() => readChartTokens());
949
- const tokensRef = useRef(tokens);
950
- useEffect(() => {
951
- const sync = () => {
952
- const next = readChartTokens();
953
- if (sameChartTokens(tokensRef.current, next)) return;
954
- tokensRef.current = next;
955
- setTokens(next);
956
- };
957
- sync();
958
- return watchChartTokens(sync);
959
- }, []);
960
- return tokens;
961
- }
962
- var SERIES_TOKEN_NAME_RE = /^chart-([1-5])$/;
963
- var TONE_NAME_RE = /^(?:positive|warning|negative|neutral|info)(?:-fill)?$/;
964
- var CSS_VAR_RE = /^var\(\s*(--[\w-]+)\s*(?:,\s*(.+))?\)$/;
965
- var EMBEDDED_VAR_RE = /var\(\s*(--[\w-]+)\s*\)/g;
966
- function resolveChartColors(colors, tokens) {
967
- return colors.map((color) => {
968
- const token = SERIES_TOKEN_NAME_RE.exec(color.trim());
969
- if (token) return tokens?.series[Number(token[1]) - 1] ?? "";
970
- if (TONE_NAME_RE.test(color.trim())) {
971
- if (typeof document === "undefined") return "";
972
- return toCanvasColor(getComputedStyle(document.documentElement).getPropertyValue(`--${color.trim()}`)) ?? "";
973
- }
974
- if (typeof document === "undefined") return color;
975
- let value = color.trim();
976
- const cssVar = CSS_VAR_RE.exec(value);
977
- const styles = getComputedStyle(document.documentElement);
978
- if (cssVar) {
979
- value = styles.getPropertyValue(cssVar[1]).trim() || (cssVar[2] ?? "").trim();
980
- } else if (value.includes("var(")) {
981
- value = value.replace(EMBEDDED_VAR_RE, (_, name) => styles.getPropertyValue(name).trim());
982
- }
983
- return toCanvasColor(value) ?? "";
984
- });
985
- }
986
- function resolveFillColors(tokens) {
987
- const [positive = "", warning = "", negative = "", neutral = ""] = resolveChartColors(
988
- ["positive-fill", "warning-fill", "negative-fill", "neutral-fill"],
989
- tokens
990
- );
991
- return { positive, warning, negative, neutral };
992
- }
993
- var TRANSPARENT_RE = /^(?:transparent|rgba\([^)]*,\s*0(?:\.0+)?\))$/i;
994
- function readChartSurface(el) {
995
- if (typeof document === "undefined") return null;
996
- for (let node = el; node; node = node.parentElement) {
997
- const bg = getComputedStyle(node).backgroundColor.trim();
998
- if (bg && !TRANSPARENT_RE.test(bg)) {
999
- const color = toCanvasColor(bg);
1000
- if (color) return color;
1001
- }
1002
- }
1003
- return toCanvasColor(getComputedStyle(document.documentElement).getPropertyValue("--background"));
1004
- }
1005
- var WIDTH_BUCKET = 40;
1006
- function useChartSurface(forwarded, tokens) {
1007
- const [node, setNode] = useState(null);
1008
- const [surface, setSurface] = useState(void 0);
1009
- const [width, setWidth] = useState(void 0);
1010
- const ref = useCallback(
1011
- (el) => {
1012
- setNode(el);
1013
- if (typeof forwarded === "function") forwarded(el);
1014
- else if (forwarded) forwarded.current = el;
1015
- },
1016
- [forwarded]
1017
- );
1018
- useEffect(() => {
1019
- if (!node) return;
1020
- setSurface(readChartSurface(node) ?? void 0);
1021
- }, [node, tokens]);
1022
- useEffect(() => {
1023
- if (!node || typeof ResizeObserver === "undefined") return;
1024
- const update = (w) => setWidth(Math.floor(w / WIDTH_BUCKET) * WIDTH_BUCKET);
1025
- update(node.getBoundingClientRect().width);
1026
- const observer = new ResizeObserver((entries) => update(entries[0]?.contentRect.width ?? 0));
1027
- observer.observe(node);
1028
- return () => observer.disconnect();
1029
- }, [node]);
1030
- return { ref, surface, width };
1031
- }
1032
677
  var DEFAULT_CHART_HEIGHT = 288;
1033
- var DEFAULT_EMPTY_TITLE = "\u8868\u793A\u3067\u304D\u308B\u30C7\u30FC\u30BF\u304C\u3042\u308A\u307E\u305B\u3093";
678
+ var TEXT3 = {
679
+ ja: { emptyTitle: "\u8868\u793A\u3067\u304D\u308B\u30C7\u30FC\u30BF\u304C\u3042\u308A\u307E\u305B\u3093", loading: "\u8AAD\u307F\u8FBC\u307F\u4E2D" },
680
+ en: { emptyTitle: "No data to display", loading: "Loading" }
681
+ };
1034
682
  var ChartFrame = forwardRef(function ChartFrame2({
1035
683
  title,
1036
684
  summary,
@@ -1047,6 +695,7 @@ var ChartFrame = forwardRef(function ChartFrame2({
1047
695
  ...props
1048
696
  }, ref) {
1049
697
  const id = useId();
698
+ const t = TEXT3[uiLanguage(useLocale())];
1050
699
  const titleId = title ? `${id}-title` : void 0;
1051
700
  const summaryId = summary ? `${id}-summary` : void 0;
1052
701
  const state = isLoading ? "loading" : isEmpty ? "empty" : "ready";
@@ -1068,7 +717,7 @@ var ChartFrame = forwardRef(function ChartFrame2({
1068
717
  "aria-busy": isLoading || void 0,
1069
718
  className: "relative w-full min-w-0",
1070
719
  style: { height: typeof height === "number" ? `${height}px` : height },
1071
- children: state === "loading" ? /* @__PURE__ */ jsx(ChartSkeleton, { variant }) : state === "empty" ? /* @__PURE__ */ jsx(ChartEmpty, { ...emptyState }) : /* @__PURE__ */ jsx(ChartFrameContext.Provider, { value: true, children })
720
+ children: state === "loading" ? /* @__PURE__ */ jsx(ChartSkeleton, { variant, loadingText: t.loading }) : state === "empty" ? /* @__PURE__ */ jsx(ChartEmpty, { ...emptyState, defaultTitle: t.emptyTitle }) : /* @__PURE__ */ jsx(ChartFrameContext.Provider, { value: true, children })
1072
721
  }
1073
722
  ),
1074
723
  state === "ready" && dataTable && dataTable.rows.length > 0 && /* @__PURE__ */ jsx(ChartDataTableView, { table: dataTable, fallbackCaption: title ?? ariaLabel })
@@ -1078,14 +727,14 @@ ChartFrame.displayName = "ChartFrame";
1078
727
  var BAR_HEIGHTS = [58, 74, 46, 88, 64, 80, 52];
1079
728
  var LIST_WIDTHS = [92, 76, 64, 48, 36];
1080
729
  var LINE_POINTS = "0,70 16,58 33,62 50,40 66,46 83,28 100,34";
1081
- function ChartSkeleton({ variant }) {
730
+ function ChartSkeleton({ variant, loadingText }) {
1082
731
  const pulse = "animate-pulse motion-reduce:animate-none";
1083
732
  return /* @__PURE__ */ jsxs("div", { "data-slot": "chart-skeleton", "data-variant": variant, className: "absolute inset-0 flex flex-col gap-3", children: [
1084
733
  /* @__PURE__ */ jsx("div", { "aria-hidden": "true", className: "contents", children: variant === "list" ? /* @__PURE__ */ jsx("div", { className: cn("flex flex-1 flex-col justify-around", pulse), children: LIST_WIDTHS.map((w) => /* @__PURE__ */ jsx("div", { className: "flex items-center gap-3", children: /* @__PURE__ */ jsx("div", { className: "h-5 rounded-sm bg-muted", style: { width: `${w}%` } }) }, w)) }) : variant === "donut" ? /* @__PURE__ */ jsx("div", { className: cn("flex flex-1 items-center justify-center", pulse), children: /* @__PURE__ */ jsx("svg", { viewBox: "0 0 100 100", className: "h-full max-h-full w-auto text-muted", children: /* @__PURE__ */ jsx("circle", { cx: "50", cy: "50", r: "40", fill: "none", stroke: "currentColor", strokeWidth: "14" }) }) }) : variant === "bar" ? /* @__PURE__ */ jsx("div", { className: cn("flex flex-1 items-end gap-3 px-1", pulse), children: BAR_HEIGHTS.map((h, i) => /* @__PURE__ */ jsx("div", { className: "flex-1 rounded-t-sm bg-muted", style: { height: `${h}%` } }, i)) }) : (
1085
734
  // A soft muted silhouette only — no stroke, no baseline, nothing that reads as a data line.
1086
735
  /* @__PURE__ */ jsx("div", { className: cn("relative flex-1", pulse), children: /* @__PURE__ */ jsx("svg", { viewBox: "0 0 100 100", preserveAspectRatio: "none", className: "absolute inset-0 h-full w-full text-muted", children: /* @__PURE__ */ jsx("polygon", { points: `${LINE_POINTS} 100,100 0,100`, fill: "currentColor", opacity: variant === "area" ? 0.8 : 0.5 }) }) })
1087
736
  ) }),
1088
- /* @__PURE__ */ jsx("span", { className: "sr-only", children: "\u8AAD\u307F\u8FBC\u307F\u4E2D" })
737
+ /* @__PURE__ */ jsx("span", { className: "sr-only", children: loadingText })
1089
738
  ] });
1090
739
  }
1091
740
  function ChartDataTableView({ table, fallbackCaption }) {
@@ -1098,370 +747,20 @@ function ChartDataTableView({ table, fallbackCaption }) {
1098
747
  ) }, r)) })
1099
748
  ] }) });
1100
749
  }
1101
- function ChartEmpty({ title, description, action }) {
750
+ function ChartEmpty({ title, description, action, defaultTitle }) {
1102
751
  return /* @__PURE__ */ jsxs(
1103
752
  "div",
1104
753
  {
1105
754
  "data-slot": "chart-empty",
1106
755
  className: "absolute inset-0 flex flex-col items-center justify-center gap-1 rounded-md border border-dashed border-border p-6 text-center",
1107
756
  children: [
1108
- /* @__PURE__ */ jsx("p", { className: "text-sm font-medium text-balance", children: title ?? DEFAULT_EMPTY_TITLE }),
757
+ /* @__PURE__ */ jsx("p", { className: "text-sm font-medium text-balance", children: title ?? defaultTitle }),
1109
758
  description && /* @__PURE__ */ jsx("p", { className: "max-w-prose text-sm text-balance text-muted-foreground", children: description }),
1110
759
  action && /* @__PURE__ */ jsx("div", { className: "mt-3", children: action })
1111
760
  ]
1112
761
  }
1113
762
  );
1114
763
  }
1115
- use([
1116
- BarChart,
1117
- CustomChart,
1118
- LineChart,
1119
- PieChart,
1120
- GridComponent,
1121
- LegendComponent,
1122
- MarkAreaComponent,
1123
- MarkLineComponent,
1124
- MarkPointComponent,
1125
- TooltipComponent,
1126
- CanvasRenderer
1127
- ]);
1128
- var HEADER_PAD_X = 16;
1129
- var HEADER_PAD_TOP = 16;
1130
- var HEADER_PAD_BOTTOM = 12;
1131
- var HEADER_LINE_HEIGHT = 20;
1132
- var HEADER_GAP = 4;
1133
- var HEADER_FONT_SIZE = 14;
1134
- function wrapChartText(text, maxWidth, measure) {
1135
- const lines = [];
1136
- let line = "";
1137
- for (const ch of text) {
1138
- if (ch === "\n") {
1139
- lines.push(line);
1140
- line = "";
1141
- continue;
1142
- }
1143
- if (line !== "" && measure(line + ch) > maxWidth) {
1144
- lines.push(line);
1145
- line = ch.trim() === "" ? "" : ch;
1146
- } else {
1147
- line += ch;
1148
- }
1149
- }
1150
- if (line !== "" || lines.length === 0) lines.push(line);
1151
- return lines.filter((l, i) => l !== "" || i < lines.length - 1);
1152
- }
1153
- function chartExportHeaderLayout(header, width, measure) {
1154
- const title = header?.title?.trim();
1155
- const summary = header?.summary?.trim();
1156
- if (!title && !summary) return { lines: [], height: 0 };
1157
- const room = Math.max(40, width - HEADER_PAD_X * 2);
1158
- const lines = [
1159
- ...title ? wrapChartText(title, room, (t) => measure(t, "title")).map((text) => ({ text, kind: "title" })) : [],
1160
- ...summary ? wrapChartText(summary, room, (t) => measure(t, "summary")).map((text) => ({ text, kind: "summary" })) : []
1161
- ];
1162
- const gap = title && summary ? HEADER_GAP : 0;
1163
- return { lines, height: HEADER_PAD_TOP + lines.length * HEADER_LINE_HEIGHT + gap + HEADER_PAD_BOTTOM };
1164
- }
1165
- function loadImage(src) {
1166
- return new Promise((resolve, reject) => {
1167
- const image = new Image();
1168
- image.onload = () => resolve(image);
1169
- image.onerror = () => reject(new Error("PNG \u306E\u8AAD\u307F\u8FBC\u307F\u306B\u5931\u6557\u3057\u307E\u3057\u305F"));
1170
- image.src = src;
1171
- });
1172
- }
1173
- async function pngWithHeader(dataUrl, header, look, pixelRatio) {
1174
- const image = await loadImage(dataUrl);
1175
- const width = image.width / pixelRatio;
1176
- const plotHeight = image.height / pixelRatio;
1177
- const canvas = document.createElement("canvas");
1178
- const ctx = canvas.getContext("2d");
1179
- if (!ctx) return dataUrl;
1180
- const font = (kind) => `${kind === "title" ? 500 : 400} ${HEADER_FONT_SIZE}px ${look.fontFamily}`;
1181
- ctx.font = font("title");
1182
- const layout = chartExportHeaderLayout(header, width, (text, kind) => {
1183
- ctx.font = font(kind);
1184
- return ctx.measureText(text).width;
1185
- });
1186
- if (layout.height === 0) return dataUrl;
1187
- canvas.width = Math.round(image.width);
1188
- canvas.height = Math.round((layout.height + plotHeight) * pixelRatio);
1189
- ctx.scale(pixelRatio, pixelRatio);
1190
- ctx.fillStyle = look.background;
1191
- ctx.fillRect(0, 0, width, layout.height + plotHeight);
1192
- ctx.textBaseline = "middle";
1193
- let y = HEADER_PAD_TOP;
1194
- let previous = null;
1195
- for (const line of layout.lines) {
1196
- if (previous === "title" && line.kind === "summary") y += HEADER_GAP;
1197
- ctx.font = font(line.kind);
1198
- ctx.fillStyle = line.kind === "title" ? look.color : look.mutedColor;
1199
- ctx.fillText(line.text, HEADER_PAD_X, y + HEADER_LINE_HEIGHT / 2);
1200
- y += HEADER_LINE_HEIGHT;
1201
- previous = line.kind;
1202
- }
1203
- ctx.drawImage(image, 0, layout.height, width, plotHeight);
1204
- return canvas.toDataURL("image/png");
1205
- }
1206
- function useResolvedChartColors(colors) {
1207
- const tokens = useChartTokens();
1208
- const key = colors.join("\0");
1209
- return useMemo(() => resolveChartColors(colors, tokens), [key, tokens]);
1210
- }
1211
- var COMPONENT_MAIN_TYPES = /* @__PURE__ */ new Set([
1212
- "title",
1213
- "legend",
1214
- "grid",
1215
- "xAxis",
1216
- "yAxis",
1217
- "polar",
1218
- "radiusAxis",
1219
- "angleAxis",
1220
- "radar",
1221
- "dataZoom",
1222
- "visualMap",
1223
- "tooltip",
1224
- "axisPointer",
1225
- "toolbox",
1226
- "brush",
1227
- "geo",
1228
- "parallel",
1229
- "parallelAxis",
1230
- "singleAxis",
1231
- "graphic",
1232
- "calendar",
1233
- "dataset",
1234
- "series",
1235
- "matrix",
1236
- "thumbnail"
1237
- ]);
1238
- function echartSetOptionOpts(prev, next) {
1239
- const special = (o) => "timeline" in o || "baseOption" in o || "options" in o || "media" in o;
1240
- if (!prev || special(prev) || special(next)) return { notMerge: true, lazyUpdate: true };
1241
- const types = /* @__PURE__ */ new Set();
1242
- for (const key of [...Object.keys(prev), ...Object.keys(next)]) if (COMPONENT_MAIN_TYPES.has(key)) types.add(key);
1243
- return { notMerge: false, replaceMerge: [...types], lazyUpdate: true };
1244
- }
1245
- function withGraphicFont(option, fontFamily) {
1246
- const graphic = option.graphic;
1247
- if (!fontFamily || !Array.isArray(graphic)) return option;
1248
- return {
1249
- ...option,
1250
- graphic: graphic.map(
1251
- (g) => g && g.type === "text" && g.style && !g.style.fontFamily ? { ...g, style: { ...g.style, fontFamily } } : g
1252
- )
1253
- };
1254
- }
1255
- function withMotionPreference(option, reducedMotion) {
1256
- return { ...option, animation: reducedMotion ? false : option.animation ?? true };
1257
- }
1258
- var REDUCED_MOTION_QUERY = "(prefers-reduced-motion: reduce)";
1259
- function usePrefersReducedMotion() {
1260
- const [reduced, setReduced] = useState(
1261
- () => typeof window !== "undefined" && typeof window.matchMedia === "function" && window.matchMedia(REDUCED_MOTION_QUERY).matches
1262
- );
1263
- useEffect(() => {
1264
- if (typeof window === "undefined" || typeof window.matchMedia !== "function") return;
1265
- const media = window.matchMedia(REDUCED_MOTION_QUERY);
1266
- const sync = () => setReduced(media.matches);
1267
- sync();
1268
- media.addEventListener("change", sync);
1269
- return () => media.removeEventListener("change", sync);
1270
- }, []);
1271
- return reduced;
1272
- }
1273
- var EChart = forwardRef(function EChart2({
1274
- option,
1275
- height,
1276
- loading = false,
1277
- theme,
1278
- onEvents,
1279
- ariaLabel,
1280
- className,
1281
- actions = false,
1282
- fileName = "chart.png",
1283
- exportHeader
1284
- }, ref) {
1285
- const containerRef = useRef(null);
1286
- const [instance, setInstance] = useState(null);
1287
- const [copied, setCopied] = useState(false);
1288
- const [tokens, setTokens] = useState(() => readChartTokens());
1289
- const reducedMotion = usePrefersReducedMotion();
1290
- const appliedRef = useRef(null);
1291
- const tokensRef = useRef(tokens);
1292
- useEffect(() => {
1293
- if (theme !== void 0) return;
1294
- const sync = () => {
1295
- const base = readChartTokens();
1296
- const font = containerRef.current ? getComputedStyle(containerRef.current).fontFamily : "";
1297
- const next = base && font ? { ...base, fontFamily: font } : base;
1298
- if (sameChartTokens(tokensRef.current, next)) return;
1299
- tokensRef.current = next;
1300
- setTokens(next);
1301
- };
1302
- sync();
1303
- const stop = watchChartTokens(sync);
1304
- const ancestors = new MutationObserver(sync);
1305
- for (let node = containerRef.current?.parentElement; node; node = node.parentElement) {
1306
- ancestors.observe(node, { attributes: true, attributeFilter: ["class", "style"] });
1307
- }
1308
- return () => {
1309
- stop();
1310
- ancestors.disconnect();
1311
- };
1312
- }, [theme]);
1313
- const autoTheme = useMemo(() => tokens ? buildChartTheme(tokens) : void 0, [tokens]);
1314
- const resolvedTheme = theme ?? autoTheme;
1315
- useEffect(() => {
1316
- const container = containerRef.current;
1317
- if (!container) return;
1318
- const inst = init(container, resolvedTheme, { renderer: "canvas" });
1319
- appliedRef.current = null;
1320
- container.dataset.rendering = "";
1321
- inst.on("finished", () => {
1322
- delete container.dataset.rendering;
1323
- });
1324
- setInstance(inst);
1325
- let frame = 0;
1326
- const observer = new ResizeObserver(() => {
1327
- cancelAnimationFrame(frame);
1328
- frame = requestAnimationFrame(() => {
1329
- if (!inst.isDisposed()) inst.resize();
1330
- });
1331
- });
1332
- observer.observe(container);
1333
- return () => {
1334
- observer.disconnect();
1335
- cancelAnimationFrame(frame);
1336
- inst.dispose();
1337
- };
1338
- }, [resolvedTheme]);
1339
- useEffect(() => {
1340
- if (!instance) return;
1341
- if (containerRef.current) containerRef.current.dataset.rendering = "";
1342
- const next = withGraphicFont(withMotionPreference(option, reducedMotion), theme === void 0 ? tokens?.fontFamily : void 0);
1343
- instance.setOption(next, echartSetOptionOpts(appliedRef.current, next));
1344
- appliedRef.current = next;
1345
- }, [instance, option, reducedMotion, theme, tokens?.fontFamily]);
1346
- useEffect(() => {
1347
- if (!instance) return;
1348
- if (loading) instance.showLoading();
1349
- else instance.hideLoading();
1350
- }, [instance, loading]);
1351
- useEffect(() => {
1352
- if (!instance || !onEvents) return;
1353
- const entries = Object.entries(onEvents);
1354
- for (const [event, handler] of entries) {
1355
- instance.on(event, handler);
1356
- }
1357
- return () => {
1358
- if (instance.isDisposed()) return;
1359
- for (const [event, handler] of entries) {
1360
- instance.off(event, handler);
1361
- }
1362
- };
1363
- }, [instance, onEvents]);
1364
- const includeTitle = typeof actions === "object" ? actions.includeTitle ?? true : true;
1365
- const getPngDataUrl = useCallback(async () => {
1366
- if (!instance) return null;
1367
- let backgroundColor = "#ffffff";
1368
- for (let el = containerRef.current; el; el = el.parentElement) {
1369
- const bg = getComputedStyle(el).backgroundColor;
1370
- if (bg && bg !== "rgba(0, 0, 0, 0)" && bg !== "transparent") {
1371
- backgroundColor = bg;
1372
- break;
1373
- }
1374
- }
1375
- const pixelRatio = 2;
1376
- const dataUrl = instance.getDataURL({ type: "png", pixelRatio, backgroundColor });
1377
- if (!includeTitle || !exportHeader || !(exportHeader.title || exportHeader.summary) || !containerRef.current) return dataUrl;
1378
- try {
1379
- const style = getComputedStyle(containerRef.current);
1380
- return await pngWithHeader(
1381
- dataUrl,
1382
- exportHeader,
1383
- { background: backgroundColor, color: style.color, mutedColor: tokens?.mutedForeground ?? style.color, fontFamily: style.fontFamily },
1384
- pixelRatio
1385
- );
1386
- } catch {
1387
- return dataUrl;
1388
- }
1389
- }, [instance, includeTitle, exportHeader, tokens]);
1390
- const handleCopy = useCallback(async () => {
1391
- const dataUrl = await getPngDataUrl();
1392
- if (!dataUrl) return;
1393
- try {
1394
- const blob = await (await fetch(dataUrl)).blob();
1395
- await navigator.clipboard.write([new ClipboardItem({ "image/png": blob })]);
1396
- setCopied(true);
1397
- setTimeout(() => setCopied(false), 2e3);
1398
- } catch {
1399
- }
1400
- }, [getPngDataUrl]);
1401
- const handleDownload = useCallback(async () => {
1402
- const dataUrl = await getPngDataUrl();
1403
- if (!dataUrl) return;
1404
- const link = document.createElement("a");
1405
- link.href = dataUrl;
1406
- link.download = fileName;
1407
- link.click();
1408
- }, [getPngDataUrl, fileName]);
1409
- const inFrame = useContext(ChartFrameContext);
1410
- const styleHeight = height == null ? void 0 : typeof height === "number" ? `${height}px` : height;
1411
- return /* @__PURE__ */ jsxs(
1412
- "div",
1413
- {
1414
- ref,
1415
- "data-slot": "echart",
1416
- className: cn("group relative w-full", height == null && "h-[400px]", className),
1417
- style: styleHeight != null ? { height: styleHeight } : void 0,
1418
- children: [
1419
- /* @__PURE__ */ jsx(
1420
- "div",
1421
- {
1422
- ref: containerRef,
1423
- "data-slot": "echart-canvas",
1424
- className: "h-full w-full",
1425
- role: inFrame ? void 0 : "img",
1426
- "aria-label": inFrame ? void 0 : ariaLabel ?? "\u30C1\u30E3\u30FC\u30C8"
1427
- }
1428
- ),
1429
- actions && /* @__PURE__ */ jsxs(
1430
- "div",
1431
- {
1432
- "data-slot": "echart-actions",
1433
- className: "absolute top-2 right-2 z-10 flex gap-1 pointer-events-none opacity-0 transition-opacity group-hover:pointer-events-auto group-hover:opacity-100 focus-within:pointer-events-auto focus-within:opacity-100 [@media(hover:none)]:pointer-events-auto [@media(hover:none)]:opacity-100",
1434
- children: [
1435
- /* @__PURE__ */ jsx(
1436
- Button,
1437
- {
1438
- type: "button",
1439
- variant: "ghost",
1440
- size: "icon-sm",
1441
- onClick: handleCopy,
1442
- "aria-label": copied ? "\u30B3\u30D4\u30FC\u3057\u307E\u3057\u305F" : "PNG \u3092\u30AF\u30EA\u30C3\u30D7\u30DC\u30FC\u30C9\u306B\u30B3\u30D4\u30FC",
1443
- children: copied ? /* @__PURE__ */ jsx(Check, { className: "size-4" }) : /* @__PURE__ */ jsx(Copy, { className: "size-4" })
1444
- }
1445
- ),
1446
- /* @__PURE__ */ jsx(
1447
- Button,
1448
- {
1449
- type: "button",
1450
- variant: "ghost",
1451
- size: "icon-sm",
1452
- onClick: handleDownload,
1453
- "aria-label": "PNG \u3092\u30C0\u30A6\u30F3\u30ED\u30FC\u30C9",
1454
- children: /* @__PURE__ */ jsx(Download, { className: "size-4" })
1455
- }
1456
- )
1457
- ]
1458
- }
1459
- )
1460
- ]
1461
- }
1462
- );
1463
- });
1464
- EChart.displayName = "EChart";
1465
764
 
1466
765
  // ../squadkit/registry/lib/chart-utils.ts
1467
766
  var ROOT_PROP_KEYS = /* @__PURE__ */ new Set(["id", "style", "role", "tabIndex", "lang", "hidden"]);
@@ -1504,37 +803,63 @@ function chartColorAt(colors, i) {
1504
803
  function tintCss(cssColor, percent) {
1505
804
  return `color-mix(in oklab, ${cssColor} ${percent}%, transparent)`;
1506
805
  }
1507
- function resolveValueFormatter(valueFormatter, format2, locale) {
1508
- return valueFormatter ?? toValueFormatter(format2, locale);
806
+ function resolveValueFormatter(valueFormatter, format, locale) {
807
+ return valueFormatter ?? toValueFormatter(format, locale);
1509
808
  }
1510
- function resolveAxisFormatter(valueFormatter, format2, locale = DEFAULT_LOCALE) {
809
+ function resolveAxisFormatter(valueFormatter, format, localeArg) {
1511
810
  if (valueFormatter) return valueFormatter;
1512
- const spec = format2 === void 0 ? { type: "compact" } : typeof format2 === "string" ? { type: format2 } : format2;
1513
- if (spec.type !== "compact" && spec.type !== "number" && spec.type !== "currency") return toValueFormatter(format2, locale);
811
+ const locale = resolveLocale(localeArg);
812
+ const spec = format === void 0 ? { type: "compact" } : typeof format === "string" ? { type: format } : format;
813
+ if (spec.type !== "compact" && spec.type !== "number" && spec.type !== "currency") return toValueFormatter(format, locale);
1514
814
  const currency = "currency" in spec ? spec.currency : void 0;
1515
815
  const short = spec.type === "currency" ? { type: "currency", currency, notation: "compact" } : { type: "compact" };
1516
816
  return (value) => formatValue(value, short, locale);
1517
817
  }
1518
- var JA_UNITS = [
1519
- { char: "\u5146", size: 1e12 },
1520
- { char: "\u5104", size: 1e8 },
1521
- { char: "\u4E07", size: 1e4 }
1522
- ];
1523
- var JA_NUMBER_TOKEN_RE = /\d[\d,]*(?:\.\d+)?(?:兆|億|万)?/;
1524
- function resolveAxisTickFormatter(valueFormatter, format2, locale = DEFAULT_LOCALE) {
1525
- const base = resolveAxisFormatter(valueFormatter, format2, locale);
1526
- const spec = format2 === void 0 ? { type: "compact" } : typeof format2 === "string" ? { type: format2 } : format2;
1527
- const aligns = !valueFormatter && locale.toLowerCase().startsWith("ja") && (spec.type === "compact" || spec.type === "number" || spec.type === "currency");
1528
- if (!aligns) return () => base;
818
+ var compactUnitCache = /* @__PURE__ */ new Map();
819
+ function compactUnits(locale) {
820
+ const cached = compactUnitCache.get(locale);
821
+ if (cached !== void 0) return cached;
822
+ let units = [];
823
+ try {
824
+ const compact = new Intl.NumberFormat(locale, { notation: "compact" });
825
+ const seen = /* @__PURE__ */ new Set();
826
+ for (let exp = 3; exp <= 15; exp++) {
827
+ const parts = compact.formatToParts(10 ** exp);
828
+ const at = parts.findIndex((p) => p.type === "compact");
829
+ if (at === -1) continue;
830
+ if (parts[at - 1]?.type !== "integer" || at !== parts.length - 1) {
831
+ units = null;
832
+ break;
833
+ }
834
+ const token = parts[at].value;
835
+ if (seen.has(token)) continue;
836
+ seen.add(token);
837
+ units.push({ token, size: 10 ** exp });
838
+ }
839
+ } catch {
840
+ units = null;
841
+ }
842
+ const sorted = units && units.length > 0 ? units.sort((a, b) => b.size - a.size) : null;
843
+ compactUnitCache.set(locale, sorted);
844
+ return sorted;
845
+ }
846
+ var escapeRegExp = (text) => text.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
847
+ function resolveAxisTickFormatter(valueFormatter, format, localeArg) {
848
+ const locale = resolveLocale(localeArg);
849
+ const base = resolveAxisFormatter(valueFormatter, format, locale);
850
+ const spec = format === void 0 ? { type: "compact" } : typeof format === "string" ? { type: format } : format;
851
+ const units = !valueFormatter && (spec.type === "compact" || spec.type === "number" || spec.type === "currency") ? compactUnits(locale) : null;
852
+ if (!units) return () => base;
1529
853
  const number = new Intl.NumberFormat(locale, { maximumFractionDigits: 3 });
854
+ const numberToken = new RegExp(`\\d[\\d,]*(?:\\.\\d+)?(?:${units.map((u) => escapeRegExp(u.token)).join("|")})?`);
1530
855
  return (top) => {
1531
- const unit = JA_UNITS.find((u) => Math.abs(top) >= u.size);
856
+ const unit = units.find((u) => Math.abs(top) >= u.size);
1532
857
  if (!unit) return base;
1533
858
  return (value) => {
1534
859
  const text = base(value);
1535
860
  if (value === 0 || !Number.isFinite(value)) return text;
1536
- const scaled = `${number.format(Math.abs(value) / unit.size)}${unit.char}`;
1537
- return text.replace(JA_NUMBER_TOKEN_RE, () => scaled);
861
+ const scaled = `${number.format(Math.abs(value) / unit.size)}${unit.token}`;
862
+ return text.replace(numberToken, () => scaled);
1538
863
  };
1539
864
  };
1540
865
  }
@@ -1551,8 +876,15 @@ function clamp(value, min, max) {
1551
876
  return Math.min(max, Math.max(min, value));
1552
877
  }
1553
878
  var MAX_CHART_SERIES = 5;
1554
- var OTHER_SERIES_LABEL = "\u305D\u306E\u4ED6";
1555
- function aggregateTopN(items, n = MAX_CHART_SERIES, otherLabel = OTHER_SERIES_LABEL) {
879
+ var OTHER_SERIES_LABELS = { ja: "\u305D\u306E\u4ED6", en: "Other" };
880
+ function otherSeriesLabel(locale) {
881
+ return OTHER_SERIES_LABELS[uiLanguage(resolveLocale(locale))];
882
+ }
883
+ var OTHER_NAMES = new Set(Object.values(OTHER_SERIES_LABELS));
884
+ function isOtherName(name) {
885
+ return typeof name === "string" && OTHER_NAMES.has(name);
886
+ }
887
+ function aggregateTopN(items, n = MAX_CHART_SERIES, otherLabel = otherSeriesLabel()) {
1556
888
  if (items.length <= n) return { top: [...items], rest: [], other: null };
1557
889
  const ranked = items.map((item, i) => ({ item, i })).sort((a, b) => b.item.value - a.item.value || a.i - b.i);
1558
890
  const keep = new Set(ranked.slice(0, n).map((r) => r.i));
@@ -1560,7 +892,7 @@ function aggregateTopN(items, n = MAX_CHART_SERIES, otherLabel = OTHER_SERIES_LA
1560
892
  const rest = items.filter((_, i) => !keep.has(i));
1561
893
  return { top, rest, other: { name: otherLabel, value: rest.reduce((sum, item) => sum + item.value, 0) } };
1562
894
  }
1563
- function aggregateSeries(data, categories, n = MAX_CHART_SERIES, otherLabel = OTHER_SERIES_LABEL) {
895
+ function aggregateSeries(data, categories, n = MAX_CHART_SERIES, otherLabel = otherSeriesLabel()) {
1564
896
  const totals = categories.map((name) => ({
1565
897
  name,
1566
898
  value: data.reduce((sum, row) => sum + (toChartNumber(row[name]) ?? 0), 0)
@@ -1581,12 +913,13 @@ function aggregateSeries(data, categories, n = MAX_CHART_SERIES, otherLabel = OT
1581
913
  otherCategory: other.name
1582
914
  };
1583
915
  }
1584
- function aggregateSeriesKeeping(data, categories, keep, n = MAX_CHART_SERIES) {
1585
- if (keep === void 0 || !categories.includes(keep)) return aggregateSeries(data, categories, n);
916
+ function aggregateSeriesKeeping(data, categories, keep, n = MAX_CHART_SERIES, otherLabel = otherSeriesLabel()) {
917
+ if (keep === void 0 || !categories.includes(keep)) return aggregateSeries(data, categories, n, otherLabel);
1586
918
  const aggregated = aggregateSeries(
1587
919
  data,
1588
920
  categories.filter((c) => c !== keep),
1589
- n
921
+ n,
922
+ otherLabel
1590
923
  );
1591
924
  return { ...aggregated, categories: [...aggregated.categories, keep] };
1592
925
  }
@@ -1608,7 +941,7 @@ function seriesColorsFor(categories, colors, otherColor, otherCategory = null, a
1608
941
  const list = Array.isArray(colors) ? colors : void 0;
1609
942
  const record = !Array.isArray(colors) && colors ? colors : void 0;
1610
943
  return categories.map((category, i) => {
1611
- if (otherCategory !== null && category === otherCategory || category === OTHER_SERIES_LABEL) return otherColor;
944
+ if (otherCategory !== null && category === otherCategory || isOtherName(category)) return otherColor;
1612
945
  const fromRecord = record?.[category];
1613
946
  if (fromRecord) return fromRecord;
1614
947
  if (list && list.length > 0) {
@@ -1618,7 +951,7 @@ function seriesColorsFor(categories, colors, otherColor, otherCategory = null, a
1618
951
  return DEFAULT_CHART_COLORS[i % DEFAULT_CHART_COLORS.length];
1619
952
  });
1620
953
  }
1621
- function donutSlices(data, { index, value, colors, maxSlices = MAX_CHART_SERIES, otherColor, otherLabel = OTHER_SERIES_LABEL }) {
954
+ function donutSlices(data, { index, value, colors, maxSlices = MAX_CHART_SERIES, otherColor, otherLabel = otherSeriesLabel() }) {
1622
955
  const items = data.map((row, i) => {
1623
956
  const n = toChartNumber(row[value]);
1624
957
  return { name: String(row[index] ?? ""), value: n !== null && n > 0 ? n : 0, row, i };
@@ -1628,7 +961,8 @@ function donutSlices(data, { index, value, colors, maxSlices = MAX_CHART_SERIES,
1628
961
  const slices = top.map((item, rank) => ({
1629
962
  name: item.name,
1630
963
  value: item.value,
1631
- color: palette[rank % palette.length],
964
+ // A row the data itself names「その他」/ "Other" is the same remainder: grey, like the folded slice.
965
+ color: isOtherName(item.name) ? otherColor : palette[rank % palette.length],
1632
966
  isOther: false,
1633
967
  row: item.row
1634
968
  }));
@@ -1649,7 +983,7 @@ function sortBarListData(data, sortOrder) {
1649
983
  else if (sortOrder === "descending") rows.sort((a, b) => b.value - a.value);
1650
984
  return rows;
1651
985
  }
1652
- function barListRows(data, { index = "name", category = "value", sortOrder = "descending", maxItems = MAX_CHART_SERIES, otherLabel = OTHER_SERIES_LABEL, exclude } = {}) {
986
+ function barListRows(data, { index = "name", category = "value", sortOrder = "descending", maxItems = MAX_CHART_SERIES, otherLabel = otherSeriesLabel(), exclude } = {}) {
1653
987
  const items = data.map((row) => {
1654
988
  const cells = row;
1655
989
  const name = String(cells[index] ?? "");
@@ -1683,7 +1017,7 @@ var BAR_LIST_TINT = 45;
1683
1017
  var BAR_LIST_OTHER_TINT = 30;
1684
1018
  function barListFills(rows, color, otherColor) {
1685
1019
  return rows.map(
1686
- (row) => row.isOther ? tintCss(otherColor, BAR_LIST_OTHER_TINT) : tintCss(chartColorToCss(row.color ?? color), BAR_LIST_TINT)
1020
+ (row) => row.isOther || isOtherName(row.name) ? tintCss(otherColor, BAR_LIST_OTHER_TINT) : tintCss(chartColorToCss(row.color ?? color), BAR_LIST_TINT)
1687
1021
  );
1688
1022
  }
1689
1023
  function barListShareText(value, total) {
@@ -1780,6 +1114,22 @@ function progressCircleGeometry(value, max, radius, strokeWidth) {
1780
1114
  const circumference = 2 * Math.PI * normalizedRadius;
1781
1115
  return { size: radius * 2, normalizedRadius, circumference, offset: circumference * (1 - ratio), ratio };
1782
1116
  }
1117
+ var SUMMARY_TEXT = {
1118
+ ja: {
1119
+ up: "\u3001\u524D\u306E\u70B9\u3088\u308A\u5897\u52A0",
1120
+ down: "\u3001\u524D\u306E\u70B9\u3088\u308A\u6E1B\u5C11",
1121
+ flat: "\u3001\u524D\u306E\u70B9\u3068\u6A2A\u3070\u3044",
1122
+ latest: (label2, value) => `\u6700\u65B0 ${label2} \u306F ${value}`,
1123
+ top: (name, share) => `\u6700\u5927\u306F ${name}(${share})`
1124
+ },
1125
+ en: {
1126
+ up: ", up from the previous point",
1127
+ down: ", down from the previous point",
1128
+ flat: ", flat from the previous point",
1129
+ latest: (label2, value) => `Latest ${label2}: ${value}`,
1130
+ top: (name, share) => `Largest: ${name} (${share})`
1131
+ }
1132
+ };
1783
1133
  function buildChartSummary(input) {
1784
1134
  const key = input.categories[0];
1785
1135
  if (key === void 0) return void 0;
@@ -1791,54 +1141,96 @@ function buildChartSummary(input) {
1791
1141
  }
1792
1142
  const latest = points[points.length - 1];
1793
1143
  if (!latest) return void 0;
1794
- const text = input.valueFormatter ?? toValueFormatter(input.format ?? "compact");
1144
+ const locale = resolveLocale(input.locale);
1145
+ const t = SUMMARY_TEXT[uiLanguage(locale)];
1146
+ const text = input.valueFormatter ?? toValueFormatter(input.format ?? "compact", locale);
1795
1147
  const prev = points[points.length - 2];
1796
- const direction = !prev ? "" : latest.value > prev.value ? "\u3001\u524D\u306E\u70B9\u3088\u308A\u5897\u52A0" : latest.value < prev.value ? "\u3001\u524D\u306E\u70B9\u3088\u308A\u6E1B\u5C11" : "\u3001\u524D\u306E\u70B9\u3068\u6A2A\u3070\u3044";
1148
+ const direction = !prev ? "" : latest.value > prev.value ? t.up : latest.value < prev.value ? t.down : t.flat;
1797
1149
  const head = input.title ? `${input.title}: ` : "";
1798
- return `${head}\u6700\u65B0 ${latest.label} \u306F ${text(latest.value)}${direction}`;
1150
+ return `${head}${t.latest(latest.label, text(latest.value))}${direction}`;
1799
1151
  }
1800
- function buildShareSummary(slices, title) {
1152
+ function buildShareSummary(slices, title, locale) {
1801
1153
  const total = slices.reduce((sum, s) => sum + s.value, 0);
1802
1154
  const top = slices[0];
1803
1155
  if (!top || total <= 0) return void 0;
1804
1156
  const share = `${Math.round(top.value / total * 1e3) / 10}%`;
1805
- return `${title ? `${title}: ` : ""}\u6700\u5927\u306F ${top.name}(${share})`;
1157
+ return `${title ? `${title}: ` : ""}${SUMMARY_TEXT[uiLanguage(resolveLocale(locale))].top(top.name, share)}`;
1806
1158
  }
1807
1159
 
1808
1160
  // ../squadkit/registry/lib/comparison.ts
1809
1161
  var COMPARISON_LABELS = {
1810
- "prior-period": "\u524D\u671F\u6BD4",
1811
- "prior-year": "\u524D\u5E74\u540C\u671F\u6BD4",
1812
- target: "\u76EE\u6A19\u6BD4"
1162
+ "prior-period": "vs. prior period",
1163
+ "prior-year": "vs. same period last year",
1164
+ target: "vs. target"
1813
1165
  };
1814
1166
  var BASELINE_NOUNS = {
1815
- "prior-period": {
1816
- day: "\u524D\u65E5",
1817
- week: "\u524D\u9031",
1818
- month: "\u524D\u6708",
1819
- quarter: "\u524D\u56DB\u534A\u671F",
1820
- year: "\u524D\u5E74",
1821
- unknown: "\u524D\u671F"
1167
+ ja: {
1168
+ "prior-period": {
1169
+ day: "\u524D\u65E5",
1170
+ week: "\u524D\u9031",
1171
+ month: "\u524D\u6708",
1172
+ quarter: "\u524D\u56DB\u534A\u671F",
1173
+ year: "\u524D\u5E74",
1174
+ unknown: "\u524D\u671F"
1175
+ },
1176
+ "prior-year": {
1177
+ day: "\u524D\u5E74\u540C\u65E5",
1178
+ week: "\u524D\u5E74\u540C\u9031",
1179
+ month: "\u524D\u5E74\u540C\u6708",
1180
+ quarter: "\u524D\u5E74\u540C\u671F",
1181
+ year: "\u524D\u5E74",
1182
+ unknown: "\u524D\u5E74\u540C\u671F"
1183
+ },
1184
+ target: "\u76EE\u6A19",
1185
+ custom: "\u6BD4\u8F03\u5BFE\u8C61"
1822
1186
  },
1823
- "prior-year": {
1824
- day: "\u524D\u5E74\u540C\u65E5",
1825
- week: "\u524D\u5E74\u540C\u9031",
1826
- month: "\u524D\u5E74\u540C\u6708",
1827
- quarter: "\u524D\u5E74\u540C\u671F",
1828
- year: "\u524D\u5E74",
1829
- unknown: "\u524D\u5E74\u540C\u671F"
1187
+ en: {
1188
+ "prior-period": {
1189
+ day: "prior day",
1190
+ week: "prior week",
1191
+ month: "prior month",
1192
+ quarter: "prior quarter",
1193
+ year: "prior year",
1194
+ unknown: "prior period"
1195
+ },
1196
+ "prior-year": {
1197
+ day: "same day last year",
1198
+ week: "same week last year",
1199
+ month: "same month last year",
1200
+ quarter: "same quarter last year",
1201
+ year: "prior year",
1202
+ unknown: "same period last year"
1203
+ },
1204
+ target: "target",
1205
+ custom: "baseline"
1830
1206
  }
1831
1207
  };
1832
- function comparisonBaseline(vs, grain, label2, toDate2) {
1208
+ var LABEL_OF = {
1209
+ ja: (baseline) => `${baseline}\u6BD4`,
1210
+ en: (baseline) => `vs. ${baseline}`
1211
+ };
1212
+ function baselineOfLabel(named, language) {
1213
+ if (named.length > 1 && named.endsWith("\u6BD4")) return named.slice(0, -1);
1214
+ if (language === "en") {
1215
+ const stripped = named.replace(/^vs\.?\s+/i, "");
1216
+ if (stripped) return stripped;
1217
+ }
1218
+ return named;
1219
+ }
1220
+ function comparisonBaseline(vs, grain, label2, toDate2, locale) {
1221
+ const language = uiLanguage(resolveLocale(locale));
1222
+ const nouns = BASELINE_NOUNS[language];
1833
1223
  const named = label2?.trim();
1834
- if (named) return named.length > 1 && named.endsWith("\u6BD4") ? named.slice(0, -1) : named;
1835
- if (vs === "custom") return "\u6BD4\u8F03\u5BFE\u8C61";
1836
- if (vs === "target") return "\u76EE\u6A19";
1837
- if (vs === "prior-year" && toDate2) return BASELINE_NOUNS["prior-year"].unknown;
1838
- return BASELINE_NOUNS[vs][grain ?? "unknown"];
1224
+ if (named) return baselineOfLabel(named, language);
1225
+ if (vs === "custom") return nouns.custom;
1226
+ if (vs === "target") return nouns.target;
1227
+ if (vs === "prior-year" && toDate2) return nouns["prior-year"].unknown;
1228
+ return nouns[vs][grain ?? "unknown"];
1839
1229
  }
1840
- function comparisonLabel(vs, grain, label2, toDate2) {
1841
- return label2?.trim() ? label2 : `${comparisonBaseline(vs, grain, void 0, toDate2)}\u6BD4`;
1230
+ function comparisonLabel(vs, grain, label2, toDate2, locale) {
1231
+ if (label2?.trim()) return label2;
1232
+ const resolved = resolveLocale(locale);
1233
+ return LABEL_OF[uiLanguage(resolved)](comparisonBaseline(vs, grain, void 0, toDate2, resolved));
1842
1234
  }
1843
1235
  var toNumber = (v) => v === null || v === void 0 || Number.isNaN(v) ? null : v;
1844
1236
  function computeComparison(current, comparison, options) {
@@ -1846,7 +1238,7 @@ function computeComparison(current, comparison, options) {
1846
1238
  const neutralBand = options?.neutralBand ?? 0.01;
1847
1239
  const cur = toNumber(current);
1848
1240
  const prev = toNumber(comparison.previous);
1849
- const label2 = comparisonLabel(comparison.vs, comparison.grain, comparison.label, comparison.toDate);
1241
+ const label2 = comparisonLabel(comparison.vs, comparison.grain, comparison.label, comparison.toDate, options?.locale);
1850
1242
  const difference = cur !== null && prev !== null ? cur - prev : null;
1851
1243
  const ratio = difference !== null && prev !== null && prev !== 0 ? difference / Math.abs(prev) : null;
1852
1244
  let direction;
@@ -1859,20 +1251,20 @@ function computeComparison(current, comparison, options) {
1859
1251
  else if (direction === "down") sentiment = polarity === "higher-is-better" ? "negative" : "positive";
1860
1252
  return { current: cur, previous: prev, difference, ratio, direction, sentiment, label: label2, vs: comparison.vs };
1861
1253
  }
1862
- function defaultChangeDisplay(format2) {
1863
- return formatKind(format2) === "percent" ? "points" : "relative";
1254
+ function defaultChangeDisplay(format) {
1255
+ return formatKind(format) === "percent" ? "points" : "relative";
1864
1256
  }
1865
- function formatChange(result, display = "relative", locale = DEFAULT_LOCALE, format2, digits) {
1257
+ function formatChange(result, display = "relative", locale, format, digits) {
1866
1258
  if (result.direction === "none") return null;
1867
- if (display === "difference") return result.difference === null ? null : formatDelta(result.difference, format2, locale);
1259
+ if (display === "difference") return result.difference === null ? null : formatDelta(result.difference, format, locale);
1868
1260
  if (display === "points")
1869
1261
  return result.difference === null ? null : formatPoints(result.difference, locale, digits === void 0 ? void 0 : { digits });
1870
1262
  return result.ratio === null ? null : formatDelta(result.ratio, digits === void 0 ? "percent" : { type: "percent", digits }, locale);
1871
1263
  }
1872
- function formatChangeAmount(result, display = "relative", locale = DEFAULT_LOCALE, format2, digits) {
1264
+ function formatChangeAmount(result, display = "relative", locale, format, digits) {
1873
1265
  if (result.direction === "none") return null;
1874
1266
  if (display === "difference")
1875
- return result.difference === null ? null : formatValue(Math.abs(result.difference), format2, locale);
1267
+ return result.difference === null ? null : formatValue(Math.abs(result.difference), format, locale);
1876
1268
  if (display === "points")
1877
1269
  return result.difference === null ? null : formatPoints(result.difference, locale, { signDisplay: "never", ...digits === void 0 ? {} : { digits } });
1878
1270
  return result.ratio === null ? null : formatValue(Math.abs(result.ratio), digits === void 0 ? "percent" : { type: "percent", digits }, locale);
@@ -1891,6 +1283,29 @@ function toneForValue(value, thresholds) {
1891
1283
  }
1892
1284
 
1893
1285
  // ../squadkit/registry/lib/chart-options.ts
1286
+ var CHART_TEXT = {
1287
+ ja: {
1288
+ target: "\u76EE\u6A19",
1289
+ forecast: "\u4E88\u6E2C",
1290
+ total: "\u5408\u8A08",
1291
+ provisional: "\u901F\u5831",
1292
+ noComparison: "\u6BD4\u8F03\u306A\u3057",
1293
+ share: (share) => `\uFF08${share}\uFF09`,
1294
+ targetRate: (rate) => `\uFF08\u9054\u6210\u7387 ${rate}\uFF09`,
1295
+ provisionalTitle: (title, label2) => `${title}(${label2})`
1296
+ },
1297
+ en: {
1298
+ target: "Target",
1299
+ forecast: "Forecast",
1300
+ total: "Total",
1301
+ provisional: "Preliminary",
1302
+ noComparison: "No comparison",
1303
+ share: (share) => ` (${share})`,
1304
+ targetRate: (rate) => ` (${rate} achieved)`,
1305
+ provisionalTitle: (title, label2) => `${title} (${label2})`
1306
+ }
1307
+ };
1308
+ var chartText = (locale) => CHART_TEXT[uiLanguage(resolveLocale(locale))];
1894
1309
  function chartMotion(reducedMotion) {
1895
1310
  if (reducedMotion) return { animation: false };
1896
1311
  return { animation: true, animationDuration: 0, animationDurationUpdate: 300, animationEasingUpdate: "cubicOut" };
@@ -1955,12 +1370,12 @@ function parseTimeIndex(values) {
1955
1370
  var timeFormatCache = /* @__PURE__ */ new Map();
1956
1371
  function timeFormat(locale, options) {
1957
1372
  const key = `${locale}|${JSON.stringify(options)}`;
1958
- let format2 = timeFormatCache.get(key);
1959
- if (!format2) {
1960
- format2 = new Intl.DateTimeFormat(locale, options);
1961
- timeFormatCache.set(key, format2);
1373
+ let format = timeFormatCache.get(key);
1374
+ if (!format) {
1375
+ format = new Intl.DateTimeFormat(locale, options);
1376
+ timeFormatCache.set(key, format);
1962
1377
  }
1963
- return format2;
1378
+ return format;
1964
1379
  }
1965
1380
  var toDate = (t) => new Date(t.year, t.month - 1, t.day);
1966
1381
  var TIME_AXIS_MAX_LABELS = 6;
@@ -1979,9 +1394,10 @@ function timeAxisLabelStep(values, maxLabels = TIME_AXIS_MAX_LABELS) {
1979
1394
  const steps = TIME_AXIS_STEPS[parsed.granularity];
1980
1395
  return steps.find((step) => Math.ceil(count / step) <= max) ?? Math.ceil(count / max);
1981
1396
  }
1982
- function timeAxisLabels(values, locale = DEFAULT_LOCALE, shown = () => true) {
1397
+ function timeAxisLabels(values, localeArg, shown = () => true) {
1983
1398
  const parsed = parseTimeIndex(values);
1984
1399
  if (!parsed) return null;
1400
+ const locale = resolveLocale(localeArg);
1985
1401
  const { granularity, times } = parsed;
1986
1402
  let prevYear = null;
1987
1403
  return times.map((t, i) => {
@@ -1993,9 +1409,10 @@ function timeAxisLabels(values, locale = DEFAULT_LOCALE, shown = () => true) {
1993
1409
  return timeFormat(locale, options).format(toDate(t));
1994
1410
  });
1995
1411
  }
1996
- function timeTooltipLabels(values, locale = DEFAULT_LOCALE) {
1412
+ function timeTooltipLabels(values, localeArg) {
1997
1413
  const parsed = parseTimeIndex(values);
1998
1414
  if (!parsed) return null;
1415
+ const locale = resolveLocale(localeArg);
1999
1416
  const options = parsed.granularity === "year" ? { year: "numeric" } : parsed.granularity === "month" ? { year: "numeric", month: "long" } : { year: "numeric", month: "long", day: "numeric" };
2000
1417
  return parsed.times.map((t, i) => t === null ? String(values[i] ?? "") : timeFormat(locale, options).format(toDate(t)));
2001
1418
  }
@@ -2072,16 +1489,16 @@ function escapeHtml(value) {
2072
1489
  }
2073
1490
  var shareFormat = new Intl.NumberFormat(DEFAULT_LOCALE, { maximumFractionDigits: 1 });
2074
1491
  var formatShare = (share) => `${shareFormat.format(share)}%`;
2075
- function tooltipHtml(title, rows, valueFormatter, notes = []) {
1492
+ function tooltipHtml(title, rows, valueFormatter, notes = [], locale) {
1493
+ const t = chartText(locale);
2076
1494
  const lines = rows.map(
2077
- (row) => `<div style="display:flex;align-items:center;gap:8px;line-height:20px"><span style="display:inline-block;width:8px;height:8px;border-radius:9999px;background:${escapeHtml(row.color)}"></span><span style="flex:1;opacity:.8">${escapeHtml(row.name)}</span><span style="font-weight:600;font-variant-numeric:tabular-nums;margin-left:12px">${row.value === null ? EMPTY_VALUE : escapeHtml(valueFormatter(row.value))}${row.share === void 0 ? "" : `<span style="opacity:.6;margin-left:4px">\uFF08${escapeHtml(formatShare(row.share))}\uFF09</span>`}</span></div>` + (row.note === void 0 ? "" : `<div style="padding-left:16px;line-height:18px;font-size:12px;opacity:.7;font-variant-numeric:tabular-nums">${escapeHtml(row.note)}</div>`)
1495
+ (row) => `<div style="display:flex;align-items:center;gap:8px;line-height:20px"><span style="display:inline-block;width:8px;height:8px;border-radius:9999px;background:${escapeHtml(row.color)}"></span><span style="flex:1;opacity:.8">${escapeHtml(row.name)}</span><span style="font-weight:600;font-variant-numeric:tabular-nums;margin-left:12px">${row.value === null ? EMPTY_VALUE : escapeHtml(valueFormatter(row.value))}${row.share === void 0 ? "" : `<span style="opacity:.6;margin-left:4px">${escapeHtml(t.share(formatShare(row.share)))}</span>`}</span></div>` + (row.note === void 0 ? "" : `<div style="padding-left:16px;line-height:18px;font-size:12px;opacity:.7;font-variant-numeric:tabular-nums">${escapeHtml(row.note)}</div>`)
2078
1496
  );
2079
1497
  const noteLines = notes.map(
2080
1498
  (note) => `<div style="margin-top:4px;line-height:18px;font-size:12px;opacity:.7">${escapeHtml(note)}</div>`
2081
1499
  );
2082
1500
  return `<div style="font-weight:500;margin-bottom:4px">${escapeHtml(title)}</div>${lines.join("")}${noteLines.join("")}`;
2083
1501
  }
2084
- var BAR_TARGET_LABEL = "\u76EE\u6A19";
2085
1502
  var TARGET_MARKER_OVERHANG = 4;
2086
1503
  function targetMarkerRenderer(horizontalBars, barCategoryGap, color) {
2087
1504
  return (_params, api) => {
@@ -2107,10 +1524,10 @@ function achievementRate(value, target) {
2107
1524
  if (value === null || value === void 0 || target === null || target === void 0 || !(target > 0)) return null;
2108
1525
  return value / target * 100;
2109
1526
  }
2110
- function barTargetNote(label2, value, target, valueFormatter) {
1527
+ function barTargetNote(label2, value, target, valueFormatter, locale) {
2111
1528
  if (target === null) return null;
2112
1529
  const rate = achievementRate(value, target);
2113
- return `${label2} ${valueFormatter(target)}${rate === null ? "" : `\uFF08\u9054\u6210\u7387 ${formatShare(rate)}\uFF09`}`;
1530
+ return `${label2} ${valueFormatter(target)}${rate === null ? "" : chartText(locale).targetRate(formatShare(rate))}`;
2114
1531
  }
2115
1532
  function barHalfWidth(barCategoryGap) {
2116
1533
  const gap = typeof barCategoryGap === "string" && /^\d+(\.\d+)?%$/.test(barCategoryGap.trim()) ? parseFloat(barCategoryGap) / 100 : 0.2;
@@ -2158,9 +1575,8 @@ var OVERLAY_SERIES_ID = "__overlay";
2158
1575
  var TARGET_MARKER_SERIES_ID = "__target-marker";
2159
1576
  var TARGET_LEGEND_SERIES_ID = "__target-legend";
2160
1577
  var TARGET_LEGEND_ICON = "path://M0,0 L100,0 L100,24 L0,24 Z";
2161
- var DEFAULT_FORECAST_LABEL = "\u4E88\u6E2C";
2162
- function forecastBoundaryText(label2 = DEFAULT_FORECAST_LABEL) {
2163
- return `${label2} \u2192`;
1578
+ function forecastBoundaryText(label2, locale) {
1579
+ return `${label2 ?? chartText(locale).forecast} \u2192`;
2164
1580
  }
2165
1581
  var COMPARISON_LINE_WIDTH = 1.5;
2166
1582
  var COMPARISON_OPACITY = 0.6;
@@ -2186,7 +1602,6 @@ function isDarkSurface(color) {
2186
1602
  });
2187
1603
  return 0.2126 * r + 0.7152 * g + 0.0722 * b < 0.4;
2188
1604
  }
2189
- var STACK_TOTAL_LABEL = "\u5408\u8A08";
2190
1605
  function stackTotalsOf(values) {
2191
1606
  const length = Math.max(0, ...values.map((v) => v.length));
2192
1607
  return Array.from({ length }, (_, i) => {
@@ -2252,13 +1667,15 @@ function indexGrain(values) {
2252
1667
  const parsed = parseTimeIndex(values);
2253
1668
  return parsed ? parsed.granularity : null;
2254
1669
  }
2255
- function comparisonNote(current, previous, comparison, grain, format2, locale = DEFAULT_LOCALE) {
1670
+ function comparisonNote(current, previous, comparison, grain, format, localeArg) {
1671
+ const locale = resolveLocale(localeArg);
2256
1672
  const result = computeComparison(
2257
1673
  current,
2258
- comparison.vs === "custom" ? { previous, vs: "custom", label: comparison.label ?? "", grain } : { previous, vs: comparison.vs, label: comparison.label, grain }
1674
+ comparison.vs === "custom" ? { previous, vs: "custom", label: comparison.label ?? "", grain } : { previous, vs: comparison.vs, label: comparison.label, grain },
1675
+ { locale }
2259
1676
  );
2260
- const text = formatChange(result, defaultChangeDisplay(format2), locale, format2);
2261
- if (text === null) return `\u6BD4\u8F03\u306A\u3057 ${result.label}`;
1677
+ const text = formatChange(result, defaultChangeDisplay(format), locale, format);
1678
+ if (text === null) return `${chartText(locale).noComparison} ${result.label}`;
2262
1679
  const arrow = result.direction === "up" ? "\u2191" : result.direction === "down" ? "\u2193" : "\u2192";
2263
1680
  return `${arrow} ${text.replace(/^-/, "\u2212")} ${result.label}`;
2264
1681
  }
@@ -2283,7 +1700,6 @@ function buildCartesianOption(cfg) {
2283
1700
  toneColors,
2284
1701
  valueFormatter,
2285
1702
  axisFormatter = valueFormatter,
2286
- locale = DEFAULT_LOCALE,
2287
1703
  type = "default",
2288
1704
  layout = "horizontal",
2289
1705
  curveType = "linear",
@@ -2320,7 +1736,9 @@ function buildCartesianOption(cfg) {
2320
1736
  chartOptions,
2321
1737
  reserveActions = false
2322
1738
  } = cfg;
2323
- const provisionalLabel = cfg.provisionalLabel ?? DEFAULT_PROVISIONAL_LABEL;
1739
+ const locale = resolveLocale(cfg.locale);
1740
+ const text = chartText(locale);
1741
+ const provisionalLabel = cfg.provisionalLabel ?? text.provisional;
2324
1742
  const stacked = kind !== "line" && type !== "default";
2325
1743
  const percent = kind !== "line" && type === "percent";
2326
1744
  const horizontalBars = kind === "bar" && layout === "vertical";
@@ -2391,8 +1809,8 @@ function buildCartesianOption(cfg) {
2391
1809
  const edgeAlign = (i) => horizontalBars || labels.length < 2 ? void 0 : i === boundaryIndex && i !== last ? { align: "right", offset: [-6, 0] } : i === last ? { align: "right", ...kind === "bar" ? { offset: [8, 0] } : {} } : i === 0 ? { align: "left", ...kind === "bar" ? { offset: [-8, 0] } : {} } : void 0;
2392
1810
  const perBarTarget = kind === "bar" && Boolean(targetKey);
2393
1811
  const hasTarget = !perBarTarget && target !== void 0 && Number.isFinite(target);
2394
- const targetText = hasTarget ? targetLabel ?? `\u76EE\u6A19 ${axisFormatter(target)}` : "";
2395
- const highlightText = (value) => shareHighlight ? `${Math.round(value)}%` : `${stackTotals ? `${STACK_TOTAL_LABEL} ` : ""}${axisFormatter(value)}`;
1812
+ const targetText = hasTarget ? targetLabel ?? `${text.target} ${axisFormatter(target)}` : "";
1813
+ const highlightText = (value) => shareHighlight ? `${Math.round(value)}%` : `${stackTotals ? `${text.total} ` : ""}${axisFormatter(value)}`;
2396
1814
  const nearTargetLabel = (p, side) => {
2397
1815
  if (!hasTarget || !plotWidth || kind === "bar" || labels.length < 2) return false;
2398
1816
  if (side === "under" ? p.value > target : p.value <= target) return false;
@@ -2409,7 +1827,7 @@ function buildCartesianOption(cfg) {
2409
1827
  const below = (p) => !shareHighlight && !hideTargetLabel && nearTargetLabel(p, "under");
2410
1828
  const targetLabelBelow = !shareHighlight && !hideTargetLabel && highlightPoints.some((p) => nearTargetLabel(p, "over"));
2411
1829
  const barTargets = perBarTarget && targetKey && !percent && (stacked || categories.length === 1) ? barTargetValues(data, targetKey) : null;
2412
- const barTargetName = targetLabel ?? BAR_TARGET_LABEL;
1830
+ const barTargetName = targetLabel ?? text.target;
2413
1831
  const barTargetColor = labelColor ?? guideColor;
2414
1832
  const markPointFor = (c, color) => c === highlightSeries && highlightPoints.length > 0 ? {
2415
1833
  silent: true,
@@ -2588,7 +2006,7 @@ function buildCartesianOption(cfg) {
2588
2006
  data: []
2589
2007
  });
2590
2008
  }
2591
- const forecastLabel = forecast?.label ?? DEFAULT_FORECAST_LABEL;
2009
+ const forecastLabel = forecast?.label ?? text.forecast;
2592
2010
  const forecastBandAlpha = isDarkSurface(labelBackground) ? FORECAST_BAND_ALPHA_DARK : FORECAST_BAND_ALPHA_LIGHT;
2593
2011
  const forecastValues = [];
2594
2012
  if (forecast) {
@@ -2865,8 +2283,8 @@ function buildCartesianOption(cfg) {
2865
2283
  const top = percent ? 100 : maxValue ?? Math.max(0, ...(stacked ? stackTotalsOf(values) : values.flat()).map((v) => v ?? 0));
2866
2284
  const categoryColumn = showYAxis ? (yAxisWidth ?? Math.min(160, Math.max(0, ...labels.map(estimateTextWidth)))) + 8 : 0;
2867
2285
  const plot = plotWidth - categoryColumn - (highlightPoints.length > 0 ? 64 : 16) - 4;
2868
- const text = percent ? (v) => `${v}%` : (v) => axisFormatter(v);
2869
- return valueAxisSplitNumber(plot, [text(0), text(top)]);
2286
+ const text2 = percent ? (v) => `${v}%` : (v) => axisFormatter(v);
2287
+ return valueAxisSplitNumber(plot, [text2(0), text2(top)]);
2870
2288
  })();
2871
2289
  const limits = valueAxisLimits({ minValue, maxValue }, kind !== "line");
2872
2290
  const splitNumber = horizontalBars ? valueSplitNumber : valueAxisSplitCount(plotHeight);
@@ -3004,7 +2422,7 @@ function buildCartesianOption(cfg) {
3004
2422
  });
3005
2423
  }
3006
2424
  if (stackTotals && i <= lastActual && rows.length > 1) {
3007
- rows.push({ name: STACK_TOTAL_LABEL, color: "transparent", value: stackTotals[i] ?? null });
2425
+ rows.push({ name: text.total, color: "transparent", value: stackTotals[i] ?? null });
3008
2426
  }
3009
2427
  const provisional = provStart !== -1 && i >= provStart && i <= lastActual;
3010
2428
  if (provisional) {
@@ -3019,19 +2437,19 @@ function buildCartesianOption(cfg) {
3019
2437
  ...noteFor(at)
3020
2438
  });
3021
2439
  });
3022
- if (stackTotals && rows.length > 1) rows.push({ name: STACK_TOTAL_LABEL, color: "transparent", value: stackTotals[i] ?? null });
2440
+ if (stackTotals && rows.length > 1) rows.push({ name: text.total, color: "transparent", value: stackTotals[i] ?? null });
3023
2441
  }
3024
2442
  const title = tooltipTitles[i] ?? labels[i] ?? "";
3025
2443
  const lines = [];
3026
2444
  if (barTargets && i <= lastActual) {
3027
2445
  const total = stackTotals ? stackTotals[i] ?? null : values[0]?.[i] ?? null;
3028
- const note = barTargetNote(barTargetName, total, barTargets[i] ?? null, valueFormatter);
2446
+ const note = barTargetNote(barTargetName, total, barTargets[i] ?? null, valueFormatter, locale);
3029
2447
  if (note) lines.push(note);
3030
2448
  }
3031
2449
  for (const note of notes) {
3032
2450
  if (note.to === void 0 ? note.from === i : note.from <= i && i <= note.to) lines.push(note.label);
3033
2451
  }
3034
- return tooltipHtml(provisional ? `${title}(${provisionalLabel})` : title, rows, valueFormatter, lines);
2452
+ return tooltipHtml(provisional ? text.provisionalTitle(title, provisionalLabel) : title, rows, valueFormatter, lines, locale);
3035
2453
  }
3036
2454
  },
3037
2455
  xAxis: horizontalBars ? valueAxis : categoryAxis,
@@ -3060,7 +2478,6 @@ function donutTopText(slices, labels) {
3060
2478
  return top ? { label: labelOf(top.name, labels), amount: donutShareText(top.value, total) } : null;
3061
2479
  }
3062
2480
  var DONUT_OUTSIDE_LABELS = 2;
3063
- var DEFAULT_TOTAL_LABEL = "\u5408\u8A08";
3064
2481
  var sliceValue = (value) => Number.isFinite(value) && value > 0 ? value : 0;
3065
2482
  function donutShareText(value, total) {
3066
2483
  const v = sliceValue(value);
@@ -3072,7 +2489,8 @@ function donutLegendItems(slices) {
3072
2489
  const total = slices.reduce((sum, s) => sum + sliceValue(s.value), 0);
3073
2490
  return slices.map((s, slice) => ({ name: s.name, value: sliceValue(s.value), share: donutShareText(s.value, total), isOther: Boolean(s.isOther), slice })).sort((a, b) => Number(a.isOther) - Number(b.isOther) || b.value - a.value || a.slice - b.slice);
3074
2491
  }
3075
- function donutCenterText(total, valueFormatter, { totalLabel = DEFAULT_TOTAL_LABEL, unit } = {}) {
2492
+ function donutCenterText(total, valueFormatter, { totalLabel, unit, locale } = {}) {
2493
+ totalLabel ??= chartText(locale).total;
3076
2494
  const amount = valueFormatter(total);
3077
2495
  return { label: totalLabel, value: unit ? `${amount} ${unit}` : amount, amount, ...unit ? { unit } : {} };
3078
2496
  }
@@ -3192,7 +2610,6 @@ function labelRows(data, index, labels) {
3192
2610
  function hasLabel(labels, key) {
3193
2611
  return Boolean(labels) && Object.prototype.hasOwnProperty.call(labels, key);
3194
2612
  }
3195
- var DEFAULT_PROVISIONAL_LABEL = "\u901F\u5831";
3196
2613
  function provisionalStart(indexValues, from) {
3197
2614
  if (from === void 0 || from === null) return -1;
3198
2615
  const key = String(from);
@@ -3205,6 +2622,10 @@ function splitProvisional(values, start) {
3205
2622
  provisional: values.map((v, i) => i >= Math.max(0, start - 1) ? v : null)
3206
2623
  };
3207
2624
  }
2625
+ var TEXT4 = {
2626
+ ja: { item: "\u9805\u76EE", chart: (categories) => `${categories.join("\u30FB")}\u306E\u9762\u30B0\u30E9\u30D5` },
2627
+ en: { item: "Item", chart: (categories) => `Area chart of ${categories.join(", ")}` }
2628
+ };
3208
2629
  var NO_ROWS = [];
3209
2630
  function AreaChartImpl({
3210
2631
  data = NO_ROWS,
@@ -3213,7 +2634,7 @@ function AreaChartImpl({
3213
2634
  colors,
3214
2635
  labels,
3215
2636
  valueFormatter,
3216
- format: format2,
2637
+ format,
3217
2638
  title,
3218
2639
  summary,
3219
2640
  actions,
@@ -3252,14 +2673,18 @@ function AreaChartImpl({
3252
2673
  className,
3253
2674
  ...rest
3254
2675
  }, ref) {
3255
- const tokens = useChartTokens();
3256
- const { ref: frameRef, surface, width: plotWidth } = useChartSurface(ref, tokens);
3257
- const tooltipFormatter = useMemo(() => resolveValueFormatter(valueFormatter, format2), [valueFormatter, format2]);
3258
- const axisFormatter = useMemo(() => resolveAxisFormatter(valueFormatter, format2), [valueFormatter, format2]);
3259
- const axisTicks = useMemo(() => resolveAxisTickFormatter(valueFormatter, format2), [valueFormatter, format2]);
2676
+ const { ref: frameRef, surface, width: plotWidth, tokens } = useChartSurface(ref);
2677
+ const locale = useLocale();
2678
+ const t = TEXT4[uiLanguage(locale)];
2679
+ const tooltipFormatter = useMemo(() => resolveValueFormatter(valueFormatter, format, locale), [valueFormatter, format, locale]);
2680
+ const axisFormatter = useMemo(() => resolveAxisFormatter(valueFormatter, format, locale), [valueFormatter, format, locale]);
2681
+ const axisTicks = useMemo(() => resolveAxisTickFormatter(valueFormatter, format, locale), [valueFormatter, format, locale]);
3260
2682
  const comparisonCategory = comparison && categories.includes(comparison.category) ? comparison.category : void 0;
3261
2683
  const comparisonConfig = comparisonCategory === void 0 ? void 0 : comparison;
3262
- const series = useMemo(() => aggregateSeriesKeeping(data, categories, comparisonCategory), [data, categories, comparisonCategory]);
2684
+ const series = useMemo(
2685
+ () => aggregateSeriesKeeping(data, categories, comparisonCategory, void 0, otherSeriesLabel(locale)),
2686
+ [data, categories, comparisonCategory, locale]
2687
+ );
3263
2688
  const palette = useMemo(
3264
2689
  () => resolveChartColors(
3265
2690
  seriesColorsWithComparison(series.categories, colors, CHART_OTHER_COLOR, series.otherCategory, categories, comparisonCategory),
@@ -3306,7 +2731,7 @@ function AreaChartImpl({
3306
2731
  annotations,
3307
2732
  forecast,
3308
2733
  comparison: comparisonConfig,
3309
- comparisonFormat: format2,
2734
+ comparisonFormat: format,
3310
2735
  provisionalFrom,
3311
2736
  provisionalLabel,
3312
2737
  reserveActions: Boolean(actions),
@@ -3315,7 +2740,8 @@ function AreaChartImpl({
3315
2740
  labelColor: tokens?.foreground ?? void 0,
3316
2741
  plotWidth,
3317
2742
  plotHeight: typeof height === "number" ? height : void 0,
3318
- chartOptions
2743
+ chartOptions,
2744
+ locale
3319
2745
  }),
3320
2746
  [
3321
2747
  series,
@@ -3351,23 +2777,24 @@ function AreaChartImpl({
3351
2777
  annotations,
3352
2778
  forecast,
3353
2779
  comparisonConfig,
3354
- format2,
2780
+ format,
3355
2781
  height,
3356
2782
  tokens,
3357
2783
  surface,
3358
2784
  plotWidth,
3359
- chartOptions
2785
+ chartOptions,
2786
+ locale
3360
2787
  ]
3361
2788
  );
3362
2789
  const dataTable = useMemo(() => {
3363
- const table = chartDataTable(labelRows(series.data, index, labels), index, series.categories, tooltipFormatter, labels, "\u9805\u76EE");
3364
- const times = timeTooltipLabels(series.data.map((row) => row[index]));
2790
+ const table = chartDataTable(labelRows(series.data, index, labels), index, series.categories, tooltipFormatter, labels, t.item);
2791
+ const times = timeTooltipLabels(series.data.map((row) => row[index]), locale);
3365
2792
  return times ? { ...table, rows: table.rows.map((row, i) => [times[i] ?? row[0] ?? "", ...row.slice(1)]) } : table;
3366
- }, [series, index, tooltipFormatter, labels]);
3367
- const label2 = ariaLabel ?? `${categories.join("\u30FB")}\u306E\u9762\u30B0\u30E9\u30D5`;
2793
+ }, [series, index, tooltipFormatter, labels, t, locale]);
2794
+ const label2 = ariaLabel ?? t.chart(categories);
3368
2795
  const resolvedSummary = useMemo(
3369
- () => summary === "auto" ? buildChartSummary({ data, index, categories, title, format: format2, valueFormatter }) : summary,
3370
- [summary, data, index, categories, title, format2, valueFormatter]
2796
+ () => summary === "auto" ? buildChartSummary({ data, index, categories, title, format, valueFormatter, locale }) : summary,
2797
+ [summary, data, index, categories, title, format, valueFormatter, locale]
3371
2798
  );
3372
2799
  return /* @__PURE__ */ jsx(
3373
2800
  ChartFrame,
@@ -3390,6 +2817,10 @@ function AreaChartImpl({
3390
2817
  }
3391
2818
  var AreaChart = forwardRef(AreaChartImpl);
3392
2819
  AreaChart.displayName = "AreaChart";
2820
+ var TEXT5 = {
2821
+ ja: { item: "\u9805\u76EE", chart: (categories) => `${categories.join("\u30FB")}\u306E\u68D2\u30B0\u30E9\u30D5` },
2822
+ en: { item: "Item", chart: (categories) => `Bar chart of ${categories.join(", ")}` }
2823
+ };
3393
2824
  var NO_ROWS2 = [];
3394
2825
  function BarChartImpl({
3395
2826
  data = NO_ROWS2,
@@ -3398,7 +2829,7 @@ function BarChartImpl({
3398
2829
  colors,
3399
2830
  labels,
3400
2831
  valueFormatter,
3401
- format: format2,
2832
+ format,
3402
2833
  title,
3403
2834
  summary,
3404
2835
  actions,
@@ -3435,12 +2866,13 @@ function BarChartImpl({
3435
2866
  className,
3436
2867
  ...rest
3437
2868
  }, ref) {
3438
- const tokens = useChartTokens();
3439
- const { ref: frameRef, surface, width: plotWidth } = useChartSurface(ref, tokens);
3440
- const tooltipFormatter = useMemo(() => resolveValueFormatter(valueFormatter, format2), [valueFormatter, format2]);
3441
- const axisFormatter = useMemo(() => resolveAxisFormatter(valueFormatter, format2), [valueFormatter, format2]);
3442
- const axisTicks = useMemo(() => resolveAxisTickFormatter(valueFormatter, format2), [valueFormatter, format2]);
3443
- const series = useMemo(() => aggregateSeries(data, categories), [data, categories]);
2869
+ const { ref: frameRef, surface, width: plotWidth, tokens } = useChartSurface(ref);
2870
+ const locale = useLocale();
2871
+ const t = TEXT5[uiLanguage(locale)];
2872
+ const tooltipFormatter = useMemo(() => resolveValueFormatter(valueFormatter, format, locale), [valueFormatter, format, locale]);
2873
+ const axisFormatter = useMemo(() => resolveAxisFormatter(valueFormatter, format, locale), [valueFormatter, format, locale]);
2874
+ const axisTicks = useMemo(() => resolveAxisTickFormatter(valueFormatter, format, locale), [valueFormatter, format, locale]);
2875
+ const series = useMemo(() => aggregateSeries(data, categories, void 0, otherSeriesLabel(locale)), [data, categories, locale]);
3444
2876
  const palette = useMemo(
3445
2877
  () => resolveChartColors(
3446
2878
  // Meaning colours on bars are AREA colours (`warning` -> `--warning-fill`), the same as the thresholds' and a legend's.
@@ -3498,7 +2930,8 @@ function BarChartImpl({
3498
2930
  labelColor: tokens?.foreground ?? void 0,
3499
2931
  plotWidth,
3500
2932
  plotHeight: typeof height === "number" ? height : void 0,
3501
- chartOptions
2933
+ chartOptions,
2934
+ locale
3502
2935
  }),
3503
2936
  [
3504
2937
  series,
@@ -3539,18 +2972,19 @@ function BarChartImpl({
3539
2972
  tokens,
3540
2973
  surface,
3541
2974
  plotWidth,
3542
- chartOptions
2975
+ chartOptions,
2976
+ locale
3543
2977
  ]
3544
2978
  );
3545
2979
  const dataTable = useMemo(() => {
3546
- const table = chartDataTable(labelRows(series.data, index, labels), index, series.categories, tooltipFormatter, labels, "\u9805\u76EE");
3547
- const times = timeTooltipLabels(series.data.map((row) => row[index]));
2980
+ const table = chartDataTable(labelRows(series.data, index, labels), index, series.categories, tooltipFormatter, labels, t.item);
2981
+ const times = timeTooltipLabels(series.data.map((row) => row[index]), locale);
3548
2982
  return times ? { ...table, rows: table.rows.map((row, i) => [times[i] ?? row[0] ?? "", ...row.slice(1)]) } : table;
3549
- }, [series, index, tooltipFormatter, labels]);
3550
- const label2 = ariaLabel ?? `${categories.join("\u30FB")}\u306E\u68D2\u30B0\u30E9\u30D5`;
2983
+ }, [series, index, tooltipFormatter, labels, t, locale]);
2984
+ const label2 = ariaLabel ?? t.chart(categories);
3551
2985
  const resolvedSummary = useMemo(
3552
- () => summary === "auto" ? buildChartSummary({ data, index, categories, title, format: format2, valueFormatter }) : summary,
3553
- [summary, data, index, categories, title, format2, valueFormatter]
2986
+ () => summary === "auto" ? buildChartSummary({ data, index, categories, title, format, valueFormatter, locale }) : summary,
2987
+ [summary, data, index, categories, title, format, valueFormatter, locale]
3554
2988
  );
3555
2989
  return /* @__PURE__ */ jsx(
3556
2990
  ChartFrame,
@@ -3571,8 +3005,12 @@ function BarChartImpl({
3571
3005
  }
3572
3006
  );
3573
3007
  }
3574
- var BarChart2 = forwardRef(BarChartImpl);
3575
- BarChart2.displayName = "BarChart";
3008
+ var BarChart = forwardRef(BarChartImpl);
3009
+ BarChart.displayName = "BarChart";
3010
+ var TEXT6 = {
3011
+ ja: { item: "\u9805\u76EE", chart: (categories) => `${categories.join("\u30FB")}\u306E\u6298\u308C\u7DDA\u30B0\u30E9\u30D5` },
3012
+ en: { item: "Item", chart: (categories) => `Line chart of ${categories.join(", ")}` }
3013
+ };
3576
3014
  var NO_ROWS3 = [];
3577
3015
  function LineChartImpl({
3578
3016
  data = NO_ROWS3,
@@ -3581,7 +3019,7 @@ function LineChartImpl({
3581
3019
  colors,
3582
3020
  labels,
3583
3021
  valueFormatter,
3584
- format: format2,
3022
+ format,
3585
3023
  title,
3586
3024
  summary,
3587
3025
  actions,
@@ -3620,14 +3058,18 @@ function LineChartImpl({
3620
3058
  className,
3621
3059
  ...rest
3622
3060
  }, ref) {
3623
- const tokens = useChartTokens();
3624
- const { ref: frameRef, surface, width: plotWidth } = useChartSurface(ref, tokens);
3625
- const tooltipFormatter = useMemo(() => resolveValueFormatter(valueFormatter, format2), [valueFormatter, format2]);
3626
- const axisFormatter = useMemo(() => resolveAxisFormatter(valueFormatter, format2), [valueFormatter, format2]);
3627
- const axisTicks = useMemo(() => resolveAxisTickFormatter(valueFormatter, format2), [valueFormatter, format2]);
3061
+ const { ref: frameRef, surface, width: plotWidth, tokens } = useChartSurface(ref);
3062
+ const locale = useLocale();
3063
+ const t = TEXT6[uiLanguage(locale)];
3064
+ const tooltipFormatter = useMemo(() => resolveValueFormatter(valueFormatter, format, locale), [valueFormatter, format, locale]);
3065
+ const axisFormatter = useMemo(() => resolveAxisFormatter(valueFormatter, format, locale), [valueFormatter, format, locale]);
3066
+ const axisTicks = useMemo(() => resolveAxisTickFormatter(valueFormatter, format, locale), [valueFormatter, format, locale]);
3628
3067
  const comparisonCategory = comparison && categories.includes(comparison.category) ? comparison.category : void 0;
3629
3068
  const comparisonConfig = comparisonCategory === void 0 ? void 0 : comparison;
3630
- const series = useMemo(() => aggregateSeriesKeeping(data, categories, comparisonCategory), [data, categories, comparisonCategory]);
3069
+ const series = useMemo(
3070
+ () => aggregateSeriesKeeping(data, categories, comparisonCategory, void 0, otherSeriesLabel(locale)),
3071
+ [data, categories, comparisonCategory, locale]
3072
+ );
3631
3073
  const palette = useMemo(
3632
3074
  () => resolveChartColors(
3633
3075
  seriesColorsWithComparison(series.categories, colors, CHART_OTHER_COLOR, series.otherCategory, categories, comparisonCategory),
@@ -3675,7 +3117,7 @@ function LineChartImpl({
3675
3117
  annotations,
3676
3118
  forecast,
3677
3119
  comparison: comparisonConfig,
3678
- comparisonFormat: format2,
3120
+ comparisonFormat: format,
3679
3121
  provisionalFrom,
3680
3122
  provisionalLabel,
3681
3123
  reserveActions: Boolean(actions),
@@ -3684,7 +3126,8 @@ function LineChartImpl({
3684
3126
  labelColor: tokens?.foreground ?? void 0,
3685
3127
  plotWidth,
3686
3128
  plotHeight: typeof height === "number" ? height : void 0,
3687
- chartOptions
3129
+ chartOptions,
3130
+ locale
3688
3131
  }),
3689
3132
  [
3690
3133
  series,
@@ -3721,23 +3164,24 @@ function LineChartImpl({
3721
3164
  annotations,
3722
3165
  forecast,
3723
3166
  comparisonConfig,
3724
- format2,
3167
+ format,
3725
3168
  height,
3726
3169
  tokens,
3727
3170
  surface,
3728
3171
  plotWidth,
3729
- chartOptions
3172
+ chartOptions,
3173
+ locale
3730
3174
  ]
3731
3175
  );
3732
3176
  const dataTable = useMemo(() => {
3733
- const table = chartDataTable(labelRows(series.data, index, labels), index, series.categories, tooltipFormatter, labels, "\u9805\u76EE");
3734
- const times = timeTooltipLabels(series.data.map((row) => row[index]));
3177
+ const table = chartDataTable(labelRows(series.data, index, labels), index, series.categories, tooltipFormatter, labels, t.item);
3178
+ const times = timeTooltipLabels(series.data.map((row) => row[index]), locale);
3735
3179
  return times ? { ...table, rows: table.rows.map((row, i) => [times[i] ?? row[0] ?? "", ...row.slice(1)]) } : table;
3736
- }, [series, index, tooltipFormatter, labels]);
3737
- const label2 = ariaLabel ?? `${categories.join("\u30FB")}\u306E\u6298\u308C\u7DDA\u30B0\u30E9\u30D5`;
3180
+ }, [series, index, tooltipFormatter, labels, t, locale]);
3181
+ const label2 = ariaLabel ?? t.chart(categories);
3738
3182
  const resolvedSummary = useMemo(
3739
- () => summary === "auto" ? buildChartSummary({ data, index, categories, title, format: format2, valueFormatter }) : summary,
3740
- [summary, data, index, categories, title, format2, valueFormatter]
3183
+ () => summary === "auto" ? buildChartSummary({ data, index, categories, title, format, valueFormatter, locale }) : summary,
3184
+ [summary, data, index, categories, title, format, valueFormatter, locale]
3741
3185
  );
3742
3186
  return /* @__PURE__ */ jsx(
3743
3187
  ChartFrame,
@@ -3758,8 +3202,12 @@ function LineChartImpl({
3758
3202
  }
3759
3203
  );
3760
3204
  }
3761
- var LineChart2 = forwardRef(LineChartImpl);
3762
- LineChart2.displayName = "LineChart";
3205
+ var LineChart = forwardRef(LineChartImpl);
3206
+ LineChart.displayName = "LineChart";
3207
+ var TEXT7 = {
3208
+ ja: { item: "\u9805\u76EE", value: "\u5024", chart: (shares) => `\u69CB\u6210\u6BD4\u306E\u30C9\u30FC\u30CA\u30C4\u30B0\u30E9\u30D5\uFF08${shares.join("\u3001")}\uFF09` },
3209
+ en: { item: "Item", value: "Value", chart: (shares) => `Donut chart of shares (${shares.join(", ")})` }
3210
+ };
3763
3211
  function useElementWidth() {
3764
3212
  const [node, setNode] = useState(null);
3765
3213
  const [width, setWidth] = useState(null);
@@ -3779,7 +3227,7 @@ function DonutChartImpl({
3779
3227
  categories,
3780
3228
  colors,
3781
3229
  labels,
3782
- format: format2,
3230
+ format,
3783
3231
  valueFormatter: valueFormatterProp,
3784
3232
  title,
3785
3233
  summary,
@@ -3808,11 +3256,13 @@ function DonutChartImpl({
3808
3256
  const center = resolveDonutCenter(donutOptions?.centerLabel, { showLabel: donutOptions?.showLabel ?? showLabel, label: label2 });
3809
3257
  const maxSlices = donutOptions?.maxSlices;
3810
3258
  const showLegend = donutOptions?.showLegend ?? true;
3811
- const valueFormatter = useMemo(() => resolveValueFormatter(valueFormatterProp, format2), [valueFormatterProp, format2]);
3812
- const tokens = useChartTokens();
3259
+ const locale = useLocale();
3260
+ const t = TEXT7[uiLanguage(locale)];
3261
+ const valueFormatter = useMemo(() => resolveValueFormatter(valueFormatterProp, format, locale), [valueFormatterProp, format, locale]);
3262
+ const { ref: frameRef, tokens } = useChartSurface(ref);
3813
3263
  const slices = useMemo(
3814
- () => donutSlices(data, { index: labelKey, value: valueKey, colors, maxSlices, otherColor: CHART_OTHER_COLOR }),
3815
- [data, labelKey, valueKey, colors, maxSlices]
3264
+ () => donutSlices(data, { index: labelKey, value: valueKey, colors, maxSlices, otherColor: CHART_OTHER_COLOR, otherLabel: otherSeriesLabel(locale) }),
3265
+ [data, labelKey, valueKey, colors, maxSlices, locale]
3816
3266
  );
3817
3267
  const palette = useMemo(() => resolveChartColors(slices.map((s) => chartFillName(s.color)), tokens), [slices, tokens]);
3818
3268
  const rows = useMemo(() => slices.map((s) => s.row), [slices]);
@@ -3849,13 +3299,13 @@ function DonutChartImpl({
3849
3299
  let centerLabel = null;
3850
3300
  if (center.kind === "custom") centerLabel = center.node;
3851
3301
  else if (center.kind === "total") {
3852
- const text = donutCenterText(total, valueFormatter, { totalLabel: donutOptions?.totalLabel, unit: donutOptions?.unit });
3302
+ const text = donutCenterText(total, valueFormatter, { totalLabel: donutOptions?.totalLabel, unit: donutOptions?.unit, locale });
3853
3303
  centerLabel = caption(text.label, text.amount, text.unit);
3854
3304
  } else if (center.kind === "top") {
3855
3305
  const top = donutTopText(slices, labels);
3856
3306
  centerLabel = top && caption(top.label, top.amount);
3857
3307
  }
3858
- const a11yLabel = ariaLabel ?? `\u69CB\u6210\u6BD4\u306E\u30C9\u30FC\u30CA\u30C4\u30B0\u30E9\u30D5\uFF08${legend.map((item) => `${labelOf(item.name, labels)} ${item.share}`).join("\u3001")}\uFF09`;
3308
+ const a11yLabel = ariaLabel ?? t.chart(legend.map((item) => `${labelOf(item.name, labels)} ${item.share}`));
3859
3309
  const dataTable = useMemo(
3860
3310
  () => chartDataTable(
3861
3311
  // Fixed keys, so `labels` (which renames the rows) cannot collide with the column names.
@@ -3863,19 +3313,19 @@ function DonutChartImpl({
3863
3313
  "name",
3864
3314
  ["value"],
3865
3315
  valueFormatter,
3866
- { name: labels?.[labelKey] ?? "\u9805\u76EE", value: labels?.[valueKey] ?? "\u5024" }
3316
+ { name: labels?.[labelKey] ?? t.item, value: labels?.[valueKey] ?? t.value }
3867
3317
  ),
3868
- [rows, labelKey, valueKey, valueFormatter, labels]
3318
+ [rows, labelKey, valueKey, valueFormatter, labels, t]
3869
3319
  );
3870
3320
  const resolvedSummary = useMemo(
3871
- () => summary === "auto" ? buildShareSummary(slices, title) : summary,
3872
- [summary, slices, title]
3321
+ () => summary === "auto" ? buildShareSummary(slices, title, locale) : summary,
3322
+ [summary, slices, title, locale]
3873
3323
  );
3874
3324
  return /* @__PURE__ */ jsx(
3875
3325
  ChartFrame,
3876
3326
  {
3877
3327
  ...chartRootProps(rest),
3878
- ref,
3328
+ ref: frameRef,
3879
3329
  title,
3880
3330
  summary: resolvedSummary,
3881
3331
  isLoading: isLoading ?? loading ?? false,
@@ -3924,6 +3374,10 @@ function DonutChartImpl({
3924
3374
  }
3925
3375
  var DonutChart = forwardRef(DonutChartImpl);
3926
3376
  DonutChart.displayName = "DonutChart";
3377
+ var TEXT8 = {
3378
+ ja: { item: "\u9805\u76EE", value: "\u5024" },
3379
+ en: { item: "Item", value: "Value" }
3380
+ };
3927
3381
  var listHeight = (n) => n * 32 + Math.max(0, n - 1) * 6;
3928
3382
  var isExternal = (href) => /^https?:\/\//.test(href);
3929
3383
  var NO_ROWS5 = [];
@@ -3935,7 +3389,7 @@ function BarListImpl({
3935
3389
  labels,
3936
3390
  thresholds,
3937
3391
  highlight,
3938
- format: format2,
3392
+ format,
3939
3393
  valueFormatter,
3940
3394
  formatValue: formatValue2,
3941
3395
  title,
@@ -3957,16 +3411,18 @@ function BarListImpl({
3957
3411
  const frame = requestAnimationFrame(() => setMounted(true));
3958
3412
  return () => cancelAnimationFrame(frame);
3959
3413
  }, [showAnimation]);
3414
+ const locale = useLocale();
3415
+ const t = TEXT8[uiLanguage(locale)];
3960
3416
  const maxItems = barListOptions?.maxItems ?? MAX_CHART_SERIES;
3961
3417
  const token = Array.isArray(colors) ? colors[0] : colors;
3962
3418
  const barColor = token ?? color ?? "chart-1";
3963
- const formatter = resolveValueFormatter(valueFormatter ?? formatValue2, format2);
3419
+ const formatter = resolveValueFormatter(valueFormatter ?? formatValue2, format, locale);
3964
3420
  const baseRows = barListRows(data, {
3965
3421
  index,
3966
3422
  category: categories?.[0],
3967
3423
  sortOrder: barListOptions?.sortOrder ?? sortOrder ?? "descending",
3968
3424
  maxItems,
3969
- otherLabel: barListOptions?.otherLabel,
3425
+ otherLabel: barListOptions?.otherLabel ?? otherSeriesLabel(locale),
3970
3426
  exclude: barListOptions?.exclude
3971
3427
  });
3972
3428
  const rows = baseRows.map((row) => {
@@ -3985,7 +3441,7 @@ function BarListImpl({
3985
3441
  "name",
3986
3442
  ["value"],
3987
3443
  formatter,
3988
- { name: index && labels?.[index] || "\u9805\u76EE", value: categories?.[0] && labels?.[categories[0]] || "\u5024" }
3444
+ { name: index && labels?.[index] || t.item, value: categories?.[0] && labels?.[categories[0]] || t.value }
3989
3445
  );
3990
3446
  const list = /* @__PURE__ */ jsxs("div", { "data-slot": "bar-list", className: "flex justify-between gap-6 text-sm", ...props, children: [
3991
3447
  /* @__PURE__ */ jsx("div", { className: "relative min-w-0 flex-1 space-y-1.5", children: rows.map((row, i) => {
@@ -4059,9 +3515,10 @@ function BarListImpl({
4059
3515
  var BarList = forwardRef(BarListImpl);
4060
3516
  BarList.displayName = "BarList";
4061
3517
  var NO_ROWS6 = [];
4062
- var CategoryBar = forwardRef(function CategoryBar2({ values = NO_ROWS6, colors, marker, showLabels = true, format: format2, valueFormatter: valueFormatterProp, className, ...props }, forwardedRef) {
3518
+ var CategoryBar = forwardRef(function CategoryBar2({ values = NO_ROWS6, colors, marker, showLabels = true, format, valueFormatter: valueFormatterProp, className, ...props }, forwardedRef) {
4063
3519
  const { ref, width } = useChartSurface(forwardedRef, null);
4064
- const valueFormatter = useMemo(() => resolveAxisFormatter(valueFormatterProp, format2), [valueFormatterProp, format2]);
3520
+ const locale = useLocale();
3521
+ const valueFormatter = useMemo(() => resolveAxisFormatter(valueFormatterProp, format, locale), [valueFormatterProp, format, locale]);
4065
3522
  const segments = categoryBarSegments(values);
4066
3523
  const markerPosition = marker ? categoryBarMarkerPosition(marker.value, values) : 0;
4067
3524
  const allLabels = showLabels ? categoryBarLabels(values, void 0, marker ? markerPosition : void 0) : [];
@@ -4191,8 +3648,14 @@ function blockColorToCss(color) {
4191
3648
  }
4192
3649
  var NO_ROWS7 = [];
4193
3650
  var Tracker = forwardRef(function Tracker2({ data = NO_ROWS7, defaultColor, hoverEffect = true, className, ...props }, ref) {
3651
+ const containerRef = useRef(null);
3652
+ const setRef = useCallback((node) => {
3653
+ containerRef.current = node;
3654
+ if (typeof ref === "function") return ref(node);
3655
+ if (ref) ref.current = node;
3656
+ }, [ref]);
4194
3657
  const fallback = defaultColor ? blockColorToCss(defaultColor) : DEFAULT_BLOCK_COLOR;
4195
- return /* @__PURE__ */ jsx("div", { ref, "data-slot": "tracker", className: cn("flex h-6 w-full gap-0.5", className), ...props, children: data.map((block, i) => {
3658
+ return /* @__PURE__ */ jsx("div", { ref: setRef, "data-slot": "tracker", className: cn("flex h-6 w-full gap-0.5", className), ...props, children: data.map((block, i) => {
4196
3659
  const blockClass = cn(
4197
3660
  "h-full min-w-0 flex-1 rounded-[2px]",
4198
3661
  hoverEffect && "transition-opacity hover:opacity-60 motion-reduce:transition-none"
@@ -4206,12 +3669,51 @@ var Tracker = forwardRef(function Tracker2({ data = NO_ROWS7, defaultColor, hove
4206
3669
  render: /* @__PURE__ */ jsx("div", { "data-slot": "tracker-block", role: "img", tabIndex: 0, "aria-label": block.tooltip, className: blockClass, style })
4207
3670
  }
4208
3671
  ),
4209
- /* @__PURE__ */ jsx(TooltipContent, { children: block.tooltip })
3672
+ /* @__PURE__ */ jsx(TooltipContent, { container: containerRef, children: block.tooltip })
4210
3673
  ] }, block.key ?? i) : /* @__PURE__ */ jsx("div", { "data-slot": "tracker-block", className: blockClass, style }, block.key ?? i);
4211
3674
  }) });
4212
3675
  });
4213
3676
  Tracker.displayName = "Tracker";
4214
3677
  use([GraphicComponent]);
3678
+ var TEXT9 = {
3679
+ ja: {
3680
+ net: "\u7D14\u5897",
3681
+ total: "\u5408\u8A08",
3682
+ change: "\u5897\u6E1B",
3683
+ cumulative: "\u7D2F\u8A08",
3684
+ cumulativeChange: "\u7D2F\u8A08\u5897\u6E1B",
3685
+ item: "\u9805\u76EE",
3686
+ start: "\u958B\u59CB",
3687
+ end: "\u7D42\u4E86",
3688
+ fromTo: (from, to, net) => `${from} \u2192 ${to}\uFF08${net}\uFF09`,
3689
+ from: (from, net) => `${from} \u304B\u3089 ${net}`,
3690
+ to: (to, net) => `${to}\uFF08${net}\uFF09`,
3691
+ netOnly: (net) => `\u5897\u6E1B\u306E\u5408\u8A08 ${net}`,
3692
+ increase: (name, value) => `\u6700\u5927\u306E\u5897\u52A0\u306F ${name}\uFF08${value}\uFF09`,
3693
+ decrease: (name, value) => `\u6700\u5927\u306E\u6E1B\u5C11\u306F ${name}\uFF08${value}\uFF09`,
3694
+ sentenceJoin: "\u3002",
3695
+ chart: (label2) => `${label2}\u306E\u30A6\u30A9\u30FC\u30BF\u30FC\u30D5\u30A9\u30FC\u30EB\u30C1\u30E3\u30FC\u30C8`
3696
+ },
3697
+ en: {
3698
+ net: "Net change",
3699
+ total: "Total",
3700
+ change: "Change",
3701
+ cumulative: "Cumulative",
3702
+ cumulativeChange: "Cumulative change",
3703
+ item: "Item",
3704
+ start: "Start",
3705
+ end: "End",
3706
+ fromTo: (from, to, net) => `${from} \u2192 ${to} (${net})`,
3707
+ from: (from, net) => `${net} from ${from}`,
3708
+ to: (to, net) => `${to} (${net})`,
3709
+ netOnly: (net) => `Net change ${net}`,
3710
+ increase: (name, value) => `Largest increase: ${name} (${value})`,
3711
+ decrease: (name, value) => `Largest decrease: ${name} (${value})`,
3712
+ sentenceJoin: ". ",
3713
+ chart: (label2) => `Waterfall chart of ${label2}`
3714
+ }
3715
+ };
3716
+ var textOf = (locale) => TEXT9[uiLanguage(resolveLocale(locale))];
4215
3717
  function waterfallSteps(data, config) {
4216
3718
  const totals = new Set(config.totals ?? []);
4217
3719
  const delta = config.mode === "delta";
@@ -4230,11 +3732,13 @@ function waterfallSteps(data, config) {
4230
3732
  return { name, kind: n > 0 ? "increase" : n < 0 ? "decrease" : "flat", value: n, start, end: running, row };
4231
3733
  });
4232
3734
  if (delta && steps.some((s) => s.kind !== "gap")) {
4233
- steps.push({ name: DELTA_TOTAL_NAME, kind: "total", value: running, start: 0, end: running, row: {} });
3735
+ steps.push({ name: deltaTotalName(config.locale), kind: "total", value: running, start: 0, end: running, row: {} });
4234
3736
  }
4235
3737
  return steps;
4236
3738
  }
4237
- var DELTA_TOTAL_NAME = "\u7D14\u5897";
3739
+ function deltaTotalName(locale) {
3740
+ return textOf(locale).net;
3741
+ }
4238
3742
  function waterfallDeltaEnds(data, config) {
4239
3743
  const totals = new Set(config.totals ?? []);
4240
3744
  const kinds = data.map((row) => totals.has(String(row[config.index] ?? "")));
@@ -4250,16 +3754,17 @@ function waterfallDeltaEnds(data, config) {
4250
3754
  const closing = closingRow && closingRow.value === null && opening?.value != null ? { ...closingRow, value: opening.value + net } : closingRow;
4251
3755
  return { opening, closing, net };
4252
3756
  }
4253
- function waterfallDeltaNote(ends, formatter, labels) {
3757
+ function waterfallDeltaNote(ends, formatter, labels, locale) {
3758
+ const t = textOf(locale);
4254
3759
  const net = signedText(ends.net, formatter);
4255
3760
  const { opening, closing } = ends;
4256
3761
  const side = (e) => e && e.value !== null ? `${labelOf(e.name, labels)} ${formatter(e.value)}` : null;
4257
3762
  const from = side(opening);
4258
3763
  const to = side(closing);
4259
- if (from && to) return `${from} \u2192 ${to}\uFF08${net}\uFF09`;
4260
- if (from) return `${from} \u304B\u3089 ${net}`;
4261
- if (to) return `${to}\uFF08${net}\uFF09`;
4262
- return `\u5897\u6E1B\u306E\u5408\u8A08 ${net}`;
3764
+ if (from && to) return t.fromTo(from, to, net);
3765
+ if (from) return t.from(from, net);
3766
+ if (to) return t.to(to, net);
3767
+ return t.netOnly(net);
4263
3768
  }
4264
3769
  function waterfallStack(steps) {
4265
3770
  const base = [];
@@ -4311,7 +3816,8 @@ function waterfallStepText(step, formatter, delta = false) {
4311
3816
  if (step.value === null) return EMPTY_VALUE;
4312
3817
  return step.kind === "total" && !delta ? formatter(step.value) : signedText(step.value, formatter);
4313
3818
  }
4314
- function buildWaterfallSummary(steps, formatter, title, labels, delta) {
3819
+ function buildWaterfallSummary(steps, formatter, title, labels, delta, locale) {
3820
+ const t = textOf(locale);
4315
3821
  const real = steps.filter((s) => s.kind !== "gap");
4316
3822
  const first = real[0];
4317
3823
  const last = real[real.length - 1];
@@ -4319,7 +3825,7 @@ function buildWaterfallSummary(steps, formatter, title, labels, delta) {
4319
3825
  const name = (s) => labelOf(s.name, labels);
4320
3826
  const head = title ? `${title}: ` : "";
4321
3827
  const parts = [
4322
- delta ? waterfallDeltaNote(delta, formatter, labels) : real.length === 1 ? `${name(first)} ${formatter(first.end)}` : `${name(first)} ${formatter(first.end)} \u2192 ${name(last)} ${formatter(last.end)}`
3828
+ delta ? waterfallDeltaNote(delta, formatter, labels, locale) : real.length === 1 ? `${name(first)} ${formatter(first.end)}` : `${name(first)} ${formatter(first.end)} \u2192 ${name(last)} ${formatter(last.end)}`
4323
3829
  ];
4324
3830
  let up;
4325
3831
  let down;
@@ -4327,21 +3833,22 @@ function buildWaterfallSummary(steps, formatter, title, labels, delta) {
4327
3833
  if (s.kind === "increase" && (!up || s.value > up.value)) up = s;
4328
3834
  if (s.kind === "decrease" && (!down || s.value < down.value)) down = s;
4329
3835
  }
4330
- if (up) parts.push(`\u6700\u5927\u306E\u5897\u52A0\u306F ${name(up)}\uFF08${signedText(up.value, formatter)}\uFF09`);
4331
- if (down) parts.push(`\u6700\u5927\u306E\u6E1B\u5C11\u306F ${name(down)}\uFF08${signedText(down.value, formatter)}\uFF09`);
4332
- return `${head}${parts.join("\u3002")}`;
3836
+ if (up) parts.push(t.increase(name(up), signedText(up.value, formatter)));
3837
+ if (down) parts.push(t.decrease(name(down), signedText(down.value, formatter)));
3838
+ return `${head}${parts.join(t.sentenceJoin)}`;
4333
3839
  }
4334
- function waterfallDataTable(steps, names, formatter, labels, delta) {
3840
+ function waterfallDataTable(steps, names, formatter, labels, delta, locale) {
3841
+ const t = textOf(locale);
4335
3842
  const label2 = (key) => labelOf(key, labels);
4336
3843
  const rows = steps.map((s) => [
4337
3844
  label2(s.name),
4338
- s.kind === "total" ? delta ? DELTA_TOTAL_NAME : "\u5408\u8A08" : s.value === null ? EMPTY_VALUE : signedText(s.value, formatter),
3845
+ s.kind === "total" ? delta ? t.net : t.total : s.value === null ? EMPTY_VALUE : signedText(s.value, formatter),
4339
3846
  s.kind === "gap" ? EMPTY_VALUE : delta ? signedText(s.end, formatter) : formatter(s.end)
4340
3847
  ]);
4341
3848
  const end = (e, role) => e && e.value !== null ? [[label2(e.name), role, formatter(e.value)]] : [];
4342
3849
  return {
4343
- columns: [labels?.[names.index] ?? "\u9805\u76EE", "\u5897\u6E1B", delta ? "\u7D2F\u8A08\u5897\u6E1B" : "\u7D2F\u8A08"],
4344
- rows: delta ? [...end(delta.opening, "\u958B\u59CB"), ...rows, ...end(delta.closing, "\u7D42\u4E86")] : rows
3850
+ columns: [labels?.[names.index] ?? t.item, t.change, delta ? t.cumulativeChange : t.cumulative],
3851
+ rows: delta ? [...end(delta.opening, t.start), ...rows, ...end(delta.closing, t.end)] : rows
4345
3852
  };
4346
3853
  }
4347
3854
  var WATERFALL_BAR_SHARE = 0.45;
@@ -4423,6 +3930,7 @@ function waterfallConnectorRenderer(color) {
4423
3930
  var ROW_STYLE = "display:flex;align-items:center;gap:8px;line-height:20px";
4424
3931
  function buildWaterfallOption(config) {
4425
3932
  const { steps, colors, polarity, labels, valueFormatter, showValues = true, showTooltip = true } = config;
3933
+ const t = textOf(config.locale);
4426
3934
  const delta = config.mode === "delta";
4427
3935
  const axisFormatter = config.axisFormatter ?? valueFormatter;
4428
3936
  const noteWidth = config.plotWidth ? Math.max(120, config.plotWidth - 16) : void 0;
@@ -4493,7 +4001,7 @@ function buildWaterfallOption(config) {
4493
4001
  if (!step) return "";
4494
4002
  const color = escapeHtml(colorOf(step) ?? "currentColor");
4495
4003
  const line = (name, text) => `<div style="${ROW_STYLE}"><span style="display:inline-block;width:8px;height:8px;border-radius:9999px;background:${color}"></span><span style="flex:1;opacity:.8">${escapeHtml(name)}</span><span style="font-weight:500;font-variant-numeric:tabular-nums;margin-left:12px">${escapeHtml(text)}</span></div>`;
4496
- const rows = step.kind === "total" ? line(delta ? DELTA_TOTAL_NAME : "\u5408\u8A08", delta ? signedText(step.end, valueFormatter) : valueFormatter(step.end)) : line("\u5897\u6E1B", waterfallStepText(step, valueFormatter)) + (step.kind === "gap" ? "" : delta ? line("\u7D2F\u8A08\u5897\u6E1B", signedText(step.end, valueFormatter)) : line("\u7D2F\u8A08", valueFormatter(step.end)));
4004
+ const rows = step.kind === "total" ? line(delta ? t.net : t.total, delta ? signedText(step.end, valueFormatter) : valueFormatter(step.end)) : line(t.change, waterfallStepText(step, valueFormatter)) + (step.kind === "gap" ? "" : delta ? line(t.cumulativeChange, signedText(step.end, valueFormatter)) : line(t.cumulative, valueFormatter(step.end)));
4497
4005
  return `<div style="font-weight:500;margin-bottom:4px">${escapeHtml(labelOf(step.name, labels))}</div>${rows}`;
4498
4006
  }
4499
4007
  },
@@ -4563,7 +4071,7 @@ function WaterfallChartImpl({
4563
4071
  mode = "total",
4564
4072
  polarity = "higher-is-better",
4565
4073
  labels,
4566
- format: format2,
4074
+ format,
4567
4075
  valueFormatter: valueFormatterProp,
4568
4076
  showValues = true,
4569
4077
  showTooltip = true,
@@ -4583,13 +4091,16 @@ function WaterfallChartImpl({
4583
4091
  ...rest
4584
4092
  }, ref) {
4585
4093
  const valueKey = categories[0] ?? "";
4586
- const tokens = useChartTokens();
4587
- const { ref: frameRef, width: plotWidth } = useChartSurface(ref, tokens);
4588
- const valueFormatter = useMemo(() => resolveValueFormatter(valueFormatterProp, format2), [valueFormatterProp, format2]);
4589
- const axisFormatter = useMemo(() => resolveAxisFormatter(valueFormatterProp, format2), [valueFormatterProp, format2]);
4590
- const steps = useMemo(() => waterfallSteps(data, { index, value: valueKey, totals, mode }), [data, index, valueKey, totals, mode]);
4094
+ const { ref: frameRef, width: plotWidth, tokens } = useChartSurface(ref);
4095
+ const locale = useLocale();
4096
+ const valueFormatter = useMemo(() => resolveValueFormatter(valueFormatterProp, format, locale), [valueFormatterProp, format, locale]);
4097
+ const axisFormatter = useMemo(() => resolveAxisFormatter(valueFormatterProp, format, locale), [valueFormatterProp, format, locale]);
4098
+ const steps = useMemo(
4099
+ () => waterfallSteps(data, { index, value: valueKey, totals, mode, locale }),
4100
+ [data, index, valueKey, totals, mode, locale]
4101
+ );
4591
4102
  const ends = useMemo(() => mode === "delta" ? waterfallDeltaEnds(data, { index, value: valueKey, totals }) : void 0, [data, index, valueKey, totals, mode]);
4592
- const deltaNote = useMemo(() => ends ? waterfallDeltaNote(ends, valueFormatter, labels) : void 0, [ends, valueFormatter, labels]);
4103
+ const deltaNote = useMemo(() => ends ? waterfallDeltaNote(ends, valueFormatter, labels, locale) : void 0, [ends, valueFormatter, labels, locale]);
4593
4104
  const colors = useMemo(() => {
4594
4105
  const fills = resolveFillColors(tokens);
4595
4106
  const [total = ""] = resolveChartColors(["chart-1"], tokens);
@@ -4619,19 +4130,21 @@ function WaterfallChartImpl({
4619
4130
  chartOptions,
4620
4131
  minValue,
4621
4132
  maxValue,
4622
- yAxisWidth
4133
+ yAxisWidth,
4134
+ locale
4623
4135
  }),
4624
- [steps, colors, polarity, labels, valueFormatter, axisFormatter, showValues, showTooltip, tokens, mode, deltaNote, plotWidth, chartOptions, minValue, maxValue, yAxisWidth]
4136
+ [steps, colors, polarity, labels, valueFormatter, axisFormatter, showValues, showTooltip, tokens, mode, deltaNote, plotWidth, chartOptions, minValue, maxValue, yAxisWidth, locale]
4625
4137
  );
4626
4138
  const dataTable = useMemo(
4627
- () => waterfallDataTable(steps, { index}, valueFormatter, labels, ends),
4628
- [steps, index, valueKey, valueFormatter, labels, ends]
4139
+ () => waterfallDataTable(steps, { index}, valueFormatter, labels, ends, locale),
4140
+ [steps, index, valueKey, valueFormatter, labels, ends, locale]
4629
4141
  );
4630
4142
  const resolvedSummary = useMemo(
4631
- () => summary === "auto" ? buildWaterfallSummary(steps, valueFormatter, title, labels, ends) : summary,
4632
- [summary, steps, valueFormatter, title, labels, ends]
4143
+ () => summary === "auto" ? buildWaterfallSummary(steps, valueFormatter, title, labels, ends, locale) : summary,
4144
+ [summary, steps, valueFormatter, title, labels, ends, locale]
4633
4145
  );
4634
- const label2 = ariaLabel ?? `${labelOf(valueKey, labels) || "\u5897\u6E1B"}\u306E\u30A6\u30A9\u30FC\u30BF\u30FC\u30D5\u30A9\u30FC\u30EB\u30C1\u30E3\u30FC\u30C8`;
4146
+ const t = textOf(locale);
4147
+ const label2 = ariaLabel ?? t.chart(labelOf(valueKey, labels) || t.change.toLowerCase());
4635
4148
  return /* @__PURE__ */ jsx(
4636
4149
  ChartFrame,
4637
4150
  {
@@ -4673,7 +4186,38 @@ function scatterPoints(data, config) {
4673
4186
  }
4674
4187
  return points;
4675
4188
  }
4676
- function scatterSeries(points, max = MAX_CHART_SERIES) {
4189
+ var TEXT10 = {
4190
+ ja: {
4191
+ who: (name, value) => `${name}\uFF08${value}\uFF09`,
4192
+ summary: (count, y, who) => `${count}\u70B9\u3002${y}\u304C\u6700\u5927\u306A\u306E\u306F ${who}`,
4193
+ name: "\u540D\u524D",
4194
+ series: "\u7CFB\u5217",
4195
+ x: "\u6A2A\u8EF8",
4196
+ y: "\u7E26\u8EF8",
4197
+ size: "\u5927\u304D\u3055",
4198
+ pair: (y, x) => `${y}\xD7${x}`,
4199
+ first: (pair, count) => `${pair}\uFF08\u5148\u982D ${count} \u70B9\uFF09`,
4200
+ guide: (label2, axis, value) => `${label2}\uFF08${axis} ${value}\uFF09`,
4201
+ caption: (base, guides) => `${base}\u3002\u57FA\u6E96\u7DDA: ${guides.join("\u3001")}`,
4202
+ chart: (y, x) => `${y}\xD7${x}\u306E\u6563\u5E03\u56F3`
4203
+ },
4204
+ en: {
4205
+ who: (name, value) => `${name} (${value})`,
4206
+ summary: (count, y, who) => `${count === 1 ? "1 point" : `${count} points`}. Highest ${y}: ${who}`,
4207
+ name: "Name",
4208
+ series: "Series",
4209
+ x: "X",
4210
+ y: "Y",
4211
+ size: "Size",
4212
+ pair: (y, x) => `${y} \xD7 ${x}`,
4213
+ first: (pair, count) => `${pair} (first ${count} points)`,
4214
+ guide: (label2, axis, value) => `${label2} (${axis} ${value})`,
4215
+ caption: (base, guides) => `${base}. Reference lines: ${guides.join(", ")}`,
4216
+ chart: (y, x) => `Scatter plot of ${y} \xD7 ${x}`
4217
+ }
4218
+ };
4219
+ var textOf2 = (locale) => TEXT10[uiLanguage(resolveLocale(locale))];
4220
+ function scatterSeries(points, max = MAX_CHART_SERIES, otherLabel = otherSeriesLabel()) {
4677
4221
  const order = [];
4678
4222
  const counts = /* @__PURE__ */ new Map();
4679
4223
  for (const p of points) {
@@ -4686,7 +4230,7 @@ function scatterSeries(points, max = MAX_CHART_SERIES) {
4686
4230
  const ranked = order.map((name, at) => ({ name, at, n: counts.get(name) ?? 0 })).sort((a, b) => b.n - a.n || a.at - b.at);
4687
4231
  const kept = new Set(ranked.slice(0, Math.max(1, max)).map((r) => r.name));
4688
4232
  const result = order.filter((name) => kept.has(name)).map((name) => ({ name, isOther: false, points: points.filter((p) => p.series === name) }));
4689
- result.push({ name: OTHER_SERIES_LABEL, isOther: true, points: points.filter((p) => !kept.has(p.series)) });
4233
+ result.push({ name: otherLabel, isOther: true, points: points.filter((p) => !kept.has(p.series)) });
4690
4234
  return result;
4691
4235
  }
4692
4236
  var SCATTER_FADED_OPACITY = 0.2;
@@ -4700,24 +4244,26 @@ function scatterBubbleSize(value, max) {
4700
4244
  function pointTitle(point, labels) {
4701
4245
  return labelOf(point.name || point.series, labels);
4702
4246
  }
4703
- function buildScatterSummary(points, yName, yFormatter, title, labels) {
4247
+ function buildScatterSummary(points, yName, yFormatter, title, labels, locale) {
4704
4248
  if (points.length === 0) return void 0;
4249
+ const t = textOf2(locale);
4705
4250
  let best = points[0];
4706
4251
  for (const p of points) if (p.y > best.y) best = p;
4707
4252
  const head = title ? `${title}: ` : "";
4708
- const who = best.name ? `${labelOf(best.name, labels)}\uFF08${yFormatter(best.y)}\uFF09` : yFormatter(best.y);
4709
- return `${head}${points.length}\u70B9\u3002${labelOf(yName, labels)}\u304C\u6700\u5927\u306A\u306E\u306F ${who}`;
4253
+ const who = best.name ? t.who(labelOf(best.name, labels), yFormatter(best.y)) : yFormatter(best.y);
4254
+ return `${head}${t.summary(points.length, labelOf(yName, labels), who)}`;
4710
4255
  }
4711
4256
  var SCATTER_TABLE_MAX_ROWS = 100;
4712
4257
  function scatterDataTable(points, config) {
4258
+ const t = textOf2(config.locale);
4713
4259
  const label2 = (key) => labelOf(key, config.labels);
4714
4260
  const column = (key, fallback) => config.labels?.[key] ?? fallback;
4715
4261
  const columns = [
4716
- ...config.index ? [column(config.index, "\u540D\u524D")] : [],
4717
- ...config.series ? [column(config.series, "\u7CFB\u5217")] : [],
4718
- column(config.x, "\u6A2A\u8EF8"),
4719
- column(config.y, "\u7E26\u8EF8"),
4720
- ...config.size ? [column(config.size, "\u5927\u304D\u3055")] : []
4262
+ ...config.index ? [column(config.index, t.name)] : [],
4263
+ ...config.series ? [column(config.series, t.series)] : [],
4264
+ column(config.x, t.x),
4265
+ column(config.y, t.y),
4266
+ ...config.size ? [column(config.size, t.size)] : []
4721
4267
  ];
4722
4268
  const shown = points.slice(0, SCATTER_TABLE_MAX_ROWS);
4723
4269
  const rows = shown.map((p, i) => {
@@ -4730,14 +4276,15 @@ function scatterDataTable(points, config) {
4730
4276
  ];
4731
4277
  return config.index ? cells : [String(i + 1), ...cells];
4732
4278
  });
4733
- const base = points.length > shown.length ? `${label2(config.y)}\xD7${label2(config.x)}\uFF08\u5148\u982D ${shown.length} \u70B9\uFF09` : `${label2(config.y)}\xD7${label2(config.x)}`;
4279
+ const pair = t.pair(label2(config.y), label2(config.x));
4280
+ const base = points.length > shown.length ? t.first(pair, shown.length) : pair;
4734
4281
  const guides = (config.referenceLines ?? []).map((line) => {
4735
4282
  const key = line.axis === "x" ? config.x : config.y;
4736
4283
  const text = config.formatters[line.axis](line.value);
4737
- return line.label ? `${line.label}\uFF08${label2(key)} ${text}\uFF09` : `${label2(key)} ${text}`;
4284
+ return line.label ? t.guide(line.label, label2(key), text) : `${label2(key)} ${text}`;
4738
4285
  });
4739
4286
  return {
4740
- caption: guides.length > 0 ? `${base}\u3002\u57FA\u6E96\u7DDA: ${guides.join("\u3001")}` : base,
4287
+ caption: guides.length > 0 ? t.caption(base, guides) : base,
4741
4288
  columns: config.index ? columns : ["#", ...columns],
4742
4289
  rows
4743
4290
  };
@@ -4959,7 +4506,7 @@ function ScatterChartImpl({
4959
4506
  referenceLines,
4960
4507
  colors,
4961
4508
  labels,
4962
- format: format2,
4509
+ format,
4963
4510
  xFormat,
4964
4511
  yFormat,
4965
4512
  sizeFormat,
@@ -4983,28 +4530,28 @@ function ScatterChartImpl({
4983
4530
  className,
4984
4531
  ...rest
4985
4532
  }, ref) {
4986
- const tokens = useChartTokens();
4987
- const { ref: frameRef, width: plotWidth } = useChartSurface(ref, tokens);
4533
+ const { ref: frameRef, width: plotWidth, tokens } = useChartSurface(ref);
4534
+ const locale = useLocale();
4988
4535
  const formatters = useMemo(
4989
4536
  () => ({
4990
- x: resolveValueFormatter(valueFormatter, xFormat ?? format2),
4991
- y: resolveValueFormatter(valueFormatter, yFormat ?? format2),
4992
- size: resolveValueFormatter(valueFormatter, sizeFormat ?? format2)
4537
+ x: resolveValueFormatter(valueFormatter, xFormat ?? format, locale),
4538
+ y: resolveValueFormatter(valueFormatter, yFormat ?? format, locale),
4539
+ size: resolveValueFormatter(valueFormatter, sizeFormat ?? format, locale)
4993
4540
  }),
4994
- [valueFormatter, xFormat, yFormat, sizeFormat, format2]
4541
+ [valueFormatter, xFormat, yFormat, sizeFormat, format, locale]
4995
4542
  );
4996
4543
  const axisFormatters = useMemo(
4997
4544
  () => ({
4998
- x: resolveAxisFormatter(valueFormatter, xFormat ?? format2),
4999
- y: resolveAxisFormatter(valueFormatter, yFormat ?? format2)
4545
+ x: resolveAxisFormatter(valueFormatter, xFormat ?? format, locale),
4546
+ y: resolveAxisFormatter(valueFormatter, yFormat ?? format, locale)
5000
4547
  }),
5001
- [valueFormatter, xFormat, yFormat, format2]
4548
+ [valueFormatter, xFormat, yFormat, format, locale]
5002
4549
  );
5003
4550
  const points = useMemo(
5004
4551
  () => scatterPoints(data, { x, y, size, index, series: seriesKey, labelKey }),
5005
4552
  [data, x, y, size, index, seriesKey, labelKey]
5006
4553
  );
5007
- const series = useMemo(() => scatterSeries(points), [points]);
4554
+ const series = useMemo(() => scatterSeries(points, void 0, otherSeriesLabel(locale)), [points, locale]);
5008
4555
  const palette = useMemo(
5009
4556
  () => resolveChartColors(scatterSeriesColors(series, colors).map(chartFillName), tokens),
5010
4557
  [series, colors, tokens]
@@ -5040,14 +4587,14 @@ function ScatterChartImpl({
5040
4587
  [series, palette, x, y, size, seriesKey, seriesLabel, highlightList, referenceLines, labelKey, tokens, labels, formatters, axisFormatters, fitToData, showLegend, showTooltip, actions, plotWidth, chartOptions, minValue, maxValue, xMinValue, xMaxValue]
5041
4588
  );
5042
4589
  const dataTable = useMemo(
5043
- () => scatterDataTable(points, { x, y, size, index: index ?? labelKey, series: seriesKey, formatters, labels, referenceLines }),
5044
- [points, x, y, size, index, labelKey, seriesKey, formatters, labels, referenceLines]
4590
+ () => scatterDataTable(points, { x, y, size, index: index ?? labelKey, series: seriesKey, formatters, labels, referenceLines, locale }),
4591
+ [points, x, y, size, index, labelKey, seriesKey, formatters, labels, referenceLines, locale]
5045
4592
  );
5046
4593
  const resolvedSummary = useMemo(
5047
- () => summary === "auto" ? buildScatterSummary(points, y, formatters.y, title, labels) : summary,
5048
- [summary, points, y, formatters, title, labels]
4594
+ () => summary === "auto" ? buildScatterSummary(points, y, formatters.y, title, labels, locale) : summary,
4595
+ [summary, points, y, formatters, title, labels, locale]
5049
4596
  );
5050
- const label2 = ariaLabel ?? `${labelOf(y, labels)}\xD7${labelOf(x, labels)}\u306E\u6563\u5E03\u56F3`;
4597
+ const label2 = ariaLabel ?? textOf2(locale).chart(labelOf(y, labels), labelOf(x, labels));
5051
4598
  return /* @__PURE__ */ jsx(
5052
4599
  ChartFrame,
5053
4600
  {
@@ -5072,7 +4619,12 @@ ScatterChart.displayName = "ScatterChart";
5072
4619
  function legendColors(categories, colors) {
5073
4620
  return seriesColorsFor(categories, colors, CHART_OTHER_COLOR).map((color) => chartFillToCss(color));
5074
4621
  }
5075
- var Legend = forwardRef(function Legend2({ categories, colors, labels, layout = "horizontal", ariaLabel = "\u51E1\u4F8B", className }, ref) {
4622
+ var TEXT11 = {
4623
+ ja: { legend: "\u51E1\u4F8B" },
4624
+ en: { legend: "Legend" }
4625
+ };
4626
+ var Legend = forwardRef(function Legend2({ categories, colors, labels, layout = "horizontal", ariaLabel, className }, ref) {
4627
+ const t = TEXT11[uiLanguage(useLocale())];
5076
4628
  if (categories.length === 0) return null;
5077
4629
  const swatches = legendColors(categories, colors);
5078
4630
  return /* @__PURE__ */ jsx(
@@ -5081,7 +4633,7 @@ var Legend = forwardRef(function Legend2({ categories, colors, labels, layout =
5081
4633
  ref,
5082
4634
  "data-slot": "legend",
5083
4635
  "data-layout": layout,
5084
- "aria-label": ariaLabel,
4636
+ "aria-label": ariaLabel ?? t.legend,
5085
4637
  className: cn("m-0 flex list-none gap-x-4 gap-y-1 p-0 text-xs", layout === "vertical" ? "flex-col" : "flex-row flex-wrap", className),
5086
4638
  children: categories.map((category, i) => /* @__PURE__ */ jsxs("li", { "data-slot": "legend-item", className: "flex min-w-0 items-center gap-1.5", children: [
5087
4639
  /* @__PURE__ */ jsx("span", { "aria-hidden": "true", className: "size-2.5 shrink-0 rounded-[2px]", style: { background: swatches[i] } }),
@@ -5179,9 +4731,27 @@ var funnelConversionVariants = cva("flex items-center text-muted-foreground", {
5179
4731
  direction: "vertical"
5180
4732
  }
5181
4733
  });
5182
- function resolveFunnelFormatter(valueFormatter, formatValue2, format2) {
5183
- return resolveValueFormatter(valueFormatter ?? formatValue2, format2);
4734
+ function resolveFunnelFormatter(valueFormatter, formatValue2, format, locale) {
4735
+ return resolveValueFormatter(valueFormatter ?? formatValue2, format, locale);
5184
4736
  }
4737
+ var TEXT12 = {
4738
+ ja: {
4739
+ step: "\u30B9\u30C6\u30C3\u30D7",
4740
+ value: "\u5024",
4741
+ previous: "\u524D\u671F",
4742
+ previousHeader: "\u524D\u671F",
4743
+ change: (label2, points) => `(${label2}\u6BD4 ${points})`,
4744
+ funnel: "\u30D5\u30A1\u30CD\u30EB"
4745
+ },
4746
+ en: {
4747
+ step: "Step",
4748
+ value: "Value",
4749
+ previous: "prior period",
4750
+ previousHeader: "Prior period",
4751
+ change: (label2, points) => `(vs. ${label2} ${points})`,
4752
+ funnel: "Funnel"
4753
+ }
4754
+ };
5185
4755
  function lowestConversionStep(values) {
5186
4756
  if (values.length < 3) return -1;
5187
4757
  let lowest = -1;
@@ -5263,7 +4833,9 @@ function FunnelStepsImpl({
5263
4833
  }, ref) {
5264
4834
  const [mounted, setMounted] = useState(false);
5265
4835
  const isHorizontal = direction === "horizontal";
5266
- const format2 = resolveFunnelFormatter(valueFormatter, formatValue2, valueFormat);
4836
+ const locale = useLocale();
4837
+ const t = TEXT12[uiLanguage(locale)];
4838
+ const format = resolveFunnelFormatter(valueFormatter, formatValue2, valueFormat, locale);
5267
4839
  useEffect(() => {
5268
4840
  if (animate) setMounted(true);
5269
4841
  }, [animate]);
@@ -5275,15 +4847,19 @@ function FunnelStepsImpl({
5275
4847
  const maxValue = steps.length > 0 ? steps[0].value : 0;
5276
4848
  const values = steps.map((s) => s.value);
5277
4849
  const previous = comparison?.values;
5278
- const comparisonLabel2 = comparison?.label ?? "\u524D\u671F";
4850
+ const comparisonLabel2 = comparison?.label ?? t.previous;
5279
4851
  const showRates = showConversion || previous !== void 0;
5280
4852
  const focus = !showRates ? -1 : previous ? worstChangeStep(values, previous) : lowestConversionStep(values);
5281
4853
  const dataTable = chartDataTable(
5282
4854
  steps.map((step, i) => ({ label: step.label, value: step.value, previous: previous?.[i] ?? null })),
5283
4855
  "label",
5284
4856
  previous ? ["value", "previous"] : ["value"],
5285
- format2,
5286
- { label: labels?.[index] ?? "\u30B9\u30C6\u30C3\u30D7", value: categories?.[0] && labels?.[categories[0]] || "\u5024", previous: comparisonLabel2 }
4857
+ format,
4858
+ {
4859
+ label: labels?.[index] ?? t.step,
4860
+ value: categories?.[0] && labels?.[categories[0]] || t.value,
4861
+ previous: comparison?.label ?? t.previousHeader
4862
+ }
5287
4863
  );
5288
4864
  const list = /* @__PURE__ */ jsx("div", { "data-slot": "funnel-steps", role: "list", className: funnelStepsVariants({ size, direction }), ...props, children: steps.map((step, index2) => {
5289
4865
  const percentage = maxValue > 0 ? step.value / maxValue * 100 : 0;
@@ -5309,7 +4885,7 @@ function FunnelStepsImpl({
5309
4885
  {
5310
4886
  role: "listitem",
5311
4887
  className: "flex min-w-0 flex-1 flex-col items-center gap-1",
5312
- "aria-label": `${step.label}: ${format2(step.value)}`,
4888
+ "aria-label": `${step.label}: ${format(step.value)}`,
5313
4889
  children: [
5314
4890
  /* @__PURE__ */ jsx(
5315
4891
  "span",
@@ -5319,7 +4895,7 @@ function FunnelStepsImpl({
5319
4895
  "text-muted-foreground tabular-nums",
5320
4896
  size === "sm" ? "text-xs" : "text-sm"
5321
4897
  ),
5322
- children: format2(step.value)
4898
+ children: format(step.value)
5323
4899
  }
5324
4900
  ),
5325
4901
  /* @__PURE__ */ jsx("div", { className: funnelBarContainerHorizontalVariants({ size }), children: /* @__PURE__ */ jsx(
@@ -5351,10 +4927,10 @@ function FunnelStepsImpl({
5351
4927
  )
5352
4928
  ]
5353
4929
  }
5354
- ) : /* @__PURE__ */ jsxs("div", { role: "listitem", "aria-label": `${step.label}: ${format2(step.value)}`, children: [
4930
+ ) : /* @__PURE__ */ jsxs("div", { role: "listitem", "aria-label": `${step.label}: ${format(step.value)}`, children: [
5355
4931
  /* @__PURE__ */ jsxs("div", { className: funnelLabelVariants({ size }), children: [
5356
4932
  /* @__PURE__ */ jsx("span", { className: "truncate", children: step.label }),
5357
- /* @__PURE__ */ jsx("span", { "data-slot": "funnel-value", className: "tabular-nums", children: format2(step.value) })
4933
+ /* @__PURE__ */ jsx("span", { "data-slot": "funnel-value", className: "tabular-nums", children: format(step.value) })
5358
4934
  ] }),
5359
4935
  /* @__PURE__ */ jsx("div", { className: "relative w-full overflow-hidden rounded-sm bg-muted", children: /* @__PURE__ */ jsx(
5360
4936
  "div",
@@ -5378,13 +4954,7 @@ function FunnelStepsImpl({
5378
4954
  children: [
5379
4955
  "\u2192 ",
5380
4956
  computeConversionRate(steps[index2 + 1].value, step.value),
5381
- previous && /* @__PURE__ */ jsxs("span", { "data-slot": "funnel-change", className: "ml-1 tabular-nums", children: [
5382
- "(",
5383
- comparisonLabel2,
5384
- "\u6BD4 ",
5385
- formatPoints(conversionChange(values, previous, index2 + 1)),
5386
- ")"
5387
- ] })
4957
+ previous && /* @__PURE__ */ jsx("span", { "data-slot": "funnel-change", className: "ml-1 tabular-nums", children: t.change(comparisonLabel2, formatPoints(conversionChange(values, previous, index2 + 1), locale)) })
5388
4958
  ]
5389
4959
  }
5390
4960
  ) })
@@ -5401,7 +4971,7 @@ function FunnelStepsImpl({
5401
4971
  emptyState,
5402
4972
  height: ready ? "auto" : FRAME_HEIGHT[size ?? "md"],
5403
4973
  variant: "list",
5404
- ariaLabel: ariaLabel ?? "\u30D5\u30A1\u30CD\u30EB",
4974
+ ariaLabel: ariaLabel ?? t.funnel,
5405
4975
  plotRole: "group",
5406
4976
  dataTable,
5407
4977
  className,
@@ -5518,8 +5088,26 @@ function heatmapCellFontSize(plotWidth, columns, rowNames, texts) {
5518
5088
  if (text + HEATMAP_CELL_PADDING <= cell) return 12;
5519
5089
  return text * 10 / 12 + HEATMAP_CELL_PADDING <= cell ? 10 : null;
5520
5090
  }
5091
+ var TEXT13 = {
5092
+ ja: {
5093
+ join: "\u30FB",
5094
+ flagged: "\u8981\u6CE8\u610F",
5095
+ item: "\u9805\u76EE",
5096
+ top: (y, x, value) => `\u6700\u5927\u306F ${y} ${x} \u306E ${value}`,
5097
+ chart: (y, x) => `${y}\xD7${x}\u306E\u30D2\u30FC\u30C8\u30DE\u30C3\u30D7`
5098
+ },
5099
+ en: {
5100
+ join: ", ",
5101
+ flagged: "Needs attention",
5102
+ item: "Item",
5103
+ top: (y, x, value) => `Highest: ${y} ${x} (${value})`,
5104
+ chart: (y, x) => `Heatmap of ${y} \xD7 ${x}`
5105
+ }
5106
+ };
5107
+ var textOf3 = (locale) => TEXT13[uiLanguage(resolveLocale(locale))];
5521
5108
  function buildHeatmapOption(config) {
5522
5109
  const { model, labels, valueFormatter } = config;
5110
+ const t = textOf3(config.locale);
5523
5111
  const label2 = (key) => labels?.[key] ?? key;
5524
5112
  const present = model.cells.filter((c) => c.value !== null);
5525
5113
  const missing = model.cells.filter((c) => c.value === null);
@@ -5533,9 +5121,9 @@ function buildHeatmapOption(config) {
5533
5121
  const extras = (config.details ?? []).map((key) => {
5534
5122
  const n = cell.row ? toChartNumber(cell.row[key]) : null;
5535
5123
  return `${escapeHtml2(label2(key))} ${n === null ? EMPTY_VALUE : escapeHtml2(valueFormatter(n))}`;
5536
- }).join("\u30FB");
5537
- const flag = cell.flagged ? "\u30FB\u8981\u6CE8\u610F" : "";
5538
- return `${head} ${main}${extras ? `\u30FB${extras}` : ""}${flag}`;
5124
+ }).join(t.join);
5125
+ const flag = cell.flagged ? `${t.join}${t.flagged}` : "";
5126
+ return `${head} ${main}${extras ? `${t.join}${extras}` : ""}${flag}`;
5539
5127
  };
5540
5128
  const cellFont = config.plotWidth ? heatmapCellFontSize(
5541
5129
  config.plotWidth,
@@ -5633,7 +5221,7 @@ function mergeDeep(a, b) {
5633
5221
  }
5634
5222
  return out;
5635
5223
  }
5636
- function heatmapDataTable(model, names, formatter, labels) {
5224
+ function heatmapDataTable(model, names, formatter, labels, locale) {
5637
5225
  const label2 = (key) => labels?.[key] ?? key;
5638
5226
  const rows = model.ys.map((yk, yi) => [
5639
5227
  label2(yk),
@@ -5642,15 +5230,15 @@ function heatmapDataTable(model, names, formatter, labels) {
5642
5230
  return v === null || v === void 0 ? EMPTY_VALUE : formatter(v);
5643
5231
  })
5644
5232
  ]);
5645
- return { caption: `${label2(names.y)}\xD7${label2(names.x)}`, columns: [labels?.[names.y] ?? "\u9805\u76EE", ...model.xs.map(label2)], rows };
5233
+ return { caption: `${label2(names.y)}\xD7${label2(names.x)}`, columns: [labels?.[names.y] ?? textOf3(locale).item, ...model.xs.map(label2)], rows };
5646
5234
  }
5647
- function buildHeatmapSummary(model, formatter, title, labels) {
5235
+ function buildHeatmapSummary(model, formatter, title, labels, locale) {
5648
5236
  let best;
5649
5237
  for (const cell of model.cells) if (cell.value !== null && (!best || cell.value > best.value)) best = cell;
5650
5238
  if (!best) return void 0;
5651
5239
  const label2 = (key) => labels?.[key] ?? key;
5652
5240
  const head = title ? `${title}: ` : "";
5653
- return `${head}\u6700\u5927\u306F ${label2(model.ys[best.yi])} ${label2(model.xs[best.xi])} \u306E ${formatter(best.value)}`;
5241
+ return `${head}${textOf3(locale).top(label2(model.ys[best.yi]), label2(model.xs[best.xi]), formatter(best.value))}`;
5654
5242
  }
5655
5243
  function colorsFor(tokens, tone) {
5656
5244
  const [color = "", flag = "", muted = ""] = resolveChartColors([tone, "negative", "var(--muted-foreground)"], tokens);
@@ -5665,7 +5253,7 @@ function HeatmapImpl({
5665
5253
  xLabels,
5666
5254
  yLabels,
5667
5255
  labels,
5668
- format: format2,
5256
+ format,
5669
5257
  valueFormatter,
5670
5258
  tone = "chart-1",
5671
5259
  scale,
@@ -5688,9 +5276,9 @@ function HeatmapImpl({
5688
5276
  ariaLabel,
5689
5277
  ...rest
5690
5278
  }, ref) {
5691
- const tokens = useChartTokens();
5692
- const { ref: frameRef, surface, width: plotWidth } = useChartSurface(ref, tokens);
5693
- const formatter = useMemo(() => resolveValueFormatter(valueFormatter, format2 ?? "number"), [valueFormatter, format2]);
5279
+ const { ref: frameRef, surface, width: plotWidth, tokens } = useChartSurface(ref);
5280
+ const locale = useLocale();
5281
+ const formatter = useMemo(() => resolveValueFormatter(valueFormatter, format ?? "number", locale), [valueFormatter, format, locale]);
5694
5282
  const model = useMemo(
5695
5283
  () => buildHeatmapModel({ data, x, y, value, xLabels, yLabels, flag, scale, minValue, maxValue }),
5696
5284
  [data, x, y, value, xLabels, yLabels, flag, scale?.min, scale?.max, minValue, maxValue]
@@ -5711,16 +5299,17 @@ function HeatmapImpl({
5711
5299
  showValues,
5712
5300
  showTooltip,
5713
5301
  plotWidth,
5714
- chartOptions
5302
+ chartOptions,
5303
+ locale
5715
5304
  }),
5716
- [model, x, y, value, colors, surface, tokens, labels, formatter, details, showValues, showTooltip, plotWidth, chartOptions]
5305
+ [model, x, y, value, colors, surface, tokens, labels, formatter, details, showValues, showTooltip, plotWidth, chartOptions, locale]
5717
5306
  );
5718
- const dataTable = useMemo(() => heatmapDataTable(model, { x, y }, formatter, labels), [model, x, y, formatter, labels]);
5307
+ const dataTable = useMemo(() => heatmapDataTable(model, { x, y }, formatter, labels, locale), [model, x, y, formatter, labels, locale]);
5719
5308
  const resolvedSummary = useMemo(
5720
- () => summary === "auto" ? buildHeatmapSummary(model, formatter, title, labels) : summary,
5721
- [summary, model, formatter, title, labels]
5309
+ () => summary === "auto" ? buildHeatmapSummary(model, formatter, title, labels, locale) : summary,
5310
+ [summary, model, formatter, title, labels, locale]
5722
5311
  );
5723
- const label2 = ariaLabel ?? `${labels?.[y] ?? y}\xD7${labels?.[x] ?? x}\u306E\u30D2\u30FC\u30C8\u30DE\u30C3\u30D7`;
5312
+ const label2 = ariaLabel ?? textOf3(locale).chart(labels?.[y] ?? y, labels?.[x] ?? x);
5724
5313
  const legend = showLegend ? /* @__PURE__ */ jsx(HeatmapLegend, { model, formatter, tone }) : null;
5725
5314
  return /* @__PURE__ */ jsx(
5726
5315
  ChartFrame,
@@ -5758,174 +5347,68 @@ function HeatmapLegend({
5758
5347
  }
5759
5348
  var Heatmap = forwardRef(HeatmapImpl);
5760
5349
  Heatmap.displayName = "Heatmap";
5761
- var VB_WIDTH = 100;
5762
- function normalizeData(values, height, vPad = 2) {
5763
- const min = Math.min(...values);
5764
- const max = Math.max(...values);
5765
- const range = max - min;
5766
- const drawHeight = height - vPad * 2;
5767
- if (range === 0) return values.map(() => vPad + drawHeight / 2);
5768
- return values.map((v) => height - vPad - (v - min) / range * drawHeight);
5769
- }
5770
- function buildLinePath(ys) {
5771
- if (ys.length === 0) return "";
5772
- const step = ys.length > 1 ? VB_WIDTH / (ys.length - 1) : 0;
5773
- return ys.map((y, i) => `${i === 0 ? "M" : "L"}${(i * step).toFixed(2)},${y.toFixed(2)}`).join(" ");
5774
- }
5775
- function buildAreaPath(ys, height) {
5776
- if (ys.length === 0) return "";
5777
- const step = ys.length > 1 ? VB_WIDTH / (ys.length - 1) : 0;
5778
- const lastX = ((ys.length - 1) * step).toFixed(2);
5779
- return `${buildLinePath(ys)} L${lastX},${height} L0,${height} Z`;
5780
- }
5781
- function sparklineHighlightPoints(values) {
5782
- if (values.length === 0) return [];
5783
- const last = values.length - 1;
5784
- const points = [{ kind: "latest", index: last }];
5785
- let maxI = 0;
5786
- let minI = 0;
5787
- let max = values[0];
5788
- let min = max;
5789
- values.forEach((v, i) => {
5790
- if (v >= max) [max, maxI] = [v, i];
5791
- if (v <= min) [min, minI] = [v, i];
5792
- });
5793
- const latest = values[last];
5794
- if (max === min) return points;
5795
- if (max !== latest) points.push({ kind: "max", index: maxI });
5796
- if (min !== latest) points.push({ kind: "min", index: minI });
5797
- return points;
5798
- }
5799
- function buildBarRects(ys, height, gap = 1) {
5800
- const barW = Math.max(1, VB_WIDTH / ys.length - gap);
5801
- return ys.map((y, i) => ({ x: i * (barW + gap), y, w: barW, h: height - y }));
5802
- }
5803
- var NO_ROWS12 = [];
5804
- var Sparkline = forwardRef(function Sparkline2({
5805
- data = NO_ROWS12,
5806
- variant = "line",
5807
- height = 40,
5808
- color = "text-chart-1",
5809
- area = false,
5810
- animate = false,
5811
- highlight = "auto",
5812
- "aria-label": ariaLabel,
5813
- className,
5814
- ...props
5815
- }, ref) {
5816
- const [mounted, setMounted] = useState(false);
5817
- useEffect(() => {
5818
- if (animate) setMounted(true);
5819
- }, [animate]);
5820
- if (data.length === 0) return null;
5821
- const values = data.map((d) => d.value);
5822
- const ys = normalizeData(values, height);
5823
- const step = ys.length > 1 ? VB_WIDTH / (ys.length - 1) : 0;
5824
- const points = variant !== "line" ? [] : highlight === "auto" ? sparklineHighlightPoints(values) : highlight === "latest" ? [{ kind: "latest", index: values.length - 1 }] : [];
5825
- return /* @__PURE__ */ jsxs(
5826
- "svg",
5827
- {
5828
- ref,
5829
- "data-slot": "sparkline",
5830
- viewBox: `0 0 ${VB_WIDTH} ${height}`,
5831
- preserveAspectRatio: "none",
5832
- width: "100%",
5833
- height,
5834
- role: ariaLabel ? "img" : void 0,
5835
- "aria-label": ariaLabel,
5836
- "aria-hidden": ariaLabel ? void 0 : true,
5837
- className: cn("overflow-visible", className),
5838
- ...props,
5839
- children: [
5840
- variant === "line" && /* @__PURE__ */ jsxs(Fragment, { children: [
5841
- area && /* @__PURE__ */ jsx(
5842
- "path",
5843
- {
5844
- d: buildAreaPath(ys, height),
5845
- strokeWidth: 0,
5846
- className: cn("fill-current opacity-15", color)
5847
- }
5848
- ),
5849
- /* @__PURE__ */ jsx(
5850
- "path",
5851
- {
5852
- d: buildLinePath(ys),
5853
- fill: "none",
5854
- strokeWidth: 1.5,
5855
- strokeLinecap: "round",
5856
- strokeLinejoin: "round",
5857
- vectorEffect: "non-scaling-stroke",
5858
- pathLength: animate ? 1 : void 0,
5859
- strokeDasharray: animate ? 1 : void 0,
5860
- strokeDashoffset: animate ? mounted ? 0 : 1 : void 0,
5861
- className: cn("stroke-current", animate && "motion-reduce:transition-none!", color),
5862
- style: animate ? { transition: "stroke-dashoffset 0.6s ease-in-out" } : void 0
5863
- }
5864
- ),
5865
- points.map((p) => {
5866
- const x = (p.index * step).toFixed(2);
5867
- const y = (ys[p.index] ?? 0).toFixed(2);
5868
- return /* @__PURE__ */ jsx(
5869
- "path",
5870
- {
5871
- "data-slot": "sparkline-point",
5872
- "data-point": p.kind,
5873
- d: `M${x},${y} L${x},${y}`,
5874
- fill: "none",
5875
- strokeWidth: p.kind === "latest" ? 5 : 4,
5876
- strokeLinecap: "round",
5877
- vectorEffect: "non-scaling-stroke",
5878
- className: cn("stroke-current", p.kind === "latest" ? color : "text-muted-foreground")
5879
- },
5880
- p.kind
5881
- );
5882
- })
5883
- ] }),
5884
- variant === "bar" && buildBarRects(ys, height).map((rect, i) => /* @__PURE__ */ jsx(
5885
- "rect",
5886
- {
5887
- x: rect.x,
5888
- y: animate ? mounted ? rect.y : height : rect.y,
5889
- width: rect.w,
5890
- height: animate ? mounted ? rect.h : 0 : rect.h,
5891
- rx: 0.5,
5892
- className: cn("fill-current", animate && "motion-reduce:transition-none!", color),
5893
- style: animate ? {
5894
- transition: `height 0.4s ease-out ${i * 0.02}s, y 0.4s ease-out ${i * 0.02}s`
5895
- } : void 0
5896
- },
5897
- i
5898
- ))
5899
- ]
5900
- }
5901
- );
5902
- });
5903
- Sparkline.displayName = "Sparkline";
5904
- function resolveFormat(format2, row) {
5905
- return typeof format2 === "function" ? format2(row) : format2;
5350
+ var TEXT14 = {
5351
+ ja: {
5352
+ tones: { positive: "\u826F\u597D", warning: "\u6CE8\u610F", negative: "\u8981\u5BFE\u5FDC", neutral: "\u4E2D\u7ACB" },
5353
+ toneNote: (label2) => `\uFF08${label2}\uFF09`,
5354
+ selectAll: "\u5168\u3066\u9078\u629E",
5355
+ selectRow: "\u884C\u3092\u9078\u629E",
5356
+ trend: (points, first, last, min, max) => `${points}\u70B9\u306E\u63A8\u79FB\u3001${first}\u304B\u3089${last}\u3001\u6700\u5C0F${min}\u3001\u6700\u5927${max}`,
5357
+ noData: "\u30C7\u30FC\u30BF\u304C\u3042\u308A\u307E\u305B\u3093",
5358
+ pageSize: (size) => `${size}\u4EF6`,
5359
+ range: (total, start, end) => `${total}\u4EF6\u4E2D ${start} - ${end} \u3092\u8868\u793A`,
5360
+ first: "\u6700\u521D",
5361
+ previous: "\u524D\u3078",
5362
+ next: "\u6B21\u3078",
5363
+ last: "\u6700\u5F8C",
5364
+ columns: "\u8868\u793A\u3059\u308B\u5217",
5365
+ exportCsv: "CSV \u3092\u66F8\u304D\u51FA\u3059"
5366
+ },
5367
+ en: {
5368
+ tones: { positive: "Good", warning: "Caution", negative: "Needs action", neutral: "Neutral" },
5369
+ toneNote: (label2) => ` (${label2})`,
5370
+ selectAll: "Select all",
5371
+ selectRow: "Select row",
5372
+ trend: (points, first, last, min, max) => `Trend over ${points} points: ${first} to ${last}, min ${min}, max ${max}`,
5373
+ noData: "No results.",
5374
+ pageSize: (size) => `${size} / page`,
5375
+ range: (total, start, end) => `Showing ${start}\u2013${end} of ${total}`,
5376
+ first: "First",
5377
+ previous: "Previous",
5378
+ next: "Next",
5379
+ last: "Last",
5380
+ columns: "Columns",
5381
+ exportCsv: "Export CSV"
5382
+ }
5383
+ };
5384
+ var useText = () => TEXT14[uiLanguage(useLocale())];
5385
+ function resolveFormat(format, row) {
5386
+ return typeof format === "function" ? format(row) : format;
5906
5387
  }
5907
5388
  function isMissingCell(value) {
5908
5389
  return value === null || value === void 0 || value === "" || typeof value === "number" && Number.isNaN(value);
5909
5390
  }
5910
- function formatCellText(value, row, meta) {
5391
+ function formatCellText(value, row, meta, locale) {
5911
5392
  if (isMissingCell(value)) return meta.nullLabel ?? EMPTY_VALUE;
5912
5393
  if (meta.dateFormat && (value instanceof Date || typeof value === "string" || typeof value === "number")) {
5913
- const text = formatDate(value, meta.dateFormat, void 0, { timeZone: meta.timeZone });
5394
+ const text = formatDate(value, meta.dateFormat, locale, { timeZone: meta.timeZone });
5914
5395
  return text === EMPTY_VALUE ? String(value) : text;
5915
5396
  }
5916
5397
  if (typeof value !== "number") return String(value);
5917
- return formatValue(value, resolveFormat(meta.format, row));
5398
+ return formatValue(value, resolveFormat(meta.format, row), locale);
5918
5399
  }
5919
5400
  var THRESHOLD_TONE_STYLES = {
5920
- positive: { Icon: CircleCheck, text: "text-positive", label: "\u826F\u597D" },
5921
- warning: { Icon: TriangleAlert, text: "text-warning", label: "\u6CE8\u610F" },
5922
- negative: { Icon: CircleX, text: "text-negative", label: "\u8981\u5BFE\u5FDC" },
5923
- neutral: { Icon: Minus, text: "text-neutral", label: "\u4E2D\u7ACB" }
5401
+ positive: { Icon: CircleCheck, text: "text-positive" },
5402
+ warning: { Icon: TriangleAlert, text: "text-warning" },
5403
+ negative: { Icon: CircleX, text: "text-negative" },
5404
+ neutral: { Icon: Minus, text: "text-neutral" }
5924
5405
  };
5925
5406
  function ThresholdCell({ value, text, thresholds }) {
5407
+ const t = useText();
5926
5408
  const tone = typeof value === "number" ? toneForValue(value, thresholds) : void 0;
5927
5409
  if (!tone) return /* @__PURE__ */ jsx("div", { className: "text-right tabular-nums", children: text });
5928
- const { Icon, text: toneClass, label: label2 } = THRESHOLD_TONE_STYLES[tone];
5410
+ const { Icon, text: toneClass } = THRESHOLD_TONE_STYLES[tone];
5411
+ const label2 = t.tones[tone];
5929
5412
  return /* @__PURE__ */ jsxs(
5930
5413
  "div",
5931
5414
  {
@@ -5935,11 +5418,7 @@ function ThresholdCell({ value, text, thresholds }) {
5935
5418
  children: [
5936
5419
  /* @__PURE__ */ jsx(Icon, { className: "size-3.5 shrink-0", "aria-hidden": "true" }),
5937
5420
  /* @__PURE__ */ jsx("span", { children: text }),
5938
- /* @__PURE__ */ jsxs("span", { className: "sr-only", children: [
5939
- "\uFF08",
5940
- label2,
5941
- "\uFF09"
5942
- ] })
5421
+ /* @__PURE__ */ jsx("span", { className: "sr-only", children: t.toneNote(label2) })
5943
5422
  ]
5944
5423
  }
5945
5424
  );
@@ -5965,10 +5444,10 @@ function useDataTable() {
5965
5444
  if (!ctx) throw new Error("useDataTable must be used inside <DataTable>");
5966
5445
  return ctx;
5967
5446
  }
5968
- var NO_ROWS13 = [];
5447
+ var NO_ROWS12 = [];
5969
5448
  function DataTable({
5970
- columns = NO_ROWS13,
5971
- data = NO_ROWS13,
5449
+ columns = NO_ROWS12,
5450
+ data = NO_ROWS12,
5972
5451
  enableSorting = true,
5973
5452
  sorting: sortingProp,
5974
5453
  onSortingChange,
@@ -5994,6 +5473,8 @@ function DataTable({
5994
5473
  className,
5995
5474
  children
5996
5475
  }) {
5476
+ const locale = useLocale();
5477
+ const t = TEXT14[uiLanguage(locale)];
5997
5478
  const [sorting, setSorting] = useControlledState(sortingProp, [], onSortingChange);
5998
5479
  const [columnFilters, setColumnFilters] = useControlledState(
5999
5480
  columnFiltersProp,
@@ -6032,7 +5513,7 @@ function DataTable({
6032
5513
  ...column,
6033
5514
  cell: ({ row, getValue }) => {
6034
5515
  const value = getValue();
6035
- const text = formatCellText(value, row.original, meta2 ?? {});
5516
+ const text = formatCellText(value, row.original, meta2 ?? {}, locale);
6036
5517
  if (thresholds) return /* @__PURE__ */ jsx(ThresholdCell, { value, text, thresholds });
6037
5518
  if (aligned) return /* @__PURE__ */ jsx("div", { className: "text-right tabular-nums", children: text });
6038
5519
  if (meta2?.dateFormat) return /* @__PURE__ */ jsx("span", { className: "tabular-nums", children: text });
@@ -6049,7 +5530,7 @@ function DataTable({
6049
5530
  checked: table2.getIsAllPageRowsSelected(),
6050
5531
  indeterminate: table2.getIsSomePageRowsSelected(),
6051
5532
  onCheckedChange: (checked) => table2.toggleAllPageRowsSelected(checked),
6052
- "aria-label": "\u5168\u3066\u9078\u629E"
5533
+ "aria-label": t.selectAll
6053
5534
  }
6054
5535
  ),
6055
5536
  cell: ({ row }) => /* @__PURE__ */ jsx(
@@ -6057,14 +5538,14 @@ function DataTable({
6057
5538
  {
6058
5539
  checked: row.getIsSelected(),
6059
5540
  onCheckedChange: (checked) => row.toggleSelected(checked),
6060
- "aria-label": "\u884C\u3092\u9078\u629E"
5541
+ "aria-label": t.selectRow
6061
5542
  }
6062
5543
  ),
6063
5544
  enableSorting: false,
6064
5545
  enableHiding: false
6065
5546
  };
6066
5547
  return [selectionColumn, ...formatted];
6067
- }, [columns, enableRowSelection]);
5548
+ }, [columns, enableRowSelection, locale, t]);
6068
5549
  const autoResetPage = enablePagination && pageCount === void 0 && rowCount === void 0;
6069
5550
  const resetKey = useRef(null);
6070
5551
  useEffect(() => {
@@ -6230,6 +5711,7 @@ function SortIcon({ sorted }) {
6230
5711
  var DataTableContent = forwardRef(
6231
5712
  ({ className, ...props }, ref) => {
6232
5713
  const { table, visibleColumnCount, isLoading, enablePagination } = useDataTable();
5714
+ const t = useText();
6233
5715
  const { comparisonOf, comparisonIds } = pairComparisons(table.getVisibleLeafColumns());
6234
5716
  return /* @__PURE__ */ jsx(
6235
5717
  "div",
@@ -6310,7 +5792,7 @@ var DataTableContent = forwardRef(
6310
5792
  {
6311
5793
  colSpan: visibleColumnCount,
6312
5794
  className: "h-24 text-center text-muted-foreground",
6313
- children: "\u30C7\u30FC\u30BF\u304C\u3042\u308A\u307E\u305B\u3093"
5795
+ children: t.noData
6314
5796
  }
6315
5797
  ) }) })
6316
5798
  ] })
@@ -6322,6 +5804,7 @@ DataTableContent.displayName = "DataTableContent";
6322
5804
  var DataTablePagination = forwardRef(
6323
5805
  ({ pageSizeOptions = [10, 20, 50], className, ...props }, ref) => {
6324
5806
  const { table, isLoading } = useDataTable();
5807
+ const t = useText();
6325
5808
  const totalRows = table.options.rowCount !== void 0 ? table.getRowCount() : table.getFilteredRowModel().rows.length;
6326
5809
  const currentPageSize = table.getState().pagination.pageSize;
6327
5810
  const currentPageIndex = table.getState().pagination.pageIndex;
@@ -6329,7 +5812,7 @@ var DataTablePagination = forwardRef(
6329
5812
  const rangeEnd = Math.min((currentPageIndex + 1) * currentPageSize, totalRows);
6330
5813
  const pageSizeItems = pageSizeOptions.map((size) => ({
6331
5814
  value: String(size),
6332
- label: `${size}\u4EF6`
5815
+ label: t.pageSize(size)
6333
5816
  }));
6334
5817
  return /* @__PURE__ */ jsxs(
6335
5818
  "div",
@@ -6341,14 +5824,7 @@ var DataTablePagination = forwardRef(
6341
5824
  ...props,
6342
5825
  children: [
6343
5826
  /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2 text-sm text-muted-foreground", children: [
6344
- /* @__PURE__ */ jsxs("span", { children: [
6345
- totalRows,
6346
- "\u4EF6\u4E2D ",
6347
- rangeStart,
6348
- " - ",
6349
- rangeEnd,
6350
- " \u3092\u8868\u793A"
6351
- ] }),
5827
+ /* @__PURE__ */ jsx("span", { children: t.range(totalRows, rangeStart, rangeEnd) }),
6352
5828
  /* @__PURE__ */ jsxs(
6353
5829
  Select,
6354
5830
  {
@@ -6356,7 +5832,7 @@ var DataTablePagination = forwardRef(
6356
5832
  value: String(currentPageSize),
6357
5833
  onValueChange: (value) => table.setPageSize(Number(value)),
6358
5834
  children: [
6359
- /* @__PURE__ */ jsx(SelectTrigger, { size: "sm", className: "w-[80px]", children: /* @__PURE__ */ jsx(SelectValue, {}) }),
5835
+ /* @__PURE__ */ jsx(SelectTrigger, { size: "sm", className: "min-w-[80px]", children: /* @__PURE__ */ jsx(SelectValue, {}) }),
6360
5836
  /* @__PURE__ */ jsx(SelectContent, { children: pageSizeItems.map((item) => /* @__PURE__ */ jsx(SelectItem, { value: item.value, children: item.label }, item.value)) })
6361
5837
  ]
6362
5838
  }
@@ -6370,7 +5846,7 @@ var DataTablePagination = forwardRef(
6370
5846
  size: "sm",
6371
5847
  onClick: () => table.firstPage(),
6372
5848
  disabled: isLoading || !table.getCanPreviousPage(),
6373
- children: "\u6700\u521D"
5849
+ children: t.first
6374
5850
  }
6375
5851
  ),
6376
5852
  /* @__PURE__ */ jsx(
@@ -6380,7 +5856,7 @@ var DataTablePagination = forwardRef(
6380
5856
  size: "sm",
6381
5857
  onClick: () => table.previousPage(),
6382
5858
  disabled: isLoading || !table.getCanPreviousPage(),
6383
- children: "\u524D\u3078"
5859
+ children: t.previous
6384
5860
  }
6385
5861
  ),
6386
5862
  /* @__PURE__ */ jsx(
@@ -6390,7 +5866,7 @@ var DataTablePagination = forwardRef(
6390
5866
  size: "sm",
6391
5867
  onClick: () => table.nextPage(),
6392
5868
  disabled: isLoading || !table.getCanNextPage(),
6393
- children: "\u6B21\u3078"
5869
+ children: t.next
6394
5870
  }
6395
5871
  ),
6396
5872
  /* @__PURE__ */ jsx(
@@ -6400,7 +5876,7 @@ var DataTablePagination = forwardRef(
6400
5876
  size: "sm",
6401
5877
  onClick: () => table.lastPage(),
6402
5878
  disabled: isLoading || !table.getCanNextPage(),
6403
- children: "\u6700\u5F8C"
5879
+ children: t.last
6404
5880
  }
6405
5881
  )
6406
5882
  ] })
@@ -6412,6 +5888,7 @@ var DataTablePagination = forwardRef(
6412
5888
  DataTablePagination.displayName = "DataTablePagination";
6413
5889
  var DataTableColumnVisibility = forwardRef(({ columnLabels, className }, ref) => {
6414
5890
  const { table } = useDataTable();
5891
+ const t = useText();
6415
5892
  const hideableColumns = table.getAllColumns().filter((column) => column.getCanHide());
6416
5893
  if (hideableColumns.length === 0) return null;
6417
5894
  return /* @__PURE__ */ jsxs(DropdownMenu, { children: [
@@ -6421,7 +5898,7 @@ var DataTableColumnVisibility = forwardRef(({ columnLabels, className }, ref) =>
6421
5898
  ref,
6422
5899
  render: /* @__PURE__ */ jsx(Button, { variant: "outline", size: "sm", className: cn(className) }),
6423
5900
  "data-slot": "data-table-column-visibility",
6424
- "aria-label": "\u8868\u793A\u3059\u308B\u5217",
5901
+ "aria-label": t.columns,
6425
5902
  children: /* @__PURE__ */ jsx(Columns3, { className: "size-4", "aria-hidden": "true" })
6426
5903
  }
6427
5904
  ),
@@ -6456,7 +5933,8 @@ function toCsv(header, rows, options = {}) {
6456
5933
  ];
6457
5934
  return (bom ? "\uFEFF" : "") + lines.join("\r\n");
6458
5935
  }
6459
- function tableToCsv(table, { values = "display", scope = "filtered" } = {}) {
5936
+ function tableToCsv(table, { values = "display", scope = "filtered", locale: localeArg } = {}) {
5937
+ const locale = resolveLocale(localeArg);
6460
5938
  const columns = table.getVisibleLeafColumns().filter((column) => column.id !== "_select");
6461
5939
  const rows = scope === "page" ? table.getRowModel().rows : table.getSortedRowModel().rows;
6462
5940
  const header = columns.map(
@@ -6466,7 +5944,7 @@ function tableToCsv(table, { values = "display", scope = "filtered" } = {}) {
6466
5944
  (row) => columns.map((column) => {
6467
5945
  const value = row.getValue(column.id);
6468
5946
  const meta = column.columnDef.meta;
6469
- if (values === "display" && (meta?.format || meta?.dateFormat)) return formatCellText(value, row.original, meta);
5947
+ if (values === "display" && (meta?.format || meta?.dateFormat)) return formatCellText(value, row.original, meta, locale);
6470
5948
  if (value === null || value === void 0) return "";
6471
5949
  if (typeof value === "number" || typeof value === "string") return value;
6472
5950
  if (value instanceof Date) return value.toISOString();
@@ -6479,12 +5957,13 @@ function DataTableExport({
6479
5957
  fileName = "export.csv",
6480
5958
  values = "display",
6481
5959
  scope = "filtered",
6482
- children = "CSV \u3092\u66F8\u304D\u51FA\u3059",
5960
+ children,
6483
5961
  className
6484
5962
  }) {
6485
5963
  const { table, isLoading } = useDataTable();
5964
+ const locale = useLocale();
6486
5965
  const onClick = () => {
6487
- const csv = tableToCsv(table, { values, scope });
5966
+ const csv = tableToCsv(table, { values, scope, locale });
6488
5967
  const url = URL.createObjectURL(new Blob([csv], { type: "text/csv;charset=utf-8" }));
6489
5968
  const a = document.createElement("a");
6490
5969
  a.href = url;
@@ -6504,7 +5983,7 @@ function DataTableExport({
6504
5983
  disabled: isLoading,
6505
5984
  children: [
6506
5985
  /* @__PURE__ */ jsx(Download, { className: "size-4", "aria-hidden": "true" }),
6507
- children
5986
+ children ?? TEXT14[uiLanguage(locale)].exportCsv
6508
5987
  ]
6509
5988
  }
6510
5989
  );
@@ -6539,24 +6018,44 @@ function DataTablePreset({
6539
6018
  }
6540
6019
  DataTablePreset.displayName = "DataTablePreset";
6541
6020
  var FilterBarContext = createContext(null);
6021
+ var TEXT15 = {
6022
+ ja: {
6023
+ filters: "\u30D5\u30A3\u30EB\u30BF\u30FC",
6024
+ selected: (count) => ` (${count}\u4EF6\u9078\u629E\u4E2D)`,
6025
+ remove: (filter, option) => `${filter}: ${option} \u3092\u524A\u9664`,
6026
+ clear: "\u30AF\u30EA\u30A2",
6027
+ clearAll: "\u3059\u3079\u3066\u306E\u30D5\u30A3\u30EB\u30BF\u30FC\u3092\u30AF\u30EA\u30A2"
6028
+ },
6029
+ en: {
6030
+ filters: "Filters",
6031
+ selected: (count) => ` (${count} selected)`,
6032
+ remove: (filter, option) => `Remove ${filter}: ${option}`,
6033
+ clear: "Clear",
6034
+ clearAll: "Clear all filters"
6035
+ }
6036
+ };
6037
+ var useText2 = () => TEXT15[uiLanguage(useLocale())];
6542
6038
  function useFilterBar() {
6543
6039
  const ctx = useContext(FilterBarContext);
6544
6040
  if (!ctx) throw new Error("useFilterBar must be used within <FilterBar>");
6545
6041
  return ctx;
6546
6042
  }
6547
6043
  var FilterBar = forwardRef(
6548
- ({ value, onChange, onClear, className, children, ...props }, ref) => /* @__PURE__ */ jsx(FilterBarContext.Provider, { value: { value, onChange, onClear }, children: /* @__PURE__ */ jsx(
6549
- "div",
6550
- {
6551
- ref,
6552
- role: "search",
6553
- "aria-label": "\u30D5\u30A3\u30EB\u30BF\u30FC",
6554
- "data-slot": "filter-bar",
6555
- className: cn("flex flex-wrap items-center gap-2", className),
6556
- ...props,
6557
- children
6558
- }
6559
- ) })
6044
+ ({ value, onChange, onClear, className, children, ...props }, ref) => {
6045
+ const t = useText2();
6046
+ return /* @__PURE__ */ jsx(FilterBarContext.Provider, { value: { value, onChange, onClear }, children: /* @__PURE__ */ jsx(
6047
+ "div",
6048
+ {
6049
+ ref,
6050
+ role: "search",
6051
+ "aria-label": t.filters,
6052
+ "data-slot": "filter-bar",
6053
+ className: cn("flex flex-wrap items-center gap-2", className),
6054
+ ...props,
6055
+ children
6056
+ }
6057
+ ) });
6058
+ }
6560
6059
  );
6561
6060
  FilterBar.displayName = "FilterBar";
6562
6061
  var ALL_VALUE = "__squadkit_all__";
@@ -6598,6 +6097,7 @@ function FilterBarMultiSelect({
6598
6097
  className
6599
6098
  }) {
6600
6099
  const { value, onChange } = useFilterBar();
6100
+ const t = useText2();
6601
6101
  const selected = value[filterKey] ?? [];
6602
6102
  const handleToggle = (option) => {
6603
6103
  const next = selected.includes(option) ? selected.filter((v) => v !== option) : [...selected, option];
@@ -6608,7 +6108,7 @@ function FilterBarMultiSelect({
6608
6108
  PopoverTrigger,
6609
6109
  {
6610
6110
  render: /* @__PURE__ */ jsx(Button, { variant: "outline", size: "sm", className: cn("h-8 gap-1", className) }),
6611
- "aria-label": `${placeholder ?? label2}${selected.length > 0 ? ` (${selected.length}\u4EF6\u9078\u629E\u4E2D)` : ""}`,
6111
+ "aria-label": `${placeholder ?? label2}${selected.length > 0 ? t.selected(selected.length) : ""}`,
6612
6112
  "data-slot": "filter-bar-multi-select",
6613
6113
  children: [
6614
6114
  placeholder ?? label2,
@@ -6640,6 +6140,7 @@ function FilterBarMultiSelect({
6640
6140
  FilterBarMultiSelect.displayName = "FilterBarMultiSelect";
6641
6141
  function FilterBarActiveChips({ filters, className }) {
6642
6142
  const { value, onChange } = useFilterBar();
6143
+ const t = useText2();
6643
6144
  const getActiveChips = () => {
6644
6145
  const chips = [];
6645
6146
  const pushRaw = (key, v) => {
@@ -6710,7 +6211,7 @@ function FilterBarActiveChips({ filters, className }) {
6710
6211
  type: "button",
6711
6212
  className: "ml-0.5 rounded-full p-0.5 hover:bg-muted-foreground/20",
6712
6213
  onClick: () => handleRemoveFilter(chip.key, chip.optionValue),
6713
- "aria-label": `${chip.filterLabel}: ${chip.optionLabel} \u3092\u524A\u9664`,
6214
+ "aria-label": t.remove(chip.filterLabel, chip.optionLabel),
6714
6215
  children: /* @__PURE__ */ jsx(X, { className: "size-3", "aria-hidden": "true" })
6715
6216
  }
6716
6217
  )
@@ -6720,8 +6221,9 @@ function FilterBarActiveChips({ filters, className }) {
6720
6221
  )) });
6721
6222
  }
6722
6223
  FilterBarActiveChips.displayName = "FilterBarActiveChips";
6723
- function FilterBarClearButton({ label: label2 = "\u30AF\u30EA\u30A2", className }) {
6224
+ function FilterBarClearButton({ label: label2, className }) {
6724
6225
  const { value, onClear } = useFilterBar();
6226
+ const t = useText2();
6725
6227
  const hasActiveFilters = Object.values(value).some(
6726
6228
  (v) => Array.isArray(v) ? v.length > 0 : v !== void 0 && v !== ""
6727
6229
  );
@@ -6733,9 +6235,9 @@ function FilterBarClearButton({ label: label2 = "\u30AF\u30EA\u30A2", className
6733
6235
  size: "sm",
6734
6236
  className: cn("h-7 px-2 text-xs", className),
6735
6237
  onClick: onClear,
6736
- "aria-label": "\u3059\u3079\u3066\u306E\u30D5\u30A3\u30EB\u30BF\u30FC\u3092\u30AF\u30EA\u30A2",
6238
+ "aria-label": t.clearAll,
6737
6239
  "data-slot": "filter-bar-clear-button",
6738
- children: label2
6240
+ children: label2 ?? t.clear
6739
6241
  }
6740
6242
  );
6741
6243
  }
@@ -6783,13 +6285,16 @@ function FilterBarPreset({
6783
6285
  ] });
6784
6286
  }
6785
6287
  FilterBarPreset.displayName = "FilterBarPreset";
6786
- var DEFAULT_FISCAL_YEAR_START_MONTH = 4;
6787
- var DEFAULT_DATE_PICKER_LOCALE = "en-US";
6788
- function normalizeFiscalYearStartMonth(month) {
6789
- return typeof month === "number" && Number.isInteger(month) && month >= 1 && month <= 12 ? month : DEFAULT_FISCAL_YEAR_START_MONTH;
6790
- }
6791
- function fiscalPeriodRange(date, { unit, fiscalYearStartMonth, offset = 0 }) {
6792
- const startMonth = normalizeFiscalYearStartMonth(fiscalYearStartMonth);
6288
+ function normalizeFiscalYearStartMonth(month, locale) {
6289
+ return typeof month === "number" && Number.isInteger(month) && month >= 1 && month <= 12 ? month : defaultFiscalYearStartMonth(locale);
6290
+ }
6291
+ function fiscalPeriodRange(date, {
6292
+ unit,
6293
+ fiscalYearStartMonth,
6294
+ offset = 0,
6295
+ locale
6296
+ }) {
6297
+ const startMonth = normalizeFiscalYearStartMonth(fiscalYearStartMonth, locale);
6793
6298
  const length = unit === "year" ? 12 : 3;
6794
6299
  const sinceYearStart = (date.getMonth() - (startMonth - 1) + 12) % 12;
6795
6300
  const into = unit === "year" ? sinceYearStart : sinceYearStart % 3;
@@ -6832,16 +6337,20 @@ var PRESET_LABELS = {
6832
6337
  lastFiscalYear: "Last fiscal year"
6833
6338
  }
6834
6339
  };
6835
- var isJapanese = (locale) => locale.toLowerCase().startsWith("ja");
6836
- var WEEK_OPTIONS = { weekStartsOn: 1 };
6837
- var calendarLocale = (locale) => isJapanese(locale) ? ja : void 0;
6340
+ var TEXT16 = {
6341
+ ja: { placeholder: "\u671F\u9593\u3092\u9078\u629E", rangeSeparator: " - " },
6342
+ en: { placeholder: "Pick a date range", rangeSeparator: " \u2013 " }
6343
+ };
6344
+ var calendarLocale = (locale) => uiLanguage(locale) === "ja" ? ja : void 0;
6838
6345
  function createDatePresets({
6839
- locale = DEFAULT_DATE_PICKER_LOCALE,
6840
- fiscalYearStartMonth = DEFAULT_FISCAL_YEAR_START_MONTH,
6346
+ locale: localeArg,
6347
+ fiscalYearStartMonth,
6841
6348
  now = () => /* @__PURE__ */ new Date()
6842
6349
  } = {}) {
6843
- const t = PRESET_LABELS[isJapanese(locale) ? "ja" : "en"];
6844
- const startMonth = normalizeFiscalYearStartMonth(fiscalYearStartMonth);
6350
+ const locale = resolveLocale(localeArg);
6351
+ const t = PRESET_LABELS[uiLanguage(locale)];
6352
+ const startMonth = normalizeFiscalYearStartMonth(fiscalYearStartMonth, locale);
6353
+ const WEEK_OPTIONS = { weekStartsOn: weekStartsOn(locale) };
6845
6354
  const lastDays = (days) => () => {
6846
6355
  const today = now();
6847
6356
  return { from: startOfDay(subDays(today, days - 1)), to: endOfDay(today) };
@@ -6910,24 +6419,26 @@ function findMatchingPreset(presets, value) {
6910
6419
  return range.from != null && range.to != null && isSameDay(range.from, from) && isSameDay(range.to, to);
6911
6420
  });
6912
6421
  }
6913
- var defaultPresets = createDatePresets();
6422
+ var defaultPresets = createDatePresets({ locale: FALLBACK_LOCALE });
6914
6423
  var DateRangePicker = forwardRef(
6915
6424
  function DateRangePicker2({
6916
6425
  value,
6917
6426
  onChange,
6918
6427
  presets: presetsProp,
6919
6428
  showPresets = true,
6920
- locale = DEFAULT_DATE_PICKER_LOCALE,
6921
- fiscalYearStartMonth = DEFAULT_FISCAL_YEAR_START_MONTH,
6429
+ locale: localeProp,
6430
+ fiscalYearStartMonth,
6922
6431
  maxDate,
6923
6432
  minDate,
6924
- placeholder = "\u671F\u9593\u3092\u9078\u629E",
6433
+ placeholder,
6925
6434
  disabled = false,
6926
6435
  className,
6927
6436
  align = "start"
6928
6437
  }, ref) {
6929
6438
  const [open, setOpen] = useState(false);
6930
6439
  const isMobile = useIsMobile();
6440
+ const locale = useLocale(localeProp);
6441
+ const t = TEXT16[uiLanguage(locale)];
6931
6442
  const presets = useMemo(
6932
6443
  () => presetsProp ?? createDatePresets({ locale, fiscalYearStartMonth }),
6933
6444
  [presetsProp, locale, fiscalYearStartMonth]
@@ -6946,9 +6457,9 @@ var DateRangePicker = forwardRef(
6946
6457
  [onChange]
6947
6458
  );
6948
6459
  const formatDateRange2 = () => {
6949
- if (!value?.from) return placeholder;
6950
- if (!value.to) return format(value.from, "yyyy/MM/dd");
6951
- return `${format(value.from, "yyyy/MM/dd")} - ${format(value.to, "yyyy/MM/dd")}`;
6460
+ if (!value?.from) return placeholder ?? t.placeholder;
6461
+ if (!value.to) return formatDate(value.from, "date", locale);
6462
+ return `${formatDate(value.from, "date", locale)}${t.rangeSeparator}${formatDate(value.to, "date", locale)}`;
6952
6463
  };
6953
6464
  const selectedPreset = findMatchingPreset(presets, value);
6954
6465
  const presetLabel = selectedPreset?.label;
@@ -7009,7 +6520,7 @@ var DateRangePicker = forwardRef(
7009
6520
  mode: "range",
7010
6521
  defaultMonth,
7011
6522
  locale: calendarLocale(locale),
7012
- weekStartsOn: isJapanese(locale) ? 1 : void 0,
6523
+ weekStartsOn: weekStartsOn(locale),
7013
6524
  numberOfMonths: isMobile ? 1 : 2,
7014
6525
  selected: calendarSelected,
7015
6526
  onSelect: handleCalendarSelect,
@@ -7144,6 +6655,10 @@ function RemoveButton({ label: label2, onRemove, iconClassName }) {
7144
6655
  }
7145
6656
  );
7146
6657
  }
6658
+ var TEXT17 = {
6659
+ ja: { placeholder: "\u9078\u629E\u3057\u3066\u304F\u3060\u3055\u3044", search: "\u691C\u7D22...", empty: "\u898B\u3064\u304B\u308A\u307E\u305B\u3093\u3067\u3057\u305F", clear: "\u30AF\u30EA\u30A2" },
6660
+ en: { placeholder: "Select an option", search: "Search...", empty: "No results found.", clear: "Clear" }
6661
+ };
7147
6662
  var NO_OPTIONS2 = [];
7148
6663
  var SearchableSelect = forwardRef(
7149
6664
  function SearchableSelect2({
@@ -7151,15 +6666,16 @@ var SearchableSelect = forwardRef(
7151
6666
  value,
7152
6667
  onChange,
7153
6668
  onSearch,
7154
- placeholder = "\u9078\u629E\u3057\u3066\u304F\u3060\u3055\u3044",
7155
- searchPlaceholder = "\u691C\u7D22...",
7156
- emptyText = "\u898B\u3064\u304B\u308A\u307E\u305B\u3093\u3067\u3057\u305F",
6669
+ placeholder,
6670
+ searchPlaceholder,
6671
+ emptyText,
7157
6672
  isLoading = false,
7158
6673
  disabled = false,
7159
6674
  clearable = true,
7160
6675
  className
7161
6676
  }, ref) {
7162
6677
  const [open, setOpen] = useState(false);
6678
+ const t = TEXT17[uiLanguage(useLocale())];
7163
6679
  const allOptions = useMemo(() => flattenOptions(options), [options]);
7164
6680
  const selectedOption = useMemo(
7165
6681
  () => allOptions.find((opt) => opt.value === value),
@@ -7188,9 +6704,9 @@ var SearchableSelect = forwardRef(
7188
6704
  role: "combobox",
7189
6705
  "aria-expanded": open,
7190
6706
  children: [
7191
- /* @__PURE__ */ jsx("span", { className: "truncate", children: selectedOption ? selectedOption.label : placeholder }),
6707
+ /* @__PURE__ */ jsx("span", { className: "truncate", children: selectedOption ? selectedOption.label : placeholder ?? t.placeholder }),
7192
6708
  /* @__PURE__ */ jsxs("span", { className: "flex shrink-0 items-center gap-1", children: [
7193
- clearable && value && /* @__PURE__ */ jsx(RemoveButton, { label: "\u30AF\u30EA\u30A2", onRemove: () => onChange?.(void 0) }),
6709
+ clearable && value && /* @__PURE__ */ jsx(RemoveButton, { label: t.clear, onRemove: () => onChange?.(void 0) }),
7194
6710
  /* @__PURE__ */ jsx(ChevronDownIcon, { className: "size-4 opacity-50" })
7195
6711
  ] })
7196
6712
  ]
@@ -7204,14 +6720,30 @@ var SearchableSelect = forwardRef(
7204
6720
  onSelect: handleSelect,
7205
6721
  onSearch,
7206
6722
  isLoading,
7207
- searchPlaceholder,
7208
- emptyText
6723
+ searchPlaceholder: searchPlaceholder ?? t.search,
6724
+ emptyText: emptyText ?? t.empty
7209
6725
  }
7210
6726
  ) })
7211
6727
  ] }) });
7212
6728
  }
7213
6729
  );
7214
6730
  SearchableSelect.displayName = "SearchableSelect";
6731
+ var TEXT18 = {
6732
+ ja: {
6733
+ placeholder: "\u9078\u629E\u3057\u3066\u304F\u3060\u3055\u3044",
6734
+ search: "\u691C\u7D22...",
6735
+ empty: "\u898B\u3064\u304B\u308A\u307E\u305B\u3093\u3067\u3057\u305F",
6736
+ remove: (label2) => `${label2}\u3092\u524A\u9664`,
6737
+ more: (count) => `+${count}\u4EF6`
6738
+ },
6739
+ en: {
6740
+ placeholder: "Select options",
6741
+ search: "Search...",
6742
+ empty: "No results found.",
6743
+ remove: (label2) => `Remove ${label2}`,
6744
+ more: (count) => `+${count} more`
6745
+ }
6746
+ };
7215
6747
  var NO_OPTIONS3 = [];
7216
6748
  var NO_VALUES = [];
7217
6749
  var MultiSelect = forwardRef(function MultiSelect2({
@@ -7220,15 +6752,16 @@ var MultiSelect = forwardRef(function MultiSelect2({
7220
6752
  onChange,
7221
6753
  onSearch,
7222
6754
  maxCount = 3,
7223
- placeholder = "\u9078\u629E\u3057\u3066\u304F\u3060\u3055\u3044",
7224
- searchPlaceholder = "\u691C\u7D22...",
7225
- emptyText = "\u898B\u3064\u304B\u308A\u307E\u305B\u3093\u3067\u3057\u305F",
6755
+ placeholder,
6756
+ searchPlaceholder,
6757
+ emptyText,
7226
6758
  isLoading = false,
7227
6759
  disabled = false,
7228
6760
  className
7229
6761
  }, ref) {
7230
6762
  const [open, setOpen] = useState(false);
7231
6763
  const listId = useId();
6764
+ const t = TEXT18[uiLanguage(useLocale())];
7232
6765
  const allOptions = useMemo(() => flattenOptions(options), [options]);
7233
6766
  const selectedOptions = useMemo(
7234
6767
  () => allOptions.filter((opt) => value.includes(opt.value)),
@@ -7256,23 +6789,19 @@ var MultiSelect = forwardRef(function MultiSelect2({
7256
6789
  className
7257
6790
  ),
7258
6791
  children: [
7259
- /* @__PURE__ */ jsx("span", { className: "flex min-w-0 flex-1 flex-wrap items-center gap-1", children: selectedOptions.length === 0 ? /* @__PURE__ */ jsx("span", { className: "text-muted-foreground", children: placeholder }) : /* @__PURE__ */ jsxs(Fragment, { children: [
6792
+ /* @__PURE__ */ jsx("span", { className: "flex min-w-0 flex-1 flex-wrap items-center gap-1", children: selectedOptions.length === 0 ? /* @__PURE__ */ jsx("span", { className: "text-muted-foreground", children: placeholder ?? t.placeholder }) : /* @__PURE__ */ jsxs(Fragment, { children: [
7260
6793
  visibleBadges.map((option) => /* @__PURE__ */ jsxs(Badge, { variant: "secondary", className: "shrink-0 gap-1 pr-1", children: [
7261
6794
  /* @__PURE__ */ jsx("span", { className: "max-w-[120px] truncate", children: option.label }),
7262
6795
  /* @__PURE__ */ jsx(
7263
6796
  RemoveButton,
7264
6797
  {
7265
- label: `${option.label}\u3092\u524A\u9664`,
6798
+ label: t.remove(option.label),
7266
6799
  onRemove: () => onChange?.(value.filter((v) => v !== option.value)),
7267
6800
  iconClassName: "size-3"
7268
6801
  }
7269
6802
  )
7270
6803
  ] }, option.value)),
7271
- overflowCount > 0 && /* @__PURE__ */ jsxs(Badge, { variant: "secondary", className: "shrink-0", children: [
7272
- "+",
7273
- overflowCount,
7274
- "\u4EF6"
7275
- ] })
6804
+ overflowCount > 0 && /* @__PURE__ */ jsx(Badge, { variant: "secondary", className: "shrink-0", children: t.more(overflowCount) })
7276
6805
  ] }) }),
7277
6806
  /* @__PURE__ */ jsx(ChevronDownIcon, { className: "size-4 shrink-0 opacity-50" })
7278
6807
  ]
@@ -7286,8 +6815,8 @@ var MultiSelect = forwardRef(function MultiSelect2({
7286
6815
  onSelect: handleSelect,
7287
6816
  onSearch,
7288
6817
  isLoading,
7289
- searchPlaceholder,
7290
- emptyText
6818
+ searchPlaceholder: searchPlaceholder ?? t.search,
6819
+ emptyText: emptyText ?? t.empty
7291
6820
  }
7292
6821
  ) })
7293
6822
  ] }) });
@@ -7376,14 +6905,17 @@ function inferPeriodGrain(period) {
7376
6905
  return void 0;
7377
6906
  }
7378
6907
  var RECORD_MIN_POINTS = 6;
7379
- var GRAIN_UNITS = {
7380
- day: "\u65E5",
7381
- week: "\u9031",
7382
- month: "\u304B\u6708",
7383
- quarter: "\u56DB\u534A\u671F",
7384
- year: "\u5E74"
6908
+ var RECORD_TEXT = {
6909
+ ja: (span, grain, lower) => {
6910
+ const units = { day: "\u65E5", week: "\u9031", month: "\u304B\u6708", quarter: "\u56DB\u534A\u671F", year: "\u5E74" };
6911
+ return `\u904E\u53BB ${span} ${units[grain]}\u3067${lower ? "\u6700\u4F4E" : "\u6700\u9AD8"}`;
6912
+ },
6913
+ en: (span, grain, lower) => {
6914
+ const units = { day: "days", week: "weeks", month: "months", quarter: "quarters", year: "years" };
6915
+ return `${lower ? "Lowest" : "Highest"} in ${span} ${units[grain]}`;
6916
+ }
7385
6917
  };
7386
- function detectRecord(history, grain = "month", polarity = "higher-is-better") {
6918
+ function detectRecord(history, grain = "month", polarity = "higher-is-better", locale) {
7387
6919
  if (!history) return null;
7388
6920
  const points = history.filter(isFiniteNumber);
7389
6921
  if (points.length < RECORD_MIN_POINTS) return null;
@@ -7396,7 +6928,7 @@ function detectRecord(history, grain = "month", polarity = "higher-is-better") {
7396
6928
  span,
7397
6929
  grain,
7398
6930
  kind: lower ? "lowest" : "highest",
7399
- label: `\u904E\u53BB ${span} ${GRAIN_UNITS[grain]}\u3067${lower ? "\u6700\u4F4E" : "\u6700\u9AD8"}`
6931
+ label: RECORD_TEXT[uiLanguage(resolveLocale(locale))](span, grain, lower)
7400
6932
  };
7401
6933
  }
7402
6934
  var deltaVariants = cva(
@@ -7404,7 +6936,7 @@ var deltaVariants = cva(
7404
6936
  {
7405
6937
  variants: {
7406
6938
  variant: {
7407
- badge: "h-5 rounded-4xl px-2 py-0.5 text-xs font-semibold [&>svg]:size-3",
6939
+ badge: "h-5 rounded-md border px-2 py-0.5 text-xs font-medium [&>svg]:size-3",
7408
6940
  inline: "text-sm [&>svg]:size-3.5"
7409
6941
  },
7410
6942
  sentiment: {
@@ -7414,9 +6946,9 @@ var deltaVariants = cva(
7414
6946
  }
7415
6947
  },
7416
6948
  compoundVariants: [
7417
- { variant: "badge", sentiment: "positive", className: "bg-positive-subtle" },
7418
- { variant: "badge", sentiment: "negative", className: "bg-negative-subtle" },
7419
- { variant: "badge", sentiment: "neutral", className: "bg-neutral-subtle" }
6949
+ { variant: "badge", sentiment: "positive", className: "border-positive/20 bg-positive-subtle dark:border-positive/25" },
6950
+ { variant: "badge", sentiment: "negative", className: "border-negative/20 bg-negative-subtle dark:border-negative/25" },
6951
+ { variant: "badge", sentiment: "neutral", className: "border-neutral/20 bg-neutral-subtle dark:border-neutral/25" }
7420
6952
  ],
7421
6953
  defaultVariants: {
7422
6954
  variant: "badge",
@@ -7425,37 +6957,59 @@ var deltaVariants = cva(
7425
6957
  }
7426
6958
  );
7427
6959
  var DELTA_NOT_COMPARABLE = EMPTY_VALUE;
7428
- function deltaAriaLabel(result, locale = DEFAULT_LOCALE, change = "relative", format2, digits) {
6960
+ var ARIA_TEXT = {
6961
+ ja: {
6962
+ none: (label2) => `${label2} \u6BD4\u8F03\u3067\u304D\u307E\u305B\u3093`,
6963
+ flat: (label2) => `${label2} \u6A2A\u3070\u3044`,
6964
+ points: " \u30DD\u30A4\u30F3\u30C8",
6965
+ change: (label2, amount, up) => `${label2} ${amount} ${up ? "\u5897\u52A0" : "\u6E1B\u5C11"}`
6966
+ },
6967
+ en: {
6968
+ none: (label2) => `${label2}: not comparable`,
6969
+ flat: (label2) => `Flat ${label2}`,
6970
+ points: " points",
6971
+ change: (label2, amount, up) => `${up ? "Up" : "Down"} ${amount} ${label2}`
6972
+ }
6973
+ };
6974
+ function deltaAriaLabel(result, locale, change = "relative", format, digits) {
6975
+ const resolved = resolveLocale(locale);
6976
+ const t = ARIA_TEXT[uiLanguage(resolved)];
7429
6977
  const { label: label2, direction, ratio } = result;
7430
- if (direction === "none" || ratio === null) return `${label2} \u6BD4\u8F03\u3067\u304D\u307E\u305B\u3093`;
7431
- if (direction === "flat") return `${label2} \u6A2A\u3070\u3044`;
7432
- const amount = formatChangeAmount(result, change, locale, format2, digits);
7433
- if (amount === null) return `${label2} \u6BD4\u8F03\u3067\u304D\u307E\u305B\u3093`;
7434
- return `${label2} ${change === "points" ? amount.replace(/pt$/, " \u30DD\u30A4\u30F3\u30C8") : amount} ${direction === "up" ? "\u5897\u52A0" : "\u6E1B\u5C11"}`;
6978
+ if (direction === "none" || ratio === null) return t.none(label2);
6979
+ if (direction === "flat") return t.flat(label2);
6980
+ const amount = formatChangeAmount(result, change, resolved, format, digits);
6981
+ if (amount === null) return t.none(label2);
6982
+ return t.change(label2, change === "points" ? amount.replace(/pt$/, t.points) : amount, direction === "up");
7435
6983
  }
7436
6984
  var Delta = forwardRef(
7437
6985
  ({
7438
6986
  value,
7439
6987
  comparison,
6988
+ betterWhen,
7440
6989
  polarity,
7441
6990
  neutralBand,
7442
- format: format2,
6991
+ format,
7443
6992
  change,
7444
6993
  digits,
7445
- locale = DEFAULT_LOCALE,
6994
+ locale: localeProp,
7446
6995
  showLabel = true,
7447
6996
  variant = "badge",
7448
6997
  className,
7449
6998
  ...props
7450
6999
  }, ref) => {
7000
+ const locale = useLocale(localeProp);
7451
7001
  if (!comparison) return null;
7452
- const result = computeComparison(value, comparison, { polarity, neutralBand });
7453
- const display = change ?? defaultChangeDisplay(format2);
7454
- const formatDigits = typeof format2 === "object" && format2 !== null && "digits" in format2 ? format2.digits : void 0;
7002
+ const result = computeComparison(value, comparison, {
7003
+ polarity: betterWhen ? betterWhen === "down" ? "lower-is-better" : "higher-is-better" : polarity,
7004
+ neutralBand,
7005
+ locale
7006
+ });
7007
+ const display = change ?? defaultChangeDisplay(format);
7008
+ const formatDigits = typeof format === "object" && format !== null && "digits" in format ? format.digits : void 0;
7455
7009
  const changeDigits = display === "points" ? digits ?? formatDigits : digits;
7456
7010
  const comparable = result.direction !== "none";
7457
7011
  const Icon = result.direction === "up" ? ArrowUp : result.direction === "down" ? ArrowDown : ArrowRight;
7458
- const text = formatChange(result, display, locale, format2, changeDigits);
7012
+ const text = formatChange(result, display, locale, format, changeDigits);
7459
7013
  return /* @__PURE__ */ jsxs(
7460
7014
  "span",
7461
7015
  {
@@ -7464,7 +7018,7 @@ var Delta = forwardRef(
7464
7018
  "data-slot": "delta",
7465
7019
  "data-direction": result.direction,
7466
7020
  "data-sentiment": result.sentiment,
7467
- "aria-label": deltaAriaLabel(result, locale, display, format2, changeDigits),
7021
+ "aria-label": deltaAriaLabel(result, locale, display, format, changeDigits),
7468
7022
  className: cn(
7469
7023
  deltaVariants({ variant, sentiment: result.sentiment }),
7470
7024
  !comparable && "text-muted-foreground",
@@ -7489,7 +7043,69 @@ var LONG_VALUE_CHARS = 10;
7489
7043
  var DELTA_UNDER_PLACEMENT = "col-start-1 row-span-1 row-start-3 justify-self-start";
7490
7044
  var KPI_FOOTER_CLASS = "flex-col items-start gap-2 rounded-none border-t-0 bg-transparent pt-0 text-sm";
7491
7045
  var PLACEHOLDER = /\{(\w+)\}/g;
7492
- var isJapanese2 = (locale) => locale.toLowerCase().startsWith("ja");
7046
+ var TEXT19 = {
7047
+ ja: {
7048
+ target: "\u76EE\u6A19",
7049
+ provisional: "\u901F\u5831",
7050
+ joiner: "\u30FB",
7051
+ countFrom: (count) => `${count}\u4EF6\u304B\u3089\u96C6\u8A08`,
7052
+ excluded: (count) => `${count}\u4EF6\u3092\u9664\u5916`,
7053
+ noBaseline: (baseline) => `${baseline}\u306E\u5B9F\u7E3E\u304C\u306A\u3044\u305F\u3081\u3001\u6BD4\u8F03\u3067\u304D\u307E\u305B\u3093\u3002`,
7054
+ previous: (baseline, value) => `${baseline} ${value}`,
7055
+ noPrevious: (baseline) => `${baseline}\u306E\u5B9F\u7E3E\u306A\u3057`,
7056
+ barLead: (tl, pct) => `${tl}\u306E ${pct}`,
7057
+ pace: (pct) => `\u3053\u306E\u30DA\u30FC\u30B9\u306A\u3089 ${pct}`,
7058
+ provisionalSuffix: "\uFF08\u78BA\u5B9A\u524D\uFF09",
7059
+ provisionalReached: (tl, target) => `${tl} ${target} \u306B\u5230\u9054\uFF08\u78BA\u5B9A\u524D\uFF09`,
7060
+ provisionalSoFar: (tl, target, pct) => `${tl} ${target} \u306B\u5BFE\u3057\u3066\u73FE\u6642\u70B9 ${pct}\uFF08\u78BA\u5B9A\u524D\uFF09`,
7061
+ provisionalToGo: (tl, target, distance) => `${tl} ${target} \u307E\u3067\u3042\u3068 ${distance}\uFF08\u78BA\u5B9A\u524D\uFF09`,
7062
+ provisionalToGoRate: (tl, distance, pct) => `${tl}\u307E\u3067\u3042\u3068 ${distance}\uFF08\u73FE\u6642\u70B9 ${pct}\u30FB\u78BA\u5B9A\u524D\uFF09`,
7063
+ met: (tl, target) => `${tl} ${target} \u3092\u9054\u6210`,
7064
+ toGo: (tl, target, distance) => `${tl} ${target} \u307E\u3067\u3042\u3068 ${distance}`,
7065
+ reached: (tl, target) => `${tl} ${target} \u306B\u5230\u9054`,
7066
+ reachedRate: (tl, target, pct) => `${tl} ${target} \u306B\u5230\u9054\uFF08${pct} \u9054\u6210\uFF09`,
7067
+ toGoRate: (tl, distance, pct) => `${tl}\u307E\u3067\u3042\u3068 ${distance}\uFF08${pct} \u9054\u6210\uFF09`,
7068
+ progressLabel: (tl) => `${tl}\u306B\u5BFE\u3059\u308B\u9032\u6357`,
7069
+ progressValue: (tl, target, value, pct) => `${tl} ${target} \u306B\u5BFE\u3057\u3066 ${value}\uFF08${pct}\uFF09`,
7070
+ history: (label2, points) => `${label2}\u306E\u63A8\u79FB\uFF08\u76F4\u8FD1 ${points} \u70B9\uFF09`,
7071
+ updatedRelative: (relative2) => `${relative2}\u306B\u66F4\u65B0`,
7072
+ updatedAbsolute: (absolute2) => `${absolute2} \u306B\u66F4\u65B0`,
7073
+ updatedBoth: (absolute2, relative2) => `${absolute2} \u306B\u66F4\u65B0\uFF08${relative2}\uFF09`,
7074
+ summaryExample: "{label}\u306F\u76EE\u6A19\u306E {achievement} \u307E\u3067\u6765\u3066\u3044\u307E\u3059\u3002"
7075
+ },
7076
+ en: {
7077
+ target: "Target",
7078
+ provisional: "Preliminary",
7079
+ joiner: " \xB7 ",
7080
+ countFrom: (count) => `Based on ${count} records`,
7081
+ excluded: (count) => `${count} excluded`,
7082
+ noBaseline: (baseline) => `No ${baseline} data to compare against.`,
7083
+ previous: (baseline, value) => `${capitalize(baseline)}: ${value}`,
7084
+ noPrevious: (baseline) => `No ${baseline} data`,
7085
+ barLead: (tl, pct) => `${tl}: ${pct}`,
7086
+ pace: (pct) => `On pace for ${pct}`,
7087
+ provisionalSuffix: " (preliminary)",
7088
+ provisionalReached: (tl, target) => `${tl} ${target}: reached (preliminary)`,
7089
+ provisionalSoFar: (tl, target, pct) => `${tl} ${target}: ${pct} so far (preliminary)`,
7090
+ provisionalToGo: (tl, target, distance) => `${tl} ${target}: ${distance} to go (preliminary)`,
7091
+ provisionalToGoRate: (tl, distance, pct) => `${tl}: ${distance} to go (${pct} so far, preliminary)`,
7092
+ met: (tl, target) => `${tl} ${target}: met`,
7093
+ toGo: (tl, target, distance) => `${tl} ${target}: ${distance} to go`,
7094
+ reached: (tl, target) => `${tl} ${target}: reached`,
7095
+ reachedRate: (tl, target, pct) => `${tl} ${target}: reached (${pct} achieved)`,
7096
+ toGoRate: (tl, distance, pct) => `${tl}: ${distance} to go (${pct} achieved)`,
7097
+ progressLabel: (tl) => `Progress toward ${tl}`,
7098
+ progressValue: (tl, target, value, pct) => `${value} of ${tl} ${target} (${pct})`,
7099
+ history: (label2, points) => `${label2} trend (last ${points} points)`,
7100
+ updatedRelative: (relative2) => `Updated ${relative2}`,
7101
+ updatedAbsolute: (absolute2) => `Updated ${absolute2}`,
7102
+ updatedBoth: (absolute2, relative2) => `Updated ${absolute2} (${relative2})`,
7103
+ summaryExample: "{label} is at {achievement} of target."
7104
+ }
7105
+ };
7106
+ function capitalize(text) {
7107
+ return text.charAt(0).toUpperCase() + text.slice(1);
7108
+ }
7493
7109
  var isMissing = (v) => v === null || v === void 0 || v === "";
7494
7110
  function fillKpiTemplate(template, values, fallback) {
7495
7111
  let missing = false;
@@ -7517,11 +7133,11 @@ function isProduction() {
7517
7133
  return true;
7518
7134
  }
7519
7135
  }
7520
- function warnShallowSummary(template) {
7136
+ function warnShallowSummary(template, t) {
7521
7137
  if (shallowSummaryWarned || isProduction() || !isShallowSummary(template)) return;
7522
7138
  shallowSummaryWarned = true;
7523
7139
  console.warn(
7524
- `[KpiCard] summary="${template}" only repeats the delta badge and the previous actual. Say one fact beyond the comparison \u2014 composition, target, record or rate (e.g. "{label}\u306F\u76EE\u6A19\u306E {achievement} \u307E\u3067\u6765\u3066\u3044\u307E\u3059\u3002").`
7140
+ `[KpiCard] summary="${template}" only repeats the delta badge and the previous actual. Say one fact beyond the comparison \u2014 composition, target, record or rate (e.g. "${t.summaryExample}").`
7525
7141
  );
7526
7142
  }
7527
7143
  function digitGroups(text) {
@@ -7530,18 +7146,19 @@ function digitGroups(text) {
7530
7146
  function KpiCard({
7531
7147
  label: label2,
7532
7148
  value,
7533
- format: format2,
7534
- locale = DEFAULT_LOCALE,
7149
+ format,
7150
+ locale: localeProp,
7535
7151
  comparison: comparisonProp,
7536
7152
  comparisons,
7537
7153
  provisional,
7538
- polarity,
7154
+ betterWhen,
7155
+ polarity: polarityProp,
7539
7156
  change,
7540
7157
  neutralBand,
7541
7158
  showPrevious = true,
7542
7159
  summary,
7543
7160
  target,
7544
- targetLabel = "\u76EE\u6A19",
7161
+ targetLabel,
7545
7162
  targetDisplay,
7546
7163
  period,
7547
7164
  history,
@@ -7557,21 +7174,24 @@ function KpiCard({
7557
7174
  className,
7558
7175
  ...props
7559
7176
  }) {
7177
+ const locale = useLocale(localeProp);
7178
+ const t = TEXT19[uiLanguage(locale)];
7560
7179
  const allComparisons = [...comparisonProp ? [comparisonProp] : [], ...comparisons ?? []];
7561
7180
  const comparison = allComparisons[0];
7562
7181
  const isProvisional = provisional !== void 0 && provisional !== false;
7563
- const provisionalLabel = typeof provisional === "object" && provisional.label ? provisional.label : "\u901F\u5831";
7182
+ const provisionalLabel = typeof provisional === "object" && provisional.label ? provisional.label : t.provisional;
7564
7183
  const sample = useSampleMark();
7184
+ const polarity = betterWhen ? betterWhen === "down" ? "lower-is-better" : "higher-is-better" : polarityProp;
7565
7185
  const neutral = polarity === "neutral";
7566
7186
  const hasPrevious = comparison !== void 0 && showPrevious;
7567
7187
  const stacked = allComparisons.length > 1;
7568
7188
  const hasTarget = target !== void 0;
7569
7189
  const grain = comparison?.grain ?? historyGrain ?? inferPeriodGrain(period);
7570
- const record = isProvisional || neutral ? null : detectRecord(history, historyGrain ?? grain, polarity);
7190
+ const record = isProvisional || neutral ? null : detectRecord(history, historyGrain ?? grain, polarity, locale);
7571
7191
  const sourceParts = source ? [
7572
7192
  source.period !== void 0 ? formatDatesInText(source.period, locale) : void 0,
7573
- source.count !== void 0 ? `${formatValue(source.count, "number", locale)}\u4EF6\u304B\u3089\u96C6\u8A08` : void 0,
7574
- source.excluded !== void 0 && Number.isFinite(source.excluded) && source.excluded > 0 ? isJapanese2(locale) ? `${formatValue(source.excluded, "number", locale)}\u4EF6\u3092\u9664\u5916` : `${formatValue(source.excluded, "number", locale)} excluded` : void 0,
7193
+ source.count !== void 0 ? t.countFrom(formatValue(source.count, "number", locale)) : void 0,
7194
+ source.excluded !== void 0 && Number.isFinite(source.excluded) && source.excluded > 0 ? t.excluded(formatValue(source.excluded, "number", locale)) : void 0,
7575
7195
  source.name,
7576
7196
  source.note
7577
7197
  ].filter((p) => typeof p === "string" && p !== "") : [];
@@ -7579,11 +7199,11 @@ function KpiCard({
7579
7199
  const historyPoints = (history ?? []).filter((v) => typeof v === "number" && Number.isFinite(v));
7580
7200
  const small = size === "sm";
7581
7201
  const showSparkline = !small && showHistory && historyPoints.length >= SPARKLINE_MIN_POINTS;
7582
- const isRate = formatKind(format2) === "percent";
7202
+ const isRate = formatKind(format) === "percent";
7583
7203
  const byPoints = (targetDisplay ?? (isRate ? "points" : "achievement")) === "points";
7584
7204
  const lower = polarity === "lower-is-better";
7585
7205
  const targetBar = hasTarget && !neutral && !byPoints && !lower;
7586
- if (summary !== void 0) warnShallowSummary(summary);
7206
+ if (summary !== void 0) warnShallowSummary(summary, t);
7587
7207
  const cardClass = cn("row-span-2 grid content-start gap-y-0 grid-rows-subgrid", className);
7588
7208
  const valueSize = small ? "text-xl @[218px]/card:text-2xl" : "text-2xl @[218px]/card:text-4xl";
7589
7209
  if (isLoading) {
@@ -7625,15 +7245,15 @@ function KpiCard({
7625
7245
  }
7626
7246
  );
7627
7247
  }
7628
- const fmt = (v) => formatValue(v, format2, locale);
7248
+ const fmt = (v) => formatValue(v, format, locale);
7629
7249
  const fmtDistance = (v) => isRate ? formatPoints(v, locale, { signDisplay: "never" }) : fmt(v);
7630
7250
  const pct = (v) => formatValue(v, { type: "percent", digits: 0 }, locale);
7631
- const tl = targetLabel;
7632
- const display = change ?? defaultChangeDisplay(format2);
7633
- const digits = display === "points" && typeof format2 === "object" && format2 !== null && "digits" in format2 ? format2.digits : void 0;
7251
+ const tl = targetLabel ?? t.target;
7252
+ const display = change ?? defaultChangeDisplay(format);
7253
+ const digits = display === "points" && typeof format === "object" && format !== null && "digits" in format ? format.digits : void 0;
7634
7254
  const graded = comparison ? { ...comparison, grain } : void 0;
7635
- const result = graded ? computeComparison(value, graded, { polarity, neutralBand }) : null;
7636
- const baseline = graded ? comparisonBaseline(graded.vs, grain, graded.label, graded.toDate) : null;
7255
+ const result = graded ? computeComparison(value, graded, { polarity, neutralBand, locale }) : null;
7256
+ const baseline = graded ? comparisonBaseline(graded.vs, grain, graded.label, graded.toDate, locale) : null;
7637
7257
  const progress = hasTarget && !neutral ? computeTargetProgress(value, target, { period, now, polarity }) : null;
7638
7258
  const projectedValue = !isRate && !byPoints && progress?.projected != null && progress.elapsed ? value / progress.elapsed : null;
7639
7259
  const summaryText = summary ? fillKpiTemplate(
@@ -7641,14 +7261,14 @@ function KpiCard({
7641
7261
  {
7642
7262
  value: fmt(value),
7643
7263
  label: label2,
7644
- delta: result ? formatChange(result, display, locale, format2, digits) : null,
7645
- difference: result?.difference != null ? isRate ? formatPoints(result.difference, locale) : formatDelta(result.difference, format2, locale) : null,
7264
+ delta: result ? formatChange(result, display, locale, format, digits) : null,
7265
+ difference: result?.difference != null ? isRate ? formatPoints(result.difference, locale) : formatDelta(result.difference, format, locale) : null,
7646
7266
  previous: result?.previous != null ? fmt(result.previous) : null,
7647
7267
  target: hasTarget ? fmt(target) : null,
7648
7268
  achievement: progress ? byPoints ? formatPoints(value - target, locale) : pct(progress.achievement) : null,
7649
7269
  remaining: progress ? fmtDistance(progress.remaining) : null
7650
7270
  },
7651
- result && result.direction === "none" && baseline ? `${baseline}\u306E\u5B9F\u7E3E\u304C\u306A\u3044\u305F\u3081\u3001\u6BD4\u8F03\u3067\u304D\u307E\u305B\u3093\u3002` : null
7271
+ result && result.direction === "none" && baseline ? t.noBaseline(baseline) : null
7652
7272
  ) : null;
7653
7273
  const bar = targetBar && progress ? progressBar() : null;
7654
7274
  function progressBar() {
@@ -7656,9 +7276,9 @@ function KpiCard({
7656
7276
  const projected = projectedValue !== null && projectedValue > actual ? projectedValue : actual;
7657
7277
  const scale = Math.max(target, actual, projected);
7658
7278
  const at = (v) => scale > 0 ? v / scale * 100 : 0;
7659
- const parts = [`${tl}\u306E ${pct(progress.achievement)}`];
7279
+ const parts = [t.barLead(tl, pct(progress.achievement))];
7660
7280
  if (projectedValue !== null && progress.projected != null)
7661
- parts.push(`\u3053\u306E\u30DA\u30FC\u30B9\u306A\u3089 ${formatValue(progress.projected, { type: "percent", digits: 0 }, locale)}`);
7281
+ parts.push(t.pace(formatValue(progress.projected, { type: "percent", digits: 0 }, locale)));
7662
7282
  return {
7663
7283
  actualAt: at(actual),
7664
7284
  projectedAt: at(projected),
@@ -7671,13 +7291,13 @@ function KpiCard({
7671
7291
  if (hasTarget && !bar) {
7672
7292
  if (!progress) targetText = `${tl} ${fmt(target)}`;
7673
7293
  else if (isProvisional)
7674
- targetText = progress.achieved ? byPoints ? `${tl} ${fmt(target)} \u306B\u5230\u9054\uFF08\u78BA\u5B9A\u524D\uFF09` : `${tl} ${fmt(target)} \u306B\u5BFE\u3057\u3066\u73FE\u6642\u70B9 ${pct(progress.achievement)}\uFF08\u78BA\u5B9A\u524D\uFF09` : byPoints ? `${tl} ${fmt(target)} \u307E\u3067\u3042\u3068 ${fmtDistance(progress.remaining)}\uFF08\u78BA\u5B9A\u524D\uFF09` : `${tl}\u307E\u3067\u3042\u3068 ${fmtDistance(progress.remaining)}\uFF08\u73FE\u6642\u70B9 ${pct(progress.achievement)}\u30FB\u78BA\u5B9A\u524D\uFF09`;
7294
+ targetText = progress.achieved ? byPoints ? t.provisionalReached(tl, fmt(target)) : t.provisionalSoFar(tl, fmt(target), pct(progress.achievement)) : byPoints ? t.provisionalToGo(tl, fmt(target), fmtDistance(progress.remaining)) : t.provisionalToGoRate(tl, fmtDistance(progress.remaining), pct(progress.achievement));
7675
7295
  else if (lower)
7676
- targetText = progress.achieved ? `${tl} ${fmt(target)} \u3092\u9054\u6210` : `${tl} ${fmt(target)} \u307E\u3067\u3042\u3068 ${fmtDistance(progress.remaining)}`;
7296
+ targetText = progress.achieved ? t.met(tl, fmt(target)) : t.toGo(tl, fmt(target), fmtDistance(progress.remaining));
7677
7297
  else if (byPoints)
7678
- targetText = progress.achieved ? `${tl} ${fmt(target)} \u306B\u5230\u9054` : `${tl} ${fmt(target)} \u307E\u3067\u3042\u3068 ${fmtDistance(progress.remaining)}`;
7298
+ targetText = progress.achieved ? t.reached(tl, fmt(target)) : t.toGo(tl, fmt(target), fmtDistance(progress.remaining));
7679
7299
  else
7680
- targetText = progress.achieved ? `${tl} ${fmt(target)} \u306B\u5230\u9054\uFF08${pct(progress.achievement)} \u9054\u6210\uFF09` : `${tl}\u307E\u3067\u3042\u3068 ${fmtDistance(progress.remaining)}\uFF08${pct(progress.achievement)} \u9054\u6210\uFF09`;
7300
+ targetText = progress.achieved ? t.reachedRate(tl, fmt(target), pct(progress.achievement)) : t.toGoRate(tl, fmtDistance(progress.remaining), pct(progress.achievement));
7681
7301
  }
7682
7302
  const hasFooter = Boolean(summaryText) || record !== null || Boolean(targetText) || sourceParts.length > 0 || hasUpdated || showSparkline;
7683
7303
  const deltas = allComparisons.map((c, i) => /* @__PURE__ */ jsx(
@@ -7687,7 +7307,7 @@ function KpiCard({
7687
7307
  comparison: i === 0 ? graded ?? c : { ...c, grain: c.grain ?? grain },
7688
7308
  polarity,
7689
7309
  neutralBand,
7690
- format: format2,
7310
+ format,
7691
7311
  change: display,
7692
7312
  digits,
7693
7313
  locale
@@ -7720,18 +7340,18 @@ function KpiCard({
7720
7340
  }
7721
7341
  ),
7722
7342
  comparison && (stacked ? /* @__PURE__ */ jsx("div", { "data-slot": "kpi-card-comparisons", className: "flex flex-wrap items-center gap-1", children: deltas }) : /* @__PURE__ */ jsx(CardAction, { className: longValue ? DELTA_UNDER_PLACEMENT : DELTA_PLACEMENT, children: deltas })),
7723
- hasPrevious && comparison && /* @__PURE__ */ jsx("div", { "data-slot": "kpi-card-previous", className: "col-span-full text-sm text-muted-foreground tabular-nums", children: result?.previous != null ? `${baseline} ${fmt(result.previous)}` : `${baseline}\u306E\u5B9F\u7E3E\u306A\u3057` }),
7343
+ hasPrevious && comparison && /* @__PURE__ */ jsx("div", { "data-slot": "kpi-card-previous", className: "col-span-full text-sm text-muted-foreground tabular-nums", children: result?.previous != null ? t.previous(baseline ?? "", fmt(result.previous)) : t.noPrevious(baseline ?? "") }),
7724
7344
  bar && progress && /* @__PURE__ */ jsxs("div", { "data-slot": "kpi-card-target-progress", className: "col-span-full mt-1 flex min-w-0 flex-col gap-1.5", children: [
7725
7345
  /* @__PURE__ */ jsxs(
7726
7346
  "div",
7727
7347
  {
7728
7348
  "data-slot": "kpi-card-target-bar",
7729
7349
  role: "progressbar",
7730
- "aria-label": `${tl}\u306B\u5BFE\u3059\u308B\u9032\u6357`,
7350
+ "aria-label": t.progressLabel(tl),
7731
7351
  "aria-valuemin": 0,
7732
7352
  "aria-valuemax": target,
7733
7353
  "aria-valuenow": Math.min(Math.max(value, 0), target),
7734
- "aria-valuetext": `${tl} ${fmt(target)} \u306B\u5BFE\u3057\u3066 ${fmt(value)}\uFF08${pct(progress.achievement)}\uFF09`,
7354
+ "aria-valuetext": t.progressValue(tl, fmt(target), fmt(value), pct(progress.achievement)),
7735
7355
  className: "relative h-2 w-full overflow-hidden rounded-full bg-muted",
7736
7356
  children: [
7737
7357
  /* @__PURE__ */ jsx("div", { className: "absolute inset-y-0 left-0 bg-chart-1", style: { width: `${bar.actualAt}%` } }),
@@ -7758,15 +7378,15 @@ function KpiCard({
7758
7378
  "p",
7759
7379
  {
7760
7380
  "data-slot": "kpi-card-target",
7761
- title: [bar.lead, bar.pace].filter(Boolean).join("\u30FB"),
7381
+ title: [bar.lead, bar.pace].filter(Boolean).join(t.joiner),
7762
7382
  className: "truncate text-sm text-muted-foreground tabular-nums",
7763
7383
  children: [
7764
7384
  bar.lead,
7765
7385
  bar.pace && /* @__PURE__ */ jsxs(Fragment, { children: [
7766
- "\u30FB",
7386
+ t.joiner,
7767
7387
  /* @__PURE__ */ jsx("span", { "data-slot": "kpi-card-projection", "data-estimate": "", children: bar.pace })
7768
7388
  ] }),
7769
- isProvisional && "\uFF08\u78BA\u5B9A\u524D\uFF09"
7389
+ isProvisional && t.provisionalSuffix
7770
7390
  ]
7771
7391
  }
7772
7392
  )
@@ -7780,12 +7400,12 @@ function KpiCard({
7780
7400
  "p",
7781
7401
  {
7782
7402
  "data-slot": "kpi-card-source",
7783
- title: sourceParts.join("\u30FB"),
7403
+ title: sourceParts.join(t.joiner),
7784
7404
  className: "line-clamp-2 w-full text-xs leading-normal text-muted-foreground tabular-nums",
7785
- children: sourceParts.join("\u30FB")
7405
+ children: sourceParts.join(t.joiner)
7786
7406
  }
7787
7407
  ),
7788
- hasUpdated && /* @__PURE__ */ jsx("p", { "data-slot": "kpi-card-updated", className: "text-xs leading-normal text-muted-foreground", children: updatedAtText(updatedAt, updatedAtDisplay, locale, now, timeZone) }),
7408
+ hasUpdated && /* @__PURE__ */ jsx("p", { "data-slot": "kpi-card-updated", className: "text-xs leading-normal text-muted-foreground", children: updatedAtText(updatedAt, updatedAtDisplay, locale, t, now, timeZone) }),
7789
7409
  showSparkline && // mt-auto: the footers of a row are as tall as the tallest, so the sparklines share one bottom edge.
7790
7410
  /* @__PURE__ */ jsx("div", { "data-slot": "kpi-card-history", className: "mt-auto w-full pt-2 text-chart-1", children: /* @__PURE__ */ jsx(
7791
7411
  Sparkline,
@@ -7794,23 +7414,35 @@ function KpiCard({
7794
7414
  height: SPARKLINE_HEIGHT,
7795
7415
  color: "text-chart-1",
7796
7416
  highlight: "latest",
7797
- "aria-label": `${label2}\u306E\u63A8\u79FB\uFF08\u76F4\u8FD1 ${historyPoints.length} \u70B9\uFF09`
7417
+ "aria-label": t.history(label2, historyPoints.length)
7798
7418
  }
7799
7419
  ) })
7800
7420
  ] })
7801
7421
  ] });
7802
7422
  }
7803
- function updatedAtText(updatedAt, display, locale, now, timeZone) {
7423
+ function updatedAtText(updatedAt, display, locale, t, now, timeZone) {
7804
7424
  const relative2 = formatRelativeTime(updatedAt, { now, locale });
7805
- if (display === "relative") return `${relative2}\u306B\u66F4\u65B0`;
7425
+ if (display === "relative") return t.updatedRelative(relative2);
7806
7426
  const absolute2 = formatDate(updatedAt, "datetime", locale, { timeZone });
7807
- return display === "absolute" ? `${absolute2} \u306B\u66F4\u65B0` : `${absolute2} \u306B\u66F4\u65B0\uFF08${relative2}\uFF09`;
7427
+ return display === "absolute" ? t.updatedAbsolute(absolute2) : t.updatedBoth(absolute2, relative2);
7808
7428
  }
7429
+ var TEXT20 = {
7430
+ ja: {
7431
+ flat: (value) => `\u5909\u5316\u306A\u3057 ${value}%`,
7432
+ up: (value) => `${value}% \u5897\u52A0`,
7433
+ down: (value) => `${value}% \u6E1B\u5C11`
7434
+ },
7435
+ en: {
7436
+ flat: (value) => `No change ${value}%`,
7437
+ up: (value) => `Up ${value}%`,
7438
+ down: (value) => `Down ${value}%`
7439
+ }
7440
+ };
7809
7441
  var trendIndicatorVariants = cva("inline-flex items-center gap-0.5 text-sm font-medium", {
7810
7442
  variants: {
7811
7443
  sentiment: {
7812
- positive: "text-chart-1",
7813
- negative: "text-primary",
7444
+ positive: "text-positive",
7445
+ negative: "text-negative",
7814
7446
  neutral: "text-muted-foreground"
7815
7447
  }
7816
7448
  },
@@ -7823,7 +7455,8 @@ var TrendIndicator = forwardRef(
7823
7455
  const isGood = direction === "neutral" ? null : direction === "up" === positiveIsGood;
7824
7456
  const sentiment = isGood === null ? "neutral" : isGood ? "positive" : "negative";
7825
7457
  const Icon = direction === "up" ? ArrowUp : direction === "down" ? ArrowDown : Minus;
7826
- const ariaLabel = direction === "neutral" ? `\u5909\u5316\u306A\u3057 ${value}%` : direction === "up" ? `${value}% \u5897\u52A0` : `${value}% \u6E1B\u5C11`;
7458
+ const t = TEXT20[uiLanguage(useLocale())];
7459
+ const ariaLabel = direction === "neutral" ? t.flat(value) : direction === "up" ? t.up(value) : t.down(value);
7827
7460
  return /* @__PURE__ */ jsxs(
7828
7461
  "span",
7829
7462
  {
@@ -7843,21 +7476,49 @@ var TrendIndicator = forwardRef(
7843
7476
  }
7844
7477
  );
7845
7478
  TrendIndicator.displayName = "TrendIndicator";
7479
+ var STATUS_LABELS = {
7480
+ ja: {
7481
+ success: "\u6B63\u5E38",
7482
+ partial: "\u4E00\u90E8\u5931\u6557",
7483
+ failed: "\u5931\u6557",
7484
+ delayed: "\u9045\u5EF6",
7485
+ running: "\u5B9F\u884C\u4E2D",
7486
+ stopped: "\u505C\u6B62\u4E2D",
7487
+ active: "\u6709\u52B9",
7488
+ inactive: "\u7121\u52B9",
7489
+ warning: "\u8B66\u544A",
7490
+ error: "\u30A8\u30E9\u30FC",
7491
+ pending: "\u4FDD\u7559\u4E2D"
7492
+ },
7493
+ en: {
7494
+ success: "Healthy",
7495
+ partial: "Partially failed",
7496
+ failed: "Failed",
7497
+ delayed: "Delayed",
7498
+ running: "Running",
7499
+ stopped: "Stopped",
7500
+ active: "Active",
7501
+ inactive: "Inactive",
7502
+ warning: "Warning",
7503
+ error: "Error",
7504
+ pending: "Pending"
7505
+ }
7506
+ };
7846
7507
  var STATUS_VOCABULARY = {
7847
- success: { label: "\u6B63\u5E38", tone: "positive" },
7848
- partial: { label: "\u4E00\u90E8\u5931\u6557", tone: "warning" },
7849
- failed: { label: "\u5931\u6557", tone: "negative" },
7850
- delayed: { label: "\u9045\u5EF6", tone: "warning" },
7851
- running: { label: "\u5B9F\u884C\u4E2D", tone: "info" },
7852
- stopped: { label: "\u505C\u6B62\u4E2D", tone: "neutral" },
7853
- active: { label: "\u6709\u52B9", tone: "positive" },
7854
- inactive: { label: "\u7121\u52B9", tone: "neutral" },
7855
- warning: { label: "\u8B66\u544A", tone: "warning" },
7856
- error: { label: "\u30A8\u30E9\u30FC", tone: "negative" },
7857
- pending: { label: "\u4FDD\u7559\u4E2D", tone: "info" }
7508
+ success: { label: STATUS_LABELS.en.success, tone: "positive" },
7509
+ partial: { label: STATUS_LABELS.en.partial, tone: "warning" },
7510
+ failed: { label: STATUS_LABELS.en.failed, tone: "negative" },
7511
+ delayed: { label: STATUS_LABELS.en.delayed, tone: "warning" },
7512
+ running: { label: STATUS_LABELS.en.running, tone: "info" },
7513
+ stopped: { label: STATUS_LABELS.en.stopped, tone: "neutral" },
7514
+ active: { label: STATUS_LABELS.en.active, tone: "positive" },
7515
+ inactive: { label: STATUS_LABELS.en.inactive, tone: "neutral" },
7516
+ warning: { label: STATUS_LABELS.en.warning, tone: "warning" },
7517
+ error: { label: STATUS_LABELS.en.error, tone: "negative" },
7518
+ pending: { label: STATUS_LABELS.en.pending, tone: "info" }
7858
7519
  };
7859
- function statusLabel(status) {
7860
- return Object.hasOwn(STATUS_VOCABULARY, status) ? STATUS_VOCABULARY[status].label : status;
7520
+ function statusLabel(status, locale) {
7521
+ return Object.hasOwn(STATUS_VOCABULARY, status) ? STATUS_LABELS[uiLanguage(resolveLocale(locale))][status] : status;
7861
7522
  }
7862
7523
  var defaultColorMap = Object.fromEntries(
7863
7524
  Object.entries(STATUS_VOCABULARY).map(([key, { tone }]) => [key, tone])
@@ -7870,11 +7531,11 @@ var legacyColorTones = {
7870
7531
  blue: "info"
7871
7532
  };
7872
7533
  var toneStyles = {
7873
- positive: { dot: "bg-positive", bg: "bg-positive-subtle", text: "text-positive" },
7874
- negative: { dot: "bg-negative", bg: "bg-negative-subtle", text: "text-negative" },
7875
- warning: { dot: "bg-warning", bg: "bg-warning-subtle", text: "text-warning" },
7876
- info: { dot: "bg-info", bg: "bg-info-subtle", text: "text-info" },
7877
- neutral: { dot: "bg-neutral", bg: "bg-neutral-subtle", text: "text-neutral" }
7534
+ positive: { dot: "bg-positive", bg: "bg-positive-subtle", text: "text-positive", border: "border-positive/20 dark:border-positive/25" },
7535
+ negative: { dot: "bg-negative", bg: "bg-negative-subtle", text: "text-negative", border: "border-negative/20 dark:border-negative/25" },
7536
+ warning: { dot: "bg-warning", bg: "bg-warning-subtle", text: "text-warning", border: "border-warning/20 dark:border-warning/25" },
7537
+ info: { dot: "bg-info", bg: "bg-info-subtle", text: "text-info", border: "border-info/20 dark:border-info/25" },
7538
+ neutral: { dot: "bg-neutral", bg: "bg-neutral-subtle", text: "text-neutral", border: "border-neutral/20 dark:border-neutral/25" }
7878
7539
  };
7879
7540
  var resolveTone = (color) => {
7880
7541
  if (color === void 0) return "neutral";
@@ -7882,19 +7543,20 @@ var resolveTone = (color) => {
7882
7543
  return legacyColorTones[color] ?? "neutral";
7883
7544
  };
7884
7545
  var StatusBadge = forwardRef(function StatusBadge2({ status, label: label2, colorMap, className }, ref) {
7546
+ const locale = useLocale();
7885
7547
  const mergedColorMap = { ...defaultColorMap, ...colorMap };
7886
7548
  const style = toneStyles[resolveTone(mergedColorMap[status])];
7887
- const displayLabel = label2 ?? statusLabel(status);
7549
+ const displayLabel = label2 ?? statusLabel(status, locale);
7888
7550
  return /* @__PURE__ */ jsxs(
7889
7551
  Badge,
7890
7552
  {
7891
7553
  ref,
7892
7554
  "data-slot": "status-badge",
7893
7555
  variant: "outline",
7894
- className: cn("gap-1.5 border-transparent", style.bg, style.text, className),
7556
+ className: cn("gap-1.5 rounded-md", style.border, style.bg, style.text, className),
7895
7557
  "aria-label": displayLabel,
7896
7558
  children: [
7897
- /* @__PURE__ */ jsx("span", { className: cn("inline-block size-2 rounded-full", style.dot), "aria-hidden": "true" }),
7559
+ /* @__PURE__ */ jsx("span", { className: cn("inline-block size-1.5 rounded-full", style.dot), "aria-hidden": "true" }),
7898
7560
  displayLabel
7899
7561
  ]
7900
7562
  }
@@ -7914,6 +7576,6 @@ var Placeholder = forwardRef(function Placeholder2({ className, ...props }, ref)
7914
7576
  });
7915
7577
  Placeholder.displayName = "Placeholder";
7916
7578
 
7917
- export { AppShell, AreaChart, BarChart2 as BarChart, BarList, COMPARISON_LABELS, CategoryBar, ChartFrame, DEFAULT_LOCALE, DEFAULT_SAMPLE_LABEL, DELTA_NOT_COMPARABLE, DashboardCard, DashboardCardAction, DashboardCardContent, DashboardCardDescription, DashboardCardFooter, DashboardCardHeader, DashboardCardPreset, DashboardCardSkeleton, DashboardCardTitle, DataTable, DataTableColumnVisibility, DataTableContent, DataTableExport, DataTablePagination, DataTablePreset, DataTableToolbar, DateRangePicker, Delta, DonutChart, EChart, EMPTY_VALUE, FilterBar, FilterBarActiveChips, FilterBarClearButton, FilterBarMultiSelect, FilterBarPreset, FilterBarSelect, FunnelSteps, Heatmap, KpiCard, Legend, LineChart2 as LineChart, MINUS_SIGN, MetricUnit, MetricValue, MultiSelect, PageShell, PageShellActions, PageShellContent, PageShellDescription, PageShellHeader, PageShellHeaderEnd, PageShellHeading, PageShellMeta, PageShellSummary, PageShellSummaryCard, PageShellTitle, Placeholder, ProgressCircle, RECORD_MIN_POINTS, SampleBadge, SampleClaim, SampleData, ScatterChart, SearchableSelect, SectionHeader, SegmentedControl, Sparkline, StatusBadge, Tracker, TrendIndicator, UpdatedAt, WaterfallChart, comparisonBaseline, comparisonLabel, computeComparison, computeTargetProgress, defaultChangeDisplay, defaultPresets, deltaVariants, detectRecord, fillKpiTemplate, flattenOptions, formatChange, formatChangeAmount, formatDate, formatDateRange, formatDatesInText, formatDelta, formatKind, formatPoints, formatRelativeTime, formatValue, funnelStepsVariants, inferPeriodGrain, isGroupedOptions, metricValueVariants, pageShellSummaryCardVariants, tableToCsv, toCsv, toValueFormatter, toneForValue, useDataTable, useResolvedChartColors, useSampleMark };
7918
- //# sourceMappingURL=chunk-HKSVYMYJ.js.map
7919
- //# sourceMappingURL=chunk-HKSVYMYJ.js.map
7579
+ export { AppShell, AreaChart, BarChart, BarList, COMPARISON_LABELS, CategoryBar, ChartFrame, DEFAULT_SAMPLE_LABEL, DELTA_NOT_COMPARABLE, DashboardCard, DashboardCardAction, DashboardCardContent, DashboardCardDescription, DashboardCardFooter, DashboardCardHeader, DashboardCardPreset, DashboardCardSkeleton, DashboardCardTitle, DataTable, DataTableColumnVisibility, DataTableContent, DataTableExport, DataTablePagination, DataTablePreset, DataTableToolbar, DateRangePicker, Delta, DonutChart, FilterBar, FilterBarActiveChips, FilterBarClearButton, FilterBarMultiSelect, FilterBarPreset, FilterBarSelect, FunnelSteps, Heatmap, KpiCard, Legend, LineChart, MetricUnit, MetricValue, MultiSelect, PageShell, PageShellActions, PageShellContent, PageShellDescription, PageShellHeader, PageShellHeaderEnd, PageShellHeading, PageShellMeta, PageShellSummary, PageShellSummaryCard, PageShellTitle, Placeholder, ProgressCircle, RECORD_MIN_POINTS, SampleBadge, SampleClaim, SampleData, ScatterChart, SearchableSelect, SectionHeader, SegmentedControl, StatusBadge, Tracker, TrendIndicator, UpdatedAt, WaterfallChart, comparisonBaseline, comparisonLabel, computeComparison, computeTargetProgress, defaultChangeDisplay, defaultPresets, deltaVariants, detectRecord, fillKpiTemplate, flattenOptions, formatChange, formatChangeAmount, formatRelativeTime, funnelStepsVariants, inferPeriodGrain, isGroupedOptions, metricValueVariants, pageShellSummaryCardVariants, tableToCsv, toCsv, toneForValue, useDataTable, useSampleMark };
7580
+ //# sourceMappingURL=chunk-77CISBMG.js.map
7581
+ //# sourceMappingURL=chunk-77CISBMG.js.map