@nocoo/basalt 2.0.3 → 2.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (295) hide show
  1. package/README.md +134 -15
  2. package/ai/COMPATIBILITY.md +180 -0
  3. package/ai/INTEGRATION.md +1760 -0
  4. package/ai/RECIPES.md +161 -0
  5. package/ai/USAGE.md +99 -0
  6. package/ai/registry.json +38099 -0
  7. package/ai/sources.json +10 -0
  8. package/dist/assets/brand-mark.d.ts +1 -0
  9. package/dist/assets/brand-mark.js +7 -0
  10. package/dist/assets/brand-mark.js.map +1 -0
  11. package/dist/charts/area.d.ts +58 -5
  12. package/dist/charts/area.js +20 -12
  13. package/dist/charts/area.js.map +1 -1
  14. package/dist/charts/bar.d.ts +54 -5
  15. package/dist/charts/bar.js +16 -10
  16. package/dist/charts/bar.js.map +1 -1
  17. package/dist/charts/bullet.d.ts +18 -1
  18. package/dist/charts/bullet.js +6 -3
  19. package/dist/charts/bullet.js.map +1 -1
  20. package/dist/charts/charts.d.ts +58 -5
  21. package/dist/charts/charts.js +13 -2
  22. package/dist/charts/charts.js.map +1 -1
  23. package/dist/charts/config.d.ts +7 -0
  24. package/dist/charts/config.js +5 -1
  25. package/dist/charts/config.js.map +1 -1
  26. package/dist/charts/custom-chart.d.ts +58 -5
  27. package/dist/charts/custom-chart.js +13 -2
  28. package/dist/charts/custom-chart.js.map +1 -1
  29. package/dist/charts/donut.d.ts +18 -1
  30. package/dist/charts/donut.js +6 -3
  31. package/dist/charts/donut.js.map +1 -1
  32. package/dist/charts/frame.d.ts +40 -3
  33. package/dist/charts/frame.js +55 -28
  34. package/dist/charts/frame.js.map +1 -1
  35. package/dist/charts/funnel.d.ts +18 -1
  36. package/dist/charts/funnel.js +5 -1
  37. package/dist/charts/funnel.js.map +1 -1
  38. package/dist/charts/gauge.d.ts +18 -1
  39. package/dist/charts/gauge.js +38 -20
  40. package/dist/charts/gauge.js.map +1 -1
  41. package/dist/charts/grouped-bar.d.ts +54 -5
  42. package/dist/charts/grouped-bar.js +16 -10
  43. package/dist/charts/grouped-bar.js.map +1 -1
  44. package/dist/charts/heatmap-calendar.d.ts +61 -0
  45. package/dist/charts/heatmap-calendar.js +287 -96
  46. package/dist/charts/heatmap-calendar.js.map +1 -1
  47. package/dist/charts/heatmap-matrix.d.ts +99 -0
  48. package/dist/charts/heatmap-matrix.js +249 -0
  49. package/dist/charts/heatmap-matrix.js.map +1 -0
  50. package/dist/charts/line.d.ts +66 -5
  51. package/dist/charts/line.js +37 -30
  52. package/dist/charts/line.js.map +1 -1
  53. package/dist/charts/palette.d.ts +1 -0
  54. package/dist/charts/palette.js +7 -1
  55. package/dist/charts/palette.js.map +1 -1
  56. package/dist/charts/radar.d.ts +18 -1
  57. package/dist/charts/radar.js +26 -19
  58. package/dist/charts/radar.js.map +1 -1
  59. package/dist/charts/sankey.d.ts +18 -1
  60. package/dist/charts/sankey.js +4 -1
  61. package/dist/charts/sankey.js.map +1 -1
  62. package/dist/charts/series.d.ts +5 -7
  63. package/dist/charts/series.js.map +1 -1
  64. package/dist/charts/slot-bar.d.ts +38 -6
  65. package/dist/charts/slot-bar.js +5 -2
  66. package/dist/charts/slot-bar.js.map +1 -1
  67. package/dist/charts/sparkline.d.ts +35 -5
  68. package/dist/charts/sparkline.js +22 -18
  69. package/dist/charts/sparkline.js.map +1 -1
  70. package/dist/charts/stacked-bar.d.ts +58 -5
  71. package/dist/charts/stacked-bar.js +19 -12
  72. package/dist/charts/stacked-bar.js.map +1 -1
  73. package/dist/charts/stat-card.d.ts +51 -1
  74. package/dist/charts/stat-card.js +66 -39
  75. package/dist/charts/stat-card.js.map +1 -1
  76. package/dist/charts/timeline.d.ts +3 -0
  77. package/dist/charts/timeline.js +4 -3
  78. package/dist/charts/timeline.js.map +1 -1
  79. package/dist/charts/timeseries.d.ts +58 -5
  80. package/dist/charts/timeseries.js +13 -2
  81. package/dist/charts/timeseries.js.map +1 -1
  82. package/dist/charts/tooltip.d.ts +57 -0
  83. package/dist/charts/tooltip.js +119 -2
  84. package/dist/charts/tooltip.js.map +1 -1
  85. package/dist/components/accordion.d.ts +117 -2
  86. package/dist/components/accordion.js +20 -13
  87. package/dist/components/accordion.js.map +1 -1
  88. package/dist/components/alert-dialog.d.ts +131 -13
  89. package/dist/components/alert-dialog.js +12 -9
  90. package/dist/components/alert-dialog.js.map +1 -1
  91. package/dist/components/app-header.js +18 -17
  92. package/dist/components/app-header.js.map +1 -1
  93. package/dist/components/app-shell.js +15 -14
  94. package/dist/components/app-shell.js.map +1 -1
  95. package/dist/components/autocomplete.d.ts +4 -0
  96. package/dist/components/autocomplete.js.map +1 -1
  97. package/dist/components/avatar.d.ts +76 -3
  98. package/dist/components/avatar.js.map +1 -1
  99. package/dist/components/badge.d.ts +15 -1
  100. package/dist/components/badge.js +17 -16
  101. package/dist/components/badge.js.map +1 -1
  102. package/dist/components/banner.d.ts +88 -2
  103. package/dist/components/banner.js +41 -40
  104. package/dist/components/banner.js.map +1 -1
  105. package/dist/components/basalt-mark.js +14 -8
  106. package/dist/components/basalt-mark.js.map +1 -1
  107. package/dist/components/battery-meter.d.ts +10 -0
  108. package/dist/components/battery-meter.js +56 -0
  109. package/dist/components/battery-meter.js.map +1 -0
  110. package/dist/components/breadcrumbs.d.ts +27 -7
  111. package/dist/components/breadcrumbs.js +21 -20
  112. package/dist/components/breadcrumbs.js.map +1 -1
  113. package/dist/components/button.d.ts +48 -2
  114. package/dist/components/button.js +87 -36
  115. package/dist/components/button.js.map +1 -1
  116. package/dist/components/chat-bubble.d.ts +7 -0
  117. package/dist/components/chat-bubble.js +14 -13
  118. package/dist/components/chat-bubble.js.map +1 -1
  119. package/dist/components/chat-composer.d.ts +7 -3
  120. package/dist/components/chat-composer.js.map +1 -1
  121. package/dist/components/chat-header.d.ts +6 -1
  122. package/dist/components/chat-header.js +17 -16
  123. package/dist/components/chat-header.js.map +1 -1
  124. package/dist/components/chat-inbox.d.ts +7 -2
  125. package/dist/components/chat-inbox.js.map +1 -1
  126. package/dist/components/checkbox.js +84 -53
  127. package/dist/components/checkbox.js.map +1 -1
  128. package/dist/components/clipboard-text.d.ts +13 -2
  129. package/dist/components/clipboard-text.js +4 -4
  130. package/dist/components/clipboard-text.js.map +1 -1
  131. package/dist/components/collapsible.d.ts +58 -15
  132. package/dist/components/collapsible.js.map +1 -1
  133. package/dist/components/command-palette.d.ts +151 -61
  134. package/dist/components/command-palette.js.map +1 -1
  135. package/dist/components/confirm-dialog.d.ts +1 -1
  136. package/dist/components/confirm-dialog.js +6 -4
  137. package/dist/components/confirm-dialog.js.map +1 -1
  138. package/dist/components/context-menu.d.ts +210 -2
  139. package/dist/components/context-menu.js +7 -4
  140. package/dist/components/context-menu.js.map +1 -1
  141. package/dist/components/data-table.d.ts +40 -2
  142. package/dist/components/data-table.js +168 -120
  143. package/dist/components/data-table.js.map +1 -1
  144. package/dist/components/date-picker.d.ts +53 -2
  145. package/dist/components/date-picker.js +387 -219
  146. package/dist/components/date-picker.js.map +1 -1
  147. package/dist/components/delete-resource.d.ts +7 -1
  148. package/dist/components/delete-resource.js +22 -18
  149. package/dist/components/delete-resource.js.map +1 -1
  150. package/dist/components/description-list.js +16 -15
  151. package/dist/components/description-list.js.map +1 -1
  152. package/dist/components/dialog.d.ts +141 -12
  153. package/dist/components/dialog.js +42 -38
  154. package/dist/components/dialog.js.map +1 -1
  155. package/dist/components/dock.d.ts +1 -1
  156. package/dist/components/dock.js +39 -58
  157. package/dist/components/dock.js.map +1 -1
  158. package/dist/components/dropdown-menu.d.ts +229 -15
  159. package/dist/components/dropdown-menu.js +9 -6
  160. package/dist/components/dropdown-menu.js.map +1 -1
  161. package/dist/components/editable-nav-item.d.ts +33 -0
  162. package/dist/components/editable-nav-item.js +90 -0
  163. package/dist/components/editable-nav-item.js.map +1 -0
  164. package/dist/components/empty.d.ts +22 -2
  165. package/dist/components/empty.js +22 -13
  166. package/dist/components/empty.js.map +1 -1
  167. package/dist/components/field.js +31 -30
  168. package/dist/components/field.js.map +1 -1
  169. package/dist/components/file-dropzone.d.ts +37 -0
  170. package/dist/components/file-dropzone.js +103 -0
  171. package/dist/components/file-dropzone.js.map +1 -0
  172. package/dist/components/filter-bar.d.ts +34 -0
  173. package/dist/components/filter-bar.js +52 -0
  174. package/dist/components/filter-bar.js.map +1 -0
  175. package/dist/components/flow.js +19 -18
  176. package/dist/components/flow.js.map +1 -1
  177. package/dist/components/grid.d.ts +3 -1
  178. package/dist/components/grid.js.map +1 -1
  179. package/dist/components/hover-card.d.ts +111 -1
  180. package/dist/components/hover-card.js +9 -6
  181. package/dist/components/hover-card.js.map +1 -1
  182. package/dist/components/icon-picker.d.ts +34 -0
  183. package/dist/components/icon-picker.js +77 -0
  184. package/dist/components/icon-picker.js.map +1 -0
  185. package/dist/components/inline-editable.d.ts +46 -0
  186. package/dist/components/inline-editable.js +124 -0
  187. package/dist/components/inline-editable.js.map +1 -0
  188. package/dist/components/input-area.js +3 -3
  189. package/dist/components/input-group.js +7 -7
  190. package/dist/components/input.js +3 -3
  191. package/dist/components/label.js +18 -17
  192. package/dist/components/label.js.map +1 -1
  193. package/dist/components/layer-card.d.ts +10 -2
  194. package/dist/components/layer-card.js +71 -68
  195. package/dist/components/layer-card.js.map +1 -1
  196. package/dist/components/loader.d.ts +10 -2
  197. package/dist/components/loader.js.map +1 -1
  198. package/dist/components/menu-bar.d.ts +174 -6
  199. package/dist/components/menu-bar.js +33 -29
  200. package/dist/components/menu-bar.js.map +1 -1
  201. package/dist/components/meter.d.ts +27 -2
  202. package/dist/components/meter.js.map +1 -1
  203. package/dist/components/multi-select.d.ts +64 -0
  204. package/dist/components/multi-select.js +218 -0
  205. package/dist/components/multi-select.js.map +1 -0
  206. package/dist/components/navigation-menu.d.ts +88 -5
  207. package/dist/components/navigation-menu.js.map +1 -1
  208. package/dist/components/overlay.js +6 -5
  209. package/dist/components/overlay.js.map +1 -1
  210. package/dist/components/page-header.js +23 -21
  211. package/dist/components/page-header.js.map +1 -1
  212. package/dist/components/pagination.js +7 -7
  213. package/dist/components/popover.d.ts +136 -16
  214. package/dist/components/popover.js +32 -28
  215. package/dist/components/popover.js.map +1 -1
  216. package/dist/components/radio.js +38 -37
  217. package/dist/components/radio.js.map +1 -1
  218. package/dist/components/resource-list.d.ts +26 -1
  219. package/dist/components/resource-list.js +28 -15
  220. package/dist/components/resource-list.js.map +1 -1
  221. package/dist/components/responsive-master-detail.d.ts +27 -0
  222. package/dist/components/responsive-master-detail.js +85 -0
  223. package/dist/components/responsive-master-detail.js.map +1 -0
  224. package/dist/components/section-rule.js +23 -22
  225. package/dist/components/section-rule.js.map +1 -1
  226. package/dist/components/select.d.ts +27 -3
  227. package/dist/components/select.js +11 -11
  228. package/dist/components/select.js.map +1 -1
  229. package/dist/components/sheet.d.ts +115 -11
  230. package/dist/components/sheet.js +37 -30
  231. package/dist/components/sheet.js.map +1 -1
  232. package/dist/components/sidebar.d.ts +109 -17
  233. package/dist/components/sidebar.js +109 -108
  234. package/dist/components/sidebar.js.map +1 -1
  235. package/dist/components/skeleton-line.d.ts +22 -2
  236. package/dist/components/skeleton-line.js.map +1 -1
  237. package/dist/components/slider.d.ts +61 -1
  238. package/dist/components/slider.js +31 -15
  239. package/dist/components/slider.js.map +1 -1
  240. package/dist/components/stat-strip.js +16 -15
  241. package/dist/components/stat-strip.js.map +1 -1
  242. package/dist/components/switch.js +78 -47
  243. package/dist/components/switch.js.map +1 -1
  244. package/dist/components/table-of-contents.js +18 -17
  245. package/dist/components/table-of-contents.js.map +1 -1
  246. package/dist/components/table-pager.js +20 -19
  247. package/dist/components/table-pager.js.map +1 -1
  248. package/dist/components/table.d.ts +9 -3
  249. package/dist/components/table.js +19 -18
  250. package/dist/components/table.js.map +1 -1
  251. package/dist/components/tabs.js +29 -22
  252. package/dist/components/tabs.js.map +1 -1
  253. package/dist/components/tag-badge.d.ts +58 -0
  254. package/dist/components/tag-badge.js +72 -0
  255. package/dist/components/tag-badge.js.map +1 -0
  256. package/dist/components/tag-color-picker.d.ts +20 -0
  257. package/dist/components/tag-color-picker.js +42 -0
  258. package/dist/components/tag-color-picker.js.map +1 -0
  259. package/dist/components/text.js +17 -16
  260. package/dist/components/text.js.map +1 -1
  261. package/dist/components/toast.d.ts +173 -3
  262. package/dist/components/toast.js +1 -1
  263. package/dist/components/toast.js.map +1 -1
  264. package/dist/components/toggle-group.d.ts +88 -2
  265. package/dist/components/toggle-group.js +32 -31
  266. package/dist/components/toggle-group.js.map +1 -1
  267. package/dist/components/toggle.d.ts +35 -2
  268. package/dist/components/toggle.js +12 -11
  269. package/dist/components/toggle.js.map +1 -1
  270. package/dist/components/tooltip.d.ts +144 -6
  271. package/dist/components/tooltip.js +9 -6
  272. package/dist/components/tooltip.js.map +1 -1
  273. package/dist/components/typeahead-field.js +193 -132
  274. package/dist/components/typeahead-field.js.map +1 -1
  275. package/dist/components/upload-queue.d.ts +51 -0
  276. package/dist/components/upload-queue.js +116 -0
  277. package/dist/components/upload-queue.js.map +1 -0
  278. package/dist/providers/accent.d.ts +46 -2
  279. package/dist/providers/accent.js +358 -172
  280. package/dist/providers/accent.js.map +1 -1
  281. package/dist/providers/link.d.ts +14 -4
  282. package/dist/providers/link.js.map +1 -1
  283. package/dist/providers/theme.d.ts +38 -2
  284. package/dist/providers/theme.js +160 -27
  285. package/dist/providers/theme.js.map +1 -1
  286. package/dist/styles/base.css +83 -0
  287. package/dist/styles/standalone.css +711 -120
  288. package/dist/styles/tailwind.css +21 -7
  289. package/dist/styles/tokens.css +145 -91
  290. package/dist/utils/control-surface.d.ts +2 -1
  291. package/dist/utils/control-surface.js +4 -4
  292. package/dist/utils/control-surface.js.map +1 -1
  293. package/dist/utils/selection-indicator.js +2 -2
  294. package/dist/utils/selection-indicator.js.map +1 -1
  295. package/package.json +8 -4
@@ -1,10 +1,10 @@
1
1
  "use client";
2
2
  import { cn as e } from "../utils/cn.js";
3
3
  import { Tooltip as t, TooltipContent as n, TooltipProvider as r, TooltipTrigger as i } from "../components/tooltip.js";
4
- import { useMemo as a } from "react";
5
- import { jsx as o, jsxs as s } from "react/jsx-runtime";
4
+ import { useEffect as a, useId as o, useMemo as s, useRef as c, useState as l } from "react";
5
+ import { jsx as u, jsxs as d } from "react/jsx-runtime";
6
6
  //#region src/charts/heatmap-calendar.tsx
7
- var c = {
7
+ var f = {
8
8
  green: [
9
9
  "hsl(var(--basalt-muted))",
10
10
  "hsl(var(--basalt-heatmap-green-1))",
@@ -34,165 +34,356 @@ var c = {
34
34
  "hsl(var(--basalt-heatmap-orange-4))"
35
35
  ]
36
36
  };
37
- function l(e) {
37
+ function p(e) {
38
38
  return Array.from({ length: 7 }, (t, n) => new Intl.DateTimeFormat(e, { weekday: "short" }).format(new Date(2023, 0, 1 + n)));
39
39
  }
40
- function u(e) {
40
+ function m(e) {
41
41
  return Array.from({ length: 12 }, (t, n) => new Intl.DateTimeFormat(e, { month: "short" }).format(new Date(2023, n, 1)));
42
42
  }
43
- function d(e) {
43
+ function h(e) {
44
44
  let t = [], n = new Date(e, 0, 1), r = new Date(e, 11, 31), i = new Date(n);
45
45
  i.setDate(i.getDate() - i.getDay());
46
46
  let a = new Date(i), o = [];
47
47
  for (; (a <= r || o.length > 0) && (o.length === 7 && (t.push(o), o = []), !(a > r));) o.push(new Date(a)), a = new Date(a), a.setDate(a.getDate() + 1);
48
48
  return o.length > 0 && t.push(o), t;
49
49
  }
50
- function f(e) {
50
+ function g(e) {
51
51
  return `${e.getFullYear()}-${String(e.getMonth() + 1).padStart(2, "0")}-${String(e.getDate()).padStart(2, "0")}`;
52
52
  }
53
- function p(e, t, n) {
53
+ function _(e, t, n) {
54
54
  if (e === 0) return 0;
55
55
  let r = n.length - 1, i = Math.min(e / t, 1);
56
56
  return Math.ceil(i * r);
57
57
  }
58
- function m(t) {
59
- if ("data" in t) {
60
- let { colorScale: e = c.green, valueFormatter: n = (e) => e.toLocaleString(), metricLabel: r = "Value", cellSize: i = 12, cellGap: a = 2, locale: s = "en-US", weekdayLabels: l, monthLabels: u, lessLabel: d = "Less", moreLabel: f = "More", ariaLabel: p = "Heatmap calendar", className: m } = t;
61
- return /* @__PURE__ */ o(h, {
62
- data: t.data,
63
- year: t.year,
64
- colorScale: e,
58
+ function v(e) {
59
+ if ("data" in e) {
60
+ let { colorScale: t = f.green, valueFormatter: n = (e) => e.toLocaleString(), metricLabel: r = "Value", cellSize: i = 12, cellGap: a = 2, locale: o = "en-US", weekdayLabels: s, monthLabels: c, lessLabel: l = "Less", moreLabel: d = "More", ariaLabel: p = "Heatmap calendar", className: m } = e;
61
+ return /* @__PURE__ */ u(b, {
62
+ data: e.data,
63
+ year: e.year,
64
+ colorScale: t,
65
65
  valueFormatter: n,
66
66
  metricLabel: r,
67
67
  cellSize: i,
68
68
  cellGap: a,
69
- locale: s,
70
- weekdayLabels: l,
71
- monthLabels: u,
72
- lessLabel: d,
73
- moreLabel: f,
69
+ locale: o,
70
+ weekdayLabels: s,
71
+ monthLabels: c,
72
+ lessLabel: l,
73
+ moreLabel: d,
74
74
  ariaLabel: p,
75
75
  className: m
76
76
  });
77
77
  }
78
- let { ariaLabel: n = "Heatmap calendar", className: r } = t;
79
- return /* @__PURE__ */ o("div", {
80
- className: e("grid grid-cols-7 gap-1", r),
81
- role: "img",
82
- "aria-label": n,
83
- children: t.values.map((e, t) => /* @__PURE__ */ o("span", {
84
- className: "h-3 w-3 rounded-sm bg-basalt-primary",
85
- style: { opacity: .2 + Math.min(4, Math.max(0, e)) * .15 }
86
- }, t))
78
+ let { ariaLabel: t = "Heatmap calendar", className: n } = e;
79
+ return /* @__PURE__ */ u(y, {
80
+ values: e.values,
81
+ ariaLabel: t,
82
+ className: n
87
83
  });
88
84
  }
89
- function h({ data: c, year: m, colorScale: h, valueFormatter: g, metricLabel: _, cellSize: v, cellGap: y, locale: b, weekdayLabels: x, monthLabels: S, lessLabel: C, moreLabel: w, ariaLabel: T, className: E }) {
90
- let D = x ?? l(b), O = S ?? u(b), { weeks: k, dataMap: A, maxValue: j, labels: M } = a(() => {
91
- let e = d(m), t = /* @__PURE__ */ new Map(), n = 0;
92
- for (let e of c) t.set(e.date, e.value), e.value > n && (n = e.value);
85
+ function y({ values: o, ariaLabel: s, className: f }) {
86
+ let [p, m] = l(0), [h, g] = l(null), _ = c(null), v = c([]), y = c(!1);
87
+ a(() => {
88
+ let e = y.current;
89
+ if (o.length === 0) m(0), g(null), e && _.current?.focus();
90
+ else if (p >= o.length) {
91
+ let t = o.length - 1;
92
+ m(t), e && v.current[t]?.focus();
93
+ } else e && v.current[p]?.focus();
94
+ }, [o.length, p]);
95
+ let b = (e, t) => {
96
+ if (o.length === 0) return;
97
+ if (e.key === "Escape") {
98
+ g(null);
99
+ return;
100
+ }
101
+ let n = t;
102
+ if (e.key === "ArrowRight") n = Math.min(o.length - 1, t + 1);
103
+ else if (e.key === "ArrowLeft") n = Math.max(0, t - 1);
104
+ else if (e.key === "ArrowDown") n = Math.min(o.length - 1, t + 7);
105
+ else if (e.key === "ArrowUp") n = Math.max(0, t - 7);
106
+ else if (e.key === "Home") n = 0;
107
+ else if (e.key === "End") n = o.length - 1;
108
+ else return;
109
+ e.preventDefault(), m(n), g(n), v.current[n]?.focus();
110
+ };
111
+ return o.length === 0 ? /* @__PURE__ */ u("div", {
112
+ ref: _,
113
+ tabIndex: -1,
114
+ role: "region",
115
+ "aria-label": s,
116
+ onFocus: () => {
117
+ y.current = !0;
118
+ },
119
+ onBlur: (e) => {
120
+ e.currentTarget.contains(e.relatedTarget) || (y.current = !1);
121
+ },
122
+ className: e("grid grid-cols-7 gap-1 p-0.5 outline-none", f)
123
+ }) : /* @__PURE__ */ u(r, { children: /* @__PURE__ */ u("div", {
124
+ ref: _,
125
+ tabIndex: -1,
126
+ role: "region",
127
+ "aria-label": s,
128
+ onFocus: () => {
129
+ y.current = !0;
130
+ },
131
+ onBlur: (e) => {
132
+ e.currentTarget.contains(e.relatedTarget) || (y.current = !1);
133
+ },
134
+ className: e("grid grid-cols-7 gap-1 p-0.5 outline-none", f),
135
+ children: o.map((e, r) => /* @__PURE__ */ d(t, {
136
+ open: h === r,
137
+ onOpenChange: (e) => {
138
+ g(e ? r : (e) => e === r ? v.current[r] !== null && document.activeElement === v.current[r] ? e : null : e);
139
+ },
140
+ children: [/* @__PURE__ */ u(i, {
141
+ asChild: !0,
142
+ children: /* @__PURE__ */ u("button", {
143
+ ref: (e) => {
144
+ v.current[r] = e;
145
+ },
146
+ type: "button",
147
+ tabIndex: r === p ? 0 : -1,
148
+ onFocus: () => {
149
+ m(r), g(r);
150
+ },
151
+ onBlur: () => {
152
+ g((e) => e === r ? null : e);
153
+ },
154
+ onKeyDown: (e) => b(e, r),
155
+ "aria-label": `Position ${r + 1}: ${e}`,
156
+ className: "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",
157
+ style: { backgroundColor: `hsl(var(--basalt-chart-5) / ${.2 + Math.min(4, Math.max(0, e)) * .15})` }
158
+ })
159
+ }), /* @__PURE__ */ u(n, { children: /* @__PURE__ */ d("div", {
160
+ className: "text-xs",
161
+ children: [
162
+ "Position ",
163
+ r + 1,
164
+ ": ",
165
+ e
166
+ ]
167
+ }) })]
168
+ }, r))
169
+ }) });
170
+ }
171
+ function b({ data: f, year: v, colorScale: y, valueFormatter: b, metricLabel: x, cellSize: S, cellGap: C, locale: w, weekdayLabels: T, monthLabels: E, lessLabel: D, moreLabel: O, ariaLabel: k, className: A }) {
172
+ let j = T ?? p(w), M = E ?? m(w), N = o(), P = c(null), { weeks: F, dataMap: I, maxValue: L, labels: R, validDays: z, dateToValidIndex: B } = s(() => {
173
+ let e = h(v), t = /* @__PURE__ */ new Map(), n = 0;
174
+ for (let e of f) t.set(e.date, e.value), e.value > n && (n = e.value);
93
175
  let r = [], i = -1;
94
- return e.forEach((e, t) => {
95
- let n = e.find((e) => e.getFullYear() === m);
176
+ e.forEach((e, t) => {
177
+ let n = e.find((e) => e.getFullYear() === v);
96
178
  if (n) {
97
179
  let e = n.getMonth();
98
180
  e !== i && (r.push({
99
- month: O[e],
181
+ month: M[e],
100
182
  weekIndex: t
101
183
  }), i = e);
102
184
  }
185
+ });
186
+ let a = [], o = /* @__PURE__ */ new Map();
187
+ return e.forEach((e, r) => {
188
+ e.forEach((e, i) => {
189
+ if (e.getFullYear() === v) {
190
+ let s = g(e), c = t.get(s) ?? 0, l = _(c, n, y);
191
+ o.set(s, a.length), a.push({
192
+ dateStr: s,
193
+ value: c,
194
+ weekIndex: r,
195
+ dayIndex: i,
196
+ colorIndex: l
197
+ });
198
+ }
199
+ });
103
200
  }), {
104
201
  weeks: e,
105
202
  dataMap: t,
106
203
  maxValue: n,
107
- labels: r
204
+ labels: r,
205
+ validDays: a,
206
+ dateToValidIndex: o
108
207
  };
109
208
  }, [
110
- c,
111
- O,
112
- m
209
+ f,
210
+ M,
211
+ v,
212
+ y
213
+ ]), [V, H] = l(() => z[0]?.dateStr ?? `${v}-01-01`), [U, W] = l(null), G = c(/* @__PURE__ */ new Map()), K = c(!1);
214
+ a(() => {
215
+ let e = K.current;
216
+ if (z.length === 0) H(""), W(null), e && P.current?.focus();
217
+ else if (!B.has(V)) {
218
+ let t = z[0]?.dateStr ?? "";
219
+ H(t), e && G.current.get(t)?.focus();
220
+ }
221
+ }, [
222
+ z,
223
+ B,
224
+ V
113
225
  ]);
114
- return /* @__PURE__ */ o("div", {
115
- className: e("overflow-x-auto", E),
116
- role: "img",
117
- "aria-label": T,
118
- children: /* @__PURE__ */ o(r, { children: /* @__PURE__ */ s("div", {
119
- className: "inline-block",
226
+ let q = s(() => {
227
+ let e = B.get(V);
228
+ return e === void 0 ? z[0] : z[e];
229
+ }, [
230
+ V,
231
+ B,
232
+ z
233
+ ]), J = (e) => {
234
+ e && (H(e.dateStr), W(e.dateStr), G.current.get(e.dateStr)?.focus());
235
+ }, Y = (e, t) => {
236
+ if (z.length === 0) return;
237
+ let n = B.get(t.dateStr) ?? 0;
238
+ if (e.key === "Escape") {
239
+ W(null);
240
+ return;
241
+ }
242
+ if (e.key === "ArrowDown") {
243
+ e.preventDefault();
244
+ let t = z[n + 1];
245
+ t && J(t);
246
+ } else if (e.key === "ArrowUp") {
247
+ e.preventDefault();
248
+ let t = z[n - 1];
249
+ t && J(t);
250
+ } else if (e.key === "ArrowRight") {
251
+ e.preventDefault();
252
+ let t = n + 7;
253
+ t < z.length ? J(z[t]) : J(z[z.length - 1]);
254
+ } else if (e.key === "ArrowLeft") {
255
+ e.preventDefault();
256
+ let t = n - 7;
257
+ J(t >= 0 ? z[t] : z[0]);
258
+ } else e.key === "Home" ? (e.preventDefault(), J(z[0])) : e.key === "End" && (e.preventDefault(), J(z[z.length - 1]));
259
+ };
260
+ return /* @__PURE__ */ u("div", {
261
+ ref: P,
262
+ tabIndex: -1,
263
+ role: "region",
264
+ "aria-label": `${k} scrollable view`,
265
+ onFocus: () => {
266
+ K.current = !0;
267
+ },
268
+ onBlur: (e) => {
269
+ e.currentTarget.contains(e.relatedTarget) || (K.current = !1);
270
+ },
271
+ className: e("overflow-x-auto rounded-md outline-none focus-visible:ring-1 focus-visible:ring-basalt-ring", A),
272
+ children: /* @__PURE__ */ u(r, { children: /* @__PURE__ */ d("div", {
273
+ className: "inline-block p-1",
274
+ role: "group",
275
+ "aria-label": k,
120
276
  children: [
121
- /* @__PURE__ */ o("div", {
277
+ /* @__PURE__ */ u("div", {
122
278
  className: "relative mb-1 h-4 text-xs text-basalt-muted-foreground",
123
279
  style: { marginLeft: 30 },
124
- children: M.map((e) => /* @__PURE__ */ o("div", {
280
+ children: R.map((e) => /* @__PURE__ */ u("div", {
125
281
  className: "absolute",
126
- style: { left: e.weekIndex * (v + y) },
282
+ style: { left: e.weekIndex * (S + C) },
127
283
  children: e.month
128
284
  }, `${e.month}-${e.weekIndex}`))
129
285
  }),
130
- /* @__PURE__ */ s("div", {
286
+ /* @__PURE__ */ d("div", {
131
287
  className: "flex",
132
- children: [/* @__PURE__ */ o("div", {
133
- className: "mr-1 flex flex-col text-xs text-basalt-muted-foreground",
288
+ children: [/* @__PURE__ */ u("div", {
289
+ className: "mr-1 flex flex-col text-xs text-basalt-muted-foreground select-none",
134
290
  style: { width: 30 },
135
- children: D.map((e, t) => /* @__PURE__ */ o("div", {
291
+ "aria-hidden": "true",
292
+ children: j.map((e, t) => /* @__PURE__ */ u("div", {
136
293
  style: {
137
- height: v + y,
138
- lineHeight: `${v + y}px`,
294
+ height: S + C,
295
+ lineHeight: `${S + C}px`,
139
296
  visibility: t % 2 == 1 ? "visible" : "hidden"
140
297
  },
141
298
  children: e
142
299
  }, `${e}-${t}`))
143
- }), /* @__PURE__ */ o("div", {
300
+ }), /* @__PURE__ */ u("div", {
144
301
  className: "flex",
145
- style: { gap: y },
146
- children: k.map((e, r) => /* @__PURE__ */ o("div", {
302
+ style: { gap: C },
303
+ children: F.map((e, r) => /* @__PURE__ */ u("div", {
147
304
  className: "flex flex-col",
148
- style: { gap: y },
149
- children: e.map((e, r) => {
150
- let a = f(e), c = A.get(a) ?? 0, l = e.getFullYear() === m, u = p(c, j, h);
151
- return l ? /* @__PURE__ */ s(t, { children: [/* @__PURE__ */ o(i, {
152
- asChild: !0,
153
- children: /* @__PURE__ */ o("div", {
154
- className: "cursor-pointer rounded-sm transition-colors hover:ring-1 hover:ring-basalt-foreground",
155
- style: {
156
- width: v,
157
- height: v,
158
- backgroundColor: h[u]
159
- }
160
- })
161
- }), /* @__PURE__ */ o(n, { children: /* @__PURE__ */ s("div", {
162
- className: "text-sm",
163
- children: [/* @__PURE__ */ o("div", {
164
- className: "font-medium",
165
- children: a
166
- }), /* @__PURE__ */ s("div", {
167
- className: "text-basalt-muted-foreground",
168
- children: [
169
- _,
170
- ": ",
171
- g(c, a)
172
- ]
305
+ style: { gap: C },
306
+ children: e.map((e, a) => {
307
+ let o = g(e);
308
+ if (e.getFullYear() !== v) return /* @__PURE__ */ u("div", {
309
+ style: {
310
+ width: S,
311
+ height: S,
312
+ visibility: "hidden"
313
+ },
314
+ "aria-hidden": "true"
315
+ }, a);
316
+ let s = I.get(o) ?? 0, c = _(s, L, y), l = q?.dateStr === o, f = b(s, o), p = `${o}, ${x}: ${f}`, m = U === o, h = {
317
+ dateStr: o,
318
+ value: s,
319
+ weekIndex: r,
320
+ dayIndex: a,
321
+ colorIndex: c
322
+ };
323
+ return /* @__PURE__ */ d(t, {
324
+ open: m,
325
+ onOpenChange: (e) => {
326
+ W(e ? o : (e) => e === o ? document.activeElement === G.current.get(o) ? e : null : e);
327
+ },
328
+ children: [/* @__PURE__ */ u(i, {
329
+ asChild: !0,
330
+ children: /* @__PURE__ */ u("button", {
331
+ ref: (e) => {
332
+ e ? G.current.set(o, e) : G.current.delete(o);
333
+ },
334
+ type: "button",
335
+ "aria-label": p,
336
+ tabIndex: l ? 0 : -1,
337
+ onFocus: () => {
338
+ H(o), W(o);
339
+ },
340
+ onBlur: () => {
341
+ W((e) => e === o ? null : e);
342
+ },
343
+ onKeyDown: (e) => Y(e, h),
344
+ className: "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",
345
+ style: {
346
+ width: S,
347
+ height: S,
348
+ backgroundColor: y[c]
349
+ }
350
+ })
351
+ }), /* @__PURE__ */ u(n, {
352
+ id: `${N}-${o}`,
353
+ children: /* @__PURE__ */ d("div", {
354
+ className: "text-sm",
355
+ children: [/* @__PURE__ */ u("div", {
356
+ className: "font-medium",
357
+ children: o
358
+ }), /* @__PURE__ */ d("div", {
359
+ className: "text-basalt-muted-foreground",
360
+ children: [
361
+ x,
362
+ ": ",
363
+ f
364
+ ]
365
+ })]
366
+ })
173
367
  })]
174
- }) })] }, r) : /* @__PURE__ */ o("div", { style: {
175
- width: v,
176
- height: v,
177
- visibility: "hidden"
178
- } }, r);
368
+ }, a);
179
369
  })
180
370
  }, r))
181
371
  })]
182
372
  }),
183
- /* @__PURE__ */ s("div", {
184
- className: "mt-2 flex items-center justify-end gap-1 text-xs text-basalt-muted-foreground",
373
+ /* @__PURE__ */ d("div", {
374
+ className: "mt-2 flex items-center justify-end gap-1 text-xs text-basalt-muted-foreground select-none",
375
+ "aria-hidden": "true",
185
376
  children: [
186
- /* @__PURE__ */ o("span", { children: C }),
187
- h.map((e) => /* @__PURE__ */ o("div", {
377
+ /* @__PURE__ */ u("span", { children: D }),
378
+ y.map((e) => /* @__PURE__ */ u("div", {
188
379
  className: "rounded-sm",
189
380
  style: {
190
- width: v,
191
- height: v,
381
+ width: S,
382
+ height: S,
192
383
  backgroundColor: e
193
384
  }
194
385
  }, e)),
195
- /* @__PURE__ */ o("span", { children: w })
386
+ /* @__PURE__ */ u("span", { children: O })
196
387
  ]
197
388
  })
198
389
  ]
@@ -200,6 +391,6 @@ function h({ data: c, year: m, colorScale: h, valueFormatter: g, metricLabel: _,
200
391
  });
201
392
  }
202
393
  //#endregion
203
- export { m as HeatmapCalendar, c as heatmapColorScales };
394
+ export { v as HeatmapCalendar, f as heatmapColorScales };
204
395
 
205
396
  //# sourceMappingURL=heatmap-calendar.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"heatmap-calendar.js","names":[],"sources":["../../src/charts/heatmap-calendar.tsx"],"sourcesContent":["import { useMemo } 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\tvalues: number[];\n\tariaLabel?: string;\n\tclassName?: string;\n};\n\nexport type HeatmapCalendarYearProps = {\n\tdata: HeatmapDataPoint[];\n\tyear: number;\n\tcolorScale?: readonly string[];\n\tvalueFormatter?: (value: number, date: string) => string;\n\tmetricLabel?: string;\n\tcellSize?: number;\n\tcellGap?: number;\n\tlocale?: string;\n\tweekdayLabels?: string[];\n\tmonthLabels?: string[];\n\tlessLabel?: string;\n\tmoreLabel?: string;\n\tariaLabel?: string;\n\tclassName?: string;\n};\n\nexport type HeatmapCalendarProps = HeatmapCalendarValuesProps | HeatmapCalendarYearProps;\n\nexport function HeatmapCalendar(props: HeatmapCalendarProps) {\n\tif (\"data\" in props) {\n\t\tconst {\n\t\t\tcolorScale = heatmapColorScales.green,\n\t\t\tvalueFormatter = (value) => value.toLocaleString(),\n\t\t\tmetricLabel = \"Value\",\n\t\t\tcellSize = 12,\n\t\t\tcellGap = 2,\n\t\t\tlocale = \"en-US\",\n\t\t\tweekdayLabels,\n\t\t\tmonthLabels,\n\t\t\tlessLabel = \"Less\",\n\t\t\tmoreLabel = \"More\",\n\t\t\tariaLabel = \"Heatmap calendar\",\n\t\t\tclassName,\n\t\t} = props;\n\t\treturn (\n\t\t\t<YearHeatmap\n\t\t\t\tdata={props.data}\n\t\t\t\tyear={props.year}\n\t\t\t\tcolorScale={colorScale}\n\t\t\t\tvalueFormatter={valueFormatter}\n\t\t\t\tmetricLabel={metricLabel}\n\t\t\t\tcellSize={cellSize}\n\t\t\t\tcellGap={cellGap}\n\t\t\t\tlocale={locale}\n\t\t\t\tweekdayLabels={weekdayLabels}\n\t\t\t\tmonthLabels={monthLabels}\n\t\t\t\tlessLabel={lessLabel}\n\t\t\t\tmoreLabel={moreLabel}\n\t\t\t\tariaLabel={ariaLabel}\n\t\t\t\tclassName={className}\n\t\t\t/>\n\t\t);\n\t}\n\tconst { ariaLabel = \"Heatmap calendar\", className } = props;\n\treturn (\n\t\t<div className={cn(\"grid grid-cols-7 gap-1\", className)} role=\"img\" aria-label={ariaLabel}>\n\t\t\t{props.values.map((value, index) => (\n\t\t\t\t<span\n\t\t\t\t\tkey={index}\n\t\t\t\t\tclassName=\"h-3 w-3 rounded-sm bg-basalt-primary\"\n\t\t\t\t\tstyle={{ opacity: 0.2 + Math.min(4, Math.max(0, value)) * 0.15 }}\n\t\t\t\t/>\n\t\t\t))}\n\t\t</div>\n\t);\n}\n\nfunction YearHeatmap({\n\tdata,\n\tyear,\n\tcolorScale,\n\tvalueFormatter,\n\tmetricLabel,\n\tcellSize,\n\tcellGap,\n\tlocale,\n\tweekdayLabels,\n\tmonthLabels,\n\tlessLabel,\n\tmoreLabel,\n\tariaLabel,\n\tclassName,\n}: {\n\tdata: HeatmapDataPoint[];\n\tyear: number;\n\tcolorScale: readonly string[];\n\tvalueFormatter: (value: number, date: string) => string;\n\tmetricLabel: string;\n\tcellSize: number;\n\tcellGap: number;\n\tlocale: string;\n\tweekdayLabels?: string[];\n\tmonthLabels?: string[];\n\tlessLabel: string;\n\tmoreLabel: string;\n\tariaLabel: string;\n\tclassName?: string;\n}) {\n\tconst weekdays = weekdayLabels ?? weekdayNames(locale);\n\tconst months = monthLabels ?? monthNames(locale);\n\tconst { weeks, dataMap, maxValue, labels } = 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\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\t\treturn { weeks, dataMap, maxValue, labels };\n\t}, [data, months, year]);\n\tconst labelWidth = 30;\n\treturn (\n\t\t<div className={cn(\"overflow-x-auto\", className)} role=\"img\" aria-label={ariaLabel}>\n\t\t\t<TooltipProvider>\n\t\t\t\t<div className=\"inline-block\">\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\"\n\t\t\t\t\t\t\tstyle={{ width: labelWidth }}\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 value = dataMap.get(dateStr) ?? 0;\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\tconst colorIndex = getColorIndex(value, maxValue, colorScale);\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/>\n\t\t\t\t\t\t\t\t\t\t\t);\n\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t\treturn (\n\t\t\t\t\t\t\t\t\t\t\t<Tooltip key={dayIndex}>\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<div\n\t\t\t\t\t\t\t\t\t\t\t\t\t\tclassName=\"cursor-pointer rounded-sm transition-colors hover:ring-1 hover:ring-basalt-foreground\"\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>\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}: {valueFormatter(value, dateStr)}\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 className=\"mt-2 flex items-center justify-end gap-1 text-xs text-basalt-muted-foreground\">\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":[],"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\tconst {\n\t\t\tcolorScale = heatmapColorScales.green,\n\t\t\tvalueFormatter = (value) => value.toLocaleString(),\n\t\t\tmetricLabel = \"Value\",\n\t\t\tcellSize = 12,\n\t\t\tcellGap = 2,\n\t\t\tlocale = \"en-US\",\n\t\t\tweekdayLabels,\n\t\t\tmonthLabels,\n\t\t\tlessLabel = \"Less\",\n\t\t\tmoreLabel = \"More\",\n\t\t\tariaLabel = \"Heatmap calendar\",\n\t\t\tclassName,\n\t\t} = props;\n\t\treturn (\n\t\t\t<YearHeatmap\n\t\t\t\tdata={props.data}\n\t\t\t\tyear={props.year}\n\t\t\t\tcolorScale={colorScale}\n\t\t\t\tvalueFormatter={valueFormatter}\n\t\t\t\tmetricLabel={metricLabel}\n\t\t\t\tcellSize={cellSize}\n\t\t\t\tcellGap={cellGap}\n\t\t\t\tlocale={locale}\n\t\t\t\tweekdayLabels={weekdayLabels}\n\t\t\t\tmonthLabels={monthLabels}\n\t\t\t\tlessLabel={lessLabel}\n\t\t\t\tmoreLabel={moreLabel}\n\t\t\t\tariaLabel={ariaLabel}\n\t\t\t\tclassName={className}\n\t\t\t/>\n\t\t);\n\t}\n\tconst { ariaLabel = \"Heatmap calendar\", className } = props;\n\treturn <ValuesHeatmap values={props.values} ariaLabel={ariaLabel} className={className} />;\n}\n\nfunction ValuesHeatmap({\n\tvalues,\n\tariaLabel,\n\tclassName,\n}: {\n\tvalues: number[];\n\tariaLabel: string;\n\tclassName?: string;\n}) {\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\tif (values.length === 0) {\n\t\treturn (\n\t\t\t<div\n\t\t\t\tref={containerRef}\n\t\t\t\ttabIndex={-1}\n\t\t\t\trole=\"region\"\n\t\t\t\taria-label={ariaLabel}\n\t\t\t\tonFocus={() => {\n\t\t\t\t\tisFocusedInsideRef.current = true;\n\t\t\t\t}}\n\t\t\t\tonBlur={(e) => {\n\t\t\t\t\tif (!e.currentTarget.contains(e.relatedTarget)) {\n\t\t\t\t\t\tisFocusedInsideRef.current = false;\n\t\t\t\t\t}\n\t\t\t\t}}\n\t\t\t\tclassName={cn(\"grid grid-cols-7 gap-1 p-0.5 outline-none\", className)}\n\t\t\t/>\n\t\t);\n\t}\n\n\treturn (\n\t\t<TooltipProvider>\n\t\t\t<div\n\t\t\t\tref={containerRef}\n\t\t\t\ttabIndex={-1}\n\t\t\t\trole=\"region\"\n\t\t\t\taria-label={ariaLabel}\n\t\t\t\tonFocus={() => {\n\t\t\t\t\tisFocusedInsideRef.current = true;\n\t\t\t\t}}\n\t\t\t\tonBlur={(e) => {\n\t\t\t\t\tif (!e.currentTarget.contains(e.relatedTarget)) {\n\t\t\t\t\t\tisFocusedInsideRef.current = false;\n\t\t\t\t\t}\n\t\t\t\t}}\n\t\t\t\tclassName={cn(\"grid grid-cols-7 gap-1 p-0.5 outline-none\", className)}\n\t\t\t>\n\t\t\t\t{values.map((value, index) => {\n\t\t\t\t\tconst isCurrent = index === activeIdx;\n\t\t\t\t\tconst isOpen = openTooltipIdx === index;\n\t\t\t\t\treturn (\n\t\t\t\t\t\t<Tooltip\n\t\t\t\t\t\t\tkey={index}\n\t\t\t\t\t\t\topen={isOpen}\n\t\t\t\t\t\t\tonOpenChange={(next) => {\n\t\t\t\t\t\t\t\tif (next) {\n\t\t\t\t\t\t\t\t\tsetOpenTooltipIdx(index);\n\t\t\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\t\t\tsetOpenTooltipIdx((curr) => {\n\t\t\t\t\t\t\t\t\t\tif (curr !== index) return curr;\n\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\tconst isCellFocused =\n\t\t\t\t\t\t\t\t\t\t\tcellRefs.current[index] !== null &&\n\t\t\t\t\t\t\t\t\t\t\tdocument.activeElement === cellRefs.current[index];\n\t\t\t\t\t\t\t\t\t\treturn isCellFocused ? curr : null;\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}}\n\t\t\t\t\t\t>\n\t\t\t\t\t\t\t<TooltipTrigger asChild>\n\t\t\t\t\t\t\t\t<button\n\t\t\t\t\t\t\t\t\tref={(el) => {\n\t\t\t\t\t\t\t\t\t\tcellRefs.current[index] = el;\n\t\t\t\t\t\t\t\t\t}}\n\t\t\t\t\t\t\t\t\ttype=\"button\"\n\t\t\t\t\t\t\t\t\ttabIndex={isCurrent ? 0 : -1}\n\t\t\t\t\t\t\t\t\tonFocus={() => {\n\t\t\t\t\t\t\t\t\t\tsetActiveIdx(index);\n\t\t\t\t\t\t\t\t\t\tsetOpenTooltipIdx(index);\n\t\t\t\t\t\t\t\t\t}}\n\t\t\t\t\t\t\t\t\tonBlur={() => {\n\t\t\t\t\t\t\t\t\t\tsetOpenTooltipIdx((curr) => (curr === index ? null : curr));\n\t\t\t\t\t\t\t\t\t}}\n\t\t\t\t\t\t\t\t\tonKeyDown={(e) => handleKeyDown(e, index)}\n\t\t\t\t\t\t\t\t\taria-label={`Position ${index + 1}: ${value}`}\n\t\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\t\tstyle={{\n\t\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\t}}\n\t\t\t\t\t\t\t\t/>\n\t\t\t\t\t\t\t</TooltipTrigger>\n\t\t\t\t\t\t\t<TooltipContent>\n\t\t\t\t\t\t\t\t<div className=\"text-xs\">\n\t\t\t\t\t\t\t\t\tPosition {index + 1}: {value}\n\t\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t\t</TooltipContent>\n\t\t\t\t\t\t</Tooltip>\n\t\t\t\t\t);\n\t\t\t\t})}\n\t\t\t</div>\n\t\t</TooltipProvider>\n\t);\n}\n\ninterface YearDayCell {\n\tdateStr: string;\n\tvalue: number;\n\tweekIndex: number;\n\tdayIndex: number;\n\tcolorIndex: number;\n}\n\nfunction YearHeatmap({\n\tdata,\n\tyear,\n\tcolorScale,\n\tvalueFormatter,\n\tmetricLabel,\n\tcellSize,\n\tcellGap,\n\tlocale,\n\tweekdayLabels,\n\tmonthLabels,\n\tlessLabel,\n\tmoreLabel,\n\tariaLabel,\n\tclassName,\n}: {\n\tdata: HeatmapDataPoint[];\n\tyear: number;\n\tcolorScale: readonly string[];\n\tvalueFormatter: (value: number, date: string) => string;\n\tmetricLabel: string;\n\tcellSize: number;\n\tcellGap: number;\n\tlocale: string;\n\tweekdayLabels?: string[];\n\tmonthLabels?: string[];\n\tlessLabel: string;\n\tmoreLabel: string;\n\tariaLabel: string;\n\tclassName?: string;\n}) {\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: YearDayCell[] = [];\n\t\tconst dateToValidIndex = new Map<string, number>();\n\n\t\tweeks.forEach((week, weekIndex) => {\n\t\t\tweek.forEach((date, dayIndex) => {\n\t\t\t\tif (date.getFullYear() === year) {\n\t\t\t\t\tconst dateStr = formatDate(date);\n\t\t\t\t\tconst value = dataMap.get(dateStr) ?? 0;\n\t\t\t\t\tconst colorIndex = getColorIndex(value, maxValue, colorScale);\n\t\t\t\t\tdateToValidIndex.set(dateStr, validDays.length);\n\t\t\t\t\tvalidDays.push({\n\t\t\t\t\t\tdateStr,\n\t\t\t\t\t\tvalue,\n\t\t\t\t\t\tweekIndex,\n\t\t\t\t\t\tdayIndex,\n\t\t\t\t\t\tcolorIndex,\n\t\t\t\t\t});\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, colorScale]);\n\n\tconst [activeDate, setActiveDate] = useState<string>(() => {\n\t\treturn validDays[0]?.dateStr ?? `${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]?.dateStr ?? \"\";\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 activeDay = useMemo(() => {\n\t\tconst idx = dateToValidIndex.get(activeDate);\n\t\treturn idx !== undefined ? validDays[idx] : validDays[0];\n\t}, [activeDate, dateToValidIndex, validDays]);\n\n\tconst navigateToDay = (targetDay: YearDayCell | undefined) => {\n\t\tif (!targetDay) return;\n\t\tsetActiveDate(targetDay.dateStr);\n\t\tsetOpenTooltipDate(targetDay.dateStr);\n\t\tconst btn = cellRefs.current.get(targetDay.dateStr);\n\t\tbtn?.focus();\n\t};\n\n\tconst handleCellKeyDown = (e: KeyboardEvent<HTMLButtonElement>, cell: YearDayCell) => {\n\t\tif (validDays.length === 0) return;\n\n\t\tconst currentIdx = dateToValidIndex.get(cell.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 = activeDay?.dateStr === 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\t\t\t\t\t\t\t\t\t\tconst currentCell: YearDayCell = {\n\t\t\t\t\t\t\t\t\t\t\tdateStr,\n\t\t\t\t\t\t\t\t\t\t\tvalue,\n\t\t\t\t\t\t\t\t\t\t\tweekIndex,\n\t\t\t\t\t\t\t\t\t\t\tdayIndex,\n\t\t\t\t\t\t\t\t\t\t\tcolorIndex,\n\t\t\t\t\t\t\t\t\t\t};\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, currentCell)}\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":";;;;;;AAMA,IAAa,IAAqB;CACjC,OAAO;EACN;EACA;EACA;EACA;EACA;CACD;CACA,KAAK;EACJ;EACA;EACA;EACA;EACA;CACD;CACA,MAAM;EACL;EACA;EACA;EACA;EACA;CACD;CACA,QAAQ;EACP;EACA;EACA;EACA;EACA;CACD;AACD;AAEA,SAAS,EAAa,GAAgB;CACrC,OAAO,MAAM,KAAK,EAAE,QAAQ,EAAE,IAAI,GAAG,MACpC,IAAI,KAAK,eAAe,GAAQ,EAAE,SAAS,QAAQ,CAAC,CAAC,CAAC,OAAO,IAAI,KAAK,MAAM,GAAG,IAAI,CAAK,CAAC,CAC1F;AACD;AAEA,SAAS,EAAW,GAAgB;CACnC,OAAO,MAAM,KAAK,EAAE,QAAQ,GAAG,IAAI,GAAG,MACrC,IAAI,KAAK,eAAe,GAAQ,EAAE,OAAO,QAAQ,CAAC,CAAC,CAAC,OAAO,IAAI,KAAK,MAAM,GAAO,CAAC,CAAC,CACpF;AACD;AAEA,SAAS,EAAa,GAAwB;CAC7C,IAAM,IAAkB,CAAC,GACnB,IAAY,IAAI,KAAK,GAAM,GAAG,CAAC,GAC/B,IAAU,IAAI,KAAK,GAAM,IAAI,EAAE,GAC/B,IAAW,IAAI,KAAK,CAAS;CACnC,EAAS,QAAQ,EAAS,QAAQ,IAAI,EAAS,OAAO,CAAC;CACvD,IAAI,IAAc,IAAI,KAAK,CAAQ,GAC/B,IAAsB,CAAC;CAC3B,QAAO,KAAe,KAAW,EAAY,SAAS,OACjD,EAAY,WAAW,MAC1B,EAAM,KAAK,CAAW,GACtB,IAAc,CAAC,IAEZ,MAAc,MAKlB,AAFA,EAAY,KAAK,IAAI,KAAK,CAAW,CAAC,GACtC,IAAc,IAAI,KAAK,CAAW,GAClC,EAAY,QAAQ,EAAY,QAAQ,IAAI,CAAC;CAK9C,OAHI,EAAY,SAAS,KACxB,EAAM,KAAK,CAAW,GAEhB;AACR;AAEA,SAAS,EAAW,GAAoB;CAIvC,OAAO,GAHM,EAAK,YAGR,EAAK,GAFD,OAAO,EAAK,SAAS,IAAI,CAAC,CAAC,CAAC,SAAS,GAAG,GAEpC,EAAM,GADZ,OAAO,EAAK,QAAQ,CAAC,CAAC,CAAC,SAAS,GAAG,GACpB;AAC5B;AAEA,SAAS,EAAc,GAAe,GAAkB,GAAuC;CAC9F,IAAI,MAAU,GACb,OAAO;CAER,IAAM,IAAS,EAAW,SAAS,GAC7B,IAAa,KAAK,IAAI,IAAQ,GAAU,CAAC;CAC/C,OAAO,KAAK,KAAK,IAAa,CAAM;AACrC;AAwFA,SAAgB,EAAgB,GAA6B;CAC5D,IAAI,UAAU,GAAO;EACpB,IAAM,EACL,gBAAa,EAAmB,OAChC,qBAAkB,MAAU,EAAM,eAAe,GACjD,iBAAc,SACd,cAAW,IACX,aAAU,GACV,YAAS,SACT,kBACA,gBACA,eAAY,QACZ,eAAY,QACZ,eAAY,oBACZ,iBACG;EACJ,OACC,kBAAC,GAAD;GACC,MAAM,EAAM;GACZ,MAAM,EAAM;GACA;GACI;GACH;GACH;GACD;GACD;GACO;GACF;GACF;GACA;GACA;GACA;EACX,CAAA;CAEH;CACA,IAAM,EAAE,eAAY,oBAAoB,iBAAc;CACtD,OAAO,kBAAC,GAAD;EAAe,QAAQ,EAAM;EAAmB;EAAsB;CAAY,CAAA;AAC1F;AAEA,SAAS,EAAc,EACtB,WACA,cACA,gBAKE;CACF,IAAM,CAAC,GAAW,KAAgB,EAAS,CAAC,GACtC,CAAC,GAAgB,KAAqB,EAAwB,IAAI,GAClE,IAAe,EAA8B,IAAI,GACjD,IAAW,EAAqC,CAAC,CAAC,GAClD,IAAqB,EAAO,EAAK;CAIvC,QAAgB;EACf,IAAM,IAAW,EAAmB;EACpC,IAAI,EAAO,WAAW,GAGrB,AAFA,EAAa,CAAC,GACd,EAAkB,IAAI,GAClB,KACH,EAAa,SAAS,MAAM;OAEvB,IAAI,KAAa,EAAO,QAAQ;GACtC,IAAM,IAAO,EAAO,SAAS;GAE7B,AADA,EAAa,CAAI,GACb,KACH,EAAS,QAAQ,EAAK,EAAE,MAAM;EAEhC,OAAO,AAAI,KACV,EAAS,QAAQ,EAAU,EAAE,MAAM;CAErC,GAAG,CAAC,EAAO,QAAQ,CAAS,CAAC;CAE7B,IAAM,KAAiB,GAAqC,MAAyB;EACpF,IAAI,EAAO,WAAW,GAAG;EAEzB,IAAI,EAAE,QAAQ,UAAU;GACvB,EAAkB,IAAI;GACtB;EACD;EAEA,IAAI,IAAU;EACd,IAAI,EAAE,QAAQ,cACb,IAAU,KAAK,IAAI,EAAO,SAAS,GAAG,IAAe,CAAC;OAChD,IAAI,EAAE,QAAQ,aACpB,IAAU,KAAK,IAAI,GAAG,IAAe,CAAC;OAChC,IAAI,EAAE,QAAQ,aACpB,IAAU,KAAK,IAAI,EAAO,SAAS,GAAG,IAAe,CAAC;OAChD,IAAI,EAAE,QAAQ,WACpB,IAAU,KAAK,IAAI,GAAG,IAAe,CAAC;OAChC,IAAI,EAAE,QAAQ,QACpB,IAAU;OACJ,IAAI,EAAE,QAAQ,OACpB,IAAU,EAAO,SAAS;OAE1B;EAMD,AAHA,EAAE,eAAe,GACjB,EAAa,CAAO,GACpB,EAAkB,CAAO,GACzB,EAAS,QAAQ,EAAQ,EAAE,MAAM;CAClC;CAsBA,OApBI,EAAO,WAAW,IAEpB,kBAAC,OAAD;EACC,KAAK;EACL,UAAU;EACV,MAAK;EACL,cAAY;EACZ,eAAe;GACd,EAAmB,UAAU;EAC9B;EACA,SAAS,MAAM;GACd,AAAK,EAAE,cAAc,SAAS,EAAE,aAAa,MAC5C,EAAmB,UAAU;EAE/B;EACA,WAAW,EAAG,6CAA6C,CAAS;CACpE,CAAA,IAKF,kBAAC,GAAD,EAAA,UACC,kBAAC,OAAD;EACC,KAAK;EACL,UAAU;EACV,MAAK;EACL,cAAY;EACZ,eAAe;GACd,EAAmB,UAAU;EAC9B;EACA,SAAS,MAAM;GACd,AAAK,EAAE,cAAc,SAAS,EAAE,aAAa,MAC5C,EAAmB,UAAU;EAE/B;EACA,WAAW,EAAG,6CAA6C,CAAS;EAEnE,UAAA,EAAO,KAAK,GAAO,MAIlB,kBAAC,GAAD;GAEC,MAJa,MAAmB;GAKhC,eAAe,MAAS;IACvB,AACC,EADG,IACe,KAEC,MACd,MAAS,IAGZ,EAAS,QAAQ,OAAW,QAC5B,SAAS,kBAAkB,EAAS,QAAQ,KACtB,IAAO,OALH,CAM3B;GAEH;GAhBD,UAAA,CAkBC,kBAAC,GAAD;IAAgB,SAAA;IACf,UAAA,kBAAC,UAAD;KACC,MAAM,MAAO;MACZ,EAAS,QAAQ,KAAS;KAC3B;KACA,MAAK;KACL,UA3Bc,MAAU,IA2BF,IAAI;KAC1B,eAAe;MAEd,AADA,EAAa,CAAK,GAClB,EAAkB,CAAK;KACxB;KACA,cAAc;MACb,GAAmB,MAAU,MAAS,IAAQ,OAAO,CAAK;KAC3D;KACA,YAAY,MAAM,EAAc,GAAG,CAAK;KACxC,cAAY,YAAY,IAAQ,EAAE,IAAI;KACtC,WAAU;KACV,OAAO,EACN,iBAAiB,+BAA+B,KAAM,KAAK,IAAI,GAAG,KAAK,IAAI,GAAG,CAAK,CAAC,IAAI,IAAK,GAC9F;IACA,CAAA;GACc,CAAA,GAChB,kBAAC,GAAD,EAAA,UACC,kBAAC,OAAD;IAAK,WAAU;IAAf,UAAA;KAAyB;KACd,IAAQ;KAAE;KAAG;IACnB;GACU,CAAA,EAAA,CAAA,CACR;EA5CH,GAAA,CA4CG,CAEV;CACG,CAAA,EACW,CAAA;AAEnB;AAUA,SAAS,EAAY,EACpB,SACA,SACA,eACA,mBACA,gBACA,aACA,YACA,WACA,kBACA,gBACA,cACA,cACA,cACA,gBAgBE;CACF,IAAM,IAAW,KAAiB,EAAa,CAAM,GAC/C,IAAS,KAAe,EAAW,CAAM,GACzC,IAAa,EAAM,GACnB,IAAkB,EAA8B,IAAI,GAEpD,EAAE,UAAO,YAAS,aAAU,WAAQ,cAAW,wBAAqB,QAAc;EACvF,IAAM,IAAQ,EAAa,CAAI,GACzB,oBAAU,IAAI,IAAoB,GACpC,IAAW;EACf,KAAK,IAAM,KAAS,GAEnB,AADA,EAAQ,IAAI,EAAM,MAAM,EAAM,KAAK,GAC/B,EAAM,QAAQ,MACjB,IAAW,EAAM;EAInB,IAAM,IAAiD,CAAC,GACpD,IAAY;EAChB,EAAM,SAAS,GAAM,MAAc;GAClC,IAAM,IAAiB,EAAK,MAAM,MAAS,EAAK,YAAY,MAAM,CAAI;GACtE,IAAI,GAAgB;IACnB,IAAM,IAAQ,EAAe,SAAS;IACtC,AAAI,MAAU,MACb,EAAO,KAAK;KAAE,OAAO,EAAO;KAAQ;IAAU,CAAC,GAC/C,IAAY;GAEd;EACD,CAAC;EAED,IAAM,IAA2B,CAAC,GAC5B,oBAAmB,IAAI,IAAoB;EAoBjD,OAlBA,EAAM,SAAS,GAAM,MAAc;GAClC,EAAK,SAAS,GAAM,MAAa;IAChC,IAAI,EAAK,YAAY,MAAM,GAAM;KAChC,IAAM,IAAU,EAAW,CAAI,GACzB,IAAQ,EAAQ,IAAI,CAAO,KAAK,GAChC,IAAa,EAAc,GAAO,GAAU,CAAU;KAE5D,AADA,EAAiB,IAAI,GAAS,EAAU,MAAM,GAC9C,EAAU,KAAK;MACd;MACA;MACA;MACA;MACA;KACD,CAAC;IACF;GACD,CAAC;EACF,CAAC,GAEM;GAAE;GAAO;GAAS;GAAU;GAAQ;GAAW;EAAiB;CACxE,GAAG;EAAC;EAAM;EAAQ;EAAM;CAAU,CAAC,GAE7B,CAAC,GAAY,KAAiB,QAC5B,EAAU,EAAE,EAAE,WAAW,GAAG,EAAK,OACxC,GACK,CAAC,GAAiB,KAAsB,EAAwB,IAAI,GAEpE,IAAW,kBAAuC,IAAI,IAAI,CAAC,GAC3D,IAAyB,EAAO,EAAK;CAI3C,QAAgB;EACf,IAAM,IAAW,EAAuB;EACxC,IAAI,EAAU,WAAW,GAGxB,AAFA,EAAc,EAAE,GAChB,EAAmB,IAAI,GACnB,KACH,EAAgB,SAAS,MAAM;OAE1B,IAAI,CAAC,EAAiB,IAAI,CAAU,GAAG;GAC7C,IAAM,IAAW,EAAU,EAAE,EAAE,WAAW;GAE1C,AADA,EAAc,CAAQ,GAClB,KACH,EAAS,QAAQ,IAAI,CAAQ,CAAC,EAAE,MAAM;EAExC;CACD,GAAG;EAAC;EAAW;EAAkB;CAAU,CAAC;CAE5C,IAAM,IAAY,QAAc;EAC/B,IAAM,IAAM,EAAiB,IAAI,CAAU;EAC3C,OAAO,MAAQ,KAAA,IAA6B,EAAU,KAA3B,EAAU;CACtC,GAAG;EAAC;EAAY;EAAkB;CAAS,CAAC,GAEtC,KAAiB,MAAuC;EACxD,MACL,EAAc,EAAU,OAAO,GAC/B,EAAmB,EAAU,OAAO,GAEpC,EADqB,QAAQ,IAAI,EAAU,OAC3C,CAAA,EAAK,MAAM;CACZ,GAEM,KAAqB,GAAqC,MAAsB;EACrF,IAAI,EAAU,WAAW,GAAG;EAE5B,IAAM,IAAa,EAAiB,IAAI,EAAK,OAAO,KAAK;EAEzD,IAAI,EAAE,QAAQ,UAAU;GACvB,EAAmB,IAAI;GACvB;EACD;EAEA,IAAI,EAAE,QAAQ,aAAa;GAC1B,EAAE,eAAe;GAEjB,IAAM,IAAU,EAAU,IAAa;GACvC,AAAI,KACH,EAAc,CAAO;EAEvB,OAAO,IAAI,EAAE,QAAQ,WAAW;GAC/B,EAAE,eAAe;GAEjB,IAAM,IAAU,EAAU,IAAa;GACvC,AAAI,KACH,EAAc,CAAO;EAEvB,OAAO,IAAI,EAAE,QAAQ,cAAc;GAClC,EAAE,eAAe;GAEjB,IAAM,IAAY,IAAa;GAC/B,AAAI,IAAY,EAAU,SACzB,EAAc,EAAU,EAAU,IAElC,EAAc,EAAU,EAAU,SAAS,EAAE;EAE/C,OAAO,IAAI,EAAE,QAAQ,aAAa;GACjC,EAAE,eAAe;GAEjB,IAAM,IAAY,IAAa;GAC/B,AACC,EADG,KAAa,IACF,EAAU,KAEV,EAAU,EAAE;EAE5B,OAAO,AAAI,EAAE,QAAQ,UACpB,EAAE,eAAe,GACjB,EAAc,EAAU,EAAE,KAChB,EAAE,QAAQ,UACpB,EAAE,eAAe,GACjB,EAAc,EAAU,EAAU,SAAS,EAAE;CAE/C;CAIA,OACC,kBAAC,OAAD;EACC,KAAK;EACL,UAAU;EACV,MAAK;EACL,cAAY,GAAG,EAAU;EACzB,eAAe;GACd,EAAuB,UAAU;EAClC;EACA,SAAS,MAAM;GACd,AAAK,EAAE,cAAc,SAAS,EAAE,aAAa,MAC5C,EAAuB,UAAU;EAEnC;EACA,WAAW,EACV,+FACA,CACD;EAEA,UAAA,kBAAC,GAAD,EAAA,UACC,kBAAC,OAAD;GAAK,WAAU;GAAmB,MAAK;GAAQ,cAAY;GAA3D,UAAA;IACC,kBAAC,OAAD;KACC,WAAU;KACV,OAAO,EAAE,YAAY,GAAW;KAE/B,UAAA,EAAO,KAAK,MACZ,kBAAC,OAAD;MAEC,WAAU;MACV,OAAO,EAAE,MAAM,EAAM,aAAa,IAAW,GAAS;MAErD,UAAA,EAAM;KACH,GALC,GAAG,EAAM,MAAM,GAAG,EAAM,WAKzB,CACL;IACG,CAAA;IACL,kBAAC,OAAD;KAAK,WAAU;KAAf,UAAA,CACC,kBAAC,OAAD;MACC,WAAU;MACV,OAAO,EAAE,OAAO,GAAW;MAC3B,eAAY;MAEX,UAAA,EAAS,KAAK,GAAK,MACnB,kBAAC,OAAD;OAEC,OAAO;QACN,QAAQ,IAAW;QACnB,YAAY,GAAG,IAAW,EAAQ;QAClC,YAAY,IAAQ,KAAM,IAAI,YAAY;OAC3C;OAEC,UAAA;MACG,GARC,GAAG,EAAI,GAAG,GAQX,CACL;KACG,CAAA,GACL,kBAAC,OAAD;MAAK,WAAU;MAAO,OAAO,EAAE,KAAK,EAAQ;MAC1C,UAAA,EAAM,KAAK,GAAM,MACjB,kBAAC,OAAD;OAAqB,WAAU;OAAgB,OAAO,EAAE,KAAK,EAAQ;OACnE,UAAA,EAAK,KAAK,GAAM,MAAa;QAC7B,IAAM,IAAU,EAAW,CAAI;QAE/B,IADsB,EAAK,YAAY,MAAM,GAE5C,OACC,kBAAC,OAAD;SAEC,OAAO;UACN,OAAO;UACP,QAAQ;UACR,YAAY;SACb;SACA,eAAY;QACZ,GAPK,CAOL;QAIH,IAAM,IAAQ,EAAQ,IAAI,CAAO,KAAK,GAChC,IAAa,EAAc,GAAO,GAAU,CAAU,GACtD,IAAa,GAAW,YAAY,GACpC,IAAiB,EAAe,GAAO,CAAO,GAC9C,IAAY,GAAG,EAAQ,IAAI,EAAY,IAAI,KAC3C,IAAS,MAAoB,GAC7B,IAA2B;SAChC;SACA;SACA;SACA;SACA;QACD;QAEA,OACC,kBAAC,GAAD;SAEC,MAAM;SACN,eAAe,MAAS;UACvB,AACC,EADG,IACgB,KAEC,MACf,MAAS,IAGZ,SAAS,kBAAkB,EAAS,QAAQ,IAAI,CAAO,IACjC,IAAO,OAJD,CAK7B;SAEH;SAfD,UAAA,CAiBC,kBAAC,GAAD;UAAgB,SAAA;UACf,UAAA,kBAAC,UAAD;WACC,MAAM,MAAO;YACZ,AAAI,IACH,EAAS,QAAQ,IAAI,GAAS,CAAE,IAEhC,EAAS,QAAQ,OAAO,CAAO;WAEjC;WACA,MAAK;WACL,cAAY;WACZ,UAAU,IAAa,IAAI;WAC3B,eAAe;YAEd,AADA,EAAc,CAAO,GACrB,EAAmB,CAAO;WAC3B;WACA,cAAc;YACb,GAAoB,MAAU,MAAS,IAAU,OAAO,CAAK;WAC9D;WACA,YAAY,MAAM,EAAkB,GAAG,CAAW;WAClD,WAAU;WACV,OAAO;YACN,OAAO;YACP,QAAQ;YACR,iBAAiB,EAAW;WAC7B;UACA,CAAA;SACc,CAAA,GAChB,kBAAC,GAAD;UAAgB,IAAI,GAAG,EAAW,GAAG;UACpC,UAAA,kBAAC,OAAD;WAAK,WAAU;WAAf,UAAA,CACC,kBAAC,OAAD;YAAK,WAAU;YAAe,UAAA;WAAa,CAAA,GAC3C,kBAAC,OAAD;YAAK,WAAU;YAAf,UAAA;aACE;aAAY;aAAG;YACZ;WACD,CAAA,CAAA;;SACU,CAAA,CACR;QApDH,GAAA,CAoDG;OAEX,CAAC;MACG,GAzFK,CAyFL,CACL;KACG,CAAA,CACD;;IACL,kBAAC,OAAD;KACC,WAAU;KACV,eAAY;KAFb,UAAA;MAIC,kBAAC,QAAD,EAAA,UAAO,EAAgB,CAAA;MACtB,EAAW,KAAK,MAChB,kBAAC,OAAD;OAEC,WAAU;OACV,OAAO;QACN,OAAO;QACP,QAAQ;QACR,iBAAiB;OAClB;MACA,GAPK,CAOL,CACD;MACD,kBAAC,QAAD,EAAA,UAAO,EAAgB,CAAA;KACnB;;GACD;EACW,CAAA,EAAA,CAAA;CACb,CAAA;AAEP"}