@siyahi/ui 0.0.0-stage → 0.1.0-next.3

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 (192) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +174 -2
  3. package/THIRD_PARTY_NOTICES.md +51 -0
  4. package/dist/components/registry/dashboard-01/section-cards.d.ts +17 -0
  5. package/dist/components/registry/dashboard-01/section-cards.js +39 -0
  6. package/dist/components/registry/dashboardcn/bar-list.d.ts +24 -0
  7. package/dist/components/registry/dashboardcn/bar-list.js +71 -0
  8. package/dist/components/registry/heatmap/calendar-heatmap.d.ts +134 -0
  9. package/dist/components/registry/heatmap/calendar-heatmap.js +497 -0
  10. package/dist/components/registry/heatmap/status-heatmap.d.ts +120 -0
  11. package/dist/components/registry/heatmap/status-heatmap.js +330 -0
  12. package/dist/components/registry/heatmap/weekday-heatmap.d.ts +145 -0
  13. package/dist/components/registry/heatmap/weekday-heatmap.js +489 -0
  14. package/dist/components/registry/niko-table/components/data-table-column-actions.d.ts +26 -0
  15. package/dist/components/registry/niko-table/components/data-table-column-actions.js +32 -0
  16. package/dist/components/registry/niko-table/components/data-table-column-filter.d.ts +13 -0
  17. package/dist/components/registry/niko-table/components/data-table-column-filter.js +17 -0
  18. package/dist/components/registry/niko-table/components/data-table-column-header.d.ts +30 -0
  19. package/dist/components/registry/niko-table/components/data-table-column-header.js +35 -0
  20. package/dist/components/registry/niko-table/components/data-table-column-sort.d.ts +21 -0
  21. package/dist/components/registry/niko-table/components/data-table-column-sort.js +36 -0
  22. package/dist/components/registry/niko-table/components/data-table-column-title.d.ts +12 -0
  23. package/dist/components/registry/niko-table/components/data-table-column-title.js +18 -0
  24. package/dist/components/registry/niko-table/components/data-table-empty-state.d.ts +108 -0
  25. package/dist/components/registry/niko-table/components/data-table-empty-state.js +148 -0
  26. package/dist/components/registry/niko-table/components/data-table-faceted-filter.d.ts +46 -0
  27. package/dist/components/registry/niko-table/components/data-table-faceted-filter.js +133 -0
  28. package/dist/components/registry/niko-table/components/data-table-grouped-rows.d.ts +111 -0
  29. package/dist/components/registry/niko-table/components/data-table-grouped-rows.js +77 -0
  30. package/dist/components/registry/niko-table/components/data-table-row-context-menu-slot.d.ts +65 -0
  31. package/dist/components/registry/niko-table/components/data-table-row-context-menu-slot.js +65 -0
  32. package/dist/components/registry/niko-table/components/data-table-row-context-menu.d.ts +50 -0
  33. package/dist/components/registry/niko-table/components/data-table-row-context-menu.js +42 -0
  34. package/dist/components/registry/niko-table/components/data-table-row-menu.d.ts +51 -0
  35. package/dist/components/registry/niko-table/components/data-table-row-menu.js +65 -0
  36. package/dist/components/registry/niko-table/components/data-table-toolbar-section.d.ts +7 -0
  37. package/dist/components/registry/niko-table/components/data-table-toolbar-section.js +63 -0
  38. package/dist/components/registry/niko-table/config/data-table.d.ts +156 -0
  39. package/dist/components/registry/niko-table/config/data-table.js +279 -0
  40. package/dist/components/registry/niko-table/config/feature-detection.d.ts +39 -0
  41. package/dist/components/registry/niko-table/config/feature-detection.js +174 -0
  42. package/dist/components/registry/niko-table/core/data-table-context.d.ts +157 -0
  43. package/dist/components/registry/niko-table/core/data-table-context.js +326 -0
  44. package/dist/components/registry/niko-table/core/data-table-error-boundary.d.ts +85 -0
  45. package/dist/components/registry/niko-table/core/data-table-error-boundary.js +116 -0
  46. package/dist/components/registry/niko-table/core/data-table-grouped-row.d.ts +49 -0
  47. package/dist/components/registry/niko-table/core/data-table-grouped-row.js +112 -0
  48. package/dist/components/registry/niko-table/core/data-table-root.d.ts +62 -0
  49. package/dist/components/registry/niko-table/core/data-table-root.js +406 -0
  50. package/dist/components/registry/niko-table/core/data-table-structure.d.ts +153 -0
  51. package/dist/components/registry/niko-table/core/data-table-structure.js +370 -0
  52. package/dist/components/registry/niko-table/core/data-table.d.ts +30 -0
  53. package/dist/components/registry/niko-table/core/data-table.js +126 -0
  54. package/dist/components/registry/niko-table/filters/table-column-actions.d.ts +49 -0
  55. package/dist/components/registry/niko-table/filters/table-column-actions.js +48 -0
  56. package/dist/components/registry/niko-table/filters/table-column-sort.d.ts +51 -0
  57. package/dist/components/registry/niko-table/filters/table-column-sort.js +184 -0
  58. package/dist/components/registry/niko-table/filters/table-column-title.d.ts +17 -0
  59. package/dist/components/registry/niko-table/filters/table-column-title.js +20 -0
  60. package/dist/components/registry/niko-table/filters/table-faceted-filter.d.ts +40 -0
  61. package/dist/components/registry/niko-table/filters/table-faceted-filter.js +210 -0
  62. package/dist/components/registry/niko-table/hooks/use-derived-column-title.d.ts +29 -0
  63. package/dist/components/registry/niko-table/hooks/use-derived-column-title.js +40 -0
  64. package/dist/components/registry/niko-table/hooks/use-generated-options.d.ts +49 -0
  65. package/dist/components/registry/niko-table/hooks/use-generated-options.js +144 -0
  66. package/dist/components/registry/niko-table/lib/build-faceted-options.d.ts +59 -0
  67. package/dist/components/registry/niko-table/lib/build-faceted-options.js +82 -0
  68. package/dist/components/registry/niko-table/lib/column-resize-handle.d.ts +33 -0
  69. package/dist/components/registry/niko-table/lib/column-resize-handle.js +175 -0
  70. package/dist/components/registry/niko-table/lib/constants.d.ts +128 -0
  71. package/dist/components/registry/niko-table/lib/constants.js +123 -0
  72. package/dist/components/registry/niko-table/lib/create-scroll-handler.d.ts +35 -0
  73. package/dist/components/registry/niko-table/lib/create-scroll-handler.js +63 -0
  74. package/dist/components/registry/niko-table/lib/data-table-features.d.ts +218 -0
  75. package/dist/components/registry/niko-table/lib/data-table-features.js +127 -0
  76. package/dist/components/registry/niko-table/lib/filter-functions.d.ts +47 -0
  77. package/dist/components/registry/niko-table/lib/filter-functions.js +309 -0
  78. package/dist/components/registry/niko-table/lib/filter-rows.d.ts +14 -0
  79. package/dist/components/registry/niko-table/lib/filter-rows.js +28 -0
  80. package/dist/components/registry/niko-table/lib/flex-columns.d.ts +48 -0
  81. package/dist/components/registry/niko-table/lib/flex-columns.js +65 -0
  82. package/dist/components/registry/niko-table/lib/format.d.ts +33 -0
  83. package/dist/components/registry/niko-table/lib/format.js +99 -0
  84. package/dist/components/registry/niko-table/lib/render-cell-content.d.ts +17 -0
  85. package/dist/components/registry/niko-table/lib/render-cell-content.js +65 -0
  86. package/dist/components/registry/niko-table/lib/row-click.d.ts +67 -0
  87. package/dist/components/registry/niko-table/lib/row-click.js +28 -0
  88. package/dist/components/registry/niko-table/lib/styles.d.ts +6 -0
  89. package/dist/components/registry/niko-table/lib/styles.js +24 -0
  90. package/dist/components/registry/niko-table/lib/use-header-min-widths.d.ts +17 -0
  91. package/dist/components/registry/niko-table/lib/use-header-min-widths.js +82 -0
  92. package/dist/components/registry/niko-table/types/index.d.ts +141 -0
  93. package/dist/components/registry/niko-table/types/index.js +2 -0
  94. package/dist/components/registry/niko-table/ui/table.d.ts +13 -0
  95. package/dist/components/registry/niko-table/ui/table.js +74 -0
  96. package/dist/components/registry/sidebar-07/app-sidebar.d.ts +18 -0
  97. package/dist/components/registry/sidebar-07/app-sidebar.js +26 -0
  98. package/dist/components/registry/sidebar-07/nav-main.d.ts +15 -0
  99. package/dist/components/registry/sidebar-07/nav-main.js +25 -0
  100. package/dist/components/registry/sidebar-07/nav-projects.d.ts +9 -0
  101. package/dist/components/registry/sidebar-07/nav-projects.js +43 -0
  102. package/dist/components/registry/sidebar-07/nav-user.d.ts +9 -0
  103. package/dist/components/registry/sidebar-07/nav-user.js +70 -0
  104. package/dist/components/registry/sidebar-07/team-switcher.d.ts +10 -0
  105. package/dist/components/registry/sidebar-07/team-switcher.js +70 -0
  106. package/dist/components/siyahi/delta.d.ts +10 -0
  107. package/dist/components/siyahi/delta.js +27 -0
  108. package/dist/components/siyahi/local-time.d.ts +7 -0
  109. package/dist/components/siyahi/local-time.js +22 -0
  110. package/dist/components/siyahi/price-chart.d.ts +12 -0
  111. package/dist/components/siyahi/price-chart.js +80 -0
  112. package/dist/components/siyahi/siyahi-provider.d.ts +12 -0
  113. package/dist/components/siyahi/siyahi-provider.js +31 -0
  114. package/dist/components/siyahi/treemap.d.ts +14 -0
  115. package/dist/components/siyahi/treemap.js +58 -0
  116. package/dist/components/ui/alert.d.ts +12 -0
  117. package/dist/components/ui/alert.js +43 -0
  118. package/dist/components/ui/avatar.d.ts +13 -0
  119. package/dist/components/ui/avatar.js +50 -0
  120. package/dist/components/ui/badge.d.ts +9 -0
  121. package/dist/components/ui/badge.js +29 -0
  122. package/dist/components/ui/breadcrumb.d.ts +12 -0
  123. package/dist/components/ui/breadcrumb.js +72 -0
  124. package/dist/components/ui/button.d.ts +10 -0
  125. package/dist/components/ui/button.js +44 -0
  126. package/dist/components/ui/calendar.d.ts +12 -0
  127. package/dist/components/ui/calendar.js +107 -0
  128. package/dist/components/ui/card.d.ts +13 -0
  129. package/dist/components/ui/card.js +56 -0
  130. package/dist/components/ui/chart.d.ts +46 -0
  131. package/dist/components/ui/chart.js +149 -0
  132. package/dist/components/ui/collapsible.d.ts +7 -0
  133. package/dist/components/ui/collapsible.js +24 -0
  134. package/dist/components/ui/command.d.ts +21 -0
  135. package/dist/components/ui/command.js +88 -0
  136. package/dist/components/ui/context-menu.d.ts +31 -0
  137. package/dist/components/ui/context-menu.js +132 -0
  138. package/dist/components/ui/dialog.d.ts +19 -0
  139. package/dist/components/ui/dialog.js +91 -0
  140. package/dist/components/ui/dropdown-menu.d.ts +31 -0
  141. package/dist/components/ui/dropdown-menu.js +136 -0
  142. package/dist/components/ui/input-group.d.ts +20 -0
  143. package/dist/components/ui/input-group.js +79 -0
  144. package/dist/components/ui/input.d.ts +5 -0
  145. package/dist/components/ui/input.js +15 -0
  146. package/dist/components/ui/popover.d.ts +11 -0
  147. package/dist/components/ui/popover.js +55 -0
  148. package/dist/components/ui/progress.d.ts +9 -0
  149. package/dist/components/ui/progress.js +43 -0
  150. package/dist/components/ui/scroll-area.d.ts +7 -0
  151. package/dist/components/ui/scroll-area.js +36 -0
  152. package/dist/components/ui/select.d.ts +17 -0
  153. package/dist/components/ui/select.js +97 -0
  154. package/dist/components/ui/separator.d.ts +5 -0
  155. package/dist/components/ui/separator.js +15 -0
  156. package/dist/components/ui/sheet.d.ts +16 -0
  157. package/dist/components/ui/sheet.js +89 -0
  158. package/dist/components/ui/sidebar.d.ts +65 -0
  159. package/dist/components/ui/sidebar.js +385 -0
  160. package/dist/components/ui/skeleton.d.ts +4 -0
  161. package/dist/components/ui/skeleton.js +12 -0
  162. package/dist/components/ui/slider.d.ts +5 -0
  163. package/dist/components/ui/slider.js +33 -0
  164. package/dist/components/ui/table.d.ts +12 -0
  165. package/dist/components/ui/table.js +66 -0
  166. package/dist/components/ui/tabs.d.ts +12 -0
  167. package/dist/components/ui/tabs.js +45 -0
  168. package/dist/components/ui/textarea.d.ts +5 -0
  169. package/dist/components/ui/textarea.js +13 -0
  170. package/dist/components/ui/toggle-group.d.ts +13 -0
  171. package/dist/components/ui/toggle-group.js +52 -0
  172. package/dist/components/ui/toggle.d.ts +10 -0
  173. package/dist/components/ui/toggle.js +36 -0
  174. package/dist/components/ui/tooltip.d.ts +8 -0
  175. package/dist/components/ui/tooltip.js +41 -0
  176. package/dist/hooks/use-mobile.d.ts +3 -0
  177. package/dist/hooks/use-mobile.js +18 -0
  178. package/dist/index.d.ts +73 -0
  179. package/dist/index.js +71 -0
  180. package/dist/lib/format.d.ts +24 -0
  181. package/dist/lib/format.js +58 -0
  182. package/dist/lib/locale.d.ts +12 -0
  183. package/dist/lib/locale.js +8 -0
  184. package/dist/lib/recharts.d.ts +2 -0
  185. package/dist/lib/recharts.js +1 -0
  186. package/dist/lib/utils.d.ts +2 -0
  187. package/dist/lib/utils.js +1 -0
  188. package/package.json +78 -3
  189. package/registry.lock.json +413 -0
  190. package/report.css +129 -0
  191. package/styles/shadcn.css +643 -0
  192. package/styles/siyahi.css +189 -0
@@ -0,0 +1,330 @@
1
+ import { cn } from "../../../lib/utils.js";
2
+ import { Fragment, createContext, use, useMemo } from "react";
3
+ import { Fragment as Fragment$1, jsx, jsxs } from "react/jsx-runtime";
4
+ import { format } from "date-fns";
5
+ //#region src/components/registry/heatmap/status-heatmap.tsx
6
+ const DEFAULT_COLORS = {
7
+ 0: "var(--color-secondary)",
8
+ 1: "var(--negative)",
9
+ 2: "var(--warning)",
10
+ 3: "var(--positive)"
11
+ };
12
+ const SEMANTIC_KEYS = {
13
+ 0: "noData",
14
+ 1: "critical",
15
+ 2: "degraded",
16
+ 3: "healthy"
17
+ };
18
+ const resolveColor = (value, colors) => {
19
+ const semanticKey = SEMANTIC_KEYS[value];
20
+ if (colors) {
21
+ const numeric = colors[value];
22
+ if (typeof numeric === "string") return numeric;
23
+ if (semanticKey) {
24
+ const semantic = colors[semanticKey];
25
+ if (typeof semantic === "string") return semantic;
26
+ }
27
+ }
28
+ return DEFAULT_COLORS[value] ?? DEFAULT_COLORS[0];
29
+ };
30
+ const resolveStatusLabel = (value, labels) => {
31
+ if (labels) {
32
+ const numeric = labels[value];
33
+ if (typeof numeric === "string") return numeric;
34
+ const semanticKey = SEMANTIC_KEYS[value];
35
+ if (semanticKey) {
36
+ const semantic = labels[semanticKey];
37
+ if (typeof semantic === "string") return semantic;
38
+ }
39
+ }
40
+ switch (value) {
41
+ case 0: return "No Data";
42
+ case 1: return "Critical";
43
+ case 2: return "Degraded";
44
+ case 3: return "Healthy";
45
+ default: return `Status ${value}`;
46
+ }
47
+ };
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
+ };
53
+ const EMPTY_STYLE = {};
54
+ const StatusHeatmapContext = createContext(null);
55
+ const useStatusHeatmap = () => {
56
+ const context = use(StatusHeatmapContext);
57
+ if (!context) throw new Error("StatusHeatmap components must be used within a StatusHeatmap");
58
+ return context;
59
+ };
60
+ /**
61
+ * Status Heatmap
62
+ *
63
+ * A timeline indicator showing daily status over a period (e.g., 90 days).
64
+ * Similar to Atlassian Statuspage - each day is represented by a vertical bar.
65
+ * Supports 4 status values: 0=no-data, 1=critical, 2=degraded, 3=healthy
66
+ *
67
+ * @example
68
+ * ```tsx
69
+ * <StatusHeatmap data={data} blockAspectRatio={0.2}>
70
+ * <StatusHeatmapBody>
71
+ * {({ activity, dayIndex }) => (
72
+ * <StatusHeatmapBlock
73
+ * activity={activity}
74
+ * dayIndex={dayIndex}
75
+ * />
76
+ * )}
77
+ * </StatusHeatmapBody>
78
+ * <StatusHeatmapFooter>
79
+ * <StatusHeatmapStat />
80
+ * <StatusHeatmapLegend />
81
+ * </StatusHeatmapFooter>
82
+ * </StatusHeatmap>
83
+ * ```
84
+ *
85
+ * @param data - Array of activities with date (YYYY-MM-DD) and status value (0-3)
86
+ * @param dateFormat - Date format string for tooltips. Default: "MMM d"
87
+ * @param blockAspectRatio - Width/height ratio of blocks. Default: 0.2 (narrow vertical bars)
88
+ * @param colors - Custom colors for critical, degraded, and healthy states
89
+ */
90
+ const StatusHeatmap = ({ data, dateFormat = "MMM d", blockSize = 40, blockMargin = 2, blockRadius = 2, blockAspectRatio = .2, colors, locale, labels: labelsProp, fontSize = 14, emptyState, statusValues = [
91
+ 0,
92
+ 1,
93
+ 2,
94
+ 3
95
+ ], healthyValue = 3, style = EMPTY_STYLE, className, children, ...props }) => {
96
+ const labels = useMemo(() => ({
97
+ statuses: {
98
+ noData: "No Data",
99
+ critical: "Critical",
100
+ degraded: "Degraded",
101
+ healthy: "Healthy"
102
+ },
103
+ cellLabel: "{{date}}: {{status}}",
104
+ heatmapLabel: "Status heatmap",
105
+ legendLabel: "Status legend",
106
+ ...labelsProp
107
+ }), [labelsProp]);
108
+ const dates = useMemo(() => {
109
+ const uniqueDates = /* @__PURE__ */ new Set();
110
+ data.forEach((activity) => {
111
+ uniqueDates.add(activity.date);
112
+ });
113
+ return Array.from(uniqueDates).sort();
114
+ }, [data]);
115
+ const blockWidth = blockSize * blockAspectRatio;
116
+ const width = dates.length * (blockWidth + blockMargin) - blockMargin;
117
+ const height = blockSize;
118
+ const contextValue = useMemo(() => ({
119
+ data,
120
+ dates,
121
+ blockMargin,
122
+ blockRadius,
123
+ blockSize,
124
+ blockAspectRatio,
125
+ blockWidth,
126
+ fontSize,
127
+ labels,
128
+ statusValues,
129
+ healthyValue,
130
+ width,
131
+ height,
132
+ dateFormat,
133
+ locale,
134
+ colors
135
+ }), [
136
+ data,
137
+ dates,
138
+ blockMargin,
139
+ blockRadius,
140
+ blockSize,
141
+ blockAspectRatio,
142
+ blockWidth,
143
+ fontSize,
144
+ labels,
145
+ statusValues,
146
+ healthyValue,
147
+ width,
148
+ height,
149
+ dateFormat,
150
+ locale,
151
+ colors
152
+ ]);
153
+ if (data.length === 0 || dates.length === 0) return emptyState ? emptyState : null;
154
+ return /* @__PURE__ */ jsx(StatusHeatmapContext, {
155
+ value: contextValue,
156
+ children: /* @__PURE__ */ jsx("div", {
157
+ "data-slot": "status-heatmap",
158
+ className: cn("flex w-max max-w-full flex-col gap-2 p-4", className),
159
+ style: {
160
+ fontSize,
161
+ ...style
162
+ },
163
+ ...props,
164
+ children
165
+ })
166
+ });
167
+ };
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();
170
+ const statusText = resolveStatusLabel(activity.value, labels.statuses);
171
+ const ariaLabel = (labels.cellLabel ?? "{{date}}: {{status}}").replace("{{date}}", activity.date).replace("{{status}}", statusText);
172
+ const xPosition = (blockWidth + blockMargin) * dayIndex;
173
+ return /* @__PURE__ */ jsx("rect", {
174
+ ref,
175
+ "data-slot": "status-heatmap-block",
176
+ role: onCellClick ? "button" : "img",
177
+ tabIndex: onCellClick ? 0 : -1,
178
+ "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),
180
+ "data-value": activity.value,
181
+ "data-date": activity.date,
182
+ "data-highlighted": highlighted || void 0,
183
+ height: blockSize,
184
+ rx: blockRadius,
185
+ ry: blockRadius,
186
+ width: blockWidth,
187
+ x: xPosition,
188
+ y: 0,
189
+ style: {
190
+ fill: getStatusFill(activity.value, colors, highlighted),
191
+ ...styleProp
192
+ },
193
+ onClick: (event) => {
194
+ onCellClick?.(activity);
195
+ onClick?.(event);
196
+ },
197
+ onKeyDown: (event) => {
198
+ if (onCellClick && (event.key === "Enter" || event.key === " ")) {
199
+ event.preventDefault();
200
+ onCellClick(activity);
201
+ }
202
+ onKeyDown?.(event);
203
+ },
204
+ onMouseEnter: (event) => {
205
+ onCellHover?.(activity);
206
+ onMouseEnter?.(event);
207
+ },
208
+ onMouseLeave: (event) => {
209
+ onCellHover?.(null);
210
+ onMouseLeave?.(event);
211
+ },
212
+ ...props
213
+ });
214
+ };
215
+ StatusHeatmapBlock.displayName = "StatusHeatmapBlock";
216
+ const StatusHeatmapBody = ({ hideDateLabels = false, labelInterval = 30, className, labelClassName, children, ...props }) => {
217
+ const { data, dates, width, height, blockWidth, blockMargin, fontSize, dateFormat, locale, labels } = useStatusHeatmap();
218
+ const activityMap = useMemo(() => {
219
+ const map = /* @__PURE__ */ new Map();
220
+ data.forEach((activity) => {
221
+ map.set(activity.date, activity);
222
+ });
223
+ return map;
224
+ }, [data]);
225
+ const allActivities = useMemo(() => {
226
+ return dates.map((date) => {
227
+ return activityMap.get(date) || {
228
+ date,
229
+ value: 0
230
+ };
231
+ });
232
+ }, [dates, activityMap]);
233
+ const labelFontSize = fontSize * .75;
234
+ const labelHeight = hideDateLabels ? 0 : labelFontSize * 2;
235
+ return /* @__PURE__ */ jsx("div", {
236
+ "data-slot": "status-heatmap-body",
237
+ className: cn("max-w-full overflow-x-auto overflow-y-hidden", className),
238
+ ...props,
239
+ children: /* @__PURE__ */ jsxs("svg", {
240
+ role: "img",
241
+ "aria-label": labels.heatmapLabel ?? "Status heatmap",
242
+ 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}`);
263
+ })
264
+ }), allActivities.map((activity, dayIndex) => {
265
+ const key = activity.date;
266
+ return /* @__PURE__ */ jsx(Fragment, { children: children({
267
+ activity,
268
+ dayIndex
269
+ }) }, key);
270
+ })]
271
+ })
272
+ });
273
+ };
274
+ const StatusHeatmapFooter = ({ className, ...props }) => /* @__PURE__ */ jsx("div", {
275
+ "data-slot": "status-heatmap-footer",
276
+ className: cn("flex flex-wrap gap-1 whitespace-nowrap sm:gap-x-4", className),
277
+ ...props
278
+ });
279
+ const StatusHeatmapStat = ({ compute, label, className, children, ...props }) => {
280
+ const { data, healthyValue, labels } = useStatusHeatmap();
281
+ const value = compute ? compute(data) : data.filter((a) => a.value === healthyValue).length;
282
+ if (children) return /* @__PURE__ */ jsx(Fragment$1, { children: children({
283
+ value,
284
+ data
285
+ }) });
286
+ const template = label ?? labels.stat ?? "{{value}} days healthy";
287
+ return /* @__PURE__ */ jsx("div", {
288
+ "data-slot": "status-heatmap-stat",
289
+ className: cn("text-muted-foreground tabular-nums", className),
290
+ ...props,
291
+ children: template.replace("{{value}}", String(value))
292
+ });
293
+ };
294
+ const StatusHeatmapLegend = ({ labels: labelsProp, className, children, ...props }) => {
295
+ const { labels, statusValues, blockSize, blockWidth, blockRadius, colors } = useStatusHeatmap();
296
+ const statuses = statusValues.map((value) => ({
297
+ value,
298
+ label: resolveStatusLabel(value, labelsProp ?? labels.statuses)
299
+ }));
300
+ return /* @__PURE__ */ jsx("fieldset", {
301
+ "data-slot": "status-heatmap-legend",
302
+ "aria-label": labels.legendLabel ?? "Status legend",
303
+ className: cn("ml-auto flex items-center gap-1", className),
304
+ ...props,
305
+ children: statuses.map((status) => children ? /* @__PURE__ */ jsx(Fragment, { children: children({
306
+ value: status.value,
307
+ label: status.label
308
+ }) }, `status-${status.value}`) : /* @__PURE__ */ jsxs("div", {
309
+ className: "flex items-center gap-1",
310
+ children: [/* @__PURE__ */ jsx("svg", {
311
+ "aria-hidden": "true",
312
+ height: blockSize / 2,
313
+ width: blockWidth,
314
+ children: /* @__PURE__ */ jsx("rect", {
315
+ "data-value": status.value,
316
+ height: blockSize / 2,
317
+ rx: blockRadius,
318
+ ry: blockRadius,
319
+ width: blockWidth,
320
+ style: { fill: getStatusFill(status.value, colors) }
321
+ })
322
+ }), /* @__PURE__ */ jsx("span", {
323
+ className: "font-medium text-muted-foreground text-xs",
324
+ children: status.label
325
+ })]
326
+ }, `status-${status.value}`))
327
+ });
328
+ };
329
+ //#endregion
330
+ export { StatusHeatmap, StatusHeatmapBlock, StatusHeatmapBody, StatusHeatmapFooter, StatusHeatmapLegend, StatusHeatmapStat };
@@ -0,0 +1,145 @@
1
+ import { CSSProperties, HTMLAttributes, ReactNode } from "react";
2
+ import { Day, Locale } from "date-fns";
3
+ //#region src/components/registry/heatmap/weekday-heatmap.d.ts
4
+ export type WeekdayIndex = 0 | 1 | 2 | 3 | 4 | 5 | 6;
5
+ export type WeekdayHour = 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23;
6
+ export type WeekdayHourlyActivity = {
7
+ weekday: number;
8
+ hour: number;
9
+ value: number;
10
+ };
11
+ type WeekdayHourlyActivityWithLevel = WeekdayHourlyActivity & {
12
+ level: number;
13
+ };
14
+ export type WeekdayExtraRowSpec = {
15
+ label: ReactNode;
16
+ compute: (data: WeekdayHourlyActivity[]) => number[];
17
+ };
18
+ export type WeekdayExtraColumnSpec = {
19
+ label: ReactNode;
20
+ compute: (data: WeekdayHourlyActivity[]) => number[];
21
+ };
22
+ export type WeekdayHeatmapLabels = {
23
+ hours?: string[];
24
+ endHour?: string | null;
25
+ weekdays?: string[];
26
+ stat?: string;
27
+ cellLabel?: string;
28
+ heatmapLabel?: string;
29
+ legendLabel?: string;
30
+ legendLevelLabel?: string;
31
+ };
32
+ export type ColorConfig = {
33
+ empty?: string;
34
+ scale?: string;
35
+ };
36
+ export type WeekdayHeatmapProps = HTMLAttributes<HTMLDivElement> & {
37
+ data: WeekdayHourlyActivity[];
38
+ weekStart?: Day;
39
+ use12Hour?: boolean;
40
+ blockSize?: number;
41
+ blockMargin?: number;
42
+ blockRadius?: number;
43
+ blockAspectRatio?: number;
44
+ levels?: number;
45
+ isNormalized?: boolean;
46
+ colors?: ColorConfig;
47
+ locale?: Locale;
48
+ labels?: WeekdayHeatmapLabels;
49
+ fontSize?: number;
50
+ emptyState?: ReactNode;
51
+ totalCount?: number;
52
+ extraRow?: WeekdayExtraRowSpec;
53
+ extraColumn?: WeekdayExtraColumnSpec;
54
+ style?: CSSProperties;
55
+ className?: string;
56
+ children: ReactNode;
57
+ };
58
+ /**
59
+ * Weekday Heatmap
60
+ *
61
+ * A GitHub punch card style heatmap showing activity distribution by weekday (rows) and hour (columns).
62
+ * Renders a 7 × 24 grid with optional extra row (aggregated per hour) and extra column (aggregated per weekday).
63
+ *
64
+ * @example
65
+ * ```tsx
66
+ * <WeekdayHeatmap data={data} weekStart={1} use12Hour>
67
+ * <WeekdayHeatmapBody>
68
+ * {({ activity }) => (
69
+ * <WeekdayHeatmapBlock activity={activity} />
70
+ * )}
71
+ * </WeekdayHeatmapBody>
72
+ * <WeekdayHeatmapFooter>
73
+ * <WeekdayHeatmapStat />
74
+ * <WeekdayHeatmapLegend />
75
+ * </WeekdayHeatmapFooter>
76
+ * </WeekdayHeatmap>
77
+ * ```
78
+ *
79
+ * @param data - Array of activities with weekday (0-6 for Sun-Sat), hour (0-23), and numeric value
80
+ * @param weekStart - First day of week (0=Sunday, 1=Monday). Default: 0
81
+ * @param use12Hour - Use 12-hour format for hour labels. Default: false
82
+ * @param blockSize - Block height in pixels. Default: 24
83
+ * @param blockAspectRatio - Block width/height ratio. Default: 1 (square)
84
+ * @param levels - Total number of legend cells (including empty when not normalized). Default: 5
85
+ * @param isNormalized - When true, uses min-max normalization across the dataset (suitable for signed values like temperature). When false (default), treats 0 as empty and scales from 0 to max.
86
+ * @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
+ * @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
+ */
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;
90
+ export type WeekdayHeatmapBlockProps = HTMLAttributes<SVGRectElement> & {
91
+ activity: WeekdayHourlyActivityWithLevel;
92
+ extra?: "row" | "column";
93
+ highlighted?: boolean;
94
+ onCellClick?: (activity: WeekdayHourlyActivityWithLevel) => void;
95
+ onCellHover?: (activity: WeekdayHourlyActivityWithLevel | null) => void;
96
+ className?: string;
97
+ };
98
+ export declare function WeekdayHeatmapBlock({ ref, activity, extra, highlighted, onCellClick, onCellHover, onClick, onKeyDown, onMouseEnter, onMouseLeave, className, style: styleProp, ...props }: WeekdayHeatmapBlockProps & {
99
+ ref?: React.RefObject<SVGRectElement | null>;
100
+ }): import("react").JSX.Element;
101
+ export declare namespace WeekdayHeatmapBlock {
102
+ var displayName: string;
103
+ }
104
+ export type WeekdayHeatmapBodyProps = Omit<HTMLAttributes<HTMLDivElement>, "children"> & {
105
+ hideHourLabels?: boolean;
106
+ hideWeekdayLabels?: boolean;
107
+ className?: string;
108
+ labelClassName?: string;
109
+ children: (props: {
110
+ activity: WeekdayHourlyActivityWithLevel;
111
+ weekdayIndex: number;
112
+ }) => ReactNode;
113
+ renderExtraRow?: (props: {
114
+ activity: WeekdayHourlyActivityWithLevel;
115
+ weekdayIndex: number;
116
+ }) => ReactNode;
117
+ renderExtraColumn?: (props: {
118
+ activity: WeekdayHourlyActivityWithLevel;
119
+ weekdayIndex: number;
120
+ }) => ReactNode;
121
+ };
122
+ export declare const WeekdayHeatmapBody: ({ hideHourLabels, hideWeekdayLabels, className, labelClassName, children, renderExtraRow, renderExtraColumn, ...props }: WeekdayHeatmapBodyProps) => import("react").JSX.Element;
123
+ export type WeekdayHeatmapFooterProps = HTMLAttributes<HTMLDivElement>;
124
+ export declare const WeekdayHeatmapFooter: ({ className, ...props }: WeekdayHeatmapFooterProps) => import("react").JSX.Element;
125
+ export type WeekdayHeatmapStatProps = Omit<HTMLAttributes<HTMLDivElement>, "children"> & {
126
+ compute?: (data: WeekdayHourlyActivityWithLevel[]) => number | string;
127
+ label?: string;
128
+ children?: (result: {
129
+ value: number | string;
130
+ data: WeekdayHourlyActivityWithLevel[];
131
+ }) => ReactNode;
132
+ };
133
+ export declare const WeekdayHeatmapStat: ({ compute, label, className, children, ...props }: WeekdayHeatmapStatProps) => import("react").JSX.Element;
134
+ export type WeekdayHeatmapLegendProps = Omit<HTMLAttributes<HTMLFieldSetElement>, "children"> & {
135
+ labels?: {
136
+ less?: string;
137
+ more?: string;
138
+ };
139
+ children?: (props: {
140
+ level: number;
141
+ }) => ReactNode;
142
+ };
143
+ export declare const WeekdayHeatmapLegend: ({ labels: labelsProp, className, children, ...props }: WeekdayHeatmapLegendProps) => import("react").JSX.Element;
144
+ //#endregion
145
+ export {};