@misoto22/design 0.3.1 → 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.
Files changed (266) hide show
  1. package/README.md +124 -0
  2. package/bin/misoto22-design.mjs +205 -0
  3. package/dist/agent/Accordion.md +41 -0
  4. package/dist/agent/Alert.md +42 -0
  5. package/dist/agent/AppShell.md +40 -0
  6. package/dist/agent/AreaChart.md +68 -0
  7. package/dist/agent/Article.md +41 -0
  8. package/dist/agent/Avatar.md +32 -0
  9. package/dist/agent/Badge.md +40 -0
  10. package/dist/agent/BarChart.md +65 -0
  11. package/dist/agent/BarList.md +40 -0
  12. package/dist/agent/BigNumber.md +45 -0
  13. package/dist/agent/BoxPlot.md +58 -0
  14. package/dist/agent/Breadcrumb.md +32 -0
  15. package/dist/agent/BulletChart.md +48 -0
  16. package/dist/agent/Button.md +56 -0
  17. package/dist/agent/Calendar.md +42 -0
  18. package/dist/agent/Card.md +49 -0
  19. package/dist/agent/Checkbox.md +35 -0
  20. package/dist/agent/Collapsible.md +46 -0
  21. package/dist/agent/Combobox.md +50 -0
  22. package/dist/agent/Command.md +93 -0
  23. package/dist/agent/ComposedChart.md +57 -0
  24. package/dist/agent/ContextMenu.md +59 -0
  25. package/dist/agent/DatePicker.md +75 -0
  26. package/dist/agent/Diagram.md +46 -0
  27. package/dist/agent/Dialog.md +52 -0
  28. package/dist/agent/DropdownMenu.md +70 -0
  29. package/dist/agent/EmptyState.md +37 -0
  30. package/dist/agent/ErrorState.md +41 -0
  31. package/dist/agent/Facet.md +82 -0
  32. package/dist/agent/Field.md +37 -0
  33. package/dist/agent/FigureBand.md +37 -0
  34. package/dist/agent/FloatingIconButton.md +38 -0
  35. package/dist/agent/FunnelChart.md +52 -0
  36. package/dist/agent/Heatmap.md +53 -0
  37. package/dist/agent/Histogram.md +63 -0
  38. package/dist/agent/Input.md +30 -0
  39. package/dist/agent/Kbd.md +29 -0
  40. package/dist/agent/LineChart.md +60 -0
  41. package/dist/agent/LinkArrow.md +29 -0
  42. package/dist/agent/NativeSelect.md +40 -0
  43. package/dist/agent/NavItem.md +35 -0
  44. package/dist/agent/Pagination.md +43 -0
  45. package/dist/agent/PieChart.md +55 -0
  46. package/dist/agent/Popover.md +57 -0
  47. package/dist/agent/Progress.md +33 -0
  48. package/dist/agent/RadarChart.md +54 -0
  49. package/dist/agent/RadialChart.md +57 -0
  50. package/dist/agent/RadioGroup.md +44 -0
  51. package/dist/agent/SankeyChart.md +61 -0
  52. package/dist/agent/ScatterChart.md +54 -0
  53. package/dist/agent/ScrollArea.md +40 -0
  54. package/dist/agent/SearchableMenu.md +46 -0
  55. package/dist/agent/Select.md +75 -0
  56. package/dist/agent/Separator.md +35 -0
  57. package/dist/agent/Sheet.md +57 -0
  58. package/dist/agent/Skeleton.md +73 -0
  59. package/dist/agent/Slider.md +39 -0
  60. package/dist/agent/Sparkline.md +45 -0
  61. package/dist/agent/Spinner.md +39 -0
  62. package/dist/agent/StatusDot.md +36 -0
  63. package/dist/agent/StatusPill.md +28 -0
  64. package/dist/agent/Steps.md +44 -0
  65. package/dist/agent/Switch.md +29 -0
  66. package/dist/agent/Table.md +85 -0
  67. package/dist/agent/Tabs.md +48 -0
  68. package/dist/agent/Tag.md +35 -0
  69. package/dist/agent/Textarea.md +26 -0
  70. package/dist/agent/Toast.md +26 -0
  71. package/dist/agent/ToggleGroup.md +44 -0
  72. package/dist/agent/Tooltip.md +51 -0
  73. package/dist/agent/TreemapChart.md +52 -0
  74. package/dist/agent/WaterfallChart.md +62 -0
  75. package/dist/agent/catalog.json +1791 -0
  76. package/dist/agent/index.md +131 -0
  77. package/dist/article.css +393 -0
  78. package/dist/charts/AreaChart/AreaChart.d.ts +191 -0
  79. package/dist/charts/AreaChart/AreaChart.js +480 -0
  80. package/dist/charts/AreaChart/AreaChart.js.map +1 -0
  81. package/dist/charts/BarChart/BarChart.d.ts +179 -0
  82. package/dist/charts/BarChart/BarChart.js +591 -0
  83. package/dist/charts/BarChart/BarChart.js.map +1 -0
  84. package/dist/charts/BarList/BarList.d.ts +57 -0
  85. package/dist/charts/BarList/BarList.js +71 -0
  86. package/dist/charts/BarList/BarList.js.map +1 -0
  87. package/dist/charts/BigNumber/BigNumber.d.ts +56 -0
  88. package/dist/charts/BigNumber/BigNumber.js +31 -0
  89. package/dist/charts/BigNumber/BigNumber.js.map +1 -0
  90. package/dist/charts/BoxPlot/BoxPlot.d.ts +177 -0
  91. package/dist/charts/BoxPlot/BoxPlot.js +495 -0
  92. package/dist/charts/BoxPlot/BoxPlot.js.map +1 -0
  93. package/dist/charts/BulletChart/BulletChart.d.ts +100 -0
  94. package/dist/charts/BulletChart/BulletChart.js +162 -0
  95. package/dist/charts/BulletChart/BulletChart.js.map +1 -0
  96. package/dist/charts/ComposedChart/ComposedChart.d.ts +171 -0
  97. package/dist/charts/ComposedChart/ComposedChart.js +667 -0
  98. package/dist/charts/ComposedChart/ComposedChart.js.map +1 -0
  99. package/dist/charts/Facet/Facet.d.ts +240 -0
  100. package/dist/charts/Facet/Facet.js +133 -0
  101. package/dist/charts/Facet/Facet.js.map +1 -0
  102. package/dist/charts/Facet/panels.d.ts +187 -0
  103. package/dist/charts/Facet/panels.js +203 -0
  104. package/dist/charts/Facet/panels.js.map +1 -0
  105. package/dist/charts/FunnelChart/FunnelChart.d.ts +101 -0
  106. package/dist/charts/FunnelChart/FunnelChart.js +147 -0
  107. package/dist/charts/FunnelChart/FunnelChart.js.map +1 -0
  108. package/dist/charts/Heatmap/Heatmap.d.ts +78 -0
  109. package/dist/charts/Heatmap/Heatmap.js +108 -0
  110. package/dist/charts/Heatmap/Heatmap.js.map +1 -0
  111. package/dist/charts/Histogram/Histogram.d.ts +165 -0
  112. package/dist/charts/Histogram/Histogram.js +350 -0
  113. package/dist/charts/Histogram/Histogram.js.map +1 -0
  114. package/dist/charts/LineChart/LineChart.d.ts +167 -0
  115. package/dist/charts/LineChart/LineChart.js +486 -0
  116. package/dist/charts/LineChart/LineChart.js.map +1 -0
  117. package/dist/charts/PieChart/PieChart.d.ts +128 -0
  118. package/dist/charts/PieChart/PieChart.js +309 -0
  119. package/dist/charts/PieChart/PieChart.js.map +1 -0
  120. package/dist/charts/RadarChart/RadarChart.d.ts +123 -0
  121. package/dist/charts/RadarChart/RadarChart.js +299 -0
  122. package/dist/charts/RadarChart/RadarChart.js.map +1 -0
  123. package/dist/charts/RadialChart/RadialChart.d.ts +124 -0
  124. package/dist/charts/RadialChart/RadialChart.js +257 -0
  125. package/dist/charts/RadialChart/RadialChart.js.map +1 -0
  126. package/dist/charts/SankeyChart/SankeyChart.d.ts +137 -0
  127. package/dist/charts/SankeyChart/SankeyChart.js +501 -0
  128. package/dist/charts/SankeyChart/SankeyChart.js.map +1 -0
  129. package/dist/charts/ScatterChart/ScatterChart.d.ts +128 -0
  130. package/dist/charts/ScatterChart/ScatterChart.js +269 -0
  131. package/dist/charts/ScatterChart/ScatterChart.js.map +1 -0
  132. package/dist/charts/Sparkline/Sparkline.d.ts +53 -0
  133. package/dist/charts/Sparkline/Sparkline.js +93 -0
  134. package/dist/charts/Sparkline/Sparkline.js.map +1 -0
  135. package/dist/charts/TreemapChart/TreemapChart.d.ts +93 -0
  136. package/dist/charts/TreemapChart/TreemapChart.js +118 -0
  137. package/dist/charts/TreemapChart/TreemapChart.js.map +1 -0
  138. package/dist/charts/WaterfallChart/WaterfallChart.d.ts +164 -0
  139. package/dist/charts/WaterfallChart/WaterfallChart.js +319 -0
  140. package/dist/charts/WaterfallChart/WaterfallChart.js.map +1 -0
  141. package/dist/charts/index.d.ts +41 -0
  142. package/dist/charts/index.js +128 -0
  143. package/dist/charts/index.js.map +1 -0
  144. package/dist/charts/lib/annotations.d.ts +103 -0
  145. package/dist/charts/lib/annotations.js +99 -0
  146. package/dist/charts/lib/annotations.js.map +1 -0
  147. package/dist/charts/lib/axis.d.ts +18 -0
  148. package/dist/charts/lib/axis.js +21 -0
  149. package/dist/charts/lib/axis.js.map +1 -0
  150. package/dist/charts/lib/background.d.ts +33 -0
  151. package/dist/charts/lib/background.js +173 -0
  152. package/dist/charts/lib/background.js.map +1 -0
  153. package/dist/charts/lib/brush.d.ts +94 -0
  154. package/dist/charts/lib/brush.js +535 -0
  155. package/dist/charts/lib/brush.js.map +1 -0
  156. package/dist/charts/lib/chart.d.ts +94 -0
  157. package/dist/charts/lib/chart.js +134 -0
  158. package/dist/charts/lib/chart.js.map +1 -0
  159. package/dist/charts/lib/dot.d.ts +29 -0
  160. package/dist/charts/lib/dot.js +78 -0
  161. package/dist/charts/lib/dot.js.map +1 -0
  162. package/dist/charts/lib/empty.d.ts +31 -0
  163. package/dist/charts/lib/empty.js +13 -0
  164. package/dist/charts/lib/empty.js.map +1 -0
  165. package/dist/charts/lib/export.d.ts +103 -0
  166. package/dist/charts/lib/export.js +204 -0
  167. package/dist/charts/lib/export.js.map +1 -0
  168. package/dist/charts/lib/figure.d.ts +61 -0
  169. package/dist/charts/lib/figure.js +59 -0
  170. package/dist/charts/lib/figure.js.map +1 -0
  171. package/dist/charts/lib/format.d.ts +46 -0
  172. package/dist/charts/lib/format.js +56 -0
  173. package/dist/charts/lib/format.js.map +1 -0
  174. package/dist/charts/lib/legend.d.ts +45 -0
  175. package/dist/charts/lib/legend.js +117 -0
  176. package/dist/charts/lib/legend.js.map +1 -0
  177. package/dist/charts/lib/loading.d.ts +48 -0
  178. package/dist/charts/lib/loading.js +105 -0
  179. package/dist/charts/lib/loading.js.map +1 -0
  180. package/dist/charts/lib/paint.d.ts +154 -0
  181. package/dist/charts/lib/paint.js +551 -0
  182. package/dist/charts/lib/paint.js.map +1 -0
  183. package/dist/charts/lib/sonify-control.d.ts +163 -0
  184. package/dist/charts/lib/sonify-control.js +172 -0
  185. package/dist/charts/lib/sonify-control.js.map +1 -0
  186. package/dist/charts/lib/sonify.d.ts +248 -0
  187. package/dist/charts/lib/sonify.js +262 -0
  188. package/dist/charts/lib/sonify.js.map +1 -0
  189. package/dist/charts/lib/toolbar.d.ts +143 -0
  190. package/dist/charts/lib/toolbar.js +156 -0
  191. package/dist/charts/lib/toolbar.js.map +1 -0
  192. package/dist/charts/lib/tooltip.d.ts +59 -0
  193. package/dist/charts/lib/tooltip.js +135 -0
  194. package/dist/charts/lib/tooltip.js.map +1 -0
  195. package/dist/charts/lib/values.d.ts +56 -0
  196. package/dist/charts/lib/values.js +71 -0
  197. package/dist/charts/lib/values.js.map +1 -0
  198. package/dist/charts/lib/zoom.d.ts +139 -0
  199. package/dist/charts/lib/zoom.js +314 -0
  200. package/dist/charts/lib/zoom.js.map +1 -0
  201. package/dist/components/AppShell/AppShell.d.ts +15 -1
  202. package/dist/components/AppShell/AppShell.js +8 -4
  203. package/dist/components/AppShell/AppShell.js.map +1 -1
  204. package/dist/components/Article/Article.d.ts +51 -0
  205. package/dist/components/Article/Article.js +21 -0
  206. package/dist/components/Article/Article.js.map +1 -0
  207. package/dist/components/Button/Button.js +2 -2
  208. package/dist/components/Button/Button.js.map +1 -1
  209. package/dist/components/Calendar/Calendar.d.ts +1 -1
  210. package/dist/components/Calendar/Calendar.js +259 -24
  211. package/dist/components/Calendar/Calendar.js.map +1 -1
  212. package/dist/components/Checkbox/Checkbox.js +1 -1
  213. package/dist/components/Checkbox/Checkbox.js.map +1 -1
  214. package/dist/components/Collapsible/Collapsible.d.ts +15 -1
  215. package/dist/components/Collapsible/Collapsible.js +18 -0
  216. package/dist/components/Collapsible/Collapsible.js.map +1 -1
  217. package/dist/components/Combobox/Combobox.js +1 -1
  218. package/dist/components/Combobox/Combobox.js.map +1 -1
  219. package/dist/components/Command/Command.js +7 -7
  220. package/dist/components/Command/Command.js.map +1 -1
  221. package/dist/components/ContextMenu/ContextMenu.js +2 -2
  222. package/dist/components/ContextMenu/ContextMenu.js.map +1 -1
  223. package/dist/components/Diagram/Diagram.d.ts +81 -0
  224. package/dist/components/Diagram/Diagram.js +139 -0
  225. package/dist/components/Diagram/Diagram.js.map +1 -0
  226. package/dist/components/Dialog/Dialog.js +1 -1
  227. package/dist/components/Dialog/Dialog.js.map +1 -1
  228. package/dist/components/DropdownMenu/DropdownMenu.js +2 -2
  229. package/dist/components/DropdownMenu/DropdownMenu.js.map +1 -1
  230. package/dist/components/FigureBand/FigureBand.js +41 -30
  231. package/dist/components/FigureBand/FigureBand.js.map +1 -1
  232. package/dist/components/Popover/Popover.js +1 -1
  233. package/dist/components/Popover/Popover.js.map +1 -1
  234. package/dist/components/Select/Select.js +2 -2
  235. package/dist/components/Select/Select.js.map +1 -1
  236. package/dist/components/Sheet/Sheet.js +1 -1
  237. package/dist/components/Sheet/Sheet.js.map +1 -1
  238. package/dist/components/Slider/Slider.js +1 -1
  239. package/dist/components/Slider/Slider.js.map +1 -1
  240. package/dist/components/Steps/Steps.d.ts +65 -0
  241. package/dist/components/Steps/Steps.js +55 -0
  242. package/dist/components/Steps/Steps.js.map +1 -0
  243. package/dist/components/Switch/Switch.js +1 -1
  244. package/dist/components/Switch/Switch.js.map +1 -1
  245. package/dist/components/Tooltip/Tooltip.js +1 -1
  246. package/dist/components/Tooltip/Tooltip.js.map +1 -1
  247. package/dist/index.d.ts +4 -1
  248. package/dist/index.js +3 -0
  249. package/dist/index.js.map +1 -1
  250. package/dist/lib/useSelectionIndicator.js +14 -10
  251. package/dist/lib/useSelectionIndicator.js.map +1 -1
  252. package/dist/semantic.css +19 -0
  253. package/dist/styles.css +1 -1
  254. package/dist/themes.css +103 -7
  255. package/dist/tokens.css +193 -10
  256. package/dist/tokens.d.ts +25 -0
  257. package/dist/tokens.js +154 -8
  258. package/dist/tokens.json +154 -8
  259. package/package.json +45 -20
  260. package/skills/misoto22-design/SKILL.md +171 -0
  261. package/skills/misoto22-design/evals/claims.json +95 -0
  262. package/skills/misoto22-design/rules/a11y.md +115 -0
  263. package/skills/misoto22-design/rules/composition.md +108 -0
  264. package/skills/misoto22-design/rules/forms.md +128 -0
  265. package/skills/misoto22-design/rules/naming.md +155 -0
  266. package/skills/misoto22-design/rules/tokens.md +131 -0
@@ -0,0 +1,59 @@
1
+ import * as react from 'react';
2
+ import { ComponentProps, CSSProperties } from 'react';
3
+ import { Tooltip, DefaultTooltipContentProps } from 'recharts';
4
+ import { ValueType, NameType } from 'recharts/types/component/DefaultTooltipContent';
5
+
6
+ /**
7
+ * The tooltip's corner, on the system's radius ladder.
8
+ *
9
+ * Three steps, not the four this was ported with: the ladder has four rungs and
10
+ * the fourth is the pill, which is a shape rather than a corner. An `xl` that
11
+ * resolved to "the same as lg, but 4px more" would be a fifth step invented for
12
+ * one component.
13
+ */
14
+ type ChartTooltipRoundness = 'sm' | 'md' | 'lg';
15
+ /** The tooltip's ground: the page's own, or a translucent plate over the plot. */
16
+ type ChartTooltipVariant = 'solid' | 'frosted';
17
+ /** How a series is marked beside its value. */
18
+ type ChartTooltipIndicator = 'dot' | 'line' | 'dashed';
19
+ interface ChartTooltipContentProps extends Omit<DefaultTooltipContentProps<ValueType, NameType>, 'accessibilityLayer' | 'formatter' | 'labelFormatter'>, Pick<ComponentProps<typeof Tooltip>, 'formatter' | 'labelFormatter' | 'active'> {
20
+ className?: string;
21
+ labelClassName?: string;
22
+ /** Drops the row of series marks, leaving only the label. */
23
+ hideIndicator?: boolean;
24
+ /** Drops the heading row — the date, the category. */
25
+ hideLabel?: boolean;
26
+ indicator?: ChartTooltipIndicator;
27
+ /** The row field holding a series name, when it is not the `dataKey`. */
28
+ nameKey?: string;
29
+ /** The row field holding the heading, when it is not the axis value. */
30
+ labelKey?: string;
31
+ /** The chart's selected series, so the tooltip dims the rest with the plot. */
32
+ selected?: string | null;
33
+ roundness?: ChartTooltipRoundness;
34
+ variant?: ChartTooltipVariant;
35
+ }
36
+ /**
37
+ * What the hover tooltip prints: a heading, then one row per series.
38
+ *
39
+ * Values are set in the mono face and `tabular-nums` so a column of numbers
40
+ * lines up as the pointer moves along the axis — without it the row width
41
+ * changes under the cursor and the reader chases it.
42
+ */
43
+ declare function ChartTooltipContent({ active, payload, className, indicator, hideLabel, hideIndicator, label, labelFormatter, labelClassName, formatter, nameKey, labelKey, selected, roundness, variant, }: ChartTooltipContentProps): react.JSX.Element;
44
+ /**
45
+ * The series swatch: one colour, or the same gradient the mark is painted with.
46
+ *
47
+ * A dashed indicator has no fill — it IS its border — so the paint moves to
48
+ * `borderColor`, which cannot take a gradient and takes the first stop instead.
49
+ */
50
+ declare function swatchStyle(key: string, stops: number, dashed?: boolean): CSSProperties;
51
+ /**
52
+ * The Recharts tooltip, with the system's timing.
53
+ *
54
+ * 200ms is short enough that the panel keeps up with a pointer travelling the
55
+ * axis, which is the whole failure mode a slower fade has.
56
+ */
57
+ declare function ChartTooltip({ animationDuration, ...rest }: ComponentProps<typeof Tooltip>): react.JSX.Element;
58
+
59
+ export { ChartTooltip, ChartTooltipContent, type ChartTooltipContentProps, type ChartTooltipIndicator, type ChartTooltipRoundness, type ChartTooltipVariant, swatchStyle };
@@ -0,0 +1,135 @@
1
+ "use client";
2
+ import { Fragment, jsx, jsxs } from "react/jsx-runtime";
3
+ import { useMemo } from "react";
4
+ import { Tooltip as RechartsTooltip } from "recharts";
5
+ import { cn } from "../../lib/cn.js";
6
+ import { colorStops, cssName, seriesFromPayload, useChart } from "./chart.js";
7
+ const ROUNDNESS = {
8
+ sm: "rounded-(--radius-sm)",
9
+ md: "rounded-(--radius)",
10
+ lg: "rounded-(--radius-lg)"
11
+ };
12
+ const VARIANT = {
13
+ solid: "bg-(--chart-surface)",
14
+ // The one place the system reaches for a backdrop filter. It is not a shadow
15
+ // — law 2 bans blurred DEPTH — it is the plot showing through a plate that
16
+ // sits on it, which is why the plate still needs its hairline to read as one.
17
+ frosted: "bg-(--chart-surface)/75 backdrop-blur-sm"
18
+ };
19
+ function ChartTooltipContent({
20
+ active,
21
+ payload,
22
+ className,
23
+ indicator = "dot",
24
+ hideLabel = false,
25
+ hideIndicator = false,
26
+ label,
27
+ labelFormatter,
28
+ labelClassName,
29
+ formatter,
30
+ nameKey,
31
+ labelKey,
32
+ selected,
33
+ roundness = "lg",
34
+ variant = "solid"
35
+ }) {
36
+ const { config } = useChart();
37
+ const heading = useMemo(() => {
38
+ if (hideLabel || !payload?.length) return null;
39
+ const [item] = payload;
40
+ const key = `${labelKey ?? item?.dataKey ?? item?.name ?? "value"}`;
41
+ const series = seriesFromPayload(config, item, key);
42
+ const value = !labelKey && typeof label === "string" ? config[label]?.label ?? label : series?.label;
43
+ if (labelFormatter) {
44
+ return /* @__PURE__ */ jsx("div", { className: cn("font-medium text-(--ink)", labelClassName), children: labelFormatter(value, payload) });
45
+ }
46
+ if (!value) return null;
47
+ return /* @__PURE__ */ jsx("div", { className: cn("font-medium text-(--ink)", labelClassName), children: value });
48
+ }, [config, hideLabel, label, labelClassName, labelFormatter, labelKey, payload]);
49
+ if (!active || !payload?.length) return /* @__PURE__ */ jsx("span", { className: "p-4" });
50
+ const nested = payload.length === 1 && indicator !== "dot";
51
+ return /* @__PURE__ */ jsxs(
52
+ "div",
53
+ {
54
+ className: cn(
55
+ "grid min-w-32 items-start gap-1.5 border border-(--rule-2) px-2.5 py-1.5 text-xs",
56
+ ROUNDNESS[roundness],
57
+ VARIANT[variant],
58
+ className
59
+ ),
60
+ children: [
61
+ !nested ? heading : null,
62
+ /* @__PURE__ */ jsx("div", { className: "grid gap-1.5", children: payload.filter((item) => item.type !== "none").map((item, index) => {
63
+ const named = nameKey && item.payload ? item.payload[nameKey] : void 0;
64
+ const key = `${named ?? item.name ?? item.dataKey ?? "value"}`;
65
+ const series = seriesFromPayload(config, item, key);
66
+ const stops = colorStops(series);
67
+ return /* @__PURE__ */ jsx(
68
+ "div",
69
+ {
70
+ className: cn(
71
+ "flex w-full flex-wrap items-stretch gap-2 [&>svg]:size-2.5 [&>svg]:text-(--ink-3-aa)",
72
+ indicator === "dot" && "items-center",
73
+ selected != null && selected !== item.dataKey && "opacity-30"
74
+ ),
75
+ children: formatter && item?.value !== void 0 && item.name ? formatter(item.value, item.name, item, index, payload) : /* @__PURE__ */ jsxs(Fragment, { children: [
76
+ series?.icon ? /* @__PURE__ */ jsx(series.icon, {}) : !hideIndicator && /* @__PURE__ */ jsx(
77
+ "span",
78
+ {
79
+ "aria-hidden": true,
80
+ className: cn("shrink-0 rounded-[2px]", {
81
+ "size-2.5": indicator === "dot",
82
+ "w-1": indicator === "line",
83
+ "w-0 border-[1.5px] border-dashed bg-transparent!": indicator === "dashed",
84
+ "my-0.5": nested && indicator === "dashed"
85
+ }),
86
+ style: swatchStyle(key, stops, indicator === "dashed")
87
+ }
88
+ ),
89
+ /* @__PURE__ */ jsxs(
90
+ "div",
91
+ {
92
+ className: cn(
93
+ "flex flex-1 justify-between gap-4 leading-none",
94
+ nested ? "items-end" : "items-center"
95
+ ),
96
+ children: [
97
+ /* @__PURE__ */ jsxs("div", { className: "grid gap-1.5", children: [
98
+ nested ? heading : null,
99
+ /* @__PURE__ */ jsx("span", { className: "text-(--ink-3-aa)", children: series?.label ?? item.name })
100
+ ] }),
101
+ item.value != null && /* @__PURE__ */ jsx("span", { className: "font-mono font-medium tabular-nums text-(--ink)", children: typeof item.value === "number" ? item.value.toLocaleString() : String(item.value) })
102
+ ]
103
+ }
104
+ )
105
+ ] })
106
+ },
107
+ index
108
+ );
109
+ }) })
110
+ ]
111
+ }
112
+ );
113
+ }
114
+ function swatchStyle(key, stops, dashed = false) {
115
+ const name = cssName(key);
116
+ if (dashed) return { borderColor: `var(--color-${name}-0)` };
117
+ if (stops <= 1) return { background: `var(--color-${name}-0)` };
118
+ const gradient = Array.from({ length: stops }, (_, index) => {
119
+ const offset = index / (stops - 1) * 100;
120
+ return `var(--color-${name}-${index}) ${offset}%`;
121
+ }).join(", ");
122
+ return { background: `linear-gradient(to right, ${gradient})` };
123
+ }
124
+ function ChartTooltip({
125
+ animationDuration = 200,
126
+ ...rest
127
+ }) {
128
+ return /* @__PURE__ */ jsx(RechartsTooltip, { animationDuration, ...rest });
129
+ }
130
+ export {
131
+ ChartTooltip,
132
+ ChartTooltipContent,
133
+ swatchStyle
134
+ };
135
+ //# sourceMappingURL=tooltip.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../../src/charts/lib/tooltip.tsx"],"sourcesContent":["'use client'\n\nimport { useMemo, type ComponentProps, type CSSProperties } from 'react'\nimport { Tooltip as RechartsTooltip } from 'recharts'\nimport type { NameType, ValueType } from 'recharts/types/component/DefaultTooltipContent'\nimport type { DefaultTooltipContentProps } from 'recharts'\nimport { cn } from '../../lib/cn'\nimport { colorStops, cssName, seriesFromPayload, useChart } from './chart'\n\n/**\n * The tooltip's corner, on the system's radius ladder.\n *\n * Three steps, not the four this was ported with: the ladder has four rungs and\n * the fourth is the pill, which is a shape rather than a corner. An `xl` that\n * resolved to \"the same as lg, but 4px more\" would be a fifth step invented for\n * one component.\n */\nexport type ChartTooltipRoundness = 'sm' | 'md' | 'lg'\n\n/** The tooltip's ground: the page's own, or a translucent plate over the plot. */\nexport type ChartTooltipVariant = 'solid' | 'frosted'\n\n/** How a series is marked beside its value. */\nexport type ChartTooltipIndicator = 'dot' | 'line' | 'dashed'\n\nconst ROUNDNESS: Record<ChartTooltipRoundness, string> = {\n sm: 'rounded-(--radius-sm)',\n md: 'rounded-(--radius)',\n lg: 'rounded-(--radius-lg)',\n}\n\nconst VARIANT: Record<ChartTooltipVariant, string> = {\n solid: 'bg-(--chart-surface)',\n // The one place the system reaches for a backdrop filter. It is not a shadow\n // — law 2 bans blurred DEPTH — it is the plot showing through a plate that\n // sits on it, which is why the plate still needs its hairline to read as one.\n frosted: 'bg-(--chart-surface)/75 backdrop-blur-sm',\n}\n\nexport interface ChartTooltipContentProps\n extends Omit<\n DefaultTooltipContentProps<ValueType, NameType>,\n 'accessibilityLayer' | 'formatter' | 'labelFormatter'\n >,\n Pick<ComponentProps<typeof RechartsTooltip>, 'formatter' | 'labelFormatter' | 'active'> {\n className?: string\n labelClassName?: string\n /** Drops the row of series marks, leaving only the label. */\n hideIndicator?: boolean\n /** Drops the heading row — the date, the category. */\n hideLabel?: boolean\n indicator?: ChartTooltipIndicator\n /** The row field holding a series name, when it is not the `dataKey`. */\n nameKey?: string\n /** The row field holding the heading, when it is not the axis value. */\n labelKey?: string\n /** The chart's selected series, so the tooltip dims the rest with the plot. */\n selected?: string | null\n roundness?: ChartTooltipRoundness\n variant?: ChartTooltipVariant\n}\n\n/**\n * What the hover tooltip prints: a heading, then one row per series.\n *\n * Values are set in the mono face and `tabular-nums` so a column of numbers\n * lines up as the pointer moves along the axis — without it the row width\n * changes under the cursor and the reader chases it.\n */\nexport function ChartTooltipContent({\n active,\n payload,\n className,\n indicator = 'dot',\n hideLabel = false,\n hideIndicator = false,\n label,\n labelFormatter,\n labelClassName,\n formatter,\n nameKey,\n labelKey,\n selected,\n roundness = 'lg',\n variant = 'solid',\n}: ChartTooltipContentProps) {\n const { config } = useChart()\n\n const heading = useMemo(() => {\n if (hideLabel || !payload?.length) return null\n\n const [item] = payload\n const key = `${labelKey ?? item?.dataKey ?? item?.name ?? 'value'}`\n const series = seriesFromPayload(config, item, key)\n const value =\n !labelKey && typeof label === 'string' ? (config[label]?.label ?? label) : series?.label\n\n if (labelFormatter) {\n return (\n <div className={cn('font-medium text-(--ink)', labelClassName)}>\n {labelFormatter(value, payload)}\n </div>\n )\n }\n if (!value) return null\n return <div className={cn('font-medium text-(--ink)', labelClassName)}>{value}</div>\n }, [config, hideLabel, label, labelClassName, labelFormatter, labelKey, payload])\n\n // An empty span rather than null: returning nothing lets Recharts reset the\n // tooltip's position to the origin, so the next hover animates in from the\n // top-left corner of the chart instead of from where the pointer is.\n if (!active || !payload?.length) return <span className=\"p-4\" />\n\n const nested = payload.length === 1 && indicator !== 'dot'\n\n return (\n <div\n className={cn(\n 'grid min-w-32 items-start gap-1.5 border border-(--rule-2) px-2.5 py-1.5 text-xs',\n ROUNDNESS[roundness],\n VARIANT[variant],\n className,\n )}\n >\n {!nested ? heading : null}\n <div className=\"grid gap-1.5\">\n {payload\n .filter((item) => item.type !== 'none')\n .map((item, index) => {\n const named =\n nameKey && item.payload\n ? (item.payload as Record<string, unknown>)[nameKey]\n : undefined\n const key = `${named ?? item.name ?? item.dataKey ?? 'value'}`\n const series = seriesFromPayload(config, item, key)\n const stops = colorStops(series)\n\n return (\n <div\n key={index}\n className={cn(\n 'flex w-full flex-wrap items-stretch gap-2 [&>svg]:size-2.5 [&>svg]:text-(--ink-3-aa)',\n indicator === 'dot' && 'items-center',\n selected != null && selected !== item.dataKey && 'opacity-30',\n )}\n >\n {formatter && item?.value !== undefined && item.name ? (\n formatter(item.value, item.name, item, index, payload)\n ) : (\n <>\n {series?.icon ? (\n <series.icon />\n ) : (\n !hideIndicator && (\n <span\n aria-hidden\n className={cn('shrink-0 rounded-[2px]', {\n 'size-2.5': indicator === 'dot',\n 'w-1': indicator === 'line',\n 'w-0 border-[1.5px] border-dashed bg-transparent!':\n indicator === 'dashed',\n 'my-0.5': nested && indicator === 'dashed',\n })}\n style={swatchStyle(key, stops, indicator === 'dashed')}\n />\n )\n )}\n <div\n className={cn(\n 'flex flex-1 justify-between gap-4 leading-none',\n nested ? 'items-end' : 'items-center',\n )}\n >\n <div className=\"grid gap-1.5\">\n {nested ? heading : null}\n <span className=\"text-(--ink-3-aa)\">{series?.label ?? item.name}</span>\n </div>\n {item.value != null && (\n <span className=\"font-mono font-medium tabular-nums text-(--ink)\">\n {typeof item.value === 'number'\n ? item.value.toLocaleString()\n : String(item.value)}\n </span>\n )}\n </div>\n </>\n )}\n </div>\n )\n })}\n </div>\n </div>\n )\n}\n\n/**\n * The series swatch: one colour, or the same gradient the mark is painted with.\n *\n * A dashed indicator has no fill — it IS its border — so the paint moves to\n * `borderColor`, which cannot take a gradient and takes the first stop instead.\n */\nexport function swatchStyle(key: string, stops: number, dashed = false): CSSProperties {\n const name = cssName(key)\n if (dashed) return { borderColor: `var(--color-${name}-0)` }\n if (stops <= 1) return { background: `var(--color-${name}-0)` }\n\n const gradient = Array.from({ length: stops }, (_, index) => {\n const offset = (index / (stops - 1)) * 100\n return `var(--color-${name}-${index}) ${offset}%`\n }).join(', ')\n\n // `to right` rather than a logical direction: the swatch mirrors the mark's\n // own gradient, and the mark is painted in SVG user space, which does not\n // flip with the document.\n return { background: `linear-gradient(to right, ${gradient})` }\n}\n\n/**\n * The Recharts tooltip, with the system's timing.\n *\n * 200ms is short enough that the panel keeps up with a pointer travelling the\n * axis, which is the whole failure mode a slower fade has.\n */\nexport function ChartTooltip({\n animationDuration = 200,\n ...rest\n}: ComponentProps<typeof RechartsTooltip>) {\n return <RechartsTooltip animationDuration={animationDuration} {...rest} />\n}\n"],"mappings":"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","names":[]}
@@ -0,0 +1,56 @@
1
+ import * as react from 'react';
2
+ import { FC, ReactNode } from 'react';
3
+
4
+ /**
5
+ * The props of the first child of a given type, or null.
6
+ *
7
+ * Every configuration slot in the package is read this way — a component that
8
+ * renders nothing, whose PROPS are the configuration. It reads better at the
9
+ * call site than a prop bag (`<Chart.Values show="last" />` beside the mark it
10
+ * labels, rather than `valuesShow="last"` on the mark) and it keeps the marks'
11
+ * prop lists from growing a section per optional decoration.
12
+ */
13
+ declare function findSlot<TProps>(children: ReactNode, type: unknown): TProps | null;
14
+ /**
15
+ * Which points get their number printed.
16
+ *
17
+ * The default is `last`, and the default matters more here than usual: a
18
+ * number on every point is the most common way a chart is spoiled, because the
19
+ * labels then compete with the shape they are annotating and the reader loses
20
+ * both. What a reader almost always wants is the number they would otherwise
21
+ * have to trace back to the axis for — the latest value, or the two ends.
22
+ *
23
+ * `all` exists for the case it is right for: five or six bars, no line, and the
24
+ * exact figures ARE the point. Past that it is a table wearing a chart.
25
+ */
26
+ type ValueLabelMode = 'all' | 'first' | 'last' | 'first-last' | 'extremes';
27
+ interface ValuesProps {
28
+ /** Which points are labelled. */
29
+ show?: ValueLabelMode;
30
+ /** Formats each number. Defaults to the axis's own compact formatting. */
31
+ formatValue?: (value: number) => string;
32
+ /** Where the label sits relative to its point. */
33
+ position?: 'top' | 'bottom' | 'inside' | 'right';
34
+ }
35
+ /**
36
+ * Prints the numbers on a series.
37
+ *
38
+ * A slot: it renders nothing itself, and the mark it is composed inside reads
39
+ * its props.
40
+ *
41
+ * @example
42
+ * <BarChart.Bar dataKey="visitors">
43
+ * <BarChart.Values show="all" />
44
+ * </BarChart.Bar>
45
+ */
46
+ declare const Values: FC<ValuesProps>;
47
+ /**
48
+ * Turns a composed `<Values>` slot into a Recharts label list.
49
+ *
50
+ * `values` is the whole series, needed because `extremes` cannot be decided
51
+ * one point at a time — and Recharts hands a label renderer one point at a
52
+ * time.
53
+ */
54
+ declare function resolveValues(slot: ValuesProps | null, values: number[], fallbackPosition?: ValuesProps['position']): react.JSX.Element | null;
55
+
56
+ export { type ValueLabelMode, Values, type ValuesProps, findSlot, resolveValues };
@@ -0,0 +1,71 @@
1
+ "use client";
2
+ import { jsx } from "react/jsx-runtime";
3
+ import { Children, isValidElement } from "react";
4
+ import { LabelList } from "recharts";
5
+ import { defaultTick } from "./format.js";
6
+ function findSlot(children, type) {
7
+ let found = null;
8
+ Children.forEach(children, (child) => {
9
+ if (isValidElement(child) && child.type === type) {
10
+ found = child.props;
11
+ }
12
+ });
13
+ return found;
14
+ }
15
+ const Values = () => null;
16
+ function shows(mode, index, count, value, values) {
17
+ switch (mode) {
18
+ case "all":
19
+ return true;
20
+ case "first":
21
+ return index === 0;
22
+ case "first-last":
23
+ return index === 0 || index === count - 1;
24
+ case "extremes": {
25
+ const min = Math.min(...values);
26
+ const max = Math.max(...values);
27
+ return value === min || value === max;
28
+ }
29
+ default:
30
+ return index === count - 1;
31
+ }
32
+ }
33
+ function resolveValues(slot, values, fallbackPosition = "top") {
34
+ if (!slot) return null;
35
+ const mode = slot.show ?? "last";
36
+ const format = slot.formatValue ?? defaultTick;
37
+ const count = values.length;
38
+ return /* @__PURE__ */ jsx(
39
+ LabelList,
40
+ {
41
+ position: slot.position ?? fallbackPosition,
42
+ offset: 8,
43
+ content: (raw) => {
44
+ const props = raw;
45
+ const index = props.index ?? -1;
46
+ const value = Number(props.value);
47
+ if (index < 0 || !Number.isFinite(value)) return null;
48
+ if (!shows(mode, index, count, value, values)) return null;
49
+ const x = Number(props.x ?? 0) + Number(props.width ?? 0) / 2;
50
+ const y = Number(props.y ?? 0) - 6;
51
+ return /* @__PURE__ */ jsx(
52
+ "text",
53
+ {
54
+ x,
55
+ y,
56
+ textAnchor: "middle",
57
+ className: "fill-(--ink) font-mono text-[11px] font-medium tabular-nums",
58
+ style: { pointerEvents: "none" },
59
+ children: format(value)
60
+ }
61
+ );
62
+ }
63
+ }
64
+ );
65
+ }
66
+ export {
67
+ Values,
68
+ findSlot,
69
+ resolveValues
70
+ };
71
+ //# sourceMappingURL=values.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../../src/charts/lib/values.tsx"],"sourcesContent":["'use client'\n\nimport { Children, isValidElement, type FC, type ReactElement, type ReactNode } from 'react'\nimport { LabelList } from 'recharts'\nimport { defaultTick } from './format'\n\n/**\n * The props of the first child of a given type, or null.\n *\n * Every configuration slot in the package is read this way — a component that\n * renders nothing, whose PROPS are the configuration. It reads better at the\n * call site than a prop bag (`<Chart.Values show=\"last\" />` beside the mark it\n * labels, rather than `valuesShow=\"last\"` on the mark) and it keeps the marks'\n * prop lists from growing a section per optional decoration.\n */\nexport function findSlot<TProps>(children: ReactNode, type: unknown): TProps | null {\n let found: TProps | null = null\n Children.forEach(children, (child) => {\n if (isValidElement(child) && child.type === type) {\n found = (child as ReactElement<TProps>).props\n }\n })\n return found\n}\n\n/**\n * Which points get their number printed.\n *\n * The default is `last`, and the default matters more here than usual: a\n * number on every point is the most common way a chart is spoiled, because the\n * labels then compete with the shape they are annotating and the reader loses\n * both. What a reader almost always wants is the number they would otherwise\n * have to trace back to the axis for — the latest value, or the two ends.\n *\n * `all` exists for the case it is right for: five or six bars, no line, and the\n * exact figures ARE the point. Past that it is a table wearing a chart.\n */\nexport type ValueLabelMode = 'all' | 'first' | 'last' | 'first-last' | 'extremes'\n\nexport interface ValuesProps {\n /** Which points are labelled. */\n show?: ValueLabelMode\n /** Formats each number. Defaults to the axis's own compact formatting. */\n formatValue?: (value: number) => string\n /** Where the label sits relative to its point. */\n position?: 'top' | 'bottom' | 'inside' | 'right'\n}\n\n/**\n * Prints the numbers on a series.\n *\n * A slot: it renders nothing itself, and the mark it is composed inside reads\n * its props.\n *\n * @example\n * <BarChart.Bar dataKey=\"visitors\">\n * <BarChart.Values show=\"all\" />\n * </BarChart.Bar>\n */\nexport const Values: FC<ValuesProps> = () => null\n\n/** Whether the point at `index` is one of the labelled ones. */\nfunction shows(mode: ValueLabelMode, index: number, count: number, value: number, values: number[]): boolean {\n switch (mode) {\n case 'all':\n return true\n case 'first':\n return index === 0\n case 'first-last':\n return index === 0 || index === count - 1\n case 'extremes': {\n // The min and the max, which is what \"which was the worst month\" asks\n // for and what an axis cannot answer without counting gridlines.\n const min = Math.min(...values)\n const max = Math.max(...values)\n return value === min || value === max\n }\n default:\n return index === count - 1\n }\n}\n\n/**\n * Turns a composed `<Values>` slot into a Recharts label list.\n *\n * `values` is the whole series, needed because `extremes` cannot be decided\n * one point at a time — and Recharts hands a label renderer one point at a\n * time.\n */\nexport function resolveValues(\n slot: ValuesProps | null,\n values: number[],\n fallbackPosition: ValuesProps['position'] = 'top',\n) {\n if (!slot) return null\n\n const mode = slot.show ?? 'last'\n const format = slot.formatValue ?? defaultTick\n const count = values.length\n\n return (\n <LabelList\n position={slot.position ?? fallbackPosition}\n offset={8}\n content={(raw) => {\n // Recharts types x/y/width as `string | number`, because a label can be\n // positioned in percentages. Everything that reaches this renderer is\n // resolved geometry, so the coercion is the honest read.\n const props = raw as {\n index?: number\n value?: unknown\n x?: string | number\n y?: string | number\n width?: string | number\n }\n const index = props.index ?? -1\n const value = Number(props.value)\n if (index < 0 || !Number.isFinite(value)) return null\n if (!shows(mode, index, count, value, values)) return null\n\n const x = Number(props.x ?? 0) + Number(props.width ?? 0) / 2\n const y = Number(props.y ?? 0) - 6\n\n return (\n <text\n x={x}\n y={y}\n textAnchor=\"middle\"\n // Mono and tabular, like every other number in the system: a column\n // of labels that jitters as the digits change reads as noise.\n className=\"fill-(--ink) font-mono text-[11px] font-medium tabular-nums\"\n style={{ pointerEvents: 'none' }}\n >\n {format(value)}\n </text>\n )\n }}\n />\n )\n}\n"],"mappings":";AA4HU;AA1HV,SAAS,UAAU,sBAAkE;AACrF,SAAS,iBAAiB;AAC1B,SAAS,mBAAmB;AAWrB,SAAS,SAAiB,UAAqB,MAA8B;AAClF,MAAI,QAAuB;AAC3B,WAAS,QAAQ,UAAU,CAAC,UAAU;AACpC,QAAI,eAAe,KAAK,KAAK,MAAM,SAAS,MAAM;AAChD,cAAS,MAA+B;AAAA,IAC1C;AAAA,EACF,CAAC;AACD,SAAO;AACT;AAoCO,MAAM,SAA0B,MAAM;AAG7C,SAAS,MAAM,MAAsB,OAAe,OAAe,OAAe,QAA2B;AAC3G,UAAQ,MAAM;AAAA,IACZ,KAAK;AACH,aAAO;AAAA,IACT,KAAK;AACH,aAAO,UAAU;AAAA,IACnB,KAAK;AACH,aAAO,UAAU,KAAK,UAAU,QAAQ;AAAA,IAC1C,KAAK,YAAY;AAGf,YAAM,MAAM,KAAK,IAAI,GAAG,MAAM;AAC9B,YAAM,MAAM,KAAK,IAAI,GAAG,MAAM;AAC9B,aAAO,UAAU,OAAO,UAAU;AAAA,IACpC;AAAA,IACA;AACE,aAAO,UAAU,QAAQ;AAAA,EAC7B;AACF;AASO,SAAS,cACd,MACA,QACA,mBAA4C,OAC5C;AACA,MAAI,CAAC,KAAM,QAAO;AAElB,QAAM,OAAO,KAAK,QAAQ;AAC1B,QAAM,SAAS,KAAK,eAAe;AACnC,QAAM,QAAQ,OAAO;AAErB,SACE;AAAA,IAAC;AAAA;AAAA,MACC,UAAU,KAAK,YAAY;AAAA,MAC3B,QAAQ;AAAA,MACR,SAAS,CAAC,QAAQ;AAIhB,cAAM,QAAQ;AAOd,cAAM,QAAQ,MAAM,SAAS;AAC7B,cAAM,QAAQ,OAAO,MAAM,KAAK;AAChC,YAAI,QAAQ,KAAK,CAAC,OAAO,SAAS,KAAK,EAAG,QAAO;AACjD,YAAI,CAAC,MAAM,MAAM,OAAO,OAAO,OAAO,MAAM,EAAG,QAAO;AAEtD,cAAM,IAAI,OAAO,MAAM,KAAK,CAAC,IAAI,OAAO,MAAM,SAAS,CAAC,IAAI;AAC5D,cAAM,IAAI,OAAO,MAAM,KAAK,CAAC,IAAI;AAEjC,eACE;AAAA,UAAC;AAAA;AAAA,YACC;AAAA,YACA;AAAA,YACA,YAAW;AAAA,YAGX,WAAU;AAAA,YACV,OAAO,EAAE,eAAe,OAAO;AAAA,YAE9B,iBAAO,KAAK;AAAA;AAAA,QACf;AAAA,MAEJ;AAAA;AAAA,EACF;AAEJ;","names":[]}
@@ -0,0 +1,139 @@
1
+ import * as react from 'react';
2
+ import { RefObject, ReactNode } from 'react';
3
+ import { ChartBrushRange } from './brush.js';
4
+ import 'recharts';
5
+ import './chart.js';
6
+
7
+ /**
8
+ * A range pulled back inside the data, with the minimum span enforced.
9
+ *
10
+ * Every other function here ends by calling this, so an inverted range, an
11
+ * index past the end and a window narrower than `minSpan` all have exactly one
12
+ * definition of what they become.
13
+ */
14
+ declare function clampWindow(range: ChartBrushRange, total: number, minSpan?: number): ChartBrushRange;
15
+ /**
16
+ * The window after one zoom step.
17
+ *
18
+ * `factor` below 1 closes the window and above 1 opens it. `anchor` is the row
19
+ * index that must stay where it is on screen — the pointer's row for a wheel
20
+ * zoom, the window's own centre for a button — because a zoom that re-centres
21
+ * is a zoom that loses the point the reader was looking at.
22
+ *
23
+ * The span is floored when closing and ceiled when opening rather than rounded
24
+ * in both directions, so a step always moves: rounding leaves a three-row
25
+ * window stuck at three when the step is a half.
26
+ */
27
+ declare function zoomWindow(range: ChartBrushRange, total: number, factor: number, minSpan?: number, anchor?: number): ChartBrushRange;
28
+ /**
29
+ * The window slid along by `delta` rows, keeping its span.
30
+ *
31
+ * At either end it stops rather than shrinking. A pan that narrowed itself
32
+ * against the edge would change the scale under the reader, which is a
33
+ * different gesture from the one they made.
34
+ */
35
+ declare function panWindow(range: ChartBrushRange, total: number, delta: number): ChartBrushRange;
36
+ interface ChartZoomOptions<TData extends Record<string, unknown>> {
37
+ /** The whole dataset. The window is expressed as indexes into it. */
38
+ data: TData[];
39
+ /** The row field behind a row's name, used by the spoken window description. */
40
+ xDataKey?: keyof TData & string;
41
+ /** The fewest rows a zoom will leave on screen. */
42
+ minSpan?: number;
43
+ /** The fraction of the window one zoom step keeps. */
44
+ step?: number;
45
+ /** Fires whenever the window changes, from any of the four inputs. */
46
+ onZoomChange?: (range: ChartBrushRange) => void;
47
+ }
48
+ interface ChartZoom<TData extends Record<string, unknown> = Record<string, unknown>> {
49
+ /** The rows on screen, as indexes into the whole dataset. */
50
+ range: ChartBrushRange;
51
+ /** The rows the plot should draw. */
52
+ visibleData: TData[];
53
+ /** Whether anything is hidden — what "reset zoom" is enabled by. */
54
+ isZoomed: boolean;
55
+ canZoomIn: boolean;
56
+ canZoomOut: boolean;
57
+ /** Closes the window one step around `anchor`, or around its own centre. */
58
+ zoomIn: (anchor?: number) => void;
59
+ /** Opens the window one step around `anchor`, or around its own centre. */
60
+ zoomOut: (anchor?: number) => void;
61
+ /** Back to the whole dataset. */
62
+ reset: () => void;
63
+ /** Slides the window by a number of rows, keeping its span. */
64
+ panBy: (delta: number) => void;
65
+ /** Jumps straight to a window — what a drag across the plot commits. */
66
+ zoomTo: (range: ChartBrushRange) => void;
67
+ /** How many rows there are in total. */
68
+ total: number;
69
+ /** A row's name, for an announcement or a label. */
70
+ labelAt: (index: number) => string;
71
+ /** Spread onto `<ChartBrush>` to make it a controlled view of this window. */
72
+ brushProps: {
73
+ startIndex: number;
74
+ endIndex: number;
75
+ onChange: (range: ChartBrushRange) => void;
76
+ };
77
+ }
78
+ /**
79
+ * A windowed view of a chart's rows, driven by the toolbar, the wheel, a drag
80
+ * across the plot, and the keyboard.
81
+ *
82
+ * ## How this composes with `<Chart.Brush>`
83
+ *
84
+ * They are two views of ONE window, not two windows. This hook owns
85
+ * `{ startIndex, endIndex }`; the brush is rendered controlled from it through
86
+ * `brushProps` and reports back through the same commit path the toolbar
87
+ * buttons use. So dragging a brush handle moves the toolbar's idea of the
88
+ * window, "reset zoom" snaps the handles back to the full range, and neither
89
+ * part has to know the other exists.
90
+ *
91
+ * The alternative — a zoom window layered on top of a brushed slice — was
92
+ * rejected because it needs a composition rule ("zoom is relative to the
93
+ * brush") that nobody can predict from the call site, and because it makes
94
+ * reset ambiguous: reset the zoom, the brush, or both.
95
+ *
96
+ * This is a superset of `useChartBrush`, so a chart that can carry a toolbar
97
+ * uses it in place of that hook rather than running the two side by side.
98
+ *
99
+ * @example
100
+ * const zoom = useChartZoom({ data, xDataKey: 'month' })
101
+ * <ChartBrush data={data} config={config} {...zoom.brushProps} />
102
+ */
103
+ declare function useChartZoom<TData extends Record<string, unknown>>({ data, xDataKey, minSpan, step, onZoomChange, }: ChartZoomOptions<TData>): ChartZoom<TData>;
104
+ interface ChartZoomSurfaceProps {
105
+ /** The window this surface drives. */
106
+ zoom: ChartZoom;
107
+ /** Names the region for a screen reader — pass the figure's title. */
108
+ label: string;
109
+ /**
110
+ * Off leaves the plot inert while the toolbar buttons keep working. Use it
111
+ * for a chart whose only control is export.
112
+ */
113
+ enabled?: boolean;
114
+ /** The plot's box, handed out because the PNG export needs the measured one. */
115
+ ref?: RefObject<HTMLDivElement | null>;
116
+ children: ReactNode;
117
+ }
118
+ /**
119
+ * The plot, made zoomable and pannable by pointer AND by keyboard.
120
+ *
121
+ * The keyboard half is not a nicety. A chart whose only zoom is a drag gesture
122
+ * is a chart a keyboard user can watch and cannot operate, which is the exact
123
+ * failure the brush was rewritten to fix — so the surface is focusable, carries
124
+ * its instructions in an `aria-describedby` note, and announces the window it
125
+ * moved to through a polite live region.
126
+ *
127
+ * Arrow keys pan by a row, `PageUp`/`PageDown` by a screenful, `Home`/`End`
128
+ * jump to the ends, `+`/`-` zoom and `0` resets. `ArrowLeft` means EARLIER in
129
+ * every writing direction, matching the brush: the rendering engine lays a
130
+ * cartesian plot out left-to-right whatever `dir` says, so mirroring the keys
131
+ * would put "earlier" on the side the data does not run to.
132
+ *
133
+ * The wheel is deliberately gated behind Ctrl or Cmd. A chart that swallowed a
134
+ * plain wheel event traps the page's scroll under the pointer, which is the
135
+ * single most complained-about behaviour in an embedded map.
136
+ */
137
+ declare function ChartZoomSurface({ zoom, label, enabled, ref, children, }: ChartZoomSurfaceProps): react.JSX.Element;
138
+
139
+ export { type ChartZoom, type ChartZoomOptions, ChartZoomSurface, type ChartZoomSurfaceProps, clampWindow, panWindow, useChartZoom, zoomWindow };