@spatika/react 1.3.1 → 1.4.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 (58) hide show
  1. package/dist/composites/EventCalendar.d.ts +13 -2
  2. package/dist/composites/EventCalendar.d.ts.map +1 -1
  3. package/dist/composites/EventCalendar.js +10 -24
  4. package/dist/composites/cartesian-charts.d.ts +12 -2
  5. package/dist/composites/cartesian-charts.d.ts.map +1 -1
  6. package/dist/composites/cartesian-charts.js +27 -13
  7. package/dist/composites/chart-composition.d.ts +19 -1
  8. package/dist/composites/chart-composition.d.ts.map +1 -1
  9. package/dist/composites/chart-composition.js +124 -62
  10. package/dist/composites/chart-interaction.d.ts +81 -0
  11. package/dist/composites/chart-interaction.d.ts.map +1 -0
  12. package/dist/composites/chart-interaction.js +56 -0
  13. package/dist/composites/chart-ui.d.ts +8 -13
  14. package/dist/composites/chart-ui.d.ts.map +1 -1
  15. package/dist/composites/chart-ui.js +9 -6
  16. package/dist/composites/flow-charts.d.ts +6 -1
  17. package/dist/composites/flow-charts.d.ts.map +1 -1
  18. package/dist/composites/flow-charts.js +28 -14
  19. package/dist/composites/radial-charts.d.ts +11 -1
  20. package/dist/composites/radial-charts.d.ts.map +1 -1
  21. package/dist/composites/radial-charts.js +33 -14
  22. package/dist/composites/scheduler-ui.d.ts +14 -1
  23. package/dist/composites/scheduler-ui.d.ts.map +1 -1
  24. package/dist/composites/scheduler-ui.js +23 -2
  25. package/dist/index.d.ts +8 -6
  26. package/dist/index.d.ts.map +1 -1
  27. package/dist/index.js +4 -4
  28. package/dist/lib/chips.d.ts +3 -0
  29. package/dist/lib/chips.d.ts.map +1 -1
  30. package/dist/lib/chips.js +10 -0
  31. package/dist/lib/scheduler.d.ts +12 -0
  32. package/dist/lib/scheduler.d.ts.map +1 -1
  33. package/dist/lib/scheduler.js +22 -0
  34. package/dist/primitives/NativeSelect.d.ts +10 -1
  35. package/dist/primitives/NativeSelect.d.ts.map +1 -1
  36. package/dist/primitives/NativeSelect.js +2 -2
  37. package/package.json +2 -2
  38. package/skills/spatika-ui/SKILL.md +4 -0
  39. package/src/composites/EventCalendar.tsx +35 -24
  40. package/src/composites/cartesian-charts.test.tsx +86 -2
  41. package/src/composites/cartesian-charts.tsx +84 -16
  42. package/src/composites/chart-composition.test.tsx +15 -0
  43. package/src/composites/chart-composition.tsx +229 -88
  44. package/src/composites/chart-interaction.ts +136 -0
  45. package/src/composites/chart-ui.tsx +35 -27
  46. package/src/composites/flow-charts.test.tsx +21 -2
  47. package/src/composites/flow-charts.tsx +59 -25
  48. package/src/composites/radial-charts.test.tsx +17 -2
  49. package/src/composites/radial-charts.tsx +38 -12
  50. package/src/composites/scheduler-ui.tsx +128 -26
  51. package/src/composites/scheduler.test.tsx +39 -0
  52. package/src/index.test.ts +4 -0
  53. package/src/index.ts +18 -1
  54. package/src/lib/chips.ts +16 -0
  55. package/src/lib/scheduler.test.ts +16 -0
  56. package/src/lib/scheduler.ts +34 -0
  57. package/src/primitives/NativeSelect.test.tsx +28 -0
  58. package/src/primitives/NativeSelect.tsx +14 -4
@@ -1,4 +1,4 @@
1
- import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
1
+ import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
2
2
  import { createContext, useCallback, useContext, useEffect, useId, useMemo, useRef, useState, } from "react";
3
3
  import { Download, Maximize2, Move, SquareDashedMousePointer, ZoomIn, ZoomOut } from "lucide-react";
4
4
  import { cn } from "../lib/cn";
@@ -6,6 +6,7 @@ import { exportChart } from "../lib/chart-export";
6
6
  import { DEFAULT_CHART_MARGIN, DEFAULT_ZOOM, applyZoom, areaPath, axisDataFromDataset, bandScale, chartColor, clampZoom, extent, formatAxisValue, formatChartNumber, inferScaleType, linePath, linearScale, markOpacity, niceTicks, panZoom, plotBox, pointScale, rangeAreaPath, roundedRectPath, seriesDataFromDataset, stackSeries, wheelZoom, zoomFromBrush, } from "../lib/charts";
7
7
  import { IconButton } from "../primitives/IconButton";
8
8
  import { CartesianGrid, CategoryAxis, ChartLegend, ChartTooltip, ValueAxis, categoryLabels, formatSeriesValue, resolveMargin, seriesMeta, } from "./chart-ui";
9
+ import { bindChartMark, seriesItemColor, } from "./chart-interaction";
9
10
  const ChartContext = createContext(null);
10
11
  export function useChartContext() {
11
12
  const value = useContext(ChartContext);
@@ -45,6 +46,7 @@ function resolveSeries(series, dataset, colors) {
45
46
  type,
46
47
  label: item.label ?? item.dataKey ?? item.id ?? `Series ${index + 1}`,
47
48
  color: item.color ?? chartColor(index, colors),
49
+ itemColors: item.itemColors,
48
50
  data,
49
51
  stack: item.stack,
50
52
  yAxisId: item.yAxisId,
@@ -104,12 +106,13 @@ function numericDomain(series, stacked, axis) {
104
106
  function leftId(axis) {
105
107
  return axis?.id ?? "left";
106
108
  }
107
- export function ChartContainer({ slot = "chart-container", className, width, height = 280, margin, dataset, xAxis, yAxis, series, colors, hideLegend, hideGrid, stacked = false, barGapRatio = 0.15, borderRadius = 6, zoom, defaultZoom, onZoomChange, showToolbar, highlightScope = "item", selected, animated = true, locale, children, "aria-label": ariaLabel, }) {
109
+ export function ChartContainer({ slot = "chart-container", className, width, height = 280, margin, dataset, xAxis, yAxis, series, colors, hideLegend, hideGrid, stacked = false, barGapRatio = 0.15, borderRadius = 6, zoom, defaultZoom, onZoomChange, showToolbar, highlightScope = "item", selected, animated = true, locale, children, "aria-label": ariaLabel, fillHeight = false, onItemClick, renderTooltip, renderMark, referenceLines, showLabels = false, }) {
108
110
  const surfaceRef = useRef(null);
109
111
  const svgRef = useRef(null);
110
112
  const clipPathId = `spk-chart-clip-${useId().replace(/:/g, "")}`;
111
113
  const measured = useElementSize(surfaceRef, width ?? 320, height);
112
114
  const plotWidth = width ?? measured.width;
115
+ const plotHeight = fillHeight ? measured.height : height;
113
116
  const hasRight = yAxis?.some((axis) => axis.position === "right");
114
117
  const m = resolveMargin(margin ?? (hasRight ? { ...DEFAULT_CHART_MARGIN, right: 48 } : undefined));
115
118
  const resolved = useMemo(() => resolveSeries(series, dataset, colors), [series, dataset, colors]);
@@ -148,7 +151,7 @@ export function ChartContainer({ slot = "chart-container", className, width, hei
148
151
  const [hover, setHover] = useState(null);
149
152
  const [brush, setBrush] = useState(null);
150
153
  const activeHighlight = selected ?? highlighted;
151
- const plot = plotBox(plotWidth, height, m);
154
+ const plot = plotBox(plotWidth, plotHeight, m);
152
155
  const visible = resolved.filter((item) => !hidden.has(item.id));
153
156
  const leftSeries = visible.filter((item) => !item.yAxisId || item.yAxisId === (leftAxis?.id ?? item.yAxisId));
154
157
  const rightSeries = visible.filter((item) => rightAxis && item.yAxisId === rightAxis.id);
@@ -192,7 +195,7 @@ export function ChartContainer({ slot = "chart-container", className, width, hei
192
195
  const ctx = {
193
196
  slot,
194
197
  width: plotWidth,
195
- height,
198
+ height: plotHeight,
196
199
  margin: m,
197
200
  plot,
198
201
  categories,
@@ -229,15 +232,19 @@ export function ChartContainer({ slot = "chart-container", className, width, hei
229
232
  brush,
230
233
  setBrush,
231
234
  exportChart: doExport,
235
+ onItemClick,
236
+ renderMark,
237
+ referenceLines,
238
+ showLabels,
232
239
  };
233
240
  const legend = seriesMeta(resolved, colors);
234
241
  const label = ariaLabel ??
235
242
  `Chart of ${resolved.map((item) => item.label).join(", ")}`;
236
- return (_jsx(ChartContext.Provider, { value: ctx, children: _jsxs("div", { "data-slot": slot, className: cn("spk-chart", animated && "spk-chart--animated", className), role: "img", "aria-label": label, children: [showToolbar ? _jsx(ChartsToolbar, {}) : null, hideLegend ? null : (_jsx(ChartLegend, { items: legend, hiddenIds: hidden, onToggle: toggleSeries })), _jsxs("div", { ref: surfaceRef, className: "spk-chart-surface", style: { height }, children: [plotWidth > 0 ? children ?? _jsx(DefaultChartSurface, {}) : null, _jsx(ChartTooltip, { hover: hover, boundsWidth: plotWidth })] }), _jsx(ChartA11yTable, {})] }) }));
243
+ return (_jsx(ChartContext.Provider, { value: ctx, children: _jsxs("div", { "data-slot": slot, className: cn("spk-chart", animated && "spk-chart--animated", fillHeight && "spk-chart--fill", className), role: "img", "aria-label": label, children: [showToolbar ? _jsx(ChartsToolbar, {}) : null, hideLegend ? null : (_jsx(ChartLegend, { items: legend, hiddenIds: hidden, onToggle: toggleSeries })), _jsxs("div", { ref: surfaceRef, className: "spk-chart-surface", style: fillHeight ? undefined : { height: plotHeight }, children: [plotWidth > 0 && plotHeight > 0 ? children ?? _jsx(DefaultChartSurface, {}) : null, _jsx(ChartTooltip, { hover: hover, boundsWidth: plotWidth, render: renderTooltip })] }), _jsx(ChartA11yTable, {})] }) }));
237
244
  }
238
245
  function DefaultChartSurface() {
239
246
  const { rightAxis } = useChartContext();
240
- return (_jsxs(ChartSurface, { children: [_jsx(ChartsGrid, {}), _jsx(BarPlot, {}), _jsx(AreaPlot, {}), _jsx(LinePlot, {}), _jsx(ScatterPlot, {}), _jsx(ChartsXAxis, {}), _jsx(ChartsYAxis, {}), rightAxis ? _jsx(ChartsYAxis, { position: "right" }) : null, _jsx(ChartsBrush, {})] }));
247
+ return (_jsxs(ChartSurface, { children: [_jsx(ChartsGrid, {}), _jsx(BarPlot, {}), _jsx(AreaPlot, {}), _jsx(LinePlot, {}), _jsx(ScatterPlot, {}), _jsx(ChartsXAxis, {}), _jsx(ChartsYAxis, {}), rightAxis ? _jsx(ChartsYAxis, { position: "right" }) : null, _jsx(ChartsReferenceLine, {}), _jsx(ChartsBrush, {})] }));
241
248
  }
242
249
  export function ChartSurface({ children, className }) {
243
250
  const ctx = useChartContext();
@@ -342,38 +349,53 @@ export function BarPlot() {
342
349
  const gap = n > 1 ? ctx.bandwidth * ctx.barGapRatio : 0;
343
350
  const barW = (ctx.bandwidth - gap * (n - 1)) / n;
344
351
  const zero = ctx.yAt(0);
345
- return (_jsx(PlotClip, { slot: "bar-plot", children: bars.map((item, s) => item.data.map((value, i) => {
346
- if (value == null)
347
- return null;
348
- let x = ctx.xAt(i);
349
- let y1;
350
- let y2;
351
- if (stacks) {
352
- const seg = stacks[s][i];
353
- y1 = ctx.yAt(seg.end, item.yAxisId);
354
- y2 = ctx.yAt(seg.start, item.yAxisId);
355
- }
356
- else {
357
- x = ctx.xAt(i) + s * (barW + gap);
358
- y1 = ctx.yAt(value, item.yAxisId);
359
- y2 = zero;
360
- }
361
- const y = Math.min(y1, y2);
362
- const h = Math.max(1, Math.abs(y2 - y1));
363
- const opacity = markOpacity(ctx.highlightScope, ctx.highlighted, item.id, i);
364
- return (_jsx("path", { className: "spk-chart-mark", d: roundedRectPath(x, y, ctx.stacked ? ctx.bandwidth : barW, h, ctx.borderRadius), fill: item.color, opacity: opacity, onMouseEnter: (event) => {
365
- ctx.setHighlighted({ seriesId: item.id, dataIndex: i });
366
- ctx.setHover({
367
- x: event.nativeEvent.offsetX,
368
- y: event.nativeEvent.offsetY,
369
- title: String(ctx.categories[i]),
370
- items: [{ color: item.color, label: item.label, value: formatSeriesValue(value) }],
371
- });
372
- }, onMouseLeave: () => {
373
- ctx.setHighlighted(null);
374
- ctx.setHover(null);
375
- } }, `${item.id}-${i}`));
376
- })) }));
352
+ return (_jsxs(_Fragment, { children: [_jsx(PlotClip, { slot: "bar-plot", children: bars.map((item, s) => item.data.map((value, i) => {
353
+ if (value == null)
354
+ return null;
355
+ let x = ctx.xAt(i);
356
+ let y1;
357
+ let y2;
358
+ if (stacks) {
359
+ const seg = stacks[s][i];
360
+ y1 = ctx.yAt(seg.end, item.yAxisId);
361
+ y2 = ctx.yAt(seg.start, item.yAxisId);
362
+ }
363
+ else {
364
+ x = ctx.xAt(i) + s * (barW + gap);
365
+ y1 = ctx.yAt(value, item.yAxisId);
366
+ y2 = zero;
367
+ }
368
+ const y = Math.min(y1, y2);
369
+ const h = Math.max(1, Math.abs(y2 - y1));
370
+ const opacity = markOpacity(ctx.highlightScope, ctx.highlighted, item.id, i);
371
+ const color = seriesItemColor(item.color, item.itemColors, i);
372
+ const event = {
373
+ seriesId: item.id,
374
+ seriesLabel: item.label,
375
+ dataIndex: i,
376
+ category: ctx.categories[i] ?? i,
377
+ value,
378
+ color,
379
+ };
380
+ return (_jsx("path", { d: roundedRectPath(x, y, ctx.stacked ? ctx.bandwidth : barW, h, ctx.borderRadius), fill: color, opacity: opacity, ...bindChartMark({
381
+ event,
382
+ hover: {
383
+ title: String(ctx.categories[i]),
384
+ items: [{ color, label: item.label, value: formatSeriesValue(value) }],
385
+ },
386
+ onItemClick: ctx.onItemClick,
387
+ setHover: ctx.setHover,
388
+ clearHover: () => ctx.setHover(null),
389
+ onHighlight: ctx.setHighlighted,
390
+ }) }, `${item.id}-${i}`));
391
+ })) }), ctx.showLabels ? (_jsx("g", { "data-slot": "bar-labels", pointerEvents: "none", children: bars.map((item, s) => item.data.map((value, i) => {
392
+ if (value == null)
393
+ return null;
394
+ const x = ctx.stacked ? ctx.xAt(i) : ctx.xAt(i) + s * (barW + gap);
395
+ const y = ctx.yAt(value, item.yAxisId);
396
+ const width = ctx.stacked ? ctx.bandwidth : barW;
397
+ return (_jsx("text", { className: "spk-chart-label", x: x + width / 2, y: y - 4, textAnchor: "middle", children: formatSeriesValue(value) }, `${item.id}-${i}-label`));
398
+ })) })) : null] }));
377
399
  }
378
400
  function LineLikePlot({ types, slot }) {
379
401
  const ctx = useChartContext();
@@ -403,18 +425,31 @@ function LineLikePlot({ types, slot }) {
403
425
  return (_jsxs("g", { opacity: opacity, children: [fill ? (_jsx("path", { d: baseline
404
426
  ? rangeAreaPath(pts, baseline, item.curve)
405
427
  : areaPath(pts, ctx.plot.bottom, item.curve), fill: item.color, opacity: baseline ? 0.88 : 0.18, className: "spk-chart-mark" })) : null, _jsx("path", { d: linePath(pts, item.curve), fill: "none", stroke: item.color, strokeWidth: 2.25, strokeLinejoin: "round", strokeLinecap: "round", className: "spk-chart-mark" }), item.showMark
406
- ? pts.map((pt) => (_jsx("circle", { cx: pt.x, cy: pt.y, r: 3.4, fill: item.color, className: "spk-chart-mark", onMouseEnter: () => {
407
- ctx.setHighlighted({ seriesId: item.id, dataIndex: pt.i });
408
- ctx.setHover({
409
- x: pt.x,
410
- y: pt.y,
411
- title: String(ctx.categories[pt.i]),
412
- items: [{ color: item.color, label: item.label, value: formatSeriesValue(pt.value) }],
413
- });
414
- }, onMouseLeave: () => {
415
- ctx.setHighlighted(null);
416
- ctx.setHover(null);
417
- } }, pt.i)))
428
+ ? pts.map((pt) => {
429
+ const color = seriesItemColor(item.color, item.itemColors, pt.i);
430
+ const event = {
431
+ seriesId: item.id,
432
+ seriesLabel: item.label,
433
+ dataIndex: pt.i,
434
+ category: ctx.categories[pt.i] ?? pt.i,
435
+ value: pt.value,
436
+ color,
437
+ };
438
+ const mark = ctx.renderMark?.({ ...event, x: pt.x, y: pt.y }) ?? (_jsx("circle", { cx: pt.x, cy: pt.y, r: 3.4, fill: color }));
439
+ return (_jsx("g", { ...bindChartMark({
440
+ event,
441
+ hover: {
442
+ x: pt.x,
443
+ y: pt.y,
444
+ title: String(ctx.categories[pt.i]),
445
+ items: [{ color, label: item.label, value: formatSeriesValue(pt.value) }],
446
+ },
447
+ onItemClick: ctx.onItemClick,
448
+ setHover: ctx.setHover,
449
+ clearHover: () => ctx.setHover(null),
450
+ onHighlight: ctx.setHighlighted,
451
+ }), children: mark }, pt.i));
452
+ })
418
453
  : null] }, item.id));
419
454
  }) }));
420
455
  }
@@ -441,21 +476,29 @@ export function ScatterPlot() {
441
476
  const cx = applyZoom(xScale(point.x), ctx.plot.left, ctx.plot.iw, ctx.zoom.x);
442
477
  const cy = ctx.yAt(point.y, item.yAxisId);
443
478
  const opacity = markOpacity(ctx.highlightScope, ctx.highlighted, item.id, i);
444
- return (_jsx("circle", { cx: cx, cy: cy, r: 4.5, fill: item.color, opacity: opacity, className: "spk-chart-mark", onMouseEnter: (event) => {
445
- ctx.setHighlighted({ seriesId: item.id, dataIndex: i });
446
- ctx.setHover({
447
- x: event.nativeEvent.offsetX,
448
- y: event.nativeEvent.offsetY,
479
+ const color = seriesItemColor(item.color, item.itemColors, i);
480
+ const event = {
481
+ seriesId: item.id,
482
+ seriesLabel: item.label,
483
+ dataIndex: i,
484
+ category: point.id ?? i,
485
+ value: point.y,
486
+ color,
487
+ };
488
+ return (_jsx("circle", { cx: cx, cy: cy, r: 4.5, fill: color, opacity: opacity, ...bindChartMark({
489
+ event,
490
+ hover: {
449
491
  title: item.label,
450
492
  items: [
451
- { color: item.color, label: "x", value: formatChartNumber(point.x, ctx.locale) },
452
- { color: item.color, label: "y", value: formatChartNumber(point.y, ctx.locale) },
493
+ { color, label: "x", value: formatChartNumber(point.x, ctx.locale) },
494
+ { color, label: "y", value: formatChartNumber(point.y, ctx.locale) },
453
495
  ],
454
- });
455
- }, onMouseLeave: () => {
456
- ctx.setHighlighted(null);
457
- ctx.setHover(null);
458
- } }, `${item.id}-${point.id ?? i}`));
496
+ },
497
+ onItemClick: ctx.onItemClick,
498
+ setHover: ctx.setHover,
499
+ clearHover: () => ctx.setHover(null),
500
+ onHighlight: ctx.setHighlighted,
501
+ }) }, `${item.id}-${point.id ?? i}`));
459
502
  });
460
503
  }) }));
461
504
  }
@@ -467,6 +510,25 @@ export function ChartsBrush() {
467
510
  const width = Math.abs(brush.x1 - brush.x0);
468
511
  return (_jsx("rect", { "data-slot": "chart-brush", className: "spk-chart-brush", x: x, y: plot.top, width: width, height: plot.ih }));
469
512
  }
513
+ /** Horizontal (value) or vertical (category index) guide overlay. */
514
+ export function ChartsReferenceLine() {
515
+ const { referenceLines, yAt, xAt, plot, bandwidth } = useChartContext();
516
+ if (!referenceLines?.length)
517
+ return null;
518
+ return (_jsx("g", { "data-slot": "chart-reference-lines", children: referenceLines.map((line, index) => {
519
+ const color = line.color ?? "var(--primary)";
520
+ const dash = line.strokeDasharray ?? "4 4";
521
+ if (line.y != null) {
522
+ const y = yAt(line.y, line.yAxisId);
523
+ return (_jsxs("g", { children: [_jsx("line", { className: "spk-chart-ref-line", x1: plot.left, x2: plot.right, y1: y, y2: y, stroke: color, strokeDasharray: dash }), line.label ? (_jsx("text", { className: "spk-chart-ref-label", x: plot.right - 4, y: y - 4, textAnchor: "end", children: line.label })) : null] }, `y-${index}`));
524
+ }
525
+ if (line.xIndex != null) {
526
+ const x = xAt(line.xIndex) + bandwidth / 2;
527
+ return (_jsxs("g", { children: [_jsx("line", { className: "spk-chart-ref-line", x1: x, x2: x, y1: plot.top, y2: plot.bottom, stroke: color, strokeDasharray: dash }), line.label ? (_jsx("text", { className: "spk-chart-ref-label", x: x + 4, y: plot.top + 12, children: line.label })) : null] }, `x-${index}`));
528
+ }
529
+ return null;
530
+ }) }));
531
+ }
470
532
  export function ChartsLegend() {
471
533
  const { series, hidden, toggleSeries } = useChartContext();
472
534
  return (_jsx(ChartLegend, { items: series.map((item) => ({ id: item.id, label: item.label, color: item.color })), hiddenIds: hidden, onToggle: toggleSeries }));
@@ -0,0 +1,81 @@
1
+ import type { ReactNode } from "react";
2
+ export type ChartTooltipItem = {
3
+ color: string;
4
+ label: string;
5
+ value: string;
6
+ };
7
+ export type ChartHover = {
8
+ x: number;
9
+ y: number;
10
+ title?: string;
11
+ items: ChartTooltipItem[];
12
+ dataIndex?: number;
13
+ seriesId?: string;
14
+ category?: string | number | Date;
15
+ } | null;
16
+ /** Payload fired when a chart mark (bar, slice, point, cell) is activated. */
17
+ export type ChartItemEvent = {
18
+ seriesId: string;
19
+ seriesLabel: string;
20
+ dataIndex: number;
21
+ category: string | number | Date;
22
+ value: number | null;
23
+ color: string;
24
+ };
25
+ /** Geometry plus item identity, used by `renderMark` on line and area series. */
26
+ export type ChartMarkRenderContext = ChartItemEvent & {
27
+ x: number;
28
+ y: number;
29
+ };
30
+ /**
31
+ * Overlay guide on a cartesian plot.
32
+ * Set `y` for a horizontal value line, or `xIndex` for a vertical category line.
33
+ */
34
+ export type ChartReferenceLine = {
35
+ y?: number;
36
+ xIndex?: number;
37
+ yAxisId?: string;
38
+ color?: string;
39
+ label?: string;
40
+ strokeDasharray?: string;
41
+ };
42
+ export type ChartTooltipRenderer = (hover: NonNullable<ChartHover>) => ReactNode;
43
+ export type ChartMarkBind = {
44
+ className: string;
45
+ role?: "button";
46
+ tabIndex?: number;
47
+ "aria-label"?: string;
48
+ onClick?: (event: {
49
+ stopPropagation(): void;
50
+ }) => void;
51
+ onKeyDown?: (event: {
52
+ key: string;
53
+ preventDefault(): void;
54
+ }) => void;
55
+ onMouseEnter?: (event: {
56
+ nativeEvent: {
57
+ offsetX: number;
58
+ offsetY: number;
59
+ };
60
+ }) => void;
61
+ onMouseLeave?: () => void;
62
+ };
63
+ /** Per-category color, falling back to the series token. */
64
+ export declare function seriesItemColor(color: string, itemColors: Array<string | null | undefined> | undefined, index: number): string;
65
+ export declare function chartItemAriaLabel(event: ChartItemEvent): string;
66
+ /**
67
+ * Pointer, keyboard, and hover bindings for an SVG mark.
68
+ * Adds a button role only when `onItemClick` is set so legends stay the sole named buttons.
69
+ */
70
+ export declare function bindChartMark({ event, hover, onItemClick, setHover, clearHover, onHighlight, }: {
71
+ event: ChartItemEvent;
72
+ hover: Pick<NonNullable<ChartHover>, "title" | "items"> & Partial<NonNullable<ChartHover>>;
73
+ onItemClick?: (event: ChartItemEvent) => void;
74
+ setHover: (hover: ChartHover) => void;
75
+ clearHover: () => void;
76
+ onHighlight?: (item: {
77
+ seriesId: string;
78
+ dataIndex: number;
79
+ } | null) => void;
80
+ }): ChartMarkBind;
81
+ //# sourceMappingURL=chart-interaction.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"chart-interaction.d.ts","sourceRoot":"","sources":["../../src/composites/chart-interaction.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,56 @@
1
+ import { cn } from "../lib/cn";
2
+ /** Per-category color, falling back to the series token. */
3
+ export function seriesItemColor(color, itemColors, index) {
4
+ return itemColors?.[index] || color;
5
+ }
6
+ export function chartItemAriaLabel(event) {
7
+ const category = String(event.category);
8
+ if (event.seriesLabel && event.seriesLabel !== category) {
9
+ return `${event.seriesLabel} ${category}`;
10
+ }
11
+ return category;
12
+ }
13
+ /**
14
+ * Pointer, keyboard, and hover bindings for an SVG mark.
15
+ * Adds a button role only when `onItemClick` is set so legends stay the sole named buttons.
16
+ */
17
+ export function bindChartMark({ event, hover, onItemClick, setHover, clearHover, onHighlight, }) {
18
+ const clickable = Boolean(onItemClick);
19
+ const applyHover = (x, y) => {
20
+ onHighlight?.({ seriesId: event.seriesId, dataIndex: event.dataIndex });
21
+ setHover({
22
+ x: hover.x ?? x,
23
+ y: hover.y ?? y,
24
+ title: hover.title,
25
+ items: hover.items,
26
+ dataIndex: event.dataIndex,
27
+ seriesId: event.seriesId,
28
+ category: event.category,
29
+ });
30
+ };
31
+ return {
32
+ className: cn("spk-chart-mark", clickable && "spk-chart-mark--interactive"),
33
+ role: clickable ? "button" : undefined,
34
+ tabIndex: clickable ? 0 : undefined,
35
+ "aria-label": clickable ? chartItemAriaLabel(event) : undefined,
36
+ onClick: clickable
37
+ ? (native) => {
38
+ native.stopPropagation();
39
+ onItemClick?.(event);
40
+ }
41
+ : undefined,
42
+ onKeyDown: clickable
43
+ ? (native) => {
44
+ if (native.key === "Enter" || native.key === " ") {
45
+ native.preventDefault();
46
+ onItemClick?.(event);
47
+ }
48
+ }
49
+ : undefined,
50
+ onMouseEnter: (native) => applyHover(native.nativeEvent.offsetX, native.nativeEvent.offsetY),
51
+ onMouseLeave: () => {
52
+ onHighlight?.(null);
53
+ clearHover();
54
+ },
55
+ };
56
+ }
@@ -1,31 +1,25 @@
1
1
  import { type ReactNode } from "react";
2
2
  import { type ChartAxisConfig, type ChartMargin } from "../lib/charts";
3
- export type ChartTooltipItem = {
4
- color: string;
5
- label: string;
6
- value: string;
7
- };
3
+ import { type ChartHover, type ChartTooltipRenderer } from "./chart-interaction";
4
+ export type { ChartHover, ChartTooltipItem } from "./chart-interaction";
8
5
  export type ChartLegendItem = {
9
6
  id: string;
10
7
  label: string;
11
8
  color: string;
12
9
  };
13
- export type ChartHover = {
14
- x: number;
15
- y: number;
16
- title?: string;
17
- items: ChartTooltipItem[];
18
- } | null;
19
10
  export type ChartFrameProps = {
20
11
  slot: string;
21
12
  className?: string;
22
13
  width?: number;
23
14
  height?: number;
15
+ /** When true, plot height follows the parent instead of the numeric `height`. */
16
+ fillHeight?: boolean;
24
17
  margin?: ChartMargin;
25
18
  legend?: ChartLegendItem[];
26
19
  hiddenIds?: Set<string>;
27
20
  onToggleSeries?: (id: string) => void;
28
21
  hover?: ChartHover;
22
+ renderTooltip?: ChartTooltipRenderer;
29
23
  "aria-label"?: string;
30
24
  children: (plot: {
31
25
  width: number;
@@ -34,15 +28,16 @@ export type ChartFrameProps = {
34
28
  }) => ReactNode;
35
29
  };
36
30
  export declare function resolveMargin(margin?: ChartMargin): Required<ChartMargin>;
37
- export declare function ChartFrame({ slot, className, width, height, margin, legend, hiddenIds, onToggleSeries, hover, "aria-label": ariaLabel, children, }: ChartFrameProps): import("react").JSX.Element;
31
+ export declare function ChartFrame({ slot, className, width, height, fillHeight, margin, legend, hiddenIds, onToggleSeries, hover, renderTooltip, "aria-label": ariaLabel, children, }: ChartFrameProps): import("react").JSX.Element;
38
32
  export declare function ChartLegend({ items, hiddenIds, onToggle, }: {
39
33
  items: ChartLegendItem[];
40
34
  hiddenIds?: Set<string>;
41
35
  onToggle?: (id: string) => void;
42
36
  }): import("react").JSX.Element;
43
- export declare function ChartTooltip({ hover, boundsWidth, }: {
37
+ export declare function ChartTooltip({ hover, boundsWidth, render, }: {
44
38
  hover: ChartHover;
45
39
  boundsWidth: number;
40
+ render?: ChartTooltipRenderer;
46
41
  }): import("react").JSX.Element | null;
47
42
  export declare function CartesianGrid({ ticks, scale, left, right, top, bottom, }: {
48
43
  ticks: number[];
@@ -1 +1 @@
1
- {"version":3,"file":"chart-ui.d.ts","sourceRoot":"","sources":["../../src/composites/chart-ui.tsx"],"names":[],"mappings":"AAAA,OAAO,EAIL,KAAK,SAAS,EAEf,MAAM,OAAO,CAAC;AAEf,OAAO,EAKL,KAAK,eAAe,EACpB,KAAK,WAAW,EACjB,MAAM,eAAe,CAAC;AAEvB,MAAM,MAAM,gBAAgB,GAAG;IAC7B,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,MAAM,CAAC;CACf,CAAC;AAEF,MAAM,MAAM,eAAe,GAAG;IAC5B,EAAE,EAAE,MAAM,CAAC;IACX,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,MAAM,CAAC;CACf,CAAC;AAEF,MAAM,MAAM,UAAU,GAAG;IACvB,CAAC,EAAE,MAAM,CAAC;IACV,CAAC,EAAE,MAAM,CAAC;IACV,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,KAAK,EAAE,gBAAgB,EAAE,CAAC;CAC3B,GAAG,IAAI,CAAC;AAET,MAAM,MAAM,eAAe,GAAG;IAC5B,IAAI,EAAE,MAAM,CAAC;IACb,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,MAAM,CAAC,EAAE,WAAW,CAAC;IACrB,MAAM,CAAC,EAAE,eAAe,EAAE,CAAC;IAC3B,SAAS,CAAC,EAAE,GAAG,CAAC,MAAM,CAAC,CAAC;IACxB,cAAc,CAAC,EAAE,CAAC,EAAE,EAAE,MAAM,KAAK,IAAI,CAAC;IACtC,KAAK,CAAC,EAAE,UAAU,CAAC;IACnB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,QAAQ,EAAE,CAAC,IAAI,EAAE;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAC;QAAC,CAAC,EAAE,QAAQ,CAAC,WAAW,CAAC,CAAA;KAAE,KAAK,SAAS,CAAC;CAC5F,CAAC;AAEF,wBAAgB,aAAa,CAAC,MAAM,CAAC,EAAE,WAAW,GAAG,QAAQ,CAAC,WAAW,CAAC,CAOzE;AA4BD,wBAAgB,UAAU,CAAC,EACzB,IAAI,EACJ,SAAS,EACT,KAAK,EACL,MAAY,EACZ,MAAM,EACN,MAAM,EACN,SAAS,EACT,cAAc,EACd,KAAK,EACL,YAAY,EAAE,SAAS,EACvB,QAAQ,GACT,EAAE,eAAe,+BA2BjB;AAED,wBAAgB,WAAW,CAAC,EAC1B,KAAK,EACL,SAAS,EACT,QAAQ,GACT,EAAE;IACD,KAAK,EAAE,eAAe,EAAE,CAAC;IACzB,SAAS,CAAC,EAAE,GAAG,CAAC,MAAM,CAAC,CAAC;IACxB,QAAQ,CAAC,EAAE,CAAC,EAAE,EAAE,MAAM,KAAK,IAAI,CAAC;CACjC,+BAiBA;AAED,wBAAgB,YAAY,CAAC,EAC3B,KAAK,EACL,WAAW,GACZ,EAAE;IACD,KAAK,EAAE,UAAU,CAAC;IAClB,WAAW,EAAE,MAAM,CAAC;CACrB,sCAiBA;AAUD,wBAAgB,aAAa,CAAC,EAC5B,KAAK,EACL,KAAK,EACL,IAAI,EACJ,KAAK,EACL,GAAG,EACH,MAAM,GACP,EAAE;IACD,KAAK,EAAE,MAAM,EAAE,CAAC;IAChB,KAAK,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,MAAM,CAAC;IACjC,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,MAAM,CAAC;IACd,GAAG,EAAE,MAAM,CAAC;IACZ,MAAM,EAAE,MAAM,CAAC;CAChB,+BAiBA;AAED,wBAAgB,SAAS,CAAC,EACxB,KAAK,EACL,KAAK,EACL,IAAI,EACJ,KAAK,GACN,EAAE;IACD,KAAK,EAAE,MAAM,EAAE,CAAC;IAChB,KAAK,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,MAAM,CAAC;IACjC,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB,+BA0BA;AAED,wBAAgB,YAAY,CAAC,EAC3B,MAAM,EACN,QAAQ,EACR,CAAC,GACF,EAAE;IACD,MAAM,EAAE,KAAK,CAAC,MAAM,GAAG,MAAM,GAAG,IAAI,CAAC,CAAC;IACtC,QAAQ,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,MAAM,CAAC;IACpC,CAAC,EAAE,MAAM,CAAC;CACX,+BAoBA;AAED,wBAAgB,eAAe,CAAC,GAAG,EAAE,MAAM,EAAE;;iBAEvB,MAAM;;EAU3B;AAED,wBAAgB,UAAU,CACxB,MAAM,EAAE,KAAK,CAAC;IAAE,EAAE,CAAC,EAAE,MAAM,CAAC;IAAC,KAAK,CAAC,EAAE,MAAM,CAAC;IAAC,KAAK,CAAC,EAAE,MAAM,CAAA;CAAE,CAAC,EAC9D,MAAM,CAAC,EAAE,MAAM,EAAE,GAChB,eAAe,EAAE,CAMnB;AAED,wBAAgB,aAAa;;;;EAG5B;AAED,wBAAgB,cAAc,CAAC,IAAI,CAAC,EAAE,eAAe,EAAE,MAAM,SAAI,GAAG,KAAK,CAAC,MAAM,GAAG,MAAM,GAAG,IAAI,CAAC,CAGhG;AAED,wBAAgB,iBAAiB,CAAC,KAAK,EAAE,MAAM,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,GAAG,SAAS,UAI7E"}
1
+ {"version":3,"file":"chart-ui.d.ts","sourceRoot":"","sources":["../../src/composites/chart-ui.tsx"],"names":[],"mappings":"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"}
@@ -1,4 +1,4 @@
1
- import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
1
+ import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
2
2
  import { useEffect, useRef, useState, } from "react";
3
3
  import { cn } from "../lib/cn";
4
4
  import { DEFAULT_CHART_MARGIN, chartColor, formatAxisValue, formatChartNumber, } from "../lib/charts";
@@ -31,22 +31,25 @@ function useElementSize(ref, fallbackWidth, fallbackHeight) {
31
31
  }, [fallbackWidth, fallbackHeight, ref]);
32
32
  return size;
33
33
  }
34
- export function ChartFrame({ slot, className, width, height = 280, margin, legend, hiddenIds, onToggleSeries, hover, "aria-label": ariaLabel, children, }) {
34
+ export function ChartFrame({ slot, className, width, height = 280, fillHeight = false, margin, legend, hiddenIds, onToggleSeries, hover, renderTooltip, "aria-label": ariaLabel, children, }) {
35
35
  const surfaceRef = useRef(null);
36
36
  const measured = useElementSize(surfaceRef, width ?? 320, height);
37
37
  const plotWidth = width ?? measured.width;
38
- const plotHeight = height;
38
+ const plotHeight = fillHeight ? measured.height : height;
39
39
  const m = resolveMargin(margin);
40
- return (_jsxs("div", { "data-slot": slot, className: cn("spk-chart", className), role: "img", "aria-label": ariaLabel, children: [legend?.length ? (_jsx(ChartLegend, { items: legend, hiddenIds: hiddenIds, onToggle: onToggleSeries })) : null, _jsxs("div", { ref: surfaceRef, className: "spk-chart-surface", style: { height: plotHeight }, children: [plotWidth > 0 ? children({ width: plotWidth, height: plotHeight, m }) : null, _jsx(ChartTooltip, { hover: hover ?? null, boundsWidth: plotWidth })] })] }));
40
+ return (_jsxs("div", { "data-slot": slot, className: cn("spk-chart", fillHeight && "spk-chart--fill", className), role: "img", "aria-label": ariaLabel, children: [legend?.length ? (_jsx(ChartLegend, { items: legend, hiddenIds: hiddenIds, onToggle: onToggleSeries })) : null, _jsxs("div", { ref: surfaceRef, className: "spk-chart-surface", style: fillHeight ? undefined : { height: plotHeight }, children: [plotWidth > 0 && plotHeight > 0 ? children({ width: plotWidth, height: plotHeight, m }) : null, _jsx(ChartTooltip, { hover: hover ?? null, boundsWidth: plotWidth, render: renderTooltip })] })] }));
41
41
  }
42
42
  export function ChartLegend({ items, hiddenIds, onToggle, }) {
43
43
  return (_jsx("div", { className: "spk-chart-legend", children: items.map((item) => (_jsxs("button", { type: "button", className: "spk-chart-legend-item", "data-hidden": hiddenIds?.has(item.id) ? "true" : undefined, onClick: () => onToggle?.(item.id), children: [_jsx("span", { className: "spk-chart-swatch", style: { background: item.color } }), item.label] }, item.id))) }));
44
44
  }
45
- export function ChartTooltip({ hover, boundsWidth, }) {
45
+ export function ChartTooltip({ hover, boundsWidth, render, }) {
46
46
  if (!hover || !hover.items.length)
47
47
  return null;
48
+ const custom = render?.(hover);
49
+ if (render && custom == null)
50
+ return null;
48
51
  const left = clampTooltip(hover.x, boundsWidth);
49
- return (_jsxs("div", { className: "spk-chart-tooltip", style: { left, top: hover.y }, role: "tooltip", children: [hover.title ? _jsx("p", { className: "spk-chart-tooltip-title", children: hover.title }) : null, _jsx("ul", { children: hover.items.map((item) => (_jsxs("li", { children: [_jsx("span", { className: "spk-chart-swatch", style: { background: item.color } }), _jsx("span", { children: item.label }), _jsx("strong", { children: item.value })] }, item.label))) })] }));
52
+ return (_jsx("div", { className: "spk-chart-tooltip", style: { left, top: hover.y }, role: "tooltip", children: render ? (custom) : (_jsxs(_Fragment, { children: [hover.title ? _jsx("p", { className: "spk-chart-tooltip-title", children: hover.title }) : null, _jsx("ul", { children: hover.items.map((item) => (_jsxs("li", { children: [_jsx("span", { className: "spk-chart-swatch", style: { background: item.color } }), _jsx("span", { children: item.label }), _jsx("strong", { children: item.value })] }, item.label))) })] })) }));
50
53
  }
51
54
  function clampTooltip(x, width) {
52
55
  return clampNum(x, 72, Math.max(72, width - 72));
@@ -1,4 +1,5 @@
1
1
  import { type ChartAxisConfig, type ChartMargin, type SankeyLink, type SankeyNode, type TreeNode } from "../lib/charts";
2
+ import { type ChartItemEvent, type ChartTooltipRenderer } from "./chart-interaction";
2
3
  export type HeatDatum = {
3
4
  x: number;
4
5
  y: number;
@@ -16,8 +17,12 @@ export type HeatmapProps = {
16
17
  showColorScale?: boolean;
17
18
  margin?: ChartMargin;
18
19
  className?: string;
20
+ fillHeight?: boolean;
21
+ onItemClick?: (event: ChartItemEvent) => void;
22
+ renderTooltip?: ChartTooltipRenderer;
23
+ showCellLabels?: boolean | ((cell: HeatDatum) => string);
19
24
  };
20
- export declare function Heatmap({ xAxis, yAxis, series, height, width, hideLegend, showColorScale, margin, className, }: HeatmapProps): import("react").JSX.Element;
25
+ export declare function Heatmap({ xAxis, yAxis, series, height, width, hideLegend, showColorScale, margin, className, fillHeight, onItemClick, renderTooltip, showCellLabels, }: HeatmapProps): import("react").JSX.Element;
21
26
  export type FunnelDatum = {
22
27
  id?: string;
23
28
  label: string;
@@ -1 +1 @@
1
- {"version":3,"file":"flow-charts.d.ts","sourceRoot":"","sources":["../../src/composites/flow-charts.tsx"],"names":[],"mappings":"AACA,OAAO,EAUL,KAAK,eAAe,EACpB,KAAK,WAAW,EAChB,KAAK,UAAU,EACf,KAAK,UAAU,EACf,KAAK,QAAQ,EACd,MAAM,eAAe,CAAC;AASvB,MAAM,MAAM,SAAS,GAAG;IAAE,CAAC,EAAE,MAAM,CAAC;IAAC,CAAC,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,CAAC;AAEhE,MAAM,MAAM,YAAY,GAAG;IACzB,KAAK,CAAC,EAAE,eAAe,EAAE,CAAC;IAC1B,KAAK,CAAC,EAAE,eAAe,EAAE,CAAC;IAC1B,MAAM,EAAE,KAAK,CAAC;QAAE,IAAI,EAAE,SAAS,EAAE,CAAA;KAAE,CAAC,CAAC;IACrC,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,cAAc,CAAC,EAAE,OAAO,CAAC;IACzB,MAAM,CAAC,EAAE,WAAW,CAAC;IACrB,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB,CAAC;AAEF,wBAAgB,OAAO,CAAC,EACtB,KAAK,EACL,KAAK,EACL,MAAM,EACN,MAAY,EACZ,KAAK,EACL,UAAU,EACV,cAAc,EACd,MAAM,EACN,SAAS,GACV,EAAE,YAAY,+BAqHd;AAED,MAAM,MAAM,WAAW,GAAG;IAAE,EAAE,CAAC,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,CAAC;IAAC,KAAK,CAAC,EAAE,MAAM,CAAA;CAAE,CAAC;AAExF,MAAM,MAAM,YAAY,GAAG;IACzB,EAAE,CAAC,EAAE,MAAM,CAAC;IACZ,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,IAAI,EAAE,WAAW,EAAE,CAAC;CACrB,CAAC;AAEF,MAAM,MAAM,mBAAmB,GAAG,QAAQ,GAAG,SAAS,GAAG,MAAM,CAAC;AAEhE,MAAM,MAAM,gBAAgB,GAAG;IAC7B,MAAM,EAAE,YAAY,EAAE,CAAC;IACvB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,MAAM,CAAC,EAAE,MAAM,EAAE,CAAC;IAClB,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,OAAO,CAAC,EAAE,QAAQ,GAAG,SAAS,CAAC;IAC/B,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,aAAa,CAAC,EAAE,mBAAmB,CAAC;IACpC,cAAc,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,KAAK,MAAM,CAAC;CAC7D,CAAC;AAEF,wBAAgB,WAAW,CAAC,EAC1B,MAAM,EACN,MAAY,EACZ,KAAK,EACL,MAAM,EACN,UAAU,EACV,SAAS,EACT,OAAkB,EAClB,GAAO,EACP,aAAa,EACb,cAAc,GACf,EAAE,gBAAgB,+BAgIlB;AAED,wBAAgB,YAAY,CAAC,KAAK,EAAE,gBAAgB,+BAEnD;AAED,MAAM,MAAM,gBAAgB,GAAG;IAC7B,MAAM,EAAE;QAAE,IAAI,EAAE,UAAU,EAAE,CAAC;QAAC,KAAK,EAAE,UAAU,EAAE,CAAA;KAAE,CAAC;IACpD,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,MAAM,CAAC,EAAE,MAAM,EAAE,CAAC;IAClB,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB,CAAC;AAEF,wBAAgB,WAAW,CAAC,EAAE,MAAM,EAAE,MAAY,EAAE,KAAK,EAAE,MAAM,EAAE,SAAS,EAAE,EAAE,gBAAgB,+BAkE/F;AAED,MAAM,MAAM,YAAY,GAAG;IACzB,MAAM,EAAE,KAAK,CAAC;QAAE,IAAI,EAAE,QAAQ,EAAE,CAAA;KAAE,CAAC,CAAC;IACpC,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,MAAM,CAAC,EAAE,MAAM,EAAE,CAAC;IAClB,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB,CAAC;AAEF,wBAAgB,OAAO,CAAC,EAAE,MAAM,EAAE,MAAY,EAAE,KAAK,EAAE,MAAM,EAAE,SAAS,EAAE,EAAE,YAAY,+BA2DvF;AAED,MAAM,MAAM,kBAAkB,GAAG;IAC/B,MAAM,EAAE,KAAK,CAAC;QAAE,IAAI,EAAE,QAAQ,EAAE,CAAA;KAAE,CAAC,CAAC;IACpC,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,MAAM,CAAC,EAAE,MAAM,EAAE,CAAC;IAClB,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB,CAAC;AAEF,wBAAgB,aAAa,CAAC,EAAE,MAAM,EAAE,MAAY,EAAE,KAAK,EAAE,MAAM,EAAE,SAAS,EAAE,EAAE,kBAAkB,+BAkDnG;AAED,MAAM,MAAM,eAAe,GAAG;IAC5B,MAAM,EAAE;QAAE,IAAI,EAAE,MAAM,EAAE,CAAC;QAAC,MAAM,EAAE,MAAM,EAAE,EAAE,CAAA;KAAE,CAAC;IAC/C,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,MAAM,CAAC,EAAE,MAAM,EAAE,CAAC;IAClB,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB,CAAC;AAEF,wBAAgB,UAAU,CAAC,EAAE,MAAM,EAAE,MAAY,EAAE,KAAK,EAAE,MAAM,EAAE,SAAS,EAAE,EAAE,eAAe,+BAyD7F"}
1
+ {"version":3,"file":"flow-charts.d.ts","sourceRoot":"","sources":["../../src/composites/flow-charts.tsx"],"names":[],"mappings":"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"}