@squadbase/vantage 0.7.1-dev1.9d223a2 → 0.7.1-dev1.bb6bd72

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 (67) hide show
  1. package/dist/{build-U7GO26HR.js → build-AON4MAQQ.js} +3 -3
  2. package/dist/{build-U7GO26HR.js.map → build-AON4MAQQ.js.map} +1 -1
  3. package/dist/{chunk-MQUIAP66.js → chunk-5HBUBVQ3.js} +28 -7
  4. package/dist/chunk-5HBUBVQ3.js.map +1 -0
  5. package/dist/{chunk-EG4PX726.js → chunk-GWXKENNH.js} +122 -5
  6. package/dist/chunk-GWXKENNH.js.map +1 -0
  7. package/dist/{chunk-YJQCB3UP.js → chunk-I2GWIPTD.js} +219 -67
  8. package/dist/chunk-I2GWIPTD.js.map +1 -0
  9. package/dist/{chunk-SDJTTMLK.js → chunk-SR43D6EF.js} +13 -8
  10. package/dist/chunk-SR43D6EF.js.map +1 -0
  11. package/dist/{chunk-P2KIHF65.js → chunk-U6MWBCM6.js} +28 -7
  12. package/dist/chunk-U6MWBCM6.js.map +1 -0
  13. package/dist/cli.js +2 -2
  14. package/dist/components/index.d.ts +223 -6
  15. package/dist/components/index.js +4 -4
  16. package/dist/{dev-O42JFQ64.js → dev-BZ7FXDB3.js} +3 -3
  17. package/dist/{dev-O42JFQ64.js.map → dev-BZ7FXDB3.js.map} +1 -1
  18. package/dist/doc/index.js +1 -1
  19. package/dist/slide/index.js +1 -1
  20. package/dist/table/index.js +4 -4
  21. package/dist/ui/index.d.ts +35 -4
  22. package/dist/ui/index.js +174 -10
  23. package/dist/ui/index.js.map +1 -1
  24. package/dist/vite/index.js +1 -1
  25. package/package.json +2 -2
  26. package/registry/parts.json +101 -3
  27. package/registry/ui/area-chart.tsx +43 -8
  28. package/registry/ui/bar-chart.tsx +43 -8
  29. package/registry/ui/bar-list.tsx +43 -8
  30. package/registry/ui/box-plot-chart.tsx +42 -7
  31. package/registry/ui/category-bar.tsx +25 -5
  32. package/registry/ui/chart-frame.tsx +47 -14
  33. package/registry/ui/checkbox.tsx +4 -3
  34. package/registry/ui/code-block.tsx +44 -0
  35. package/registry/ui/combo-chart.tsx +20 -3
  36. package/registry/ui/combobox.tsx +7 -0
  37. package/registry/ui/context-menu.tsx +71 -0
  38. package/registry/ui/dashboard-card.tsx +20 -9
  39. package/registry/ui/data-table.tsx +7 -1
  40. package/registry/ui/date-range-picker.tsx +51 -4
  41. package/registry/ui/delta.tsx +36 -11
  42. package/registry/ui/donut-chart.tsx +43 -8
  43. package/registry/ui/echart.tsx +167 -7
  44. package/registry/ui/file-dropzone.tsx +143 -0
  45. package/registry/ui/filter-bar.tsx +74 -1
  46. package/registry/ui/forecast-chart.tsx +42 -7
  47. package/registry/ui/funnel-steps.tsx +22 -4
  48. package/registry/ui/heatmap.tsx +20 -3
  49. package/registry/ui/histogram-chart.tsx +42 -7
  50. package/registry/ui/kpi-card.tsx +12 -8
  51. package/registry/ui/legend.tsx +73 -15
  52. package/registry/ui/line-chart.tsx +43 -8
  53. package/registry/ui/page-shell.tsx +2 -0
  54. package/registry/ui/paired-chart.tsx +43 -8
  55. package/registry/ui/progress.tsx +1 -1
  56. package/registry/ui/scatter-chart.tsx +50 -12
  57. package/registry/ui/sparkline.tsx +43 -8
  58. package/registry/ui/states.tsx +34 -1
  59. package/registry/ui/status-badge.tsx +7 -7
  60. package/registry/ui/tabs.tsx +1 -0
  61. package/registry/ui/treemap.tsx +20 -3
  62. package/registry/ui/waterfall-chart.tsx +64 -11
  63. package/dist/chunk-EG4PX726.js.map +0 -1
  64. package/dist/chunk-MQUIAP66.js.map +0 -1
  65. package/dist/chunk-P2KIHF65.js.map +0 -1
  66. package/dist/chunk-SDJTTMLK.js.map +0 -1
  67. package/dist/chunk-YJQCB3UP.js.map +0 -1
@@ -1,18 +1,18 @@
1
- import { ChartFrameContext, useChartSurface, resolveChartColors, resolveFillColors, EChart, CHART_OTHER_COLOR } from './chunk-EG4PX726.js';
2
- import { Sparkline } from './chunk-P2KIHF65.js';
1
+ import { ChartFrameContext, useChartSurface, resolveChartColors, resolveFillColors, EChart, CHART_OTHER_COLOR } from './chunk-GWXKENNH.js';
2
+ import { Sparkline } from './chunk-U6MWBCM6.js';
3
3
  import { formatDateRange, EMPTY_VALUE, toValueFormatter, formatDate, formatValue, formatPoints, formatKind, formatDelta, MINUS_SIGN, DEFAULT_LOCALE, formatDatesInText } from './chunk-XRKSIC5Z.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, Empty, Checkbox, Card, CardHeader, CardDescription, CardTitle, CardAction, CardFooter } from './chunk-MQUIAP66.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, Empty, Checkbox, DropdownMenuSub, DropdownMenuSubTrigger, DropdownMenuSubContent, Card, CardHeader, CardDescription, CardTitle, CardAction, CardFooter } from './chunk-5HBUBVQ3.js';
5
5
  import { useLocale, uiLanguage, Button, weekStartsOn, resolveLocale, defaultFiscalYearStartMonth, FALLBACK_LOCALE } from './chunk-ROHNXP7J.js';
6
6
  import { cn } from './chunk-U736PVHY.js';
7
- import { forwardRef, useState, useEffect, createContext, useId, useMemo, useRef, useCallback, Fragment as Fragment$1, useContext, useInsertionEffect, useLayoutEffect } from 'react';
7
+ import { forwardRef, useState, useEffect, createContext, useId, useCallback, useMemo, useRef, Fragment as Fragment$1, useContext, useInsertionEffect, useLayoutEffect } from 'react';
8
8
  import { cva } from 'class-variance-authority';
9
9
  import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
10
- import { Search, Columns3, CalendarIcon, ChevronDownIcon, ArrowUp, ArrowDown, ArrowRight, Minus, ChevronRight, ArrowUpDown, XIcon, LoaderIcon, CheckIcon, Download, ChevronDown, X, CircleX, TriangleAlert, CircleCheck } from 'lucide-react';
10
+ import { Search, Columns3, CalendarIcon, ChevronDownIcon, ArrowUp, ArrowDown, ArrowRight, Minus, ChevronRight, ArrowUpDown, XIcon, LoaderIcon, CheckIcon, Download, ChevronDown, Plus, X, CircleX, TriangleAlert, CircleCheck } from 'lucide-react';
11
11
  import { use, registerMap } from 'echarts/core';
12
12
  import { GraphicComponent, VisualMapComponent, GeoComponent } from 'echarts/components';
13
13
  import { ScatterChart as ScatterChart$1, HeatmapChart, MapChart, TreemapChart } from 'echarts/charts';
14
14
  import 'echarts';
15
- import { subMonths, subDays, endOfDay, startOfDay, startOfWeek, subWeeks, endOfWeek, startOfMonth, endOfMonth, isSameDay, addMonths, differenceInCalendarDays, parseISO } from 'date-fns';
15
+ import { subMonths, subDays, endOfDay, startOfDay, startOfWeek, subWeeks, endOfWeek, startOfMonth, endOfMonth, isSameDay, subYears, differenceInCalendarDays, addMonths, parseISO } from 'date-fns';
16
16
  import { flexRender, useReactTable, getPaginationRowModel, getFilteredRowModel, getSortedRowModel, getCoreRowModel } from '@tanstack/react-table';
17
17
  import { ja } from 'date-fns/locale';
18
18
 
@@ -627,7 +627,7 @@ var DashboardCardFooter = forwardRef(
627
627
  {
628
628
  ref,
629
629
  "data-slot": "dashboard-card-footer",
630
- className: cn("flex items-center px-3 py-1.5 group-data-[size=sm]:px-2", className),
630
+ className: cn("-mx-1 -mb-1 flex min-w-0 items-center justify-between gap-3 border-t px-4 py-2.5 text-xs text-muted-foreground tabular-nums group-data-[size=sm]:px-3", className),
631
631
  ...props
632
632
  }
633
633
  )
@@ -653,6 +653,7 @@ function DashboardCardSkeleton({ className }) {
653
653
  function DashboardCardPreset({
654
654
  title,
655
655
  description,
656
+ headline,
656
657
  actions,
657
658
  footer,
658
659
  children,
@@ -664,15 +665,21 @@ function DashboardCardPreset({
664
665
  ...props
665
666
  }) {
666
667
  const sample = useSampleMark();
667
- const hasHeader = title || description || actions || sample;
668
- return /* @__PURE__ */ jsx(DashboardCard, { className, subgrid, ...props, children: /* @__PURE__ */ jsxs(SampleClaim, { children: [
668
+ const hasTitle = Boolean(title || description);
669
+ const floatingMark = sample && !hasTitle && !headline && !actions;
670
+ const hasHeader = hasTitle || headline || actions || sample && !floatingMark;
671
+ return /* @__PURE__ */ jsx(DashboardCard, { className: cn(floatingMark && "relative", className), subgrid, ...props, children: /* @__PURE__ */ jsxs(SampleClaim, { children: [
672
+ floatingMark && /* @__PURE__ */ jsx(SampleBadge, { label: sample.label, className: "absolute top-2 right-2 z-10" }),
669
673
  hasHeader && /* @__PURE__ */ jsxs(DashboardCardHeader, { className: cn(subgrid && "row-start-1", headerClassName), children: [
670
- (title || description) && /* @__PURE__ */ jsxs("div", { children: [
671
- title && /* @__PURE__ */ jsx(DashboardCardTitle, { children: title }),
674
+ (hasTitle || sample) && /* @__PURE__ */ jsxs("div", { className: "min-w-0", children: [
675
+ /* @__PURE__ */ jsxs("div", { className: "flex flex-wrap items-center gap-x-2 gap-y-1", children: [
676
+ title && /* @__PURE__ */ jsx(DashboardCardTitle, { children: title }),
677
+ sample && /* @__PURE__ */ jsx(SampleBadge, { label: sample.label })
678
+ ] }),
672
679
  description && /* @__PURE__ */ jsx(DashboardCardDescription, { children: description })
673
680
  ] }),
674
- (actions || sample) && /* @__PURE__ */ jsxs(DashboardCardAction, { className: cn(sample && actions && "flex items-center gap-2"), children: [
675
- sample && /* @__PURE__ */ jsx(SampleBadge, { label: sample.label }),
681
+ (headline || actions) && /* @__PURE__ */ jsxs(DashboardCardAction, { className: "flex items-center gap-2", children: [
682
+ headline && /* @__PURE__ */ jsx("div", { "data-slot": "dashboard-card-headline", className: "text-sm tabular-nums text-muted-foreground", children: headline }),
676
683
  actions
677
684
  ] })
678
685
  ] }),
@@ -706,6 +713,17 @@ var ChartFrame = forwardRef(function ChartFrame2({
706
713
  const titleId = title ? `${id}-title` : void 0;
707
714
  const summaryId = summary ? `${id}-summary` : void 0;
708
715
  const state = isLoading ? "loading" : isEmpty ? "empty" : "ready";
716
+ const [claims, setClaims] = useState(0);
717
+ const claim = useCallback(() => {
718
+ setClaims((n) => n + 1);
719
+ return () => setClaims((n) => n - 1);
720
+ }, []);
721
+ const claimed = claims > 0 && plotRole === "img";
722
+ const plotOwnsImage = state === "ready" && claimed;
723
+ const plot = useMemo(
724
+ () => ({ image: plotRole === "img", claimed, claim, ariaLabel: titleId ? void 0 : ariaLabel, ariaLabelledBy: titleId, ariaDescribedBy: summaryId }),
725
+ [plotRole, claimed, claim, titleId, ariaLabel, summaryId]
726
+ );
709
727
  return /* @__PURE__ */ jsxs("figure", { "data-slot": "chart-frame", className: cn("m-0 flex w-full min-w-0 flex-col gap-3", className), ...props, children: [
710
728
  (title || summary) && /* @__PURE__ */ jsxs("figcaption", { "data-slot": "chart-frame-header", className: "flex flex-col gap-1", children: [
711
729
  title && /* @__PURE__ */ jsx("h3", { id: titleId, "data-slot": "chart-frame-title", className: "text-sm leading-snug font-semibold", children: title }),
@@ -717,14 +735,14 @@ var ChartFrame = forwardRef(function ChartFrame2({
717
735
  ref,
718
736
  "data-slot": "chart-frame-body",
719
737
  "data-state": state,
720
- role: state === "ready" ? plotRole : "group",
721
- "aria-label": titleId ? void 0 : ariaLabel,
722
- "aria-labelledby": titleId,
723
- "aria-describedby": summaryId,
738
+ role: plotOwnsImage ? void 0 : state === "ready" ? plotRole : "group",
739
+ "aria-label": plotOwnsImage || titleId ? void 0 : ariaLabel,
740
+ "aria-labelledby": plotOwnsImage ? void 0 : titleId,
741
+ "aria-describedby": plotOwnsImage ? void 0 : summaryId,
724
742
  "aria-busy": isLoading || void 0,
725
743
  className: "relative w-full min-w-0",
726
744
  style: { height: typeof height === "number" ? `${height}px` : height },
727
- 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 })
745
+ children: state === "loading" ? /* @__PURE__ */ jsx(ChartSkeleton, { variant, loadingText: t.loading }) : state === "empty" ? /* @__PURE__ */ jsx(ChartEmpty, { ...emptyState, defaultTitle: t.emptyTitle }) : /* @__PURE__ */ jsx(ChartFrameContext.Provider, { value: plot, children })
728
746
  }
729
747
  ),
730
748
  footnote && /* @__PURE__ */ jsx("p", { "data-slot": "chart-frame-footnote", className: "text-xs leading-snug text-muted-foreground", children: footnote }),
@@ -1630,6 +1648,9 @@ function legendLines(items, plotWidth, reserve = 0) {
1630
1648
  return Math.min(3, Math.max(1, Math.ceil(width / budget)));
1631
1649
  }
1632
1650
  var ACTIONS_RESERVE = 80;
1651
+ var BAR_MAX_WIDTH = 40;
1652
+ var BAR_RADIUS = 3;
1653
+ var STACK_GAP = 1.5;
1633
1654
  var TIME_LABEL_WIDTH = 80;
1634
1655
  var HIGHLIGHT_LABEL_WIDTH = 96;
1635
1656
  var TARGET_NEAR_SHARE = 0.12;
@@ -1760,6 +1781,7 @@ function buildCartesianOption(cfg) {
1760
1781
  const compared = cartesianSeriesValues(data, [categories[compIdx]], "default")[0];
1761
1782
  return categories.map((_, i) => i === compIdx ? compared : main[mainIdx.indexOf(i)]);
1762
1783
  })();
1784
+ const diverging = kind === "bar" && values.some((s) => s.some((v) => typeof v === "number" && v < 0));
1763
1785
  const comparisonColor = guideColor ? withAlpha(guideColor, COMPARISON_OPACITY) : void 0;
1764
1786
  const labels = data.map((row) => String(row[index] ?? ""));
1765
1787
  const rawIndex = data.map((row) => row[index]);
@@ -1875,14 +1897,16 @@ function buildCartesianOption(cfg) {
1875
1897
  const seriesData = pad(values[c]);
1876
1898
  if (kind === "bar") {
1877
1899
  const rounded = horizontalBars ? [0, 4, 4, 0] : [4, 4, 0, 0];
1878
- const radius = stacked && c !== categories.length - 1 ? 0 : rounded;
1900
+ const radius = stacked ? BAR_RADIUS : rounded;
1901
+ const gapStyle = stacked && labelBackground ? { borderColor: labelBackground, borderWidth: STACK_GAP } : {};
1879
1902
  return {
1880
1903
  id: SERIES_ID_PREFIX + category,
1881
1904
  type: "bar",
1882
1905
  name: category,
1883
1906
  stack: stacked ? "total" : void 0,
1884
1907
  barCategoryGap,
1885
- itemStyle: { color, borderRadius: radius },
1908
+ barMaxWidth: BAR_MAX_WIDTH,
1909
+ itemStyle: { color, borderRadius: radius, ...gapStyle },
1886
1910
  markPoint: markPointFor(c, solid),
1887
1911
  markLine: void 0,
1888
1912
  data: seriesData.map((value, i) => {
@@ -2137,6 +2161,14 @@ function buildCartesianOption(cfg) {
2137
2161
  }
2138
2162
  });
2139
2163
  }
2164
+ if (diverging) {
2165
+ markLines.push({
2166
+ name: "zero",
2167
+ [horizontalBars ? "xAxis" : "yAxis"]: 0,
2168
+ lineStyle: { type: "solid", width: 1, color: guideColor },
2169
+ label: { show: false }
2170
+ });
2171
+ }
2140
2172
  if (forecast2) {
2141
2173
  const forecastSpan = plotWidth && labels.length > 1 ? Math.max(1, plotWidth - (showYAxis ? yAxisWidth ?? Y_AXIS_ESTIMATE : 0) - LINE_RIGHT_MARGIN) / (labels.length - 1) * (labels.length - 1 - lastActual) + LINE_RIGHT_MARGIN : null;
2142
2174
  markLines.push({
@@ -2268,6 +2300,8 @@ function buildCartesianOption(cfg) {
2268
2300
  show: horizontalBars ? showYAxis : showXAxis,
2269
2301
  boundaryGap: kind === "bar",
2270
2302
  inverse: horizontalBars,
2303
+ // Diverging: the axis stays at the plot's edge (not at 0, where labels would hit the negative bars); the zero line is a mark line.
2304
+ axisLine: diverging ? { show: false, onZero: false } : void 0,
2271
2305
  axisTick: { show: false },
2272
2306
  axisLabel: {
2273
2307
  hideOverlap: true,
@@ -2356,7 +2390,7 @@ function buildCartesianOption(cfg) {
2356
2390
  show: showLegend,
2357
2391
  top: 0,
2358
2392
  // Narrow: left-aligned and wrapping above the plot, so nothing is cut off at the right edge.
2359
- ...plotWidth !== void 0 && plotWidth < NARROW_PLOT_WIDTH ? { left: 0, right: 0 } : { right: reserveActions ? ACTIONS_RESERVE : 0 },
2393
+ ...plotWidth !== void 0 && plotWidth < NARROW_PLOT_WIDTH ? { left: 0, right: 0 } : { left: 0, right: reserveActions ? ACTIONS_RESERVE : 0 },
2360
2394
  // Plain wraps onto a second line at narrow widths instead of hiding items behind arrows.
2361
2395
  type: "plain",
2362
2396
  icon: "circle",
@@ -3539,7 +3573,8 @@ var CategoryBar = forwardRef(function CategoryBar2({ values = NO_ROWS6, colors,
3539
3573
  style: { background: markerColor }
3540
3574
  }
3541
3575
  );
3542
- return /* @__PURE__ */ jsxs("div", { ref, "data-slot": "category-bar", className: cn("w-full", className), ...props, children: [
3576
+ const labelled = props["aria-label"] != null || props["aria-labelledby"] != null;
3577
+ return /* @__PURE__ */ jsxs("div", { ref, "data-slot": "category-bar", role: labelled ? "group" : void 0, className: cn("w-full", className), ...props, children: [
3543
3578
  showLabels && labels.length > 0 && /* @__PURE__ */ jsx("div", { "data-slot": "category-bar-labels", className: "relative mb-2 h-4 text-xs text-muted-foreground tabular-nums", children: labels.map((label2, i) => /* @__PURE__ */ jsx(
3544
3579
  "span",
3545
3580
  {
@@ -3574,7 +3609,7 @@ var CategoryBar = forwardRef(function CategoryBar2({ values = NO_ROWS6, colors,
3574
3609
  ),
3575
3610
  style: { left: `${markerPosition}%` },
3576
3611
  children: marker.tooltip ? /* @__PURE__ */ jsxs(Tooltip, { children: [
3577
- /* @__PURE__ */ jsx(TooltipTrigger, { render: /* @__PURE__ */ jsx("span", { "aria-label": marker.tooltip, className: "block py-1" }), children: markerDot }),
3612
+ /* @__PURE__ */ jsx(TooltipTrigger, { render: /* @__PURE__ */ jsx("button", { type: "button", "aria-label": marker.tooltip, className: "block cursor-default py-1" }), children: markerDot }),
3578
3613
  /* @__PURE__ */ jsx(TooltipContent, { children: marker.tooltip })
3579
3614
  ] }) : markerDot
3580
3615
  }
@@ -3883,8 +3918,19 @@ var STEP_LABEL_MIN_SLOT = 44;
3883
3918
  function stepLabelWidth(plotWidth, steps) {
3884
3919
  return Math.max(24, stepSlotWidth(plotWidth, steps) - 8);
3885
3920
  }
3886
- function stepLabelLayout(plotWidth, steps) {
3887
- return stepSlotWidth(plotWidth, steps) >= STEP_LABEL_MIN_SLOT ? { width: stepLabelWidth(plotWidth, steps), rotate: 0 } : { rotate: 45 };
3921
+ function longestWordWidth(names) {
3922
+ let widest = 0;
3923
+ for (const name of names) {
3924
+ for (const word of name.split(/\s+/)) {
3925
+ let w = 0;
3926
+ for (const ch of word) w += ch.charCodeAt(0) > 11903 ? 12 : 7;
3927
+ widest = Math.max(widest, w);
3928
+ }
3929
+ }
3930
+ return widest;
3931
+ }
3932
+ function stepLabelLayout(plotWidth, steps, names = []) {
3933
+ return stepSlotWidth(plotWidth, steps) >= STEP_LABEL_MIN_SLOT && longestWordWidth(names) <= stepLabelWidth(plotWidth, steps) ? { width: stepLabelWidth(plotWidth, steps), rotate: 0 } : { rotate: 45 };
3888
3934
  }
3889
3935
  function waterfallValueLabelPlan(steps, texts, plotWidth) {
3890
3936
  const show = steps.map((s) => s.kind !== "gap");
@@ -4025,7 +4071,7 @@ function buildWaterfallOption(config) {
4025
4071
  interval: 0,
4026
4072
  hideOverlap: false,
4027
4073
  formatter: (value) => labelOf(value, labels),
4028
- ...config.plotWidth ? { ...stepLabelLayout(config.plotWidth, steps.length), overflow: "break" } : {}
4074
+ ...config.plotWidth ? { ...stepLabelLayout(config.plotWidth, steps.length, steps.map((st) => labelOf(st.name, labels))), overflow: "break" } : {}
4029
4075
  }
4030
4076
  },
4031
4077
  yAxis: {
@@ -4386,8 +4432,8 @@ function buildScatterOption(config) {
4386
4432
  legend: {
4387
4433
  show: showLegend,
4388
4434
  ...legendBelow ? { bottom: 0 } : { top: 0 },
4389
- // With a heading the legend reads from the left, after it; otherwise it sits at the right edge.
4390
- ...headingWidth > 0 ? { left: headingWidth } : legendBelow ? { left: 0 } : { right: config.reserveActions ? 72 : 0 },
4435
+ // With a heading the legend reads from the left, after it; otherwise it sits at the left edge (as in every chart).
4436
+ ...headingWidth > 0 ? { left: headingWidth } : { left: 0, ...legendBelow ? {} : { right: config.reserveActions ? 72 : 0 } },
4391
4437
  type: "plain",
4392
4438
  icon: "circle",
4393
4439
  itemWidth: 8,
@@ -4400,7 +4446,9 @@ function buildScatterOption(config) {
4400
4446
  top: (showLegend && !legendBelow ? 12 + 24 * legendLineCount : 12) + (guides.some((line) => line.axis === "x" && line.label) && (!showLegend || legendBelow) ? 14 : 0),
4401
4447
  right: 24,
4402
4448
  bottom: legendBelow ? 24 + 24 * legendLineCount : 24,
4403
- left: 24,
4449
+ // The rotated y axis name lies outside `containLabel`'s reach (its right edge is `nameGap` left of the axis line): the
4450
+ // margin holds its height, so the name is never cut at the chart's left edge.
4451
+ left: 36,
4404
4452
  containLabel: true
4405
4453
  },
4406
4454
  ...headingWidth > 0 ? {
@@ -4449,7 +4497,7 @@ function buildScatterOption(config) {
4449
4497
  label: {
4450
4498
  show: keptLabels === null,
4451
4499
  position: "right",
4452
- distance: 6,
4500
+ distance: 8,
4453
4501
  fontSize: 11,
4454
4502
  color: config.textColors?.label,
4455
4503
  // Plain text: an outline / shadow reads as a halo on a dark surface.
@@ -4457,7 +4505,8 @@ function buildScatterOption(config) {
4457
4505
  textShadowBlur: 0,
4458
4506
  formatter: (p) => p.data?.point?.label ?? ""
4459
4507
  },
4460
- labelLayout: { hideOverlap: true, moveOverlap: "shiftY" }
4508
+ // A name stays beside its own dot: one that would collide with another is hidden, not pushed onto a neighbouring dot.
4509
+ labelLayout: { hideOverlap: true }
4461
4510
  } : {},
4462
4511
  // The guide lines hang off the first series (a markLine belongs to one).
4463
4512
  ...i === 0 && guides.length > 0 ? {
@@ -4631,7 +4680,7 @@ var TEXT11 = {
4631
4680
  ja: { legend: "\u51E1\u4F8B" },
4632
4681
  en: { legend: "Legend" }
4633
4682
  };
4634
- var Legend = forwardRef(function Legend2({ categories, colors, labels, layout = "horizontal", ariaLabel, className }, ref) {
4683
+ var Legend = forwardRef(function Legend2({ categories, colors, labels, layout = "horizontal", hidden = [], onHiddenChange, ariaLabel, className }, ref) {
4635
4684
  const t = TEXT11[uiLanguage(useLocale())];
4636
4685
  if (categories.length === 0) return null;
4637
4686
  const swatches = legendColors(categories, colors);
@@ -4643,10 +4692,23 @@ var Legend = forwardRef(function Legend2({ categories, colors, labels, layout =
4643
4692
  "data-layout": layout,
4644
4693
  "aria-label": ariaLabel ?? t.legend,
4645
4694
  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),
4646
- children: categories.map((category, i) => /* @__PURE__ */ jsxs("li", { "data-slot": "legend-item", className: "flex min-w-0 items-center gap-1.5", children: [
4647
- /* @__PURE__ */ jsx("span", { "aria-hidden": "true", className: "size-2.5 shrink-0 rounded-[2px]", style: { background: swatches[i] } }),
4648
- /* @__PURE__ */ jsx("span", { className: "min-w-0 truncate text-muted-foreground", children: labelOf(category, labels) })
4649
- ] }, category))
4695
+ children: categories.map((category, i) => {
4696
+ const off = hidden.includes(category);
4697
+ const chip = /* @__PURE__ */ jsxs(Fragment, { children: [
4698
+ /* @__PURE__ */ jsx("span", { "aria-hidden": "true", className: cn("size-2.5 shrink-0 rounded-[2px]", off && "opacity-30"), style: { background: swatches[i] } }),
4699
+ /* @__PURE__ */ jsx("span", { className: cn("min-w-0 truncate text-muted-foreground", off && "line-through opacity-60"), children: labelOf(category, labels) })
4700
+ ] });
4701
+ return /* @__PURE__ */ jsx("li", { "data-slot": "legend-item", "data-hidden": off || void 0, className: "flex min-w-0 items-center gap-1.5", children: onHiddenChange ? /* @__PURE__ */ jsx(
4702
+ "button",
4703
+ {
4704
+ type: "button",
4705
+ "aria-pressed": !off,
4706
+ onClick: () => onHiddenChange(off ? hidden.filter((c) => c !== category) : [...hidden, category]),
4707
+ className: "flex min-w-0 cursor-pointer items-center gap-1.5 rounded-sm outline-none focus-visible:ring-2 focus-visible:ring-ring",
4708
+ children: chip
4709
+ }
4710
+ ) : chip }, category);
4711
+ })
4650
4712
  }
4651
4713
  );
4652
4714
  });
@@ -5446,7 +5508,7 @@ function buildPairedOption(cfg) {
5446
5508
  const right = 16;
5447
5509
  const option = {
5448
5510
  ...barOpt,
5449
- legend: { ...barOpt.legend, show: showLegend, data: legendNames, right: cfg.reserveActions ? 80 : 0 },
5511
+ legend: { ...barOpt.legend, show: showLegend, data: legendNames, left: 0, right: cfg.reserveActions ? 80 : 0 },
5450
5512
  grid: [
5451
5513
  { top, height: upper, left: gridLeft, right, containLabel: true },
5452
5514
  { top: top + upper + PANEL_GAP, bottom: 4, left: gridLeft, right, containLabel: true }
@@ -6214,11 +6276,11 @@ var legacyColorTones = {
6214
6276
  blue: "info"
6215
6277
  };
6216
6278
  var toneStyles = {
6217
- positive: { dot: "bg-positive", bg: "bg-positive-subtle", text: "text-positive", border: "border-positive/20 dark:border-positive/25" },
6218
- negative: { dot: "bg-negative", bg: "bg-negative-subtle", text: "text-negative", border: "border-negative/20 dark:border-negative/25" },
6219
- warning: { dot: "bg-warning", bg: "bg-warning-subtle", text: "text-warning", border: "border-warning/20 dark:border-warning/25" },
6220
- info: { dot: "bg-info", bg: "bg-info-subtle", text: "text-info", border: "border-info/20 dark:border-info/25" },
6221
- neutral: { dot: "bg-neutral", bg: "bg-neutral-subtle", text: "text-neutral", border: "border-neutral/20 dark:border-neutral/25" }
6279
+ positive: { dot: "bg-positive", bg: "bg-positive-subtle", text: "text-positive" },
6280
+ negative: { dot: "bg-negative", bg: "bg-negative-subtle", text: "text-negative" },
6281
+ warning: { dot: "bg-warning", bg: "bg-warning-subtle", text: "text-warning" },
6282
+ info: { dot: "bg-info", bg: "bg-info-subtle", text: "text-info" },
6283
+ neutral: { dot: "bg-neutral", bg: "bg-neutral-subtle", text: "text-neutral" }
6222
6284
  };
6223
6285
  var resolveTone = (color) => {
6224
6286
  if (color === void 0) return "neutral";
@@ -6236,7 +6298,7 @@ var StatusBadge = forwardRef(function StatusBadge2({ status, label: label2, colo
6236
6298
  ref,
6237
6299
  "data-slot": "status-badge",
6238
6300
  variant: "outline",
6239
- className: cn("gap-1.5 rounded-md", style.border, style.bg, style.text, className),
6301
+ className: cn("gap-1.5 rounded-md border-transparent", style.bg, style.text, className),
6240
6302
  "aria-label": displayLabel,
6241
6303
  children: [
6242
6304
  /* @__PURE__ */ jsx("span", { className: cn("inline-block size-1.5 rounded-full", style.dot), "aria-hidden": "true" }),
@@ -8421,6 +8483,8 @@ var TEXT23 = {
8421
8483
  selectRow: "\u884C\u3092\u9078\u629E",
8422
8484
  trend: (points, first, last, min, max) => `${points}\u70B9\u306E\u63A8\u79FB\u3001${first}\u304B\u3089${last}\u3001\u6700\u5C0F${min}\u3001\u6700\u5927${max}`,
8423
8485
  noData: "\u30C7\u30FC\u30BF\u304C\u3042\u308A\u307E\u305B\u3093",
8486
+ search: "\u691C\u7D22",
8487
+ pageSizeLabel: "1\u30DA\u30FC\u30B8\u306E\u8868\u793A\u4EF6\u6570",
8424
8488
  pageSize: (size) => `${size}\u4EF6`,
8425
8489
  range: (total, start, end) => `${total}\u4EF6\u4E2D ${start} - ${end} \u3092\u8868\u793A`,
8426
8490
  first: "\u6700\u521D",
@@ -8437,6 +8501,8 @@ var TEXT23 = {
8437
8501
  selectRow: "Select row",
8438
8502
  trend: (points, first, last, min, max) => `Trend over ${points} points: ${first} to ${last}, min ${min}, max ${max}`,
8439
8503
  noData: "No results.",
8504
+ search: "Search",
8505
+ pageSizeLabel: "Rows per page",
8440
8506
  pageSize: (size) => `${size} / page`,
8441
8507
  range: (total, start, end) => `Showing ${start}\u2013${end} of ${total}`,
8442
8508
  first: "First",
@@ -8699,6 +8765,7 @@ DataTable.displayName = "DataTable";
8699
8765
  var DataTableToolbar = forwardRef(
8700
8766
  ({ showSearch, toolbar, bulkActions, className, ...props }, ref) => {
8701
8767
  const { globalFilter, setGlobalFilter, hasSelection, selectedRows, enableFiltering } = useDataTable();
8768
+ const t = useText();
8702
8769
  const showSearchEffective = showSearch ?? enableFiltering;
8703
8770
  const hasContent = showSearchEffective || toolbar != null || hasSelection && bulkActions != null;
8704
8771
  if (!hasContent) return null;
@@ -8715,6 +8782,7 @@ var DataTableToolbar = forwardRef(
8715
8782
  /* @__PURE__ */ jsx(
8716
8783
  Input,
8717
8784
  {
8785
+ "aria-label": t.search,
8718
8786
  value: globalFilter,
8719
8787
  onChange: (e) => setGlobalFilter(e.target.value),
8720
8788
  className: "max-w-sm pl-8"
@@ -8898,7 +8966,7 @@ var DataTablePagination = forwardRef(
8898
8966
  value: String(currentPageSize),
8899
8967
  onValueChange: (value) => table.setPageSize(Number(value)),
8900
8968
  children: [
8901
- /* @__PURE__ */ jsx(SelectTrigger, { size: "sm", className: "min-w-[80px]", children: /* @__PURE__ */ jsx(SelectValue, {}) }),
8969
+ /* @__PURE__ */ jsx(SelectTrigger, { size: "sm", className: "min-w-[80px]", "aria-label": t.pageSizeLabel, children: /* @__PURE__ */ jsx(SelectValue, {}) }),
8902
8970
  /* @__PURE__ */ jsx(SelectContent, { children: pageSizeItems.map((item) => /* @__PURE__ */ jsx(SelectItem, { value: item.value, children: item.label }, item.value)) })
8903
8971
  ]
8904
8972
  }
@@ -9229,6 +9297,7 @@ var FilterBarContext = createContext(null);
9229
9297
  var TEXT25 = {
9230
9298
  ja: {
9231
9299
  filters: "\u30D5\u30A3\u30EB\u30BF\u30FC",
9300
+ addFilter: "\u30D5\u30A3\u30EB\u30BF\u30FC\u3092\u8FFD\u52A0",
9232
9301
  selected: (count) => ` (${count}\u4EF6\u9078\u629E\u4E2D)`,
9233
9302
  remove: (filter, option) => `${filter}: ${option} \u3092\u524A\u9664`,
9234
9303
  clear: "\u30AF\u30EA\u30A2",
@@ -9236,6 +9305,7 @@ var TEXT25 = {
9236
9305
  },
9237
9306
  en: {
9238
9307
  filters: "Filters",
9308
+ addFilter: "Add filter",
9239
9309
  selected: (count) => ` (${count} selected)`,
9240
9310
  remove: (filter, option) => `Remove ${filter}: ${option}`,
9241
9311
  clear: "Clear",
@@ -9346,6 +9416,50 @@ function FilterBarMultiSelect({
9346
9416
  ] });
9347
9417
  }
9348
9418
  FilterBarMultiSelect.displayName = "FilterBarMultiSelect";
9419
+ function FilterBarAddFilter({ filters, className }) {
9420
+ const { value, onChange } = useFilterBar();
9421
+ const t = useText2();
9422
+ const toggle = (filter, option) => {
9423
+ if (filter.type === "multi-select") {
9424
+ const current = value[filter.key] ?? [];
9425
+ const next = current.includes(option) ? current.filter((v) => v !== option) : [...current, option];
9426
+ onChange({ ...value, [filter.key]: next.length > 0 ? next : void 0 });
9427
+ } else {
9428
+ onChange({ ...value, [filter.key]: value[filter.key] === option ? void 0 : option });
9429
+ }
9430
+ };
9431
+ const isChecked = (filter, option) => {
9432
+ const v = value[filter.key];
9433
+ return Array.isArray(v) ? v.includes(option) : v === option;
9434
+ };
9435
+ return /* @__PURE__ */ jsxs(DropdownMenu, { children: [
9436
+ /* @__PURE__ */ jsxs(
9437
+ DropdownMenuTrigger,
9438
+ {
9439
+ render: /* @__PURE__ */ jsx(Button, { variant: "outline", size: "sm", className: cn("h-8 gap-1", className) }),
9440
+ "data-slot": "filter-bar-add-filter",
9441
+ children: [
9442
+ /* @__PURE__ */ jsx(Plus, { className: "size-3.5", "aria-hidden": "true" }),
9443
+ t.addFilter
9444
+ ]
9445
+ }
9446
+ ),
9447
+ /* @__PURE__ */ jsx(DropdownMenuContent, { align: "start", className: "w-48", children: filters.filter((f) => (f.type === "select" || f.type === "multi-select") && f.options?.length).map((filter) => /* @__PURE__ */ jsxs(DropdownMenuSub, { children: [
9448
+ /* @__PURE__ */ jsx(DropdownMenuSubTrigger, { children: filter.label }),
9449
+ /* @__PURE__ */ jsx(DropdownMenuSubContent, { children: filter.options?.map((option) => /* @__PURE__ */ jsx(
9450
+ DropdownMenuCheckboxItem,
9451
+ {
9452
+ checked: isChecked(filter, option.value),
9453
+ disabled: option.disabled,
9454
+ onCheckedChange: () => toggle(filter, option.value),
9455
+ children: option.label
9456
+ },
9457
+ option.value
9458
+ )) })
9459
+ ] }, filter.key)) })
9460
+ ] });
9461
+ }
9462
+ FilterBarAddFilter.displayName = "FilterBarAddFilter";
9349
9463
  function FilterBarActiveChips({ filters, className }) {
9350
9464
  const { value, onChange } = useFilterBar();
9351
9465
  const t = useText2();
@@ -9509,6 +9623,11 @@ function fiscalPeriodRange(date, {
9509
9623
  const periodStart = addMonths(startOfMonth(subMonths(date, into)), offset * length);
9510
9624
  return { from: periodStart, to: endOfMonth(addMonths(periodStart, length - 1)) };
9511
9625
  }
9626
+ function comparisonRange({ from, to }, kind) {
9627
+ if (kind === "previous-year") return { from: subYears(from, 1), to: subYears(to, 1) };
9628
+ const days = differenceInCalendarDays(to, from) + 1;
9629
+ return { from: subDays(from, days), to: subDays(from, 1) };
9630
+ }
9512
9631
  var PRESET_LABELS = {
9513
9632
  ja: {
9514
9633
  today: "\u4ECA\u65E5",
@@ -9546,8 +9665,14 @@ var PRESET_LABELS = {
9546
9665
  }
9547
9666
  };
9548
9667
  var TEXT26 = {
9549
- ja: { placeholder: "\u671F\u9593\u3092\u9078\u629E", rangeSeparator: " - " },
9550
- en: { placeholder: "Pick a date range", rangeSeparator: " \u2013 " }
9668
+ ja: {
9669
+ placeholder: "\u671F\u9593\u3092\u9078\u629E",
9670
+ comparison: { "previous-period": "\u524D\u671F\u9593", "previous-year": "\u524D\u5E74\u540C\u671F" }
9671
+ },
9672
+ en: {
9673
+ placeholder: "Pick a date range",
9674
+ comparison: { "previous-period": "vs. previous period", "previous-year": "vs. same period last year" }
9675
+ }
9551
9676
  };
9552
9677
  var calendarLocale = (locale) => uiLanguage(locale) === "ja" ? ja : void 0;
9553
9678
  function createDatePresets({
@@ -9636,6 +9761,7 @@ var DateRangePicker = forwardRef(
9636
9761
  showPresets = true,
9637
9762
  locale: localeProp,
9638
9763
  fiscalYearStartMonth,
9764
+ comparison,
9639
9765
  maxDate,
9640
9766
  minDate,
9641
9767
  placeholder,
@@ -9667,10 +9793,14 @@ var DateRangePicker = forwardRef(
9667
9793
  const formatDateRange2 = () => {
9668
9794
  if (!value?.from) return placeholder ?? t.placeholder;
9669
9795
  if (!value.to) return formatDate(value.from, "date", locale);
9670
- return `${formatDate(value.from, "date", locale)}${t.rangeSeparator}${formatDate(value.to, "date", locale)}`;
9796
+ return formatDateRange(value.from, value.to, { locale });
9671
9797
  };
9672
9798
  const selectedPreset = findMatchingPreset(presets, value);
9673
9799
  const presetLabel = selectedPreset?.label;
9800
+ const comparisonText = comparison && value?.from && value.to ? (() => {
9801
+ const c = comparisonRange({ from: value.from, to: value.to }, comparison);
9802
+ return `${t.comparison[comparison]} ${formatDateRange(c.from, c.to, { locale })}`;
9803
+ })() : void 0;
9674
9804
  const endMonth = value?.to ?? value?.from;
9675
9805
  const defaultMonth = endMonth ? isMobile ? endMonth : subMonths(endMonth, 1) : void 0;
9676
9806
  const calendarSelected = value?.from ? { from: value.from, to: value.to ?? void 0 } : void 0;
@@ -9697,7 +9827,8 @@ var DateRangePicker = forwardRef(
9697
9827
  presetLabel ? /* @__PURE__ */ jsxs(Fragment, { children: [
9698
9828
  /* @__PURE__ */ jsx("span", { children: presetLabel }),
9699
9829
  /* @__PURE__ */ jsx("span", { className: "text-muted-foreground", children: formatDateRange2() })
9700
- ] }) : /* @__PURE__ */ jsx("span", { children: formatDateRange2() })
9830
+ ] }) : /* @__PURE__ */ jsx("span", { children: formatDateRange2() }),
9831
+ comparisonText && /* @__PURE__ */ jsx("span", { "data-slot": "date-range-picker-comparison", className: "text-muted-foreground", children: comparisonText })
9701
9832
  ]
9702
9833
  }
9703
9834
  ),
@@ -10144,7 +10275,7 @@ var deltaVariants = cva(
10144
10275
  {
10145
10276
  variants: {
10146
10277
  variant: {
10147
- badge: "h-5 rounded-md border px-2 py-0.5 text-xs font-medium [&>svg]:size-3",
10278
+ badge: "h-5 rounded-md px-2 py-0.5 text-xs font-medium [&>svg]:size-3",
10148
10279
  inline: "text-sm [&>svg]:size-3.5"
10149
10280
  },
10150
10281
  sentiment: {
@@ -10154,9 +10285,9 @@ var deltaVariants = cva(
10154
10285
  }
10155
10286
  },
10156
10287
  compoundVariants: [
10157
- { variant: "badge", sentiment: "positive", className: "border-positive/20 bg-positive-subtle dark:border-positive/25" },
10158
- { variant: "badge", sentiment: "negative", className: "border-negative/20 bg-negative-subtle dark:border-negative/25" },
10159
- { variant: "badge", sentiment: "neutral", className: "border-neutral/20 bg-neutral-subtle dark:border-neutral/25" }
10288
+ { variant: "badge", sentiment: "positive", className: "bg-positive-subtle" },
10289
+ { variant: "badge", sentiment: "negative", className: "bg-negative-subtle" },
10290
+ { variant: "badge", sentiment: "neutral", className: "bg-neutral-subtle" }
10160
10291
  ],
10161
10292
  defaultVariants: {
10162
10293
  variant: "badge",
@@ -10189,6 +10320,7 @@ function deltaAriaLabel(result, locale, change = "relative", format, digits) {
10189
10320
  if (amount === null) return t.none(label2);
10190
10321
  return t.change(label2, change === "points" ? amount.replace(/pt$/, t.points) : amount, direction === "up");
10191
10322
  }
10323
+ var SENTIMENT_TEXT = { positive: "text-positive", negative: "text-negative", neutral: "text-neutral" };
10192
10324
  var Delta = forwardRef(
10193
10325
  ({
10194
10326
  value,
@@ -10218,7 +10350,7 @@ var Delta = forwardRef(
10218
10350
  const comparable = result.direction !== "none";
10219
10351
  const Icon = result.direction === "up" ? ArrowUp : result.direction === "down" ? ArrowDown : ArrowRight;
10220
10352
  const text = formatChange(result, display, locale, format, changeDigits);
10221
- return /* @__PURE__ */ jsxs(
10353
+ return /* @__PURE__ */ jsx(
10222
10354
  "span",
10223
10355
  {
10224
10356
  ref,
@@ -10228,16 +10360,31 @@ var Delta = forwardRef(
10228
10360
  "data-sentiment": result.sentiment,
10229
10361
  "aria-label": deltaAriaLabel(result, locale, display, format, changeDigits),
10230
10362
  className: cn(
10231
- deltaVariants({ variant, sentiment: result.sentiment }),
10363
+ variant === "badge" ? "inline-flex w-fit shrink-0 items-center gap-1.5 font-medium whitespace-nowrap tabular-nums" : deltaVariants({ variant, sentiment: result.sentiment }),
10364
+ // The chip carries the colour of the change; the root repeats it for the "—" case and for `className` consumers.
10365
+ variant === "badge" && SENTIMENT_TEXT[result.sentiment],
10232
10366
  !comparable && "text-muted-foreground",
10233
10367
  className
10234
10368
  ),
10235
10369
  ...props,
10236
- children: [
10370
+ children: variant === "badge" ? /* @__PURE__ */ jsxs(Fragment, { children: [
10371
+ /* @__PURE__ */ jsxs(
10372
+ "span",
10373
+ {
10374
+ "data-slot": "delta-chip",
10375
+ className: cn(deltaVariants({ variant, sentiment: result.sentiment }), !comparable && "text-muted-foreground"),
10376
+ children: [
10377
+ comparable && /* @__PURE__ */ jsx(Icon, { "aria-hidden": "true" }),
10378
+ /* @__PURE__ */ jsx("span", { "aria-hidden": "true", children: text ?? DELTA_NOT_COMPARABLE })
10379
+ ]
10380
+ }
10381
+ ),
10382
+ showLabel && /* @__PURE__ */ jsx("span", { "aria-hidden": "true", className: "text-xs font-normal text-muted-foreground", children: result.label })
10383
+ ] }) : /* @__PURE__ */ jsxs(Fragment, { children: [
10237
10384
  comparable && /* @__PURE__ */ jsx(Icon, { "aria-hidden": "true" }),
10238
10385
  /* @__PURE__ */ jsx("span", { "aria-hidden": "true", children: text ?? DELTA_NOT_COMPARABLE }),
10239
10386
  showLabel && /* @__PURE__ */ jsx("span", { "aria-hidden": "true", className: "font-normal text-muted-foreground", children: result.label })
10240
- ]
10387
+ ] })
10241
10388
  }
10242
10389
  );
10243
10390
  }
@@ -10413,7 +10560,7 @@ function KpiCard({
10413
10560
  const targetBar = hasTarget && !neutral && !byPoints && !lower;
10414
10561
  if (summary !== void 0) warnShallowSummary(summary, t);
10415
10562
  const cardClass = cn("row-span-2 grid content-start gap-y-0 grid-rows-subgrid", className);
10416
- const valueSize = small ? "text-xl @[218px]/card:text-2xl" : "text-2xl @[218px]/card:text-4xl";
10563
+ const valueSize = small ? "text-xl @[218px]/card:text-2xl" : "text-2xl @[218px]/card:text-[26px]";
10417
10564
  if (isLoading) {
10418
10565
  return /* @__PURE__ */ jsxs(
10419
10566
  Card,
@@ -10518,7 +10665,8 @@ function KpiCard({
10518
10665
  format,
10519
10666
  change: display,
10520
10667
  digits,
10521
- locale
10668
+ locale,
10669
+ className: "min-w-0 shrink whitespace-normal"
10522
10670
  },
10523
10671
  i
10524
10672
  ));
@@ -10526,16 +10674,20 @@ function KpiCard({
10526
10674
  const longValue = valueText.length > LONG_VALUE_CHARS;
10527
10675
  return /* @__PURE__ */ jsxs(Card, { "data-slot": "kpi-card", size, className: cardClass, ...props, children: [
10528
10676
  /* @__PURE__ */ jsxs(CardHeader, { className: HEADER_CLASS, children: [
10529
- /* @__PURE__ */ jsx(CardDescription, { "data-slot": "kpi-card-label", title: label2, className: "col-start-1 min-w-0 truncate text-[13px] leading-snug font-medium text-muted-foreground", children: label2 }),
10677
+ /* @__PURE__ */ jsxs(CardDescription, { "data-slot": "kpi-card-label", title: label2, className: "col-start-1 flex min-w-0 items-center gap-2 text-[13px] leading-snug font-medium text-muted-foreground", children: [
10678
+ /* @__PURE__ */ jsx("span", { className: "min-w-0 truncate", children: label2 }),
10679
+ sample && /* @__PURE__ */ jsx(SampleBadge, { label: sample.label, className: "shrink-0" })
10680
+ ] }),
10530
10681
  /* @__PURE__ */ jsxs(
10531
10682
  CardTitle,
10532
10683
  {
10533
10684
  "data-slot": "kpi-card-value",
10534
10685
  title: valueText,
10535
10686
  className: cn(
10536
- "col-start-1 flex min-w-0 flex-wrap items-center gap-x-2 gap-y-1 leading-none font-semibold tracking-tight tabular-nums",
10687
+ "col-start-1 flex min-w-0 items-center gap-x-2 gap-y-1 leading-none font-medium tracking-tight tabular-nums",
10537
10688
  // Fixed size: the step follows the card width only, never the length of the value.
10538
- valueSize
10689
+ valueSize,
10690
+ (longValue || isProvisional) && "flex-wrap"
10539
10691
  ),
10540
10692
  children: [
10541
10693
  /* @__PURE__ */ jsx("span", { "data-slot": "kpi-card-value-text", className: longValue ? "min-w-0 break-words" : "whitespace-nowrap", children: longValue ? digitGroups(valueText).map((group, i) => /* @__PURE__ */ jsxs("span", { className: "whitespace-nowrap", children: [
@@ -10543,11 +10695,11 @@ function KpiCard({
10543
10695
  /* @__PURE__ */ jsx("wbr", {})
10544
10696
  ] }, i)) : valueText }),
10545
10697
  isProvisional && /* @__PURE__ */ jsx(Badge, { "data-slot": "kpi-card-provisional", variant: "outline", className: "align-middle", children: provisionalLabel }),
10546
- sample && /* @__PURE__ */ jsx(SampleBadge, { label: sample.label })
10698
+ comparison && !stacked && !longValue && deltas
10547
10699
  ]
10548
10700
  }
10549
10701
  ),
10550
- 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 })),
10702
+ comparison && (stacked ? /* @__PURE__ */ jsx("div", { "data-slot": "kpi-card-comparisons", className: "flex flex-wrap items-center gap-1", children: deltas }) : longValue && /* @__PURE__ */ jsx(CardAction, { className: DELTA_UNDER_PLACEMENT, children: deltas })),
10551
10703
  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 ?? "") }),
10552
10704
  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: [
10553
10705
  /* @__PURE__ */ jsxs(
@@ -10620,7 +10772,7 @@ function KpiCard({
10620
10772
  {
10621
10773
  data: historyPoints.map((v) => ({ value: v })),
10622
10774
  height: SPARKLINE_HEIGHT,
10623
- color: "text-chart-1",
10775
+ color: "chart-1",
10624
10776
  highlight: "latest",
10625
10777
  "aria-label": t.history(label2, historyPoints.length)
10626
10778
  }
@@ -10759,6 +10911,6 @@ function DraftChartPreview({ children }) {
10759
10911
  return /* @__PURE__ */ jsx("div", { ref, "data-slot": "draft-chart", style: { display: "contents" }, children });
10760
10912
  }
10761
10913
 
10762
- export { AppShell, AreaChart, AttentionList, BarChart, BarList, BoxPlotChart, COMPARISON_LABELS, CategoryBar, ChartFrame, ComboChart, 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, DraftChart, FilledMap, FilterBar, FilterBarActiveChips, FilterBarClearButton, FilterBarMultiSelect, FilterBarPreset, FilterBarSelect, ForecastChart, FunnelSteps, Heatmap, HistogramChart, KpiCard, Legend, LineChart, MetricUnit, MetricValue, MultiSelect, PageShell, PageShellActions, PageShellContent, PageShellDescription, PageShellHeader, PageShellHeaderEnd, PageShellHeading, PageShellMeta, PageShellSummary, PageShellSummaryCard, PageShellTitle, PairedChart, PivotTable, Placeholder, ProgressCircle, RECORD_MIN_POINTS, SampleBadge, SampleClaim, SampleData, ScatterChart, SearchableSelect, SectionHeader, SegmentedControl, StatusBadge, SymbolMap, Tracker, Treemap, 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 };
10763
- //# sourceMappingURL=chunk-YJQCB3UP.js.map
10764
- //# sourceMappingURL=chunk-YJQCB3UP.js.map
10914
+ export { AppShell, AreaChart, AttentionList, BarChart, BarList, BoxPlotChart, COMPARISON_LABELS, CategoryBar, ChartFrame, ComboChart, 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, DraftChart, FilledMap, FilterBar, FilterBarActiveChips, FilterBarAddFilter, FilterBarClearButton, FilterBarMultiSelect, FilterBarPreset, FilterBarSelect, ForecastChart, FunnelSteps, Heatmap, HistogramChart, KpiCard, Legend, LineChart, MetricUnit, MetricValue, MultiSelect, PageShell, PageShellActions, PageShellContent, PageShellDescription, PageShellHeader, PageShellHeaderEnd, PageShellHeading, PageShellMeta, PageShellSummary, PageShellSummaryCard, PageShellTitle, PairedChart, PivotTable, Placeholder, ProgressCircle, RECORD_MIN_POINTS, SampleBadge, SampleClaim, SampleData, ScatterChart, SearchableSelect, SectionHeader, SegmentedControl, StatusBadge, SymbolMap, Tracker, Treemap, 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 };
10915
+ //# sourceMappingURL=chunk-I2GWIPTD.js.map
10916
+ //# sourceMappingURL=chunk-I2GWIPTD.js.map