@tulipfarm/sprout 0.3.0 → 0.4.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 (349) hide show
  1. package/README.md +45 -40
  2. package/dist/components/accordion.d.ts +2 -2
  3. package/dist/components/accordion.js +9 -9
  4. package/dist/components/agent-fanout.d.ts +2 -2
  5. package/dist/components/agent-fanout.js +65 -87
  6. package/dist/components/alert-dialog.d.ts +6 -6
  7. package/dist/components/alert-dialog.js +20 -20
  8. package/dist/components/alert.d.ts +6 -6
  9. package/dist/components/alert.js +13 -13
  10. package/dist/components/aspect-ratio.d.ts +2 -2
  11. package/dist/components/aspect-ratio.js +2 -2
  12. package/dist/components/attachment.d.ts +17 -17
  13. package/dist/components/attachment.js +82 -115
  14. package/dist/components/avatar.d.ts +10 -10
  15. package/dist/components/avatar.js +14 -14
  16. package/dist/components/badge.d.ts +4 -4
  17. package/dist/components/badge.js +18 -18
  18. package/dist/components/board.d.ts +107 -0
  19. package/dist/components/board.js +640 -0
  20. package/dist/components/brand-icon.d.ts +6 -6
  21. package/dist/components/brand-icon.js +55 -63
  22. package/dist/components/breadcrumb.d.ts +11 -11
  23. package/dist/components/breadcrumb.js +16 -18
  24. package/dist/components/button-group.d.ts +6 -6
  25. package/dist/components/button-group.js +14 -14
  26. package/dist/components/button.d.ts +11 -11
  27. package/dist/components/button.js +46 -56
  28. package/dist/components/calendar.d.ts +5 -5
  29. package/dist/components/calendar.js +44 -53
  30. package/dist/components/canvas.d.ts +4 -4
  31. package/dist/components/canvas.js +39 -46
  32. package/dist/components/card.d.ts +6 -6
  33. package/dist/components/card.js +17 -17
  34. package/dist/components/carousel.d.ts +7 -7
  35. package/dist/components/carousel.js +57 -75
  36. package/dist/components/chart.d.ts +5 -112
  37. package/dist/components/chart.js +5 -172
  38. package/dist/components/chat-confirmation.d.ts +13 -11
  39. package/dist/components/chat-confirmation.js +32 -38
  40. package/dist/components/chat-input.d.ts +4 -4
  41. package/dist/components/chat-input.js +74 -81
  42. package/dist/components/chat-plan.d.ts +2 -2
  43. package/dist/components/chat-plan.js +15 -20
  44. package/dist/components/chat-sources.d.ts +8 -8
  45. package/dist/components/chat-sources.js +18 -27
  46. package/dist/components/checkbox.d.ts +1 -1
  47. package/dist/components/checkbox.js +9 -9
  48. package/dist/components/choice-list.d.ts +2 -2
  49. package/dist/components/choice-list.js +16 -18
  50. package/dist/components/code-block.d.ts +5 -5
  51. package/dist/components/code-block.js +26 -26
  52. package/dist/components/collapsible.d.ts +1 -1
  53. package/dist/components/collapsible.js +7 -11
  54. package/dist/components/combobox.d.ts +3 -3
  55. package/dist/components/combobox.js +24 -24
  56. package/dist/components/command.d.ts +13 -13
  57. package/dist/components/command.js +61 -73
  58. package/dist/components/context-menu.d.ts +5 -5
  59. package/dist/components/context-menu.js +22 -22
  60. package/dist/components/dialog.d.ts +6 -6
  61. package/dist/components/dialog.js +23 -28
  62. package/dist/components/direction.d.ts +1 -1
  63. package/dist/components/direction.js +1 -1
  64. package/dist/components/dropdown-menu.d.ts +5 -5
  65. package/dist/components/dropdown-menu.js +20 -20
  66. package/dist/components/field.d.ts +11 -11
  67. package/dist/components/field.js +41 -61
  68. package/dist/components/file-explorer.d.ts +2 -2
  69. package/dist/components/file-explorer.js +89 -105
  70. package/dist/components/file-viewer.d.ts +10 -10
  71. package/dist/components/file-viewer.js +112 -140
  72. package/dist/components/form.d.ts +7 -7
  73. package/dist/components/form.js +24 -28
  74. package/dist/components/glass-banner.d.ts +3 -3
  75. package/dist/components/glass-banner.js +21 -24
  76. package/dist/components/gradient-banner.d.ts +5 -5
  77. package/dist/components/gradient-banner.js +13 -22
  78. package/dist/components/hover-card.d.ts +4 -4
  79. package/dist/components/hover-card.js +6 -6
  80. package/dist/components/input-group.d.ts +11 -11
  81. package/dist/components/input-group.js +22 -36
  82. package/dist/components/input-otp.d.ts +10 -10
  83. package/dist/components/input-otp.js +13 -15
  84. package/dist/components/input.d.ts +1 -1
  85. package/dist/components/input.js +7 -7
  86. package/dist/components/kbd.d.ts +3 -3
  87. package/dist/components/kbd.js +5 -5
  88. package/dist/components/label.d.ts +2 -2
  89. package/dist/components/label.js +2 -2
  90. package/dist/components/mention-list.d.ts +3 -3
  91. package/dist/components/mention-list.js +10 -10
  92. package/dist/components/menubar.d.ts +6 -6
  93. package/dist/components/menubar.js +22 -22
  94. package/dist/components/message-actions.d.ts +2 -2
  95. package/dist/components/message-actions.js +29 -31
  96. package/dist/components/message-response.d.ts +3 -3
  97. package/dist/components/message-response.js +18 -18
  98. package/dist/components/message-scroller.d.ts +12 -12
  99. package/dist/components/message-scroller.js +44 -56
  100. package/dist/components/message.d.ts +11 -11
  101. package/dist/components/message.js +25 -25
  102. package/dist/components/navigation-menu.d.ts +2 -2
  103. package/dist/components/navigation-menu.js +15 -15
  104. package/dist/components/notice-banner.d.ts +2 -2
  105. package/dist/components/notice-banner.js +2 -2
  106. package/dist/components/page-content.d.ts +2 -2
  107. package/dist/components/page-content.js +2 -2
  108. package/dist/components/page-header.d.ts +1 -1
  109. package/dist/components/page-header.js +16 -16
  110. package/dist/components/pagination.d.ts +9 -9
  111. package/dist/components/pagination.js +17 -17
  112. package/dist/components/plan-outline.d.ts +2 -2
  113. package/dist/components/plan-outline.js +43 -60
  114. package/dist/components/popover.d.ts +6 -6
  115. package/dist/components/popover.js +15 -15
  116. package/dist/components/presence-cursor.d.ts +2 -2
  117. package/dist/components/presence-cursor.js +3 -3
  118. package/dist/components/progress.d.ts +1 -1
  119. package/dist/components/progress.js +8 -8
  120. package/dist/components/prompt-list.d.ts +3 -3
  121. package/dist/components/prompt-list.js +6 -6
  122. package/dist/components/questionnaire.d.ts +19 -19
  123. package/dist/components/questionnaire.js +183 -242
  124. package/dist/components/radio-group.d.ts +2 -2
  125. package/dist/components/radio-group.js +6 -6
  126. package/dist/components/reasoning-effort.d.ts +3 -3
  127. package/dist/components/reasoning-effort.js +9 -12
  128. package/dist/components/record-list.d.ts +66 -0
  129. package/dist/components/record-list.js +151 -0
  130. package/dist/components/resizable.d.ts +5 -5
  131. package/dist/components/resizable.js +76 -102
  132. package/dist/components/result-card.d.ts +10 -5
  133. package/dist/components/result-card.js +42 -53
  134. package/dist/components/result-notice.d.ts +18 -0
  135. package/dist/components/result-notice.js +29 -0
  136. package/dist/components/review-card.d.ts +6 -6
  137. package/dist/components/review-card.js +18 -18
  138. package/dist/components/rich-text-editor.d.ts +2 -2
  139. package/dist/components/rich-text-editor.js +56 -72
  140. package/dist/components/schema-diagram.d.ts +3 -3
  141. package/dist/components/schema-diagram.js +39 -53
  142. package/dist/components/scroll-area.d.ts +1 -1
  143. package/dist/components/scroll-area.js +10 -14
  144. package/dist/components/search-dialog.d.ts +6 -6
  145. package/dist/components/search-dialog.js +16 -16
  146. package/dist/components/search-field.d.ts +1 -1
  147. package/dist/components/search-field.js +11 -11
  148. package/dist/components/select.d.ts +3 -3
  149. package/dist/components/select.js +20 -20
  150. package/dist/components/selection-slot.d.ts +2 -2
  151. package/dist/components/selection-slot.js +6 -9
  152. package/dist/components/separator.d.ts +15 -15
  153. package/dist/components/separator.js +22 -27
  154. package/dist/components/settings-list.d.ts +3 -3
  155. package/dist/components/settings-list.js +5 -5
  156. package/dist/components/sheet.d.ts +6 -6
  157. package/dist/components/sheet.js +27 -27
  158. package/dist/components/sidebar.d.ts +22 -22
  159. package/dist/components/sidebar.js +57 -58
  160. package/dist/components/skeleton.d.ts +5 -5
  161. package/dist/components/skeleton.js +14 -21
  162. package/dist/components/slider.d.ts +2 -2
  163. package/dist/components/slider.js +6 -6
  164. package/dist/components/spinner.d.ts +5 -5
  165. package/dist/components/spinner.js +22 -26
  166. package/dist/components/sql-viewer.d.ts +14 -14
  167. package/dist/components/sql-viewer.js +99 -128
  168. package/dist/components/state-panel-samples.d.ts +2 -2
  169. package/dist/components/state-panel-samples.js +209 -245
  170. package/dist/components/state-panel.d.ts +2 -35
  171. package/dist/components/state-panel.js +2 -29
  172. package/dist/components/state-sample.d.ts +7 -7
  173. package/dist/components/state-sample.js +18 -31
  174. package/dist/components/switch.d.ts +1 -1
  175. package/dist/components/switch.js +7 -7
  176. package/dist/components/table-nuqs.d.ts +2 -2
  177. package/dist/components/table-nuqs.js +11 -12
  178. package/dist/components/table.d.ts +4 -4
  179. package/dist/components/table.js +166 -235
  180. package/dist/components/tabs.d.ts +2 -2
  181. package/dist/components/tabs.js +12 -12
  182. package/dist/components/textarea.d.ts +2 -2
  183. package/dist/components/textarea.js +6 -8
  184. package/dist/components/timeline.d.ts +3 -0
  185. package/dist/components/timeline.js +3 -0
  186. package/dist/components/toast.d.ts +2 -2
  187. package/dist/components/toast.js +19 -25
  188. package/dist/components/toggle-group.d.ts +2 -2
  189. package/dist/components/toggle-group.js +18 -20
  190. package/dist/components/toggle.d.ts +2 -2
  191. package/dist/components/toggle.js +8 -8
  192. package/dist/components/tool-activity.d.ts +1 -1
  193. package/dist/components/tool-activity.js +83 -110
  194. package/dist/components/toolbar-status.d.ts +2 -2
  195. package/dist/components/toolbar-status.js +7 -7
  196. package/dist/components/tooltip.d.ts +5 -5
  197. package/dist/components/tooltip.js +12 -11
  198. package/dist/components/typed-text.d.ts +2 -2
  199. package/dist/components/typed-text.js +10 -12
  200. package/dist/components/view-switcher.d.ts +51 -0
  201. package/dist/components/view-switcher.js +114 -0
  202. package/dist/index.d.ts +98 -93
  203. package/dist/index.js +98 -93
  204. package/dist/internal/chart-kit.d.ts +142 -0
  205. package/dist/internal/chart-kit.js +200 -0
  206. package/dist/internal/charts/bars.d.ts +61 -0
  207. package/dist/internal/charts/bars.js +86 -0
  208. package/dist/internal/charts/lines.d.ts +67 -0
  209. package/dist/internal/charts/lines.js +70 -0
  210. package/dist/internal/charts/more.d.ts +77 -0
  211. package/dist/internal/charts/more.js +68 -0
  212. package/dist/internal/charts/parts.d.ts +54 -0
  213. package/dist/internal/charts/parts.js +82 -0
  214. package/dist/internal/charts/timeline-dates.d.ts +38 -0
  215. package/dist/internal/charts/timeline-dates.js +113 -0
  216. package/dist/internal/charts/timeline-window.d.ts +31 -0
  217. package/dist/internal/charts/timeline-window.js +26 -0
  218. package/dist/internal/charts/timeline.d.ts +72 -0
  219. package/dist/internal/charts/timeline.js +287 -0
  220. package/dist/internal/classes.d.ts +1 -1
  221. package/dist/internal/classes.js +7 -9
  222. package/dist/internal/code-tokens.d.ts +2 -2
  223. package/dist/internal/code-tokens.js +12 -12
  224. package/dist/internal/fieldset.d.ts +1 -1
  225. package/dist/internal/fieldset.js +6 -6
  226. package/dist/internal/file-kind.d.ts +1 -1
  227. package/dist/internal/file-kind.js +43 -51
  228. package/dist/internal/flow.d.ts +4 -4
  229. package/dist/internal/flow.js +20 -23
  230. package/dist/internal/languages.js +999 -999
  231. package/dist/internal/message-scroller.d.ts +3 -3
  232. package/dist/internal/message-scroller.js +64 -112
  233. package/dist/internal/pressable.d.ts +1 -1
  234. package/dist/internal/pressable.js +7 -7
  235. package/dist/internal/state-panel.d.ts +35 -0
  236. package/dist/internal/state-panel.js +22 -0
  237. package/dist/internal/syntax.d.ts +2 -2
  238. package/dist/internal/syntax.js +36 -47
  239. package/dist/styles/accordion.css +3 -5
  240. package/dist/styles/agent-fanout.css +64 -60
  241. package/dist/styles/alert-dialog.css +12 -26
  242. package/dist/styles/alert.css +10 -15
  243. package/dist/styles/attachment.css +51 -93
  244. package/dist/styles/avatar.css +17 -24
  245. package/dist/styles/badge.css +11 -36
  246. package/dist/styles/board.css +571 -0
  247. package/dist/styles/brand-icon.css +7 -8
  248. package/dist/styles/breadcrumb.css +4 -7
  249. package/dist/styles/button-group.css +8 -14
  250. package/dist/styles/button.css +22 -27
  251. package/dist/styles/calendar.css +24 -36
  252. package/dist/styles/canvas.css +2 -3
  253. package/dist/styles/card.css +7 -23
  254. package/dist/styles/carousel.css +11 -12
  255. package/dist/styles/chart.css +215 -31
  256. package/dist/styles/chat-input.css +15 -39
  257. package/dist/styles/chat-plan.css +3 -4
  258. package/dist/styles/chat-sources.css +3 -6
  259. package/dist/styles/checkbox.css +11 -25
  260. package/dist/styles/choice-list.css +17 -31
  261. package/dist/styles/code-block.css +11 -25
  262. package/dist/styles/collapsible.css +10 -15
  263. package/dist/styles/combobox.css +11 -15
  264. package/dist/styles/command.css +5 -8
  265. package/dist/styles/context-menu.css +2 -2
  266. package/dist/styles/dialog.css +5 -16
  267. package/dist/styles/dropdown-menu.css +2 -2
  268. package/dist/styles/field.css +15 -21
  269. package/dist/styles/file-explorer.css +19 -33
  270. package/dist/styles/file-viewer.css +13 -17
  271. package/dist/styles/form.css +3 -3
  272. package/dist/styles/glass-banner.css +12 -47
  273. package/dist/styles/gradient-banner.css +17 -35
  274. package/dist/styles/hover-card.css +9 -15
  275. package/dist/styles/index.css +116 -108
  276. package/dist/styles/input-group.css +25 -41
  277. package/dist/styles/input-otp.css +5 -6
  278. package/dist/styles/input.css +5 -5
  279. package/dist/styles/kbd.css +1 -1
  280. package/dist/styles/label.css +9 -30
  281. package/dist/styles/mention-list.css +6 -8
  282. package/dist/styles/menubar.css +5 -6
  283. package/dist/styles/message-actions.css +1 -1
  284. package/dist/styles/message-response.css +3 -5
  285. package/dist/styles/message-scroller.css +14 -21
  286. package/dist/styles/message.css +23 -60
  287. package/dist/styles/navigation-menu.css +14 -29
  288. package/dist/styles/notice-banner.css +1 -2
  289. package/dist/styles/page-header.css +7 -10
  290. package/dist/styles/pagination.css +1 -4
  291. package/dist/styles/plan-outline.css +20 -37
  292. package/dist/styles/popover.css +10 -19
  293. package/dist/styles/presence-cursor.css +1 -2
  294. package/dist/styles/progress.css +2 -4
  295. package/dist/styles/prompt-list.css +6 -17
  296. package/dist/styles/questionnaire.css +16 -40
  297. package/dist/styles/radio-group.css +12 -23
  298. package/dist/styles/reasoning-effort.css +8 -15
  299. package/dist/styles/record-list.css +243 -0
  300. package/dist/styles/resizable.css +10 -11
  301. package/dist/styles/result-card.css +17 -3
  302. package/dist/styles/result-notice.css +80 -0
  303. package/dist/styles/review-card.css +2 -3
  304. package/dist/styles/rich-text-editor.css +1 -2
  305. package/dist/styles/schema-diagram.css +12 -17
  306. package/dist/styles/scroll-area.css +8 -10
  307. package/dist/styles/search-dialog.css +1 -5
  308. package/dist/styles/search-field.css +1 -2
  309. package/dist/styles/select.css +7 -7
  310. package/dist/styles/selection-slot.css +1 -2
  311. package/dist/styles/separator.css +7 -8
  312. package/dist/styles/settings-list.css +1 -2
  313. package/dist/styles/sheet.css +40 -73
  314. package/dist/styles/sidebar.css +17 -21
  315. package/dist/styles/skeleton.css +9 -11
  316. package/dist/styles/slider.css +11 -21
  317. package/dist/styles/spinner.css +2 -2
  318. package/dist/styles/sql-viewer.css +29 -29
  319. package/dist/styles/state-panel.css +8 -9
  320. package/dist/styles/state-sample.css +20 -33
  321. package/dist/styles/switch.css +11 -18
  322. package/dist/styles/table.css +51 -77
  323. package/dist/styles/tabs.css +12 -16
  324. package/dist/styles/textarea.css +3 -3
  325. package/dist/styles/themes/chatgpt.css +11 -23
  326. package/dist/styles/themes/claude.css +12 -24
  327. package/dist/styles/themes/cloudflare.css +11 -23
  328. package/dist/styles/themes/discord.css +11 -23
  329. package/dist/styles/themes/github.css +11 -23
  330. package/dist/styles/themes/grok.css +11 -23
  331. package/dist/styles/themes/linear.css +12 -25
  332. package/dist/styles/themes/neutral.css +11 -23
  333. package/dist/styles/themes/notion.css +11 -23
  334. package/dist/styles/themes/perplexity.css +11 -23
  335. package/dist/styles/themes/raycast.css +11 -23
  336. package/dist/styles/themes/spotify.css +11 -23
  337. package/dist/styles/themes/stripe.css +11 -23
  338. package/dist/styles/themes/supabase.css +11 -23
  339. package/dist/styles/themes/tulipfarm.css +9 -10
  340. package/dist/styles/themes/vercel.css +12 -25
  341. package/dist/styles/timeline.css +276 -0
  342. package/dist/styles/toast.css +13 -20
  343. package/dist/styles/toggle-group.css +17 -23
  344. package/dist/styles/toggle.css +8 -8
  345. package/dist/styles/tool-activity.css +7 -13
  346. package/dist/styles/toolbar-status.css +2 -7
  347. package/dist/styles/tooltip.css +15 -21
  348. package/dist/styles/view-switcher.css +279 -0
  349. package/package.json +21 -1
@@ -0,0 +1,142 @@
1
+ import { type ComponentProps, type ComponentType, type ReactNode } from 'react';
2
+ import { ResponsiveContainer, Tooltip, type BarShapeProps, type DefaultLegendContentProps, type DefaultTooltipContentProps, type TooltipValueType } from 'recharts';
3
+ /** Theme names a `ChartConfig` entry can color, and the selector each one uses. */
4
+ declare const THEMES: {
5
+ readonly light: "";
6
+ readonly dark: ".dark";
7
+ };
8
+ export declare const chartIndicatorNames: readonly ["dot", "line", "dashed"];
9
+ export type ChartIndicator = (typeof chartIndicatorNames)[number];
10
+ export type ChartConfig = Record<string, {
11
+ label?: ReactNode;
12
+ icon?: ComponentType;
13
+ } & ({
14
+ color?: string;
15
+ theme?: never;
16
+ } | {
17
+ color?: never;
18
+ theme: Record<keyof typeof THEMES, string>;
19
+ })>;
20
+ /**
21
+ * The CSS variable a `ChartContainer` sets for one config key. Pass it as a
22
+ * series `fill` or `stroke`, for example `fill={chartColor("tasks")}`.
23
+ */
24
+ export declare function chartColor(key: string): string;
25
+ export type ChartContainerProps = ComponentProps<'div'> & {
26
+ config: ChartConfig;
27
+ children: ComponentProps<typeof ResponsiveContainer>['children'];
28
+ /** Size used before the container is measured, and on the server. */
29
+ initialDimension?: {
30
+ width: number;
31
+ height: number;
32
+ };
33
+ };
34
+ /**
35
+ * Sizes a Recharts chart to its box and turns `config` into series colors
36
+ * and labels for the tooltip and legend. The box is 16:9 unless `className`
37
+ * or `style` gives it a height.
38
+ */
39
+ export declare function ChartContainer({ id, className, children, config, initialDimension, ...props }: ChartContainerProps): import("react").JSX.Element;
40
+ /**
41
+ * Writes `--sprout-chart-color-<key>` for every colored config entry, with a
42
+ * dark value for entries that pass `theme`. `ChartContainer` renders it.
43
+ */
44
+ export declare function ChartStyle({ id, config }: {
45
+ id: string;
46
+ config: ChartConfig;
47
+ }): import("react").JSX.Element | null;
48
+ export type ChartTooltipProps = ComponentProps<typeof Tooltip>;
49
+ /**
50
+ * Recharts' `Tooltip`, moving in 160ms. Pass `content={<ChartTooltipContent />}`.
51
+ * It stays still when reduced motion is on.
52
+ */
53
+ export declare function ChartTooltip(props: ChartTooltipProps): import("react").JSX.Element;
54
+ type TooltipNameType = number | string;
55
+ export type ChartTooltipContentProps = ComponentProps<typeof Tooltip> & ComponentProps<'div'> & {
56
+ hideLabel?: boolean;
57
+ hideIndicator?: boolean;
58
+ indicator?: ChartIndicator;
59
+ nameKey?: string;
60
+ labelKey?: string;
61
+ /** Formats each row's number, for example as currency. */
62
+ valueFormatter?: ValueFormatter;
63
+ } & Omit<DefaultTooltipContentProps<TooltipValueType, TooltipNameType>, 'accessibilityLayer'>;
64
+ /**
65
+ * The tooltip card: a label, then one row per series with its indicator,
66
+ * config label, and value. Recharts passes `active`, `payload`, and `label`.
67
+ */
68
+ export declare function ChartTooltipContent({ active, payload, className, indicator, hideLabel, hideIndicator, label, labelFormatter, labelClassName, formatter, color, nameKey, labelKey, valueFormatter, }: ChartTooltipContentProps): import("react").JSX.Element | null;
69
+ /** Recharts' `Legend`. Pass `content={<ChartLegendContent />}`. */
70
+ export declare const ChartLegend: import("react").MemoExoticComponent<(outsideProps: import("recharts").LegendProps) => React.ReactPortal | null>;
71
+ export type ChartLegendContentProps = ComponentProps<'div'> & {
72
+ hideIcon?: boolean;
73
+ nameKey?: string;
74
+ } & DefaultLegendContentProps;
75
+ /** A centered row of swatches and config labels, one per series. */
76
+ export declare function ChartLegendContent({ className, hideIcon, payload, verticalAlign, nameKey, }: ChartLegendContentProps): import("react").JSX.Element | null;
77
+ /** One series: its data key, legend and tooltip label, and color. */
78
+ export type ChartSeries = {
79
+ key: string;
80
+ label: string;
81
+ color: string;
82
+ };
83
+ export type UsageSeries = ChartSeries;
84
+ /** One data row: a category or label key plus a number per series key. */
85
+ export type ChartRow = Record<string, number | string | null | undefined>;
86
+ /** Turns a number into the text an axis tick or tooltip shows. */
87
+ export type ValueFormatter = (value: number) => string;
88
+ export declare const formatNumber: ValueFormatter;
89
+ /** The five chart colors, in order. */
90
+ export declare const chartPalette: string[];
91
+ /** The color for parts past the fifth, folded into one "N more" part. */
92
+ export declare const chartOtherColor = "var(--sprout-muted)";
93
+ /** The palette color for a part, or the muted color past the fifth. */
94
+ export declare const partColor: (index: number) => string;
95
+ /**
96
+ * One of `steps` shades of `color`, mixed with the surface so it reads in
97
+ * light and dark. Step 1 is lightest; the last step is `color` itself.
98
+ */
99
+ export declare const chartShade: (color: string, step: number, steps?: number) => string;
100
+ export type ChartPart = {
101
+ name: string;
102
+ value: number;
103
+ fill: string;
104
+ };
105
+ /**
106
+ * Sorts rows by `value`, keeps the top `limit` as colored parts, and folds the
107
+ * rest into one muted "N more" part.
108
+ */
109
+ export declare function foldParts(rows: ChartRow[], category: string, value: string, limit?: number): ChartPart[];
110
+ /** A config entry per part, so the tooltip and legend show part names. */
111
+ export declare const partConfig: (parts: ChartPart[]) => ChartConfig;
112
+ /** Shared props for every ready chart. */
113
+ export interface ReadyChartProps {
114
+ /** Names the chart for screen readers. */
115
+ title?: string;
116
+ /** Formats axis ticks and tooltip values, for example as currency. */
117
+ valueFormatter?: ValueFormatter;
118
+ className?: string;
119
+ }
120
+ export declare const seriesConfig: (series: ChartSeries[]) => ChartConfig;
121
+ export declare const tooltipCursor: {
122
+ fill: string;
123
+ };
124
+ /** Axis props every ready chart shares: no tick marks, no axis line. */
125
+ export declare const quietAxis: {
126
+ readonly tickLine: false;
127
+ readonly axisLine: false;
128
+ };
129
+ /** How series pile up: side by side, stacked, or stacked to 100%. */
130
+ export type ChartStack = 'none' | 'stacked' | 'percent';
131
+ export declare const stackOffset: (stack: ChartStack) => "expand" | undefined;
132
+ export declare const formatPercent: ValueFormatter;
133
+ /** A short day label, like "Oct 17", for a `YYYY-MM-DD` string or a time. */
134
+ export declare const dayLabel: (value: unknown, locale?: string) => string;
135
+ /**
136
+ * Legend content listing every config entry, for charts whose marks are not
137
+ * one series each. Pass it as `<ChartLegend content={configLegend(config)} />`.
138
+ */
139
+ export declare const configLegend: (config: ChartConfig) => () => import("react").JSX.Element;
140
+ /** A bar shape that takes its color from the row's `fill`. */
141
+ export declare const rowFillShape: (props: BarShapeProps) => import("react").JSX.Element;
142
+ export {};
@@ -0,0 +1,200 @@
1
+ 'use client';
2
+ import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
3
+ import { createContext, useContext, useId, useMemo, } from 'react';
4
+ import { Legend, Rectangle, ResponsiveContainer, Tooltip, } from 'recharts';
5
+ import { cn } from './classes.js';
6
+ /** Theme names a `ChartConfig` entry can color, and the selector each one uses. */
7
+ const THEMES = { light: '', dark: '.dark' };
8
+ const INITIAL_DIMENSION = { width: 320, height: 200 };
9
+ export const chartIndicatorNames = ['dot', 'line', 'dashed'];
10
+ const cssKey = (key) => key.replace(/[^\w-]/g, '_');
11
+ /**
12
+ * The CSS variable a `ChartContainer` sets for one config key. Pass it as a
13
+ * series `fill` or `stroke`, for example `fill={chartColor("tasks")}`.
14
+ */
15
+ export function chartColor(key) {
16
+ return `var(--sprout-chart-color-${cssKey(key)})`;
17
+ }
18
+ const ChartContext = createContext(null);
19
+ function useChart() {
20
+ const context = useContext(ChartContext);
21
+ if (!context)
22
+ throw new Error('useChart must be used within a <ChartContainer />');
23
+ return context;
24
+ }
25
+ /**
26
+ * Sizes a Recharts chart to its box and turns `config` into series colors
27
+ * and labels for the tooltip and legend. The box is 16:9 unless `className`
28
+ * or `style` gives it a height.
29
+ */
30
+ export function ChartContainer({ id, className, children, config, initialDimension = INITIAL_DIMENSION, ...props }) {
31
+ const uniqueId = useId();
32
+ const chartId = `chart-${cssKey(id ?? uniqueId)}`;
33
+ const value = useMemo(() => ({ config }), [config]);
34
+ return (_jsx(ChartContext.Provider, { value: value, children: _jsxs("div", { "data-slot": "chart", "data-chart": chartId, className: cn('sprout-chart', className), ...props, children: [_jsx(ChartStyle, { id: chartId, config: config }), _jsx(ResponsiveContainer, { initialDimension: initialDimension, children: children })] }) }));
35
+ }
36
+ /**
37
+ * Writes `--sprout-chart-color-<key>` for every colored config entry, with a
38
+ * dark value for entries that pass `theme`. `ChartContainer` renders it.
39
+ */
40
+ export function ChartStyle({ id, config }) {
41
+ const colorConfig = Object.entries(config).filter(([, item]) => item.theme ?? item.color);
42
+ if (!colorConfig.length)
43
+ return null;
44
+ const rules = (theme) => colorConfig
45
+ .map(([key, item]) => {
46
+ const color = item.theme?.[theme] ?? item.color;
47
+ return color ? ` --sprout-chart-color-${cssKey(key)}: ${color};` : null;
48
+ })
49
+ .filter(Boolean)
50
+ .join('\n');
51
+ const scope = `[data-chart="${cssKey(id)}"]`;
52
+ const themed = colorConfig.some(([, item]) => item.theme);
53
+ const css = [
54
+ `${scope} {\n${rules('light')}\n}`,
55
+ themed ? `${THEMES.dark} ${scope} {\n${rules('dark')}\n}` : '',
56
+ themed
57
+ ? `@media (prefers-color-scheme: dark) {\n:root:not(.light):not(.dark) ${scope} {\n${rules('dark')}\n}\n}`
58
+ : '',
59
+ ]
60
+ .filter(Boolean)
61
+ .join('\n');
62
+ return _jsx("style", { dangerouslySetInnerHTML: { __html: css } });
63
+ }
64
+ /**
65
+ * Recharts' `Tooltip`, moving in 160ms. Pass `content={<ChartTooltipContent />}`.
66
+ * It stays still when reduced motion is on.
67
+ */
68
+ export function ChartTooltip(props) {
69
+ return _jsx(Tooltip, { animationDuration: 160, ...props });
70
+ }
71
+ /**
72
+ * The tooltip card: a label, then one row per series with its indicator,
73
+ * config label, and value. Recharts passes `active`, `payload`, and `label`.
74
+ */
75
+ export function ChartTooltipContent({ active, payload, className, indicator = 'dot', hideLabel = false, hideIndicator = false, label, labelFormatter, labelClassName, formatter, color, nameKey, labelKey, valueFormatter = formatNumber, }) {
76
+ const { config } = useChart();
77
+ const tooltipLabel = useMemo(() => {
78
+ if (hideLabel || !payload?.length)
79
+ return null;
80
+ const [item] = payload;
81
+ const key = `${labelKey ?? item?.dataKey ?? item?.name ?? 'value'}`;
82
+ const itemConfig = getPayloadConfigFromPayload(config, item, key);
83
+ const value = !labelKey && typeof label === 'string' ? (config[label]?.label ?? label) : itemConfig?.label;
84
+ if (labelFormatter)
85
+ return _jsx("div", { className: cn('sprout-chart-tooltip-label', labelClassName), children: labelFormatter(value, payload) });
86
+ if (!value)
87
+ return null;
88
+ return _jsx("div", { className: cn('sprout-chart-tooltip-label', labelClassName), children: value });
89
+ }, [label, labelFormatter, payload, hideLabel, labelClassName, config, labelKey]);
90
+ if (!active || !payload?.length)
91
+ return null;
92
+ const nestLabel = payload.length === 1 && indicator !== 'dot';
93
+ return (_jsxs("div", { "data-slot": "chart-tooltip", "data-indicator": indicator, className: cn('sprout-chart-tooltip', className), children: [!nestLabel ? tooltipLabel : null, _jsx("div", { className: "sprout-chart-tooltip-items", children: payload
94
+ .filter(item => item.type !== 'none')
95
+ .map((item, index) => {
96
+ const key = `${nameKey ?? item.name ?? item.dataKey ?? 'value'}`;
97
+ const itemConfig = getPayloadConfigFromPayload(config, item, key);
98
+ const indicatorColor = color ?? item.payload?.fill ?? item.color;
99
+ return (_jsx("div", { "data-slot": "chart-tooltip-item", className: "sprout-chart-tooltip-item", children: formatter && item?.value !== undefined && item.name ? (formatter(item.value, item.name, item, index, item.payload)) : (_jsxs(_Fragment, { children: [itemConfig?.icon ? (_jsx(itemConfig.icon, {})) : (!hideIndicator && (_jsx("span", { "aria-hidden": "true", "data-slot": "chart-tooltip-indicator", className: "sprout-chart-tooltip-indicator", style: {
100
+ '--sprout-chart-indicator': indicatorColor,
101
+ } }))), _jsxs("div", { className: "sprout-chart-tooltip-row", "data-nested": nestLabel || undefined, children: [_jsxs("div", { className: "sprout-chart-tooltip-name", children: [nestLabel ? tooltipLabel : null, _jsx("span", { children: itemConfig?.label ?? item.name })] }), item.value != null && (_jsx("span", { className: "sprout-chart-tooltip-value", children: typeof item.value === 'number' ? valueFormatter(item.value) : String(item.value) }))] })] })) }, index));
102
+ }) })] }));
103
+ }
104
+ /** Recharts' `Legend`. Pass `content={<ChartLegendContent />}`. */
105
+ export const ChartLegend = Legend;
106
+ /** A centered row of swatches and config labels, one per series. */
107
+ export function ChartLegendContent({ className, hideIcon = false, payload, verticalAlign = 'bottom', nameKey, }) {
108
+ const { config } = useChart();
109
+ if (!payload?.length)
110
+ return null;
111
+ return (_jsx("div", { "data-slot": "chart-legend", "data-align": verticalAlign === 'top' ? 'top' : 'bottom', className: cn('sprout-chart-legend', className), children: payload
112
+ .filter(item => item.type !== 'none')
113
+ .map((item, index) => {
114
+ const key = `${nameKey ?? item.dataKey ?? 'value'}`;
115
+ const itemConfig = getPayloadConfigFromPayload(config, item, key);
116
+ return (_jsxs("div", { "data-slot": "chart-legend-item", className: "sprout-chart-legend-item", children: [itemConfig?.icon && !hideIcon ? (_jsx(itemConfig.icon, {})) : (_jsx("span", { "aria-hidden": "true", className: "sprout-chart-legend-swatch", style: { backgroundColor: item.color } })), itemConfig?.label] }, index));
117
+ }) }));
118
+ }
119
+ function getPayloadConfigFromPayload(config, payload, key) {
120
+ if (typeof payload !== 'object' || payload === null)
121
+ return undefined;
122
+ const inner = 'payload' in payload && typeof payload.payload === 'object' && payload.payload !== null
123
+ ? payload.payload
124
+ : undefined;
125
+ const outer = payload;
126
+ let configLabelKey = key;
127
+ if (typeof outer[key] === 'string')
128
+ configLabelKey = outer[key];
129
+ else if (inner && typeof inner[key] === 'string')
130
+ configLabelKey = inner[key];
131
+ return configLabelKey in config ? config[configLabelKey] : config[key];
132
+ }
133
+ export const formatNumber = value => value.toLocaleString();
134
+ /** The five chart colors, in order. */
135
+ export const chartPalette = [1, 2, 3, 4, 5].map(step => `var(--sprout-chart-${step})`);
136
+ /** The color for parts past the fifth, folded into one "N more" part. */
137
+ export const chartOtherColor = 'var(--sprout-muted)';
138
+ /** The palette color for a part, or the muted color past the fifth. */
139
+ export const partColor = (index) => chartPalette[index] ?? chartOtherColor;
140
+ /**
141
+ * One of `steps` shades of `color`, mixed with the surface so it reads in
142
+ * light and dark. Step 1 is lightest; the last step is `color` itself.
143
+ */
144
+ export const chartShade = (color, step, steps = 5) => `color-mix(in oklab, ${color} ${Math.round((step / steps) * 100)}%, var(--sprout-surface))`;
145
+ /**
146
+ * Sorts rows by `value`, keeps the top `limit` as colored parts, and folds the
147
+ * rest into one muted "N more" part.
148
+ */
149
+ export function foldParts(rows, category, value, limit = chartPalette.length) {
150
+ const parts = rows
151
+ .map(row => ({
152
+ name: String(row[category] ?? ''),
153
+ value: Number(row[value]) || 0,
154
+ }))
155
+ .filter(part => part.value > 0)
156
+ .sort((a, b) => b.value - a.value);
157
+ const kept = parts.slice(0, limit);
158
+ const rest = parts.slice(kept.length);
159
+ const colored = kept.map((part, index) => ({
160
+ ...part,
161
+ fill: partColor(index),
162
+ }));
163
+ if (!rest.length)
164
+ return colored;
165
+ return [
166
+ ...colored,
167
+ {
168
+ name: `${rest.length} more`,
169
+ value: rest.reduce((sum, part) => sum + part.value, 0),
170
+ fill: chartOtherColor,
171
+ },
172
+ ];
173
+ }
174
+ /** A config entry per part, so the tooltip and legend show part names. */
175
+ export const partConfig = (parts) => Object.fromEntries(parts.map(part => [part.name, { label: part.name, color: part.fill }]));
176
+ export const seriesConfig = (series) => Object.fromEntries(series.map(item => [item.key, { label: item.label, color: item.color }]));
177
+ export const tooltipCursor = { fill: 'var(--sprout-hover)' };
178
+ /** Axis props every ready chart shares: no tick marks, no axis line. */
179
+ export const quietAxis = { tickLine: false, axisLine: false };
180
+ export const stackOffset = (stack) => (stack === 'percent' ? 'expand' : undefined);
181
+ export const formatPercent = value => `${Math.round(value * 100)}%`;
182
+ /** A short day label, like "Oct 17", for a `YYYY-MM-DD` string or a time. */
183
+ export const dayLabel = (value, locale) => new Date(typeof value === 'number' || value instanceof Date ? value : `${String(value)}T00:00:00Z`).toLocaleDateString(locale, {
184
+ month: 'short',
185
+ day: 'numeric',
186
+ timeZone: 'UTC',
187
+ });
188
+ /**
189
+ * Legend content listing every config entry, for charts whose marks are not
190
+ * one series each. Pass it as `<ChartLegend content={configLegend(config)} />`.
191
+ */
192
+ export const configLegend = (config) => function ConfigLegend() {
193
+ return (_jsx(ChartLegendContent, { payload: Object.keys(config).map(key => ({
194
+ value: key,
195
+ dataKey: key,
196
+ color: chartColor(key),
197
+ })) }));
198
+ };
199
+ /** A bar shape that takes its color from the row's `fill`. */
200
+ export const rowFillShape = (props) => (_jsx(Rectangle, { ...props, fill: props.payload.fill }));
@@ -0,0 +1,61 @@
1
+ import { type ChartRow, type ChartSeries, type ChartStack, type ReadyChartProps, type UsageSeries } from '../chart-kit.js';
2
+ export type UsageDay = {
3
+ date: string;
4
+ } & Record<string, number | string | null>;
5
+ export interface UsageChartProps {
6
+ /** One row per UTC day (`YYYY-MM-DD`), keyed by series. */
7
+ days: UsageDay[];
8
+ series: UsageSeries[];
9
+ /** Names the chart for screen readers. */
10
+ title?: string;
11
+ /** Locale for day labels. Defaults to the reader's. */
12
+ locale?: string;
13
+ className?: string;
14
+ }
15
+ /**
16
+ * Stacked daily bars, 256px tall. Days are rows keyed by series; a missing or
17
+ * null value keeps that series out of the day's tooltip. The top series gets
18
+ * rounded corners.
19
+ */
20
+ export declare function UsageChart({ days, series, title, locale, className }: UsageChartProps): import("react").JSX.Element;
21
+ export interface CategoryChartProps extends ReadyChartProps {
22
+ /** One row per category, keyed by `category` and by each series key. */
23
+ rows: ChartRow[];
24
+ /** The row key whose value names each group of bars. */
25
+ category: string;
26
+ series: ChartSeries[];
27
+ /** Bars grow sideways, one row per category. Good for long names. */
28
+ horizontal?: boolean;
29
+ /** `stacked` piles series in one bar; `percent` stacks them to 100%. */
30
+ stack?: ChartStack;
31
+ }
32
+ /**
33
+ * Bars per category with a legend in series order, 288px tall. Negative
34
+ * values hang below a zero line, for profit and loss.
35
+ */
36
+ export declare function CategoryChart({ rows, category, series, horizontal, stack, title, valueFormatter, className, }: CategoryChartProps): import("react").JSX.Element;
37
+ export interface WaterfallChartProps extends ReadyChartProps {
38
+ /** One row per step. `value` is the change that step adds or takes away. */
39
+ rows: ChartRow[];
40
+ /** The row key whose value names each step. */
41
+ category: string;
42
+ /** The row key holding each step's change. */
43
+ value: string;
44
+ /**
45
+ * Steps drawn as a full bar from zero, like a start or end balance. A total
46
+ * with a value starts the running total there; one without shows the
47
+ * running total so far.
48
+ */
49
+ totals?: string[];
50
+ /** Legend labels for rises, falls, and totals. */
51
+ labels?: {
52
+ increase?: string;
53
+ decrease?: string;
54
+ total?: string;
55
+ };
56
+ }
57
+ /**
58
+ * A running total, step by step: green bars rise, red bars fall, and blue
59
+ * totals stand on zero. 288px tall.
60
+ */
61
+ export declare function WaterfallChart({ rows, category, value, totals, labels, title, valueFormatter, className, }: WaterfallChartProps): import("react").JSX.Element;
@@ -0,0 +1,86 @@
1
+ 'use client';
2
+ import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
3
+ import { useMemo } from 'react';
4
+ import { Bar, BarChart, CartesianGrid, ReferenceLine, XAxis, YAxis } from 'recharts';
5
+ import { cn } from '../classes.js';
6
+ import { ChartContainer, ChartLegend, ChartLegendContent, ChartTooltip, ChartTooltipContent, chartColor, configLegend, dayLabel, formatNumber, formatPercent, quietAxis, rowFillShape, seriesConfig, stackOffset, tooltipCursor, } from '../chart-kit.js';
7
+ /**
8
+ * Stacked daily bars, 256px tall. Days are rows keyed by series; a missing or
9
+ * null value keeps that series out of the day's tooltip. The top series gets
10
+ * rounded corners.
11
+ */
12
+ export function UsageChart({ days, series, title = 'Usage by day', locale, className }) {
13
+ const config = useMemo(() => seriesConfig(series), [series]);
14
+ const usageDay = (date) => dayLabel(date, locale);
15
+ return (_jsx(ChartContainer, { "data-variant": "usage", className: cn('sprout-chart-usage', className), config: config, children: _jsxs(BarChart, { data: days, accessibilityLayer: true, title: title, barCategoryGap: "20%", children: [_jsx(CartesianGrid, { vertical: false }), _jsx(XAxis, { dataKey: "date", tickFormatter: usageDay, ...quietAxis, minTickGap: 24 }), _jsx(YAxis, { width: 40, ...quietAxis, allowDecimals: false }), _jsx(ChartTooltip, { cursor: tooltipCursor, content: _jsx(ChartTooltipContent, { labelFormatter: usageDay }) }), series.map((item, index) => (_jsx(Bar, { dataKey: item.key, stackId: "usage", fill: chartColor(item.key), radius: index === series.length - 1 ? [3, 3, 0, 0] : 0, isAnimationActive: false }, item.key)))] }) }));
16
+ }
17
+ const hasNegative = (rows, series) => rows.some(row => series.some(item => Number(row[item.key]) < 0));
18
+ /**
19
+ * Bars per category with a legend in series order, 288px tall. Negative
20
+ * values hang below a zero line, for profit and loss.
21
+ */
22
+ export function CategoryChart({ rows, category, series, horizontal = false, stack = 'none', title, valueFormatter = formatNumber, className, }) {
23
+ const config = useMemo(() => seriesConfig(series), [series]);
24
+ const name = title ?? `${series.map(item => item.label).join(', ')} by ${category}`;
25
+ const stacked = stack !== 'none';
26
+ const end = horizontal ? [0, 3, 3, 0] : [3, 3, 0, 0];
27
+ const tick = stack === 'percent' ? formatPercent : valueFormatter;
28
+ const categoryAxis = { dataKey: category, ...quietAxis };
29
+ const valueAxis = { ...quietAxis, tickFormatter: tick };
30
+ return (_jsx(ChartContainer, { "data-variant": "category", className: cn('sprout-chart-category', className), config: config, children: _jsxs(BarChart, { data: rows, accessibilityLayer: true, title: name, layout: horizontal ? 'vertical' : 'horizontal', stackOffset: stackOffset(stack), barCategoryGap: "24%", children: [_jsx(CartesianGrid, { vertical: horizontal, horizontal: !horizontal }), horizontal ? (_jsxs(_Fragment, { children: [_jsx(XAxis, { type: "number", ...valueAxis }), _jsx(YAxis, { type: "category", width: "auto", ...categoryAxis, interval: 0 })] })) : (_jsxs(_Fragment, { children: [_jsx(XAxis, { ...categoryAxis, minTickGap: 16 }), _jsx(YAxis, { width: "auto", ...valueAxis, allowDecimals: stack === 'percent' })] })), hasNegative(rows, series) ? (_jsx(ReferenceLine, { ...(horizontal ? { x: 0 } : { y: 0 }), stroke: "var(--sprout-border-strong)" })) : null, _jsx(ChartTooltip, { cursor: tooltipCursor, content: _jsx(ChartTooltipContent, { valueFormatter: valueFormatter }) }), _jsx(ChartLegend, { itemSorter: null, content: _jsx(ChartLegendContent, {}) }), series.map((item, index) => (_jsx(Bar, { dataKey: item.key, stackId: stacked ? 'category' : undefined, fill: chartColor(item.key), radius: !stacked || index === series.length - 1 ? end : 0, isAnimationActive: false }, item.key)))] }) }));
31
+ }
32
+ const waterfallColors = {
33
+ increase: 'var(--sprout-green)',
34
+ decrease: 'var(--sprout-red)',
35
+ total: 'var(--sprout-blue)',
36
+ };
37
+ /**
38
+ * A running total, step by step: green bars rise, red bars fall, and blue
39
+ * totals stand on zero. 288px tall.
40
+ */
41
+ export function WaterfallChart({ rows, category, value, totals = [], labels, title = 'Running total by step', valueFormatter = formatNumber, className, }) {
42
+ const steps = useMemo(() => {
43
+ let running = 0;
44
+ return rows.map(row => {
45
+ const name = String(row[category] ?? '');
46
+ const raw = row[value];
47
+ const change = Number(raw) || 0;
48
+ if (totals.includes(name)) {
49
+ if (raw != null && raw !== '')
50
+ running = change;
51
+ return {
52
+ name,
53
+ kind: 'total',
54
+ range: [0, running],
55
+ amount: running,
56
+ fill: waterfallColors.total,
57
+ };
58
+ }
59
+ const from = running;
60
+ running += change;
61
+ const kind = change < 0 ? 'decrease' : 'increase';
62
+ return {
63
+ name,
64
+ kind,
65
+ range: [from, running],
66
+ amount: change,
67
+ fill: waterfallColors[kind],
68
+ };
69
+ });
70
+ }, [rows, category, value, totals]);
71
+ const config = useMemo(() => ({
72
+ increase: {
73
+ label: labels?.increase ?? 'Increase',
74
+ color: waterfallColors.increase,
75
+ },
76
+ decrease: {
77
+ label: labels?.decrease ?? 'Decrease',
78
+ color: waterfallColors.decrease,
79
+ },
80
+ total: { label: labels?.total ?? 'Total', color: waterfallColors.total },
81
+ }), [labels]);
82
+ return (_jsx(ChartContainer, { "data-variant": "waterfall", className: cn('sprout-chart-waterfall', className), config: config, children: _jsxs(BarChart, { data: steps, accessibilityLayer: true, title: title, barCategoryGap: "16%", children: [_jsx(CartesianGrid, { vertical: false }), _jsx(XAxis, { dataKey: "name", ...quietAxis, minTickGap: 8 }), _jsx(YAxis, { width: "auto", ...quietAxis, tickFormatter: valueFormatter }), _jsx(ReferenceLine, { y: 0, stroke: "var(--sprout-border-strong)" }), _jsx(ChartLegend, { content: configLegend(config) }), _jsx(ChartTooltip, { cursor: tooltipCursor, content: props => (_jsx(ChartTooltipContent, { active: props.active, label: props.label, nameKey: "kind", valueFormatter: valueFormatter, payload: props.payload?.map(item => ({
83
+ ...item,
84
+ value: item.payload.amount,
85
+ })) })) }), _jsx(Bar, { dataKey: "range", radius: 3, shape: rowFillShape, isAnimationActive: false })] }) }));
86
+ }
@@ -0,0 +1,67 @@
1
+ import { type ChartRow, type ChartSeries, type ChartStack, type ReadyChartProps, type ValueFormatter } from '../chart-kit.js';
2
+ export type TrendCurve = 'smooth' | 'linear' | 'step';
3
+ /** A series for `ComboChart`: drawn as bars or a line, on the left or right axis. */
4
+ export type ComboSeries = ChartSeries & {
5
+ kind?: 'bar' | 'line';
6
+ axis?: 'left' | 'right';
7
+ };
8
+ interface TrendBaseProps extends ReadyChartProps {
9
+ /** One row per point on the x axis, keyed by `category` and each series. */
10
+ rows: ChartRow[];
11
+ /** The row key for the x axis, such as a date or month. */
12
+ category: string;
13
+ series: ChartSeries[];
14
+ /** `smooth` curves, `linear` straight segments, or `step` stairs. */
15
+ curve?: TrendCurve;
16
+ /** Draws a dot at every point. */
17
+ dots?: boolean;
18
+ /** Formats x axis ticks and the tooltip label, for example dates. */
19
+ categoryFormatter?: (value: unknown) => string;
20
+ }
21
+ export type TrendChartProps = TrendBaseProps;
22
+ /** Lines over time, one per series, 288px tall. A legend shows past one series. */
23
+ export declare function TrendChart({ curve, dots, ...props }: TrendChartProps): import("react").JSX.Element;
24
+ export interface AreaTrendChartProps extends TrendBaseProps {
25
+ /** `stacked` piles series; `percent` stacks them to 100%. */
26
+ stack?: ChartStack;
27
+ }
28
+ /**
29
+ * Filled areas over time with a soft gradient, 288px tall. Stack them to show
30
+ * a total, or to 100% to show shares.
31
+ */
32
+ export declare function AreaTrendChart({ curve, dots, stack, ...props }: AreaTrendChartProps): import("react").JSX.Element;
33
+ export interface ComboChartProps extends ReadyChartProps {
34
+ /** One row per category, keyed by `category` and each series. */
35
+ rows: ChartRow[];
36
+ category: string;
37
+ /** Bars by default. Set `kind: "line"` and `axis: "right"` for a rate. */
38
+ series: ComboSeries[];
39
+ /** Formats the right axis and its series in the tooltip, such as percent. */
40
+ rightValueFormatter?: ValueFormatter;
41
+ categoryFormatter?: (value: unknown) => string;
42
+ /** Stacks the bar series. */
43
+ stacked?: boolean;
44
+ }
45
+ /**
46
+ * Bars and lines on one chart, like revenue with its growth rate, 288px tall.
47
+ * Series on `axis: "right"` get their own scale.
48
+ */
49
+ export declare function ComboChart({ stacked, ...props }: ComboChartProps): import("react").JSX.Element;
50
+ export interface SparklineProps {
51
+ /** The points, oldest first. */
52
+ values: number[];
53
+ /** Names the trend for screen readers, such as "MRR, last 12 weeks". */
54
+ title: string;
55
+ /** Any CSS color. Defaults to `--sprout-chart-1`. */
56
+ color?: string;
57
+ /** Fills under the line. */
58
+ area?: boolean;
59
+ valueFormatter?: ValueFormatter;
60
+ className?: string;
61
+ }
62
+ /**
63
+ * A tiny trend line for a stat tile, 40px tall and as wide as its box. No
64
+ * axes; hover shows the value.
65
+ */
66
+ export declare function Sparkline({ values, title, color, area, valueFormatter, className, }: SparklineProps): import("react").JSX.Element;
67
+ export {};
@@ -0,0 +1,70 @@
1
+ 'use client';
2
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
3
+ import { useId, useMemo } from 'react';
4
+ import { Area, Bar, CartesianGrid, ComposedChart, Line, XAxis, YAxis } from 'recharts';
5
+ import { cn } from '../classes.js';
6
+ import { ChartContainer, ChartLegend, ChartLegendContent, ChartTooltip, ChartTooltipContent, chartColor, formatNumber, formatPercent, quietAxis, seriesConfig, stackOffset, tooltipCursor, } from '../chart-kit.js';
7
+ const curveType = {
8
+ smooth: 'monotone',
9
+ linear: 'linear',
10
+ step: 'step',
11
+ };
12
+ function SeriesPlot({ variant, rows, category, series, mark, curve, dots, stack, title, valueFormatter = formatNumber, rightValueFormatter = valueFormatter, categoryFormatter, className, }) {
13
+ const config = useMemo(() => seriesConfig(series), [series]);
14
+ const gradient = `sprout-area-${useId().replace(/:/g, '')}`;
15
+ const stacked = stack !== 'none';
16
+ const right = series.some(item => item.axis === 'right');
17
+ const anyBar = series.some(item => mark(item) === 'bar');
18
+ const tick = stack === 'percent' ? formatPercent : valueFormatter;
19
+ const format = (key) => series.find(item => item.key === key)?.axis === 'right' ? rightValueFormatter : valueFormatter;
20
+ const name = title ?? `${series.map(item => item.label).join(', ')} by ${category}`;
21
+ const type = curveType[curve];
22
+ return (_jsx(ChartContainer, { "data-variant": variant, className: cn(`sprout-chart-${variant}`, className), config: config, children: _jsxs(ComposedChart, { data: rows, accessibilityLayer: true, title: name, stackOffset: stackOffset(stack), barCategoryGap: "24%", margin: { top: 4, right: right ? 0 : 12, bottom: 0, left: 0 }, children: [_jsx("defs", { children: series.map(item => (_jsxs("linearGradient", { id: `${gradient}-${item.key}`, x1: "0", y1: "0", x2: "0", y2: "1", children: [_jsx("stop", { offset: "5%", stopColor: chartColor(item.key), stopOpacity: 0.4 }), _jsx("stop", { offset: "95%", stopColor: chartColor(item.key), stopOpacity: 0.04 })] }, item.key))) }), _jsx(CartesianGrid, { vertical: false }), _jsx(XAxis, { dataKey: category, tickFormatter: categoryFormatter, ...quietAxis, minTickGap: 16 }), _jsx(YAxis, { yAxisId: "left", width: "auto", tickFormatter: tick, ...quietAxis }), right ? (_jsx(YAxis, { yAxisId: "right", orientation: "right", width: "auto", tickFormatter: rightValueFormatter, ...quietAxis })) : null, _jsx(ChartTooltip, { cursor: anyBar ? tooltipCursor : true, content: props => (_jsx(ChartTooltipContent, { active: props.active, label: props.label, indicator: anyBar ? 'dot' : 'line', labelFormatter: categoryFormatter
23
+ ? (_, payload) => categoryFormatter(payload[0]?.payload?.[category])
24
+ : undefined, payload: props.payload?.map(item => ({
25
+ ...item,
26
+ value: typeof item.value === 'number' ? format(String(item.dataKey))(item.value) : item.value,
27
+ })) })) }), series.length > 1 ? (_jsx(ChartLegend, { verticalAlign: "top", itemSorter: null, content: _jsx(ChartLegendContent, {}) })) : null, series.map((item, index) => {
28
+ const color = chartColor(item.key);
29
+ const shared = {
30
+ dataKey: item.key,
31
+ yAxisId: item.axis ?? 'left',
32
+ stackId: stacked ? 'series' : undefined,
33
+ isAnimationActive: false,
34
+ };
35
+ const kind = mark(item);
36
+ if (kind === 'bar')
37
+ return (_jsx(Bar, { ...shared, fill: color, radius: !stacked || index === series.length - 1 ? [3, 3, 0, 0] : 0 }, item.key));
38
+ if (kind === 'area')
39
+ return (_jsx(Area, { ...shared, type: type, stroke: color, strokeWidth: 2, fill: `url(#${gradient}-${item.key})`, dot: dots ? { r: 3, fill: color } : false, activeDot: { r: 4 } }, item.key));
40
+ return (_jsx(Line, { ...shared, type: type, stroke: color, strokeWidth: 2, dot: dots ? { r: 3, fill: color } : false, activeDot: { r: 4 } }, item.key));
41
+ })] }) }));
42
+ }
43
+ /** Lines over time, one per series, 288px tall. A legend shows past one series. */
44
+ export function TrendChart({ curve = 'smooth', dots = false, ...props }) {
45
+ return _jsx(SeriesPlot, { variant: "trend", mark: () => 'line', curve: curve, dots: dots, stack: "none", ...props });
46
+ }
47
+ /**
48
+ * Filled areas over time with a soft gradient, 288px tall. Stack them to show
49
+ * a total, or to 100% to show shares.
50
+ */
51
+ export function AreaTrendChart({ curve = 'smooth', dots = false, stack = 'none', ...props }) {
52
+ return _jsx(SeriesPlot, { variant: "area", mark: () => 'area', curve: curve, dots: dots, stack: stack, ...props });
53
+ }
54
+ /**
55
+ * Bars and lines on one chart, like revenue with its growth rate, 288px tall.
56
+ * Series on `axis: "right"` get their own scale.
57
+ */
58
+ export function ComboChart({ stacked = false, ...props }) {
59
+ return (_jsx(SeriesPlot, { variant: "combo", mark: item => item.kind ?? 'bar', curve: "smooth", dots: true, stack: stacked ? 'stacked' : 'none', ...props }));
60
+ }
61
+ /**
62
+ * A tiny trend line for a stat tile, 40px tall and as wide as its box. No
63
+ * axes; hover shows the value.
64
+ */
65
+ export function Sparkline({ values, title, color = 'var(--sprout-chart-1)', area = false, valueFormatter = formatNumber, className, }) {
66
+ const rows = useMemo(() => values.map((value, index) => ({ index, value })), [values]);
67
+ const config = useMemo(() => ({ value: { label: title, color } }), [title, color]);
68
+ const gradient = `sprout-spark-${useId().replace(/:/g, '')}`;
69
+ return (_jsx(ChartContainer, { "data-variant": "sparkline", className: cn('sprout-chart-sparkline', className), config: config, initialDimension: { width: 120, height: 40 }, children: _jsxs(ComposedChart, { data: rows, accessibilityLayer: true, title: title, margin: { top: 4, right: 4, bottom: 4, left: 4 }, children: [_jsx("defs", { children: _jsxs("linearGradient", { id: gradient, x1: "0", y1: "0", x2: "0", y2: "1", children: [_jsx("stop", { offset: "5%", stopColor: chartColor('value'), stopOpacity: 0.3 }), _jsx("stop", { offset: "95%", stopColor: chartColor('value'), stopOpacity: 0 })] }) }), _jsx(YAxis, { hide: true, domain: ['dataMin', 'dataMax'] }), _jsx(ChartTooltip, { cursor: false, content: _jsx(ChartTooltipContent, { hideLabel: true, indicator: "line", valueFormatter: valueFormatter }) }), _jsx(Area, { dataKey: "value", type: "monotone", stroke: chartColor('value'), strokeWidth: 1.5, fill: area ? `url(#${gradient})` : 'none', dot: false, activeDot: { r: 3 }, isAnimationActive: false })] }) }));
70
+ }