gridsmith-ui 0.31.1 → 0.33.0

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 (84) hide show
  1. package/CHANGELOG.md +78 -1
  2. package/README.md +4 -2
  3. package/dist/charts.d.ts +111 -31
  4. package/dist/charts.js +288 -148
  5. package/dist/charts.js.map +1 -1
  6. package/dist/chat.js +6 -6
  7. package/dist/{chunk-EZ3ZGFGA.js → chunk-2724SJO2.js} +12 -4
  8. package/dist/chunk-2724SJO2.js.map +1 -0
  9. package/dist/{chunk-I6JJ7KKP.js → chunk-6NRLTG5W.js} +16 -11
  10. package/dist/chunk-6NRLTG5W.js.map +1 -0
  11. package/dist/{chunk-BHTAVJIG.js → chunk-6XCWKLJZ.js} +41 -6
  12. package/dist/chunk-6XCWKLJZ.js.map +1 -0
  13. package/dist/{chunk-TH272DIC.js → chunk-AB4UQ4G5.js} +125 -235
  14. package/dist/chunk-AB4UQ4G5.js.map +1 -0
  15. package/dist/{chunk-IOHGE4EW.js → chunk-AVSP6NDX.js} +8 -8
  16. package/dist/chunk-AVSP6NDX.js.map +1 -0
  17. package/dist/chunk-F2XMZOUP.js +81 -0
  18. package/dist/chunk-F2XMZOUP.js.map +1 -0
  19. package/dist/{chunk-HQFTP7Y5.js → chunk-FF57N3P7.js} +10 -8
  20. package/dist/chunk-FF57N3P7.js.map +1 -0
  21. package/dist/chunk-GIA4BMGI.js +18 -0
  22. package/dist/chunk-GIA4BMGI.js.map +1 -0
  23. package/dist/{chunk-DR6WEI3A.js → chunk-HCEHTJ5E.js} +3 -3
  24. package/dist/{chunk-DR6WEI3A.js.map → chunk-HCEHTJ5E.js.map} +1 -1
  25. package/dist/{chunk-IZW5XHKA.js → chunk-OWGF362U.js} +10 -8
  26. package/dist/chunk-OWGF362U.js.map +1 -0
  27. package/dist/chunk-P3NUUIL6.js +9 -0
  28. package/dist/chunk-P3NUUIL6.js.map +1 -0
  29. package/dist/{chunk-W3GY5ROH.js → chunk-R2IAK3J3.js} +3 -3
  30. package/dist/{chunk-W3GY5ROH.js.map → chunk-R2IAK3J3.js.map} +1 -1
  31. package/dist/chunk-R7FG4ZQ5.js +16 -0
  32. package/dist/chunk-R7FG4ZQ5.js.map +1 -0
  33. package/dist/{chunk-V73LHNRL.js → chunk-RS624TD5.js} +29 -10
  34. package/dist/chunk-RS624TD5.js.map +1 -0
  35. package/dist/{chunk-DBHVJ7Z3.js → chunk-SS3C24IJ.js} +3 -2
  36. package/dist/chunk-SS3C24IJ.js.map +1 -0
  37. package/dist/{chunk-K3NAFQ4S.js → chunk-TMPPBXX3.js} +3 -3
  38. package/dist/{chunk-K3NAFQ4S.js.map → chunk-TMPPBXX3.js.map} +1 -1
  39. package/dist/{chunk-NDL2JGQ7.js → chunk-UBLBVCQN.js} +5 -5
  40. package/dist/{chunk-NDL2JGQ7.js.map → chunk-UBLBVCQN.js.map} +1 -1
  41. package/dist/{chunk-2TCCSKL3.js → chunk-WD6T57ZJ.js} +5 -5
  42. package/dist/{chunk-2TCCSKL3.js.map → chunk-WD6T57ZJ.js.map} +1 -1
  43. package/dist/{chunk-SLGGZ3MU.js → chunk-WSKPESAX.js} +12 -10
  44. package/dist/chunk-WSKPESAX.js.map +1 -0
  45. package/dist/chunk-ZQV26NND.js +213 -0
  46. package/dist/chunk-ZQV26NND.js.map +1 -0
  47. package/dist/dashboard.d.ts +207 -0
  48. package/dist/dashboard.js +1210 -0
  49. package/dist/dashboard.js.map +1 -0
  50. package/dist/data-grid.js +11 -10
  51. package/dist/data-grid.js.map +1 -1
  52. package/dist/editor-mentions.js +2 -2
  53. package/dist/editor.js +3 -2
  54. package/dist/editor.js.map +1 -1
  55. package/dist/index.d.ts +94 -12
  56. package/dist/index.js +601 -316
  57. package/dist/index.js.map +1 -1
  58. package/dist/kanban.js +9 -9
  59. package/dist/resizable.d.ts +11 -2
  60. package/dist/resizable.js +97 -22
  61. package/dist/resizable.js.map +1 -1
  62. package/dist/roots.css +2 -2
  63. package/dist/tokens.css +6 -6
  64. package/dist/utils.d.ts +51 -1
  65. package/dist/utils.js +55 -4
  66. package/dist/utils.js.map +1 -1
  67. package/dist/virtualized.js +9 -8
  68. package/dist/virtualized.js.map +1 -1
  69. package/dist-static/tokens.css +6 -6
  70. package/package.json +6 -1
  71. package/dist/chunk-BHTAVJIG.js.map +0 -1
  72. package/dist/chunk-DBHVJ7Z3.js.map +0 -1
  73. package/dist/chunk-EZ3ZGFGA.js.map +0 -1
  74. package/dist/chunk-HQFTP7Y5.js.map +0 -1
  75. package/dist/chunk-I6JJ7KKP.js.map +0 -1
  76. package/dist/chunk-IOHGE4EW.js.map +0 -1
  77. package/dist/chunk-IZW5XHKA.js.map +0 -1
  78. package/dist/chunk-KSJTMSYA.js +0 -71
  79. package/dist/chunk-KSJTMSYA.js.map +0 -1
  80. package/dist/chunk-LJYSVZMI.js +0 -25
  81. package/dist/chunk-LJYSVZMI.js.map +0 -1
  82. package/dist/chunk-SLGGZ3MU.js.map +0 -1
  83. package/dist/chunk-TH272DIC.js.map +0 -1
  84. package/dist/chunk-V73LHNRL.js.map +0 -1
package/dist/charts.js CHANGED
@@ -1,16 +1,18 @@
1
1
  "use client";
2
- import { SegmentedControl, TITLE_TEXT, Skeleton } from './chunk-BHTAVJIG.js';
3
- import { useKeyboardScroll } from './chunk-KSJTMSYA.js';
4
- import { useFormatLocale, useHydrated } from './chunk-LJYSVZMI.js';
5
- import './chunk-IZW5XHKA.js';
2
+ import { SegmentedControl, CELL_FRAME, TITLE_TEXT, TITLE_FLOOR, CELL_ROOM_INNER, CELL_HIDE_CHART_ACTIONS, Skeleton } from './chunk-6XCWKLJZ.js';
3
+ import { useFormatLocale } from './chunk-R7FG4ZQ5.js';
4
+ import './chunk-OWGF362U.js';
6
5
  import { formatLocale } from './chunk-7QLXYRPD.js';
6
+ import './chunk-R2IAK3J3.js';
7
+ import { DashboardCellContext } from './chunk-P3NUUIL6.js';
8
+ import { useHydrated } from './chunk-GIA4BMGI.js';
7
9
  import { FormChangeCtx } from './chunk-72SDAX54.js';
8
- import { elementType } from './chunk-HQFTP7Y5.js';
10
+ import { elementType } from './chunk-FF57N3P7.js';
9
11
  import './chunk-7RKC5C7G.js';
10
- import './chunk-W3GY5ROH.js';
11
- import { mergeRefs } from './chunk-DR6WEI3A.js';
12
+ import { useKeyboardScroll } from './chunk-F2XMZOUP.js';
13
+ import { mergeRefs } from './chunk-HCEHTJ5E.js';
12
14
  import { warnOnce } from './chunk-53F7GVBQ.js';
13
- import { cn, FOCUS_INSET, GLASS_SURFACE } from './chunk-EZ3ZGFGA.js';
15
+ import { cn, FOCUS_INSET, GLASS_SURFACE } from './chunk-2724SJO2.js';
14
16
  import { createContext, forwardRef, useContext, useRef, useState, useId, useMemo, useLayoutEffect, useEffect, useCallback, useSyncExternalStore, Children, isValidElement } from 'react';
15
17
  import { ResponsiveContainer, BarChart as BarChart$1, CartesianGrid, XAxis, YAxis, Tooltip, Bar, LineChart as LineChart$1, Line, AreaChart as AreaChart$1, Area, PieChart as PieChart$1, Pie, Cell, ComposedChart, ScatterChart as ScatterChart$1, ZAxis, Scatter, Symbols, RadarChart as RadarChart$1, PolarGrid, PolarAngleAxis, PolarRadiusAxis, Radar, RadialBarChart as RadialBarChart$1, RadialBar, FunnelChart as FunnelChart$1, Funnel, LabelList, Treemap, Sankey, Text, Legend, ReferenceArea, ReferenceLine, getNiceTickValues, Rectangle, usePlotArea, ZIndexLayer, DefaultZIndexes } from 'recharts';
16
18
  import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
@@ -480,20 +482,26 @@ function percent(part, whole) {
480
482
  function referenceNote(r, format) {
481
483
  return isNumber(r.to) ? `${r.label}: ${format(r.value)} to ${format(r.to)}` : `${r.label}: ${format(r.value)}`;
482
484
  }
483
- var SUMMED = 3;
484
- function seriesSentence(label, points, over, f) {
485
+ var NAMED = 3;
486
+ var namesOrCount = (names, unit) => names.length <= NAMED ? listOf(names) : `${names.length} ${unit}`;
487
+ function leadSaid(points, over, f) {
485
488
  if (!points.length) return null;
486
- if (points.length === 1) return `${label}: ${f(points[0].value)} (${points[0].cat}).`;
489
+ if (points.length === 1) return `${f(points[0].value)} (${points[0].cat})`;
490
+ const same = (a, b) => f(a) === f(b);
487
491
  const high = points.reduce((a, b) => b.value > a.value ? b : a);
488
492
  const low = points.reduce((a, b) => b.value < a.value ? b : a);
489
- if (high.value === low.value) return over === "scale" ? `${label}: ${f(high.value)} throughout.` : `${label}: ${f(high.value)} for all ${points.length}.`;
490
- const extremes = `highest ${f(high.value)} (${high.cat}), lowest ${f(low.value)} (${low.cat})`;
491
- if (over === "names") return `${label}: ${extremes}.`;
493
+ if (same(high.value, low.value)) return over === "scale" ? `${f(high.value)} throughout` : `${f(high.value)} for each`;
494
+ const at = (v) => namesOrCount(points.filter((p) => same(p.value, v)).map((p) => p.cat), "categories");
495
+ if (over === "names") return `highest ${f(high.value)} (${at(high.value)}), lowest ${f(low.value)} (${at(low.value)})`;
492
496
  const first = points[0], end = points[points.length - 1];
493
497
  const steps = points.slice(1).map((p, i) => p.value - points[i].value);
494
498
  const up = steps.every((d) => d >= 0), down = steps.every((d) => d <= 0);
495
499
  const course = `${up ? "up from" : down ? "down from" : "from"} ${f(first.value)} (${first.cat}) to ${f(end.value)} (${end.cat})`;
496
- return up || down ? `${label}: ${course}.` : `${label}: ${course}, ${extremes}.`;
500
+ const top = Math.max(first.value, end.value), bottom = Math.min(first.value, end.value);
501
+ const above = same(high.value, top) ? 0 : high.value - top;
502
+ const below = same(low.value, bottom) ? 0 : bottom - low.value;
503
+ if (up || down || above <= 0 && below <= 0) return course;
504
+ return above >= below ? `${course}, highest ${f(high.value)} (${at(high.value)})` : `${course}, lowest ${f(low.value)} (${at(low.value)})`;
497
505
  }
498
506
  function cartesianAccess(o) {
499
507
  const { data, categoryKey, series, format } = o;
@@ -514,15 +522,26 @@ function cartesianAccess(o) {
514
522
  ...forecastNote ? [forecastNote] : []
515
523
  ];
516
524
  const names = series.map((s) => s.label);
525
+ const heading = o.valueHeading?.trim() ?? "";
526
+ const measure2 = series.length <= NAMED ? listOf(names) : (heading.match(/\p{L}/gu)?.length ?? 0) >= 3 ? heading : `${series.length} series`;
517
527
  const span = o.over === "scale" && cats.length > 1 ? ` from ${cats[0]} to ${cats[last]}` : cats.length === 1 ? ` for ${cats[0]}` : ` across ${cats.length} categories`;
518
- const sentences = [`${o.kind}: ${listOf(names)}${span}.`];
519
528
  const measured = forecastFrom > 0 ? forecastFrom : data.length;
520
- for (const s of series.slice(0, SUMMED)) {
521
- const points = data.slice(0, measured).map((row, i) => ({ cat: cats[i], value: numberOf(row[s.dataKey]) })).filter((p) => p.value !== null);
522
- const said = seriesSentence(s.label, points, o.over, (v) => format(v, s.dataKey));
523
- if (said) sentences.push(said);
524
- }
525
- if (series.length > SUMMED) sentences.push(`And ${series.length - SUMMED} more series.`);
529
+ const rowsMeasured = data.slice(0, measured);
530
+ const stack = o.totals === true ? series : o.totals ? series.filter((s) => o.totals.series.includes(s.dataKey)) : [];
531
+ const oneSign = rowsMeasured.every((row) => {
532
+ const values = stack.map((s) => numberOf(row[s.dataKey])).filter((v) => v !== null && v !== 0);
533
+ return values.every((v) => v > 0) || values.every((v) => v < 0);
534
+ });
535
+ const totals = stack.length > 1 && oneSign;
536
+ const lead = series.find((s) => rowsMeasured.some((row) => numberOf(row[s.dataKey]) !== null)) ?? series[0];
537
+ const points = !lead ? [] : rowsMeasured.map((row, i) => {
538
+ const values = (totals ? stack : [lead]).map((s) => numberOf(row[s.dataKey]));
539
+ return { cat: cats[i], value: values.every((v) => v === null) ? null : values.reduce((sum, v) => sum + (v ?? 0), 0) };
540
+ }).filter((p) => p.value !== null);
541
+ const said = lead ? leadSaid(points, o.over, (v) => format(v, totals ? void 0 : lead.dataKey)) : null;
542
+ const totalName = o.totals && o.totals !== true ? o.totals.name : "the total";
543
+ const leadName = series.length > 1 ? `${totals ? totalName : lead.label} ` : "";
544
+ const sentences = [`${o.kind} of ${measure2}${span}${said ? `: ${leadName}${said}` : ""}.`];
526
545
  for (const note of notes) sentences.push(`${note}.`);
527
546
  return {
528
547
  table: { columns: [o.categoryHeading || "Category", ...names], numeric: [false, ...series.map(() => true)], rows, notes },
@@ -563,7 +582,10 @@ function partsAccess(o) {
563
582
  const groups = new Set(items.map((p) => p.group)).size;
564
583
  if (grouped) description += ` in ${groups} ${groups === 1 ? "group" : "groups"}`;
565
584
  if (largest && smallest && items.length > 1) {
566
- description += o.kind === "radial" ? `: ${largest.name} the highest (${f(largest.value)}), ${smallest.name} the lowest (${f(smallest.value)}).` : `: ${largest.name} the largest (${f(largest.value)}, ${percent(largest.value, total)}), ${smallest.name} the smallest (${f(smallest.value)}, ${percent(smallest.value, total)}).`;
585
+ const alike = (v) => namesOrCount(items.filter((p) => f(p.value) === f(v)).map((p) => p.name), unit);
586
+ const ties = items.filter((p) => f(p.value) === f(largest.value)).length;
587
+ const share = (v) => o.kind === "radial" ? "" : ` (${percent(v, total)})`;
588
+ description += f(largest.value) === f(smallest.value) ? `: each ${f(largest.value)}${share(largest.value)}.` : o.kind === "radial" ? `: ${alike(largest.value)} the highest (${f(largest.value)}), ${alike(smallest.value)} the lowest (${f(smallest.value)}).` : ties > 1 ? `: ${alike(largest.value)} the largest, each ${f(largest.value)}${share(largest.value)}.` : `: ${largest.name} the largest (${f(largest.value)}, ${percent(largest.value, total)}).`;
567
589
  } else {
568
590
  description += ".";
569
591
  }
@@ -575,18 +597,14 @@ function partsAccess(o) {
575
597
  function pointsAccess(o) {
576
598
  const withZ = !!o.zHeading && o.series.some((s) => s.points.some((p) => numberOf(p.z) !== null));
577
599
  const rows = [];
578
- const xs = [];
579
- const ys = [];
580
600
  for (const s of o.series) {
581
601
  for (const p of s.points) {
582
602
  const x = numberOf(p.x), y = numberOf(p.y), z = numberOf(p.z);
583
603
  if (x === null || y === null) continue;
584
- xs.push(x);
585
- ys.push(y);
586
604
  rows.push([s.name, o.formatX(x), o.formatY(y), ...withZ ? [z !== null ? String(z) : "\u2013"] : []]);
587
605
  }
588
606
  }
589
- const range = (vs, fmt) => vs.length ? `from ${fmt(Math.min(...vs))} to ${fmt(Math.max(...vs))}` : "";
607
+ const inSeries = o.series.length > 1 ? ` in ${o.series.length} series` : "";
590
608
  return {
591
609
  table: {
592
610
  columns: ["Series", o.xHeading, o.yHeading, ...withZ ? [o.zHeading] : []],
@@ -594,7 +612,7 @@ function pointsAccess(o) {
594
612
  rows,
595
613
  notes: []
596
614
  },
597
- description: `Scatter chart of ${rows.length} ${rows.length === 1 ? "point" : "points"} in ${o.series.length} ${o.series.length === 1 ? "series" : "series"}${xs.length ? `: ${o.xHeading} ${range(xs, o.formatX)}, ${o.yHeading} ${range(ys, o.formatY)}` : ""}.`
615
+ description: `Scatter chart of ${o.yHeading} against ${o.xHeading}: ${rows.length} ${rows.length === 1 ? "point" : "points"}${inSeries}.`
598
616
  };
599
617
  }
600
618
  function flowAccess(o) {
@@ -653,15 +671,24 @@ function PlotNames({ children }) {
653
671
  const value = useMemo(() => ({ place, moves }), [place, moves]);
654
672
  return /* @__PURE__ */ jsx(PlotNamesContext.Provider, { value, children });
655
673
  }
674
+ var SEGMENT_GAP = 2;
656
675
  function markOf(index, marks) {
657
676
  return (index + Math.floor(index / CHART_COLOR_COUNT)) % marks;
658
677
  }
678
+ function repeatMark(index, marks) {
679
+ const round = Math.floor(index / CHART_COLOR_COUNT);
680
+ return round === 0 ? 0 : 1 + (round - 1) % (marks - 1);
681
+ }
682
+ function markFor(index, count, marks, patterns2) {
683
+ if (count < 2) return 0;
684
+ return patterns2 ? markOf(index, marks) : repeatMark(index, marks);
685
+ }
659
686
  var DASHES = [void 0, "6 3", "2 3", "8 3 2 3", "12 3 3 3", "1 4"];
660
- function seriesDash(index, count) {
661
- return count >= 2 ? DASHES[markOf(index, DASHES.length)] : void 0;
687
+ function seriesDash(index, count, patterns2 = false) {
688
+ return DASHES[markFor(index, count, DASHES.length, patterns2)];
662
689
  }
663
- function lineDashes(lines) {
664
- const marks = lines.map((line, i) => lines.length >= 2 ? markOf(i, DASHES.length) : line.dashed ? 1 : 0);
690
+ function lineDashes(lines, patterns2 = false) {
691
+ const marks = lines.map((line, i) => lines.length >= 2 ? markFor(i, lines.length, DASHES.length, patterns2) : line.dashed ? 1 : 0);
665
692
  const colour = (i) => i % CHART_COLOR_COUNT;
666
693
  const inColour = (i, k, ...but) => marks.some((m, j) => m === k && colour(j) === colour(i) && j !== i && !but.includes(j));
667
694
  lines.forEach((line, i) => {
@@ -686,12 +713,12 @@ function seriesSymbol(index, count) {
686
713
  return count >= 2 ? SYMBOLS[index % SYMBOLS.length] : "circle";
687
714
  }
688
715
  var PATTERNS = 5;
689
- function seriesPatternKind(index, count) {
690
- const mark = markOf(index, PATTERNS + 1);
691
- return count < 2 || mark === 0 ? void 0 : mark - 1;
716
+ function seriesPatternKind(index, count, patterns2 = false) {
717
+ const mark = markFor(index, count, PATTERNS + 1, patterns2);
718
+ return mark === 0 ? void 0 : mark - 1;
692
719
  }
693
- function seriesPattern(chartId, index, count) {
694
- if (seriesPatternKind(index, count) === void 0) return void 0;
720
+ function seriesPattern(chartId, index, count, patterns2 = false) {
721
+ if (seriesPatternKind(index, count, patterns2) === void 0) return void 0;
695
722
  return `${chartId.replace(/[^a-zA-Z0-9_-]/g, "")}-series-${index}`;
696
723
  }
697
724
  var aheadPattern = (id) => `${id}-ahead`;
@@ -786,13 +813,13 @@ function Pattern({ id, kind, fill, on }) {
786
813
  kind === 4 && /* @__PURE__ */ jsx("path", { d: "M3,0 v6", ...mark })
787
814
  ] });
788
815
  }
789
- function SeriesPatterns({ chartId, colors, surface, ahead = false }) {
816
+ function SeriesPatterns({ chartId, colors, surface, ahead = false, patterns: patterns2 = false }) {
790
817
  const ink = useResolvedToken("--ds-text-primary");
791
818
  const canvas = useResolvedToken("--ds-bg-canvas");
792
- if (colors.length < 2) return null;
819
+ if (!colors.some((_, i) => seriesPattern(chartId, i, colors.length, patterns2))) return null;
793
820
  return /* @__PURE__ */ jsx("defs", { children: colors.map((color, i) => {
794
- const id = seriesPattern(chartId, i, colors.length);
795
- const kind = seriesPatternKind(i, colors.length);
821
+ const id = seriesPattern(chartId, i, colors.length, patterns2);
822
+ const kind = seriesPatternKind(i, colors.length, patterns2);
796
823
  if (!id || kind === void 0) return null;
797
824
  const faint = ahead ? aheadFill(color, surface, canvas) : null;
798
825
  return [
@@ -830,7 +857,9 @@ function PlotName({ x = 0, y = 0, viewBox, value, id, order, place, ink }) {
830
857
  const line = { across: viewBox?.height === 0 && (viewBox?.width ?? 0) > 0, up: viewBox?.width === 0 && (viewBox?.height ?? 0) > 0 };
831
858
  const top = place !== "insideBottomRight";
832
859
  const flip = !!size && !!plot && (line.across && top && y + size.height > plot.y + plot.height + 0.5 || line.up && x - size.width < plot.x - 0.5);
833
- const placed = flip && line.across ? { x, y: (viewBox?.y ?? 0) - OFFSET, top: false, start: false } : flip && line.up ? { x: (viewBox?.x ?? 0) + OFFSET, y, top: false, start: true } : { x, y, top, start: place === "insideTopLeft" };
860
+ const band = (viewBox?.width ?? 0) > 0 && (viewBox?.height ?? 0) > 0;
861
+ const beside = band && !!size && (place === "insideTopRight" ? size.width + 2 * OFFSET > (viewBox?.width ?? 0) : place === "insideBottomRight" ? size.height + 2 * OFFSET > (viewBox?.height ?? 0) : false);
862
+ const placed = flip && line.across ? { x, y: (viewBox?.y ?? 0) - OFFSET, top: false, start: false } : flip && line.up ? { x: (viewBox?.x ?? 0) + OFFSET, y, top: false, start: true } : beside && place === "insideTopRight" ? { x: (viewBox?.x ?? 0) - OFFSET, y, top, start: false } : beside ? { x, y: (viewBox?.y ?? 0) - OFFSET, top: false, start: false } : { x, y, top, start: place === "insideTopLeft" };
834
863
  const inside = (from, length, edge, span) => from < edge ? edge - from : from + length > edge + span ? Math.max(edge - from, edge + span - (from + length)) : 0;
835
864
  const at = size && plot ? {
836
865
  ...placed,
@@ -952,35 +981,45 @@ function forecastElements(categories, from, label, look) {
952
981
  }
953
982
  return elements;
954
983
  }
955
- function ChartTable({ table, name, labelledBy }) {
984
+ function ChartTable({ table, name, labelledBy, cell = false }) {
956
985
  const [frame, setFrame] = useState(null);
957
986
  useKeyboardScroll(frame, name, true, false, "both");
958
- return /* @__PURE__ */ jsxs("div", { "data-chart-table": "", className: "flex min-h-0 flex-1 flex-col gap-ds-2", children: [
959
- /* @__PURE__ */ jsx(
960
- "div",
961
- {
962
- ref: setFrame,
963
- className: cn(
964
- "min-h-0 max-h-[var(--ds-chart-height-lg)] overflow-auto rounded-[var(--ds-radius-md)]",
965
- "border-[length:var(--ds-border-width)] border-[var(--ds-border-subtle)]",
966
- FOCUS_INSET
987
+ return /* @__PURE__ */ jsxs(
988
+ "div",
989
+ {
990
+ "data-chart-table": "",
991
+ className: cell ? "flex flex-[1_1_0px] flex-col gap-ds-2" : "flex min-h-0 flex-1 flex-col gap-ds-2",
992
+ style: cell ? { minHeight: "var(--ds-chart-height-sm)" } : void 0,
993
+ children: [
994
+ /* @__PURE__ */ jsx(
995
+ "div",
996
+ {
997
+ ref: setFrame,
998
+ className: cn(
999
+ "min-h-0",
1000
+ !cell && "max-h-[var(--ds-chart-height-lg)]",
1001
+ "overflow-auto rounded-[var(--ds-radius-md)]",
1002
+ "border-[length:var(--ds-border-width)] border-[var(--ds-border-subtle)]",
1003
+ FOCUS_INSET
1004
+ ),
1005
+ children: /* @__PURE__ */ jsxs("table", { className: "w-full border-collapse text-sm", "aria-labelledby": labelledBy, "aria-label": labelledBy ? void 0 : name, children: [
1006
+ /* @__PURE__ */ jsx("thead", { className: "bg-[var(--ds-bg-muted)]", children: /* @__PURE__ */ jsx("tr", { children: table.columns.map((column, i) => /* @__PURE__ */ jsx(
1007
+ "th",
1008
+ {
1009
+ scope: "col",
1010
+ className: cn("px-ds-3 py-ds-2 text-xs font-semibold text-[var(--ds-text-secondary)] whitespace-nowrap", table.numeric[i] ? "text-right" : "text-left"),
1011
+ children: column
1012
+ },
1013
+ i
1014
+ )) }) }),
1015
+ /* @__PURE__ */ jsx("tbody", { children: table.rows.map((row, r) => /* @__PURE__ */ jsx("tr", { className: "border-t-[length:var(--ds-divider-width)] border-[var(--ds-border-subtle)]", children: row.map((cell2, i) => i === (table.rowHeader ?? 0) ? /* @__PURE__ */ jsx("th", { scope: "row", className: "px-ds-3 py-ds-2 text-left font-normal text-[var(--ds-text-primary)]", children: cell2 }, i) : /* @__PURE__ */ jsx("td", { className: cn("px-ds-3 py-ds-2 text-[var(--ds-text-primary)]", table.numeric[i] && "text-right tabular-nums whitespace-nowrap"), children: cell2 }, i)) }, r)) })
1016
+ ] })
1017
+ }
967
1018
  ),
968
- children: /* @__PURE__ */ jsxs("table", { className: "w-full border-collapse text-sm", "aria-labelledby": labelledBy, "aria-label": labelledBy ? void 0 : name, children: [
969
- /* @__PURE__ */ jsx("thead", { className: "bg-[var(--ds-bg-muted)]", children: /* @__PURE__ */ jsx("tr", { children: table.columns.map((column, i) => /* @__PURE__ */ jsx(
970
- "th",
971
- {
972
- scope: "col",
973
- className: cn("px-ds-3 py-ds-2 text-xs font-semibold text-[var(--ds-text-secondary)] whitespace-nowrap", table.numeric[i] ? "text-right" : "text-left"),
974
- children: column
975
- },
976
- i
977
- )) }) }),
978
- /* @__PURE__ */ jsx("tbody", { children: table.rows.map((row, r) => /* @__PURE__ */ jsx("tr", { className: "border-t-[length:var(--ds-divider-width)] border-[var(--ds-border-subtle)]", children: row.map((cell, i) => i === (table.rowHeader ?? 0) ? /* @__PURE__ */ jsx("th", { scope: "row", className: "px-ds-3 py-ds-2 text-left font-normal text-[var(--ds-text-primary)]", children: cell }, i) : /* @__PURE__ */ jsx("td", { className: cn("px-ds-3 py-ds-2 text-[var(--ds-text-primary)]", table.numeric[i] && "text-right tabular-nums whitespace-nowrap"), children: cell }, i)) }, r)) })
979
- ] })
980
- }
981
- ),
982
- table.notes.length > 0 && /* @__PURE__ */ jsx("ul", { "data-chart-notes": "", className: "text-xs text-[var(--ds-text-secondary)]", children: table.notes.map((note, i) => /* @__PURE__ */ jsx("li", { children: note }, i)) })
983
- ] });
1019
+ table.notes.length > 0 && /* @__PURE__ */ jsx("ul", { "data-chart-notes": "", className: "text-xs text-[var(--ds-text-secondary)]", children: table.notes.map((note, i) => /* @__PURE__ */ jsx("li", { children: note }, i)) })
1020
+ ]
1021
+ }
1022
+ );
984
1023
  }
985
1024
  var CHART_HEIGHTS = {
986
1025
  sm: "var(--ds-chart-height-sm)",
@@ -1006,6 +1045,9 @@ function plotBoxStyle(size, fixed) {
1006
1045
  }
1007
1046
  return { height: fixed ?? `clamp(${SM}, 50cqi, ${LG})`, maxHeight: `max(${fixed ?? LG}, 100cqi)`, flex: "1 0 auto" };
1008
1047
  }
1048
+ function cellPlotStyle(size) {
1049
+ return size.model === "rows" ? plotBoxStyle(size, void 0) : { flex: "1 1 0px", minHeight: SM };
1050
+ }
1009
1051
  var CHART_MARK = /* @__PURE__ */ Symbol.for("gridsmith.Chart");
1010
1052
  function markChart(component) {
1011
1053
  Object.assign(component, { [CHART_MARK]: true });
@@ -1038,6 +1080,8 @@ function remapRowKeys(e) {
1038
1080
  const event = new View.KeyboardEvent("keydown", { key: next ? "ArrowLeft" : "ArrowRight", bubbles: true, cancelable: true });
1039
1081
  REMAPPED.add(event);
1040
1082
  target.dispatchEvent(event);
1083
+ const plot = e.currentTarget;
1084
+ View.requestAnimationFrame(() => plot.querySelector(".recharts-tooltip-cursor")?.scrollIntoView?.({ block: "nearest", inline: "nearest" }));
1041
1085
  }
1042
1086
  var ChartWrapper = forwardRef(function ChartWrapper2({
1043
1087
  height = "auto",
@@ -1060,7 +1104,8 @@ var ChartWrapper = forwardRef(function ChartWrapper2({
1060
1104
  const rootRef = useRef(null);
1061
1105
  const [plotEl, setPlotEl] = useState(null);
1062
1106
  const [view, setView] = useState("chart");
1063
- const descriptionId = useId();
1107
+ const subtitleId = useId();
1108
+ const summaryId = useId();
1064
1109
  const [legend, setLegend] = useState(null);
1065
1110
  const [live, setLive] = useState(null);
1066
1111
  const frame = useMemo(() => ({ legend, live, formatValue, marks }), [legend, live, formatValue, marks]);
@@ -1076,11 +1121,14 @@ var ChartWrapper = forwardRef(function ChartWrapper2({
1076
1121
  observer.observe(plot);
1077
1122
  return () => observer.disconnect();
1078
1123
  }, [plotEl]);
1079
- const fill = container?.fillArea === true;
1124
+ const cell = container?.cell === true;
1125
+ const fill = !cell && container?.fillArea === true;
1080
1126
  const fixed = container?.height ?? fixedChartHeight(height);
1081
- const plotStyle = fill ? { flex: "1 1 0%", minHeight: 0 } : plotBoxStyle(size, fixed);
1082
- const sentence = description?.trim() ? description : access?.description;
1083
- const describedBy = sentence ? { "aria-describedby": descriptionId } : {};
1127
+ const plotStyle = cell ? cellPlotStyle(size) : fill ? { flex: "1 1 0%", minHeight: 0 } : plotBoxStyle(size, fixed);
1128
+ const subtitle = description?.trim() || void 0;
1129
+ const summary = access?.description;
1130
+ const describers = [subtitle && subtitleId, summary && summaryId].filter(Boolean).join(" ");
1131
+ const describedBy = describers ? { "aria-describedby": describers } : {};
1084
1132
  const named = ariaLabel ? { role: "img", "aria-label": ariaLabel, ...describedBy } : container?.titleId ? { role: "img", "aria-labelledby": container.titleId, ...describedBy } : {};
1085
1133
  useEffect(() => {
1086
1134
  const root = rootRef.current;
@@ -1101,6 +1149,26 @@ var ChartWrapper = forwardRef(function ChartWrapper2({
1101
1149
  }, [categoryAxis, plotEl]);
1102
1150
  const register = container?.register;
1103
1151
  useLayoutEffect(() => register?.(), [register]);
1152
+ const drawing = container?.drawing;
1153
+ useLayoutEffect(() => {
1154
+ if (!drawing || !plotEl || typeof MutationObserver === "undefined") return;
1155
+ let counted;
1156
+ const read = () => {
1157
+ const surface = !!plotEl.querySelector('svg[tabindex="0"]');
1158
+ if (surface && !counted) counted = drawing();
1159
+ else if (!surface && counted) {
1160
+ counted();
1161
+ counted = void 0;
1162
+ }
1163
+ };
1164
+ read();
1165
+ const observer = new MutationObserver(read);
1166
+ observer.observe(plotEl, { childList: true, subtree: true, attributes: true, attributeFilter: ["tabindex"] });
1167
+ return () => {
1168
+ observer.disconnect();
1169
+ counted?.();
1170
+ };
1171
+ }, [drawing, plotEl]);
1104
1172
  const switcher = access ? /* @__PURE__ */ jsx(FormChangeCtx, { value: null, children: /* @__PURE__ */ jsx(
1105
1173
  SegmentedControl,
1106
1174
  {
@@ -1112,8 +1180,10 @@ var ChartWrapper = forwardRef(function ChartWrapper2({
1112
1180
  }
1113
1181
  ) }) : null;
1114
1182
  const actions = container?.actions && container.charts === 1 ? container.actions : null;
1115
- const sentenceShown = !fill || view === "table";
1116
- const sentenceLine = sentence ? /* @__PURE__ */ jsx("p", { id: descriptionId, "data-chart-description": "", className: sentenceShown ? "min-w-0 text-sm text-[var(--ds-text-secondary)]" : "sr-only", children: sentence }) : null;
1183
+ const sentenceShown = view === "table";
1184
+ const subtitleLine = subtitle ? /* @__PURE__ */ jsx("p", { id: subtitleId, "data-chart-subtitle": "", className: "min-w-0 text-sm text-[var(--ds-text-secondary)]", children: subtitle }) : null;
1185
+ const summaryLine = summary ? /* @__PURE__ */ jsx("p", { id: summaryId, "data-chart-description": "", className: sentenceShown ? "min-w-0 text-sm text-[var(--ds-text-secondary)]" : "sr-only", children: summary }) : null;
1186
+ const headText = subtitleLine || sentenceShown && summaryLine;
1117
1187
  return /* @__PURE__ */ jsxs(
1118
1188
  "div",
1119
1189
  {
@@ -1121,14 +1191,17 @@ var ChartWrapper = forwardRef(function ChartWrapper2({
1121
1191
  "data-gs-chart": chart,
1122
1192
  "data-category-kind": categoryKind2,
1123
1193
  "data-categories": categories,
1124
- className: cn("relative flex w-full flex-col", fill && "h-full", className),
1194
+ className: cn("relative flex w-full flex-col", fill && "h-full", cell && "min-h-full", className),
1125
1195
  style: { containerType: "inline-size", minInlineSize: "min(100%, 16rem)", ...fill ? {} : { flex: "1 0 auto" } },
1126
1196
  children: [
1127
- (sentenceLine && sentenceShown || switcher && !actions) && /* @__PURE__ */ jsxs("div", { "data-chart-head": "", className: "mb-ds-3 flex items-start justify-between gap-ds-3", children: [
1128
- sentenceShown && sentenceLine,
1197
+ (headText || switcher && !actions) && /* @__PURE__ */ jsxs("div", { "data-chart-head": "", className: "mb-ds-3 flex items-start justify-between gap-ds-3", children: [
1198
+ headText && /* @__PURE__ */ jsxs("div", { className: "flex min-w-0 flex-col gap-ds-1", children: [
1199
+ subtitleLine,
1200
+ sentenceShown && summaryLine
1201
+ ] }),
1129
1202
  !actions && switcher && /* @__PURE__ */ jsx("div", { className: "ml-auto shrink-0", children: switcher })
1130
1203
  ] }),
1131
- !sentenceShown && sentenceLine,
1204
+ !sentenceShown && summaryLine,
1132
1205
  actions && switcher && createPortal(switcher, actions),
1133
1206
  view === "chart" || !access ? /* @__PURE__ */ jsxs(
1134
1207
  "div",
@@ -1144,7 +1217,7 @@ var ChartWrapper = forwardRef(function ChartWrapper2({
1144
1217
  /* @__PURE__ */ jsx("div", { className: "absolute inset-0", style: drawn2 ? { minWidth: drawn2.width, minHeight: drawn2.height } : void 0, children: /* @__PURE__ */ jsx(ChartFrameContext.Provider, { value: frame, children: /* @__PURE__ */ jsx(PlotNames, { children }) }) })
1145
1218
  ]
1146
1219
  }
1147
- ) : /* @__PURE__ */ jsx(ChartTable, { table: access.table, name: `${ariaLabel || container?.title || "The chart"}: values`, labelledBy: ariaLabel ? void 0 : container?.titleId }),
1220
+ ) : /* @__PURE__ */ jsx(ChartTable, { table: access.table, name: `${ariaLabel || container?.title || "The chart"}: values`, labelledBy: ariaLabel ? void 0 : container?.titleId, cell }),
1148
1221
  /* @__PURE__ */ jsx("div", { ref: setLegend, "data-chart-legend": "" }),
1149
1222
  /* @__PURE__ */ jsx("div", { ref: setLive, role: "status", "aria-live": "polite", className: "sr-only" }),
1150
1223
  /* @__PURE__ */ jsx(
@@ -1430,21 +1503,36 @@ function anyStack(bars, stacked) {
1430
1503
  function barGroups(bars, stacked) {
1431
1504
  return Math.max(1, new Set(bars.map((bar, i) => barStackOf(bar, stacked) ?? `\0${i}`)).size);
1432
1505
  }
1506
+ function insetEnd(box, sideways, gap) {
1507
+ const size = Number(sideways ? box.width : box.height) || 0;
1508
+ const by = Math.sign(size) * Math.min(gap, Math.max(0, Math.abs(size) - 1));
1509
+ return sideways ? { width: size - by } : { y: (Number(box.y) || 0) + by, height: size - by };
1510
+ }
1511
+ function insetStart(box, sideways, gap) {
1512
+ const size = Number(sideways ? box.width : box.height) || 0;
1513
+ const by = Math.sign(size) * Math.min(gap, Math.max(0, Math.abs(size) - 1));
1514
+ return sideways ? { x: (Number(box.x) || 0) + by, width: size - by } : { height: size - by };
1515
+ }
1516
+ var edgeWidth = (stroke, width) => typeof stroke === "string" && stroke !== "" && stroke !== "none" ? Number(width) || 1 : 0;
1433
1517
  function barShape(bars, index, stacked, radius, horizontal = false, forecast) {
1434
1518
  const round = horizontal ? [0, radius, radius, 0] : [radius, radius, 0, 0];
1435
1519
  const square = [0, 0, 0, 0];
1436
1520
  const stack = barStackOf(bars[index], stacked);
1437
1521
  const above = stack == null ? [] : bars.filter((b, j) => j > index && barStackOf(b, stacked) === stack);
1522
+ const below = stack == null ? [] : bars.filter((b, j) => j < index && barStackOf(b, stacked) === stack);
1438
1523
  const Shape = (props) => {
1439
1524
  const p = props;
1440
1525
  const row = p.payload ?? {};
1441
- const down = Number(row[bars[index].dataKey]) < 0;
1442
- const onTop = above.every((b) => {
1443
- const value = Number(row[b.dataKey]);
1444
- return !(down ? value < 0 : value > 0);
1445
- });
1446
- const ahead = forecast && forecast.from >= 0 && (p.index ?? -1) >= forecast.from ? { ...forecast.fill ? { fill: forecast.fill } : { fillOpacity: AHEAD_STRENGTH }, stroke: forecast.edge, strokeWidth: 1.5, strokeDasharray: "3 2" } : {};
1447
- return /* @__PURE__ */ jsx(Rectangle, { ...withoutRowFields(props), ...ahead, radius: onTop ? round : square });
1526
+ const valueOf = (b) => Number(row[b.dataKey]);
1527
+ const down = valueOf(bars[index]) < 0;
1528
+ const onTop = above.every((b) => !(down ? valueOf(b) < 0 : valueOf(b) > 0));
1529
+ const meetsZero = down && below.every((b) => !(valueOf(b) < 0)) && [...below, ...above].some((b) => valueOf(b) > 0);
1530
+ const at = p.originalDataIndex ?? p.index ?? -1;
1531
+ const ahead = forecast && forecast.from >= 0 && at >= forecast.from ? { ...forecast.fill ? { fill: forecast.fill } : { fillOpacity: AHEAD_STRENGTH }, stroke: forecast.edge, strokeWidth: 1.5, strokeDasharray: "3 2" } : void 0;
1532
+ const gap = SEGMENT_GAP + (ahead ? ahead.strokeWidth : edgeWidth(p.stroke, p.strokeWidth));
1533
+ const far = onTop ? { ...p } : { ...p, ...insetEnd(p, horizontal, gap) };
1534
+ const inset = { ...onTop ? {} : insetEnd(p, horizontal, gap), ...meetsZero ? insetStart(far, horizontal, gap) : {} };
1535
+ return /* @__PURE__ */ jsx(Rectangle, { ...withoutRowFields(props), ...ahead, ...inset, radius: onTop ? round : square });
1448
1536
  };
1449
1537
  return Shape;
1450
1538
  }
@@ -1474,7 +1562,8 @@ var BarChart = markChart(forwardRef(function BarChart2({
1474
1562
  description,
1475
1563
  references,
1476
1564
  forecastFrom,
1477
- forecastLabel = "Forecast"
1565
+ forecastLabel = "Forecast",
1566
+ patterns: patterns2 = false
1478
1567
  }, ref) {
1479
1568
  const wrapperRef = useRef(null);
1480
1569
  const chartId = useId();
@@ -1524,14 +1613,14 @@ var BarChart = markChart(forwardRef(function BarChart2({
1524
1613
  const canvas = useResolvedToken("--ds-bg-canvas");
1525
1614
  const ink = useResolvedToken("--ds-text-secondary");
1526
1615
  const fills = bars.map((bar, i) => bar.soft ? softColors[i] : solidColors[i]);
1527
- const patterns2 = bars.map((_, i) => seriesPattern(chartId, i, bars.length));
1616
+ const fillPatterns = bars.map((_, i) => seriesPattern(chartId, i, bars.length, patterns2));
1528
1617
  const aheadBarFill = (fill, pattern) => {
1529
1618
  const faint = aheadFill(fill, surface, canvas);
1530
1619
  return faint && pattern ? `url(#${aheadPattern(pattern)})` : faint;
1531
1620
  };
1532
1621
  const marks = useMemo(
1533
- () => Object.fromEntries(bars.map((bar, i) => [bar.dataKey, { kind: "fill", color: bar.soft ? softColors[i] : solidColors[i], edge: solidColors[i], pattern: seriesPattern(chartId, i, bars.length) }])),
1534
- [bars, softColors, solidColors, chartId]
1622
+ () => Object.fromEntries(bars.map((bar, i) => [bar.dataKey, { kind: "fill", color: bar.soft ? softColors[i] : solidColors[i], edge: solidColors[i], pattern: seriesPattern(chartId, i, bars.length, patterns2) }])),
1623
+ [bars, softColors, solidColors, chartId, patterns2]
1535
1624
  );
1536
1625
  const forecastAt = forecastIndex(data ?? [], xAxisKey, forecastFrom);
1537
1626
  const access = useMemo(() => cartesianAccess({
@@ -1539,12 +1628,14 @@ var BarChart = markChart(forwardRef(function BarChart2({
1539
1628
  data: data ?? [],
1540
1629
  categoryKey: xAxisKey,
1541
1630
  categoryHeading: categoryTitle,
1631
+ valueHeading: valueTitle,
1542
1632
  series: bars.map((b) => ({ dataKey: b.dataKey, label: b.label ?? b.dataKey })),
1543
1633
  format: fullFormat,
1544
1634
  over: names ? "names" : "scale",
1635
+ totals: anyStack(bars, stacked) && barGroups(bars, stacked) === 1,
1545
1636
  references,
1546
1637
  forecast: forecastAt >= 0 ? { from: forecastAt, label: forecastLabel } : void 0
1547
- }), [data, xAxisKey, categoryTitle, bars, fullFormat, names, references, forecastAt, forecastLabel]);
1638
+ }), [data, xAxisKey, categoryTitle, valueTitle, bars, stacked, fullFormat, names, references, forecastAt, forecastLabel]);
1548
1639
  if (!data?.length) return null;
1549
1640
  return /* @__PURE__ */ jsx(
1550
1641
  ChartWrapper,
@@ -1573,7 +1664,7 @@ var BarChart = markChart(forwardRef(function BarChart2({
1573
1664
  margin: { top: 4 + (topTitle ? titleLine(measured.px) : 0), right: sideways || names ? 4 : xTicks.endMargin, bottom: 4, left: 4 },
1574
1665
  accessibilityLayer: true,
1575
1666
  children: [
1576
- /* @__PURE__ */ jsx(SeriesPatterns, { chartId, colors: fills, surface, ahead: forecastAt >= 0 }),
1667
+ /* @__PURE__ */ jsx(SeriesPatterns, { chartId, colors: fills, surface, ahead: forecastAt >= 0, patterns: patterns2 }),
1577
1668
  showGrid && /* @__PURE__ */ jsx(CartesianGrid, { strokeDasharray: "3 3", stroke: gridStroke, vertical: !sideways, horizontal: true }),
1578
1669
  sideways ? /* @__PURE__ */ jsxs(Fragment, { children: [
1579
1670
  /* @__PURE__ */ jsx(XAxis, { type: "number", ...axisStyle.tick, axisLine: false, tickLine: false, height: "auto", label: bottomLabel, tickFormatter: tickFormat }),
@@ -1617,10 +1708,10 @@ var BarChart = markChart(forwardRef(function BarChart2({
1617
1708
  {
1618
1709
  dataKey: bar.dataKey,
1619
1710
  name: bar.label ?? bar.dataKey,
1620
- fill: patterns2[i] ? `url(#${patterns2[i]})` : fills[i],
1711
+ fill: fillPatterns[i] ? `url(#${fillPatterns[i]})` : fills[i],
1621
1712
  stroke: bar.soft ? solidColors[i] : void 0,
1622
1713
  strokeWidth: bar.soft ? 1 : void 0,
1623
- shape: barShape(bars, i, stacked, radius, sideways, forecastAt >= 0 ? { from: forecastAt, edge: solidColors[i], fill: aheadBarFill(fills[i], patterns2[i]) } : void 0),
1714
+ shape: barShape(bars, i, stacked, radius, sideways, forecastAt >= 0 ? { from: forecastAt, edge: solidColors[i], fill: aheadBarFill(fills[i], fillPatterns[i]) } : void 0),
1624
1715
  stackId: barStackOf(bar, stacked),
1625
1716
  maxBarSize,
1626
1717
  isAnimationActive: isAnimated
@@ -1653,7 +1744,8 @@ var LineChart = markChart(forwardRef(function LineChart2({
1653
1744
  description,
1654
1745
  references,
1655
1746
  forecastFrom,
1656
- forecastLabel = "Forecast"
1747
+ forecastLabel = "Forecast",
1748
+ patterns: patterns2 = false
1657
1749
  }, ref) {
1658
1750
  const wrapperRef = useRef(null);
1659
1751
  const values = useMemo(() => [...seriesValues(data ?? [], lines.map((s) => s.dataKey), false), ...referenceValues(references)], [data, lines, references]);
@@ -1670,7 +1762,7 @@ var LineChart = markChart(forwardRef(function LineChart2({
1670
1762
  const axisLabelStyle = { fontSize: "var(--ds-font-size-xs)", fontFamily: "var(--ds-font-sans)", fill: axisStyle.tick.fill };
1671
1763
  const top = 4 + (yAxisLabel ? Math.ceil(measured.px * 1.5) + 4 : 0);
1672
1764
  const ink = useResolvedToken("--ds-text-secondary");
1673
- const dashes = useMemo(() => lineDashes(lines), [lines]);
1765
+ const dashes = useMemo(() => lineDashes(lines, patterns2), [lines, patterns2]);
1674
1766
  const marks = useMemo(
1675
1767
  () => Object.fromEntries(lines.map((l, i) => [l.dataKey, { kind: "line", color: colors[i], dash: dashes[i] }])),
1676
1768
  [lines, colors, dashes]
@@ -1682,12 +1774,13 @@ var LineChart = markChart(forwardRef(function LineChart2({
1682
1774
  data: data ?? [],
1683
1775
  categoryKey: xAxisKey,
1684
1776
  categoryHeading: xAxisLabel,
1777
+ valueHeading: yAxisLabel,
1685
1778
  series: lines.map((l) => ({ dataKey: l.dataKey, label: l.label ?? l.dataKey })),
1686
1779
  format: fullFormat,
1687
1780
  over: "scale",
1688
1781
  references,
1689
1782
  forecast: forecastAt >= 0 ? { from: forecastAt, label: forecastLabel } : void 0
1690
- }), [data, xAxisKey, xAxisLabel, lines, fullFormat, references, forecastAt, forecastLabel]);
1783
+ }), [data, xAxisKey, xAxisLabel, yAxisLabel, lines, fullFormat, references, forecastAt, forecastLabel]);
1691
1784
  if (!data?.length) return null;
1692
1785
  return /* @__PURE__ */ jsx(
1693
1786
  ChartWrapper,
@@ -1768,7 +1861,8 @@ var AreaChart = markChart(forwardRef(function AreaChart2({
1768
1861
  description,
1769
1862
  references,
1770
1863
  forecastFrom,
1771
- forecastLabel = "Forecast"
1864
+ forecastLabel = "Forecast",
1865
+ patterns: patterns2 = false
1772
1866
  }, ref) {
1773
1867
  const wrapperRef = useRef(null);
1774
1868
  const values = useMemo(() => [...seriesValues(data ?? [], areas.map((s) => s.dataKey), stacked), ...referenceValues(references)], [data, areas, stacked, references]);
@@ -1787,10 +1881,10 @@ var AreaChart = markChart(forwardRef(function AreaChart2({
1787
1881
  const axisLabelStyle = { fontSize: "var(--ds-font-size-xs)", fontFamily: "var(--ds-font-sans)", fill: axisStyle.tick.fill };
1788
1882
  const top = 4 + (yAxisLabel ? Math.ceil(measured.px * 1.5) + 4 : 0);
1789
1883
  const ink = useResolvedToken("--ds-text-secondary");
1790
- const dashes = areas.map((_, i) => seriesDash(i, areas.length));
1884
+ const dashes = areas.map((_, i) => seriesDash(i, areas.length, patterns2));
1791
1885
  const marks = useMemo(
1792
- () => Object.fromEntries(areas.map((a, i) => [a.dataKey, { kind: "line", color: solidColors[i], dash: seriesDash(i, areas.length) }])),
1793
- [areas, solidColors]
1886
+ () => Object.fromEntries(areas.map((a, i) => [a.dataKey, { kind: "line", color: solidColors[i], dash: seriesDash(i, areas.length, patterns2) }])),
1887
+ [areas, solidColors, patterns2]
1794
1888
  );
1795
1889
  const forecastAt = forecastIndex(data ?? [], xAxisKey, forecastFrom);
1796
1890
  const hatch = forecastHatchId(instanceId);
@@ -1799,12 +1893,14 @@ var AreaChart = markChart(forwardRef(function AreaChart2({
1799
1893
  data: data ?? [],
1800
1894
  categoryKey: xAxisKey,
1801
1895
  categoryHeading: xAxisLabel,
1896
+ valueHeading: yAxisLabel,
1802
1897
  series: areas.map((a) => ({ dataKey: a.dataKey, label: a.label ?? a.dataKey })),
1803
1898
  format: fullFormat,
1804
1899
  over: "scale",
1900
+ totals: stacked,
1805
1901
  references,
1806
1902
  forecast: forecastAt >= 0 ? { from: forecastAt, label: forecastLabel } : void 0
1807
- }), [data, xAxisKey, xAxisLabel, areas, fullFormat, references, forecastAt, forecastLabel]);
1903
+ }), [data, xAxisKey, xAxisLabel, yAxisLabel, areas, stacked, fullFormat, references, forecastAt, forecastLabel]);
1808
1904
  if (!data?.length) return null;
1809
1905
  return /* @__PURE__ */ jsx(
1810
1906
  ChartWrapper,
@@ -1878,25 +1974,29 @@ var PieChart = markChart(forwardRef(function PieChart2({
1878
1974
  animated,
1879
1975
  "aria-label": ariaLabel,
1880
1976
  className,
1881
- description
1977
+ description,
1978
+ patterns: patterns2 = false
1882
1979
  }, ref) {
1883
1980
  const colors = useChartColors(data.length, false);
1884
1981
  const chartId = useId();
1885
1982
  const surface = useResolvedToken("--ds-bg-surface");
1983
+ const canvas = useResolvedToken("--ds-bg-canvas");
1984
+ const ground = useMemo(() => groundColour(surface, canvas), [surface, canvas]);
1886
1985
  const locale = useFormatLocale();
1887
1986
  const format = useMemo(() => fullValueFormatter(void 0, locale), [locale]);
1888
1987
  const isAnimated = useChartAnimation(animated);
1889
1988
  const renderLabel = showLabels ? ({ percent: percent2 }) => `${((percent2 ?? 0) * 100).toFixed(0)}%` : false;
1890
1989
  const chartData = data.map((d) => ({ name: d.name, value: numberOf(d.value) ?? 0 }));
1990
+ const single = chartData.filter((d) => d.value > 0).length <= 1;
1891
1991
  const fills = data.map((_, i) => colors[i % colors.length]);
1892
1992
  const marks = useMemo(
1893
- () => Object.fromEntries(data.map((d, i) => [d.name, { kind: "fill", color: colors[i % colors.length], pattern: seriesPattern(chartId, i, data.length) }])),
1894
- [data, colors, chartId]
1993
+ () => Object.fromEntries(data.map((d, i) => [d.name, { kind: "fill", color: colors[i % colors.length], pattern: seriesPattern(chartId, i, data.length, patterns2) }])),
1994
+ [data, colors, chartId, patterns2]
1895
1995
  );
1896
1996
  const access = useMemo(() => partsAccess({ kind: "pie", items: data.map((d) => ({ name: d.name, value: d.value })), format }), [data, format]);
1897
1997
  if (!data?.length) return null;
1898
1998
  return /* @__PURE__ */ jsx(ChartWrapper, { ref, height, size: { model: "square" }, chart: "pie", className, "aria-label": ariaLabel, access, description, marks, children: /* @__PURE__ */ jsx(ResponsiveContainer, { width: "100%", height: "100%", children: /* @__PURE__ */ jsxs(PieChart$1, { accessibilityLayer: true, children: [
1899
- /* @__PURE__ */ jsx(SeriesPatterns, { chartId, colors: fills, surface }),
1999
+ /* @__PURE__ */ jsx(SeriesPatterns, { chartId, colors: fills, surface, patterns: patterns2 }),
1900
2000
  /* @__PURE__ */ jsx(
1901
2001
  Pie,
1902
2002
  {
@@ -1908,12 +2008,14 @@ var PieChart = markChart(forwardRef(function PieChart2({
1908
2008
  outerRadius: "75%",
1909
2009
  innerRadius: donut ? "55%" : 0,
1910
2010
  label: renderLabel,
1911
- labelLine: showLabels,
2011
+ labelLine: showLabels ? { strokeWidth: 1 } : false,
1912
2012
  isAnimationActive: isAnimated,
2013
+ stroke: single ? "none" : ground,
2014
+ strokeWidth: single ? 0 : SEGMENT_GAP,
1913
2015
  fontSize: "var(--ds-font-size-xs)",
1914
2016
  fontFamily: "var(--ds-font-sans)",
1915
2017
  children: data.map((_, i) => {
1916
- const pattern = seriesPattern(chartId, i, data.length);
2018
+ const pattern = seriesPattern(chartId, i, data.length, patterns2);
1917
2019
  return /* @__PURE__ */ jsx(Cell, { fill: pattern ? `url(#${pattern})` : fills[i] }, i);
1918
2020
  })
1919
2021
  }
@@ -1946,7 +2048,8 @@ var CompositeChart = markChart(forwardRef(function CompositeChart2({
1946
2048
  description,
1947
2049
  references,
1948
2050
  forecastFrom,
1949
- forecastLabel = "Forecast"
2051
+ forecastLabel = "Forecast",
2052
+ patterns: patterns2 = false
1950
2053
  }, ref) {
1951
2054
  const wrapperRef = useRef(null);
1952
2055
  const chartId = useId();
@@ -2011,28 +2114,31 @@ var CompositeChart = markChart(forwardRef(function CompositeChart2({
2011
2114
  const surface = useResolvedToken("--ds-bg-surface");
2012
2115
  const canvas = useResolvedToken("--ds-bg-canvas");
2013
2116
  const ink = useResolvedToken("--ds-text-secondary");
2014
- const patterns2 = bars.map((_, i) => seriesPattern(chartId, i, bars.length));
2117
+ const fillPatterns = bars.map((_, i) => seriesPattern(chartId, i, bars.length, patterns2));
2015
2118
  const aheadBarFill = (fill, pattern) => {
2016
2119
  const faint = aheadFill(fill, surface, canvas);
2017
2120
  return faint && pattern ? `url(#${aheadPattern(pattern)})` : faint;
2018
2121
  };
2019
- const dashes = useMemo(() => lineDashes(lines), [lines]);
2122
+ const dashes = useMemo(() => lineDashes(lines, patterns2), [lines, patterns2]);
2020
2123
  const marks = useMemo(() => Object.fromEntries([
2021
- ...bars.map((bar, i) => [bar.dataKey, { kind: "fill", color: barSoftColors[i], edge: barSolidColors[i], pattern: seriesPattern(chartId, i, bars.length) }]),
2124
+ ...bars.map((bar, i) => [bar.dataKey, { kind: "fill", color: barSoftColors[i], edge: barSolidColors[i], pattern: seriesPattern(chartId, i, bars.length, patterns2) }]),
2022
2125
  ...lines.map((line, i) => [line.dataKey, { kind: "line", color: lineColors[i], dash: dashes[i] }])
2023
- ]), [bars, lines, barSoftColors, barSolidColors, lineColors, chartId, dashes]);
2126
+ ]), [bars, lines, barSoftColors, barSolidColors, lineColors, chartId, dashes, patterns2]);
2024
2127
  const forecastAt = forecastIndex(data ?? [], xAxisKey, forecastFrom);
2025
2128
  const access = useMemo(() => cartesianAccess({
2026
2129
  kind: "Bar and line chart",
2027
2130
  data: data ?? [],
2028
2131
  categoryKey: xAxisKey,
2029
2132
  categoryHeading: xAxisLabel,
2133
+ valueHeading: yAxisLabel,
2030
2134
  series: [...bars, ...lines].map((s) => ({ dataKey: s.dataKey, label: s.label ?? s.dataKey })),
2031
2135
  format: fullFormat,
2032
2136
  over: names ? "names" : "scale",
2137
+ // bars that all stack into one column are summed up by their total, the lines left out of it (the fix pass of 25.33)
2138
+ totals: anyStack(bars, stacked) && barGroups(bars, stacked) === 1 ? { series: bars.map((bar) => bar.dataKey), name: "the bars' total" } : void 0,
2033
2139
  references,
2034
2140
  forecast: forecastAt >= 0 ? { from: forecastAt, label: forecastLabel } : void 0
2035
- }), [data, xAxisKey, xAxisLabel, bars, lines, fullFormat, names, references, forecastAt, forecastLabel]);
2141
+ }), [data, xAxisKey, xAxisLabel, yAxisLabel, bars, lines, stacked, fullFormat, names, references, forecastAt, forecastLabel]);
2036
2142
  if (!data?.length) return null;
2037
2143
  return /* @__PURE__ */ jsx(
2038
2144
  ChartWrapper,
@@ -2061,7 +2167,7 @@ var CompositeChart = markChart(forwardRef(function CompositeChart2({
2061
2167
  margin: { top, right: sideways || names ? 4 : xTicks.endMargin, bottom: 4, left: 4 },
2062
2168
  accessibilityLayer: true,
2063
2169
  children: [
2064
- /* @__PURE__ */ jsx(SeriesPatterns, { chartId, colors: barSoftColors, surface, ahead: forecastAt >= 0 }),
2170
+ /* @__PURE__ */ jsx(SeriesPatterns, { chartId, colors: barSoftColors, surface, ahead: forecastAt >= 0, patterns: patterns2 }),
2065
2171
  showGrid && /* @__PURE__ */ jsx(CartesianGrid, { strokeDasharray: "3 3", stroke: gridStroke, vertical: !sideways, horizontal: true }),
2066
2172
  sideways ? /* @__PURE__ */ jsxs(Fragment, { children: [
2067
2173
  /* @__PURE__ */ jsx(XAxis, { xAxisId: "left", type: "number", ...axisStyle.tick, axisLine: false, tickLine: false, height: "auto", label: bottomLabel, tickFormatter: tickFormat }),
@@ -2107,10 +2213,10 @@ var CompositeChart = markChart(forwardRef(function CompositeChart2({
2107
2213
  {
2108
2214
  dataKey: bar.dataKey,
2109
2215
  name: bar.label ?? bar.dataKey,
2110
- fill: patterns2[i] ? `url(#${patterns2[i]})` : barSoftColors[i],
2216
+ fill: fillPatterns[i] ? `url(#${fillPatterns[i]})` : barSoftColors[i],
2111
2217
  stroke: barSolidColors[i],
2112
2218
  strokeWidth: 1,
2113
- shape: barShape(bars, i, stacked, radius, sideways, forecastAt >= 0 ? { from: forecastAt, edge: barSolidColors[i], fill: aheadBarFill(barSoftColors[i], patterns2[i]) } : void 0),
2219
+ shape: barShape(bars, i, stacked, radius, sideways, forecastAt >= 0 ? { from: forecastAt, edge: barSolidColors[i], fill: aheadBarFill(barSoftColors[i], fillPatterns[i]) } : void 0),
2114
2220
  stackId: barStackOf(bar, stacked),
2115
2221
  maxBarSize,
2116
2222
  ...barAxis,
@@ -2272,7 +2378,8 @@ var RadarChart = markChart(forwardRef(function RadarChart2({
2272
2378
  valueFormat = "number",
2273
2379
  "aria-label": ariaLabel,
2274
2380
  className,
2275
- description
2381
+ description,
2382
+ patterns: patterns2 = false
2276
2383
  }, ref) {
2277
2384
  const solidColors = useChartColors(dataKeys.length, false);
2278
2385
  const softColors = useChartColors(dataKeys.length, true);
@@ -2282,10 +2389,10 @@ var RadarChart = markChart(forwardRef(function RadarChart2({
2282
2389
  const locale = useFormatLocale();
2283
2390
  const tickFormat = useMemo(() => axisTickFormatter(values, valueFormat, locale), [values, valueFormat, locale]);
2284
2391
  const fullFormat = useMemo(() => fullValueFormatter(valueFormat, locale), [valueFormat, locale]);
2285
- const dashes = dataKeys.map((_, i) => seriesDash(i, dataKeys.length));
2392
+ const dashes = dataKeys.map((_, i) => seriesDash(i, dataKeys.length, patterns2));
2286
2393
  const marks = useMemo(
2287
- () => Object.fromEntries(dataKeys.map((dk, i) => [dk.key, { kind: "line", color: solidColors[i], dash: seriesDash(i, dataKeys.length) }])),
2288
- [dataKeys, solidColors]
2394
+ () => Object.fromEntries(dataKeys.map((dk, i) => [dk.key, { kind: "line", color: solidColors[i], dash: seriesDash(i, dataKeys.length, patterns2) }])),
2395
+ [dataKeys, solidColors, patterns2]
2289
2396
  );
2290
2397
  const access = useMemo(() => cartesianAccess({
2291
2398
  kind: "Radar chart",
@@ -2342,7 +2449,8 @@ var RadialBarChart = markChart(forwardRef(function RadialBarChart2({
2342
2449
  animated,
2343
2450
  "aria-label": ariaLabel,
2344
2451
  className,
2345
- description
2452
+ description,
2453
+ patterns: patterns2 = false
2346
2454
  }, ref) {
2347
2455
  const colors = useChartColors(data.length, false);
2348
2456
  const chartId = useId();
@@ -2350,17 +2458,19 @@ var RadialBarChart = markChart(forwardRef(function RadialBarChart2({
2350
2458
  const locale = useFormatLocale();
2351
2459
  const format = useMemo(() => fullValueFormatter(void 0, locale), [locale]);
2352
2460
  const isAnimated = useChartAnimation(animated);
2353
- const chartData = data.map((d, i) => ({
2354
- name: d.name,
2355
- // a number written as text is drawn as the table and the sentence read it (Sprint 25.8.9)
2356
- value: numberOf(d.value) ?? 0,
2357
- ...d.max !== void 0 ? { max: d.max } : {},
2358
- // Sprint 25.8.9 item 4: each bar after the first fills with a pattern over its colour, as the legend shows it
2359
- fill: seriesPattern(chartId, i, data.length) ? `url(#${seriesPattern(chartId, i, data.length)})` : colors[i % colors.length]
2360
- }));
2461
+ const chartData = data.map((d, i) => {
2462
+ const pattern = seriesPattern(chartId, i, data.length, patterns2);
2463
+ return {
2464
+ name: d.name,
2465
+ // a number written as text is drawn as the table and the sentence read it (Sprint 25.8.9)
2466
+ value: numberOf(d.value) ?? 0,
2467
+ ...d.max !== void 0 ? { max: d.max } : {},
2468
+ fill: pattern ? `url(#${pattern})` : colors[i % colors.length]
2469
+ };
2470
+ });
2361
2471
  const marks = useMemo(
2362
- () => Object.fromEntries(data.map((d, i) => [d.name, { kind: "fill", color: colors[i % colors.length], pattern: seriesPattern(chartId, i, data.length) }])),
2363
- [data, colors, chartId]
2472
+ () => Object.fromEntries(data.map((d, i) => [d.name, { kind: "fill", color: colors[i % colors.length], pattern: seriesPattern(chartId, i, data.length, patterns2) }])),
2473
+ [data, colors, chartId, patterns2]
2364
2474
  );
2365
2475
  const access = useMemo(() => partsAccess({ kind: "radial", items: data.map((d) => ({ name: d.name, value: d.value, ...d.max !== void 0 ? { max: d.max } : {} })), format }), [data, format]);
2366
2476
  if (!data?.length) return null;
@@ -2376,7 +2486,7 @@ var RadialBarChart = markChart(forwardRef(function RadialBarChart2({
2376
2486
  endAngle,
2377
2487
  accessibilityLayer: true,
2378
2488
  children: [
2379
- /* @__PURE__ */ jsx(SeriesPatterns, { chartId, colors: data.map((_, i) => colors[i % colors.length]), surface }),
2489
+ /* @__PURE__ */ jsx(SeriesPatterns, { chartId, colors: data.map((_, i) => colors[i % colors.length]), surface, patterns: patterns2 }),
2380
2490
  /* @__PURE__ */ jsx(
2381
2491
  RadialBar,
2382
2492
  {
@@ -2404,6 +2514,9 @@ var FunnelChart = markChart(forwardRef(function FunnelChart2({
2404
2514
  description
2405
2515
  }, ref) {
2406
2516
  const colors = useChartColors(data.length, false);
2517
+ const surface = useResolvedToken("--ds-bg-surface");
2518
+ const canvas = useResolvedToken("--ds-bg-canvas");
2519
+ const ground = useMemo(() => groundColour(surface, canvas), [surface, canvas]);
2407
2520
  const locale = useFormatLocale();
2408
2521
  const format = useMemo(() => fullValueFormatter(void 0, locale), [locale]);
2409
2522
  const access = useMemo(() => partsAccess({ kind: "funnel", items: data.map((d) => ({ name: d.name, value: d.value })), format }), [data, format]);
@@ -2415,7 +2528,7 @@ var FunnelChart = markChart(forwardRef(function FunnelChart2({
2415
2528
  }));
2416
2529
  if (!data?.length) return null;
2417
2530
  return /* @__PURE__ */ jsx(ChartWrapper, { ref, height, size: { model: "rows", units: data.length * STAGE_ROWS, axis: "16px" }, chart: "funnel", className, "aria-label": ariaLabel, access, description, children: /* @__PURE__ */ jsx(ResponsiveContainer, { width: "100%", height: "100%", children: /* @__PURE__ */ jsxs(FunnelChart$1, { accessibilityLayer: true, children: [
2418
- /* @__PURE__ */ jsx(Funnel, { dataKey: "value", data: chartData, isAnimationActive: isAnimated, children: showLabels && /* @__PURE__ */ jsx(
2531
+ /* @__PURE__ */ jsx(Funnel, { dataKey: "value", data: chartData, isAnimationActive: isAnimated, stroke: ground, strokeWidth: SEGMENT_GAP, children: showLabels && /* @__PURE__ */ jsx(
2419
2532
  LabelList,
2420
2533
  {
2421
2534
  dataKey: "name",
@@ -2647,7 +2760,7 @@ var TreemapChart = markChart(forwardRef(function TreemapChart2({
2647
2760
  children: showTooltip && /* @__PURE__ */ jsx(Tooltip, { content: /* @__PURE__ */ jsx(ChartTooltipContent, {}) })
2648
2761
  }
2649
2762
  ) }),
2650
- /* @__PURE__ */ jsx("span", { ref: probe2, "aria-hidden": true, className: LABEL_TEXT, style: { position: "absolute", visibility: "hidden", pointerEvents: "none" }, children: "M" })
2763
+ /* @__PURE__ */ jsx("span", { ref: probe2, "aria-hidden": true, className: LABEL_TEXT, style: { position: "absolute", top: 0, left: 0, visibility: "hidden", pointerEvents: "none" }, children: "M" })
2651
2764
  ] });
2652
2765
  }));
2653
2766
  function oneWayFlows(links) {
@@ -2818,10 +2931,11 @@ var Sparkline = forwardRef(function Sparkline2({
2818
2931
  const chartColor = useResolvedToken(tokenName);
2819
2932
  const softColor = useResolvedToken(softTokenName);
2820
2933
  const chartData = data.map((value, i) => ({ value, index: i }));
2934
+ const picture = ariaLabel ? { role: "img", "aria-label": ariaLabel } : { "aria-hidden": true };
2821
2935
  const containerStyle = insideContainer ? { width: "100%", height: "100%" } : { width: typeof width === "number" ? `${width}px` : width, height: `${height}px` };
2822
2936
  if (!data?.length) return null;
2823
2937
  if (variant === "bar") {
2824
- return /* @__PURE__ */ jsx("div", { ref, style: containerStyle, className, ...ariaLabel ? { role: "img", "aria-label": ariaLabel } : {}, children: /* @__PURE__ */ jsx(ResponsiveContainer, { width: "100%", height: "100%", children: /* @__PURE__ */ jsxs(BarChart$1, { data: chartData, margin: { top: 0, right: 0, bottom: 0, left: 0 }, children: [
2938
+ return /* @__PURE__ */ jsx("div", { ref, style: containerStyle, className, ...picture, children: /* @__PURE__ */ jsx(ResponsiveContainer, { width: "100%", height: "100%", children: /* @__PURE__ */ jsxs(BarChart$1, { data: chartData, margin: { top: 0, right: 0, bottom: 0, left: 0 }, accessibilityLayer: false, children: [
2825
2939
  /* @__PURE__ */ jsx(XAxis, { dataKey: "index", hide: true }),
2826
2940
  /* @__PURE__ */ jsx(YAxis, { hide: true }),
2827
2941
  showTooltip && /* @__PURE__ */ jsx(Tooltip, { content: /* @__PURE__ */ jsx(ChartTooltipContent, {}), cursor: false }),
@@ -2838,7 +2952,7 @@ var Sparkline = forwardRef(function Sparkline2({
2838
2952
  }
2839
2953
  if (variant === "area") {
2840
2954
  const gradientId = `sparkline-gradient-${instanceId}-${color}`;
2841
- return /* @__PURE__ */ jsx("div", { ref, style: containerStyle, className, ...ariaLabel ? { role: "img", "aria-label": ariaLabel } : {}, children: /* @__PURE__ */ jsx(ResponsiveContainer, { width: "100%", height: "100%", children: /* @__PURE__ */ jsxs(AreaChart$1, { data: chartData, margin: { top: 2, right: 2, bottom: 2, left: 2 }, children: [
2955
+ return /* @__PURE__ */ jsx("div", { ref, style: containerStyle, className, ...picture, children: /* @__PURE__ */ jsx(ResponsiveContainer, { width: "100%", height: "100%", children: /* @__PURE__ */ jsxs(AreaChart$1, { data: chartData, margin: { top: 2, right: 2, bottom: 2, left: 2 }, accessibilityLayer: false, children: [
2842
2956
  /* @__PURE__ */ jsx("defs", { children: /* @__PURE__ */ jsxs("linearGradient", { id: gradientId, x1: "0", y1: "0", x2: "0", y2: "1", children: [
2843
2957
  /* @__PURE__ */ jsx("stop", { offset: "0%", stopColor: softColor, stopOpacity: 1 }),
2844
2958
  /* @__PURE__ */ jsx("stop", { offset: "95%", stopColor: softColor, stopOpacity: 0.1 })
@@ -2861,7 +2975,7 @@ var Sparkline = forwardRef(function Sparkline2({
2861
2975
  )
2862
2976
  ] }) }) });
2863
2977
  }
2864
- return /* @__PURE__ */ jsx("div", { ref, style: containerStyle, className, ...ariaLabel ? { role: "img", "aria-label": ariaLabel } : {}, children: /* @__PURE__ */ jsx(ResponsiveContainer, { width: "100%", height: "100%", children: /* @__PURE__ */ jsxs(LineChart$1, { data: chartData, margin: { top: 2, right: 2, bottom: 2, left: 2 }, children: [
2978
+ return /* @__PURE__ */ jsx("div", { ref, style: containerStyle, className, ...picture, children: /* @__PURE__ */ jsx(ResponsiveContainer, { width: "100%", height: "100%", children: /* @__PURE__ */ jsxs(LineChart$1, { data: chartData, margin: { top: 2, right: 2, bottom: 2, left: 2 }, accessibilityLayer: false, children: [
2865
2979
  /* @__PURE__ */ jsx(XAxis, { dataKey: "index", hide: true }),
2866
2980
  /* @__PURE__ */ jsx(YAxis, { hide: true, domain: ["dataMin - 1", "dataMax + 1"] }),
2867
2981
  showTooltip && /* @__PURE__ */ jsx(Tooltip, { content: /* @__PURE__ */ jsx(ChartTooltipContent, {}), cursor: false }),
@@ -2879,10 +2993,12 @@ var Sparkline = forwardRef(function Sparkline2({
2879
2993
  )
2880
2994
  ] }) }) });
2881
2995
  });
2996
+ var CELL_BODY = "min-h-0 overflow-y-auto -m-[4px] p-[4px] scroll-p-[4px]";
2882
2997
  var CHART_TITLE_CLASSES = TITLE_TEXT;
2883
2998
  function ChartContainer({
2884
2999
  height = "auto",
2885
3000
  title,
3001
+ actions: pageActions,
2886
3002
  loading = false,
2887
3003
  emptyState,
2888
3004
  variant = "default",
@@ -2890,9 +3006,27 @@ function ChartContainer({
2890
3006
  className
2891
3007
  }) {
2892
3008
  const titleId = useId();
3009
+ const hint = useContext(DashboardCellContext) !== null;
3010
+ const rootRef = useRef(null);
3011
+ const [nested, setNested] = useState(false);
3012
+ useLayoutEffect(() => {
3013
+ if (hint) setNested(!rootRef.current?.matches(CELL_FRAME));
3014
+ }, [hint]);
3015
+ const cell = hint && !nested;
2893
3016
  const fixed = fixedChartHeight(height);
2894
3017
  const sizesItself = !loading && !!children && isLibraryChart(children);
2895
3018
  const area = fixed ?? CHART_HEIGHTS.md;
3019
+ const [bodyEl, setBodyEl] = useState(null);
3020
+ const [drawings, setDrawings] = useState(0);
3021
+ const drawing = useCallback(() => {
3022
+ setDrawings((n) => n + 1);
3023
+ return () => setDrawings((n) => n - 1);
3024
+ }, []);
3025
+ useKeyboardScroll(bodyEl, title || "Chart", cell && drawings === 0);
3026
+ const strayActions = !title && !!pageActions;
3027
+ useEffect(() => {
3028
+ if (strayActions) warnOnce("ChartContainer", "actions are drawn in the chart's header, beside its title, and this chart has no title: give it a title (what the chart is), or the actions don't show.");
3029
+ }, [strayActions]);
2896
3030
  const [actions, setActions] = useState(null);
2897
3031
  const [charts, setCharts] = useState(0);
2898
3032
  const register = useCallback(() => {
@@ -2900,8 +3034,8 @@ function ChartContainer({
2900
3034
  return () => setCharts((n) => n - 1);
2901
3035
  }, []);
2902
3036
  const context = useMemo(
2903
- () => ({ height: fixed, titleId: title ? titleId : void 0, title: title || void 0, fillArea: !sizesItself, actions, charts, register }),
2904
- [fixed, title, titleId, sizesItself, actions, charts, register]
3037
+ () => ({ height: fixed, titleId: title ? titleId : void 0, title: title || void 0, fillArea: !sizesItself, cell, actions, charts, register, drawing: cell ? drawing : void 0 }),
3038
+ [fixed, title, titleId, sizesItself, cell, actions, charts, register, drawing]
2905
3039
  );
2906
3040
  let body = null;
2907
3041
  if (loading) {
@@ -2910,16 +3044,17 @@ function ChartContainer({
2910
3044
  /* @__PURE__ */ jsx(Skeleton, { variant: "text", lines: 1, className: "w-full" })
2911
3045
  ] });
2912
3046
  } else if (children) {
2913
- body = /* @__PURE__ */ jsx(ChartContainerContext.Provider, { value: context, children: sizesItself ? children : (
3047
+ body = /* @__PURE__ */ jsx(ChartContainerContext.Provider, { value: context, children: /* @__PURE__ */ jsx(DashboardCellContext, { value: null, children: sizesItself || cell ? children : (
2914
3048
  // the area is absolute, so a child that fills 100% has a definite height to fill
2915
3049
  /* @__PURE__ */ jsx("div", { className: "absolute inset-0", children: /* @__PURE__ */ jsx("div", { className: "h-full w-full", children }) })
2916
- ) });
3050
+ ) }) });
2917
3051
  } else if (emptyState) {
2918
3052
  body = /* @__PURE__ */ jsx("div", { className: "flex flex-1 items-center justify-center", children: emptyState });
2919
3053
  }
2920
3054
  return /* @__PURE__ */ jsxs(
2921
3055
  "div",
2922
3056
  {
3057
+ ref: rootRef,
2923
3058
  "data-card": "",
2924
3059
  "data-gs": "chart",
2925
3060
  className: cn(
@@ -2933,16 +3068,21 @@ function ChartContainer({
2933
3068
  className
2934
3069
  ),
2935
3070
  children: [
2936
- title && /* @__PURE__ */ jsxs("div", { "data-chart-header": "", className: "mb-ds-4 flex items-start justify-between gap-ds-3", children: [
2937
- /* @__PURE__ */ jsx("h3", { id: titleId, className: cn(CHART_TITLE_CLASSES, "min-w-0 flex-1"), children: title }),
3071
+ title && // Sprint 32 (F2): CardHeader's rule for the title's room. Its basis is its floor (TITLE_FLOOR) and it takes what's
3072
+ // left, so the page's actions and the switch's slot, items of their own, wrap under it, at the end, only when the
3073
+ // title would go under its floor; a title that fits draws as before, and a word wider than the frame breaks there
3074
+ /* @__PURE__ */ jsxs("div", { "data-chart-header": "", className: cn("mb-ds-4 flex flex-wrap items-start justify-end gap-x-ds-3 gap-y-ds-2", CELL_ROOM_INNER, CELL_HIDE_CHART_ACTIONS), children: [
3075
+ /* @__PURE__ */ jsx("h3", { id: titleId, className: cn(CHART_TITLE_CLASSES, "min-w-0 grow me-auto", TITLE_FLOOR), children: title }),
3076
+ pageActions ? /* @__PURE__ */ jsx("div", { "data-chart-page-actions": "", className: "flex shrink-0 items-center gap-ds-2", children: pageActions }) : null,
2938
3077
  /* @__PURE__ */ jsx("div", { ref: setActions, "data-chart-actions": "", className: "shrink-0 empty:hidden" })
2939
3078
  ] }),
2940
3079
  /* @__PURE__ */ jsx(
2941
3080
  "div",
2942
3081
  {
3082
+ ref: setBodyEl,
2943
3083
  "data-chart-body": "",
2944
- className: "relative flex min-w-0 flex-col",
2945
- style: { flex: "1 1 0%", minHeight: sizesItself ? void 0 : area },
3084
+ className: cn("relative flex min-w-0 flex-col", cell && [CELL_BODY, FOCUS_INSET]),
3085
+ style: { flex: "1 1 0%", minHeight: sizesItself || cell ? void 0 : area },
2946
3086
  children: body
2947
3087
  }
2948
3088
  )