@squadbase/vantage 0.7.1-dev1.618b9b9 → 0.7.1-dev1.797ffdf

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.
@@ -1,10 +1,10 @@
1
- import { ChartFrameContext, useChartSurface, resolveChartColors, resolveFillColors, EChart, CHART_OTHER_COLOR } from './chunk-EG4PX726.js';
1
+ import { ChartFrameContext, useChartSurface, resolveChartColors, resolveFillColors, EChart, CHART_OTHER_COLOR } from './chunk-5AONNQZ6.js';
2
2
  import { Sparkline } from './chunk-P2KIHF65.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, 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
10
  import { Search, Columns3, CalendarIcon, ChevronDownIcon, ArrowUp, ArrowDown, ArrowRight, Minus, ChevronRight, ArrowUpDown, XIcon, LoaderIcon, CheckIcon, Download, ChevronDown, X, CircleX, TriangleAlert, CircleCheck } from 'lucide-react';
@@ -12,7 +12,7 @@ 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
  }
@@ -4386,8 +4421,8 @@ function buildScatterOption(config) {
4386
4421
  legend: {
4387
4422
  show: showLegend,
4388
4423
  ...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 },
4424
+ // With a heading the legend reads from the left, after it; otherwise it sits at the left edge (as in every chart).
4425
+ ...headingWidth > 0 ? { left: headingWidth } : { left: 0, ...legendBelow ? {} : { right: config.reserveActions ? 72 : 0 } },
4391
4426
  type: "plain",
4392
4427
  icon: "circle",
4393
4428
  itemWidth: 8,
@@ -4631,7 +4666,7 @@ var TEXT11 = {
4631
4666
  ja: { legend: "\u51E1\u4F8B" },
4632
4667
  en: { legend: "Legend" }
4633
4668
  };
4634
- var Legend = forwardRef(function Legend2({ categories, colors, labels, layout = "horizontal", ariaLabel, className }, ref) {
4669
+ var Legend = forwardRef(function Legend2({ categories, colors, labels, layout = "horizontal", hidden = [], onHiddenChange, ariaLabel, className }, ref) {
4635
4670
  const t = TEXT11[uiLanguage(useLocale())];
4636
4671
  if (categories.length === 0) return null;
4637
4672
  const swatches = legendColors(categories, colors);
@@ -4643,10 +4678,23 @@ var Legend = forwardRef(function Legend2({ categories, colors, labels, layout =
4643
4678
  "data-layout": layout,
4644
4679
  "aria-label": ariaLabel ?? t.legend,
4645
4680
  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))
4681
+ children: categories.map((category, i) => {
4682
+ const off = hidden.includes(category);
4683
+ const chip = /* @__PURE__ */ jsxs(Fragment, { children: [
4684
+ /* @__PURE__ */ jsx("span", { "aria-hidden": "true", className: cn("size-2.5 shrink-0 rounded-[2px]", off && "opacity-30"), style: { background: swatches[i] } }),
4685
+ /* @__PURE__ */ jsx("span", { className: cn("min-w-0 truncate text-muted-foreground", off && "line-through opacity-60"), children: labelOf(category, labels) })
4686
+ ] });
4687
+ 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(
4688
+ "button",
4689
+ {
4690
+ type: "button",
4691
+ "aria-pressed": !off,
4692
+ onClick: () => onHiddenChange(off ? hidden.filter((c) => c !== category) : [...hidden, category]),
4693
+ className: "flex min-w-0 cursor-pointer items-center gap-1.5 rounded-sm outline-none focus-visible:ring-2 focus-visible:ring-ring",
4694
+ children: chip
4695
+ }
4696
+ ) : chip }, category);
4697
+ })
4650
4698
  }
4651
4699
  );
4652
4700
  });
@@ -5446,7 +5494,7 @@ function buildPairedOption(cfg) {
5446
5494
  const right = 16;
5447
5495
  const option = {
5448
5496
  ...barOpt,
5449
- legend: { ...barOpt.legend, show: showLegend, data: legendNames, right: cfg.reserveActions ? 80 : 0 },
5497
+ legend: { ...barOpt.legend, show: showLegend, data: legendNames, left: 0, right: cfg.reserveActions ? 80 : 0 },
5450
5498
  grid: [
5451
5499
  { top, height: upper, left: gridLeft, right, containLabel: true },
5452
5500
  { top: top + upper + PANEL_GAP, bottom: 4, left: gridLeft, right, containLabel: true }
@@ -6214,11 +6262,11 @@ var legacyColorTones = {
6214
6262
  blue: "info"
6215
6263
  };
6216
6264
  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" }
6265
+ positive: { dot: "bg-positive", bg: "bg-positive-subtle", text: "text-positive" },
6266
+ negative: { dot: "bg-negative", bg: "bg-negative-subtle", text: "text-negative" },
6267
+ warning: { dot: "bg-warning", bg: "bg-warning-subtle", text: "text-warning" },
6268
+ info: { dot: "bg-info", bg: "bg-info-subtle", text: "text-info" },
6269
+ neutral: { dot: "bg-neutral", bg: "bg-neutral-subtle", text: "text-neutral" }
6222
6270
  };
6223
6271
  var resolveTone = (color) => {
6224
6272
  if (color === void 0) return "neutral";
@@ -6236,7 +6284,7 @@ var StatusBadge = forwardRef(function StatusBadge2({ status, label: label2, colo
6236
6284
  ref,
6237
6285
  "data-slot": "status-badge",
6238
6286
  variant: "outline",
6239
- className: cn("gap-1.5 rounded-md", style.border, style.bg, style.text, className),
6287
+ className: cn("gap-1.5 rounded-md border-transparent", style.bg, style.text, className),
6240
6288
  "aria-label": displayLabel,
6241
6289
  children: [
6242
6290
  /* @__PURE__ */ jsx("span", { className: cn("inline-block size-1.5 rounded-full", style.dot), "aria-hidden": "true" }),
@@ -8421,6 +8469,8 @@ var TEXT23 = {
8421
8469
  selectRow: "\u884C\u3092\u9078\u629E",
8422
8470
  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
8471
  noData: "\u30C7\u30FC\u30BF\u304C\u3042\u308A\u307E\u305B\u3093",
8472
+ search: "\u691C\u7D22",
8473
+ pageSizeLabel: "1\u30DA\u30FC\u30B8\u306E\u8868\u793A\u4EF6\u6570",
8424
8474
  pageSize: (size) => `${size}\u4EF6`,
8425
8475
  range: (total, start, end) => `${total}\u4EF6\u4E2D ${start} - ${end} \u3092\u8868\u793A`,
8426
8476
  first: "\u6700\u521D",
@@ -8437,6 +8487,8 @@ var TEXT23 = {
8437
8487
  selectRow: "Select row",
8438
8488
  trend: (points, first, last, min, max) => `Trend over ${points} points: ${first} to ${last}, min ${min}, max ${max}`,
8439
8489
  noData: "No results.",
8490
+ search: "Search",
8491
+ pageSizeLabel: "Rows per page",
8440
8492
  pageSize: (size) => `${size} / page`,
8441
8493
  range: (total, start, end) => `Showing ${start}\u2013${end} of ${total}`,
8442
8494
  first: "First",
@@ -8699,6 +8751,7 @@ DataTable.displayName = "DataTable";
8699
8751
  var DataTableToolbar = forwardRef(
8700
8752
  ({ showSearch, toolbar, bulkActions, className, ...props }, ref) => {
8701
8753
  const { globalFilter, setGlobalFilter, hasSelection, selectedRows, enableFiltering } = useDataTable();
8754
+ const t = useText();
8702
8755
  const showSearchEffective = showSearch ?? enableFiltering;
8703
8756
  const hasContent = showSearchEffective || toolbar != null || hasSelection && bulkActions != null;
8704
8757
  if (!hasContent) return null;
@@ -8715,6 +8768,7 @@ var DataTableToolbar = forwardRef(
8715
8768
  /* @__PURE__ */ jsx(
8716
8769
  Input,
8717
8770
  {
8771
+ "aria-label": t.search,
8718
8772
  value: globalFilter,
8719
8773
  onChange: (e) => setGlobalFilter(e.target.value),
8720
8774
  className: "max-w-sm pl-8"
@@ -8898,7 +8952,7 @@ var DataTablePagination = forwardRef(
8898
8952
  value: String(currentPageSize),
8899
8953
  onValueChange: (value) => table.setPageSize(Number(value)),
8900
8954
  children: [
8901
- /* @__PURE__ */ jsx(SelectTrigger, { size: "sm", className: "min-w-[80px]", children: /* @__PURE__ */ jsx(SelectValue, {}) }),
8955
+ /* @__PURE__ */ jsx(SelectTrigger, { size: "sm", className: "min-w-[80px]", "aria-label": t.pageSizeLabel, children: /* @__PURE__ */ jsx(SelectValue, {}) }),
8902
8956
  /* @__PURE__ */ jsx(SelectContent, { children: pageSizeItems.map((item) => /* @__PURE__ */ jsx(SelectItem, { value: item.value, children: item.label }, item.value)) })
8903
8957
  ]
8904
8958
  }
@@ -9229,6 +9283,7 @@ var FilterBarContext = createContext(null);
9229
9283
  var TEXT25 = {
9230
9284
  ja: {
9231
9285
  filters: "\u30D5\u30A3\u30EB\u30BF\u30FC",
9286
+ addFilter: "\u30D5\u30A3\u30EB\u30BF\u30FC\u3092\u8FFD\u52A0",
9232
9287
  selected: (count) => ` (${count}\u4EF6\u9078\u629E\u4E2D)`,
9233
9288
  remove: (filter, option) => `${filter}: ${option} \u3092\u524A\u9664`,
9234
9289
  clear: "\u30AF\u30EA\u30A2",
@@ -9236,6 +9291,7 @@ var TEXT25 = {
9236
9291
  },
9237
9292
  en: {
9238
9293
  filters: "Filters",
9294
+ addFilter: "Add filter",
9239
9295
  selected: (count) => ` (${count} selected)`,
9240
9296
  remove: (filter, option) => `Remove ${filter}: ${option}`,
9241
9297
  clear: "Clear",
@@ -9509,6 +9565,11 @@ function fiscalPeriodRange(date, {
9509
9565
  const periodStart = addMonths(startOfMonth(subMonths(date, into)), offset * length);
9510
9566
  return { from: periodStart, to: endOfMonth(addMonths(periodStart, length - 1)) };
9511
9567
  }
9568
+ function comparisonRange({ from, to }, kind) {
9569
+ if (kind === "previous-year") return { from: subYears(from, 1), to: subYears(to, 1) };
9570
+ const days = differenceInCalendarDays(to, from) + 1;
9571
+ return { from: subDays(from, days), to: subDays(from, 1) };
9572
+ }
9512
9573
  var PRESET_LABELS = {
9513
9574
  ja: {
9514
9575
  today: "\u4ECA\u65E5",
@@ -9546,8 +9607,16 @@ var PRESET_LABELS = {
9546
9607
  }
9547
9608
  };
9548
9609
  var TEXT26 = {
9549
- ja: { placeholder: "\u671F\u9593\u3092\u9078\u629E", rangeSeparator: " - " },
9550
- en: { placeholder: "Pick a date range", rangeSeparator: " \u2013 " }
9610
+ ja: {
9611
+ placeholder: "\u671F\u9593\u3092\u9078\u629E",
9612
+ rangeSeparator: " - ",
9613
+ comparison: { "previous-period": "\u524D\u671F\u9593", "previous-year": "\u524D\u5E74\u540C\u671F" }
9614
+ },
9615
+ en: {
9616
+ placeholder: "Pick a date range",
9617
+ rangeSeparator: " \u2013 ",
9618
+ comparison: { "previous-period": "vs. previous period", "previous-year": "vs. same period last year" }
9619
+ }
9551
9620
  };
9552
9621
  var calendarLocale = (locale) => uiLanguage(locale) === "ja" ? ja : void 0;
9553
9622
  function createDatePresets({
@@ -9636,6 +9705,7 @@ var DateRangePicker = forwardRef(
9636
9705
  showPresets = true,
9637
9706
  locale: localeProp,
9638
9707
  fiscalYearStartMonth,
9708
+ comparison,
9639
9709
  maxDate,
9640
9710
  minDate,
9641
9711
  placeholder,
@@ -9671,6 +9741,10 @@ var DateRangePicker = forwardRef(
9671
9741
  };
9672
9742
  const selectedPreset = findMatchingPreset(presets, value);
9673
9743
  const presetLabel = selectedPreset?.label;
9744
+ const comparisonText = comparison && value?.from && value.to ? (() => {
9745
+ const c = comparisonRange({ from: value.from, to: value.to }, comparison);
9746
+ return `${t.comparison[comparison]} ${formatDate(c.from, "date", locale)}${t.rangeSeparator}${formatDate(c.to, "date", locale)}`;
9747
+ })() : void 0;
9674
9748
  const endMonth = value?.to ?? value?.from;
9675
9749
  const defaultMonth = endMonth ? isMobile ? endMonth : subMonths(endMonth, 1) : void 0;
9676
9750
  const calendarSelected = value?.from ? { from: value.from, to: value.to ?? void 0 } : void 0;
@@ -9697,7 +9771,8 @@ var DateRangePicker = forwardRef(
9697
9771
  presetLabel ? /* @__PURE__ */ jsxs(Fragment, { children: [
9698
9772
  /* @__PURE__ */ jsx("span", { children: presetLabel }),
9699
9773
  /* @__PURE__ */ jsx("span", { className: "text-muted-foreground", children: formatDateRange2() })
9700
- ] }) : /* @__PURE__ */ jsx("span", { children: formatDateRange2() })
9774
+ ] }) : /* @__PURE__ */ jsx("span", { children: formatDateRange2() }),
9775
+ comparisonText && /* @__PURE__ */ jsx("span", { "data-slot": "date-range-picker-comparison", className: "text-muted-foreground", children: comparisonText })
9701
9776
  ]
9702
9777
  }
9703
9778
  ),
@@ -10144,7 +10219,7 @@ var deltaVariants = cva(
10144
10219
  {
10145
10220
  variants: {
10146
10221
  variant: {
10147
- badge: "h-5 rounded-md border px-2 py-0.5 text-xs font-medium [&>svg]:size-3",
10222
+ badge: "h-5 rounded-md px-2 py-0.5 text-xs font-medium [&>svg]:size-3",
10148
10223
  inline: "text-sm [&>svg]:size-3.5"
10149
10224
  },
10150
10225
  sentiment: {
@@ -10154,9 +10229,9 @@ var deltaVariants = cva(
10154
10229
  }
10155
10230
  },
10156
10231
  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" }
10232
+ { variant: "badge", sentiment: "positive", className: "bg-positive-subtle" },
10233
+ { variant: "badge", sentiment: "negative", className: "bg-negative-subtle" },
10234
+ { variant: "badge", sentiment: "neutral", className: "bg-neutral-subtle" }
10160
10235
  ],
10161
10236
  defaultVariants: {
10162
10237
  variant: "badge",
@@ -10189,6 +10264,7 @@ function deltaAriaLabel(result, locale, change = "relative", format, digits) {
10189
10264
  if (amount === null) return t.none(label2);
10190
10265
  return t.change(label2, change === "points" ? amount.replace(/pt$/, t.points) : amount, direction === "up");
10191
10266
  }
10267
+ var SENTIMENT_TEXT = { positive: "text-positive", negative: "text-negative", neutral: "text-neutral" };
10192
10268
  var Delta = forwardRef(
10193
10269
  ({
10194
10270
  value,
@@ -10218,7 +10294,7 @@ var Delta = forwardRef(
10218
10294
  const comparable = result.direction !== "none";
10219
10295
  const Icon = result.direction === "up" ? ArrowUp : result.direction === "down" ? ArrowDown : ArrowRight;
10220
10296
  const text = formatChange(result, display, locale, format, changeDigits);
10221
- return /* @__PURE__ */ jsxs(
10297
+ return /* @__PURE__ */ jsx(
10222
10298
  "span",
10223
10299
  {
10224
10300
  ref,
@@ -10228,16 +10304,31 @@ var Delta = forwardRef(
10228
10304
  "data-sentiment": result.sentiment,
10229
10305
  "aria-label": deltaAriaLabel(result, locale, display, format, changeDigits),
10230
10306
  className: cn(
10231
- deltaVariants({ variant, sentiment: result.sentiment }),
10307
+ variant === "badge" ? "inline-flex w-fit shrink-0 items-center gap-1.5 font-medium whitespace-nowrap tabular-nums" : deltaVariants({ variant, sentiment: result.sentiment }),
10308
+ // The chip carries the colour of the change; the root repeats it for the "—" case and for `className` consumers.
10309
+ variant === "badge" && SENTIMENT_TEXT[result.sentiment],
10232
10310
  !comparable && "text-muted-foreground",
10233
10311
  className
10234
10312
  ),
10235
10313
  ...props,
10236
- children: [
10314
+ children: variant === "badge" ? /* @__PURE__ */ jsxs(Fragment, { children: [
10315
+ /* @__PURE__ */ jsxs(
10316
+ "span",
10317
+ {
10318
+ "data-slot": "delta-chip",
10319
+ className: cn(deltaVariants({ variant, sentiment: result.sentiment }), !comparable && "text-muted-foreground"),
10320
+ children: [
10321
+ comparable && /* @__PURE__ */ jsx(Icon, { "aria-hidden": "true" }),
10322
+ /* @__PURE__ */ jsx("span", { "aria-hidden": "true", children: text ?? DELTA_NOT_COMPARABLE })
10323
+ ]
10324
+ }
10325
+ ),
10326
+ showLabel && /* @__PURE__ */ jsx("span", { "aria-hidden": "true", className: "text-xs font-normal text-muted-foreground", children: result.label })
10327
+ ] }) : /* @__PURE__ */ jsxs(Fragment, { children: [
10237
10328
  comparable && /* @__PURE__ */ jsx(Icon, { "aria-hidden": "true" }),
10238
10329
  /* @__PURE__ */ jsx("span", { "aria-hidden": "true", children: text ?? DELTA_NOT_COMPARABLE }),
10239
10330
  showLabel && /* @__PURE__ */ jsx("span", { "aria-hidden": "true", className: "font-normal text-muted-foreground", children: result.label })
10240
- ]
10331
+ ] })
10241
10332
  }
10242
10333
  );
10243
10334
  }
@@ -10413,7 +10504,7 @@ function KpiCard({
10413
10504
  const targetBar = hasTarget && !neutral && !byPoints && !lower;
10414
10505
  if (summary !== void 0) warnShallowSummary(summary, t);
10415
10506
  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";
10507
+ const valueSize = small ? "text-xl @[218px]/card:text-2xl" : "text-2xl @[218px]/card:text-[26px]";
10417
10508
  if (isLoading) {
10418
10509
  return /* @__PURE__ */ jsxs(
10419
10510
  Card,
@@ -10518,7 +10609,8 @@ function KpiCard({
10518
10609
  format,
10519
10610
  change: display,
10520
10611
  digits,
10521
- locale
10612
+ locale,
10613
+ className: "min-w-0 shrink whitespace-normal"
10522
10614
  },
10523
10615
  i
10524
10616
  ));
@@ -10526,16 +10618,20 @@ function KpiCard({
10526
10618
  const longValue = valueText.length > LONG_VALUE_CHARS;
10527
10619
  return /* @__PURE__ */ jsxs(Card, { "data-slot": "kpi-card", size, className: cardClass, ...props, children: [
10528
10620
  /* @__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 }),
10621
+ /* @__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: [
10622
+ /* @__PURE__ */ jsx("span", { className: "min-w-0 truncate", children: label2 }),
10623
+ sample && /* @__PURE__ */ jsx(SampleBadge, { label: sample.label, className: "shrink-0" })
10624
+ ] }),
10530
10625
  /* @__PURE__ */ jsxs(
10531
10626
  CardTitle,
10532
10627
  {
10533
10628
  "data-slot": "kpi-card-value",
10534
10629
  title: valueText,
10535
10630
  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",
10631
+ "col-start-1 flex min-w-0 items-center gap-x-2 gap-y-1 leading-none font-medium tracking-tight tabular-nums",
10537
10632
  // Fixed size: the step follows the card width only, never the length of the value.
10538
- valueSize
10633
+ valueSize,
10634
+ (longValue || isProvisional) && "flex-wrap"
10539
10635
  ),
10540
10636
  children: [
10541
10637
  /* @__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 +10639,11 @@ function KpiCard({
10543
10639
  /* @__PURE__ */ jsx("wbr", {})
10544
10640
  ] }, i)) : valueText }),
10545
10641
  isProvisional && /* @__PURE__ */ jsx(Badge, { "data-slot": "kpi-card-provisional", variant: "outline", className: "align-middle", children: provisionalLabel }),
10546
- sample && /* @__PURE__ */ jsx(SampleBadge, { label: sample.label })
10642
+ comparison && !stacked && !longValue && deltas
10547
10643
  ]
10548
10644
  }
10549
10645
  ),
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 })),
10646
+ 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
10647
  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
10648
  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
10649
  /* @__PURE__ */ jsxs(
@@ -10760,5 +10856,5 @@ function DraftChartPreview({ children }) {
10760
10856
  }
10761
10857
 
10762
10858
  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
10859
+ //# sourceMappingURL=chunk-PPWIDZPC.js.map
10860
+ //# sourceMappingURL=chunk-PPWIDZPC.js.map