@misoto22/design 0.5.0 → 0.6.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/README.md +124 -0
- package/bin/misoto22-design.mjs +205 -0
- package/dist/agent/Accordion.md +41 -0
- package/dist/agent/Alert.md +42 -0
- package/dist/agent/AppShell.md +40 -0
- package/dist/agent/AreaChart.md +68 -0
- package/dist/agent/Article.md +41 -0
- package/dist/agent/Avatar.md +32 -0
- package/dist/agent/Badge.md +40 -0
- package/dist/agent/BarChart.md +65 -0
- package/dist/agent/BarList.md +40 -0
- package/dist/agent/BigNumber.md +45 -0
- package/dist/agent/BoxPlot.md +58 -0
- package/dist/agent/Breadcrumb.md +32 -0
- package/dist/agent/BulletChart.md +48 -0
- package/dist/agent/Button.md +56 -0
- package/dist/agent/Calendar.md +42 -0
- package/dist/agent/Card.md +49 -0
- package/dist/agent/Checkbox.md +35 -0
- package/dist/agent/Collapsible.md +46 -0
- package/dist/agent/Combobox.md +50 -0
- package/dist/agent/Command.md +93 -0
- package/dist/agent/ComposedChart.md +57 -0
- package/dist/agent/ContextMenu.md +59 -0
- package/dist/agent/DatePicker.md +75 -0
- package/dist/agent/Diagram.md +46 -0
- package/dist/agent/Dialog.md +52 -0
- package/dist/agent/DropdownMenu.md +70 -0
- package/dist/agent/EmptyState.md +37 -0
- package/dist/agent/ErrorState.md +41 -0
- package/dist/agent/Facet.md +82 -0
- package/dist/agent/Field.md +37 -0
- package/dist/agent/FigureBand.md +37 -0
- package/dist/agent/FloatingIconButton.md +38 -0
- package/dist/agent/FunnelChart.md +52 -0
- package/dist/agent/Heatmap.md +53 -0
- package/dist/agent/Histogram.md +63 -0
- package/dist/agent/Input.md +30 -0
- package/dist/agent/Kbd.md +29 -0
- package/dist/agent/LineChart.md +60 -0
- package/dist/agent/LinkArrow.md +29 -0
- package/dist/agent/NativeSelect.md +40 -0
- package/dist/agent/NavItem.md +35 -0
- package/dist/agent/Pagination.md +43 -0
- package/dist/agent/PieChart.md +55 -0
- package/dist/agent/Popover.md +57 -0
- package/dist/agent/Progress.md +33 -0
- package/dist/agent/RadarChart.md +54 -0
- package/dist/agent/RadialChart.md +57 -0
- package/dist/agent/RadioGroup.md +44 -0
- package/dist/agent/SankeyChart.md +61 -0
- package/dist/agent/ScatterChart.md +54 -0
- package/dist/agent/ScrollArea.md +40 -0
- package/dist/agent/SearchableMenu.md +46 -0
- package/dist/agent/Select.md +75 -0
- package/dist/agent/Separator.md +35 -0
- package/dist/agent/Sheet.md +57 -0
- package/dist/agent/Skeleton.md +73 -0
- package/dist/agent/Slider.md +39 -0
- package/dist/agent/Sparkline.md +45 -0
- package/dist/agent/Spinner.md +39 -0
- package/dist/agent/StatusDot.md +36 -0
- package/dist/agent/StatusPill.md +28 -0
- package/dist/agent/Steps.md +44 -0
- package/dist/agent/Switch.md +29 -0
- package/dist/agent/Table.md +85 -0
- package/dist/agent/Tabs.md +48 -0
- package/dist/agent/Tag.md +35 -0
- package/dist/agent/Textarea.md +26 -0
- package/dist/agent/Toast.md +26 -0
- package/dist/agent/ToggleGroup.md +44 -0
- package/dist/agent/Tooltip.md +51 -0
- package/dist/agent/TreemapChart.md +52 -0
- package/dist/agent/WaterfallChart.md +62 -0
- package/dist/agent/catalog.json +1791 -0
- package/dist/agent/index.md +131 -0
- package/dist/charts/AreaChart/AreaChart.d.ts +191 -0
- package/dist/charts/AreaChart/AreaChart.js +480 -0
- package/dist/charts/AreaChart/AreaChart.js.map +1 -0
- package/dist/charts/BarChart/BarChart.d.ts +179 -0
- package/dist/charts/BarChart/BarChart.js +591 -0
- package/dist/charts/BarChart/BarChart.js.map +1 -0
- package/dist/charts/BarList/BarList.d.ts +57 -0
- package/dist/charts/BarList/BarList.js +71 -0
- package/dist/charts/BarList/BarList.js.map +1 -0
- package/dist/charts/BigNumber/BigNumber.d.ts +56 -0
- package/dist/charts/BigNumber/BigNumber.js +31 -0
- package/dist/charts/BigNumber/BigNumber.js.map +1 -0
- package/dist/charts/BoxPlot/BoxPlot.d.ts +177 -0
- package/dist/charts/BoxPlot/BoxPlot.js +495 -0
- package/dist/charts/BoxPlot/BoxPlot.js.map +1 -0
- package/dist/charts/BulletChart/BulletChart.d.ts +100 -0
- package/dist/charts/BulletChart/BulletChart.js +162 -0
- package/dist/charts/BulletChart/BulletChart.js.map +1 -0
- package/dist/charts/ComposedChart/ComposedChart.d.ts +171 -0
- package/dist/charts/ComposedChart/ComposedChart.js +667 -0
- package/dist/charts/ComposedChart/ComposedChart.js.map +1 -0
- package/dist/charts/Facet/Facet.d.ts +240 -0
- package/dist/charts/Facet/Facet.js +133 -0
- package/dist/charts/Facet/Facet.js.map +1 -0
- package/dist/charts/Facet/panels.d.ts +187 -0
- package/dist/charts/Facet/panels.js +203 -0
- package/dist/charts/Facet/panels.js.map +1 -0
- package/dist/charts/FunnelChart/FunnelChart.d.ts +101 -0
- package/dist/charts/FunnelChart/FunnelChart.js +147 -0
- package/dist/charts/FunnelChart/FunnelChart.js.map +1 -0
- package/dist/charts/Heatmap/Heatmap.d.ts +78 -0
- package/dist/charts/Heatmap/Heatmap.js +108 -0
- package/dist/charts/Heatmap/Heatmap.js.map +1 -0
- package/dist/charts/Histogram/Histogram.d.ts +165 -0
- package/dist/charts/Histogram/Histogram.js +350 -0
- package/dist/charts/Histogram/Histogram.js.map +1 -0
- package/dist/charts/LineChart/LineChart.d.ts +167 -0
- package/dist/charts/LineChart/LineChart.js +486 -0
- package/dist/charts/LineChart/LineChart.js.map +1 -0
- package/dist/charts/PieChart/PieChart.d.ts +128 -0
- package/dist/charts/PieChart/PieChart.js +309 -0
- package/dist/charts/PieChart/PieChart.js.map +1 -0
- package/dist/charts/RadarChart/RadarChart.d.ts +123 -0
- package/dist/charts/RadarChart/RadarChart.js +299 -0
- package/dist/charts/RadarChart/RadarChart.js.map +1 -0
- package/dist/charts/RadialChart/RadialChart.d.ts +124 -0
- package/dist/charts/RadialChart/RadialChart.js +257 -0
- package/dist/charts/RadialChart/RadialChart.js.map +1 -0
- package/dist/charts/SankeyChart/SankeyChart.d.ts +137 -0
- package/dist/charts/SankeyChart/SankeyChart.js +501 -0
- package/dist/charts/SankeyChart/SankeyChart.js.map +1 -0
- package/dist/charts/ScatterChart/ScatterChart.d.ts +128 -0
- package/dist/charts/ScatterChart/ScatterChart.js +269 -0
- package/dist/charts/ScatterChart/ScatterChart.js.map +1 -0
- package/dist/charts/Sparkline/Sparkline.d.ts +53 -0
- package/dist/charts/Sparkline/Sparkline.js +93 -0
- package/dist/charts/Sparkline/Sparkline.js.map +1 -0
- package/dist/charts/TreemapChart/TreemapChart.d.ts +93 -0
- package/dist/charts/TreemapChart/TreemapChart.js +118 -0
- package/dist/charts/TreemapChart/TreemapChart.js.map +1 -0
- package/dist/charts/WaterfallChart/WaterfallChart.d.ts +164 -0
- package/dist/charts/WaterfallChart/WaterfallChart.js +319 -0
- package/dist/charts/WaterfallChart/WaterfallChart.js.map +1 -0
- package/dist/charts/index.d.ts +41 -0
- package/dist/charts/index.js +128 -0
- package/dist/charts/index.js.map +1 -0
- package/dist/charts/lib/annotations.d.ts +103 -0
- package/dist/charts/lib/annotations.js +99 -0
- package/dist/charts/lib/annotations.js.map +1 -0
- package/dist/charts/lib/axis.d.ts +18 -0
- package/dist/charts/lib/axis.js +21 -0
- package/dist/charts/lib/axis.js.map +1 -0
- package/dist/charts/lib/background.d.ts +33 -0
- package/dist/charts/lib/background.js +173 -0
- package/dist/charts/lib/background.js.map +1 -0
- package/dist/charts/lib/brush.d.ts +94 -0
- package/dist/charts/lib/brush.js +535 -0
- package/dist/charts/lib/brush.js.map +1 -0
- package/dist/charts/lib/chart.d.ts +94 -0
- package/dist/charts/lib/chart.js +134 -0
- package/dist/charts/lib/chart.js.map +1 -0
- package/dist/charts/lib/dot.d.ts +29 -0
- package/dist/charts/lib/dot.js +78 -0
- package/dist/charts/lib/dot.js.map +1 -0
- package/dist/charts/lib/empty.d.ts +31 -0
- package/dist/charts/lib/empty.js +13 -0
- package/dist/charts/lib/empty.js.map +1 -0
- package/dist/charts/lib/export.d.ts +103 -0
- package/dist/charts/lib/export.js +204 -0
- package/dist/charts/lib/export.js.map +1 -0
- package/dist/charts/lib/figure.d.ts +61 -0
- package/dist/charts/lib/figure.js +59 -0
- package/dist/charts/lib/figure.js.map +1 -0
- package/dist/charts/lib/format.d.ts +46 -0
- package/dist/charts/lib/format.js +56 -0
- package/dist/charts/lib/format.js.map +1 -0
- package/dist/charts/lib/legend.d.ts +45 -0
- package/dist/charts/lib/legend.js +117 -0
- package/dist/charts/lib/legend.js.map +1 -0
- package/dist/charts/lib/loading.d.ts +48 -0
- package/dist/charts/lib/loading.js +105 -0
- package/dist/charts/lib/loading.js.map +1 -0
- package/dist/charts/lib/paint.d.ts +154 -0
- package/dist/charts/lib/paint.js +551 -0
- package/dist/charts/lib/paint.js.map +1 -0
- package/dist/charts/lib/sonify-control.d.ts +163 -0
- package/dist/charts/lib/sonify-control.js +172 -0
- package/dist/charts/lib/sonify-control.js.map +1 -0
- package/dist/charts/lib/sonify.d.ts +248 -0
- package/dist/charts/lib/sonify.js +262 -0
- package/dist/charts/lib/sonify.js.map +1 -0
- package/dist/charts/lib/toolbar.d.ts +143 -0
- package/dist/charts/lib/toolbar.js +156 -0
- package/dist/charts/lib/toolbar.js.map +1 -0
- package/dist/charts/lib/tooltip.d.ts +59 -0
- package/dist/charts/lib/tooltip.js +135 -0
- package/dist/charts/lib/tooltip.js.map +1 -0
- package/dist/charts/lib/values.d.ts +56 -0
- package/dist/charts/lib/values.js +71 -0
- package/dist/charts/lib/values.js.map +1 -0
- package/dist/charts/lib/zoom.d.ts +139 -0
- package/dist/charts/lib/zoom.js +314 -0
- package/dist/charts/lib/zoom.js.map +1 -0
- package/dist/semantic.css +19 -0
- package/dist/styles.css +1 -1
- package/dist/themes.css +50 -0
- package/dist/tokens.css +118 -0
- package/dist/tokens.d.ts +17 -0
- package/dist/tokens.js +101 -0
- package/dist/tokens.json +101 -0
- package/package.json +26 -4
- package/skills/misoto22-design/SKILL.md +171 -0
- package/skills/misoto22-design/evals/claims.json +95 -0
- package/skills/misoto22-design/rules/a11y.md +115 -0
- package/skills/misoto22-design/rules/composition.md +108 -0
- package/skills/misoto22-design/rules/forms.md +128 -0
- package/skills/misoto22-design/rules/naming.md +155 -0
- package/skills/misoto22-design/rules/tokens.md +131 -0
|
@@ -0,0 +1,350 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { Fragment, jsx, jsxs } from "react/jsx-runtime";
|
|
3
|
+
import {
|
|
4
|
+
createContext,
|
|
5
|
+
useContext,
|
|
6
|
+
useId,
|
|
7
|
+
useMemo
|
|
8
|
+
} from "react";
|
|
9
|
+
import {
|
|
10
|
+
Bar as RechartsBar,
|
|
11
|
+
BarChart as RechartsBarChart,
|
|
12
|
+
CartesianGrid,
|
|
13
|
+
XAxis as RechartsXAxis,
|
|
14
|
+
YAxis as RechartsYAxis,
|
|
15
|
+
usePlotArea
|
|
16
|
+
} from "recharts";
|
|
17
|
+
import { ChartContainer } from "../lib/chart.js";
|
|
18
|
+
import { ChartFigure } from "../lib/figure.js";
|
|
19
|
+
import { ChartEmpty } from "../lib/empty.js";
|
|
20
|
+
import { ChartBackground } from "../lib/background.js";
|
|
21
|
+
import { ChartTooltip } from "../lib/tooltip.js";
|
|
22
|
+
import { BarHatchedFill, SeriesGradient } from "../lib/paint.js";
|
|
23
|
+
import { Annotation, ReferenceBand, ReferenceLine } from "../lib/annotations.js";
|
|
24
|
+
import { axisLabel } from "../lib/axis.js";
|
|
25
|
+
import { defaultTick, formatNumber } from "../lib/format.js";
|
|
26
|
+
import { cn } from "../../lib/cn.js";
|
|
27
|
+
const DEFAULT_CONFIG = { count: { label: "Count" } };
|
|
28
|
+
const CHART_MARGIN = { top: 12, right: 12, bottom: 0, left: 12 };
|
|
29
|
+
const MAX_BINS = 200;
|
|
30
|
+
const BAR_SEPARATION = 1;
|
|
31
|
+
function quantile(sorted, p) {
|
|
32
|
+
if (sorted.length === 0) return Number.NaN;
|
|
33
|
+
if (sorted.length === 1) return sorted[0];
|
|
34
|
+
const h = (sorted.length - 1) * p;
|
|
35
|
+
const lower = sorted[Math.floor(h)];
|
|
36
|
+
const upper = sorted[Math.ceil(h)];
|
|
37
|
+
return lower + (h - Math.floor(h)) * (upper - lower);
|
|
38
|
+
}
|
|
39
|
+
function binCount(sorted) {
|
|
40
|
+
const n = sorted.length;
|
|
41
|
+
const span = sorted[n - 1] - sorted[0];
|
|
42
|
+
if (span <= 0) return 1;
|
|
43
|
+
const iqr = quantile(sorted, 0.75) - quantile(sorted, 0.25);
|
|
44
|
+
const width = 2 * iqr * Math.pow(n, -1 / 3);
|
|
45
|
+
const suggested = width > 0 ? Math.ceil(span / width) : Math.ceil(Math.log2(n)) + 1;
|
|
46
|
+
return Math.max(1, Math.min(MAX_BINS, suggested));
|
|
47
|
+
}
|
|
48
|
+
function binEdges(sorted, bins) {
|
|
49
|
+
if (Array.isArray(bins)) {
|
|
50
|
+
const edges = [...new Set(bins.filter(Number.isFinite))].sort((a, b) => a - b);
|
|
51
|
+
return edges.length >= 2 ? edges : [];
|
|
52
|
+
}
|
|
53
|
+
const low = sorted[0];
|
|
54
|
+
const high = sorted[sorted.length - 1];
|
|
55
|
+
if (high === low) return [low - 0.5, low + 0.5];
|
|
56
|
+
const count = Math.max(1, Math.min(MAX_BINS, typeof bins === "number" ? bins : binCount(sorted)));
|
|
57
|
+
const width = (high - low) / count;
|
|
58
|
+
return Array.from({ length: count + 1 }, (_, index) => low + index * width);
|
|
59
|
+
}
|
|
60
|
+
function bin(values, bins) {
|
|
61
|
+
const sorted = values.filter(Number.isFinite).sort((a, b) => a - b);
|
|
62
|
+
if (sorted.length === 0) return [];
|
|
63
|
+
const edges = binEdges(sorted, bins);
|
|
64
|
+
if (edges.length < 2) return [];
|
|
65
|
+
const counts = new Array(edges.length - 1).fill(0);
|
|
66
|
+
for (const value of sorted) {
|
|
67
|
+
if (value < edges[0] || value > edges[edges.length - 1]) continue;
|
|
68
|
+
let index = counts.length - 1;
|
|
69
|
+
for (let i = 0; i < counts.length; i += 1) {
|
|
70
|
+
if (value < edges[i + 1]) {
|
|
71
|
+
index = i;
|
|
72
|
+
break;
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
counts[index] = counts[index] + 1;
|
|
76
|
+
}
|
|
77
|
+
return counts.map((count, index) => ({ from: edges[index], to: edges[index + 1], count }));
|
|
78
|
+
}
|
|
79
|
+
function resolve(bins, mode, formatValue) {
|
|
80
|
+
const total = bins.reduce((sum, entry) => sum + entry.count, 0);
|
|
81
|
+
return bins.map((entry) => {
|
|
82
|
+
const width = entry.to - entry.from;
|
|
83
|
+
return {
|
|
84
|
+
...entry,
|
|
85
|
+
center: entry.from + width / 2,
|
|
86
|
+
// Density is `count / (n × width)`, so the bars enclose an area of 1 and
|
|
87
|
+
// uneven buckets stop lying: under frequency a bucket twice as wide
|
|
88
|
+
// stands twice as tall for the same underlying rate.
|
|
89
|
+
height: mode === "density" && total > 0 && width > 0 ? entry.count / (total * width) : entry.count,
|
|
90
|
+
label: `${formatValue(entry.from)} \u2013 ${formatValue(entry.to)}`
|
|
91
|
+
};
|
|
92
|
+
});
|
|
93
|
+
}
|
|
94
|
+
const HistogramContext = createContext(null);
|
|
95
|
+
function useHistogram() {
|
|
96
|
+
const context = useContext(HistogramContext);
|
|
97
|
+
if (!context) throw new Error("A histogram part must be rendered inside <Histogram>");
|
|
98
|
+
return context;
|
|
99
|
+
}
|
|
100
|
+
const densityTick = formatNumber({ style: "plain", fractionDigits: 3 });
|
|
101
|
+
function Histogram({
|
|
102
|
+
config = DEFAULT_CONFIG,
|
|
103
|
+
values,
|
|
104
|
+
data,
|
|
105
|
+
bins,
|
|
106
|
+
mode = "frequency",
|
|
107
|
+
title,
|
|
108
|
+
showTitle,
|
|
109
|
+
description,
|
|
110
|
+
children,
|
|
111
|
+
className,
|
|
112
|
+
chartProps,
|
|
113
|
+
formatValue = defaultTick,
|
|
114
|
+
hideDataTable = false,
|
|
115
|
+
empty
|
|
116
|
+
}) {
|
|
117
|
+
const chartId = useId().replace(/:/g, "");
|
|
118
|
+
const seriesKey = Object.keys(config)[0] ?? "count";
|
|
119
|
+
const resolved = useMemo(
|
|
120
|
+
() => resolve(data ?? bin(values ?? [], bins), mode, formatValue),
|
|
121
|
+
[data, values, bins, mode, formatValue]
|
|
122
|
+
);
|
|
123
|
+
const domain = useMemo(
|
|
124
|
+
() => resolved.length > 0 ? [resolved[0].from, resolved[resolved.length - 1].to] : [0, 1],
|
|
125
|
+
[resolved]
|
|
126
|
+
);
|
|
127
|
+
const total = useMemo(
|
|
128
|
+
() => resolved.reduce((sum, entry) => sum + entry.count, 0),
|
|
129
|
+
[resolved]
|
|
130
|
+
);
|
|
131
|
+
const context = useMemo(
|
|
132
|
+
() => ({ config, seriesKey, bins: resolved, domain, mode, total, formatValue }),
|
|
133
|
+
[config, seriesKey, resolved, domain, mode, total, formatValue]
|
|
134
|
+
);
|
|
135
|
+
const isEmpty = empty !== false && resolved.length === 0;
|
|
136
|
+
return /* @__PURE__ */ jsx(HistogramContext.Provider, { value: context, children: /* @__PURE__ */ jsx(
|
|
137
|
+
ChartFigure,
|
|
138
|
+
{
|
|
139
|
+
title,
|
|
140
|
+
showTitle,
|
|
141
|
+
description,
|
|
142
|
+
className,
|
|
143
|
+
table: hideDataTable ? false : {
|
|
144
|
+
rows: resolved,
|
|
145
|
+
rowKey: "label",
|
|
146
|
+
columns: [
|
|
147
|
+
{ key: "count", label: "Count" },
|
|
148
|
+
...mode === "density" ? [{ key: "height", label: "Density" }] : []
|
|
149
|
+
]
|
|
150
|
+
},
|
|
151
|
+
children: isEmpty ? /* @__PURE__ */ jsx(ChartEmpty, { ...empty || {} }) : /* @__PURE__ */ jsx(ChartContainer, { config, children: /* @__PURE__ */ jsx(
|
|
152
|
+
RechartsBarChart,
|
|
153
|
+
{
|
|
154
|
+
id: chartId,
|
|
155
|
+
accessibilityLayer: true,
|
|
156
|
+
margin: CHART_MARGIN,
|
|
157
|
+
data: resolved,
|
|
158
|
+
...chartProps,
|
|
159
|
+
children
|
|
160
|
+
}
|
|
161
|
+
) })
|
|
162
|
+
}
|
|
163
|
+
) });
|
|
164
|
+
}
|
|
165
|
+
function Bars({ radius = 0, hatched = false, barProps }) {
|
|
166
|
+
const { config, seriesKey } = useHistogram();
|
|
167
|
+
const id = useId().replace(/:/g, "");
|
|
168
|
+
return /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
169
|
+
/* @__PURE__ */ jsx(
|
|
170
|
+
RechartsBar,
|
|
171
|
+
{
|
|
172
|
+
dataKey: "height",
|
|
173
|
+
name: seriesKey,
|
|
174
|
+
isAnimationActive: false,
|
|
175
|
+
fill: `url(#${id}-colors-${seriesKey})`,
|
|
176
|
+
shape: (props) => /* @__PURE__ */ jsx(BinShape, { ...props, id, seriesKey, radius, hatched }),
|
|
177
|
+
activeBar: (props) => /* @__PURE__ */ jsx(BinShape, { ...props, id, seriesKey, radius, hatched }),
|
|
178
|
+
...barProps
|
|
179
|
+
}
|
|
180
|
+
),
|
|
181
|
+
/* @__PURE__ */ jsxs("defs", { children: [
|
|
182
|
+
/* @__PURE__ */ jsx(SeriesGradient, { id, dataKey: seriesKey, config, direction: "vertical" }),
|
|
183
|
+
hatched && /* @__PURE__ */ jsx(BarHatchedFill, { id, dataKey: seriesKey })
|
|
184
|
+
] })
|
|
185
|
+
] });
|
|
186
|
+
}
|
|
187
|
+
function BinShape({
|
|
188
|
+
x = 0,
|
|
189
|
+
y = 0,
|
|
190
|
+
width = 0,
|
|
191
|
+
height = 0,
|
|
192
|
+
payload,
|
|
193
|
+
id,
|
|
194
|
+
seriesKey,
|
|
195
|
+
radius,
|
|
196
|
+
hatched
|
|
197
|
+
}) {
|
|
198
|
+
const plot = usePlotArea();
|
|
199
|
+
const { domain } = useHistogram();
|
|
200
|
+
if (!payload) return null;
|
|
201
|
+
const [low, high] = domain;
|
|
202
|
+
const span = high - low;
|
|
203
|
+
const edges = plot && span > 0 ? {
|
|
204
|
+
start: plot.x + (payload.from - low) / span * plot.width,
|
|
205
|
+
end: plot.x + (payload.to - low) / span * plot.width
|
|
206
|
+
} : (
|
|
207
|
+
// Before the chart has measured itself there is no plot to map onto,
|
|
208
|
+
// and Recharts' own band is the only geometry available.
|
|
209
|
+
{ start: x, end: x + width }
|
|
210
|
+
);
|
|
211
|
+
const drawn = Math.max(1, edges.end - edges.start - BAR_SEPARATION);
|
|
212
|
+
return /* @__PURE__ */ jsx(
|
|
213
|
+
"rect",
|
|
214
|
+
{
|
|
215
|
+
x: edges.start + BAR_SEPARATION / 2,
|
|
216
|
+
y,
|
|
217
|
+
width: drawn,
|
|
218
|
+
height: Math.max(0, height),
|
|
219
|
+
rx: radius || void 0,
|
|
220
|
+
fill: hatched ? `url(#${id}-hatched-${seriesKey})` : `url(#${id}-colors-${seriesKey})`
|
|
221
|
+
}
|
|
222
|
+
);
|
|
223
|
+
}
|
|
224
|
+
function XAxis({
|
|
225
|
+
dataKey = "center",
|
|
226
|
+
type = "number",
|
|
227
|
+
tickLine = false,
|
|
228
|
+
axisLine = false,
|
|
229
|
+
tickMargin = 8,
|
|
230
|
+
minTickGap = 8,
|
|
231
|
+
label,
|
|
232
|
+
domain,
|
|
233
|
+
tickFormatter,
|
|
234
|
+
...rest
|
|
235
|
+
}) {
|
|
236
|
+
const { domain: measured, formatValue } = useHistogram();
|
|
237
|
+
return /* @__PURE__ */ jsx(
|
|
238
|
+
RechartsXAxis,
|
|
239
|
+
{
|
|
240
|
+
dataKey,
|
|
241
|
+
type,
|
|
242
|
+
domain: domain ?? measured,
|
|
243
|
+
tickLine,
|
|
244
|
+
axisLine,
|
|
245
|
+
tickMargin,
|
|
246
|
+
minTickGap,
|
|
247
|
+
tickFormatter: tickFormatter ?? formatValue,
|
|
248
|
+
...rest,
|
|
249
|
+
children: axisLabel(label, "x")
|
|
250
|
+
}
|
|
251
|
+
);
|
|
252
|
+
}
|
|
253
|
+
function YAxis({
|
|
254
|
+
tickLine = false,
|
|
255
|
+
axisLine = false,
|
|
256
|
+
tickMargin = 8,
|
|
257
|
+
width = "auto",
|
|
258
|
+
label,
|
|
259
|
+
tickFormatter,
|
|
260
|
+
...rest
|
|
261
|
+
}) {
|
|
262
|
+
const { mode } = useHistogram();
|
|
263
|
+
return /* @__PURE__ */ jsx(
|
|
264
|
+
RechartsYAxis,
|
|
265
|
+
{
|
|
266
|
+
tickLine,
|
|
267
|
+
axisLine,
|
|
268
|
+
tickMargin,
|
|
269
|
+
width,
|
|
270
|
+
tickFormatter: tickFormatter ?? (mode === "density" ? densityTick : defaultTick),
|
|
271
|
+
...rest,
|
|
272
|
+
children: axisLabel(label ?? (mode === "density" ? "Density" : void 0), "y")
|
|
273
|
+
}
|
|
274
|
+
);
|
|
275
|
+
}
|
|
276
|
+
function Grid({
|
|
277
|
+
strokeDasharray = "3 3",
|
|
278
|
+
vertical = false,
|
|
279
|
+
...rest
|
|
280
|
+
}) {
|
|
281
|
+
return /* @__PURE__ */ jsx(CartesianGrid, { strokeDasharray, vertical, ...rest });
|
|
282
|
+
}
|
|
283
|
+
function Tooltip({ variant = "solid", roundness = "lg", defaultIndex }) {
|
|
284
|
+
const { mode, total, formatValue } = useHistogram();
|
|
285
|
+
return /* @__PURE__ */ jsx(
|
|
286
|
+
ChartTooltip,
|
|
287
|
+
{
|
|
288
|
+
cursor: false,
|
|
289
|
+
defaultIndex,
|
|
290
|
+
content: (props) => {
|
|
291
|
+
const { active, payload } = props;
|
|
292
|
+
const entry = payload?.[0]?.payload;
|
|
293
|
+
if (!active || !entry) return /* @__PURE__ */ jsx("span", { className: "p-4" });
|
|
294
|
+
const share = total > 0 ? entry.count / total : 0;
|
|
295
|
+
return /* @__PURE__ */ jsxs(
|
|
296
|
+
"div",
|
|
297
|
+
{
|
|
298
|
+
className: cn(
|
|
299
|
+
"grid min-w-40 gap-1.5 border border-(--rule-2) px-2.5 py-1.5 text-xs",
|
|
300
|
+
roundness === "sm" && "rounded-(--radius-sm)",
|
|
301
|
+
roundness === "md" && "rounded-(--radius)",
|
|
302
|
+
roundness === "lg" && "rounded-(--radius-lg)",
|
|
303
|
+
variant === "frosted" ? "bg-(--chart-surface)/75 backdrop-blur-sm" : "bg-(--chart-surface)"
|
|
304
|
+
),
|
|
305
|
+
children: [
|
|
306
|
+
/* @__PURE__ */ jsxs("div", { className: "font-medium text-(--ink)", children: [
|
|
307
|
+
formatValue(entry.from),
|
|
308
|
+
" \u2013 ",
|
|
309
|
+
formatValue(entry.to)
|
|
310
|
+
] }),
|
|
311
|
+
/* @__PURE__ */ jsxs("div", { className: "flex justify-between gap-4 leading-none", children: [
|
|
312
|
+
/* @__PURE__ */ jsx("span", { className: "text-(--ink-3-aa)", children: "Count" }),
|
|
313
|
+
/* @__PURE__ */ jsx("span", { className: "font-mono font-medium tabular-nums text-(--ink)", children: entry.count.toLocaleString() })
|
|
314
|
+
] }),
|
|
315
|
+
/* @__PURE__ */ jsxs("div", { className: "flex justify-between gap-4 leading-none", children: [
|
|
316
|
+
/* @__PURE__ */ jsx("span", { className: "text-(--ink-3-aa)", children: "Share" }),
|
|
317
|
+
/* @__PURE__ */ jsxs("span", { className: "font-mono font-medium tabular-nums text-(--ink)", children: [
|
|
318
|
+
(share * 100).toFixed(1),
|
|
319
|
+
"%"
|
|
320
|
+
] })
|
|
321
|
+
] }),
|
|
322
|
+
mode === "density" && /* @__PURE__ */ jsxs("div", { className: "flex justify-between gap-4 leading-none", children: [
|
|
323
|
+
/* @__PURE__ */ jsx("span", { className: "text-(--ink-3-aa)", children: "Density" }),
|
|
324
|
+
/* @__PURE__ */ jsx("span", { className: "font-mono font-medium tabular-nums text-(--ink)", children: densityTick(entry.height) })
|
|
325
|
+
] })
|
|
326
|
+
]
|
|
327
|
+
}
|
|
328
|
+
);
|
|
329
|
+
}
|
|
330
|
+
}
|
|
331
|
+
);
|
|
332
|
+
}
|
|
333
|
+
function Background({ variant }) {
|
|
334
|
+
return /* @__PURE__ */ jsx(ChartBackground, { variant });
|
|
335
|
+
}
|
|
336
|
+
Histogram.Bars = Bars;
|
|
337
|
+
Histogram.XAxis = XAxis;
|
|
338
|
+
Histogram.YAxis = YAxis;
|
|
339
|
+
Histogram.Grid = Grid;
|
|
340
|
+
Histogram.Tooltip = Tooltip;
|
|
341
|
+
Histogram.Background = Background;
|
|
342
|
+
Histogram.ReferenceLine = ReferenceLine;
|
|
343
|
+
Histogram.ReferenceBand = ReferenceBand;
|
|
344
|
+
Histogram.Annotation = Annotation;
|
|
345
|
+
var Histogram_default = Histogram;
|
|
346
|
+
export {
|
|
347
|
+
Histogram,
|
|
348
|
+
Histogram_default as default
|
|
349
|
+
};
|
|
350
|
+
//# sourceMappingURL=Histogram.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../../src/charts/Histogram/Histogram.tsx"],"sourcesContent":["'use client'\n\nimport {\n createContext,\n useContext,\n useId,\n useMemo,\n type ComponentProps,\n type ReactNode,\n} from 'react'\nimport {\n Bar as RechartsBar,\n BarChart as RechartsBarChart,\n CartesianGrid,\n XAxis as RechartsXAxis,\n YAxis as RechartsYAxis,\n usePlotArea,\n} from 'recharts'\nimport { ChartContainer, type ChartConfig } from '../lib/chart'\nimport { ChartFigure } from '../lib/figure'\nimport { ChartEmpty, type ChartEmptyProps } from '../lib/empty'\nimport { ChartBackground, type ChartBackgroundVariant } from '../lib/background'\nimport { ChartTooltip } from '../lib/tooltip'\nimport { BarHatchedFill, SeriesGradient } from '../lib/paint'\nimport { Annotation, ReferenceBand, ReferenceLine } from '../lib/annotations'\nimport { axisLabel } from '../lib/axis'\nimport { defaultTick, formatNumber } from '../lib/format'\nimport { cn } from '../../lib/cn'\nimport type { ChartXAxisProps, ChartYAxisProps } from '../BarChart/BarChart'\nimport type { ChartTooltipSlotProps } from '../AreaChart/AreaChart'\n\n/** The series a chart with only one of them falls back to. */\nconst DEFAULT_CONFIG: ChartConfig = { count: { label: 'Count' } }\n\nconst CHART_MARGIN = { top: 12, right: 12, bottom: 0, left: 12 }\n\n/**\n * The most bins the automatic rule will ever ask for.\n *\n * Freedman–Diaconis divides by the interquartile range, so a distribution with\n * a tight middle and a long tail can ask for tens of thousands of bins — each\n * one a rectangle narrower than a pixel. The cap turns that into a coarse\n * histogram rather than into a hung tab.\n */\nconst MAX_BINS = 200\n\n/** Bars touch in a histogram; this is the hairline that keeps them countable. */\nconst BAR_SEPARATION = 1\n\n/** What the bar heights mean. */\nexport type HistogramMode = 'frequency' | 'density'\n\n/** One bucket, as the chart draws it. */\nexport interface HistogramBin {\n /** The bucket's lower edge, inclusive. */\n from: number\n /** The bucket's upper edge, exclusive — except the last, which includes it. */\n to: number\n /** How many observations fell in it. */\n count: number\n}\n\n/** A bin with everything the marks and the table need resolved. */\ninterface ResolvedBin extends HistogramBin {\n /** The bucket's midpoint, which is where Recharts positions the bar. */\n center: number\n /** What the bar's length encodes, per `mode`. */\n height: number\n /** The bucket's range, written out — the table's row header. */\n label: string\n}\n\n/**\n * The quantile at `p`, interpolated between neighbouring order statistics\n * (R type 7 / NumPy default). Used only to get the IQR the bin-width rule\n * needs.\n */\nfunction quantile(sorted: number[], p: number): number {\n if (sorted.length === 0) return Number.NaN\n if (sorted.length === 1) return sorted[0]!\n\n const h = (sorted.length - 1) * p\n const lower = sorted[Math.floor(h)]!\n const upper = sorted[Math.ceil(h)]!\n return lower + (h - Math.floor(h)) * (upper - lower)\n}\n\n/**\n * How many bins to cut the data into when the call site does not say.\n *\n * Freedman–Diaconis: bin width is `2 × IQR × n^(-1/3)`, which is the rule that\n * minimises the difference between the drawn histogram and the density it is\n * standing in for, and — because it reads the IQR rather than the range — the\n * one that a single far outlier cannot stretch into one tall bar and forty\n * empty ones.\n *\n * It has one failure mode: a distribution with more than half its mass on one\n * value has an IQR of zero and asks for infinitely many bins. Sturges' rule,\n * `⌈log₂ n⌉ + 1`, is the fallback there.\n */\nfunction binCount(sorted: number[]): number {\n const n = sorted.length\n const span = sorted[n - 1]! - sorted[0]!\n if (span <= 0) return 1\n\n const iqr = quantile(sorted, 0.75) - quantile(sorted, 0.25)\n const width = 2 * iqr * Math.pow(n, -1 / 3)\n const suggested =\n width > 0 ? Math.ceil(span / width) : Math.ceil(Math.log2(n)) + 1\n\n return Math.max(1, Math.min(MAX_BINS, suggested))\n}\n\n/** The edges the observations are cut at, low to high. */\nfunction binEdges(sorted: number[], bins: number | number[] | undefined): number[] {\n if (Array.isArray(bins)) {\n const edges = [...new Set(bins.filter(Number.isFinite))].sort((a, b) => a - b)\n return edges.length >= 2 ? edges : []\n }\n\n const low = sorted[0]!\n const high = sorted[sorted.length - 1]!\n // Every observation on one value still has to be drawn as something, and a\n // zero-width bar is nothing. One unit of room either side is the smallest\n // honest answer: one bar, centred on the only value there is.\n if (high === low) return [low - 0.5, low + 0.5]\n\n const count = Math.max(1, Math.min(MAX_BINS, typeof bins === 'number' ? bins : binCount(sorted)))\n const width = (high - low) / count\n return Array.from({ length: count + 1 }, (_, index) => low + index * width)\n}\n\n/** Raw observations, cut into buckets. */\nfunction bin(values: number[], bins: number | number[] | undefined): HistogramBin[] {\n const sorted = values.filter(Number.isFinite).sort((a, b) => a - b)\n if (sorted.length === 0) return []\n\n const edges = binEdges(sorted, bins)\n if (edges.length < 2) return []\n\n const counts = new Array<number>(edges.length - 1).fill(0)\n for (const value of sorted) {\n if (value < edges[0]! || value > edges[edges.length - 1]!) continue\n // The top edge belongs to the last bucket. Without that the largest\n // observation falls out of the histogram entirely, which is exactly the\n // point a reader is most likely to be looking for.\n let index = counts.length - 1\n for (let i = 0; i < counts.length; i += 1) {\n if (value < edges[i + 1]!) {\n index = i\n break\n }\n }\n counts[index] = counts[index]! + 1\n }\n\n return counts.map((count, index) => ({ from: edges[index]!, to: edges[index + 1]!, count }))\n}\n\n/** The bins with their midpoints, drawn heights and printed ranges. */\nfunction resolve(\n bins: HistogramBin[],\n mode: HistogramMode,\n formatValue: (value: number) => string,\n): ResolvedBin[] {\n const total = bins.reduce((sum, entry) => sum + entry.count, 0)\n\n return bins.map((entry) => {\n const width = entry.to - entry.from\n return {\n ...entry,\n center: entry.from + width / 2,\n // Density is `count / (n × width)`, so the bars enclose an area of 1 and\n // uneven buckets stop lying: under frequency a bucket twice as wide\n // stands twice as tall for the same underlying rate.\n height:\n mode === 'density' && total > 0 && width > 0 ? entry.count / (total * width) : entry.count,\n label: `${formatValue(entry.from)} – ${formatValue(entry.to)}`,\n }\n })\n}\n\ninterface HistogramContextValue {\n config: ChartConfig\n seriesKey: string\n bins: ResolvedBin[]\n domain: [number, number]\n mode: HistogramMode\n total: number\n formatValue: (value: number) => string\n}\n\nconst HistogramContext = createContext<HistogramContextValue | null>(null)\n\nfunction useHistogram(): HistogramContextValue {\n const context = useContext(HistogramContext)\n if (!context) throw new Error('A histogram part must be rendered inside <Histogram>')\n return context\n}\n\n/** Density values are small and unequal; the count axis is integers. */\nconst densityTick = formatNumber({ style: 'plain', fractionDigits: 3 })\n\nexport interface HistogramProps {\n /**\n * The single series — its label and its paint. Only the FIRST entry is read;\n * a histogram has one distribution and as many bars as it has buckets.\n */\n config?: ChartConfig\n /**\n * The raw observations, in any order. Binned for you by `bins`.\n *\n * Give this OR `data`, not both — `data` wins if both arrive.\n */\n values?: number[]\n /**\n * Buckets that were counted somewhere else — by a database, by a sketch, by\n * a metrics backend that only ever ships histograms.\n *\n * Uneven bucket widths are drawn at their real widths, which is the whole\n * reason this takes edges rather than labels. Set `mode=\"density\"` when they\n * are uneven, or the wide buckets will read as tall ones.\n */\n data?: HistogramBin[]\n /**\n * How to cut `values` up: a number of equal-width bins, or the explicit\n * edges. Defaults to Freedman–Diaconis (`2 × IQR × n^(-1/3)`), falling back\n * to Sturges when the interquartile range is zero.\n */\n bins?: number | number[]\n /**\n * What the bar heights mean.\n *\n * `frequency` is the count in each bucket and is what a reader assumes.\n * `density` is `count / (n × bin width)`, so the total area is 1 — which is\n * what makes two histograms of different sample sizes comparable, and what\n * makes uneven buckets honest.\n */\n mode?: HistogramMode\n /**\n * What the chart shows, in a sentence a reader could act on. Required, and\n * announced to a screen reader even when it is not printed.\n */\n title: string\n /** Prints the title above the plot instead of hiding it from sight. */\n showTitle?: boolean\n /** A line under the title — the unit, the window, the caveat. */\n description?: ReactNode\n /** The composed parts — axes, grid, tooltip, and `<Histogram.Bars>`. */\n children: ReactNode\n /** Merged onto the figure, last, so a call site can size or space it. */\n className?: string\n /** Escape hatch onto the raw Recharts chart element. */\n chartProps?: ComponentProps<typeof RechartsBarChart>\n /** Formats the measured values — bin edges, ticks, the tooltip's heading. */\n formatValue?: (value: number) => string\n /** Drops the hidden table view. Only correct when the page prints the data itself. */\n hideDataTable?: boolean\n /**\n * What the chart shows when it has nothing to draw. `false` keeps the axes,\n * for a chart whose emptiness is itself the reading.\n */\n empty?: ChartEmptyProps | false\n}\n\n/**\n * The shape of one distribution — where the mass sits, how it leans, whether\n * there is more than one hump in it.\n *\n * The form that answers what a `<BoxPlot>` structurally cannot: two clusters,\n * a hard floor, a pile-up at a timeout value. Reach for the box plot when\n * several distributions have to be compared side by side, and for this one when\n * a single distribution has to be understood.\n *\n * **A histogram's shape is a property of its bin width, not only of its data.**\n * The same numbers cut into eight buckets and into eighty are two different\n * pictures, and a gap between two humps can be created or erased by moving a\n * bin edge. That is not a defect to be fixed, it is what binning IS, and the\n * defence is to say which rule drew the picture — the default here is\n * Freedman–Diaconis — and to look at more than one width before believing a\n * feature. Uneven buckets add a second trap: under `frequency` a bucket twice\n * as wide stands twice as tall at the same underlying rate, which is what\n * `mode=\"density\"` exists to correct.\n *\n * Recharts earns its place here for the axes, the grid and the tooltip, but not\n * for the bars: a bar chart's bars are positioned by CATEGORY and a histogram's\n * are positioned and SIZED by a continuous measurement. So the x axis is\n * numeric and each bar is drawn from its own two edges — which is what lets an\n * uneven bucket be as wide as it really is instead of being flattened into an\n * equal slot beside its neighbours.\n *\n * @example\n * <Histogram title=\"Response times\" values={samples} bins={20}>\n * <Histogram.Grid />\n * <Histogram.XAxis label=\"ms\" />\n * <Histogram.YAxis />\n * <Histogram.Tooltip />\n * <Histogram.Bars />\n * </Histogram>\n *\n * @example\n * // Buckets that arrived already counted, with uneven widths.\n * <Histogram title=\"Payload size\" data={buckets} mode=\"density\">\n * <Histogram.XAxis />\n * <Histogram.YAxis />\n * <Histogram.Bars />\n * </Histogram>\n */\nexport function Histogram({\n config = DEFAULT_CONFIG,\n values,\n data,\n bins,\n mode = 'frequency',\n title,\n showTitle,\n description,\n children,\n className,\n chartProps,\n formatValue = defaultTick,\n hideDataTable = false,\n empty,\n}: HistogramProps) {\n const chartId = useId().replace(/:/g, '')\n const seriesKey = Object.keys(config)[0] ?? 'count'\n\n const resolved = useMemo(\n () => resolve(data ?? bin(values ?? [], bins), mode, formatValue),\n [data, values, bins, mode, formatValue],\n )\n\n const domain = useMemo<[number, number]>(\n () =>\n resolved.length > 0 ? [resolved[0]!.from, resolved[resolved.length - 1]!.to] : [0, 1],\n [resolved],\n )\n\n const total = useMemo(\n () => resolved.reduce((sum, entry) => sum + entry.count, 0),\n [resolved],\n )\n\n const context = useMemo<HistogramContextValue>(\n () => ({ config, seriesKey, bins: resolved, domain, mode, total, formatValue }),\n [config, seriesKey, resolved, domain, mode, total, formatValue],\n )\n\n const isEmpty = empty !== false && resolved.length === 0\n\n return (\n <HistogramContext.Provider value={context}>\n <ChartFigure\n title={title}\n showTitle={showTitle}\n description={description}\n className={className}\n table={\n hideDataTable\n ? false\n : {\n rows: resolved as unknown as Record<string, unknown>[],\n rowKey: 'label',\n columns: [\n { key: 'count', label: 'Count' },\n ...(mode === 'density' ? [{ key: 'height', label: 'Density' }] : []),\n ],\n }\n }\n >\n {isEmpty ? (\n <ChartEmpty {...(empty || {})} />\n ) : (\n <ChartContainer config={config}>\n <RechartsBarChart\n id={chartId}\n accessibilityLayer\n margin={CHART_MARGIN}\n data={resolved}\n {...chartProps}\n >\n {children}\n </RechartsBarChart>\n </ChartContainer>\n )}\n </ChartFigure>\n </HistogramContext.Provider>\n )\n}\n\nexport interface HistogramBarsProps {\n /**\n * The bars' corner. Zero by default, unlike `<BarChart>`: a histogram's bars\n * are one continuous surface cut into pieces, and a rounded corner draws a\n * gap between two buckets that are touching.\n */\n radius?: number\n /** Adds a 45° texture, for a histogram printed in greyscale or overlaid. */\n hatched?: boolean\n /** Escape hatch onto the underlying Recharts bar. */\n barProps?: ComponentProps<typeof RechartsBar>\n}\n\n/**\n * The bars themselves, each drawn between its own two bin edges.\n *\n * Recharts positions a bar on a numeric axis by CENTRING it on the value and\n * sizing it from the band, which would draw every bucket the same width. The\n * shape re-derives both edges from the plot area and the axis domain instead,\n * so a bucket is exactly as wide as the range it counts.\n */\nfunction Bars({ radius = 0, hatched = false, barProps }: HistogramBarsProps) {\n const { config, seriesKey } = useHistogram()\n const id = useId().replace(/:/g, '')\n\n return (\n <>\n <RechartsBar\n dataKey=\"height\"\n name={seriesKey}\n isAnimationActive={false}\n fill={`url(#${id}-colors-${seriesKey})`}\n shape={(props: unknown) => (\n <BinShape {...(props as BinGeometry)} id={id} seriesKey={seriesKey} radius={radius} hatched={hatched} />\n )}\n activeBar={(props: unknown) => (\n <BinShape {...(props as BinGeometry)} id={id} seriesKey={seriesKey} radius={radius} hatched={hatched} />\n )}\n {...barProps}\n />\n <defs>\n <SeriesGradient id={id} dataKey={seriesKey} config={config} direction=\"vertical\" />\n {hatched && <BarHatchedFill id={id} dataKey={seriesKey} />}\n </defs>\n </>\n )\n}\n\n/** The geometry Recharts hands a custom bar shape, plus the bin behind it. */\ninterface BinGeometry {\n x?: number\n y?: number\n width?: number\n height?: number\n payload?: ResolvedBin\n}\n\ninterface BinShapeProps extends BinGeometry {\n id: string\n seriesKey: string\n radius: number\n hatched: boolean\n}\n\n/** One bucket, spanning its real width on the measured axis. */\nfunction BinShape({\n x = 0,\n y = 0,\n width = 0,\n height = 0,\n payload,\n id,\n seriesKey,\n radius,\n hatched,\n}: BinShapeProps) {\n const plot = usePlotArea()\n const { domain } = useHistogram()\n\n if (!payload) return null\n\n const [low, high] = domain\n const span = high - low\n const edges =\n plot && span > 0\n ? {\n start: plot.x + ((payload.from - low) / span) * plot.width,\n end: plot.x + ((payload.to - low) / span) * plot.width,\n }\n : // Before the chart has measured itself there is no plot to map onto,\n // and Recharts' own band is the only geometry available.\n { start: x, end: x + width }\n\n const drawn = Math.max(1, edges.end - edges.start - BAR_SEPARATION)\n\n return (\n <rect\n x={edges.start + BAR_SEPARATION / 2}\n y={y}\n width={drawn}\n height={Math.max(0, height)}\n rx={radius || undefined}\n fill={hatched ? `url(#${id}-hatched-${seriesKey})` : `url(#${id}-colors-${seriesKey})`}\n />\n )\n}\n\n/** The measured axis. Numeric, because the buckets are a cut of a real scale. */\nfunction XAxis({\n dataKey = 'center',\n type = 'number',\n tickLine = false,\n axisLine = false,\n tickMargin = 8,\n minTickGap = 8,\n label,\n domain,\n tickFormatter,\n ...rest\n}: ChartXAxisProps) {\n const { domain: measured, formatValue } = useHistogram()\n\n return (\n <RechartsXAxis\n dataKey={dataKey}\n type={type}\n // Pinned to the outermost bin edges rather than left to Recharts, which\n // would pad the domain out to round numbers and leave the first and last\n // bars floating off their own edges.\n domain={domain ?? measured}\n tickLine={tickLine}\n axisLine={axisLine}\n tickMargin={tickMargin}\n minTickGap={minTickGap}\n tickFormatter={tickFormatter ?? formatValue}\n {...rest}\n >\n {axisLabel(label, 'x')}\n </RechartsXAxis>\n )\n}\n\n/** The count axis, or the density axis. */\nfunction YAxis({\n tickLine = false,\n axisLine = false,\n tickMargin = 8,\n width = 'auto',\n label,\n tickFormatter,\n ...rest\n}: ChartYAxisProps) {\n const { mode } = useHistogram()\n\n return (\n <RechartsYAxis\n tickLine={tickLine}\n axisLine={axisLine}\n tickMargin={tickMargin}\n width={width}\n tickFormatter={tickFormatter ?? (mode === 'density' ? densityTick : defaultTick)}\n {...rest}\n >\n {axisLabel(label ?? (mode === 'density' ? 'Density' : undefined), 'y')}\n </RechartsYAxis>\n )\n}\n\n/** Rules across the count axis. */\nfunction Grid({\n strokeDasharray = '3 3',\n vertical = false,\n ...rest\n}: ComponentProps<typeof CartesianGrid>) {\n return <CartesianGrid strokeDasharray={strokeDasharray} vertical={vertical} {...rest} />\n}\n\n/**\n * The hover panel, printing the bucket's range rather than its midpoint.\n *\n * The generic tooltip would head the panel with the centre value, which is a\n * number no observation necessarily has. What a reader wants from a histogram\n * bar is the interval it counts and how much of the sample fell in it.\n */\nfunction Tooltip({ variant = 'solid', roundness = 'lg', defaultIndex }: ChartTooltipSlotProps) {\n const { mode, total, formatValue } = useHistogram()\n\n return (\n <ChartTooltip\n cursor={false}\n defaultIndex={defaultIndex}\n content={(props) => {\n const { active, payload } = props as unknown as {\n active?: boolean\n payload?: { payload?: ResolvedBin }[]\n }\n const entry = payload?.[0]?.payload\n if (!active || !entry) return <span className=\"p-4\" />\n\n const share = total > 0 ? entry.count / total : 0\n\n return (\n <div\n className={cn(\n 'grid min-w-40 gap-1.5 border border-(--rule-2) px-2.5 py-1.5 text-xs',\n roundness === 'sm' && 'rounded-(--radius-sm)',\n roundness === 'md' && 'rounded-(--radius)',\n roundness === 'lg' && 'rounded-(--radius-lg)',\n variant === 'frosted'\n ? 'bg-(--chart-surface)/75 backdrop-blur-sm'\n : 'bg-(--chart-surface)',\n )}\n >\n <div className=\"font-medium text-(--ink)\">\n {formatValue(entry.from)} – {formatValue(entry.to)}\n </div>\n <div className=\"flex justify-between gap-4 leading-none\">\n <span className=\"text-(--ink-3-aa)\">Count</span>\n <span className=\"font-mono font-medium tabular-nums text-(--ink)\">\n {entry.count.toLocaleString()}\n </span>\n </div>\n <div className=\"flex justify-between gap-4 leading-none\">\n <span className=\"text-(--ink-3-aa)\">Share</span>\n <span className=\"font-mono font-medium tabular-nums text-(--ink)\">\n {(share * 100).toFixed(1)}%\n </span>\n </div>\n {mode === 'density' && (\n <div className=\"flex justify-between gap-4 leading-none\">\n <span className=\"text-(--ink-3-aa)\">Density</span>\n <span className=\"font-mono font-medium tabular-nums text-(--ink)\">\n {densityTick(entry.height)}\n </span>\n </div>\n )}\n </div>\n )\n }}\n />\n )\n}\n\n/** The decorative plate behind the plot. */\nfunction Background({ variant }: { variant: ChartBackgroundVariant }) {\n return <ChartBackground variant={variant} />\n}\n\nHistogram.Bars = Bars\nHistogram.XAxis = XAxis\nHistogram.YAxis = YAxis\nHistogram.Grid = Grid\nHistogram.Tooltip = Tooltip\nHistogram.Background = Background\nHistogram.ReferenceLine = ReferenceLine\nHistogram.ReferenceBand = ReferenceBand\nHistogram.Annotation = Annotation\n\nexport default Histogram\n"],"mappings":"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","names":[]}
|
|
@@ -0,0 +1,167 @@
|
|
|
1
|
+
import { ChartCurveType, AreaStrokeVariant, ChartTooltipSlotProps, ChartLegendSlotProps } from '../AreaChart/AreaChart.js';
|
|
2
|
+
import * as react from 'react';
|
|
3
|
+
import { ComponentProps, ReactNode, FC } from 'react';
|
|
4
|
+
import { XAxis, YAxis, LineChart as LineChart$1, Line, CartesianGrid } from 'recharts';
|
|
5
|
+
import { ChartConfig } from '../lib/chart.js';
|
|
6
|
+
import { ChartEmptyProps } from '../lib/empty.js';
|
|
7
|
+
import { ValuesProps } from '../lib/values.js';
|
|
8
|
+
import { SonifyProps } from '../lib/sonify-control.js';
|
|
9
|
+
import { ChartBackgroundVariant } from '../lib/background.js';
|
|
10
|
+
import { BrushProps } from '../lib/brush.js';
|
|
11
|
+
import { ToolbarProps } from '../lib/toolbar.js';
|
|
12
|
+
import { ChartRevealType } from '../lib/paint.js';
|
|
13
|
+
import { ChartDotVariant } from '../lib/dot.js';
|
|
14
|
+
import { ReferenceLine, ReferenceBand, Annotation } from '../lib/annotations.js';
|
|
15
|
+
import '../lib/legend.js';
|
|
16
|
+
import '../lib/tooltip.js';
|
|
17
|
+
import 'recharts/types/component/DefaultTooltipContent';
|
|
18
|
+
import '../lib/sonify.js';
|
|
19
|
+
import '../lib/zoom.js';
|
|
20
|
+
import '../lib/figure.js';
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* The axis props, with `label` narrowed to a string.
|
|
24
|
+
*
|
|
25
|
+
* Recharts' own `label` accepts a render function and a config object, neither
|
|
26
|
+
* of which a call site should be reaching for to name an axis — and both of
|
|
27
|
+
* which would let a consumer opt out of the system's own axis type styling
|
|
28
|
+
* without noticing.
|
|
29
|
+
*/
|
|
30
|
+
type ChartXAxisProps = Omit<ComponentProps<typeof XAxis>, 'label'> & {
|
|
31
|
+
/** What this axis measures. Say the unit here or in the series label, once. */
|
|
32
|
+
label?: string;
|
|
33
|
+
};
|
|
34
|
+
type ChartYAxisProps = Omit<ComponentProps<typeof YAxis>, 'label'> & {
|
|
35
|
+
/** What this axis measures. Say the unit here or in the series label, once. */
|
|
36
|
+
label?: string;
|
|
37
|
+
};
|
|
38
|
+
|
|
39
|
+
/** How a line is drawn. Same vocabulary as an area's stroke. */
|
|
40
|
+
type LineStrokeVariant = AreaStrokeVariant;
|
|
41
|
+
type ValidateKeys<TData, TConfig> = {
|
|
42
|
+
[K in keyof TConfig]: K extends keyof TData ? ChartConfig[string] : never;
|
|
43
|
+
};
|
|
44
|
+
interface LineChartProps<TData extends Record<string, unknown>, TConfig extends Record<string, ChartConfig[string]>> {
|
|
45
|
+
config: TConfig & ValidateKeys<TData, TConfig>;
|
|
46
|
+
/** The rows the chart draws. One entry per point, bar or category. */
|
|
47
|
+
data: TData[];
|
|
48
|
+
/**
|
|
49
|
+
* What the chart shows, in a sentence a reader could act on. Required, and
|
|
50
|
+
* announced to a screen reader even when it is not printed.
|
|
51
|
+
*/
|
|
52
|
+
title: string;
|
|
53
|
+
/** Prints the title above the plot instead of hiding it from sight. */
|
|
54
|
+
showTitle?: boolean;
|
|
55
|
+
/** A line under the title — the unit, the window, the caveat. */
|
|
56
|
+
description?: ReactNode;
|
|
57
|
+
/**
|
|
58
|
+
* The composed parts — axes, grid, tooltip, legend, and the marks
|
|
59
|
+
* themselves.
|
|
60
|
+
*/
|
|
61
|
+
children: ReactNode;
|
|
62
|
+
/** Merged onto the figure, last, so a call site can size or space it. */
|
|
63
|
+
className?: string;
|
|
64
|
+
/** Escape hatch onto the raw Recharts chart element. */
|
|
65
|
+
chartProps?: ComponentProps<typeof LineChart$1>;
|
|
66
|
+
/**
|
|
67
|
+
* How the line between two points is interpolated. Every mark inherits it
|
|
68
|
+
* unless it says otherwise.
|
|
69
|
+
*/
|
|
70
|
+
curveType?: ChartCurveType;
|
|
71
|
+
animationType?: ChartRevealType;
|
|
72
|
+
/** The series lit on first render. Selection dims every other series. */
|
|
73
|
+
defaultSelectedDataKey?: string | null;
|
|
74
|
+
/** Fires when the selection changes, and with null when it is cleared. */
|
|
75
|
+
onSelectionChange?: (selectedDataKey: string | null) => void;
|
|
76
|
+
/**
|
|
77
|
+
* Swaps the marks for an animated skeleton, keeping the measured height so
|
|
78
|
+
* the page does not jump when the data lands.
|
|
79
|
+
*/
|
|
80
|
+
isLoading?: boolean;
|
|
81
|
+
/** How many points the skeleton draws. */
|
|
82
|
+
loadingPoints?: number;
|
|
83
|
+
/**
|
|
84
|
+
* The row field on the category axis. Needed by the brush and by the table
|
|
85
|
+
* view.
|
|
86
|
+
*/
|
|
87
|
+
xDataKey?: keyof TData & string;
|
|
88
|
+
/**
|
|
89
|
+
* Drops the hidden table view. Only correct when the page prints the data
|
|
90
|
+
* itself.
|
|
91
|
+
*/
|
|
92
|
+
hideDataTable?: boolean;
|
|
93
|
+
/**
|
|
94
|
+
* What the chart shows when it has nothing to draw.
|
|
95
|
+
*
|
|
96
|
+
* Rendered instead of the plot whenever `data` is empty and the chart is not
|
|
97
|
+
* loading — the state a real dashboard reaches within a week, and the one an
|
|
98
|
+
* empty pair of axes is indistinguishable from a failed load. `false` keeps
|
|
99
|
+
* the axes, for a chart whose emptiness is itself the reading.
|
|
100
|
+
*/
|
|
101
|
+
empty?: ChartEmptyProps | false;
|
|
102
|
+
}
|
|
103
|
+
/**
|
|
104
|
+
* Several series compared over a continuous axis — the shape for "which of
|
|
105
|
+
* these is going where".
|
|
106
|
+
*
|
|
107
|
+
* The difference from `<AreaChart>` is what the reader is asked to do: an area
|
|
108
|
+
* says "read the magnitude under this", a line says "compare these against each
|
|
109
|
+
* other". Filling four overlapping series makes the second question unanswerable,
|
|
110
|
+
* which is why a line chart has no fill variant to offer.
|
|
111
|
+
*
|
|
112
|
+
* @example
|
|
113
|
+
* <LineChart title="Visitors per month" config={config} data={data}>
|
|
114
|
+
* <LineChart.Grid />
|
|
115
|
+
* <LineChart.XAxis dataKey="month" />
|
|
116
|
+
* <LineChart.Tooltip />
|
|
117
|
+
* <LineChart.Line dataKey="desktop">
|
|
118
|
+
* <LineChart.Dot variant="border" />
|
|
119
|
+
* </LineChart.Line>
|
|
120
|
+
* </LineChart>
|
|
121
|
+
*/
|
|
122
|
+
declare function LineChart<TData extends Record<string, unknown>, TConfig extends Record<string, ChartConfig[string]>>({ config, data, title, showTitle, description, children, className, chartProps, curveType, animationType, defaultSelectedDataKey, onSelectionChange, isLoading, loadingPoints, xDataKey, hideDataTable, empty, }: LineChartProps<TData, TConfig>): react.JSX.Element;
|
|
123
|
+
declare namespace LineChart {
|
|
124
|
+
var Line: ({ dataKey, strokeVariant, strokeWidth, curveType, animationType, connectNulls, isClickable, glowing, buffer, children, lineProps, }: LineProps) => react.JSX.Element | null;
|
|
125
|
+
var Dot: FC<DotProps>;
|
|
126
|
+
var ActiveDot: FC<DotProps>;
|
|
127
|
+
var XAxis: ({ tickLine, axisLine, tickMargin, minTickGap, label, ...rest }: ChartXAxisProps) => react.JSX.Element | null;
|
|
128
|
+
var YAxis: ({ tickLine, axisLine, tickMargin, minTickGap, width, tickFormatter, label, ...rest }: ChartYAxisProps) => react.JSX.Element | null;
|
|
129
|
+
var Grid: ({ vertical, strokeDasharray, ...rest }: ComponentProps<typeof CartesianGrid>) => react.JSX.Element;
|
|
130
|
+
var Tooltip: ({ variant, roundness, defaultIndex, cursor }: ChartTooltipSlotProps) => react.JSX.Element | null;
|
|
131
|
+
var Legend: ({ variant, align, verticalAlign, isClickable, }: ChartLegendSlotProps) => react.JSX.Element;
|
|
132
|
+
var Background: ({ variant }: {
|
|
133
|
+
variant: ChartBackgroundVariant;
|
|
134
|
+
}) => react.JSX.Element | null;
|
|
135
|
+
var ReferenceLine: typeof ReferenceLine;
|
|
136
|
+
var ReferenceBand: typeof ReferenceBand;
|
|
137
|
+
var Annotation: typeof Annotation;
|
|
138
|
+
var Values: FC<ValuesProps>;
|
|
139
|
+
var Brush: FC<BrushProps>;
|
|
140
|
+
var Toolbar: FC<ToolbarProps>;
|
|
141
|
+
var Sonify: FC<SonifyProps>;
|
|
142
|
+
}
|
|
143
|
+
interface LineProps {
|
|
144
|
+
dataKey: string;
|
|
145
|
+
strokeVariant?: LineStrokeVariant;
|
|
146
|
+
strokeWidth?: number;
|
|
147
|
+
curveType?: ChartCurveType;
|
|
148
|
+
animationType?: ChartRevealType;
|
|
149
|
+
connectNulls?: boolean;
|
|
150
|
+
isClickable?: boolean;
|
|
151
|
+
/** A halo around the line — for the one series that is the point of the figure. */
|
|
152
|
+
glowing?: boolean;
|
|
153
|
+
/**
|
|
154
|
+
* Draws the LAST segment dashed.
|
|
155
|
+
*
|
|
156
|
+
* The idiom for a projection or a period still open: the line reaches the
|
|
157
|
+
* same point either way, but the last leg is visibly a different kind of fact.
|
|
158
|
+
*/
|
|
159
|
+
buffer?: boolean;
|
|
160
|
+
children?: ReactNode;
|
|
161
|
+
lineProps?: ComponentProps<typeof Line>;
|
|
162
|
+
}
|
|
163
|
+
interface DotProps {
|
|
164
|
+
variant?: ChartDotVariant;
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
export { type ChartXAxisProps, type ChartYAxisProps, type DotProps, LineChart, type LineChartProps, type LineProps, type LineStrokeVariant, LineChart as default };
|