@seekalfred/primitives 0.6.0 → 0.7.1

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 (322) hide show
  1. package/README.md +19 -11
  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 +5 -1
  8. package/dist/alert/alert.js +68 -7
  9. package/dist/alert/alert.js.map +1 -1
  10. package/dist/alert-dialog/alert-dialog.d.ts +45 -18
  11. package/dist/alert-dialog/alert-dialog.js +128 -9
  12. package/dist/alert-dialog/alert-dialog.js.map +1 -1
  13. package/dist/alert-dialog/index.d.ts +2 -2
  14. package/dist/alert-dialog/index.js +2 -2
  15. package/dist/animated-counter/animated-counter.d.ts +38 -0
  16. package/dist/animated-counter/animated-counter.js +230 -0
  17. package/dist/animated-counter/animated-counter.js.map +1 -0
  18. package/dist/animated-counter/index.d.ts +2 -0
  19. package/dist/animated-counter/index.js +2 -0
  20. package/dist/announcement-bar/announcement-bar.d.ts +67 -0
  21. package/dist/announcement-bar/announcement-bar.js +364 -0
  22. package/dist/announcement-bar/announcement-bar.js.map +1 -0
  23. package/dist/announcement-bar/index.d.ts +2 -0
  24. package/dist/announcement-bar/index.js +2 -0
  25. package/dist/badge/badge.d.ts +1 -1
  26. package/dist/bar-chart/bar-chart.d.ts +51 -0
  27. package/dist/bar-chart/bar-chart.js +565 -0
  28. package/dist/bar-chart/bar-chart.js.map +1 -0
  29. package/dist/bar-chart/index.d.ts +2 -0
  30. package/dist/bar-chart/index.js +2 -0
  31. package/dist/breadcrumb/breadcrumb.d.ts +2 -2
  32. package/dist/breadcrumb/breadcrumb.js +12 -3
  33. package/dist/breadcrumb/breadcrumb.js.map +1 -1
  34. package/dist/brush-chart/brush-chart.d.ts +64 -0
  35. package/dist/brush-chart/brush-chart.js +1056 -0
  36. package/dist/brush-chart/brush-chart.js.map +1 -0
  37. package/dist/brush-chart/index.d.ts +2 -0
  38. package/dist/brush-chart/index.js +2 -0
  39. package/dist/button/button.d.ts +2 -2
  40. package/dist/button/button.js +31 -21
  41. package/dist/button/button.js.map +1 -1
  42. package/dist/button-group/button-group.js +3 -4
  43. package/dist/button-group/button-group.js.map +1 -1
  44. package/dist/card/card.js +1 -1
  45. package/dist/card/card.js.map +1 -1
  46. package/dist/card-stack/card-stack.d.ts +54 -0
  47. package/dist/card-stack/card-stack.js +492 -0
  48. package/dist/card-stack/card-stack.js.map +1 -0
  49. package/dist/card-stack/index.d.ts +2 -0
  50. package/dist/card-stack/index.js +2 -0
  51. package/dist/carousel/carousel.d.ts +56 -0
  52. package/dist/carousel/carousel.js +389 -0
  53. package/dist/carousel/carousel.js.map +1 -0
  54. package/dist/carousel/index.d.ts +2 -0
  55. package/dist/carousel/index.js +2 -0
  56. package/dist/checkbox/checkbox.js +4 -4
  57. package/dist/checkbox/checkbox.js.map +1 -1
  58. package/dist/chip-group/chip-group.d.ts +37 -0
  59. package/dist/chip-group/chip-group.js +148 -0
  60. package/dist/chip-group/chip-group.js.map +1 -0
  61. package/dist/chip-group/index.d.ts +2 -0
  62. package/dist/chip-group/index.js +2 -0
  63. package/dist/countdown/countdown.d.ts +45 -0
  64. package/dist/countdown/countdown.js +298 -0
  65. package/dist/countdown/countdown.js.map +1 -0
  66. package/dist/countdown/index.d.ts +2 -0
  67. package/dist/countdown/index.js +2 -0
  68. package/dist/date-picker/picker-parts.js +1 -1
  69. package/dist/date-picker/picker-parts.js.map +1 -1
  70. package/dist/dialog/dialog.js +1 -1
  71. package/dist/dialog/dialog.js.map +1 -1
  72. package/dist/donut-chart/donut-chart.d.ts +64 -0
  73. package/dist/donut-chart/donut-chart.js +576 -0
  74. package/dist/donut-chart/donut-chart.js.map +1 -0
  75. package/dist/donut-chart/index.d.ts +2 -0
  76. package/dist/donut-chart/index.js +2 -0
  77. package/dist/empty-state/empty-state.d.ts +21 -10
  78. package/dist/empty-state/empty-state.js +32 -26
  79. package/dist/empty-state/empty-state.js.map +1 -1
  80. package/dist/empty-state/index.d.ts +2 -2
  81. package/dist/empty-state/index.js +2 -2
  82. package/dist/file-drop-zone/file-drop-zone.js +1 -1
  83. package/dist/file-drop-zone/file-drop-zone.js.map +1 -1
  84. package/dist/filter-bar/filter-bar.d.ts +47 -26
  85. package/dist/filter-bar/filter-bar.js +272 -156
  86. package/dist/filter-bar/filter-bar.js.map +1 -1
  87. package/dist/gauge/gauge.d.ts +45 -0
  88. package/dist/gauge/gauge.js +219 -0
  89. package/dist/gauge/gauge.js.map +1 -0
  90. package/dist/gauge/index.d.ts +2 -0
  91. package/dist/gauge/index.js +2 -0
  92. package/dist/in-view-title/in-view-title.d.ts +33 -0
  93. package/dist/in-view-title/in-view-title.js +119 -0
  94. package/dist/in-view-title/in-view-title.js.map +1 -0
  95. package/dist/in-view-title/index.d.ts +2 -0
  96. package/dist/in-view-title/index.js +2 -0
  97. package/dist/index.d.ts +49 -6
  98. package/dist/index.js +48 -8
  99. package/dist/lib/cn.js +11 -1
  100. package/dist/lib/cn.js.map +1 -1
  101. package/dist/lib/field-message.js +28 -10
  102. package/dist/lib/field-message.js.map +1 -1
  103. package/dist/lib/field-surface.js +9 -8
  104. package/dist/lib/field-surface.js.map +1 -1
  105. package/dist/lib/flag-emoji.js +50 -0
  106. package/dist/lib/flag-emoji.js.map +1 -0
  107. package/dist/lib/flip.js +11 -3
  108. package/dist/lib/flip.js.map +1 -1
  109. package/dist/lib/menu-highlight.js +64 -0
  110. package/dist/lib/menu-highlight.js.map +1 -0
  111. package/dist/lib/motion.js +9 -2
  112. package/dist/lib/motion.js.map +1 -1
  113. package/dist/lib/rolling-value.js +1 -1
  114. package/dist/lib/rolling-value.js.map +1 -1
  115. package/dist/lib/spring-tween.js +500 -0
  116. package/dist/lib/spring-tween.js.map +1 -0
  117. package/dist/lib/swap-text.js +3 -1
  118. package/dist/lib/swap-text.js.map +1 -1
  119. package/dist/line-chart/index.d.ts +2 -0
  120. package/dist/line-chart/index.js +2 -0
  121. package/dist/line-chart/line-chart.d.ts +76 -0
  122. package/dist/line-chart/line-chart.js +611 -0
  123. package/dist/line-chart/line-chart.js.map +1 -0
  124. package/dist/mention-input/index.d.ts +2 -0
  125. package/dist/mention-input/index.js +2 -0
  126. package/dist/mention-input/mention-input.d.ts +98 -0
  127. package/dist/mention-input/mention-input.js +576 -0
  128. package/dist/mention-input/mention-input.js.map +1 -0
  129. package/dist/menu/menu.d.ts +2 -0
  130. package/dist/menu/menu.js +23 -12
  131. package/dist/menu/menu.js.map +1 -1
  132. package/dist/money-input/index.d.ts +2 -0
  133. package/dist/money-input/index.js +2 -0
  134. package/dist/money-input/money-input.d.ts +65 -0
  135. package/dist/money-input/money-input.js +607 -0
  136. package/dist/money-input/money-input.js.map +1 -0
  137. package/dist/morph-select/index.d.ts +2 -0
  138. package/dist/morph-select/index.js +2 -0
  139. package/dist/morph-select/morph-select.d.ts +71 -0
  140. package/dist/morph-select/morph-select.js +693 -0
  141. package/dist/morph-select/morph-select.js.map +1 -0
  142. package/dist/multi-select/index.d.ts +2 -0
  143. package/dist/multi-select/index.js +2 -0
  144. package/dist/multi-select/multi-select.d.ts +36 -0
  145. package/dist/multi-select/multi-select.js +152 -0
  146. package/dist/multi-select/multi-select.js.map +1 -0
  147. package/dist/number-field/index.d.ts +2 -0
  148. package/dist/number-field/index.js +2 -0
  149. package/dist/number-field/number-field.d.ts +42 -0
  150. package/dist/number-field/number-field.js +199 -0
  151. package/dist/number-field/number-field.js.map +1 -0
  152. package/dist/onboarding-checklist/index.d.ts +2 -0
  153. package/dist/onboarding-checklist/index.js +2 -0
  154. package/dist/onboarding-checklist/onboarding-checklist.d.ts +55 -0
  155. package/dist/onboarding-checklist/onboarding-checklist.js +577 -0
  156. package/dist/onboarding-checklist/onboarding-checklist.js.map +1 -0
  157. package/dist/password-field/password-field.js +2 -2
  158. package/dist/password-field/password-field.js.map +1 -1
  159. package/dist/phone-input/index.d.ts +3 -0
  160. package/dist/phone-input/index.js +3 -0
  161. package/dist/phone-input/phone-countries.d.ts +29 -0
  162. package/dist/phone-input/phone-countries.js +170 -0
  163. package/dist/phone-input/phone-countries.js.map +1 -0
  164. package/dist/phone-input/phone-input.d.ts +66 -0
  165. package/dist/phone-input/phone-input.js +440 -0
  166. package/dist/phone-input/phone-input.js.map +1 -0
  167. package/dist/popover/popover.d.ts +12 -0
  168. package/dist/popover/popover.js +31 -7
  169. package/dist/popover/popover.js.map +1 -1
  170. package/dist/progress/progress.js +1 -1
  171. package/dist/radio-group/radio-group.js +1 -1
  172. package/dist/radio-group/radio-group.js.map +1 -1
  173. package/dist/reactions/index.d.ts +2 -0
  174. package/dist/reactions/index.js +2 -0
  175. package/dist/reactions/reactions.d.ts +50 -0
  176. package/dist/reactions/reactions.js +315 -0
  177. package/dist/reactions/reactions.js.map +1 -0
  178. package/dist/rich-text-editor/index.d.ts +3 -0
  179. package/dist/rich-text-editor/index.js +2 -0
  180. package/dist/rich-text-editor/rich-text-editor.d.ts +70 -0
  181. package/dist/rich-text-editor/rich-text-editor.js +909 -0
  182. package/dist/rich-text-editor/rich-text-editor.js.map +1 -0
  183. package/dist/rich-text-editor/rich-text-engine.d.ts +16 -0
  184. package/dist/rich-text-editor/rich-text-engine.js +366 -0
  185. package/dist/rich-text-editor/rich-text-engine.js.map +1 -0
  186. package/dist/rich-text-editor/rich-text-html.js +174 -0
  187. package/dist/rich-text-editor/rich-text-html.js.map +1 -0
  188. package/dist/rich-text-editor/rich-text-icons.js +43 -0
  189. package/dist/rich-text-editor/rich-text-icons.js.map +1 -0
  190. package/dist/ridgeline/index.d.ts +2 -0
  191. package/dist/ridgeline/index.js +2 -0
  192. package/dist/ridgeline/ridgeline.d.ts +55 -0
  193. package/dist/ridgeline/ridgeline.js +701 -0
  194. package/dist/ridgeline/ridgeline.js.map +1 -0
  195. package/dist/scroll-area/index.d.ts +2 -2
  196. package/dist/scroll-area/index.js +2 -2
  197. package/dist/scroll-area/scroll-area.d.ts +68 -31
  198. package/dist/scroll-area/scroll-area.js +208 -59
  199. package/dist/scroll-area/scroll-area.js.map +1 -1
  200. package/dist/scrub-input/evaluate.d.ts +14 -0
  201. package/dist/scrub-input/evaluate.js +72 -0
  202. package/dist/scrub-input/evaluate.js.map +1 -0
  203. package/dist/scrub-input/index.d.ts +3 -0
  204. package/dist/scrub-input/index.js +3 -0
  205. package/dist/scrub-input/scrub-input.d.ts +74 -0
  206. package/dist/scrub-input/scrub-input.js +486 -0
  207. package/dist/scrub-input/scrub-input.js.map +1 -0
  208. package/dist/search-field/search-field.d.ts +2 -1
  209. package/dist/search-field/search-field.js +4 -4
  210. package/dist/search-field/search-field.js.map +1 -1
  211. package/dist/select/select.d.ts +3 -1
  212. package/dist/select/select.js +20 -8
  213. package/dist/select/select.js.map +1 -1
  214. package/dist/separator/separator.d.ts +1 -1
  215. package/dist/sheet/sheet.js +2 -1
  216. package/dist/sheet/sheet.js.map +1 -1
  217. package/dist/shortcut-recorder/index.d.ts +3 -0
  218. package/dist/shortcut-recorder/index.js +3 -0
  219. package/dist/shortcut-recorder/shortcut-model.d.ts +27 -0
  220. package/dist/shortcut-recorder/shortcut-model.js +206 -0
  221. package/dist/shortcut-recorder/shortcut-model.js.map +1 -0
  222. package/dist/shortcut-recorder/shortcut-recorder.d.ts +93 -0
  223. package/dist/shortcut-recorder/shortcut-recorder.js +489 -0
  224. package/dist/shortcut-recorder/shortcut-recorder.js.map +1 -0
  225. package/dist/slider/index.d.ts +2 -2
  226. package/dist/slider/slider.d.ts +46 -14
  227. package/dist/slider/slider.js +151 -67
  228. package/dist/slider/slider.js.map +1 -1
  229. package/dist/slope-chart/index.d.ts +2 -0
  230. package/dist/slope-chart/index.js +2 -0
  231. package/dist/slope-chart/slope-chart.d.ts +54 -0
  232. package/dist/slope-chart/slope-chart.js +568 -0
  233. package/dist/slope-chart/slope-chart.js.map +1 -0
  234. package/dist/sparkline/index.d.ts +2 -0
  235. package/dist/sparkline/index.js +2 -0
  236. package/dist/sparkline/sparkline.d.ts +46 -0
  237. package/dist/sparkline/sparkline.js +390 -0
  238. package/dist/sparkline/sparkline.js.map +1 -0
  239. package/dist/split-bar/index.d.ts +2 -0
  240. package/dist/split-bar/index.js +2 -0
  241. package/dist/split-bar/split-bar.d.ts +62 -0
  242. package/dist/split-bar/split-bar.js +513 -0
  243. package/dist/split-bar/split-bar.js.map +1 -0
  244. package/dist/split-button/split-button.d.ts +1 -1
  245. package/dist/split-button/split-button.js +12 -11
  246. package/dist/split-button/split-button.js.map +1 -1
  247. package/dist/stat-card/index.d.ts +2 -2
  248. package/dist/stat-card/index.js +2 -2
  249. package/dist/stat-card/stat-card.d.ts +24 -4
  250. package/dist/stat-card/stat-card.js +114 -17
  251. package/dist/stat-card/stat-card.js.map +1 -1
  252. package/dist/stepper/index.d.ts +2 -0
  253. package/dist/stepper/index.js +2 -0
  254. package/dist/stepper/stepper.d.ts +51 -0
  255. package/dist/stepper/stepper.js +215 -0
  256. package/dist/stepper/stepper.js.map +1 -0
  257. package/dist/streamgraph/index.d.ts +2 -0
  258. package/dist/streamgraph/index.js +2 -0
  259. package/dist/streamgraph/streamgraph.d.ts +70 -0
  260. package/dist/streamgraph/streamgraph.js +613 -0
  261. package/dist/streamgraph/streamgraph.js.map +1 -0
  262. package/dist/styles.css +1 -1
  263. package/dist/swipe-actions/index.d.ts +2 -0
  264. package/dist/swipe-actions/index.js +2 -0
  265. package/dist/swipe-actions/swipe-actions.d.ts +67 -0
  266. package/dist/swipe-actions/swipe-actions.js +552 -0
  267. package/dist/swipe-actions/swipe-actions.js.map +1 -0
  268. package/dist/switch/switch.js +2 -2
  269. package/dist/switch/switch.js.map +1 -1
  270. package/dist/table/index.d.ts +2 -2
  271. package/dist/table/index.js +2 -2
  272. package/dist/table/table.d.ts +56 -4
  273. package/dist/table/table.js +340 -165
  274. package/dist/table/table.js.map +1 -1
  275. package/dist/tabs/tabs.js +2 -2
  276. package/dist/tabs/tabs.js.map +1 -1
  277. package/dist/tag-input/index.d.ts +2 -0
  278. package/dist/tag-input/index.js +2 -0
  279. package/dist/tag-input/tag-input.d.ts +40 -0
  280. package/dist/tag-input/tag-input.js +269 -0
  281. package/dist/tag-input/tag-input.js.map +1 -0
  282. package/dist/text-morph/index.d.ts +2 -0
  283. package/dist/text-morph/index.js +2 -0
  284. package/dist/text-morph/text-morph.d.ts +23 -0
  285. package/dist/text-morph/text-morph.js +21 -0
  286. package/dist/text-morph/text-morph.js.map +1 -0
  287. package/dist/text-reveal/index.d.ts +2 -0
  288. package/dist/text-reveal/index.js +2 -0
  289. package/dist/text-reveal/text-reveal.d.ts +27 -0
  290. package/dist/text-reveal/text-reveal.js +51 -0
  291. package/dist/text-reveal/text-reveal.js.map +1 -0
  292. package/dist/text-shimmer/index.d.ts +2 -0
  293. package/dist/text-shimmer/index.js +2 -0
  294. package/dist/text-shimmer/text-shimmer.d.ts +29 -0
  295. package/dist/text-shimmer/text-shimmer.js +29 -0
  296. package/dist/text-shimmer/text-shimmer.js.map +1 -0
  297. package/dist/time-picker/time-picker.js +2 -2
  298. package/dist/time-picker/time-picker.js.map +1 -1
  299. package/dist/toast/index.d.ts +2 -2
  300. package/dist/toast/index.js +2 -2
  301. package/dist/toast/toast.d.ts +6 -0
  302. package/dist/toast/toast.js +82 -40
  303. package/dist/toast/toast.js.map +1 -1
  304. package/dist/tooltip/tooltip.d.ts +9 -2
  305. package/dist/tooltip/tooltip.js +7 -7
  306. package/dist/tooltip/tooltip.js.map +1 -1
  307. package/dist/treemap/index.d.ts +2 -0
  308. package/dist/treemap/index.js +2 -0
  309. package/dist/treemap/treemap.d.ts +53 -0
  310. package/dist/treemap/treemap.js +699 -0
  311. package/dist/treemap/treemap.js.map +1 -0
  312. package/dist/usage-meter/index.d.ts +2 -0
  313. package/dist/usage-meter/index.js +2 -0
  314. package/dist/usage-meter/usage-meter.d.ts +50 -0
  315. package/dist/usage-meter/usage-meter.js +440 -0
  316. package/dist/usage-meter/usage-meter.js.map +1 -0
  317. package/dist/waffle-chart/index.d.ts +2 -0
  318. package/dist/waffle-chart/index.js +2 -0
  319. package/dist/waffle-chart/waffle-chart.d.ts +57 -0
  320. package/dist/waffle-chart/waffle-chart.js +426 -0
  321. package/dist/waffle-chart/waffle-chart.js.map +1 -0
  322. package/package.json +165 -3
@@ -0,0 +1,701 @@
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 { REVEAL, SWELL, tween } from "../lib/spring-tween.js";
6
+ import { forwardRef, useEffect, useMemo, useRef, useState } from "react";
7
+ import { Fragment as Fragment$1, jsx, jsxs } from "react/jsx-runtime";
8
+ //#region src/ridgeline/ridgeline.tsx
9
+ /** Points along each ridge, the axis strip, the gap between the tooltip and what it describes, and how far the lifted ridge rises, in pixels. */
10
+ const SAMPLES = 96;
11
+ const AXIS = 28;
12
+ const TIP = 14;
13
+ const LIFT = 6;
14
+ const GROUPED = new Intl.NumberFormat("en-US", { maximumFractionDigits: 1 });
15
+ const PERCENT = new Intl.NumberFormat("en-US", {
16
+ style: "percent",
17
+ maximumFractionDigits: 0
18
+ });
19
+ const clamp = (value, low, high) => Math.min(high, Math.max(low, value));
20
+ const mix = (a, b, t) => a + (b - a) * t;
21
+ function quantile(sorted, q) {
22
+ if (!sorted.length) return 0;
23
+ const at = (sorted.length - 1) * q;
24
+ const low = Math.floor(at);
25
+ const high = Math.ceil(at);
26
+ return sorted[low] + (sorted[high] - sorted[low]) * (at - low);
27
+ }
28
+ function statsOf(values) {
29
+ const sorted = values.filter(Number.isFinite).sort((a, b) => a - b);
30
+ return {
31
+ sorted,
32
+ n: sorted.length,
33
+ min: sorted[0] ?? 0,
34
+ max: sorted[sorted.length - 1] ?? 0,
35
+ q1: quantile(sorted, .25),
36
+ median: quantile(sorted, .5),
37
+ q3: quantile(sorted, .75)
38
+ };
39
+ }
40
+ /** Silverman's rule of thumb for the smoothing of a Gaussian kernel. */
41
+ function silverman(stats) {
42
+ if (stats.n < 2) return 1;
43
+ const mean = stats.sorted.reduce((sum, value) => sum + value, 0) / stats.n;
44
+ const sd = Math.sqrt(stats.sorted.reduce((sum, value) => sum + (value - mean) ** 2, 0) / (stats.n - 1));
45
+ const spread = Math.min(sd, (stats.q3 - stats.q1) / 1.34 || sd);
46
+ return Math.max(1e-6, .9 * (spread || 1) * Math.pow(stats.n, -.2));
47
+ }
48
+ function niceStep(span, count) {
49
+ const raw = span / Math.max(1, count) || 1;
50
+ const power = Math.pow(10, Math.floor(Math.log10(raw)));
51
+ const unit = raw / power;
52
+ return (unit >= 5 ? 5 : unit >= 2 ? 2 : 1) * power;
53
+ }
54
+ /** Samples a Gaussian kernel density across the domain. */
55
+ function density(stats, lo, hi, bandwidth) {
56
+ const xs = [];
57
+ const ys = [];
58
+ const norm = 1 / (Math.max(1, stats.n) * bandwidth * Math.sqrt(2 * Math.PI));
59
+ for (let i = 0; i < SAMPLES; i++) {
60
+ const x = lo + (hi - lo) * i / 95;
61
+ let sum = 0;
62
+ for (const value of stats.sorted) {
63
+ const u = (x - value) / bandwidth;
64
+ if (u > -5 && u < 5) sum += Math.exp(-.5 * u * u);
65
+ }
66
+ xs.push(x);
67
+ ys.push(sum * norm);
68
+ }
69
+ return {
70
+ xs,
71
+ ys
72
+ };
73
+ }
74
+ const heightAt = (shape, x) => {
75
+ const { xs, ys } = shape;
76
+ if (x <= xs[0] || x >= xs[xs.length - 1]) return 0;
77
+ let i = 1;
78
+ while (i < xs.length - 1 && xs[i] < x) i++;
79
+ const t = (x - xs[i - 1]) / (xs[i] - xs[i - 1] || 1);
80
+ return mix(ys[i - 1], ys[i], t);
81
+ };
82
+ /** Ridge tone: one hue, the first series colour, from a light tint (low median) to full strength (high median), so the scale never passes through a muddy middle. */
83
+ const toneOf = (t) => `color-mix(in oklab, var(--color-chart-1) ${Math.round(38 + clamp(t, 0, 1) * 62)}%, var(--color-surface))`;
84
+ const Ridgeline = forwardRef(function Ridgeline({ series, label, unit = "", formatValue, domain, overlap = 2.4, rowHeight = 30, bandwidth, tint = true, active, defaultActive = null, onActiveChange, emptyLabel = "No data yet", className }, ref) {
85
+ const figure = useRef(null);
86
+ const refs = useMemo(() => mergeRefs(ref, figure), [ref]);
87
+ const plot = useRef(null);
88
+ const tip = useRef(null);
89
+ const cross = useRef(null);
90
+ const format = (value) => formatValue ? formatValue(value) : `${GROUPED.format(value).replace("-", "−")}${unit}`;
91
+ const [width, setWidth] = useState(0);
92
+ useIsomorphicLayoutEffect(() => {
93
+ const node = plot.current;
94
+ if (!node || typeof ResizeObserver === "undefined") return;
95
+ const observer = new ResizeObserver(() => setWidth(node.clientWidth));
96
+ observer.observe(node);
97
+ setWidth(node.clientWidth);
98
+ return () => observer.disconnect();
99
+ }, []);
100
+ const signature = JSON.stringify([
101
+ series,
102
+ domain,
103
+ bandwidth
104
+ ]);
105
+ const model = useMemo(() => {
106
+ const stats = series.map((entry) => statsOf(entry.values));
107
+ const widths = stats.map((entry) => bandwidth ?? silverman(entry));
108
+ const filled = stats.map((entry, index) => ({
109
+ entry,
110
+ room: 2.5 * widths[index]
111
+ })).filter(({ entry }) => entry.n);
112
+ let lo = domain?.[0] ?? Math.min(...filled.map(({ entry, room }) => entry.min - room));
113
+ let hi = domain?.[1] ?? Math.max(...filled.map(({ entry, room }) => entry.max + room));
114
+ if (!Number.isFinite(lo) || !Number.isFinite(hi) || lo === hi) {
115
+ lo = 0;
116
+ hi = 1;
117
+ }
118
+ if (!domain) {
119
+ const step = niceStep(hi - lo, 5);
120
+ lo = Math.floor(lo / step) * step;
121
+ hi = Math.ceil(hi / step) * step;
122
+ }
123
+ const curves = stats.map((entry, index) => entry.n ? density(entry, lo, hi, widths[index]) : {
124
+ xs: Array.from({ length: SAMPLES }, (_, i) => lo + (hi - lo) * i / 95),
125
+ ys: new Array(SAMPLES).fill(0)
126
+ });
127
+ const peak = Math.max(1e-9, ...curves.flatMap((curve) => curve.ys));
128
+ const shapes = new Map(series.map((entry, index) => {
129
+ const curve = curves[index];
130
+ const stat = stats[index];
131
+ return [entry.id, {
132
+ xs: curve.xs,
133
+ ys: curve.ys.map((y) => y / peak),
134
+ row: index,
135
+ q1: stat.q1,
136
+ median: stat.median,
137
+ q3: stat.q3
138
+ }];
139
+ }));
140
+ return {
141
+ stats: new Map(series.map((entry, index) => [entry.id, stats[index]])),
142
+ shapes,
143
+ lo,
144
+ hi
145
+ };
146
+ }, [signature]);
147
+ const [ownActive, setOwnActive] = useState(defaultActive);
148
+ const current = active !== void 0 ? active : ownActive;
149
+ const setCurrent = (id) => {
150
+ if (active === void 0) setOwnActive(id);
151
+ if (id !== current) onActiveChange?.(id);
152
+ };
153
+ const [cursor, setCursor] = useState(null);
154
+ const gutter = width > 0 && width < 420 ? 36 : 52;
155
+ const top = Math.ceil((overlap - 1) * rowHeight) + LIFT + 8;
156
+ const height = top + series.length * rowHeight + AXIS;
157
+ const plotWidth = Math.max(40, width - gutter - 4);
158
+ const baselineOf = (row) => top + (row + 1) * rowHeight;
159
+ const drawn = useRef({
160
+ shapes: /* @__PURE__ */ new Map(),
161
+ lo: 0,
162
+ hi: 1
163
+ });
164
+ const geometry = useRef({
165
+ gutter,
166
+ plotWidth,
167
+ rowHeight,
168
+ overlap,
169
+ top,
170
+ current
171
+ });
172
+ const xOf = (value) => {
173
+ const d = drawn.current;
174
+ return gutter + (value - d.lo) / (d.hi - d.lo || 1) * plotWidth;
175
+ };
176
+ const paint = () => {
177
+ const root = plot.current;
178
+ if (!root) return;
179
+ const d = drawn.current;
180
+ const g = geometry.current;
181
+ const sx = (value) => g.gutter + (value - d.lo) / (d.hi - d.lo || 1) * g.plotWidth;
182
+ const lift = g.rowHeight * g.overlap;
183
+ /** A ridge as a path; `from` and `to` cut it to a stretch of the axis (the middle half). */
184
+ const curvePath = (shape, closed, from = -Infinity, to = Infinity) => {
185
+ const base = g.top + (shape.row + 1) * g.rowHeight;
186
+ const points = [];
187
+ const push = (x, y) => points.push(`${sx(x).toFixed(2)},${(base - y * lift).toFixed(2)}`);
188
+ if (from > -Infinity) push(from, heightAt(shape, from));
189
+ shape.xs.forEach((x, i) => {
190
+ if (x > from && x < to) push(x, shape.ys[i]);
191
+ });
192
+ if (to < Infinity) push(to, heightAt(shape, to));
193
+ if (!points.length) return "";
194
+ const first = from > -Infinity ? from : shape.xs[0];
195
+ const last = to < Infinity ? to : shape.xs[shape.xs.length - 1];
196
+ return closed ? `M${sx(first).toFixed(2)},${base}L${points.join("L")}L${sx(last).toFixed(2)},${base}Z` : `M${points.join("L")}`;
197
+ };
198
+ const mark = (node, shape) => {
199
+ if (!node) return;
200
+ const x = sx(shape.median).toFixed(2);
201
+ const base = g.top + (shape.row + 1) * g.rowHeight;
202
+ node.setAttribute("x1", x);
203
+ node.setAttribute("x2", x);
204
+ node.setAttribute("y1", String(base));
205
+ node.setAttribute("y2", (base - heightAt(shape, shape.median) * lift).toFixed(2));
206
+ };
207
+ for (const [id, shape] of d.shapes) {
208
+ const group = root.querySelector(`[data-ridge="${CSS.escape(id)}"]`);
209
+ group?.querySelector("[data-part=fill]")?.setAttribute("d", curvePath(shape, true));
210
+ group?.querySelector("[data-part=line]")?.setAttribute("d", curvePath(shape, false));
211
+ mark(group?.querySelector("[data-part=median]") ?? null, shape);
212
+ }
213
+ const shape = g.current ? d.shapes.get(g.current) : void 0;
214
+ if (shape) {
215
+ const lens = root.querySelector("[data-part=lens]");
216
+ lens?.querySelector("[data-part=lens-fill]")?.setAttribute("d", curvePath(shape, true));
217
+ lens?.querySelector("[data-part=lens-line]")?.setAttribute("d", curvePath(shape, false));
218
+ lens?.querySelector("[data-part=lens-band]")?.setAttribute("d", curvePath(shape, true, shape.q1, shape.q3));
219
+ mark(lens?.querySelector("[data-part=lens-median]") ?? null, shape);
220
+ }
221
+ for (const node of root.querySelectorAll("[data-tick]")) node.style.transform = `translate3d(${sx(Number(node.dataset.tick)).toFixed(2)}px, 0, 0)`;
222
+ };
223
+ const paintRef = useRef(paint);
224
+ useIsomorphicLayoutEffect(() => {
225
+ geometry.current = {
226
+ gutter,
227
+ plotWidth,
228
+ rowHeight,
229
+ overlap,
230
+ top,
231
+ current
232
+ };
233
+ paintRef.current = paint;
234
+ paint();
235
+ });
236
+ const [shown, setShown] = useState(false);
237
+ useEffect(() => {
238
+ const node = figure.current;
239
+ if (!node || prefersReducedMotion() || typeof IntersectionObserver === "undefined") {
240
+ setShown(true);
241
+ return;
242
+ }
243
+ const observer = new IntersectionObserver(([entry]) => {
244
+ if (!entry?.isIntersecting) return;
245
+ observer.disconnect();
246
+ setShown(true);
247
+ }, { threshold: .3 });
248
+ observer.observe(node);
249
+ return () => observer.disconnect();
250
+ }, []);
251
+ useEffect(() => {
252
+ if (!shown) return;
253
+ const d = drawn.current;
254
+ const first = d.shapes.size === 0;
255
+ const from = /* @__PURE__ */ new Map();
256
+ for (const [id, target] of model.shapes) {
257
+ const now = d.shapes.get(id);
258
+ from.set(id, now ? {
259
+ ...now,
260
+ xs: [...now.xs],
261
+ ys: [...now.ys]
262
+ } : {
263
+ ...target,
264
+ ys: target.ys.map(() => 0),
265
+ q1: target.median,
266
+ q3: target.median
267
+ });
268
+ }
269
+ const fromLo = first ? model.lo : d.lo;
270
+ const fromHi = first ? model.hi : d.hi;
271
+ const settle = () => {
272
+ d.shapes = new Map([...model.shapes].map(([id, shape]) => [id, { ...shape }]));
273
+ d.lo = model.lo;
274
+ d.hi = model.hi;
275
+ paintRef.current();
276
+ };
277
+ d.shapes = new Map([...from].map(([id, shape]) => [id, {
278
+ ...shape,
279
+ xs: [...shape.xs],
280
+ ys: [...shape.ys]
281
+ }]));
282
+ return tween(first ? SWELL : REVEAL, (t) => {
283
+ d.lo = mix(fromLo, model.lo, t);
284
+ d.hi = mix(fromHi, model.hi, t);
285
+ for (const [id, to] of model.shapes) {
286
+ const f = from.get(id);
287
+ const out = d.shapes.get(id);
288
+ const local = first ? clamp((t - to.row * .025) / (1 - Math.min(.5, model.shapes.size * .025)), 0, 1) : t;
289
+ for (let i = 0; i < SAMPLES; i++) {
290
+ out.xs[i] = mix(f.xs[i], to.xs[i], local);
291
+ out.ys[i] = mix(f.ys[i], to.ys[i], local);
292
+ }
293
+ out.row = mix(f.row, to.row, local);
294
+ out.q1 = mix(f.q1, to.q1, local);
295
+ out.median = mix(f.median, to.median, local);
296
+ out.q3 = mix(f.q3, to.q3, local);
297
+ }
298
+ paintRef.current();
299
+ }, settle);
300
+ }, [shown, model]);
301
+ const tickCount = Math.max(2, Math.floor(plotWidth / 72));
302
+ const step = niceStep(model.hi - model.lo, tickCount);
303
+ const ticks = [];
304
+ for (let value = Math.ceil(model.lo / step) * step; value <= model.hi + 1e-9; value += step) ticks.push(Math.round(value * 1e6) / 1e6 || 0);
305
+ const activeStats = current ? model.stats.get(current) : void 0;
306
+ const activeSeries = current ? series.find((entry) => entry.id === current) : void 0;
307
+ const reading = cursor && activeStats ? {
308
+ value: cursor.value,
309
+ below: activeStats.n ? activeStats.sorted.filter((value) => value <= cursor.value).length / activeStats.n : 0
310
+ } : null;
311
+ const [held, setHeld] = useState(null);
312
+ if (current && (held?.id !== current || held.value !== (reading?.value ?? null))) setHeld({
313
+ id: current,
314
+ value: reading?.value ?? null
315
+ });
316
+ const tipSeries = held ? series.find((entry) => entry.id === held.id) : void 0;
317
+ const tipStats = held ? model.stats.get(held.id) : void 0;
318
+ const tipBelow = held && held.value !== null && tipStats?.n ? tipStats.sorted.filter((value) => value <= held.value).length / tipStats.n : 0;
319
+ const shownBefore = useRef(false);
320
+ useIsomorphicLayoutEffect(() => {
321
+ const bubble = tip.current;
322
+ const shape = current ? model.shapes.get(current) : void 0;
323
+ if (cross.current) cross.current.style.transform = `translate3d(${reading ? xOf(reading.value).toFixed(2) : 0}px, 0, 0)`;
324
+ if (!bubble || !shape || !width) {
325
+ shownBefore.current = false;
326
+ return;
327
+ }
328
+ const tw = bubble.offsetWidth;
329
+ const th = bubble.offsetHeight;
330
+ const ax = reading ? xOf(reading.value) : xOf(shape.median);
331
+ const ay = cursor?.pointerY ?? baselineOf(shape.row) - heightAt(shape, shape.median) * rowHeight * overlap - LIFT;
332
+ let left = ax + TIP;
333
+ if (left + tw > width) left = ax - TIP - tw;
334
+ let y = ay - th - TIP;
335
+ if (y < 0) y = ay + TIP;
336
+ if (!shownBefore.current) bubble.style.transition = "none";
337
+ bubble.style.translate = `${clamp(left, 0, Math.max(0, width - tw))}px ${clamp(y, 0, Math.max(0, height - th))}px`;
338
+ if (!shownBefore.current) {
339
+ bubble.offsetWidth;
340
+ bubble.style.transition = "";
341
+ }
342
+ shownBefore.current = true;
343
+ });
344
+ const valueAt = (x) => {
345
+ const d = drawn.current;
346
+ return d.lo + clamp((x - gutter) / plotWidth, 0, 1) * (d.hi - d.lo);
347
+ };
348
+ /** The ridge under the pointer: the front-most one whose outline holds it, else the row it is in. */
349
+ const pick = (x, y) => {
350
+ const value = valueAt(x);
351
+ const lift = rowHeight * overlap;
352
+ let best = null;
353
+ let bestId = null;
354
+ for (const [id, shape] of drawn.current.shapes) {
355
+ const base = baselineOf(shape.row);
356
+ const h = heightAt(shape, value) * lift;
357
+ if (y <= base + 2 && y >= base - h - 4 && (!best || shape.row > best.row)) {
358
+ best = shape;
359
+ bestId = id;
360
+ }
361
+ }
362
+ if (!bestId) bestId = series[clamp(Math.floor((y - top) / rowHeight), 0, series.length - 1)]?.id ?? null;
363
+ return {
364
+ id: bestId,
365
+ value
366
+ };
367
+ };
368
+ const onPointerMove = (event) => {
369
+ const rect = event.currentTarget.getBoundingClientRect();
370
+ const x = event.clientX - rect.left;
371
+ const y = event.clientY - rect.top;
372
+ if (x < gutter - 8 || y > height - AXIS + 4) {
373
+ if (event.pointerType === "mouse") {
374
+ setCurrent(null);
375
+ setCursor(null);
376
+ }
377
+ return;
378
+ }
379
+ const hit = pick(x, y);
380
+ setCurrent(hit.id);
381
+ setCursor({
382
+ value: hit.value,
383
+ pointerY: y
384
+ });
385
+ };
386
+ const onKeyDown = (event) => {
387
+ const at = current ? series.findIndex((entry) => entry.id === current) : -1;
388
+ const choose = (index) => {
389
+ event.preventDefault();
390
+ const next = series[clamp(index, 0, series.length - 1)];
391
+ if (!next) return;
392
+ setCurrent(next.id);
393
+ setCursor({
394
+ value: cursor?.value ?? model.stats.get(next.id)?.median ?? model.lo,
395
+ pointerY: null
396
+ });
397
+ };
398
+ const nudge = (direction) => {
399
+ event.preventDefault();
400
+ if (!current) {
401
+ choose(0);
402
+ return;
403
+ }
404
+ const base = cursor?.value ?? model.stats.get(current)?.median ?? model.lo;
405
+ setCursor({
406
+ value: clamp((Math.round(base / step) + direction) * step, model.lo, model.hi),
407
+ pointerY: null
408
+ });
409
+ };
410
+ if (event.key === "ArrowDown") choose(at + 1);
411
+ else if (event.key === "ArrowUp") choose(at < 0 ? 0 : at - 1);
412
+ else if (event.key === "Home") choose(0);
413
+ else if (event.key === "End") choose(series.length - 1);
414
+ else if (event.key === "ArrowRight") nudge(1);
415
+ else if (event.key === "ArrowLeft") nudge(-1);
416
+ else if (event.key === "Escape" && current) {
417
+ event.preventDefault();
418
+ setCurrent(null);
419
+ setCursor(null);
420
+ }
421
+ };
422
+ const empty = !series.length || series.every((entry) => !entry.values.length);
423
+ const ridgeColor = (value) => tint ? toneOf((value - model.lo) / (model.hi - model.lo || 1)) : "var(--color-chart-1)";
424
+ const describe = (entry) => {
425
+ const s = model.stats.get(entry.id);
426
+ return `${entry.label}: median ${format(s.median)}, middle half ${format(s.q1)} to ${format(s.q3)}, range ${format(s.min)} to ${format(s.max)}, ${s.n} values`;
427
+ };
428
+ const spoken = activeSeries ? `${describe(activeSeries)}${reading ? `. ${PERCENT.format(reading.below)} at or below ${format(reading.value)}` : ""}` : "";
429
+ const summary = empty ? `${label}. ${emptyLabel}.` : `${label}. ${series.map(describe).join(". ")}.`;
430
+ return /* @__PURE__ */ jsxs("figure", {
431
+ ref: refs,
432
+ "data-slot": "ridgeline",
433
+ "aria-label": label,
434
+ className: cn("ridgeline box-border font-sans text-foreground", className),
435
+ children: [
436
+ /* @__PURE__ */ jsxs("div", {
437
+ ref: plot,
438
+ "data-slot": "ridgeline-plot",
439
+ "data-active": current ? "" : void 0,
440
+ "data-scrubbing": current ? "" : void 0,
441
+ "data-cursor": reading ? "" : void 0,
442
+ role: empty ? void 0 : "slider",
443
+ tabIndex: empty ? void 0 : 0,
444
+ "aria-label": empty ? void 0 : `${label}, choose a ridge`,
445
+ "aria-orientation": empty ? void 0 : "vertical",
446
+ "aria-valuemin": empty ? void 0 : 1,
447
+ "aria-valuemax": empty ? void 0 : series.length,
448
+ "aria-valuenow": empty ? void 0 : (activeSeries ? series.indexOf(activeSeries) : 0) + 1,
449
+ "aria-valuetext": empty ? void 0 : spoken || summary,
450
+ className: "ridgeline-plot",
451
+ style: { height },
452
+ onPointerMove,
453
+ onPointerDown: onPointerMove,
454
+ onPointerLeave: (event) => {
455
+ if (event.pointerType === "mouse") {
456
+ setCurrent(null);
457
+ setCursor(null);
458
+ }
459
+ },
460
+ onKeyDown,
461
+ onBlur: () => {
462
+ setCurrent(null);
463
+ setCursor(null);
464
+ },
465
+ children: [
466
+ /* @__PURE__ */ jsx("div", {
467
+ "aria-hidden": "true",
468
+ className: "pointer-events-none absolute inset-x-0 top-0",
469
+ style: { height: height - AXIS + 22 },
470
+ children: ticks.map((value) => /* @__PURE__ */ jsx("div", {
471
+ "data-tick": value,
472
+ className: "ridgeline-tick motion-safe:animate-fade-in",
473
+ style: { top: top - rowHeight * .5 },
474
+ children: /* @__PURE__ */ jsx("span", {
475
+ className: "ridgeline-tick-label",
476
+ children: format(value)
477
+ })
478
+ }, value))
479
+ }),
480
+ /* @__PURE__ */ jsx("div", {
481
+ ref: cross,
482
+ "aria-hidden": "true",
483
+ className: "ridgeline-crosshair",
484
+ style: {
485
+ top: top - rowHeight * .5,
486
+ height: height - AXIS - top + rowHeight * .5
487
+ }
488
+ }),
489
+ /* @__PURE__ */ jsxs("svg", {
490
+ width: width || void 0,
491
+ height,
492
+ viewBox: `0 0 ${Math.max(1, width)} ${height}`,
493
+ "aria-hidden": "true",
494
+ focusable: "false",
495
+ className: "absolute inset-0 block overflow-visible",
496
+ children: [series.map((entry) => /* @__PURE__ */ jsxs("g", {
497
+ "data-ridge": entry.id,
498
+ "data-dim": current !== null && current !== entry.id || void 0,
499
+ "data-lifted": current === entry.id || void 0,
500
+ className: "ridgeline-ridge",
501
+ style: { "--ridge": ridgeColor(model.stats.get(entry.id)?.median ?? model.lo) },
502
+ children: [
503
+ /* @__PURE__ */ jsx("path", {
504
+ "data-part": "fill",
505
+ className: "ridgeline-fill"
506
+ }),
507
+ /* @__PURE__ */ jsx("line", {
508
+ "data-part": "median",
509
+ className: "ridgeline-median"
510
+ }),
511
+ /* @__PURE__ */ jsx("path", {
512
+ "data-part": "line",
513
+ className: "ridgeline-line"
514
+ })
515
+ ]
516
+ }, entry.id)), /* @__PURE__ */ jsxs("g", {
517
+ "data-part": "lens",
518
+ "data-on": current ? "" : void 0,
519
+ className: "ridgeline-lens",
520
+ style: tipStats ? { "--ridge": ridgeColor(tipStats.median) } : void 0,
521
+ children: [
522
+ /* @__PURE__ */ jsx("path", {
523
+ "data-part": "lens-fill",
524
+ className: "ridgeline-lens-fill"
525
+ }),
526
+ /* @__PURE__ */ jsx("path", {
527
+ "data-part": "lens-band",
528
+ className: "ridgeline-lens-band"
529
+ }),
530
+ /* @__PURE__ */ jsx("line", {
531
+ "data-part": "lens-median",
532
+ className: "ridgeline-lens-median"
533
+ }),
534
+ /* @__PURE__ */ jsx("path", {
535
+ "data-part": "lens-line",
536
+ className: "ridgeline-lens-line"
537
+ })
538
+ ]
539
+ })]
540
+ }),
541
+ /* @__PURE__ */ jsx("div", {
542
+ "aria-hidden": "true",
543
+ className: "pointer-events-none absolute inset-0",
544
+ children: series.map((entry, index) => /* @__PURE__ */ jsx("span", {
545
+ "data-active": current === entry.id || void 0,
546
+ className: "ridgeline-row-label",
547
+ style: {
548
+ top: baselineOf(index) - 18,
549
+ width: gutter - 10
550
+ },
551
+ children: entry.label
552
+ }, entry.id))
553
+ }),
554
+ empty ? /* @__PURE__ */ jsx("p", {
555
+ className: "pointer-events-none absolute inset-0 m-0 grid place-items-center text-sm text-muted-foreground",
556
+ children: emptyLabel
557
+ }) : null,
558
+ /* @__PURE__ */ jsx("div", {
559
+ ref: tip,
560
+ "aria-hidden": "true",
561
+ "data-slot": "ridgeline-tooltip",
562
+ className: "line-chart-tooltip",
563
+ children: tipSeries && tipStats ? /* @__PURE__ */ jsxs(Fragment$1, { children: [
564
+ /* @__PURE__ */ jsx("p", {
565
+ className: "m-0 mb-0.5 text-xs text-text-secondary",
566
+ children: tipSeries.label
567
+ }),
568
+ /* @__PURE__ */ jsxs("p", {
569
+ className: "ridgeline-tip-row text-sm font-medium",
570
+ children: [/* @__PURE__ */ jsx("span", {
571
+ className: "text-xs font-normal text-muted-foreground",
572
+ children: "Median"
573
+ }), /* @__PURE__ */ jsx("span", { children: format(tipStats.median) })]
574
+ }),
575
+ /* @__PURE__ */ jsxs("p", {
576
+ className: "ridgeline-tip-row text-xs",
577
+ children: [/* @__PURE__ */ jsx("span", {
578
+ className: "text-muted-foreground",
579
+ children: "Middle half"
580
+ }), /* @__PURE__ */ jsxs("span", { children: [
581
+ format(tipStats.q1),
582
+ " to ",
583
+ format(tipStats.q3)
584
+ ] })]
585
+ }),
586
+ /* @__PURE__ */ jsxs("p", {
587
+ className: "ridgeline-tip-row text-xs",
588
+ children: [/* @__PURE__ */ jsx("span", {
589
+ className: "text-muted-foreground",
590
+ children: "Range"
591
+ }), /* @__PURE__ */ jsxs("span", { children: [
592
+ format(tipStats.min),
593
+ " to ",
594
+ format(tipStats.max)
595
+ ] })]
596
+ }),
597
+ held?.value != null ? /* @__PURE__ */ jsxs("p", {
598
+ className: "m-0 mt-1 text-xs tabular-nums text-muted-foreground",
599
+ children: [
600
+ PERCENT.format(tipBelow),
601
+ " at or below ",
602
+ format(held.value)
603
+ ]
604
+ }) : null
605
+ ] }) : null
606
+ })
607
+ ]
608
+ }),
609
+ tint && !empty ? /* @__PURE__ */ jsxs("div", {
610
+ "aria-hidden": "true",
611
+ className: "mt-3 flex flex-wrap items-center justify-end gap-2 text-xs tabular-nums text-muted-foreground",
612
+ children: [
613
+ /* @__PURE__ */ jsx("span", {
614
+ className: "me-1 text-text-secondary",
615
+ children: "Median"
616
+ }),
617
+ /* @__PURE__ */ jsx("span", { children: format(model.lo) }),
618
+ /* @__PURE__ */ jsx("span", {
619
+ className: "inline-flex gap-0.5",
620
+ children: [
621
+ 0,
622
+ .25,
623
+ .5,
624
+ .75,
625
+ 1
626
+ ].map((at) => /* @__PURE__ */ jsx("span", {
627
+ className: "ridgeline-step",
628
+ style: { "--ridge": toneOf(at) }
629
+ }, at))
630
+ }),
631
+ /* @__PURE__ */ jsx("span", { children: format(model.hi) })
632
+ ]
633
+ }) : null,
634
+ /* @__PURE__ */ jsx("p", {
635
+ className: "sr-only",
636
+ children: summary
637
+ }),
638
+ /* @__PURE__ */ jsx("p", {
639
+ className: "sr-only",
640
+ "aria-live": "polite",
641
+ "aria-atomic": "true",
642
+ children: spoken
643
+ }),
644
+ empty ? null : /* @__PURE__ */ jsx("div", {
645
+ className: "sr-only",
646
+ children: /* @__PURE__ */ jsxs("table", { children: [
647
+ /* @__PURE__ */ jsx("caption", { children: label }),
648
+ /* @__PURE__ */ jsx("thead", { children: /* @__PURE__ */ jsxs("tr", { children: [
649
+ /* @__PURE__ */ jsx("th", {
650
+ scope: "col",
651
+ children: "Series"
652
+ }),
653
+ /* @__PURE__ */ jsx("th", {
654
+ scope: "col",
655
+ children: "Median"
656
+ }),
657
+ /* @__PURE__ */ jsx("th", {
658
+ scope: "col",
659
+ children: "First quartile"
660
+ }),
661
+ /* @__PURE__ */ jsx("th", {
662
+ scope: "col",
663
+ children: "Third quartile"
664
+ }),
665
+ /* @__PURE__ */ jsx("th", {
666
+ scope: "col",
667
+ children: "Lowest"
668
+ }),
669
+ /* @__PURE__ */ jsx("th", {
670
+ scope: "col",
671
+ children: "Highest"
672
+ }),
673
+ /* @__PURE__ */ jsx("th", {
674
+ scope: "col",
675
+ children: "Count"
676
+ })
677
+ ] }) }),
678
+ /* @__PURE__ */ jsx("tbody", { children: series.map((entry) => {
679
+ const s = model.stats.get(entry.id);
680
+ return /* @__PURE__ */ jsxs("tr", { children: [
681
+ /* @__PURE__ */ jsx("th", {
682
+ scope: "row",
683
+ children: entry.label
684
+ }),
685
+ /* @__PURE__ */ jsx("td", { children: format(s.median) }),
686
+ /* @__PURE__ */ jsx("td", { children: format(s.q1) }),
687
+ /* @__PURE__ */ jsx("td", { children: format(s.q3) }),
688
+ /* @__PURE__ */ jsx("td", { children: format(s.min) }),
689
+ /* @__PURE__ */ jsx("td", { children: format(s.max) }),
690
+ /* @__PURE__ */ jsx("td", { children: s.n })
691
+ ] }, entry.id);
692
+ }) })
693
+ ] })
694
+ })
695
+ ]
696
+ });
697
+ });
698
+ //#endregion
699
+ export { Ridgeline };
700
+
701
+ //# sourceMappingURL=ridgeline.js.map