basalt-ui 1.30.2 → 1.31.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 (334) hide show
  1. package/AGENTS.md +1 -1
  2. package/CHANGELOG.md +31 -0
  3. package/MIGRATING.md +172 -12
  4. package/agent/rules/basalt-controls.md +19 -19
  5. package/agent/rules/basalt-mantine.md +1 -1
  6. package/configs/oxlint-plugin.js +254 -4
  7. package/configs/oxlint-plugin.test.ts +145 -2
  8. package/configs/oxlint.json +2 -1
  9. package/dist/agent-chat/composer.d.ts.map +1 -1
  10. package/dist/agent-chat/composer.js +41 -43
  11. package/dist/agent-chat/thread-workspace.d.ts +2 -2
  12. package/dist/agent-chat/thread-workspace.d.ts.map +1 -1
  13. package/dist/agent-chat/thread-workspace.js +3 -4
  14. package/dist/agent-chat/use-keyboard-inset.d.ts +2 -0
  15. package/dist/agent-chat/use-keyboard-inset.d.ts.map +1 -0
  16. package/dist/agent-chat/use-keyboard-inset.js +34 -0
  17. package/dist/charts/cursor/touch-pin.d.ts +45 -0
  18. package/dist/charts/cursor/touch-pin.d.ts.map +1 -0
  19. package/dist/charts/cursor/touch-pin.js +79 -0
  20. package/dist/charts/hooks/use-discrete-cursor.d.ts +66 -0
  21. package/dist/charts/hooks/use-discrete-cursor.d.ts.map +1 -0
  22. package/dist/charts/hooks/use-discrete-cursor.js +198 -0
  23. package/dist/charts/hooks/use-hysteresis.d.ts +18 -0
  24. package/dist/charts/hooks/use-hysteresis.d.ts.map +1 -0
  25. package/dist/charts/hooks/use-hysteresis.js +12 -0
  26. package/dist/charts/hooks/useBandPlot.d.ts +7 -0
  27. package/dist/charts/hooks/useBandPlot.d.ts.map +1 -1
  28. package/dist/charts/hooks/useBandPlot.js +62 -18
  29. package/dist/charts/hooks/useChartCursor.d.ts +40 -11
  30. package/dist/charts/hooks/useChartCursor.d.ts.map +1 -1
  31. package/dist/charts/hooks/useChartCursor.js +102 -11
  32. package/dist/charts/index.d.ts +0 -1
  33. package/dist/charts/index.d.ts.map +1 -1
  34. package/dist/charts/index.js +0 -10
  35. package/dist/charts/kinds/BandStrip.d.ts.map +1 -1
  36. package/dist/charts/kinds/BandStrip.js +54 -41
  37. package/dist/charts/kinds/Donut.d.ts +9 -3
  38. package/dist/charts/kinds/Donut.d.ts.map +1 -1
  39. package/dist/charts/kinds/Donut.js +110 -48
  40. package/dist/charts/kinds/DualPanel.d.ts.map +1 -1
  41. package/dist/charts/kinds/DualPanel.js +145 -131
  42. package/dist/charts/kinds/Heatmap.d.ts +7 -0
  43. package/dist/charts/kinds/Heatmap.d.ts.map +1 -1
  44. package/dist/charts/kinds/Heatmap.js +37 -16
  45. package/dist/charts/kinds/MirroredBars.d.ts.map +1 -1
  46. package/dist/charts/kinds/MirroredBars.js +83 -68
  47. package/dist/charts/kinds/donut-layout.d.ts +47 -0
  48. package/dist/charts/kinds/donut-layout.d.ts.map +1 -0
  49. package/dist/charts/kinds/donut-layout.js +52 -0
  50. package/dist/charts/layout/auto-margin.d.ts +7 -2
  51. package/dist/charts/layout/auto-margin.d.ts.map +1 -1
  52. package/dist/charts/layout/auto-margin.js +12 -3
  53. package/dist/charts/layout/end-labels.d.ts +64 -0
  54. package/dist/charts/layout/end-labels.d.ts.map +1 -0
  55. package/dist/charts/layout/end-labels.js +76 -0
  56. package/dist/charts/primitives/Axes.d.ts +32 -4
  57. package/dist/charts/primitives/Axes.d.ts.map +1 -1
  58. package/dist/charts/primitives/Axes.js +62 -16
  59. package/dist/charts/primitives/CartesianChart.d.ts +7 -6
  60. package/dist/charts/primitives/CartesianChart.d.ts.map +1 -1
  61. package/dist/charts/primitives/CartesianChart.js +271 -125
  62. package/dist/charts/primitives/ChartCard.d.ts +0 -14
  63. package/dist/charts/primitives/ChartCard.d.ts.map +1 -1
  64. package/dist/charts/primitives/ChartCard.js +74 -21
  65. package/dist/charts/primitives/ChartFrame.d.ts +28 -22
  66. package/dist/charts/primitives/ChartFrame.d.ts.map +1 -1
  67. package/dist/charts/primitives/ChartFrame.js +133 -34
  68. package/dist/charts/primitives/ChartLegend.d.ts +19 -15
  69. package/dist/charts/primitives/ChartLegend.d.ts.map +1 -1
  70. package/dist/charts/primitives/ChartLegend.js +212 -71
  71. package/dist/charts/primitives/ChartTooltip.d.ts.map +1 -1
  72. package/dist/charts/primitives/ChartTooltip.js +4 -3
  73. package/dist/charts/primitives/Crosshair.js +2 -2
  74. package/dist/charts/primitives/HoverOverlay.d.ts +6 -1
  75. package/dist/charts/primitives/HoverOverlay.d.ts.map +1 -1
  76. package/dist/charts/primitives/HoverOverlay.js +37 -26
  77. package/dist/charts/primitives/HoverOverlay.module.css +13 -0
  78. package/dist/charts/primitives/HoverOverlay.module.css.d.ts +8 -0
  79. package/dist/charts/primitives/chart-card-context.d.ts +29 -0
  80. package/dist/charts/primitives/chart-card-context.d.ts.map +1 -0
  81. package/dist/charts/primitives/chart-card-context.js +13 -0
  82. package/dist/charts/primitives/chart-frame-layout.d.ts +93 -113
  83. package/dist/charts/primitives/chart-frame-layout.d.ts.map +1 -1
  84. package/dist/charts/primitives/chart-frame-layout.js +76 -29
  85. package/dist/charts/primitives/chart-layout.d.ts +112 -0
  86. package/dist/charts/primitives/chart-layout.d.ts.map +1 -0
  87. package/dist/charts/primitives/chart-layout.js +175 -0
  88. package/dist/charts/primitives/chart-tier.d.ts +13 -11
  89. package/dist/charts/primitives/chart-tier.d.ts.map +1 -1
  90. package/dist/charts/primitives/chart-tier.js +42 -13
  91. package/dist/charts/series.d.ts +4 -1
  92. package/dist/charts/series.d.ts.map +1 -1
  93. package/dist/charts/utils/ticks.d.ts +27 -8
  94. package/dist/charts/utils/ticks.d.ts.map +1 -1
  95. package/dist/charts/utils/ticks.js +35 -11
  96. package/dist/common/errors.d.ts +11 -1
  97. package/dist/common/errors.d.ts.map +1 -1
  98. package/dist/common/errors.js +16 -2
  99. package/dist/common/hit-floor.d.ts +10 -0
  100. package/dist/common/hit-floor.d.ts.map +1 -0
  101. package/dist/common/hit-floor.js +6 -0
  102. package/dist/{shell → common}/isomorphic-layout-effect.d.ts +4 -3
  103. package/dist/common/isomorphic-layout-effect.d.ts.map +1 -0
  104. package/dist/common/use-measured-widths.d.ts +37 -0
  105. package/dist/common/use-measured-widths.d.ts.map +1 -0
  106. package/dist/common/use-measured-widths.js +51 -0
  107. package/dist/common/use-media-query.d.ts +6 -0
  108. package/dist/common/use-media-query.d.ts.map +1 -0
  109. package/dist/common/use-media-query.js +40 -0
  110. package/dist/common/validate.d.ts +9 -0
  111. package/dist/common/validate.d.ts.map +1 -1
  112. package/dist/common/validate.js +9 -4
  113. package/dist/content/article-layout.d.ts +4 -2
  114. package/dist/content/article-layout.d.ts.map +1 -1
  115. package/dist/content/article-layout.js +43 -3
  116. package/dist/content/article-layout.module.css +45 -4
  117. package/dist/content/article-layout.module.css.d.ts +3 -0
  118. package/dist/content/code-block.d.ts.map +1 -1
  119. package/dist/content/code-block.js +40 -2
  120. package/dist/content/code-block.module.css +32 -2
  121. package/dist/content/prose.module.css +13 -8
  122. package/dist/controls/actions.d.ts +29 -6
  123. package/dist/controls/actions.d.ts.map +1 -1
  124. package/dist/controls/actions.js +158 -27
  125. package/dist/controls/actions.module.css +14 -1
  126. package/dist/controls/actions.module.css.d.ts +1 -0
  127. package/dist/controls/controls.module.css +8 -31
  128. package/dist/controls/enum-filter.js +2 -2
  129. package/dist/controls/filter-context.d.ts +10 -0
  130. package/dist/controls/filter-context.d.ts.map +1 -1
  131. package/dist/controls/filter-context.js +2 -0
  132. package/dist/controls/filter-pill.d.ts.map +1 -1
  133. package/dist/controls/filter-pill.js +1 -0
  134. package/dist/controls/index.d.ts +1 -1
  135. package/dist/controls/index.d.ts.map +1 -1
  136. package/dist/controls/index.js +0 -2
  137. package/dist/controls/multi-select-filter.js +2 -2
  138. package/dist/controls/sync-button.module.css +1 -1
  139. package/dist/dashboard/section.d.ts.map +1 -1
  140. package/dist/dashboard/section.js +1 -0
  141. package/dist/dashboard/section.module.css +1 -26
  142. package/dist/dashboard/stat-card.d.ts +1 -1
  143. package/dist/dashboard/stat-card.d.ts.map +1 -1
  144. package/dist/dashboard/stat-card.js +4 -1
  145. package/dist/dashboard/stat-card.module.css +6 -9
  146. package/dist/dashboard/stat-group.module.css +16 -4
  147. package/dist/dashboard/widget-grid.d.ts.map +1 -1
  148. package/dist/dashboard/widget-header.d.ts +14 -4
  149. package/dist/dashboard/widget-header.d.ts.map +1 -1
  150. package/dist/dashboard/widget-header.js +23 -6
  151. package/dist/dashboard/widget-header.module.css +145 -133
  152. package/dist/dashboard/widget-header.module.css.d.ts +2 -0
  153. package/dist/data/data-table.d.ts +23 -0
  154. package/dist/data/data-table.d.ts.map +1 -1
  155. package/dist/data/data-table.js +339 -141
  156. package/dist/data/data-table.module.css +94 -0
  157. package/dist/data/data-table.module.css.d.ts +11 -0
  158. package/dist/data/virtual-list.d.ts.map +1 -1
  159. package/dist/data/virtual-list.js +10 -0
  160. package/dist/forms/form-layout.d.ts.map +1 -1
  161. package/dist/forms/form-layout.js +3 -3
  162. package/dist/forms/form-layout.module.css +30 -5
  163. package/dist/forms/form-layout.module.css.d.ts +1 -0
  164. package/dist/guard/index.d.ts +8 -2
  165. package/dist/guard/index.d.ts.map +1 -1
  166. package/dist/guard/index.js +67 -2
  167. package/dist/guard/types.d.ts +3 -3
  168. package/dist/guard/types.d.ts.map +1 -1
  169. package/dist/index.d.ts +1 -1
  170. package/dist/index.d.ts.map +1 -1
  171. package/dist/index.js +3 -1
  172. package/dist/provider/index.d.ts +20 -1
  173. package/dist/provider/index.d.ts.map +1 -1
  174. package/dist/provider/index.js +22 -2
  175. package/dist/shell/app-brand.d.ts.map +1 -1
  176. package/dist/shell/app-brand.js +1 -0
  177. package/dist/shell/app-brand.module.css +2 -2
  178. package/dist/shell/app-header.module.css +18 -8
  179. package/dist/shell/app-main.module.css +54 -3
  180. package/dist/shell/app-main.module.css.d.ts +1 -0
  181. package/dist/shell/app-mobile-nav.module.css +16 -4
  182. package/dist/shell/app-sidebar.module.css +4 -6
  183. package/dist/shell/index.d.ts +12 -0
  184. package/dist/shell/index.d.ts.map +1 -1
  185. package/dist/shell/index.js +57 -16
  186. package/dist/shell/mobile-nav-model.d.ts +1 -1
  187. package/dist/shell/page-aside.d.ts +22 -3
  188. package/dist/shell/page-aside.d.ts.map +1 -1
  189. package/dist/shell/page-aside.js +27 -13
  190. package/dist/shell/page-bar.d.ts.map +1 -1
  191. package/dist/shell/page-bar.js +10 -5
  192. package/dist/shell/page-bar.module.css +10 -34
  193. package/dist/shell/use-breakpoint.d.ts +3 -4
  194. package/dist/shell/use-breakpoint.d.ts.map +1 -1
  195. package/dist/shell/use-breakpoint.js +3 -25
  196. package/dist/shell/use-size-class.d.ts +6 -0
  197. package/dist/shell/use-size-class.d.ts.map +1 -0
  198. package/dist/shell/use-size-class.js +19 -0
  199. package/dist/state/persisted-or-local.d.ts +4 -1
  200. package/dist/state/persisted-or-local.d.ts.map +1 -1
  201. package/dist/state/persisted-or-local.js +4 -3
  202. package/dist/state/persisted.d.ts +10 -0
  203. package/dist/state/persisted.d.ts.map +1 -1
  204. package/dist/state/persisted.js +44 -14
  205. package/dist/styles.css +41 -0
  206. package/dist/surfaces.d.ts +4 -4
  207. package/dist/surfaces.d.ts.map +1 -1
  208. package/dist/surfaces.js +11 -3
  209. package/dist/theme/controls.module.css +7 -0
  210. package/dist/theme/ctl-theme.d.ts +1 -0
  211. package/dist/theme/ctl-theme.d.ts.map +1 -1
  212. package/dist/theme/ctl-theme.js +12 -4
  213. package/dist/theme/floating.module.css +36 -0
  214. package/dist/theme/floating.module.css.d.ts +3 -0
  215. package/dist/theme/index.d.ts +2 -2
  216. package/dist/theme/index.d.ts.map +1 -1
  217. package/dist/theme/index.js +34 -5
  218. package/dist/theme/nav-link.module.css +7 -0
  219. package/dist/tokens/index.d.ts +7 -16
  220. package/dist/tokens/index.d.ts.map +1 -1
  221. package/dist/tokens/index.js +23 -28
  222. package/dist/tokens/palette.d.ts +5 -27
  223. package/dist/tokens/palette.d.ts.map +1 -1
  224. package/dist/tokens/palette.js +8 -30
  225. package/dist/tokens/size-classes.d.ts +40 -0
  226. package/dist/tokens/size-classes.d.ts.map +1 -0
  227. package/dist/tokens/size-classes.js +29 -0
  228. package/dist/tokens.css +8 -4
  229. package/llms.txt +3 -3
  230. package/package.json +17 -17
  231. package/src/agent-chat/composer.tsx +74 -47
  232. package/src/agent-chat/thread-workspace.tsx +8 -11
  233. package/src/agent-chat/use-keyboard-inset.ts +68 -0
  234. package/src/charts/cursor/touch-pin.ts +138 -0
  235. package/src/charts/hooks/use-discrete-cursor.ts +335 -0
  236. package/src/charts/hooks/use-hysteresis.ts +26 -0
  237. package/src/charts/hooks/useBandPlot.ts +90 -27
  238. package/src/charts/hooks/useChartCursor.ts +211 -26
  239. package/src/charts/index.ts +0 -8
  240. package/src/charts/kinds/BandStrip.tsx +11 -1
  241. package/src/charts/kinds/Donut.tsx +153 -62
  242. package/src/charts/kinds/DualPanel.tsx +19 -4
  243. package/src/charts/kinds/Heatmap.tsx +61 -22
  244. package/src/charts/kinds/MirroredBars.tsx +15 -3
  245. package/src/charts/kinds/donut-layout.ts +82 -0
  246. package/src/charts/layout/auto-margin.ts +24 -5
  247. package/src/charts/layout/end-labels.ts +135 -0
  248. package/src/charts/primitives/Axes.tsx +112 -21
  249. package/src/charts/primitives/CartesianChart.tsx +282 -68
  250. package/src/charts/primitives/ChartCard.tsx +141 -48
  251. package/src/charts/primitives/ChartFrame.tsx +243 -60
  252. package/src/charts/primitives/ChartLegend.tsx +257 -73
  253. package/src/charts/primitives/ChartTooltip.tsx +8 -3
  254. package/src/charts/primitives/Crosshair.tsx +2 -2
  255. package/src/charts/primitives/HoverOverlay.module.css +13 -0
  256. package/src/charts/primitives/HoverOverlay.module.css.d.ts +8 -0
  257. package/src/charts/primitives/HoverOverlay.tsx +15 -4
  258. package/src/charts/primitives/chart-card-context.ts +37 -0
  259. package/src/charts/primitives/chart-frame-layout.ts +214 -177
  260. package/src/charts/primitives/chart-layout.ts +318 -0
  261. package/src/charts/primitives/chart-tier.tsx +66 -21
  262. package/src/charts/series.ts +4 -1
  263. package/src/charts/utils/ticks.ts +95 -19
  264. package/src/common/errors.ts +25 -1
  265. package/src/common/hit-floor.ts +9 -0
  266. package/src/{shell → common}/isomorphic-layout-effect.ts +4 -3
  267. package/src/common/use-measured-widths.ts +88 -0
  268. package/src/common/use-media-query.ts +56 -0
  269. package/src/common/validate.ts +17 -4
  270. package/src/content/article-layout.module.css +45 -4
  271. package/src/content/article-layout.module.css.d.ts +3 -0
  272. package/src/content/article-layout.tsx +60 -5
  273. package/src/content/code-block.module.css +32 -2
  274. package/src/content/code-block.tsx +47 -3
  275. package/src/content/prose.module.css +13 -8
  276. package/src/controls/actions.module.css +14 -1
  277. package/src/controls/actions.module.css.d.ts +1 -0
  278. package/src/controls/actions.tsx +223 -75
  279. package/src/controls/controls.module.css +8 -31
  280. package/src/controls/enum-filter.tsx +2 -2
  281. package/src/controls/filter-context.tsx +11 -0
  282. package/src/controls/filter-pill.tsx +1 -0
  283. package/src/controls/index.ts +0 -1
  284. package/src/controls/multi-select-filter.tsx +2 -2
  285. package/src/controls/sync-button.module.css +1 -1
  286. package/src/dashboard/section.module.css +1 -26
  287. package/src/dashboard/section.tsx +1 -0
  288. package/src/dashboard/stat-card.module.css +6 -9
  289. package/src/dashboard/stat-card.tsx +6 -3
  290. package/src/dashboard/stat-group.module.css +16 -4
  291. package/src/dashboard/widget-grid.tsx +7 -6
  292. package/src/dashboard/widget-header.module.css +145 -133
  293. package/src/dashboard/widget-header.module.css.d.ts +2 -0
  294. package/src/dashboard/widget-header.tsx +45 -11
  295. package/src/data/data-table.module.css +94 -0
  296. package/src/data/data-table.module.css.d.ts +11 -0
  297. package/src/data/data-table.tsx +503 -164
  298. package/src/data/virtual-list.tsx +31 -0
  299. package/src/forms/form-layout.module.css +30 -5
  300. package/src/forms/form-layout.module.css.d.ts +1 -0
  301. package/src/forms/form-layout.tsx +12 -10
  302. package/src/guard/index.ts +183 -3
  303. package/src/guard/types.ts +3 -2
  304. package/src/index.ts +2 -0
  305. package/src/provider/index.tsx +53 -1
  306. package/src/shell/app-brand.module.css +2 -2
  307. package/src/shell/app-brand.tsx +1 -0
  308. package/src/shell/app-header.module.css +18 -8
  309. package/src/shell/app-main.module.css +54 -3
  310. package/src/shell/app-main.module.css.d.ts +1 -0
  311. package/src/shell/app-mobile-nav.module.css +16 -4
  312. package/src/shell/app-sidebar.module.css +4 -6
  313. package/src/shell/index.tsx +200 -129
  314. package/src/shell/mobile-nav-model.ts +1 -1
  315. package/src/shell/page-aside.tsx +70 -21
  316. package/src/shell/page-bar.module.css +10 -34
  317. package/src/shell/page-bar.tsx +10 -5
  318. package/src/shell/use-breakpoint.ts +9 -45
  319. package/src/shell/use-size-class.ts +31 -0
  320. package/src/state/persisted-or-local.ts +10 -4
  321. package/src/state/persisted.ts +76 -17
  322. package/src/styles.css +41 -0
  323. package/src/surfaces.ts +9 -1
  324. package/src/theme/controls.module.css +7 -0
  325. package/src/theme/ctl-theme.tsx +15 -3
  326. package/src/theme/floating.module.css +36 -0
  327. package/src/theme/floating.module.css.d.ts +3 -0
  328. package/src/theme/index.ts +46 -8
  329. package/src/theme/nav-link.module.css +7 -0
  330. package/src/tokens/index.ts +20 -30
  331. package/src/tokens/palette.ts +6 -28
  332. package/src/tokens/size-classes.ts +46 -0
  333. package/dist/shell/isomorphic-layout-effect.d.ts.map +0 -1
  334. /package/dist/{shell → common}/isomorphic-layout-effect.js +0 -0
@@ -1,51 +1,121 @@
1
1
  import { jsx, jsxs } from "react/jsx-runtime";
2
2
  import { Group } from "@visx/group";
3
3
  import { Pie } from "@visx/shape";
4
- import { memo, useMemo, useState } from "react";
4
+ import { memo, useMemo } from "react";
5
+ import { useChartSize } from "../hooks/useChartSize.js";
6
+ import { useDiscreteCursor } from "../hooks/use-discrete-cursor.js";
7
+ import { useHysteresis } from "../hooks/use-hysteresis.js";
5
8
  import { assertRequiredProps } from "../../common/validate.js";
6
9
  import { ChartTooltipFloat, TooltipBody, TooltipRow } from "../primitives/ChartTooltip.js";
7
10
  import { ChartFrame } from "../primitives/ChartFrame.js";
8
11
  import { VX } from "../../tokens/index.js";
12
+ import { resolveContainerClass } from "../../tokens/size-classes.js";
13
+ import { resolveFrameHeight } from "../primitives/chart-frame-layout.js";
14
+ import {
15
+ foldOther,
16
+ resolveDonutLayout,
17
+ resolveDonutRadius,
18
+ resolveOtherKey,
19
+ sharePercent
20
+ } from "./donut-layout.js";
21
+ const identityLabel = (key) => key;
9
22
  function DonutInner(props) {
10
23
  assertRequiredProps("Donut", props, ["data", "colorForKey"]);
11
24
  const {
12
25
  data,
13
26
  height,
14
27
  colorForKey,
15
- seriesLabel = (k) => k,
28
+ formatValue,
29
+ seriesLabel = identityLabel,
16
30
  ariaLabel,
17
31
  isPending,
18
32
  state,
19
33
  className,
20
34
  style
21
35
  } = props;
22
- const series = data.map((d) => ({
23
- key: d.key,
24
- label: seriesLabel(d.key),
25
- color: colorForKey(d.key),
26
- mark: "bar"
27
- }));
36
+ const { ref, width: frameW, height: measuredH } = useChartSize();
37
+ const containerClass = resolveContainerClass(frameW);
38
+ const frameH = height === void 0 ? measuredH : resolveFrameHeight(height, containerClass);
39
+ const side = useHysteresis(
40
+ (wasSide) => resolveDonutLayout({
41
+ frameW,
42
+ frameH,
43
+ containerClass,
44
+ wasSide: height === void 0 && wasSide
45
+ }).side,
46
+ false
47
+ );
48
+ const slices = useMemo(() => {
49
+ const { kept, other } = foldOther(data);
50
+ const out = kept.map((d) => ({
51
+ key: d.key,
52
+ label: seriesLabel(d.key),
53
+ color: colorForKey(d.key),
54
+ value: d.value
55
+ }));
56
+ if (other !== null)
57
+ out.push({
58
+ key: resolveOtherKey(kept.map((d) => d.key)),
59
+ label: "Other",
60
+ color: VX.neutral,
61
+ value: other
62
+ });
63
+ return out;
64
+ }, [data, seriesLabel, colorForKey]);
65
+ const total = useMemo(() => slices.reduce((sum, d) => sum + d.value, 0), [slices]);
66
+ const series = useMemo(
67
+ () => slices.map((d) => ({
68
+ key: d.key,
69
+ label: side ? `${d.label} \xB7 ${formatValue(d.value)} \xB7 ${sharePercent(d.value, total)}%` : d.label,
70
+ color: d.color,
71
+ mark: "bar"
72
+ })),
73
+ [slices, side, formatValue, total]
74
+ );
28
75
  return /* @__PURE__ */ jsx(
29
- ChartFrame,
76
+ "div",
30
77
  {
31
- series,
32
- ...height !== void 0 && { height },
33
- ...ariaLabel !== void 0 && { ariaLabel },
34
- ...isPending !== void 0 && { isPending },
35
- ...state !== void 0 && { state },
78
+ ref,
36
79
  ...className !== void 0 && { className },
37
- ...style !== void 0 && { style },
38
- children: (plot) => /* @__PURE__ */ jsx(DonutPlot, { ...props, plot })
80
+ style: { display: "flex", flexDirection: "column", flex: "1 1 auto", minHeight: 0, ...style },
81
+ children: /* @__PURE__ */ jsx(
82
+ ChartFrame,
83
+ {
84
+ series,
85
+ legend: { placement: side ? "right" : "bottom", maxRows: series.length, headerSlot: false },
86
+ ...height !== void 0 && { height },
87
+ ...ariaLabel !== void 0 && { ariaLabel },
88
+ ...isPending !== void 0 && { isPending },
89
+ ...state !== void 0 && { state },
90
+ children: (plot) => /* @__PURE__ */ jsx(
91
+ DonutPlot,
92
+ {
93
+ slices,
94
+ total,
95
+ side,
96
+ frameW,
97
+ plot,
98
+ formatValue,
99
+ ...props.centerLabel !== void 0 && { centerLabel: props.centerLabel },
100
+ ...props.centerSubLabel !== void 0 && { centerSubLabel: props.centerSubLabel },
101
+ ...props.centerContent !== void 0 && { centerContent: props.centerContent },
102
+ ...props.innerRatio !== void 0 && { innerRatio: props.innerRatio },
103
+ ...props.padAngle !== void 0 && { padAngle: props.padAngle }
104
+ }
105
+ )
106
+ }
107
+ )
39
108
  }
40
109
  );
41
110
  }
42
111
  function DonutPlot(props) {
43
112
  const {
44
- data,
113
+ slices,
114
+ total,
45
115
  plot,
46
- colorForKey,
116
+ side,
117
+ frameW,
47
118
  formatValue,
48
- seriesLabel = (k) => k,
49
119
  centerLabel,
50
120
  centerSubLabel,
51
121
  centerContent,
@@ -53,20 +123,19 @@ function DonutPlot(props) {
53
123
  padAngle = 0.01
54
124
  } = props;
55
125
  const { width, height, hidden } = plot;
56
- const [tip, setTip] = useState(null);
57
- const hoveredKey = tip?.key ?? null;
58
- const visibleData = useMemo(() => data.filter((d) => !hidden.has(d.key)), [data, hidden]);
59
- const radius = Math.min(width, height) / 2 - 4;
126
+ const visibleData = useMemo(() => slices.filter((d) => !hidden.has(d.key)), [slices, hidden]);
127
+ const cursor = useDiscreteCursor({
128
+ targets: visibleData,
129
+ getKey: (d) => d.key,
130
+ ariaLabel: "Donut slices \u2014 use arrow keys to select, Escape to dismiss"
131
+ });
132
+ const activeKey = cursor.tip?.target.key ?? null;
133
+ const radius = resolveDonutRadius({ plotW: width, plotH: height, frameW, side });
60
134
  const innerRadius = radius * innerRatio;
61
135
  const centerX = width / 2;
62
136
  const centerY = height / 2;
63
- const total = useMemo(() => visibleData.reduce((sum, d) => sum + d.value, 0), [visibleData]);
64
- const show = (d, event) => {
65
- setTip({ key: d.key, value: d.value, anchor: { x: event.clientX, y: event.clientY } });
66
- };
67
- const hide = () => setTip(null);
68
137
  return /* @__PURE__ */ jsxs("div", { style: { position: "relative" }, children: [
69
- /* @__PURE__ */ jsx("svg", { width, height, children: /* @__PURE__ */ jsxs(Group, { left: centerX, top: centerY, children: [
138
+ /* @__PURE__ */ jsx("svg", { width, height, ...cursor.hostProps, children: /* @__PURE__ */ jsxs(Group, { left: centerX, top: centerY, children: [
70
139
  /* @__PURE__ */ jsx(
71
140
  Pie,
72
141
  {
@@ -82,27 +151,20 @@ function DonutPlot(props) {
82
151
  return /* @__PURE__ */ jsx(
83
152
  "g",
84
153
  {
85
- onPointerEnter: (event) => {
86
- show(arc.data, event);
87
- },
88
- onPointerMove: (event) => {
89
- show(arc.data, event);
90
- },
91
- onPointerLeave: () => {
92
- hide();
93
- },
94
- onPointerCancel: () => {
95
- hide();
96
- },
154
+ id: cursor.optionId(arc.data),
155
+ role: "option",
156
+ "aria-selected": activeKey === key,
157
+ "aria-label": `${arc.data.label}: ${formatValue(arc.data.value)}, ${sharePercent(arc.data.value, total)}%`,
158
+ ...cursor.pointerProps(arc.data),
97
159
  style: { cursor: "pointer" },
98
160
  children: /* @__PURE__ */ jsx(
99
161
  "path",
100
162
  {
101
163
  d: pie.path(arc) || "",
102
- fill: colorForKey(key),
164
+ fill: arc.data.color,
103
165
  stroke: VX.surface.panel,
104
166
  strokeWidth: 1.5,
105
- opacity: hoveredKey === null || hoveredKey === key ? 1 : 0.4
167
+ opacity: activeKey === null || activeKey === key ? 1 : 0.4
106
168
  }
107
169
  )
108
170
  },
@@ -153,13 +215,13 @@ function DonutPlot(props) {
153
215
  children: centerContent
154
216
  }
155
217
  ),
156
- tip !== null && /* @__PURE__ */ jsx(ChartTooltipFloat, { anchor: tip.anchor, children: /* @__PURE__ */ jsxs(TooltipBody, { children: [
218
+ cursor.tip !== null && /* @__PURE__ */ jsx(ChartTooltipFloat, { anchor: cursor.tip.anchor, children: /* @__PURE__ */ jsxs(TooltipBody, { children: [
157
219
  /* @__PURE__ */ jsx(
158
220
  TooltipRow,
159
221
  {
160
- color: colorForKey(tip.key),
161
- label: seriesLabel(tip.key),
162
- value: formatValue(tip.value),
222
+ color: cursor.tip.target.color,
223
+ label: cursor.tip.target.label,
224
+ value: formatValue(cursor.tip.target.value),
163
225
  shape: "bar"
164
226
  }
165
227
  ),
@@ -168,7 +230,7 @@ function DonutPlot(props) {
168
230
  {
169
231
  color: VX.grid,
170
232
  label: "Share",
171
- value: `${total > 0 ? Math.round(tip.value / total * 100) : 0}%`,
233
+ value: `${sharePercent(cursor.tip.target.value, total)}%`,
172
234
  shape: "bar"
173
235
  }
174
236
  )
@@ -1 +1 @@
1
- {"version":3,"file":"DualPanel.d.ts","sourceRoot":"","sources":["../../../src/charts/kinds/DualPanel.tsx"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"DualPanel.d.ts","sourceRoot":"","sources":["../../../src/charts/kinds/DualPanel.tsx"],"names":[],"mappings":"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"}
@@ -178,12 +178,14 @@ function DualPanelPlot(props) {
178
178
  }),
179
179
  [bottomDomain, bottomH, useNiceBottom]
180
180
  );
181
+ const svgRef = useRef(null);
181
182
  const cursor = useChartCursor({
182
183
  data,
183
184
  chartId,
184
185
  getKey: getX,
185
186
  xScale,
186
187
  marginLeft: margin.left,
188
+ boundaryRef: svgRef,
187
189
  ...cursorResolution !== void 0 && { resolution: cursorResolution }
188
190
  });
189
191
  const xLabelPx = useMemo(() => xLabelPxFor(xLabelsAll), [xLabelsAll]);
@@ -286,145 +288,157 @@ function DualPanelPlot(props) {
286
288
  }),
287
289
  [visibleSeries, lineValid, xScale, topYScale, getX]
288
290
  );
289
- const svgRef = useRef(null);
290
291
  const point = cursor.point;
291
292
  const sx = point !== null ? xScale(getX(point)) ?? 0 : 0;
292
293
  const syncedBar = point !== null ? getBar(point) : null;
293
294
  const isFollowerRender = !cursor.isSource && onFollow === true;
294
295
  const showTooltip = point !== null && (cursor.isSource || isFollowerRender);
295
- const anchorX = isFollowerRender && point !== null ? sx : null;
296
+ const anchorX = (isFollowerRender || cursor.isTouch) && point !== null ? sx : null;
296
297
  const svgRect = anchorX === null ? void 0 : svgRef.current?.getBoundingClientRect();
297
298
  const tooltipAnchor = svgRect === void 0 || anchorX === null ? cursor.anchor : { x: svgRect.left + margin.left + anchorX, y: svgRect.top + margin.top };
298
299
  return /* @__PURE__ */ jsxs(Fragment, { children: [
299
- /* @__PURE__ */ jsxs("svg", { ref: svgRef, width: plot.width, height: plot.height, children: [
300
- /* @__PURE__ */ jsxs(Group, { left: margin.left, top: margin.top, children: [
301
- /* @__PURE__ */ jsx(GridRows, { scale: topYScale, width: xMax, stroke: VX.grid, numTicks: 4 }),
302
- /* @__PURE__ */ jsx(ZoneRects, { zones: topZones, width: xMax, leftScale: topYScale }),
303
- fillBetween && fillPts.length > 0 && /* @__PURE__ */ jsx(
304
- Threshold,
305
- {
306
- id: `${chartId}-fill`,
307
- data: fillPts,
308
- x: (p) => xScale(getX(p.__d)) ?? 0,
309
- y0: (p) => topYScale(p.__from),
310
- y1: (p) => topYScale(p.__to),
311
- clipAboveTo: 0,
312
- clipBelowTo: topH,
313
- curve: fillCurve,
314
- belowAreaProps: { fill: fillBetween.fill },
315
- aboveAreaProps: { fill: fillBetween.aboveFill ?? fillBetween.fill }
316
- }
317
- ),
318
- topRefLines.map((r, i) => /* @__PURE__ */ jsx(
319
- "line",
320
- {
321
- x1: 0,
322
- x2: xMax,
323
- y1: topYScale(r.value),
324
- y2: topYScale(r.value),
325
- stroke: r.color,
326
- strokeDasharray: r.dashed ? VX.dashArray : void 0
327
- },
328
- `top-ref-${i}`
329
- )),
330
- visibleSeries.map((s) => {
331
- const valid = lineValid.get(s.key) ?? [];
332
- if (valid.length === 0) return null;
333
- return /* @__PURE__ */ jsx(
334
- LinePath,
335
- {
336
- data: valid,
337
- x: (p) => xScale(getX(p.__d)) ?? 0,
338
- y: (p) => topYScale(p.__y),
339
- stroke: s.color,
340
- strokeWidth: s.strokeWidth ?? VX.lineWidth,
341
- strokeDasharray: s.dash === "dashed" ? VX.dashArray : void 0,
342
- strokeOpacity: s.strokeOpacity ?? 1,
343
- curve: curveFor(s.curve)
344
- },
345
- `top-line-${s.key}`
346
- );
347
- }),
348
- markerNodes,
349
- point !== null && /* @__PURE__ */ jsx(Fragment, { children: visibleSeries.map((s) => {
350
- const v = s.getValue(point);
351
- if (v === null || v === void 0 || Number.isNaN(v)) return null;
352
- return /* @__PURE__ */ jsx(SeriesDot, { cx: sx, cy: topYScale(v), color: s.color }, `top-dot-${s.key}`);
353
- }) }),
354
- /* @__PURE__ */ jsx(AxisLeftNumeric, { scale: topYScale, numTicks: 4, tickFormat: formatTop }),
355
- /* @__PURE__ */ jsx(
356
- HoverOverlay,
357
- {
358
- width: xMax,
359
- height: topH + PANE_GAP,
360
- onMove: cursor.onPointerMove,
361
- onLeave: cursor.onPointerLeave,
362
- onKeyDown: cursor.onKeyDown,
363
- onBlur: cursor.onBlur,
364
- valueMax: Math.max(data.length - 1, 0),
365
- ...point !== null && {
366
- valueNow: data.indexOf(point),
367
- valueText: formatX(getX(point))
368
- },
369
- ...ariaLabel !== void 0 && { ariaLabel }
370
- }
371
- )
372
- ] }),
373
- /* @__PURE__ */ jsxs(Group, { left: margin.left, top: margin.top + bottomTop, children: [
374
- /* @__PURE__ */ jsx(
375
- "line",
376
- {
377
- x1: 0,
378
- x2: xMax,
379
- y1: bottomYScale(0),
380
- y2: bottomYScale(0),
381
- stroke: VX.grid,
382
- strokeWidth: 1
383
- }
384
- ),
385
- histogramBars.map((b) => /* @__PURE__ */ jsx(
386
- Bar,
387
- {
388
- x: b.x,
389
- y: b.y,
390
- width: b.width,
391
- height: b.height,
392
- fill: b.fill,
393
- fillOpacity: 0.7,
394
- rx: 1.4
395
- },
396
- b.key
397
- )),
398
- barVisible && point !== null && syncedBar !== null && syncedBar !== void 0 && !Number.isNaN(syncedBar) && /* @__PURE__ */ jsx(
399
- SeriesDot,
400
- {
401
- cx: sx,
402
- cy: bottomYScale(syncedBar),
403
- color: syncedBar >= 0 ? barColorPositive : barColorNegative
404
- }
405
- ),
406
- /* @__PURE__ */ jsx(AxisLeftNumeric, { scale: bottomYScale, numTicks: 3, tickFormat: formatBottom }),
407
- /* @__PURE__ */ jsx(
408
- AxisBottomDate,
409
- {
410
- top: bottomH,
411
- scale: xScale,
412
- tickValues,
413
- tickFormat: formatX
414
- }
415
- ),
416
- /* @__PURE__ */ jsx(
417
- HoverOverlay,
418
- {
419
- width: xMax,
420
- height: bottomH + margin.bottom,
421
- onMove: cursor.onPointerMove,
422
- onLeave: cursor.onPointerLeave
423
- }
424
- )
425
- ] }),
426
- point !== null && /* @__PURE__ */ jsx(Group, { left: margin.left, top: margin.top, children: /* @__PURE__ */ jsx(Crosshair, { x: sx, top: 0, bottom: innerH }) })
427
- ] }),
300
+ /* @__PURE__ */ jsxs(
301
+ "svg",
302
+ {
303
+ ref: svgRef,
304
+ width: plot.width,
305
+ height: plot.height,
306
+ style: { touchAction: "pan-y" },
307
+ children: [
308
+ /* @__PURE__ */ jsxs(Group, { left: margin.left, top: margin.top, children: [
309
+ /* @__PURE__ */ jsx(GridRows, { scale: topYScale, width: xMax, stroke: VX.grid, numTicks: 4 }),
310
+ /* @__PURE__ */ jsx(ZoneRects, { zones: topZones, width: xMax, leftScale: topYScale }),
311
+ fillBetween && fillPts.length > 0 && /* @__PURE__ */ jsx(
312
+ Threshold,
313
+ {
314
+ id: `${chartId}-fill`,
315
+ data: fillPts,
316
+ x: (p) => xScale(getX(p.__d)) ?? 0,
317
+ y0: (p) => topYScale(p.__from),
318
+ y1: (p) => topYScale(p.__to),
319
+ clipAboveTo: 0,
320
+ clipBelowTo: topH,
321
+ curve: fillCurve,
322
+ belowAreaProps: { fill: fillBetween.fill },
323
+ aboveAreaProps: { fill: fillBetween.aboveFill ?? fillBetween.fill }
324
+ }
325
+ ),
326
+ topRefLines.map((r, i) => /* @__PURE__ */ jsx(
327
+ "line",
328
+ {
329
+ x1: 0,
330
+ x2: xMax,
331
+ y1: topYScale(r.value),
332
+ y2: topYScale(r.value),
333
+ stroke: r.color,
334
+ strokeDasharray: r.dashed ? VX.dashArray : void 0
335
+ },
336
+ `top-ref-${i}`
337
+ )),
338
+ visibleSeries.map((s) => {
339
+ const valid = lineValid.get(s.key) ?? [];
340
+ if (valid.length === 0) return null;
341
+ return /* @__PURE__ */ jsx(
342
+ LinePath,
343
+ {
344
+ data: valid,
345
+ x: (p) => xScale(getX(p.__d)) ?? 0,
346
+ y: (p) => topYScale(p.__y),
347
+ stroke: s.color,
348
+ strokeWidth: s.strokeWidth ?? VX.lineWidth,
349
+ strokeDasharray: s.dash === "dashed" ? VX.dashArray : void 0,
350
+ strokeOpacity: s.strokeOpacity ?? 1,
351
+ curve: curveFor(s.curve)
352
+ },
353
+ `top-line-${s.key}`
354
+ );
355
+ }),
356
+ markerNodes,
357
+ point !== null && /* @__PURE__ */ jsx(Fragment, { children: visibleSeries.map((s) => {
358
+ const v = s.getValue(point);
359
+ if (v === null || v === void 0 || Number.isNaN(v)) return null;
360
+ return /* @__PURE__ */ jsx(SeriesDot, { cx: sx, cy: topYScale(v), color: s.color }, `top-dot-${s.key}`);
361
+ }) }),
362
+ /* @__PURE__ */ jsx(AxisLeftNumeric, { scale: topYScale, numTicks: 4, tickFormat: formatTop }),
363
+ /* @__PURE__ */ jsx(
364
+ HoverOverlay,
365
+ {
366
+ width: xMax,
367
+ height: topH + PANE_GAP,
368
+ onMove: cursor.onPointerMove,
369
+ onDown: cursor.onPointerDown,
370
+ onUp: cursor.onPointerUp,
371
+ onLeave: cursor.onPointerLeave,
372
+ onKeyDown: cursor.onKeyDown,
373
+ onBlur: cursor.onBlur,
374
+ valueMax: Math.max(data.length - 1, 0),
375
+ ...point !== null && {
376
+ valueNow: data.indexOf(point),
377
+ valueText: formatX(getX(point))
378
+ },
379
+ ...ariaLabel !== void 0 && { ariaLabel }
380
+ }
381
+ )
382
+ ] }),
383
+ /* @__PURE__ */ jsxs(Group, { left: margin.left, top: margin.top + bottomTop, children: [
384
+ /* @__PURE__ */ jsx(
385
+ "line",
386
+ {
387
+ x1: 0,
388
+ x2: xMax,
389
+ y1: bottomYScale(0),
390
+ y2: bottomYScale(0),
391
+ stroke: VX.grid,
392
+ strokeWidth: 1
393
+ }
394
+ ),
395
+ histogramBars.map((b) => /* @__PURE__ */ jsx(
396
+ Bar,
397
+ {
398
+ x: b.x,
399
+ y: b.y,
400
+ width: b.width,
401
+ height: b.height,
402
+ fill: b.fill,
403
+ fillOpacity: 0.7,
404
+ rx: 1.4
405
+ },
406
+ b.key
407
+ )),
408
+ barVisible && point !== null && syncedBar !== null && syncedBar !== void 0 && !Number.isNaN(syncedBar) && /* @__PURE__ */ jsx(
409
+ SeriesDot,
410
+ {
411
+ cx: sx,
412
+ cy: bottomYScale(syncedBar),
413
+ color: syncedBar >= 0 ? barColorPositive : barColorNegative
414
+ }
415
+ ),
416
+ /* @__PURE__ */ jsx(AxisLeftNumeric, { scale: bottomYScale, numTicks: 3, tickFormat: formatBottom }),
417
+ /* @__PURE__ */ jsx(
418
+ AxisBottomDate,
419
+ {
420
+ top: bottomH,
421
+ scale: xScale,
422
+ tickValues,
423
+ tickFormat: formatX
424
+ }
425
+ ),
426
+ /* @__PURE__ */ jsx(
427
+ HoverOverlay,
428
+ {
429
+ width: xMax,
430
+ height: bottomH + margin.bottom,
431
+ onMove: cursor.onPointerMove,
432
+ onDown: cursor.onPointerDown,
433
+ onUp: cursor.onPointerUp,
434
+ onLeave: cursor.onPointerLeave
435
+ }
436
+ )
437
+ ] }),
438
+ point !== null && /* @__PURE__ */ jsx(Group, { left: margin.left, top: margin.top, children: /* @__PURE__ */ jsx(Crosshair, { x: sx, top: 0, bottom: innerH }) })
439
+ ]
440
+ }
441
+ ),
428
442
  showTooltip && /* @__PURE__ */ jsxs(ChartTooltipFloat, { anchor: tooltipAnchor, ariaLive: cursor.isSource, children: [
429
443
  /* @__PURE__ */ jsx(
430
444
  TooltipHeader,
@@ -68,6 +68,13 @@ export type HeatmapProps<T> = BasaltProps & {
68
68
  * right gutter reserves half the widest column label, so no two painted labels overlap and the
69
69
  * last one cannot clip.
70
70
  *
71
+ * Tap-to-pin, keyboard stepping and focus over the grid come from `useDiscreteCursor`
72
+ * (`docs/CHARTS-SPEC.md` §4, Tooltip), the discrete counterpart of `HoverOverlay`. Its targets are
73
+ * the FULL row-major grid (data cells and empty ones alike) so Up/Down can jump one row via a fixed
74
+ * `columns` stride; only a cell WITH data renders a tooltip or takes pointer input, matching today's
75
+ * hover behavior — an empty cell is still a keyboard stop (so the grid reads as one rectangle), it
76
+ * just carries no readout.
77
+ *
71
78
  * Composes `ChartFrame` purely for measuring (`height`/`aspectRatio`/`fill`, the same three
72
79
  * sizing modes every other kind exposes) — `legend={false}` and an empty `series` opt out of
73
80
  * `ChartFrame`'s own derived legend, since Heatmap already ships its own gradient strip.
@@ -1 +1 @@
1
- {"version":3,"file":"Heatmap.d.ts","sourceRoot":"","sources":["../../../src/charts/kinds/Heatmap.tsx"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAgB,SAAS,EAAE,MAAM,OAAO,CAAA;AAGpD,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAA;AAQrD,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,0BAA0B,CAAA;AAErE,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,4BAA4B,CAAA;AAK5D,kFAAkF;AAClF,KAAK,WAAW,GAAG;IAAE,GAAG,EAAE,MAAM,CAAC;IAAC,GAAG,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,CAAA;AAK9D,MAAM,MAAM,YAAY,CAAC,CAAC,IAAI,WAAW,GAAG;IAC1C,IAAI,EAAE,CAAC,EAAE,CAAA;IACT;;+CAE2C;IAC3C,MAAM,CAAC,EAAE,MAAM,GAAG,qBAAqB,CAAA;IACvC,qFAAqF;IACrF,WAAW,CAAC,EAAE,MAAM,CAAA;IACpB,uFAAuF;IACvF,IAAI,CAAC,EAAE,OAAO,CAAA;IACd,OAAO,EAAE,MAAM,CAAA;IACf,4DAA4D;IAC5D,MAAM,EAAE,CAAC,CAAC,EAAE,CAAC,KAAK,MAAM,CAAA;IACxB,+DAA+D;IAC/D,MAAM,EAAE,CAAC,CAAC,EAAE,CAAC,KAAK,MAAM,CAAA;IACxB,yCAAyC;IACzC,QAAQ,EAAE,CAAC,CAAC,EAAE,CAAC,KAAK,MAAM,CAAA;IAC1B,+DAA+D;IAC/D,IAAI,CAAC,EAAE,MAAM,EAAE,CAAA;IACf,kEAAkE;IAClE,IAAI,CAAC,EAAE,MAAM,EAAE,CAAA;IACf,yDAAyD;IACzD,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,2DAA2D;IAC3D,SAAS,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,KAAK,MAAM,CAAA;IAClD,yCAAyC;IACzC,OAAO,CAAC,EAAE,MAAM,CAAA;IAChB,kDAAkD;IAClD,UAAU,CAAC,EAAE,MAAM,CAAA;IACnB,uCAAuC;IACvC,WAAW,CAAC,EAAE,CAAC,CAAC,EAAE,MAAM,KAAK,MAAM,CAAA;IACnC,2DAA2D;IAC3D,QAAQ,CAAC,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,MAAM,CAAA;IAClC,8DAA8D;IAC9D,QAAQ,CAAC,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,MAAM,CAAA;IAClC,iEAAiE;IACjE,aAAa,CAAC,EAAE,CAAC,IAAI,EAAE,WAAW,KAAK,SAAS,CAAA;IAChD,2EAA2E;IAC3E,MAAM,CAAC,EAAE;QAAE,GAAG,EAAE,MAAM,CAAC;QAAC,GAAG,EAAE,MAAM,CAAA;KAAE,CAAA;IACrC,iGAAiG;IACjG,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB,4FAA4F;IAC5F,SAAS,CAAC,EAAE,OAAO,CAAA;IACnB;4FACwF;IACxF,KAAK,CAAC,EAAE,UAAU,CAAA;CACnB,CAAA;AAoCD;;;;;;;;;;;;;GAaG;AACH,iBAAS,YAAY,CAAC,CAAC,EAAE,KAAK,EAAE,YAAY,CAAC,CAAC,CAAC,+BAyB9C;AAkND,eAAO,MAAM,OAAO,EAAkB,OAAO,YAAY,CAAA"}
1
+ {"version":3,"file":"Heatmap.d.ts","sourceRoot":"","sources":["../../../src/charts/kinds/Heatmap.tsx"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,OAAO,CAAA;AAGtC,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAA;AAQrD,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,0BAA0B,CAAA;AAGrE,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,4BAA4B,CAAA;AAK5D,kFAAkF;AAClF,KAAK,WAAW,GAAG;IAAE,GAAG,EAAE,MAAM,CAAC;IAAC,GAAG,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,CAAA;AAM9D,MAAM,MAAM,YAAY,CAAC,CAAC,IAAI,WAAW,GAAG;IAC1C,IAAI,EAAE,CAAC,EAAE,CAAA;IACT;;+CAE2C;IAC3C,MAAM,CAAC,EAAE,MAAM,GAAG,qBAAqB,CAAA;IACvC,qFAAqF;IACrF,WAAW,CAAC,EAAE,MAAM,CAAA;IACpB,uFAAuF;IACvF,IAAI,CAAC,EAAE,OAAO,CAAA;IACd,OAAO,EAAE,MAAM,CAAA;IACf,4DAA4D;IAC5D,MAAM,EAAE,CAAC,CAAC,EAAE,CAAC,KAAK,MAAM,CAAA;IACxB,+DAA+D;IAC/D,MAAM,EAAE,CAAC,CAAC,EAAE,CAAC,KAAK,MAAM,CAAA;IACxB,yCAAyC;IACzC,QAAQ,EAAE,CAAC,CAAC,EAAE,CAAC,KAAK,MAAM,CAAA;IAC1B,+DAA+D;IAC/D,IAAI,CAAC,EAAE,MAAM,EAAE,CAAA;IACf,kEAAkE;IAClE,IAAI,CAAC,EAAE,MAAM,EAAE,CAAA;IACf,yDAAyD;IACzD,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,2DAA2D;IAC3D,SAAS,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,KAAK,MAAM,CAAA;IAClD,yCAAyC;IACzC,OAAO,CAAC,EAAE,MAAM,CAAA;IAChB,kDAAkD;IAClD,UAAU,CAAC,EAAE,MAAM,CAAA;IACnB,uCAAuC;IACvC,WAAW,CAAC,EAAE,CAAC,CAAC,EAAE,MAAM,KAAK,MAAM,CAAA;IACnC,2DAA2D;IAC3D,QAAQ,CAAC,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,MAAM,CAAA;IAClC,8DAA8D;IAC9D,QAAQ,CAAC,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,MAAM,CAAA;IAClC,iEAAiE;IACjE,aAAa,CAAC,EAAE,CAAC,IAAI,EAAE,WAAW,KAAK,SAAS,CAAA;IAChD,2EAA2E;IAC3E,MAAM,CAAC,EAAE;QAAE,GAAG,EAAE,MAAM,CAAC;QAAC,GAAG,EAAE,MAAM,CAAA;KAAE,CAAA;IACrC,iGAAiG;IACjG,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB,4FAA4F;IAC5F,SAAS,CAAC,EAAE,OAAO,CAAA;IACnB;4FACwF;IACxF,KAAK,CAAC,EAAE,UAAU,CAAA;CACnB,CAAA;AAoCD;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,iBAAS,YAAY,CAAC,CAAC,EAAE,KAAK,EAAE,YAAY,CAAC,CAAC,CAAC,+BAyB9C;AAgPD,eAAO,MAAM,OAAO,EAAkB,OAAO,YAAY,CAAA"}