@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,593 @@
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 { useCountTo } from "../lib/count-to.js";
6
+ import { REVEAL, SETTLE, SNAPPY, live, retarget } from "../lib/spring-tween.js";
7
+ import { forwardRef, useCallback, useEffect, useId, useMemo, useRef, useState } from "react";
8
+ import { Fragment as Fragment$1, jsx, jsxs } from "react/jsx-runtime";
9
+ //#region src/donut-chart/donut-chart.tsx
10
+ const OTHER = "__other";
11
+ const TAU = Math.PI * 2;
12
+ /** Neutral steps after the four series colours, and the quietest step for Other. */
13
+ const NEUTRAL = [
14
+ 56,
15
+ 42,
16
+ 32
17
+ ];
18
+ const seriesColor = (index) => index < 4 ? `var(--color-chart-${index + 1})` : `color-mix(in oklab, var(--color-foreground) ${NEUTRAL[(index - 4) % NEUTRAL.length]}%, var(--color-surface))`;
19
+ const OTHER_COLOR = "color-mix(in oklab, var(--color-foreground) 26%, var(--color-surface))";
20
+ /** Room outside the ring for the lift; growth, margin, the gap between segments and their corner radius, in pixels. */
21
+ const LIFT = 4;
22
+ const GROW = 2;
23
+ const MARGIN = 7;
24
+ const GAP = 3;
25
+ const CORNER = 4;
26
+ /** Stagger of the trailing edges on the first sweep. */
27
+ const STAGGER_MS = 35;
28
+ const GROUPED = new Intl.NumberFormat("en-US", { maximumFractionDigits: 1 });
29
+ const PERCENT = new Intl.NumberFormat("en-US", {
30
+ style: "percent",
31
+ maximumFractionDigits: 0
32
+ });
33
+ const shareText = (share) => share > 0 && share < .01 ? "<1%" : PERCENT.format(share);
34
+ const n2 = (value) => (Math.round(value * 100) / 100).toString();
35
+ /** Small parts join one "Other" segment, but only when at least two would; grouping a single part hides it for nothing. */
36
+ function sliceData(data, groupBelow, maxSegments, otherLabel) {
37
+ const parts = data.filter((item) => item.value > 0);
38
+ const total = parts.reduce((sum, item) => sum + item.value, 0);
39
+ if (!total) return [];
40
+ const ranked = [...parts].sort((a, b) => b.value - a.value);
41
+ const keep = new Set(ranked.filter((item, rank) => item.value / total >= groupBelow && rank < maxSegments - 1).map((item) => item.key));
42
+ const rest = parts.filter((item) => !keep.has(item.key));
43
+ if (rest.length < 2) return parts.map((item) => ({ ...item }));
44
+ return [...parts.filter((item) => keep.has(item.key)).map((item) => ({ ...item })), {
45
+ key: OTHER,
46
+ label: otherLabel,
47
+ value: rest.reduce((sum, item) => sum + item.value, 0),
48
+ members: rest
49
+ }];
50
+ }
51
+ /** Turns of the ring for each slice in data order; a hidden slice closes to a point where it sits. */
52
+ function layout(slices, hidden) {
53
+ const total = slices.reduce((sum, item) => sum + (hidden.has(item.key) ? 0 : item.value), 0) || 1;
54
+ let at = 0;
55
+ return new Map(slices.map((item) => {
56
+ const arc = {
57
+ start: at,
58
+ end: at + (hidden.has(item.key) ? 0 : item.value / total)
59
+ };
60
+ at = arc.end;
61
+ return [item.key, arc];
62
+ }));
63
+ }
64
+ /** Half the width, in pixels, of a sector's outer edge once the gap is cut; below a couple of pixels a segment fades rather than drawing a hairline. */
65
+ function breadth(R, t0, t1, gap) {
66
+ const turns = t1 - t0;
67
+ if (turns >= 1 - 1e-6) return Infinity;
68
+ return Math.sin(Math.min(turns * Math.PI, Math.PI / 2)) * R - Math.min(gap / 2, (1 - turns) * TAU * R / 2);
69
+ }
70
+ /**
71
+ * An annular sector between two turns of the ring, clockwise from the top, with
72
+ * rounded corners. Its sides run parallel to the radius at a fixed distance, so
73
+ * the gap between neighbours is the same width from the inner edge to the outer.
74
+ * A thin sector narrows to a wedge and then to nothing, so a closing one never pops.
75
+ */
76
+ function sector(c, R, r, t0, t1, gap, corner) {
77
+ const turns = t1 - t0;
78
+ if (turns <= 1e-6) return "";
79
+ const at = (radius, angle) => `${n2(c + radius * Math.cos(angle))} ${n2(c + radius * Math.sin(angle))}`;
80
+ if (turns >= 1 - 1e-6) return `M${at(R, -Math.PI / 2)}A${n2(R)} ${n2(R)} 0 1 1 ${at(R, Math.PI / 2)}A${n2(R)} ${n2(R)} 0 1 1 ${at(R, -Math.PI / 2)}ZM${at(r, -Math.PI / 2)}A${n2(r)} ${n2(r)} 0 1 0 ${at(r, Math.PI / 2)}A${n2(r)} ${n2(r)} 0 1 0 ${at(r, -Math.PI / 2)}Z`;
81
+ const p = Math.min(gap / 2, (1 - turns) * TAU * R / 2);
82
+ const a0 = t0 * TAU - Math.PI / 2;
83
+ const a1 = t1 * TAU - Math.PI / 2;
84
+ const half = (a1 - a0) / 2;
85
+ const s = Math.sin(Math.min(half, Math.PI / 2));
86
+ if (s * R <= p + 1e-6) return "";
87
+ const side = (t, angle, sign) => `${n2(c + t * Math.cos(angle) - sign * p * Math.sin(angle))} ${n2(c + t * Math.sin(angle) + sign * p * Math.cos(angle))}`;
88
+ const band = (R - r) / 2;
89
+ const ro = Math.max(0, Math.min(corner, band, s >= .9999 ? Infinity : (s * R - p) / (1 + s)));
90
+ const dO = Math.asin(Math.min(1, (p + ro) / (R - ro)));
91
+ const tO = Math.sqrt(Math.max(0, (R - ro) ** 2 - (p + ro) ** 2));
92
+ const bigO = a1 - a0 - 2 * dO > Math.PI ? 1 : 0;
93
+ let d = `M${side(tO, a0, 1)}`;
94
+ if (ro > .01) d += `A${n2(ro)} ${n2(ro)} 0 0 1 ${at(R, a0 + dO)}`;
95
+ d += `A${n2(R)} ${n2(R)} 0 ${bigO} 1 ${at(R, a1 - dO)}`;
96
+ if (ro > .01) d += `A${n2(ro)} ${n2(ro)} 0 0 1 ${side(tO, a1, -1)}`;
97
+ if (s * r > p + 1e-6 || s >= .9999) {
98
+ const ri = Math.max(0, Math.min(corner, band, s >= .9999 ? Infinity : (s * r - p) / (1 - s)));
99
+ const dI = Math.asin(Math.min(1, (p + ri) / (r + ri)));
100
+ const tI = Math.sqrt(Math.max(0, (r + ri) ** 2 - (p + ri) ** 2));
101
+ const bigI = a1 - a0 - 2 * dI > Math.PI ? 1 : 0;
102
+ d += `L${side(tI, a1, -1)}`;
103
+ if (ri > .01) d += `A${n2(ri)} ${n2(ri)} 0 0 1 ${at(r, a1 - dI)}`;
104
+ d += `A${n2(r)} ${n2(r)} 0 ${bigI} 0 ${at(r, a0 + dI)}`;
105
+ if (ri > .01) d += `A${n2(ri)} ${n2(ri)} 0 0 1 ${side(tI, a0, 1)}`;
106
+ } else d += `L${at(p / s, (a0 + a1) / 2)}`;
107
+ return `${d}Z`;
108
+ }
109
+ /**
110
+ * A number that counts to each new value on the smooth spring. useCountTo counts
111
+ * in whole steps, so a fraction (a share) is counted in ten-thousandths.
112
+ */
113
+ function Count({ value, format }) {
114
+ const fine = !Number.isInteger(value);
115
+ const shown = useCountTo(fine ? value * 1e4 : value);
116
+ return /* @__PURE__ */ jsx(Fragment$1, { children: format(fine ? shown / 1e4 : shown) });
117
+ }
118
+ const DonutChart = forwardRef(function DonutChart({ data, label, unit = "", formatValue = (value) => GROUPED.format(value), totalLabel = "Total", center = "total", size = 208, thickness = 24, groupBelow = .04, maxSegments = 6, otherLabel = "Other", activeKey, defaultActiveKey = null, onActiveChange, hiddenKeys, defaultHiddenKeys, onHiddenKeysChange, legendAction = "toggle", legend = true, emptyLabel = "No data yet", className }, ref) {
119
+ const figure = useRef(null);
120
+ const refs = useMemo(() => mergeRefs(ref, figure), [ref]);
121
+ const legendId = useId();
122
+ const slices = sliceData(data, groupBelow, maxSegments, otherLabel);
123
+ const [ownHidden, setOwnHidden] = useState(defaultHiddenKeys ?? []);
124
+ const hiddenList = hiddenKeys ?? ownHidden;
125
+ const hidden = new Set(hiddenList.filter((key) => slices.some((item) => item.key === key)));
126
+ const visible = slices.filter((item) => !hidden.has(item.key));
127
+ const total = visible.reduce((sum, item) => sum + item.value, 0);
128
+ const signature = slices.map((item) => `${item.key}:${item.value}${hidden.has(item.key) ? "h" : ""}`).join("|");
129
+ const suffix = unit ? ` ${unit}` : "";
130
+ const [palette, setPalette] = useState(() => new Map(data.map((item, index) => [item.key, index])));
131
+ if (data.some((item) => !palette.has(item.key))) {
132
+ const next = new Map(palette);
133
+ for (const item of data) if (!next.has(item.key)) next.set(item.key, next.size);
134
+ setPalette(next);
135
+ }
136
+ const colorFor = (item) => item.color ?? (item.key === OTHER ? OTHER_COLOR : seriesColor(palette.get(item.key) ?? 0));
137
+ const [drawn, setDrawn] = useState(slices);
138
+ const [seen, setSeen] = useState(signature);
139
+ if (seen !== signature) {
140
+ setSeen(signature);
141
+ const next = [...slices];
142
+ drawn.forEach((item, index) => {
143
+ if (next.some((slice) => slice.key === item.key)) return;
144
+ const before = drawn.slice(0, index).reverse().find((prior) => next.some((slice) => slice.key === prior.key));
145
+ next.splice(before ? next.findIndex((slice) => slice.key === before.key) + 1 : 0, 0, {
146
+ ...item,
147
+ value: 0
148
+ });
149
+ });
150
+ setDrawn(next);
151
+ }
152
+ const [ownActive, setOwnActive] = useState(defaultActiveKey);
153
+ const selected = activeKey !== void 0 ? activeKey : ownActive;
154
+ const [preview, setPreview] = useState(null);
155
+ const select = (key) => {
156
+ if (activeKey === void 0) setOwnActive(key);
157
+ onActiveChange?.(key);
158
+ };
159
+ const current = [preview, selected].find((key) => key && visible.some((item) => item.key === key)) ?? null;
160
+ const activeSlice = visible.find((item) => item.key === current) ?? null;
161
+ const [announcement, setAnnouncement] = useState("");
162
+ const setHidden = (key) => {
163
+ const isHidden = hidden.has(key);
164
+ if (!isHidden && visible.length <= 1) return;
165
+ const next = isHidden ? hiddenList.filter((item) => item !== key) : [...hiddenList, key];
166
+ if (hiddenKeys === void 0) setOwnHidden(next);
167
+ onHiddenKeysChange?.(next);
168
+ const item = slices.find((slice) => slice.key === key);
169
+ const nextTotal = slices.reduce((sum, slice) => sum + (next.includes(slice.key) ? 0 : slice.value), 0);
170
+ const totalText = center === "total" ? ` ${totalLabel} ${formatValue(nextTotal)}${suffix}.` : "";
171
+ if (item) setAnnouncement(`${item.label} ${isHidden ? "shown" : "hidden"}.${totalText}`);
172
+ };
173
+ const c = size / 2;
174
+ const outer = c - MARGIN;
175
+ const inner = Math.max(8, outer - thickness);
176
+ const corner = Math.min(CORNER, thickness / 4);
177
+ const geometry = useRef({
178
+ c,
179
+ outer,
180
+ inner,
181
+ corner
182
+ });
183
+ const segments = useRef(/* @__PURE__ */ new Map());
184
+ const svg = useRef(null);
185
+ /** One writer: every path's shape, opacity and lift, straight onto the elements. */
186
+ const paint = useCallback(() => {
187
+ const root = svg.current;
188
+ if (!root) return;
189
+ const { c, outer, inner, corner } = geometry.current;
190
+ for (const node of root.querySelectorAll("[data-key]")) {
191
+ const segment = segments.current.get(node.dataset.key);
192
+ if (!segment) {
193
+ node.setAttribute("d", "");
194
+ continue;
195
+ }
196
+ const start = segment.start.value;
197
+ const end = segment.end.value;
198
+ const lift = Math.max(0, segment.lift.value);
199
+ const R = outer + lift * GROW;
200
+ node.setAttribute("d", sector(c, R, inner - lift * GROW * .5, start, end, GAP, corner));
201
+ node.setAttribute("fill-opacity", n2(Math.min(1, Math.max(0, (breadth(R, start, end, GAP) - 1) / 3))));
202
+ const middle = (start + end) / 2 * TAU - Math.PI / 2;
203
+ node.setAttribute("transform", `translate(${n2(Math.cos(middle) * lift * LIFT)} ${n2(Math.sin(middle) * lift * LIFT)})`);
204
+ }
205
+ }, []);
206
+ useIsomorphicLayoutEffect(() => {
207
+ geometry.current = {
208
+ c,
209
+ outer,
210
+ inner,
211
+ corner
212
+ };
213
+ paint();
214
+ });
215
+ useEffect(() => () => {
216
+ for (const segment of segments.current.values()) {
217
+ segment.start.stop();
218
+ segment.end.stop();
219
+ segment.lift.stop();
220
+ }
221
+ }, []);
222
+ const [shown, setShown] = useState(false);
223
+ useEffect(() => {
224
+ const node = figure.current;
225
+ if (!node || prefersReducedMotion() || typeof IntersectionObserver === "undefined") {
226
+ setShown(true);
227
+ return;
228
+ }
229
+ const observer = new IntersectionObserver(([entry]) => {
230
+ if (!entry?.isIntersecting) return;
231
+ observer.disconnect();
232
+ setShown(true);
233
+ }, { threshold: .35 });
234
+ observer.observe(node);
235
+ return () => observer.disconnect();
236
+ }, []);
237
+ const targets = useRef(/* @__PURE__ */ new Map());
238
+ const latest = useRef({
239
+ drawn,
240
+ slices
241
+ });
242
+ useIsomorphicLayoutEffect(() => {
243
+ latest.current = {
244
+ drawn,
245
+ slices
246
+ };
247
+ });
248
+ useEffect(() => {
249
+ if (!shown) return;
250
+ const { drawn: order, slices: now } = latest.current;
251
+ const goal = layout(now, hidden);
252
+ targets.current = goal;
253
+ const first = segments.current.size === 0;
254
+ const place = (index) => {
255
+ const before = order.slice(0, index).reverse().find((item) => goal.has(item.key));
256
+ return before ? goal.get(before.key).end : 0;
257
+ };
258
+ const drop = (key) => {
259
+ if (latest.current.slices.some((item) => item.key === key)) return;
260
+ segments.current.delete(key);
261
+ setDrawn((list) => list.filter((item) => item.key !== key));
262
+ };
263
+ order.forEach((item, index) => {
264
+ const leaving = !goal.has(item.key);
265
+ const to = goal.get(item.key) ?? {
266
+ start: place(index),
267
+ end: place(index)
268
+ };
269
+ let segment = segments.current.get(item.key);
270
+ if (!segment) {
271
+ const prior = order.slice(0, index).reverse().map((entry) => segments.current.get(entry.key)).find(Boolean);
272
+ const from = first ? 0 : prior ? prior.end.value : 0;
273
+ segment = {
274
+ start: live(from),
275
+ end: live(from),
276
+ lift: live(0)
277
+ };
278
+ segments.current.set(item.key, segment);
279
+ }
280
+ if (first) {
281
+ retarget(segment.start, to.start, REVEAL, paint);
282
+ retarget(segment.end, to.end, REVEAL, paint, 40 + index * STAGGER_MS);
283
+ return;
284
+ }
285
+ retarget(segment.start, to.start, SETTLE, paint);
286
+ retarget(segment.end, to.end, SETTLE, paint, 0, leaving ? () => drop(item.key) : void 0);
287
+ });
288
+ paint();
289
+ }, [
290
+ shown,
291
+ signature,
292
+ paint
293
+ ]);
294
+ useEffect(() => {
295
+ for (const [key, segment] of segments.current) retarget(segment.lift, key === current ? 1 : 0, SNAPPY, paint);
296
+ }, [
297
+ current,
298
+ drawn,
299
+ shown,
300
+ paint
301
+ ]);
302
+ const hit = (event) => {
303
+ const box = svg.current?.getBoundingClientRect();
304
+ if (!box?.width) return void 0;
305
+ const scale = size / box.width;
306
+ const x = (event.clientX - box.left) * scale - c;
307
+ const y = (event.clientY - box.top) * scale - c;
308
+ const radius = Math.hypot(x, y);
309
+ if (radius < inner - 6 || radius > c) return null;
310
+ let turn = (Math.atan2(y, x) + Math.PI / 2) / TAU;
311
+ if (turn < 0) turn += 1;
312
+ for (const [key, arc] of targets.current) if (arc.end > arc.start && turn >= arc.start && turn < arc.end && visible.some((item) => item.key === key)) return key;
313
+ };
314
+ const onRingMove = (event) => {
315
+ if (event.pointerType !== "mouse") return;
316
+ const key = hit(event);
317
+ if (key !== void 0 && key !== preview) setPreview(key);
318
+ };
319
+ const onRingClick = (event) => {
320
+ const key = hit(event);
321
+ if (key) select(selected === key ? null : key);
322
+ };
323
+ const format = (value) => `${formatValue(value)}${suffix}`;
324
+ const showShare = center === "total";
325
+ const shareOf = (value) => showShare ? `, ${shareText(value / (total || 1))}` : "";
326
+ const describe = (item) => `${item.label}, ${format(item.value)}${shareOf(item.value)}${item.members ? `. Includes ${item.members.map((member) => member.label).join(", ")}` : ""}`;
327
+ const rows = useRef([]);
328
+ const step = (key, index, count) => {
329
+ return {
330
+ ArrowDown: index + 1,
331
+ ArrowRight: index + 1,
332
+ ArrowUp: index - 1,
333
+ ArrowLeft: index - 1,
334
+ Home: 0,
335
+ End: count - 1
336
+ }[key];
337
+ };
338
+ const onLegendKey = (event, index) => {
339
+ if (event.key === "Escape" && selected) {
340
+ event.preventDefault();
341
+ select(null);
342
+ return;
343
+ }
344
+ const next = step(event.key, index, slices.length);
345
+ if (next === void 0) return;
346
+ event.preventDefault();
347
+ rows.current[(next + slices.length) % slices.length]?.focus();
348
+ };
349
+ const onRingKey = (event) => {
350
+ if (!visible.length) return;
351
+ if (event.key === "Escape") {
352
+ event.preventDefault();
353
+ setPreview(null);
354
+ if (selected) select(null);
355
+ return;
356
+ }
357
+ if ((event.key === "Enter" || event.key === " ") && current) {
358
+ event.preventDefault();
359
+ select(selected === current ? null : current);
360
+ return;
361
+ }
362
+ const index = visible.findIndex((item) => item.key === current);
363
+ const next = step(event.key, index < 0 ? event.key.endsWith("Up") || event.key.endsWith("Left") ? 0 : -1 : index, visible.length);
364
+ if (next === void 0) return;
365
+ event.preventDefault();
366
+ const item = visible[(next + visible.length) % visible.length];
367
+ setPreview(item.key);
368
+ setAnnouncement(describe(item));
369
+ };
370
+ const onLegendBlur = (event) => {
371
+ if (!(event.relatedTarget instanceof Node && event.currentTarget.closest("ul")?.contains(event.relatedTarget))) setPreview(null);
372
+ };
373
+ const rest = center === "total" ? {
374
+ label: totalLabel,
375
+ value: total
376
+ } : center === "none" ? {
377
+ label: " ",
378
+ value: ""
379
+ } : center;
380
+ const identity = activeSlice ? activeSlice.key : "__total";
381
+ const custom = typeof center === "object" && total > 0;
382
+ const readouts = [{
383
+ key: "__total",
384
+ label: total ? rest.label : emptyLabel,
385
+ value: total ? rest.value : 0,
386
+ meta: null,
387
+ custom
388
+ }, ...slices.map((item) => ({
389
+ key: item.key,
390
+ label: item.label,
391
+ value: item.value,
392
+ meta: item,
393
+ custom: false
394
+ }))];
395
+ const activeIndex = Math.max(0, readouts.findIndex((item) => item.key === identity));
396
+ const restValue = (value) => typeof value === "number" ? format(value) : value;
397
+ const restText = center === "total" ? `${totalLabel} ${format(total)}. ` : center === "none" ? "" : `${[center.label, restValue(center.value)].filter(Boolean).join(" ")}. `;
398
+ const summary = total ? `${label}. ${restText}${visible.map(describe).join(". ")}.` : `${label}. ${emptyLabel}.`;
399
+ const members = (item) => item.members ? item.members.length > 2 ? `${item.members.slice(0, 2).map((member) => member.label).join(", ")} and ${item.members.length - 2} more` : item.members.map((member) => member.label).join(" and ") : null;
400
+ return /* @__PURE__ */ jsxs("figure", {
401
+ ref: refs,
402
+ "data-slot": "donut-chart",
403
+ "aria-label": label,
404
+ "data-legend": legend || void 0,
405
+ className: cn("donut-chart box-border font-sans text-foreground", className),
406
+ children: [
407
+ /* @__PURE__ */ jsxs("div", {
408
+ "data-slot": "donut-chart-ring",
409
+ className: "donut-chart-ring",
410
+ style: {
411
+ width: size,
412
+ "--inner": `${inner * 2 / size * 100}%`
413
+ },
414
+ tabIndex: legend ? void 0 : 0,
415
+ role: legend ? void 0 : "application",
416
+ "aria-label": legend ? void 0 : `${label}. Use the arrow keys to read each segment.`,
417
+ onKeyDown: legend ? void 0 : onRingKey,
418
+ onBlur: legend ? void 0 : () => setPreview(null),
419
+ children: [/* @__PURE__ */ jsxs("svg", {
420
+ ref: svg,
421
+ viewBox: `0 0 ${size} ${size}`,
422
+ "aria-hidden": "true",
423
+ focusable: "false",
424
+ onPointerMove: onRingMove,
425
+ onPointerLeave: () => setPreview(null),
426
+ onClick: onRingClick,
427
+ "data-hovering": current !== null || void 0,
428
+ className: "block size-full overflow-visible data-[hovering]:cursor-pointer",
429
+ children: [/* @__PURE__ */ jsx("circle", {
430
+ className: "donut-chart-track",
431
+ cx: c,
432
+ cy: c,
433
+ r: (outer + inner) / 2,
434
+ strokeWidth: outer - inner,
435
+ "data-idle": !shown || !total || void 0
436
+ }), drawn.map((item) => /* @__PURE__ */ jsx("path", {
437
+ "data-key": item.key,
438
+ "data-active": item.key === current || void 0,
439
+ "data-dim": current !== null && item.key !== current || void 0,
440
+ className: "donut-chart-segment",
441
+ style: { "--slice": colorFor(item) }
442
+ }, item.key))]
443
+ }), /* @__PURE__ */ jsx("div", {
444
+ "aria-hidden": "true",
445
+ "data-center": center === "total" || center === "none" ? center : "custom",
446
+ className: "donut-chart-center",
447
+ children: readouts.map((item, index) => /* @__PURE__ */ jsxs("span", {
448
+ "data-place": Math.sign(index - activeIndex),
449
+ className: "donut-chart-readout",
450
+ children: [
451
+ /* @__PURE__ */ jsx("span", {
452
+ className: "block w-full min-h-5 truncate text-xs text-text-secondary",
453
+ children: item.label
454
+ }),
455
+ /* @__PURE__ */ jsx("span", {
456
+ className: "block max-w-full min-h-8 truncate text-h3 font-medium tabular-nums",
457
+ children: typeof item.value === "string" ? item.value || " " : item.value || item.meta || item.custom ? /* @__PURE__ */ jsx(Count, {
458
+ value: item.value,
459
+ format: formatValue
460
+ }) : " "
461
+ }),
462
+ /* @__PURE__ */ jsx("span", {
463
+ className: "block w-full min-h-5 truncate text-xs tabular-nums text-muted-foreground",
464
+ children: item.meta && showShare ? /* @__PURE__ */ jsxs(Fragment$1, { children: [
465
+ /* @__PURE__ */ jsx(Count, {
466
+ value: total && !hidden.has(item.key) ? item.meta.value / total : 0,
467
+ format: shareText
468
+ }),
469
+ " ",
470
+ "of ",
471
+ totalLabel.toLowerCase()
472
+ ] }) : typeof item.value === "number" ? unit || " " : " "
473
+ })
474
+ ]
475
+ }, item.key))
476
+ })]
477
+ }),
478
+ legend && slices.length > 0 ? /* @__PURE__ */ jsx("ul", {
479
+ id: legendId,
480
+ "aria-label": `${label}, segments${legendAction === "toggle" ? ". Press a segment to show or hide it" : ""}`,
481
+ onPointerLeave: () => setPreview(null),
482
+ className: "m-0 -mb-0.5 grid list-none p-0",
483
+ children: slices.map((item, index) => {
484
+ const off = hidden.has(item.key);
485
+ return /* @__PURE__ */ jsx("li", {
486
+ className: "overflow-hidden motion-safe:animate-fade-in",
487
+ children: /* @__PURE__ */ jsxs("button", {
488
+ ref: (node) => {
489
+ rows.current[index] = node;
490
+ },
491
+ type: "button",
492
+ "data-slot": "donut-chart-row",
493
+ "aria-pressed": legendAction === "toggle" ? !off : selected === item.key,
494
+ "aria-label": off ? `${item.label}, hidden` : describe(item),
495
+ "data-active": item.key === current || void 0,
496
+ "data-pinned": selected === item.key || void 0,
497
+ "data-hidden": off || void 0,
498
+ "data-share": showShare ? void 0 : "none",
499
+ style: { "--slice": colorFor(item) },
500
+ onClick: () => legendAction === "toggle" ? setHidden(item.key) : select(selected === item.key ? null : item.key),
501
+ onPointerEnter: (event) => {
502
+ if (event.pointerType === "mouse") setPreview(off ? null : item.key);
503
+ },
504
+ onFocus: (event) => {
505
+ if (event.currentTarget.matches(":focus-visible")) setPreview(off ? null : item.key);
506
+ },
507
+ onBlur: onLegendBlur,
508
+ onKeyDown: (event) => onLegendKey(event, index),
509
+ className: "donut-chart-row",
510
+ children: [
511
+ /* @__PURE__ */ jsx("span", {
512
+ "aria-hidden": "true",
513
+ className: "donut-chart-dot"
514
+ }),
515
+ /* @__PURE__ */ jsxs("span", {
516
+ className: "grid min-w-0",
517
+ children: [/* @__PURE__ */ jsx("span", {
518
+ className: "donut-chart-row-label truncate",
519
+ children: item.label
520
+ }), item.members ? /* @__PURE__ */ jsx("span", {
521
+ className: "truncate text-xs text-muted-foreground",
522
+ children: members(item)
523
+ }) : null]
524
+ }),
525
+ /* @__PURE__ */ jsx("span", {
526
+ "aria-hidden": "true",
527
+ className: "donut-chart-row-value justify-self-end tabular-nums text-text-secondary",
528
+ children: /* @__PURE__ */ jsx(Count, {
529
+ value: item.value,
530
+ format: formatValue
531
+ })
532
+ }),
533
+ showShare ? /* @__PURE__ */ jsx("span", {
534
+ "aria-hidden": "true",
535
+ className: "donut-chart-row-value justify-self-end font-medium tabular-nums",
536
+ children: /* @__PURE__ */ jsx(Count, {
537
+ value: off || !total ? 0 : item.value / total,
538
+ format: shareText
539
+ })
540
+ }) : null
541
+ ]
542
+ })
543
+ }, item.key);
544
+ })
545
+ }) : null,
546
+ /* @__PURE__ */ jsx("p", {
547
+ className: "sr-only",
548
+ children: summary
549
+ }),
550
+ /* @__PURE__ */ jsx("p", {
551
+ className: "sr-only",
552
+ "aria-live": "polite",
553
+ children: announcement
554
+ }),
555
+ total > 0 ? /* @__PURE__ */ jsx("div", {
556
+ className: "sr-only",
557
+ children: /* @__PURE__ */ jsxs("table", { children: [
558
+ /* @__PURE__ */ jsx("caption", { children: label }),
559
+ /* @__PURE__ */ jsx("thead", { children: /* @__PURE__ */ jsxs("tr", { children: [
560
+ /* @__PURE__ */ jsx("th", {
561
+ scope: "col",
562
+ children: "Segment"
563
+ }),
564
+ /* @__PURE__ */ jsx("th", {
565
+ scope: "col",
566
+ children: "Value"
567
+ }),
568
+ showShare ? /* @__PURE__ */ jsx("th", {
569
+ scope: "col",
570
+ children: "Share"
571
+ }) : null
572
+ ] }) }),
573
+ /* @__PURE__ */ jsx("tbody", { children: visible.flatMap((item) => item.members ? item.members.map((member) => ({
574
+ key: member.key,
575
+ label: `${member.label} (${otherLabel})`,
576
+ value: member.value
577
+ })) : [item]).map((item) => /* @__PURE__ */ jsxs("tr", { children: [
578
+ /* @__PURE__ */ jsx("th", {
579
+ scope: "row",
580
+ children: item.label
581
+ }),
582
+ /* @__PURE__ */ jsx("td", { children: format(item.value) }),
583
+ showShare ? /* @__PURE__ */ jsx("td", { children: shareText(item.value / total) }) : null
584
+ ] }, item.key)) })
585
+ ] })
586
+ }) : null
587
+ ]
588
+ });
589
+ });
590
+ //#endregion
591
+ export { DonutChart };
592
+
593
+ //# sourceMappingURL=donut-chart.js.map