@nocoo/basalt 2.0.3 → 2.1.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 (295) hide show
  1. package/README.md +134 -15
  2. package/ai/COMPATIBILITY.md +180 -0
  3. package/ai/INTEGRATION.md +1760 -0
  4. package/ai/RECIPES.md +161 -0
  5. package/ai/USAGE.md +99 -0
  6. package/ai/registry.json +38099 -0
  7. package/ai/sources.json +10 -0
  8. package/dist/assets/brand-mark.d.ts +1 -0
  9. package/dist/assets/brand-mark.js +7 -0
  10. package/dist/assets/brand-mark.js.map +1 -0
  11. package/dist/charts/area.d.ts +58 -5
  12. package/dist/charts/area.js +20 -12
  13. package/dist/charts/area.js.map +1 -1
  14. package/dist/charts/bar.d.ts +54 -5
  15. package/dist/charts/bar.js +16 -10
  16. package/dist/charts/bar.js.map +1 -1
  17. package/dist/charts/bullet.d.ts +18 -1
  18. package/dist/charts/bullet.js +6 -3
  19. package/dist/charts/bullet.js.map +1 -1
  20. package/dist/charts/charts.d.ts +58 -5
  21. package/dist/charts/charts.js +13 -2
  22. package/dist/charts/charts.js.map +1 -1
  23. package/dist/charts/config.d.ts +7 -0
  24. package/dist/charts/config.js +5 -1
  25. package/dist/charts/config.js.map +1 -1
  26. package/dist/charts/custom-chart.d.ts +58 -5
  27. package/dist/charts/custom-chart.js +13 -2
  28. package/dist/charts/custom-chart.js.map +1 -1
  29. package/dist/charts/donut.d.ts +18 -1
  30. package/dist/charts/donut.js +6 -3
  31. package/dist/charts/donut.js.map +1 -1
  32. package/dist/charts/frame.d.ts +40 -3
  33. package/dist/charts/frame.js +55 -28
  34. package/dist/charts/frame.js.map +1 -1
  35. package/dist/charts/funnel.d.ts +18 -1
  36. package/dist/charts/funnel.js +5 -1
  37. package/dist/charts/funnel.js.map +1 -1
  38. package/dist/charts/gauge.d.ts +18 -1
  39. package/dist/charts/gauge.js +38 -20
  40. package/dist/charts/gauge.js.map +1 -1
  41. package/dist/charts/grouped-bar.d.ts +54 -5
  42. package/dist/charts/grouped-bar.js +16 -10
  43. package/dist/charts/grouped-bar.js.map +1 -1
  44. package/dist/charts/heatmap-calendar.d.ts +61 -0
  45. package/dist/charts/heatmap-calendar.js +287 -96
  46. package/dist/charts/heatmap-calendar.js.map +1 -1
  47. package/dist/charts/heatmap-matrix.d.ts +99 -0
  48. package/dist/charts/heatmap-matrix.js +249 -0
  49. package/dist/charts/heatmap-matrix.js.map +1 -0
  50. package/dist/charts/line.d.ts +66 -5
  51. package/dist/charts/line.js +37 -30
  52. package/dist/charts/line.js.map +1 -1
  53. package/dist/charts/palette.d.ts +1 -0
  54. package/dist/charts/palette.js +7 -1
  55. package/dist/charts/palette.js.map +1 -1
  56. package/dist/charts/radar.d.ts +18 -1
  57. package/dist/charts/radar.js +26 -19
  58. package/dist/charts/radar.js.map +1 -1
  59. package/dist/charts/sankey.d.ts +18 -1
  60. package/dist/charts/sankey.js +4 -1
  61. package/dist/charts/sankey.js.map +1 -1
  62. package/dist/charts/series.d.ts +5 -7
  63. package/dist/charts/series.js.map +1 -1
  64. package/dist/charts/slot-bar.d.ts +38 -6
  65. package/dist/charts/slot-bar.js +5 -2
  66. package/dist/charts/slot-bar.js.map +1 -1
  67. package/dist/charts/sparkline.d.ts +35 -5
  68. package/dist/charts/sparkline.js +22 -18
  69. package/dist/charts/sparkline.js.map +1 -1
  70. package/dist/charts/stacked-bar.d.ts +58 -5
  71. package/dist/charts/stacked-bar.js +19 -12
  72. package/dist/charts/stacked-bar.js.map +1 -1
  73. package/dist/charts/stat-card.d.ts +51 -1
  74. package/dist/charts/stat-card.js +66 -39
  75. package/dist/charts/stat-card.js.map +1 -1
  76. package/dist/charts/timeline.d.ts +3 -0
  77. package/dist/charts/timeline.js +4 -3
  78. package/dist/charts/timeline.js.map +1 -1
  79. package/dist/charts/timeseries.d.ts +58 -5
  80. package/dist/charts/timeseries.js +13 -2
  81. package/dist/charts/timeseries.js.map +1 -1
  82. package/dist/charts/tooltip.d.ts +57 -0
  83. package/dist/charts/tooltip.js +119 -2
  84. package/dist/charts/tooltip.js.map +1 -1
  85. package/dist/components/accordion.d.ts +117 -2
  86. package/dist/components/accordion.js +20 -13
  87. package/dist/components/accordion.js.map +1 -1
  88. package/dist/components/alert-dialog.d.ts +131 -13
  89. package/dist/components/alert-dialog.js +12 -9
  90. package/dist/components/alert-dialog.js.map +1 -1
  91. package/dist/components/app-header.js +18 -17
  92. package/dist/components/app-header.js.map +1 -1
  93. package/dist/components/app-shell.js +15 -14
  94. package/dist/components/app-shell.js.map +1 -1
  95. package/dist/components/autocomplete.d.ts +4 -0
  96. package/dist/components/autocomplete.js.map +1 -1
  97. package/dist/components/avatar.d.ts +76 -3
  98. package/dist/components/avatar.js.map +1 -1
  99. package/dist/components/badge.d.ts +15 -1
  100. package/dist/components/badge.js +17 -16
  101. package/dist/components/badge.js.map +1 -1
  102. package/dist/components/banner.d.ts +88 -2
  103. package/dist/components/banner.js +41 -40
  104. package/dist/components/banner.js.map +1 -1
  105. package/dist/components/basalt-mark.js +14 -8
  106. package/dist/components/basalt-mark.js.map +1 -1
  107. package/dist/components/battery-meter.d.ts +10 -0
  108. package/dist/components/battery-meter.js +56 -0
  109. package/dist/components/battery-meter.js.map +1 -0
  110. package/dist/components/breadcrumbs.d.ts +27 -7
  111. package/dist/components/breadcrumbs.js +21 -20
  112. package/dist/components/breadcrumbs.js.map +1 -1
  113. package/dist/components/button.d.ts +48 -2
  114. package/dist/components/button.js +87 -36
  115. package/dist/components/button.js.map +1 -1
  116. package/dist/components/chat-bubble.d.ts +7 -0
  117. package/dist/components/chat-bubble.js +14 -13
  118. package/dist/components/chat-bubble.js.map +1 -1
  119. package/dist/components/chat-composer.d.ts +7 -3
  120. package/dist/components/chat-composer.js.map +1 -1
  121. package/dist/components/chat-header.d.ts +6 -1
  122. package/dist/components/chat-header.js +17 -16
  123. package/dist/components/chat-header.js.map +1 -1
  124. package/dist/components/chat-inbox.d.ts +7 -2
  125. package/dist/components/chat-inbox.js.map +1 -1
  126. package/dist/components/checkbox.js +84 -53
  127. package/dist/components/checkbox.js.map +1 -1
  128. package/dist/components/clipboard-text.d.ts +13 -2
  129. package/dist/components/clipboard-text.js +4 -4
  130. package/dist/components/clipboard-text.js.map +1 -1
  131. package/dist/components/collapsible.d.ts +58 -15
  132. package/dist/components/collapsible.js.map +1 -1
  133. package/dist/components/command-palette.d.ts +151 -61
  134. package/dist/components/command-palette.js.map +1 -1
  135. package/dist/components/confirm-dialog.d.ts +1 -1
  136. package/dist/components/confirm-dialog.js +6 -4
  137. package/dist/components/confirm-dialog.js.map +1 -1
  138. package/dist/components/context-menu.d.ts +210 -2
  139. package/dist/components/context-menu.js +7 -4
  140. package/dist/components/context-menu.js.map +1 -1
  141. package/dist/components/data-table.d.ts +40 -2
  142. package/dist/components/data-table.js +168 -120
  143. package/dist/components/data-table.js.map +1 -1
  144. package/dist/components/date-picker.d.ts +53 -2
  145. package/dist/components/date-picker.js +387 -219
  146. package/dist/components/date-picker.js.map +1 -1
  147. package/dist/components/delete-resource.d.ts +7 -1
  148. package/dist/components/delete-resource.js +22 -18
  149. package/dist/components/delete-resource.js.map +1 -1
  150. package/dist/components/description-list.js +16 -15
  151. package/dist/components/description-list.js.map +1 -1
  152. package/dist/components/dialog.d.ts +141 -12
  153. package/dist/components/dialog.js +42 -38
  154. package/dist/components/dialog.js.map +1 -1
  155. package/dist/components/dock.d.ts +1 -1
  156. package/dist/components/dock.js +39 -58
  157. package/dist/components/dock.js.map +1 -1
  158. package/dist/components/dropdown-menu.d.ts +229 -15
  159. package/dist/components/dropdown-menu.js +9 -6
  160. package/dist/components/dropdown-menu.js.map +1 -1
  161. package/dist/components/editable-nav-item.d.ts +33 -0
  162. package/dist/components/editable-nav-item.js +90 -0
  163. package/dist/components/editable-nav-item.js.map +1 -0
  164. package/dist/components/empty.d.ts +22 -2
  165. package/dist/components/empty.js +22 -13
  166. package/dist/components/empty.js.map +1 -1
  167. package/dist/components/field.js +31 -30
  168. package/dist/components/field.js.map +1 -1
  169. package/dist/components/file-dropzone.d.ts +37 -0
  170. package/dist/components/file-dropzone.js +103 -0
  171. package/dist/components/file-dropzone.js.map +1 -0
  172. package/dist/components/filter-bar.d.ts +34 -0
  173. package/dist/components/filter-bar.js +52 -0
  174. package/dist/components/filter-bar.js.map +1 -0
  175. package/dist/components/flow.js +19 -18
  176. package/dist/components/flow.js.map +1 -1
  177. package/dist/components/grid.d.ts +3 -1
  178. package/dist/components/grid.js.map +1 -1
  179. package/dist/components/hover-card.d.ts +111 -1
  180. package/dist/components/hover-card.js +9 -6
  181. package/dist/components/hover-card.js.map +1 -1
  182. package/dist/components/icon-picker.d.ts +34 -0
  183. package/dist/components/icon-picker.js +77 -0
  184. package/dist/components/icon-picker.js.map +1 -0
  185. package/dist/components/inline-editable.d.ts +46 -0
  186. package/dist/components/inline-editable.js +124 -0
  187. package/dist/components/inline-editable.js.map +1 -0
  188. package/dist/components/input-area.js +3 -3
  189. package/dist/components/input-group.js +7 -7
  190. package/dist/components/input.js +3 -3
  191. package/dist/components/label.js +18 -17
  192. package/dist/components/label.js.map +1 -1
  193. package/dist/components/layer-card.d.ts +10 -2
  194. package/dist/components/layer-card.js +71 -68
  195. package/dist/components/layer-card.js.map +1 -1
  196. package/dist/components/loader.d.ts +10 -2
  197. package/dist/components/loader.js.map +1 -1
  198. package/dist/components/menu-bar.d.ts +174 -6
  199. package/dist/components/menu-bar.js +33 -29
  200. package/dist/components/menu-bar.js.map +1 -1
  201. package/dist/components/meter.d.ts +27 -2
  202. package/dist/components/meter.js.map +1 -1
  203. package/dist/components/multi-select.d.ts +64 -0
  204. package/dist/components/multi-select.js +218 -0
  205. package/dist/components/multi-select.js.map +1 -0
  206. package/dist/components/navigation-menu.d.ts +88 -5
  207. package/dist/components/navigation-menu.js.map +1 -1
  208. package/dist/components/overlay.js +6 -5
  209. package/dist/components/overlay.js.map +1 -1
  210. package/dist/components/page-header.js +23 -21
  211. package/dist/components/page-header.js.map +1 -1
  212. package/dist/components/pagination.js +7 -7
  213. package/dist/components/popover.d.ts +136 -16
  214. package/dist/components/popover.js +32 -28
  215. package/dist/components/popover.js.map +1 -1
  216. package/dist/components/radio.js +38 -37
  217. package/dist/components/radio.js.map +1 -1
  218. package/dist/components/resource-list.d.ts +26 -1
  219. package/dist/components/resource-list.js +28 -15
  220. package/dist/components/resource-list.js.map +1 -1
  221. package/dist/components/responsive-master-detail.d.ts +27 -0
  222. package/dist/components/responsive-master-detail.js +85 -0
  223. package/dist/components/responsive-master-detail.js.map +1 -0
  224. package/dist/components/section-rule.js +23 -22
  225. package/dist/components/section-rule.js.map +1 -1
  226. package/dist/components/select.d.ts +27 -3
  227. package/dist/components/select.js +11 -11
  228. package/dist/components/select.js.map +1 -1
  229. package/dist/components/sheet.d.ts +115 -11
  230. package/dist/components/sheet.js +37 -30
  231. package/dist/components/sheet.js.map +1 -1
  232. package/dist/components/sidebar.d.ts +109 -17
  233. package/dist/components/sidebar.js +109 -108
  234. package/dist/components/sidebar.js.map +1 -1
  235. package/dist/components/skeleton-line.d.ts +22 -2
  236. package/dist/components/skeleton-line.js.map +1 -1
  237. package/dist/components/slider.d.ts +61 -1
  238. package/dist/components/slider.js +31 -15
  239. package/dist/components/slider.js.map +1 -1
  240. package/dist/components/stat-strip.js +16 -15
  241. package/dist/components/stat-strip.js.map +1 -1
  242. package/dist/components/switch.js +78 -47
  243. package/dist/components/switch.js.map +1 -1
  244. package/dist/components/table-of-contents.js +18 -17
  245. package/dist/components/table-of-contents.js.map +1 -1
  246. package/dist/components/table-pager.js +20 -19
  247. package/dist/components/table-pager.js.map +1 -1
  248. package/dist/components/table.d.ts +9 -3
  249. package/dist/components/table.js +19 -18
  250. package/dist/components/table.js.map +1 -1
  251. package/dist/components/tabs.js +29 -22
  252. package/dist/components/tabs.js.map +1 -1
  253. package/dist/components/tag-badge.d.ts +58 -0
  254. package/dist/components/tag-badge.js +72 -0
  255. package/dist/components/tag-badge.js.map +1 -0
  256. package/dist/components/tag-color-picker.d.ts +20 -0
  257. package/dist/components/tag-color-picker.js +42 -0
  258. package/dist/components/tag-color-picker.js.map +1 -0
  259. package/dist/components/text.js +17 -16
  260. package/dist/components/text.js.map +1 -1
  261. package/dist/components/toast.d.ts +173 -3
  262. package/dist/components/toast.js +1 -1
  263. package/dist/components/toast.js.map +1 -1
  264. package/dist/components/toggle-group.d.ts +88 -2
  265. package/dist/components/toggle-group.js +32 -31
  266. package/dist/components/toggle-group.js.map +1 -1
  267. package/dist/components/toggle.d.ts +35 -2
  268. package/dist/components/toggle.js +12 -11
  269. package/dist/components/toggle.js.map +1 -1
  270. package/dist/components/tooltip.d.ts +144 -6
  271. package/dist/components/tooltip.js +9 -6
  272. package/dist/components/tooltip.js.map +1 -1
  273. package/dist/components/typeahead-field.js +193 -132
  274. package/dist/components/typeahead-field.js.map +1 -1
  275. package/dist/components/upload-queue.d.ts +51 -0
  276. package/dist/components/upload-queue.js +116 -0
  277. package/dist/components/upload-queue.js.map +1 -0
  278. package/dist/providers/accent.d.ts +46 -2
  279. package/dist/providers/accent.js +358 -172
  280. package/dist/providers/accent.js.map +1 -1
  281. package/dist/providers/link.d.ts +14 -4
  282. package/dist/providers/link.js.map +1 -1
  283. package/dist/providers/theme.d.ts +38 -2
  284. package/dist/providers/theme.js +160 -27
  285. package/dist/providers/theme.js.map +1 -1
  286. package/dist/styles/base.css +83 -0
  287. package/dist/styles/standalone.css +711 -120
  288. package/dist/styles/tailwind.css +21 -7
  289. package/dist/styles/tokens.css +145 -91
  290. package/dist/utils/control-surface.d.ts +2 -1
  291. package/dist/utils/control-surface.js +4 -4
  292. package/dist/utils/control-surface.js.map +1 -1
  293. package/dist/utils/selection-indicator.js +2 -2
  294. package/dist/utils/selection-indicator.js.map +1 -1
  295. package/package.json +8 -4
@@ -1,20 +1,70 @@
1
1
  import type { LucideIcon } from "lucide-react";
2
2
  import type { ReactNode } from "react";
3
3
  export type StatCardProps = {
4
+ /**
5
+ * Secondary heading label for the metric card (overridden by title).
6
+ */
4
7
  label?: string;
8
+ /**
9
+ * Primary heading title for the metric card (takes precedence over label).
10
+ */
5
11
  title?: string;
12
+ /**
13
+ * Metric value, formatted via toLocaleString() if a number is provided.
14
+ * Overridden by the status slot if provided.
15
+ */
6
16
  value: string | number;
17
+ /**
18
+ * Supporting descriptive subtitle text rendered below value.
19
+ */
7
20
  subtitle?: string;
21
+ /**
22
+ * Optional decorative Lucide icon component.
23
+ */
8
24
  icon?: LucideIcon;
25
+ /**
26
+ * Color class applied to the icon wrapper.
27
+ * @default "text-basalt-muted-foreground"
28
+ */
9
29
  iconColor?: string;
30
+ /**
31
+ * Structured percentage trend value and optional label.
32
+ * Overridden by the trendContent slot if provided.
33
+ */
10
34
  trend?: {
11
35
  value: number;
12
36
  label?: string;
13
37
  };
38
+ /**
39
+ * Optional header action or interactive element (e.g. tooltip trigger or button).
40
+ * Renders alongside the title/icon. Switches card role to group for accessible descendants.
41
+ */
42
+ action?: ReactNode;
43
+ /**
44
+ * Optional custom status replacement slot (e.g. loading skeleton, error state, or empty state).
45
+ * Takes precedence over the default value display and excludes value from accessible name.
46
+ * Subtitle and trend remain caller-managed; when error/empty state is shown, callers should omit trend.
47
+ */
48
+ status?: ReactNode;
49
+ /**
50
+ * Optional custom trend replacement slot (e.g. custom badge, sparkline, or localized trend indicator).
51
+ * Takes precedence over the default trend calculation and excludes default trend from accessible name.
52
+ */
53
+ trendContent?: ReactNode;
54
+ /**
55
+ * Optional custom content rendered below the metric value and above or alongside the trend.
56
+ */
57
+ children?: ReactNode;
58
+ /**
59
+ * Explicit accessible label overriding automatic accessible name calculation.
60
+ */
14
61
  ariaLabel?: string;
62
+ /**
63
+ * Additional CSS class names for styling the card root.
64
+ */
15
65
  className?: string;
16
66
  };
17
- export declare function StatCard({ label, title, value, subtitle, icon: Icon, iconColor, trend, ariaLabel, className, }: StatCardProps): import("react").JSX.Element;
67
+ export declare function StatCard({ label, title, value, subtitle, icon: Icon, iconColor, trend, action, status, trendContent, children, ariaLabel, className, }: StatCardProps): import("react").JSX.Element;
18
68
  export type StatGridProps = {
19
69
  children: ReactNode;
20
70
  columns?: 2 | 3 | 4;
@@ -1,66 +1,93 @@
1
1
  "use client";
2
2
  import { cn as e } from "../utils/cn.js";
3
- import { jsx as t, jsxs as n } from "react/jsx-runtime";
3
+ import { Fragment as t, jsx as n, jsxs as r } from "react/jsx-runtime";
4
4
  //#region src/charts/stat-card.tsx
5
- function r({ label: r, title: i, value: a, subtitle: o, icon: s, iconColor: c = "text-basalt-muted-foreground", trend: l, ariaLabel: u, className: d }) {
6
- let f = i ?? r, p = typeof a == "number" ? a.toLocaleString() : a, m = l && l.value > 0, h = l && l.value < 0, g = u ?? [
7
- f,
8
- p,
9
- o,
10
- l ? `${m ? "+" : ""}${l.value}% ${l.label ?? ""}` : null
11
- ].filter(Boolean).join(" ").trim();
12
- return /* @__PURE__ */ n("div", {
13
- className: e("rounded-basalt-md border border-basalt-border bg-basalt-secondary p-4", d),
14
- role: "img",
15
- "aria-label": g,
16
- children: [/* @__PURE__ */ n("div", {
17
- className: "flex items-start justify-between",
18
- children: [/* @__PURE__ */ n("div", {
19
- className: "space-y-1",
5
+ function i(e) {
6
+ return e != null && e !== !1;
7
+ }
8
+ function a({ label: a, title: o, value: s, subtitle: c, icon: l, iconColor: u = "text-basalt-muted-foreground", trend: d, action: f, status: p, trendContent: m, children: h, ariaLabel: g, className: _ }) {
9
+ let v = o ?? a, y = i(p), b = i(m), x = i(f), S = i(h), C = x || y || b || S, w = x || !!l, T = typeof s == "number" ? s.toLocaleString() : s, E = d && d.value > 0, D = d && d.value < 0, O = g ?? [
10
+ v,
11
+ y ? null : T,
12
+ c,
13
+ !b && d ? `${E ? "+" : ""}${d.value}% ${d.label ?? ""}` : null
14
+ ].filter(Boolean).join(" ").trim(), k = /* @__PURE__ */ r(t, { children: [
15
+ /* @__PURE__ */ r("div", {
16
+ className: "flex items-start justify-between gap-3",
17
+ children: [/* @__PURE__ */ r("div", {
18
+ className: "min-w-0 flex-1 space-y-1",
20
19
  children: [
21
- /* @__PURE__ */ t("p", {
20
+ /* @__PURE__ */ n("p", {
22
21
  className: "text-xs text-basalt-muted-foreground md:text-sm",
23
- children: f
22
+ children: v
24
23
  }),
25
- /* @__PURE__ */ t("p", {
26
- className: "font-display text-xl font-semibold tracking-tight text-basalt-foreground md:text-2xl",
24
+ y ? /* @__PURE__ */ n("div", {
25
+ className: "pt-0.5",
27
26
  children: p
27
+ }) : /* @__PURE__ */ n("p", {
28
+ className: "font-display text-xl font-semibold tracking-tight text-basalt-foreground md:text-2xl",
29
+ children: T
28
30
  }),
29
- o ? /* @__PURE__ */ t("p", {
31
+ c ? /* @__PURE__ */ n("p", {
30
32
  className: "text-xs text-basalt-muted-foreground",
31
- children: o
33
+ children: c
32
34
  }) : null
33
35
  ]
34
- }), s ? /* @__PURE__ */ t("div", {
35
- className: e("rounded-md bg-basalt-card p-2", c),
36
- children: /* @__PURE__ */ t(s, {
37
- className: "h-5 w-5",
38
- strokeWidth: 1.5
39
- })
36
+ }), w ? /* @__PURE__ */ r("div", {
37
+ className: "flex items-center gap-2 shrink-0",
38
+ children: [x ? /* @__PURE__ */ n("div", {
39
+ className: "flex items-center",
40
+ children: f
41
+ }) : null, l ? /* @__PURE__ */ n("div", {
42
+ className: e("rounded-md bg-basalt-card p-2", u),
43
+ children: /* @__PURE__ */ n(l, {
44
+ className: "h-5 w-5",
45
+ strokeWidth: 1.5
46
+ })
47
+ }) : null]
40
48
  }) : null]
41
- }), l ? /* @__PURE__ */ n("div", {
49
+ }),
50
+ S ? /* @__PURE__ */ n("div", {
51
+ className: "mt-2",
52
+ children: h
53
+ }) : null,
54
+ b ? /* @__PURE__ */ n("div", {
55
+ className: "mt-3 flex items-center gap-1 text-xs",
56
+ children: m
57
+ }) : d ? /* @__PURE__ */ r("div", {
42
58
  className: "mt-3 flex items-center gap-1 text-xs",
43
- children: [/* @__PURE__ */ t("span", {
44
- className: e("font-medium", m && "text-basalt-heatmap-green-4", h && "text-basalt-destructive", !m && !h && "text-basalt-muted-foreground"),
45
- children: `${m ? "+" : ""}${l.value}%`
46
- }), l.label ? /* @__PURE__ */ t("span", {
59
+ children: [/* @__PURE__ */ n("span", {
60
+ className: e("font-medium", E && "text-basalt-heatmap-green-4", D && "text-basalt-destructive", !E && !D && "text-basalt-muted-foreground"),
61
+ children: `${E ? "+" : ""}${d.value}%`
62
+ }), d.label ? /* @__PURE__ */ n("span", {
47
63
  className: "text-basalt-muted-foreground",
48
- children: l.label
64
+ children: d.label
49
65
  }) : null]
50
- }) : null]
66
+ }) : null
67
+ ] });
68
+ return C ? /* @__PURE__ */ n("div", {
69
+ className: e("rounded-basalt-md border border-basalt-border bg-basalt-secondary p-4", _),
70
+ role: "group",
71
+ "aria-label": O,
72
+ children: k
73
+ }) : /* @__PURE__ */ n("div", {
74
+ className: e("rounded-basalt-md border border-basalt-border bg-basalt-secondary p-4", _),
75
+ role: "img",
76
+ "aria-label": O,
77
+ children: k
51
78
  });
52
79
  }
53
- function i({ children: n, columns: r = 4, className: i }) {
54
- return /* @__PURE__ */ t("div", {
80
+ function o({ children: t, columns: r = 4, className: i }) {
81
+ return /* @__PURE__ */ n("div", {
55
82
  className: e("grid gap-3 md:gap-4", {
56
83
  2: "grid-cols-1 sm:grid-cols-2",
57
84
  3: "grid-cols-1 sm:grid-cols-2 lg:grid-cols-3",
58
85
  4: "grid-cols-1 sm:grid-cols-2 lg:grid-cols-4"
59
86
  }[r], i),
60
- children: n
87
+ children: t
61
88
  });
62
89
  }
63
90
  //#endregion
64
- export { r as StatCard, i as StatGrid };
91
+ export { a as StatCard, o as StatGrid };
65
92
 
66
93
  //# sourceMappingURL=stat-card.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"stat-card.js","names":[],"sources":["../../src/charts/stat-card.tsx"],"sourcesContent":["import type { LucideIcon } from \"lucide-react\";\nimport type { ReactNode } from \"react\";\nimport { cn } from \"../utils/cn\";\n\nexport type StatCardProps = {\n\tlabel?: string;\n\ttitle?: string;\n\tvalue: string | number;\n\tsubtitle?: string;\n\ticon?: LucideIcon;\n\ticonColor?: string;\n\ttrend?: { value: number; label?: string };\n\tariaLabel?: string;\n\tclassName?: string;\n};\n\nexport function StatCard({\n\tlabel,\n\ttitle,\n\tvalue,\n\tsubtitle,\n\ticon: Icon,\n\ticonColor = \"text-basalt-muted-foreground\",\n\ttrend,\n\tariaLabel,\n\tclassName,\n}: StatCardProps) {\n\tconst heading = title ?? label;\n\tconst display = typeof value === \"number\" ? value.toLocaleString() : value;\n\tconst isPositiveTrend = trend && trend.value > 0;\n\tconst isNegativeTrend = trend && trend.value < 0;\n\tconst named =\n\t\tariaLabel ??\n\t\t[\n\t\t\theading,\n\t\t\tdisplay,\n\t\t\tsubtitle,\n\t\t\ttrend ? `${isPositiveTrend ? \"+\" : \"\"}${trend.value}% ${trend.label ?? \"\"}` : null,\n\t\t]\n\t\t\t.filter(Boolean)\n\t\t\t.join(\" \")\n\t\t\t.trim();\n\treturn (\n\t\t<div\n\t\t\tclassName={cn(\n\t\t\t\t\"rounded-basalt-md border border-basalt-border bg-basalt-secondary p-4\",\n\t\t\t\tclassName,\n\t\t\t)}\n\t\t\trole=\"img\"\n\t\t\taria-label={named}\n\t\t>\n\t\t\t<div className=\"flex items-start justify-between\">\n\t\t\t\t<div className=\"space-y-1\">\n\t\t\t\t\t<p className=\"text-xs text-basalt-muted-foreground md:text-sm\">{heading}</p>\n\t\t\t\t\t<p className=\"font-display text-xl font-semibold tracking-tight text-basalt-foreground md:text-2xl\">\n\t\t\t\t\t\t{display}\n\t\t\t\t\t</p>\n\t\t\t\t\t{subtitle ? <p className=\"text-xs text-basalt-muted-foreground\">{subtitle}</p> : null}\n\t\t\t\t</div>\n\t\t\t\t{Icon ? (\n\t\t\t\t\t<div className={cn(\"rounded-md bg-basalt-card p-2\", iconColor)}>\n\t\t\t\t\t\t<Icon className=\"h-5 w-5\" strokeWidth={1.5} />\n\t\t\t\t\t</div>\n\t\t\t\t) : null}\n\t\t\t</div>\n\t\t\t{trend ? (\n\t\t\t\t<div className=\"mt-3 flex items-center gap-1 text-xs\">\n\t\t\t\t\t<span\n\t\t\t\t\t\tclassName={cn(\n\t\t\t\t\t\t\t\"font-medium\",\n\t\t\t\t\t\t\tisPositiveTrend && \"text-basalt-heatmap-green-4\",\n\t\t\t\t\t\t\tisNegativeTrend && \"text-basalt-destructive\",\n\t\t\t\t\t\t\t!isPositiveTrend && !isNegativeTrend && \"text-basalt-muted-foreground\",\n\t\t\t\t\t\t)}\n\t\t\t\t\t>\n\t\t\t\t\t\t{`${isPositiveTrend ? \"+\" : \"\"}${trend.value}%`}\n\t\t\t\t\t</span>\n\t\t\t\t\t{trend.label ? <span className=\"text-basalt-muted-foreground\">{trend.label}</span> : null}\n\t\t\t\t</div>\n\t\t\t) : null}\n\t\t</div>\n\t);\n}\n\nexport type StatGridProps = {\n\tchildren: ReactNode;\n\tcolumns?: 2 | 3 | 4;\n\tclassName?: string;\n};\n\nexport function StatGrid({ children, columns = 4, className }: StatGridProps) {\n\tconst gridCols = {\n\t\t2: \"grid-cols-1 sm:grid-cols-2\",\n\t\t3: \"grid-cols-1 sm:grid-cols-2 lg:grid-cols-3\",\n\t\t4: \"grid-cols-1 sm:grid-cols-2 lg:grid-cols-4\",\n\t};\n\treturn <div className={cn(\"grid gap-3 md:gap-4\", gridCols[columns], className)}>{children}</div>;\n}\n"],"mappings":";;;;AAgBA,SAAgB,EAAS,EACxB,UACA,UACA,UACA,aACA,MAAM,GACN,eAAY,gCACZ,UACA,cACA,gBACiB;CACjB,IAAM,IAAU,KAAS,GACnB,IAAU,OAAO,KAAU,WAAW,EAAM,eAAe,IAAI,GAC/D,IAAkB,KAAS,EAAM,QAAQ,GACzC,IAAkB,KAAS,EAAM,QAAQ,GACzC,IACL,KACA;EACC;EACA;EACA;EACA,IAAQ,GAAG,IAAkB,MAAM,KAAK,EAAM,MAAM,IAAI,EAAM,SAAS,OAAO;CAC/E,CAAC,CACC,OAAO,OAAO,CAAC,CACf,KAAK,GAAG,CAAC,CACT,KAAK;CACR,OACC,kBAAC,OAAD;EACC,WAAW,EACV,yEACA,CACD;EACA,MAAK;EACL,cAAY;EANb,UAAA,CAQC,kBAAC,OAAD;GAAK,WAAU;GAAf,UAAA,CACC,kBAAC,OAAD;IAAK,WAAU;IAAf,UAAA;KACC,kBAAC,KAAD;MAAG,WAAU;MAAmD,UAAA;KAAW,CAAA;KAC3E,kBAAC,KAAD;MAAG,WAAU;MACX,UAAA;KACC,CAAA;KACF,IAAW,kBAAC,KAAD;MAAG,WAAU;MAAwC,UAAA;KAAY,CAAA,IAAI;IAC7E;GACJ,CAAA,GAAA,IACA,kBAAC,OAAD;IAAK,WAAW,EAAG,iCAAiC,CAAS;IAC5D,UAAA,kBAAC,GAAD;KAAM,WAAU;KAAU,aAAa;IAAM,CAAA;GACzC,CAAA,IACF,IACA;EACJ,CAAA,GAAA,IACA,kBAAC,OAAD;GAAK,WAAU;GAAf,UAAA,CACC,kBAAC,QAAD;IACC,WAAW,EACV,eACA,KAAmB,+BACnB,KAAmB,2BACnB,CAAC,KAAmB,CAAC,KAAmB,8BACzC;IAEC,UAAA,GAAG,IAAkB,MAAM,KAAK,EAAM,MAAM;GACxC,CAAA,GACL,EAAM,QAAQ,kBAAC,QAAD;IAAM,WAAU;IAAgC,UAAA,EAAM;GAAY,CAAA,IAAI,IACjF;EACF,CAAA,IAAA,IACA;;AAEP;AAQA,SAAgB,EAAS,EAAE,aAAU,aAAU,GAAG,gBAA4B;CAM7E,OAAO,kBAAC,OAAD;EAAK,WAAW,EAAG,uBAAuB;GAJhD,GAAG;GACH,GAAG;GACH,GAAG;EAE6C,EAAS,IAAU,CAAS;EAAI;CAAc,CAAA;AAChG"}
1
+ {"version":3,"file":"stat-card.js","names":[],"sources":["../../src/charts/stat-card.tsx"],"sourcesContent":["import type { LucideIcon } from \"lucide-react\";\nimport type { ReactNode } from \"react\";\nimport { cn } from \"../utils/cn\";\n\nexport type StatCardProps = {\n\t/**\n\t * Secondary heading label for the metric card (overridden by title).\n\t */\n\tlabel?: string;\n\t/**\n\t * Primary heading title for the metric card (takes precedence over label).\n\t */\n\ttitle?: string;\n\t/**\n\t * Metric value, formatted via toLocaleString() if a number is provided.\n\t * Overridden by the status slot if provided.\n\t */\n\tvalue: string | number;\n\t/**\n\t * Supporting descriptive subtitle text rendered below value.\n\t */\n\tsubtitle?: string;\n\t/**\n\t * Optional decorative Lucide icon component.\n\t */\n\ticon?: LucideIcon;\n\t/**\n\t * Color class applied to the icon wrapper.\n\t * @default \"text-basalt-muted-foreground\"\n\t */\n\ticonColor?: string;\n\t/**\n\t * Structured percentage trend value and optional label.\n\t * Overridden by the trendContent slot if provided.\n\t */\n\ttrend?: { value: number; label?: string };\n\t/**\n\t * Optional header action or interactive element (e.g. tooltip trigger or button).\n\t * Renders alongside the title/icon. Switches card role to group for accessible descendants.\n\t */\n\taction?: ReactNode;\n\t/**\n\t * Optional custom status replacement slot (e.g. loading skeleton, error state, or empty state).\n\t * Takes precedence over the default value display and excludes value from accessible name.\n\t * Subtitle and trend remain caller-managed; when error/empty state is shown, callers should omit trend.\n\t */\n\tstatus?: ReactNode;\n\t/**\n\t * Optional custom trend replacement slot (e.g. custom badge, sparkline, or localized trend indicator).\n\t * Takes precedence over the default trend calculation and excludes default trend from accessible name.\n\t */\n\ttrendContent?: ReactNode;\n\t/**\n\t * Optional custom content rendered below the metric value and above or alongside the trend.\n\t */\n\tchildren?: ReactNode;\n\t/**\n\t * Explicit accessible label overriding automatic accessible name calculation.\n\t */\n\tariaLabel?: string;\n\t/**\n\t * Additional CSS class names for styling the card root.\n\t */\n\tclassName?: string;\n};\n\nfunction hasSlotContent(slot: ReactNode | undefined): boolean {\n\treturn slot !== undefined && slot !== null && slot !== false;\n}\n\nexport function StatCard({\n\tlabel,\n\ttitle,\n\tvalue,\n\tsubtitle,\n\ticon: Icon,\n\ticonColor = \"text-basalt-muted-foreground\",\n\ttrend,\n\taction,\n\tstatus,\n\ttrendContent,\n\tchildren,\n\tariaLabel,\n\tclassName,\n}: StatCardProps) {\n\tconst heading = title ?? label;\n\tconst hasStatus = hasSlotContent(status);\n\tconst hasTrendContent = hasSlotContent(trendContent);\n\tconst hasAction = hasSlotContent(action);\n\tconst hasChildren = hasSlotContent(children);\n\tconst isInteractive = hasAction || hasStatus || hasTrendContent || hasChildren;\n\tconst hasHeaderEnd = hasAction || Boolean(Icon);\n\n\tconst display = typeof value === \"number\" ? value.toLocaleString() : value;\n\tconst isPositiveTrend = trend && trend.value > 0;\n\tconst isNegativeTrend = trend && trend.value < 0;\n\n\t// Accessible name: If custom status or custom trendContent is provided, do not report\n\t// the overridden hidden default value or default trend to assistive technology.\n\tconst named =\n\t\tariaLabel ??\n\t\t[\n\t\t\theading,\n\t\t\t!hasStatus ? display : null,\n\t\t\tsubtitle,\n\t\t\t!hasTrendContent && trend\n\t\t\t\t? `${isPositiveTrend ? \"+\" : \"\"}${trend.value}% ${trend.label ?? \"\"}`\n\t\t\t\t: null,\n\t\t]\n\t\t\t.filter(Boolean)\n\t\t\t.join(\" \")\n\t\t\t.trim();\n\n\tconst cardContent = (\n\t\t<>\n\t\t\t<div className=\"flex items-start justify-between gap-3\">\n\t\t\t\t<div className=\"min-w-0 flex-1 space-y-1\">\n\t\t\t\t\t<p className=\"text-xs text-basalt-muted-foreground md:text-sm\">{heading}</p>\n\t\t\t\t\t{hasStatus ? (\n\t\t\t\t\t\t<div className=\"pt-0.5\">{status}</div>\n\t\t\t\t\t) : (\n\t\t\t\t\t\t<p className=\"font-display text-xl font-semibold tracking-tight text-basalt-foreground md:text-2xl\">\n\t\t\t\t\t\t\t{display}\n\t\t\t\t\t\t</p>\n\t\t\t\t\t)}\n\t\t\t\t\t{subtitle ? <p className=\"text-xs text-basalt-muted-foreground\">{subtitle}</p> : null}\n\t\t\t\t</div>\n\t\t\t\t{hasHeaderEnd ? (\n\t\t\t\t\t<div className=\"flex items-center gap-2 shrink-0\">\n\t\t\t\t\t\t{hasAction ? <div className=\"flex items-center\">{action}</div> : null}\n\t\t\t\t\t\t{Icon ? (\n\t\t\t\t\t\t\t<div className={cn(\"rounded-md bg-basalt-card p-2\", iconColor)}>\n\t\t\t\t\t\t\t\t<Icon className=\"h-5 w-5\" strokeWidth={1.5} />\n\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t) : null}\n\t\t\t\t\t</div>\n\t\t\t\t) : null}\n\t\t\t</div>\n\n\t\t\t{hasChildren ? <div className=\"mt-2\">{children}</div> : null}\n\n\t\t\t{hasTrendContent ? (\n\t\t\t\t<div className=\"mt-3 flex items-center gap-1 text-xs\">{trendContent}</div>\n\t\t\t) : trend ? (\n\t\t\t\t<div className=\"mt-3 flex items-center gap-1 text-xs\">\n\t\t\t\t\t<span\n\t\t\t\t\t\tclassName={cn(\n\t\t\t\t\t\t\t\"font-medium\",\n\t\t\t\t\t\t\tisPositiveTrend && \"text-basalt-heatmap-green-4\",\n\t\t\t\t\t\t\tisNegativeTrend && \"text-basalt-destructive\",\n\t\t\t\t\t\t\t!isPositiveTrend && !isNegativeTrend && \"text-basalt-muted-foreground\",\n\t\t\t\t\t\t)}\n\t\t\t\t\t>\n\t\t\t\t\t\t{`${isPositiveTrend ? \"+\" : \"\"}${trend.value}%`}\n\t\t\t\t\t</span>\n\t\t\t\t\t{trend.label ? <span className=\"text-basalt-muted-foreground\">{trend.label}</span> : null}\n\t\t\t\t</div>\n\t\t\t) : null}\n\t\t</>\n\t);\n\n\tif (isInteractive) {\n\t\treturn (\n\t\t\t<div\n\t\t\t\tclassName={cn(\n\t\t\t\t\t\"rounded-basalt-md border border-basalt-border bg-basalt-secondary p-4\",\n\t\t\t\t\tclassName,\n\t\t\t\t)}\n\t\t\t\trole=\"group\"\n\t\t\t\taria-label={named}\n\t\t\t>\n\t\t\t\t{cardContent}\n\t\t\t</div>\n\t\t);\n\t}\n\n\treturn (\n\t\t<div\n\t\t\tclassName={cn(\n\t\t\t\t\"rounded-basalt-md border border-basalt-border bg-basalt-secondary p-4\",\n\t\t\t\tclassName,\n\t\t\t)}\n\t\t\trole=\"img\"\n\t\t\taria-label={named}\n\t\t>\n\t\t\t{cardContent}\n\t\t</div>\n\t);\n}\n\nexport type StatGridProps = {\n\tchildren: ReactNode;\n\tcolumns?: 2 | 3 | 4;\n\tclassName?: string;\n};\n\nexport function StatGrid({ children, columns = 4, className }: StatGridProps) {\n\tconst gridCols = {\n\t\t2: \"grid-cols-1 sm:grid-cols-2\",\n\t\t3: \"grid-cols-1 sm:grid-cols-2 lg:grid-cols-3\",\n\t\t4: \"grid-cols-1 sm:grid-cols-2 lg:grid-cols-4\",\n\t};\n\treturn <div className={cn(\"grid gap-3 md:gap-4\", gridCols[columns], className)}>{children}</div>;\n}\n"],"mappings":";;;;AAkEA,SAAS,EAAe,GAAsC;CAC7D,OAAO,KAA+B,QAAQ,MAAS;AACxD;AAEA,SAAgB,EAAS,EACxB,UACA,UACA,UACA,aACA,MAAM,GACN,eAAY,gCACZ,UACA,WACA,WACA,iBACA,aACA,cACA,gBACiB;CACjB,IAAM,IAAU,KAAS,GACnB,IAAY,EAAe,CAAM,GACjC,IAAkB,EAAe,CAAY,GAC7C,IAAY,EAAe,CAAM,GACjC,IAAc,EAAe,CAAQ,GACrC,IAAgB,KAAa,KAAa,KAAmB,GAC7D,IAAe,KAAa,EAAQ,GAEpC,IAAU,OAAO,KAAU,WAAW,EAAM,eAAe,IAAI,GAC/D,IAAkB,KAAS,EAAM,QAAQ,GACzC,IAAkB,KAAS,EAAM,QAAQ,GAIzC,IACL,KACA;EACC;EACC,IAAsB,OAAV;EACb;EACA,CAAC,KAAmB,IACjB,GAAG,IAAkB,MAAM,KAAK,EAAM,MAAM,IAAI,EAAM,SAAS,OAC/D;CACJ,CAAC,CACC,OAAO,OAAO,CAAC,CACf,KAAK,GAAG,CAAC,CACT,KAAK,GAEF,IACL,kBAAA,GAAA,EAAA,UAAA;EACC,kBAAC,OAAD;GAAK,WAAU;GAAf,UAAA,CACC,kBAAC,OAAD;IAAK,WAAU;IAAf,UAAA;KACC,kBAAC,KAAD;MAAG,WAAU;MAAmD,UAAA;KAAW,CAAA;KAC1E,IACA,kBAAC,OAAD;MAAK,WAAU;MAAU,UAAA;KAAY,CAAA,IAErC,kBAAC,KAAD;MAAG,WAAU;MACX,UAAA;KACC,CAAA;KAEH,IAAW,kBAAC,KAAD;MAAG,WAAU;MAAwC,UAAA;KAAY,CAAA,IAAI;IAC7E;GACJ,CAAA,GAAA,IACA,kBAAC,OAAD;IAAK,WAAU;IAAf,UAAA,CACE,IAAY,kBAAC,OAAD;KAAK,WAAU;KAAqB,UAAA;IAAY,CAAA,IAAI,MAChE,IACA,kBAAC,OAAD;KAAK,WAAW,EAAG,iCAAiC,CAAS;KAC5D,UAAA,kBAAC,GAAD;MAAM,WAAU;MAAU,aAAa;KAAM,CAAA;IACzC,CAAA,IACF,IACA;GACF,CAAA,IAAA,IACA;;EAEJ,IAAc,kBAAC,OAAD;GAAK,WAAU;GAAQ;EAAc,CAAA,IAAI;EAEvD,IACA,kBAAC,OAAD;GAAK,WAAU;GAAwC,UAAA;EAAkB,CAAA,IACtE,IACH,kBAAC,OAAD;GAAK,WAAU;GAAf,UAAA,CACC,kBAAC,QAAD;IACC,WAAW,EACV,eACA,KAAmB,+BACnB,KAAmB,2BACnB,CAAC,KAAmB,CAAC,KAAmB,8BACzC;IAEC,UAAA,GAAG,IAAkB,MAAM,KAAK,EAAM,MAAM;GACxC,CAAA,GACL,EAAM,QAAQ,kBAAC,QAAD;IAAM,WAAU;IAAgC,UAAA,EAAM;GAAY,CAAA,IAAI,IACjF;EACF,CAAA,IAAA;CACH,EAAA,CAAA;CAkBH,OAfI,IAEF,kBAAC,OAAD;EACC,WAAW,EACV,yEACA,CACD;EACA,MAAK;EACL,cAAY;EAEX,UAAA;CACG,CAAA,IAKN,kBAAC,OAAD;EACC,WAAW,EACV,yEACA,CACD;EACA,MAAK;EACL,cAAY;EAEX,UAAA;CACG,CAAA;AAEP;AAQA,SAAgB,EAAS,EAAE,aAAU,aAAU,GAAG,gBAA4B;CAM7E,OAAO,kBAAC,OAAD;EAAK,WAAW,EAAG,uBAAuB;GAJhD,GAAG;GACH,GAAG;GACH,GAAG;EAE6C,EAAS,IAAU,CAAS;EAAI;CAAc,CAAA;AAChG"}
@@ -3,7 +3,10 @@ export type TimelineEvent = {
3
3
  time: string;
4
4
  title: string;
5
5
  subtitle?: string;
6
+ /** Background utility classes for the event row. */
6
7
  color?: string;
8
+ /** Optional CSS text color for a custom background; subtitles inherit it without dimming. */
9
+ textColor?: string;
7
10
  };
8
11
  export type TimelineItem = {
9
12
  id?: string;
@@ -36,16 +36,17 @@ function o({ events: a, ariaLabel: o, className: s }) {
36
36
  children: r.map((r) => {
37
37
  let i = c.get(r) ?? [], a = i.length > 0;
38
38
  return /* @__PURE__ */ n("li", {
39
- className: e("relative flex items-start border-l-2 py-2 pl-4", a ? "border-basalt-primary" : "border-basalt-border"),
39
+ className: e("relative flex items-start border-l-2 py-2 pl-4", a ? "border-basalt-chart-1" : "border-basalt-border"),
40
40
  children: [
41
41
  /* @__PURE__ */ n("div", {
42
42
  className: "absolute left-0 w-12 -translate-x-full pr-2 text-right text-xs text-basalt-muted-foreground",
43
43
  children: [r.toString().padStart(2, "0"), ":00"]
44
44
  }),
45
- /* @__PURE__ */ t("div", { className: e("absolute -left-[5px] top-2 h-2 w-2 rounded-full", a ? "bg-basalt-primary" : "bg-basalt-border") }),
45
+ /* @__PURE__ */ t("div", { className: e("absolute -left-[5px] top-2 h-2 w-2 rounded-full", a ? "bg-basalt-chart-1" : "bg-basalt-border") }),
46
46
  /* @__PURE__ */ t("div", {
47
47
  className: "flex min-h-[24px] w-full flex-col gap-1",
48
48
  children: i.map((r) => /* @__PURE__ */ n("div", {
49
+ style: r.textColor ? { color: r.textColor } : void 0,
49
50
  className: e("flex items-center gap-2 rounded-md px-2 py-1 text-xs", r.color ? `${r.color} text-white` : "bg-basalt-muted text-basalt-foreground"),
50
51
  children: [
51
52
  /* @__PURE__ */ t("span", {
@@ -57,7 +58,7 @@ function o({ events: a, ariaLabel: o, className: s }) {
57
58
  children: r.title
58
59
  }),
59
60
  r.subtitle ? /* @__PURE__ */ t("span", {
60
- className: e("truncate", r.color ? "text-white/80" : "text-basalt-muted-foreground"),
61
+ className: e("truncate", r.textColor ? "text-current" : r.color ? "text-white/80" : "text-basalt-muted-foreground"),
61
62
  children: r.subtitle
62
63
  }) : null
63
64
  ]
@@ -1 +1 @@
1
- {"version":3,"file":"timeline.js","names":[],"sources":["../../src/charts/timeline.tsx"],"sourcesContent":["import { cn } from \"../utils/cn\";\n\nexport type TimelineEvent = {\n\tid: string;\n\ttime: string;\n\ttitle: string;\n\tsubtitle?: string;\n\tcolor?: string;\n};\n\nconst hours = Array.from({ length: 24 }, (_, index) => index);\n\nfunction getHour(time: string) {\n\treturn Number.parseInt(time.split(\":\")[0] ?? \"0\", 10);\n}\n\nexport type TimelineItem = { id?: string; title: string; at?: string };\n\nexport type TimelineItemsProps = {\n\titems: TimelineItem[];\n\tariaLabel?: string;\n\tclassName?: string;\n};\nexport type TimelineEventsProps = {\n\tevents: TimelineEvent[];\n\tariaLabel?: string;\n\tclassName?: string;\n};\nexport type TimelineProps = TimelineItemsProps | TimelineEventsProps;\n\nexport function Timeline(props: TimelineProps) {\n\tconst { ariaLabel = \"Timeline\", className } = props;\n\tif (\"events\" in props) {\n\t\treturn <HourTimeline events={props.events} ariaLabel={ariaLabel} className={className} />;\n\t}\n\treturn (\n\t\t<ol className={cn(\"space-y-2 text-sm\", className)} aria-label={ariaLabel}>\n\t\t\t{props.items.map((item, index) => (\n\t\t\t\t<li key={item.id ?? `${item.at ?? \"\"}-${item.title}-${index}`} className=\"flex gap-2\">\n\t\t\t\t\t<span className=\"text-basalt-muted-foreground\">{item.at}</span>\n\t\t\t\t\t<span>{item.title}</span>\n\t\t\t\t</li>\n\t\t\t))}\n\t\t</ol>\n\t);\n}\n\nfunction HourTimeline({\n\tevents,\n\tariaLabel,\n\tclassName,\n}: {\n\tevents: TimelineEvent[];\n\tariaLabel: string;\n\tclassName?: string;\n}) {\n\tconst eventsByHour = new Map<number, TimelineEvent[]>();\n\tfor (const event of events) {\n\t\tconst hour = getHour(event.time);\n\t\tconst existing = eventsByHour.get(hour) ?? [];\n\t\teventsByHour.set(hour, [...existing, event]);\n\t}\n\treturn (\n\t\t<ol className={cn(\"flex flex-col pl-14\", className)} aria-label={ariaLabel}>\n\t\t\t{hours.map((hour) => {\n\t\t\t\tconst hourEvents = eventsByHour.get(hour) ?? [];\n\t\t\t\tconst hasEvents = hourEvents.length > 0;\n\t\t\t\treturn (\n\t\t\t\t\t<li\n\t\t\t\t\t\tkey={hour}\n\t\t\t\t\t\tclassName={cn(\n\t\t\t\t\t\t\t\"relative flex items-start border-l-2 py-2 pl-4\",\n\t\t\t\t\t\t\thasEvents ? \"border-basalt-primary\" : \"border-basalt-border\",\n\t\t\t\t\t\t)}\n\t\t\t\t\t>\n\t\t\t\t\t\t<div className=\"absolute left-0 w-12 -translate-x-full pr-2 text-right text-xs text-basalt-muted-foreground\">\n\t\t\t\t\t\t\t{hour.toString().padStart(2, \"0\")}:00\n\t\t\t\t\t\t</div>\n\t\t\t\t\t\t<div\n\t\t\t\t\t\t\tclassName={cn(\n\t\t\t\t\t\t\t\t\"absolute -left-[5px] top-2 h-2 w-2 rounded-full\",\n\t\t\t\t\t\t\t\thasEvents ? \"bg-basalt-primary\" : \"bg-basalt-border\",\n\t\t\t\t\t\t\t)}\n\t\t\t\t\t\t/>\n\t\t\t\t\t\t<div className=\"flex min-h-[24px] w-full flex-col gap-1\">\n\t\t\t\t\t\t\t{hourEvents.map((event) => (\n\t\t\t\t\t\t\t\t<div\n\t\t\t\t\t\t\t\t\tkey={event.id}\n\t\t\t\t\t\t\t\t\tclassName={cn(\n\t\t\t\t\t\t\t\t\t\t\"flex items-center gap-2 rounded-md px-2 py-1 text-xs\",\n\t\t\t\t\t\t\t\t\t\tevent.color\n\t\t\t\t\t\t\t\t\t\t\t? `${event.color} text-white`\n\t\t\t\t\t\t\t\t\t\t\t: \"bg-basalt-muted text-basalt-foreground\",\n\t\t\t\t\t\t\t\t\t)}\n\t\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t\t<span className=\"font-medium\">{event.time}</span>\n\t\t\t\t\t\t\t\t\t<span className=\"truncate\">{event.title}</span>\n\t\t\t\t\t\t\t\t\t{event.subtitle ? (\n\t\t\t\t\t\t\t\t\t\t<span\n\t\t\t\t\t\t\t\t\t\t\tclassName={cn(\n\t\t\t\t\t\t\t\t\t\t\t\t\"truncate\",\n\t\t\t\t\t\t\t\t\t\t\t\tevent.color ? \"text-white/80\" : \"text-basalt-muted-foreground\",\n\t\t\t\t\t\t\t\t\t\t\t)}\n\t\t\t\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t\t\t\t{event.subtitle}\n\t\t\t\t\t\t\t\t\t\t</span>\n\t\t\t\t\t\t\t\t\t) : null}\n\t\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t\t))}\n\t\t\t\t\t\t</div>\n\t\t\t\t\t</li>\n\t\t\t\t);\n\t\t\t})}\n\t\t</ol>\n\t);\n}\n"],"mappings":";;;;AAUA,IAAM,IAAQ,MAAM,KAAK,EAAE,QAAQ,GAAG,IAAI,GAAG,MAAU,CAAK;AAE5D,SAAS,EAAQ,GAAc;CAC9B,OAAO,OAAO,SAAS,EAAK,MAAM,GAAG,CAAC,CAAC,MAAM,KAAK,EAAE;AACrD;AAgBA,SAAgB,EAAS,GAAsB;CAC9C,IAAM,EAAE,eAAY,YAAY,iBAAc;CAI9C,OAHI,YAAY,IACR,kBAAC,GAAD;EAAc,QAAQ,EAAM;EAAmB;EAAsB;CAAY,CAAA,IAGxF,kBAAC,MAAD;EAAI,WAAW,EAAG,qBAAqB,CAAS;EAAG,cAAY;EAC7D,UAAA,EAAM,MAAM,KAAK,GAAM,MACvB,kBAAC,MAAD;GAA+D,WAAU;GAAzE,UAAA,CACC,kBAAC,QAAD;IAAM,WAAU;IAAgC,UAAA,EAAK;GAAS,CAAA,GAC9D,kBAAC,QAAD,EAAA,UAAO,EAAK,MAAY,CAAA,CACrB;EAHK,GAAA,EAAK,MAAM,GAAG,EAAK,MAAM,GAAG,GAAG,EAAK,MAAM,GAAG,GAGlD,CACJ;CACE,CAAA;AAEN;AAEA,SAAS,EAAa,EACrB,WACA,cACA,gBAKE;CACF,IAAM,oBAAe,IAAI,IAA6B;CACtD,KAAK,IAAM,KAAS,GAAQ;EAC3B,IAAM,IAAO,EAAQ,EAAM,IAAI,GACzB,IAAW,EAAa,IAAI,CAAI,KAAK,CAAC;EAC5C,EAAa,IAAI,GAAM,CAAC,GAAG,GAAU,CAAK,CAAC;CAC5C;CACA,OACC,kBAAC,MAAD;EAAI,WAAW,EAAG,uBAAuB,CAAS;EAAG,cAAY;EAC/D,UAAA,EAAM,KAAK,MAAS;GACpB,IAAM,IAAa,EAAa,IAAI,CAAI,KAAK,CAAC,GACxC,IAAY,EAAW,SAAS;GACtC,OACC,kBAAC,MAAD;IAEC,WAAW,EACV,kDACA,IAAY,0BAA0B,sBACvC;IALD,UAAA;KAOC,kBAAC,OAAD;MAAK,WAAU;MAAf,UAAA,CACE,EAAK,SAAS,CAAC,CAAC,SAAS,GAAG,GAAG,GAAE,KAC9B;;KACL,kBAAC,OAAD,EACC,WAAW,EACV,mDACA,IAAY,sBAAsB,kBACnC,EACA,CAAA;KACD,kBAAC,OAAD;MAAK,WAAU;MACb,UAAA,EAAW,KAAK,MAChB,kBAAC,OAAD;OAEC,WAAW,EACV,wDACA,EAAM,QACH,GAAG,EAAM,MAAM,eACf,wCACJ;OAPD,UAAA;QASC,kBAAC,QAAD;SAAM,WAAU;SAAe,UAAA,EAAM;QAAW,CAAA;QAChD,kBAAC,QAAD;SAAM,WAAU;SAAY,UAAA,EAAM;QAAY,CAAA;QAC7C,EAAM,WACN,kBAAC,QAAD;SACC,WAAW,EACV,YACA,EAAM,QAAQ,kBAAkB,8BACjC;SAEC,UAAA,EAAM;QACF,CAAA,IACH;OACA;MApBC,GAAA,EAAM,EAoBP,CACL;KACG,CAAA;IACF;GAzCE,GAAA,CAyCF;EAEN,CAAC;CACE,CAAA;AAEN"}
1
+ {"version":3,"file":"timeline.js","names":[],"sources":["../../src/charts/timeline.tsx"],"sourcesContent":["import { cn } from \"../utils/cn\";\n\nexport type TimelineEvent = {\n\tid: string;\n\ttime: string;\n\ttitle: string;\n\tsubtitle?: string;\n\t/** Background utility classes for the event row. */\n\tcolor?: string;\n\t/** Optional CSS text color for a custom background; subtitles inherit it without dimming. */\n\ttextColor?: string;\n};\n\nconst hours = Array.from({ length: 24 }, (_, index) => index);\n\nfunction getHour(time: string) {\n\treturn Number.parseInt(time.split(\":\")[0] ?? \"0\", 10);\n}\n\nexport type TimelineItem = { id?: string; title: string; at?: string };\n\nexport type TimelineItemsProps = {\n\titems: TimelineItem[];\n\tariaLabel?: string;\n\tclassName?: string;\n};\nexport type TimelineEventsProps = {\n\tevents: TimelineEvent[];\n\tariaLabel?: string;\n\tclassName?: string;\n};\nexport type TimelineProps = TimelineItemsProps | TimelineEventsProps;\n\nexport function Timeline(props: TimelineProps) {\n\tconst { ariaLabel = \"Timeline\", className } = props;\n\tif (\"events\" in props) {\n\t\treturn <HourTimeline events={props.events} ariaLabel={ariaLabel} className={className} />;\n\t}\n\treturn (\n\t\t<ol className={cn(\"space-y-2 text-sm\", className)} aria-label={ariaLabel}>\n\t\t\t{props.items.map((item, index) => (\n\t\t\t\t<li key={item.id ?? `${item.at ?? \"\"}-${item.title}-${index}`} className=\"flex gap-2\">\n\t\t\t\t\t<span className=\"text-basalt-muted-foreground\">{item.at}</span>\n\t\t\t\t\t<span>{item.title}</span>\n\t\t\t\t</li>\n\t\t\t))}\n\t\t</ol>\n\t);\n}\n\nfunction HourTimeline({\n\tevents,\n\tariaLabel,\n\tclassName,\n}: {\n\tevents: TimelineEvent[];\n\tariaLabel: string;\n\tclassName?: string;\n}) {\n\tconst eventsByHour = new Map<number, TimelineEvent[]>();\n\tfor (const event of events) {\n\t\tconst hour = getHour(event.time);\n\t\tconst existing = eventsByHour.get(hour) ?? [];\n\t\teventsByHour.set(hour, [...existing, event]);\n\t}\n\treturn (\n\t\t<ol className={cn(\"flex flex-col pl-14\", className)} aria-label={ariaLabel}>\n\t\t\t{hours.map((hour) => {\n\t\t\t\tconst hourEvents = eventsByHour.get(hour) ?? [];\n\t\t\t\tconst hasEvents = hourEvents.length > 0;\n\t\t\t\treturn (\n\t\t\t\t\t<li\n\t\t\t\t\t\tkey={hour}\n\t\t\t\t\t\tclassName={cn(\n\t\t\t\t\t\t\t\"relative flex items-start border-l-2 py-2 pl-4\",\n\t\t\t\t\t\t\thasEvents ? \"border-basalt-chart-1\" : \"border-basalt-border\",\n\t\t\t\t\t\t)}\n\t\t\t\t\t>\n\t\t\t\t\t\t<div className=\"absolute left-0 w-12 -translate-x-full pr-2 text-right text-xs text-basalt-muted-foreground\">\n\t\t\t\t\t\t\t{hour.toString().padStart(2, \"0\")}:00\n\t\t\t\t\t\t</div>\n\t\t\t\t\t\t<div\n\t\t\t\t\t\t\tclassName={cn(\n\t\t\t\t\t\t\t\t\"absolute -left-[5px] top-2 h-2 w-2 rounded-full\",\n\t\t\t\t\t\t\t\thasEvents ? \"bg-basalt-chart-1\" : \"bg-basalt-border\",\n\t\t\t\t\t\t\t)}\n\t\t\t\t\t\t/>\n\t\t\t\t\t\t<div className=\"flex min-h-[24px] w-full flex-col gap-1\">\n\t\t\t\t\t\t\t{hourEvents.map((event) => (\n\t\t\t\t\t\t\t\t<div\n\t\t\t\t\t\t\t\t\tkey={event.id}\n\t\t\t\t\t\t\t\t\tstyle={event.textColor ? { color: event.textColor } : undefined}\n\t\t\t\t\t\t\t\t\tclassName={cn(\n\t\t\t\t\t\t\t\t\t\t\"flex items-center gap-2 rounded-md px-2 py-1 text-xs\",\n\t\t\t\t\t\t\t\t\t\tevent.color\n\t\t\t\t\t\t\t\t\t\t\t? `${event.color} text-white`\n\t\t\t\t\t\t\t\t\t\t\t: \"bg-basalt-muted text-basalt-foreground\",\n\t\t\t\t\t\t\t\t\t)}\n\t\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t\t<span className=\"font-medium\">{event.time}</span>\n\t\t\t\t\t\t\t\t\t<span className=\"truncate\">{event.title}</span>\n\t\t\t\t\t\t\t\t\t{event.subtitle ? (\n\t\t\t\t\t\t\t\t\t\t<span\n\t\t\t\t\t\t\t\t\t\t\tclassName={cn(\n\t\t\t\t\t\t\t\t\t\t\t\t\"truncate\",\n\t\t\t\t\t\t\t\t\t\t\t\tevent.textColor\n\t\t\t\t\t\t\t\t\t\t\t\t\t? \"text-current\"\n\t\t\t\t\t\t\t\t\t\t\t\t\t: event.color\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t? \"text-white/80\"\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t: \"text-basalt-muted-foreground\",\n\t\t\t\t\t\t\t\t\t\t\t)}\n\t\t\t\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t\t\t\t{event.subtitle}\n\t\t\t\t\t\t\t\t\t\t</span>\n\t\t\t\t\t\t\t\t\t) : null}\n\t\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t\t))}\n\t\t\t\t\t\t</div>\n\t\t\t\t\t</li>\n\t\t\t\t);\n\t\t\t})}\n\t\t</ol>\n\t);\n}\n"],"mappings":";;;;AAaA,IAAM,IAAQ,MAAM,KAAK,EAAE,QAAQ,GAAG,IAAI,GAAG,MAAU,CAAK;AAE5D,SAAS,EAAQ,GAAc;CAC9B,OAAO,OAAO,SAAS,EAAK,MAAM,GAAG,CAAC,CAAC,MAAM,KAAK,EAAE;AACrD;AAgBA,SAAgB,EAAS,GAAsB;CAC9C,IAAM,EAAE,eAAY,YAAY,iBAAc;CAI9C,OAHI,YAAY,IACR,kBAAC,GAAD;EAAc,QAAQ,EAAM;EAAmB;EAAsB;CAAY,CAAA,IAGxF,kBAAC,MAAD;EAAI,WAAW,EAAG,qBAAqB,CAAS;EAAG,cAAY;EAC7D,UAAA,EAAM,MAAM,KAAK,GAAM,MACvB,kBAAC,MAAD;GAA+D,WAAU;GAAzE,UAAA,CACC,kBAAC,QAAD;IAAM,WAAU;IAAgC,UAAA,EAAK;GAAS,CAAA,GAC9D,kBAAC,QAAD,EAAA,UAAO,EAAK,MAAY,CAAA,CACrB;EAHK,GAAA,EAAK,MAAM,GAAG,EAAK,MAAM,GAAG,GAAG,EAAK,MAAM,GAAG,GAGlD,CACJ;CACE,CAAA;AAEN;AAEA,SAAS,EAAa,EACrB,WACA,cACA,gBAKE;CACF,IAAM,oBAAe,IAAI,IAA6B;CACtD,KAAK,IAAM,KAAS,GAAQ;EAC3B,IAAM,IAAO,EAAQ,EAAM,IAAI,GACzB,IAAW,EAAa,IAAI,CAAI,KAAK,CAAC;EAC5C,EAAa,IAAI,GAAM,CAAC,GAAG,GAAU,CAAK,CAAC;CAC5C;CACA,OACC,kBAAC,MAAD;EAAI,WAAW,EAAG,uBAAuB,CAAS;EAAG,cAAY;EAC/D,UAAA,EAAM,KAAK,MAAS;GACpB,IAAM,IAAa,EAAa,IAAI,CAAI,KAAK,CAAC,GACxC,IAAY,EAAW,SAAS;GACtC,OACC,kBAAC,MAAD;IAEC,WAAW,EACV,kDACA,IAAY,0BAA0B,sBACvC;IALD,UAAA;KAOC,kBAAC,OAAD;MAAK,WAAU;MAAf,UAAA,CACE,EAAK,SAAS,CAAC,CAAC,SAAS,GAAG,GAAG,GAAE,KAC9B;;KACL,kBAAC,OAAD,EACC,WAAW,EACV,mDACA,IAAY,sBAAsB,kBACnC,EACA,CAAA;KACD,kBAAC,OAAD;MAAK,WAAU;MACb,UAAA,EAAW,KAAK,MAChB,kBAAC,OAAD;OAEC,OAAO,EAAM,YAAY,EAAE,OAAO,EAAM,UAAU,IAAI,KAAA;OACtD,WAAW,EACV,wDACA,EAAM,QACH,GAAG,EAAM,MAAM,eACf,wCACJ;OARD,UAAA;QAUC,kBAAC,QAAD;SAAM,WAAU;SAAe,UAAA,EAAM;QAAW,CAAA;QAChD,kBAAC,QAAD;SAAM,WAAU;SAAY,UAAA,EAAM;QAAY,CAAA;QAC7C,EAAM,WACN,kBAAC,QAAD;SACC,WAAW,EACV,YACA,EAAM,YACH,iBACA,EAAM,QACL,kBACA,8BACL;SAEC,UAAA,EAAM;QACF,CAAA,IACH;OACA;MAzBC,GAAA,EAAM,EAyBP,CACL;KACG,CAAA;IACF;GA9CE,GAAA,CA8CF;EAEN,CAAC;CACE,CAAA;AAEN"}
@@ -1,8 +1,61 @@
1
- import type { XYPoint, XYSeriesDescriptor } from "./series.js";
2
- export type TimeseriesProps = {
3
- data: XYPoint[];
4
- series?: XYSeriesDescriptor[];
1
+ import type { ReactNode } from "react";
2
+ import { type LineChartAxisDomain, type LineChartLegendRenderer, type LineChartNumericKeys, type LineChartTooltipRenderer } from "./line.js";
3
+ import type { ChartSeriesDescriptor, XYPoint } from "./series.js";
4
+ export type TimeseriesProps<TData extends {
5
+ x: string | number;
6
+ } = XYPoint, K extends LineChartNumericKeys<TData> & string = LineChartNumericKeys<TData> & string> = {
7
+ /**
8
+ * Dataset array where each record requires an `x` category or time coordinate.
9
+ * Any remaining fields with numeric, nullable, or optional number values are inferred as valid series keys.
10
+ */
11
+ data: TData[];
12
+ /**
13
+ * Series descriptors identifying which numeric keys to plot.
14
+ * Inferred strictly from numeric keys of `TData` (rejects non-numeric fields, `x`, and typos).
15
+ */
16
+ series?: Array<ChartSeriesDescriptor<NoInfer<K>>>;
5
17
  ariaLabel?: string;
6
18
  className?: string;
19
+ showAxes?: boolean;
20
+ showLegend?: boolean;
21
+ color?: string;
22
+ /**
23
+ * Value formatter for Y-axis tick values and fallback tooltip values.
24
+ */
25
+ valueFormatter?: (value: number) => string;
26
+ /**
27
+ * Formatter for X-axis category or time tick labels.
28
+ */
29
+ xValueFormatter?: (value: string | number) => string;
30
+ /**
31
+ * Custom numerical or keyword bounds for the Y-axis.
32
+ */
33
+ yDomain?: LineChartAxisDomain;
34
+ /**
35
+ * Custom legend slot or render function receiving resolved series descriptors.
36
+ */
37
+ legend?: ReactNode | LineChartLegendRenderer<K>;
38
+ /**
39
+ * Custom tooltip content renderer receiving Recharts payload, active status, and coordinate label.
40
+ */
41
+ customTooltip?: LineChartTooltipRenderer;
42
+ /**
43
+ * Textual summary describing key insights, highs, lows, and keyboard exploration instructions.
44
+ * Associated with the chart via useId and aria-describedby.
45
+ */
46
+ summary?: ReactNode;
47
+ /**
48
+ * Accessible tabular or structured data alternative rendered outside the plot area.
49
+ */
50
+ dataAlternative?: ReactNode;
51
+ /**
52
+ * Whether the interactive accessibility layer is enabled on the underlying Recharts graphic.
53
+ * Enables keyboard exploration with Tab and arrow keys where supported by the underlying chart type.
54
+ * Non-interactive compact or decorative charts without tooltip navigation should provide summary or dataAlternative.
55
+ * @default true
56
+ */
57
+ accessibilityLayer?: boolean;
7
58
  };
8
- export declare function Timeseries({ data, series, ariaLabel, className }: TimeseriesProps): import("react").JSX.Element;
59
+ export declare function Timeseries<TData extends {
60
+ x: string | number;
61
+ } = XYPoint, K extends LineChartNumericKeys<TData> & string = LineChartNumericKeys<TData> & string>({ data, series, ariaLabel, className, showAxes, showLegend, color, valueFormatter, xValueFormatter, yDomain, legend, customTooltip, summary, dataAlternative, accessibilityLayer, }: TimeseriesProps<TData, K>): import("react").JSX.Element;
@@ -2,12 +2,23 @@
2
2
  import { LineChart as e } from "./line.js";
3
3
  import { jsx as t } from "react/jsx-runtime";
4
4
  //#region src/charts/timeseries.tsx
5
- function n({ data: n, series: r, ariaLabel: i = "Timeseries", className: a }) {
5
+ function n({ data: n, series: r, ariaLabel: i = "Timeseries", className: a, showAxes: o = !1, showLegend: s = !1, color: c, valueFormatter: l, xValueFormatter: u, yDomain: d, legend: f, customTooltip: p, summary: m, dataAlternative: h, accessibilityLayer: g }) {
6
6
  return /* @__PURE__ */ t(e, {
7
7
  data: n,
8
8
  series: r,
9
9
  ariaLabel: i,
10
- className: a
10
+ className: a,
11
+ showAxes: o,
12
+ showLegend: s,
13
+ color: c,
14
+ valueFormatter: l,
15
+ xValueFormatter: u,
16
+ yDomain: d,
17
+ legend: f,
18
+ customTooltip: p,
19
+ summary: m,
20
+ dataAlternative: h,
21
+ accessibilityLayer: g
11
22
  });
12
23
  }
13
24
  //#endregion
@@ -1 +1 @@
1
- {"version":3,"file":"timeseries.js","names":[],"sources":["../../src/charts/timeseries.tsx"],"sourcesContent":["import { LineChart } from \"./line\";\nimport type { XYPoint, XYSeriesDescriptor } from \"./series\";\n\nexport type TimeseriesProps = {\n\tdata: XYPoint[];\n\tseries?: XYSeriesDescriptor[];\n\tariaLabel?: string;\n\tclassName?: string;\n};\n\nexport function Timeseries({ data, series, ariaLabel = \"Timeseries\", className }: TimeseriesProps) {\n\treturn <LineChart data={data} series={series} ariaLabel={ariaLabel} className={className} />;\n}\n"],"mappings":";;;;AAUA,SAAgB,EAAW,EAAE,SAAM,WAAQ,eAAY,cAAc,gBAA8B;CAClG,OAAO,kBAAC,GAAD;EAAiB;EAAc;EAAmB;EAAsB;CAAY,CAAA;AAC5F"}
1
+ {"version":3,"file":"timeseries.js","names":[],"sources":["../../src/charts/timeseries.tsx"],"sourcesContent":["import type { ReactNode } from \"react\";\nimport {\n\tLineChart,\n\ttype LineChartAxisDomain,\n\ttype LineChartLegendRenderer,\n\ttype LineChartNumericKeys,\n\ttype LineChartTooltipRenderer,\n} from \"./line\";\nimport type { ChartSeriesDescriptor, XYPoint } from \"./series\";\n\nexport type TimeseriesProps<\n\tTData extends { x: string | number } = XYPoint,\n\tK extends LineChartNumericKeys<TData> & string = LineChartNumericKeys<TData> & string,\n> = {\n\t/**\n\t * Dataset array where each record requires an `x` category or time coordinate.\n\t * Any remaining fields with numeric, nullable, or optional number values are inferred as valid series keys.\n\t */\n\tdata: TData[];\n\t/**\n\t * Series descriptors identifying which numeric keys to plot.\n\t * Inferred strictly from numeric keys of `TData` (rejects non-numeric fields, `x`, and typos).\n\t */\n\tseries?: Array<ChartSeriesDescriptor<NoInfer<K>>>;\n\tariaLabel?: string;\n\tclassName?: string;\n\tshowAxes?: boolean;\n\tshowLegend?: boolean;\n\tcolor?: string;\n\t/**\n\t * Value formatter for Y-axis tick values and fallback tooltip values.\n\t */\n\tvalueFormatter?: (value: number) => string;\n\t/**\n\t * Formatter for X-axis category or time tick labels.\n\t */\n\txValueFormatter?: (value: string | number) => string;\n\t/**\n\t * Custom numerical or keyword bounds for the Y-axis.\n\t */\n\tyDomain?: LineChartAxisDomain;\n\t/**\n\t * Custom legend slot or render function receiving resolved series descriptors.\n\t */\n\tlegend?: ReactNode | LineChartLegendRenderer<K>;\n\t/**\n\t * Custom tooltip content renderer receiving Recharts payload, active status, and coordinate label.\n\t */\n\tcustomTooltip?: LineChartTooltipRenderer;\n\t/**\n\t * Textual summary describing key insights, highs, lows, and keyboard exploration instructions.\n\t * Associated with the chart via useId and aria-describedby.\n\t */\n\tsummary?: ReactNode;\n\t/**\n\t * Accessible tabular or structured data alternative rendered outside the plot area.\n\t */\n\tdataAlternative?: ReactNode;\n\t/**\n\t * Whether the interactive accessibility layer is enabled on the underlying Recharts graphic.\n\t * Enables keyboard exploration with Tab and arrow keys where supported by the underlying chart type.\n\t * Non-interactive compact or decorative charts without tooltip navigation should provide summary or dataAlternative.\n\t * @default true\n\t */\n\taccessibilityLayer?: boolean;\n};\n\nexport function Timeseries<\n\tTData extends { x: string | number } = XYPoint,\n\tK extends LineChartNumericKeys<TData> & string = LineChartNumericKeys<TData> & string,\n>({\n\tdata,\n\tseries,\n\tariaLabel = \"Timeseries\",\n\tclassName,\n\tshowAxes = false,\n\tshowLegend = false,\n\tcolor,\n\tvalueFormatter,\n\txValueFormatter,\n\tyDomain,\n\tlegend,\n\tcustomTooltip,\n\tsummary,\n\tdataAlternative,\n\taccessibilityLayer,\n}: TimeseriesProps<TData, K>) {\n\treturn (\n\t\t<LineChart\n\t\t\tdata={data}\n\t\t\tseries={series}\n\t\t\tariaLabel={ariaLabel}\n\t\t\tclassName={className}\n\t\t\tshowAxes={showAxes}\n\t\t\tshowLegend={showLegend}\n\t\t\tcolor={color}\n\t\t\tvalueFormatter={valueFormatter}\n\t\t\txValueFormatter={xValueFormatter}\n\t\t\tyDomain={yDomain}\n\t\t\tlegend={legend}\n\t\t\tcustomTooltip={customTooltip}\n\t\t\tsummary={summary}\n\t\t\tdataAlternative={dataAlternative}\n\t\t\taccessibilityLayer={accessibilityLayer}\n\t\t/>\n\t);\n}\n"],"mappings":";;;;AAmEA,SAAgB,EAGd,EACD,SACA,WACA,eAAY,cACZ,cACA,cAAW,IACX,gBAAa,IACb,UACA,mBACA,oBACA,YACA,WACA,kBACA,YACA,oBACA,yBAC6B;CAC7B,OACC,kBAAC,GAAD;EACO;EACE;EACG;EACA;EACD;EACE;EACL;EACS;EACC;EACR;EACD;EACO;EACN;EACQ;EACG;CACpB,CAAA;AAEH"}
@@ -1,3 +1,4 @@
1
+ import type { ComponentProps, ReactNode } from "react";
1
2
  export type ChartTooltipItem = {
2
3
  name?: string;
3
4
  value?: number | string;
@@ -12,5 +13,61 @@ export type ChartTooltipContentProps = {
12
13
  label?: string | number;
13
14
  formatter?: (value: number) => string;
14
15
  };
16
+ export interface ChartTooltipRowProps extends Omit<ComponentProps<"div">, "children"> {
17
+ /**
18
+ * Series or metric name displayed beside the color dot.
19
+ * Preserves numeric `0` and React nodes; nullish values omit the label element.
20
+ */
21
+ label?: ReactNode;
22
+ /**
23
+ * Display value of the point or metric.
24
+ * Finite numbers are automatically formatted via `formatter` or `formatChartNumber`.
25
+ * `null` or `undefined` renders placeholder "—". ReactNode values are passed through.
26
+ */
27
+ value?: ReactNode;
28
+ /**
29
+ * Dot swatch indicator color. Defaults to `--basalt-chart-1`.
30
+ */
31
+ color?: string;
32
+ /**
33
+ * Optional unit suffix (e.g., "ms", "req/s", "%") rendered adjacent to valid values.
34
+ * Omitted when `value` evaluates to placeholder "—".
35
+ */
36
+ unit?: ReactNode;
37
+ /**
38
+ * Custom numeric value formatter overriding `formatChartNumber`.
39
+ */
40
+ formatter?: (value: number) => string;
41
+ /**
42
+ * When true, suppresses rendering of the decorative color dot.
43
+ * @default false
44
+ */
45
+ hideIndicator?: boolean;
46
+ }
47
+ export interface ChartTooltipSummaryProps extends Omit<ComponentProps<"div">, "children"> {
48
+ /**
49
+ * Summary row heading label.
50
+ * Preserves numeric `0` and custom nodes.
51
+ * @default "Total"
52
+ */
53
+ label?: ReactNode;
54
+ /**
55
+ * Aggregated metric value. Finite numbers are formatted; nullish renders "—".
56
+ */
57
+ value?: ReactNode;
58
+ /**
59
+ * Optional unit suffix appended to the summary value.
60
+ */
61
+ unit?: ReactNode;
62
+ /**
63
+ * Custom numeric formatter for the summary value.
64
+ */
65
+ formatter?: (value: number) => string;
66
+ }
67
+ export interface ChartTooltipDividerProps extends Omit<ComponentProps<"hr">, "children"> {
68
+ }
15
69
  export declare function formatChartNumber(value: number): string;
70
+ export declare function ChartTooltipRow({ label, value, color, unit, formatter, hideIndicator, style, ...rest }: ChartTooltipRowProps): import("react").JSX.Element;
71
+ export declare function ChartTooltipDivider({ style, ...rest }: ChartTooltipDividerProps): import("react").JSX.Element;
72
+ export declare function ChartTooltipSummary({ label, value, unit, formatter, style, ...rest }: ChartTooltipSummaryProps): import("react").JSX.Element;
16
73
  export declare function ChartTooltipContent({ active, payload, label, formatter, }: ChartTooltipContentProps): import("react").JSX.Element | null;
@@ -18,7 +18,124 @@ function s(e) {
18
18
  function c(e) {
19
19
  return e.color ?? e.fill ?? e.stroke ?? "hsl(var(--basalt-chart-1))";
20
20
  }
21
- function l({ active: n, payload: l, label: u, formatter: d }) {
21
+ function l(e, t) {
22
+ return e == null ? "—" : typeof e == "number" ? t ? t(e) : o(e) : e;
23
+ }
24
+ function u({ label: n, value: r, color: o, unit: s, formatter: c, hideIndicator: u = !1, style: d, ...f }) {
25
+ let p = l(r, c), m = n != null, h = o ?? "hsl(var(--basalt-chart-1))";
26
+ return /* @__PURE__ */ t("div", {
27
+ "data-testid": "chart-tooltip-row",
28
+ style: {
29
+ alignItems: "center",
30
+ display: "flex",
31
+ fontSize: i,
32
+ gap: 8,
33
+ lineHeight: "20px",
34
+ minWidth: 0,
35
+ ...d
36
+ },
37
+ ...f,
38
+ children: [
39
+ u ? null : /* @__PURE__ */ e("span", {
40
+ "aria-hidden": "true",
41
+ style: {
42
+ background: h,
43
+ borderRadius: 999,
44
+ boxShadow: "0 0 0 1px hsl(var(--basalt-popover-foreground) / 0.12)",
45
+ flexShrink: 0,
46
+ height: a,
47
+ width: a
48
+ }
49
+ }),
50
+ m ? /* @__PURE__ */ e("span", {
51
+ style: {
52
+ color: "hsl(var(--basalt-muted-foreground))",
53
+ flex: 1,
54
+ minWidth: 0,
55
+ overflow: "hidden",
56
+ textOverflow: "ellipsis",
57
+ whiteSpace: "nowrap"
58
+ },
59
+ children: n
60
+ }) : null,
61
+ /* @__PURE__ */ t("span", {
62
+ style: {
63
+ color: "hsl(var(--basalt-popover-foreground))",
64
+ flexShrink: 0,
65
+ fontVariantNumeric: "tabular-nums",
66
+ fontWeight: 600,
67
+ marginLeft: m ? 0 : "auto"
68
+ },
69
+ children: [p, s != null && p !== "—" ? /* @__PURE__ */ e("span", {
70
+ style: {
71
+ fontWeight: 400,
72
+ marginLeft: 2
73
+ },
74
+ children: s
75
+ }) : null]
76
+ })
77
+ ]
78
+ });
79
+ }
80
+ function d({ style: t, ...n }) {
81
+ return /* @__PURE__ */ e("hr", {
82
+ "aria-orientation": "horizontal",
83
+ "data-testid": "chart-tooltip-divider",
84
+ style: {
85
+ backgroundColor: "hsl(var(--basalt-border) / 0.55)",
86
+ border: 0,
87
+ height: 1,
88
+ margin: "4px 0",
89
+ width: "100%",
90
+ ...t
91
+ },
92
+ ...n
93
+ });
94
+ }
95
+ function f({ label: n = "Total", value: r, unit: a, formatter: o, style: s, ...c }) {
96
+ let u = l(r, o), d = n != null;
97
+ return /* @__PURE__ */ t("div", {
98
+ "data-testid": "chart-tooltip-summary",
99
+ style: {
100
+ alignItems: "center",
101
+ display: "flex",
102
+ fontSize: i,
103
+ gap: 8,
104
+ lineHeight: "20px",
105
+ minWidth: 0,
106
+ ...s
107
+ },
108
+ ...c,
109
+ children: [d ? /* @__PURE__ */ e("span", {
110
+ style: {
111
+ color: "hsl(var(--basalt-muted-foreground))",
112
+ flex: 1,
113
+ fontWeight: 600,
114
+ minWidth: 0,
115
+ overflow: "hidden",
116
+ textOverflow: "ellipsis",
117
+ whiteSpace: "nowrap"
118
+ },
119
+ children: n
120
+ }) : null, /* @__PURE__ */ t("span", {
121
+ style: {
122
+ color: "hsl(var(--basalt-popover-foreground))",
123
+ flexShrink: 0,
124
+ fontVariantNumeric: "tabular-nums",
125
+ fontWeight: 700,
126
+ marginLeft: d ? 0 : "auto"
127
+ },
128
+ children: [u, a != null && u !== "—" ? /* @__PURE__ */ e("span", {
129
+ style: {
130
+ fontWeight: 500,
131
+ marginLeft: 2
132
+ },
133
+ children: a
134
+ }) : null]
135
+ })]
136
+ });
137
+ }
138
+ function p({ active: n, payload: l, label: u, formatter: d }) {
22
139
  if (!n || !l?.length) return null;
23
140
  let f = d ?? o, p = u == null || u === "" ? void 0 : String(u);
24
141
  return /* @__PURE__ */ t("div", {
@@ -100,6 +217,6 @@ function l({ active: n, payload: l, label: u, formatter: d }) {
100
217
  });
101
218
  }
102
219
  //#endregion
103
- export { l as ChartTooltipContent, o as formatChartNumber };
220
+ export { p as ChartTooltipContent, d as ChartTooltipDivider, u as ChartTooltipRow, f as ChartTooltipSummary, o as formatChartNumber };
104
221
 
105
222
  //# sourceMappingURL=tooltip.js.map