@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.
- package/dist/composites/EventCalendar.d.ts +13 -2
- package/dist/composites/EventCalendar.d.ts.map +1 -1
- package/dist/composites/EventCalendar.js +10 -24
- package/dist/composites/cartesian-charts.d.ts +12 -2
- package/dist/composites/cartesian-charts.d.ts.map +1 -1
- package/dist/composites/cartesian-charts.js +27 -13
- package/dist/composites/chart-composition.d.ts +19 -1
- package/dist/composites/chart-composition.d.ts.map +1 -1
- package/dist/composites/chart-composition.js +124 -62
- package/dist/composites/chart-interaction.d.ts +81 -0
- package/dist/composites/chart-interaction.d.ts.map +1 -0
- package/dist/composites/chart-interaction.js +56 -0
- package/dist/composites/chart-ui.d.ts +8 -13
- package/dist/composites/chart-ui.d.ts.map +1 -1
- package/dist/composites/chart-ui.js +9 -6
- package/dist/composites/flow-charts.d.ts +6 -1
- package/dist/composites/flow-charts.d.ts.map +1 -1
- package/dist/composites/flow-charts.js +28 -14
- package/dist/composites/radial-charts.d.ts +11 -1
- package/dist/composites/radial-charts.d.ts.map +1 -1
- package/dist/composites/radial-charts.js +33 -14
- package/dist/composites/scheduler-ui.d.ts +14 -1
- package/dist/composites/scheduler-ui.d.ts.map +1 -1
- package/dist/composites/scheduler-ui.js +23 -2
- package/dist/index.d.ts +8 -6
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +4 -4
- package/dist/lib/chips.d.ts +3 -0
- package/dist/lib/chips.d.ts.map +1 -1
- package/dist/lib/chips.js +10 -0
- package/dist/lib/scheduler.d.ts +12 -0
- package/dist/lib/scheduler.d.ts.map +1 -1
- package/dist/lib/scheduler.js +22 -0
- package/dist/primitives/NativeSelect.d.ts +10 -1
- package/dist/primitives/NativeSelect.d.ts.map +1 -1
- package/dist/primitives/NativeSelect.js +2 -2
- package/package.json +2 -2
- package/skills/spatika-ui/SKILL.md +4 -0
- package/src/composites/EventCalendar.tsx +35 -24
- package/src/composites/cartesian-charts.test.tsx +86 -2
- package/src/composites/cartesian-charts.tsx +84 -16
- package/src/composites/chart-composition.test.tsx +15 -0
- package/src/composites/chart-composition.tsx +229 -88
- package/src/composites/chart-interaction.ts +136 -0
- package/src/composites/chart-ui.tsx +35 -27
- package/src/composites/flow-charts.test.tsx +21 -2
- package/src/composites/flow-charts.tsx +59 -25
- package/src/composites/radial-charts.test.tsx +17 -2
- package/src/composites/radial-charts.tsx +38 -12
- package/src/composites/scheduler-ui.tsx +128 -26
- package/src/composites/scheduler.test.tsx +39 -0
- package/src/index.test.ts +4 -0
- package/src/index.ts +18 -1
- package/src/lib/chips.ts +16 -0
- package/src/lib/scheduler.test.ts +16 -0
- package/src/lib/scheduler.ts +34 -0
- package/src/primitives/NativeSelect.test.tsx +28 -0
- 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,
|
|
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
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
ctx.
|
|
374
|
-
|
|
375
|
-
|
|
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) =>
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
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
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
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
|
|
452
|
-
{ color
|
|
493
|
+
{ color, label: "x", value: formatChartNumber(point.x, ctx.locale) },
|
|
494
|
+
{ color, label: "y", value: formatChartNumber(point.y, ctx.locale) },
|
|
453
495
|
],
|
|
454
|
-
}
|
|
455
|
-
|
|
456
|
-
ctx.
|
|
457
|
-
ctx.setHover(null)
|
|
458
|
-
|
|
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":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,OAAO,CAAC;AAGvC,MAAM,MAAM,gBAAgB,GAAG;IAC7B,KAAK,EAAE,MAAM,CAAC;IACd,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;IAC1B,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,QAAQ,CAAC,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAAC;CACnC,GAAG,IAAI,CAAC;AAET,8EAA8E;AAC9E,MAAM,MAAM,cAAc,GAAG;IAC3B,QAAQ,EAAE,MAAM,CAAC;IACjB,WAAW,EAAE,MAAM,CAAC;IACpB,SAAS,EAAE,MAAM,CAAC;IAClB,QAAQ,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAAC;IACjC,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;IACrB,KAAK,EAAE,MAAM,CAAC;CACf,CAAC;AAEF,iFAAiF;AACjF,MAAM,MAAM,sBAAsB,GAAG,cAAc,GAAG;IACpD,CAAC,EAAE,MAAM,CAAC;IACV,CAAC,EAAE,MAAM,CAAC;CACX,CAAC;AAEF;;;GAGG;AACH,MAAM,MAAM,kBAAkB,GAAG;IAC/B,CAAC,CAAC,EAAE,MAAM,CAAC;IACX,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,eAAe,CAAC,EAAE,MAAM,CAAC;CAC1B,CAAC;AAEF,MAAM,MAAM,oBAAoB,GAAG,CAAC,KAAK,EAAE,WAAW,CAAC,UAAU,CAAC,KAAK,SAAS,CAAC;AAEjF,MAAM,MAAM,aAAa,GAAG;IAC1B,SAAS,EAAE,MAAM,CAAC;IAClB,IAAI,CAAC,EAAE,QAAQ,CAAC;IAChB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,OAAO,CAAC,EAAE,CAAC,KAAK,EAAE;QAAE,eAAe,IAAI,IAAI,CAAA;KAAE,KAAK,IAAI,CAAC;IACvD,SAAS,CAAC,EAAE,CAAC,KAAK,EAAE;QAAE,GAAG,EAAE,MAAM,CAAC;QAAC,cAAc,IAAI,IAAI,CAAA;KAAE,KAAK,IAAI,CAAC;IACrE,YAAY,CAAC,EAAE,CAAC,KAAK,EAAE;QAAE,WAAW,EAAE;YAAE,OAAO,EAAE,MAAM,CAAC;YAAC,OAAO,EAAE,MAAM,CAAA;SAAE,CAAA;KAAE,KAAK,IAAI,CAAC;IACtF,YAAY,CAAC,EAAE,MAAM,IAAI,CAAC;CAC3B,CAAC;AAEF,4DAA4D;AAC5D,wBAAgB,eAAe,CAC7B,KAAK,EAAE,MAAM,EACb,UAAU,EAAE,KAAK,CAAC,MAAM,GAAG,IAAI,GAAG,SAAS,CAAC,GAAG,SAAS,EACxD,KAAK,EAAE,MAAM,GACZ,MAAM,CAER;AAED,wBAAgB,kBAAkB,CAAC,KAAK,EAAE,cAAc,GAAG,MAAM,CAMhE;AAED;;;GAGG;AACH,wBAAgB,aAAa,CAAC,EAC5B,KAAK,EACL,KAAK,EACL,WAAW,EACX,QAAQ,EACR,UAAU,EACV,WAAW,GACZ,EAAE;IACD,KAAK,EAAE,cAAc,CAAC;IACtB,KAAK,EAAE,IAAI,CAAC,WAAW,CAAC,UAAU,CAAC,EAAE,OAAO,GAAG,OAAO,CAAC,GAAG,OAAO,CAAC,WAAW,CAAC,UAAU,CAAC,CAAC,CAAC;IAC3F,WAAW,CAAC,EAAE,CAAC,KAAK,EAAE,cAAc,KAAK,IAAI,CAAC;IAC9C,QAAQ,EAAE,CAAC,KAAK,EAAE,UAAU,KAAK,IAAI,CAAC;IACtC,UAAU,EAAE,MAAM,IAAI,CAAC;IACvB,WAAW,CAAC,EAAE,CAAC,IAAI,EAAE;QAAE,QAAQ,EAAE,MAAM,CAAC;QAAC,SAAS,EAAE,MAAM,CAAA;KAAE,GAAG,IAAI,KAAK,IAAI,CAAC;CAC9E,GAAG,aAAa,CAuChB"}
|
|
@@ -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
|
-
|
|
4
|
-
|
|
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;
|
|
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 (
|
|
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;
|
|
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;AAQvB,OAAO,EAAiB,KAAK,cAAc,EAAE,KAAK,oBAAoB,EAAE,MAAM,qBAAqB,CAAC;AAEpG,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;IACnB,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,WAAW,CAAC,EAAE,CAAC,KAAK,EAAE,cAAc,KAAK,IAAI,CAAC;IAC9C,aAAa,CAAC,EAAE,oBAAoB,CAAC;IACrC,cAAc,CAAC,EAAE,OAAO,GAAG,CAAC,CAAC,IAAI,EAAE,SAAS,KAAK,MAAM,CAAC,CAAC;CAC1D,CAAC;AAEF,wBAAgB,OAAO,CAAC,EACtB,KAAK,EACL,KAAK,EACL,MAAM,EACN,MAAY,EACZ,KAAK,EACL,UAAU,EACV,cAAc,EACd,MAAM,EACN,SAAS,EACT,UAAU,EACV,WAAW,EACX,aAAa,EACb,cAAsB,GACvB,EAAE,YAAY,+BA8Id;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"}
|