gridsmith-ui 0.30.1 → 0.31.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 (80) hide show
  1. package/CHANGELOG.md +73 -1
  2. package/dist/charts.d.ts +114 -1
  3. package/dist/charts.js +1113 -206
  4. package/dist/charts.js.map +1 -1
  5. package/dist/chat.js +24 -10
  6. package/dist/chat.js.map +1 -1
  7. package/dist/{chunk-ULCACQSA.js → chunk-2Q4HOGEI.js} +16 -51
  8. package/dist/chunk-2Q4HOGEI.js.map +1 -0
  9. package/dist/{chunk-T52LAFKG.js → chunk-3J67NISC.js} +13 -15
  10. package/dist/chunk-3J67NISC.js.map +1 -0
  11. package/dist/{chunk-L6HWACK7.js → chunk-53F7GVBQ.js} +6 -3
  12. package/dist/chunk-53F7GVBQ.js.map +1 -0
  13. package/dist/{chunk-SLRTSBCJ.js → chunk-BKYWKMUN.js} +73 -678
  14. package/dist/chunk-BKYWKMUN.js.map +1 -0
  15. package/dist/{chunk-KMKBOTFR.js → chunk-EKWXPSTI.js} +10 -12
  16. package/dist/chunk-EKWXPSTI.js.map +1 -0
  17. package/dist/{chunk-SJZWEBHL.js → chunk-GP2COVJC.js} +24 -11
  18. package/dist/chunk-GP2COVJC.js.map +1 -0
  19. package/dist/{chunk-OVHBQT3Z.js → chunk-GT6M74IZ.js} +6 -6
  20. package/dist/{chunk-OVHBQT3Z.js.map → chunk-GT6M74IZ.js.map} +1 -1
  21. package/dist/{chunk-IELIF4PJ.js → chunk-HUNEJIKV.js} +3 -3
  22. package/dist/{chunk-IELIF4PJ.js.map → chunk-HUNEJIKV.js.map} +1 -1
  23. package/dist/{chunk-NEUWZUK6.js → chunk-LE72KHIE.js} +3 -4
  24. package/dist/chunk-LE72KHIE.js.map +1 -0
  25. package/dist/{chunk-OX3NNMWG.js → chunk-OFACAHRV.js} +10 -6
  26. package/dist/chunk-OFACAHRV.js.map +1 -0
  27. package/dist/{chunk-R5QXMNW7.js → chunk-OWQ7M6R7.js} +177 -27
  28. package/dist/chunk-OWQ7M6R7.js.map +1 -0
  29. package/dist/{chunk-TYNDXMBV.js → chunk-QOMP4D6V.js} +3 -3
  30. package/dist/{chunk-TYNDXMBV.js.map → chunk-QOMP4D6V.js.map} +1 -1
  31. package/dist/chunk-U7WBI4AV.js +285 -0
  32. package/dist/chunk-U7WBI4AV.js.map +1 -0
  33. package/dist/chunk-V2ARGHJN.js +755 -0
  34. package/dist/chunk-V2ARGHJN.js.map +1 -0
  35. package/dist/chunk-V73LHNRL.js +51 -0
  36. package/dist/chunk-V73LHNRL.js.map +1 -0
  37. package/dist/{chunk-UDJOIVKQ.js → chunk-XSQD3UGY.js} +77 -7
  38. package/dist/chunk-XSQD3UGY.js.map +1 -0
  39. package/dist/{chunk-ISONVOA7.js → chunk-YFHTREH5.js} +6 -8
  40. package/dist/chunk-YFHTREH5.js.map +1 -0
  41. package/dist/data-grid.js +10 -13
  42. package/dist/data-grid.js.map +1 -1
  43. package/dist/editor-mentions.js +2 -4
  44. package/dist/editor-mentions.js.map +1 -1
  45. package/dist/editor.js +3 -7
  46. package/dist/editor.js.map +1 -1
  47. package/dist/icons.js +1 -1
  48. package/dist/index.d.ts +104 -16
  49. package/dist/index.js +1075 -654
  50. package/dist/index.js.map +1 -1
  51. package/dist/kanban.js +9 -13
  52. package/dist/kanban.js.map +1 -1
  53. package/dist/resizable.js +9 -13
  54. package/dist/resizable.js.map +1 -1
  55. package/dist/virtualized.js +10 -13
  56. package/dist/virtualized.js.map +1 -1
  57. package/package.json +1 -1
  58. package/dist/chunk-6C2IUMY7.js +0 -46
  59. package/dist/chunk-6C2IUMY7.js.map +0 -1
  60. package/dist/chunk-7Q46JXSK.js +0 -51
  61. package/dist/chunk-7Q46JXSK.js.map +0 -1
  62. package/dist/chunk-HTXP5BMM.js +0 -38
  63. package/dist/chunk-HTXP5BMM.js.map +0 -1
  64. package/dist/chunk-ISONVOA7.js.map +0 -1
  65. package/dist/chunk-KMKBOTFR.js.map +0 -1
  66. package/dist/chunk-L6HWACK7.js.map +0 -1
  67. package/dist/chunk-NEUWZUK6.js.map +0 -1
  68. package/dist/chunk-NKUCS67T.js +0 -13
  69. package/dist/chunk-NKUCS67T.js.map +0 -1
  70. package/dist/chunk-OX3NNMWG.js.map +0 -1
  71. package/dist/chunk-R5QXMNW7.js.map +0 -1
  72. package/dist/chunk-SJZWEBHL.js.map +0 -1
  73. package/dist/chunk-SLRTSBCJ.js.map +0 -1
  74. package/dist/chunk-T52LAFKG.js.map +0 -1
  75. package/dist/chunk-UDJOIVKQ.js.map +0 -1
  76. package/dist/chunk-ULCACQSA.js.map +0 -1
  77. package/dist/chunk-WIUGPZOH.js +0 -88
  78. package/dist/chunk-WIUGPZOH.js.map +0 -1
  79. package/dist/chunk-YL5KD5RC.js +0 -49
  80. package/dist/chunk-YL5KD5RC.js.map +0 -1
package/dist/charts.js CHANGED
@@ -1,14 +1,20 @@
1
1
  "use client";
2
- import { TITLE_TEXT, Skeleton } from './chunk-6C2IUMY7.js';
2
+ import { SegmentedControl, TITLE_TEXT, Skeleton } from './chunk-U7WBI4AV.js';
3
+ import { useKeyboardScroll } from './chunk-GP2COVJC.js';
3
4
  import { useFormatLocale, useHydrated } from './chunk-LJYSVZMI.js';
5
+ import './chunk-BKYWKMUN.js';
4
6
  import { formatLocale } from './chunk-7QLXYRPD.js';
5
- import { elementType } from './chunk-NKUCS67T.js';
6
- import { mergeRefs } from './chunk-7Q46JXSK.js';
7
- import { cn, GLASS_SURFACE } from './chunk-YL5KD5RC.js';
8
- import { createContext, forwardRef, useContext, useRef, useState, useMemo, useLayoutEffect, useEffect, useId, useSyncExternalStore, Children, isValidElement } from 'react';
9
- 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, getNiceTickValues, Rectangle } from 'recharts';
7
+ import './chunk-7RKC5C7G.js';
8
+ import { FormChangeCtx } from './chunk-72SDAX54.js';
9
+ import { elementType } from './chunk-2Q4HOGEI.js';
10
+ import './chunk-HUNEJIKV.js';
11
+ import { mergeRefs } from './chunk-XSQD3UGY.js';
12
+ import { warnOnce } from './chunk-53F7GVBQ.js';
13
+ import { cn, FOCUS_INSET, GLASS_SURFACE } from './chunk-OWQ7M6R7.js';
14
+ import { createContext, forwardRef, useContext, useRef, useState, useId, useMemo, useLayoutEffect, useEffect, useCallback, useSyncExternalStore, Children, isValidElement } from 'react';
15
+ 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
+ import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
10
17
  import { createPortal } from 'react-dom';
11
- import { jsxs, jsx, Fragment } from 'react/jsx-runtime';
12
18
 
13
19
  var CHART_TOKENS = [
14
20
  "--ds-chart-1",
@@ -18,6 +24,7 @@ var CHART_TOKENS = [
18
24
  "--ds-chart-5",
19
25
  "--ds-chart-6"
20
26
  ];
27
+ var CHART_COLOR_COUNT = CHART_TOKENS.length;
21
28
  var CHART_TOKENS_SOFT = [
22
29
  "--ds-chart-1-soft",
23
30
  "--ds-chart-2-soft",
@@ -40,6 +47,7 @@ var FALLBACK_COLORS = {
40
47
  "--ds-chart-5-soft": "rgba(8, 145, 178, 0.3)",
41
48
  "--ds-chart-6-soft": "rgba(124, 58, 237, 0.3)",
42
49
  "--ds-bg-surface": "#ffffff",
50
+ "--ds-bg-canvas": "#ffffff",
43
51
  "--ds-border-subtle": "#e5e7eb",
44
52
  "--ds-text-primary": "#111827",
45
53
  "--ds-text-secondary": "#6b7280",
@@ -275,30 +283,30 @@ function categoryKind(labels, locale) {
275
283
  return "names";
276
284
  }
277
285
  if (raw instanceof Date) continue;
278
- const text = String(raw).trim();
279
- if (!text) continue;
280
- if (!list.some((re) => re.test(text))) return "names";
286
+ const text2 = String(raw).trim();
287
+ if (!text2) continue;
288
+ if (!list.some((re) => re.test(text2))) return "names";
281
289
  }
282
290
  return "scale";
283
291
  }
284
292
  function resolvedAxisFont(el) {
285
293
  const doc = el.ownerDocument;
286
294
  const view = doc.defaultView;
287
- let probe = el.querySelector("[data-chart-probe]");
295
+ let probe2 = el.querySelector("[data-chart-probe]");
288
296
  let temporary = false;
289
- if (!probe) {
290
- probe = doc.createElement("span");
291
- probe.setAttribute("aria-hidden", "true");
292
- probe.style.cssText = "position:absolute;visibility:hidden;pointer-events:none;white-space:nowrap;font-size:var(--ds-font-size-xs);font-family:var(--ds-font-sans)";
293
- el.appendChild(probe);
297
+ if (!probe2) {
298
+ probe2 = doc.createElement("span");
299
+ probe2.setAttribute("aria-hidden", "true");
300
+ probe2.style.cssText = "position:absolute;visibility:hidden;pointer-events:none;white-space:nowrap;font-size:var(--ds-font-size-xs);font-family:var(--ds-font-sans)";
301
+ el.appendChild(probe2);
294
302
  temporary = true;
295
303
  }
296
- const cs = view?.getComputedStyle(probe);
304
+ const cs = view?.getComputedStyle(probe2);
297
305
  const px = parseFloat(cs?.fontSize ?? "") || 12;
298
306
  const family = (cs?.fontFamily ?? "").trim() || "sans-serif";
299
307
  const style = cs?.fontStyle && cs.fontStyle !== "normal" ? `${cs.fontStyle} ` : "";
300
308
  const weight = cs?.fontWeight && cs.fontWeight !== "400" && cs.fontWeight !== "normal" ? `${cs.fontWeight} ` : "";
301
- if (temporary) probe.remove();
309
+ if (temporary) probe2.remove();
302
310
  return { font: `${style}${weight}${px}px ${family}`, px };
303
311
  }
304
312
  var shared = null;
@@ -321,66 +329,659 @@ function createAxisMeasurer(el) {
321
329
  const { font, px } = resolvedAxisFont(el);
322
330
  ctx.font = font;
323
331
  const widths = /* @__PURE__ */ new Map();
324
- const measure = (text) => {
325
- let w = widths.get(text);
332
+ const measure2 = (text2) => {
333
+ let w = widths.get(text2);
326
334
  if (w === void 0) {
327
335
  ctx.font = font;
328
- w = ctx.measureText(text).width;
329
- widths.set(text, w);
336
+ w = ctx.measureText(text2).width;
337
+ widths.set(text2, w);
330
338
  }
331
339
  return w;
332
340
  };
333
- return { measure, px, font };
341
+ return { measure: measure2, px, font };
334
342
  }
335
343
  var ELLIPSIS = "\u2026";
336
344
  var letters = (s) => s.replace(/\s+/g, "").replace(/…/g, "").length;
337
- function prefixThatFits(text, width, measure, suffix = "") {
345
+ function prefixThatFits(text2, width, measure2, suffix = "") {
338
346
  let lo = 1;
339
- let hi = text.length;
347
+ let hi = text2.length;
340
348
  let best = 0;
341
349
  while (lo <= hi) {
342
350
  const mid = lo + hi >> 1;
343
- if (measure(text.slice(0, mid).trimEnd() + suffix) <= width) {
351
+ if (measure2(text2.slice(0, mid).trimEnd() + suffix) <= width) {
344
352
  best = mid;
345
353
  lo = mid + 1;
346
354
  } else hi = mid - 1;
347
355
  }
348
356
  return best;
349
357
  }
350
- function fitLabel(name, width, measure) {
351
- const text = name.replace(/\s+/g, " ").trim();
352
- if (!measure || !text || width <= 0 || measure(text) <= width) return { lines: [text], cut: false, shown: letters(text) };
353
- const words = text.split(" ");
358
+ function fitLabel(name, width, measure2) {
359
+ const text2 = name.replace(/\s+/g, " ").trim();
360
+ if (!measure2 || !text2 || width <= 0 || measure2(text2) <= width) return { lines: [text2], cut: false, shown: letters(text2) };
361
+ const words = text2.split(" ");
354
362
  let first = "";
355
363
  let firstShown = "";
356
364
  let rest = "";
357
365
  for (let i = words.length - 1; i >= 1; i--) {
358
366
  const candidate = words.slice(0, i).join(" ");
359
- if (measure(candidate) <= width) {
367
+ if (measure2(candidate) <= width) {
360
368
  first = firstShown = candidate;
361
369
  rest = words.slice(i).join(" ");
362
370
  break;
363
371
  }
364
372
  }
365
373
  if (!first) {
366
- const k2 = Math.max(1, prefixThatFits(text, width, measure, "-"));
367
- firstShown = text.slice(0, k2).trimEnd();
368
- rest = text.slice(k2).trimStart();
369
- first = rest && !text.slice(k2 - 1, k2 + 1).includes(" ") ? `${firstShown}-` : firstShown;
374
+ const k2 = Math.max(1, prefixThatFits(text2, width, measure2, "-"));
375
+ firstShown = text2.slice(0, k2).trimEnd();
376
+ rest = text2.slice(k2).trimStart();
377
+ first = rest && !text2.slice(k2 - 1, k2 + 1).includes(" ") ? `${firstShown}-` : firstShown;
370
378
  }
371
379
  if (!rest) return { lines: [first], cut: false, shown: letters(firstShown) };
372
- if (measure(rest) <= width) return { lines: [first, rest], cut: false, shown: letters(firstShown) + letters(rest) };
373
- const k = prefixThatFits(rest, width, measure, ELLIPSIS);
380
+ if (measure2(rest) <= width) return { lines: [first, rest], cut: false, shown: letters(firstShown) + letters(rest) };
381
+ const k = prefixThatFits(rest, width, measure2, ELLIPSIS);
374
382
  const kept = k > 0 ? rest.slice(0, k).trimEnd() : "";
375
383
  return { lines: [first, kept + ELLIPSIS], cut: true, shown: letters(firstShown) + letters(kept) };
376
384
  }
377
385
  var MIN_NAME_CHARS = 6;
378
- function namesCutShort(names, width, measure) {
386
+ function namesCutShort(names, width, measure2) {
379
387
  return names.some((n) => {
380
- const fit = fitLabel(n, width, measure);
388
+ const fit = fitLabel(n, width, measure2);
381
389
  return fit.cut && fit.shown < MIN_NAME_CHARS;
382
390
  });
383
391
  }
392
+ var TICK_COUNT = 5;
393
+ var TIME_UNITS = [["hour", 36e5], ["minute", 6e4], ["second", 1e3], ["millisecond", 1]];
394
+ var BYTE_UNITS = [["petabyte", 1e15], ["terabyte", 1e12], ["gigabyte", 1e9], ["megabyte", 1e6], ["kilobyte", 1e3], ["byte", 1]];
395
+ var MAX_FRACTION = 10;
396
+ function exact(format, maxDigits = MAX_FRACTION) {
397
+ for (let digits = 0; digits < maxDigits; digits++) {
398
+ const label = format(digits);
399
+ if (label === format(digits + 6)) return label;
400
+ }
401
+ return format(maxDigits);
402
+ }
403
+ var unitFormat = (unit, value, locale) => (digits) => new Intl.NumberFormat(locale, { style: "unit", unit, unitDisplay: "short", maximumFractionDigits: digits }).format(value);
404
+ var unitsOf = (format) => format === "bytes" ? BYTE_UNITS : TIME_UNITS;
405
+ function unitReached(units, value) {
406
+ return units.find(([, size]) => Math.abs(value) >= size) ?? units[units.length - 1];
407
+ }
408
+ function axisUnit(units, ticks) {
409
+ const largest = Math.max(0, ...ticks.map(Math.abs));
410
+ const exactIn = (size) => ticks.every((t) => Math.abs(t / size * 100 - Math.round(t / size * 100)) < 1e-6);
411
+ return units.find(([, size]) => largest / size >= 1 && exactIn(size)) ?? units[units.length - 1];
412
+ }
413
+ function valueAxisTicks(values) {
414
+ const finite = values.filter(Number.isFinite);
415
+ if (!finite.length) return [];
416
+ const lo = Math.min(0, ...finite);
417
+ const hi = Math.max(0, ...finite);
418
+ if (lo === hi) return [lo];
419
+ return getNiceTickValues([lo, hi], TICK_COUNT, true).map(Number);
420
+ }
421
+ function axisTickFormatter(values, format, locale) {
422
+ if (typeof format === "function") return format;
423
+ if (format === "percent") return (value) => exact((d) => new Intl.NumberFormat(locale, { style: "percent", maximumFractionDigits: d }).format(value / 100));
424
+ if (format === "milliseconds" || format === "bytes") {
425
+ const [unit, size] = axisUnit(unitsOf(format), valueAxisTicks(values));
426
+ return (value) => exact(unitFormat(unit, value / size, locale));
427
+ }
428
+ const compact = (value) => exact((d) => new Intl.NumberFormat(locale, { notation: "compact", maximumFractionDigits: d }).format(value));
429
+ const plain = (value) => exact((d) => new Intl.NumberFormat(locale, { maximumFractionDigits: d }).format(value));
430
+ const largest = Math.max(0, ...values.filter(Number.isFinite).map(Math.abs));
431
+ return largest >= COMPACT_FROM ? compact : plain;
432
+ }
433
+ var COMPACT_FROM = 1e4;
434
+ function fullValueFormatter(format, locale) {
435
+ if (typeof format === "function") return format;
436
+ if (format === void 0 || format === "number") return (value) => value.toLocaleString(locale);
437
+ if (format === "percent") return (value) => exact((d) => new Intl.NumberFormat(locale, { style: "percent", maximumFractionDigits: d }).format(value / 100), 4);
438
+ return (value) => {
439
+ const [unit, size] = unitReached(unitsOf(format), value);
440
+ return exact(unitFormat(unit, value / size, locale), 4);
441
+ };
442
+ }
443
+ function numberOf(raw) {
444
+ const v = typeof raw === "number" ? raw : typeof raw === "string" && raw.trim() !== "" ? Number(raw) : NaN;
445
+ return Number.isFinite(v) ? v : null;
446
+ }
447
+ function axisExtent(data, series) {
448
+ return data.flatMap((row) => {
449
+ const own = [];
450
+ const up = /* @__PURE__ */ new Map();
451
+ const down = /* @__PURE__ */ new Map();
452
+ for (const s of series) {
453
+ const v = numberOf(row[s.dataKey]);
454
+ if (v === null) continue;
455
+ if (s.stack == null) own.push(v);
456
+ else if (v >= 0) up.set(s.stack, (up.get(s.stack) ?? 0) + v);
457
+ else down.set(s.stack, (down.get(s.stack) ?? 0) + v);
458
+ }
459
+ return [...own, ...up.values(), ...down.values()];
460
+ });
461
+ }
462
+ function seriesValues(data, keys, stacked = false) {
463
+ return axisExtent(data, keys.map((dataKey) => ({ dataKey, stack: stacked ? "stack" : null })));
464
+ }
465
+
466
+ // ../../showcase/src/components/charts/chart-access.ts
467
+ var isNumber = (v) => typeof v === "number" && Number.isFinite(v);
468
+ var text = (v) => v == null ? "" : String(v);
469
+ function listOf(items) {
470
+ if (items.length <= 1) return items[0] ?? "";
471
+ return `${items.slice(0, -1).join(", ")} and ${items[items.length - 1]}`;
472
+ }
473
+ function percent(part, whole) {
474
+ if (!(whole > 0)) return "0%";
475
+ const p = part / whole * 100;
476
+ if (p > 0 && p < 1) return "under 1%";
477
+ if (p > 99 && p < 100) return "over 99%";
478
+ return `${Math.round(p)}%`;
479
+ }
480
+ function referenceNote(r, format) {
481
+ return isNumber(r.to) ? `${r.label}: ${format(r.value)} to ${format(r.to)}` : `${r.label}: ${format(r.value)}`;
482
+ }
483
+ var SUMMED = 3;
484
+ function seriesSentence(label, points, over, f) {
485
+ if (!points.length) return null;
486
+ if (points.length === 1) return `${label}: ${f(points[0].value)} (${points[0].cat}).`;
487
+ const high = points.reduce((a, b) => b.value > a.value ? b : a);
488
+ 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}.`;
492
+ const first = points[0], end = points[points.length - 1];
493
+ const steps = points.slice(1).map((p, i) => p.value - points[i].value);
494
+ const up = steps.every((d) => d >= 0), down = steps.every((d) => d <= 0);
495
+ 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}.`;
497
+ }
498
+ function cartesianAccess(o) {
499
+ const { data, categoryKey, series, format } = o;
500
+ const cats = data.map((row) => text(row[categoryKey]));
501
+ const last = data.length - 1;
502
+ const forecastFrom = o.forecast && o.forecast.from >= 0 && o.forecast.from < data.length ? o.forecast.from : -1;
503
+ const rows = data.map((row, i) => [
504
+ forecastFrom >= 0 && i >= forecastFrom ? `${cats[i]} (${o.forecast.label})` : cats[i],
505
+ ...series.map((s) => {
506
+ const v = numberOf(row[s.dataKey]);
507
+ return v === null ? "\u2013" : format(v, s.dataKey);
508
+ })
509
+ ]);
510
+ const runs = forecastFrom < last ? `${cats[forecastFrom]} to ${cats[last]}` : cats[forecastFrom];
511
+ const forecastNote = forecastFrom >= 0 ? `${o.forecast.label}: ${forecastFrom === 0 ? `every value (${runs})` : runs}` : null;
512
+ const notes = [
513
+ ...(o.references ?? []).map((r) => referenceNote(r, (v) => format(v))),
514
+ ...forecastNote ? [forecastNote] : []
515
+ ];
516
+ const names = series.map((s) => s.label);
517
+ 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
+ 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.`);
526
+ for (const note of notes) sentences.push(`${note}.`);
527
+ return {
528
+ table: { columns: [o.categoryHeading || "Category", ...names], numeric: [false, ...series.map(() => true)], rows, notes },
529
+ description: sentences.join(" ")
530
+ };
531
+ }
532
+ function partsAccess(o) {
533
+ const items = o.items.map((p) => ({ ...p, value: numberOf(p.value), max: numberOf(p.max) })).filter((p) => p.value !== null);
534
+ const f = (v) => o.format(v);
535
+ const total = items.reduce((sum, p) => sum + Math.max(0, p.value), 0);
536
+ const largest = items.reduce((a, b) => !a || b.value > a.value ? b : a, null);
537
+ const smallest = items.reduce((a, b) => !a || b.value < a.value ? b : a, null);
538
+ const grouped = o.kind === "treemap" && items.some((p) => p.group);
539
+ const withMax = o.kind === "radial" && items.some((p) => p.max !== null);
540
+ if (o.kind === "funnel") {
541
+ const first = items[0], last = items[items.length - 1];
542
+ return {
543
+ table: {
544
+ columns: ["Stage", "Value", "Of the first stage"],
545
+ numeric: [false, true, true],
546
+ rows: items.map((p) => [p.name, f(p.value), first && first.value > 0 ? percent(p.value, first.value) : "\u2013"]),
547
+ notes: []
548
+ },
549
+ // a first stage of nothing has no share to carry through
550
+ description: first && last && items.length > 1 ? `Funnel of ${items.length} stages, from ${first.name} (${f(first.value)}) to ${last.name} (${f(last.value)})${first.value > 0 ? `: ${percent(last.value, first.value)} of the first stage reach the last` : ""}.` : `Funnel of ${items.length} ${items.length === 1 ? "stage" : "stages"}.`
551
+ };
552
+ }
553
+ const columns = [...grouped ? ["Group"] : [], "Name", "Value", ...withMax ? ["Of its maximum"] : o.kind === "radial" ? [] : ["Share"]];
554
+ const rows = items.map((p) => [
555
+ ...grouped ? [p.group ?? ""] : [],
556
+ p.name,
557
+ f(p.value),
558
+ ...withMax ? [p.max !== null ? percent(p.value, p.max) : "\u2013"] : o.kind === "radial" ? [] : [percent(p.value, total)]
559
+ ]);
560
+ const what = o.kind === "pie" ? "Pie chart" : o.kind === "radial" ? "Radial bar chart" : "Treemap";
561
+ const unit = o.kind === "pie" ? "parts" : o.kind === "radial" ? "bars" : "items";
562
+ let description = `${what} of ${items.length} ${items.length === 1 ? unit.replace(/s$/, "") : unit}`;
563
+ const groups = new Set(items.map((p) => p.group)).size;
564
+ if (grouped) description += ` in ${groups} ${groups === 1 ? "group" : "groups"}`;
565
+ 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)}).`;
567
+ } else {
568
+ description += ".";
569
+ }
570
+ return {
571
+ table: { columns, numeric: columns.map((c) => c !== "Group" && c !== "Name"), rows, notes: [], rowHeader: grouped ? 1 : 0 },
572
+ description
573
+ };
574
+ }
575
+ function pointsAccess(o) {
576
+ const withZ = !!o.zHeading && o.series.some((s) => s.points.some((p) => numberOf(p.z) !== null));
577
+ const rows = [];
578
+ const xs = [];
579
+ const ys = [];
580
+ for (const s of o.series) {
581
+ for (const p of s.points) {
582
+ const x = numberOf(p.x), y = numberOf(p.y), z = numberOf(p.z);
583
+ if (x === null || y === null) continue;
584
+ xs.push(x);
585
+ ys.push(y);
586
+ rows.push([s.name, o.formatX(x), o.formatY(y), ...withZ ? [z !== null ? String(z) : "\u2013"] : []]);
587
+ }
588
+ }
589
+ const range = (vs, fmt) => vs.length ? `from ${fmt(Math.min(...vs))} to ${fmt(Math.max(...vs))}` : "";
590
+ return {
591
+ table: {
592
+ columns: ["Series", o.xHeading, o.yHeading, ...withZ ? [o.zHeading] : []],
593
+ numeric: [false, true, true, ...withZ ? [true] : []],
594
+ rows,
595
+ notes: []
596
+ },
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)}` : ""}.`
598
+ };
599
+ }
600
+ function flowAccess(o) {
601
+ const name = (i) => o.nodes[i]?.name ?? String(i);
602
+ const undrawn = new Set(o.undrawn ?? []);
603
+ const links = o.links.map((l) => ({ ...l, value: numberOf(l.value), drawn: !undrawn.has(l) })).filter((l) => l.value !== null);
604
+ const largest = links.filter((l) => l.drawn).reduce((a, b) => !a || b.value > a.value ? b : a, null);
605
+ const back = links.filter((l) => !l.drawn);
606
+ const backSaid = back.length === 1 ? ` The flow from ${name(back[0].source)} to ${name(back[0].target)} runs back, so it isn't drawn.` : back.length > 1 ? ` ${back.length} flows that run back aren't drawn.` : "";
607
+ return {
608
+ table: {
609
+ columns: ["From", "To", "Value"],
610
+ numeric: [false, false, true],
611
+ rows: links.map((l) => [name(l.source), name(l.target), o.format(l.value)]),
612
+ notes: back.map((l) => `Not drawn, as it runs back: ${name(l.source)} to ${name(l.target)} (${o.format(l.value)})`)
613
+ },
614
+ description: `Flow chart of ${links.length} ${links.length === 1 ? "flow" : "flows"} between ${o.nodes.length} ${o.nodes.length === 1 ? "point" : "points"}${largest ? `: the largest from ${name(largest.source)} to ${name(largest.target)} (${o.format(largest.value)})` : ""}.${backSaid}`
615
+ };
616
+ }
617
+ var GAP = 2;
618
+ var overlaps = (a, b) => a.x < b.x + b.width && b.x < a.x + a.width && a.y < b.y + b.height && b.y < a.y + a.height;
619
+ function placeNames(names) {
620
+ const placed = [];
621
+ const moves = /* @__PURE__ */ new Map();
622
+ for (const [id, box] of [...names].sort((a, b) => a[1].order - b[1].order)) {
623
+ const clear = (away) => {
624
+ let dy2 = 0;
625
+ for (let tries = 0; tries <= placed.length; tries++) {
626
+ const hit = placed.find((p) => overlaps({ ...box, y: box.y + dy2 }, p));
627
+ if (!hit) break;
628
+ dy2 = away > 0 ? hit.y + hit.height + GAP - box.y : hit.y - GAP - box.height - box.y;
629
+ }
630
+ return dy2;
631
+ };
632
+ const inside = (dy2) => !box.bounds || box.y + dy2 >= box.bounds.top - 0.5 && box.y + dy2 + box.height <= box.bounds.bottom + 0.5;
633
+ let dy = clear(box.away);
634
+ if (!inside(dy)) {
635
+ const other = clear(box.away > 0 ? -1 : 1);
636
+ if (inside(other)) dy = other;
637
+ }
638
+ moves.set(id, dy);
639
+ placed.push({ ...box, y: box.y + dy });
640
+ }
641
+ return moves;
642
+ }
643
+ var PlotNamesContext = createContext(null);
644
+ function PlotNames({ children }) {
645
+ const boxes = useRef(/* @__PURE__ */ new Map());
646
+ const [moves, setMoves] = useState(() => /* @__PURE__ */ new Map());
647
+ const place = useCallback((id, box) => {
648
+ if (box) boxes.current.set(id, box);
649
+ else boxes.current.delete(id);
650
+ const next = placeNames([...boxes.current]);
651
+ setMoves((prev) => prev.size === next.size && [...next].every(([k, v]) => prev.get(k) === v) ? prev : next);
652
+ }, []);
653
+ const value = useMemo(() => ({ place, moves }), [place, moves]);
654
+ return /* @__PURE__ */ jsx(PlotNamesContext.Provider, { value, children });
655
+ }
656
+ function markOf(index, marks) {
657
+ return (index + Math.floor(index / CHART_COLOR_COUNT)) % marks;
658
+ }
659
+ 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;
662
+ }
663
+ function lineDashes(lines) {
664
+ const marks = lines.map((line, i) => lines.length >= 2 ? markOf(i, DASHES.length) : line.dashed ? 1 : 0);
665
+ const colour = (i) => i % CHART_COLOR_COUNT;
666
+ const inColour = (i, k, ...but) => marks.some((m, j) => m === k && colour(j) === colour(i) && j !== i && !but.includes(j));
667
+ lines.forEach((line, i) => {
668
+ if (!line.dashed || marks[i] !== 0) return;
669
+ const free = DASHES.findIndex((_, k) => k > 0 && !marks.includes(k));
670
+ if (free > 0) {
671
+ marks[i] = free;
672
+ return;
673
+ }
674
+ const trade = lines.findIndex((other, j) => j !== i && !other.dashed && marks[j] !== 0 && !inColour(i, marks[j], j) && !inColour(j, 0, i));
675
+ if (trade >= 0) {
676
+ [marks[i], marks[trade]] = [marks[trade], 0];
677
+ return;
678
+ }
679
+ const own = DASHES.findIndex((_, k) => k > 0 && !inColour(i, k));
680
+ marks[i] = own > 0 ? own : 1;
681
+ });
682
+ return marks.map((k) => DASHES[k]);
683
+ }
684
+ var SYMBOLS = ["circle", "square", "triangle", "diamond", "cross", "star", "wye"];
685
+ function seriesSymbol(index, count) {
686
+ return count >= 2 ? SYMBOLS[index % SYMBOLS.length] : "circle";
687
+ }
688
+ 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;
692
+ }
693
+ function seriesPattern(chartId, index, count) {
694
+ if (seriesPatternKind(index, count) === void 0) return void 0;
695
+ return `${chartId.replace(/[^a-zA-Z0-9_-]/g, "")}-series-${index}`;
696
+ }
697
+ var aheadPattern = (id) => `${id}-ahead`;
698
+ function parseRgba(colour) {
699
+ const c = colour.trim();
700
+ const hex = /^#([0-9a-f]{3,4}|[0-9a-f]{6}|[0-9a-f]{8})$/i.exec(c)?.[1];
701
+ if (hex) {
702
+ const full = hex.length <= 4 ? [...hex].map((h) => h + h).join("") : hex;
703
+ const n = (k) => parseInt(full.slice(k * 2, k * 2 + 2), 16);
704
+ return [n(0), n(1), n(2), full.length === 8 ? n(3) / 255 : 1];
705
+ }
706
+ const fn = /^rgba?\(\s*([\d.]+)[\s,]+([\d.]+)[\s,]+([\d.]+)(?:\s*[,/]\s*([\d.]+%?))?\s*\)$/i.exec(c);
707
+ if (!fn) return null;
708
+ const alpha = fn[4] === void 0 ? 1 : fn[4].endsWith("%") ? parseFloat(fn[4]) / 100 : parseFloat(fn[4]);
709
+ return [Number(fn[1]), Number(fn[2]), Number(fn[3]), alpha];
710
+ }
711
+ var probe;
712
+ var drawnColours = /* @__PURE__ */ new Map();
713
+ var UNREAD = "rgba(1, 2, 3, 0.5)";
714
+ function drawn(colour, ground = [255, 255, 255]) {
715
+ const key = `${colour}|${ground.join(",")}`;
716
+ if (drawnColours.has(key)) return drawnColours.get(key);
717
+ let out = null;
718
+ const parsed = parseRgba(colour);
719
+ if (parsed) {
720
+ const [r, g, b, a] = parsed;
721
+ out = [r, g, b].map((v, i) => Math.round(v * a + ground[i] * (1 - a)));
722
+ } else {
723
+ if (probe === void 0) {
724
+ try {
725
+ probe = typeof document === "undefined" || /jsdom/i.test(navigator.userAgent) ? null : document.createElement("canvas").getContext("2d", { willReadFrequently: true });
726
+ } catch {
727
+ probe = null;
728
+ }
729
+ }
730
+ if (probe) {
731
+ probe.fillStyle = UNREAD;
732
+ const unread = probe.fillStyle;
733
+ probe.fillStyle = colour;
734
+ if (probe.fillStyle !== unread) {
735
+ probe.fillStyle = `rgb(${ground.join(",")})`;
736
+ probe.fillRect(0, 0, 1, 1);
737
+ probe.fillStyle = colour;
738
+ probe.fillRect(0, 0, 1, 1);
739
+ const d = probe.getImageData(0, 0, 1, 1).data;
740
+ out = [d[0], d[1], d[2]];
741
+ }
742
+ }
743
+ }
744
+ drawnColours.set(key, out);
745
+ return out;
746
+ }
747
+ var channel = (c) => c / 255 <= 0.04045 ? c / 255 / 12.92 : ((c / 255 + 0.055) / 1.055) ** 2.4;
748
+ var luminance = ([r, g, b]) => 0.2126 * channel(r) + 0.7152 * channel(g) + 0.0722 * channel(b);
749
+ function contrast(a, b) {
750
+ const [hi, lo] = [luminance(a), luminance(b)].sort((x, y) => y - x);
751
+ return (hi + 0.05) / (lo + 0.05);
752
+ }
753
+ var css = (c) => `rgb(${c.join(" ")})`;
754
+ function chartGround(surface, canvas) {
755
+ const page = drawn(canvas);
756
+ return page && drawn(surface, page);
757
+ }
758
+ function groundColour(surface, canvas) {
759
+ const ground = chartGround(surface, canvas);
760
+ return ground ? css(ground) : surface;
761
+ }
762
+ function markInk(fill, surface, ink, canvas) {
763
+ const ground = chartGround(surface, canvas);
764
+ const filled = ground && drawn(fill, ground);
765
+ const text2 = ground && drawn(ink, ground);
766
+ if (!ground || !filled || !text2) return surface;
767
+ const theme = contrast(filled, text2) >= contrast(filled, ground) ? text2 : ground;
768
+ if (contrast(filled, theme) >= 3) return css(theme);
769
+ return css(contrast(filled, [0, 0, 0]) >= contrast(filled, [255, 255, 255]) ? [0, 0, 0] : [255, 255, 255]);
770
+ }
771
+ var AHEAD_STRENGTH = 0.45;
772
+ function aheadFill(colour, surface, canvas) {
773
+ const ground = chartGround(surface, canvas);
774
+ const own = ground && drawn(colour, ground);
775
+ if (!ground || !own) return null;
776
+ return css(own.map((v, i) => Math.round(v * AHEAD_STRENGTH + ground[i] * (1 - AHEAD_STRENGTH))));
777
+ }
778
+ function Pattern({ id, kind, fill, on }) {
779
+ const mark = { stroke: on, strokeWidth: 1.5 };
780
+ return /* @__PURE__ */ jsxs("pattern", { id, width: 6, height: 6, patternUnits: "userSpaceOnUse", children: [
781
+ /* @__PURE__ */ jsx("rect", { width: 6, height: 6, fill }),
782
+ kind === 0 && /* @__PURE__ */ jsx("path", { d: "M-1,1 l2,-2 M0,6 l6,-6 M5,7 l2,-2", ...mark }),
783
+ kind === 1 && /* @__PURE__ */ jsx("circle", { cx: 3, cy: 3, r: 1.3, fill: on }),
784
+ kind === 2 && /* @__PURE__ */ jsx("path", { d: "M-1,1 l2,-2 M0,6 l6,-6 M5,7 l2,-2 M-1,5 l2,2 M0,0 l6,6 M5,-1 l2,2", ...mark, strokeWidth: 1 }),
785
+ kind === 3 && /* @__PURE__ */ jsx("path", { d: "M0,3 h6", ...mark }),
786
+ kind === 4 && /* @__PURE__ */ jsx("path", { d: "M3,0 v6", ...mark })
787
+ ] });
788
+ }
789
+ function SeriesPatterns({ chartId, colors, surface, ahead = false }) {
790
+ const ink = useResolvedToken("--ds-text-primary");
791
+ const canvas = useResolvedToken("--ds-bg-canvas");
792
+ if (colors.length < 2) return null;
793
+ return /* @__PURE__ */ jsx("defs", { children: colors.map((color, i) => {
794
+ const id = seriesPattern(chartId, i, colors.length);
795
+ const kind = seriesPatternKind(i, colors.length);
796
+ if (!id || kind === void 0) return null;
797
+ const faint = ahead ? aheadFill(color, surface, canvas) : null;
798
+ return [
799
+ /* @__PURE__ */ jsx(Pattern, { id, kind, fill: color, on: markInk(color, surface, ink, canvas) }, id),
800
+ faint && /* @__PURE__ */ jsx(Pattern, { id: aheadPattern(id), kind, fill: faint, on: markInk(faint, surface, ink, canvas) }, aheadPattern(id))
801
+ ];
802
+ }) });
803
+ }
804
+ function SeriesSwatch({ mark, color }) {
805
+ if (mark?.kind === "line") {
806
+ return /* @__PURE__ */ jsx("svg", { width: 18, height: 10, "aria-hidden": "true", className: "shrink-0", children: /* @__PURE__ */ jsx("line", { x1: 1, y1: 5, x2: 17, y2: 5, stroke: mark.color, strokeWidth: 2.5, strokeDasharray: mark.dash, strokeLinecap: "butt" }) });
807
+ }
808
+ if (mark?.kind === "symbol") {
809
+ return /* @__PURE__ */ jsx("svg", { width: 12, height: 12, "aria-hidden": "true", className: "shrink-0", children: /* @__PURE__ */ jsx(Symbols, { cx: 6, cy: 6, size: 60, type: mark.symbol, fill: mark.color }) });
810
+ }
811
+ const fill = mark?.kind === "fill" && mark.pattern ? `url(#${mark.pattern})` : mark?.color ?? color;
812
+ return /* @__PURE__ */ jsx("svg", { width: 12, height: 12, "aria-hidden": "true", className: "shrink-0", children: /* @__PURE__ */ jsx("rect", { x: 0.75, y: 0.75, width: 10.5, height: 10.5, rx: 2.5, fill, stroke: mark?.kind === "fill" && mark.edge || mark?.color || color, strokeWidth: 1.5 }) });
813
+ }
814
+ var isNumber2 = (v) => typeof v === "number" && Number.isFinite(v);
815
+ var OFFSET = 5;
816
+ function PlotName({ x = 0, y = 0, viewBox, value, id, order, place, ink }) {
817
+ const names = useContext(PlotNamesContext);
818
+ const plot = usePlotArea();
819
+ const surface = useResolvedToken("--ds-bg-surface");
820
+ const canvas = useResolvedToken("--ds-bg-canvas");
821
+ const halo = useMemo(() => groundColour(surface, canvas), [surface, canvas]);
822
+ const text2 = useRef(null);
823
+ const words = String(value ?? "");
824
+ const [size, setSize] = useState(null);
825
+ useLayoutEffect(() => {
826
+ const drawn2 = text2.current && typeof text2.current.getBBox === "function" ? text2.current.getBBox() : null;
827
+ const next = drawn2 && drawn2.width > 0 ? { width: drawn2.width, height: drawn2.height } : { width: words.length * 7, height: 14 };
828
+ setSize((prev) => prev && prev.width === next.width && prev.height === next.height ? prev : next);
829
+ }, [words]);
830
+ const line = { across: viewBox?.height === 0 && (viewBox?.width ?? 0) > 0, up: viewBox?.width === 0 && (viewBox?.height ?? 0) > 0 };
831
+ const top = place !== "insideBottomRight";
832
+ 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" };
834
+ const inside = (from, length, edge, span) => from < edge ? edge - from : from + length > edge + span ? Math.max(edge - from, edge + span - (from + length)) : 0;
835
+ const at = size && plot ? {
836
+ ...placed,
837
+ x: placed.x + inside(placed.start ? placed.x : placed.x - size.width, size.width, plot.x, plot.width),
838
+ y: placed.y + inside(placed.top ? placed.y : placed.y - size.height, size.height, plot.y, plot.height)
839
+ } : placed;
840
+ const register = names?.place;
841
+ const bounds = plot ? { top: plot.y, bottom: plot.y + plot.height } : void 0;
842
+ useLayoutEffect(() => {
843
+ if (!register || !size) return;
844
+ register(id, { x: at.start ? at.x : at.x - size.width, y: at.top ? at.y : at.y - size.height, ...size, order, away: at.top ? 1 : -1, ...bounds ? { bounds } : {} });
845
+ return () => register(id, null);
846
+ }, [register, id, at.x, at.y, at.top, at.start, size, order, bounds?.top, bounds?.bottom]);
847
+ const move = names?.moves.get(id) ?? 0;
848
+ return /* @__PURE__ */ jsx(ZIndexLayer, { zIndex: DefaultZIndexes.label, children: /* @__PURE__ */ jsx("g", { transform: move ? `translate(0 ${move})` : void 0, children: /* @__PURE__ */ jsx(
849
+ "text",
850
+ {
851
+ ref: text2,
852
+ className: "recharts-label",
853
+ "data-plot-name": "",
854
+ x: at.x,
855
+ y: at.y,
856
+ dy: at.top ? "0.71em" : void 0,
857
+ textAnchor: at.start ? "start" : "end",
858
+ fill: ink,
859
+ stroke: halo,
860
+ strokeWidth: 3,
861
+ strokeLinejoin: "round",
862
+ paintOrder: "stroke",
863
+ style: { fontSize: "var(--ds-font-size-xs)", fontFamily: "var(--ds-font-sans)" },
864
+ children: words
865
+ }
866
+ ) }) });
867
+ }
868
+ var nameLabel = (value, position, id, order, ink) => ({
869
+ value,
870
+ position,
871
+ content: /* @__PURE__ */ jsx(PlotName, { id, order, place: position, ink })
872
+ });
873
+ var onAxis = (look) => look.axisId === void 0 ? {} : look.axis === "y" ? { yAxisId: look.axisId } : { xAxisId: look.axisId };
874
+ function referenceElements(refs, look) {
875
+ return (refs ?? []).map((r, i) => {
876
+ const axisProps = onAxis(look);
877
+ if (isNumber2(r.to)) {
878
+ const span = look.axis === "y" ? { y1: Math.min(r.value, r.to), y2: Math.max(r.value, r.to) } : { x1: Math.min(r.value, r.to), x2: Math.max(r.value, r.to) };
879
+ return /* @__PURE__ */ jsx(
880
+ ReferenceArea,
881
+ {
882
+ ...span,
883
+ ...axisProps,
884
+ fill: look.ink,
885
+ fillOpacity: 0.1,
886
+ stroke: "none",
887
+ ifOverflow: "extendDomain",
888
+ label: nameLabel(r.label, look.axis === "y" ? "insideTopLeft" : "insideTopRight", `reference-${i}`, i, look.ink)
889
+ },
890
+ `reference-${i}`
891
+ );
892
+ }
893
+ return /* @__PURE__ */ jsx(
894
+ ReferenceLine,
895
+ {
896
+ ...look.axis === "y" ? { y: r.value } : { x: r.value },
897
+ ...axisProps,
898
+ stroke: look.ink,
899
+ strokeDasharray: "4 3",
900
+ strokeWidth: 1.5,
901
+ ifOverflow: "extendDomain",
902
+ label: nameLabel(`${r.label}: ${look.format(r.value)}`, look.axis === "y" ? "insideTopRight" : "insideBottomRight", `reference-${i}`, i, look.ink)
903
+ },
904
+ `reference-${i}`
905
+ );
906
+ });
907
+ }
908
+ function referenceValues(refs) {
909
+ return (refs ?? []).flatMap((r) => isNumber2(r.to) ? [r.value, r.to] : [r.value]);
910
+ }
911
+ function forecastIndex(data, categoryKey, from) {
912
+ if (from === void 0 || from === null) return -1;
913
+ return data.findIndex((row) => row[categoryKey] === from || String(row[categoryKey]) === String(from));
914
+ }
915
+ var forecastHatchId = (chartId) => `${chartId.replace(/[^a-zA-Z0-9_-]/g, "")}-forecast`;
916
+ function ForecastHatch({ id, ink }) {
917
+ return /* @__PURE__ */ jsx("defs", { children: /* @__PURE__ */ jsx("pattern", { id, width: 6, height: 6, patternUnits: "userSpaceOnUse", patternTransform: "rotate(45)", children: /* @__PURE__ */ jsx("line", { x1: 0, y1: 0, x2: 0, y2: 6, stroke: ink, strokeWidth: 1.5, strokeOpacity: 0.25 }) }) });
918
+ }
919
+ function forecastElements(categories, from, label, look) {
920
+ if (from < 0 || from >= categories.length || look.scale === "point" && categories.length < 2) return [];
921
+ const start = look.scale === "point" ? Math.max(0, from - 1) : from;
922
+ const first = categories[start], last = categories[categories.length - 1];
923
+ const span = look.scale === "point" ? (categories.length - 1 - start) / Math.max(1, categories.length - 1) : (categories.length - start) / categories.length;
924
+ const wide = span >= 0.25;
925
+ const elements = [
926
+ /* @__PURE__ */ jsx(
927
+ ReferenceArea,
928
+ {
929
+ ...look.axis === "y" ? { x1: first, x2: last } : { y1: first, y2: last },
930
+ ...onAxis(look),
931
+ fill: `url(#${look.hatch})`,
932
+ stroke: "none",
933
+ label: nameLabel(label, look.axis === "y" ? wide ? "insideTopLeft" : "insideTopRight" : wide ? "insideTopRight" : "insideBottomRight", "forecast", Number.MAX_SAFE_INTEGER, look.ink)
934
+ },
935
+ "forecast"
936
+ )
937
+ ];
938
+ if (from > 0) {
939
+ elements.push(
940
+ /* @__PURE__ */ jsx(
941
+ ReferenceLine,
942
+ {
943
+ ...look.axis === "y" ? { x: first } : { y: first },
944
+ ...onAxis(look),
945
+ position: look.scale === "band" ? "start" : void 0,
946
+ stroke: look.ink,
947
+ strokeDasharray: "2 3"
948
+ },
949
+ "forecast-start"
950
+ )
951
+ );
952
+ }
953
+ return elements;
954
+ }
955
+ function ChartTable({ table, name, labelledBy }) {
956
+ const [frame, setFrame] = useState(null);
957
+ 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
967
+ ),
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
+ ] });
984
+ }
384
985
  var CHART_HEIGHTS = {
385
986
  sm: "var(--ds-chart-height-sm)",
386
987
  md: "var(--ds-chart-height-md)",
@@ -450,17 +1051,22 @@ var ChartWrapper = forwardRef(function ChartWrapper2({
450
1051
  className,
451
1052
  children,
452
1053
  formatValue,
453
- "aria-label": ariaLabel
1054
+ "aria-label": ariaLabel,
1055
+ access,
1056
+ description,
1057
+ marks
454
1058
  }, ref) {
455
1059
  const container = useContext(ChartContainerContext);
456
1060
  const rootRef = useRef(null);
457
- const plotRef = useRef(null);
1061
+ const [plotEl, setPlotEl] = useState(null);
1062
+ const [view, setView] = useState("chart");
1063
+ const descriptionId = useId();
458
1064
  const [legend, setLegend] = useState(null);
459
1065
  const [live, setLive] = useState(null);
460
- const frame = useMemo(() => ({ legend, live, formatValue }), [legend, live, formatValue]);
461
- const [drawn, setDrawn] = useState(null);
1066
+ const frame = useMemo(() => ({ legend, live, formatValue, marks }), [legend, live, formatValue, marks]);
1067
+ const [drawn2, setDrawn] = useState(null);
462
1068
  useLayoutEffect(() => {
463
- const plot = plotRef.current;
1069
+ const plot = plotEl;
464
1070
  if (!plot || typeof ResizeObserver === "undefined") return;
465
1071
  const observer = new ResizeObserver((entries) => {
466
1072
  const box = entries[entries.length - 1]?.contentRect;
@@ -469,14 +1075,16 @@ var ChartWrapper = forwardRef(function ChartWrapper2({
469
1075
  });
470
1076
  observer.observe(plot);
471
1077
  return () => observer.disconnect();
472
- }, []);
1078
+ }, [plotEl]);
473
1079
  const fill = container?.fillArea === true;
474
1080
  const fixed = container?.height ?? fixedChartHeight(height);
475
1081
  const plotStyle = fill ? { flex: "1 1 0%", minHeight: 0 } : plotBoxStyle(size, fixed);
476
- const named = ariaLabel ? { role: "img", "aria-label": ariaLabel } : container?.titleId ? { role: "img", "aria-labelledby": container.titleId } : {};
1082
+ const sentence = description?.trim() ? description : access?.description;
1083
+ const describedBy = sentence ? { "aria-describedby": descriptionId } : {};
1084
+ const named = ariaLabel ? { role: "img", "aria-label": ariaLabel, ...describedBy } : container?.titleId ? { role: "img", "aria-labelledby": container.titleId, ...describedBy } : {};
477
1085
  useEffect(() => {
478
1086
  const root = rootRef.current;
479
- const plot = plotRef.current;
1087
+ const plot = plotEl;
480
1088
  if (!root || !plot || !categoryAxis || typeof MutationObserver === "undefined") return;
481
1089
  const selector = `.recharts-${categoryAxis}Axis-tick-labels .recharts-cartesian-axis-tick-value`;
482
1090
  const count = () => {
@@ -490,7 +1098,22 @@ var ChartWrapper = forwardRef(function ChartWrapper2({
490
1098
  const observer = new MutationObserver(count);
491
1099
  observer.observe(plot, { subtree: true, childList: true, characterData: true, attributes: true, attributeFilter: ["data-cut"] });
492
1100
  return () => observer.disconnect();
493
- }, [categoryAxis]);
1101
+ }, [categoryAxis, plotEl]);
1102
+ const register = container?.register;
1103
+ useLayoutEffect(() => register?.(), [register]);
1104
+ const switcher = access ? /* @__PURE__ */ jsx(FormChangeCtx, { value: null, children: /* @__PURE__ */ jsx(
1105
+ SegmentedControl,
1106
+ {
1107
+ size: "xs",
1108
+ "aria-label": `Show ${ariaLabel || container?.title || "the chart"} as`,
1109
+ value: view,
1110
+ onChange: (v) => setView(v === "table" ? "table" : "chart"),
1111
+ options: [{ value: "chart", label: "Chart" }, { value: "table", label: "Table" }]
1112
+ }
1113
+ ) }) : null;
1114
+ 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;
494
1117
  return /* @__PURE__ */ jsxs(
495
1118
  "div",
496
1119
  {
@@ -501,10 +1124,16 @@ var ChartWrapper = forwardRef(function ChartWrapper2({
501
1124
  className: cn("relative flex w-full flex-col", fill && "h-full", className),
502
1125
  style: { containerType: "inline-size", minInlineSize: "min(100%, 16rem)", ...fill ? {} : { flex: "1 0 auto" } },
503
1126
  children: [
504
- /* @__PURE__ */ jsxs(
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,
1129
+ !actions && switcher && /* @__PURE__ */ jsx("div", { className: "ml-auto shrink-0", children: switcher })
1130
+ ] }),
1131
+ !sentenceShown && sentenceLine,
1132
+ actions && switcher && createPortal(switcher, actions),
1133
+ view === "chart" || !access ? /* @__PURE__ */ jsxs(
505
1134
  "div",
506
1135
  {
507
- ref: plotRef,
1136
+ ref: setPlotEl,
508
1137
  "data-chart-plot": "",
509
1138
  className: "relative w-full",
510
1139
  style: plotStyle,
@@ -512,10 +1141,10 @@ var ChartWrapper = forwardRef(function ChartWrapper2({
512
1141
  ...named,
513
1142
  children: [
514
1143
  axisTitle && /* @__PURE__ */ jsx("span", { "data-chart-axis-title": "", className: "absolute left-0 top-0 whitespace-nowrap text-xs text-[var(--ds-text-muted)] font-[family-name:var(--ds-font-sans)] leading-normal", children: axisTitle }),
515
- /* @__PURE__ */ jsx("div", { className: "absolute inset-0", style: drawn ? { minWidth: drawn.width, minHeight: drawn.height } : void 0, children: /* @__PURE__ */ jsx(ChartFrameContext.Provider, { value: frame, children }) })
1144
+ /* @__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 }) }) })
516
1145
  ]
517
1146
  }
518
- ),
1147
+ ) : /* @__PURE__ */ jsx(ChartTable, { table: access.table, name: `${ariaLabel || container?.title || "The chart"}: values`, labelledBy: ariaLabel ? void 0 : container?.titleId }),
519
1148
  /* @__PURE__ */ jsx("div", { ref: setLegend, "data-chart-legend": "" }),
520
1149
  /* @__PURE__ */ jsx("div", { ref: setLive, role: "status", "aria-live": "polite", className: "sr-only" }),
521
1150
  /* @__PURE__ */ jsx(
@@ -531,76 +1160,6 @@ var ChartWrapper = forwardRef(function ChartWrapper2({
531
1160
  }
532
1161
  );
533
1162
  });
534
- var TICK_COUNT = 5;
535
- var TIME_UNITS = [["hour", 36e5], ["minute", 6e4], ["second", 1e3], ["millisecond", 1]];
536
- var BYTE_UNITS = [["petabyte", 1e15], ["terabyte", 1e12], ["gigabyte", 1e9], ["megabyte", 1e6], ["kilobyte", 1e3], ["byte", 1]];
537
- var MAX_FRACTION = 10;
538
- function exact(format, maxDigits = MAX_FRACTION) {
539
- for (let digits = 0; digits < maxDigits; digits++) {
540
- const label = format(digits);
541
- if (label === format(digits + 6)) return label;
542
- }
543
- return format(maxDigits);
544
- }
545
- var unitFormat = (unit, value, locale) => (digits) => new Intl.NumberFormat(locale, { style: "unit", unit, unitDisplay: "short", maximumFractionDigits: digits }).format(value);
546
- var unitsOf = (format) => format === "bytes" ? BYTE_UNITS : TIME_UNITS;
547
- function unitReached(units, value) {
548
- return units.find(([, size]) => Math.abs(value) >= size) ?? units[units.length - 1];
549
- }
550
- function axisUnit(units, ticks) {
551
- const largest = Math.max(0, ...ticks.map(Math.abs));
552
- const exactIn = (size) => ticks.every((t) => Math.abs(t / size * 100 - Math.round(t / size * 100)) < 1e-6);
553
- return units.find(([, size]) => largest / size >= 1 && exactIn(size)) ?? units[units.length - 1];
554
- }
555
- function valueAxisTicks(values) {
556
- const finite = values.filter(Number.isFinite);
557
- if (!finite.length) return [];
558
- const lo = Math.min(0, ...finite);
559
- const hi = Math.max(0, ...finite);
560
- if (lo === hi) return [lo];
561
- return getNiceTickValues([lo, hi], TICK_COUNT, true).map(Number);
562
- }
563
- function axisTickFormatter(values, format, locale) {
564
- if (typeof format === "function") return format;
565
- if (format === "percent") return (value) => exact((d) => new Intl.NumberFormat(locale, { style: "percent", maximumFractionDigits: d }).format(value / 100));
566
- if (format === "milliseconds" || format === "bytes") {
567
- const [unit, size] = axisUnit(unitsOf(format), valueAxisTicks(values));
568
- return (value) => exact(unitFormat(unit, value / size, locale));
569
- }
570
- const compact = (value) => exact((d) => new Intl.NumberFormat(locale, { notation: "compact", maximumFractionDigits: d }).format(value));
571
- const plain = (value) => exact((d) => new Intl.NumberFormat(locale, { maximumFractionDigits: d }).format(value));
572
- const largest = Math.max(0, ...values.filter(Number.isFinite).map(Math.abs));
573
- return largest >= COMPACT_FROM ? compact : plain;
574
- }
575
- var COMPACT_FROM = 1e4;
576
- function fullValueFormatter(format, locale) {
577
- if (typeof format === "function") return format;
578
- if (format === void 0 || format === "number") return (value) => value.toLocaleString(locale);
579
- if (format === "percent") return (value) => exact((d) => new Intl.NumberFormat(locale, { style: "percent", maximumFractionDigits: d }).format(value / 100), 4);
580
- return (value) => {
581
- const [unit, size] = unitReached(unitsOf(format), value);
582
- return exact(unitFormat(unit, value / size, locale), 4);
583
- };
584
- }
585
- function axisExtent(data, series) {
586
- return data.flatMap((row) => {
587
- const own = [];
588
- const up = /* @__PURE__ */ new Map();
589
- const down = /* @__PURE__ */ new Map();
590
- for (const s of series) {
591
- const raw = row[s.dataKey];
592
- const v = typeof raw === "number" ? raw : typeof raw === "string" && raw.trim() !== "" ? Number(raw) : NaN;
593
- if (!Number.isFinite(v)) continue;
594
- if (s.stack == null) own.push(v);
595
- else if (v >= 0) up.set(s.stack, (up.get(s.stack) ?? 0) + v);
596
- else down.set(s.stack, (down.get(s.stack) ?? 0) + v);
597
- }
598
- return [...own, ...up.values(), ...down.values()];
599
- });
600
- }
601
- function seriesValues(data, keys, stacked = false) {
602
- return axisExtent(data, keys.map((dataKey) => ({ dataKey, stack: stacked ? "stack" : null })));
603
- }
604
1163
  var hasLabel = (label) => label != null && label !== "" && typeof label !== "number";
605
1164
  var entryName = (entry, label) => !hasLabel(label) && typeof entry.payload?.name === "string" && entry.payload.name || entry.name;
606
1165
  var entryValue = (entry, format, locale) => typeof entry.value === "number" ? format ? format(entry.value, entry.dataKey) : entry.value.toLocaleString(locale) : entry.value;
@@ -617,12 +1176,15 @@ function tooltipAnnouncement(label, payload, format, locale = formatLocale()) {
617
1176
  const values = payload.map((entry) => `${entryName(entry, label)} ${entryValue(entry, format, locale)}`).join(", ");
618
1177
  return hasLabel(label) ? `${String(label)}: ${values}` : values;
619
1178
  }
1179
+ function plainColour(value) {
1180
+ return typeof value === "string" && value.trim() !== "" && !value.trim().startsWith("url(") ? value : void 0;
1181
+ }
620
1182
  function ChartTooltipContent({ active, payload, label }) {
621
1183
  const bgSurface = useResolvedToken("--ds-bg-surface");
622
1184
  const borderSubtle = useResolvedToken("--ds-border-subtle");
623
1185
  const textPrimary = useResolvedToken("--ds-text-primary");
624
1186
  const textSecondary = useResolvedToken("--ds-text-secondary");
625
- const { live, formatValue } = useContext(ChartFrameContext);
1187
+ const { live, formatValue, marks } = useContext(ChartFrameContext);
626
1188
  const locale = useFormatLocale();
627
1189
  const on = !!active && !!payload?.length;
628
1190
  const showLabel = hasLabel(label);
@@ -638,9 +1200,10 @@ function ChartTooltipContent({ active, payload, label }) {
638
1200
  children: [
639
1201
  showLabel && /* @__PURE__ */ jsx("p", { className: "font-medium mb-ds-1", style: { color: textPrimary }, children: label }),
640
1202
  payload.map((entry, i) => {
641
- const dotColor = entry.payload?.fill || entry.color || textSecondary;
1203
+ const dotColor = plainColour(entry.payload?.fill) ?? plainColour(entry.color) ?? textSecondary;
1204
+ const mark = (entry.graphicalItemId ? marks?.[entry.graphicalItemId] : void 0) ?? (entry.dataKey ? marks?.[entry.dataKey] : void 0) ?? marks?.[String(entry.name)] ?? marks?.[String(entry.payload?.name)];
642
1205
  return /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-ds-2", style: { marginTop: i > 0 ? 2 : 0 }, children: [
643
- /* @__PURE__ */ jsx(
1206
+ mark ? /* @__PURE__ */ jsx(SeriesSwatch, { mark, color: dotColor }) : /* @__PURE__ */ jsx(
644
1207
  "span",
645
1208
  {
646
1209
  className: "shrink-0 rounded-[var(--ds-radius-full)]",
@@ -671,17 +1234,22 @@ function swatchEdge(entry) {
671
1234
  }
672
1235
  function ChartLegendContent({ payload }) {
673
1236
  const textSecondary = useResolvedToken("--ds-text-secondary");
674
- if (!payload?.length) return null;
675
- return /* @__PURE__ */ jsx("div", { className: "flex flex-wrap justify-center gap-y-ds-1 gap-x-ds-4 font-[family-name:var(--ds-font-sans)] text-sm", children: payload.map((entry, i) => /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-ds-1.5", children: [
676
- /* @__PURE__ */ jsx(
677
- "span",
678
- {
679
- className: "shrink-0 rounded-[var(--ds-radius-full)]",
680
- style: { width: 10, height: 10, backgroundColor: entry.color, border: `1.5px solid ${swatchEdge(entry)}` }
681
- }
682
- ),
683
- /* @__PURE__ */ jsx("span", { style: { color: textSecondary }, children: entry.value })
684
- ] }, i)) });
1237
+ const { marks } = useContext(ChartFrameContext);
1238
+ const entries = payload?.filter((entry) => entry.type !== "none") ?? [];
1239
+ if (!entries.length) return null;
1240
+ return /* @__PURE__ */ jsx("div", { className: "flex flex-wrap justify-center gap-y-ds-1 gap-x-ds-4 font-[family-name:var(--ds-font-sans)] text-sm", children: entries.map((entry, i) => {
1241
+ const mark = (entry.dataKey ? marks?.[entry.dataKey] : void 0) ?? marks?.[entry.value];
1242
+ return /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-ds-1.5", children: [
1243
+ mark ? /* @__PURE__ */ jsx(SeriesSwatch, { mark, color: entry.color }) : /* @__PURE__ */ jsx(
1244
+ "span",
1245
+ {
1246
+ className: "shrink-0 rounded-[var(--ds-radius-full)]",
1247
+ style: { width: 10, height: 10, backgroundColor: entry.color, border: `1.5px solid ${swatchEdge(entry)}` }
1248
+ }
1249
+ ),
1250
+ /* @__PURE__ */ jsx("span", { "data-legend-label": "", style: { color: textSecondary }, children: entry.value })
1251
+ ] }, i);
1252
+ }) });
685
1253
  }
686
1254
  function seriesSorter(order, by = "dataKey") {
687
1255
  return (item) => {
@@ -726,17 +1294,17 @@ function xAxisTick(props) {
726
1294
  var LINE_EM = 1.2;
727
1295
  var NAME_GAP = 8;
728
1296
  var NAME_COLUMN_INSET = 12;
729
- function namesTick(measure, orientation, column) {
1297
+ function namesTick(measure2, orientation, column) {
730
1298
  return function NamesTick(props) {
731
1299
  const { x, y, payload, width, visibleTicksCount, className, fill, fontSize, fontFamily } = props;
732
1300
  const name = String(payload?.value ?? "");
733
1301
  const room = orientation === "x" ? (Number(width) || 0) / Math.max(1, Number(visibleTicksCount) || 1) - NAME_GAP : (column ?? (Number(width) || 0)) - NAME_COLUMN_INSET;
734
- const fit = fitLabel(name, room, measure);
735
- const text = { fill, fontSize, fontFamily, stroke: "none" };
1302
+ const fit = fitLabel(name, room, measure2);
1303
+ const text2 = { fill, fontSize, fontFamily, stroke: "none" };
736
1304
  const firstDy = orientation === "x" ? 0.71 : 0.355 - (fit.lines.length - 1) * LINE_EM / 2;
737
1305
  return /* @__PURE__ */ jsxs("g", { className, "data-cut": fit.cut ? "" : void 0, "data-lines": fit.lines.length, children: [
738
1306
  /* @__PURE__ */ jsx("title", { children: name }),
739
- fit.lines.map((line, i) => /* @__PURE__ */ jsx("text", { x, y, dy: `${firstDy + i * LINE_EM}em`, textAnchor: orientation === "x" ? "middle" : "end", ...text, children: line }, i))
1307
+ fit.lines.map((line, i) => /* @__PURE__ */ jsx("text", { x, y, dy: `${firstDy + i * LINE_EM}em`, textAnchor: orientation === "x" ? "middle" : "end", ...text2, children: line }, i))
740
1308
  ] });
741
1309
  };
742
1310
  }
@@ -750,8 +1318,8 @@ function useAxisMeasure(ref, enabled = true) {
750
1318
  const update = (fresh = false) => {
751
1319
  if (!live) return;
752
1320
  const measured = el.clientWidth;
753
- const probe = el.querySelector("[data-chart-probe]");
754
- const row = probe?.getBoundingClientRect().height ?? 0;
1321
+ const probe2 = el.querySelector("[data-chart-probe]");
1322
+ const row = probe2?.getBoundingClientRect().height ?? 0;
755
1323
  const next = createAxisMeasurer(el);
756
1324
  setState((prev) => {
757
1325
  const width = measured > 0 ? measured : prev.width;
@@ -779,10 +1347,10 @@ function useAxisMeasure(ref, enabled = true) {
779
1347
  }, [ref, enabled]);
780
1348
  return state;
781
1349
  }
782
- function valueAxisWidth(values, measure, format = String) {
1350
+ function valueAxisWidth(values, measure2, format = String) {
783
1351
  const ticks = valueAxisTicks(values);
784
- if (!ticks.length) return Math.ceil(measure(format(0))) + 8;
785
- return Math.ceil(Math.max(...ticks.map((t) => measure(format(t))))) + 8;
1352
+ if (!ticks.length) return Math.ceil(measure2(format(0))) + 8;
1353
+ return Math.ceil(Math.max(...ticks.map((t) => measure2(format(t))))) + 8;
786
1354
  }
787
1355
  var SWITCH_HYSTERESIS = 32;
788
1356
  function useSidewaysSwitch(enabled, names, m, axisWidth, sideMargins) {
@@ -862,7 +1430,7 @@ function anyStack(bars, stacked) {
862
1430
  function barGroups(bars, stacked) {
863
1431
  return Math.max(1, new Set(bars.map((bar, i) => barStackOf(bar, stacked) ?? `\0${i}`)).size);
864
1432
  }
865
- function barShape(bars, index, stacked, radius, horizontal = false) {
1433
+ function barShape(bars, index, stacked, radius, horizontal = false, forecast) {
866
1434
  const round = horizontal ? [0, radius, radius, 0] : [radius, radius, 0, 0];
867
1435
  const square = [0, 0, 0, 0];
868
1436
  const stack = barStackOf(bars[index], stacked);
@@ -875,7 +1443,8 @@ function barShape(bars, index, stacked, radius, horizontal = false) {
875
1443
  const value = Number(row[b.dataKey]);
876
1444
  return !(down ? value < 0 : value > 0);
877
1445
  });
878
- return /* @__PURE__ */ jsx(Rectangle, { ...withoutRowFields(props), radius: onTop ? round : square });
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 });
879
1448
  };
880
1449
  return Shape;
881
1450
  }
@@ -901,16 +1470,21 @@ var BarChart = markChart(forwardRef(function BarChart2({
901
1470
  valueFormat,
902
1471
  animated,
903
1472
  "aria-label": ariaLabel,
904
- className
1473
+ className,
1474
+ description,
1475
+ references,
1476
+ forecastFrom,
1477
+ forecastLabel = "Forecast"
905
1478
  }, ref) {
906
1479
  const wrapperRef = useRef(null);
1480
+ const chartId = useId();
907
1481
  const labels = useMemo(() => (data ?? []).map((d) => String(d[xAxisKey] ?? "")), [data, xAxisKey]);
908
1482
  const locale = useFormatLocale();
909
1483
  const hydrated = useHydrated();
910
1484
  const kind = categoryKind2 ?? categoryKind((data ?? []).map((d) => d[xAxisKey]), hydrated ? void 0 : locale);
911
1485
  const names = kind === "names";
912
1486
  const measured = useAxisMeasure(wrapperRef, (data?.length ?? 0) > 0);
913
- const values = useMemo(() => valueExtent(data ?? [], bars, stacked), [data, bars, stacked]);
1487
+ const values = useMemo(() => [...valueExtent(data ?? [], bars, stacked), ...referenceValues(references)], [data, bars, stacked, references]);
914
1488
  const tickFormat = useMemo(() => axisTickFormatter(values, valueFormat, locale), [values, valueFormat, locale]);
915
1489
  const fullFormat = useMemo(() => fullValueFormatter(valueFormat, locale), [valueFormat, locale]);
916
1490
  const axisWidth = useMemo(
@@ -946,6 +1520,31 @@ var BarChart = markChart(forwardRef(function BarChart2({
946
1520
  axis: titles ? `calc(${CHART_ROW} + ${titles} * ${TITLE_LINE_CSS})` : CHART_ROW
947
1521
  } : { model: "ratio" };
948
1522
  const maxBarSize = sideways ? Math.max(4, Math.round(measured.rowPx * perCategory * 0.7 / groups)) : void 0;
1523
+ const surface = useResolvedToken("--ds-bg-surface");
1524
+ const canvas = useResolvedToken("--ds-bg-canvas");
1525
+ const ink = useResolvedToken("--ds-text-secondary");
1526
+ const fills = bars.map((bar, i) => bar.soft ? softColors[i] : solidColors[i]);
1527
+ const patterns2 = bars.map((_, i) => seriesPattern(chartId, i, bars.length));
1528
+ const aheadBarFill = (fill, pattern) => {
1529
+ const faint = aheadFill(fill, surface, canvas);
1530
+ return faint && pattern ? `url(#${aheadPattern(pattern)})` : faint;
1531
+ };
1532
+ 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]
1535
+ );
1536
+ const forecastAt = forecastIndex(data ?? [], xAxisKey, forecastFrom);
1537
+ const access = useMemo(() => cartesianAccess({
1538
+ kind: "Bar chart",
1539
+ data: data ?? [],
1540
+ categoryKey: xAxisKey,
1541
+ categoryHeading: categoryTitle,
1542
+ series: bars.map((b) => ({ dataKey: b.dataKey, label: b.label ?? b.dataKey })),
1543
+ format: fullFormat,
1544
+ over: names ? "names" : "scale",
1545
+ references,
1546
+ forecast: forecastAt >= 0 ? { from: forecastAt, label: forecastLabel } : void 0
1547
+ }), [data, xAxisKey, categoryTitle, bars, fullFormat, names, references, forecastAt, forecastLabel]);
949
1548
  if (!data?.length) return null;
950
1549
  return /* @__PURE__ */ jsx(
951
1550
  ChartWrapper,
@@ -962,6 +1561,9 @@ var BarChart = markChart(forwardRef(function BarChart2({
962
1561
  formatValue: fullFormat,
963
1562
  className,
964
1563
  "aria-label": ariaLabel,
1564
+ access,
1565
+ description,
1566
+ marks,
965
1567
  children: /* @__PURE__ */ jsx(ResponsiveContainer, { width: "100%", height: "100%", children: /* @__PURE__ */ jsxs(
966
1568
  BarChart$1,
967
1569
  {
@@ -971,6 +1573,7 @@ var BarChart = markChart(forwardRef(function BarChart2({
971
1573
  margin: { top: 4 + (topTitle ? titleLine(measured.px) : 0), right: sideways || names ? 4 : xTicks.endMargin, bottom: 4, left: 4 },
972
1574
  accessibilityLayer: true,
973
1575
  children: [
1576
+ /* @__PURE__ */ jsx(SeriesPatterns, { chartId, colors: fills, surface, ahead: forecastAt >= 0 }),
974
1577
  showGrid && /* @__PURE__ */ jsx(CartesianGrid, { strokeDasharray: "3 3", stroke: gridStroke, vertical: !sideways, horizontal: true }),
975
1578
  sideways ? /* @__PURE__ */ jsxs(Fragment, { children: [
976
1579
  /* @__PURE__ */ jsx(XAxis, { type: "number", ...axisStyle.tick, axisLine: false, tickLine: false, height: "auto", label: bottomLabel, tickFormatter: tickFormat }),
@@ -1006,15 +1609,18 @@ var BarChart = markChart(forwardRef(function BarChart2({
1006
1609
  ] }),
1007
1610
  showTooltip && /* @__PURE__ */ jsx(Tooltip, { content: /* @__PURE__ */ jsx(ChartTooltipContent, {}), cursor: { fill: "var(--ds-bg-muted)", opacity: 0.5 } }),
1008
1611
  legendVisible && /* @__PURE__ */ jsx(ChartLegend, { order: bars.map((b) => b.dataKey) }),
1612
+ referenceElements(references, { axis: sideways ? "x" : "y", ink, format: (v) => fullFormat(v) }),
1613
+ forecastAt >= 0 && /* @__PURE__ */ jsx(ForecastHatch, { id: forecastHatchId(chartId), ink }),
1614
+ forecastElements(data.map((row) => row[xAxisKey]), forecastAt, forecastLabel, { axis: sideways ? "x" : "y", ink, scale: "band", hatch: forecastHatchId(chartId) }),
1009
1615
  bars.map((bar, i) => /* @__PURE__ */ jsx(
1010
1616
  Bar,
1011
1617
  {
1012
1618
  dataKey: bar.dataKey,
1013
1619
  name: bar.label ?? bar.dataKey,
1014
- fill: bar.soft ? softColors[i] : solidColors[i],
1620
+ fill: patterns2[i] ? `url(#${patterns2[i]})` : fills[i],
1015
1621
  stroke: bar.soft ? solidColors[i] : void 0,
1016
1622
  strokeWidth: bar.soft ? 1 : void 0,
1017
- shape: barShape(bars, i, stacked, radius, sideways),
1623
+ shape: barShape(bars, i, stacked, radius, sideways, forecastAt >= 0 ? { from: forecastAt, edge: solidColors[i], fill: aheadBarFill(fills[i], patterns2[i]) } : void 0),
1018
1624
  stackId: barStackOf(bar, stacked),
1019
1625
  maxBarSize,
1020
1626
  isAnimationActive: isAnimated
@@ -1043,10 +1649,14 @@ var LineChart = markChart(forwardRef(function LineChart2({
1043
1649
  valueFormat,
1044
1650
  animated,
1045
1651
  "aria-label": ariaLabel,
1046
- className
1652
+ className,
1653
+ description,
1654
+ references,
1655
+ forecastFrom,
1656
+ forecastLabel = "Forecast"
1047
1657
  }, ref) {
1048
1658
  const wrapperRef = useRef(null);
1049
- const values = useMemo(() => seriesValues(data ?? [], lines.map((s) => s.dataKey), false), [data, lines]);
1659
+ const values = useMemo(() => [...seriesValues(data ?? [], lines.map((s) => s.dataKey), false), ...referenceValues(references)], [data, lines, references]);
1050
1660
  const locale = useFormatLocale();
1051
1661
  const tickFormat = useMemo(() => axisTickFormatter(values, valueFormat, locale), [values, valueFormat, locale]);
1052
1662
  const fullFormat = useMemo(() => fullValueFormatter(valueFormat, locale), [valueFormat, locale]);
@@ -1059,6 +1669,25 @@ var LineChart = markChart(forwardRef(function LineChart2({
1059
1669
  const legendVisible = showLegend ?? lines.length >= 2;
1060
1670
  const axisLabelStyle = { fontSize: "var(--ds-font-size-xs)", fontFamily: "var(--ds-font-sans)", fill: axisStyle.tick.fill };
1061
1671
  const top = 4 + (yAxisLabel ? Math.ceil(measured.px * 1.5) + 4 : 0);
1672
+ const ink = useResolvedToken("--ds-text-secondary");
1673
+ const dashes = useMemo(() => lineDashes(lines), [lines]);
1674
+ const marks = useMemo(
1675
+ () => Object.fromEntries(lines.map((l, i) => [l.dataKey, { kind: "line", color: colors[i], dash: dashes[i] }])),
1676
+ [lines, colors, dashes]
1677
+ );
1678
+ const forecastAt = forecastIndex(data ?? [], xAxisKey, forecastFrom);
1679
+ const hatch = forecastHatchId(useId());
1680
+ const access = useMemo(() => cartesianAccess({
1681
+ kind: "Line chart",
1682
+ data: data ?? [],
1683
+ categoryKey: xAxisKey,
1684
+ categoryHeading: xAxisLabel,
1685
+ series: lines.map((l) => ({ dataKey: l.dataKey, label: l.label ?? l.dataKey })),
1686
+ format: fullFormat,
1687
+ over: "scale",
1688
+ references,
1689
+ forecast: forecastAt >= 0 ? { from: forecastAt, label: forecastLabel } : void 0
1690
+ }), [data, xAxisKey, xAxisLabel, lines, fullFormat, references, forecastAt, forecastLabel]);
1062
1691
  if (!data?.length) return null;
1063
1692
  return /* @__PURE__ */ jsx(
1064
1693
  ChartWrapper,
@@ -1074,6 +1703,9 @@ var LineChart = markChart(forwardRef(function LineChart2({
1074
1703
  formatValue: fullFormat,
1075
1704
  className,
1076
1705
  "aria-label": ariaLabel,
1706
+ access,
1707
+ description,
1708
+ marks,
1077
1709
  children: /* @__PURE__ */ jsx(ResponsiveContainer, { width: "100%", height: "100%", children: /* @__PURE__ */ jsxs(LineChart$1, { data, margin: { top, right: xTicks.endMargin, bottom: 4, left: 4 }, accessibilityLayer: true, children: [
1078
1710
  showGrid && /* @__PURE__ */ jsx(CartesianGrid, { strokeDasharray: "3 3", stroke: gridStroke }),
1079
1711
  /* @__PURE__ */ jsx(
@@ -1093,6 +1725,9 @@ var LineChart = markChart(forwardRef(function LineChart2({
1093
1725
  /* @__PURE__ */ jsx(YAxis, { width: "auto", ...axisStyle.tick, axisLine: false, tickLine: false, tickFormatter: tickFormat }),
1094
1726
  showTooltip && /* @__PURE__ */ jsx(Tooltip, { content: /* @__PURE__ */ jsx(ChartTooltipContent, {}) }),
1095
1727
  legendVisible && /* @__PURE__ */ jsx(ChartLegend, { order: lines.map((l) => l.dataKey) }),
1728
+ referenceElements(references, { axis: "y", ink, format: (v) => fullFormat(v) }),
1729
+ forecastAt >= 0 && /* @__PURE__ */ jsx(ForecastHatch, { id: hatch, ink }),
1730
+ forecastElements(data.map((row) => row[xAxisKey]), forecastAt, forecastLabel, { axis: "y", ink, scale: "point", hatch }),
1096
1731
  lines.map((line, i) => /* @__PURE__ */ jsx(
1097
1732
  Line,
1098
1733
  {
@@ -1101,7 +1736,7 @@ var LineChart = markChart(forwardRef(function LineChart2({
1101
1736
  name: line.label ?? line.dataKey,
1102
1737
  stroke: colors[i],
1103
1738
  strokeWidth: 2,
1104
- strokeDasharray: line.dashed ? "5 5" : void 0,
1739
+ strokeDasharray: dashes[i],
1105
1740
  dot: showDots,
1106
1741
  activeDot: { r: 5, strokeWidth: 2 },
1107
1742
  isAnimationActive: isAnimated
@@ -1129,10 +1764,14 @@ var AreaChart = markChart(forwardRef(function AreaChart2({
1129
1764
  valueFormat,
1130
1765
  animated,
1131
1766
  "aria-label": ariaLabel,
1132
- className
1767
+ className,
1768
+ description,
1769
+ references,
1770
+ forecastFrom,
1771
+ forecastLabel = "Forecast"
1133
1772
  }, ref) {
1134
1773
  const wrapperRef = useRef(null);
1135
- const values = useMemo(() => seriesValues(data ?? [], areas.map((s) => s.dataKey), stacked), [data, areas, stacked]);
1774
+ const values = useMemo(() => [...seriesValues(data ?? [], areas.map((s) => s.dataKey), stacked), ...referenceValues(references)], [data, areas, stacked, references]);
1136
1775
  const locale = useFormatLocale();
1137
1776
  const tickFormat = useMemo(() => axisTickFormatter(values, valueFormat, locale), [values, valueFormat, locale]);
1138
1777
  const fullFormat = useMemo(() => fullValueFormatter(valueFormat, locale), [valueFormat, locale]);
@@ -1147,6 +1786,25 @@ var AreaChart = markChart(forwardRef(function AreaChart2({
1147
1786
  const legendVisible = showLegend ?? areas.length >= 2;
1148
1787
  const axisLabelStyle = { fontSize: "var(--ds-font-size-xs)", fontFamily: "var(--ds-font-sans)", fill: axisStyle.tick.fill };
1149
1788
  const top = 4 + (yAxisLabel ? Math.ceil(measured.px * 1.5) + 4 : 0);
1789
+ const ink = useResolvedToken("--ds-text-secondary");
1790
+ const dashes = areas.map((_, i) => seriesDash(i, areas.length));
1791
+ 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]
1794
+ );
1795
+ const forecastAt = forecastIndex(data ?? [], xAxisKey, forecastFrom);
1796
+ const hatch = forecastHatchId(instanceId);
1797
+ const access = useMemo(() => cartesianAccess({
1798
+ kind: "Area chart",
1799
+ data: data ?? [],
1800
+ categoryKey: xAxisKey,
1801
+ categoryHeading: xAxisLabel,
1802
+ series: areas.map((a) => ({ dataKey: a.dataKey, label: a.label ?? a.dataKey })),
1803
+ format: fullFormat,
1804
+ over: "scale",
1805
+ references,
1806
+ forecast: forecastAt >= 0 ? { from: forecastAt, label: forecastLabel } : void 0
1807
+ }), [data, xAxisKey, xAxisLabel, areas, fullFormat, references, forecastAt, forecastLabel]);
1150
1808
  if (!data?.length) return null;
1151
1809
  return /* @__PURE__ */ jsx(
1152
1810
  ChartWrapper,
@@ -1162,6 +1820,9 @@ var AreaChart = markChart(forwardRef(function AreaChart2({
1162
1820
  formatValue: fullFormat,
1163
1821
  className,
1164
1822
  "aria-label": ariaLabel,
1823
+ access,
1824
+ description,
1825
+ marks,
1165
1826
  children: /* @__PURE__ */ jsx(ResponsiveContainer, { width: "100%", height: "100%", children: /* @__PURE__ */ jsxs(AreaChart$1, { data, margin: { top, right: xTicks.endMargin, bottom: 4, left: 4 }, accessibilityLayer: true, children: [
1166
1827
  /* @__PURE__ */ jsx("defs", { children: areas.map((area, i) => /* @__PURE__ */ jsxs("linearGradient", { id: `gradient-${instanceId}-${area.dataKey}`, x1: "0", y1: "0", x2: "0", y2: "1", children: [
1167
1828
  /* @__PURE__ */ jsx("stop", { offset: "0%", stopColor: softColors[i], stopOpacity: 1 }),
@@ -1185,6 +1846,9 @@ var AreaChart = markChart(forwardRef(function AreaChart2({
1185
1846
  /* @__PURE__ */ jsx(YAxis, { width: "auto", ...axisStyle.tick, axisLine: false, tickLine: false, tickFormatter: tickFormat }),
1186
1847
  showTooltip && /* @__PURE__ */ jsx(Tooltip, { content: /* @__PURE__ */ jsx(ChartTooltipContent, {}) }),
1187
1848
  legendVisible && /* @__PURE__ */ jsx(ChartLegend, { order: areas.map((a) => a.dataKey) }),
1849
+ referenceElements(references, { axis: "y", ink, format: (v) => fullFormat(v) }),
1850
+ forecastAt >= 0 && /* @__PURE__ */ jsx(ForecastHatch, { id: hatch, ink }),
1851
+ forecastElements(data.map((row) => row[xAxisKey]), forecastAt, forecastLabel, { axis: "y", ink, scale: "point", hatch }),
1188
1852
  areas.map((area, i) => /* @__PURE__ */ jsx(
1189
1853
  Area,
1190
1854
  {
@@ -1193,6 +1857,7 @@ var AreaChart = markChart(forwardRef(function AreaChart2({
1193
1857
  name: area.label ?? area.dataKey,
1194
1858
  stroke: solidColors[i],
1195
1859
  strokeWidth: 2,
1860
+ strokeDasharray: dashes[i],
1196
1861
  fill: gradient ? `url(#gradient-${instanceId}-${area.dataKey})` : softColors[i],
1197
1862
  stackId: stacked ? "stack" : void 0,
1198
1863
  isAnimationActive: isAnimated
@@ -1212,14 +1877,26 @@ var PieChart = markChart(forwardRef(function PieChart2({
1212
1877
  showLabels = false,
1213
1878
  animated,
1214
1879
  "aria-label": ariaLabel,
1215
- className
1880
+ className,
1881
+ description
1216
1882
  }, ref) {
1217
1883
  const colors = useChartColors(data.length, false);
1884
+ const chartId = useId();
1885
+ const surface = useResolvedToken("--ds-bg-surface");
1886
+ const locale = useFormatLocale();
1887
+ const format = useMemo(() => fullValueFormatter(void 0, locale), [locale]);
1218
1888
  const isAnimated = useChartAnimation(animated);
1219
- const renderLabel = showLabels ? ({ percent }) => `${((percent ?? 0) * 100).toFixed(0)}%` : false;
1220
- const chartData = data.map((d) => ({ name: d.name, value: d.value }));
1889
+ const renderLabel = showLabels ? ({ percent: percent2 }) => `${((percent2 ?? 0) * 100).toFixed(0)}%` : false;
1890
+ const chartData = data.map((d) => ({ name: d.name, value: numberOf(d.value) ?? 0 }));
1891
+ const fills = data.map((_, i) => colors[i % colors.length]);
1892
+ 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]
1895
+ );
1896
+ const access = useMemo(() => partsAccess({ kind: "pie", items: data.map((d) => ({ name: d.name, value: d.value })), format }), [data, format]);
1221
1897
  if (!data?.length) return null;
1222
- return /* @__PURE__ */ jsx(ChartWrapper, { ref, height, size: { model: "square" }, chart: "pie", className, "aria-label": ariaLabel, children: /* @__PURE__ */ jsx(ResponsiveContainer, { width: "100%", height: "100%", children: /* @__PURE__ */ jsxs(PieChart$1, { accessibilityLayer: true, children: [
1898
+ 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 }),
1223
1900
  /* @__PURE__ */ jsx(
1224
1901
  Pie,
1225
1902
  {
@@ -1235,7 +1912,10 @@ var PieChart = markChart(forwardRef(function PieChart2({
1235
1912
  isAnimationActive: isAnimated,
1236
1913
  fontSize: "var(--ds-font-size-xs)",
1237
1914
  fontFamily: "var(--ds-font-sans)",
1238
- children: data.map((_, i) => /* @__PURE__ */ jsx(Cell, { fill: colors[i % colors.length] }, i))
1915
+ children: data.map((_, i) => {
1916
+ const pattern = seriesPattern(chartId, i, data.length);
1917
+ return /* @__PURE__ */ jsx(Cell, { fill: pattern ? `url(#${pattern})` : fills[i] }, i);
1918
+ })
1239
1919
  }
1240
1920
  ),
1241
1921
  showTooltip && /* @__PURE__ */ jsx(Tooltip, { content: /* @__PURE__ */ jsx(ChartTooltipContent, {}) }),
@@ -1262,9 +1942,14 @@ var CompositeChart = markChart(forwardRef(function CompositeChart2({
1262
1942
  lineValueFormat = valueFormat,
1263
1943
  animated,
1264
1944
  "aria-label": ariaLabel,
1265
- className
1945
+ className,
1946
+ description,
1947
+ references,
1948
+ forecastFrom,
1949
+ forecastLabel = "Forecast"
1266
1950
  }, ref) {
1267
1951
  const wrapperRef = useRef(null);
1952
+ const chartId = useId();
1268
1953
  const labels = useMemo(() => (data ?? []).map((d) => String(d[xAxisKey] ?? "")), [data, xAxisKey]);
1269
1954
  const locale = useFormatLocale();
1270
1955
  const hydrated = useHydrated();
@@ -1277,8 +1962,9 @@ var CompositeChart = markChart(forwardRef(function CompositeChart2({
1277
1962
  ...dualAxis ? [] : lines.map((l) => ({ dataKey: l.dataKey, stack: null }))
1278
1963
  ]);
1279
1964
  const lineValues2 = (data ?? []).flatMap((row) => lines.map((l) => Number(row[l.dataKey])));
1280
- return [values2, lineValues2];
1281
- }, [data, bars, lines, stacked, dualAxis]);
1965
+ const onLines = !bars.length && dualAxis;
1966
+ return [[...values2, ...onLines ? [] : referenceValues(references)], [...lineValues2, ...onLines ? referenceValues(references) : []]];
1967
+ }, [data, bars, lines, stacked, dualAxis, references]);
1282
1968
  const tickFormat = useMemo(() => axisTickFormatter(values, valueFormat, locale), [values, valueFormat, locale]);
1283
1969
  const lineTickFormat = useMemo(() => axisTickFormatter(lineValues, lineValueFormat, locale), [lineValues, lineValueFormat, locale]);
1284
1970
  const fullFormat = useMemo(() => {
@@ -1321,6 +2007,32 @@ var CompositeChart = markChart(forwardRef(function CompositeChart2({
1321
2007
  const maxBarSize = sideways ? Math.max(4, Math.round(measured.rowPx * perCategory * 0.7 / groups)) : void 0;
1322
2008
  const barAxis = sideways ? { xAxisId: "left" } : { yAxisId: "left" };
1323
2009
  const lineAxis = sideways ? { xAxisId: dualAxis ? "right" : "left" } : { yAxisId: dualAxis ? "right" : "left" };
2010
+ const valueAxisId = bars.length || !dualAxis ? "left" : "right";
2011
+ const surface = useResolvedToken("--ds-bg-surface");
2012
+ const canvas = useResolvedToken("--ds-bg-canvas");
2013
+ const ink = useResolvedToken("--ds-text-secondary");
2014
+ const patterns2 = bars.map((_, i) => seriesPattern(chartId, i, bars.length));
2015
+ const aheadBarFill = (fill, pattern) => {
2016
+ const faint = aheadFill(fill, surface, canvas);
2017
+ return faint && pattern ? `url(#${aheadPattern(pattern)})` : faint;
2018
+ };
2019
+ const dashes = useMemo(() => lineDashes(lines), [lines]);
2020
+ 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) }]),
2022
+ ...lines.map((line, i) => [line.dataKey, { kind: "line", color: lineColors[i], dash: dashes[i] }])
2023
+ ]), [bars, lines, barSoftColors, barSolidColors, lineColors, chartId, dashes]);
2024
+ const forecastAt = forecastIndex(data ?? [], xAxisKey, forecastFrom);
2025
+ const access = useMemo(() => cartesianAccess({
2026
+ kind: "Bar and line chart",
2027
+ data: data ?? [],
2028
+ categoryKey: xAxisKey,
2029
+ categoryHeading: xAxisLabel,
2030
+ series: [...bars, ...lines].map((s) => ({ dataKey: s.dataKey, label: s.label ?? s.dataKey })),
2031
+ format: fullFormat,
2032
+ over: names ? "names" : "scale",
2033
+ references,
2034
+ forecast: forecastAt >= 0 ? { from: forecastAt, label: forecastLabel } : void 0
2035
+ }), [data, xAxisKey, xAxisLabel, bars, lines, fullFormat, names, references, forecastAt, forecastLabel]);
1324
2036
  if (!data?.length) return null;
1325
2037
  return /* @__PURE__ */ jsx(
1326
2038
  ChartWrapper,
@@ -1337,6 +2049,9 @@ var CompositeChart = markChart(forwardRef(function CompositeChart2({
1337
2049
  formatValue: fullFormat,
1338
2050
  className,
1339
2051
  "aria-label": ariaLabel,
2052
+ access,
2053
+ description,
2054
+ marks,
1340
2055
  children: /* @__PURE__ */ jsx(ResponsiveContainer, { width: "100%", height: "100%", children: /* @__PURE__ */ jsxs(
1341
2056
  ComposedChart,
1342
2057
  {
@@ -1346,6 +2061,7 @@ var CompositeChart = markChart(forwardRef(function CompositeChart2({
1346
2061
  margin: { top, right: sideways || names ? 4 : xTicks.endMargin, bottom: 4, left: 4 },
1347
2062
  accessibilityLayer: true,
1348
2063
  children: [
2064
+ /* @__PURE__ */ jsx(SeriesPatterns, { chartId, colors: barSoftColors, surface, ahead: forecastAt >= 0 }),
1349
2065
  showGrid && /* @__PURE__ */ jsx(CartesianGrid, { strokeDasharray: "3 3", stroke: gridStroke, vertical: !sideways, horizontal: true }),
1350
2066
  sideways ? /* @__PURE__ */ jsxs(Fragment, { children: [
1351
2067
  /* @__PURE__ */ jsx(XAxis, { xAxisId: "left", type: "number", ...axisStyle.tick, axisLine: false, tickLine: false, height: "auto", label: bottomLabel, tickFormatter: tickFormat }),
@@ -1383,15 +2099,18 @@ var CompositeChart = markChart(forwardRef(function CompositeChart2({
1383
2099
  ] }),
1384
2100
  showTooltip && /* @__PURE__ */ jsx(Tooltip, { content: /* @__PURE__ */ jsx(ChartTooltipContent, {}) }),
1385
2101
  showLegend && /* @__PURE__ */ jsx(ChartLegend, { order: [...bars.map((b) => b.dataKey), ...lines.map((l) => l.dataKey)] }),
2102
+ referenceElements(references, { axis: sideways ? "x" : "y", axisId: valueAxisId, ink, format: (v) => fullFormat(v, valueAxisId === "right" ? lines[0]?.dataKey : void 0) }),
2103
+ forecastAt >= 0 && /* @__PURE__ */ jsx(ForecastHatch, { id: forecastHatchId(chartId), ink }),
2104
+ forecastElements(data.map((row) => row[xAxisKey]), forecastAt, forecastLabel, { axis: sideways ? "x" : "y", axisId: valueAxisId, ink, scale: bars.length ? "band" : "point", hatch: forecastHatchId(chartId) }),
1386
2105
  bars.map((bar, i) => /* @__PURE__ */ jsx(
1387
2106
  Bar,
1388
2107
  {
1389
2108
  dataKey: bar.dataKey,
1390
2109
  name: bar.label ?? bar.dataKey,
1391
- fill: barSoftColors[i],
2110
+ fill: patterns2[i] ? `url(#${patterns2[i]})` : barSoftColors[i],
1392
2111
  stroke: barSolidColors[i],
1393
2112
  strokeWidth: 1,
1394
- shape: barShape(bars, i, stacked, radius, sideways),
2113
+ shape: barShape(bars, i, stacked, radius, sideways, forecastAt >= 0 ? { from: forecastAt, edge: barSolidColors[i], fill: aheadBarFill(barSoftColors[i], patterns2[i]) } : void 0),
1395
2114
  stackId: barStackOf(bar, stacked),
1396
2115
  maxBarSize,
1397
2116
  ...barAxis,
@@ -1407,7 +2126,7 @@ var CompositeChart = markChart(forwardRef(function CompositeChart2({
1407
2126
  name: line.label ?? line.dataKey,
1408
2127
  stroke: lineColors[i],
1409
2128
  strokeWidth: 2,
1410
- strokeDasharray: line.dashed ? "5 5" : void 0,
2129
+ strokeDasharray: dashes[i],
1411
2130
  dot: false,
1412
2131
  ...lineAxis,
1413
2132
  isAnimationActive: isAnimated
@@ -1432,7 +2151,8 @@ var ScatterChart = markChart(forwardRef(function ScatterChart2({
1432
2151
  xValueFormat,
1433
2152
  animated,
1434
2153
  "aria-label": ariaLabel,
1435
- className
2154
+ className,
2155
+ description
1436
2156
  }, ref) {
1437
2157
  const wrapperRef = useRef(null);
1438
2158
  const locale = useFormatLocale();
@@ -1453,6 +2173,23 @@ var ScatterChart = markChart(forwardRef(function ScatterChart2({
1453
2173
  const isAnimated = useChartAnimation(animated);
1454
2174
  const legendVisible = showLegend ?? data.length >= 2;
1455
2175
  const axisLabelStyle = { fontSize: "var(--ds-font-size-xs)", fontFamily: "var(--ds-font-sans)", fill: axisStyle.tick.fill };
2176
+ const seriesId = useId();
2177
+ const idOf = (i) => `${seriesId}-scatter-${i}`;
2178
+ const marks = useMemo(
2179
+ () => Object.fromEntries((data ?? []).flatMap((s, i) => {
2180
+ const mark = { kind: "symbol", color: colors[i], symbol: seriesSymbol(i, data.length) };
2181
+ return [[s.name, mark], [`${seriesId}-scatter-${i}`, mark]];
2182
+ })),
2183
+ [data, colors, seriesId]
2184
+ );
2185
+ const access = useMemo(() => pointsAccess({
2186
+ series: data ?? [],
2187
+ xHeading: xLabel ?? "x",
2188
+ yHeading: yLabel ?? "y",
2189
+ zHeading: "Size",
2190
+ formatX: (v) => fullFormat(v, "x"),
2191
+ formatY: (v) => fullFormat(v, "y")
2192
+ }), [data, xLabel, yLabel, fullFormat]);
1456
2193
  if (!data?.length) return null;
1457
2194
  return /* @__PURE__ */ jsx(
1458
2195
  ChartWrapper,
@@ -1465,6 +2202,9 @@ var ScatterChart = markChart(forwardRef(function ScatterChart2({
1465
2202
  formatValue: fullFormat,
1466
2203
  className,
1467
2204
  "aria-label": ariaLabel,
2205
+ access,
2206
+ description,
2207
+ marks,
1468
2208
  children: /* @__PURE__ */ jsx(ResponsiveContainer, { width: "100%", height: "100%", children: /* @__PURE__ */ jsxs(
1469
2209
  ScatterChart$1,
1470
2210
  {
@@ -1504,11 +2244,12 @@ var ScatterChart = markChart(forwardRef(function ScatterChart2({
1504
2244
  data.map((series, i) => /* @__PURE__ */ jsx(
1505
2245
  Scatter,
1506
2246
  {
2247
+ id: idOf(i),
1507
2248
  name: series.name,
1508
2249
  data: series.points,
1509
2250
  fill: colors[i],
1510
2251
  isAnimationActive: isAnimated,
1511
- shape: (p) => /* @__PURE__ */ jsx(Symbols, { ...withoutRowFields(p), type: "circle" })
2252
+ shape: (p) => /* @__PURE__ */ jsx(Symbols, { ...withoutRowFields(p), type: seriesSymbol(i, data.length) })
1512
2253
  },
1513
2254
  series.name
1514
2255
  ))
@@ -1530,7 +2271,8 @@ var RadarChart = markChart(forwardRef(function RadarChart2({
1530
2271
  animated,
1531
2272
  valueFormat = "number",
1532
2273
  "aria-label": ariaLabel,
1533
- className
2274
+ className,
2275
+ description
1534
2276
  }, ref) {
1535
2277
  const solidColors = useChartColors(dataKeys.length, false);
1536
2278
  const softColors = useChartColors(dataKeys.length, true);
@@ -1540,8 +2282,21 @@ var RadarChart = markChart(forwardRef(function RadarChart2({
1540
2282
  const locale = useFormatLocale();
1541
2283
  const tickFormat = useMemo(() => axisTickFormatter(values, valueFormat, locale), [values, valueFormat, locale]);
1542
2284
  const fullFormat = useMemo(() => fullValueFormatter(valueFormat, locale), [valueFormat, locale]);
2285
+ const dashes = dataKeys.map((_, i) => seriesDash(i, dataKeys.length));
2286
+ 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]
2289
+ );
2290
+ const access = useMemo(() => cartesianAccess({
2291
+ kind: "Radar chart",
2292
+ data: data ?? [],
2293
+ categoryKey: axisKey,
2294
+ series: dataKeys.map((dk) => ({ dataKey: dk.key, label: dk.label ?? dk.key })),
2295
+ format: fullFormat,
2296
+ over: "names"
2297
+ }), [data, axisKey, dataKeys, fullFormat]);
1543
2298
  if (!data?.length) return null;
1544
- return /* @__PURE__ */ jsx(ChartWrapper, { ref, height, size: { model: "square" }, chart: "radar", className, "aria-label": ariaLabel, formatValue: fullFormat, children: /* @__PURE__ */ jsx(ResponsiveContainer, { width: "100%", height: "100%", children: /* @__PURE__ */ jsxs(RadarChart$1, { data, cx: "50%", cy: "50%", outerRadius: "75%", accessibilityLayer: true, children: [
2299
+ return /* @__PURE__ */ jsx(ChartWrapper, { ref, height, size: { model: "square" }, chart: "radar", className, "aria-label": ariaLabel, formatValue: fullFormat, access, description, marks, children: /* @__PURE__ */ jsx(ResponsiveContainer, { width: "100%", height: "100%", children: /* @__PURE__ */ jsxs(RadarChart$1, { data, cx: "50%", cy: "50%", outerRadius: "75%", accessibilityLayer: true, children: [
1545
2300
  /* @__PURE__ */ jsx(PolarGrid, { stroke: "var(--ds-border-subtle)" }),
1546
2301
  /* @__PURE__ */ jsx(
1547
2302
  PolarAngleAxis,
@@ -1568,6 +2323,7 @@ var RadarChart = markChart(forwardRef(function RadarChart2({
1568
2323
  stroke: solidColors[i],
1569
2324
  fill: filled ? softColors[i] : "transparent",
1570
2325
  strokeWidth: 2,
2326
+ strokeDasharray: dashes[i],
1571
2327
  dot: showDots ? { r: 3, fill: solidColors[i] } : false,
1572
2328
  isAnimationActive: isAnimated
1573
2329
  },
@@ -1585,18 +2341,30 @@ var RadialBarChart = markChart(forwardRef(function RadialBarChart2({
1585
2341
  endAngle = -270,
1586
2342
  animated,
1587
2343
  "aria-label": ariaLabel,
1588
- className
2344
+ className,
2345
+ description
1589
2346
  }, ref) {
1590
2347
  const colors = useChartColors(data.length, false);
2348
+ const chartId = useId();
2349
+ const surface = useResolvedToken("--ds-bg-surface");
2350
+ const locale = useFormatLocale();
2351
+ const format = useMemo(() => fullValueFormatter(void 0, locale), [locale]);
1591
2352
  const isAnimated = useChartAnimation(animated);
1592
2353
  const chartData = data.map((d, i) => ({
1593
2354
  name: d.name,
1594
- value: d.value,
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,
1595
2357
  ...d.max !== void 0 ? { max: d.max } : {},
1596
- fill: colors[i % colors.length]
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]
1597
2360
  }));
2361
+ 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]
2364
+ );
2365
+ 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]);
1598
2366
  if (!data?.length) return null;
1599
- return /* @__PURE__ */ jsx(ChartWrapper, { ref, height, size: { model: "square" }, chart: "radial-bar", className, "aria-label": ariaLabel, children: /* @__PURE__ */ jsx(ResponsiveContainer, { width: "100%", height: "100%", children: /* @__PURE__ */ jsxs(
2367
+ return /* @__PURE__ */ jsx(ChartWrapper, { ref, height, size: { model: "square" }, chart: "radial-bar", className, "aria-label": ariaLabel, access, description, marks, children: /* @__PURE__ */ jsx(ResponsiveContainer, { width: "100%", height: "100%", children: /* @__PURE__ */ jsxs(
1600
2368
  RadialBarChart$1,
1601
2369
  {
1602
2370
  data: chartData,
@@ -1608,6 +2376,7 @@ var RadialBarChart = markChart(forwardRef(function RadialBarChart2({
1608
2376
  endAngle,
1609
2377
  accessibilityLayer: true,
1610
2378
  children: [
2379
+ /* @__PURE__ */ jsx(SeriesPatterns, { chartId, colors: data.map((_, i) => colors[i % colors.length]), surface }),
1611
2380
  /* @__PURE__ */ jsx(
1612
2381
  RadialBar,
1613
2382
  {
@@ -1631,17 +2400,21 @@ var FunnelChart = markChart(forwardRef(function FunnelChart2({
1631
2400
  showLabels = true,
1632
2401
  animated,
1633
2402
  "aria-label": ariaLabel,
1634
- className
2403
+ className,
2404
+ description
1635
2405
  }, ref) {
1636
2406
  const colors = useChartColors(data.length, false);
2407
+ const locale = useFormatLocale();
2408
+ const format = useMemo(() => fullValueFormatter(void 0, locale), [locale]);
2409
+ const access = useMemo(() => partsAccess({ kind: "funnel", items: data.map((d) => ({ name: d.name, value: d.value })), format }), [data, format]);
1637
2410
  const isAnimated = useChartAnimation(animated);
1638
2411
  const chartData = data.map((d, i) => ({
1639
2412
  name: d.name,
1640
- value: d.value,
2413
+ value: numberOf(d.value) ?? 0,
1641
2414
  fill: colors[i % colors.length]
1642
2415
  }));
1643
2416
  if (!data?.length) return null;
1644
- return /* @__PURE__ */ jsx(ChartWrapper, { ref, height, size: { model: "rows", units: data.length * STAGE_ROWS, axis: "16px" }, chart: "funnel", className, "aria-label": ariaLabel, children: /* @__PURE__ */ jsx(ResponsiveContainer, { width: "100%", height: "100%", children: /* @__PURE__ */ jsxs(FunnelChart$1, { accessibilityLayer: true, children: [
2417
+ 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: [
1645
2418
  /* @__PURE__ */ jsx(Funnel, { dataKey: "value", data: chartData, isAnimationActive: isAnimated, children: showLabels && /* @__PURE__ */ jsx(
1646
2419
  LabelList,
1647
2420
  {
@@ -1727,9 +2500,9 @@ var TINT_L_MIN = 0.1;
1727
2500
  var TINT_L_STEP = 0.01;
1728
2501
  var WHITE_RANGE = [1, 1];
1729
2502
  var DARK_RANGE = luminanceRange(DARK_TEXT_CANDIDATE);
1730
- function minContrast(text, fills) {
2503
+ function minContrast(text2, fills) {
1731
2504
  let min = Infinity;
1732
- for (const f of fills) min = Math.min(min, worstContrastOf(text, luminanceRange(f)));
2505
+ for (const f of fills) min = Math.min(min, worstContrastOf(text2, luminanceRange(f)));
1733
2506
  return min;
1734
2507
  }
1735
2508
  function onFillDarkTint(fill, ...moreFills) {
@@ -1754,22 +2527,25 @@ function onFillTextValue(fill, ...moreFills) {
1754
2527
  if (tint) return oklchCss(tint);
1755
2528
  return minContrast(DARK_RANGE, fills) >= whiteMin ? ON_FILL_DARK : ON_FILL_WHITE;
1756
2529
  }
2530
+ function treemapLeaves(nodes, path = []) {
2531
+ return nodes.flatMap((node) => node.children?.length ? treemapLeaves(node.children, [...path, node.name]) : [{ name: node.name, value: numberOf(node.value) ?? 0, ...path.length ? { group: path.join(" \u203A ") } : {} }]);
2532
+ }
1757
2533
  var LABEL_INSET = 4;
1758
2534
  function treemapLabelLines(width, height, metrics) {
1759
2535
  if (width - 2 * LABEL_INSET < metrics.fontSize * 3) return 0;
1760
2536
  return Math.max(0, Math.floor((height - 2 * LABEL_INSET) / metrics.lineHeight));
1761
2537
  }
1762
2538
  var computedColors = /* @__PURE__ */ new Map();
1763
- function computedColor(css) {
1764
- if (typeof document === "undefined") return css;
1765
- let value = computedColors.get(css);
2539
+ function computedColor(css2) {
2540
+ if (typeof document === "undefined") return css2;
2541
+ let value = computedColors.get(css2);
1766
2542
  if (value === void 0) {
1767
- const probe = document.createElement("span");
1768
- probe.style.color = css;
1769
- document.body.appendChild(probe);
1770
- value = getComputedStyle(probe).color;
1771
- probe.remove();
1772
- computedColors.set(css, value);
2543
+ const probe2 = document.createElement("span");
2544
+ probe2.style.color = css2;
2545
+ document.body.appendChild(probe2);
2546
+ value = getComputedStyle(probe2).color;
2547
+ probe2.remove();
2548
+ computedColors.set(css2, value);
1773
2549
  }
1774
2550
  return value;
1775
2551
  }
@@ -1781,8 +2557,8 @@ function contrastColor(color) {
1781
2557
  const rgb = /^rgba?\(\s*(\d+)[\s,]+(\d+)[\s,]+(\d+)/.exec(color);
1782
2558
  const c = color.replace("#", "");
1783
2559
  const [r, g, b] = rgb ? [Number(rgb[1]), Number(rgb[2]), Number(rgb[3])] : c.length >= 6 ? [parseInt(c.substring(0, 2), 16), parseInt(c.substring(2, 4), 16), parseInt(c.substring(4, 6), 16)] : [0, 0, 0];
1784
- const luminance = (0.299 * r + 0.587 * g + 0.114 * b) / 255;
1785
- return luminance > 0.55 ? "#1f2937" : "#ffffff";
2560
+ const luminance2 = (0.299 * r + 0.587 * g + 0.114 * b) / 255;
2561
+ return luminance2 > 0.55 ? "#1f2937" : "#ffffff";
1786
2562
  }
1787
2563
  function TreemapContent({ x = 0, y = 0, width = 0, height: h = 0, name, depth, colors, radius, index = 0, metrics }) {
1788
2564
  const fill = colors[index % colors.length];
@@ -1821,15 +2597,15 @@ function addFillToNodes(nodes, colors, counter = { i: 0 }) {
1821
2597
  }
1822
2598
  const fill = colors[counter.i % colors.length];
1823
2599
  counter.i++;
1824
- return { ...node, fill };
2600
+ return { ...node, value: numberOf(node.value) ?? 0, fill };
1825
2601
  });
1826
2602
  }
1827
2603
  var LABEL_TEXT = "text-xs leading-tight font-[family-name:var(--ds-font-sans)]";
1828
2604
  function useLabelMetrics() {
1829
- const probe = useRef(null);
2605
+ const probe2 = useRef(null);
1830
2606
  const [metrics, setMetrics] = useState(null);
1831
2607
  useLayoutEffect(() => {
1832
- const el = probe.current;
2608
+ const el = probe2.current;
1833
2609
  if (!el) return;
1834
2610
  const cs = getComputedStyle(el);
1835
2611
  const fontSize = parseFloat(cs.fontSize);
@@ -1837,7 +2613,7 @@ function useLabelMetrics() {
1837
2613
  if (!(fontSize > 0) || !(lineHeight > 0)) return;
1838
2614
  if (!metrics || metrics.fontSize !== fontSize || metrics.lineHeight !== lineHeight) setMetrics({ fontSize, lineHeight });
1839
2615
  });
1840
- return [probe, metrics];
2616
+ return [probe2, metrics];
1841
2617
  }
1842
2618
  var TreemapChart = markChart(forwardRef(function TreemapChart2({
1843
2619
  data,
@@ -1845,15 +2621,19 @@ var TreemapChart = markChart(forwardRef(function TreemapChart2({
1845
2621
  showTooltip = true,
1846
2622
  animated,
1847
2623
  "aria-label": ariaLabel,
1848
- className
2624
+ className,
2625
+ description
1849
2626
  }, ref) {
1850
2627
  const colors = useChartColors(6, false);
2628
+ const locale = useFormatLocale();
2629
+ const format = useMemo(() => fullValueFormatter(void 0, locale), [locale]);
2630
+ const access = useMemo(() => partsAccess({ kind: "treemap", items: treemapLeaves(data ?? []), format }), [data, format]);
1851
2631
  const isAnimated = useChartAnimation(animated);
1852
2632
  const radius = useRadius();
1853
- const [probe, metrics] = useLabelMetrics();
2633
+ const [probe2, metrics] = useLabelMetrics();
1854
2634
  const chartData = addFillToNodes(data, colors);
1855
2635
  if (!data?.length) return null;
1856
- return /* @__PURE__ */ jsxs(ChartWrapper, { ref, height, size: { model: "ratio" }, chart: "treemap", className, "aria-label": ariaLabel, children: [
2636
+ return /* @__PURE__ */ jsxs(ChartWrapper, { ref, height, size: { model: "ratio" }, chart: "treemap", className, "aria-label": ariaLabel, access, description, children: [
1857
2637
  /* @__PURE__ */ jsx(ResponsiveContainer, { width: "100%", height: "100%", children: /* @__PURE__ */ jsx(
1858
2638
  Treemap,
1859
2639
  {
@@ -1867,35 +2647,153 @@ var TreemapChart = markChart(forwardRef(function TreemapChart2({
1867
2647
  children: showTooltip && /* @__PURE__ */ jsx(Tooltip, { content: /* @__PURE__ */ jsx(ChartTooltipContent, {}) })
1868
2648
  }
1869
2649
  ) }),
1870
- /* @__PURE__ */ jsx("span", { ref: probe, "aria-hidden": true, className: LABEL_TEXT, style: { position: "absolute", visibility: "hidden", pointerEvents: "none" }, children: "M" })
2650
+ /* @__PURE__ */ jsx("span", { ref: probe2, "aria-hidden": true, className: LABEL_TEXT, style: { position: "absolute", visibility: "hidden", pointerEvents: "none" }, children: "M" })
1871
2651
  ] });
1872
2652
  }));
2653
+ function oneWayFlows(links) {
2654
+ const next = /* @__PURE__ */ new Map();
2655
+ const reaches = (from, to) => {
2656
+ const seen = /* @__PURE__ */ new Set();
2657
+ const stack = [from];
2658
+ while (stack.length) {
2659
+ const at = stack.pop();
2660
+ if (at === to) return true;
2661
+ if (seen.has(at)) continue;
2662
+ seen.add(at);
2663
+ stack.push(...next.get(at) ?? []);
2664
+ }
2665
+ return false;
2666
+ };
2667
+ const kept = /* @__PURE__ */ new Set();
2668
+ const loops = [];
2669
+ const largestFirst = links.map((link, i) => ({ link, i })).sort((a, b) => (numberOf(b.link.value) ?? 0) - (numberOf(a.link.value) ?? 0) || a.i - b.i);
2670
+ for (const { link, i } of largestFirst) {
2671
+ if (reaches(link.target, link.source)) {
2672
+ loops.push(link);
2673
+ continue;
2674
+ }
2675
+ kept.add(i);
2676
+ next.set(link.source, [...next.get(link.source) ?? [], link.target]);
2677
+ }
2678
+ return { flows: links.filter((_, i) => kept.has(i)), loops };
2679
+ }
2680
+ function stepsOf(count, flows) {
2681
+ const depth = new Array(count).fill(0);
2682
+ const valid = flows.filter((f) => f.source >= 0 && f.source < count && f.target >= 0 && f.target < count);
2683
+ for (let pass = 0; pass < count; pass++) {
2684
+ let moved = false;
2685
+ for (const f of valid) if (depth[f.target] < depth[f.source] + 1) {
2686
+ depth[f.target] = depth[f.source] + 1;
2687
+ moved = true;
2688
+ }
2689
+ if (!moved) break;
2690
+ }
2691
+ return Math.max(0, ...depth);
2692
+ }
2693
+ var measure;
2694
+ function textWidth(text2, el) {
2695
+ const style = getComputedStyle(el);
2696
+ const size = parseFloat(style.fontSize) || 12;
2697
+ if (measure === void 0) {
2698
+ try {
2699
+ measure = /jsdom/i.test(navigator.userAgent) ? null : document.createElement("canvas").getContext("2d");
2700
+ } catch {
2701
+ measure = null;
2702
+ }
2703
+ }
2704
+ if (!measure) return text2.length * size * 0.6;
2705
+ measure.font = `${style.fontWeight || "400"} ${size}px ${style.fontFamily || "sans-serif"}`;
2706
+ return measure.measureText(text2).width;
2707
+ }
2708
+ var NAME_GAP2 = 6;
2709
+ var INSET = 8;
2710
+ function SankeyNode({ x, y, width, height, payload, ink, steps, inset, drawn: drawn2 }) {
2711
+ const end = steps > 0 && !payload.targetLinks?.length;
2712
+ const name = String(payload.name ?? "");
2713
+ const text2 = useRef(null);
2714
+ const [shown, setShown] = useState(name);
2715
+ useLayoutEffect(() => {
2716
+ const el = text2.current;
2717
+ const drawing = drawn2 > 0 ? drawn2 : Number(el?.ownerSVGElement?.getAttribute("width")) || 0;
2718
+ if (!el || drawing <= 0) {
2719
+ setShown(name);
2720
+ return;
2721
+ }
2722
+ const step = steps > 0 ? (drawing - 2 * inset - width) / steps : drawing - 2 * inset;
2723
+ const gap = step - width;
2724
+ const shared2 = end || (payload.depth ?? 0) === steps - 1;
2725
+ const room = Math.max(0, (shared2 ? gap / 2 : gap) - 2 * NAME_GAP2);
2726
+ if (textWidth(name, el) <= room) {
2727
+ setShown(name);
2728
+ return;
2729
+ }
2730
+ let fits = 0;
2731
+ for (let lo = 1, hi = name.length - 1; lo <= hi; ) {
2732
+ const mid = Math.floor((lo + hi) / 2);
2733
+ if (textWidth(`${name.slice(0, mid).trimEnd()}\u2026`, el) <= room) {
2734
+ fits = mid;
2735
+ lo = mid + 1;
2736
+ } else hi = mid - 1;
2737
+ }
2738
+ setShown(fits > 0 ? `${name.slice(0, fits).trimEnd()}\u2026` : "");
2739
+ }, [name, steps, inset, width, end, payload.depth, drawn2]);
2740
+ return /* @__PURE__ */ jsxs("g", { children: [
2741
+ /* @__PURE__ */ jsx("rect", { x, y, width, height, fill: payload.fill }),
2742
+ /* @__PURE__ */ jsx(
2743
+ "text",
2744
+ {
2745
+ ref: text2,
2746
+ "data-sankey-name": "",
2747
+ x: end ? x - NAME_GAP2 : x + width + NAME_GAP2,
2748
+ y: y + height / 2,
2749
+ textAnchor: end ? "end" : "start",
2750
+ dominantBaseline: "middle",
2751
+ fill: ink,
2752
+ style: { fontSize: "var(--ds-font-size-xs)", fontFamily: "var(--ds-font-sans)" },
2753
+ children: shown
2754
+ }
2755
+ )
2756
+ ] });
2757
+ }
1873
2758
  var SankeyChart = markChart(forwardRef(function SankeyChart2({
1874
2759
  data,
1875
2760
  height = "auto",
1876
2761
  showTooltip = true,
1877
2762
  "aria-label": ariaLabel,
1878
- className
2763
+ className,
2764
+ description
1879
2765
  }, ref) {
1880
2766
  const colors = useChartColors(data.nodes.length, false);
2767
+ const locale = useFormatLocale();
2768
+ const format = useMemo(() => fullValueFormatter(void 0, locale), [locale]);
2769
+ const { flows, loops } = useMemo(() => oneWayFlows(data?.links ?? []), [data]);
2770
+ const [drawn2, setDrawn] = useState(0);
2771
+ const steps = useMemo(() => stepsOf(data?.nodes?.length ?? 0, flows), [data, flows]);
2772
+ const access = useMemo(() => flowAccess({ nodes: data?.nodes ?? [], links: data?.links ?? [], undrawn: loops, format }), [data, loops, format]);
1881
2773
  const linkStroke = useResolvedToken("--ds-border-subtle");
2774
+ const nameInk = useResolvedToken("--ds-text-secondary");
1882
2775
  const nodesWithColor = data.nodes.map((node, i) => ({
1883
2776
  ...node,
1884
2777
  fill: colors[i % colors.length]
1885
2778
  }));
2779
+ useEffect(() => {
2780
+ const loop = loops[0];
2781
+ if (loop) warnOnce("SankeyChart", `the flow from "${data.nodes[loop.source]?.name ?? loop.source}" to "${data.nodes[loop.target]?.name ?? loop.target}" closes a loop, so it isn't drawn: a Sankey chart's flows run one way. Its table still lists it.`);
2782
+ }, [loops, data]);
1886
2783
  const sankeyData = {
1887
2784
  nodes: nodesWithColor,
1888
- links: data.links
2785
+ links: flows.map((flow) => ({ ...flow, value: numberOf(flow.value) ?? 0 }))
1889
2786
  };
1890
2787
  if (!data?.nodes?.length) return null;
1891
- return /* @__PURE__ */ jsx(ChartWrapper, { ref, height, size: { model: "ratio" }, chart: "sankey", className, "aria-label": ariaLabel, children: /* @__PURE__ */ jsx(ResponsiveContainer, { width: "100%", height: "100%", children: /* @__PURE__ */ jsx(
2788
+ return /* @__PURE__ */ jsx(ChartWrapper, { ref, height, size: { model: "ratio" }, chart: "sankey", className, "aria-label": ariaLabel, access, description, children: /* @__PURE__ */ jsx(ResponsiveContainer, { width: "100%", height: "100%", onResize: (w) => setDrawn(w), children: /* @__PURE__ */ jsx(
1892
2789
  Sankey,
1893
2790
  {
1894
2791
  data: sankeyData,
1895
2792
  nodeWidth: 10,
1896
2793
  nodePadding: 24,
1897
- margin: { top: 8, right: 8, bottom: 8, left: 8 },
2794
+ margin: { top: INSET, right: INSET, bottom: INSET, left: INSET },
1898
2795
  link: { stroke: linkStroke, strokeOpacity: 0.4 },
2796
+ node: (n) => /* @__PURE__ */ jsx(SankeyNode, { x: n.x, y: n.y, width: n.width, height: n.height, payload: n.payload, ink: nameInk, steps, inset: INSET, drawn: drawn2 }),
1899
2797
  children: showTooltip && /* @__PURE__ */ jsx(Tooltip, { content: /* @__PURE__ */ jsx(ChartTooltipContent, {}) })
1900
2798
  }
1901
2799
  ) }) });
@@ -1995,9 +2893,15 @@ function ChartContainer({
1995
2893
  const fixed = fixedChartHeight(height);
1996
2894
  const sizesItself = !loading && !!children && isLibraryChart(children);
1997
2895
  const area = fixed ?? CHART_HEIGHTS.md;
2896
+ const [actions, setActions] = useState(null);
2897
+ const [charts, setCharts] = useState(0);
2898
+ const register = useCallback(() => {
2899
+ setCharts((n) => n + 1);
2900
+ return () => setCharts((n) => n - 1);
2901
+ }, []);
1998
2902
  const context = useMemo(
1999
- () => ({ height: fixed, titleId: title ? titleId : void 0, fillArea: !sizesItself }),
2000
- [fixed, title, titleId, sizesItself]
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]
2001
2905
  );
2002
2906
  let body = null;
2003
2907
  if (loading) {
@@ -2029,7 +2933,10 @@ function ChartContainer({
2029
2933
  className
2030
2934
  ),
2031
2935
  children: [
2032
- title && /* @__PURE__ */ jsx("h3", { id: titleId, className: cn(CHART_TITLE_CLASSES, "mb-ds-4"), children: title }),
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 }),
2938
+ /* @__PURE__ */ jsx("div", { ref: setActions, "data-chart-actions": "", className: "shrink-0 empty:hidden" })
2939
+ ] }),
2033
2940
  /* @__PURE__ */ jsx(
2034
2941
  "div",
2035
2942
  {