@devalok/shilp-sutra 0.38.0 → 0.40.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (361) hide show
  1. package/AGENTS.md +151 -0
  2. package/MIGRATION.md +255 -0
  3. package/README.md +3 -0
  4. package/dist/_chunks/badge-group.js +76 -75
  5. package/dist/_chunks/badge-group.js.map +1 -1
  6. package/dist/_chunks/chart-container.js +50 -0
  7. package/dist/_chunks/chart-container.js.map +1 -0
  8. package/dist/_chunks/chat.js +236 -228
  9. package/dist/_chunks/chat.js.map +1 -1
  10. package/dist/_chunks/colors.js +30 -0
  11. package/dist/_chunks/colors.js.map +1 -0
  12. package/dist/_chunks/document-preview.js +2 -2
  13. package/dist/_chunks/document-preview.js.map +1 -1
  14. package/dist/_chunks/emoji-data.js +45 -0
  15. package/dist/_chunks/emoji-data.js.map +1 -0
  16. package/dist/_chunks/grid-lines.js +72 -0
  17. package/dist/_chunks/grid-lines.js.map +1 -0
  18. package/dist/_chunks/image-preview.js +2 -2
  19. package/dist/_chunks/image-preview.js.map +1 -1
  20. package/dist/_chunks/mention-suggestion.js +35 -263
  21. package/dist/_chunks/mention-suggestion.js.map +1 -1
  22. package/dist/_chunks/normalize-icon.js +18 -0
  23. package/dist/_chunks/normalize-icon.js.map +1 -0
  24. package/dist/_chunks/oauth-button.js +227 -0
  25. package/dist/_chunks/oauth-button.js.map +1 -0
  26. package/dist/_chunks/popover.js +3 -3
  27. package/dist/_chunks/popover.js.map +1 -1
  28. package/dist/_chunks/primitives.js +107 -107
  29. package/dist/_chunks/primitives.js.map +1 -1
  30. package/dist/_chunks/shared.js +5 -5
  31. package/dist/_chunks/shared.js.map +1 -1
  32. package/dist/_chunks/{text.js → success.js} +26 -63
  33. package/dist/_chunks/success.js.map +1 -0
  34. package/dist/_chunks/tiptap.js +1952 -1949
  35. package/dist/_chunks/tiptap.js.map +1 -1
  36. package/dist/_chunks/tooltip.js +58 -0
  37. package/dist/_chunks/tooltip.js.map +1 -0
  38. package/dist/_chunks/tree-view.js +101 -96
  39. package/dist/_chunks/tree-view.js.map +1 -1
  40. package/dist/_chunks/use-calendar.js +5 -5
  41. package/dist/_chunks/use-calendar.js.map +1 -1
  42. package/dist/ai/ai-command-provider.d.ts +3 -2
  43. package/dist/ai/ai-command-provider.d.ts.map +1 -1
  44. package/dist/ai/ai-command-provider.js.map +1 -1
  45. package/dist/ai/block-renderer.js +11 -9
  46. package/dist/ai/block-renderer.js.map +1 -1
  47. package/dist/ai/blocks/error.js +31 -0
  48. package/dist/ai/blocks/error.js.map +1 -0
  49. package/dist/ai/blocks/index.d.ts +0 -2
  50. package/dist/ai/blocks/index.d.ts.map +1 -1
  51. package/dist/ai/blocks/index.js +2 -2
  52. package/dist/ai/blocks/text.js +19 -0
  53. package/dist/ai/blocks/text.js.map +1 -0
  54. package/dist/ai/command-bar.d.ts.map +1 -1
  55. package/dist/ai/command-bar.js +198 -193
  56. package/dist/ai/command-bar.js.map +1 -1
  57. package/dist/ai/conversation.d.ts +2 -1
  58. package/dist/ai/conversation.d.ts.map +1 -1
  59. package/dist/ai/conversation.js +92 -87
  60. package/dist/ai/conversation.js.map +1 -1
  61. package/dist/ai/index.d.ts +0 -4
  62. package/dist/ai/index.d.ts.map +1 -1
  63. package/dist/ai/index.js +45 -46
  64. package/dist/ai/index.js.map +1 -1
  65. package/dist/composed/activity-feed.d.ts +2 -1
  66. package/dist/composed/activity-feed.d.ts.map +1 -1
  67. package/dist/composed/activity-feed.js +5 -5
  68. package/dist/composed/activity-feed.js.map +1 -1
  69. package/dist/composed/avatar-group.js +4 -4
  70. package/dist/composed/avatar-group.js.map +1 -1
  71. package/dist/composed/bulk-action-bar.d.ts +2 -2
  72. package/dist/composed/bulk-action-bar.d.ts.map +1 -1
  73. package/dist/composed/bulk-action-bar.js +12 -12
  74. package/dist/composed/bulk-action-bar.js.map +1 -1
  75. package/dist/composed/command-palette.d.ts +2 -1
  76. package/dist/composed/command-palette.d.ts.map +1 -1
  77. package/dist/composed/command-palette.js +106 -101
  78. package/dist/composed/command-palette.js.map +1 -1
  79. package/dist/composed/content-card.js +1 -1
  80. package/dist/composed/content-card.js.map +1 -1
  81. package/dist/composed/date-picker/index.js +747 -3
  82. package/dist/composed/date-picker/index.js.map +1 -0
  83. package/dist/composed/emoji-picker.js +4 -4
  84. package/dist/composed/emoji-picker.js.map +1 -1
  85. package/dist/composed/empty-state.d.ts +3 -3
  86. package/dist/composed/empty-state.d.ts.map +1 -1
  87. package/dist/composed/empty-state.js +40 -31
  88. package/dist/composed/empty-state.js.map +1 -1
  89. package/dist/composed/error-boundary.js +3 -3
  90. package/dist/composed/error-boundary.js.map +1 -1
  91. package/dist/composed/extensions/emoji-node.js +81 -0
  92. package/dist/composed/extensions/emoji-node.js.map +1 -0
  93. package/dist/composed/extensions/emoji-suggestion.js +117 -0
  94. package/dist/composed/extensions/emoji-suggestion.js.map +1 -0
  95. package/dist/composed/file-preview.js +498 -2
  96. package/dist/composed/file-preview.js.map +1 -0
  97. package/dist/composed/filter-bar.js +1 -1
  98. package/dist/composed/filter-bar.js.map +1 -1
  99. package/dist/composed/index.d.ts +0 -15
  100. package/dist/composed/index.d.ts.map +1 -1
  101. package/dist/composed/index.js +16 -24
  102. package/dist/composed/inline-edit.js +1 -1
  103. package/dist/composed/inline-edit.js.map +1 -1
  104. package/dist/composed/loading-skeleton.js +9 -9
  105. package/dist/composed/loading-skeleton.js.map +1 -1
  106. package/dist/composed/markdown-viewer.js +3 -3
  107. package/dist/composed/markdown-viewer.js.map +1 -1
  108. package/dist/composed/multi-select-popover.js +1 -1
  109. package/dist/composed/multi-select-popover.js.map +1 -1
  110. package/dist/composed/page-header.js +1 -1
  111. package/dist/composed/page-header.js.map +1 -1
  112. package/dist/composed/page-skeletons.js +15 -15
  113. package/dist/composed/page-skeletons.js.map +1 -1
  114. package/dist/composed/priority-indicator.js +3 -3
  115. package/dist/composed/priority-indicator.js.map +1 -1
  116. package/dist/composed/rich-chat-input.js +2073 -2
  117. package/dist/composed/rich-chat-input.js.map +1 -0
  118. package/dist/composed/rich-text-editor.js +75 -72
  119. package/dist/composed/rich-text-editor.js.map +1 -1
  120. package/dist/composed/schedule-view.js +3 -3
  121. package/dist/composed/schedule-view.js.map +1 -1
  122. package/dist/composed/status-badge.d.ts +3 -2
  123. package/dist/composed/status-badge.d.ts.map +1 -1
  124. package/dist/composed/status-badge.js +58 -53
  125. package/dist/composed/status-badge.js.map +1 -1
  126. package/dist/shell/app-command-palette.d.ts +2 -1
  127. package/dist/shell/app-command-palette.d.ts.map +1 -1
  128. package/dist/shell/app-command-palette.js.map +1 -1
  129. package/dist/shell/bottom-navbar.d.ts +3 -1
  130. package/dist/shell/bottom-navbar.d.ts.map +1 -1
  131. package/dist/shell/bottom-navbar.js +94 -86
  132. package/dist/shell/bottom-navbar.js.map +1 -1
  133. package/dist/shell/command-registry.d.ts +2 -1
  134. package/dist/shell/command-registry.d.ts.map +1 -1
  135. package/dist/shell/command-registry.js.map +1 -1
  136. package/dist/shell/notification-center.js +8 -8
  137. package/dist/shell/notification-center.js.map +1 -1
  138. package/dist/shell/notification-preferences.js +1 -1
  139. package/dist/shell/notification-preferences.js.map +1 -1
  140. package/dist/shell/sidebar.d.ts +7 -4
  141. package/dist/shell/sidebar.d.ts.map +1 -1
  142. package/dist/shell/sidebar.js +148 -134
  143. package/dist/shell/sidebar.js.map +1 -1
  144. package/dist/shell/top-bar.d.ts +4 -3
  145. package/dist/shell/top-bar.d.ts.map +1 -1
  146. package/dist/shell/top-bar.js +116 -108
  147. package/dist/shell/top-bar.js.map +1 -1
  148. package/dist/tokens/semantic.css +82 -9
  149. package/dist/ui/accordion.js +1 -1
  150. package/dist/ui/accordion.js.map +1 -1
  151. package/dist/ui/alert-dialog.js +3 -3
  152. package/dist/ui/alert-dialog.js.map +1 -1
  153. package/dist/ui/alert.js +2 -2
  154. package/dist/ui/alert.js.map +1 -1
  155. package/dist/ui/autocomplete.js +2 -2
  156. package/dist/ui/autocomplete.js.map +1 -1
  157. package/dist/ui/avatar.js +11 -11
  158. package/dist/ui/avatar.js.map +1 -1
  159. package/dist/ui/badge-indicator.js +1 -1
  160. package/dist/ui/badge-indicator.js.map +1 -1
  161. package/dist/ui/badge.d.ts +3 -2
  162. package/dist/ui/badge.d.ts.map +1 -1
  163. package/dist/ui/banner.js +1 -1
  164. package/dist/ui/banner.js.map +1 -1
  165. package/dist/ui/breadcrumb.js +1 -1
  166. package/dist/ui/breadcrumb.js.map +1 -1
  167. package/dist/ui/button.d.ts +5 -4
  168. package/dist/ui/button.d.ts.map +1 -1
  169. package/dist/ui/button.js +66 -65
  170. package/dist/ui/button.js.map +1 -1
  171. package/dist/ui/card.js +5 -5
  172. package/dist/ui/card.js.map +1 -1
  173. package/dist/ui/charts/area-chart.js +177 -0
  174. package/dist/ui/charts/area-chart.js.map +1 -0
  175. package/dist/ui/charts/bar-chart.js +127 -0
  176. package/dist/ui/charts/bar-chart.js.map +1 -0
  177. package/dist/ui/charts/chart-container.js +3 -0
  178. package/dist/ui/charts/gauge-chart.js +72 -0
  179. package/dist/ui/charts/gauge-chart.js.map +1 -0
  180. package/dist/ui/charts/index.js +10 -1035
  181. package/dist/ui/charts/line-chart.js +135 -0
  182. package/dist/ui/charts/line-chart.js.map +1 -0
  183. package/dist/ui/charts/pie-chart.js +111 -0
  184. package/dist/ui/charts/pie-chart.js.map +1 -0
  185. package/dist/ui/charts/radar-chart.js +170 -0
  186. package/dist/ui/charts/radar-chart.js.map +1 -0
  187. package/dist/ui/charts/sparkline.js +119 -0
  188. package/dist/ui/charts/sparkline.js.map +1 -0
  189. package/dist/ui/chat/message.d.ts +3 -3
  190. package/dist/ui/chat/message.d.ts.map +1 -1
  191. package/dist/ui/chat/system-message.d.ts +2 -1
  192. package/dist/ui/chat/system-message.d.ts.map +1 -1
  193. package/dist/ui/checkbox.js +1 -1
  194. package/dist/ui/checkbox.js.map +1 -1
  195. package/dist/ui/code.js +2 -2
  196. package/dist/ui/code.js.map +1 -1
  197. package/dist/ui/color-input.js +10 -10
  198. package/dist/ui/color-input.js.map +1 -1
  199. package/dist/ui/color-swatch.js +3 -3
  200. package/dist/ui/color-swatch.js.map +1 -1
  201. package/dist/ui/combobox.d.ts +2 -1
  202. package/dist/ui/combobox.d.ts.map +1 -1
  203. package/dist/ui/combobox.js +100 -95
  204. package/dist/ui/combobox.js.map +1 -1
  205. package/dist/ui/container.d.ts +6 -1
  206. package/dist/ui/container.d.ts.map +1 -1
  207. package/dist/ui/container.js +2 -1
  208. package/dist/ui/container.js.map +1 -1
  209. package/dist/ui/context-menu.js +6 -6
  210. package/dist/ui/context-menu.js.map +1 -1
  211. package/dist/ui/data-table-body.js +1 -1
  212. package/dist/ui/data-table-body.js.map +1 -1
  213. package/dist/ui/data-table-bulk-actions.js +2 -2
  214. package/dist/ui/data-table-bulk-actions.js.map +1 -1
  215. package/dist/ui/data-table-card.js +2 -2
  216. package/dist/ui/data-table-card.js.map +1 -1
  217. package/dist/ui/data-table-header.js +2 -2
  218. package/dist/ui/data-table-header.js.map +1 -1
  219. package/dist/ui/data-table-pagination.js +3 -3
  220. package/dist/ui/data-table-pagination.js.map +1 -1
  221. package/dist/ui/data-table-toolbar.js +1 -1
  222. package/dist/ui/data-table-toolbar.js.map +1 -1
  223. package/dist/ui/data-table.js +1 -1
  224. package/dist/ui/data-table.js.map +1 -1
  225. package/dist/ui/devalok-grain.d.ts +1 -1
  226. package/dist/ui/devalok-grain.js.map +1 -1
  227. package/dist/ui/dialog.js +2 -2
  228. package/dist/ui/dialog.js.map +1 -1
  229. package/dist/ui/dropdown-menu.js +6 -6
  230. package/dist/ui/dropdown-menu.js.map +1 -1
  231. package/dist/ui/file-upload.js +4 -4
  232. package/dist/ui/file-upload.js.map +1 -1
  233. package/dist/ui/hover-card.js +1 -1
  234. package/dist/ui/hover-card.js.map +1 -1
  235. package/dist/ui/icon-button.d.ts +9 -2
  236. package/dist/ui/icon-button.d.ts.map +1 -1
  237. package/dist/ui/icon-button.js +14 -13
  238. package/dist/ui/icon-button.js.map +1 -1
  239. package/dist/ui/index.d.ts +1 -3
  240. package/dist/ui/index.d.ts.map +1 -1
  241. package/dist/ui/index.js +31 -33
  242. package/dist/ui/index.js.map +1 -1
  243. package/dist/ui/input-otp.js +1 -1
  244. package/dist/ui/input-otp.js.map +1 -1
  245. package/dist/ui/input.js +2 -2
  246. package/dist/ui/input.js.map +1 -1
  247. package/dist/ui/lib/icon-input.d.ts +42 -0
  248. package/dist/ui/lib/icon-input.d.ts.map +1 -0
  249. package/dist/ui/lib/normalize-icon.d.ts +39 -0
  250. package/dist/ui/lib/normalize-icon.d.ts.map +1 -0
  251. package/dist/ui/link.js +1 -1
  252. package/dist/ui/link.js.map +1 -1
  253. package/dist/ui/menubar.js +8 -8
  254. package/dist/ui/menubar.js.map +1 -1
  255. package/dist/ui/navigation-menu.js +3 -3
  256. package/dist/ui/navigation-menu.js.map +1 -1
  257. package/dist/ui/number-input.js +3 -3
  258. package/dist/ui/number-input.js.map +1 -1
  259. package/dist/ui/oauth-button/index.d.ts +3 -0
  260. package/dist/ui/oauth-button/index.d.ts.map +1 -0
  261. package/dist/ui/oauth-button/index.js +3 -0
  262. package/dist/ui/oauth-button/oauth-button.d.ts +208 -0
  263. package/dist/ui/oauth-button/oauth-button.d.ts.map +1 -0
  264. package/dist/ui/pagination.js +1 -1
  265. package/dist/ui/pagination.js.map +1 -1
  266. package/dist/ui/progress.js +2 -2
  267. package/dist/ui/progress.js.map +1 -1
  268. package/dist/ui/radio.js +1 -1
  269. package/dist/ui/radio.js.map +1 -1
  270. package/dist/ui/segmented-control.d.ts +3 -4
  271. package/dist/ui/segmented-control.d.ts.map +1 -1
  272. package/dist/ui/segmented-control.js +53 -45
  273. package/dist/ui/segmented-control.js.map +1 -1
  274. package/dist/ui/select.js +3 -3
  275. package/dist/ui/select.js.map +1 -1
  276. package/dist/ui/sheet.js +2 -2
  277. package/dist/ui/sheet.js.map +1 -1
  278. package/dist/ui/sidebar.js +11 -11
  279. package/dist/ui/sidebar.js.map +1 -1
  280. package/dist/ui/skeleton.js +9 -9
  281. package/dist/ui/skeleton.js.map +1 -1
  282. package/dist/ui/slider.js +2 -2
  283. package/dist/ui/slider.js.map +1 -1
  284. package/dist/ui/split-button.js +7 -7
  285. package/dist/ui/split-button.js.map +1 -1
  286. package/dist/ui/stack.d.ts +6 -1
  287. package/dist/ui/stack.d.ts.map +1 -1
  288. package/dist/ui/stack.js +2 -1
  289. package/dist/ui/stack.js.map +1 -1
  290. package/dist/ui/stat-card.d.ts +2 -3
  291. package/dist/ui/stat-card.d.ts.map +1 -1
  292. package/dist/ui/stat-card.js +118 -116
  293. package/dist/ui/stat-card.js.map +1 -1
  294. package/dist/ui/status-dot.js +2 -2
  295. package/dist/ui/status-dot.js.map +1 -1
  296. package/dist/ui/stepper.d.ts +2 -1
  297. package/dist/ui/stepper.d.ts.map +1 -1
  298. package/dist/ui/stepper.js +74 -69
  299. package/dist/ui/stepper.js.map +1 -1
  300. package/dist/ui/switch.js +2 -2
  301. package/dist/ui/switch.js.map +1 -1
  302. package/dist/ui/tabs.js +3 -3
  303. package/dist/ui/tabs.js.map +1 -1
  304. package/dist/ui/text.d.ts +7 -2
  305. package/dist/ui/text.d.ts.map +1 -1
  306. package/dist/ui/text.js +2 -1
  307. package/dist/ui/text.js.map +1 -1
  308. package/dist/ui/textarea.js +1 -1
  309. package/dist/ui/textarea.js.map +1 -1
  310. package/dist/ui/toast.js +8 -8
  311. package/dist/ui/toast.js.map +1 -1
  312. package/dist/ui/toaster.d.ts +11 -2
  313. package/dist/ui/toaster.d.ts.map +1 -1
  314. package/dist/ui/toaster.js.map +1 -1
  315. package/dist/ui/toggle.js +1 -1
  316. package/dist/ui/toggle.js.map +1 -1
  317. package/dist/ui/tooltip.js +12 -12
  318. package/dist/ui/tooltip.js.map +1 -1
  319. package/dist/ui/tree-view/tree-item.d.ts +3 -2
  320. package/dist/ui/tree-view/tree-item.d.ts.map +1 -1
  321. package/dist/ui/tree-view/use-tree.d.ts +2 -1
  322. package/dist/ui/tree-view/use-tree.d.ts.map +1 -1
  323. package/docs/components/_header.md +90 -1
  324. package/docs/components/ui/oauth-button.md +86 -0
  325. package/docs/recipes/customize-brand.md +100 -4
  326. package/docs/recipes/index.md +5 -1
  327. package/docs/recipes/install-astro.md +15 -0
  328. package/docs/recipes/install-next-app-router.md +21 -5
  329. package/docs/recipes/install-next-pages.md +2 -0
  330. package/docs/recipes/install-remix.md +15 -0
  331. package/docs/recipes/install-tanstack-start.md +15 -0
  332. package/docs/recipes/install-vite.md +15 -0
  333. package/docs/recipes/troubleshoot.md +22 -0
  334. package/llms-full.txt +177 -2
  335. package/llms-quick.txt +247 -0
  336. package/llms.txt +116 -3
  337. package/package.json +80 -2
  338. package/scripts/welcome.mjs +219 -0
  339. package/skill/README.md +99 -0
  340. package/skill/SKILL.md +163 -0
  341. package/skill/install.sh +59 -0
  342. package/skill/references/components-full.md +7083 -0
  343. package/skill/references/components.md +778 -0
  344. package/skill/references/customize-brand.md +314 -0
  345. package/skill/references/server-components.md +211 -0
  346. package/skill/references/setup-astro.md +195 -0
  347. package/skill/references/setup-next-app-router.md +248 -0
  348. package/skill/references/setup-next-pages.md +127 -0
  349. package/skill/references/setup-remix.md +188 -0
  350. package/skill/references/setup-tanstack-start.md +160 -0
  351. package/skill/references/setup-vite.md +187 -0
  352. package/skill/references/troubleshoot.md +241 -0
  353. package/dist/_chunks/date-picker.js +0 -748
  354. package/dist/_chunks/date-picker.js.map +0 -1
  355. package/dist/_chunks/file-preview.js +0 -499
  356. package/dist/_chunks/file-preview.js.map +0 -1
  357. package/dist/_chunks/rich-chat-input.js +0 -2071
  358. package/dist/_chunks/rich-chat-input.js.map +0 -1
  359. package/dist/_chunks/text.js.map +0 -1
  360. package/dist/ui/charts/index.js.map +0 -1
  361. /package/{LICENSE → skill/LICENSE} +0 -0
@@ -0,0 +1,135 @@
1
+ "use client";
2
+ import { motionProps as e, tweens as t } from "../lib/motion.js";
3
+ import { cn as n } from "../lib/utils.js";
4
+ import { n as r, r as i, t as a } from "../../_chunks/tooltip.js";
5
+ import { r as o, t as s } from "../../_chunks/colors.js";
6
+ import { n as c, t as l } from "../../_chunks/grid-lines.js";
7
+ import { t as u } from "../../_chunks/chart-container.js";
8
+ import * as d from "react";
9
+ import { Fragment as f, jsx as p, jsxs as m } from "react/jsx-runtime";
10
+ import { motion as h } from "framer-motion";
11
+ import { scaleLinear as g, scalePoint as _ } from "d3-scale";
12
+ import { curveLinear as v, curveMonotoneX as y, line as b } from "d3-shape";
13
+ //#region src/ui/charts/line-chart.tsx
14
+ var x = d.forwardRef(({ data: d, xKey: x, series: S, curved: C = !1, showDots: w = !1, dotSize: T = 4, strokeWidth: E = 2, height: D = 300, showGrid: O = !0, showTooltip: k = !0, showLegend: A = !1, animate: j = !0, xLabel: M, yLabel: N, ariaLabel: P, className: F, ...I }, L) => {
15
+ let { tooltip: R, show: z, hide: B } = r(), V = o(), H = j && !V, U = S.map((e, t) => s(e.color, t));
16
+ return /* @__PURE__ */ m(h.div, {
17
+ ref: L,
18
+ className: n("relative", F),
19
+ ...H ? {
20
+ initial: {
21
+ opacity: 0,
22
+ scale: .96
23
+ },
24
+ animate: {
25
+ opacity: 1,
26
+ scale: 1
27
+ },
28
+ transition: t.fade
29
+ } : {},
30
+ ...e(I),
31
+ children: [
32
+ /* @__PURE__ */ p(u, {
33
+ height: D,
34
+ ariaLabel: P ?? "Line chart",
35
+ children: ({ width: e, height: t, margin: n }) => {
36
+ let r = d.map((e) => e[x]), i = r.every((e) => typeof e == "number"), a, o;
37
+ if (i) {
38
+ let t = r, n = Math.min(...t), i = Math.max(...t), s = g().domain([n, i]).range([0, e]);
39
+ a = s, o = (e) => s(Number(e[x]));
40
+ } else {
41
+ let t = r.map(String), n = _().domain(t).range([0, e]).padding(.5);
42
+ a = n, o = (e) => n(String(e[x])) ?? 0;
43
+ }
44
+ let s = d.flatMap((e) => S.map((t) => Number(e[t.key]) || 0)), u = Math.max(...s), h = g().domain([0, u * 1.1]).range([t, 0]).nice(), D = C ? y : v, A = b().curve(D).defined((e) => e != null);
45
+ return /* @__PURE__ */ m(f, { children: [
46
+ /* @__PURE__ */ p("desc", { children: d.map((e) => `${String(e[x])} — ${S.map((t) => `${t.label}: ${Number(e[t.key]).toLocaleString()}`).join(", ")}`).join(". ") }),
47
+ O && /* @__PURE__ */ p(l, {
48
+ width: e,
49
+ height: t,
50
+ yScale: h,
51
+ horizontal: !0
52
+ }),
53
+ S.map((e, t) => /* @__PURE__ */ m("g", { children: [/* @__PURE__ */ p("path", {
54
+ d: A.x((e) => o(e)).y((t) => h(Number(t[e.key]) || 0))(d) ?? "",
55
+ fill: "none",
56
+ stroke: U[t],
57
+ strokeWidth: E,
58
+ strokeLinejoin: "round",
59
+ strokeLinecap: "round"
60
+ }), w && d.map((n, r) => /* @__PURE__ */ p("circle", {
61
+ cx: o(n),
62
+ cy: h(Number(n[e.key]) || 0),
63
+ r: T,
64
+ fill: U[t],
65
+ className: "transition-opacity hover:opacity-80"
66
+ }, `${e.key}-dot-${r}`))] }, e.key)),
67
+ k && d.map((n, r) => {
68
+ let i = o(n), a = e / Math.max(d.length - 1, 1), s = String(n[x]), c = `${s}: ${S.map((e) => `${e.label} ${Number(n[e.key]).toLocaleString()}`).join(", ")}`, l = /* @__PURE__ */ m("div", { children: [/* @__PURE__ */ p("div", {
69
+ className: "font-medium",
70
+ children: s
71
+ }), S.map((e, t) => /* @__PURE__ */ m("div", {
72
+ className: "flex items-center gap-ds-02",
73
+ children: [
74
+ /* @__PURE__ */ p("span", {
75
+ className: "inline-block h-2 w-2 rounded-pill",
76
+ style: { backgroundColor: U[t] }
77
+ }),
78
+ /* @__PURE__ */ m("span", {
79
+ className: "text-surface-fg-muted",
80
+ children: [e.label, ":"]
81
+ }),
82
+ " ",
83
+ Number(n[e.key]).toLocaleString()
84
+ ]
85
+ }, e.key))] });
86
+ return /* @__PURE__ */ p("rect", {
87
+ x: i - a / 2,
88
+ y: 0,
89
+ width: a,
90
+ height: t,
91
+ fill: "transparent",
92
+ tabIndex: 0,
93
+ role: "graphics-symbol",
94
+ "aria-label": c,
95
+ className: "focus-visible:outline-hidden",
96
+ onMouseMove: (e) => {
97
+ let t = e.currentTarget.closest("div")?.getBoundingClientRect();
98
+ z(e.clientX - (t?.left ?? 0), e.clientY - (t?.top ?? 0), l);
99
+ },
100
+ onMouseLeave: B,
101
+ onFocus: (e) => {
102
+ let t = e.currentTarget.closest("div")?.getBoundingClientRect(), n = e.currentTarget.getBoundingClientRect();
103
+ z(n.left + n.width / 2 - (t?.left ?? 0), n.top + n.height / 2 - (t?.top ?? 0), l);
104
+ },
105
+ onBlur: B
106
+ }, `hover-${r}`);
107
+ }),
108
+ /* @__PURE__ */ p(c, {
109
+ scale: a,
110
+ orientation: "bottom",
111
+ transform: `translate(0,${t})`,
112
+ label: M
113
+ }),
114
+ /* @__PURE__ */ p(c, {
115
+ scale: h,
116
+ orientation: "left",
117
+ label: N
118
+ })
119
+ ] });
120
+ }
121
+ }),
122
+ k && /* @__PURE__ */ p(a, { state: R }),
123
+ A && S.length > 1 && /* @__PURE__ */ p(i, {
124
+ items: S.map((e, t) => ({
125
+ label: e.label,
126
+ color: U[t]
127
+ })),
128
+ className: "mt-ds-04"
129
+ })
130
+ ]
131
+ });
132
+ });
133
+ x.displayName = "LineChart";
134
+ //#endregion
135
+ export { x as LineChart };
@@ -0,0 +1 @@
1
+ {"version":3,"file":"line-chart.js","names":[],"sources":["../../../src/ui/charts/line-chart.tsx"],"sourcesContent":["'use client'\n\nimport type { ScaleLinear, ScalePoint } from 'd3-scale'\nimport { scaleLinear, scalePoint } from 'd3-scale'\nimport { curveLinear,curveMonotoneX, line } from 'd3-shape'\nimport { motion } from 'framer-motion'\nimport * as React from 'react'\n\nimport { motionProps,tweens } from '../lib/motion'\nimport { cn } from '../lib/utils'\nimport { useReducedMotion } from './_internal/animation'\nimport { type AnyScale,Axis } from './_internal/axes'\nimport { resolveColor } from './_internal/colors'\nimport { GridLines } from './_internal/grid-lines'\nimport { Legend } from './_internal/legend'\nimport { ChartTooltip, useChartTooltip } from './_internal/tooltip'\nimport type { DataPoint, Series } from './_internal/types'\nimport { ChartContainer } from './chart-container'\n\nexport interface LineChartProps extends Omit<React.HTMLAttributes<HTMLDivElement>, 'children'> {\n /** Data array */\n data: DataPoint[]\n /** Key for x-axis */\n xKey: string\n /** Series definitions — each becomes a line */\n series: Series[]\n /** Use curved (monotone) interpolation */\n curved?: boolean\n /** Show dots at data points */\n showDots?: boolean\n /** Dot radius */\n dotSize?: number\n /** Line stroke width */\n strokeWidth?: number\n /** Chart height */\n height?: number\n /** Show grid lines */\n showGrid?: boolean\n /** Show tooltip on hover */\n showTooltip?: boolean\n /** Show legend */\n showLegend?: boolean\n /** Animate on mount */\n animate?: boolean\n /** X-axis label */\n xLabel?: string\n /** Y-axis label */\n yLabel?: string\n /** Accessible label for the chart */\n ariaLabel?: string\n className?: string\n}\n\nexport const LineChart = React.forwardRef<HTMLDivElement, LineChartProps>(\n (\n {\n data,\n xKey,\n series,\n curved = false,\n showDots = false,\n dotSize = 4,\n strokeWidth = 2,\n height = 300,\n showGrid = true,\n showTooltip = true,\n showLegend = false,\n animate = true,\n xLabel,\n yLabel,\n ariaLabel,\n className,\n ...props\n },\n ref,\n ) => {\n const { tooltip, show, hide } = useChartTooltip()\n const reducedMotion = useReducedMotion()\n const shouldAnimate = animate && !reducedMotion\n\n // Resolve colors for each series\n const colors = series.map((s, i) => resolveColor(s.color, i))\n\n return (\n <motion.div\n ref={ref}\n className={cn('relative', className)}\n {...(shouldAnimate\n ? { initial: { opacity: 0, scale: 0.96 }, animate: { opacity: 1, scale: 1 }, transition: tweens.fade }\n : {})}\n {...motionProps(props)}\n >\n <ChartContainer height={height} ariaLabel={ariaLabel ?? 'Line chart'}>\n {({ width, height: innerHeight, margin }) => {\n void margin\n\n // Determine if x-axis data is numeric or categorical\n const xValues = data.map((d) => d[xKey])\n const isNumericX = xValues.every((v) => typeof v === 'number')\n\n // Build x scale and accessor\n let xAxisScale: ScaleLinear<number, number> | ScalePoint<string>\n let getX: (d: DataPoint) => number\n\n if (isNumericX) {\n const numericValues = xValues as number[]\n const xMin = Math.min(...numericValues)\n const xMax = Math.max(...numericValues)\n const linearX = scaleLinear<number, number>()\n .domain([xMin, xMax])\n .range([0, width])\n xAxisScale = linearX\n getX = (d: DataPoint) => linearX(Number(d[xKey]))\n } else {\n const categories = xValues.map(String)\n const pointX = scalePoint<string>()\n .domain(categories)\n .range([0, width])\n .padding(0.5)\n xAxisScale = pointX\n getX = (d: DataPoint) => pointX(String(d[xKey])) ?? 0\n }\n\n // Build y scale across all series\n const allValues = data.flatMap((d) =>\n series.map((s) => Number(d[s.key]) || 0),\n )\n const yMax = Math.max(...allValues)\n const yScale = scaleLinear<number, number>()\n .domain([0, yMax * 1.1])\n .range([innerHeight, 0])\n .nice()\n\n // Line generator\n const curveType = curved ? curveMonotoneX : curveLinear\n const lineGen = line<DataPoint>()\n .curve(curveType)\n .defined((d) => d !== undefined && d !== null)\n\n // Build data summary for screen readers\n const dataSummary = data.map((d) => {\n const xVal = String(d[xKey])\n const vals = series.map((s) =>\n `${s.label}: ${Number(d[s.key]).toLocaleString()}`\n ).join(', ')\n return `${xVal} — ${vals}`\n }).join('. ')\n\n return (\n <>\n {/* Screen-reader data summary */}\n <desc>{dataSummary}</desc>\n\n {/* Grid */}\n {showGrid && (\n <GridLines\n width={width}\n height={innerHeight}\n yScale={yScale}\n horizontal\n />\n )}\n\n {/* Lines */}\n {series.map((s, seriesIdx) => {\n const pathGen = lineGen\n .x((d) => getX(d))\n .y((d) => yScale(Number(d[s.key]) || 0))\n\n const pathD = pathGen(data) ?? ''\n\n return (\n <g key={s.key}>\n {/* Line path */}\n <path\n d={pathD}\n fill=\"none\"\n stroke={colors[seriesIdx]}\n strokeWidth={strokeWidth}\n strokeLinejoin=\"round\"\n strokeLinecap=\"round\"\n />\n\n {/* Data point dots */}\n {showDots &&\n data.map((d, i) => {\n const cx = getX(d)\n const cy = yScale(Number(d[s.key]) || 0)\n return (\n <circle\n key={`${s.key}-dot-${i}`}\n cx={cx}\n cy={cy}\n r={dotSize}\n fill={colors[seriesIdx]}\n className=\"transition-opacity hover:opacity-80\"\n />\n )\n })}\n </g>\n )\n })}\n\n {/* Invisible hover/focus rectangles for tooltip */}\n {showTooltip &&\n data.map((d, i) => {\n const cx = getX(d)\n const sliceWidth = width / Math.max(data.length - 1, 1)\n const xVal = String(d[xKey])\n const pointAriaLabel = `${xVal}: ${series.map((s) => `${s.label} ${Number(d[s.key]).toLocaleString()}`).join(', ')}`\n\n const tooltipContent = (\n <div>\n <div className=\"font-medium\">{xVal}</div>\n {series.map((s, sIdx) => (\n <div\n key={s.key}\n className=\"flex items-center gap-ds-02\"\n >\n <span\n className=\"inline-block h-2 w-2 rounded-pill\"\n style={{ backgroundColor: colors[sIdx] }}\n />\n <span className=\"text-surface-fg-muted\">\n {s.label}:\n </span>{' '}\n {Number(d[s.key]).toLocaleString()}\n </div>\n ))}\n </div>\n )\n\n return (\n <rect\n key={`hover-${i}`}\n x={cx - sliceWidth / 2}\n y={0}\n width={sliceWidth}\n height={innerHeight}\n fill=\"transparent\"\n tabIndex={0}\n role=\"graphics-symbol\"\n aria-label={pointAriaLabel}\n className=\"focus-visible:outline-hidden\"\n onMouseMove={(e) => {\n const rect = e.currentTarget\n .closest('div')\n ?.getBoundingClientRect()\n show(\n e.clientX - (rect?.left ?? 0),\n e.clientY - (rect?.top ?? 0),\n tooltipContent,\n )\n }}\n onMouseLeave={hide}\n onFocus={(e) => {\n const svgRect = e.currentTarget\n .closest('div')\n ?.getBoundingClientRect()\n const sliceRect = e.currentTarget.getBoundingClientRect()\n show(\n sliceRect.left + sliceRect.width / 2 - (svgRect?.left ?? 0),\n sliceRect.top + sliceRect.height / 2 - (svgRect?.top ?? 0),\n tooltipContent,\n )\n }}\n onBlur={hide}\n />\n )\n })}\n\n {/* Axes */}\n <Axis\n scale={xAxisScale as AnyScale}\n orientation=\"bottom\"\n transform={`translate(0,${innerHeight})`}\n label={xLabel}\n />\n <Axis scale={yScale} orientation=\"left\" label={yLabel} />\n </>\n )\n }}\n </ChartContainer>\n\n {/* Tooltip overlay */}\n {showTooltip && <ChartTooltip state={tooltip} />}\n\n {/* Legend */}\n {showLegend && series.length > 1 && (\n <Legend\n items={series.map((s, i) => ({\n label: s.label,\n color: colors[i],\n }))}\n className=\"mt-ds-04\"\n />\n )}\n </motion.div>\n )\n },\n)\nLineChart.displayName = 'LineChart'\n"],"mappings":"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"}
@@ -0,0 +1,111 @@
1
+ "use client";
2
+ import { motionProps as e, tweens as t } from "../lib/motion.js";
3
+ import { cn as n } from "../lib/utils.js";
4
+ import { n as r, r as i, t as a } from "../../_chunks/tooltip.js";
5
+ import { r as o, t as s } from "../../_chunks/colors.js";
6
+ import * as c from "react";
7
+ import { useEffect as l, useRef as u, useState as d } from "react";
8
+ import { Fragment as f, jsx as p, jsxs as m } from "react/jsx-runtime";
9
+ import { motion as h } from "framer-motion";
10
+ import { arc as g, pie as _ } from "d3-shape";
11
+ //#region src/ui/charts/pie-chart.tsx
12
+ var v = c.forwardRef(({ data: c, variant: v = "pie", innerRadius: y = .6, padAngle: b = 0, cornerRadius: x = 0, height: S = 300, showTooltip: C = !0, showLegend: w = !1, showLabels: T = !1, animate: E = !0, className: D, centerLabel: O, ariaLabel: k, ...A }, j) => {
13
+ let M = u(null), [N, P] = d(0), [F, I] = d(null), { tooltip: L, show: R, hide: z } = r(), B = o(), V = E && !B;
14
+ l(() => {
15
+ if (!M.current) return;
16
+ let e = new ResizeObserver((e) => {
17
+ let t = e[0];
18
+ t && P(t.contentRect.width);
19
+ });
20
+ return e.observe(M.current), () => e.disconnect();
21
+ }, []);
22
+ let H = (N > 0 ? Math.min(N, S) : S) / 2, U = v === "donut" ? H * y : 0, W = c.map((e, t) => s(e.color, t)), G = c.reduce((e, t) => e + t.value, 0), K = _().value((e) => e.value).padAngle(b).sort(null)(c), q = g().innerRadius(U).outerRadius(H - 2).cornerRadius(x), J = U + (H - 2 - U) * .7, Y = g().innerRadius(J).outerRadius(J);
23
+ return /* @__PURE__ */ m(h.div, {
24
+ ref: (e) => {
25
+ M.current = e, typeof j == "function" ? j(e) : j && (j.current = e);
26
+ },
27
+ className: n("relative w-full", D),
28
+ ...V ? {
29
+ initial: {
30
+ opacity: 0,
31
+ scale: .96
32
+ },
33
+ animate: {
34
+ opacity: 1,
35
+ scale: 1
36
+ },
37
+ transition: t.fade
38
+ } : {},
39
+ ...e(A),
40
+ children: [N > 0 && /* @__PURE__ */ m(f, { children: [/* @__PURE__ */ p("svg", {
41
+ width: N,
42
+ height: S,
43
+ role: "img",
44
+ "aria-label": k ?? "Pie chart",
45
+ children: /* @__PURE__ */ m("g", {
46
+ transform: `translate(${N / 2},${S / 2})`,
47
+ children: [
48
+ K.map((e, t) => {
49
+ let n = q(e);
50
+ if (!n) return null;
51
+ let [r, i] = q.centroid(e), a = Math.atan2(i, r), o = Math.cos(a) * 4, s = Math.sin(a) * 4, c = F === t;
52
+ return /* @__PURE__ */ p("path", {
53
+ d: n,
54
+ fill: W[t],
55
+ className: "cursor-pointer transition-transform",
56
+ style: { transform: c ? `translate(${o}px, ${s}px)` : void 0 },
57
+ onMouseEnter: () => I(t),
58
+ onMouseMove: (t) => {
59
+ if (C) {
60
+ let n = t.currentTarget.closest("div")?.getBoundingClientRect(), r = G > 0 ? (e.data.value / G * 100).toFixed(1) : "0";
61
+ R(t.clientX - (n?.left ?? 0), t.clientY - (n?.top ?? 0), /* @__PURE__ */ m("div", { children: [/* @__PURE__ */ p("div", {
62
+ className: "font-medium",
63
+ children: e.data.label
64
+ }), /* @__PURE__ */ m("div", { children: [
65
+ e.data.value.toLocaleString(),
66
+ " (",
67
+ r,
68
+ "%)"
69
+ ] })] }));
70
+ }
71
+ },
72
+ onMouseLeave: () => {
73
+ I(null), z();
74
+ }
75
+ }, `slice-${e.data.label}-${t}`);
76
+ }),
77
+ T && K.map((e, t) => {
78
+ let [n, r] = Y.centroid(e), i = G > 0 ? (e.data.value / G * 100).toFixed(0) : "0";
79
+ return G > 0 && e.data.value / G < .03 ? null : /* @__PURE__ */ m("text", {
80
+ x: n,
81
+ y: r,
82
+ textAnchor: "middle",
83
+ dominantBaseline: "central",
84
+ className: "pointer-events-none fill-accent-fg text-ds-xs font-medium",
85
+ children: [i, "%"]
86
+ }, `label-${e.data.label}-${t}`);
87
+ }),
88
+ v === "donut" && O && U > 0 && /* @__PURE__ */ p("foreignObject", {
89
+ x: -U * .7,
90
+ y: -U * .7,
91
+ width: U * 1.4,
92
+ height: U * 1.4,
93
+ children: /* @__PURE__ */ p("div", {
94
+ className: "flex h-full w-full items-center justify-center text-center text-surface-fg",
95
+ children: O
96
+ })
97
+ })
98
+ ]
99
+ })
100
+ }), C && /* @__PURE__ */ p(a, { state: L })] }), w && /* @__PURE__ */ p(i, {
101
+ items: c.map((e, t) => ({
102
+ label: e.label,
103
+ color: W[t]
104
+ })),
105
+ className: "mt-ds-04"
106
+ })]
107
+ });
108
+ });
109
+ v.displayName = "PieChart";
110
+ //#endregion
111
+ export { v as PieChart };
@@ -0,0 +1 @@
1
+ {"version":3,"file":"pie-chart.js","names":[],"sources":["../../../src/ui/charts/pie-chart.tsx"],"sourcesContent":["'use client'\n\nimport type { PieArcDatum } from 'd3-shape'\nimport { arc as d3Arc,pie as d3Pie } from 'd3-shape'\nimport { motion } from 'framer-motion'\nimport * as React from 'react'\nimport { useEffect,useRef, useState } from 'react'\n\nimport { motionProps,tweens } from '../lib/motion'\nimport { cn } from '../lib/utils'\nimport { useReducedMotion } from './_internal/animation'\nimport { resolveColor } from './_internal/colors'\nimport { Legend } from './_internal/legend'\nimport { ChartTooltip, useChartTooltip } from './_internal/tooltip'\n\ninterface PieSlice {\n label: string\n value: number\n color?: string\n}\n\nexport interface PieChartProps extends Omit<React.HTMLAttributes<HTMLDivElement>, 'children'> {\n /** Data with label and value */\n data: PieSlice[]\n /** Pie or donut variant */\n variant?: 'pie' | 'donut'\n /** Inner radius ratio for donut (0-1, default 0.6) */\n innerRadius?: number\n /** Gap angle between slices in radians */\n padAngle?: number\n /** Corner radius for slice edges */\n cornerRadius?: number\n /** Chart height (and width, since pie is square) */\n height?: number\n /** Show tooltip on hover */\n showTooltip?: boolean\n /** Show legend */\n showLegend?: boolean\n /** Show percentage labels on/near slices */\n showLabels?: boolean\n /** Animate slices */\n animate?: boolean\n className?: string\n /** Content to show in center of donut */\n centerLabel?: React.ReactNode\n /** Accessible label for the chart */\n ariaLabel?: string\n}\n\nexport const PieChart = React.forwardRef<HTMLDivElement, PieChartProps>(\n (\n {\n data,\n variant = 'pie',\n innerRadius: innerRadiusRatio = 0.6,\n padAngle = 0,\n cornerRadius = 0,\n height = 300,\n showTooltip = true,\n showLegend = false,\n showLabels = false,\n animate = true,\n className,\n centerLabel,\n ariaLabel,\n ...props\n },\n ref,\n ) => {\n const containerRef = useRef<HTMLDivElement>(null)\n const [containerWidth, setContainerWidth] = useState(0)\n const [hoveredIndex, setHoveredIndex] = useState<number | null>(null)\n const { tooltip, show, hide } = useChartTooltip()\n const reducedMotion = useReducedMotion()\n const shouldAnimate = animate && !reducedMotion\n\n useEffect(() => {\n if (!containerRef.current) return\n const observer = new ResizeObserver((entries) => {\n const entry = entries[0]\n if (entry) setContainerWidth(entry.contentRect.width)\n })\n observer.observe(containerRef.current)\n return () => observer.disconnect()\n }, [])\n\n // Pie chart is square — use the smaller of width/height\n const size = containerWidth > 0 ? Math.min(containerWidth, height) : height\n const outerRadius = size / 2\n const innerR = variant === 'donut' ? outerRadius * innerRadiusRatio : 0\n\n // Resolve colors for each slice\n const colors = data.map((d, i) => resolveColor(d.color, i))\n\n // Compute total for percentages\n const total = data.reduce((sum, d) => sum + d.value, 0)\n\n // D3 pie layout\n const pieLayout = d3Pie<PieSlice>()\n .value((d) => d.value)\n .padAngle(padAngle)\n .sort(null)\n\n const arcs = pieLayout(data)\n\n // D3 arc generator\n const arcGenerator = d3Arc<PieArcDatum<PieSlice>>()\n .innerRadius(innerR)\n .outerRadius(outerRadius - 2) // slight inset so hover offset doesn't clip\n .cornerRadius(cornerRadius)\n\n // Label arc — position labels at 70% of the way from inner to outer radius\n const labelRadius = innerR + (outerRadius - 2 - innerR) * 0.7\n const labelArc = d3Arc<PieArcDatum<PieSlice>>()\n .innerRadius(labelRadius)\n .outerRadius(labelRadius)\n\n return (\n <motion.div\n ref={(node) => {\n (containerRef as React.MutableRefObject<HTMLDivElement | null>).current = node\n if (typeof ref === 'function') ref(node)\n else if (ref) (ref as React.MutableRefObject<HTMLDivElement | null>).current = node\n }}\n className={cn('relative w-full', className)}\n {...(shouldAnimate\n ? { initial: { opacity: 0, scale: 0.96 }, animate: { opacity: 1, scale: 1 }, transition: tweens.fade }\n : {})}\n {...motionProps(props)}\n >\n {containerWidth > 0 && (\n <>\n <svg\n width={containerWidth}\n height={height}\n role=\"img\"\n aria-label={ariaLabel ?? 'Pie chart'}\n >\n <g transform={`translate(${containerWidth / 2},${height / 2})`}>\n {arcs.map((d, i) => {\n const path = arcGenerator(d)\n if (!path) return null\n\n // Hover offset: push slice outward along its centroid angle\n const [cx, cy] = arcGenerator.centroid(d)\n const angle = Math.atan2(cy, cx)\n const offsetX = Math.cos(angle) * 4\n const offsetY = Math.sin(angle) * 4\n const isHovered = hoveredIndex === i\n\n return (\n <path\n key={`slice-${d.data.label}-${i}`}\n d={path}\n fill={colors[i]}\n className=\"cursor-pointer transition-transform\"\n style={{\n transform: isHovered\n ? `translate(${offsetX}px, ${offsetY}px)`\n : undefined,\n }}\n onMouseEnter={() => setHoveredIndex(i)}\n onMouseMove={(e) => {\n if (showTooltip) {\n const rect = e.currentTarget\n .closest('div')\n ?.getBoundingClientRect()\n const pct =\n total > 0\n ? ((d.data.value / total) * 100).toFixed(1)\n : '0'\n show(\n e.clientX - (rect?.left ?? 0),\n e.clientY - (rect?.top ?? 0),\n <div>\n <div className=\"font-medium\">{d.data.label}</div>\n <div>\n {d.data.value.toLocaleString()} ({pct}%)\n </div>\n </div>,\n )\n }\n }}\n onMouseLeave={() => {\n setHoveredIndex(null)\n hide()\n }}\n />\n )\n })}\n\n {/* Percentage labels */}\n {showLabels &&\n arcs.map((d, i) => {\n const [lx, ly] = labelArc.centroid(d)\n const pct =\n total > 0\n ? ((d.data.value / total) * 100).toFixed(0)\n : '0'\n\n // Skip tiny slices (< 3%) to avoid label overlap\n if (total > 0 && d.data.value / total < 0.03) return null\n\n return (\n <text\n key={`label-${d.data.label}-${i}`}\n x={lx}\n y={ly}\n textAnchor=\"middle\"\n dominantBaseline=\"central\"\n className=\"pointer-events-none fill-accent-fg text-ds-xs font-medium\"\n >\n {pct}%\n </text>\n )\n })}\n\n {/* Center label for donut variant */}\n {variant === 'donut' && centerLabel && innerR > 0 && (\n <foreignObject\n x={-innerR * 0.7}\n y={-innerR * 0.7}\n width={innerR * 1.4}\n height={innerR * 1.4}\n >\n <div className=\"flex h-full w-full items-center justify-center text-center text-surface-fg\">\n {centerLabel}\n </div>\n </foreignObject>\n )}\n </g>\n </svg>\n\n {/* Tooltip overlay */}\n {showTooltip && <ChartTooltip state={tooltip} />}\n </>\n )}\n\n {/* Legend */}\n {showLegend && (\n <Legend\n items={data.map((d, i) => ({\n label: d.label,\n color: colors[i],\n }))}\n className=\"mt-ds-04\"\n />\n )}\n </motion.div>\n )\n },\n)\nPieChart.displayName = 'PieChart'\n"],"mappings":"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"}
@@ -0,0 +1,170 @@
1
+ "use client";
2
+ import { motionProps as e, tweens as t } from "../lib/motion.js";
3
+ import { cn as n } from "../lib/utils.js";
4
+ import { n as r, r as i, t as a } from "../../_chunks/tooltip.js";
5
+ import { r as o, t as s } from "../../_chunks/colors.js";
6
+ import * as c from "react";
7
+ import { useEffect as l, useRef as u, useState as d } from "react";
8
+ import { Fragment as f, jsx as p, jsxs as m } from "react/jsx-runtime";
9
+ import { motion as h } from "framer-motion";
10
+ import { curveLinearClosed as g, lineRadial as _ } from "d3-shape";
11
+ //#region src/ui/charts/radar-chart.tsx
12
+ var v = c.forwardRef(({ data: c, axes: v, series: y, maxValue: b, levels: x = 5, fillOpacity: S = .25, showDots: C = !1, height: w = 300, showTooltip: T = !0, showLegend: E = !1, animate: D = !0, ariaLabel: O, className: k, ...A }, j) => {
13
+ let M = u(null), [N, P] = d(0), { tooltip: F, show: I, hide: L } = r(), R = o(), z = D && !R;
14
+ l(() => {
15
+ if (!M.current) return;
16
+ let e = new ResizeObserver((e) => {
17
+ let t = e[0];
18
+ t && P(t.contentRect.width);
19
+ });
20
+ return e.observe(M.current), () => e.disconnect();
21
+ }, []);
22
+ let B = (N > 0 ? Math.min(N, w) : w) / 2 - 40, V = y.map((e, t) => s(e.color, t)), H = b ?? Math.max(...c.flatMap((e) => y.map((t) => Number(e[t.key]) || 0)), 1), U = 2 * Math.PI / v.length, W = _().radius((e) => B * e / H).angle((e, t) => t * U).curve(g), G = (e) => v.map((t, n) => Number(c[n]?.[e]) || 0), K = (e, t) => {
23
+ let n = U * e - Math.PI / 2, r = B * t / H;
24
+ return {
25
+ x: r * Math.cos(n),
26
+ y: r * Math.sin(n)
27
+ };
28
+ };
29
+ return /* @__PURE__ */ m(h.div, {
30
+ ref: (e) => {
31
+ M.current = e, typeof j == "function" ? j(e) : j && (j.current = e);
32
+ },
33
+ className: n("relative w-full", k),
34
+ ...z ? {
35
+ initial: {
36
+ opacity: 0,
37
+ scale: .96
38
+ },
39
+ animate: {
40
+ opacity: 1,
41
+ scale: 1
42
+ },
43
+ transition: t.fade
44
+ } : {},
45
+ ...e(A),
46
+ children: [N > 0 && /* @__PURE__ */ m(f, { children: [/* @__PURE__ */ p("svg", {
47
+ width: N,
48
+ height: w,
49
+ role: "img",
50
+ "aria-label": O ?? "Radar chart",
51
+ children: /* @__PURE__ */ m("g", {
52
+ transform: `translate(${N / 2},${w / 2})`,
53
+ children: [
54
+ Array.from({ length: x }, (e, t) => {
55
+ let n = B / x * (t + 1);
56
+ return /* @__PURE__ */ p("polygon", {
57
+ points: v.map((e, t) => {
58
+ let r = U * t - Math.PI / 2;
59
+ return `${n * Math.cos(r)},${n * Math.sin(r)}`;
60
+ }).join(" "),
61
+ fill: "none",
62
+ stroke: "var(--color-surface-border)",
63
+ strokeDasharray: "3,3",
64
+ strokeWidth: 1
65
+ }, `grid-${t}`);
66
+ }),
67
+ v.map((e, t) => {
68
+ let n = U * t - Math.PI / 2;
69
+ return /* @__PURE__ */ p("line", {
70
+ x1: 0,
71
+ y1: 0,
72
+ x2: B * Math.cos(n),
73
+ y2: B * Math.sin(n),
74
+ stroke: "var(--color-surface-border)",
75
+ strokeWidth: 1
76
+ }, `axis-${t}`);
77
+ }),
78
+ v.map((e, t) => {
79
+ let n = U * t - Math.PI / 2, r = B + 18, i = r * Math.cos(n), a = r * Math.sin(n), o = "middle";
80
+ return Math.abs(Math.cos(n)) > .1 && (o = Math.cos(n) > 0 ? "start" : "end"), /* @__PURE__ */ p("text", {
81
+ x: i,
82
+ y: a,
83
+ textAnchor: o,
84
+ dominantBaseline: "central",
85
+ className: "fill-surface-fg-muted text-ds-xs",
86
+ children: e
87
+ }, `label-${t}`);
88
+ }),
89
+ Array.from({ length: x }, (e, t) => {
90
+ let n = Math.round(H / x * (t + 1)), r = B / x * (t + 1), i = -Math.PI / 2;
91
+ return /* @__PURE__ */ p("text", {
92
+ x: r * Math.cos(i) + 4,
93
+ y: r * Math.sin(i),
94
+ textAnchor: "start",
95
+ dominantBaseline: "auto",
96
+ className: "fill-surface-fg-subtle text-ds-xs",
97
+ children: n
98
+ }, `level-label-${t}`);
99
+ }),
100
+ y.map((e, t) => {
101
+ let n = G(e.key), r = W(n);
102
+ return r ? /* @__PURE__ */ m("g", { children: [/* @__PURE__ */ p("path", {
103
+ d: r,
104
+ fill: V[t],
105
+ fillOpacity: S,
106
+ stroke: V[t],
107
+ strokeWidth: 2,
108
+ strokeLinejoin: "round"
109
+ }), C && n.map((n, r) => {
110
+ let { x: i, y: a } = K(r, n);
111
+ return /* @__PURE__ */ p("circle", {
112
+ cx: i,
113
+ cy: a,
114
+ r: 4,
115
+ fill: V[t],
116
+ stroke: "var(--color-surface-base)",
117
+ strokeWidth: 2,
118
+ className: "transition-opacity"
119
+ }, `dot-${e.key}-${r}`);
120
+ })] }, e.key) : null;
121
+ }),
122
+ T && v.map((e, t) => {
123
+ let n = U * t - Math.PI / 2;
124
+ return /* @__PURE__ */ p("circle", {
125
+ cx: B * Math.cos(n),
126
+ cy: B * Math.sin(n),
127
+ r: 16,
128
+ fill: "transparent",
129
+ className: "cursor-pointer",
130
+ onMouseMove: (n) => {
131
+ let r = n.currentTarget.closest("div")?.getBoundingClientRect();
132
+ I(n.clientX - (r?.left ?? 0), n.clientY - (r?.top ?? 0), /* @__PURE__ */ m("div", { children: [/* @__PURE__ */ p("div", {
133
+ className: "font-medium",
134
+ children: e
135
+ }), y.map((e, n) => {
136
+ let r = Number(c[t]?.[e.key]) || 0;
137
+ return /* @__PURE__ */ m("div", {
138
+ className: "flex items-center gap-ds-02",
139
+ children: [
140
+ /* @__PURE__ */ p("span", {
141
+ className: "inline-block h-2 w-2 rounded-pill",
142
+ style: { backgroundColor: V[n] }
143
+ }),
144
+ /* @__PURE__ */ m("span", {
145
+ className: "text-surface-fg-muted",
146
+ children: [e.label, ":"]
147
+ }),
148
+ " ",
149
+ r.toLocaleString()
150
+ ]
151
+ }, e.key);
152
+ })] }));
153
+ },
154
+ onMouseLeave: L
155
+ }, `hover-${t}`);
156
+ })
157
+ ]
158
+ })
159
+ }), T && /* @__PURE__ */ p(a, { state: F })] }), E && /* @__PURE__ */ p(i, {
160
+ items: y.map((e, t) => ({
161
+ label: e.label,
162
+ color: V[t]
163
+ })),
164
+ className: "mt-ds-04"
165
+ })]
166
+ });
167
+ });
168
+ v.displayName = "RadarChart";
169
+ //#endregion
170
+ export { v as RadarChart };
@@ -0,0 +1 @@
1
+ {"version":3,"file":"radar-chart.js","names":[],"sources":["../../../src/ui/charts/radar-chart.tsx"],"sourcesContent":["'use client'\n\nimport { curveLinearClosed,lineRadial } from 'd3-shape'\nimport { motion } from 'framer-motion'\nimport * as React from 'react'\nimport { useEffect,useRef, useState } from 'react'\n\nimport { motionProps,tweens } from '../lib/motion'\nimport { cn } from '../lib/utils'\nimport { useReducedMotion } from './_internal/animation'\nimport { resolveColor } from './_internal/colors'\nimport { Legend } from './_internal/legend'\nimport { ChartTooltip, useChartTooltip } from './_internal/tooltip'\n\nexport interface RadarChartProps extends Omit<React.HTMLAttributes<HTMLDivElement>, 'children'> {\n /** Data array (one entry per data point / axis) */\n data: Record<string, string | number>[]\n /** Axis labels (3-8 axes) */\n axes: string[]\n /** Series to plot */\n series: { key: string; label: string; color?: string }[]\n /** Max value (auto-detect if not set) */\n maxValue?: number\n /** Number of concentric grid rings (default: 5) */\n levels?: number\n /** Fill opacity for the data polygon (default: 0.25) */\n fillOpacity?: number\n /** Show dots at vertices */\n showDots?: boolean\n /** Chart height (default: 300) */\n height?: number\n /** Show tooltip on hover */\n showTooltip?: boolean\n /** Show legend */\n showLegend?: boolean\n /** Animate on mount */\n animate?: boolean\n /** Accessible label for the chart */\n ariaLabel?: string\n className?: string\n}\n\nexport const RadarChart = React.forwardRef<HTMLDivElement, RadarChartProps>(\n (\n {\n data,\n axes,\n series,\n maxValue: maxValueProp,\n levels = 5,\n fillOpacity = 0.25,\n showDots = false,\n height = 300,\n showTooltip = true,\n showLegend = false,\n animate = true,\n ariaLabel,\n className,\n ...props\n },\n ref,\n ) => {\n const containerRef = useRef<HTMLDivElement>(null)\n const [containerWidth, setContainerWidth] = useState(0)\n const { tooltip, show, hide } = useChartTooltip()\n const reducedMotion = useReducedMotion()\n const shouldAnimate = animate && !reducedMotion\n\n useEffect(() => {\n if (!containerRef.current) return\n const observer = new ResizeObserver((entries) => {\n const entry = entries[0]\n if (entry) setContainerWidth(entry.contentRect.width)\n })\n observer.observe(containerRef.current)\n return () => observer.disconnect()\n }, [])\n\n // Radar chart is square — use the smaller of width/height\n const svgSize = containerWidth > 0 ? Math.min(containerWidth, height) : height\n const radius = svgSize / 2 - 40 // leave room for labels\n\n // Resolve colors for each series\n const colors = series.map((s, i) => resolveColor(s.color, i))\n\n // Auto-detect maxValue if not provided\n const maxValue =\n maxValueProp ??\n Math.max(\n ...data.flatMap((d) => series.map((s) => Number(d[s.key]) || 0)),\n 1,\n )\n\n // Angle per axis slice\n const angleSlice = (2 * Math.PI) / axes.length\n\n // D3 radial line generator for the data polygon\n const radarLine = lineRadial<number>()\n .radius((d) => (radius * d) / maxValue)\n .angle((_, i) => i * angleSlice)\n .curve(curveLinearClosed)\n\n // Convert a data row into an array of values aligned with axes\n const getSeriesValues = (seriesKey: string): number[] =>\n axes.map((_, i) => Number(data[i]?.[seriesKey]) || 0)\n\n // Convert polar to cartesian for a given axis index and value\n const polarToXY = (axisIndex: number, value: number) => {\n const angle = angleSlice * axisIndex - Math.PI / 2\n const r = (radius * value) / maxValue\n return {\n x: r * Math.cos(angle),\n y: r * Math.sin(angle),\n }\n }\n\n return (\n <motion.div\n ref={(node) => {\n (containerRef as React.MutableRefObject<HTMLDivElement | null>).current = node\n if (typeof ref === 'function') ref(node)\n else if (ref) (ref as React.MutableRefObject<HTMLDivElement | null>).current = node\n }}\n className={cn('relative w-full', className)}\n {...(shouldAnimate\n ? { initial: { opacity: 0, scale: 0.96 }, animate: { opacity: 1, scale: 1 }, transition: tweens.fade }\n : {})}\n {...motionProps(props)}\n >\n {containerWidth > 0 && (\n <>\n <svg\n width={containerWidth}\n height={height}\n role=\"img\"\n aria-label={ariaLabel ?? 'Radar chart'}\n >\n <g transform={`translate(${containerWidth / 2},${height / 2})`}>\n {/* Concentric grid polygons */}\n {Array.from({ length: levels }, (_, i) => {\n const levelRadius = (radius / levels) * (i + 1)\n const points = axes\n .map((_, j) => {\n const angle = angleSlice * j - Math.PI / 2\n return `${levelRadius * Math.cos(angle)},${levelRadius * Math.sin(angle)}`\n })\n .join(' ')\n return (\n <polygon\n key={`grid-${i}`}\n points={points}\n fill=\"none\"\n stroke=\"var(--color-surface-border)\"\n strokeDasharray=\"3,3\"\n strokeWidth={1}\n />\n )\n })}\n\n {/* Axis lines from center to outer edge */}\n {axes.map((_, i) => {\n const angle = angleSlice * i - Math.PI / 2\n const x = radius * Math.cos(angle)\n const y = radius * Math.sin(angle)\n return (\n <line\n key={`axis-${i}`}\n x1={0}\n y1={0}\n x2={x}\n y2={y}\n stroke=\"var(--color-surface-border)\"\n strokeWidth={1}\n />\n )\n })}\n\n {/* Axis labels */}\n {axes.map((label, i) => {\n const angle = angleSlice * i - Math.PI / 2\n const labelRadius = radius + 18\n const x = labelRadius * Math.cos(angle)\n const y = labelRadius * Math.sin(angle)\n\n // Determine text-anchor based on position\n let textAnchor: 'start' | 'middle' | 'end' = 'middle'\n if (Math.abs(Math.cos(angle)) > 0.1) {\n textAnchor = Math.cos(angle) > 0 ? 'start' : 'end'\n }\n\n return (\n <text\n key={`label-${i}`}\n x={x}\n y={y}\n textAnchor={textAnchor}\n dominantBaseline=\"central\"\n className=\"fill-surface-fg-muted text-ds-xs\"\n >\n {label}\n </text>\n )\n })}\n\n {/* Level value labels on the first axis */}\n {Array.from({ length: levels }, (_, i) => {\n const levelValue = Math.round((maxValue / levels) * (i + 1))\n const levelRadius = (radius / levels) * (i + 1)\n const angle = -Math.PI / 2 // first axis is at top\n const x = levelRadius * Math.cos(angle) + 4\n const y = levelRadius * Math.sin(angle)\n return (\n <text\n key={`level-label-${i}`}\n x={x}\n y={y}\n textAnchor=\"start\"\n dominantBaseline=\"auto\"\n className=\"fill-surface-fg-subtle text-ds-xs\"\n >\n {levelValue}\n </text>\n )\n })}\n\n {/* Data polygons — one per series */}\n {series.map((s, seriesIdx) => {\n const values = getSeriesValues(s.key)\n const pathD = radarLine(values)\n if (!pathD) return null\n\n return (\n <g key={s.key}>\n <path\n d={pathD}\n fill={colors[seriesIdx]}\n fillOpacity={fillOpacity}\n stroke={colors[seriesIdx]}\n strokeWidth={2}\n strokeLinejoin=\"round\"\n />\n\n {/* Vertex dots */}\n {showDots &&\n values.map((v, i) => {\n const { x, y } = polarToXY(i, v)\n return (\n <circle\n key={`dot-${s.key}-${i}`}\n cx={x}\n cy={y}\n r={4}\n fill={colors[seriesIdx]}\n stroke=\"var(--color-surface-base)\"\n strokeWidth={2}\n className=\"transition-opacity\"\n />\n )\n })}\n </g>\n )\n })}\n\n {/* Invisible hover areas at each vertex for tooltips */}\n {showTooltip &&\n axes.map((axisLabel, i) => {\n // Place a transparent circle at the outermost series point\n // for hit detection. Use the max value point for the axis.\n const angle = angleSlice * i - Math.PI / 2\n const hitX = radius * Math.cos(angle)\n const hitY = radius * Math.sin(angle)\n\n return (\n <circle\n key={`hover-${i}`}\n cx={hitX}\n cy={hitY}\n r={16}\n fill=\"transparent\"\n className=\"cursor-pointer\"\n onMouseMove={(e) => {\n const rect = e.currentTarget\n .closest('div')\n ?.getBoundingClientRect()\n show(\n e.clientX - (rect?.left ?? 0),\n e.clientY - (rect?.top ?? 0),\n <div>\n <div className=\"font-medium\">{axisLabel}</div>\n {series.map((s, sIdx) => {\n const val = Number(data[i]?.[s.key]) || 0\n return (\n <div\n key={s.key}\n className=\"flex items-center gap-ds-02\"\n >\n <span\n className=\"inline-block h-2 w-2 rounded-pill\"\n style={{ backgroundColor: colors[sIdx] }}\n />\n <span className=\"text-surface-fg-muted\">\n {s.label}:\n </span>{' '}\n {val.toLocaleString()}\n </div>\n )\n })}\n </div>,\n )\n }}\n onMouseLeave={hide}\n />\n )\n })}\n </g>\n </svg>\n\n {/* Tooltip overlay */}\n {showTooltip && <ChartTooltip state={tooltip} />}\n </>\n )}\n\n {/* Legend */}\n {showLegend && (\n <Legend\n items={series.map((s, i) => ({\n label: s.label,\n color: colors[i],\n }))}\n className=\"mt-ds-04\"\n />\n )}\n </motion.div>\n )\n },\n)\nRadarChart.displayName = 'RadarChart'\n"],"mappings":"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"}
@@ -0,0 +1,119 @@
1
+ "use client";
2
+ import { cn as e } from "../lib/utils.js";
3
+ import { r as t, t as n } from "../../_chunks/colors.js";
4
+ import * as r from "react";
5
+ import { jsx as i, jsxs as a } from "react/jsx-runtime";
6
+ import { motion as o } from "framer-motion";
7
+ import { scaleLinear as s } from "d3-scale";
8
+ import { area as c, curveMonotoneX as l, line as u } from "d3-shape";
9
+ //#region src/ui/charts/sparkline.tsx
10
+ var d = {
11
+ duration: 1,
12
+ ease: "easeOut"
13
+ }, f = r.forwardRef(({ data: r, variant: f = "line", width: p = 120, height: m = 32, color: h, showLastDot: g = !1, strokeWidth: _ = 1.5, animate: v = !0, className: y, ...b }, x) => {
14
+ let S = n(h, 0), C = t(), w = v && !C;
15
+ if (!r.length) return null;
16
+ let T = f === "bar" ? 1 : _, E = p - T * 2, D = m - T * 2, O = s().domain([0, Math.max(r.length - 1, 1)]).range([T, T + E]), k = Math.min(...r), A = Math.max(...r), j = k === A ? [k - 1, A + 1] : [k, A], M = s().domain(j).range([T + D, T]);
17
+ if (f === "bar") {
18
+ let t = Math.max(1, (E - 1 * (r.length - 1)) / r.length), n = T + D;
19
+ return /* @__PURE__ */ i("svg", {
20
+ ref: x,
21
+ width: p,
22
+ height: m,
23
+ role: "img",
24
+ "aria-label": "Sparkline bar chart",
25
+ className: e("inline-block align-middle", y),
26
+ ...b,
27
+ children: r.map((e, r) => {
28
+ let a = T + r * (t + 1), o = M(e);
29
+ return /* @__PURE__ */ i("rect", {
30
+ x: a,
31
+ y: o,
32
+ width: t,
33
+ height: Math.max(1, n - o),
34
+ rx: Math.min(1, t / 2),
35
+ fill: S
36
+ }, r);
37
+ })
38
+ });
39
+ }
40
+ if (f === "area") {
41
+ let t = c().curve(l).x((e, t) => O(t)).y0(T + D).y1((e) => M(e)), n = u().curve(l).x((e, t) => O(t)).y((e) => M(e)), s = t(r) ?? "", f = n(r) ?? "", h = O(r.length - 1), v = M(r[r.length - 1]);
42
+ return /* @__PURE__ */ a("svg", {
43
+ ref: x,
44
+ width: p,
45
+ height: m,
46
+ role: "img",
47
+ "aria-label": "Sparkline area chart",
48
+ className: e("inline-block align-middle", y),
49
+ ...b,
50
+ children: [
51
+ /* @__PURE__ */ i("path", {
52
+ d: s,
53
+ fill: S,
54
+ opacity: .2
55
+ }),
56
+ w ? /* @__PURE__ */ i(o.path, {
57
+ d: f,
58
+ fill: "none",
59
+ stroke: S,
60
+ strokeWidth: _,
61
+ strokeLinejoin: "round",
62
+ strokeLinecap: "round",
63
+ initial: { pathLength: 0 },
64
+ animate: { pathLength: 1 },
65
+ transition: d
66
+ }) : /* @__PURE__ */ i("path", {
67
+ d: f,
68
+ fill: "none",
69
+ stroke: S,
70
+ strokeWidth: _,
71
+ strokeLinejoin: "round",
72
+ strokeLinecap: "round"
73
+ }),
74
+ g && /* @__PURE__ */ i("circle", {
75
+ cx: h,
76
+ cy: v,
77
+ r: _ + 1,
78
+ fill: S
79
+ })
80
+ ]
81
+ });
82
+ }
83
+ let N = u().curve(l).x((e, t) => O(t)).y((e) => M(e))(r) ?? "", P = O(r.length - 1), F = M(r[r.length - 1]);
84
+ return /* @__PURE__ */ a("svg", {
85
+ ref: x,
86
+ width: p,
87
+ height: m,
88
+ role: "img",
89
+ "aria-label": "Sparkline chart",
90
+ className: e("inline-block align-middle", y),
91
+ ...b,
92
+ children: [w ? /* @__PURE__ */ i(o.path, {
93
+ d: N,
94
+ fill: "none",
95
+ stroke: S,
96
+ strokeWidth: _,
97
+ strokeLinejoin: "round",
98
+ strokeLinecap: "round",
99
+ initial: { pathLength: 0 },
100
+ animate: { pathLength: 1 },
101
+ transition: d
102
+ }) : /* @__PURE__ */ i("path", {
103
+ d: N,
104
+ fill: "none",
105
+ stroke: S,
106
+ strokeWidth: _,
107
+ strokeLinejoin: "round",
108
+ strokeLinecap: "round"
109
+ }), g && /* @__PURE__ */ i("circle", {
110
+ cx: P,
111
+ cy: F,
112
+ r: _ + 1,
113
+ fill: S
114
+ })]
115
+ });
116
+ });
117
+ f.displayName = "Sparkline";
118
+ //#endregion
119
+ export { f as Sparkline };