@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,535 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { Fragment, jsx, jsxs } from "react/jsx-runtime";
|
|
3
|
+
import {
|
|
4
|
+
Fragment as Fragment2,
|
|
5
|
+
useCallback,
|
|
6
|
+
useDeferredValue,
|
|
7
|
+
useEffect,
|
|
8
|
+
useId,
|
|
9
|
+
useMemo,
|
|
10
|
+
useRef,
|
|
11
|
+
useState,
|
|
12
|
+
startTransition
|
|
13
|
+
} from "react";
|
|
14
|
+
import {
|
|
15
|
+
motion,
|
|
16
|
+
useMotionValue,
|
|
17
|
+
useMotionValueEvent,
|
|
18
|
+
useSpring,
|
|
19
|
+
useTransform
|
|
20
|
+
} from "motion/react";
|
|
21
|
+
import {
|
|
22
|
+
Area,
|
|
23
|
+
AreaChart,
|
|
24
|
+
Bar,
|
|
25
|
+
BarChart,
|
|
26
|
+
Line,
|
|
27
|
+
LineChart,
|
|
28
|
+
ResponsiveContainer
|
|
29
|
+
} from "recharts";
|
|
30
|
+
import { cn } from "../../lib/cn.js";
|
|
31
|
+
import { colorStops } from "./chart.js";
|
|
32
|
+
const Brush = () => null;
|
|
33
|
+
const SPRING = { stiffness: 300, damping: 35, mass: 0.8 };
|
|
34
|
+
function useBrushDrag({
|
|
35
|
+
range,
|
|
36
|
+
totalPoints,
|
|
37
|
+
containerRef,
|
|
38
|
+
commit
|
|
39
|
+
}) {
|
|
40
|
+
const drag = useRef(null);
|
|
41
|
+
const [isDragging, setIsDragging] = useState(false);
|
|
42
|
+
const toIndexDelta = useCallback(
|
|
43
|
+
(px) => {
|
|
44
|
+
const width = containerRef.current?.getBoundingClientRect().width ?? 0;
|
|
45
|
+
if (!width || totalPoints <= 1) return 0;
|
|
46
|
+
return Math.round(px / width * (totalPoints - 1));
|
|
47
|
+
},
|
|
48
|
+
[containerRef, totalPoints]
|
|
49
|
+
);
|
|
50
|
+
const onPointerDown = useCallback(
|
|
51
|
+
(event, kind) => {
|
|
52
|
+
event.preventDefault();
|
|
53
|
+
event.target.setPointerCapture(event.pointerId);
|
|
54
|
+
drag.current = { kind, originX: event.clientX, originRange: { ...range } };
|
|
55
|
+
setIsDragging(true);
|
|
56
|
+
},
|
|
57
|
+
[range]
|
|
58
|
+
);
|
|
59
|
+
const onPointerMove = useCallback(
|
|
60
|
+
(event) => {
|
|
61
|
+
const state = drag.current;
|
|
62
|
+
if (!state) return;
|
|
63
|
+
const delta = toIndexDelta(event.clientX - state.originX);
|
|
64
|
+
const origin = state.originRange;
|
|
65
|
+
if (state.kind === "start") {
|
|
66
|
+
commit({ startIndex: origin.startIndex + delta, endIndex: origin.endIndex }, "start");
|
|
67
|
+
return;
|
|
68
|
+
}
|
|
69
|
+
if (state.kind === "end") {
|
|
70
|
+
commit({ startIndex: origin.startIndex, endIndex: origin.endIndex + delta }, "end");
|
|
71
|
+
return;
|
|
72
|
+
}
|
|
73
|
+
const span = origin.endIndex - origin.startIndex;
|
|
74
|
+
let start = origin.startIndex + delta;
|
|
75
|
+
let end = start + span;
|
|
76
|
+
if (start < 0) {
|
|
77
|
+
start = 0;
|
|
78
|
+
end = span;
|
|
79
|
+
}
|
|
80
|
+
if (end > totalPoints - 1) {
|
|
81
|
+
end = totalPoints - 1;
|
|
82
|
+
start = Math.max(0, end - span);
|
|
83
|
+
}
|
|
84
|
+
commit({ startIndex: start, endIndex: end }, "pan");
|
|
85
|
+
},
|
|
86
|
+
[commit, toIndexDelta, totalPoints]
|
|
87
|
+
);
|
|
88
|
+
const onPointerUp = useCallback((event) => {
|
|
89
|
+
;
|
|
90
|
+
event.target.releasePointerCapture(event.pointerId);
|
|
91
|
+
drag.current = null;
|
|
92
|
+
setIsDragging(false);
|
|
93
|
+
}, []);
|
|
94
|
+
const bind = useCallback(
|
|
95
|
+
(kind) => ({
|
|
96
|
+
onPointerDown: (event) => onPointerDown(event, kind),
|
|
97
|
+
onPointerMove,
|
|
98
|
+
onPointerUp
|
|
99
|
+
}),
|
|
100
|
+
[onPointerDown, onPointerMove, onPointerUp]
|
|
101
|
+
);
|
|
102
|
+
return { isDragging, bind };
|
|
103
|
+
}
|
|
104
|
+
function ChartBrush({
|
|
105
|
+
data,
|
|
106
|
+
config,
|
|
107
|
+
dataKeys,
|
|
108
|
+
xDataKey,
|
|
109
|
+
variant = "area",
|
|
110
|
+
height = 56,
|
|
111
|
+
className,
|
|
112
|
+
stacked = false,
|
|
113
|
+
strokeVariant = "solid",
|
|
114
|
+
connectNulls = false,
|
|
115
|
+
barRadius,
|
|
116
|
+
startIndex: controlledStart,
|
|
117
|
+
endIndex: controlledEnd,
|
|
118
|
+
defaultStartIndex = 0,
|
|
119
|
+
defaultEndIndex,
|
|
120
|
+
onChange,
|
|
121
|
+
formatLabel,
|
|
122
|
+
curveType = "monotone",
|
|
123
|
+
minSpan = 2,
|
|
124
|
+
showLabels = true,
|
|
125
|
+
label = "Visible range"
|
|
126
|
+
}) {
|
|
127
|
+
const containerRef = useRef(null);
|
|
128
|
+
const keys = useMemo(() => dataKeys ?? Object.keys(config), [dataKeys, config]);
|
|
129
|
+
const totalPoints = data.length;
|
|
130
|
+
const maxIndex = Math.max(0, totalPoints - 1);
|
|
131
|
+
const isControlled = controlledStart !== void 0 && controlledEnd !== void 0;
|
|
132
|
+
const [range, setRange] = useState(() => ({
|
|
133
|
+
startIndex: Math.max(0, Math.min(defaultStartIndex, maxIndex)),
|
|
134
|
+
endIndex: Math.max(0, Math.min(defaultEndIndex ?? maxIndex, maxIndex))
|
|
135
|
+
}));
|
|
136
|
+
const committed = useRef(range);
|
|
137
|
+
useEffect(() => {
|
|
138
|
+
if (isControlled) return;
|
|
139
|
+
setRange((previous) => {
|
|
140
|
+
const adjusted = {
|
|
141
|
+
startIndex: Math.min(previous.startIndex, maxIndex),
|
|
142
|
+
endIndex: Math.min(previous.endIndex, maxIndex)
|
|
143
|
+
};
|
|
144
|
+
committed.current = adjusted;
|
|
145
|
+
return adjusted;
|
|
146
|
+
});
|
|
147
|
+
}, [isControlled, maxIndex]);
|
|
148
|
+
const clamp = useCallback(
|
|
149
|
+
(next, kind) => {
|
|
150
|
+
let startIndex = Math.max(0, Math.min(next.startIndex, maxIndex));
|
|
151
|
+
let endIndex = Math.max(0, Math.min(next.endIndex, maxIndex));
|
|
152
|
+
if (kind === "start") {
|
|
153
|
+
return { startIndex: Math.min(startIndex, Math.max(0, endIndex - minSpan)), endIndex };
|
|
154
|
+
}
|
|
155
|
+
if (kind === "end") {
|
|
156
|
+
return { startIndex, endIndex: Math.max(endIndex, Math.min(maxIndex, startIndex + minSpan)) };
|
|
157
|
+
}
|
|
158
|
+
if (endIndex - startIndex < minSpan) {
|
|
159
|
+
endIndex = Math.min(startIndex + minSpan, maxIndex);
|
|
160
|
+
if (endIndex - startIndex < minSpan) startIndex = Math.max(0, endIndex - minSpan);
|
|
161
|
+
}
|
|
162
|
+
return { startIndex, endIndex };
|
|
163
|
+
},
|
|
164
|
+
[maxIndex, minSpan]
|
|
165
|
+
);
|
|
166
|
+
const commit = useCallback(
|
|
167
|
+
(next, kind) => {
|
|
168
|
+
const clamped = clamp(next, kind);
|
|
169
|
+
const last = committed.current;
|
|
170
|
+
if (last.startIndex === clamped.startIndex && last.endIndex === clamped.endIndex) return;
|
|
171
|
+
committed.current = clamped;
|
|
172
|
+
setRange(clamped);
|
|
173
|
+
startTransition(() => onChange?.(clamped));
|
|
174
|
+
},
|
|
175
|
+
[clamp, onChange]
|
|
176
|
+
);
|
|
177
|
+
const { isDragging, bind } = useBrushDrag({ range, totalPoints, containerRef, commit });
|
|
178
|
+
useEffect(() => {
|
|
179
|
+
if (!isControlled || isDragging) return;
|
|
180
|
+
const synced = { startIndex: controlledStart, endIndex: controlledEnd };
|
|
181
|
+
setRange(synced);
|
|
182
|
+
committed.current = synced;
|
|
183
|
+
}, [controlledEnd, controlledStart, isControlled, isDragging]);
|
|
184
|
+
const startPercent = maxIndex > 0 ? range.startIndex / maxIndex * 100 : 0;
|
|
185
|
+
const endPercent = maxIndex > 0 ? range.endIndex / maxIndex * 100 : 100;
|
|
186
|
+
const startTarget = useMotionValue(startPercent);
|
|
187
|
+
const endTarget = useMotionValue(endPercent);
|
|
188
|
+
if (startTarget.get() !== startPercent) startTarget.set(startPercent);
|
|
189
|
+
if (endTarget.get() !== endPercent) endTarget.set(endPercent);
|
|
190
|
+
const startSpring = useSpring(startTarget, SPRING);
|
|
191
|
+
const endSpring = useSpring(endTarget, SPRING);
|
|
192
|
+
const startEdge = useTransform(startSpring, (value) => `${value}%`);
|
|
193
|
+
const endEdge = useTransform(endSpring, (value) => `${value}%`);
|
|
194
|
+
const dimBefore = useTransform(startSpring, (value) => `${value}%`);
|
|
195
|
+
const dimAfter = useTransform(endSpring, (value) => `${Math.max(0, 100 - value)}%`);
|
|
196
|
+
const spanWidth = useMotionValue(`${Math.max(0, endPercent - startPercent)}%`);
|
|
197
|
+
const syncSpan = useCallback(() => {
|
|
198
|
+
spanWidth.set(`${Math.max(0, endSpring.get() - startSpring.get())}%`);
|
|
199
|
+
}, [endSpring, spanWidth, startSpring]);
|
|
200
|
+
useMotionValueEvent(startSpring, "change", syncSpan);
|
|
201
|
+
useMotionValueEvent(endSpring, "change", syncSpan);
|
|
202
|
+
const labelAt = useCallback(
|
|
203
|
+
(index) => {
|
|
204
|
+
if (!xDataKey) return String(index);
|
|
205
|
+
const value = data[index]?.[xDataKey];
|
|
206
|
+
return formatLabel ? formatLabel(value, index) : String(value ?? index);
|
|
207
|
+
},
|
|
208
|
+
[data, formatLabel, xDataKey]
|
|
209
|
+
);
|
|
210
|
+
const nudge = useCallback(
|
|
211
|
+
(kind, step) => {
|
|
212
|
+
const next = kind === "start" ? { startIndex: range.startIndex + step, endIndex: range.endIndex } : { startIndex: range.startIndex, endIndex: range.endIndex + step };
|
|
213
|
+
commit(next, kind);
|
|
214
|
+
},
|
|
215
|
+
[commit, range.endIndex, range.startIndex]
|
|
216
|
+
);
|
|
217
|
+
if (totalPoints === 0) return null;
|
|
218
|
+
return /* @__PURE__ */ jsxs(
|
|
219
|
+
"div",
|
|
220
|
+
{
|
|
221
|
+
ref: containerRef,
|
|
222
|
+
className: cn("group relative select-none", className),
|
|
223
|
+
style: { height },
|
|
224
|
+
children: [
|
|
225
|
+
/* @__PURE__ */ jsx("div", { className: "absolute inset-0 overflow-hidden rounded-(--radius-sm)", children: /* @__PURE__ */ jsx(
|
|
226
|
+
BrushStrip,
|
|
227
|
+
{
|
|
228
|
+
data,
|
|
229
|
+
keys,
|
|
230
|
+
config,
|
|
231
|
+
variant,
|
|
232
|
+
curveType,
|
|
233
|
+
stacked,
|
|
234
|
+
strokeVariant,
|
|
235
|
+
connectNulls,
|
|
236
|
+
barRadius
|
|
237
|
+
}
|
|
238
|
+
) }),
|
|
239
|
+
/* @__PURE__ */ jsx(
|
|
240
|
+
motion.div,
|
|
241
|
+
{
|
|
242
|
+
"aria-hidden": true,
|
|
243
|
+
className: "pointer-events-none absolute inset-y-0 rounded-(--radius-sm) bg-(--chart-surface)/70 backdrop-blur-[2px]",
|
|
244
|
+
style: { left: 0, width: dimBefore }
|
|
245
|
+
}
|
|
246
|
+
),
|
|
247
|
+
/* @__PURE__ */ jsx(
|
|
248
|
+
motion.div,
|
|
249
|
+
{
|
|
250
|
+
"aria-hidden": true,
|
|
251
|
+
className: "pointer-events-none absolute inset-y-0 rounded-(--radius-sm) bg-(--chart-surface)/70 backdrop-blur-[2px]",
|
|
252
|
+
style: { right: 0, width: dimAfter }
|
|
253
|
+
}
|
|
254
|
+
),
|
|
255
|
+
/* @__PURE__ */ jsx(
|
|
256
|
+
motion.div,
|
|
257
|
+
{
|
|
258
|
+
"aria-hidden": true,
|
|
259
|
+
className: "absolute inset-y-0 cursor-grab touch-none rounded-(--radius-sm) border border-(--rule-2) active:cursor-grabbing",
|
|
260
|
+
style: { left: startEdge, width: spanWidth },
|
|
261
|
+
...bind("pan")
|
|
262
|
+
}
|
|
263
|
+
),
|
|
264
|
+
/* @__PURE__ */ jsx(
|
|
265
|
+
BrushHandle,
|
|
266
|
+
{
|
|
267
|
+
kind: "start",
|
|
268
|
+
edge: startEdge,
|
|
269
|
+
label,
|
|
270
|
+
valueLabel: labelAt(range.startIndex),
|
|
271
|
+
showLabel: showLabels,
|
|
272
|
+
index: range.startIndex,
|
|
273
|
+
max: maxIndex,
|
|
274
|
+
bind: bind("start"),
|
|
275
|
+
onNudge: nudge
|
|
276
|
+
}
|
|
277
|
+
),
|
|
278
|
+
/* @__PURE__ */ jsx(
|
|
279
|
+
BrushHandle,
|
|
280
|
+
{
|
|
281
|
+
kind: "end",
|
|
282
|
+
edge: endEdge,
|
|
283
|
+
label,
|
|
284
|
+
valueLabel: labelAt(range.endIndex),
|
|
285
|
+
showLabel: showLabels,
|
|
286
|
+
index: range.endIndex,
|
|
287
|
+
max: maxIndex,
|
|
288
|
+
bind: bind("end"),
|
|
289
|
+
onNudge: nudge
|
|
290
|
+
}
|
|
291
|
+
)
|
|
292
|
+
]
|
|
293
|
+
}
|
|
294
|
+
);
|
|
295
|
+
}
|
|
296
|
+
function BrushHandle({
|
|
297
|
+
kind,
|
|
298
|
+
edge,
|
|
299
|
+
label,
|
|
300
|
+
valueLabel,
|
|
301
|
+
showLabel,
|
|
302
|
+
index,
|
|
303
|
+
max,
|
|
304
|
+
bind,
|
|
305
|
+
onNudge
|
|
306
|
+
}) {
|
|
307
|
+
const isStart = kind === "start";
|
|
308
|
+
const onKeyDown = (event) => {
|
|
309
|
+
const steps = {
|
|
310
|
+
ArrowLeft: -1,
|
|
311
|
+
ArrowDown: -1,
|
|
312
|
+
ArrowRight: 1,
|
|
313
|
+
ArrowUp: 1,
|
|
314
|
+
PageDown: -5,
|
|
315
|
+
PageUp: 5
|
|
316
|
+
};
|
|
317
|
+
if (event.key === "Home") {
|
|
318
|
+
event.preventDefault();
|
|
319
|
+
onNudge(kind, -max);
|
|
320
|
+
return;
|
|
321
|
+
}
|
|
322
|
+
if (event.key === "End") {
|
|
323
|
+
event.preventDefault();
|
|
324
|
+
onNudge(kind, max);
|
|
325
|
+
return;
|
|
326
|
+
}
|
|
327
|
+
const step = steps[event.key];
|
|
328
|
+
if (step === void 0) return;
|
|
329
|
+
event.preventDefault();
|
|
330
|
+
onNudge(kind, step);
|
|
331
|
+
};
|
|
332
|
+
return /* @__PURE__ */ jsxs(motion.div, { className: "absolute inset-y-0 z-(--z-rule)", style: { left: edge }, children: [
|
|
333
|
+
/* @__PURE__ */ jsx(
|
|
334
|
+
"div",
|
|
335
|
+
{
|
|
336
|
+
role: "slider",
|
|
337
|
+
tabIndex: 0,
|
|
338
|
+
"aria-label": `${label} \u2014 ${isStart ? "start" : "end"}`,
|
|
339
|
+
"aria-valuemin": 0,
|
|
340
|
+
"aria-valuemax": max,
|
|
341
|
+
"aria-valuenow": index,
|
|
342
|
+
"aria-valuetext": valueLabel,
|
|
343
|
+
onKeyDown,
|
|
344
|
+
className: cn(
|
|
345
|
+
"group/handle absolute inset-y-0 flex w-3 cursor-ew-resize touch-none items-center justify-center",
|
|
346
|
+
"after:absolute after:inset-y-0 after:w-11 after:content-['']"
|
|
347
|
+
),
|
|
348
|
+
style: { left: 0, transform: isStart ? void 0 : "translateX(-100%)" },
|
|
349
|
+
...bind,
|
|
350
|
+
children: /* @__PURE__ */ jsxs(
|
|
351
|
+
"span",
|
|
352
|
+
{
|
|
353
|
+
"aria-hidden": true,
|
|
354
|
+
className: "flex h-4 w-1.5 flex-col items-center justify-center gap-[2px] rounded-(--radius-sm) bg-(--ink-3-aa) transition-colors duration-(--duration-fast) group-hover/handle:bg-(--ink) group-focus-visible/handle:bg-(--ink)",
|
|
355
|
+
children: [
|
|
356
|
+
/* @__PURE__ */ jsx("span", { className: "size-[2px] rounded-(--radius-pill) bg-(--chart-surface)/70" }),
|
|
357
|
+
/* @__PURE__ */ jsx("span", { className: "size-[2px] rounded-(--radius-pill) bg-(--chart-surface)/70" }),
|
|
358
|
+
/* @__PURE__ */ jsx("span", { className: "size-[2px] rounded-(--radius-pill) bg-(--chart-surface)/70" })
|
|
359
|
+
]
|
|
360
|
+
}
|
|
361
|
+
)
|
|
362
|
+
}
|
|
363
|
+
),
|
|
364
|
+
showLabel && /* @__PURE__ */ jsx(
|
|
365
|
+
"span",
|
|
366
|
+
{
|
|
367
|
+
"aria-hidden": true,
|
|
368
|
+
className: "pointer-events-none absolute -bottom-3 -translate-y-1/2 rounded-[3px] bg-(--ink) px-1 py-px text-[8px] leading-tight font-medium whitespace-nowrap text-(--paper) opacity-0 transition-opacity duration-(--duration-fast) group-hover:opacity-100",
|
|
369
|
+
style: isStart ? { left: "0.375rem" } : { right: "0.375rem" },
|
|
370
|
+
children: valueLabel
|
|
371
|
+
}
|
|
372
|
+
)
|
|
373
|
+
] });
|
|
374
|
+
}
|
|
375
|
+
function BrushStrip({
|
|
376
|
+
data,
|
|
377
|
+
keys,
|
|
378
|
+
config,
|
|
379
|
+
variant,
|
|
380
|
+
curveType,
|
|
381
|
+
stacked,
|
|
382
|
+
strokeVariant,
|
|
383
|
+
connectNulls,
|
|
384
|
+
barRadius
|
|
385
|
+
}) {
|
|
386
|
+
const id = `brush-${useId().replace(/:/g, "")}`;
|
|
387
|
+
const series = useMemo(
|
|
388
|
+
() => Object.entries(config).filter(([key]) => keys.includes(key)).map(([dataKey, entry]) => ({ dataKey, stops: colorStops(entry) })),
|
|
389
|
+
[config, keys]
|
|
390
|
+
);
|
|
391
|
+
const dash = strokeVariant === "dashed" ? "4 4" : void 0;
|
|
392
|
+
const defs = /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
393
|
+
variant === "area" && /* @__PURE__ */ jsxs("linearGradient", { id: `${id}-fade`, x1: "0", y1: "0", x2: "0", y2: "1", children: [
|
|
394
|
+
/* @__PURE__ */ jsx("stop", { offset: "0%", stopColor: "white", stopOpacity: 0.15 }),
|
|
395
|
+
/* @__PURE__ */ jsx("stop", { offset: "100%", stopColor: "white", stopOpacity: 0 })
|
|
396
|
+
] }),
|
|
397
|
+
series.map(({ dataKey, stops }) => /* @__PURE__ */ jsxs(Fragment2, { children: [
|
|
398
|
+
/* @__PURE__ */ jsx("linearGradient", { id: `${id}-${dataKey}`, x1: "0", y1: "0", x2: "0", y2: "1", children: stops === 1 ? /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
399
|
+
/* @__PURE__ */ jsx("stop", { offset: "0%", stopColor: `var(--color-${dataKey}-0)` }),
|
|
400
|
+
/* @__PURE__ */ jsx("stop", { offset: "100%", stopColor: `var(--color-${dataKey}-0)` })
|
|
401
|
+
] }) : Array.from({ length: stops }, (_, index) => /* @__PURE__ */ jsx(
|
|
402
|
+
"stop",
|
|
403
|
+
{
|
|
404
|
+
offset: `${index / (stops - 1) * 100}%`,
|
|
405
|
+
stopColor: `var(--color-${dataKey}-${index}, var(--color-${dataKey}-0))`
|
|
406
|
+
},
|
|
407
|
+
index
|
|
408
|
+
)) }),
|
|
409
|
+
variant === "area" && /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
410
|
+
/* @__PURE__ */ jsx("mask", { id: `${id}-fill-mask-${dataKey}`, children: /* @__PURE__ */ jsx("rect", { width: "100%", height: "100%", fill: `url(#${id}-fade)` }) }),
|
|
411
|
+
/* @__PURE__ */ jsx(
|
|
412
|
+
"pattern",
|
|
413
|
+
{
|
|
414
|
+
id: `${id}-fill-${dataKey}`,
|
|
415
|
+
patternUnits: "userSpaceOnUse",
|
|
416
|
+
width: "100%",
|
|
417
|
+
height: "100%",
|
|
418
|
+
children: /* @__PURE__ */ jsx(
|
|
419
|
+
"rect",
|
|
420
|
+
{
|
|
421
|
+
width: "100%",
|
|
422
|
+
height: "100%",
|
|
423
|
+
fill: `url(#${id}-${dataKey})`,
|
|
424
|
+
mask: `url(#${id}-fill-mask-${dataKey})`
|
|
425
|
+
}
|
|
426
|
+
)
|
|
427
|
+
}
|
|
428
|
+
)
|
|
429
|
+
] })
|
|
430
|
+
] }, dataKey))
|
|
431
|
+
] });
|
|
432
|
+
if (variant === "line") {
|
|
433
|
+
return /* @__PURE__ */ jsx(ResponsiveContainer, { width: "100%", height: "100%", children: /* @__PURE__ */ jsxs(LineChart, { data, margin: { top: 4, right: 0, bottom: 0, left: 0 }, children: [
|
|
434
|
+
/* @__PURE__ */ jsx("defs", { children: defs }),
|
|
435
|
+
keys.map((key) => /* @__PURE__ */ jsx(
|
|
436
|
+
Line,
|
|
437
|
+
{
|
|
438
|
+
type: curveType,
|
|
439
|
+
dataKey: key,
|
|
440
|
+
stroke: `url(#${id}-${key})`,
|
|
441
|
+
strokeWidth: 1,
|
|
442
|
+
strokeOpacity: 0.5,
|
|
443
|
+
strokeDasharray: dash,
|
|
444
|
+
connectNulls,
|
|
445
|
+
dot: false,
|
|
446
|
+
activeDot: false,
|
|
447
|
+
isAnimationActive: false
|
|
448
|
+
},
|
|
449
|
+
key
|
|
450
|
+
))
|
|
451
|
+
] }) });
|
|
452
|
+
}
|
|
453
|
+
if (variant === "bar") {
|
|
454
|
+
const radius = barRadius ?? 3;
|
|
455
|
+
return /* @__PURE__ */ jsx(ResponsiveContainer, { width: "100%", height: "100%", children: /* @__PURE__ */ jsxs(
|
|
456
|
+
BarChart,
|
|
457
|
+
{
|
|
458
|
+
data,
|
|
459
|
+
margin: { top: 2, right: 0, bottom: 0, left: 0 },
|
|
460
|
+
barGap: 2,
|
|
461
|
+
barSize: 14,
|
|
462
|
+
children: [
|
|
463
|
+
/* @__PURE__ */ jsx("defs", { children: defs }),
|
|
464
|
+
keys.map((key) => /* @__PURE__ */ jsx(
|
|
465
|
+
Bar,
|
|
466
|
+
{
|
|
467
|
+
dataKey: key,
|
|
468
|
+
fill: `url(#${id}-${key})`,
|
|
469
|
+
fillOpacity: 0.35,
|
|
470
|
+
stackId: stacked ? "brush-stack" : void 0,
|
|
471
|
+
isAnimationActive: false,
|
|
472
|
+
radius: [radius, radius, radius, radius]
|
|
473
|
+
},
|
|
474
|
+
key
|
|
475
|
+
))
|
|
476
|
+
]
|
|
477
|
+
}
|
|
478
|
+
) });
|
|
479
|
+
}
|
|
480
|
+
return /* @__PURE__ */ jsx(ResponsiveContainer, { width: "100%", height: "100%", children: /* @__PURE__ */ jsxs(AreaChart, { data, margin: { top: 4, right: 0, bottom: 0, left: 0 }, children: [
|
|
481
|
+
/* @__PURE__ */ jsx("defs", { children: defs }),
|
|
482
|
+
keys.map((key) => /* @__PURE__ */ jsx(
|
|
483
|
+
Area,
|
|
484
|
+
{
|
|
485
|
+
type: curveType,
|
|
486
|
+
dataKey: key,
|
|
487
|
+
stroke: `url(#${id}-${key})`,
|
|
488
|
+
fill: `url(#${id}-fill-${key})`,
|
|
489
|
+
strokeWidth: 1,
|
|
490
|
+
strokeOpacity: 0.5,
|
|
491
|
+
strokeDasharray: dash,
|
|
492
|
+
connectNulls,
|
|
493
|
+
fillOpacity: 1,
|
|
494
|
+
stackId: stacked ? "brush-stack" : void 0,
|
|
495
|
+
dot: false,
|
|
496
|
+
activeDot: false,
|
|
497
|
+
isAnimationActive: false
|
|
498
|
+
},
|
|
499
|
+
key
|
|
500
|
+
))
|
|
501
|
+
] }) });
|
|
502
|
+
}
|
|
503
|
+
function useChartBrush({
|
|
504
|
+
data,
|
|
505
|
+
defaultStartIndex = 0,
|
|
506
|
+
defaultEndIndex
|
|
507
|
+
}) {
|
|
508
|
+
const [range, setRange] = useState({
|
|
509
|
+
startIndex: defaultStartIndex,
|
|
510
|
+
endIndex: defaultEndIndex ?? Math.max(0, data.length - 1)
|
|
511
|
+
});
|
|
512
|
+
const deferred = useDeferredValue(range);
|
|
513
|
+
useEffect(() => {
|
|
514
|
+
setRange({ startIndex: 0, endIndex: Math.max(0, data.length - 1) });
|
|
515
|
+
}, [data.length]);
|
|
516
|
+
const visibleData = useMemo(
|
|
517
|
+
() => data.slice(deferred.startIndex, deferred.endIndex + 1),
|
|
518
|
+
[data, deferred.endIndex, deferred.startIndex]
|
|
519
|
+
);
|
|
520
|
+
return {
|
|
521
|
+
range,
|
|
522
|
+
visibleData,
|
|
523
|
+
brushProps: {
|
|
524
|
+
startIndex: range.startIndex,
|
|
525
|
+
endIndex: range.endIndex,
|
|
526
|
+
onChange: setRange
|
|
527
|
+
}
|
|
528
|
+
};
|
|
529
|
+
}
|
|
530
|
+
export {
|
|
531
|
+
Brush,
|
|
532
|
+
ChartBrush,
|
|
533
|
+
useChartBrush
|
|
534
|
+
};
|
|
535
|
+
//# sourceMappingURL=brush.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../../src/charts/lib/brush.tsx"],"sourcesContent":["'use client'\n\nimport {\n Fragment,\n useCallback,\n useDeferredValue,\n useEffect,\n useId,\n useMemo,\n useRef,\n useState,\n startTransition,\n type ComponentProps,\n type FC,\n type KeyboardEvent,\n type PointerEvent as ReactPointerEvent,\n type RefObject,\n} from 'react'\nimport {\n motion,\n useMotionValue,\n useMotionValueEvent,\n useSpring,\n useTransform,\n type MotionValue,\n} from 'motion/react'\nimport {\n Area,\n AreaChart,\n Bar,\n BarChart,\n Line,\n LineChart,\n ResponsiveContainer,\n} from 'recharts'\nimport { cn } from '../../lib/cn'\nimport { colorStops, type ChartConfig } from './chart'\n\n/** The slice of the data a brush has selected, as row indexes. */\nexport interface ChartBrushRange {\n startIndex: number\n endIndex: number\n}\n\n/** Which mark the miniature strip is drawn with. */\nexport type ChartBrushVariant = 'line' | 'area' | 'bar'\n\nexport interface BrushProps {\n /** Strip height in pixels. */\n height?: number\n /** Turns a row's x value into a handle label. */\n formatLabel?: (value: unknown, index: number) => string\n onChange?: (range: ChartBrushRange) => void\n}\n\n/**\n * Declares the zoom brush under a chart.\n *\n * Renders nothing itself — its PRESENCE among the chart's children turns the\n * footer on, and its props configure it. A marker rather than a `showBrush`\n * prop because the brush is composed like every other part, so a consumer does\n * not have to remember which knobs are children and which are props.\n */\nexport const Brush: FC<BrushProps> = () => null\n\n/** How firmly the handles catch up with the pointer. */\nconst SPRING = { stiffness: 300, damping: 35, mass: 0.8 }\n\ntype DragKind = 'start' | 'end' | 'pan'\n\ninterface DragState {\n kind: DragKind\n originX: number\n originRange: ChartBrushRange\n}\n\n/**\n * Pointer-capture dragging for the two handles and the selected span.\n *\n * `setPointerCapture` routes every subsequent move to the element that was\n * pressed, so mouse, touch and pen all work from one code path and there are no\n * window-level listeners to leak.\n */\nfunction useBrushDrag({\n range,\n totalPoints,\n containerRef,\n commit,\n}: {\n range: ChartBrushRange\n totalPoints: number\n containerRef: RefObject<HTMLDivElement | null>\n commit: (next: ChartBrushRange, kind?: DragKind) => void\n}) {\n const drag = useRef<DragState | null>(null)\n const [isDragging, setIsDragging] = useState(false)\n\n const toIndexDelta = useCallback(\n (px: number) => {\n const width = containerRef.current?.getBoundingClientRect().width ?? 0\n if (!width || totalPoints <= 1) return 0\n return Math.round((px / width) * (totalPoints - 1))\n },\n [containerRef, totalPoints],\n )\n\n const onPointerDown = useCallback(\n (event: ReactPointerEvent, kind: DragKind) => {\n event.preventDefault()\n ;(event.target as HTMLElement).setPointerCapture(event.pointerId)\n drag.current = { kind, originX: event.clientX, originRange: { ...range } }\n setIsDragging(true)\n },\n [range],\n )\n\n const onPointerMove = useCallback(\n (event: ReactPointerEvent) => {\n const state = drag.current\n if (!state) return\n\n const delta = toIndexDelta(event.clientX - state.originX)\n const origin = state.originRange\n\n if (state.kind === 'start') {\n commit({ startIndex: origin.startIndex + delta, endIndex: origin.endIndex }, 'start')\n return\n }\n if (state.kind === 'end') {\n commit({ startIndex: origin.startIndex, endIndex: origin.endIndex + delta }, 'end')\n return\n }\n\n const span = origin.endIndex - origin.startIndex\n let start = origin.startIndex + delta\n let end = start + span\n if (start < 0) {\n start = 0\n end = span\n }\n if (end > totalPoints - 1) {\n end = totalPoints - 1\n start = Math.max(0, end - span)\n }\n commit({ startIndex: start, endIndex: end }, 'pan')\n },\n [commit, toIndexDelta, totalPoints],\n )\n\n const onPointerUp = useCallback((event: ReactPointerEvent) => {\n ;(event.target as HTMLElement).releasePointerCapture(event.pointerId)\n drag.current = null\n setIsDragging(false)\n }, [])\n\n const bind = useCallback(\n (kind: DragKind) => ({\n onPointerDown: (event: ReactPointerEvent) => onPointerDown(event, kind),\n onPointerMove,\n onPointerUp,\n }),\n [onPointerDown, onPointerMove, onPointerUp],\n )\n\n return { isDragging, bind }\n}\n\nexport interface ChartBrushProps {\n /** The whole dataset. The strip always draws all of it. */\n data: Record<string, unknown>[]\n config: ChartConfig\n /** Which series the strip draws. Defaults to every key in the config. */\n dataKeys?: string[]\n /** The row field behind a handle's label. */\n xDataKey?: string\n variant?: ChartBrushVariant\n height?: number\n className?: string\n stacked?: boolean\n strokeVariant?: 'solid' | 'dashed'\n connectNulls?: boolean\n barRadius?: number\n startIndex?: number\n endIndex?: number\n defaultStartIndex?: number\n defaultEndIndex?: number\n onChange?: (range: ChartBrushRange) => void\n formatLabel?: (value: unknown, index: number) => string\n curveType?: ComponentProps<typeof Area>['type']\n /** The fewest rows that may stay selected. */\n minSpan?: number\n showLabels?: boolean\n /** Names the control for a screen reader. */\n label?: string\n}\n\n/**\n * The range selector under a chart: a miniature of the whole series, with a lit\n * window over the part the chart above is showing.\n *\n * Both handles are real `slider` controls — focusable, arrow-key driven, with\n * `aria-valuetext` reading out the row they sit on. The shape this was ported\n * from was pointer-only, which made zooming a chart something a keyboard user\n * could watch but not do.\n *\n * Position is written as inline style rather than as `start-`/`end-` classes on\n * purpose. The strip's axis is the DATA's, and Recharts lays a cartesian plot\n * out left-to-right in every writing direction — so mirroring the handles under\n * `dir=\"rtl\"` would put the \"earlier\" handle at the end of a chart that still\n * runs the other way.\n */\nexport function ChartBrush({\n data,\n config,\n dataKeys,\n xDataKey,\n variant = 'area',\n height = 56,\n className,\n stacked = false,\n strokeVariant = 'solid',\n connectNulls = false,\n barRadius,\n startIndex: controlledStart,\n endIndex: controlledEnd,\n defaultStartIndex = 0,\n defaultEndIndex,\n onChange,\n formatLabel,\n curveType = 'monotone',\n minSpan = 2,\n showLabels = true,\n label = 'Visible range',\n}: ChartBrushProps) {\n const containerRef = useRef<HTMLDivElement>(null)\n const keys = useMemo(() => dataKeys ?? Object.keys(config), [dataKeys, config])\n const totalPoints = data.length\n const maxIndex = Math.max(0, totalPoints - 1)\n\n const isControlled = controlledStart !== undefined && controlledEnd !== undefined\n\n const [range, setRange] = useState<ChartBrushRange>(() => ({\n startIndex: Math.max(0, Math.min(defaultStartIndex, maxIndex)),\n endIndex: Math.max(0, Math.min(defaultEndIndex ?? maxIndex, maxIndex)),\n }))\n\n const committed = useRef<ChartBrushRange>(range)\n\n useEffect(() => {\n if (isControlled) return\n setRange((previous) => {\n const adjusted = {\n startIndex: Math.min(previous.startIndex, maxIndex),\n endIndex: Math.min(previous.endIndex, maxIndex),\n }\n committed.current = adjusted\n return adjusted\n })\n }, [isControlled, maxIndex])\n\n const clamp = useCallback(\n (next: ChartBrushRange, kind?: DragKind): ChartBrushRange => {\n let startIndex = Math.max(0, Math.min(next.startIndex, maxIndex))\n let endIndex = Math.max(0, Math.min(next.endIndex, maxIndex))\n\n if (kind === 'start') {\n return { startIndex: Math.min(startIndex, Math.max(0, endIndex - minSpan)), endIndex }\n }\n if (kind === 'end') {\n return { startIndex, endIndex: Math.max(endIndex, Math.min(maxIndex, startIndex + minSpan)) }\n }\n if (endIndex - startIndex < minSpan) {\n endIndex = Math.min(startIndex + minSpan, maxIndex)\n if (endIndex - startIndex < minSpan) startIndex = Math.max(0, endIndex - minSpan)\n }\n return { startIndex, endIndex }\n },\n [maxIndex, minSpan],\n )\n\n const commit = useCallback(\n (next: ChartBrushRange, kind?: DragKind) => {\n const clamped = clamp(next, kind)\n const last = committed.current\n if (last.startIndex === clamped.startIndex && last.endIndex === clamped.endIndex) return\n\n committed.current = clamped\n setRange(clamped)\n // The handles have to keep up with the pointer; the chart above does not.\n // Deferring lets React drop intermediate slices during a fast drag.\n startTransition(() => onChange?.(clamped))\n },\n [clamp, onChange],\n )\n\n const { isDragging, bind } = useBrushDrag({ range, totalPoints, containerRef, commit })\n\n useEffect(() => {\n if (!isControlled || isDragging) return\n const synced = { startIndex: controlledStart, endIndex: controlledEnd }\n setRange(synced)\n committed.current = synced\n }, [controlledEnd, controlledStart, isControlled, isDragging])\n\n const startPercent = maxIndex > 0 ? (range.startIndex / maxIndex) * 100 : 0\n const endPercent = maxIndex > 0 ? (range.endIndex / maxIndex) * 100 : 100\n\n const startTarget = useMotionValue(startPercent)\n const endTarget = useMotionValue(endPercent)\n if (startTarget.get() !== startPercent) startTarget.set(startPercent)\n if (endTarget.get() !== endPercent) endTarget.set(endPercent)\n\n const startSpring = useSpring(startTarget, SPRING)\n const endSpring = useSpring(endTarget, SPRING)\n const startEdge = useTransform(startSpring, (value) => `${value}%`)\n const endEdge = useTransform(endSpring, (value) => `${value}%`)\n const dimBefore = useTransform(startSpring, (value) => `${value}%`)\n const dimAfter = useTransform(endSpring, (value) => `${Math.max(0, 100 - value)}%`)\n const spanWidth = useMotionValue(`${Math.max(0, endPercent - startPercent)}%`)\n\n const syncSpan = useCallback(() => {\n spanWidth.set(`${Math.max(0, endSpring.get() - startSpring.get())}%`)\n }, [endSpring, spanWidth, startSpring])\n\n useMotionValueEvent(startSpring, 'change', syncSpan)\n useMotionValueEvent(endSpring, 'change', syncSpan)\n\n const labelAt = useCallback(\n (index: number) => {\n if (!xDataKey) return String(index)\n const value = data[index]?.[xDataKey]\n return formatLabel ? formatLabel(value, index) : String(value ?? index)\n },\n [data, formatLabel, xDataKey],\n )\n\n const nudge = useCallback(\n (kind: 'start' | 'end', step: number) => {\n const next =\n kind === 'start'\n ? { startIndex: range.startIndex + step, endIndex: range.endIndex }\n : { startIndex: range.startIndex, endIndex: range.endIndex + step }\n commit(next, kind)\n },\n [commit, range.endIndex, range.startIndex],\n )\n\n if (totalPoints === 0) return null\n\n return (\n <div\n ref={containerRef}\n className={cn('group relative select-none', className)}\n style={{ height }}\n >\n <div className=\"absolute inset-0 overflow-hidden rounded-(--radius-sm)\">\n <BrushStrip\n data={data}\n keys={keys}\n config={config}\n variant={variant}\n curveType={curveType}\n stacked={stacked}\n strokeVariant={strokeVariant}\n connectNulls={connectNulls}\n barRadius={barRadius}\n />\n </div>\n\n {/* The two dimmed shoulders. A wash rather than an opacity change on the\n strip: dimming the strip itself would also dim the selected window. */}\n <motion.div\n aria-hidden\n className=\"pointer-events-none absolute inset-y-0 rounded-(--radius-sm) bg-(--chart-surface)/70 backdrop-blur-[2px]\"\n style={{ left: 0, width: dimBefore }}\n />\n <motion.div\n aria-hidden\n className=\"pointer-events-none absolute inset-y-0 rounded-(--radius-sm) bg-(--chart-surface)/70 backdrop-blur-[2px]\"\n style={{ right: 0, width: dimAfter }}\n />\n\n <motion.div\n aria-hidden\n className=\"absolute inset-y-0 cursor-grab touch-none rounded-(--radius-sm) border border-(--rule-2) active:cursor-grabbing\"\n style={{ left: startEdge, width: spanWidth }}\n {...bind('pan')}\n />\n\n <BrushHandle\n kind=\"start\"\n edge={startEdge}\n label={label}\n valueLabel={labelAt(range.startIndex)}\n showLabel={showLabels}\n index={range.startIndex}\n max={maxIndex}\n bind={bind('start')}\n onNudge={nudge}\n />\n <BrushHandle\n kind=\"end\"\n edge={endEdge}\n label={label}\n valueLabel={labelAt(range.endIndex)}\n showLabel={showLabels}\n index={range.endIndex}\n max={maxIndex}\n bind={bind('end')}\n onNudge={nudge}\n />\n </div>\n )\n}\n\n/**\n * One end of the window.\n *\n * A `slider` rather than a styled div: arrow keys step it, Home and End jump it\n * to the edges, and `aria-valuetext` says which row it is on rather than which\n * index — an index is not what the reader is choosing between.\n */\nfunction BrushHandle({\n kind,\n edge,\n label,\n valueLabel,\n showLabel,\n index,\n max,\n bind,\n onNudge,\n}: {\n kind: 'start' | 'end'\n edge: MotionValue<string>\n label: string\n valueLabel: string\n showLabel: boolean\n index: number\n max: number\n bind: {\n onPointerDown: (event: ReactPointerEvent) => void\n onPointerMove: (event: ReactPointerEvent) => void\n onPointerUp: (event: ReactPointerEvent) => void\n }\n onNudge: (kind: 'start' | 'end', step: number) => void\n}) {\n const isStart = kind === 'start'\n\n const onKeyDown = (event: KeyboardEvent<HTMLDivElement>) => {\n const steps: Record<string, number> = {\n ArrowLeft: -1,\n ArrowDown: -1,\n ArrowRight: 1,\n ArrowUp: 1,\n PageDown: -5,\n PageUp: 5,\n }\n if (event.key === 'Home') {\n event.preventDefault()\n onNudge(kind, -max)\n return\n }\n if (event.key === 'End') {\n event.preventDefault()\n onNudge(kind, max)\n return\n }\n const step = steps[event.key]\n if (step === undefined) return\n event.preventDefault()\n onNudge(kind, step)\n }\n\n return (\n <motion.div className=\"absolute inset-y-0 z-(--z-rule)\" style={{ left: edge }}>\n <div\n role=\"slider\"\n tabIndex={0}\n aria-label={`${label} — ${isStart ? 'start' : 'end'}`}\n aria-valuemin={0}\n aria-valuemax={max}\n aria-valuenow={index}\n aria-valuetext={valueLabel}\n onKeyDown={onKeyDown}\n // The 44px hit target WCAG 2.5.5 asks for, as a pseudo-element so the\n // handle itself can stay 6px wide.\n className={cn(\n 'group/handle absolute inset-y-0 flex w-3 cursor-ew-resize touch-none items-center justify-center',\n \"after:absolute after:inset-y-0 after:w-11 after:content-['']\",\n )}\n // Physical, and deliberately so — see the note on ChartBrush. In a\n // class this would need an `rtl:` twin that would move the handle off\n // the edge it belongs to.\n style={{ left: 0, transform: isStart ? undefined : 'translateX(-100%)' }}\n {...bind}\n >\n <span\n aria-hidden\n className=\"flex h-4 w-1.5 flex-col items-center justify-center gap-[2px] rounded-(--radius-sm) bg-(--ink-3-aa) transition-colors duration-(--duration-fast) group-hover/handle:bg-(--ink) group-focus-visible/handle:bg-(--ink)\"\n >\n <span className=\"size-[2px] rounded-(--radius-pill) bg-(--chart-surface)/70\" />\n <span className=\"size-[2px] rounded-(--radius-pill) bg-(--chart-surface)/70\" />\n <span className=\"size-[2px] rounded-(--radius-pill) bg-(--chart-surface)/70\" />\n </span>\n </div>\n\n {showLabel && (\n <span\n aria-hidden\n className=\"pointer-events-none absolute -bottom-3 -translate-y-1/2 rounded-[3px] bg-(--ink) px-1 py-px text-[8px] leading-tight font-medium whitespace-nowrap text-(--paper) opacity-0 transition-opacity duration-(--duration-fast) group-hover:opacity-100\"\n style={isStart ? { left: '0.375rem' } : { right: '0.375rem' }}\n >\n {valueLabel}\n </span>\n )}\n </motion.div>\n )\n}\n\n/**\n * The miniature series behind the window.\n *\n * Its own gradients rather than the chart's: the strip is a second Recharts\n * tree, and an SVG paint reference cannot cross from one `<svg>` root into\n * another. The custom properties DO cross — they are inherited CSS — which is\n * why the strip needs no config of its own beyond the series list.\n */\nfunction BrushStrip({\n data,\n keys,\n config,\n variant,\n curveType,\n stacked,\n strokeVariant,\n connectNulls,\n barRadius,\n}: {\n data: Record<string, unknown>[]\n keys: string[]\n config: ChartConfig\n variant: ChartBrushVariant\n curveType: ComponentProps<typeof Area>['type']\n stacked: boolean\n strokeVariant: 'solid' | 'dashed'\n connectNulls: boolean\n barRadius?: number\n}) {\n const id = `brush-${useId().replace(/:/g, '')}`\n const series = useMemo(\n () =>\n Object.entries(config)\n .filter(([key]) => keys.includes(key))\n .map(([dataKey, entry]) => ({ dataKey, stops: colorStops(entry) })),\n [config, keys],\n )\n\n const dash = strokeVariant === 'dashed' ? '4 4' : undefined\n\n const defs = (\n <>\n {variant === 'area' && (\n <linearGradient id={`${id}-fade`} x1=\"0\" y1=\"0\" x2=\"0\" y2=\"1\">\n <stop offset=\"0%\" stopColor=\"white\" stopOpacity={0.15} />\n <stop offset=\"100%\" stopColor=\"white\" stopOpacity={0} />\n </linearGradient>\n )}\n {series.map(({ dataKey, stops }) => (\n <Fragment key={dataKey}>\n <linearGradient id={`${id}-${dataKey}`} x1=\"0\" y1=\"0\" x2=\"0\" y2=\"1\">\n {stops === 1 ? (\n <>\n <stop offset=\"0%\" stopColor={`var(--color-${dataKey}-0)`} />\n <stop offset=\"100%\" stopColor={`var(--color-${dataKey}-0)`} />\n </>\n ) : (\n Array.from({ length: stops }, (_, index) => (\n <stop\n key={index}\n offset={`${(index / (stops - 1)) * 100}%`}\n stopColor={`var(--color-${dataKey}-${index}, var(--color-${dataKey}-0))`}\n />\n ))\n )}\n </linearGradient>\n {variant === 'area' && (\n <>\n <mask id={`${id}-fill-mask-${dataKey}`}>\n <rect width=\"100%\" height=\"100%\" fill={`url(#${id}-fade)`} />\n </mask>\n <pattern\n id={`${id}-fill-${dataKey}`}\n patternUnits=\"userSpaceOnUse\"\n width=\"100%\"\n height=\"100%\"\n >\n <rect\n width=\"100%\"\n height=\"100%\"\n fill={`url(#${id}-${dataKey})`}\n mask={`url(#${id}-fill-mask-${dataKey})`}\n />\n </pattern>\n </>\n )}\n </Fragment>\n ))}\n </>\n )\n\n if (variant === 'line') {\n return (\n <ResponsiveContainer width=\"100%\" height=\"100%\">\n <LineChart data={data} margin={{ top: 4, right: 0, bottom: 0, left: 0 }}>\n <defs>{defs}</defs>\n {keys.map((key) => (\n <Line\n key={key}\n type={curveType}\n dataKey={key}\n stroke={`url(#${id}-${key})`}\n strokeWidth={1}\n strokeOpacity={0.5}\n strokeDasharray={dash}\n connectNulls={connectNulls}\n dot={false}\n activeDot={false}\n isAnimationActive={false}\n />\n ))}\n </LineChart>\n </ResponsiveContainer>\n )\n }\n\n if (variant === 'bar') {\n const radius = barRadius ?? 3\n return (\n <ResponsiveContainer width=\"100%\" height=\"100%\">\n <BarChart\n data={data}\n margin={{ top: 2, right: 0, bottom: 0, left: 0 }}\n barGap={2}\n barSize={14}\n >\n <defs>{defs}</defs>\n {keys.map((key) => (\n <Bar\n key={key}\n dataKey={key}\n fill={`url(#${id}-${key})`}\n fillOpacity={0.35}\n stackId={stacked ? 'brush-stack' : undefined}\n isAnimationActive={false}\n radius={[radius, radius, radius, radius]}\n />\n ))}\n </BarChart>\n </ResponsiveContainer>\n )\n }\n\n return (\n <ResponsiveContainer width=\"100%\" height=\"100%\">\n <AreaChart data={data} margin={{ top: 4, right: 0, bottom: 0, left: 0 }}>\n <defs>{defs}</defs>\n {keys.map((key) => (\n <Area\n key={key}\n type={curveType}\n dataKey={key}\n stroke={`url(#${id}-${key})`}\n fill={`url(#${id}-fill-${key})`}\n strokeWidth={1}\n strokeOpacity={0.5}\n strokeDasharray={dash}\n connectNulls={connectNulls}\n fillOpacity={1}\n stackId={stacked ? 'brush-stack' : undefined}\n dot={false}\n activeDot={false}\n isAnimationActive={false}\n />\n ))}\n </AreaChart>\n </ResponsiveContainer>\n )\n}\n\n/**\n * Holds the brush's range and hands back the rows the chart above should draw.\n *\n * The slicing runs on a deferred copy of the range: the handles move at pointer\n * cadence while the chart re-renders at whatever cadence it can manage, which\n * is what keeps a drag smooth over a few thousand rows.\n */\nexport function useChartBrush<TData extends Record<string, unknown>>({\n data,\n defaultStartIndex = 0,\n defaultEndIndex,\n}: {\n data: TData[]\n defaultStartIndex?: number\n defaultEndIndex?: number\n}) {\n const [range, setRange] = useState<ChartBrushRange>({\n startIndex: defaultStartIndex,\n endIndex: defaultEndIndex ?? Math.max(0, data.length - 1),\n })\n\n const deferred = useDeferredValue(range)\n\n useEffect(() => {\n setRange({ startIndex: 0, endIndex: Math.max(0, data.length - 1) })\n }, [data.length])\n\n const visibleData = useMemo(\n () => data.slice(deferred.startIndex, deferred.endIndex + 1),\n [data, deferred.endIndex, deferred.startIndex],\n )\n\n return {\n range,\n visibleData,\n brushProps: {\n startIndex: range.startIndex,\n endIndex: range.endIndex,\n onChange: setRange,\n },\n }\n}\n"],"mappings":"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","names":["Fragment"]}
|