@nocoo/basalt 2.0.3 → 2.1.2
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/README.md +134 -15
- package/ai/COMPATIBILITY.md +180 -0
- package/ai/INTEGRATION.md +1760 -0
- package/ai/RECIPES.md +161 -0
- package/ai/USAGE.md +99 -0
- package/ai/registry.json +38099 -0
- package/ai/sources.json +10 -0
- package/dist/assets/brand-mark.d.ts +1 -0
- package/dist/assets/brand-mark.js +7 -0
- package/dist/assets/brand-mark.js.map +1 -0
- package/dist/charts/area.d.ts +58 -5
- package/dist/charts/area.js +20 -12
- package/dist/charts/area.js.map +1 -1
- package/dist/charts/bar.d.ts +54 -5
- package/dist/charts/bar.js +16 -10
- package/dist/charts/bar.js.map +1 -1
- package/dist/charts/bullet.d.ts +18 -1
- package/dist/charts/bullet.js +6 -3
- package/dist/charts/bullet.js.map +1 -1
- package/dist/charts/charts.d.ts +58 -5
- package/dist/charts/charts.js +13 -2
- package/dist/charts/charts.js.map +1 -1
- package/dist/charts/config.d.ts +7 -0
- package/dist/charts/config.js +5 -1
- package/dist/charts/config.js.map +1 -1
- package/dist/charts/custom-chart.d.ts +58 -5
- package/dist/charts/custom-chart.js +13 -2
- package/dist/charts/custom-chart.js.map +1 -1
- package/dist/charts/donut.d.ts +18 -1
- package/dist/charts/donut.js +6 -3
- package/dist/charts/donut.js.map +1 -1
- package/dist/charts/frame.d.ts +40 -3
- package/dist/charts/frame.js +55 -28
- package/dist/charts/frame.js.map +1 -1
- package/dist/charts/funnel.d.ts +18 -1
- package/dist/charts/funnel.js +5 -1
- package/dist/charts/funnel.js.map +1 -1
- package/dist/charts/gauge.d.ts +18 -1
- package/dist/charts/gauge.js +38 -20
- package/dist/charts/gauge.js.map +1 -1
- package/dist/charts/grouped-bar.d.ts +54 -5
- package/dist/charts/grouped-bar.js +16 -10
- package/dist/charts/grouped-bar.js.map +1 -1
- package/dist/charts/heatmap-calendar.d.ts +61 -0
- package/dist/charts/heatmap-calendar.js +287 -96
- package/dist/charts/heatmap-calendar.js.map +1 -1
- package/dist/charts/heatmap-matrix.d.ts +99 -0
- package/dist/charts/heatmap-matrix.js +249 -0
- package/dist/charts/heatmap-matrix.js.map +1 -0
- package/dist/charts/line.d.ts +66 -5
- package/dist/charts/line.js +37 -30
- package/dist/charts/line.js.map +1 -1
- package/dist/charts/palette.d.ts +1 -0
- package/dist/charts/palette.js +7 -1
- package/dist/charts/palette.js.map +1 -1
- package/dist/charts/radar.d.ts +18 -1
- package/dist/charts/radar.js +26 -19
- package/dist/charts/radar.js.map +1 -1
- package/dist/charts/sankey.d.ts +18 -1
- package/dist/charts/sankey.js +4 -1
- package/dist/charts/sankey.js.map +1 -1
- package/dist/charts/series.d.ts +5 -7
- package/dist/charts/series.js.map +1 -1
- package/dist/charts/slot-bar.d.ts +38 -6
- package/dist/charts/slot-bar.js +5 -2
- package/dist/charts/slot-bar.js.map +1 -1
- package/dist/charts/sparkline.d.ts +35 -5
- package/dist/charts/sparkline.js +22 -18
- package/dist/charts/sparkline.js.map +1 -1
- package/dist/charts/stacked-bar.d.ts +58 -5
- package/dist/charts/stacked-bar.js +19 -12
- package/dist/charts/stacked-bar.js.map +1 -1
- package/dist/charts/stat-card.d.ts +51 -1
- package/dist/charts/stat-card.js +66 -39
- package/dist/charts/stat-card.js.map +1 -1
- package/dist/charts/timeline.d.ts +3 -0
- package/dist/charts/timeline.js +4 -3
- package/dist/charts/timeline.js.map +1 -1
- package/dist/charts/timeseries.d.ts +58 -5
- package/dist/charts/timeseries.js +13 -2
- package/dist/charts/timeseries.js.map +1 -1
- package/dist/charts/tooltip.d.ts +57 -0
- package/dist/charts/tooltip.js +119 -2
- package/dist/charts/tooltip.js.map +1 -1
- package/dist/components/accordion.d.ts +117 -2
- package/dist/components/accordion.js +20 -13
- package/dist/components/accordion.js.map +1 -1
- package/dist/components/alert-dialog.d.ts +131 -13
- package/dist/components/alert-dialog.js +12 -9
- package/dist/components/alert-dialog.js.map +1 -1
- package/dist/components/app-header.js +18 -17
- package/dist/components/app-header.js.map +1 -1
- package/dist/components/app-shell.js +15 -14
- package/dist/components/app-shell.js.map +1 -1
- package/dist/components/autocomplete.d.ts +4 -0
- package/dist/components/autocomplete.js.map +1 -1
- package/dist/components/avatar.d.ts +76 -3
- package/dist/components/avatar.js.map +1 -1
- package/dist/components/badge.d.ts +15 -1
- package/dist/components/badge.js +13 -12
- package/dist/components/badge.js.map +1 -1
- package/dist/components/banner.d.ts +88 -2
- package/dist/components/banner.js +41 -40
- package/dist/components/banner.js.map +1 -1
- package/dist/components/basalt-mark.js +14 -8
- package/dist/components/basalt-mark.js.map +1 -1
- package/dist/components/battery-meter.d.ts +10 -0
- package/dist/components/battery-meter.js +56 -0
- package/dist/components/battery-meter.js.map +1 -0
- package/dist/components/breadcrumbs.d.ts +27 -7
- package/dist/components/breadcrumbs.js +21 -20
- package/dist/components/breadcrumbs.js.map +1 -1
- package/dist/components/button.d.ts +48 -2
- package/dist/components/button.js +87 -36
- package/dist/components/button.js.map +1 -1
- package/dist/components/chat-bubble.d.ts +7 -0
- package/dist/components/chat-bubble.js +14 -13
- package/dist/components/chat-bubble.js.map +1 -1
- package/dist/components/chat-composer.d.ts +7 -3
- package/dist/components/chat-composer.js.map +1 -1
- package/dist/components/chat-header.d.ts +6 -1
- package/dist/components/chat-header.js +17 -16
- package/dist/components/chat-header.js.map +1 -1
- package/dist/components/chat-inbox.d.ts +7 -2
- package/dist/components/chat-inbox.js.map +1 -1
- package/dist/components/checkbox.js +84 -53
- package/dist/components/checkbox.js.map +1 -1
- package/dist/components/clipboard-text.d.ts +13 -2
- package/dist/components/clipboard-text.js +4 -4
- package/dist/components/clipboard-text.js.map +1 -1
- package/dist/components/collapsible.d.ts +58 -15
- package/dist/components/collapsible.js.map +1 -1
- package/dist/components/command-palette.d.ts +151 -61
- package/dist/components/command-palette.js.map +1 -1
- package/dist/components/confirm-dialog.d.ts +1 -1
- package/dist/components/confirm-dialog.js +6 -4
- package/dist/components/confirm-dialog.js.map +1 -1
- package/dist/components/context-menu.d.ts +210 -2
- package/dist/components/context-menu.js +7 -4
- package/dist/components/context-menu.js.map +1 -1
- package/dist/components/data-table.d.ts +40 -2
- package/dist/components/data-table.js +168 -120
- package/dist/components/data-table.js.map +1 -1
- package/dist/components/date-picker.d.ts +53 -2
- package/dist/components/date-picker.js +387 -219
- package/dist/components/date-picker.js.map +1 -1
- package/dist/components/delete-resource.d.ts +7 -1
- package/dist/components/delete-resource.js +22 -18
- package/dist/components/delete-resource.js.map +1 -1
- package/dist/components/description-list.js +16 -15
- package/dist/components/description-list.js.map +1 -1
- package/dist/components/dialog.d.ts +141 -12
- package/dist/components/dialog.js +42 -38
- package/dist/components/dialog.js.map +1 -1
- package/dist/components/dock.d.ts +1 -1
- package/dist/components/dock.js +39 -58
- package/dist/components/dock.js.map +1 -1
- package/dist/components/dropdown-menu.d.ts +229 -15
- package/dist/components/dropdown-menu.js +9 -6
- package/dist/components/dropdown-menu.js.map +1 -1
- package/dist/components/editable-nav-item.d.ts +33 -0
- package/dist/components/editable-nav-item.js +90 -0
- package/dist/components/editable-nav-item.js.map +1 -0
- package/dist/components/empty.d.ts +22 -2
- package/dist/components/empty.js +22 -13
- package/dist/components/empty.js.map +1 -1
- package/dist/components/field.js +31 -30
- package/dist/components/field.js.map +1 -1
- package/dist/components/file-dropzone.d.ts +37 -0
- package/dist/components/file-dropzone.js +103 -0
- package/dist/components/file-dropzone.js.map +1 -0
- package/dist/components/filter-bar.d.ts +34 -0
- package/dist/components/filter-bar.js +52 -0
- package/dist/components/filter-bar.js.map +1 -0
- package/dist/components/flow.js +19 -18
- package/dist/components/flow.js.map +1 -1
- package/dist/components/grid.d.ts +3 -1
- package/dist/components/grid.js.map +1 -1
- package/dist/components/hover-card.d.ts +111 -1
- package/dist/components/hover-card.js +9 -6
- package/dist/components/hover-card.js.map +1 -1
- package/dist/components/icon-picker.d.ts +34 -0
- package/dist/components/icon-picker.js +77 -0
- package/dist/components/icon-picker.js.map +1 -0
- package/dist/components/inline-editable.d.ts +46 -0
- package/dist/components/inline-editable.js +124 -0
- package/dist/components/inline-editable.js.map +1 -0
- package/dist/components/input-area.js +3 -3
- package/dist/components/input-group.js +7 -7
- package/dist/components/input.js +3 -3
- package/dist/components/label.js +18 -17
- package/dist/components/label.js.map +1 -1
- package/dist/components/layer-card.d.ts +10 -2
- package/dist/components/layer-card.js +71 -68
- package/dist/components/layer-card.js.map +1 -1
- package/dist/components/loader.d.ts +10 -2
- package/dist/components/loader.js.map +1 -1
- package/dist/components/menu-bar.d.ts +174 -6
- package/dist/components/menu-bar.js +33 -29
- package/dist/components/menu-bar.js.map +1 -1
- package/dist/components/meter.d.ts +27 -2
- package/dist/components/meter.js.map +1 -1
- package/dist/components/multi-select.d.ts +64 -0
- package/dist/components/multi-select.js +218 -0
- package/dist/components/multi-select.js.map +1 -0
- package/dist/components/navigation-menu.d.ts +88 -5
- package/dist/components/navigation-menu.js.map +1 -1
- package/dist/components/overlay.js +6 -5
- package/dist/components/overlay.js.map +1 -1
- package/dist/components/page-header.js +23 -21
- package/dist/components/page-header.js.map +1 -1
- package/dist/components/pagination.js +7 -7
- package/dist/components/popover.d.ts +136 -16
- package/dist/components/popover.js +32 -28
- package/dist/components/popover.js.map +1 -1
- package/dist/components/radio.js +38 -37
- package/dist/components/radio.js.map +1 -1
- package/dist/components/resource-list.d.ts +26 -1
- package/dist/components/resource-list.js +28 -15
- package/dist/components/resource-list.js.map +1 -1
- package/dist/components/responsive-master-detail.d.ts +27 -0
- package/dist/components/responsive-master-detail.js +85 -0
- package/dist/components/responsive-master-detail.js.map +1 -0
- package/dist/components/section-rule.js +23 -22
- package/dist/components/section-rule.js.map +1 -1
- package/dist/components/select.d.ts +27 -3
- package/dist/components/select.js +11 -11
- package/dist/components/select.js.map +1 -1
- package/dist/components/sheet.d.ts +115 -11
- package/dist/components/sheet.js +37 -30
- package/dist/components/sheet.js.map +1 -1
- package/dist/components/sidebar.d.ts +109 -17
- package/dist/components/sidebar.js +112 -111
- package/dist/components/sidebar.js.map +1 -1
- package/dist/components/skeleton-line.d.ts +22 -2
- package/dist/components/skeleton-line.js.map +1 -1
- package/dist/components/slider.d.ts +61 -1
- package/dist/components/slider.js +31 -15
- package/dist/components/slider.js.map +1 -1
- package/dist/components/stat-strip.js +16 -15
- package/dist/components/stat-strip.js.map +1 -1
- package/dist/components/switch.js +78 -47
- package/dist/components/switch.js.map +1 -1
- package/dist/components/table-of-contents.js +18 -17
- package/dist/components/table-of-contents.js.map +1 -1
- package/dist/components/table-pager.js +20 -19
- package/dist/components/table-pager.js.map +1 -1
- package/dist/components/table.d.ts +9 -3
- package/dist/components/table.js +19 -18
- package/dist/components/table.js.map +1 -1
- package/dist/components/tabs.js +29 -22
- package/dist/components/tabs.js.map +1 -1
- package/dist/components/tag-badge.d.ts +58 -0
- package/dist/components/tag-badge.js +72 -0
- package/dist/components/tag-badge.js.map +1 -0
- package/dist/components/tag-color-picker.d.ts +20 -0
- package/dist/components/tag-color-picker.js +42 -0
- package/dist/components/tag-color-picker.js.map +1 -0
- package/dist/components/text.js +17 -16
- package/dist/components/text.js.map +1 -1
- package/dist/components/toast.d.ts +173 -3
- package/dist/components/toast.js +1 -1
- package/dist/components/toast.js.map +1 -1
- package/dist/components/toggle-group.d.ts +88 -2
- package/dist/components/toggle-group.js +32 -31
- package/dist/components/toggle-group.js.map +1 -1
- package/dist/components/toggle.d.ts +35 -2
- package/dist/components/toggle.js +12 -11
- package/dist/components/toggle.js.map +1 -1
- package/dist/components/tooltip.d.ts +144 -6
- package/dist/components/tooltip.js +9 -6
- package/dist/components/tooltip.js.map +1 -1
- package/dist/components/typeahead-field.js +193 -132
- package/dist/components/typeahead-field.js.map +1 -1
- package/dist/components/upload-queue.d.ts +51 -0
- package/dist/components/upload-queue.js +116 -0
- package/dist/components/upload-queue.js.map +1 -0
- package/dist/providers/accent.d.ts +46 -2
- package/dist/providers/accent.js +358 -172
- package/dist/providers/accent.js.map +1 -1
- package/dist/providers/link.d.ts +14 -4
- package/dist/providers/link.js.map +1 -1
- package/dist/providers/theme.d.ts +38 -2
- package/dist/providers/theme.js +160 -27
- package/dist/providers/theme.js.map +1 -1
- package/dist/styles/base.css +83 -0
- package/dist/styles/standalone.css +699 -120
- package/dist/styles/tailwind.css +21 -7
- package/dist/styles/tokens.css +145 -91
- package/dist/utils/control-surface.d.ts +2 -1
- package/dist/utils/control-surface.js +4 -4
- package/dist/utils/control-surface.js.map +1 -1
- package/dist/utils/selection-indicator.js +2 -2
- package/dist/utils/selection-indicator.js.map +1 -1
- package/package.json +8 -4
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
import { type ComponentProps, type ReactNode } from "react";
|
|
2
|
+
export type HeatmapMatrixValue = number | null | undefined;
|
|
3
|
+
export interface HeatmapMatrixCellContext {
|
|
4
|
+
rowIndex: number;
|
|
5
|
+
colIndex: number;
|
|
6
|
+
rowLabel: string;
|
|
7
|
+
columnLabel: string;
|
|
8
|
+
value: HeatmapMatrixValue;
|
|
9
|
+
formattedValue: string;
|
|
10
|
+
isMissing: boolean;
|
|
11
|
+
colorIndex: number;
|
|
12
|
+
}
|
|
13
|
+
export interface HeatmapMatrixProps extends Omit<ComponentProps<"div">, "children"> {
|
|
14
|
+
/**
|
|
15
|
+
* Ordered row labels (e.g. weekdays ["Mon", "Tue", ...], service tiers, or regions).
|
|
16
|
+
*/
|
|
17
|
+
rowLabels: readonly string[];
|
|
18
|
+
/**
|
|
19
|
+
* Ordered column labels (e.g. 24 hours ["00:00", ...], days, or status buckets).
|
|
20
|
+
*/
|
|
21
|
+
columnLabels: readonly string[];
|
|
22
|
+
/**
|
|
23
|
+
* 2D matrix of values indexed by [rowIndex][colIndex].
|
|
24
|
+
* Supports ragged rows, null, undefined, and non-finite values (treated as missing).
|
|
25
|
+
* Numeric `0` is a valid reading and distinct from missing data.
|
|
26
|
+
*/
|
|
27
|
+
values: readonly (readonly HeatmapMatrixValue[])[];
|
|
28
|
+
/**
|
|
29
|
+
* Explicit [min, max] domain for color intensity scaling.
|
|
30
|
+
* If reversed [max, min], bounds are automatically normalized to [min, max].
|
|
31
|
+
* If equal [v, v], values <= v receive level 0 while values > v clamp to the highest level.
|
|
32
|
+
* If non-finite or omitted, dynamically derived solely from visible finite numeric cells in the dataset (or [0, 0] if no finite values exist).
|
|
33
|
+
* Values at or below min receive level 0; values >= max clamp to the highest level.
|
|
34
|
+
*/
|
|
35
|
+
domain?: readonly [min: number, max: number];
|
|
36
|
+
/**
|
|
37
|
+
* Sequential color palette array from lowest to highest intensity.
|
|
38
|
+
* If empty or single-color, gracefully resolves to base level.
|
|
39
|
+
* @default heatmapColorScales.green
|
|
40
|
+
*/
|
|
41
|
+
colorScale?: readonly string[];
|
|
42
|
+
/**
|
|
43
|
+
* Formatter for numeric values displayed in tooltips and accessible labels.
|
|
44
|
+
* Defaults to `value.toLocaleString()`.
|
|
45
|
+
*/
|
|
46
|
+
valueFormatter?: (value: number) => string;
|
|
47
|
+
/**
|
|
48
|
+
* Placeholder string used for missing/null/undefined readings.
|
|
49
|
+
* @default "—"
|
|
50
|
+
*/
|
|
51
|
+
missingLabel?: string;
|
|
52
|
+
/**
|
|
53
|
+
* Accessible label describing the matrix purpose or metric name.
|
|
54
|
+
* @default "Heatmap matrix"
|
|
55
|
+
*/
|
|
56
|
+
metricLabel?: string;
|
|
57
|
+
/**
|
|
58
|
+
* Accessible name for the entire grid region.
|
|
59
|
+
* @default "Heatmap matrix"
|
|
60
|
+
*/
|
|
61
|
+
ariaLabel?: string;
|
|
62
|
+
/**
|
|
63
|
+
* Pixel height (and default width) of each matrix data cell.
|
|
64
|
+
* @default 16
|
|
65
|
+
*/
|
|
66
|
+
cellSize?: number;
|
|
67
|
+
/**
|
|
68
|
+
* Pixel width of each matrix column / data cell.
|
|
69
|
+
* When omitted, falls back to `cellSize` for square cells.
|
|
70
|
+
* Allows wider rectangular cells to fit readable column headers (e.g. timestamps or service names).
|
|
71
|
+
*/
|
|
72
|
+
columnWidth?: number;
|
|
73
|
+
/**
|
|
74
|
+
* Pixel gap between adjacent cells.
|
|
75
|
+
* @default 2
|
|
76
|
+
*/
|
|
77
|
+
cellGap?: number;
|
|
78
|
+
/**
|
|
79
|
+
* Text for lowest bound legend.
|
|
80
|
+
* @default "Less"
|
|
81
|
+
*/
|
|
82
|
+
lessLabel?: string;
|
|
83
|
+
/**
|
|
84
|
+
* Text for highest bound legend.
|
|
85
|
+
* @default "More"
|
|
86
|
+
*/
|
|
87
|
+
moreLabel?: string;
|
|
88
|
+
/**
|
|
89
|
+
* Whether to show the bottom intensity scale legend.
|
|
90
|
+
* @default true
|
|
91
|
+
*/
|
|
92
|
+
showLegend?: boolean;
|
|
93
|
+
/**
|
|
94
|
+
* Custom cell tooltip content renderer.
|
|
95
|
+
* If provided, replaces the default tooltip contents.
|
|
96
|
+
*/
|
|
97
|
+
renderTooltip?: (cell: HeatmapMatrixCellContext) => ReactNode;
|
|
98
|
+
}
|
|
99
|
+
export declare const HeatmapMatrix: import("react").ForwardRefExoticComponent<Omit<HeatmapMatrixProps, "ref"> & import("react").RefAttributes<HTMLDivElement>>;
|
|
@@ -0,0 +1,249 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { cn as e } from "../utils/cn.js";
|
|
3
|
+
import { Tooltip as t, TooltipContent as n, TooltipProvider as r, TooltipTrigger as i } from "../components/tooltip.js";
|
|
4
|
+
import { heatmapColorScales as a } from "./heatmap-calendar.js";
|
|
5
|
+
import { forwardRef as o, useCallback as s, useEffect as c, useId as l, useMemo as u, useRef as d, useState as f } from "react";
|
|
6
|
+
import { Fragment as p, jsx as m, jsxs as h } from "react/jsx-runtime";
|
|
7
|
+
//#region src/charts/heatmap-matrix.tsx
|
|
8
|
+
function g(e, t, n, r) {
|
|
9
|
+
if (e == null || typeof e != "number" || !Number.isFinite(e)) return -1;
|
|
10
|
+
if (r <= 1) return 0;
|
|
11
|
+
let i = r - 1;
|
|
12
|
+
if (n <= t) return e > t ? i : 0;
|
|
13
|
+
let a = (Math.max(t, Math.min(n, e)) - t) / (n - t);
|
|
14
|
+
return a <= 0 ? 0 : Math.min(i, Math.ceil(a * i));
|
|
15
|
+
}
|
|
16
|
+
var _ = o(function({ rowLabels: o, columnLabels: _, values: v, domain: y, colorScale: b = a.green, valueFormatter: x = (e) => e.toLocaleString(), missingLabel: S = "—", metricLabel: C = "Heatmap matrix", ariaLabel: w = "Heatmap matrix", cellSize: T = 16, columnWidth: E, cellGap: D = 2, lessLabel: O = "Less", moreLabel: ee = "More", showLegend: te = !0, renderTooltip: k, className: A, style: j, onFocus: M, onBlur: N, onKeyDown: P, ...F }, I) {
|
|
17
|
+
let L = l(), R = o.length, z = _.length, B = E ?? T, [V, H] = u(() => {
|
|
18
|
+
if (y) {
|
|
19
|
+
let [e, t] = y;
|
|
20
|
+
if (Number.isFinite(e) && Number.isFinite(t)) return [Math.min(e, t), Math.max(e, t)];
|
|
21
|
+
}
|
|
22
|
+
let e = Infinity, t = -Infinity;
|
|
23
|
+
for (let n = 0; n < R; n++) {
|
|
24
|
+
let r = v[n];
|
|
25
|
+
if (r) for (let n = 0; n < z; n++) {
|
|
26
|
+
let i = r[n];
|
|
27
|
+
typeof i == "number" && Number.isFinite(i) && (i < e && (e = i), i > t && (t = i));
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
return !Number.isFinite(e) || !Number.isFinite(t) ? [0, 0] : [e, t];
|
|
31
|
+
}, [
|
|
32
|
+
y,
|
|
33
|
+
v,
|
|
34
|
+
R,
|
|
35
|
+
z
|
|
36
|
+
]), [U, W] = f([0, 0]), [G, K] = f(null), q = d(!1), J = d([0, 0]);
|
|
37
|
+
J.current = U;
|
|
38
|
+
let Y = d(null), X = d(/* @__PURE__ */ new Map()), Z = d(!1);
|
|
39
|
+
c(() => {
|
|
40
|
+
let e = Z.current;
|
|
41
|
+
if (R === 0 || z === 0) {
|
|
42
|
+
W(([e, t]) => e === 0 && t === 0 ? [e, t] : [0, 0]), K(null), e && Y.current?.focus();
|
|
43
|
+
return;
|
|
44
|
+
}
|
|
45
|
+
let [t, n] = J.current, r = Math.min(R - 1, Math.max(0, t)), i = Math.min(z - 1, Math.max(0, n));
|
|
46
|
+
if (W((e) => e[0] === r && e[1] === i ? e : [r, i]), e) {
|
|
47
|
+
let e = `${r}-${i}`, t = X.current.get(e);
|
|
48
|
+
t && document.activeElement !== t && t.focus();
|
|
49
|
+
}
|
|
50
|
+
}, [R, z]);
|
|
51
|
+
let ne = (e) => {
|
|
52
|
+
if (e.key === "Escape" && (q.current = !0, K(null)), P?.(e), e.defaultPrevented || R === 0 || z === 0 || e.key === "Escape") return;
|
|
53
|
+
let [t, n] = J.current, r = t, i = n;
|
|
54
|
+
if (e.key === "ArrowRight") i = Math.min(z - 1, n + 1);
|
|
55
|
+
else if (e.key === "ArrowLeft") i = Math.max(0, n - 1);
|
|
56
|
+
else if (e.key === "ArrowDown") r = Math.min(R - 1, t + 1);
|
|
57
|
+
else if (e.key === "ArrowUp") r = Math.max(0, t - 1);
|
|
58
|
+
else if (e.key === "Home") i = 0;
|
|
59
|
+
else if (e.key === "End") i = z - 1;
|
|
60
|
+
else if (e.key === "PageUp") r = 0;
|
|
61
|
+
else if (e.key === "PageDown") r = R - 1;
|
|
62
|
+
else return;
|
|
63
|
+
e.preventDefault(), q.current = !1, W([r, i]);
|
|
64
|
+
let a = `${r}-${i}`;
|
|
65
|
+
K(a);
|
|
66
|
+
let o = X.current.get(a);
|
|
67
|
+
if (o) {
|
|
68
|
+
o.focus();
|
|
69
|
+
let e = o.closest("[role=\"region\"][aria-label$=\"scrollable table\"]"), t = o.closest("tr")?.querySelector("th[scope=\"row\"]");
|
|
70
|
+
if (e) {
|
|
71
|
+
let n = e.getBoundingClientRect(), r = o.getBoundingClientRect(), i = t ? t.getBoundingClientRect().width : 0, a = n.left + i, s = n.right;
|
|
72
|
+
r.left < a ? e.scrollLeft -= a - r.left + D : r.right > s && (e.scrollLeft += r.right - s + D);
|
|
73
|
+
} else typeof o.scrollIntoView == "function" && o.scrollIntoView({
|
|
74
|
+
block: "nearest",
|
|
75
|
+
inline: "nearest"
|
|
76
|
+
});
|
|
77
|
+
}
|
|
78
|
+
}, re = (e) => {
|
|
79
|
+
Z.current = !0, M?.(e);
|
|
80
|
+
}, ie = (e) => {
|
|
81
|
+
e.currentTarget.contains(e.relatedTarget) || (Z.current = !1, q.current = !1), N?.(e);
|
|
82
|
+
}, Q = d(void 0), ae = s((e) => {
|
|
83
|
+
if (Y.current = e, Q.current &&= (Q.current(), void 0), typeof I == "function") {
|
|
84
|
+
let t = I(e);
|
|
85
|
+
typeof t == "function" && (Q.current = t);
|
|
86
|
+
} else I && (I.current = e);
|
|
87
|
+
return () => {
|
|
88
|
+
Y.current = null, Q.current ? (Q.current(), Q.current = void 0) : typeof I == "function" ? I(null) : I && (I.current = null);
|
|
89
|
+
};
|
|
90
|
+
}, [I]), $ = R === 0 || z === 0;
|
|
91
|
+
return /* @__PURE__ */ m(r, { children: /* @__PURE__ */ m("div", {
|
|
92
|
+
ref: ae,
|
|
93
|
+
tabIndex: $ ? -1 : void 0,
|
|
94
|
+
role: "region",
|
|
95
|
+
"aria-label": w,
|
|
96
|
+
"data-testid": "heatmap-matrix",
|
|
97
|
+
className: e("flex flex-col gap-2 rounded-lg border border-basalt-border/60 bg-basalt-card p-3 text-xs outline-none", $ ? "text-basalt-muted-foreground" : "text-basalt-foreground", A),
|
|
98
|
+
style: j,
|
|
99
|
+
onFocus: re,
|
|
100
|
+
onBlur: ie,
|
|
101
|
+
onKeyDown: ne,
|
|
102
|
+
...F,
|
|
103
|
+
children: $ ? /* @__PURE__ */ m("span", {
|
|
104
|
+
className: "italic",
|
|
105
|
+
children: S
|
|
106
|
+
}) : /* @__PURE__ */ h(p, { children: [/* @__PURE__ */ m("div", {
|
|
107
|
+
tabIndex: -1,
|
|
108
|
+
role: "region",
|
|
109
|
+
"aria-label": `${w} scrollable table`,
|
|
110
|
+
className: "w-full overflow-x-auto outline-none",
|
|
111
|
+
children: /* @__PURE__ */ h("table", {
|
|
112
|
+
role: "grid",
|
|
113
|
+
"aria-label": w,
|
|
114
|
+
className: "border-separate",
|
|
115
|
+
style: { borderSpacing: D },
|
|
116
|
+
children: [/* @__PURE__ */ m("thead", { children: /* @__PURE__ */ h("tr", { children: [/* @__PURE__ */ m("th", {
|
|
117
|
+
scope: "col",
|
|
118
|
+
className: "sticky left-0 z-10 bg-basalt-card p-0 text-left font-normal",
|
|
119
|
+
style: { minWidth: 64 },
|
|
120
|
+
children: /* @__PURE__ */ m("span", {
|
|
121
|
+
className: "sr-only",
|
|
122
|
+
children: "Row \\ Column"
|
|
123
|
+
})
|
|
124
|
+
}), _.map((e, t) => /* @__PURE__ */ m("th", {
|
|
125
|
+
scope: "col",
|
|
126
|
+
className: "p-0 text-center font-mono text-[10px] text-basalt-muted-foreground select-none",
|
|
127
|
+
style: {
|
|
128
|
+
width: B,
|
|
129
|
+
maxWidth: B,
|
|
130
|
+
overflow: "hidden",
|
|
131
|
+
textOverflow: "ellipsis",
|
|
132
|
+
whiteSpace: "nowrap"
|
|
133
|
+
},
|
|
134
|
+
title: e,
|
|
135
|
+
children: e
|
|
136
|
+
}, `${L}-col-${t}`))] }) }), /* @__PURE__ */ m("tbody", { children: o.map((e, r) => /* @__PURE__ */ h("tr", { children: [/* @__PURE__ */ m("th", {
|
|
137
|
+
scope: "row",
|
|
138
|
+
className: "sticky left-0 z-10 bg-basalt-card pr-2 text-left font-medium text-basalt-foreground select-none",
|
|
139
|
+
style: {
|
|
140
|
+
lineHeight: `${T}px`,
|
|
141
|
+
minWidth: 64,
|
|
142
|
+
whiteSpace: "nowrap"
|
|
143
|
+
},
|
|
144
|
+
children: e
|
|
145
|
+
}), _.map((a, o) => {
|
|
146
|
+
let s = `${r}-${o}`, c = v[r]?.[o], l = c == null || typeof c != "number" || !Number.isFinite(c), u = g(c, V, H, b.length), d = l ? S : x(c), f = u < 0 ? "hsl(var(--basalt-muted) / 0.4)" : b[u] ?? "hsl(var(--basalt-muted))", p = `${e}, ${a}: ${d} (${C})`, _ = U[0] === r && U[1] === o, y = G === s, w = {
|
|
147
|
+
rowIndex: r,
|
|
148
|
+
colIndex: o,
|
|
149
|
+
rowLabel: e,
|
|
150
|
+
columnLabel: a,
|
|
151
|
+
value: c,
|
|
152
|
+
formattedValue: d,
|
|
153
|
+
isMissing: l,
|
|
154
|
+
colorIndex: u
|
|
155
|
+
};
|
|
156
|
+
return /* @__PURE__ */ m("td", {
|
|
157
|
+
role: "gridcell",
|
|
158
|
+
className: "p-0 text-center",
|
|
159
|
+
children: /* @__PURE__ */ h(t, {
|
|
160
|
+
open: y,
|
|
161
|
+
onOpenChange: (e) => {
|
|
162
|
+
e ? q.current || K(s) : K((e) => e === s ? q.current ? null : document.activeElement === X.current.get(s) ? e : null : e);
|
|
163
|
+
},
|
|
164
|
+
children: [/* @__PURE__ */ m(i, {
|
|
165
|
+
asChild: !0,
|
|
166
|
+
children: /* @__PURE__ */ m("button", {
|
|
167
|
+
ref: (e) => {
|
|
168
|
+
e ? X.current.set(s, e) : X.current.delete(s);
|
|
169
|
+
},
|
|
170
|
+
type: "button",
|
|
171
|
+
"aria-label": p,
|
|
172
|
+
tabIndex: _ ? 0 : -1,
|
|
173
|
+
onFocus: () => {
|
|
174
|
+
W([r, o]), q.current = !1, K(s);
|
|
175
|
+
},
|
|
176
|
+
onBlur: () => {
|
|
177
|
+
K((e) => e === s ? null : e);
|
|
178
|
+
},
|
|
179
|
+
className: "box-border block cursor-pointer rounded-xs border-0 p-0 transition-colors hover:ring-1 hover:ring-basalt-foreground focus-visible:outline-2 focus-visible:outline-offset-1 focus-visible:outline-basalt-ring",
|
|
180
|
+
style: {
|
|
181
|
+
width: B,
|
|
182
|
+
height: T,
|
|
183
|
+
backgroundColor: f
|
|
184
|
+
}
|
|
185
|
+
})
|
|
186
|
+
}), /* @__PURE__ */ m(n, {
|
|
187
|
+
id: `${L}-${s}`,
|
|
188
|
+
onEscapeKeyDown: () => {
|
|
189
|
+
q.current = !0, K(null);
|
|
190
|
+
},
|
|
191
|
+
children: k ? k(w) : /* @__PURE__ */ h("div", {
|
|
192
|
+
className: "text-xs",
|
|
193
|
+
children: [/* @__PURE__ */ h("div", {
|
|
194
|
+
className: "font-semibold text-basalt-popover-foreground",
|
|
195
|
+
children: [
|
|
196
|
+
e,
|
|
197
|
+
" · ",
|
|
198
|
+
a
|
|
199
|
+
]
|
|
200
|
+
}), /* @__PURE__ */ h("div", {
|
|
201
|
+
className: "text-basalt-muted-foreground",
|
|
202
|
+
children: [
|
|
203
|
+
C,
|
|
204
|
+
":",
|
|
205
|
+
" ",
|
|
206
|
+
/* @__PURE__ */ m("span", {
|
|
207
|
+
className: "font-medium text-basalt-popover-foreground",
|
|
208
|
+
children: d
|
|
209
|
+
})
|
|
210
|
+
]
|
|
211
|
+
})]
|
|
212
|
+
})
|
|
213
|
+
})]
|
|
214
|
+
})
|
|
215
|
+
}, s);
|
|
216
|
+
})] }, `${L}-row-${r}`)) })]
|
|
217
|
+
})
|
|
218
|
+
}), te ? /* @__PURE__ */ h("div", {
|
|
219
|
+
className: "mt-1 flex items-center justify-end gap-1 text-[11px] text-basalt-muted-foreground select-none",
|
|
220
|
+
"aria-hidden": "true",
|
|
221
|
+
children: [
|
|
222
|
+
/* @__PURE__ */ m("span", { children: O }),
|
|
223
|
+
/* @__PURE__ */ m("div", {
|
|
224
|
+
className: "rounded-xs",
|
|
225
|
+
title: "Missing data",
|
|
226
|
+
style: {
|
|
227
|
+
width: T,
|
|
228
|
+
height: T,
|
|
229
|
+
backgroundColor: "hsl(var(--basalt-muted) / 0.4)"
|
|
230
|
+
}
|
|
231
|
+
}),
|
|
232
|
+
b.map((e, t) => /* @__PURE__ */ m("div", {
|
|
233
|
+
className: "rounded-xs",
|
|
234
|
+
style: {
|
|
235
|
+
width: T,
|
|
236
|
+
height: T,
|
|
237
|
+
backgroundColor: e
|
|
238
|
+
}
|
|
239
|
+
}, `${e}-${t}`)),
|
|
240
|
+
/* @__PURE__ */ m("span", { children: ee })
|
|
241
|
+
]
|
|
242
|
+
}) : null] })
|
|
243
|
+
}) });
|
|
244
|
+
});
|
|
245
|
+
_.displayName = "HeatmapMatrix";
|
|
246
|
+
//#endregion
|
|
247
|
+
export { _ as HeatmapMatrix };
|
|
248
|
+
|
|
249
|
+
//# sourceMappingURL=heatmap-matrix.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"heatmap-matrix.js","names":[],"sources":["../../src/charts/heatmap-matrix.tsx"],"sourcesContent":["import {\n\ttype ComponentProps,\n\ttype FocusEvent,\n\tforwardRef,\n\ttype KeyboardEvent,\n\ttype ReactNode,\n\tuseCallback,\n\tuseEffect,\n\tuseId,\n\tuseMemo,\n\tuseRef,\n\tuseState,\n} from \"react\";\nimport { Tooltip, TooltipContent, TooltipProvider, TooltipTrigger } from \"../components/tooltip\";\nimport { cn } from \"../utils/cn\";\nimport { heatmapColorScales } from \"./heatmap-calendar\";\n\nexport type HeatmapMatrixValue = number | null | undefined;\n\nexport interface HeatmapMatrixCellContext {\n\trowIndex: number;\n\tcolIndex: number;\n\trowLabel: string;\n\tcolumnLabel: string;\n\tvalue: HeatmapMatrixValue;\n\tformattedValue: string;\n\tisMissing: boolean;\n\tcolorIndex: number;\n}\n\nexport interface HeatmapMatrixProps extends Omit<ComponentProps<\"div\">, \"children\"> {\n\t/**\n\t * Ordered row labels (e.g. weekdays [\"Mon\", \"Tue\", ...], service tiers, or regions).\n\t */\n\trowLabels: readonly string[];\n\t/**\n\t * Ordered column labels (e.g. 24 hours [\"00:00\", ...], days, or status buckets).\n\t */\n\tcolumnLabels: readonly string[];\n\t/**\n\t * 2D matrix of values indexed by [rowIndex][colIndex].\n\t * Supports ragged rows, null, undefined, and non-finite values (treated as missing).\n\t * Numeric `0` is a valid reading and distinct from missing data.\n\t */\n\tvalues: readonly (readonly HeatmapMatrixValue[])[];\n\t/**\n\t * Explicit [min, max] domain for color intensity scaling.\n\t * If reversed [max, min], bounds are automatically normalized to [min, max].\n\t * If equal [v, v], values <= v receive level 0 while values > v clamp to the highest level.\n\t * If non-finite or omitted, dynamically derived solely from visible finite numeric cells in the dataset (or [0, 0] if no finite values exist).\n\t * Values at or below min receive level 0; values >= max clamp to the highest level.\n\t */\n\tdomain?: readonly [min: number, max: number];\n\t/**\n\t * Sequential color palette array from lowest to highest intensity.\n\t * If empty or single-color, gracefully resolves to base level.\n\t * @default heatmapColorScales.green\n\t */\n\tcolorScale?: readonly string[];\n\t/**\n\t * Formatter for numeric values displayed in tooltips and accessible labels.\n\t * Defaults to `value.toLocaleString()`.\n\t */\n\tvalueFormatter?: (value: number) => string;\n\t/**\n\t * Placeholder string used for missing/null/undefined readings.\n\t * @default \"—\"\n\t */\n\tmissingLabel?: string;\n\t/**\n\t * Accessible label describing the matrix purpose or metric name.\n\t * @default \"Heatmap matrix\"\n\t */\n\tmetricLabel?: string;\n\t/**\n\t * Accessible name for the entire grid region.\n\t * @default \"Heatmap matrix\"\n\t */\n\tariaLabel?: string;\n\t/**\n\t * Pixel height (and default width) of each matrix data cell.\n\t * @default 16\n\t */\n\tcellSize?: number;\n\t/**\n\t * Pixel width of each matrix column / data cell.\n\t * When omitted, falls back to `cellSize` for square cells.\n\t * Allows wider rectangular cells to fit readable column headers (e.g. timestamps or service names).\n\t */\n\tcolumnWidth?: number;\n\t/**\n\t * Pixel gap between adjacent cells.\n\t * @default 2\n\t */\n\tcellGap?: number;\n\t/**\n\t * Text for lowest bound legend.\n\t * @default \"Less\"\n\t */\n\tlessLabel?: string;\n\t/**\n\t * Text for highest bound legend.\n\t * @default \"More\"\n\t */\n\tmoreLabel?: string;\n\t/**\n\t * Whether to show the bottom intensity scale legend.\n\t * @default true\n\t */\n\tshowLegend?: boolean;\n\t/**\n\t * Custom cell tooltip content renderer.\n\t * If provided, replaces the default tooltip contents.\n\t */\n\trenderTooltip?: (cell: HeatmapMatrixCellContext) => ReactNode;\n}\n\nfunction resolveColorIndex(\n\tvalue: HeatmapMatrixValue,\n\tmin: number,\n\tmax: number,\n\tcolorScaleLength: number,\n): number {\n\tif (value == null || typeof value !== \"number\" || !Number.isFinite(value)) {\n\t\treturn -1; // missing indicator\n\t}\n\tif (colorScaleLength <= 1) {\n\t\treturn 0;\n\t}\n\tconst levels = colorScaleLength - 1;\n\tif (max <= min) {\n\t\treturn value > min ? levels : 0;\n\t}\n\tconst clamped = Math.max(min, Math.min(max, value));\n\tconst normalized = (clamped - min) / (max - min);\n\tif (normalized <= 0) {\n\t\treturn 0;\n\t}\n\treturn Math.min(levels, Math.ceil(normalized * levels));\n}\n\nexport const HeatmapMatrix = forwardRef<HTMLDivElement, HeatmapMatrixProps>(function HeatmapMatrix(\n\t{\n\t\trowLabels,\n\t\tcolumnLabels,\n\t\tvalues,\n\t\tdomain,\n\t\tcolorScale = heatmapColorScales.green,\n\t\tvalueFormatter = (val) => val.toLocaleString(),\n\t\tmissingLabel = \"—\",\n\t\tmetricLabel = \"Heatmap matrix\",\n\t\tariaLabel = \"Heatmap matrix\",\n\t\tcellSize = 16,\n\t\tcolumnWidth,\n\t\tcellGap = 2,\n\t\tlessLabel = \"Less\",\n\t\tmoreLabel = \"More\",\n\t\tshowLegend = true,\n\t\trenderTooltip,\n\t\tclassName,\n\t\tstyle,\n\t\tonFocus,\n\t\tonBlur,\n\t\tonKeyDown,\n\t\t...rest\n\t},\n\tref,\n) {\n\tconst matrixId = useId();\n\tconst numRows = rowLabels.length;\n\tconst numCols = columnLabels.length;\n\tconst effectiveColWidth = columnWidth ?? cellSize;\n\n\t// Derive domain restricted to visible row/col matrix bounds\n\tconst [minVal, maxVal] = useMemo(() => {\n\t\tif (domain) {\n\t\t\tconst [d0, d1] = domain;\n\t\t\tif (Number.isFinite(d0) && Number.isFinite(d1)) {\n\t\t\t\treturn [Math.min(d0, d1), Math.max(d0, d1)];\n\t\t\t}\n\t\t}\n\t\tlet lowest = Number.POSITIVE_INFINITY;\n\t\tlet highest = Number.NEGATIVE_INFINITY;\n\t\tfor (let r = 0; r < numRows; r++) {\n\t\t\tconst row = values[r];\n\t\t\tif (!row) continue;\n\t\t\tfor (let c = 0; c < numCols; c++) {\n\t\t\t\tconst v = row[c];\n\t\t\t\tif (typeof v === \"number\" && Number.isFinite(v)) {\n\t\t\t\t\tif (v < lowest) lowest = v;\n\t\t\t\t\tif (v > highest) highest = v;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\tif (!Number.isFinite(lowest) || !Number.isFinite(highest)) {\n\t\t\treturn [0, 0];\n\t\t}\n\t\treturn [lowest, highest];\n\t}, [domain, values, numRows, numCols]);\n\n\t// Focus state: active cell position [rowIndex, colIndex]\n\tconst [activePos, setActivePos] = useState<[number, number]>([0, 0]);\n\tconst [openTooltipPos, setOpenTooltipPos] = useState<string | null>(null);\n\tconst dismissedByEscapeRef = useRef(false);\n\n\tconst activePosRef = useRef<[number, number]>([0, 0]);\n\tactivePosRef.current = activePos;\n\n\tconst containerRef = useRef<HTMLDivElement | null>(null);\n\tconst cellRefs = useRef<Map<string, HTMLButtonElement>>(new Map());\n\tconst isFocusedInsideRef = useRef(false);\n\n\t// Clamp active position when dimensions change\n\tuseEffect(() => {\n\t\tconst hadFocus = isFocusedInsideRef.current;\n\t\tif (numRows === 0 || numCols === 0) {\n\t\t\tsetActivePos(([curR, curC]) => {\n\t\t\t\tif (curR === 0 && curC === 0) return [curR, curC];\n\t\t\t\treturn [0, 0];\n\t\t\t});\n\t\t\tsetOpenTooltipPos(null);\n\t\t\tif (hadFocus) {\n\t\t\t\tcontainerRef.current?.focus();\n\t\t\t}\n\t\t\treturn;\n\t\t}\n\n\t\tconst [curR, curC] = activePosRef.current;\n\t\tconst nextR = Math.min(numRows - 1, Math.max(0, curR));\n\t\tconst nextC = Math.min(numCols - 1, Math.max(0, curC));\n\n\t\tsetActivePos((prev) => {\n\t\t\tif (prev[0] === nextR && prev[1] === nextC) {\n\t\t\t\treturn prev;\n\t\t\t}\n\t\t\treturn [nextR, nextC];\n\t\t});\n\n\t\tif (hadFocus) {\n\t\t\tconst key = `${nextR}-${nextC}`;\n\t\t\tconst target = cellRefs.current.get(key);\n\t\t\tif (target && document.activeElement !== target) {\n\t\t\t\ttarget.focus();\n\t\t\t}\n\t\t}\n\t}, [numRows, numCols]);\n\n\tconst handleContainerKeyDown = (e: KeyboardEvent<HTMLDivElement>) => {\n\t\tif (e.key === \"Escape\") {\n\t\t\tdismissedByEscapeRef.current = true;\n\t\t\tsetOpenTooltipPos(null);\n\t\t}\n\n\t\t// Call caller onKeyDown first so caller can inspect or preventDefault\n\t\tonKeyDown?.(e);\n\t\tif (e.defaultPrevented) {\n\t\t\treturn;\n\t\t}\n\n\t\tif (numRows === 0 || numCols === 0) return;\n\t\tif (e.key === \"Escape\") return;\n\n\t\tconst [currentRow, currentCol] = activePosRef.current;\n\t\tlet nextR = currentRow;\n\t\tlet nextC = currentCol;\n\n\t\tif (e.key === \"ArrowRight\") {\n\t\t\tnextC = Math.min(numCols - 1, currentCol + 1);\n\t\t} else if (e.key === \"ArrowLeft\") {\n\t\t\tnextC = Math.max(0, currentCol - 1);\n\t\t} else if (e.key === \"ArrowDown\") {\n\t\t\tnextR = Math.min(numRows - 1, currentRow + 1);\n\t\t} else if (e.key === \"ArrowUp\") {\n\t\t\tnextR = Math.max(0, currentRow - 1);\n\t\t} else if (e.key === \"Home\") {\n\t\t\tnextC = 0;\n\t\t} else if (e.key === \"End\") {\n\t\t\tnextC = numCols - 1;\n\t\t} else if (e.key === \"PageUp\") {\n\t\t\tnextR = 0;\n\t\t} else if (e.key === \"PageDown\") {\n\t\t\tnextR = numRows - 1;\n\t\t} else {\n\t\t\treturn;\n\t\t}\n\n\t\te.preventDefault();\n\t\tdismissedByEscapeRef.current = false;\n\t\tsetActivePos([nextR, nextC]);\n\t\tconst nextKey = `${nextR}-${nextC}`;\n\t\tsetOpenTooltipPos(nextKey);\n\t\tconst targetButton = cellRefs.current.get(nextKey);\n\t\tif (targetButton) {\n\t\t\ttargetButton.focus();\n\t\t\tconst scrollContainer = targetButton.closest<HTMLElement>(\n\t\t\t\t'[role=\"region\"][aria-label$=\"scrollable table\"]',\n\t\t\t);\n\t\t\tconst rowHeader = targetButton.closest(\"tr\")?.querySelector<HTMLElement>('th[scope=\"row\"]');\n\n\t\t\tif (scrollContainer) {\n\t\t\t\tconst containerRect = scrollContainer.getBoundingClientRect();\n\t\t\t\tconst btnRect = targetButton.getBoundingClientRect();\n\t\t\t\tconst stickyWidth = rowHeader ? rowHeader.getBoundingClientRect().width : 0;\n\n\t\t\t\tconst visibleLeft = containerRect.left + stickyWidth;\n\t\t\t\tconst visibleRight = containerRect.right;\n\n\t\t\t\tif (btnRect.left < visibleLeft) {\n\t\t\t\t\tscrollContainer.scrollLeft -= visibleLeft - btnRect.left + cellGap;\n\t\t\t\t} else if (btnRect.right > visibleRight) {\n\t\t\t\t\tscrollContainer.scrollLeft += btnRect.right - visibleRight + cellGap;\n\t\t\t\t}\n\t\t\t} else if (typeof targetButton.scrollIntoView === \"function\") {\n\t\t\t\ttargetButton.scrollIntoView({ block: \"nearest\", inline: \"nearest\" });\n\t\t\t}\n\t\t}\n\t};\n\n\tconst handleContainerFocus = (e: FocusEvent<HTMLDivElement>) => {\n\t\tisFocusedInsideRef.current = true;\n\t\tonFocus?.(e);\n\t};\n\n\tconst handleContainerBlur = (e: FocusEvent<HTMLDivElement>) => {\n\t\tif (!e.currentTarget.contains(e.relatedTarget)) {\n\t\t\tisFocusedInsideRef.current = false;\n\t\t\tdismissedByEscapeRef.current = false;\n\t\t}\n\t\tonBlur?.(e);\n\t};\n\n\tconst callerCleanupRef = useRef<(() => void) | undefined>(undefined);\n\n\tconst setRootRef = useCallback(\n\t\t(node: HTMLDivElement | null) => {\n\t\t\tcontainerRef.current = node;\n\n\t\t\tif (callerCleanupRef.current) {\n\t\t\t\tcallerCleanupRef.current();\n\t\t\t\tcallerCleanupRef.current = undefined;\n\t\t\t}\n\n\t\t\tif (typeof ref === \"function\") {\n\t\t\t\tconst cleanup = ref(node);\n\t\t\t\tif (typeof cleanup === \"function\") {\n\t\t\t\t\tcallerCleanupRef.current = cleanup;\n\t\t\t\t}\n\t\t\t} else if (ref) {\n\t\t\t\tref.current = node;\n\t\t\t}\n\n\t\t\treturn () => {\n\t\t\t\tcontainerRef.current = null;\n\t\t\t\tif (callerCleanupRef.current) {\n\t\t\t\t\tcallerCleanupRef.current();\n\t\t\t\t\tcallerCleanupRef.current = undefined;\n\t\t\t\t} else if (typeof ref === \"function\") {\n\t\t\t\t\tref(null);\n\t\t\t\t} else if (ref) {\n\t\t\t\t\tref.current = null;\n\t\t\t\t}\n\t\t\t};\n\t\t},\n\t\t[ref],\n\t);\n\n\tconst isEmpty = numRows === 0 || numCols === 0;\n\n\treturn (\n\t\t<TooltipProvider>\n\t\t\t<div\n\t\t\t\tref={setRootRef}\n\t\t\t\ttabIndex={isEmpty ? -1 : undefined}\n\t\t\t\trole=\"region\"\n\t\t\t\taria-label={ariaLabel}\n\t\t\t\tdata-testid=\"heatmap-matrix\"\n\t\t\t\tclassName={cn(\n\t\t\t\t\t\"flex flex-col gap-2 rounded-lg border border-basalt-border/60 bg-basalt-card p-3 text-xs outline-none\",\n\t\t\t\t\tisEmpty ? \"text-basalt-muted-foreground\" : \"text-basalt-foreground\",\n\t\t\t\t\tclassName,\n\t\t\t\t)}\n\t\t\t\tstyle={style}\n\t\t\t\tonFocus={handleContainerFocus}\n\t\t\t\tonBlur={handleContainerBlur}\n\t\t\t\tonKeyDown={handleContainerKeyDown}\n\t\t\t\t{...rest}\n\t\t\t>\n\t\t\t\t{isEmpty ? (\n\t\t\t\t\t<span className=\"italic\">{missingLabel}</span>\n\t\t\t\t) : (\n\t\t\t\t\t<>\n\t\t\t\t\t\t{/* Scrollable table container */}\n\t\t\t\t\t\t<div\n\t\t\t\t\t\t\ttabIndex={-1}\n\t\t\t\t\t\t\trole=\"region\"\n\t\t\t\t\t\t\taria-label={`${ariaLabel} scrollable table`}\n\t\t\t\t\t\t\tclassName=\"w-full overflow-x-auto outline-none\"\n\t\t\t\t\t\t>\n\t\t\t\t\t\t\t<table\n\t\t\t\t\t\t\t\t// biome-ignore lint/a11y/noNoninteractiveElementToInteractiveRole: W3C ARIA interactive 2D grid table with descendant roving tab buttons\n\t\t\t\t\t\t\t\trole=\"grid\"\n\t\t\t\t\t\t\t\taria-label={ariaLabel}\n\t\t\t\t\t\t\t\tclassName=\"border-separate\"\n\t\t\t\t\t\t\t\tstyle={{ borderSpacing: cellGap }}\n\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t<thead>\n\t\t\t\t\t\t\t\t\t<tr>\n\t\t\t\t\t\t\t\t\t\t{/* Top-left empty header */}\n\t\t\t\t\t\t\t\t\t\t<th\n\t\t\t\t\t\t\t\t\t\t\tscope=\"col\"\n\t\t\t\t\t\t\t\t\t\t\tclassName=\"sticky left-0 z-10 bg-basalt-card p-0 text-left font-normal\"\n\t\t\t\t\t\t\t\t\t\t\tstyle={{ minWidth: 64 }}\n\t\t\t\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t\t\t\t<span className=\"sr-only\">Row \\ Column</span>\n\t\t\t\t\t\t\t\t\t\t</th>\n\t\t\t\t\t\t\t\t\t\t{columnLabels.map((col, colIdx) => (\n\t\t\t\t\t\t\t\t\t\t\t<th\n\t\t\t\t\t\t\t\t\t\t\t\tkey={`${matrixId}-col-${colIdx}`}\n\t\t\t\t\t\t\t\t\t\t\t\tscope=\"col\"\n\t\t\t\t\t\t\t\t\t\t\t\tclassName=\"p-0 text-center font-mono text-[10px] text-basalt-muted-foreground select-none\"\n\t\t\t\t\t\t\t\t\t\t\t\tstyle={{\n\t\t\t\t\t\t\t\t\t\t\t\t\twidth: effectiveColWidth,\n\t\t\t\t\t\t\t\t\t\t\t\t\tmaxWidth: effectiveColWidth,\n\t\t\t\t\t\t\t\t\t\t\t\t\toverflow: \"hidden\",\n\t\t\t\t\t\t\t\t\t\t\t\t\ttextOverflow: \"ellipsis\",\n\t\t\t\t\t\t\t\t\t\t\t\t\twhiteSpace: \"nowrap\",\n\t\t\t\t\t\t\t\t\t\t\t\t}}\n\t\t\t\t\t\t\t\t\t\t\t\ttitle={col}\n\t\t\t\t\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t\t\t\t\t{col}\n\t\t\t\t\t\t\t\t\t\t\t</th>\n\t\t\t\t\t\t\t\t\t\t))}\n\t\t\t\t\t\t\t\t\t</tr>\n\t\t\t\t\t\t\t\t</thead>\n\t\t\t\t\t\t\t\t<tbody>\n\t\t\t\t\t\t\t\t\t{rowLabels.map((rowName, rowIdx) => (\n\t\t\t\t\t\t\t\t\t\t<tr key={`${matrixId}-row-${rowIdx}`}>\n\t\t\t\t\t\t\t\t\t\t\t<th\n\t\t\t\t\t\t\t\t\t\t\t\tscope=\"row\"\n\t\t\t\t\t\t\t\t\t\t\t\tclassName=\"sticky left-0 z-10 bg-basalt-card pr-2 text-left font-medium text-basalt-foreground select-none\"\n\t\t\t\t\t\t\t\t\t\t\t\tstyle={{\n\t\t\t\t\t\t\t\t\t\t\t\t\tlineHeight: `${cellSize}px`,\n\t\t\t\t\t\t\t\t\t\t\t\t\tminWidth: 64,\n\t\t\t\t\t\t\t\t\t\t\t\t\twhiteSpace: \"nowrap\",\n\t\t\t\t\t\t\t\t\t\t\t\t}}\n\t\t\t\t\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t\t\t\t\t{rowName}\n\t\t\t\t\t\t\t\t\t\t\t</th>\n\t\t\t\t\t\t\t\t\t\t\t{columnLabels.map((colName, colIdx) => {\n\t\t\t\t\t\t\t\t\t\t\t\tconst cellKey = `${rowIdx}-${colIdx}`;\n\t\t\t\t\t\t\t\t\t\t\t\tconst rawVal = values[rowIdx]?.[colIdx];\n\t\t\t\t\t\t\t\t\t\t\t\tconst isMissing =\n\t\t\t\t\t\t\t\t\t\t\t\t\trawVal == null || typeof rawVal !== \"number\" || !Number.isFinite(rawVal);\n\t\t\t\t\t\t\t\t\t\t\t\tconst colorIdx = resolveColorIndex(\n\t\t\t\t\t\t\t\t\t\t\t\t\trawVal,\n\t\t\t\t\t\t\t\t\t\t\t\t\tminVal,\n\t\t\t\t\t\t\t\t\t\t\t\t\tmaxVal,\n\t\t\t\t\t\t\t\t\t\t\t\t\tcolorScale.length,\n\t\t\t\t\t\t\t\t\t\t\t\t);\n\n\t\t\t\t\t\t\t\t\t\t\t\tconst formattedVal = isMissing\n\t\t\t\t\t\t\t\t\t\t\t\t\t? missingLabel\n\t\t\t\t\t\t\t\t\t\t\t\t\t: valueFormatter(rawVal as number);\n\n\t\t\t\t\t\t\t\t\t\t\t\tconst cellBg =\n\t\t\t\t\t\t\t\t\t\t\t\t\tcolorIdx < 0\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t? \"hsl(var(--basalt-muted) / 0.4)\"\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t: (colorScale[colorIdx] ?? \"hsl(var(--basalt-muted))\");\n\n\t\t\t\t\t\t\t\t\t\t\t\tconst accessibleCellLabel = `${rowName}, ${colName}: ${formattedVal} (${metricLabel})`;\n\t\t\t\t\t\t\t\t\t\t\t\tconst isSelected = activePos[0] === rowIdx && activePos[1] === colIdx;\n\t\t\t\t\t\t\t\t\t\t\t\tconst isOpen = openTooltipPos === cellKey;\n\n\t\t\t\t\t\t\t\t\t\t\t\tconst cellContext: HeatmapMatrixCellContext = {\n\t\t\t\t\t\t\t\t\t\t\t\t\trowIndex: rowIdx,\n\t\t\t\t\t\t\t\t\t\t\t\t\tcolIndex: colIdx,\n\t\t\t\t\t\t\t\t\t\t\t\t\trowLabel: rowName,\n\t\t\t\t\t\t\t\t\t\t\t\t\tcolumnLabel: colName,\n\t\t\t\t\t\t\t\t\t\t\t\t\tvalue: rawVal,\n\t\t\t\t\t\t\t\t\t\t\t\t\tformattedValue: formattedVal,\n\t\t\t\t\t\t\t\t\t\t\t\t\tisMissing,\n\t\t\t\t\t\t\t\t\t\t\t\t\tcolorIndex: colorIdx,\n\t\t\t\t\t\t\t\t\t\t\t\t};\n\n\t\t\t\t\t\t\t\t\t\t\t\treturn (\n\t\t\t\t\t\t\t\t\t\t\t\t\t// biome-ignore lint/a11y/noNoninteractiveElementToInteractiveRole: ARIA gridcell container wrapping roving interactive button\n\t\t\t\t\t\t\t\t\t\t\t\t\t// biome-ignore lint/a11y/useFocusableInteractive: Focus is managed on child button via roving tabindex\n\t\t\t\t\t\t\t\t\t\t\t\t\t<td key={cellKey} role=\"gridcell\" className=\"p-0 text-center\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t<Tooltip\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\topen={isOpen}\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tonOpenChange={(next) => {\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tif (next) {\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tif (!dismissedByEscapeRef.current) {\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tsetOpenTooltipPos(cellKey);\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tsetOpenTooltipPos((curr) => {\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tif (curr !== cellKey) return curr;\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tif (dismissedByEscapeRef.current) return null;\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tconst isCellFocused =\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tdocument.activeElement === cellRefs.current.get(cellKey);\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\treturn isCellFocused ? curr : null;\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t});\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t}}\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<TooltipTrigger asChild>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<button\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tref={(el) => {\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tif (el) cellRefs.current.set(cellKey, el);\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\telse cellRefs.current.delete(cellKey);\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t}}\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\ttype=\"button\"\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\taria-label={accessibleCellLabel}\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\ttabIndex={isSelected ? 0 : -1}\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tonFocus={() => {\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tsetActivePos([rowIdx, colIdx]);\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tdismissedByEscapeRef.current = false;\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tsetOpenTooltipPos(cellKey);\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t}}\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tonBlur={() => {\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tsetOpenTooltipPos((curr) => (curr === cellKey ? null : curr));\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t}}\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tclassName=\"box-border block cursor-pointer rounded-xs border-0 p-0 transition-colors hover:ring-1 hover:ring-basalt-foreground focus-visible:outline-2 focus-visible:outline-offset-1 focus-visible:outline-basalt-ring\"\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tstyle={{\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\twidth: effectiveColWidth,\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\theight: cellSize,\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tbackgroundColor: cellBg,\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t}}\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t/>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</TooltipTrigger>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<TooltipContent\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tid={`${matrixId}-${cellKey}`}\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tonEscapeKeyDown={() => {\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tdismissedByEscapeRef.current = true;\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tsetOpenTooltipPos(null);\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t}}\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t{renderTooltip ? (\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\trenderTooltip(cellContext)\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t) : (\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<div className=\"text-xs\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<div className=\"font-semibold text-basalt-popover-foreground\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t{rowName} · {colName}\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<div className=\"text-basalt-muted-foreground\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t{metricLabel}:{\" \"}\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<span className=\"font-medium text-basalt-popover-foreground\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t{formattedVal}\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</span>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t)}\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</TooltipContent>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t</Tooltip>\n\t\t\t\t\t\t\t\t\t\t\t\t\t</td>\n\t\t\t\t\t\t\t\t\t\t\t\t);\n\t\t\t\t\t\t\t\t\t\t\t})}\n\t\t\t\t\t\t\t\t\t\t</tr>\n\t\t\t\t\t\t\t\t\t))}\n\t\t\t\t\t\t\t\t</tbody>\n\t\t\t\t\t\t\t</table>\n\t\t\t\t\t\t</div>\n\n\t\t\t\t\t\t{/* Legend footer */}\n\t\t\t\t\t\t{showLegend ? (\n\t\t\t\t\t\t\t<div\n\t\t\t\t\t\t\t\tclassName=\"mt-1 flex items-center justify-end gap-1 text-[11px] text-basalt-muted-foreground select-none\"\n\t\t\t\t\t\t\t\taria-hidden=\"true\"\n\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t<span>{lessLabel}</span>\n\t\t\t\t\t\t\t\t<div\n\t\t\t\t\t\t\t\t\tclassName=\"rounded-xs\"\n\t\t\t\t\t\t\t\t\ttitle=\"Missing data\"\n\t\t\t\t\t\t\t\t\tstyle={{\n\t\t\t\t\t\t\t\t\t\twidth: cellSize,\n\t\t\t\t\t\t\t\t\t\theight: cellSize,\n\t\t\t\t\t\t\t\t\t\tbackgroundColor: \"hsl(var(--basalt-muted) / 0.4)\",\n\t\t\t\t\t\t\t\t\t}}\n\t\t\t\t\t\t\t\t/>\n\t\t\t\t\t\t\t\t{colorScale.map((color, idx) => (\n\t\t\t\t\t\t\t\t\t<div\n\t\t\t\t\t\t\t\t\t\tkey={`${color}-${idx}`}\n\t\t\t\t\t\t\t\t\t\tclassName=\"rounded-xs\"\n\t\t\t\t\t\t\t\t\t\tstyle={{\n\t\t\t\t\t\t\t\t\t\t\twidth: cellSize,\n\t\t\t\t\t\t\t\t\t\t\theight: cellSize,\n\t\t\t\t\t\t\t\t\t\t\tbackgroundColor: color,\n\t\t\t\t\t\t\t\t\t\t}}\n\t\t\t\t\t\t\t\t\t/>\n\t\t\t\t\t\t\t\t))}\n\t\t\t\t\t\t\t\t<span>{moreLabel}</span>\n\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t) : null}\n\t\t\t\t\t</>\n\t\t\t\t)}\n\t\t\t</div>\n\t\t</TooltipProvider>\n\t);\n});\n\nHeatmapMatrix.displayName = \"HeatmapMatrix\";\n"],"mappings":"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"}
|
package/dist/charts/line.d.ts
CHANGED
|
@@ -1,12 +1,73 @@
|
|
|
1
|
-
import
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
1
|
+
import type { ReactNode } from "react";
|
|
2
|
+
import { type ChartSeriesDescriptor, type XYPoint } from "./series.js";
|
|
3
|
+
import type { ChartTooltipItem } from "./tooltip.js";
|
|
4
|
+
export type LineChartAxisDomain = [number | "auto" | "dataMin", number | "auto" | "dataMax"] | readonly [number | "auto" | "dataMin", number | "auto" | "dataMax"];
|
|
5
|
+
export type LineChartNumericKeys<T> = {
|
|
6
|
+
[K in keyof T]-?: K extends "x" ? never : [NonNullable<T[K]>] extends [never] ? never : NonNullable<T[K]> extends number ? K extends string ? K : never : never;
|
|
7
|
+
}[keyof T];
|
|
8
|
+
export type LineChartLegendRenderer<K extends string = string> = (props: {
|
|
9
|
+
items: Array<ChartSeriesDescriptor<K>>;
|
|
10
|
+
}) => ReactNode;
|
|
11
|
+
export type LineChartTooltipRenderer = (props: {
|
|
12
|
+
active?: boolean;
|
|
13
|
+
payload?: readonly ChartTooltipItem[];
|
|
14
|
+
label?: string | number;
|
|
15
|
+
}) => ReactNode;
|
|
16
|
+
export type LineChartProps<TData extends {
|
|
17
|
+
x: string | number;
|
|
18
|
+
} = XYPoint, K extends LineChartNumericKeys<TData> & string = LineChartNumericKeys<TData> & string> = {
|
|
19
|
+
/**
|
|
20
|
+
* Dataset array where each record requires an `x` category or time coordinate.
|
|
21
|
+
* Any remaining fields with numeric, nullable, or optional number values are inferred as valid series keys.
|
|
22
|
+
*/
|
|
23
|
+
data: TData[];
|
|
24
|
+
/**
|
|
25
|
+
* Series descriptors identifying which numeric keys to plot.
|
|
26
|
+
* Inferred strictly from numeric keys of `TData` (rejects non-numeric fields, `x`, and typos).
|
|
27
|
+
*/
|
|
28
|
+
series?: Array<ChartSeriesDescriptor<NoInfer<K>>>;
|
|
5
29
|
ariaLabel?: string;
|
|
6
30
|
className?: string;
|
|
7
31
|
showAxes?: boolean;
|
|
8
32
|
showLegend?: boolean;
|
|
9
33
|
color?: string;
|
|
34
|
+
/**
|
|
35
|
+
* Value formatter for Y-axis tick values and fallback tooltip values.
|
|
36
|
+
*/
|
|
10
37
|
valueFormatter?: (value: number) => string;
|
|
38
|
+
/**
|
|
39
|
+
* Formatter for X-axis category or time tick labels.
|
|
40
|
+
*/
|
|
41
|
+
xValueFormatter?: (value: string | number) => string;
|
|
42
|
+
/**
|
|
43
|
+
* Custom numerical or keyword bounds for the Y-axis.
|
|
44
|
+
*/
|
|
45
|
+
yDomain?: LineChartAxisDomain;
|
|
46
|
+
/**
|
|
47
|
+
* Custom legend slot or render function receiving resolved series descriptors.
|
|
48
|
+
*/
|
|
49
|
+
legend?: ReactNode | LineChartLegendRenderer<K>;
|
|
50
|
+
/**
|
|
51
|
+
* Custom tooltip content renderer receiving Recharts payload, active status, and coordinate label.
|
|
52
|
+
*/
|
|
53
|
+
customTooltip?: LineChartTooltipRenderer;
|
|
54
|
+
/**
|
|
55
|
+
* Textual summary describing key insights, highs, lows, and keyboard exploration instructions.
|
|
56
|
+
* Associated with the chart via useId and aria-describedby.
|
|
57
|
+
*/
|
|
58
|
+
summary?: ReactNode;
|
|
59
|
+
/**
|
|
60
|
+
* Accessible tabular or structured data alternative rendered outside the plot area.
|
|
61
|
+
*/
|
|
62
|
+
dataAlternative?: ReactNode;
|
|
63
|
+
/**
|
|
64
|
+
* Whether the interactive accessibility layer is enabled on the underlying Recharts graphic.
|
|
65
|
+
* Enables keyboard exploration with Tab and arrow keys where supported by the underlying chart type.
|
|
66
|
+
* Non-interactive compact or decorative charts without tooltip navigation should provide summary or dataAlternative.
|
|
67
|
+
* @default true
|
|
68
|
+
*/
|
|
69
|
+
accessibilityLayer?: boolean;
|
|
11
70
|
};
|
|
12
|
-
export declare function LineChart
|
|
71
|
+
export declare function LineChart<TData extends {
|
|
72
|
+
x: string | number;
|
|
73
|
+
} = XYPoint, K extends LineChartNumericKeys<TData> & string = LineChartNumericKeys<TData> & string>({ data, series, ariaLabel, className, showAxes, showLegend, color, valueFormatter, xValueFormatter, yDomain, legend, customTooltip, summary, dataAlternative, accessibilityLayer, }: LineChartProps<TData, K>): import("react").JSX.Element;
|
package/dist/charts/line.js
CHANGED
|
@@ -1,42 +1,49 @@
|
|
|
1
1
|
"use client";
|
|
2
|
-
import { ANIMATION_PROPS as e, CHART_PLOT_MARGIN as t, CHART_PLOT_MARGIN_BARE as n,
|
|
3
|
-
import { applyLeadColor as
|
|
4
|
-
import { ChartShell as
|
|
5
|
-
import { ChartLegend as
|
|
6
|
-
import { jsx as
|
|
7
|
-
import { CartesianGrid as
|
|
2
|
+
import { ANIMATION_PROPS as e, CHART_PLOT_MARGIN as t, CHART_PLOT_MARGIN_BARE as n, CHART_TYPE as r, GRID_PROPS as i, cartesianAxisProps as a, chartTooltipProps as o, seriesColor as s } from "./config.js";
|
|
3
|
+
import { applyLeadColor as c, resolveChartSeries as l, xyFallbackKeys as u } from "./series.js";
|
|
4
|
+
import { ChartShell as d } from "./frame.js";
|
|
5
|
+
import { ChartLegend as f } from "./legend.js";
|
|
6
|
+
import { jsx as p, jsxs as m } from "react/jsx-runtime";
|
|
7
|
+
import { CartesianGrid as h, Line as g, LineChart as _, Tooltip as v, XAxis as y, YAxis as b } from "recharts";
|
|
8
8
|
//#region src/charts/line.tsx
|
|
9
|
-
function
|
|
10
|
-
let
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
9
|
+
function x({ data: x, series: S, ariaLabel: C = "Line chart", className: w, showAxes: T = !1, showLegend: E = !1, color: D, valueFormatter: O, xValueFormatter: k, yDomain: A, legend: j, customTooltip: M, summary: N, dataAlternative: P, accessibilityLayer: F }) {
|
|
10
|
+
let I = c(l(S, u(x)), D), L = j === void 0 ? E ? /* @__PURE__ */ p(f, {
|
|
11
|
+
items: I,
|
|
12
|
+
shape: "line"
|
|
13
|
+
}) : void 0 : typeof j == "function" ? j({ items: I }) : j;
|
|
14
|
+
return /* @__PURE__ */ p(d, {
|
|
15
|
+
ariaLabel: C,
|
|
16
|
+
className: w,
|
|
17
|
+
legend: L,
|
|
18
|
+
summary: N,
|
|
19
|
+
dataAlternative: P,
|
|
20
|
+
accessibilityLayer: F,
|
|
21
|
+
children: /* @__PURE__ */ m(_, {
|
|
22
|
+
data: x,
|
|
23
|
+
margin: T ? t : n,
|
|
21
24
|
children: [
|
|
22
|
-
|
|
23
|
-
/* @__PURE__ */
|
|
25
|
+
T ? /* @__PURE__ */ p(h, { ...i }) : null,
|
|
26
|
+
/* @__PURE__ */ p(y, {
|
|
24
27
|
dataKey: "x",
|
|
25
|
-
...
|
|
28
|
+
...a(!T),
|
|
29
|
+
tickFormatter: k
|
|
26
30
|
}),
|
|
27
|
-
/* @__PURE__ */
|
|
28
|
-
...
|
|
29
|
-
tickFormatter:
|
|
31
|
+
/* @__PURE__ */ p(b, {
|
|
32
|
+
...a(!T),
|
|
33
|
+
tickFormatter: O,
|
|
34
|
+
...A ? { domain: A } : {}
|
|
30
35
|
}),
|
|
31
|
-
/* @__PURE__ */
|
|
32
|
-
formatter:
|
|
33
|
-
cursor: "line"
|
|
36
|
+
/* @__PURE__ */ p(v, { ...o({
|
|
37
|
+
formatter: O,
|
|
38
|
+
cursor: "line",
|
|
39
|
+
customTooltip: M
|
|
34
40
|
}) }),
|
|
35
|
-
|
|
41
|
+
I.map((t, n) => /* @__PURE__ */ p(g, {
|
|
36
42
|
type: "monotone",
|
|
37
43
|
dataKey: t.key,
|
|
38
44
|
name: t.label ?? t.key,
|
|
39
|
-
stroke:
|
|
45
|
+
stroke: s(t, n),
|
|
46
|
+
strokeWidth: r.strokeWidth,
|
|
40
47
|
dot: !1,
|
|
41
48
|
...e
|
|
42
49
|
}, t.key))
|
|
@@ -45,6 +52,6 @@ function b({ data: b, series: x, ariaLabel: S = "Line chart", className: C, show
|
|
|
45
52
|
});
|
|
46
53
|
}
|
|
47
54
|
//#endregion
|
|
48
|
-
export {
|
|
55
|
+
export { x as LineChart };
|
|
49
56
|
|
|
50
57
|
//# sourceMappingURL=line.js.map
|
package/dist/charts/line.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"line.js","names":[],"sources":["../../src/charts/line.tsx"],"sourcesContent":["import { CartesianGrid, Line, LineChart as RechartsLine, Tooltip, XAxis, YAxis } from \"recharts\";\nimport {\n\tANIMATION_PROPS,\n\tCHART_PLOT_MARGIN,\n\tCHART_PLOT_MARGIN_BARE,\n\tcartesianAxisProps,\n\tchartTooltipProps,\n\tGRID_PROPS,\n\tseriesColor,\n} from \"./config\";\nimport { ChartShell } from \"./frame\";\nimport { ChartLegend } from \"./legend\";\nimport {\n\tapplyLeadColor,\n\
|
|
1
|
+
{"version":3,"file":"line.js","names":[],"sources":["../../src/charts/line.tsx"],"sourcesContent":["import type { ReactNode } from \"react\";\nimport { CartesianGrid, Line, LineChart as RechartsLine, Tooltip, XAxis, YAxis } from \"recharts\";\nimport {\n\tANIMATION_PROPS,\n\tCHART_PLOT_MARGIN,\n\tCHART_PLOT_MARGIN_BARE,\n\tCHART_TYPE,\n\tcartesianAxisProps,\n\tchartTooltipProps,\n\tGRID_PROPS,\n\tseriesColor,\n} from \"./config\";\nimport { ChartShell } from \"./frame\";\nimport { ChartLegend } from \"./legend\";\nimport {\n\tapplyLeadColor,\n\ttype ChartSeriesDescriptor,\n\tresolveChartSeries,\n\ttype XYPoint,\n\txyFallbackKeys,\n} from \"./series\";\nimport type { ChartTooltipItem } from \"./tooltip\";\n\nexport type LineChartAxisDomain =\n\t| [number | \"auto\" | \"dataMin\", number | \"auto\" | \"dataMax\"]\n\t| readonly [number | \"auto\" | \"dataMin\", number | \"auto\" | \"dataMax\"];\n\nexport type LineChartNumericKeys<T> = {\n\t[K in keyof T]-?: K extends \"x\"\n\t\t? never\n\t\t: [NonNullable<T[K]>] extends [never]\n\t\t\t? never\n\t\t\t: NonNullable<T[K]> extends number\n\t\t\t\t? K extends string\n\t\t\t\t\t? K\n\t\t\t\t\t: never\n\t\t\t\t: never;\n}[keyof T];\n\nexport type LineChartLegendRenderer<K extends string = string> = (props: {\n\titems: Array<ChartSeriesDescriptor<K>>;\n}) => ReactNode;\n\nexport type LineChartTooltipRenderer = (props: {\n\tactive?: boolean;\n\tpayload?: readonly ChartTooltipItem[];\n\tlabel?: string | number;\n}) => ReactNode;\n\nexport type LineChartProps<\n\tTData extends { x: string | number } = XYPoint,\n\tK extends LineChartNumericKeys<TData> & string = LineChartNumericKeys<TData> & string,\n> = {\n\t/**\n\t * Dataset array where each record requires an `x` category or time coordinate.\n\t * Any remaining fields with numeric, nullable, or optional number values are inferred as valid series keys.\n\t */\n\tdata: TData[];\n\t/**\n\t * Series descriptors identifying which numeric keys to plot.\n\t * Inferred strictly from numeric keys of `TData` (rejects non-numeric fields, `x`, and typos).\n\t */\n\tseries?: Array<ChartSeriesDescriptor<NoInfer<K>>>;\n\tariaLabel?: string;\n\tclassName?: string;\n\tshowAxes?: boolean;\n\tshowLegend?: boolean;\n\tcolor?: string;\n\t/**\n\t * Value formatter for Y-axis tick values and fallback tooltip values.\n\t */\n\tvalueFormatter?: (value: number) => string;\n\t/**\n\t * Formatter for X-axis category or time tick labels.\n\t */\n\txValueFormatter?: (value: string | number) => string;\n\t/**\n\t * Custom numerical or keyword bounds for the Y-axis.\n\t */\n\tyDomain?: LineChartAxisDomain;\n\t/**\n\t * Custom legend slot or render function receiving resolved series descriptors.\n\t */\n\tlegend?: ReactNode | LineChartLegendRenderer<K>;\n\t/**\n\t * Custom tooltip content renderer receiving Recharts payload, active status, and coordinate label.\n\t */\n\tcustomTooltip?: LineChartTooltipRenderer;\n\t/**\n\t * Textual summary describing key insights, highs, lows, and keyboard exploration instructions.\n\t * Associated with the chart via useId and aria-describedby.\n\t */\n\tsummary?: ReactNode;\n\t/**\n\t * Accessible tabular or structured data alternative rendered outside the plot area.\n\t */\n\tdataAlternative?: ReactNode;\n\t/**\n\t * Whether the interactive accessibility layer is enabled on the underlying Recharts graphic.\n\t * Enables keyboard exploration with Tab and arrow keys where supported by the underlying chart type.\n\t * Non-interactive compact or decorative charts without tooltip navigation should provide summary or dataAlternative.\n\t * @default true\n\t */\n\taccessibilityLayer?: boolean;\n};\n\nexport function LineChart<\n\tTData extends { x: string | number } = XYPoint,\n\tK extends LineChartNumericKeys<TData> & string = LineChartNumericKeys<TData> & string,\n>({\n\tdata,\n\tseries,\n\tariaLabel = \"Line chart\",\n\tclassName,\n\tshowAxes = false,\n\tshowLegend = false,\n\tcolor,\n\tvalueFormatter,\n\txValueFormatter,\n\tyDomain,\n\tlegend,\n\tcustomTooltip,\n\tsummary,\n\tdataAlternative,\n\taccessibilityLayer,\n}: LineChartProps<TData, K>) {\n\tconst lines = applyLeadColor(\n\t\tresolveChartSeries(\n\t\t\tseries,\n\t\t\txyFallbackKeys(data as unknown as Array<{ y2?: number; y3?: number }>) as K[],\n\t\t),\n\t\tcolor,\n\t);\n\tconst resolvedLegend =\n\t\tlegend !== undefined ? (\n\t\t\ttypeof legend === \"function\" ? (\n\t\t\t\tlegend({ items: lines })\n\t\t\t) : (\n\t\t\t\tlegend\n\t\t\t)\n\t\t) : showLegend ? (\n\t\t\t<ChartLegend items={lines} shape=\"line\" />\n\t\t) : undefined;\n\n\treturn (\n\t\t<ChartShell\n\t\t\tariaLabel={ariaLabel}\n\t\t\tclassName={className}\n\t\t\tlegend={resolvedLegend}\n\t\t\tsummary={summary}\n\t\t\tdataAlternative={dataAlternative}\n\t\t\taccessibilityLayer={accessibilityLayer}\n\t\t>\n\t\t\t<RechartsLine data={data} margin={showAxes ? CHART_PLOT_MARGIN : CHART_PLOT_MARGIN_BARE}>\n\t\t\t\t{showAxes ? <CartesianGrid {...GRID_PROPS} /> : null}\n\t\t\t\t<XAxis dataKey=\"x\" {...cartesianAxisProps(!showAxes)} tickFormatter={xValueFormatter} />\n\t\t\t\t<YAxis\n\t\t\t\t\t{...cartesianAxisProps(!showAxes)}\n\t\t\t\t\ttickFormatter={valueFormatter}\n\t\t\t\t\t{...(yDomain ? { domain: yDomain as [number, number] } : {})}\n\t\t\t\t/>\n\t\t\t\t<Tooltip\n\t\t\t\t\t{...chartTooltipProps({\n\t\t\t\t\t\tformatter: valueFormatter,\n\t\t\t\t\t\tcursor: \"line\",\n\t\t\t\t\t\tcustomTooltip,\n\t\t\t\t\t})}\n\t\t\t\t/>\n\t\t\t\t{lines.map((item, index) => (\n\t\t\t\t\t<Line\n\t\t\t\t\t\tkey={item.key}\n\t\t\t\t\t\ttype=\"monotone\"\n\t\t\t\t\t\tdataKey={item.key}\n\t\t\t\t\t\tname={item.label ?? item.key}\n\t\t\t\t\t\tstroke={seriesColor(item, index)}\n\t\t\t\t\t\tstrokeWidth={CHART_TYPE.strokeWidth}\n\t\t\t\t\t\tdot={false}\n\t\t\t\t\t\t{...ANIMATION_PROPS}\n\t\t\t\t\t/>\n\t\t\t\t))}\n\t\t\t</RechartsLine>\n\t\t</ChartShell>\n\t);\n}\n"],"mappings":";;;;;;;;AA0GA,SAAgB,EAGd,EACD,SACA,WACA,eAAY,cACZ,cACA,cAAW,IACX,gBAAa,IACb,UACA,mBACA,oBACA,YACA,WACA,kBACA,YACA,oBACA,yBAC4B;CAC5B,IAAM,IAAQ,EACb,EACC,GACA,EAAe,CAAsD,CACtE,GACA,CACD,GACM,IACL,MAAW,KAAA,IAMP,IACH,kBAAC,GAAD;EAAa,OAAO;EAAO,OAAM;CAAQ,CAAA,IACtC,KAAA,IAPH,OAAO,KAAW,aACjB,EAAO,EAAE,OAAO,EAAM,CAAC,IAEvB;CAMH,OACC,kBAAC,GAAD;EACY;EACA;EACX,QAAQ;EACC;EACQ;EACG;EAEpB,UAAA,kBAAC,GAAD;GAAoB;GAAM,QAAQ,IAAW,IAAoB;GAAjE,UAAA;IACE,IAAW,kBAAC,GAAD,EAAe,GAAI,EAAa,CAAA,IAAI;IAChD,kBAAC,GAAD;KAAO,SAAQ;KAAI,GAAI,EAAmB,CAAC,CAAQ;KAAG,eAAe;IAAkB,CAAA;IACvF,kBAAC,GAAD;KACC,GAAI,EAAmB,CAAC,CAAQ;KAChC,eAAe;KACf,GAAK,IAAU,EAAE,QAAQ,EAA4B,IAAI,CAAC;IAC1D,CAAA;IACD,kBAAC,GAAD,EACC,GAAI,EAAkB;KACrB,WAAW;KACX,QAAQ;KACR;IACD,CAAC,EACD,CAAA;IACA,EAAM,KAAK,GAAM,MACjB,kBAAC,GAAD;KAEC,MAAK;KACL,SAAS,EAAK;KACd,MAAM,EAAK,SAAS,EAAK;KACzB,QAAQ,EAAY,GAAM,CAAK;KAC/B,aAAa,EAAW;KACxB,KAAK;KACL,GAAI;IACJ,GARK,EAAK,GAQV,CACD;GACY;;CACH,CAAA;AAEd"}
|
package/dist/charts/palette.d.ts
CHANGED
|
@@ -27,6 +27,7 @@ export declare const chart: {
|
|
|
27
27
|
readonly crimson: string;
|
|
28
28
|
readonly gray: string;
|
|
29
29
|
};
|
|
30
|
+
/** Fixed five-color series cycle; independent of the application accent. */
|
|
30
31
|
export declare const CHART_COLORS: string[];
|
|
31
32
|
export type ChartPaletteProps = {
|
|
32
33
|
ariaLabel?: string;
|
package/dist/charts/palette.js
CHANGED
|
@@ -26,7 +26,13 @@ var t = (e) => `hsl(var(--basalt-${e}))`, n = (e, t) => `hsl(var(--basalt-${e})
|
|
|
26
26
|
tangerine: t("chart-22"),
|
|
27
27
|
crimson: t("chart-23"),
|
|
28
28
|
gray: t("chart-24")
|
|
29
|
-
}, o =
|
|
29
|
+
}, o = [
|
|
30
|
+
a.primary,
|
|
31
|
+
a.rose,
|
|
32
|
+
a.green,
|
|
33
|
+
a.amber,
|
|
34
|
+
a.gray
|
|
35
|
+
];
|
|
30
36
|
function s({ ariaLabel: t = "Chart colors" }) {
|
|
31
37
|
return /* @__PURE__ */ e("div", {
|
|
32
38
|
className: "flex flex-wrap gap-2",
|