@nocoo/basalt 2.2.0 → 3.0.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 (319) hide show
  1. package/README.md +2 -0
  2. package/ai/COMPATIBILITY.md +11 -1
  3. package/ai/DESIGN.md +342 -0
  4. package/ai/INTEGRATION.md +179 -128
  5. package/ai/RECIPES.md +51 -26
  6. package/ai/USAGE.md +4 -4
  7. package/ai/registry.json +2836 -270
  8. package/dist/charts/config.d.ts +11 -11
  9. package/dist/charts/config.js +4 -4
  10. package/dist/charts/config.js.map +1 -1
  11. package/dist/charts/date-navigation.js +10 -10
  12. package/dist/charts/date-navigation.js.map +1 -1
  13. package/dist/charts/donut.js +1 -1
  14. package/dist/charts/donut.js.map +1 -1
  15. package/dist/charts/frame.d.ts +1 -1
  16. package/dist/charts/frame.js +4 -4
  17. package/dist/charts/frame.js.map +1 -1
  18. package/dist/charts/gauge.js +5 -5
  19. package/dist/charts/gauge.js.map +1 -1
  20. package/dist/charts/heatmap-calendar.js +11 -11
  21. package/dist/charts/heatmap-calendar.js.map +1 -1
  22. package/dist/charts/heatmap-matrix.js +8 -8
  23. package/dist/charts/heatmap-matrix.js.map +1 -1
  24. package/dist/charts/item-list.js +1 -1
  25. package/dist/charts/item-list.js.map +1 -1
  26. package/dist/charts/legend.js +19 -19
  27. package/dist/charts/legend.js.map +1 -1
  28. package/dist/charts/palette.js +2 -2
  29. package/dist/charts/palette.js.map +1 -1
  30. package/dist/charts/slot-bar.js +2 -2
  31. package/dist/charts/slot-bar.js.map +1 -1
  32. package/dist/charts/sparkline.js +38 -23
  33. package/dist/charts/sparkline.js.map +1 -1
  34. package/dist/charts/stat-card.d.ts +2 -2
  35. package/dist/charts/stat-card.js +61 -58
  36. package/dist/charts/stat-card.js.map +1 -1
  37. package/dist/charts/timeline.js +18 -9
  38. package/dist/charts/timeline.js.map +1 -1
  39. package/dist/charts/tooltip.js +16 -16
  40. package/dist/charts/tooltip.js.map +1 -1
  41. package/dist/components/accordion.js +1 -1
  42. package/dist/components/accordion.js.map +1 -1
  43. package/dist/components/alert-dialog.js +4 -4
  44. package/dist/components/alert-dialog.js.map +1 -1
  45. package/dist/components/app-header.js +8 -8
  46. package/dist/components/app-header.js.map +1 -1
  47. package/dist/components/app-shell.js +1 -1
  48. package/dist/components/app-shell.js.map +1 -1
  49. package/dist/components/approval-card.d.ts +13 -0
  50. package/dist/components/approval-card.js +161 -0
  51. package/dist/components/approval-card.js.map +1 -0
  52. package/dist/components/avatar.d.ts +12 -0
  53. package/dist/components/avatar.js +39 -18
  54. package/dist/components/avatar.js.map +1 -1
  55. package/dist/components/badge.js +8 -8
  56. package/dist/components/badge.js.map +1 -1
  57. package/dist/components/banner.d.ts +2 -2
  58. package/dist/components/banner.js +9 -8
  59. package/dist/components/banner.js.map +1 -1
  60. package/dist/components/basalt-mark.js +1 -1
  61. package/dist/components/basalt-mark.js.map +1 -1
  62. package/dist/components/battery-meter.js +5 -5
  63. package/dist/components/battery-meter.js.map +1 -1
  64. package/dist/components/breadcrumbs.js +6 -6
  65. package/dist/components/breadcrumbs.js.map +1 -1
  66. package/dist/components/button.js +10 -10
  67. package/dist/components/button.js.map +1 -1
  68. package/dist/components/chat-bubble.js +4 -3
  69. package/dist/components/chat-bubble.js.map +1 -1
  70. package/dist/components/chat-composer.d.ts +21 -3
  71. package/dist/components/chat-composer.js +126 -60
  72. package/dist/components/chat-composer.js.map +1 -1
  73. package/dist/components/chat-header.js +6 -6
  74. package/dist/components/chat-header.js.map +1 -1
  75. package/dist/components/chat-inbox.js +34 -30
  76. package/dist/components/chat-inbox.js.map +1 -1
  77. package/dist/components/chat-markdown.d.ts +8 -0
  78. package/dist/components/chat-markdown.js +122 -0
  79. package/dist/components/chat-markdown.js.map +1 -0
  80. package/dist/components/chat-message.d.ts +26 -0
  81. package/dist/components/chat-message.js +145 -0
  82. package/dist/components/chat-message.js.map +1 -0
  83. package/dist/components/checkbox.js +11 -11
  84. package/dist/components/checkbox.js.map +1 -1
  85. package/dist/components/clipboard-text.js +3 -3
  86. package/dist/components/clipboard-text.js.map +1 -1
  87. package/dist/components/code.d.ts +22 -20
  88. package/dist/components/code.js +94 -32
  89. package/dist/components/code.js.map +1 -1
  90. package/dist/components/collapsible.js +8 -4
  91. package/dist/components/collapsible.js.map +1 -1
  92. package/dist/components/command-palette.js +73 -47
  93. package/dist/components/command-palette.js.map +1 -1
  94. package/dist/components/context-cards.d.ts +15 -0
  95. package/dist/components/context-cards.js +148 -0
  96. package/dist/components/context-cards.js.map +1 -0
  97. package/dist/components/context-menu.d.ts +1 -1
  98. package/dist/components/context-menu.js +18 -14
  99. package/dist/components/context-menu.js.map +1 -1
  100. package/dist/components/data-table.d.ts +8 -2
  101. package/dist/components/data-table.js +161 -106
  102. package/dist/components/data-table.js.map +1 -1
  103. package/dist/components/date-picker.js +13 -13
  104. package/dist/components/date-picker.js.map +1 -1
  105. package/dist/components/delete-resource.js +1 -1
  106. package/dist/components/delete-resource.js.map +1 -1
  107. package/dist/components/description-list.js +3 -3
  108. package/dist/components/description-list.js.map +1 -1
  109. package/dist/components/dialog.d.ts +2 -2
  110. package/dist/components/dialog.js +8 -8
  111. package/dist/components/dialog.js.map +1 -1
  112. package/dist/components/diff-table.d.ts +15 -0
  113. package/dist/components/diff-table.js +146 -0
  114. package/dist/components/diff-table.js.map +1 -0
  115. package/dist/components/dock.js +2 -2
  116. package/dist/components/dock.js.map +1 -1
  117. package/dist/components/dropdown-menu.js +23 -18
  118. package/dist/components/dropdown-menu.js.map +1 -1
  119. package/dist/components/editable-nav-item.js +63 -58
  120. package/dist/components/editable-nav-item.js.map +1 -1
  121. package/dist/components/empty.js +6 -6
  122. package/dist/components/empty.js.map +1 -1
  123. package/dist/components/fab.js +1 -1
  124. package/dist/components/fab.js.map +1 -1
  125. package/dist/components/field.js +3 -3
  126. package/dist/components/field.js.map +1 -1
  127. package/dist/components/file-dropzone.js +7 -7
  128. package/dist/components/file-dropzone.js.map +1 -1
  129. package/dist/components/filter-bar.js +6 -6
  130. package/dist/components/filter-bar.js.map +1 -1
  131. package/dist/components/flow.js +4 -3
  132. package/dist/components/flow.js.map +1 -1
  133. package/dist/components/grid.d.ts +3 -1
  134. package/dist/components/grid.js +15 -8
  135. package/dist/components/grid.js.map +1 -1
  136. package/dist/components/hover-card.js +1 -1
  137. package/dist/components/hover-card.js.map +1 -1
  138. package/dist/components/icon-picker.d.ts +8 -2
  139. package/dist/components/icon-picker.js +75 -47
  140. package/dist/components/icon-picker.js.map +1 -1
  141. package/dist/components/inline-editable.js +6 -6
  142. package/dist/components/inline-editable.js.map +1 -1
  143. package/dist/components/input-area.js +3 -3
  144. package/dist/components/input-area.js.map +1 -1
  145. package/dist/components/input-group.js +5 -5
  146. package/dist/components/input-group.js.map +1 -1
  147. package/dist/components/input.js +4 -4
  148. package/dist/components/input.js.map +1 -1
  149. package/dist/components/label.js +3 -3
  150. package/dist/components/label.js.map +1 -1
  151. package/dist/components/layer-card.d.ts +9 -4
  152. package/dist/components/layer-card.js +72 -67
  153. package/dist/components/layer-card.js.map +1 -1
  154. package/dist/components/loader.d.ts +16 -10
  155. package/dist/components/loader.js +46 -53
  156. package/dist/components/loader.js.map +1 -1
  157. package/dist/components/loading-screen.js +3 -3
  158. package/dist/components/loading-screen.js.map +1 -1
  159. package/dist/components/menu-bar.js +32 -27
  160. package/dist/components/menu-bar.js.map +1 -1
  161. package/dist/components/meter.d.ts +5 -5
  162. package/dist/components/meter.js +25 -12
  163. package/dist/components/meter.js.map +1 -1
  164. package/dist/components/multi-select.js +66 -62
  165. package/dist/components/multi-select.js.map +1 -1
  166. package/dist/components/navigation-menu.d.ts +2 -2
  167. package/dist/components/navigation-menu.js +22 -8
  168. package/dist/components/navigation-menu.js.map +1 -1
  169. package/dist/components/overlay.js +2 -2
  170. package/dist/components/overlay.js.map +1 -1
  171. package/dist/components/page-header.d.ts +3 -1
  172. package/dist/components/page-header.js +12 -12
  173. package/dist/components/page-header.js.map +1 -1
  174. package/dist/components/pagination.js +3 -3
  175. package/dist/components/pagination.js.map +1 -1
  176. package/dist/components/popover.js +18 -23
  177. package/dist/components/popover.js.map +1 -1
  178. package/dist/components/prompt-bar.d.ts +16 -0
  179. package/dist/components/prompt-bar.js +49 -0
  180. package/dist/components/prompt-bar.js.map +1 -0
  181. package/dist/components/radio.js +9 -9
  182. package/dist/components/radio.js.map +1 -1
  183. package/dist/components/recommendation-card.d.ts +13 -0
  184. package/dist/components/recommendation-card.js +123 -0
  185. package/dist/components/recommendation-card.js.map +1 -0
  186. package/dist/components/resource-list.js +1 -1
  187. package/dist/components/resource-list.js.map +1 -1
  188. package/dist/components/responsive-master-detail.js +4 -4
  189. package/dist/components/responsive-master-detail.js.map +1 -1
  190. package/dist/components/scroll-area.js +3 -3
  191. package/dist/components/scroll-area.js.map +1 -1
  192. package/dist/components/section-rule.d.ts +5 -3
  193. package/dist/components/section-rule.js +12 -12
  194. package/dist/components/section-rule.js.map +1 -1
  195. package/dist/components/segment-control.js +3 -3
  196. package/dist/components/segment-control.js.map +1 -1
  197. package/dist/components/select.js +47 -32
  198. package/dist/components/select.js.map +1 -1
  199. package/dist/components/sensitive-input.js +17 -19
  200. package/dist/components/sensitive-input.js.map +1 -1
  201. package/dist/components/sheet.d.ts +4 -4
  202. package/dist/components/sheet.js +11 -10
  203. package/dist/components/sheet.js.map +1 -1
  204. package/dist/components/sidebar.js +146 -137
  205. package/dist/components/sidebar.js.map +1 -1
  206. package/dist/components/skeleton-line.d.ts +1 -1
  207. package/dist/components/skeleton-line.js +2 -2
  208. package/dist/components/skeleton-line.js.map +1 -1
  209. package/dist/components/slider.js +2 -2
  210. package/dist/components/slider.js.map +1 -1
  211. package/dist/components/stat-strip.js +5 -4
  212. package/dist/components/stat-strip.js.map +1 -1
  213. package/dist/components/switch.js +6 -6
  214. package/dist/components/switch.js.map +1 -1
  215. package/dist/components/table-of-contents.js +5 -5
  216. package/dist/components/table-of-contents.js.map +1 -1
  217. package/dist/components/table-pager.js +2 -2
  218. package/dist/components/table-pager.js.map +1 -1
  219. package/dist/components/table.js +4 -4
  220. package/dist/components/table.js.map +1 -1
  221. package/dist/components/tabs.js +7 -6
  222. package/dist/components/tabs.js.map +1 -1
  223. package/dist/components/tag-badge.d.ts +10 -10
  224. package/dist/components/tag-badge.js +11 -11
  225. package/dist/components/tag-badge.js.map +1 -1
  226. package/dist/components/tag-color-picker.d.ts +8 -1
  227. package/dist/components/tag-color-picker.js +33 -25
  228. package/dist/components/tag-color-picker.js.map +1 -1
  229. package/dist/components/text.js +5 -5
  230. package/dist/components/text.js.map +1 -1
  231. package/dist/components/theme-toggle.js +1 -1
  232. package/dist/components/theme-toggle.js.map +1 -1
  233. package/dist/components/thinking.d.ts +16 -0
  234. package/dist/components/thinking.js +85 -0
  235. package/dist/components/thinking.js.map +1 -0
  236. package/dist/components/toast.js +25 -20
  237. package/dist/components/toast.js.map +1 -1
  238. package/dist/components/toggle-group.js +6 -5
  239. package/dist/components/toggle-group.js.map +1 -1
  240. package/dist/components/toggle.js +6 -6
  241. package/dist/components/toggle.js.map +1 -1
  242. package/dist/components/tool-chips.d.ts +12 -0
  243. package/dist/components/tool-chips.js +138 -0
  244. package/dist/components/tool-chips.js.map +1 -0
  245. package/dist/components/toolbar.js +3 -3
  246. package/dist/components/toolbar.js.map +1 -1
  247. package/dist/components/tooltip.js +1 -1
  248. package/dist/components/tooltip.js.map +1 -1
  249. package/dist/components/typeahead-field.js +59 -56
  250. package/dist/components/typeahead-field.js.map +1 -1
  251. package/dist/components/upload-queue.js +15 -14
  252. package/dist/components/upload-queue.js.map +1 -1
  253. package/dist/models/agent-feedback.d.ts +44 -0
  254. package/dist/models/agent-feedback.js +28 -0
  255. package/dist/models/agent-feedback.js.map +1 -0
  256. package/dist/models/avatar.d.ts +2 -0
  257. package/dist/models/avatar.js +15 -0
  258. package/dist/models/avatar.js.map +1 -0
  259. package/dist/models/code.d.ts +6 -0
  260. package/dist/models/code.js +24 -0
  261. package/dist/models/code.js.map +1 -0
  262. package/dist/models/context-cards.d.ts +13 -0
  263. package/dist/models/context-cards.js +17 -0
  264. package/dist/models/context-cards.js.map +1 -0
  265. package/dist/models/diff-table.d.ts +12 -0
  266. package/dist/models/diff-table.js +9 -0
  267. package/dist/models/diff-table.js.map +1 -0
  268. package/dist/models/recommendation.d.ts +26 -0
  269. package/dist/models/recommendation.js +23 -0
  270. package/dist/models/recommendation.js.map +1 -0
  271. package/dist/styles/base.css +14 -2
  272. package/dist/styles/standalone.css +1865 -929
  273. package/dist/styles/tailwind.css +179 -13
  274. package/dist/styles/tokens.css +679 -20
  275. package/dist/utils/cn.js +25 -4
  276. package/dist/utils/cn.js.map +1 -1
  277. package/dist/utils/control-surface.d.ts +1 -1
  278. package/dist/utils/control-surface.js +1 -1
  279. package/dist/utils/control-surface.js.map +1 -1
  280. package/dist/utils/navigation.d.ts +3 -0
  281. package/dist/utils/navigation.js +8 -0
  282. package/dist/utils/navigation.js.map +1 -0
  283. package/dist/utils/selection-indicator.d.ts +1 -1
  284. package/dist/utils/selection-indicator.js +49 -72
  285. package/dist/utils/selection-indicator.js.map +1 -1
  286. package/dist/utils/use-hover-highlight.d.ts +4 -0
  287. package/dist/utils/use-hover-highlight.js +80 -0
  288. package/dist/utils/use-hover-highlight.js.map +1 -0
  289. package/dist/viewmodels/use-approval-card.d.ts +20 -0
  290. package/dist/viewmodels/use-approval-card.js +83 -0
  291. package/dist/viewmodels/use-approval-card.js.map +1 -0
  292. package/dist/viewmodels/use-chat-composer.d.ts +16 -0
  293. package/dist/viewmodels/use-chat-composer.js +34 -0
  294. package/dist/viewmodels/use-chat-composer.js.map +1 -0
  295. package/dist/viewmodels/use-chat-message.d.ts +16 -0
  296. package/dist/viewmodels/use-chat-message.js +26 -0
  297. package/dist/viewmodels/use-chat-message.js.map +1 -0
  298. package/dist/viewmodels/use-code-block.d.ts +8 -0
  299. package/dist/viewmodels/use-code-block.js +38 -0
  300. package/dist/viewmodels/use-code-block.js.map +1 -0
  301. package/dist/viewmodels/use-context-cards.d.ts +17 -0
  302. package/dist/viewmodels/use-context-cards.js +18 -0
  303. package/dist/viewmodels/use-context-cards.js.map +1 -0
  304. package/dist/viewmodels/use-diff-table.d.ts +16 -0
  305. package/dist/viewmodels/use-diff-table.js +42 -0
  306. package/dist/viewmodels/use-diff-table.js.map +1 -0
  307. package/dist/viewmodels/use-loader.d.ts +4 -0
  308. package/dist/viewmodels/use-loader.js +22 -0
  309. package/dist/viewmodels/use-loader.js.map +1 -0
  310. package/dist/viewmodels/use-recommendation-card.d.ts +17 -0
  311. package/dist/viewmodels/use-recommendation-card.js +41 -0
  312. package/dist/viewmodels/use-recommendation-card.js.map +1 -0
  313. package/dist/viewmodels/use-thinking.d.ts +13 -0
  314. package/dist/viewmodels/use-thinking.js +18 -0
  315. package/dist/viewmodels/use-thinking.js.map +1 -0
  316. package/dist/viewmodels/use-tool-chips.d.ts +10 -0
  317. package/dist/viewmodels/use-tool-chips.js +20 -0
  318. package/dist/viewmodels/use-tool-chips.js.map +1 -0
  319. package/package.json +3 -1
@@ -1 +1 @@
1
- {"version":3,"file":"heatmap-calendar.js","names":["heatmapColorScales","weekdayNames","locale","index","monthNames","getYearWeeks","weeks","startDate","year","endDate","firstDay","currentDate","currentWeek","formatDate","date","getColorIndex","value","levels","colorScale","normalized","maxValue","HeatmapCalendar","props","YearHeatmap","ValuesHeatmap","activeIdx","setActiveIdx","useState","openTooltipIdx","setOpenTooltipIdx","containerRef","useRef","cellRefs","isFocusedInsideRef","hadFocus","values","next","handleKeyDown","nextIdx","currentIndex","container","ariaLabel","cn","className","Tooltip","curr","TooltipTrigger","el","TooltipContent","TooltipProvider","weekdays","weekdayLabels","months","monthLabels","calendarId","useId","scrollRegionRef","useMemo","dataMap","point","data","labels","lastMonth","firstDayOfWeek","week","month","validDays","dateToValidIndex","dateStr","activeDate","setActiveDate","openTooltipDate","setOpenTooltipDate","isYearFocusedInsideRef","nextDate","selectedDate","navigateToDay","targetDate","handleCellKeyDown","currentIdx","nextDay","prevDay","targetIdx","label","cellSize","cellGap","day","dayIndex","colorIndex","isSelected","formattedValue","valueFormatter","labelText","metricLabel","weekIndex","lessLabel","color","moreLabel"],"sources":["../../src/charts/heatmap-calendar.tsx"],"sourcesContent":["import { type KeyboardEvent, useEffect, useId, useMemo, useRef, useState } from \"react\";\nimport { Tooltip, TooltipContent, TooltipProvider, TooltipTrigger } from \"../components/tooltip\";\nimport { cn } from \"../utils/cn\";\n\nexport type HeatmapDataPoint = { date: string; value: number };\n\nexport const heatmapColorScales = {\n\tgreen: [\n\t\t\"hsl(var(--basalt-muted))\",\n\t\t\"hsl(var(--basalt-heatmap-green-1))\",\n\t\t\"hsl(var(--basalt-heatmap-green-2))\",\n\t\t\"hsl(var(--basalt-heatmap-green-3))\",\n\t\t\"hsl(var(--basalt-heatmap-green-4))\",\n\t],\n\tred: [\n\t\t\"hsl(var(--basalt-muted))\",\n\t\t\"hsl(var(--basalt-heatmap-red-1))\",\n\t\t\"hsl(var(--basalt-heatmap-red-2))\",\n\t\t\"hsl(var(--basalt-heatmap-red-3))\",\n\t\t\"hsl(var(--basalt-heatmap-red-4))\",\n\t],\n\tblue: [\n\t\t\"hsl(var(--basalt-muted))\",\n\t\t\"hsl(var(--basalt-heatmap-blue-1))\",\n\t\t\"hsl(var(--basalt-heatmap-blue-2))\",\n\t\t\"hsl(var(--basalt-heatmap-blue-3))\",\n\t\t\"hsl(var(--basalt-heatmap-blue-4))\",\n\t],\n\torange: [\n\t\t\"hsl(var(--basalt-muted))\",\n\t\t\"hsl(var(--basalt-heatmap-orange-1))\",\n\t\t\"hsl(var(--basalt-heatmap-orange-2))\",\n\t\t\"hsl(var(--basalt-heatmap-orange-3))\",\n\t\t\"hsl(var(--basalt-heatmap-orange-4))\",\n\t],\n} as const;\n\nfunction weekdayNames(locale: string) {\n\treturn Array.from({ length: 7 }, (_, index) =>\n\t\tnew Intl.DateTimeFormat(locale, { weekday: \"short\" }).format(new Date(2023, 0, 1 + index)),\n\t);\n}\n\nfunction monthNames(locale: string) {\n\treturn Array.from({ length: 12 }, (_, index) =>\n\t\tnew Intl.DateTimeFormat(locale, { month: \"short\" }).format(new Date(2023, index, 1)),\n\t);\n}\n\nfunction getYearWeeks(year: number): Date[][] {\n\tconst weeks: Date[][] = [];\n\tconst startDate = new Date(year, 0, 1);\n\tconst endDate = new Date(year, 11, 31);\n\tconst firstDay = new Date(startDate);\n\tfirstDay.setDate(firstDay.getDate() - firstDay.getDay());\n\tlet currentDate = new Date(firstDay);\n\tlet currentWeek: Date[] = [];\n\twhile (currentDate <= endDate || currentWeek.length > 0) {\n\t\tif (currentWeek.length === 7) {\n\t\t\tweeks.push(currentWeek);\n\t\t\tcurrentWeek = [];\n\t\t}\n\t\tif (currentDate > endDate) {\n\t\t\tbreak;\n\t\t}\n\t\tcurrentWeek.push(new Date(currentDate));\n\t\tcurrentDate = new Date(currentDate);\n\t\tcurrentDate.setDate(currentDate.getDate() + 1);\n\t}\n\tif (currentWeek.length > 0) {\n\t\tweeks.push(currentWeek);\n\t}\n\treturn weeks;\n}\n\nfunction formatDate(date: Date): string {\n\tconst year = date.getFullYear();\n\tconst month = String(date.getMonth() + 1).padStart(2, \"0\");\n\tconst day = String(date.getDate()).padStart(2, \"0\");\n\treturn `${year}-${month}-${day}`;\n}\n\nfunction getColorIndex(value: number, maxValue: number, colorScale: readonly string[]): number {\n\tif (value === 0) {\n\t\treturn 0;\n\t}\n\tconst levels = colorScale.length - 1;\n\tconst normalized = Math.min(value / maxValue, 1);\n\treturn Math.ceil(normalized * levels);\n}\n\nexport type HeatmapCalendarValuesProps = {\n\t/**\n\t * Numeric values sequence to display in a compact 7-column grid.\n\t */\n\tvalues: number[];\n\t/**\n\t * Accessible name describing the heatmap purpose or data.\n\t * @default \"Heatmap calendar\"\n\t */\n\tariaLabel?: string;\n\t/**\n\t * Additional CSS class names for the outer container.\n\t */\n\tclassName?: string;\n};\n\nexport type HeatmapCalendarYearProps = {\n\t/**\n\t * Dataset of daily metrics with ISO date strings (\"YYYY-MM-DD\") and numeric values.\n\t */\n\tdata: HeatmapDataPoint[];\n\t/**\n\t * Calendar year to render.\n\t */\n\tyear: number;\n\t/**\n\t * Array of color values forming the intensity gradient from lowest to highest.\n\t * @default heatmapColorScales.green\n\t */\n\tcolorScale?: readonly string[];\n\t/**\n\t * Formatter for tooltip value display and accessible label.\n\t * @default (value) => value.toLocaleString()\n\t */\n\tvalueFormatter?: (value: number, date: string) => string;\n\t/**\n\t * Name of the metric for accessible labeling and tooltips.\n\t * @default \"Value\"\n\t */\n\tmetricLabel?: string;\n\t/**\n\t * Pixel width and height of each day cell.\n\t * @default 12\n\t */\n\tcellSize?: number;\n\t/**\n\t * Pixel gap between adjacent cells.\n\t * @default 2\n\t */\n\tcellGap?: number;\n\t/**\n\t * BCP 47 locale tag used for weekday and month label formatting.\n\t * @default \"en-US\"\n\t */\n\tlocale?: string;\n\t/**\n\t * Explicit custom weekday labels override.\n\t */\n\tweekdayLabels?: string[];\n\t/**\n\t * Explicit custom month labels override.\n\t */\n\tmonthLabels?: string[];\n\t/**\n\t * Label text for the lower end of the color scale legend.\n\t * @default \"Less\"\n\t */\n\tlessLabel?: string;\n\t/**\n\t * Label text for the upper end of the color scale legend.\n\t * @default \"More\"\n\t */\n\tmoreLabel?: string;\n\t/**\n\t * Accessible name describing the yearly heatmap dataset.\n\t * @default \"Heatmap calendar\"\n\t */\n\tariaLabel?: string;\n\t/**\n\t * Additional CSS class names for the outer scrollable container.\n\t */\n\tclassName?: string;\n};\n\nexport type HeatmapCalendarProps = HeatmapCalendarValuesProps | HeatmapCalendarYearProps;\n\nexport function HeatmapCalendar(props: HeatmapCalendarProps) {\n\tif (\"data\" in props) {\n\t\treturn <YearHeatmap {...props} />;\n\t}\n\treturn <ValuesHeatmap {...props} />;\n}\n\nfunction ValuesHeatmap({\n\tvalues,\n\tariaLabel = \"Heatmap calendar\",\n\tclassName,\n}: HeatmapCalendarValuesProps) {\n\tconst [activeIdx, setActiveIdx] = useState(0);\n\tconst [openTooltipIdx, setOpenTooltipIdx] = useState<number | null>(null);\n\tconst containerRef = useRef<HTMLDivElement | null>(null);\n\tconst cellRefs = useRef<(HTMLButtonElement | null)[]>([]);\n\tconst isFocusedInsideRef = useRef(false);\n\n\t// When values array shrinks, empties, or restores: if an item or container currently held focus,\n\t// restore focus to the new valid index or empty container without stealing focus from outside.\n\tuseEffect(() => {\n\t\tconst hadFocus = isFocusedInsideRef.current;\n\t\tif (values.length === 0) {\n\t\t\tsetActiveIdx(0);\n\t\t\tsetOpenTooltipIdx(null);\n\t\t\tif (hadFocus) {\n\t\t\t\tcontainerRef.current?.focus();\n\t\t\t}\n\t\t} else if (activeIdx >= values.length) {\n\t\t\tconst next = values.length - 1;\n\t\t\tsetActiveIdx(next);\n\t\t\tif (hadFocus) {\n\t\t\t\tcellRefs.current[next]?.focus();\n\t\t\t}\n\t\t} else if (hadFocus) {\n\t\t\tcellRefs.current[activeIdx]?.focus();\n\t\t}\n\t}, [values.length, activeIdx]);\n\n\tconst handleKeyDown = (e: KeyboardEvent<HTMLButtonElement>, currentIndex: number) => {\n\t\tif (values.length === 0) return;\n\n\t\tif (e.key === \"Escape\") {\n\t\t\tsetOpenTooltipIdx(null);\n\t\t\treturn;\n\t\t}\n\n\t\tlet nextIdx = currentIndex;\n\t\tif (e.key === \"ArrowRight\") {\n\t\t\tnextIdx = Math.min(values.length - 1, currentIndex + 1);\n\t\t} else if (e.key === \"ArrowLeft\") {\n\t\t\tnextIdx = Math.max(0, currentIndex - 1);\n\t\t} else if (e.key === \"ArrowDown\") {\n\t\t\tnextIdx = Math.min(values.length - 1, currentIndex + 7);\n\t\t} else if (e.key === \"ArrowUp\") {\n\t\t\tnextIdx = Math.max(0, currentIndex - 7);\n\t\t} else if (e.key === \"Home\") {\n\t\t\tnextIdx = 0;\n\t\t} else if (e.key === \"End\") {\n\t\t\tnextIdx = values.length - 1;\n\t\t} else {\n\t\t\treturn;\n\t\t}\n\n\t\te.preventDefault();\n\t\tsetActiveIdx(nextIdx);\n\t\tsetOpenTooltipIdx(nextIdx);\n\t\tcellRefs.current[nextIdx]?.focus();\n\t};\n\n\tconst container = (\n\t\t<div\n\t\t\tref={containerRef}\n\t\t\ttabIndex={-1}\n\t\t\trole=\"region\"\n\t\t\taria-label={ariaLabel}\n\t\t\tonFocus={() => {\n\t\t\t\tisFocusedInsideRef.current = true;\n\t\t\t}}\n\t\t\tonBlur={(e) => {\n\t\t\t\tif (!e.currentTarget.contains(e.relatedTarget)) {\n\t\t\t\t\tisFocusedInsideRef.current = false;\n\t\t\t\t}\n\t\t\t}}\n\t\t\tclassName={cn(\"grid grid-cols-7 gap-1 p-0.5 outline-none\", className)}\n\t\t>\n\t\t\t{values.map((value, index) => {\n\t\t\t\tconst isCurrent = index === activeIdx;\n\t\t\t\tconst isOpen = openTooltipIdx === index;\n\t\t\t\treturn (\n\t\t\t\t\t<Tooltip\n\t\t\t\t\t\tkey={index}\n\t\t\t\t\t\topen={isOpen}\n\t\t\t\t\t\tonOpenChange={(next) => {\n\t\t\t\t\t\t\tif (next) {\n\t\t\t\t\t\t\t\tsetOpenTooltipIdx(index);\n\t\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\t\tsetOpenTooltipIdx((curr) => {\n\t\t\t\t\t\t\t\t\tif (curr !== index) return curr;\n\t\t\t\t\t\t\t\t\t// If this cell currently holds document focus, ignore scroll dismiss\n\t\t\t\t\t\t\t\t\tconst isCellFocused =\n\t\t\t\t\t\t\t\t\t\tcellRefs.current[index] !== null &&\n\t\t\t\t\t\t\t\t\t\tdocument.activeElement === cellRefs.current[index];\n\t\t\t\t\t\t\t\t\treturn isCellFocused ? curr : null;\n\t\t\t\t\t\t\t\t});\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}}\n\t\t\t\t\t>\n\t\t\t\t\t\t<TooltipTrigger asChild>\n\t\t\t\t\t\t\t<button\n\t\t\t\t\t\t\t\tref={(el) => {\n\t\t\t\t\t\t\t\t\tcellRefs.current[index] = el;\n\t\t\t\t\t\t\t\t}}\n\t\t\t\t\t\t\t\ttype=\"button\"\n\t\t\t\t\t\t\t\ttabIndex={isCurrent ? 0 : -1}\n\t\t\t\t\t\t\t\tonFocus={() => {\n\t\t\t\t\t\t\t\t\tsetActiveIdx(index);\n\t\t\t\t\t\t\t\t\tsetOpenTooltipIdx(index);\n\t\t\t\t\t\t\t\t}}\n\t\t\t\t\t\t\t\tonBlur={() => {\n\t\t\t\t\t\t\t\t\tsetOpenTooltipIdx((curr) => (curr === index ? null : curr));\n\t\t\t\t\t\t\t\t}}\n\t\t\t\t\t\t\t\tonKeyDown={(e) => handleKeyDown(e, index)}\n\t\t\t\t\t\t\t\taria-label={`Position ${index + 1}: ${value}`}\n\t\t\t\t\t\t\t\tclassName=\"box-border m-0 h-3 w-3 cursor-pointer rounded-sm border-0 p-0 transition-colors focus-visible:outline-2 focus-visible:outline-offset-1 focus-visible:outline-basalt-ring\"\n\t\t\t\t\t\t\t\tstyle={{\n\t\t\t\t\t\t\t\t\tbackgroundColor: `hsl(var(--basalt-chart-5) / ${0.2 + Math.min(4, Math.max(0, value)) * 0.15})`,\n\t\t\t\t\t\t\t\t}}\n\t\t\t\t\t\t\t/>\n\t\t\t\t\t\t</TooltipTrigger>\n\t\t\t\t\t\t<TooltipContent>\n\t\t\t\t\t\t\t<div className=\"text-xs\">\n\t\t\t\t\t\t\t\tPosition {index + 1}: {value}\n\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t</TooltipContent>\n\t\t\t\t\t</Tooltip>\n\t\t\t\t);\n\t\t\t})}\n\t\t</div>\n\t);\n\n\tif (values.length === 0) {\n\t\treturn container;\n\t}\n\n\treturn <TooltipProvider>{container}</TooltipProvider>;\n}\n\nfunction YearHeatmap({\n\tdata,\n\tyear,\n\tcolorScale = heatmapColorScales.green,\n\tvalueFormatter = (value) => value.toLocaleString(),\n\tmetricLabel = \"Value\",\n\tcellSize = 12,\n\tcellGap = 2,\n\tlocale = \"en-US\",\n\tweekdayLabels,\n\tmonthLabels,\n\tlessLabel = \"Less\",\n\tmoreLabel = \"More\",\n\tariaLabel = \"Heatmap calendar\",\n\tclassName,\n}: HeatmapCalendarYearProps) {\n\tconst weekdays = weekdayLabels ?? weekdayNames(locale);\n\tconst months = monthLabels ?? monthNames(locale);\n\tconst calendarId = useId();\n\tconst scrollRegionRef = useRef<HTMLDivElement | null>(null);\n\n\tconst { weeks, dataMap, maxValue, labels, validDays, dateToValidIndex } = useMemo(() => {\n\t\tconst weeks = getYearWeeks(year);\n\t\tconst dataMap = new Map<string, number>();\n\t\tlet maxValue = 0;\n\t\tfor (const point of data) {\n\t\t\tdataMap.set(point.date, point.value);\n\t\t\tif (point.value > maxValue) {\n\t\t\t\tmaxValue = point.value;\n\t\t\t}\n\t\t}\n\n\t\tconst labels: { month: string; weekIndex: number }[] = [];\n\t\tlet lastMonth = -1;\n\t\tweeks.forEach((week, weekIndex) => {\n\t\t\tconst firstDayOfWeek = week.find((date) => date.getFullYear() === year);\n\t\t\tif (firstDayOfWeek) {\n\t\t\t\tconst month = firstDayOfWeek.getMonth();\n\t\t\t\tif (month !== lastMonth) {\n\t\t\t\t\tlabels.push({ month: months[month], weekIndex });\n\t\t\t\t\tlastMonth = month;\n\t\t\t\t}\n\t\t\t}\n\t\t});\n\n\t\tconst validDays: string[] = [];\n\t\tconst dateToValidIndex = new Map<string, number>();\n\n\t\tweeks.forEach((week) => {\n\t\t\tweek.forEach((date) => {\n\t\t\t\tif (date.getFullYear() === year) {\n\t\t\t\t\tconst dateStr = formatDate(date);\n\t\t\t\t\tdateToValidIndex.set(dateStr, validDays.length);\n\t\t\t\t\tvalidDays.push(dateStr);\n\t\t\t\t}\n\t\t\t});\n\t\t});\n\n\t\treturn { weeks, dataMap, maxValue, labels, validDays, dateToValidIndex };\n\t}, [data, months, year]);\n\n\tconst [activeDate, setActiveDate] = useState<string>(() => {\n\t\treturn validDays[0] ?? `${year}-01-01`;\n\t});\n\tconst [openTooltipDate, setOpenTooltipDate] = useState<string | null>(null);\n\n\tconst cellRefs = useRef<Map<string, HTMLButtonElement>>(new Map());\n\tconst isYearFocusedInsideRef = useRef(false);\n\n\t// If year or validDays change: if a cell held focus, restore focus to the clamped\n\t// active date or scroll container; if focus was outside, do NOT steal focus.\n\tuseEffect(() => {\n\t\tconst hadFocus = isYearFocusedInsideRef.current;\n\t\tif (validDays.length === 0) {\n\t\t\tsetActiveDate(\"\");\n\t\t\tsetOpenTooltipDate(null);\n\t\t\tif (hadFocus) {\n\t\t\t\tscrollRegionRef.current?.focus();\n\t\t\t}\n\t\t} else if (!dateToValidIndex.has(activeDate)) {\n\t\t\tconst nextDate = validDays[0] ?? \"\";\n\t\t\tsetActiveDate(nextDate);\n\t\t\tif (hadFocus) {\n\t\t\t\tcellRefs.current.get(nextDate)?.focus();\n\t\t\t}\n\t\t}\n\t}, [validDays, dateToValidIndex, activeDate]);\n\n\tconst selectedDate = dateToValidIndex.has(activeDate) ? activeDate : validDays[0];\n\n\tconst navigateToDay = (targetDate: string | undefined) => {\n\t\tif (!targetDate) return;\n\t\tsetActiveDate(targetDate);\n\t\tsetOpenTooltipDate(targetDate);\n\t\tconst btn = cellRefs.current.get(targetDate);\n\t\tbtn?.focus();\n\t};\n\n\tconst handleCellKeyDown = (e: KeyboardEvent<HTMLButtonElement>, dateStr: string) => {\n\t\tif (validDays.length === 0) return;\n\n\t\tconst currentIdx = dateToValidIndex.get(dateStr) ?? 0;\n\n\t\tif (e.key === \"Escape\") {\n\t\t\tsetOpenTooltipDate(null);\n\t\t\treturn;\n\t\t}\n\n\t\tif (e.key === \"ArrowDown\") {\n\t\t\te.preventDefault();\n\t\t\t// Visually next day (down in the column)\n\t\t\tconst nextDay = validDays[currentIdx + 1];\n\t\t\tif (nextDay) {\n\t\t\t\tnavigateToDay(nextDay);\n\t\t\t}\n\t\t} else if (e.key === \"ArrowUp\") {\n\t\t\te.preventDefault();\n\t\t\t// Visually previous day (up in the column)\n\t\t\tconst prevDay = validDays[currentIdx - 1];\n\t\t\tif (prevDay) {\n\t\t\t\tnavigateToDay(prevDay);\n\t\t\t}\n\t\t} else if (e.key === \"ArrowRight\") {\n\t\t\te.preventDefault();\n\t\t\t// Visually next week (right in the row: +7 days by index)\n\t\t\tconst targetIdx = currentIdx + 7;\n\t\t\tif (targetIdx < validDays.length) {\n\t\t\t\tnavigateToDay(validDays[targetIdx]);\n\t\t\t} else {\n\t\t\t\tnavigateToDay(validDays[validDays.length - 1]);\n\t\t\t}\n\t\t} else if (e.key === \"ArrowLeft\") {\n\t\t\te.preventDefault();\n\t\t\t// Visually previous week (left in the row: -7 days by index)\n\t\t\tconst targetIdx = currentIdx - 7;\n\t\t\tif (targetIdx >= 0) {\n\t\t\t\tnavigateToDay(validDays[targetIdx]);\n\t\t\t} else {\n\t\t\t\tnavigateToDay(validDays[0]);\n\t\t\t}\n\t\t} else if (e.key === \"Home\") {\n\t\t\te.preventDefault();\n\t\t\tnavigateToDay(validDays[0]);\n\t\t} else if (e.key === \"End\") {\n\t\t\te.preventDefault();\n\t\t\tnavigateToDay(validDays[validDays.length - 1]);\n\t\t}\n\t};\n\n\tconst labelWidth = 30;\n\n\treturn (\n\t\t<div\n\t\t\tref={scrollRegionRef}\n\t\t\ttabIndex={-1}\n\t\t\trole=\"region\"\n\t\t\taria-label={`${ariaLabel} scrollable view`}\n\t\t\tonFocus={() => {\n\t\t\t\tisYearFocusedInsideRef.current = true;\n\t\t\t}}\n\t\t\tonBlur={(e) => {\n\t\t\t\tif (!e.currentTarget.contains(e.relatedTarget)) {\n\t\t\t\t\tisYearFocusedInsideRef.current = false;\n\t\t\t\t}\n\t\t\t}}\n\t\t\tclassName={cn(\n\t\t\t\t\"overflow-x-auto rounded-md outline-none focus-visible:ring-1 focus-visible:ring-basalt-ring\",\n\t\t\t\tclassName,\n\t\t\t)}\n\t\t>\n\t\t\t<TooltipProvider>\n\t\t\t\t<div className=\"inline-block p-1\" role=\"group\" aria-label={ariaLabel}>\n\t\t\t\t\t<div\n\t\t\t\t\t\tclassName=\"relative mb-1 h-4 text-xs text-basalt-muted-foreground\"\n\t\t\t\t\t\tstyle={{ marginLeft: labelWidth }}\n\t\t\t\t\t>\n\t\t\t\t\t\t{labels.map((label) => (\n\t\t\t\t\t\t\t<div\n\t\t\t\t\t\t\t\tkey={`${label.month}-${label.weekIndex}`}\n\t\t\t\t\t\t\t\tclassName=\"absolute\"\n\t\t\t\t\t\t\t\tstyle={{ left: label.weekIndex * (cellSize + cellGap) }}\n\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t{label.month}\n\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t))}\n\t\t\t\t\t</div>\n\t\t\t\t\t<div className=\"flex\">\n\t\t\t\t\t\t<div\n\t\t\t\t\t\t\tclassName=\"mr-1 flex flex-col text-xs text-basalt-muted-foreground select-none\"\n\t\t\t\t\t\t\tstyle={{ width: labelWidth }}\n\t\t\t\t\t\t\taria-hidden=\"true\"\n\t\t\t\t\t\t>\n\t\t\t\t\t\t\t{weekdays.map((day, index) => (\n\t\t\t\t\t\t\t\t<div\n\t\t\t\t\t\t\t\t\tkey={`${day}-${index}`}\n\t\t\t\t\t\t\t\t\tstyle={{\n\t\t\t\t\t\t\t\t\t\theight: cellSize + cellGap,\n\t\t\t\t\t\t\t\t\t\tlineHeight: `${cellSize + cellGap}px`,\n\t\t\t\t\t\t\t\t\t\tvisibility: index % 2 === 1 ? \"visible\" : \"hidden\",\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{day}\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\t<div className=\"flex\" style={{ gap: cellGap }}>\n\t\t\t\t\t\t\t{weeks.map((week, weekIndex) => (\n\t\t\t\t\t\t\t\t<div key={weekIndex} className=\"flex flex-col\" style={{ gap: cellGap }}>\n\t\t\t\t\t\t\t\t\t{week.map((date, dayIndex) => {\n\t\t\t\t\t\t\t\t\t\tconst dateStr = formatDate(date);\n\t\t\t\t\t\t\t\t\t\tconst isCurrentYear = date.getFullYear() === year;\n\t\t\t\t\t\t\t\t\t\tif (!isCurrentYear) {\n\t\t\t\t\t\t\t\t\t\t\treturn (\n\t\t\t\t\t\t\t\t\t\t\t\t<div\n\t\t\t\t\t\t\t\t\t\t\t\t\tkey={dayIndex}\n\t\t\t\t\t\t\t\t\t\t\t\t\tstyle={{\n\t\t\t\t\t\t\t\t\t\t\t\t\t\twidth: cellSize,\n\t\t\t\t\t\t\t\t\t\t\t\t\t\theight: cellSize,\n\t\t\t\t\t\t\t\t\t\t\t\t\t\tvisibility: \"hidden\",\n\t\t\t\t\t\t\t\t\t\t\t\t\t}}\n\t\t\t\t\t\t\t\t\t\t\t\t\taria-hidden=\"true\"\n\t\t\t\t\t\t\t\t\t\t\t\t/>\n\t\t\t\t\t\t\t\t\t\t\t);\n\t\t\t\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\t\t\t\tconst value = dataMap.get(dateStr) ?? 0;\n\t\t\t\t\t\t\t\t\t\tconst colorIndex = getColorIndex(value, maxValue, colorScale);\n\t\t\t\t\t\t\t\t\t\tconst isSelected = selectedDate === dateStr;\n\t\t\t\t\t\t\t\t\t\tconst formattedValue = valueFormatter(value, dateStr);\n\t\t\t\t\t\t\t\t\t\tconst labelText = `${dateStr}, ${metricLabel}: ${formattedValue}`;\n\t\t\t\t\t\t\t\t\t\tconst isOpen = openTooltipDate === dateStr;\n\n\t\t\t\t\t\t\t\t\t\treturn (\n\t\t\t\t\t\t\t\t\t\t\t<Tooltip\n\t\t\t\t\t\t\t\t\t\t\t\tkey={dayIndex}\n\t\t\t\t\t\t\t\t\t\t\t\topen={isOpen}\n\t\t\t\t\t\t\t\t\t\t\t\tonOpenChange={(next) => {\n\t\t\t\t\t\t\t\t\t\t\t\t\tif (next) {\n\t\t\t\t\t\t\t\t\t\t\t\t\t\tsetOpenTooltipDate(dateStr);\n\t\t\t\t\t\t\t\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\t\t\t\t\t\t\t\tsetOpenTooltipDate((curr) => {\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tif (curr !== dateStr) return curr;\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t// If this cell currently holds document focus, ignore scroll dismiss\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tconst isCellFocused =\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tdocument.activeElement === cellRefs.current.get(dateStr);\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\treturn isCellFocused ? curr : null;\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t});\n\t\t\t\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t\t\t\t}}\n\t\t\t\t\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t\t\t\t\t<TooltipTrigger asChild>\n\t\t\t\t\t\t\t\t\t\t\t\t\t<button\n\t\t\t\t\t\t\t\t\t\t\t\t\t\tref={(el) => {\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tif (el) {\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tcellRefs.current.set(dateStr, el);\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tcellRefs.current.delete(dateStr);\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t}}\n\t\t\t\t\t\t\t\t\t\t\t\t\t\ttype=\"button\"\n\t\t\t\t\t\t\t\t\t\t\t\t\t\taria-label={labelText}\n\t\t\t\t\t\t\t\t\t\t\t\t\t\ttabIndex={isSelected ? 0 : -1}\n\t\t\t\t\t\t\t\t\t\t\t\t\t\tonFocus={() => {\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tsetActiveDate(dateStr);\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tsetOpenTooltipDate(dateStr);\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t}}\n\t\t\t\t\t\t\t\t\t\t\t\t\t\tonBlur={() => {\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tsetOpenTooltipDate((curr) => (curr === dateStr ? null : curr));\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t}}\n\t\t\t\t\t\t\t\t\t\t\t\t\t\tonKeyDown={(e) => handleCellKeyDown(e, dateStr)}\n\t\t\t\t\t\t\t\t\t\t\t\t\t\tclassName=\"box-border m-0 cursor-pointer rounded-sm border-0 p-0 transition-colors hover:ring-1 hover:ring-basalt-foreground focus-visible:outline-2 focus-visible:outline-offset-1 focus-visible:outline-basalt-ring\"\n\t\t\t\t\t\t\t\t\t\t\t\t\t\tstyle={{\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\twidth: cellSize,\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\theight: cellSize,\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tbackgroundColor: colorScale[colorIndex],\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t}}\n\t\t\t\t\t\t\t\t\t\t\t\t\t/>\n\t\t\t\t\t\t\t\t\t\t\t\t</TooltipTrigger>\n\t\t\t\t\t\t\t\t\t\t\t\t<TooltipContent id={`${calendarId}-${dateStr}`}>\n\t\t\t\t\t\t\t\t\t\t\t\t\t<div className=\"text-sm\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t<div className=\"font-medium\">{dateStr}</div>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t<div className=\"text-basalt-muted-foreground\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t{metricLabel}: {formattedValue}\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t\t\t\t\t\t\t</TooltipContent>\n\t\t\t\t\t\t\t\t\t\t\t</Tooltip>\n\t\t\t\t\t\t\t\t\t\t);\n\t\t\t\t\t\t\t\t\t})}\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</div>\n\t\t\t\t\t<div\n\t\t\t\t\t\tclassName=\"mt-2 flex items-center justify-end gap-1 text-xs text-basalt-muted-foreground select-none\"\n\t\t\t\t\t\taria-hidden=\"true\"\n\t\t\t\t\t>\n\t\t\t\t\t\t<span>{lessLabel}</span>\n\t\t\t\t\t\t{colorScale.map((color) => (\n\t\t\t\t\t\t\t<div\n\t\t\t\t\t\t\t\tkey={color}\n\t\t\t\t\t\t\t\tclassName=\"rounded-sm\"\n\t\t\t\t\t\t\t\tstyle={{\n\t\t\t\t\t\t\t\t\twidth: cellSize,\n\t\t\t\t\t\t\t\t\theight: cellSize,\n\t\t\t\t\t\t\t\t\tbackgroundColor: color,\n\t\t\t\t\t\t\t\t}}\n\t\t\t\t\t\t\t/>\n\t\t\t\t\t\t))}\n\t\t\t\t\t\t<span>{moreLabel}</span>\n\t\t\t\t\t</div>\n\t\t\t\t</div>\n\t\t\t</TooltipProvider>\n\t\t</div>\n\t);\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"heatmap-calendar.js","names":["heatmapColorScales","weekdayNames","locale","index","monthNames","getYearWeeks","weeks","startDate","year","endDate","firstDay","currentDate","currentWeek","formatDate","date","getColorIndex","value","levels","colorScale","normalized","maxValue","HeatmapCalendar","props","YearHeatmap","ValuesHeatmap","activeIdx","setActiveIdx","useState","openTooltipIdx","setOpenTooltipIdx","containerRef","useRef","cellRefs","isFocusedInsideRef","hadFocus","values","next","handleKeyDown","nextIdx","currentIndex","container","ariaLabel","cn","className","Tooltip","curr","TooltipTrigger","el","TooltipContent","TooltipProvider","weekdays","weekdayLabels","months","monthLabels","calendarId","useId","scrollRegionRef","useMemo","dataMap","point","data","labels","lastMonth","firstDayOfWeek","week","month","validDays","dateToValidIndex","dateStr","activeDate","setActiveDate","openTooltipDate","setOpenTooltipDate","isYearFocusedInsideRef","nextDate","selectedDate","navigateToDay","targetDate","handleCellKeyDown","currentIdx","nextDay","prevDay","targetIdx","label","cellSize","cellGap","day","dayIndex","colorIndex","isSelected","formattedValue","valueFormatter","labelText","metricLabel","weekIndex","lessLabel","color","moreLabel"],"sources":["../../src/charts/heatmap-calendar.tsx"],"sourcesContent":["import { type KeyboardEvent, useEffect, useId, useMemo, useRef, useState } from \"react\";\nimport { Tooltip, TooltipContent, TooltipProvider, TooltipTrigger } from \"../components/tooltip\";\nimport { cn } from \"../utils/cn\";\n\nexport type HeatmapDataPoint = { date: string; value: number };\n\nexport const heatmapColorScales = {\n\tgreen: [\n\t\t\"hsl(var(--basalt-muted))\",\n\t\t\"hsl(var(--basalt-heatmap-green-1))\",\n\t\t\"hsl(var(--basalt-heatmap-green-2))\",\n\t\t\"hsl(var(--basalt-heatmap-green-3))\",\n\t\t\"hsl(var(--basalt-heatmap-green-4))\",\n\t],\n\tred: [\n\t\t\"hsl(var(--basalt-muted))\",\n\t\t\"hsl(var(--basalt-heatmap-red-1))\",\n\t\t\"hsl(var(--basalt-heatmap-red-2))\",\n\t\t\"hsl(var(--basalt-heatmap-red-3))\",\n\t\t\"hsl(var(--basalt-heatmap-red-4))\",\n\t],\n\tblue: [\n\t\t\"hsl(var(--basalt-muted))\",\n\t\t\"hsl(var(--basalt-heatmap-blue-1))\",\n\t\t\"hsl(var(--basalt-heatmap-blue-2))\",\n\t\t\"hsl(var(--basalt-heatmap-blue-3))\",\n\t\t\"hsl(var(--basalt-heatmap-blue-4))\",\n\t],\n\torange: [\n\t\t\"hsl(var(--basalt-muted))\",\n\t\t\"hsl(var(--basalt-heatmap-orange-1))\",\n\t\t\"hsl(var(--basalt-heatmap-orange-2))\",\n\t\t\"hsl(var(--basalt-heatmap-orange-3))\",\n\t\t\"hsl(var(--basalt-heatmap-orange-4))\",\n\t],\n} as const;\n\nfunction weekdayNames(locale: string) {\n\treturn Array.from({ length: 7 }, (_, index) =>\n\t\tnew Intl.DateTimeFormat(locale, { weekday: \"short\" }).format(new Date(2023, 0, 1 + index)),\n\t);\n}\n\nfunction monthNames(locale: string) {\n\treturn Array.from({ length: 12 }, (_, index) =>\n\t\tnew Intl.DateTimeFormat(locale, { month: \"short\" }).format(new Date(2023, index, 1)),\n\t);\n}\n\nfunction getYearWeeks(year: number): Date[][] {\n\tconst weeks: Date[][] = [];\n\tconst startDate = new Date(year, 0, 1);\n\tconst endDate = new Date(year, 11, 31);\n\tconst firstDay = new Date(startDate);\n\tfirstDay.setDate(firstDay.getDate() - firstDay.getDay());\n\tlet currentDate = new Date(firstDay);\n\tlet currentWeek: Date[] = [];\n\twhile (currentDate <= endDate || currentWeek.length > 0) {\n\t\tif (currentWeek.length === 7) {\n\t\t\tweeks.push(currentWeek);\n\t\t\tcurrentWeek = [];\n\t\t}\n\t\tif (currentDate > endDate) {\n\t\t\tbreak;\n\t\t}\n\t\tcurrentWeek.push(new Date(currentDate));\n\t\tcurrentDate = new Date(currentDate);\n\t\tcurrentDate.setDate(currentDate.getDate() + 1);\n\t}\n\tif (currentWeek.length > 0) {\n\t\tweeks.push(currentWeek);\n\t}\n\treturn weeks;\n}\n\nfunction formatDate(date: Date): string {\n\tconst year = date.getFullYear();\n\tconst month = String(date.getMonth() + 1).padStart(2, \"0\");\n\tconst day = String(date.getDate()).padStart(2, \"0\");\n\treturn `${year}-${month}-${day}`;\n}\n\nfunction getColorIndex(value: number, maxValue: number, colorScale: readonly string[]): number {\n\tif (value === 0) {\n\t\treturn 0;\n\t}\n\tconst levels = colorScale.length - 1;\n\tconst normalized = Math.min(value / maxValue, 1);\n\treturn Math.ceil(normalized * levels);\n}\n\nexport type HeatmapCalendarValuesProps = {\n\t/**\n\t * Numeric values sequence to display in a compact 7-column grid.\n\t */\n\tvalues: number[];\n\t/**\n\t * Accessible name describing the heatmap purpose or data.\n\t * @default \"Heatmap calendar\"\n\t */\n\tariaLabel?: string;\n\t/**\n\t * Additional CSS class names for the outer container.\n\t */\n\tclassName?: string;\n};\n\nexport type HeatmapCalendarYearProps = {\n\t/**\n\t * Dataset of daily metrics with ISO date strings (\"YYYY-MM-DD\") and numeric values.\n\t */\n\tdata: HeatmapDataPoint[];\n\t/**\n\t * Calendar year to render.\n\t */\n\tyear: number;\n\t/**\n\t * Array of color values forming the intensity gradient from lowest to highest.\n\t * @default heatmapColorScales.green\n\t */\n\tcolorScale?: readonly string[];\n\t/**\n\t * Formatter for tooltip value display and accessible label.\n\t * @default (value) => value.toLocaleString()\n\t */\n\tvalueFormatter?: (value: number, date: string) => string;\n\t/**\n\t * Name of the metric for accessible labeling and tooltips.\n\t * @default \"Value\"\n\t */\n\tmetricLabel?: string;\n\t/**\n\t * Pixel width and height of each day cell.\n\t * @default 12\n\t */\n\tcellSize?: number;\n\t/**\n\t * Pixel gap between adjacent cells.\n\t * @default 2\n\t */\n\tcellGap?: number;\n\t/**\n\t * BCP 47 locale tag used for weekday and month label formatting.\n\t * @default \"en-US\"\n\t */\n\tlocale?: string;\n\t/**\n\t * Explicit custom weekday labels override.\n\t */\n\tweekdayLabels?: string[];\n\t/**\n\t * Explicit custom month labels override.\n\t */\n\tmonthLabels?: string[];\n\t/**\n\t * Label text for the lower end of the color scale legend.\n\t * @default \"Less\"\n\t */\n\tlessLabel?: string;\n\t/**\n\t * Label text for the upper end of the color scale legend.\n\t * @default \"More\"\n\t */\n\tmoreLabel?: string;\n\t/**\n\t * Accessible name describing the yearly heatmap dataset.\n\t * @default \"Heatmap calendar\"\n\t */\n\tariaLabel?: string;\n\t/**\n\t * Additional CSS class names for the outer scrollable container.\n\t */\n\tclassName?: string;\n};\n\nexport type HeatmapCalendarProps = HeatmapCalendarValuesProps | HeatmapCalendarYearProps;\n\nexport function HeatmapCalendar(props: HeatmapCalendarProps) {\n\tif (\"data\" in props) {\n\t\treturn <YearHeatmap {...props} />;\n\t}\n\treturn <ValuesHeatmap {...props} />;\n}\n\nfunction ValuesHeatmap({\n\tvalues,\n\tariaLabel = \"Heatmap calendar\",\n\tclassName,\n}: HeatmapCalendarValuesProps) {\n\tconst [activeIdx, setActiveIdx] = useState(0);\n\tconst [openTooltipIdx, setOpenTooltipIdx] = useState<number | null>(null);\n\tconst containerRef = useRef<HTMLDivElement | null>(null);\n\tconst cellRefs = useRef<(HTMLButtonElement | null)[]>([]);\n\tconst isFocusedInsideRef = useRef(false);\n\n\t// When values array shrinks, empties, or restores: if an item or container currently held focus,\n\t// restore focus to the new valid index or empty container without stealing focus from outside.\n\tuseEffect(() => {\n\t\tconst hadFocus = isFocusedInsideRef.current;\n\t\tif (values.length === 0) {\n\t\t\tsetActiveIdx(0);\n\t\t\tsetOpenTooltipIdx(null);\n\t\t\tif (hadFocus) {\n\t\t\t\tcontainerRef.current?.focus();\n\t\t\t}\n\t\t} else if (activeIdx >= values.length) {\n\t\t\tconst next = values.length - 1;\n\t\t\tsetActiveIdx(next);\n\t\t\tif (hadFocus) {\n\t\t\t\tcellRefs.current[next]?.focus();\n\t\t\t}\n\t\t} else if (hadFocus) {\n\t\t\tcellRefs.current[activeIdx]?.focus();\n\t\t}\n\t}, [values.length, activeIdx]);\n\n\tconst handleKeyDown = (e: KeyboardEvent<HTMLButtonElement>, currentIndex: number) => {\n\t\tif (values.length === 0) return;\n\n\t\tif (e.key === \"Escape\") {\n\t\t\tsetOpenTooltipIdx(null);\n\t\t\treturn;\n\t\t}\n\n\t\tlet nextIdx = currentIndex;\n\t\tif (e.key === \"ArrowRight\") {\n\t\t\tnextIdx = Math.min(values.length - 1, currentIndex + 1);\n\t\t} else if (e.key === \"ArrowLeft\") {\n\t\t\tnextIdx = Math.max(0, currentIndex - 1);\n\t\t} else if (e.key === \"ArrowDown\") {\n\t\t\tnextIdx = Math.min(values.length - 1, currentIndex + 7);\n\t\t} else if (e.key === \"ArrowUp\") {\n\t\t\tnextIdx = Math.max(0, currentIndex - 7);\n\t\t} else if (e.key === \"Home\") {\n\t\t\tnextIdx = 0;\n\t\t} else if (e.key === \"End\") {\n\t\t\tnextIdx = values.length - 1;\n\t\t} else {\n\t\t\treturn;\n\t\t}\n\n\t\te.preventDefault();\n\t\tsetActiveIdx(nextIdx);\n\t\tsetOpenTooltipIdx(nextIdx);\n\t\tcellRefs.current[nextIdx]?.focus();\n\t};\n\n\tconst container = (\n\t\t<div\n\t\t\tref={containerRef}\n\t\t\ttabIndex={-1}\n\t\t\trole=\"region\"\n\t\t\taria-label={ariaLabel}\n\t\t\tonFocus={() => {\n\t\t\t\tisFocusedInsideRef.current = true;\n\t\t\t}}\n\t\t\tonBlur={(e) => {\n\t\t\t\tif (!e.currentTarget.contains(e.relatedTarget)) {\n\t\t\t\t\tisFocusedInsideRef.current = false;\n\t\t\t\t}\n\t\t\t}}\n\t\t\tclassName={cn(\n\t\t\t\t\"grid grid-cols-7 gap-basalt-space-sm p-basalt-space-xs outline-none\",\n\t\t\t\tclassName,\n\t\t\t)}\n\t\t>\n\t\t\t{values.map((value, index) => {\n\t\t\t\tconst isCurrent = index === activeIdx;\n\t\t\t\tconst isOpen = openTooltipIdx === index;\n\t\t\t\treturn (\n\t\t\t\t\t<Tooltip\n\t\t\t\t\t\tkey={index}\n\t\t\t\t\t\topen={isOpen}\n\t\t\t\t\t\tonOpenChange={(next) => {\n\t\t\t\t\t\t\tif (next) {\n\t\t\t\t\t\t\t\tsetOpenTooltipIdx(index);\n\t\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\t\tsetOpenTooltipIdx((curr) => {\n\t\t\t\t\t\t\t\t\tif (curr !== index) return curr;\n\t\t\t\t\t\t\t\t\t// If this cell currently holds document focus, ignore scroll dismiss\n\t\t\t\t\t\t\t\t\tconst isCellFocused =\n\t\t\t\t\t\t\t\t\t\tcellRefs.current[index] !== null &&\n\t\t\t\t\t\t\t\t\t\tdocument.activeElement === cellRefs.current[index];\n\t\t\t\t\t\t\t\t\treturn isCellFocused ? curr : null;\n\t\t\t\t\t\t\t\t});\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}}\n\t\t\t\t\t>\n\t\t\t\t\t\t<TooltipTrigger asChild>\n\t\t\t\t\t\t\t<button\n\t\t\t\t\t\t\t\tref={(el) => {\n\t\t\t\t\t\t\t\t\tcellRefs.current[index] = el;\n\t\t\t\t\t\t\t\t}}\n\t\t\t\t\t\t\t\ttype=\"button\"\n\t\t\t\t\t\t\t\ttabIndex={isCurrent ? 0 : -1}\n\t\t\t\t\t\t\t\tonFocus={() => {\n\t\t\t\t\t\t\t\t\tsetActiveIdx(index);\n\t\t\t\t\t\t\t\t\tsetOpenTooltipIdx(index);\n\t\t\t\t\t\t\t\t}}\n\t\t\t\t\t\t\t\tonBlur={() => {\n\t\t\t\t\t\t\t\t\tsetOpenTooltipIdx((curr) => (curr === index ? null : curr));\n\t\t\t\t\t\t\t\t}}\n\t\t\t\t\t\t\t\tonKeyDown={(e) => handleKeyDown(e, index)}\n\t\t\t\t\t\t\t\taria-label={`Position ${index + 1}: ${value}`}\n\t\t\t\t\t\t\t\tclassName=\"box-border m-0 h-basalt-3 w-basalt-3 cursor-pointer rounded-basalt-sm border-0 p-0 transition-colors basalt-motion focus-visible:outline-2 focus-visible:outline-offset-1 focus-visible:outline-basalt-ring\"\n\t\t\t\t\t\t\t\tstyle={{\n\t\t\t\t\t\t\t\t\tbackgroundColor: `hsl(var(--basalt-chart-5) / ${0.2 + Math.min(4, Math.max(0, value)) * 0.15})`,\n\t\t\t\t\t\t\t\t}}\n\t\t\t\t\t\t\t/>\n\t\t\t\t\t\t</TooltipTrigger>\n\t\t\t\t\t\t<TooltipContent>\n\t\t\t\t\t\t\t<div className=\"text-basalt-sm\">\n\t\t\t\t\t\t\t\tPosition {index + 1}: {value}\n\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t</TooltipContent>\n\t\t\t\t\t</Tooltip>\n\t\t\t\t);\n\t\t\t})}\n\t\t</div>\n\t);\n\n\tif (values.length === 0) {\n\t\treturn container;\n\t}\n\n\treturn <TooltipProvider>{container}</TooltipProvider>;\n}\n\nfunction YearHeatmap({\n\tdata,\n\tyear,\n\tcolorScale = heatmapColorScales.green,\n\tvalueFormatter = (value) => value.toLocaleString(),\n\tmetricLabel = \"Value\",\n\tcellSize = 12,\n\tcellGap = 2,\n\tlocale = \"en-US\",\n\tweekdayLabels,\n\tmonthLabels,\n\tlessLabel = \"Less\",\n\tmoreLabel = \"More\",\n\tariaLabel = \"Heatmap calendar\",\n\tclassName,\n}: HeatmapCalendarYearProps) {\n\tconst weekdays = weekdayLabels ?? weekdayNames(locale);\n\tconst months = monthLabels ?? monthNames(locale);\n\tconst calendarId = useId();\n\tconst scrollRegionRef = useRef<HTMLDivElement | null>(null);\n\n\tconst { weeks, dataMap, maxValue, labels, validDays, dateToValidIndex } = useMemo(() => {\n\t\tconst weeks = getYearWeeks(year);\n\t\tconst dataMap = new Map<string, number>();\n\t\tlet maxValue = 0;\n\t\tfor (const point of data) {\n\t\t\tdataMap.set(point.date, point.value);\n\t\t\tif (point.value > maxValue) {\n\t\t\t\tmaxValue = point.value;\n\t\t\t}\n\t\t}\n\n\t\tconst labels: { month: string; weekIndex: number }[] = [];\n\t\tlet lastMonth = -1;\n\t\tweeks.forEach((week, weekIndex) => {\n\t\t\tconst firstDayOfWeek = week.find((date) => date.getFullYear() === year);\n\t\t\tif (firstDayOfWeek) {\n\t\t\t\tconst month = firstDayOfWeek.getMonth();\n\t\t\t\tif (month !== lastMonth) {\n\t\t\t\t\tlabels.push({ month: months[month], weekIndex });\n\t\t\t\t\tlastMonth = month;\n\t\t\t\t}\n\t\t\t}\n\t\t});\n\n\t\tconst validDays: string[] = [];\n\t\tconst dateToValidIndex = new Map<string, number>();\n\n\t\tweeks.forEach((week) => {\n\t\t\tweek.forEach((date) => {\n\t\t\t\tif (date.getFullYear() === year) {\n\t\t\t\t\tconst dateStr = formatDate(date);\n\t\t\t\t\tdateToValidIndex.set(dateStr, validDays.length);\n\t\t\t\t\tvalidDays.push(dateStr);\n\t\t\t\t}\n\t\t\t});\n\t\t});\n\n\t\treturn { weeks, dataMap, maxValue, labels, validDays, dateToValidIndex };\n\t}, [data, months, year]);\n\n\tconst [activeDate, setActiveDate] = useState<string>(() => {\n\t\treturn validDays[0] ?? `${year}-01-01`;\n\t});\n\tconst [openTooltipDate, setOpenTooltipDate] = useState<string | null>(null);\n\n\tconst cellRefs = useRef<Map<string, HTMLButtonElement>>(new Map());\n\tconst isYearFocusedInsideRef = useRef(false);\n\n\t// If year or validDays change: if a cell held focus, restore focus to the clamped\n\t// active date or scroll container; if focus was outside, do NOT steal focus.\n\tuseEffect(() => {\n\t\tconst hadFocus = isYearFocusedInsideRef.current;\n\t\tif (validDays.length === 0) {\n\t\t\tsetActiveDate(\"\");\n\t\t\tsetOpenTooltipDate(null);\n\t\t\tif (hadFocus) {\n\t\t\t\tscrollRegionRef.current?.focus();\n\t\t\t}\n\t\t} else if (!dateToValidIndex.has(activeDate)) {\n\t\t\tconst nextDate = validDays[0] ?? \"\";\n\t\t\tsetActiveDate(nextDate);\n\t\t\tif (hadFocus) {\n\t\t\t\tcellRefs.current.get(nextDate)?.focus();\n\t\t\t}\n\t\t}\n\t}, [validDays, dateToValidIndex, activeDate]);\n\n\tconst selectedDate = dateToValidIndex.has(activeDate) ? activeDate : validDays[0];\n\n\tconst navigateToDay = (targetDate: string | undefined) => {\n\t\tif (!targetDate) return;\n\t\tsetActiveDate(targetDate);\n\t\tsetOpenTooltipDate(targetDate);\n\t\tconst btn = cellRefs.current.get(targetDate);\n\t\tbtn?.focus();\n\t};\n\n\tconst handleCellKeyDown = (e: KeyboardEvent<HTMLButtonElement>, dateStr: string) => {\n\t\tif (validDays.length === 0) return;\n\n\t\tconst currentIdx = dateToValidIndex.get(dateStr) ?? 0;\n\n\t\tif (e.key === \"Escape\") {\n\t\t\tsetOpenTooltipDate(null);\n\t\t\treturn;\n\t\t}\n\n\t\tif (e.key === \"ArrowDown\") {\n\t\t\te.preventDefault();\n\t\t\t// Visually next day (down in the column)\n\t\t\tconst nextDay = validDays[currentIdx + 1];\n\t\t\tif (nextDay) {\n\t\t\t\tnavigateToDay(nextDay);\n\t\t\t}\n\t\t} else if (e.key === \"ArrowUp\") {\n\t\t\te.preventDefault();\n\t\t\t// Visually previous day (up in the column)\n\t\t\tconst prevDay = validDays[currentIdx - 1];\n\t\t\tif (prevDay) {\n\t\t\t\tnavigateToDay(prevDay);\n\t\t\t}\n\t\t} else if (e.key === \"ArrowRight\") {\n\t\t\te.preventDefault();\n\t\t\t// Visually next week (right in the row: +7 days by index)\n\t\t\tconst targetIdx = currentIdx + 7;\n\t\t\tif (targetIdx < validDays.length) {\n\t\t\t\tnavigateToDay(validDays[targetIdx]);\n\t\t\t} else {\n\t\t\t\tnavigateToDay(validDays[validDays.length - 1]);\n\t\t\t}\n\t\t} else if (e.key === \"ArrowLeft\") {\n\t\t\te.preventDefault();\n\t\t\t// Visually previous week (left in the row: -7 days by index)\n\t\t\tconst targetIdx = currentIdx - 7;\n\t\t\tif (targetIdx >= 0) {\n\t\t\t\tnavigateToDay(validDays[targetIdx]);\n\t\t\t} else {\n\t\t\t\tnavigateToDay(validDays[0]);\n\t\t\t}\n\t\t} else if (e.key === \"Home\") {\n\t\t\te.preventDefault();\n\t\t\tnavigateToDay(validDays[0]);\n\t\t} else if (e.key === \"End\") {\n\t\t\te.preventDefault();\n\t\t\tnavigateToDay(validDays[validDays.length - 1]);\n\t\t}\n\t};\n\n\tconst labelWidth = 30;\n\n\treturn (\n\t\t<div\n\t\t\tref={scrollRegionRef}\n\t\t\ttabIndex={-1}\n\t\t\trole=\"region\"\n\t\t\taria-label={`${ariaLabel} scrollable view`}\n\t\t\tonFocus={() => {\n\t\t\t\tisYearFocusedInsideRef.current = true;\n\t\t\t}}\n\t\t\tonBlur={(e) => {\n\t\t\t\tif (!e.currentTarget.contains(e.relatedTarget)) {\n\t\t\t\t\tisYearFocusedInsideRef.current = false;\n\t\t\t\t}\n\t\t\t}}\n\t\t\tclassName={cn(\n\t\t\t\t\"overflow-x-auto rounded-basalt-md outline-none focus-visible:ring-1 focus-visible:ring-basalt-ring\",\n\t\t\t\tclassName,\n\t\t\t)}\n\t\t>\n\t\t\t<TooltipProvider>\n\t\t\t\t<div className=\"inline-block p-basalt-space-sm\" role=\"group\" aria-label={ariaLabel}>\n\t\t\t\t\t<div\n\t\t\t\t\t\tclassName=\"relative mb-basalt-space-sm h-basalt-4 text-basalt-sm text-basalt-muted-foreground\"\n\t\t\t\t\t\tstyle={{ marginLeft: labelWidth }}\n\t\t\t\t\t>\n\t\t\t\t\t\t{labels.map((label) => (\n\t\t\t\t\t\t\t<div\n\t\t\t\t\t\t\t\tkey={`${label.month}-${label.weekIndex}`}\n\t\t\t\t\t\t\t\tclassName=\"absolute\"\n\t\t\t\t\t\t\t\tstyle={{ left: label.weekIndex * (cellSize + cellGap) }}\n\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t{label.month}\n\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t))}\n\t\t\t\t\t</div>\n\t\t\t\t\t<div className=\"flex\">\n\t\t\t\t\t\t<div\n\t\t\t\t\t\t\tclassName=\"mr-basalt-space-sm flex flex-col text-basalt-sm text-basalt-muted-foreground select-none\"\n\t\t\t\t\t\t\tstyle={{ width: labelWidth }}\n\t\t\t\t\t\t\taria-hidden=\"true\"\n\t\t\t\t\t\t>\n\t\t\t\t\t\t\t{weekdays.map((day, index) => (\n\t\t\t\t\t\t\t\t<div\n\t\t\t\t\t\t\t\t\tkey={`${day}-${index}`}\n\t\t\t\t\t\t\t\t\tstyle={{\n\t\t\t\t\t\t\t\t\t\theight: cellSize + cellGap,\n\t\t\t\t\t\t\t\t\t\tlineHeight: `${cellSize + cellGap}px`,\n\t\t\t\t\t\t\t\t\t\tvisibility: index % 2 === 1 ? \"visible\" : \"hidden\",\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{day}\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\t<div className=\"flex\" style={{ gap: cellGap }}>\n\t\t\t\t\t\t\t{weeks.map((week, weekIndex) => (\n\t\t\t\t\t\t\t\t<div key={weekIndex} className=\"flex flex-col\" style={{ gap: cellGap }}>\n\t\t\t\t\t\t\t\t\t{week.map((date, dayIndex) => {\n\t\t\t\t\t\t\t\t\t\tconst dateStr = formatDate(date);\n\t\t\t\t\t\t\t\t\t\tconst isCurrentYear = date.getFullYear() === year;\n\t\t\t\t\t\t\t\t\t\tif (!isCurrentYear) {\n\t\t\t\t\t\t\t\t\t\t\treturn (\n\t\t\t\t\t\t\t\t\t\t\t\t<div\n\t\t\t\t\t\t\t\t\t\t\t\t\tkey={dayIndex}\n\t\t\t\t\t\t\t\t\t\t\t\t\tstyle={{\n\t\t\t\t\t\t\t\t\t\t\t\t\t\twidth: cellSize,\n\t\t\t\t\t\t\t\t\t\t\t\t\t\theight: cellSize,\n\t\t\t\t\t\t\t\t\t\t\t\t\t\tvisibility: \"hidden\",\n\t\t\t\t\t\t\t\t\t\t\t\t\t}}\n\t\t\t\t\t\t\t\t\t\t\t\t\taria-hidden=\"true\"\n\t\t\t\t\t\t\t\t\t\t\t\t/>\n\t\t\t\t\t\t\t\t\t\t\t);\n\t\t\t\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\t\t\t\tconst value = dataMap.get(dateStr) ?? 0;\n\t\t\t\t\t\t\t\t\t\tconst colorIndex = getColorIndex(value, maxValue, colorScale);\n\t\t\t\t\t\t\t\t\t\tconst isSelected = selectedDate === dateStr;\n\t\t\t\t\t\t\t\t\t\tconst formattedValue = valueFormatter(value, dateStr);\n\t\t\t\t\t\t\t\t\t\tconst labelText = `${dateStr}, ${metricLabel}: ${formattedValue}`;\n\t\t\t\t\t\t\t\t\t\tconst isOpen = openTooltipDate === dateStr;\n\n\t\t\t\t\t\t\t\t\t\treturn (\n\t\t\t\t\t\t\t\t\t\t\t<Tooltip\n\t\t\t\t\t\t\t\t\t\t\t\tkey={dayIndex}\n\t\t\t\t\t\t\t\t\t\t\t\topen={isOpen}\n\t\t\t\t\t\t\t\t\t\t\t\tonOpenChange={(next) => {\n\t\t\t\t\t\t\t\t\t\t\t\t\tif (next) {\n\t\t\t\t\t\t\t\t\t\t\t\t\t\tsetOpenTooltipDate(dateStr);\n\t\t\t\t\t\t\t\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\t\t\t\t\t\t\t\tsetOpenTooltipDate((curr) => {\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tif (curr !== dateStr) return curr;\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t// If this cell currently holds document focus, ignore scroll dismiss\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tconst isCellFocused =\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tdocument.activeElement === cellRefs.current.get(dateStr);\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\treturn isCellFocused ? curr : null;\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t});\n\t\t\t\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t\t\t\t}}\n\t\t\t\t\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t\t\t\t\t<TooltipTrigger asChild>\n\t\t\t\t\t\t\t\t\t\t\t\t\t<button\n\t\t\t\t\t\t\t\t\t\t\t\t\t\tref={(el) => {\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tif (el) {\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tcellRefs.current.set(dateStr, el);\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tcellRefs.current.delete(dateStr);\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t}}\n\t\t\t\t\t\t\t\t\t\t\t\t\t\ttype=\"button\"\n\t\t\t\t\t\t\t\t\t\t\t\t\t\taria-label={labelText}\n\t\t\t\t\t\t\t\t\t\t\t\t\t\ttabIndex={isSelected ? 0 : -1}\n\t\t\t\t\t\t\t\t\t\t\t\t\t\tonFocus={() => {\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tsetActiveDate(dateStr);\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tsetOpenTooltipDate(dateStr);\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t}}\n\t\t\t\t\t\t\t\t\t\t\t\t\t\tonBlur={() => {\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tsetOpenTooltipDate((curr) => (curr === dateStr ? null : curr));\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t}}\n\t\t\t\t\t\t\t\t\t\t\t\t\t\tonKeyDown={(e) => handleCellKeyDown(e, dateStr)}\n\t\t\t\t\t\t\t\t\t\t\t\t\t\tclassName=\"box-border m-0 cursor-pointer rounded-basalt-sm border-0 p-0 transition-colors basalt-motion hover:ring-1 hover:ring-basalt-foreground focus-visible:outline-2 focus-visible:outline-offset-1 focus-visible:outline-basalt-ring\"\n\t\t\t\t\t\t\t\t\t\t\t\t\t\tstyle={{\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\twidth: cellSize,\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\theight: cellSize,\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tbackgroundColor: colorScale[colorIndex],\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t}}\n\t\t\t\t\t\t\t\t\t\t\t\t\t/>\n\t\t\t\t\t\t\t\t\t\t\t\t</TooltipTrigger>\n\t\t\t\t\t\t\t\t\t\t\t\t<TooltipContent id={`${calendarId}-${dateStr}`}>\n\t\t\t\t\t\t\t\t\t\t\t\t\t<div className=\"text-basalt-base\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t<div className=\"font-medium\">{dateStr}</div>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t<div className=\"text-basalt-muted-foreground\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t{metricLabel}: {formattedValue}\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t\t\t\t\t\t\t</TooltipContent>\n\t\t\t\t\t\t\t\t\t\t\t</Tooltip>\n\t\t\t\t\t\t\t\t\t\t);\n\t\t\t\t\t\t\t\t\t})}\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</div>\n\t\t\t\t\t<div\n\t\t\t\t\t\tclassName=\"mt-basalt-space-lg flex items-center justify-end gap-basalt-space-sm text-basalt-sm text-basalt-muted-foreground select-none\"\n\t\t\t\t\t\taria-hidden=\"true\"\n\t\t\t\t\t>\n\t\t\t\t\t\t<span>{lessLabel}</span>\n\t\t\t\t\t\t{colorScale.map((color) => (\n\t\t\t\t\t\t\t<div\n\t\t\t\t\t\t\t\tkey={color}\n\t\t\t\t\t\t\t\tclassName=\"rounded-basalt-sm\"\n\t\t\t\t\t\t\t\tstyle={{\n\t\t\t\t\t\t\t\t\twidth: cellSize,\n\t\t\t\t\t\t\t\t\theight: cellSize,\n\t\t\t\t\t\t\t\t\tbackgroundColor: color,\n\t\t\t\t\t\t\t\t}}\n\t\t\t\t\t\t\t/>\n\t\t\t\t\t\t))}\n\t\t\t\t\t\t<span>{moreLabel}</span>\n\t\t\t\t\t</div>\n\t\t\t\t</div>\n\t\t\t</TooltipProvider>\n\t\t</div>\n\t);\n}\n"],"mappings":"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"}
@@ -94,7 +94,7 @@ var _ = o(function({ rowLabels: o, columnLabels: _, values: v, domain: y, colorS
94
94
  role: "region",
95
95
  "aria-label": w,
96
96
  "data-testid": "heatmap-matrix",
97
- className: e("flex flex-col gap-2 rounded-lg border border-basalt-border/60 bg-basalt-card p-3 text-xs outline-none", $ ? "text-basalt-muted-foreground" : "text-basalt-foreground", A),
97
+ className: e("flex flex-col gap-basalt-space-lg rounded-basalt-md border border-basalt-border/60 bg-basalt-card p-basalt-space-lg text-basalt-sm outline-none", $ ? "text-basalt-muted-foreground" : "text-basalt-foreground", A),
98
98
  style: j,
99
99
  onFocus: re,
100
100
  onBlur: ie,
@@ -123,7 +123,7 @@ var _ = o(function({ rowLabels: o, columnLabels: _, values: v, domain: y, colorS
123
123
  })
124
124
  }), _.map((e, t) => /* @__PURE__ */ m("th", {
125
125
  scope: "col",
126
- className: "p-0 text-center font-mono text-[10px] text-basalt-muted-foreground select-none",
126
+ className: "p-0 text-center font-mono text-basalt-xs text-basalt-muted-foreground select-none",
127
127
  style: {
128
128
  width: B,
129
129
  maxWidth: B,
@@ -135,7 +135,7 @@ var _ = o(function({ rowLabels: o, columnLabels: _, values: v, domain: y, colorS
135
135
  children: e
136
136
  }, `${L}-col-${t}`))] }) }), /* @__PURE__ */ m("tbody", { children: o.map((e, r) => /* @__PURE__ */ h("tr", { children: [/* @__PURE__ */ m("th", {
137
137
  scope: "row",
138
- className: "sticky left-0 z-10 bg-basalt-card pr-2 text-left font-medium text-basalt-foreground select-none",
138
+ className: "sticky left-0 z-10 bg-basalt-card pr-basalt-space-lg text-left font-medium text-basalt-foreground select-none",
139
139
  style: {
140
140
  lineHeight: `${T}px`,
141
141
  minWidth: 64,
@@ -176,7 +176,7 @@ var _ = o(function({ rowLabels: o, columnLabels: _, values: v, domain: y, colorS
176
176
  onBlur: () => {
177
177
  K((e) => e === s ? null : e);
178
178
  },
179
- className: "box-border block cursor-pointer rounded-xs border-0 p-0 transition-colors hover:ring-1 hover:ring-basalt-foreground focus-visible:outline-2 focus-visible:outline-offset-1 focus-visible:outline-basalt-ring",
179
+ className: "box-border block cursor-pointer rounded-basalt-sm border-0 p-0 transition-colors basalt-motion hover:ring-1 hover:ring-basalt-foreground focus-visible:outline-2 focus-visible:outline-offset-1 focus-visible:outline-basalt-ring",
180
180
  style: {
181
181
  width: B,
182
182
  height: T,
@@ -189,7 +189,7 @@ var _ = o(function({ rowLabels: o, columnLabels: _, values: v, domain: y, colorS
189
189
  q.current = !0, K(null);
190
190
  },
191
191
  children: k ? k(w) : /* @__PURE__ */ h("div", {
192
- className: "text-xs",
192
+ className: "text-basalt-sm",
193
193
  children: [/* @__PURE__ */ h("div", {
194
194
  className: "font-semibold text-basalt-popover-foreground",
195
195
  children: [
@@ -216,12 +216,12 @@ var _ = o(function({ rowLabels: o, columnLabels: _, values: v, domain: y, colorS
216
216
  })] }, `${L}-row-${r}`)) })]
217
217
  })
218
218
  }), te ? /* @__PURE__ */ h("div", {
219
- className: "mt-1 flex items-center justify-end gap-1 text-[11px] text-basalt-muted-foreground select-none",
219
+ className: "mt-basalt-space-sm flex items-center justify-end gap-basalt-space-sm text-basalt-xs text-basalt-muted-foreground select-none",
220
220
  "aria-hidden": "true",
221
221
  children: [
222
222
  /* @__PURE__ */ m("span", { children: O }),
223
223
  /* @__PURE__ */ m("div", {
224
- className: "rounded-xs",
224
+ className: "rounded-basalt-sm",
225
225
  title: "Missing data",
226
226
  style: {
227
227
  width: T,
@@ -230,7 +230,7 @@ var _ = o(function({ rowLabels: o, columnLabels: _, values: v, domain: y, colorS
230
230
  }
231
231
  }),
232
232
  b.map((e, t) => /* @__PURE__ */ m("div", {
233
- className: "rounded-xs",
233
+ className: "rounded-basalt-sm",
234
234
  style: {
235
235
  width: T,
236
236
  height: T,
@@ -1 +1 @@
1
- {"version":3,"file":"heatmap-matrix.js","names":["_Fragment","Fragment$1","resolveColorIndex","value","colorScaleLength","levels","max","min","normalized","HeatmapMatrix","forwardRef","heatmapColorScales","val","rest","matrixId","useId","numRows","rowLabels","numCols","columnLabels","effectiveColWidth","columnWidth","cellSize","minVal","maxVal","useMemo","domain","d0","d1","lowest","highest","r","row","values","c","v","activePos","setActivePos","useState","openTooltipPos","setOpenTooltipPos","dismissedByEscapeRef","useRef","activePosRef","containerRef","cellRefs","isFocusedInsideRef","hadFocus","curR","curC","nextR","nextC","prev","key","target","handleContainerKeyDown","onKeyDown","currentRow","currentCol","nextKey","targetButton","scrollContainer","rowHeader","containerRect","btnRect","stickyWidth","visibleLeft","visibleRight","cellGap","handleContainerFocus","onFocus","handleContainerBlur","onBlur","callerCleanupRef","setRootRef","useCallback","node","ref","cleanup","isEmpty","TooltipProvider","ariaLabel","cn","className","missingLabel","col","colIdx","rowName","cellKey","rowIdx","rawVal","isMissing","colorIdx","colorScale","formattedVal","valueFormatter","cellBg","accessibleCellLabel","colName","metricLabel","isSelected","isOpen","cellContext","Tooltip","next","curr","TooltipTrigger","el","TooltipContent","renderTooltip","showLegend","lessLabel","color","idx","moreLabel"],"sources":["../../src/charts/heatmap-matrix.tsx"],"sourcesContent":["import {\n\ttype ComponentProps,\n\ttype FocusEvent,\n\tforwardRef,\n\ttype KeyboardEvent,\n\ttype ReactNode,\n\tuseCallback,\n\tuseEffect,\n\tuseId,\n\tuseMemo,\n\tuseRef,\n\tuseState,\n} from \"react\";\nimport { Tooltip, TooltipContent, TooltipProvider, TooltipTrigger } from \"../components/tooltip\";\nimport { cn } from \"../utils/cn\";\nimport { heatmapColorScales } from \"./heatmap-calendar\";\n\nexport type HeatmapMatrixValue = number | null | undefined;\n\nexport interface HeatmapMatrixCellContext {\n\trowIndex: number;\n\tcolIndex: number;\n\trowLabel: string;\n\tcolumnLabel: string;\n\tvalue: HeatmapMatrixValue;\n\tformattedValue: string;\n\tisMissing: boolean;\n\tcolorIndex: number;\n}\n\nexport interface HeatmapMatrixProps extends Omit<ComponentProps<\"div\">, \"children\"> {\n\t/**\n\t * Ordered row labels (e.g. weekdays [\"Mon\", \"Tue\", ...], service tiers, or regions).\n\t */\n\trowLabels: readonly string[];\n\t/**\n\t * Ordered column labels (e.g. 24 hours [\"00:00\", ...], days, or status buckets).\n\t */\n\tcolumnLabels: readonly string[];\n\t/**\n\t * 2D matrix of values indexed by [rowIndex][colIndex].\n\t * Supports ragged rows, null, undefined, and non-finite values (treated as missing).\n\t * Numeric `0` is a valid reading and distinct from missing data.\n\t */\n\tvalues: readonly (readonly HeatmapMatrixValue[])[];\n\t/**\n\t * Explicit [min, max] domain for color intensity scaling.\n\t * If reversed [max, min], bounds are automatically normalized to [min, max].\n\t * If equal [v, v], values <= v receive level 0 while values > v clamp to the highest level.\n\t * If non-finite or omitted, dynamically derived solely from visible finite numeric cells in the dataset (or [0, 0] if no finite values exist).\n\t * Values at or below min receive level 0; values >= max clamp to the highest level.\n\t */\n\tdomain?: readonly [min: number, max: number];\n\t/**\n\t * Sequential color palette array from lowest to highest intensity.\n\t * If empty or single-color, gracefully resolves to base level.\n\t * @default heatmapColorScales.green\n\t */\n\tcolorScale?: readonly string[];\n\t/**\n\t * Formatter for numeric values displayed in tooltips and accessible labels.\n\t * Defaults to `value.toLocaleString()`.\n\t */\n\tvalueFormatter?: (value: number) => string;\n\t/**\n\t * Placeholder string used for missing/null/undefined readings.\n\t * @default \"—\"\n\t */\n\tmissingLabel?: string;\n\t/**\n\t * Accessible label describing the matrix purpose or metric name.\n\t * @default \"Heatmap matrix\"\n\t */\n\tmetricLabel?: string;\n\t/**\n\t * Accessible name for the entire grid region.\n\t * @default \"Heatmap matrix\"\n\t */\n\tariaLabel?: string;\n\t/**\n\t * Pixel height (and default width) of each matrix data cell.\n\t * @default 16\n\t */\n\tcellSize?: number;\n\t/**\n\t * Pixel width of each matrix column / data cell.\n\t * When omitted, falls back to `cellSize` for square cells.\n\t * Allows wider rectangular cells to fit readable column headers (e.g. timestamps or service names).\n\t */\n\tcolumnWidth?: number;\n\t/**\n\t * Pixel gap between adjacent cells.\n\t * @default 2\n\t */\n\tcellGap?: number;\n\t/**\n\t * Text for lowest bound legend.\n\t * @default \"Less\"\n\t */\n\tlessLabel?: string;\n\t/**\n\t * Text for highest bound legend.\n\t * @default \"More\"\n\t */\n\tmoreLabel?: string;\n\t/**\n\t * Whether to show the bottom intensity scale legend.\n\t * @default true\n\t */\n\tshowLegend?: boolean;\n\t/**\n\t * Custom cell tooltip content renderer.\n\t * If provided, replaces the default tooltip contents.\n\t */\n\trenderTooltip?: (cell: HeatmapMatrixCellContext) => ReactNode;\n}\n\nfunction resolveColorIndex(\n\tvalue: HeatmapMatrixValue,\n\tmin: number,\n\tmax: number,\n\tcolorScaleLength: number,\n): number {\n\tif (value == null || typeof value !== \"number\" || !Number.isFinite(value)) {\n\t\treturn -1; // missing indicator\n\t}\n\tif (colorScaleLength <= 1) {\n\t\treturn 0;\n\t}\n\tconst levels = colorScaleLength - 1;\n\tif (max <= min) {\n\t\treturn value > min ? levels : 0;\n\t}\n\tconst clamped = Math.max(min, Math.min(max, value));\n\tconst normalized = (clamped - min) / (max - min);\n\tif (normalized <= 0) {\n\t\treturn 0;\n\t}\n\treturn Math.min(levels, Math.ceil(normalized * levels));\n}\n\nexport const HeatmapMatrix = forwardRef<HTMLDivElement, HeatmapMatrixProps>(function HeatmapMatrix(\n\t{\n\t\trowLabels,\n\t\tcolumnLabels,\n\t\tvalues,\n\t\tdomain,\n\t\tcolorScale = heatmapColorScales.green,\n\t\tvalueFormatter = (val) => val.toLocaleString(),\n\t\tmissingLabel = \"—\",\n\t\tmetricLabel = \"Heatmap matrix\",\n\t\tariaLabel = \"Heatmap matrix\",\n\t\tcellSize = 16,\n\t\tcolumnWidth,\n\t\tcellGap = 2,\n\t\tlessLabel = \"Less\",\n\t\tmoreLabel = \"More\",\n\t\tshowLegend = true,\n\t\trenderTooltip,\n\t\tclassName,\n\t\tstyle,\n\t\tonFocus,\n\t\tonBlur,\n\t\tonKeyDown,\n\t\t...rest\n\t},\n\tref,\n) {\n\tconst matrixId = useId();\n\tconst numRows = rowLabels.length;\n\tconst numCols = columnLabels.length;\n\tconst effectiveColWidth = columnWidth ?? cellSize;\n\n\t// Derive domain restricted to visible row/col matrix bounds\n\tconst [minVal, maxVal] = useMemo(() => {\n\t\tif (domain) {\n\t\t\tconst [d0, d1] = domain;\n\t\t\tif (Number.isFinite(d0) && Number.isFinite(d1)) {\n\t\t\t\treturn [Math.min(d0, d1), Math.max(d0, d1)];\n\t\t\t}\n\t\t}\n\t\tlet lowest = Number.POSITIVE_INFINITY;\n\t\tlet highest = Number.NEGATIVE_INFINITY;\n\t\tfor (let r = 0; r < numRows; r++) {\n\t\t\tconst row = values[r];\n\t\t\tif (!row) continue;\n\t\t\tfor (let c = 0; c < numCols; c++) {\n\t\t\t\tconst v = row[c];\n\t\t\t\tif (typeof v === \"number\" && Number.isFinite(v)) {\n\t\t\t\t\tif (v < lowest) lowest = v;\n\t\t\t\t\tif (v > highest) highest = v;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\tif (!Number.isFinite(lowest) || !Number.isFinite(highest)) {\n\t\t\treturn [0, 0];\n\t\t}\n\t\treturn [lowest, highest];\n\t}, [domain, values, numRows, numCols]);\n\n\t// Focus state: active cell position [rowIndex, colIndex]\n\tconst [activePos, setActivePos] = useState<[number, number]>([0, 0]);\n\tconst [openTooltipPos, setOpenTooltipPos] = useState<string | null>(null);\n\tconst dismissedByEscapeRef = useRef(false);\n\n\tconst activePosRef = useRef<[number, number]>([0, 0]);\n\tactivePosRef.current = activePos;\n\n\tconst containerRef = useRef<HTMLDivElement | null>(null);\n\tconst cellRefs = useRef<Map<string, HTMLButtonElement>>(new Map());\n\tconst isFocusedInsideRef = useRef(false);\n\n\t// Clamp active position when dimensions change\n\tuseEffect(() => {\n\t\tconst hadFocus = isFocusedInsideRef.current;\n\t\tif (numRows === 0 || numCols === 0) {\n\t\t\tsetActivePos(([curR, curC]) => {\n\t\t\t\tif (curR === 0 && curC === 0) return [curR, curC];\n\t\t\t\treturn [0, 0];\n\t\t\t});\n\t\t\tsetOpenTooltipPos(null);\n\t\t\tif (hadFocus) {\n\t\t\t\tcontainerRef.current?.focus();\n\t\t\t}\n\t\t\treturn;\n\t\t}\n\n\t\tconst [curR, curC] = activePosRef.current;\n\t\tconst nextR = Math.min(numRows - 1, Math.max(0, curR));\n\t\tconst nextC = Math.min(numCols - 1, Math.max(0, curC));\n\n\t\tsetActivePos((prev) => {\n\t\t\tif (prev[0] === nextR && prev[1] === nextC) {\n\t\t\t\treturn prev;\n\t\t\t}\n\t\t\treturn [nextR, nextC];\n\t\t});\n\n\t\tif (hadFocus) {\n\t\t\tconst key = `${nextR}-${nextC}`;\n\t\t\tconst target = cellRefs.current.get(key);\n\t\t\tif (target && document.activeElement !== target) {\n\t\t\t\ttarget.focus();\n\t\t\t}\n\t\t}\n\t}, [numRows, numCols]);\n\n\tconst handleContainerKeyDown = (e: KeyboardEvent<HTMLDivElement>) => {\n\t\tif (e.key === \"Escape\") {\n\t\t\tdismissedByEscapeRef.current = true;\n\t\t\tsetOpenTooltipPos(null);\n\t\t}\n\n\t\t// Call caller onKeyDown first so caller can inspect or preventDefault\n\t\tonKeyDown?.(e);\n\t\tif (e.defaultPrevented) {\n\t\t\treturn;\n\t\t}\n\n\t\tif (numRows === 0 || numCols === 0) return;\n\t\tif (e.key === \"Escape\") return;\n\n\t\tconst [currentRow, currentCol] = activePosRef.current;\n\t\tlet nextR = currentRow;\n\t\tlet nextC = currentCol;\n\n\t\tif (e.key === \"ArrowRight\") {\n\t\t\tnextC = Math.min(numCols - 1, currentCol + 1);\n\t\t} else if (e.key === \"ArrowLeft\") {\n\t\t\tnextC = Math.max(0, currentCol - 1);\n\t\t} else if (e.key === \"ArrowDown\") {\n\t\t\tnextR = Math.min(numRows - 1, currentRow + 1);\n\t\t} else if (e.key === \"ArrowUp\") {\n\t\t\tnextR = Math.max(0, currentRow - 1);\n\t\t} else if (e.key === \"Home\") {\n\t\t\tnextC = 0;\n\t\t} else if (e.key === \"End\") {\n\t\t\tnextC = numCols - 1;\n\t\t} else if (e.key === \"PageUp\") {\n\t\t\tnextR = 0;\n\t\t} else if (e.key === \"PageDown\") {\n\t\t\tnextR = numRows - 1;\n\t\t} else {\n\t\t\treturn;\n\t\t}\n\n\t\te.preventDefault();\n\t\tdismissedByEscapeRef.current = false;\n\t\tsetActivePos([nextR, nextC]);\n\t\tconst nextKey = `${nextR}-${nextC}`;\n\t\tsetOpenTooltipPos(nextKey);\n\t\tconst targetButton = cellRefs.current.get(nextKey);\n\t\tif (targetButton) {\n\t\t\ttargetButton.focus();\n\t\t\tconst scrollContainer = targetButton.closest<HTMLElement>(\n\t\t\t\t'[role=\"region\"][aria-label$=\"scrollable table\"]',\n\t\t\t);\n\t\t\tconst rowHeader = targetButton.closest(\"tr\")?.querySelector<HTMLElement>('th[scope=\"row\"]');\n\n\t\t\tif (scrollContainer) {\n\t\t\t\tconst containerRect = scrollContainer.getBoundingClientRect();\n\t\t\t\tconst btnRect = targetButton.getBoundingClientRect();\n\t\t\t\tconst stickyWidth = rowHeader ? rowHeader.getBoundingClientRect().width : 0;\n\n\t\t\t\tconst visibleLeft = containerRect.left + stickyWidth;\n\t\t\t\tconst visibleRight = containerRect.right;\n\n\t\t\t\tif (btnRect.left < visibleLeft) {\n\t\t\t\t\tscrollContainer.scrollLeft -= visibleLeft - btnRect.left + cellGap;\n\t\t\t\t} else if (btnRect.right > visibleRight) {\n\t\t\t\t\tscrollContainer.scrollLeft += btnRect.right - visibleRight + cellGap;\n\t\t\t\t}\n\t\t\t} else if (typeof targetButton.scrollIntoView === \"function\") {\n\t\t\t\ttargetButton.scrollIntoView({ block: \"nearest\", inline: \"nearest\" });\n\t\t\t}\n\t\t}\n\t};\n\n\tconst handleContainerFocus = (e: FocusEvent<HTMLDivElement>) => {\n\t\tisFocusedInsideRef.current = true;\n\t\tonFocus?.(e);\n\t};\n\n\tconst handleContainerBlur = (e: FocusEvent<HTMLDivElement>) => {\n\t\tif (!e.currentTarget.contains(e.relatedTarget)) {\n\t\t\tisFocusedInsideRef.current = false;\n\t\t\tdismissedByEscapeRef.current = false;\n\t\t}\n\t\tonBlur?.(e);\n\t};\n\n\tconst callerCleanupRef = useRef<(() => void) | undefined>(undefined);\n\n\tconst setRootRef = useCallback(\n\t\t(node: HTMLDivElement | null) => {\n\t\t\tcontainerRef.current = node;\n\n\t\t\tif (callerCleanupRef.current) {\n\t\t\t\tcallerCleanupRef.current();\n\t\t\t\tcallerCleanupRef.current = undefined;\n\t\t\t}\n\n\t\t\tif (typeof ref === \"function\") {\n\t\t\t\tconst cleanup = ref(node);\n\t\t\t\tif (typeof cleanup === \"function\") {\n\t\t\t\t\tcallerCleanupRef.current = cleanup;\n\t\t\t\t}\n\t\t\t} else if (ref) {\n\t\t\t\tref.current = node;\n\t\t\t}\n\n\t\t\treturn () => {\n\t\t\t\tcontainerRef.current = null;\n\t\t\t\tif (callerCleanupRef.current) {\n\t\t\t\t\tcallerCleanupRef.current();\n\t\t\t\t\tcallerCleanupRef.current = undefined;\n\t\t\t\t} else if (typeof ref === \"function\") {\n\t\t\t\t\tref(null);\n\t\t\t\t} else if (ref) {\n\t\t\t\t\tref.current = null;\n\t\t\t\t}\n\t\t\t};\n\t\t},\n\t\t[ref],\n\t);\n\n\tconst isEmpty = numRows === 0 || numCols === 0;\n\n\treturn (\n\t\t<TooltipProvider>\n\t\t\t<div\n\t\t\t\tref={setRootRef}\n\t\t\t\ttabIndex={isEmpty ? -1 : undefined}\n\t\t\t\trole=\"region\"\n\t\t\t\taria-label={ariaLabel}\n\t\t\t\tdata-testid=\"heatmap-matrix\"\n\t\t\t\tclassName={cn(\n\t\t\t\t\t\"flex flex-col gap-2 rounded-lg border border-basalt-border/60 bg-basalt-card p-3 text-xs outline-none\",\n\t\t\t\t\tisEmpty ? \"text-basalt-muted-foreground\" : \"text-basalt-foreground\",\n\t\t\t\t\tclassName,\n\t\t\t\t)}\n\t\t\t\tstyle={style}\n\t\t\t\tonFocus={handleContainerFocus}\n\t\t\t\tonBlur={handleContainerBlur}\n\t\t\t\tonKeyDown={handleContainerKeyDown}\n\t\t\t\t{...rest}\n\t\t\t>\n\t\t\t\t{isEmpty ? (\n\t\t\t\t\t<span className=\"italic\">{missingLabel}</span>\n\t\t\t\t) : (\n\t\t\t\t\t<>\n\t\t\t\t\t\t{/* Scrollable table container */}\n\t\t\t\t\t\t<div\n\t\t\t\t\t\t\ttabIndex={-1}\n\t\t\t\t\t\t\trole=\"region\"\n\t\t\t\t\t\t\taria-label={`${ariaLabel} scrollable table`}\n\t\t\t\t\t\t\tclassName=\"w-full overflow-x-auto outline-none\"\n\t\t\t\t\t\t>\n\t\t\t\t\t\t\t<table\n\t\t\t\t\t\t\t\t// biome-ignore lint/a11y/noNoninteractiveElementToInteractiveRole: W3C ARIA interactive 2D grid table with descendant roving tab buttons\n\t\t\t\t\t\t\t\trole=\"grid\"\n\t\t\t\t\t\t\t\taria-label={ariaLabel}\n\t\t\t\t\t\t\t\tclassName=\"border-separate\"\n\t\t\t\t\t\t\t\tstyle={{ borderSpacing: cellGap }}\n\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t<thead>\n\t\t\t\t\t\t\t\t\t<tr>\n\t\t\t\t\t\t\t\t\t\t{/* Top-left empty header */}\n\t\t\t\t\t\t\t\t\t\t<th\n\t\t\t\t\t\t\t\t\t\t\tscope=\"col\"\n\t\t\t\t\t\t\t\t\t\t\tclassName=\"sticky left-0 z-10 bg-basalt-card p-0 text-left font-normal\"\n\t\t\t\t\t\t\t\t\t\t\tstyle={{ minWidth: 64 }}\n\t\t\t\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t\t\t\t<span className=\"sr-only\">Row \\ Column</span>\n\t\t\t\t\t\t\t\t\t\t</th>\n\t\t\t\t\t\t\t\t\t\t{columnLabels.map((col, colIdx) => (\n\t\t\t\t\t\t\t\t\t\t\t<th\n\t\t\t\t\t\t\t\t\t\t\t\tkey={`${matrixId}-col-${colIdx}`}\n\t\t\t\t\t\t\t\t\t\t\t\tscope=\"col\"\n\t\t\t\t\t\t\t\t\t\t\t\tclassName=\"p-0 text-center font-mono text-[10px] text-basalt-muted-foreground select-none\"\n\t\t\t\t\t\t\t\t\t\t\t\tstyle={{\n\t\t\t\t\t\t\t\t\t\t\t\t\twidth: effectiveColWidth,\n\t\t\t\t\t\t\t\t\t\t\t\t\tmaxWidth: effectiveColWidth,\n\t\t\t\t\t\t\t\t\t\t\t\t\toverflow: \"hidden\",\n\t\t\t\t\t\t\t\t\t\t\t\t\ttextOverflow: \"ellipsis\",\n\t\t\t\t\t\t\t\t\t\t\t\t\twhiteSpace: \"nowrap\",\n\t\t\t\t\t\t\t\t\t\t\t\t}}\n\t\t\t\t\t\t\t\t\t\t\t\ttitle={col}\n\t\t\t\t\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t\t\t\t\t{col}\n\t\t\t\t\t\t\t\t\t\t\t</th>\n\t\t\t\t\t\t\t\t\t\t))}\n\t\t\t\t\t\t\t\t\t</tr>\n\t\t\t\t\t\t\t\t</thead>\n\t\t\t\t\t\t\t\t<tbody>\n\t\t\t\t\t\t\t\t\t{rowLabels.map((rowName, rowIdx) => (\n\t\t\t\t\t\t\t\t\t\t<tr key={`${matrixId}-row-${rowIdx}`}>\n\t\t\t\t\t\t\t\t\t\t\t<th\n\t\t\t\t\t\t\t\t\t\t\t\tscope=\"row\"\n\t\t\t\t\t\t\t\t\t\t\t\tclassName=\"sticky left-0 z-10 bg-basalt-card pr-2 text-left font-medium text-basalt-foreground select-none\"\n\t\t\t\t\t\t\t\t\t\t\t\tstyle={{\n\t\t\t\t\t\t\t\t\t\t\t\t\tlineHeight: `${cellSize}px`,\n\t\t\t\t\t\t\t\t\t\t\t\t\tminWidth: 64,\n\t\t\t\t\t\t\t\t\t\t\t\t\twhiteSpace: \"nowrap\",\n\t\t\t\t\t\t\t\t\t\t\t\t}}\n\t\t\t\t\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t\t\t\t\t{rowName}\n\t\t\t\t\t\t\t\t\t\t\t</th>\n\t\t\t\t\t\t\t\t\t\t\t{columnLabels.map((colName, colIdx) => {\n\t\t\t\t\t\t\t\t\t\t\t\tconst cellKey = `${rowIdx}-${colIdx}`;\n\t\t\t\t\t\t\t\t\t\t\t\tconst rawVal = values[rowIdx]?.[colIdx];\n\t\t\t\t\t\t\t\t\t\t\t\tconst isMissing =\n\t\t\t\t\t\t\t\t\t\t\t\t\trawVal == null || typeof rawVal !== \"number\" || !Number.isFinite(rawVal);\n\t\t\t\t\t\t\t\t\t\t\t\tconst colorIdx = resolveColorIndex(\n\t\t\t\t\t\t\t\t\t\t\t\t\trawVal,\n\t\t\t\t\t\t\t\t\t\t\t\t\tminVal,\n\t\t\t\t\t\t\t\t\t\t\t\t\tmaxVal,\n\t\t\t\t\t\t\t\t\t\t\t\t\tcolorScale.length,\n\t\t\t\t\t\t\t\t\t\t\t\t);\n\n\t\t\t\t\t\t\t\t\t\t\t\tconst formattedVal = isMissing\n\t\t\t\t\t\t\t\t\t\t\t\t\t? missingLabel\n\t\t\t\t\t\t\t\t\t\t\t\t\t: valueFormatter(rawVal as number);\n\n\t\t\t\t\t\t\t\t\t\t\t\tconst cellBg =\n\t\t\t\t\t\t\t\t\t\t\t\t\tcolorIdx < 0\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t? \"hsl(var(--basalt-muted) / 0.4)\"\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t: (colorScale[colorIdx] ?? \"hsl(var(--basalt-muted))\");\n\n\t\t\t\t\t\t\t\t\t\t\t\tconst accessibleCellLabel = `${rowName}, ${colName}: ${formattedVal} (${metricLabel})`;\n\t\t\t\t\t\t\t\t\t\t\t\tconst isSelected = activePos[0] === rowIdx && activePos[1] === colIdx;\n\t\t\t\t\t\t\t\t\t\t\t\tconst isOpen = openTooltipPos === cellKey;\n\n\t\t\t\t\t\t\t\t\t\t\t\tconst cellContext: HeatmapMatrixCellContext = {\n\t\t\t\t\t\t\t\t\t\t\t\t\trowIndex: rowIdx,\n\t\t\t\t\t\t\t\t\t\t\t\t\tcolIndex: colIdx,\n\t\t\t\t\t\t\t\t\t\t\t\t\trowLabel: rowName,\n\t\t\t\t\t\t\t\t\t\t\t\t\tcolumnLabel: colName,\n\t\t\t\t\t\t\t\t\t\t\t\t\tvalue: rawVal,\n\t\t\t\t\t\t\t\t\t\t\t\t\tformattedValue: formattedVal,\n\t\t\t\t\t\t\t\t\t\t\t\t\tisMissing,\n\t\t\t\t\t\t\t\t\t\t\t\t\tcolorIndex: colorIdx,\n\t\t\t\t\t\t\t\t\t\t\t\t};\n\n\t\t\t\t\t\t\t\t\t\t\t\treturn (\n\t\t\t\t\t\t\t\t\t\t\t\t\t// biome-ignore lint/a11y/noNoninteractiveElementToInteractiveRole: ARIA gridcell container wrapping roving interactive button\n\t\t\t\t\t\t\t\t\t\t\t\t\t// biome-ignore lint/a11y/useFocusableInteractive: Focus is managed on child button via roving tabindex\n\t\t\t\t\t\t\t\t\t\t\t\t\t<td key={cellKey} role=\"gridcell\" className=\"p-0 text-center\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t<Tooltip\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\topen={isOpen}\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tonOpenChange={(next) => {\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tif (next) {\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tif (!dismissedByEscapeRef.current) {\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tsetOpenTooltipPos(cellKey);\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tsetOpenTooltipPos((curr) => {\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tif (curr !== cellKey) return curr;\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tif (dismissedByEscapeRef.current) return null;\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tconst isCellFocused =\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tdocument.activeElement === cellRefs.current.get(cellKey);\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\treturn isCellFocused ? curr : null;\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t});\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t}}\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<TooltipTrigger asChild>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<button\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tref={(el) => {\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tif (el) cellRefs.current.set(cellKey, el);\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\telse cellRefs.current.delete(cellKey);\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t}}\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\ttype=\"button\"\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\taria-label={accessibleCellLabel}\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\ttabIndex={isSelected ? 0 : -1}\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tonFocus={() => {\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tsetActivePos([rowIdx, colIdx]);\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tdismissedByEscapeRef.current = false;\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tsetOpenTooltipPos(cellKey);\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t}}\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tonBlur={() => {\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tsetOpenTooltipPos((curr) => (curr === cellKey ? null : curr));\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t}}\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tclassName=\"box-border block cursor-pointer rounded-xs border-0 p-0 transition-colors hover:ring-1 hover:ring-basalt-foreground focus-visible:outline-2 focus-visible:outline-offset-1 focus-visible:outline-basalt-ring\"\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tstyle={{\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\twidth: effectiveColWidth,\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\theight: cellSize,\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tbackgroundColor: cellBg,\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t}}\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t/>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</TooltipTrigger>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<TooltipContent\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tid={`${matrixId}-${cellKey}`}\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tonEscapeKeyDown={() => {\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tdismissedByEscapeRef.current = true;\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tsetOpenTooltipPos(null);\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t}}\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t{renderTooltip ? (\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\trenderTooltip(cellContext)\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t) : (\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<div className=\"text-xs\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<div className=\"font-semibold text-basalt-popover-foreground\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t{rowName} · {colName}\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<div className=\"text-basalt-muted-foreground\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t{metricLabel}:{\" \"}\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<span className=\"font-medium text-basalt-popover-foreground\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t{formattedVal}\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</span>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t)}\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</TooltipContent>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t</Tooltip>\n\t\t\t\t\t\t\t\t\t\t\t\t\t</td>\n\t\t\t\t\t\t\t\t\t\t\t\t);\n\t\t\t\t\t\t\t\t\t\t\t})}\n\t\t\t\t\t\t\t\t\t\t</tr>\n\t\t\t\t\t\t\t\t\t))}\n\t\t\t\t\t\t\t\t</tbody>\n\t\t\t\t\t\t\t</table>\n\t\t\t\t\t\t</div>\n\n\t\t\t\t\t\t{/* Legend footer */}\n\t\t\t\t\t\t{showLegend ? (\n\t\t\t\t\t\t\t<div\n\t\t\t\t\t\t\t\tclassName=\"mt-1 flex items-center justify-end gap-1 text-[11px] text-basalt-muted-foreground select-none\"\n\t\t\t\t\t\t\t\taria-hidden=\"true\"\n\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t<span>{lessLabel}</span>\n\t\t\t\t\t\t\t\t<div\n\t\t\t\t\t\t\t\t\tclassName=\"rounded-xs\"\n\t\t\t\t\t\t\t\t\ttitle=\"Missing data\"\n\t\t\t\t\t\t\t\t\tstyle={{\n\t\t\t\t\t\t\t\t\t\twidth: cellSize,\n\t\t\t\t\t\t\t\t\t\theight: cellSize,\n\t\t\t\t\t\t\t\t\t\tbackgroundColor: \"hsl(var(--basalt-muted) / 0.4)\",\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{colorScale.map((color, idx) => (\n\t\t\t\t\t\t\t\t\t<div\n\t\t\t\t\t\t\t\t\t\tkey={`${color}-${idx}`}\n\t\t\t\t\t\t\t\t\t\tclassName=\"rounded-xs\"\n\t\t\t\t\t\t\t\t\t\tstyle={{\n\t\t\t\t\t\t\t\t\t\t\twidth: cellSize,\n\t\t\t\t\t\t\t\t\t\t\theight: cellSize,\n\t\t\t\t\t\t\t\t\t\t\tbackgroundColor: color,\n\t\t\t\t\t\t\t\t\t\t}}\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<span>{moreLabel}</span>\n\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t) : null}\n\t\t\t\t\t</>\n\t\t\t\t)}\n\t\t\t</div>\n\t\t</TooltipProvider>\n\t);\n});\n\nHeatmapMatrix.displayName = \"HeatmapMatrix\";\n"],"mappings":"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"}
1
+ {"version":3,"file":"heatmap-matrix.js","names":["_Fragment","Fragment$1","resolveColorIndex","value","colorScaleLength","levels","max","min","normalized","HeatmapMatrix","forwardRef","heatmapColorScales","val","rest","matrixId","useId","numRows","rowLabels","numCols","columnLabels","effectiveColWidth","columnWidth","cellSize","minVal","maxVal","useMemo","domain","d0","d1","lowest","highest","r","row","values","c","v","activePos","setActivePos","useState","openTooltipPos","setOpenTooltipPos","dismissedByEscapeRef","useRef","activePosRef","containerRef","cellRefs","isFocusedInsideRef","hadFocus","curR","curC","nextR","nextC","prev","key","target","handleContainerKeyDown","onKeyDown","currentRow","currentCol","nextKey","targetButton","scrollContainer","rowHeader","containerRect","btnRect","stickyWidth","visibleLeft","visibleRight","cellGap","handleContainerFocus","onFocus","handleContainerBlur","onBlur","callerCleanupRef","setRootRef","useCallback","node","ref","cleanup","isEmpty","TooltipProvider","ariaLabel","cn","className","missingLabel","col","colIdx","rowName","cellKey","rowIdx","rawVal","isMissing","colorIdx","colorScale","formattedVal","valueFormatter","cellBg","accessibleCellLabel","colName","metricLabel","isSelected","isOpen","cellContext","Tooltip","next","curr","TooltipTrigger","el","TooltipContent","renderTooltip","showLegend","lessLabel","color","idx","moreLabel"],"sources":["../../src/charts/heatmap-matrix.tsx"],"sourcesContent":["import {\n\ttype ComponentProps,\n\ttype FocusEvent,\n\tforwardRef,\n\ttype KeyboardEvent,\n\ttype ReactNode,\n\tuseCallback,\n\tuseEffect,\n\tuseId,\n\tuseMemo,\n\tuseRef,\n\tuseState,\n} from \"react\";\nimport { Tooltip, TooltipContent, TooltipProvider, TooltipTrigger } from \"../components/tooltip\";\nimport { cn } from \"../utils/cn\";\nimport { heatmapColorScales } from \"./heatmap-calendar\";\n\nexport type HeatmapMatrixValue = number | null | undefined;\n\nexport interface HeatmapMatrixCellContext {\n\trowIndex: number;\n\tcolIndex: number;\n\trowLabel: string;\n\tcolumnLabel: string;\n\tvalue: HeatmapMatrixValue;\n\tformattedValue: string;\n\tisMissing: boolean;\n\tcolorIndex: number;\n}\n\nexport interface HeatmapMatrixProps extends Omit<ComponentProps<\"div\">, \"children\"> {\n\t/**\n\t * Ordered row labels (e.g. weekdays [\"Mon\", \"Tue\", ...], service tiers, or regions).\n\t */\n\trowLabels: readonly string[];\n\t/**\n\t * Ordered column labels (e.g. 24 hours [\"00:00\", ...], days, or status buckets).\n\t */\n\tcolumnLabels: readonly string[];\n\t/**\n\t * 2D matrix of values indexed by [rowIndex][colIndex].\n\t * Supports ragged rows, null, undefined, and non-finite values (treated as missing).\n\t * Numeric `0` is a valid reading and distinct from missing data.\n\t */\n\tvalues: readonly (readonly HeatmapMatrixValue[])[];\n\t/**\n\t * Explicit [min, max] domain for color intensity scaling.\n\t * If reversed [max, min], bounds are automatically normalized to [min, max].\n\t * If equal [v, v], values <= v receive level 0 while values > v clamp to the highest level.\n\t * If non-finite or omitted, dynamically derived solely from visible finite numeric cells in the dataset (or [0, 0] if no finite values exist).\n\t * Values at or below min receive level 0; values >= max clamp to the highest level.\n\t */\n\tdomain?: readonly [min: number, max: number];\n\t/**\n\t * Sequential color palette array from lowest to highest intensity.\n\t * If empty or single-color, gracefully resolves to base level.\n\t * @default heatmapColorScales.green\n\t */\n\tcolorScale?: readonly string[];\n\t/**\n\t * Formatter for numeric values displayed in tooltips and accessible labels.\n\t * Defaults to `value.toLocaleString()`.\n\t */\n\tvalueFormatter?: (value: number) => string;\n\t/**\n\t * Placeholder string used for missing/null/undefined readings.\n\t * @default \"—\"\n\t */\n\tmissingLabel?: string;\n\t/**\n\t * Accessible label describing the matrix purpose or metric name.\n\t * @default \"Heatmap matrix\"\n\t */\n\tmetricLabel?: string;\n\t/**\n\t * Accessible name for the entire grid region.\n\t * @default \"Heatmap matrix\"\n\t */\n\tariaLabel?: string;\n\t/**\n\t * Pixel height (and default width) of each matrix data cell.\n\t * @default 16\n\t */\n\tcellSize?: number;\n\t/**\n\t * Pixel width of each matrix column / data cell.\n\t * When omitted, falls back to `cellSize` for square cells.\n\t * Allows wider rectangular cells to fit readable column headers (e.g. timestamps or service names).\n\t */\n\tcolumnWidth?: number;\n\t/**\n\t * Pixel gap between adjacent cells.\n\t * @default 2\n\t */\n\tcellGap?: number;\n\t/**\n\t * Text for lowest bound legend.\n\t * @default \"Less\"\n\t */\n\tlessLabel?: string;\n\t/**\n\t * Text for highest bound legend.\n\t * @default \"More\"\n\t */\n\tmoreLabel?: string;\n\t/**\n\t * Whether to show the bottom intensity scale legend.\n\t * @default true\n\t */\n\tshowLegend?: boolean;\n\t/**\n\t * Custom cell tooltip content renderer.\n\t * If provided, replaces the default tooltip contents.\n\t */\n\trenderTooltip?: (cell: HeatmapMatrixCellContext) => ReactNode;\n}\n\nfunction resolveColorIndex(\n\tvalue: HeatmapMatrixValue,\n\tmin: number,\n\tmax: number,\n\tcolorScaleLength: number,\n): number {\n\tif (value == null || typeof value !== \"number\" || !Number.isFinite(value)) {\n\t\treturn -1; // missing indicator\n\t}\n\tif (colorScaleLength <= 1) {\n\t\treturn 0;\n\t}\n\tconst levels = colorScaleLength - 1;\n\tif (max <= min) {\n\t\treturn value > min ? levels : 0;\n\t}\n\tconst clamped = Math.max(min, Math.min(max, value));\n\tconst normalized = (clamped - min) / (max - min);\n\tif (normalized <= 0) {\n\t\treturn 0;\n\t}\n\treturn Math.min(levels, Math.ceil(normalized * levels));\n}\n\nexport const HeatmapMatrix = forwardRef<HTMLDivElement, HeatmapMatrixProps>(function HeatmapMatrix(\n\t{\n\t\trowLabels,\n\t\tcolumnLabels,\n\t\tvalues,\n\t\tdomain,\n\t\tcolorScale = heatmapColorScales.green,\n\t\tvalueFormatter = (val) => val.toLocaleString(),\n\t\tmissingLabel = \"—\",\n\t\tmetricLabel = \"Heatmap matrix\",\n\t\tariaLabel = \"Heatmap matrix\",\n\t\tcellSize = 16,\n\t\tcolumnWidth,\n\t\tcellGap = 2,\n\t\tlessLabel = \"Less\",\n\t\tmoreLabel = \"More\",\n\t\tshowLegend = true,\n\t\trenderTooltip,\n\t\tclassName,\n\t\tstyle,\n\t\tonFocus,\n\t\tonBlur,\n\t\tonKeyDown,\n\t\t...rest\n\t},\n\tref,\n) {\n\tconst matrixId = useId();\n\tconst numRows = rowLabels.length;\n\tconst numCols = columnLabels.length;\n\tconst effectiveColWidth = columnWidth ?? cellSize;\n\n\t// Derive domain restricted to visible row/col matrix bounds\n\tconst [minVal, maxVal] = useMemo(() => {\n\t\tif (domain) {\n\t\t\tconst [d0, d1] = domain;\n\t\t\tif (Number.isFinite(d0) && Number.isFinite(d1)) {\n\t\t\t\treturn [Math.min(d0, d1), Math.max(d0, d1)];\n\t\t\t}\n\t\t}\n\t\tlet lowest = Number.POSITIVE_INFINITY;\n\t\tlet highest = Number.NEGATIVE_INFINITY;\n\t\tfor (let r = 0; r < numRows; r++) {\n\t\t\tconst row = values[r];\n\t\t\tif (!row) continue;\n\t\t\tfor (let c = 0; c < numCols; c++) {\n\t\t\t\tconst v = row[c];\n\t\t\t\tif (typeof v === \"number\" && Number.isFinite(v)) {\n\t\t\t\t\tif (v < lowest) lowest = v;\n\t\t\t\t\tif (v > highest) highest = v;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\tif (!Number.isFinite(lowest) || !Number.isFinite(highest)) {\n\t\t\treturn [0, 0];\n\t\t}\n\t\treturn [lowest, highest];\n\t}, [domain, values, numRows, numCols]);\n\n\t// Focus state: active cell position [rowIndex, colIndex]\n\tconst [activePos, setActivePos] = useState<[number, number]>([0, 0]);\n\tconst [openTooltipPos, setOpenTooltipPos] = useState<string | null>(null);\n\tconst dismissedByEscapeRef = useRef(false);\n\n\tconst activePosRef = useRef<[number, number]>([0, 0]);\n\tactivePosRef.current = activePos;\n\n\tconst containerRef = useRef<HTMLDivElement | null>(null);\n\tconst cellRefs = useRef<Map<string, HTMLButtonElement>>(new Map());\n\tconst isFocusedInsideRef = useRef(false);\n\n\t// Clamp active position when dimensions change\n\tuseEffect(() => {\n\t\tconst hadFocus = isFocusedInsideRef.current;\n\t\tif (numRows === 0 || numCols === 0) {\n\t\t\tsetActivePos(([curR, curC]) => {\n\t\t\t\tif (curR === 0 && curC === 0) return [curR, curC];\n\t\t\t\treturn [0, 0];\n\t\t\t});\n\t\t\tsetOpenTooltipPos(null);\n\t\t\tif (hadFocus) {\n\t\t\t\tcontainerRef.current?.focus();\n\t\t\t}\n\t\t\treturn;\n\t\t}\n\n\t\tconst [curR, curC] = activePosRef.current;\n\t\tconst nextR = Math.min(numRows - 1, Math.max(0, curR));\n\t\tconst nextC = Math.min(numCols - 1, Math.max(0, curC));\n\n\t\tsetActivePos((prev) => {\n\t\t\tif (prev[0] === nextR && prev[1] === nextC) {\n\t\t\t\treturn prev;\n\t\t\t}\n\t\t\treturn [nextR, nextC];\n\t\t});\n\n\t\tif (hadFocus) {\n\t\t\tconst key = `${nextR}-${nextC}`;\n\t\t\tconst target = cellRefs.current.get(key);\n\t\t\tif (target && document.activeElement !== target) {\n\t\t\t\ttarget.focus();\n\t\t\t}\n\t\t}\n\t}, [numRows, numCols]);\n\n\tconst handleContainerKeyDown = (e: KeyboardEvent<HTMLDivElement>) => {\n\t\tif (e.key === \"Escape\") {\n\t\t\tdismissedByEscapeRef.current = true;\n\t\t\tsetOpenTooltipPos(null);\n\t\t}\n\n\t\t// Call caller onKeyDown first so caller can inspect or preventDefault\n\t\tonKeyDown?.(e);\n\t\tif (e.defaultPrevented) {\n\t\t\treturn;\n\t\t}\n\n\t\tif (numRows === 0 || numCols === 0) return;\n\t\tif (e.key === \"Escape\") return;\n\n\t\tconst [currentRow, currentCol] = activePosRef.current;\n\t\tlet nextR = currentRow;\n\t\tlet nextC = currentCol;\n\n\t\tif (e.key === \"ArrowRight\") {\n\t\t\tnextC = Math.min(numCols - 1, currentCol + 1);\n\t\t} else if (e.key === \"ArrowLeft\") {\n\t\t\tnextC = Math.max(0, currentCol - 1);\n\t\t} else if (e.key === \"ArrowDown\") {\n\t\t\tnextR = Math.min(numRows - 1, currentRow + 1);\n\t\t} else if (e.key === \"ArrowUp\") {\n\t\t\tnextR = Math.max(0, currentRow - 1);\n\t\t} else if (e.key === \"Home\") {\n\t\t\tnextC = 0;\n\t\t} else if (e.key === \"End\") {\n\t\t\tnextC = numCols - 1;\n\t\t} else if (e.key === \"PageUp\") {\n\t\t\tnextR = 0;\n\t\t} else if (e.key === \"PageDown\") {\n\t\t\tnextR = numRows - 1;\n\t\t} else {\n\t\t\treturn;\n\t\t}\n\n\t\te.preventDefault();\n\t\tdismissedByEscapeRef.current = false;\n\t\tsetActivePos([nextR, nextC]);\n\t\tconst nextKey = `${nextR}-${nextC}`;\n\t\tsetOpenTooltipPos(nextKey);\n\t\tconst targetButton = cellRefs.current.get(nextKey);\n\t\tif (targetButton) {\n\t\t\ttargetButton.focus();\n\t\t\tconst scrollContainer = targetButton.closest<HTMLElement>(\n\t\t\t\t'[role=\"region\"][aria-label$=\"scrollable table\"]',\n\t\t\t);\n\t\t\tconst rowHeader = targetButton.closest(\"tr\")?.querySelector<HTMLElement>('th[scope=\"row\"]');\n\n\t\t\tif (scrollContainer) {\n\t\t\t\tconst containerRect = scrollContainer.getBoundingClientRect();\n\t\t\t\tconst btnRect = targetButton.getBoundingClientRect();\n\t\t\t\tconst stickyWidth = rowHeader ? rowHeader.getBoundingClientRect().width : 0;\n\n\t\t\t\tconst visibleLeft = containerRect.left + stickyWidth;\n\t\t\t\tconst visibleRight = containerRect.right;\n\n\t\t\t\tif (btnRect.left < visibleLeft) {\n\t\t\t\t\tscrollContainer.scrollLeft -= visibleLeft - btnRect.left + cellGap;\n\t\t\t\t} else if (btnRect.right > visibleRight) {\n\t\t\t\t\tscrollContainer.scrollLeft += btnRect.right - visibleRight + cellGap;\n\t\t\t\t}\n\t\t\t} else if (typeof targetButton.scrollIntoView === \"function\") {\n\t\t\t\ttargetButton.scrollIntoView({ block: \"nearest\", inline: \"nearest\" });\n\t\t\t}\n\t\t}\n\t};\n\n\tconst handleContainerFocus = (e: FocusEvent<HTMLDivElement>) => {\n\t\tisFocusedInsideRef.current = true;\n\t\tonFocus?.(e);\n\t};\n\n\tconst handleContainerBlur = (e: FocusEvent<HTMLDivElement>) => {\n\t\tif (!e.currentTarget.contains(e.relatedTarget)) {\n\t\t\tisFocusedInsideRef.current = false;\n\t\t\tdismissedByEscapeRef.current = false;\n\t\t}\n\t\tonBlur?.(e);\n\t};\n\n\tconst callerCleanupRef = useRef<(() => void) | undefined>(undefined);\n\n\tconst setRootRef = useCallback(\n\t\t(node: HTMLDivElement | null) => {\n\t\t\tcontainerRef.current = node;\n\n\t\t\tif (callerCleanupRef.current) {\n\t\t\t\tcallerCleanupRef.current();\n\t\t\t\tcallerCleanupRef.current = undefined;\n\t\t\t}\n\n\t\t\tif (typeof ref === \"function\") {\n\t\t\t\tconst cleanup = ref(node);\n\t\t\t\tif (typeof cleanup === \"function\") {\n\t\t\t\t\tcallerCleanupRef.current = cleanup;\n\t\t\t\t}\n\t\t\t} else if (ref) {\n\t\t\t\tref.current = node;\n\t\t\t}\n\n\t\t\treturn () => {\n\t\t\t\tcontainerRef.current = null;\n\t\t\t\tif (callerCleanupRef.current) {\n\t\t\t\t\tcallerCleanupRef.current();\n\t\t\t\t\tcallerCleanupRef.current = undefined;\n\t\t\t\t} else if (typeof ref === \"function\") {\n\t\t\t\t\tref(null);\n\t\t\t\t} else if (ref) {\n\t\t\t\t\tref.current = null;\n\t\t\t\t}\n\t\t\t};\n\t\t},\n\t\t[ref],\n\t);\n\n\tconst isEmpty = numRows === 0 || numCols === 0;\n\n\treturn (\n\t\t<TooltipProvider>\n\t\t\t<div\n\t\t\t\tref={setRootRef}\n\t\t\t\ttabIndex={isEmpty ? -1 : undefined}\n\t\t\t\trole=\"region\"\n\t\t\t\taria-label={ariaLabel}\n\t\t\t\tdata-testid=\"heatmap-matrix\"\n\t\t\t\tclassName={cn(\n\t\t\t\t\t\"flex flex-col gap-basalt-space-lg rounded-basalt-md border border-basalt-border/60 bg-basalt-card p-basalt-space-lg text-basalt-sm outline-none\",\n\t\t\t\t\tisEmpty ? \"text-basalt-muted-foreground\" : \"text-basalt-foreground\",\n\t\t\t\t\tclassName,\n\t\t\t\t)}\n\t\t\t\tstyle={style}\n\t\t\t\tonFocus={handleContainerFocus}\n\t\t\t\tonBlur={handleContainerBlur}\n\t\t\t\tonKeyDown={handleContainerKeyDown}\n\t\t\t\t{...rest}\n\t\t\t>\n\t\t\t\t{isEmpty ? (\n\t\t\t\t\t<span className=\"italic\">{missingLabel}</span>\n\t\t\t\t) : (\n\t\t\t\t\t<>\n\t\t\t\t\t\t{/* Scrollable table container */}\n\t\t\t\t\t\t<div\n\t\t\t\t\t\t\ttabIndex={-1}\n\t\t\t\t\t\t\trole=\"region\"\n\t\t\t\t\t\t\taria-label={`${ariaLabel} scrollable table`}\n\t\t\t\t\t\t\tclassName=\"w-full overflow-x-auto outline-none\"\n\t\t\t\t\t\t>\n\t\t\t\t\t\t\t<table\n\t\t\t\t\t\t\t\t// biome-ignore lint/a11y/noNoninteractiveElementToInteractiveRole: W3C ARIA interactive 2D grid table with descendant roving tab buttons\n\t\t\t\t\t\t\t\trole=\"grid\"\n\t\t\t\t\t\t\t\taria-label={ariaLabel}\n\t\t\t\t\t\t\t\tclassName=\"border-separate\"\n\t\t\t\t\t\t\t\tstyle={{ borderSpacing: cellGap }}\n\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t<thead>\n\t\t\t\t\t\t\t\t\t<tr>\n\t\t\t\t\t\t\t\t\t\t{/* Top-left empty header */}\n\t\t\t\t\t\t\t\t\t\t<th\n\t\t\t\t\t\t\t\t\t\t\tscope=\"col\"\n\t\t\t\t\t\t\t\t\t\t\tclassName=\"sticky left-0 z-10 bg-basalt-card p-0 text-left font-normal\"\n\t\t\t\t\t\t\t\t\t\t\tstyle={{ minWidth: 64 }}\n\t\t\t\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t\t\t\t<span className=\"sr-only\">Row \\ Column</span>\n\t\t\t\t\t\t\t\t\t\t</th>\n\t\t\t\t\t\t\t\t\t\t{columnLabels.map((col, colIdx) => (\n\t\t\t\t\t\t\t\t\t\t\t<th\n\t\t\t\t\t\t\t\t\t\t\t\tkey={`${matrixId}-col-${colIdx}`}\n\t\t\t\t\t\t\t\t\t\t\t\tscope=\"col\"\n\t\t\t\t\t\t\t\t\t\t\t\tclassName=\"p-0 text-center font-mono text-basalt-xs text-basalt-muted-foreground select-none\"\n\t\t\t\t\t\t\t\t\t\t\t\tstyle={{\n\t\t\t\t\t\t\t\t\t\t\t\t\twidth: effectiveColWidth,\n\t\t\t\t\t\t\t\t\t\t\t\t\tmaxWidth: effectiveColWidth,\n\t\t\t\t\t\t\t\t\t\t\t\t\toverflow: \"hidden\",\n\t\t\t\t\t\t\t\t\t\t\t\t\ttextOverflow: \"ellipsis\",\n\t\t\t\t\t\t\t\t\t\t\t\t\twhiteSpace: \"nowrap\",\n\t\t\t\t\t\t\t\t\t\t\t\t}}\n\t\t\t\t\t\t\t\t\t\t\t\ttitle={col}\n\t\t\t\t\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t\t\t\t\t{col}\n\t\t\t\t\t\t\t\t\t\t\t</th>\n\t\t\t\t\t\t\t\t\t\t))}\n\t\t\t\t\t\t\t\t\t</tr>\n\t\t\t\t\t\t\t\t</thead>\n\t\t\t\t\t\t\t\t<tbody>\n\t\t\t\t\t\t\t\t\t{rowLabels.map((rowName, rowIdx) => (\n\t\t\t\t\t\t\t\t\t\t<tr key={`${matrixId}-row-${rowIdx}`}>\n\t\t\t\t\t\t\t\t\t\t\t<th\n\t\t\t\t\t\t\t\t\t\t\t\tscope=\"row\"\n\t\t\t\t\t\t\t\t\t\t\t\tclassName=\"sticky left-0 z-10 bg-basalt-card pr-basalt-space-lg text-left font-medium text-basalt-foreground select-none\"\n\t\t\t\t\t\t\t\t\t\t\t\tstyle={{\n\t\t\t\t\t\t\t\t\t\t\t\t\tlineHeight: `${cellSize}px`,\n\t\t\t\t\t\t\t\t\t\t\t\t\tminWidth: 64,\n\t\t\t\t\t\t\t\t\t\t\t\t\twhiteSpace: \"nowrap\",\n\t\t\t\t\t\t\t\t\t\t\t\t}}\n\t\t\t\t\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t\t\t\t\t{rowName}\n\t\t\t\t\t\t\t\t\t\t\t</th>\n\t\t\t\t\t\t\t\t\t\t\t{columnLabels.map((colName, colIdx) => {\n\t\t\t\t\t\t\t\t\t\t\t\tconst cellKey = `${rowIdx}-${colIdx}`;\n\t\t\t\t\t\t\t\t\t\t\t\tconst rawVal = values[rowIdx]?.[colIdx];\n\t\t\t\t\t\t\t\t\t\t\t\tconst isMissing =\n\t\t\t\t\t\t\t\t\t\t\t\t\trawVal == null || typeof rawVal !== \"number\" || !Number.isFinite(rawVal);\n\t\t\t\t\t\t\t\t\t\t\t\tconst colorIdx = resolveColorIndex(\n\t\t\t\t\t\t\t\t\t\t\t\t\trawVal,\n\t\t\t\t\t\t\t\t\t\t\t\t\tminVal,\n\t\t\t\t\t\t\t\t\t\t\t\t\tmaxVal,\n\t\t\t\t\t\t\t\t\t\t\t\t\tcolorScale.length,\n\t\t\t\t\t\t\t\t\t\t\t\t);\n\n\t\t\t\t\t\t\t\t\t\t\t\tconst formattedVal = isMissing\n\t\t\t\t\t\t\t\t\t\t\t\t\t? missingLabel\n\t\t\t\t\t\t\t\t\t\t\t\t\t: valueFormatter(rawVal as number);\n\n\t\t\t\t\t\t\t\t\t\t\t\tconst cellBg =\n\t\t\t\t\t\t\t\t\t\t\t\t\tcolorIdx < 0\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t? \"hsl(var(--basalt-muted) / 0.4)\"\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t: (colorScale[colorIdx] ?? \"hsl(var(--basalt-muted))\");\n\n\t\t\t\t\t\t\t\t\t\t\t\tconst accessibleCellLabel = `${rowName}, ${colName}: ${formattedVal} (${metricLabel})`;\n\t\t\t\t\t\t\t\t\t\t\t\tconst isSelected = activePos[0] === rowIdx && activePos[1] === colIdx;\n\t\t\t\t\t\t\t\t\t\t\t\tconst isOpen = openTooltipPos === cellKey;\n\n\t\t\t\t\t\t\t\t\t\t\t\tconst cellContext: HeatmapMatrixCellContext = {\n\t\t\t\t\t\t\t\t\t\t\t\t\trowIndex: rowIdx,\n\t\t\t\t\t\t\t\t\t\t\t\t\tcolIndex: colIdx,\n\t\t\t\t\t\t\t\t\t\t\t\t\trowLabel: rowName,\n\t\t\t\t\t\t\t\t\t\t\t\t\tcolumnLabel: colName,\n\t\t\t\t\t\t\t\t\t\t\t\t\tvalue: rawVal,\n\t\t\t\t\t\t\t\t\t\t\t\t\tformattedValue: formattedVal,\n\t\t\t\t\t\t\t\t\t\t\t\t\tisMissing,\n\t\t\t\t\t\t\t\t\t\t\t\t\tcolorIndex: colorIdx,\n\t\t\t\t\t\t\t\t\t\t\t\t};\n\n\t\t\t\t\t\t\t\t\t\t\t\treturn (\n\t\t\t\t\t\t\t\t\t\t\t\t\t// biome-ignore lint/a11y/noNoninteractiveElementToInteractiveRole: ARIA gridcell container wrapping roving interactive button\n\t\t\t\t\t\t\t\t\t\t\t\t\t// biome-ignore lint/a11y/useFocusableInteractive: Focus is managed on child button via roving tabindex\n\t\t\t\t\t\t\t\t\t\t\t\t\t<td key={cellKey} role=\"gridcell\" className=\"p-0 text-center\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t<Tooltip\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\topen={isOpen}\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tonOpenChange={(next) => {\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tif (next) {\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tif (!dismissedByEscapeRef.current) {\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tsetOpenTooltipPos(cellKey);\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tsetOpenTooltipPos((curr) => {\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tif (curr !== cellKey) return curr;\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tif (dismissedByEscapeRef.current) return null;\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tconst isCellFocused =\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tdocument.activeElement === cellRefs.current.get(cellKey);\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\treturn isCellFocused ? curr : null;\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t});\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t}}\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<TooltipTrigger asChild>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<button\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tref={(el) => {\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tif (el) cellRefs.current.set(cellKey, el);\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\telse cellRefs.current.delete(cellKey);\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t}}\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\ttype=\"button\"\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\taria-label={accessibleCellLabel}\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\ttabIndex={isSelected ? 0 : -1}\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tonFocus={() => {\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tsetActivePos([rowIdx, colIdx]);\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tdismissedByEscapeRef.current = false;\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tsetOpenTooltipPos(cellKey);\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t}}\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tonBlur={() => {\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tsetOpenTooltipPos((curr) => (curr === cellKey ? null : curr));\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t}}\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tclassName=\"box-border block cursor-pointer rounded-basalt-sm border-0 p-0 transition-colors basalt-motion hover:ring-1 hover:ring-basalt-foreground focus-visible:outline-2 focus-visible:outline-offset-1 focus-visible:outline-basalt-ring\"\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tstyle={{\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\twidth: effectiveColWidth,\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\theight: cellSize,\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tbackgroundColor: cellBg,\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t}}\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t/>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</TooltipTrigger>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<TooltipContent\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tid={`${matrixId}-${cellKey}`}\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tonEscapeKeyDown={() => {\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tdismissedByEscapeRef.current = true;\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tsetOpenTooltipPos(null);\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t}}\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t{renderTooltip ? (\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\trenderTooltip(cellContext)\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t) : (\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<div className=\"text-basalt-sm\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<div className=\"font-semibold text-basalt-popover-foreground\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t{rowName} · {colName}\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<div className=\"text-basalt-muted-foreground\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t{metricLabel}:{\" \"}\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<span className=\"font-medium text-basalt-popover-foreground\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t{formattedVal}\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</span>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t)}\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</TooltipContent>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t</Tooltip>\n\t\t\t\t\t\t\t\t\t\t\t\t\t</td>\n\t\t\t\t\t\t\t\t\t\t\t\t);\n\t\t\t\t\t\t\t\t\t\t\t})}\n\t\t\t\t\t\t\t\t\t\t</tr>\n\t\t\t\t\t\t\t\t\t))}\n\t\t\t\t\t\t\t\t</tbody>\n\t\t\t\t\t\t\t</table>\n\t\t\t\t\t\t</div>\n\n\t\t\t\t\t\t{/* Legend footer */}\n\t\t\t\t\t\t{showLegend ? (\n\t\t\t\t\t\t\t<div\n\t\t\t\t\t\t\t\tclassName=\"mt-basalt-space-sm flex items-center justify-end gap-basalt-space-sm text-basalt-xs text-basalt-muted-foreground select-none\"\n\t\t\t\t\t\t\t\taria-hidden=\"true\"\n\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t<span>{lessLabel}</span>\n\t\t\t\t\t\t\t\t<div\n\t\t\t\t\t\t\t\t\tclassName=\"rounded-basalt-sm\"\n\t\t\t\t\t\t\t\t\ttitle=\"Missing data\"\n\t\t\t\t\t\t\t\t\tstyle={{\n\t\t\t\t\t\t\t\t\t\twidth: cellSize,\n\t\t\t\t\t\t\t\t\t\theight: cellSize,\n\t\t\t\t\t\t\t\t\t\tbackgroundColor: \"hsl(var(--basalt-muted) / 0.4)\",\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{colorScale.map((color, idx) => (\n\t\t\t\t\t\t\t\t\t<div\n\t\t\t\t\t\t\t\t\t\tkey={`${color}-${idx}`}\n\t\t\t\t\t\t\t\t\t\tclassName=\"rounded-basalt-sm\"\n\t\t\t\t\t\t\t\t\t\tstyle={{\n\t\t\t\t\t\t\t\t\t\t\twidth: cellSize,\n\t\t\t\t\t\t\t\t\t\t\theight: cellSize,\n\t\t\t\t\t\t\t\t\t\t\tbackgroundColor: color,\n\t\t\t\t\t\t\t\t\t\t}}\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<span>{moreLabel}</span>\n\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t) : null}\n\t\t\t\t\t</>\n\t\t\t\t)}\n\t\t\t</div>\n\t\t</TooltipProvider>\n\t);\n});\n\nHeatmapMatrix.displayName = \"HeatmapMatrix\";\n"],"mappings":"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"}
@@ -4,7 +4,7 @@ import { jsx as t, jsxs as n } from "react/jsx-runtime";
4
4
  //#region src/charts/item-list.tsx
5
5
  function r({ items: r, ariaLabel: i = "Item list", className: a }) {
6
6
  return /* @__PURE__ */ t("ul", {
7
- className: e("space-y-1 text-sm", a),
7
+ className: e("space-y-basalt-space-sm text-basalt-base", a),
8
8
  "aria-label": i,
9
9
  children: r.map((e, t) => /* @__PURE__ */ n("li", { children: [e.label, e.value ? /* @__PURE__ */ n("span", {
10
10
  className: "text-basalt-muted-foreground",
@@ -1 +1 @@
1
- {"version":3,"file":"item-list.js","names":["ItemList","cn","className","ariaLabel","items","item","index"],"sources":["../../src/charts/item-list.tsx"],"sourcesContent":["import { cn } from \"../utils/cn\";\n\nexport type ItemListItem = { id?: string; label: string; value?: string };\n\nexport type ItemListProps = {\n\titems: ItemListItem[];\n\tariaLabel?: string;\n\tclassName?: string;\n};\n\nexport function ItemList({ items, ariaLabel = \"Item list\", className }: ItemListProps) {\n\treturn (\n\t\t<ul className={cn(\"space-y-1 text-sm\", className)} aria-label={ariaLabel}>\n\t\t\t{items.map((item, index) => (\n\t\t\t\t<li key={item.id ?? `${item.label}-${item.value ?? \"\"}-${index}`}>\n\t\t\t\t\t{item.label}\n\t\t\t\t\t{item.value ? <span className=\"text-basalt-muted-foreground\"> {item.value}</span> : null}\n\t\t\t\t</li>\n\t\t\t))}\n\t\t</ul>\n\t);\n}\n"],"mappings":";;;;AAUA,SAAgBA,EAAS,EAAE,UAAO,eAAY,aAAa,gBAA4B;CACtF,OACC,kBAAC,MAAD;EAAI,WAAWC,EAAG,qBAAqBC,CAAS;EAAG,cAAYC;EAC7D,UAAAC,EAAM,KAAK,GAAM,MACjB,kBAAC,MAAD,EAAA,UAAA,CACEC,EAAK,OACLA,EAAK,QAAQ,kBAAC,QAAD;GAAM,WAAU;GAAhB,UAAA,CAA+C,KAAEA,EAAK,KAAY;EAAI,CAAA,IAAA,IACjF,EAAA,GAHKA,EAAK,MAAM,GAAGA,EAAK,MAAM,GAAGA,EAAK,SAAS,GAAG,GAAGC,GAGrD,CACJ;CACE,CAAA;AAEN"}
1
+ {"version":3,"file":"item-list.js","names":["ItemList","cn","className","ariaLabel","items","item","index"],"sources":["../../src/charts/item-list.tsx"],"sourcesContent":["import { cn } from \"../utils/cn\";\n\nexport type ItemListItem = { id?: string; label: string; value?: string };\n\nexport type ItemListProps = {\n\titems: ItemListItem[];\n\tariaLabel?: string;\n\tclassName?: string;\n};\n\nexport function ItemList({ items, ariaLabel = \"Item list\", className }: ItemListProps) {\n\treturn (\n\t\t<ul\n\t\t\tclassName={cn(\"space-y-basalt-space-sm text-basalt-base\", className)}\n\t\t\taria-label={ariaLabel}\n\t\t>\n\t\t\t{items.map((item, index) => (\n\t\t\t\t<li key={item.id ?? `${item.label}-${item.value ?? \"\"}-${index}`}>\n\t\t\t\t\t{item.label}\n\t\t\t\t\t{item.value ? <span className=\"text-basalt-muted-foreground\"> {item.value}</span> : null}\n\t\t\t\t</li>\n\t\t\t))}\n\t\t</ul>\n\t);\n}\n"],"mappings":";;;;AAUA,SAAgBA,EAAS,EAAE,UAAO,eAAY,aAAa,gBAA4B;CACtF,OACC,kBAAC,MAAD;EACC,WAAWC,EAAG,4CAA4CC,CAAS;EACnE,cAAYC;EAEX,UAAAC,EAAM,KAAK,GAAM,MACjB,kBAAC,MAAD,EAAA,UAAA,CACEC,EAAK,OACLA,EAAK,QAAQ,kBAAC,QAAD;GAAM,WAAU;GAAhB,UAAA,CAA+C,KAAEA,EAAK,KAAY;EAAI,CAAA,IAAA,IACjF,EAAA,GAHKA,EAAK,MAAM,GAAGA,EAAK,MAAM,GAAGA,EAAK,SAAS,GAAG,GAAGC,GAGrD,CACJ;CACE,CAAA;AAEN"}
@@ -1,43 +1,43 @@
1
1
  "use client";
2
- import { CHART_TYPE as e, seriesColor as t } from "./config.js";
3
- import { jsx as n, jsxs as r } from "react/jsx-runtime";
2
+ import { seriesColor as e } from "./config.js";
3
+ import { jsx as t, jsxs as n } from "react/jsx-runtime";
4
4
  //#region src/charts/legend.tsx
5
- function i({ items: i, shape: a = "line" }) {
6
- return i.length === 0 ? null : /* @__PURE__ */ n("div", {
5
+ function r({ items: r, shape: i = "line" }) {
6
+ return r.length === 0 ? null : /* @__PURE__ */ t("div", {
7
7
  "data-testid": "chart-legend",
8
8
  style: {
9
9
  color: "hsl(var(--basalt-muted-foreground))",
10
- columnGap: 16,
10
+ columnGap: "var(--basalt-space-default)",
11
11
  display: "flex",
12
12
  flexWrap: "wrap",
13
- fontSize: e.legendFontSize,
14
- marginTop: 12,
15
- rowGap: 4
13
+ fontSize: "var(--basalt-text-sm)",
14
+ marginTop: "var(--basalt-space-default)",
15
+ rowGap: "var(--basalt-space-sm)"
16
16
  },
17
- children: i.map((e, i) => {
18
- let o = t(e, i) ?? "hsl(var(--basalt-chart-1))", s = e.label ?? e.key;
19
- return /* @__PURE__ */ r("div", {
17
+ children: r.map((r, a) => {
18
+ let o = e(r, a) ?? "hsl(var(--basalt-chart-1))", s = r.label ?? r.key;
19
+ return /* @__PURE__ */ n("div", {
20
20
  style: {
21
21
  alignItems: "center",
22
22
  display: "flex",
23
- gap: 6
23
+ gap: "var(--basalt-space-md)"
24
24
  },
25
- children: [/* @__PURE__ */ n("svg", {
25
+ children: [/* @__PURE__ */ t("svg", {
26
26
  width: "18",
27
27
  height: "10",
28
28
  "aria-hidden": "true",
29
- children: a === "bar" ? /* @__PURE__ */ n("rect", {
29
+ children: i === "bar" ? /* @__PURE__ */ t("rect", {
30
30
  x: "1",
31
31
  y: "2",
32
32
  width: "16",
33
33
  height: "6",
34
34
  rx: "1",
35
35
  fill: o
36
- }) : a === "area" ? /* @__PURE__ */ n("polygon", {
36
+ }) : i === "area" ? /* @__PURE__ */ t("polygon", {
37
37
  points: "0,8 4,4 9,6 18,2 18,8",
38
38
  fill: o,
39
39
  opacity: "0.7"
40
- }) : /* @__PURE__ */ n("line", {
40
+ }) : /* @__PURE__ */ t("line", {
41
41
  x1: "0",
42
42
  y1: "5",
43
43
  x2: "18",
@@ -45,12 +45,12 @@ function i({ items: i, shape: a = "line" }) {
45
45
  stroke: o,
46
46
  strokeWidth: "2"
47
47
  })
48
- }), /* @__PURE__ */ n("span", { children: s })]
49
- }, e.key);
48
+ }), /* @__PURE__ */ t("span", { children: s })]
49
+ }, r.key);
50
50
  })
51
51
  });
52
52
  }
53
53
  //#endregion
54
- export { i as ChartLegend };
54
+ export { r as ChartLegend };
55
55
 
56
56
  //# sourceMappingURL=legend.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"legend.js","names":["ChartLegend","items","CHART_TYPE","color","seriesColor","item","index","label","shape"],"sources":["../../src/charts/legend.tsx"],"sourcesContent":["import { CHART_TYPE, seriesColor } from \"./config\";\nimport type { ChartSeriesDescriptor } from \"./series\";\n\nexport type ChartLegendShape = \"bar\" | \"line\" | \"area\";\n\nexport type ChartLegendProps = {\n\titems: ChartSeriesDescriptor[];\n\tshape?: ChartLegendShape;\n};\n\nexport function ChartLegend({ items, shape = \"line\" }: ChartLegendProps) {\n\tif (items.length === 0) {\n\t\treturn null;\n\t}\n\treturn (\n\t\t<div\n\t\t\tdata-testid=\"chart-legend\"\n\t\t\tstyle={{\n\t\t\t\tcolor: \"hsl(var(--basalt-muted-foreground))\",\n\t\t\t\tcolumnGap: 16,\n\t\t\t\tdisplay: \"flex\",\n\t\t\t\tflexWrap: \"wrap\",\n\t\t\t\tfontSize: CHART_TYPE.legendFontSize,\n\t\t\t\tmarginTop: 12,\n\t\t\t\trowGap: 4,\n\t\t\t}}\n\t\t>\n\t\t\t{items.map((item, index) => {\n\t\t\t\tconst color = seriesColor(item, index) ?? \"hsl(var(--basalt-chart-1))\";\n\t\t\t\tconst label = item.label ?? item.key;\n\t\t\t\treturn (\n\t\t\t\t\t<div key={item.key} style={{ alignItems: \"center\", display: \"flex\", gap: 6 }}>\n\t\t\t\t\t\t<svg width=\"18\" height=\"10\" aria-hidden=\"true\">\n\t\t\t\t\t\t\t{shape === \"bar\" ? (\n\t\t\t\t\t\t\t\t<rect x=\"1\" y=\"2\" width=\"16\" height=\"6\" rx=\"1\" fill={color} />\n\t\t\t\t\t\t\t) : shape === \"area\" ? (\n\t\t\t\t\t\t\t\t<polygon points=\"0,8 4,4 9,6 18,2 18,8\" fill={color} opacity=\"0.7\" />\n\t\t\t\t\t\t\t) : (\n\t\t\t\t\t\t\t\t<line x1=\"0\" y1=\"5\" x2=\"18\" y2=\"5\" stroke={color} strokeWidth=\"2\" />\n\t\t\t\t\t\t\t)}\n\t\t\t\t\t\t</svg>\n\t\t\t\t\t\t<span>{label}</span>\n\t\t\t\t\t</div>\n\t\t\t\t);\n\t\t\t})}\n\t\t</div>\n\t);\n}\n"],"mappings":";;;;AAUA,SAAgBA,EAAY,EAAE,UAAO,WAAQ,UAA4B;CAIxE,OAHIC,EAAM,WAAW,IACb,OAGP,kBAAC,OAAD;EACC,eAAY;EACZ,OAAO;GACN,OAAO;GACP,WAAW;GACX,SAAS;GACT,UAAU;GACV,UAAUC,EAAW;GACrB,WAAW;GACX,QAAQ;EACT;EAEC,UAAAD,EAAM,KAAK,GAAM,MAAU;GAC3B,IAAME,IAAQC,EAAYC,GAAMC,CAAK,KAAK,8BACpCC,IAAQF,EAAK,SAASA,EAAK;GACjC,OACC,kBAAC,OAAD;IAAoB,OAAO;KAAE,YAAY;KAAU,SAAS;KAAQ,KAAK;IAAE;IAA3E,UAAA,CACC,kBAAC,OAAD;KAAK,OAAM;KAAK,QAAO;KAAK,eAAY;KACtC,UAAAG,MAAU,QACV,kBAAC,QAAD;MAAM,GAAE;MAAI,GAAE;MAAI,OAAM;MAAK,QAAO;MAAI,IAAG;MAAI,MAAML;KAAQ,CAAA,IAC1DK,MAAU,SACb,kBAAC,WAAD;MAAS,QAAO;MAAwB,MAAML;MAAO,SAAQ;KAAO,CAAA,IAEpE,kBAAC,QAAD;MAAM,IAAG;MAAI,IAAG;MAAI,IAAG;MAAK,IAAG;MAAI,QAAQA;MAAO,aAAY;KAAK,CAAA;IAEhE,CAAA,GACL,kBAAC,QAAD,EAAA,UAAOI,EAAY,CAAA,CACf;GAXK,GAAAF,EAAK,GAWV;EAEP,CAAC;CACG,CAAA;AAEP"}
1
+ {"version":3,"file":"legend.js","names":["ChartLegend","items","color","seriesColor","item","index","label","shape"],"sources":["../../src/charts/legend.tsx"],"sourcesContent":["import { seriesColor } from \"./config\";\nimport type { ChartSeriesDescriptor } from \"./series\";\n\nexport type ChartLegendShape = \"bar\" | \"line\" | \"area\";\n\nexport type ChartLegendProps = {\n\titems: ChartSeriesDescriptor[];\n\tshape?: ChartLegendShape;\n};\n\nexport function ChartLegend({ items, shape = \"line\" }: ChartLegendProps) {\n\tif (items.length === 0) {\n\t\treturn null;\n\t}\n\treturn (\n\t\t<div\n\t\t\tdata-testid=\"chart-legend\"\n\t\t\tstyle={{\n\t\t\t\tcolor: \"hsl(var(--basalt-muted-foreground))\",\n\t\t\t\tcolumnGap: \"var(--basalt-space-default)\",\n\t\t\t\tdisplay: \"flex\",\n\t\t\t\tflexWrap: \"wrap\",\n\t\t\t\tfontSize: \"var(--basalt-text-sm)\",\n\t\t\t\tmarginTop: \"var(--basalt-space-default)\",\n\t\t\t\trowGap: \"var(--basalt-space-sm)\",\n\t\t\t}}\n\t\t>\n\t\t\t{items.map((item, index) => {\n\t\t\t\tconst color = seriesColor(item, index) ?? \"hsl(var(--basalt-chart-1))\";\n\t\t\t\tconst label = item.label ?? item.key;\n\t\t\t\treturn (\n\t\t\t\t\t<div\n\t\t\t\t\t\tkey={item.key}\n\t\t\t\t\t\tstyle={{ alignItems: \"center\", display: \"flex\", gap: \"var(--basalt-space-md)\" }}\n\t\t\t\t\t>\n\t\t\t\t\t\t<svg width=\"18\" height=\"10\" aria-hidden=\"true\">\n\t\t\t\t\t\t\t{shape === \"bar\" ? (\n\t\t\t\t\t\t\t\t<rect x=\"1\" y=\"2\" width=\"16\" height=\"6\" rx=\"1\" fill={color} />\n\t\t\t\t\t\t\t) : shape === \"area\" ? (\n\t\t\t\t\t\t\t\t<polygon points=\"0,8 4,4 9,6 18,2 18,8\" fill={color} opacity=\"0.7\" />\n\t\t\t\t\t\t\t) : (\n\t\t\t\t\t\t\t\t<line x1=\"0\" y1=\"5\" x2=\"18\" y2=\"5\" stroke={color} strokeWidth=\"2\" />\n\t\t\t\t\t\t\t)}\n\t\t\t\t\t\t</svg>\n\t\t\t\t\t\t<span>{label}</span>\n\t\t\t\t\t</div>\n\t\t\t\t);\n\t\t\t})}\n\t\t</div>\n\t);\n}\n"],"mappings":";;;;AAUA,SAAgBA,EAAY,EAAE,UAAO,WAAQ,UAA4B;CAIxE,OAHIC,EAAM,WAAW,IACb,OAGP,kBAAC,OAAD;EACC,eAAY;EACZ,OAAO;GACN,OAAO;GACP,WAAW;GACX,SAAS;GACT,UAAU;GACV,UAAU;GACV,WAAW;GACX,QAAQ;EACT;EAEC,UAAAA,EAAM,KAAK,GAAM,MAAU;GAC3B,IAAMC,IAAQC,EAAYC,GAAMC,CAAK,KAAK,8BACpCC,IAAQF,EAAK,SAASA,EAAK;GACjC,OACC,kBAAC,OAAD;IAEC,OAAO;KAAE,YAAY;KAAU,SAAS;KAAQ,KAAK;IAAyB;IAF/E,UAAA,CAIC,kBAAC,OAAD;KAAK,OAAM;KAAK,QAAO;KAAK,eAAY;KACtC,UAAAG,MAAU,QACV,kBAAC,QAAD;MAAM,GAAE;MAAI,GAAE;MAAI,OAAM;MAAK,QAAO;MAAI,IAAG;MAAI,MAAML;KAAQ,CAAA,IAC1DK,MAAU,SACb,kBAAC,WAAD;MAAS,QAAO;MAAwB,MAAML;MAAO,SAAQ;KAAO,CAAA,IAEpE,kBAAC,QAAD;MAAM,IAAG;MAAI,IAAG;MAAI,IAAG;MAAK,IAAG;MAAI,QAAQA;MAAO,aAAY;KAAK,CAAA;IAEhE,CAAA,GACL,kBAAC,QAAD,EAAA,UAAOI,EAAY,CAAA,CACf;GAbC,GAAAF,EAAK,GAaN;EAEP,CAAC;CACG,CAAA;AAEP"}
@@ -35,11 +35,11 @@ var t = (e) => `hsl(var(--basalt-${e}))`, n = (e, t) => `hsl(var(--basalt-${e})
35
35
  ];
36
36
  function s({ ariaLabel: t = "Chart colors" }) {
37
37
  return /* @__PURE__ */ e("div", {
38
- className: "flex flex-wrap gap-2",
38
+ className: "flex flex-wrap gap-basalt-space-lg",
39
39
  role: "img",
40
40
  "aria-label": t,
41
41
  children: o.map((t) => /* @__PURE__ */ e("span", {
42
- className: "h-8 w-8 rounded-basalt-sm",
42
+ className: "h-basalt-8 w-basalt-8 rounded-basalt-sm",
43
43
  style: { background: t }
44
44
  }, t))
45
45
  });
@@ -1 +1 @@
1
- {"version":3,"file":"palette.js","names":["v","token","withAlpha","alpha","chartAxis","chartMuted","chart","CHART_COLORS","ChartPalette","ariaLabel","color"],"sources":["../../src/charts/palette.tsx"],"sourcesContent":["const v = (token: string) => `hsl(var(--basalt-${token}))`;\n\nexport const withAlpha = (token: string, alpha: number) => `hsl(var(--basalt-${token}) / ${alpha})`;\n\nexport const chartAxis = v(\"chart-axis\");\nexport const chartMuted = v(\"chart-muted\");\n\nexport const chart = {\n\tprimary: v(\"chart-1\"),\n\tsky: v(\"chart-2\"),\n\tteal: v(\"chart-3\"),\n\tjade: v(\"chart-4\"),\n\tgreen: v(\"chart-5\"),\n\tlime: v(\"chart-6\"),\n\tamber: v(\"chart-7\"),\n\torange: v(\"chart-8\"),\n\tvermilion: v(\"chart-9\"),\n\tred: v(\"chart-10\"),\n\trose: v(\"chart-11\"),\n\tmagenta: v(\"chart-12\"),\n\torchid: v(\"chart-13\"),\n\tpurple: v(\"chart-14\"),\n\tindigo: v(\"chart-15\"),\n\tcobalt: v(\"chart-16\"),\n\tsteel: v(\"chart-17\"),\n\tcadet: v(\"chart-18\"),\n\tseafoam: v(\"chart-19\"),\n\tolive: v(\"chart-20\"),\n\tgold: v(\"chart-21\"),\n\ttangerine: v(\"chart-22\"),\n\tcrimson: v(\"chart-23\"),\n\tgray: v(\"chart-24\"),\n} as const;\n\n/** Fixed five-color series cycle; independent of the application accent. */\nexport const CHART_COLORS = [chart.primary, chart.rose, chart.green, chart.amber, chart.gray];\n\nexport type ChartPaletteProps = {\n\tariaLabel?: string;\n};\n\nexport function ChartPalette({ ariaLabel = \"Chart colors\" }: ChartPaletteProps) {\n\treturn (\n\t\t<div className=\"flex flex-wrap gap-2\" role=\"img\" aria-label={ariaLabel}>\n\t\t\t{CHART_COLORS.map((color) => (\n\t\t\t\t<span key={color} className=\"h-8 w-8 rounded-basalt-sm\" style={{ background: color }} />\n\t\t\t))}\n\t\t</div>\n\t);\n}\n"],"mappings":";;;AAAA,IAAMA,KAAK,MAAkB,oBAAoBC,EAAM,KAE1CC,KAAa,GAAe,MAAkB,oBAAoBD,EAAM,MAAME,EAAM,IAEpFC,IAAYJ,EAAE,YAAY,GAC1BK,IAAaL,EAAE,aAAa,GAE5BM,IAAQ;CACpB,SAASN,EAAE,SAAS;CACpB,KAAKA,EAAE,SAAS;CAChB,MAAMA,EAAE,SAAS;CACjB,MAAMA,EAAE,SAAS;CACjB,OAAOA,EAAE,SAAS;CAClB,MAAMA,EAAE,SAAS;CACjB,OAAOA,EAAE,SAAS;CAClB,QAAQA,EAAE,SAAS;CACnB,WAAWA,EAAE,SAAS;CACtB,KAAKA,EAAE,UAAU;CACjB,MAAMA,EAAE,UAAU;CAClB,SAASA,EAAE,UAAU;CACrB,QAAQA,EAAE,UAAU;CACpB,QAAQA,EAAE,UAAU;CACpB,QAAQA,EAAE,UAAU;CACpB,QAAQA,EAAE,UAAU;CACpB,OAAOA,EAAE,UAAU;CACnB,OAAOA,EAAE,UAAU;CACnB,SAASA,EAAE,UAAU;CACrB,OAAOA,EAAE,UAAU;CACnB,MAAMA,EAAE,UAAU;CAClB,WAAWA,EAAE,UAAU;CACvB,SAASA,EAAE,UAAU;CACrB,MAAMA,EAAE,UAAU;AACnB,GAGaO,IAAe;CAACD,EAAM;CAASA,EAAM;CAAMA,EAAM;CAAOA,EAAM;CAAOA,EAAM;AAAI;AAM5F,SAAgBE,EAAa,EAAE,eAAY,kBAAqC;CAC/E,OACC,kBAAC,OAAD;EAAK,WAAU;EAAuB,MAAK;EAAM,cAAYC;EAC3D,UAAAF,EAAa,KAAK,MAClB,kBAAC,QAAD;GAAkB,WAAU;GAA4B,OAAO,EAAE,YAAYG,EAAM;EAAI,GAA5EA,CAA4E,CACvF;CACG,CAAA;AAEP"}
1
+ {"version":3,"file":"palette.js","names":["v","token","withAlpha","alpha","chartAxis","chartMuted","chart","CHART_COLORS","ChartPalette","ariaLabel","color"],"sources":["../../src/charts/palette.tsx"],"sourcesContent":["const v = (token: string) => `hsl(var(--basalt-${token}))`;\n\nexport const withAlpha = (token: string, alpha: number) => `hsl(var(--basalt-${token}) / ${alpha})`;\n\nexport const chartAxis = v(\"chart-axis\");\nexport const chartMuted = v(\"chart-muted\");\n\nexport const chart = {\n\tprimary: v(\"chart-1\"),\n\tsky: v(\"chart-2\"),\n\tteal: v(\"chart-3\"),\n\tjade: v(\"chart-4\"),\n\tgreen: v(\"chart-5\"),\n\tlime: v(\"chart-6\"),\n\tamber: v(\"chart-7\"),\n\torange: v(\"chart-8\"),\n\tvermilion: v(\"chart-9\"),\n\tred: v(\"chart-10\"),\n\trose: v(\"chart-11\"),\n\tmagenta: v(\"chart-12\"),\n\torchid: v(\"chart-13\"),\n\tpurple: v(\"chart-14\"),\n\tindigo: v(\"chart-15\"),\n\tcobalt: v(\"chart-16\"),\n\tsteel: v(\"chart-17\"),\n\tcadet: v(\"chart-18\"),\n\tseafoam: v(\"chart-19\"),\n\tolive: v(\"chart-20\"),\n\tgold: v(\"chart-21\"),\n\ttangerine: v(\"chart-22\"),\n\tcrimson: v(\"chart-23\"),\n\tgray: v(\"chart-24\"),\n} as const;\n\n/** Fixed five-color series cycle; independent of the application accent. */\nexport const CHART_COLORS = [chart.primary, chart.rose, chart.green, chart.amber, chart.gray];\n\nexport type ChartPaletteProps = {\n\tariaLabel?: string;\n};\n\nexport function ChartPalette({ ariaLabel = \"Chart colors\" }: ChartPaletteProps) {\n\treturn (\n\t\t<div className=\"flex flex-wrap gap-basalt-space-lg\" role=\"img\" aria-label={ariaLabel}>\n\t\t\t{CHART_COLORS.map((color) => (\n\t\t\t\t<span\n\t\t\t\t\tkey={color}\n\t\t\t\t\tclassName=\"h-basalt-8 w-basalt-8 rounded-basalt-sm\"\n\t\t\t\t\tstyle={{ background: color }}\n\t\t\t\t/>\n\t\t\t))}\n\t\t</div>\n\t);\n}\n"],"mappings":";;;AAAA,IAAMA,KAAK,MAAkB,oBAAoBC,EAAM,KAE1CC,KAAa,GAAe,MAAkB,oBAAoBD,EAAM,MAAME,EAAM,IAEpFC,IAAYJ,EAAE,YAAY,GAC1BK,IAAaL,EAAE,aAAa,GAE5BM,IAAQ;CACpB,SAASN,EAAE,SAAS;CACpB,KAAKA,EAAE,SAAS;CAChB,MAAMA,EAAE,SAAS;CACjB,MAAMA,EAAE,SAAS;CACjB,OAAOA,EAAE,SAAS;CAClB,MAAMA,EAAE,SAAS;CACjB,OAAOA,EAAE,SAAS;CAClB,QAAQA,EAAE,SAAS;CACnB,WAAWA,EAAE,SAAS;CACtB,KAAKA,EAAE,UAAU;CACjB,MAAMA,EAAE,UAAU;CAClB,SAASA,EAAE,UAAU;CACrB,QAAQA,EAAE,UAAU;CACpB,QAAQA,EAAE,UAAU;CACpB,QAAQA,EAAE,UAAU;CACpB,QAAQA,EAAE,UAAU;CACpB,OAAOA,EAAE,UAAU;CACnB,OAAOA,EAAE,UAAU;CACnB,SAASA,EAAE,UAAU;CACrB,OAAOA,EAAE,UAAU;CACnB,MAAMA,EAAE,UAAU;CAClB,WAAWA,EAAE,UAAU;CACvB,SAASA,EAAE,UAAU;CACrB,MAAMA,EAAE,UAAU;AACnB,GAGaO,IAAe;CAACD,EAAM;CAASA,EAAM;CAAMA,EAAM;CAAOA,EAAM;CAAOA,EAAM;AAAI;AAM5F,SAAgBE,EAAa,EAAE,eAAY,kBAAqC;CAC/E,OACC,kBAAC,OAAD;EAAK,WAAU;EAAqC,MAAK;EAAM,cAAYC;EACzE,UAAAF,EAAa,KAAK,MAClB,kBAAC,QAAD;GAEC,WAAU;GACV,OAAO,EAAE,YAAYG,EAAM;EAC3B,GAHKA,CAGL,CACD;CACG,CAAA;AAEP"}
@@ -35,13 +35,13 @@ function _(e) {
35
35
  })
36
36
  });
37
37
  }
38
- function v({ items: a, ariaLabel: o = "Slot bar chart", heightClass: s = "h-6", gapClass: c = "gap-px", emptyClass: l = "bg-basalt-muted", className: u }) {
38
+ function v({ items: a, ariaLabel: o = "Slot bar chart", heightClass: s = "h-basalt-6", gapClass: c = "gap-px", emptyClass: l = "bg-basalt-muted", className: u }) {
39
39
  if (a.length === 0) return null;
40
40
  let p = a.some((e) => e.label);
41
41
  function m(t) {
42
42
  let n = t.height ?? 1, r = n <= 0, i = t.color.startsWith("bg-"), a = r ? 100 : Math.max(n * 100, 10);
43
43
  return /* @__PURE__ */ d("div", {
44
- className: e("w-full rounded-sm", r ? l : i ? t.color : void 0),
44
+ className: e("w-full rounded-basalt-sm", r ? l : i ? t.color : void 0),
45
45
  style: {
46
46
  height: `${a}%`,
47
47
  ...r || i ? {} : { backgroundColor: t.color }
@@ -1 +1 @@
1
- {"version":3,"file":"slot-bar.js","names":["RechartsBar","Tooltip","Tooltip$1","SlotBarChart","props","SlotItemBars","bars","resolveChartSeries","series","ChartFrame","BarChart","XAxis","cartesianAxisProps","YAxis","Bar","item","seriesColor","index","BAR_RADIUS","ANIMATION_PROPS","items","hasTooltips","renderBar","heightRatio","isEmpty","isTailwindColor","heightPercent","cn","emptyClass","content","bar","TooltipTrigger","TooltipContent","container","heightClass","gapClass","className","ariaLabel","TooltipProvider"],"sources":["../../src/charts/slot-bar.tsx"],"sourcesContent":["import type { ReactNode } from \"react\";\nimport { Bar, BarChart as RechartsBar, XAxis, YAxis } from \"recharts\";\nimport { Tooltip, TooltipContent, TooltipProvider, TooltipTrigger } from \"../components/tooltip\";\nimport { cn } from \"../utils/cn\";\nimport { ANIMATION_PROPS, BAR_RADIUS, cartesianAxisProps, seriesColor } from \"./config\";\nimport { ChartFrame } from \"./frame\";\nimport type { LineChartNumericKeys } from \"./line\";\nimport { type ChartSeriesDescriptor, resolveChartSeries, type XYPoint } from \"./series\";\n\nexport type SlotBarItem = {\n\tcolor: string;\n\theight?: number;\n\tlabel?: string;\n};\n\nexport type SlotBarItemsProps = {\n\titems: SlotBarItem[];\n\tariaLabel?: string;\n\theightClass?: string;\n\tgapClass?: string;\n\temptyClass?: string;\n\tclassName?: string;\n};\n\nexport type SlotBarDataProps<\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\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 type SlotBarChartProps<\n\tTData extends { x: string | number } = XYPoint,\n\tK extends LineChartNumericKeys<TData> & string = LineChartNumericKeys<TData> & string,\n> = SlotBarItemsProps | SlotBarDataProps<TData, K>;\n\nexport function SlotBarChart<\n\tTData extends { x: string | number } = XYPoint,\n\tK extends LineChartNumericKeys<TData> & string = LineChartNumericKeys<TData> & string,\n>(props: SlotBarChartProps<TData, K>) {\n\tif (\"items\" in props) {\n\t\treturn <SlotItemBars {...props} />;\n\t}\n\tconst {\n\t\tseries,\n\t\tariaLabel = \"Slot bar chart\",\n\t\tclassName,\n\t\tsummary,\n\t\tdataAlternative,\n\t\taccessibilityLayer,\n\t} = props;\n\tconst bars = resolveChartSeries(series, [\"y\" as K]);\n\treturn (\n\t\t<ChartFrame\n\t\t\tariaLabel={ariaLabel}\n\t\t\tclassName={className}\n\t\t\tsummary={summary}\n\t\t\tdataAlternative={dataAlternative}\n\t\t\taccessibilityLayer={accessibilityLayer}\n\t\t>\n\t\t\t<RechartsBar data={props.data}>\n\t\t\t\t<XAxis dataKey=\"x\" {...cartesianAxisProps(true)} />\n\t\t\t\t<YAxis {...cartesianAxisProps(true)} />\n\t\t\t\t{bars.map((item, index) => (\n\t\t\t\t\t<Bar\n\t\t\t\t\t\tkey={item.key}\n\t\t\t\t\t\tdataKey={item.key}\n\t\t\t\t\t\tname={item.label ?? item.key}\n\t\t\t\t\t\tfill={seriesColor(item, index)}\n\t\t\t\t\t\tradius={BAR_RADIUS.vertical}\n\t\t\t\t\t\t{...ANIMATION_PROPS}\n\t\t\t\t\t/>\n\t\t\t\t))}\n\t\t\t</RechartsBar>\n\t\t</ChartFrame>\n\t);\n}\n\nfunction SlotItemBars({\n\titems,\n\tariaLabel = \"Slot bar chart\",\n\theightClass = \"h-6\",\n\tgapClass = \"gap-px\",\n\temptyClass = \"bg-basalt-muted\",\n\tclassName,\n}: SlotBarItemsProps) {\n\tif (items.length === 0) {\n\t\treturn null;\n\t}\n\tconst hasTooltips = items.some((item) => item.label);\n\tfunction renderBar(item: SlotBarItem) {\n\t\tconst heightRatio = item.height ?? 1;\n\t\tconst isEmpty = heightRatio <= 0;\n\t\tconst isTailwindColor = item.color.startsWith(\"bg-\");\n\t\tconst heightPercent = isEmpty ? 100 : Math.max(heightRatio * 100, 10);\n\t\treturn (\n\t\t\t<div\n\t\t\t\tclassName={cn(\n\t\t\t\t\t\"w-full rounded-sm\",\n\t\t\t\t\tisEmpty ? emptyClass : isTailwindColor ? item.color : undefined,\n\t\t\t\t)}\n\t\t\t\tstyle={{\n\t\t\t\t\theight: `${heightPercent}%`,\n\t\t\t\t\t...(isEmpty || isTailwindColor ? {} : { backgroundColor: item.color }),\n\t\t\t\t}}\n\t\t\t\tdata-testid=\"slot-bar\"\n\t\t\t/>\n\t\t);\n\t}\n\tconst content = items.map((item, index) => {\n\t\tconst bar =\n\t\t\thasTooltips && item.label ? (\n\t\t\t\t<Tooltip>\n\t\t\t\t\t<TooltipTrigger asChild>{renderBar(item)}</TooltipTrigger>\n\t\t\t\t\t<TooltipContent side=\"top\">\n\t\t\t\t\t\t<p>{item.label}</p>\n\t\t\t\t\t</TooltipContent>\n\t\t\t\t</Tooltip>\n\t\t\t) : (\n\t\t\t\trenderBar(item)\n\t\t\t);\n\t\treturn (\n\t\t\t<div\n\t\t\t\tkey={`${item.label ?? item.color}-${index}`}\n\t\t\t\tclassName=\"flex min-h-0 min-w-0 flex-1 items-end self-stretch\"\n\t\t\t>\n\t\t\t\t{bar}\n\t\t\t</div>\n\t\t);\n\t});\n\tconst container = (\n\t\t<div\n\t\t\tclassName={cn(\"flex w-full items-end\", heightClass, gapClass, className)}\n\t\t\trole=\"img\"\n\t\t\taria-label={ariaLabel}\n\t\t>\n\t\t\t{content}\n\t\t</div>\n\t);\n\tif (hasTooltips) {\n\t\treturn <TooltipProvider delayDuration={0}>{container}</TooltipProvider>;\n\t}\n\treturn container;\n}\n"],"mappings":";;;;;;;;;AA+DA,SAAgBG,EAGd,GAAoC;CACrC,IAAI,WAAWC,GACd,OAAO,kBAACC,GAAD,EAAc,GAAID,EAAQ,CAAA;CAElC,IAAM,EACL,WACA,eAAY,kBACZ,cACA,YACA,oBACA,0BACGA,GACEE,IAAOC,EAAmBC,GAAQ,CAAC,GAAQ,CAAC;CAClD,OACC,kBAACC,GAAD;EACY;EACA;EACF;EACQ;EACG;EAEpB,UAAA,kBAACT,GAAD;GAAa,MAAMI,EAAM;GAAzB,UAAA;IACC,kBAACO,GAAD;KAAO,SAAQ;KAAI,GAAIC,EAAmB,EAAI;IAAI,CAAA;IAClD,kBAACC,GAAD,EAAO,GAAID,EAAmB,EAAI,EAAI,CAAA;IACrCN,EAAK,KAAK,GAAM,MAChB,kBAACQ,GAAD;KAEC,SAASC,EAAK;KACd,MAAMA,EAAK,SAASA,EAAK;KACzB,MAAMC,EAAYD,GAAME,CAAK;KAC7B,QAAQC,EAAW;KACnB,GAAIC;IACJ,GANKJ,EAAK,GAMV,CACD;GACW;;CACF,CAAA;AAEd;AAEA,SAASV,EAAa,EACrB,UACA,eAAY,kBACZ,iBAAc,OACd,cAAW,UACX,gBAAa,mBACb,gBACqB;CACrB,IAAIe,EAAM,WAAW,GACpB,OAAO;CAER,IAAMC,IAAcD,EAAM,MAAM,MAASL,EAAK,KAAK;CACnD,SAASO,EAAU,GAAmB;EACrC,IAAMC,IAAcR,EAAK,UAAU,GAC7BS,IAAUD,KAAe,GACzBE,IAAkBV,EAAK,MAAM,WAAW,KAAK,GAC7CW,IAAgBF,IAAU,MAAM,KAAK,IAAID,IAAc,KAAK,EAAE;EACpE,OACC,kBAAC,OAAD;GACC,WAAWI,EACV,qBACAH,IAAUI,IAAaH,IAAkBV,EAAK,QAAQ,KAAA,CACvD;GACA,OAAO;IACN,QAAQ,GAAGW,EAAc;IACzB,GAAIF,KAAWC,IAAkB,CAAC,IAAI,EAAE,iBAAiBV,EAAK,MAAM;GACrE;GACA,eAAY;EACZ,CAAA;CAEH;CACA,IAAMc,IAAUT,EAAM,KAAK,GAAM,MAAU;EAC1C,IAAMU,IACLT,KAAeN,EAAK,QACnB,kBAACd,GAAD,EAAA,UAAA,CACC,kBAAC8B,GAAD;GAAgB,SAAA;GAAS,UAAAT,EAAUP,CAAI;EAAkB,CAAA,GACzD,kBAACiB,GAAD;GAAgB,MAAK;GACpB,UAAA,kBAAC,KAAD,EAAA,UAAIjB,EAAK,MAAS,CAAA;EACH,CAAA,CACR,EAAA,CAAA,IAETO,EAAUP,CAAI;EAEhB,OACC,kBAAC,OAAD;GAEC,WAAU;GAET,UAAAe;EACG,GAJC,GAAGf,EAAK,SAASA,EAAK,MAAM,GAAGE,GAIhC;CAEP,CAAC,GACKgB,IACL,kBAAC,OAAD;EACC,WAAWN,EAAG,yBAAyBO,GAAaC,GAAUC,CAAS;EACvE,MAAK;EACL,cAAYC;EAEX,UAAAR;CACG,CAAA;CAKN,OAHIR,IACI,kBAACiB,GAAD;EAAiB,eAAe;EAAI,UAAAL;CAA2B,CAAA,IAEhEA;AACR"}
1
+ {"version":3,"file":"slot-bar.js","names":["RechartsBar","Tooltip","Tooltip$1","SlotBarChart","props","SlotItemBars","bars","resolveChartSeries","series","ChartFrame","BarChart","XAxis","cartesianAxisProps","YAxis","Bar","item","seriesColor","index","BAR_RADIUS","ANIMATION_PROPS","items","hasTooltips","renderBar","heightRatio","isEmpty","isTailwindColor","heightPercent","cn","emptyClass","content","bar","TooltipTrigger","TooltipContent","container","heightClass","gapClass","className","ariaLabel","TooltipProvider"],"sources":["../../src/charts/slot-bar.tsx"],"sourcesContent":["import type { ReactNode } from \"react\";\nimport { Bar, BarChart as RechartsBar, XAxis, YAxis } from \"recharts\";\nimport { Tooltip, TooltipContent, TooltipProvider, TooltipTrigger } from \"../components/tooltip\";\nimport { cn } from \"../utils/cn\";\nimport { ANIMATION_PROPS, BAR_RADIUS, cartesianAxisProps, seriesColor } from \"./config\";\nimport { ChartFrame } from \"./frame\";\nimport type { LineChartNumericKeys } from \"./line\";\nimport { type ChartSeriesDescriptor, resolveChartSeries, type XYPoint } from \"./series\";\n\nexport type SlotBarItem = {\n\tcolor: string;\n\theight?: number;\n\tlabel?: string;\n};\n\nexport type SlotBarItemsProps = {\n\titems: SlotBarItem[];\n\tariaLabel?: string;\n\theightClass?: string;\n\tgapClass?: string;\n\temptyClass?: string;\n\tclassName?: string;\n};\n\nexport type SlotBarDataProps<\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\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 type SlotBarChartProps<\n\tTData extends { x: string | number } = XYPoint,\n\tK extends LineChartNumericKeys<TData> & string = LineChartNumericKeys<TData> & string,\n> = SlotBarItemsProps | SlotBarDataProps<TData, K>;\n\nexport function SlotBarChart<\n\tTData extends { x: string | number } = XYPoint,\n\tK extends LineChartNumericKeys<TData> & string = LineChartNumericKeys<TData> & string,\n>(props: SlotBarChartProps<TData, K>) {\n\tif (\"items\" in props) {\n\t\treturn <SlotItemBars {...props} />;\n\t}\n\tconst {\n\t\tseries,\n\t\tariaLabel = \"Slot bar chart\",\n\t\tclassName,\n\t\tsummary,\n\t\tdataAlternative,\n\t\taccessibilityLayer,\n\t} = props;\n\tconst bars = resolveChartSeries(series, [\"y\" as K]);\n\treturn (\n\t\t<ChartFrame\n\t\t\tariaLabel={ariaLabel}\n\t\t\tclassName={className}\n\t\t\tsummary={summary}\n\t\t\tdataAlternative={dataAlternative}\n\t\t\taccessibilityLayer={accessibilityLayer}\n\t\t>\n\t\t\t<RechartsBar data={props.data}>\n\t\t\t\t<XAxis dataKey=\"x\" {...cartesianAxisProps(true)} />\n\t\t\t\t<YAxis {...cartesianAxisProps(true)} />\n\t\t\t\t{bars.map((item, index) => (\n\t\t\t\t\t<Bar\n\t\t\t\t\t\tkey={item.key}\n\t\t\t\t\t\tdataKey={item.key}\n\t\t\t\t\t\tname={item.label ?? item.key}\n\t\t\t\t\t\tfill={seriesColor(item, index)}\n\t\t\t\t\t\tradius={BAR_RADIUS.vertical}\n\t\t\t\t\t\t{...ANIMATION_PROPS}\n\t\t\t\t\t/>\n\t\t\t\t))}\n\t\t\t</RechartsBar>\n\t\t</ChartFrame>\n\t);\n}\n\nfunction SlotItemBars({\n\titems,\n\tariaLabel = \"Slot bar chart\",\n\theightClass = \"h-basalt-6\",\n\tgapClass = \"gap-px\",\n\temptyClass = \"bg-basalt-muted\",\n\tclassName,\n}: SlotBarItemsProps) {\n\tif (items.length === 0) {\n\t\treturn null;\n\t}\n\tconst hasTooltips = items.some((item) => item.label);\n\tfunction renderBar(item: SlotBarItem) {\n\t\tconst heightRatio = item.height ?? 1;\n\t\tconst isEmpty = heightRatio <= 0;\n\t\tconst isTailwindColor = item.color.startsWith(\"bg-\");\n\t\tconst heightPercent = isEmpty ? 100 : Math.max(heightRatio * 100, 10);\n\t\treturn (\n\t\t\t<div\n\t\t\t\tclassName={cn(\n\t\t\t\t\t\"w-full rounded-basalt-sm\",\n\t\t\t\t\tisEmpty ? emptyClass : isTailwindColor ? item.color : undefined,\n\t\t\t\t)}\n\t\t\t\tstyle={{\n\t\t\t\t\theight: `${heightPercent}%`,\n\t\t\t\t\t...(isEmpty || isTailwindColor ? {} : { backgroundColor: item.color }),\n\t\t\t\t}}\n\t\t\t\tdata-testid=\"slot-bar\"\n\t\t\t/>\n\t\t);\n\t}\n\tconst content = items.map((item, index) => {\n\t\tconst bar =\n\t\t\thasTooltips && item.label ? (\n\t\t\t\t<Tooltip>\n\t\t\t\t\t<TooltipTrigger asChild>{renderBar(item)}</TooltipTrigger>\n\t\t\t\t\t<TooltipContent side=\"top\">\n\t\t\t\t\t\t<p>{item.label}</p>\n\t\t\t\t\t</TooltipContent>\n\t\t\t\t</Tooltip>\n\t\t\t) : (\n\t\t\t\trenderBar(item)\n\t\t\t);\n\t\treturn (\n\t\t\t<div\n\t\t\t\tkey={`${item.label ?? item.color}-${index}`}\n\t\t\t\tclassName=\"flex min-h-0 min-w-0 flex-1 items-end self-stretch\"\n\t\t\t>\n\t\t\t\t{bar}\n\t\t\t</div>\n\t\t);\n\t});\n\tconst container = (\n\t\t<div\n\t\t\tclassName={cn(\"flex w-full items-end\", heightClass, gapClass, className)}\n\t\t\trole=\"img\"\n\t\t\taria-label={ariaLabel}\n\t\t>\n\t\t\t{content}\n\t\t</div>\n\t);\n\tif (hasTooltips) {\n\t\treturn <TooltipProvider delayDuration={0}>{container}</TooltipProvider>;\n\t}\n\treturn container;\n}\n"],"mappings":";;;;;;;;;AA+DA,SAAgBG,EAGd,GAAoC;CACrC,IAAI,WAAWC,GACd,OAAO,kBAACC,GAAD,EAAc,GAAID,EAAQ,CAAA;CAElC,IAAM,EACL,WACA,eAAY,kBACZ,cACA,YACA,oBACA,0BACGA,GACEE,IAAOC,EAAmBC,GAAQ,CAAC,GAAQ,CAAC;CAClD,OACC,kBAACC,GAAD;EACY;EACA;EACF;EACQ;EACG;EAEpB,UAAA,kBAACT,GAAD;GAAa,MAAMI,EAAM;GAAzB,UAAA;IACC,kBAACO,GAAD;KAAO,SAAQ;KAAI,GAAIC,EAAmB,EAAI;IAAI,CAAA;IAClD,kBAACC,GAAD,EAAO,GAAID,EAAmB,EAAI,EAAI,CAAA;IACrCN,EAAK,KAAK,GAAM,MAChB,kBAACQ,GAAD;KAEC,SAASC,EAAK;KACd,MAAMA,EAAK,SAASA,EAAK;KACzB,MAAMC,EAAYD,GAAME,CAAK;KAC7B,QAAQC,EAAW;KACnB,GAAIC;IACJ,GANKJ,EAAK,GAMV,CACD;GACW;;CACF,CAAA;AAEd;AAEA,SAASV,EAAa,EACrB,UACA,eAAY,kBACZ,iBAAc,cACd,cAAW,UACX,gBAAa,mBACb,gBACqB;CACrB,IAAIe,EAAM,WAAW,GACpB,OAAO;CAER,IAAMC,IAAcD,EAAM,MAAM,MAASL,EAAK,KAAK;CACnD,SAASO,EAAU,GAAmB;EACrC,IAAMC,IAAcR,EAAK,UAAU,GAC7BS,IAAUD,KAAe,GACzBE,IAAkBV,EAAK,MAAM,WAAW,KAAK,GAC7CW,IAAgBF,IAAU,MAAM,KAAK,IAAID,IAAc,KAAK,EAAE;EACpE,OACC,kBAAC,OAAD;GACC,WAAWI,EACV,4BACAH,IAAUI,IAAaH,IAAkBV,EAAK,QAAQ,KAAA,CACvD;GACA,OAAO;IACN,QAAQ,GAAGW,EAAc;IACzB,GAAIF,KAAWC,IAAkB,CAAC,IAAI,EAAE,iBAAiBV,EAAK,MAAM;GACrE;GACA,eAAY;EACZ,CAAA;CAEH;CACA,IAAMc,IAAUT,EAAM,KAAK,GAAM,MAAU;EAC1C,IAAMU,IACLT,KAAeN,EAAK,QACnB,kBAACd,GAAD,EAAA,UAAA,CACC,kBAAC8B,GAAD;GAAgB,SAAA;GAAS,UAAAT,EAAUP,CAAI;EAAkB,CAAA,GACzD,kBAACiB,GAAD;GAAgB,MAAK;GACpB,UAAA,kBAAC,KAAD,EAAA,UAAIjB,EAAK,MAAS,CAAA;EACH,CAAA,CACR,EAAA,CAAA,IAETO,EAAUP,CAAI;EAEhB,OACC,kBAAC,OAAD;GAEC,WAAU;GAET,UAAAe;EACG,GAJC,GAAGf,EAAK,SAASA,EAAK,MAAM,GAAGE,GAIhC;CAEP,CAAC,GACKgB,IACL,kBAAC,OAAD;EACC,WAAWN,EAAG,yBAAyBO,GAAaC,GAAUC,CAAS;EACvE,MAAK;EACL,cAAYC;EAEX,UAAAR;CACG,CAAA;CAKN,OAHIR,IACI,kBAACiB,GAAD;EAAiB,eAAe;EAAI,UAAAL;CAA2B,CAAA,IAEhEA;AACR"}