@seekalfred/primitives 0.6.0 → 0.7.3

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 (346) hide show
  1. package/README.md +214 -15
  2. package/dist/activity-heatmap/activity-heatmap.d.ts +92 -0
  3. package/dist/activity-heatmap/activity-heatmap.js +699 -0
  4. package/dist/activity-heatmap/activity-heatmap.js.map +1 -0
  5. package/dist/activity-heatmap/index.d.ts +2 -0
  6. package/dist/activity-heatmap/index.js +2 -0
  7. package/dist/alert/alert.d.ts +53 -4
  8. package/dist/alert/alert.js +100 -11
  9. package/dist/alert/alert.js.map +1 -1
  10. package/dist/alert/index.d.ts +2 -2
  11. package/dist/alert/index.js +2 -2
  12. package/dist/alert-dialog/alert-dialog.d.ts +58 -18
  13. package/dist/alert-dialog/alert-dialog.js +152 -9
  14. package/dist/alert-dialog/alert-dialog.js.map +1 -1
  15. package/dist/alert-dialog/index.d.ts +2 -2
  16. package/dist/alert-dialog/index.js +2 -2
  17. package/dist/animated-counter/animated-counter.d.ts +38 -0
  18. package/dist/animated-counter/animated-counter.js +230 -0
  19. package/dist/animated-counter/animated-counter.js.map +1 -0
  20. package/dist/animated-counter/index.d.ts +2 -0
  21. package/dist/animated-counter/index.js +2 -0
  22. package/dist/announcement-bar/announcement-bar.d.ts +67 -0
  23. package/dist/announcement-bar/announcement-bar.js +364 -0
  24. package/dist/announcement-bar/announcement-bar.js.map +1 -0
  25. package/dist/announcement-bar/index.d.ts +2 -0
  26. package/dist/announcement-bar/index.js +2 -0
  27. package/dist/badge/badge.d.ts +1 -1
  28. package/dist/bar-chart/bar-chart.d.ts +51 -0
  29. package/dist/bar-chart/bar-chart.js +565 -0
  30. package/dist/bar-chart/bar-chart.js.map +1 -0
  31. package/dist/bar-chart/index.d.ts +2 -0
  32. package/dist/bar-chart/index.js +2 -0
  33. package/dist/breadcrumb/breadcrumb.d.ts +2 -2
  34. package/dist/breadcrumb/breadcrumb.js +12 -3
  35. package/dist/breadcrumb/breadcrumb.js.map +1 -1
  36. package/dist/brush-chart/brush-chart.d.ts +64 -0
  37. package/dist/brush-chart/brush-chart.js +1056 -0
  38. package/dist/brush-chart/brush-chart.js.map +1 -0
  39. package/dist/brush-chart/index.d.ts +2 -0
  40. package/dist/brush-chart/index.js +2 -0
  41. package/dist/button/button.d.ts +1 -1
  42. package/dist/button/button.js +31 -21
  43. package/dist/button/button.js.map +1 -1
  44. package/dist/button-group/button-group.js +3 -4
  45. package/dist/button-group/button-group.js.map +1 -1
  46. package/dist/calendar/calendar.d.ts +1 -1
  47. package/dist/card/card.d.ts +22 -1
  48. package/dist/card/card.js +60 -7
  49. package/dist/card/card.js.map +1 -1
  50. package/dist/card-stack/card-stack.d.ts +54 -0
  51. package/dist/card-stack/card-stack.js +492 -0
  52. package/dist/card-stack/card-stack.js.map +1 -0
  53. package/dist/card-stack/index.d.ts +2 -0
  54. package/dist/card-stack/index.js +2 -0
  55. package/dist/carousel/carousel.d.ts +77 -0
  56. package/dist/carousel/carousel.js +415 -0
  57. package/dist/carousel/carousel.js.map +1 -0
  58. package/dist/carousel/index.d.ts +2 -0
  59. package/dist/carousel/index.js +2 -0
  60. package/dist/checkbox/checkbox.js +4 -4
  61. package/dist/checkbox/checkbox.js.map +1 -1
  62. package/dist/chip-group/chip-group.d.ts +37 -0
  63. package/dist/chip-group/chip-group.js +148 -0
  64. package/dist/chip-group/chip-group.js.map +1 -0
  65. package/dist/chip-group/index.d.ts +2 -0
  66. package/dist/chip-group/index.js +2 -0
  67. package/dist/copy-button/copy-button.d.ts +18 -2
  68. package/dist/copy-button/copy-button.js +29 -8
  69. package/dist/copy-button/copy-button.js.map +1 -1
  70. package/dist/countdown/countdown.d.ts +45 -0
  71. package/dist/countdown/countdown.js +298 -0
  72. package/dist/countdown/countdown.js.map +1 -0
  73. package/dist/countdown/index.d.ts +2 -0
  74. package/dist/countdown/index.js +2 -0
  75. package/dist/date-picker/picker-parts.js +1 -1
  76. package/dist/date-picker/picker-parts.js.map +1 -1
  77. package/dist/dialog/dialog.js +1 -1
  78. package/dist/dialog/dialog.js.map +1 -1
  79. package/dist/donut-chart/donut-chart.d.ts +86 -0
  80. package/dist/donut-chart/donut-chart.js +593 -0
  81. package/dist/donut-chart/donut-chart.js.map +1 -0
  82. package/dist/donut-chart/index.d.ts +2 -0
  83. package/dist/donut-chart/index.js +2 -0
  84. package/dist/empty-state/empty-state.d.ts +42 -10
  85. package/dist/empty-state/empty-state.js +44 -26
  86. package/dist/empty-state/empty-state.js.map +1 -1
  87. package/dist/empty-state/index.d.ts +2 -2
  88. package/dist/empty-state/index.js +2 -2
  89. package/dist/file-drop-zone/file-drop-zone.js +1 -1
  90. package/dist/file-drop-zone/file-drop-zone.js.map +1 -1
  91. package/dist/filter-bar/filter-bar.d.ts +50 -26
  92. package/dist/filter-bar/filter-bar.js +317 -157
  93. package/dist/filter-bar/filter-bar.js.map +1 -1
  94. package/dist/gauge/gauge.d.ts +45 -0
  95. package/dist/gauge/gauge.js +219 -0
  96. package/dist/gauge/gauge.js.map +1 -0
  97. package/dist/gauge/index.d.ts +2 -0
  98. package/dist/gauge/index.js +2 -0
  99. package/dist/in-view-title/in-view-title.d.ts +33 -0
  100. package/dist/in-view-title/in-view-title.js +119 -0
  101. package/dist/in-view-title/in-view-title.js.map +1 -0
  102. package/dist/in-view-title/index.d.ts +2 -0
  103. package/dist/in-view-title/index.js +2 -0
  104. package/dist/index.d.ts +53 -10
  105. package/dist/index.js +52 -12
  106. package/dist/input/input.js +4 -4
  107. package/dist/input/input.js.map +1 -1
  108. package/dist/lib/cn.js +11 -1
  109. package/dist/lib/cn.js.map +1 -1
  110. package/dist/lib/field-message.js +28 -10
  111. package/dist/lib/field-message.js.map +1 -1
  112. package/dist/lib/field-shell.js +10 -3
  113. package/dist/lib/field-shell.js.map +1 -1
  114. package/dist/lib/field-surface.js +31 -9
  115. package/dist/lib/field-surface.js.map +1 -1
  116. package/dist/lib/flag-emoji.js +50 -0
  117. package/dist/lib/flag-emoji.js.map +1 -0
  118. package/dist/lib/flip.js +11 -3
  119. package/dist/lib/flip.js.map +1 -1
  120. package/dist/lib/menu-highlight.js +64 -0
  121. package/dist/lib/menu-highlight.js.map +1 -0
  122. package/dist/lib/motion.js +9 -2
  123. package/dist/lib/motion.js.map +1 -1
  124. package/dist/lib/rolling-value.js +1 -1
  125. package/dist/lib/rolling-value.js.map +1 -1
  126. package/dist/lib/spring-tween.js +500 -0
  127. package/dist/lib/spring-tween.js.map +1 -0
  128. package/dist/lib/swap-text.js +3 -1
  129. package/dist/lib/swap-text.js.map +1 -1
  130. package/dist/lib/use-copy-feedback.js +17 -3
  131. package/dist/lib/use-copy-feedback.js.map +1 -1
  132. package/dist/line-chart/index.d.ts +2 -0
  133. package/dist/line-chart/index.js +2 -0
  134. package/dist/line-chart/line-chart.d.ts +116 -0
  135. package/dist/line-chart/line-chart.js +740 -0
  136. package/dist/line-chart/line-chart.js.map +1 -0
  137. package/dist/mention-input/index.d.ts +2 -0
  138. package/dist/mention-input/index.js +2 -0
  139. package/dist/mention-input/mention-input.d.ts +98 -0
  140. package/dist/mention-input/mention-input.js +576 -0
  141. package/dist/mention-input/mention-input.js.map +1 -0
  142. package/dist/menu/menu.d.ts +2 -0
  143. package/dist/menu/menu.js +23 -12
  144. package/dist/menu/menu.js.map +1 -1
  145. package/dist/money-input/index.d.ts +2 -0
  146. package/dist/money-input/index.js +2 -0
  147. package/dist/money-input/money-input.d.ts +86 -0
  148. package/dist/money-input/money-input.js +613 -0
  149. package/dist/money-input/money-input.js.map +1 -0
  150. package/dist/morph-select/index.d.ts +2 -0
  151. package/dist/morph-select/index.js +2 -0
  152. package/dist/morph-select/morph-select.d.ts +89 -0
  153. package/dist/morph-select/morph-select.js +712 -0
  154. package/dist/morph-select/morph-select.js.map +1 -0
  155. package/dist/multi-select/index.d.ts +2 -0
  156. package/dist/multi-select/index.js +2 -0
  157. package/dist/multi-select/multi-select.d.ts +77 -0
  158. package/dist/multi-select/multi-select.js +209 -0
  159. package/dist/multi-select/multi-select.js.map +1 -0
  160. package/dist/number-field/index.d.ts +2 -0
  161. package/dist/number-field/index.js +2 -0
  162. package/dist/number-field/number-field.d.ts +42 -0
  163. package/dist/number-field/number-field.js +199 -0
  164. package/dist/number-field/number-field.js.map +1 -0
  165. package/dist/onboarding-checklist/index.d.ts +2 -0
  166. package/dist/onboarding-checklist/index.js +2 -0
  167. package/dist/onboarding-checklist/onboarding-checklist.d.ts +55 -0
  168. package/dist/onboarding-checklist/onboarding-checklist.js +577 -0
  169. package/dist/onboarding-checklist/onboarding-checklist.js.map +1 -0
  170. package/dist/password-field/password-field.d.ts +16 -0
  171. package/dist/password-field/password-field.js +39 -10
  172. package/dist/password-field/password-field.js.map +1 -1
  173. package/dist/phone-input/index.d.ts +3 -0
  174. package/dist/phone-input/index.js +3 -0
  175. package/dist/phone-input/phone-countries.d.ts +29 -0
  176. package/dist/phone-input/phone-countries.js +170 -0
  177. package/dist/phone-input/phone-countries.js.map +1 -0
  178. package/dist/phone-input/phone-input.d.ts +66 -0
  179. package/dist/phone-input/phone-input.js +440 -0
  180. package/dist/phone-input/phone-input.js.map +1 -0
  181. package/dist/popover/index.d.ts +2 -2
  182. package/dist/popover/index.js +2 -2
  183. package/dist/popover/popover.d.ts +51 -2
  184. package/dist/popover/popover.js +59 -8
  185. package/dist/popover/popover.js.map +1 -1
  186. package/dist/progress/progress.d.ts +16 -2
  187. package/dist/progress/progress.js +16 -9
  188. package/dist/progress/progress.js.map +1 -1
  189. package/dist/radio-group/index.d.ts +2 -2
  190. package/dist/radio-group/index.js +2 -2
  191. package/dist/radio-group/radio-group.d.ts +33 -3
  192. package/dist/radio-group/radio-group.js +110 -10
  193. package/dist/radio-group/radio-group.js.map +1 -1
  194. package/dist/reactions/index.d.ts +2 -0
  195. package/dist/reactions/index.js +2 -0
  196. package/dist/reactions/reactions.d.ts +50 -0
  197. package/dist/reactions/reactions.js +315 -0
  198. package/dist/reactions/reactions.js.map +1 -0
  199. package/dist/rich-text-editor/index.d.ts +3 -0
  200. package/dist/rich-text-editor/index.js +2 -0
  201. package/dist/rich-text-editor/rich-text-editor.d.ts +70 -0
  202. package/dist/rich-text-editor/rich-text-editor.js +909 -0
  203. package/dist/rich-text-editor/rich-text-editor.js.map +1 -0
  204. package/dist/rich-text-editor/rich-text-engine.d.ts +16 -0
  205. package/dist/rich-text-editor/rich-text-engine.js +366 -0
  206. package/dist/rich-text-editor/rich-text-engine.js.map +1 -0
  207. package/dist/rich-text-editor/rich-text-html.js +174 -0
  208. package/dist/rich-text-editor/rich-text-html.js.map +1 -0
  209. package/dist/rich-text-editor/rich-text-icons.js +43 -0
  210. package/dist/rich-text-editor/rich-text-icons.js.map +1 -0
  211. package/dist/ridgeline/index.d.ts +2 -0
  212. package/dist/ridgeline/index.js +2 -0
  213. package/dist/ridgeline/ridgeline.d.ts +55 -0
  214. package/dist/ridgeline/ridgeline.js +701 -0
  215. package/dist/ridgeline/ridgeline.js.map +1 -0
  216. package/dist/scroll-area/index.d.ts +2 -2
  217. package/dist/scroll-area/index.js +2 -2
  218. package/dist/scroll-area/scroll-area.d.ts +68 -31
  219. package/dist/scroll-area/scroll-area.js +212 -62
  220. package/dist/scroll-area/scroll-area.js.map +1 -1
  221. package/dist/scrub-input/evaluate.d.ts +14 -0
  222. package/dist/scrub-input/evaluate.js +72 -0
  223. package/dist/scrub-input/evaluate.js.map +1 -0
  224. package/dist/scrub-input/index.d.ts +3 -0
  225. package/dist/scrub-input/index.js +3 -0
  226. package/dist/scrub-input/scrub-input.d.ts +74 -0
  227. package/dist/scrub-input/scrub-input.js +486 -0
  228. package/dist/scrub-input/scrub-input.js.map +1 -0
  229. package/dist/search-field/search-field.d.ts +24 -2
  230. package/dist/search-field/search-field.js +24 -9
  231. package/dist/search-field/search-field.js.map +1 -1
  232. package/dist/select/select.d.ts +3 -1
  233. package/dist/select/select.js +28 -14
  234. package/dist/select/select.js.map +1 -1
  235. package/dist/separator/separator.d.ts +22 -10
  236. package/dist/separator/separator.js +33 -11
  237. package/dist/separator/separator.js.map +1 -1
  238. package/dist/sheet/sheet.js +2 -1
  239. package/dist/sheet/sheet.js.map +1 -1
  240. package/dist/shortcut-recorder/index.d.ts +3 -0
  241. package/dist/shortcut-recorder/index.js +3 -0
  242. package/dist/shortcut-recorder/shortcut-model.d.ts +27 -0
  243. package/dist/shortcut-recorder/shortcut-model.js +206 -0
  244. package/dist/shortcut-recorder/shortcut-model.js.map +1 -0
  245. package/dist/shortcut-recorder/shortcut-recorder.d.ts +93 -0
  246. package/dist/shortcut-recorder/shortcut-recorder.js +489 -0
  247. package/dist/shortcut-recorder/shortcut-recorder.js.map +1 -0
  248. package/dist/slider/index.d.ts +2 -2
  249. package/dist/slider/slider.d.ts +46 -14
  250. package/dist/slider/slider.js +151 -67
  251. package/dist/slider/slider.js.map +1 -1
  252. package/dist/slope-chart/index.d.ts +2 -0
  253. package/dist/slope-chart/index.js +2 -0
  254. package/dist/slope-chart/slope-chart.d.ts +54 -0
  255. package/dist/slope-chart/slope-chart.js +568 -0
  256. package/dist/slope-chart/slope-chart.js.map +1 -0
  257. package/dist/sparkline/index.d.ts +2 -0
  258. package/dist/sparkline/index.js +2 -0
  259. package/dist/sparkline/sparkline.d.ts +46 -0
  260. package/dist/sparkline/sparkline.js +390 -0
  261. package/dist/sparkline/sparkline.js.map +1 -0
  262. package/dist/split-bar/index.d.ts +2 -0
  263. package/dist/split-bar/index.js +2 -0
  264. package/dist/split-bar/split-bar.d.ts +62 -0
  265. package/dist/split-bar/split-bar.js +513 -0
  266. package/dist/split-bar/split-bar.js.map +1 -0
  267. package/dist/split-button/split-button.d.ts +1 -1
  268. package/dist/split-button/split-button.js +12 -11
  269. package/dist/split-button/split-button.js.map +1 -1
  270. package/dist/stat-card/index.d.ts +2 -2
  271. package/dist/stat-card/index.js +2 -2
  272. package/dist/stat-card/stat-card.d.ts +58 -5
  273. package/dist/stat-card/stat-card.js +144 -17
  274. package/dist/stat-card/stat-card.js.map +1 -1
  275. package/dist/stepper/index.d.ts +2 -0
  276. package/dist/stepper/index.js +2 -0
  277. package/dist/stepper/stepper.d.ts +51 -0
  278. package/dist/stepper/stepper.js +215 -0
  279. package/dist/stepper/stepper.js.map +1 -0
  280. package/dist/streamgraph/index.d.ts +2 -0
  281. package/dist/streamgraph/index.js +2 -0
  282. package/dist/streamgraph/streamgraph.d.ts +70 -0
  283. package/dist/streamgraph/streamgraph.js +613 -0
  284. package/dist/streamgraph/streamgraph.js.map +1 -0
  285. package/dist/styles.css +1 -1
  286. package/dist/swipe-actions/index.d.ts +2 -0
  287. package/dist/swipe-actions/index.js +2 -0
  288. package/dist/swipe-actions/swipe-actions.d.ts +67 -0
  289. package/dist/swipe-actions/swipe-actions.js +552 -0
  290. package/dist/swipe-actions/swipe-actions.js.map +1 -0
  291. package/dist/switch/switch.js +2 -2
  292. package/dist/switch/switch.js.map +1 -1
  293. package/dist/table/index.d.ts +2 -2
  294. package/dist/table/index.js +2 -2
  295. package/dist/table/table.d.ts +55 -3
  296. package/dist/table/table.js +340 -165
  297. package/dist/table/table.js.map +1 -1
  298. package/dist/tabs/tabs.js +2 -2
  299. package/dist/tabs/tabs.js.map +1 -1
  300. package/dist/tag-input/index.d.ts +2 -0
  301. package/dist/tag-input/index.js +2 -0
  302. package/dist/tag-input/tag-input.d.ts +40 -0
  303. package/dist/tag-input/tag-input.js +269 -0
  304. package/dist/tag-input/tag-input.js.map +1 -0
  305. package/dist/text-morph/index.d.ts +2 -0
  306. package/dist/text-morph/index.js +2 -0
  307. package/dist/text-morph/text-morph.d.ts +23 -0
  308. package/dist/text-morph/text-morph.js +21 -0
  309. package/dist/text-morph/text-morph.js.map +1 -0
  310. package/dist/text-reveal/index.d.ts +2 -0
  311. package/dist/text-reveal/index.js +2 -0
  312. package/dist/text-reveal/text-reveal.d.ts +27 -0
  313. package/dist/text-reveal/text-reveal.js +51 -0
  314. package/dist/text-reveal/text-reveal.js.map +1 -0
  315. package/dist/text-shimmer/index.d.ts +2 -0
  316. package/dist/text-shimmer/index.js +2 -0
  317. package/dist/text-shimmer/text-shimmer.d.ts +29 -0
  318. package/dist/text-shimmer/text-shimmer.js +29 -0
  319. package/dist/text-shimmer/text-shimmer.js.map +1 -0
  320. package/dist/time-picker/time-picker.d.ts +36 -1
  321. package/dist/time-picker/time-picker.js +35 -7
  322. package/dist/time-picker/time-picker.js.map +1 -1
  323. package/dist/toast/index.d.ts +2 -2
  324. package/dist/toast/index.js +2 -2
  325. package/dist/toast/toast.d.ts +7 -1
  326. package/dist/toast/toast.js +82 -40
  327. package/dist/toast/toast.js.map +1 -1
  328. package/dist/tooltip/tooltip.d.ts +9 -2
  329. package/dist/tooltip/tooltip.js +7 -7
  330. package/dist/tooltip/tooltip.js.map +1 -1
  331. package/dist/treemap/index.d.ts +2 -0
  332. package/dist/treemap/index.js +2 -0
  333. package/dist/treemap/treemap.d.ts +53 -0
  334. package/dist/treemap/treemap.js +699 -0
  335. package/dist/treemap/treemap.js.map +1 -0
  336. package/dist/usage-meter/index.d.ts +2 -0
  337. package/dist/usage-meter/index.js +2 -0
  338. package/dist/usage-meter/usage-meter.d.ts +80 -0
  339. package/dist/usage-meter/usage-meter.js +458 -0
  340. package/dist/usage-meter/usage-meter.js.map +1 -0
  341. package/dist/waffle-chart/index.d.ts +2 -0
  342. package/dist/waffle-chart/index.js +2 -0
  343. package/dist/waffle-chart/waffle-chart.d.ts +57 -0
  344. package/dist/waffle-chart/waffle-chart.js +426 -0
  345. package/dist/waffle-chart/waffle-chart.js.map +1 -0
  346. package/package.json +165 -3
@@ -0,0 +1,740 @@
1
+ "use client";
2
+ import { cn } from "../lib/cn.js";
3
+ import { mergeRefs } from "../lib/merge-refs.js";
4
+ import { prefersReducedMotion, useIsomorphicLayoutEffect } from "../lib/motion.js";
5
+ import { SMOOTH, SNAPPY, tween } from "../lib/spring-tween.js";
6
+ import { forwardRef, useCallback, useEffect, useId, useMemo, useRef, useState } from "react";
7
+ import { jsx, jsxs } from "react/jsx-runtime";
8
+ //#region src/line-chart/line-chart.tsx
9
+ /** Room above the top gridline, and the gap between the crosshair and its tooltip. */
10
+ const TOP = 12;
11
+ const GAP = 14;
12
+ /** The first draw: 480ms x 1.75, slow at both ends. */
13
+ const LINE_CHART_DRAW_MS = 840;
14
+ const PALETTE = [
15
+ "var(--color-chart-1)",
16
+ "color-mix(in oklab, var(--color-foreground) 46%, var(--color-surface))",
17
+ "color-mix(in oklab, var(--color-foreground) 26%, var(--color-surface))"
18
+ ];
19
+ const GROUPED = new Intl.NumberFormat("en-US", { maximumFractionDigits: 1 });
20
+ const COMPACT = new Intl.NumberFormat("en-US", {
21
+ notation: "compact",
22
+ maximumFractionDigits: 1
23
+ });
24
+ const GRID = Array.from({ length: 241 }, (_, index) => index / 240);
25
+ const clamp = (value, low, high) => Math.min(high, Math.max(low, value));
26
+ const colorOf = (line, index) => line.color ?? PALETTE[Math.min(index, PALETTE.length - 1)];
27
+ const clean = (value) => Number(value.toPrecision(12));
28
+ /** Clean gridlines: the smallest step of 1, 2, 2.5 or 5 that covers the data in four rows or fewer, from zero unless the data dips below it. */
29
+ function niceScale(low, high) {
30
+ const lo = Math.min(0, low);
31
+ const hi = Math.max(high, lo + 1);
32
+ const magnitude = 10 ** Math.floor(Math.log10((hi - lo) / 4));
33
+ for (const factor of [
34
+ 1,
35
+ 2,
36
+ 2.5,
37
+ 5,
38
+ 10
39
+ ]) {
40
+ const step = factor * magnitude;
41
+ const bottom = Math.floor(lo / step) * step;
42
+ const top = Math.ceil(hi / step) * step;
43
+ if ((top - bottom) / step <= 4 + 1e-9) {
44
+ const ticks = [];
45
+ for (let value = bottom; value <= top + step / 2; value += step) ticks.push(clean(value));
46
+ return {
47
+ min: clean(bottom),
48
+ max: clean(top),
49
+ ticks
50
+ };
51
+ }
52
+ }
53
+ return {
54
+ min: lo,
55
+ max: hi,
56
+ ticks: [lo, hi]
57
+ };
58
+ }
59
+ /** The line through every value, sampled densely on x from 0 to 1 in data units. Monotone tangents keep a smooth curve from swinging past the data. */
60
+ function curveFor(values, smooth) {
61
+ if (values.length === 0) return [];
62
+ if (values.length === 1) return [[0, values[0]], [1, values[0]]];
63
+ const last = values.length - 1;
64
+ const step = 1 / last;
65
+ if (!smooth) return values.map((value, index) => [index * step, value]);
66
+ const slopes = values.slice(1).map((value, index) => (value - values[index]) / step);
67
+ const tangents = values.map((_, index) => index === 0 || index === last ? 0 : (Math.sign(slopes[index - 1]) + Math.sign(slopes[index])) * Math.min(Math.abs(slopes[index - 1]), Math.abs(slopes[index]), Math.abs(slopes[index - 1] + slopes[index]) / 4) || 0);
68
+ if (last > 1) {
69
+ tangents[0] = (3 * slopes[0] - tangents[1]) / 2;
70
+ tangents[last] = (3 * slopes[last - 1] - tangents[last - 1]) / 2;
71
+ } else {
72
+ tangents[0] = slopes[0];
73
+ tangents[1] = slopes[0];
74
+ }
75
+ const samples = Math.max(1, Math.min(16, Math.round(192 / last)));
76
+ const points = [];
77
+ for (let index = 0; index < last; index++) {
78
+ const low = Math.min(values[index], values[index + 1]);
79
+ const high = Math.max(values[index], values[index + 1]);
80
+ for (let sample = 0; sample < samples; sample++) {
81
+ const t = sample / samples;
82
+ const t2 = t * t;
83
+ const t3 = t2 * t;
84
+ const value = (2 * t3 - 3 * t2 + 1) * values[index] + (t3 - 2 * t2 + t) * step * tangents[index] + (3 * t2 - 2 * t3) * values[index + 1] + (t3 - t2) * step * tangents[index + 1];
85
+ points.push([(index + t) * step, clamp(value, low, high)]);
86
+ }
87
+ }
88
+ points.push([1, values[last]]);
89
+ return points;
90
+ }
91
+ /** Fills each missing value straight between its present neighbours (or with the nearest one at the ends), so a gapped line still has a shape to morph. */
92
+ function fillGaps(values) {
93
+ const present = values.flatMap((value, index) => value === null ? [] : [index]);
94
+ if (!present.length) return values.map(() => 0);
95
+ return values.map((value, index) => {
96
+ if (value !== null) return value;
97
+ const after = present.find((at) => at > index);
98
+ const before = [...present].reverse().find((at) => at < index);
99
+ if (before === void 0) return values[after];
100
+ if (after === void 0) return values[before];
101
+ return values[before] + (values[after] - values[before]) * (index - before) / (after - before);
102
+ });
103
+ }
104
+ /** Where a line with missing values is not drawn: before its first value, after its last, and between two values with missing ones between them. */
105
+ function breaksFor(values) {
106
+ const present = values.flatMap((value, index) => value === null ? [] : [index]);
107
+ if (!present.length) return values.length ? [[-Infinity, Infinity]] : [];
108
+ const last = values.length - 1;
109
+ if (last === 0) return [];
110
+ const breaks = [];
111
+ if (present[0] > 0) breaks.push([-Infinity, present[0] / last]);
112
+ for (let at = 1; at < present.length; at++) if (present[at] - present[at - 1] > 1) breaks.push([present[at - 1] / last, present[at] / last]);
113
+ if (present[present.length - 1] < last) breaks.push([present[present.length - 1] / last, Infinity]);
114
+ return breaks;
115
+ }
116
+ const EDGE = 1e-9;
117
+ /** Radius of a lone point's dot, inside its 2px stroke. */
118
+ const DOT = 1.5;
119
+ const inBreak = (breaks, x) => breaks.some(([from, to]) => x > from + EDGE && x < to - EDGE);
120
+ /** The drawn runs of a line, split at its gaps. A run of one point is a dot: a small closed circle the stroke fills out to about 5px. */
121
+ function pathsFor(shape, breaks, toX, toY, bottom) {
122
+ const runs = [];
123
+ let run = null;
124
+ for (const [x, value] of shape) {
125
+ if (breaks.length && inBreak(breaks, x)) {
126
+ run = null;
127
+ continue;
128
+ }
129
+ if (!run) runs.push(run = []);
130
+ run.push(`${toX(x).toFixed(1)},${toY(value).toFixed(1)}`);
131
+ }
132
+ return {
133
+ line: runs.map((points) => {
134
+ if (points.length > 1) return `M${points.join("L")}`;
135
+ const [x, y] = points[0].split(",").map(Number);
136
+ return `M${(x - DOT).toFixed(1)},${y.toFixed(1)}a${DOT},${DOT} 0 1,0 ${DOT * 2},0a${DOT},${DOT} 0 1,0 -3,0`;
137
+ }).join(""),
138
+ area: runs.map((points) => {
139
+ const first = points[0].split(",")[0];
140
+ const lastX = points[points.length - 1].split(",")[0];
141
+ return `M${points.join("L")}L${lastX},${bottom}L${first},${bottom}Z`;
142
+ }).join("")
143
+ };
144
+ }
145
+ const isFiniteValue = (reference) => typeof reference.value === "number" && Number.isFinite(reference.value);
146
+ /** Value of a sampled line at x, straight between samples. */
147
+ function valueAt(shape, x) {
148
+ if (!shape.length) return 0;
149
+ let low = 0;
150
+ let high = shape.length - 1;
151
+ if (x <= shape[low][0]) return shape[low][1];
152
+ if (x >= shape[high][0]) return shape[high][1];
153
+ while (high - low > 1) {
154
+ const middle = low + high >> 1;
155
+ if (shape[middle][0] < x) low = middle;
156
+ else high = middle;
157
+ }
158
+ const [x0, y0] = shape[low];
159
+ const [x1, y1] = shape[high];
160
+ return x1 === x0 ? y1 : y0 + (y1 - y0) * (x - x0) / (x1 - x0);
161
+ }
162
+ /** Axis labels that fit: at most one per 76 pixels, counted back from the latest so the newest always shows. */
163
+ function axisPicks(data, width) {
164
+ const labeled = data.flatMap((item, index) => item.axisLabel ? [index] : []);
165
+ if (!width || !labeled.length) return [];
166
+ const room = Math.max(2, Math.floor(width / 76));
167
+ const stride = Math.ceil(labeled.length / room);
168
+ return labeled.reverse().filter((_, rank) => rank % stride === 0).reverse();
169
+ }
170
+ const LineChart = forwardRef(function LineChart({ data, series, label, unit = "", height = 220, formatValue, formatTick = (value) => COMPACT.format(value), hiddenSeries, defaultHiddenSeries, onHiddenSeriesChange, onActiveChange, loading = false, emptyLabel = "No data for this range", legend, categoryLabel = "Date", curve = "smooth", missing = "zero", missingLabel = "No data", references, className }, ref) {
171
+ const figure = useRef(null);
172
+ const refs = useMemo(() => mergeRefs(ref, figure), [ref]);
173
+ const plot = useRef(null);
174
+ const svg = useRef(null);
175
+ const tip = useRef(null);
176
+ const gutter = useRef(null);
177
+ const uid = `line${useId().replace(/[^a-zA-Z0-9_-]/g, "")}`;
178
+ const last = data.length - 1;
179
+ const empty = data.length === 0;
180
+ const [ownHidden, setOwnHidden] = useState(defaultHiddenSeries ?? []);
181
+ const hidden = hiddenSeries ?? ownHidden;
182
+ const toggle = (key) => {
183
+ const next = hidden.includes(key) ? hidden.filter((item) => item !== key) : [...hidden, key];
184
+ if (hiddenSeries === void 0) setOwnHidden(next);
185
+ onHiddenSeriesChange?.(next);
186
+ };
187
+ const visible = series.filter((line) => !hidden.includes(line.key));
188
+ const showLegend = legend ?? series.length > 1;
189
+ const gaps = missing === "gap";
190
+ const read = (item, key) => {
191
+ const value = item.values[key];
192
+ if (!gaps) return value ?? 0;
193
+ return typeof value === "number" && Number.isFinite(value) ? value : null;
194
+ };
195
+ const signature = `${curve}|${missing}|${series.map((line) => line.key).join(",")}|${data.map((item) => `${item.key}:${series.map((line) => read(item, line.key)).join(",")}`).join(";")}`;
196
+ const targets = useMemo(() => new Map(series.map((line) => {
197
+ const values = data.map((item) => read(item, line.key));
198
+ return [line.key, {
199
+ shape: curveFor(fillGaps(values), curve === "smooth"),
200
+ breaks: breaksFor(values)
201
+ }];
202
+ })), [signature]);
203
+ let low = Infinity;
204
+ let high = -Infinity;
205
+ for (const line of visible) for (const item of data) {
206
+ const value = read(item, line.key);
207
+ if (value === null) continue;
208
+ low = Math.min(low, value);
209
+ high = Math.max(high, value);
210
+ }
211
+ for (const reference of references ?? []) {
212
+ if (!isFiniteValue(reference)) continue;
213
+ low = Math.min(low, reference.value);
214
+ high = Math.max(high, reference.value);
215
+ }
216
+ const range = Number.isFinite(low) ? niceScale(low, high) : null;
217
+ const [steady, setSteady] = useState(() => range ?? niceScale(0, 100));
218
+ if (range && (range.min !== steady.min || range.max !== steady.max)) setSteady(range);
219
+ const [active, setActive] = useState(null);
220
+ const [seen, setSeen] = useState(signature);
221
+ if (seen !== signature) {
222
+ setSeen(signature);
223
+ setActive(null);
224
+ }
225
+ const index = active === null || empty ? null : Math.min(active, last);
226
+ const scrubbing = index !== null;
227
+ const width = useRef(0);
228
+ const [plotWidth, setPlotWidth] = useState(0);
229
+ const [drawn, setDrawn] = useState(false);
230
+ const tracks = useRef(/* @__PURE__ */ new Map());
231
+ const scale = useRef({
232
+ min: steady.min,
233
+ max: steady.max
234
+ });
235
+ const cursor = useRef(1);
236
+ const referenceAt = (reference) => {
237
+ if (typeof reference.value === "number") return isFiniteValue(reference) ? null : void 0;
238
+ const at = data.findIndex((item) => item.key === reference.at);
239
+ return at < 0 ? void 0 : last > 0 ? at / last : .5;
240
+ };
241
+ const drawnReferences = (references ?? []).filter((reference) => referenceAt(reference) !== void 0);
242
+ const live = useRef({
243
+ series,
244
+ hidden
245
+ });
246
+ useIsomorphicLayoutEffect(() => {
247
+ live.current = {
248
+ series,
249
+ hidden
250
+ };
251
+ });
252
+ /** One writer for every drawn attribute: morphs, toggles, the scale, the crosshair and the size all repaint through here. */
253
+ const paint = useCallback(() => {
254
+ const w = width.current;
255
+ const root = svg.current;
256
+ if (!w || !root) return;
257
+ const lo = scale.current.min;
258
+ const span = scale.current.max - lo || 1;
259
+ const toY = (value) => TOP + (1 - (value - lo) / span) * (height - TOP);
260
+ const at = cursor.current;
261
+ const dotYs = [];
262
+ for (const line of live.current.series) {
263
+ const track = tracks.current.get(line.key);
264
+ if (!track) continue;
265
+ const p = track.presence;
266
+ const y = (value) => toY(lo + (value - lo) * p);
267
+ const group = root.querySelector(`[data-series="${CSS.escape(line.key)}"]`);
268
+ if (track.breaks.length) {
269
+ const paths = pathsFor(track.shape, track.breaks, (x) => x * w, y, height);
270
+ group?.querySelector("[data-part=line]")?.setAttribute("d", paths.line);
271
+ group?.querySelector("[data-part=area]")?.setAttribute("d", paths.area);
272
+ } else {
273
+ const path = track.shape.length ? `M${track.shape.map(([x, value]) => `${(x * w).toFixed(1)},${y(value).toFixed(1)}`).join("L")}` : "";
274
+ group?.querySelector("[data-part=line]")?.setAttribute("d", path);
275
+ group?.querySelector("[data-part=area]")?.setAttribute("d", path ? `${path}L${w},${height}L0,${height}Z` : "");
276
+ }
277
+ if (group) group.style.opacity = String(p);
278
+ const dot = root.querySelector(`[data-dot="${CSS.escape(line.key)}"]`);
279
+ if (dot && track.shape.length) {
280
+ const gap = inBreak(track.breaks, at);
281
+ const cy = y(valueAt(track.shape, at));
282
+ dot.setAttribute("cx", (at * w).toFixed(1));
283
+ dot.setAttribute("cy", cy.toFixed(1));
284
+ if (gap) dot.setAttribute("data-gap", "");
285
+ else dot.removeAttribute("data-gap");
286
+ if (p > .5 && !gap) dotYs.push(cy);
287
+ }
288
+ }
289
+ for (const node of root.querySelectorAll("[data-grid]")) {
290
+ const yy = String(Math.round(toY(Number(node.dataset.grid))) + .5);
291
+ node.setAttribute("y1", yy);
292
+ node.setAttribute("y2", yy);
293
+ }
294
+ for (const node of gutter.current?.querySelectorAll("[data-tick]") ?? []) node.style.translate = `0 ${Math.round(toY(Number(node.dataset.tick)))}px`;
295
+ for (const node of root.querySelectorAll("[data-reference-value]")) {
296
+ const yy = String(Math.round(toY(Number(node.dataset.referenceValue))) + .5);
297
+ node.setAttribute("y1", yy);
298
+ node.setAttribute("y2", yy);
299
+ }
300
+ for (const node of root.querySelectorAll("[data-reference-at]")) {
301
+ const xx = String(Math.round(Number(node.dataset.referenceAt) * w) + .5);
302
+ node.setAttribute("x1", xx);
303
+ node.setAttribute("x2", xx);
304
+ }
305
+ for (const node of plot.current?.querySelectorAll("[data-reference-label]") ?? []) {
306
+ const { referenceValue, referenceAt } = node.dataset;
307
+ node.style.translate = referenceValue !== void 0 ? `0 ${Math.round(toY(Number(referenceValue)))}px` : `${Math.round(Number(referenceAt) * w)}px 0`;
308
+ }
309
+ const cx = Math.round(at * w) + .5;
310
+ const cross = root.querySelector("[data-part=crosshair]");
311
+ cross?.setAttribute("x1", String(cx));
312
+ cross?.setAttribute("x2", String(cx));
313
+ const bubble = tip.current;
314
+ if (bubble) {
315
+ const tw = bubble.offsetWidth;
316
+ const th = bubble.offsetHeight;
317
+ let x = cx + GAP;
318
+ if (x + tw > w) x = cx - GAP - tw;
319
+ const middle = dotYs.length ? dotYs.reduce((sum, value) => sum + value, 0) / dotYs.length : height / 2;
320
+ bubble.style.translate = `${clamp(x, 0, Math.max(0, w - tw))}px ${clamp(middle - th / 2, 0, Math.max(0, height - th))}px`;
321
+ }
322
+ }, [height]);
323
+ useIsomorphicLayoutEffect(() => {
324
+ const node = plot.current;
325
+ if (!node) return;
326
+ const read = () => {
327
+ width.current = node.clientWidth;
328
+ setPlotWidth(node.clientWidth);
329
+ paint();
330
+ };
331
+ read();
332
+ if (typeof ResizeObserver === "undefined") return;
333
+ const observer = new ResizeObserver(read);
334
+ observer.observe(node);
335
+ return () => observer.disconnect();
336
+ }, [paint]);
337
+ useIsomorphicLayoutEffect(paint);
338
+ useEffect(() => {
339
+ const moves = [];
340
+ for (const [key, { shape: target, breaks }] of targets) {
341
+ const track = tracks.current.get(key);
342
+ if (!track) {
343
+ tracks.current.set(key, {
344
+ shape: target,
345
+ breaks,
346
+ presence: live.current.hidden.includes(key) ? 0 : 1,
347
+ stop: null
348
+ });
349
+ continue;
350
+ }
351
+ track.breaks = breaks;
352
+ if (!track.shape.length || !target.length) {
353
+ track.shape = target;
354
+ continue;
355
+ }
356
+ const xs = [.../* @__PURE__ */ new Set([...GRID, ...target.map(([x]) => x)])].sort((a, b) => a - b);
357
+ moves.push({
358
+ track,
359
+ xs,
360
+ from: xs.map((x) => valueAt(track.shape, x)),
361
+ to: xs.map((x) => valueAt(target, x)),
362
+ target
363
+ });
364
+ }
365
+ if (!moves.length) {
366
+ paint();
367
+ return;
368
+ }
369
+ return tween(SMOOTH, (p) => {
370
+ for (const move of moves) move.track.shape = move.xs.map((x, at) => [x, move.from[at] + (move.to[at] - move.from[at]) * p]);
371
+ paint();
372
+ }, () => {
373
+ for (const move of moves) move.track.shape = move.target;
374
+ paint();
375
+ });
376
+ }, [paint, targets]);
377
+ const hiddenKey = hidden.join("|");
378
+ useEffect(() => {
379
+ for (const [key, track] of tracks.current) {
380
+ const to = hidden.includes(key) ? 0 : 1;
381
+ if (track.presence === to) continue;
382
+ track.stop?.();
383
+ const from = track.presence;
384
+ track.stop = tween(SMOOTH, (p) => {
385
+ track.presence = from + (to - from) * p;
386
+ paint();
387
+ });
388
+ }
389
+ paint();
390
+ }, [hiddenKey, paint]);
391
+ useEffect(() => {
392
+ const from = { ...scale.current };
393
+ if (from.min === steady.min && from.max === steady.max) return;
394
+ return tween(SMOOTH, (p) => {
395
+ scale.current = {
396
+ min: from.min + (steady.min - from.min) * p,
397
+ max: from.max + (steady.max - from.max) * p
398
+ };
399
+ paint();
400
+ });
401
+ }, [paint, steady]);
402
+ useEffect(() => {
403
+ if (empty || drawn) return;
404
+ const node = figure.current;
405
+ if (!node || prefersReducedMotion() || typeof IntersectionObserver === "undefined") {
406
+ setDrawn(true);
407
+ return;
408
+ }
409
+ const observer = new IntersectionObserver(([entry]) => {
410
+ if (!entry?.isIntersecting) return;
411
+ observer.disconnect();
412
+ setDrawn(true);
413
+ }, { threshold: .3 });
414
+ observer.observe(node);
415
+ return () => observer.disconnect();
416
+ }, [drawn, empty]);
417
+ const wasScrubbing = useRef(false);
418
+ useEffect(() => {
419
+ if (index === null) {
420
+ wasScrubbing.current = false;
421
+ return;
422
+ }
423
+ const to = last > 0 ? index / last : .5;
424
+ const from = cursor.current;
425
+ if (!wasScrubbing.current) {
426
+ wasScrubbing.current = true;
427
+ cursor.current = to;
428
+ paint();
429
+ return;
430
+ }
431
+ return tween(SNAPPY, (p) => {
432
+ cursor.current = from + (to - from) * p;
433
+ paint();
434
+ });
435
+ }, [
436
+ index,
437
+ last,
438
+ paint
439
+ ]);
440
+ const onActive = useRef(onActiveChange);
441
+ useIsomorphicLayoutEffect(() => {
442
+ onActive.current = onActiveChange;
443
+ });
444
+ useEffect(() => {
445
+ onActive.current?.(index, index === null ? null : data[index] ?? null);
446
+ }, [index]);
447
+ const pointAt = (clientX) => {
448
+ const rect = plot.current?.getBoundingClientRect();
449
+ if (!rect?.width || last < 1) return Math.max(0, last);
450
+ return clamp(Math.round((clientX - rect.left) / rect.width * last), 0, last);
451
+ };
452
+ const onKeyDown = (event) => {
453
+ if (event.key === "Escape" && scrubbing) {
454
+ event.preventDefault();
455
+ setActive(null);
456
+ return;
457
+ }
458
+ const from = index ?? last + 1;
459
+ const page = Math.max(1, Math.round(data.length / 6));
460
+ const next = {
461
+ ArrowLeft: from - 1,
462
+ ArrowDown: from - 1,
463
+ ArrowRight: index === null ? last : from + 1,
464
+ ArrowUp: index === null ? last : from + 1,
465
+ PageDown: from - page,
466
+ PageUp: from + page,
467
+ Home: 0,
468
+ End: last
469
+ }[event.key];
470
+ if (next === void 0 || empty) return;
471
+ event.preventDefault();
472
+ setActive(clamp(next, 0, last));
473
+ };
474
+ const onPointerDown = (event) => {
475
+ if (empty) return;
476
+ if (event.pointerType !== "mouse") event.currentTarget.setPointerCapture?.(event.pointerId);
477
+ setActive(pointAt(event.clientX));
478
+ };
479
+ const onPointerMove = (event) => {
480
+ if (!empty && (event.pointerType === "mouse" || event.buttons)) setActive(pointAt(event.clientX));
481
+ };
482
+ const formatNumber = (value, line) => `${formatValue ? formatValue(value, line) : GROUPED.format(value)}${unit ? ` ${unit}` : ""}`;
483
+ const format = (value, line) => value === null ? missingLabel : formatNumber(value, line);
484
+ const formatReference = (value) => series[0] ? formatNumber(value, series[0]) : `${GROUPED.format(value)}${unit ? ` ${unit}` : ""}`;
485
+ const reading = index === null ? null : data[index];
486
+ const shown = reading ?? data[last];
487
+ const valueText = reading ? `${reading.label}: ${visible.map((line) => `${line.label} ${format(read(reading, line.key), line)}`).join(", ")}` : empty ? emptyLabel : `${visible.length} of ${series.length} series shown`;
488
+ const summary = empty ? `${label}. ${emptyLabel}.` : `${label}, ${data[0].label} to ${data[last].label}. ${visible.map((line) => `${line.label}, latest ${format(read(data[last], line.key), line)}`).join(". ")}.${drawnReferences.map((reference) => typeof reference.value === "number" ? ` ${reference.label}: ${formatReference(reference.value)}.` : ` ${reference.label}: ${data.find((item) => item.key === reference.at).label}.`).join("")}`;
489
+ const picks = axisPicks(data, plotWidth);
490
+ const allHidden = !empty && visible.length === 0;
491
+ return /* @__PURE__ */ jsxs("figure", {
492
+ ref: refs,
493
+ "data-slot": "line-chart",
494
+ "aria-label": label,
495
+ "aria-busy": loading || void 0,
496
+ className: cn("m-0 grid min-w-0 gap-4 box-border font-sans text-foreground", className),
497
+ children: [
498
+ showLegend ? /* @__PURE__ */ jsx("div", {
499
+ role: "group",
500
+ "aria-label": `${label} series`,
501
+ className: "-mx-2 flex min-w-0 flex-wrap gap-x-1 gap-y-0.5",
502
+ children: series.map((line, at) => /* @__PURE__ */ jsxs("button", {
503
+ type: "button",
504
+ "data-slot": "line-chart-toggle",
505
+ "aria-pressed": !hidden.includes(line.key),
506
+ onClick: () => toggle(line.key),
507
+ style: { "--series": colorOf(line, at) },
508
+ className: "chart-legend-toggle",
509
+ children: [/* @__PURE__ */ jsx("span", {
510
+ "aria-hidden": "true",
511
+ "data-dashed": line.dashed || void 0,
512
+ className: "chart-swatch"
513
+ }), /* @__PURE__ */ jsx("span", {
514
+ className: "chart-toggle-label",
515
+ children: line.label
516
+ })]
517
+ }, line.key))
518
+ }) : null,
519
+ /* @__PURE__ */ jsxs("div", {
520
+ "data-slot": "line-chart-chart",
521
+ "data-scrubbing": scrubbing || void 0,
522
+ "data-loading": loading || void 0,
523
+ "data-drawn": drawn || void 0,
524
+ className: "line-chart-frame",
525
+ children: [
526
+ /* @__PURE__ */ jsxs("div", {
527
+ ref: plot,
528
+ "data-slot": "line-chart-plot",
529
+ role: "slider",
530
+ tabIndex: empty ? -1 : 0,
531
+ "aria-label": `${label}, explore by ${categoryLabel.toLowerCase()}`,
532
+ "aria-orientation": "horizontal",
533
+ "aria-valuemin": 1,
534
+ "aria-valuemax": Math.max(1, data.length),
535
+ "aria-valuenow": (index ?? last) + 1,
536
+ "aria-valuetext": valueText,
537
+ onPointerDown,
538
+ onPointerMove,
539
+ onPointerUp: (event) => {
540
+ if (event.pointerType !== "mouse") setActive(null);
541
+ },
542
+ onPointerCancel: () => setActive(null),
543
+ onPointerLeave: (event) => {
544
+ if (event.pointerType === "mouse") setActive(null);
545
+ },
546
+ onKeyDown,
547
+ onBlur: () => setActive(null),
548
+ onFocus: (event) => {
549
+ if (event.currentTarget.matches(":focus-visible") && !empty) setActive((current) => current ?? last);
550
+ },
551
+ className: "line-chart-plot",
552
+ style: { height },
553
+ children: [
554
+ /* @__PURE__ */ jsxs("svg", {
555
+ ref: svg,
556
+ width: "100%",
557
+ height,
558
+ "aria-hidden": "true",
559
+ focusable: "false",
560
+ className: "block overflow-visible",
561
+ children: [
562
+ /* @__PURE__ */ jsx("defs", { children: /* @__PURE__ */ jsx("clipPath", {
563
+ id: `${uid}-draw`,
564
+ clipPathUnits: "userSpaceOnUse",
565
+ children: /* @__PURE__ */ jsx("rect", {
566
+ className: "line-chart-reveal",
567
+ x: -8,
568
+ y: -16,
569
+ height: height + 32,
570
+ style: { width: drawn ? plotWidth + 16 : 0 }
571
+ })
572
+ }) }),
573
+ steady.ticks.slice(1).map((value) => /* @__PURE__ */ jsx("line", {
574
+ "data-grid": value,
575
+ className: "line-chart-grid",
576
+ x1: 0,
577
+ x2: "100%"
578
+ }, value)),
579
+ /* @__PURE__ */ jsx("line", {
580
+ className: "line-chart-baseline",
581
+ x1: 0,
582
+ x2: "100%",
583
+ y1: height - .5,
584
+ y2: height - .5
585
+ }),
586
+ drawnReferences.map((reference) => typeof reference.value === "number" ? /* @__PURE__ */ jsx("line", {
587
+ "data-reference": reference.key,
588
+ "data-reference-value": reference.value,
589
+ className: "line-chart-reference",
590
+ x1: 0,
591
+ x2: "100%"
592
+ }, reference.key) : /* @__PURE__ */ jsx("line", {
593
+ "data-reference": reference.key,
594
+ "data-reference-at": referenceAt(reference),
595
+ className: "line-chart-reference",
596
+ y1: 8,
597
+ y2: height
598
+ }, reference.key)),
599
+ /* @__PURE__ */ jsx("line", {
600
+ "data-part": "crosshair",
601
+ className: "line-chart-crosshair",
602
+ y1: 8,
603
+ y2: height
604
+ }),
605
+ /* @__PURE__ */ jsx("g", {
606
+ className: "line-chart-series",
607
+ clipPath: `url(#${uid}-draw)`,
608
+ children: series.map((line, at) => /* @__PURE__ */ jsxs("g", {
609
+ "data-series": line.key,
610
+ style: { "--series": colorOf(line, at) },
611
+ children: [line.area ?? at === 0 ? /* @__PURE__ */ jsx("path", {
612
+ "data-part": "area",
613
+ className: "line-chart-area"
614
+ }) : null, /* @__PURE__ */ jsx("path", {
615
+ "data-part": "line",
616
+ "data-dashed": line.dashed || void 0,
617
+ className: "line-chart-line"
618
+ })]
619
+ }, line.key))
620
+ }),
621
+ series.map((line, at) => /* @__PURE__ */ jsx("circle", {
622
+ "data-dot": line.key,
623
+ "data-hidden": hidden.includes(line.key) || void 0,
624
+ r: 4,
625
+ className: "line-chart-dot",
626
+ style: { "--series": colorOf(line, at) }
627
+ }, line.key))
628
+ ]
629
+ }),
630
+ drawnReferences.map((reference) => /* @__PURE__ */ jsx("span", {
631
+ "aria-hidden": "true",
632
+ "data-slot": "line-chart-reference-label",
633
+ "data-reference-label": reference.key,
634
+ "data-reference-value": typeof reference.value === "number" ? reference.value : void 0,
635
+ "data-reference-at": typeof reference.value === "number" ? void 0 : referenceAt(reference),
636
+ "data-axis": typeof reference.value === "number" ? "value" : "category",
637
+ className: "line-chart-reference-label",
638
+ children: reference.label
639
+ }, reference.key)),
640
+ /* @__PURE__ */ jsxs("div", {
641
+ ref: tip,
642
+ "aria-hidden": "true",
643
+ "data-slot": "line-chart-tooltip",
644
+ className: "line-chart-tooltip",
645
+ children: [/* @__PURE__ */ jsx("p", {
646
+ className: "m-0 mb-0.5 whitespace-nowrap text-xs tabular-nums text-text-secondary",
647
+ children: shown?.label ?? ""
648
+ }), visible.map((line) => /* @__PURE__ */ jsxs("p", {
649
+ className: "m-0 flex min-w-0 items-center gap-2 text-sm",
650
+ style: { "--series": colorOf(line, series.indexOf(line)) },
651
+ children: [
652
+ /* @__PURE__ */ jsx("span", {
653
+ "data-dashed": line.dashed || void 0,
654
+ className: "chart-tip-swatch"
655
+ }),
656
+ /* @__PURE__ */ jsx("span", {
657
+ className: "min-w-0 flex-1 truncate text-text-secondary",
658
+ children: line.label
659
+ }),
660
+ /* @__PURE__ */ jsx("span", {
661
+ className: "ms-2 flex-none whitespace-nowrap font-medium tabular-nums text-foreground",
662
+ children: shown ? format(read(shown, line.key), line) : format(0, line)
663
+ })
664
+ ]
665
+ }, line.key))]
666
+ }),
667
+ (empty || allHidden) && !loading ? /* @__PURE__ */ jsx("p", {
668
+ className: "absolute inset-0 m-0 grid place-items-center text-sm text-muted-foreground pointer-events-none motion-safe:animate-fade-in",
669
+ children: empty ? emptyLabel : "Choose a series to show"
670
+ }) : null,
671
+ loading && empty ? /* @__PURE__ */ jsx("span", {
672
+ "aria-hidden": "true",
673
+ className: "chart-skeleton"
674
+ }) : null
675
+ ]
676
+ }),
677
+ /* @__PURE__ */ jsx("div", {
678
+ ref: gutter,
679
+ "aria-hidden": "true",
680
+ className: "relative min-w-0 [grid-area:1/2]",
681
+ children: steady.ticks.map((value) => /* @__PURE__ */ jsx("span", {
682
+ "data-tick": value,
683
+ className: "line-chart-tick motion-safe:animate-fade-in",
684
+ children: /* @__PURE__ */ jsx("span", {
685
+ className: "block -translate-y-1/2 text-xs leading-none tabular-nums text-muted-foreground",
686
+ children: formatTick(value)
687
+ })
688
+ }, value))
689
+ }),
690
+ /* @__PURE__ */ jsx("div", {
691
+ "aria-hidden": "true",
692
+ className: "relative min-w-0 [grid-area:2/1]",
693
+ children: picks.map((at) => {
694
+ const share = last > 0 ? at / last : .5;
695
+ return /* @__PURE__ */ jsx("span", {
696
+ className: "absolute top-2 whitespace-nowrap text-xs leading-none tabular-nums text-muted-foreground motion-safe:animate-fade-in",
697
+ style: {
698
+ left: `${share * 100}%`,
699
+ translate: `${-share * 100}% 0`
700
+ },
701
+ children: data[at].axisLabel
702
+ }, `${data[at].key}:${data[at].axisLabel}`);
703
+ })
704
+ })
705
+ ]
706
+ }),
707
+ /* @__PURE__ */ jsx("p", {
708
+ className: "sr-only",
709
+ children: summary
710
+ }),
711
+ empty ? null : /* @__PURE__ */ jsx("div", {
712
+ className: "sr-only",
713
+ children: /* @__PURE__ */ jsxs("table", { children: [
714
+ /* @__PURE__ */ jsx("caption", { children: label }),
715
+ /* @__PURE__ */ jsx("thead", { children: /* @__PURE__ */ jsxs("tr", { children: [/* @__PURE__ */ jsx("th", {
716
+ scope: "col",
717
+ children: categoryLabel
718
+ }), series.map((line) => /* @__PURE__ */ jsx("th", {
719
+ scope: "col",
720
+ children: line.label
721
+ }, line.key))] }) }),
722
+ /* @__PURE__ */ jsx("tbody", { children: data.map((item) => /* @__PURE__ */ jsxs("tr", { children: [/* @__PURE__ */ jsx("th", {
723
+ scope: "row",
724
+ children: item.label
725
+ }), series.map((line) => /* @__PURE__ */ jsx("td", { children: format(read(item, line.key), line) }, line.key))] }, item.key)) })
726
+ ] })
727
+ }),
728
+ /* @__PURE__ */ jsx("p", {
729
+ className: "sr-only",
730
+ "aria-live": "polite",
731
+ "aria-atomic": "true",
732
+ children: loading ? "Loading" : ""
733
+ })
734
+ ]
735
+ });
736
+ });
737
+ //#endregion
738
+ export { LINE_CHART_DRAW_MS, LineChart };
739
+
740
+ //# sourceMappingURL=line-chart.js.map