@siyahi/ui 0.1.9-next.3 → 0.1.9-next.31

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 (254) hide show
  1. package/DESIGN.md +251 -0
  2. package/README.md +94 -177
  3. package/THIRD_PARTY_NOTICES.md +11 -11
  4. package/agents/examples/accordion.tsx +39 -0
  5. package/agents/examples/alert.tsx +24 -0
  6. package/agents/examples/app-sidebar.tsx +40 -0
  7. package/agents/examples/avatar.tsx +24 -0
  8. package/agents/examples/badge.tsx +26 -0
  9. package/agents/examples/bar-list-labels.tsx +22 -0
  10. package/agents/examples/bar-list-sides.tsx +40 -0
  11. package/agents/examples/bar-list.tsx +24 -0
  12. package/agents/examples/breadcrumb.tsx +28 -0
  13. package/agents/examples/button-states.tsx +23 -0
  14. package/agents/examples/button.tsx +21 -0
  15. package/agents/examples/calendar.tsx +11 -0
  16. package/agents/examples/callout.tsx +33 -0
  17. package/agents/examples/card.tsx +36 -0
  18. package/agents/examples/change-bar.tsx +104 -0
  19. package/agents/examples/change-grid-money.tsx +36 -0
  20. package/agents/examples/change-grid.tsx +43 -0
  21. package/agents/examples/chart-area-log.tsx +45 -0
  22. package/agents/examples/chart-area.tsx +39 -0
  23. package/agents/examples/chart-bar-flows.tsx +32 -0
  24. package/agents/examples/chart-bar-hourly.tsx +28 -0
  25. package/agents/examples/chart-bar-losses.tsx +29 -0
  26. package/agents/examples/chart-bar-teams.tsx +72 -0
  27. package/agents/examples/chart-bar-years.tsx +42 -0
  28. package/agents/examples/chart-bar.tsx +56 -0
  29. package/agents/examples/chart-category-ticks.tsx +50 -0
  30. package/agents/examples/chart-line-events.tsx +47 -0
  31. package/agents/examples/chart-line-forecast.tsx +36 -0
  32. package/agents/examples/chart-line-log.tsx +39 -0
  33. package/agents/examples/chart-line-quiet.tsx +114 -0
  34. package/agents/examples/chart-line-timeline.tsx +41 -0
  35. package/agents/examples/chart-line.tsx +57 -0
  36. package/agents/examples/chart-panels.tsx +94 -0
  37. package/agents/examples/code-block.tsx +40 -0
  38. package/agents/examples/collapsible.tsx +18 -0
  39. package/agents/examples/command.tsx +29 -0
  40. package/agents/examples/context-menu.tsx +17 -0
  41. package/agents/examples/copy-button.tsx +8 -0
  42. package/agents/examples/data-bar.tsx +114 -0
  43. package/agents/examples/data-table-compact.tsx +93 -0
  44. package/agents/examples/data-table-filters.tsx +103 -0
  45. package/agents/examples/data-table.tsx +96 -0
  46. package/agents/examples/delta.tsx +18 -0
  47. package/agents/examples/dialog.tsx +28 -0
  48. package/agents/examples/distribution-bar-budget.tsx +30 -0
  49. package/agents/examples/distribution-bar-tug.tsx +74 -0
  50. package/agents/examples/drawdown-chart.tsx +35 -0
  51. package/agents/examples/dropdown-menu.tsx +31 -0
  52. package/agents/examples/field.tsx +108 -0
  53. package/agents/examples/formatters.tsx +42 -0
  54. package/agents/examples/heatmap-calendar-signed.tsx +67 -0
  55. package/agents/examples/heatmap-calendar.tsx +62 -0
  56. package/agents/examples/heatmap-status.tsx +61 -0
  57. package/agents/examples/heatmap-weekday.tsx +72 -0
  58. package/agents/examples/histogram-chart.tsx +28 -0
  59. package/agents/examples/input-states.tsx +23 -0
  60. package/agents/examples/input.tsx +17 -0
  61. package/agents/examples/local-time.tsx +14 -0
  62. package/agents/examples/metric-strip.tsx +46 -0
  63. package/agents/examples/overview-dashboard.tsx +180 -0
  64. package/agents/examples/page-hero.tsx +38 -0
  65. package/agents/examples/page-section.tsx +52 -0
  66. package/agents/examples/popover.tsx +23 -0
  67. package/agents/examples/price-chart.tsx +32 -0
  68. package/agents/examples/progress-tone.tsx +29 -0
  69. package/agents/examples/progress.tsx +10 -0
  70. package/agents/examples/range-position-table.tsx +113 -0
  71. package/agents/examples/range-position.tsx +55 -0
  72. package/agents/examples/scatter-chart-quadrants.tsx +63 -0
  73. package/agents/examples/scatter-chart-scales.tsx +46 -0
  74. package/agents/examples/scatter-chart.tsx +78 -0
  75. package/agents/examples/scroll-area.tsx +22 -0
  76. package/agents/examples/section-cards-select.tsx +28 -0
  77. package/agents/examples/section-cards-trend.tsx +32 -0
  78. package/agents/examples/section-cards.tsx +48 -0
  79. package/agents/examples/select.tsx +27 -0
  80. package/agents/examples/separator.tsx +13 -0
  81. package/agents/examples/sheet.tsx +15 -0
  82. package/agents/examples/skeleton.tsx +11 -0
  83. package/agents/examples/slider.tsx +5 -0
  84. package/agents/examples/slope-chart-market.tsx +33 -0
  85. package/agents/examples/slope-chart.tsx +26 -0
  86. package/agents/examples/stale-blocks.tsx +56 -0
  87. package/agents/examples/surfaces.tsx +116 -0
  88. package/agents/examples/table.tsx +60 -0
  89. package/agents/examples/tabs.tsx +16 -0
  90. package/agents/examples/target-rows.tsx +74 -0
  91. package/agents/examples/toggle-group.tsx +12 -0
  92. package/agents/examples/toggle.tsx +11 -0
  93. package/agents/examples/tooltip.tsx +13 -0
  94. package/agents/examples/treemap.tsx +93 -0
  95. package/agents/examples/waterfall-chart-stores.tsx +27 -0
  96. package/agents/examples/waterfall-chart.tsx +37 -0
  97. package/agents/manifest.json +1391 -0
  98. package/agents/report-rules.json +7 -0
  99. package/dist/components/registry/charts/area-chart-card.d.ts +7 -3
  100. package/dist/components/registry/charts/area-chart-card.js +56 -10
  101. package/dist/components/registry/charts/bar-chart-card.d.ts +1 -1
  102. package/dist/components/registry/charts/bar-chart-card.js +20 -22
  103. package/dist/components/registry/charts/line-chart-card.d.ts +3 -3
  104. package/dist/components/registry/charts/line-chart-card.js +44 -9
  105. package/dist/components/registry/dashboard-01/section-cards.d.ts +6 -0
  106. package/dist/components/registry/dashboard-01/section-cards.js +51 -35
  107. package/dist/components/registry/dashboardcn/bar-list.js +17 -10
  108. package/dist/components/registry/dashboardcn/distribution-bar.js +6 -4
  109. package/dist/components/registry/dashboardcn/kpi-row-card.d.ts +29 -0
  110. package/dist/components/registry/dashboardcn/kpi-row-card.js +81 -0
  111. package/dist/components/registry/dashboardcn/sparkline.d.ts +22 -0
  112. package/dist/components/registry/dashboardcn/sparkline.js +117 -0
  113. package/dist/components/registry/heatmap/calendar-heatmap.d.ts +11 -3
  114. package/dist/components/registry/heatmap/calendar-heatmap.js +164 -45
  115. package/dist/components/registry/heatmap/status-heatmap.d.ts +5 -3
  116. package/dist/components/registry/heatmap/status-heatmap.js +115 -54
  117. package/dist/components/registry/heatmap/weekday-heatmap.d.ts +9 -3
  118. package/dist/components/registry/heatmap/weekday-heatmap.js +83 -53
  119. package/dist/components/registry/niko-table/core/data-table-context.d.ts +18 -1
  120. package/dist/components/registry/niko-table/core/data-table-context.js +7 -1
  121. package/dist/components/registry/niko-table/core/data-table-grouped-row.js +3 -1
  122. package/dist/components/registry/niko-table/core/data-table-root.js +39 -4
  123. package/dist/components/registry/niko-table/core/data-table-structure.js +17 -12
  124. package/dist/components/registry/niko-table/core/data-table.d.ts +2 -2
  125. package/dist/components/registry/niko-table/core/data-table.js +5 -1
  126. package/dist/components/registry/niko-table/filters/table-faceted-filter.js +5 -5
  127. package/dist/components/registry/niko-table/filters/table-search-filter.js +1 -1
  128. package/dist/components/registry/niko-table/lib/flex-columns.d.ts +1 -1
  129. package/dist/components/registry/niko-table/lib/flex-columns.js +3 -3
  130. package/dist/components/registry/niko-table/lib/styles.d.ts +1 -1
  131. package/dist/components/registry/niko-table/lib/styles.js +3 -3
  132. package/dist/components/registry/niko-table/types/index.d.ts +9 -0
  133. package/dist/components/registry/niko-table/ui/table.js +2 -2
  134. package/dist/components/registry/sidebar-07/app-sidebar.d.ts +1 -1
  135. package/dist/components/registry/sidebar-07/app-sidebar.js +3 -1
  136. package/dist/components/registry/sidebar-07/nav-main.d.ts +2 -1
  137. package/dist/components/registry/sidebar-07/nav-main.js +16 -3
  138. package/dist/components/siyahi/callout.d.ts +17 -0
  139. package/dist/components/siyahi/callout.js +34 -0
  140. package/dist/components/siyahi/change-bar.d.ts +21 -0
  141. package/dist/components/siyahi/change-bar.js +35 -0
  142. package/dist/components/siyahi/change-grid.d.ts +31 -0
  143. package/dist/components/siyahi/change-grid.js +74 -0
  144. package/dist/components/siyahi/data-bar.d.ts +19 -0
  145. package/dist/components/siyahi/data-bar.js +29 -0
  146. package/dist/components/siyahi/data-table-compact-columns-toggle.d.ts +4 -0
  147. package/dist/components/siyahi/data-table-compact-columns-toggle.js +19 -0
  148. package/dist/components/siyahi/data-table-footnote.d.ts +12 -0
  149. package/dist/components/siyahi/data-table-footnote.js +35 -0
  150. package/dist/components/siyahi/default-sidebar-open.d.ts +8 -0
  151. package/dist/components/siyahi/default-sidebar-open.js +13 -0
  152. package/dist/components/siyahi/delta.d.ts +5 -1
  153. package/dist/components/siyahi/delta.js +14 -9
  154. package/dist/components/siyahi/drawdown-chart.d.ts +34 -0
  155. package/dist/components/siyahi/drawdown-chart.js +102 -0
  156. package/dist/components/siyahi/histogram-chart.d.ts +57 -0
  157. package/dist/components/siyahi/histogram-chart.js +134 -0
  158. package/dist/components/siyahi/page-hero.d.ts +23 -0
  159. package/dist/components/siyahi/page-hero.js +43 -0
  160. package/dist/components/siyahi/page-section.d.ts +4 -1
  161. package/dist/components/siyahi/page-section.js +6 -3
  162. package/dist/components/siyahi/page-toc.d.ts +20 -0
  163. package/dist/components/siyahi/page-toc.js +76 -0
  164. package/dist/components/siyahi/panel-grid.d.ts +24 -0
  165. package/dist/components/siyahi/panel-grid.js +37 -0
  166. package/dist/components/siyahi/quote.d.ts +12 -0
  167. package/dist/components/siyahi/quote.js +23 -0
  168. package/dist/components/siyahi/range-position.d.ts +24 -0
  169. package/dist/components/siyahi/range-position.js +105 -0
  170. package/dist/components/siyahi/scale-toggle.d.ts +32 -0
  171. package/dist/components/siyahi/scale-toggle.js +61 -0
  172. package/dist/components/siyahi/scatter-chart.d.ts +69 -0
  173. package/dist/components/siyahi/scatter-chart.js +395 -0
  174. package/dist/components/siyahi/siyahi-provider.d.ts +15 -2
  175. package/dist/components/siyahi/siyahi-provider.js +17 -4
  176. package/dist/components/siyahi/slope-chart.d.ts +35 -0
  177. package/dist/components/siyahi/slope-chart.js +159 -0
  178. package/dist/components/siyahi/stale-note.d.ts +9 -0
  179. package/dist/components/siyahi/stale-note.js +12 -0
  180. package/dist/components/siyahi/status-alert.d.ts +15 -0
  181. package/dist/components/siyahi/status-alert.js +29 -0
  182. package/dist/components/siyahi/status-badge.d.ts +15 -0
  183. package/dist/components/siyahi/status-badge.js +24 -0
  184. package/dist/components/siyahi/target-rows.d.ts +34 -0
  185. package/dist/components/siyahi/target-rows.js +97 -0
  186. package/dist/components/siyahi/tone-progress.d.ts +1 -1
  187. package/dist/components/siyahi/tone-progress.js +1 -1
  188. package/dist/components/siyahi/treemap.d.ts +8 -5
  189. package/dist/components/siyahi/treemap.js +80 -34
  190. package/dist/components/siyahi/waterfall-chart.d.ts +51 -0
  191. package/dist/components/siyahi/waterfall-chart.js +147 -0
  192. package/dist/components/ui/accordion.js +5 -5
  193. package/dist/components/ui/alert.js +2 -2
  194. package/dist/components/ui/badge.js +1 -1
  195. package/dist/components/ui/breadcrumb.js +2 -2
  196. package/dist/components/ui/button.js +10 -10
  197. package/dist/components/ui/calendar.js +1 -1
  198. package/dist/components/ui/card.js +4 -4
  199. package/dist/components/ui/chart.js +1 -1
  200. package/dist/components/ui/code-block.js +13 -12
  201. package/dist/components/ui/command.js +7 -6
  202. package/dist/components/ui/context-menu.js +7 -7
  203. package/dist/components/ui/dialog.js +5 -5
  204. package/dist/components/ui/dropdown-menu.js +8 -8
  205. package/dist/components/ui/field.d.ts +26 -0
  206. package/dist/components/ui/field.js +109 -0
  207. package/dist/components/ui/input-group.js +11 -11
  208. package/dist/components/ui/input.js +1 -1
  209. package/dist/components/ui/label.d.ts +5 -0
  210. package/dist/components/ui/label.js +13 -0
  211. package/dist/components/ui/popover.js +3 -3
  212. package/dist/components/ui/progress.js +1 -1
  213. package/dist/components/ui/select.js +6 -6
  214. package/dist/components/ui/sheet.js +5 -5
  215. package/dist/components/ui/sidebar.js +17 -18
  216. package/dist/components/ui/skeleton.js +1 -1
  217. package/dist/components/ui/slider.js +2 -2
  218. package/dist/components/ui/table.js +2 -2
  219. package/dist/components/ui/tabs.js +2 -2
  220. package/dist/components/ui/textarea.js +1 -1
  221. package/dist/components/ui/toggle-group.js +2 -2
  222. package/dist/components/ui/toggle.js +4 -4
  223. package/dist/components/ui/tooltip.js +2 -2
  224. package/dist/index.d.ts +35 -8
  225. package/dist/index.js +30 -4
  226. package/dist/lib/chart-frame.d.ts +51 -7
  227. package/dist/lib/chart-frame.js +390 -133
  228. package/dist/lib/chart-marks.d.ts +83 -0
  229. package/dist/lib/chart-marks.js +216 -0
  230. package/dist/lib/chart-series.d.ts +42 -10
  231. package/dist/lib/compact-columns.d.ts +19 -0
  232. package/dist/lib/compact-columns.js +55 -0
  233. package/dist/lib/fit-text.d.ts +6 -0
  234. package/dist/lib/fit-text.js +11 -0
  235. package/dist/lib/format.d.ts +8 -3
  236. package/dist/lib/format.js +55 -17
  237. package/dist/lib/heat.d.ts +7 -0
  238. package/dist/lib/heat.js +14 -0
  239. package/dist/lib/heatmap-navigation.d.ts +8 -0
  240. package/dist/lib/heatmap-navigation.js +49 -0
  241. package/dist/lib/scatter.d.ts +88 -0
  242. package/dist/lib/scatter.js +179 -0
  243. package/dist/lib/ticks.d.ts +27 -0
  244. package/dist/lib/ticks.js +67 -0
  245. package/dist/lib/tone.d.ts +36 -0
  246. package/dist/lib/tone.js +35 -0
  247. package/dist/lib/treemap.d.ts +0 -5
  248. package/dist/lib/treemap.js +1 -11
  249. package/dist/lib/use-element-width.d.ts +5 -0
  250. package/dist/lib/use-element-width.js +15 -0
  251. package/package.json +5 -1
  252. package/registry.lock.json +16 -0
  253. package/report.css +63 -47
  254. package/styles/siyahi.css +708 -55
@@ -1,13 +1,15 @@
1
1
  import { cn } from "../../../lib/utils.js";
2
+ import { useElementWidth } from "../../../lib/use-element-width.js";
3
+ import { useHeatmapNavigation } from "../../../lib/heatmap-navigation.js";
2
4
  import { Fragment, jsx, jsxs } from "react/jsx-runtime";
3
- import { Fragment as Fragment$1, createContext, use, useMemo } from "react";
5
+ import { Fragment as Fragment$1, createContext, use, useId, useMemo } from "react";
4
6
  import { format } from "date-fns";
5
7
  //#region src/components/registry/heatmap/status-heatmap.tsx
6
8
  const DEFAULT_COLORS = {
7
9
  0: "var(--color-secondary)",
8
- 1: "var(--negative)",
10
+ 1: "var(--destructive)",
9
11
  2: "var(--warning)",
10
- 3: "var(--positive)"
12
+ 3: "color-mix(in oklab, var(--muted-foreground) 30%, transparent)"
11
13
  };
12
14
  const SEMANTIC_KEYS = {
13
15
  0: "noData",
@@ -45,12 +47,32 @@ const resolveStatusLabel = (value, labels) => {
45
47
  default: return `Status ${value}`;
46
48
  }
47
49
  };
48
- const getStatusFill = (value, colors, highlighted = false) => {
49
- const base = resolveColor(value, colors);
50
- if (!highlighted) return base;
51
- return `color-mix(in oklch, ${base} 60%, transparent)`;
52
- };
50
+ const DEGRADED = 2;
51
+ /** A degraded day's paint: amber in the lower half of the bar, the healthy grey above it. */
52
+ const DegradedGradient = ({ id, colors, healthyValue }) => /* @__PURE__ */ jsx("defs", { children: /* @__PURE__ */ jsxs("linearGradient", {
53
+ id,
54
+ x1: "0",
55
+ y1: "0",
56
+ x2: "0",
57
+ y2: "1",
58
+ children: [/* @__PURE__ */ jsx("stop", {
59
+ offset: "0.5",
60
+ style: { stopColor: resolveColor(healthyValue, colors) }
61
+ }), /* @__PURE__ */ jsx("stop", {
62
+ offset: "0.5",
63
+ style: { stopColor: resolveColor(DEGRADED, colors) }
64
+ })]
65
+ }) });
66
+ const NO_DATA = 0;
67
+ /** A no-data day is drawn hollow unless the page gave that state a colour of its own. */
68
+ const isHollow = (value, colors) => value === NO_DATA && colors?.[NO_DATA] === void 0 && colors?.noData === void 0;
69
+ /** The outline a day carries in the field-edge colour: solid round a healthy day, dashed round a day with no data. */
70
+ const edgeOf = (value, healthyValue, colors) => isHollow(value, colors) ? "dashed" : value === healthyValue ? "solid" : null;
71
+ const blockPaint = (value, degradedId, colors) => value === DEGRADED ? { fill: `url(#${degradedId})` } : { fill: isHollow(value, colors) ? "transparent" : resolveColor(value, colors) };
53
72
  const EMPTY_STYLE = {};
73
+ const LEGEND_SWATCH = 10;
74
+ const MIN_FITTED_BAR = 2;
75
+ const DEFAULT_ASPECT_RATIO = .2;
54
76
  const StatusHeatmapContext = createContext(null);
55
77
  const useStatusHeatmap = () => {
56
78
  const context = use(StatusHeatmapContext);
@@ -84,15 +106,17 @@ const useStatusHeatmap = () => {
84
106
  *
85
107
  * @param data - Array of activities with date (YYYY-MM-DD) and status value (0-3)
86
108
  * @param dateFormat - Date format string for tooltips. Default: "MMM d"
87
- * @param blockAspectRatio - Width/height ratio of blocks. Default: 0.2 (narrow vertical bars)
109
+ * @param blockAspectRatio - Width/height ratio of blocks. Default: bars share the full width
88
110
  * @param colors - Custom colors for critical, degraded, and healthy states
89
111
  */
90
- const StatusHeatmap = ({ data, dateFormat = "MMM d", blockSize = 40, blockMargin = 2, blockRadius = 2, blockAspectRatio = .2, colors, locale, labels: labelsProp, fontSize = 14, emptyState, statusValues = [
112
+ const StatusHeatmap = ({ data, dateFormat = "MMM d", blockSize = 40, blockMargin = 2, blockRadius = 2, blockAspectRatio: blockAspectRatioProp, colors, locale, labels: labelsProp, fontSize = 14, emptyState, statusValues = [
91
113
  0,
92
114
  1,
93
115
  2,
94
116
  3
95
117
  ], healthyValue = 3, style = EMPTY_STYLE, className, children, ...props }) => {
118
+ const [rootRef, rootWidth] = useElementWidth();
119
+ const degradedId = `status-degraded-${useId().replace(/[^\w-]/g, "")}`;
96
120
  const labels = useMemo(() => ({
97
121
  statuses: {
98
122
  noData: "No Data",
@@ -112,10 +136,14 @@ const StatusHeatmap = ({ data, dateFormat = "MMM d", blockSize = 40, blockMargin
112
136
  });
113
137
  return Array.from(uniqueDates).sort();
114
138
  }, [data]);
115
- const blockWidth = blockSize * blockAspectRatio;
139
+ const fits = blockAspectRatioProp === void 0;
140
+ const fitted = (rootWidth - 6 + blockMargin) / Math.max(dates.length, 1) - blockMargin;
141
+ const blockWidth = fits && rootWidth > 0 ? Math.max(MIN_FITTED_BAR, fitted) : blockSize * (blockAspectRatioProp ?? DEFAULT_ASPECT_RATIO);
142
+ const blockAspectRatio = blockWidth / blockSize;
116
143
  const width = dates.length * (blockWidth + blockMargin) - blockMargin;
117
144
  const height = blockSize;
118
145
  const contextValue = useMemo(() => ({
146
+ degradedId,
119
147
  data,
120
148
  dates,
121
149
  blockMargin,
@@ -133,6 +161,7 @@ const StatusHeatmap = ({ data, dateFormat = "MMM d", blockSize = 40, blockMargin
133
161
  locale,
134
162
  colors
135
163
  }), [
164
+ degradedId,
136
165
  data,
137
166
  dates,
138
167
  blockMargin,
@@ -154,8 +183,9 @@ const StatusHeatmap = ({ data, dateFormat = "MMM d", blockSize = 40, blockMargin
154
183
  return /* @__PURE__ */ jsx(StatusHeatmapContext, {
155
184
  value: contextValue,
156
185
  children: /* @__PURE__ */ jsx("div", {
186
+ ref: rootRef,
157
187
  "data-slot": "status-heatmap",
158
- className: cn("flex w-max max-w-full flex-col gap-2 p-4", className),
188
+ className: cn("flex flex-col gap-2", fits ? "w-full" : "w-max max-w-full", className),
159
189
  style: {
160
190
  fontSize,
161
191
  ...style
@@ -165,8 +195,9 @@ const StatusHeatmap = ({ data, dateFormat = "MMM d", blockSize = 40, blockMargin
165
195
  })
166
196
  });
167
197
  };
168
- const StatusHeatmapBlock = ({ ref, activity, dayIndex, highlighted = false, onCellClick, onCellHover, onClick, onKeyDown, onMouseEnter, onMouseLeave, className, style: styleProp, ...props }) => {
169
- const { blockSize, blockWidth, blockMargin, blockRadius, labels, colors } = useStatusHeatmap();
198
+ const StatusHeatmapBlock = ({ ref, activity, dayIndex, highlighted = false, selected = false, onCellClick, onCellHover, onClick, onKeyDown, onMouseEnter, onMouseLeave, className, style: styleProp, ...props }) => {
199
+ const { blockSize, blockWidth, blockMargin, blockRadius, labels, colors, degradedId, healthyValue } = useStatusHeatmap();
200
+ const edge = edgeOf(activity.value, healthyValue, colors);
170
201
  const statusText = resolveStatusLabel(activity.value, labels.statuses);
171
202
  const ariaLabel = (labels.cellLabel ?? "{{date}}: {{status}}").replace("{{date}}", activity.date).replace("{{status}}", statusText);
172
203
  const xPosition = (blockWidth + blockMargin) * dayIndex;
@@ -174,20 +205,23 @@ const StatusHeatmapBlock = ({ ref, activity, dayIndex, highlighted = false, onCe
174
205
  ref,
175
206
  "data-slot": "status-heatmap-block",
176
207
  role: onCellClick ? "button" : "img",
208
+ "aria-pressed": onCellClick ? selected : void 0,
177
209
  tabIndex: onCellClick ? 0 : -1,
178
210
  "aria-label": ariaLabel,
179
- className: cn("motion-safe:transition-opacity motion-safe:hover:opacity-70", onCellClick && "cursor-pointer focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring", className),
211
+ className: cn(edge && "stroke-input stroke-1", "hover:stroke-foreground hover:stroke-1", highlighted && "stroke-foreground stroke-1", selected && "stroke-foreground stroke-2 hover:stroke-2", onCellClick && "cursor-pointer", className),
180
212
  "data-value": activity.value,
181
213
  "data-date": activity.date,
182
214
  "data-highlighted": highlighted || void 0,
215
+ "data-selected": selected || void 0,
183
216
  height: blockSize,
184
217
  rx: blockRadius,
185
218
  ry: blockRadius,
186
219
  width: blockWidth,
220
+ strokeDasharray: edge === "dashed" ? "2 2" : void 0,
187
221
  x: xPosition,
188
222
  y: 0,
189
223
  style: {
190
- fill: getStatusFill(activity.value, colors, highlighted),
224
+ ...blockPaint(activity.value, degradedId, colors),
191
225
  ...styleProp
192
226
  },
193
227
  onClick: (event) => {
@@ -214,7 +248,8 @@ const StatusHeatmapBlock = ({ ref, activity, dayIndex, highlighted = false, onCe
214
248
  };
215
249
  StatusHeatmapBlock.displayName = "StatusHeatmapBlock";
216
250
  const StatusHeatmapBody = ({ hideDateLabels = false, labelInterval = 30, className, labelClassName, children, ...props }) => {
217
- const { data, dates, width, height, blockWidth, blockMargin, fontSize, dateFormat, locale, labels } = useStatusHeatmap();
251
+ const navigation = useHeatmapNavigation();
252
+ const { data, dates, width, height, blockWidth, blockMargin, fontSize, dateFormat, locale, labels, colors, degradedId, healthyValue } = useStatusHeatmap();
218
253
  const activityMap = useMemo(() => {
219
254
  const map = /* @__PURE__ */ new Map();
220
255
  data.forEach((activity) => {
@@ -234,40 +269,53 @@ const StatusHeatmapBody = ({ hideDateLabels = false, labelInterval = 30, classNa
234
269
  const labelHeight = hideDateLabels ? 0 : labelFontSize * 2;
235
270
  return /* @__PURE__ */ jsx("div", {
236
271
  "data-slot": "status-heatmap-body",
272
+ ref: navigation.ref,
237
273
  className: cn("max-w-full overflow-x-auto overflow-y-hidden", className),
238
274
  ...props,
275
+ onKeyDown: (event) => {
276
+ props.onKeyDown?.(event);
277
+ if (!event.defaultPrevented) navigation.onKeyDown(event);
278
+ },
239
279
  children: /* @__PURE__ */ jsxs("svg", {
240
280
  role: "img",
241
281
  "aria-label": labels.heatmapLabel ?? "Status heatmap",
242
282
  className: "block overflow-visible rounded-sm focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring",
243
- height: height + labelHeight + 40,
244
- viewBox: `-20 -20 ${width + 40} ${height + labelHeight + 40}`,
245
- width: width + 40,
246
- children: [!hideDateLabels && /* @__PURE__ */ jsx("g", {
247
- className: cn("fill-current font-mono", labelClassName),
248
- children: dates.map((date, dayIndex) => {
249
- const isFirst = dayIndex === 0;
250
- const isLast = dayIndex === dates.length - 1;
251
- if (dayIndex % labelInterval !== 0 && !isLast) return null;
252
- const blockLeft = (blockWidth + blockMargin) * dayIndex;
253
- const xPosition = isFirst ? blockLeft : isLast ? blockLeft + blockWidth : blockLeft + blockWidth / 2;
254
- const anchor = isFirst ? "start" : isLast ? "end" : "middle";
255
- return /* @__PURE__ */ jsx("text", {
256
- x: xPosition,
257
- y: height + labelFontSize,
258
- dominantBaseline: "hanging",
259
- textAnchor: anchor,
260
- style: { fontSize: `${labelFontSize}px` },
261
- children: format(new Date(date), dateFormat, { locale })
262
- }, `date-${date}`);
283
+ height: height + labelHeight + 6,
284
+ viewBox: `-3 -3 ${width + 6} ${height + labelHeight + 6}`,
285
+ width: width + 6,
286
+ children: [
287
+ /* @__PURE__ */ jsx(DegradedGradient, {
288
+ id: degradedId,
289
+ colors,
290
+ healthyValue
291
+ }),
292
+ !hideDateLabels && /* @__PURE__ */ jsx("g", {
293
+ className: cn("fill-current font-mono", labelClassName),
294
+ children: dates.map((date, dayIndex) => {
295
+ const isFirst = dayIndex === 0;
296
+ const isLast = dayIndex === dates.length - 1;
297
+ if (dayIndex % labelInterval !== 0 && !isLast) return null;
298
+ const blockLeft = (blockWidth + blockMargin) * dayIndex;
299
+ const xPosition = isFirst ? blockLeft : isLast ? blockLeft + blockWidth : blockLeft + blockWidth / 2;
300
+ const anchor = isFirst ? "start" : isLast ? "end" : "middle";
301
+ return /* @__PURE__ */ jsx("text", {
302
+ x: xPosition,
303
+ y: height + labelFontSize,
304
+ dominantBaseline: "hanging",
305
+ textAnchor: anchor,
306
+ style: { fontSize: `${labelFontSize}px` },
307
+ children: format(new Date(date), dateFormat, { locale })
308
+ }, `date-${date}`);
309
+ })
310
+ }),
311
+ allActivities.map((activity, dayIndex) => {
312
+ const key = activity.date;
313
+ return /* @__PURE__ */ jsx(Fragment$1, { children: children({
314
+ activity,
315
+ dayIndex
316
+ }) }, key);
263
317
  })
264
- }), allActivities.map((activity, dayIndex) => {
265
- const key = activity.date;
266
- return /* @__PURE__ */ jsx(Fragment$1, { children: children({
267
- activity,
268
- dayIndex
269
- }) }, key);
270
- })]
318
+ ]
271
319
  })
272
320
  });
273
321
  };
@@ -292,7 +340,7 @@ const StatusHeatmapStat = ({ compute, label, className, children, ...props }) =>
292
340
  });
293
341
  };
294
342
  const StatusHeatmapLegend = ({ labels: labelsProp, className, children, ...props }) => {
295
- const { labels, statusValues, blockSize, blockWidth, blockRadius, colors } = useStatusHeatmap();
343
+ const { labels, statusValues, blockRadius, colors, degradedId, healthyValue } = useStatusHeatmap();
296
344
  const statuses = statusValues.map((value) => ({
297
345
  value,
298
346
  label: resolveStatusLabel(value, labelsProp ?? labels.statuses)
@@ -300,25 +348,38 @@ const StatusHeatmapLegend = ({ labels: labelsProp, className, children, ...props
300
348
  return /* @__PURE__ */ jsx("fieldset", {
301
349
  "data-slot": "status-heatmap-legend",
302
350
  "aria-label": labels.legendLabel ?? "Status legend",
303
- className: cn("ml-auto flex items-center gap-1", className),
351
+ className: cn("ml-auto flex flex-wrap items-center gap-x-3 gap-y-1", className),
304
352
  ...props,
305
353
  children: statuses.map((status) => children ? /* @__PURE__ */ jsx(Fragment$1, { children: children({
306
354
  value: status.value,
307
355
  label: status.label
308
356
  }) }, `status-${status.value}`) : /* @__PURE__ */ jsxs("div", {
309
357
  className: "flex items-center gap-1",
310
- children: [/* @__PURE__ */ jsx("svg", {
358
+ children: [/* @__PURE__ */ jsxs("svg", {
311
359
  "aria-hidden": "true",
312
- height: blockSize / 2,
313
- width: blockWidth,
314
- children: /* @__PURE__ */ jsx("rect", {
360
+ height: LEGEND_SWATCH,
361
+ width: LEGEND_SWATCH,
362
+ children: [status.value === DEGRADED && /* @__PURE__ */ jsx(DegradedGradient, {
363
+ id: `${degradedId}-legend`,
364
+ colors,
365
+ healthyValue
366
+ }), /* @__PURE__ */ jsx("rect", {
315
367
  "data-value": status.value,
316
- height: blockSize / 2,
368
+ ...edgeOf(status.value, healthyValue, colors) ? {
369
+ x: .5,
370
+ y: .5,
371
+ height: 9,
372
+ width: 9,
373
+ className: "stroke-input",
374
+ strokeDasharray: edgeOf(status.value, healthyValue, colors) === "dashed" ? "2 1" : void 0
375
+ } : {
376
+ height: LEGEND_SWATCH,
377
+ width: LEGEND_SWATCH
378
+ },
317
379
  rx: blockRadius,
318
380
  ry: blockRadius,
319
- width: blockWidth,
320
- style: { fill: getStatusFill(status.value, colors) }
321
- })
381
+ style: blockPaint(status.value, `${degradedId}-legend`, colors)
382
+ })]
322
383
  }), /* @__PURE__ */ jsx("span", {
323
384
  className: "font-medium text-muted-foreground text-xs",
324
385
  children: status.label
@@ -36,6 +36,10 @@ export type ColorConfig = {
36
36
  export type WeekdayHeatmapProps = HTMLAttributes<HTMLDivElement> & {
37
37
  data: WeekdayHourlyActivity[];
38
38
  weekStart?: Day;
39
+ /** Displayed hours, in order; defaults to the full day. */
40
+ hours?: readonly WeekdayHour[];
41
+ /** Displayed days, in order; defaults to the full week from weekStart. */
42
+ weekdays?: readonly WeekdayIndex[];
39
43
  use12Hour?: boolean;
40
44
  blockSize?: number;
41
45
  blockMargin?: number;
@@ -86,8 +90,10 @@ export type WeekdayHeatmapProps = HTMLAttributes<HTMLDivElement> & {
86
90
  * @param extraRow - Appends an aggregated row below the grid. `compute` receives all activities and must return 24 values (one per hour). Rendered through `renderExtraRow` on the body, or falls back to `children`.
87
91
  * @param extraColumn - Appends an aggregated column to the right of the grid. `compute` receives all activities and must return 7 values indexed by weekday 0–6. Rendered through `renderExtraColumn` on the body, or falls back to `children`.
88
92
  */
89
- export declare const WeekdayHeatmap: ({ data, weekStart, use12Hour, blockSize, blockMargin, blockRadius, blockAspectRatio, levels: levelsProp, isNormalized, colors, locale, labels: labelsProp, fontSize, emptyState, totalCount: totalCountProp, extraRow, extraColumn, style, className, children, ...props }: WeekdayHeatmapProps) => string | number | bigint | true | import("react").JSX.Element | Iterable<ReactNode> | Promise<string | number | bigint | boolean | Iterable<ReactNode> | import("react").ReactElement<unknown, string | import("react").JSXElementConstructor<any>> | import("react").ReactPortal | null | undefined> | null;
93
+ export declare const WeekdayHeatmap: ({ data, weekStart, hours, weekdays: displayedWeekdays, use12Hour, blockSize: blockSizeProp, blockMargin, blockRadius, blockAspectRatio, levels: levelsProp, isNormalized, colors, locale, labels: labelsProp, fontSize, emptyState, totalCount: totalCountProp, extraRow, extraColumn, style, className, children, ...props }: WeekdayHeatmapProps) => string | number | bigint | true | import("react").JSX.Element | Iterable<ReactNode> | Promise<string | number | bigint | boolean | Iterable<ReactNode> | import("react").ReactElement<unknown, string | import("react").JSXElementConstructor<any>> | import("react").ReactPortal | null | undefined> | null;
90
94
  export type WeekdayHeatmapBlockProps = HTMLAttributes<SVGRectElement> & {
95
+ /** The cell the page has picked: drawn with a ring and announced as pressed. */
96
+ selected?: boolean;
91
97
  activity: WeekdayHourlyActivityWithLevel;
92
98
  extra?: "row" | "column";
93
99
  highlighted?: boolean;
@@ -95,9 +101,9 @@ export type WeekdayHeatmapBlockProps = HTMLAttributes<SVGRectElement> & {
95
101
  onCellHover?: (activity: WeekdayHourlyActivityWithLevel | null) => void;
96
102
  className?: string;
97
103
  };
98
- export declare function WeekdayHeatmapBlock({ ref, activity, extra, highlighted, onCellClick, onCellHover, onClick, onKeyDown, onMouseEnter, onMouseLeave, className, style: styleProp, ...props }: WeekdayHeatmapBlockProps & {
104
+ export declare function WeekdayHeatmapBlock({ ref, activity, extra, highlighted, selected, onCellClick, onCellHover, onClick, onKeyDown, onMouseEnter, onMouseLeave, className, style: styleProp, ...props }: WeekdayHeatmapBlockProps & {
99
105
  ref?: React.RefObject<SVGRectElement | null>;
100
- }): import("react").JSX.Element;
106
+ }): import("react").JSX.Element | null;
101
107
  export declare namespace WeekdayHeatmapBlock {
102
108
  var displayName: string;
103
109
  }