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

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 +170 -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 +42 -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 +40 -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 +108 -0
  43. package/agents/examples/data-table-compact.tsx +96 -0
  44. package/agents/examples/data-table-filters.tsx +103 -0
  45. package/agents/examples/data-table.tsx +99 -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 +101 -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,4 +1,6 @@
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
5
  import { Fragment as Fragment$1, createContext, use, useMemo } from "react";
4
6
  import { format } from "date-fns";
@@ -16,13 +18,12 @@ const calculateLevel = (value, minValue, maxValue, levels, isNormalized) => {
16
18
  const percentage = value / maxValue;
17
19
  return Math.max(1, Math.min(steps, Math.ceil(percentage * steps)));
18
20
  };
19
- const getLevelFill = (level, levels, isNormalized, highlighted = false, colors) => {
21
+ const getLevelFill = (level, levels, isNormalized, colors) => {
20
22
  const emptyColor = colors?.empty ?? "var(--color-secondary)";
21
23
  const scaleColor = colors?.scale ?? "var(--color-chart-1)";
22
24
  if (level === 0) return emptyColor;
23
25
  const steps = colorStepCount(levels, isNormalized);
24
- const opacity = steps === 1 ? 100 : Math.round(20 + (level - 1) * 80 / (steps - 1));
25
- return `color-mix(in oklch, ${scaleColor} ${highlighted ? Math.round(opacity * .6) : opacity}%, transparent)`;
26
+ return `color-mix(in oklch, ${scaleColor} ${steps === 1 ? 100 : Math.round(20 + (level - 1) * 80 / (steps - 1))}%, transparent)`;
26
27
  };
27
28
  const DEFAULT_HOUR_LABELS = Array.from({ length: 24 }, (_, i) => i.toString().padStart(2, "0"));
28
29
  const TWELVE_HOUR_LABELS = Array.from({ length: 24 }, (_, i) => {
@@ -47,6 +48,10 @@ const generateWeekdayLabels = (locale) => Array.from({ length: 7 }, (_, i) => {
47
48
  });
48
49
  const EMPTY_STYLE = {};
49
50
  const LABEL_MARGIN = 8;
51
+ const LEGEND_SWATCH = 12;
52
+ const MIN_FITTED_BLOCK = 14;
53
+ const MAX_FITTED_BLOCK = 44;
54
+ const DEFAULT_BLOCK = 24;
50
55
  const WeekdayHeatmapContext = createContext(null);
51
56
  const useWeekdayHeatmap = () => {
52
57
  const context = use(WeekdayHeatmapContext);
@@ -84,8 +89,10 @@ const useWeekdayHeatmap = () => {
84
89
  * @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`.
85
90
  * @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`.
86
91
  */
87
- const WeekdayHeatmap = ({ data, weekStart = 0, use12Hour = false, blockSize = 24, blockMargin = 4, blockRadius = 2, blockAspectRatio = 1, levels: levelsProp = 5, isNormalized = false, colors, locale, labels: labelsProp, fontSize = 14, emptyState, totalCount: totalCountProp, extraRow, extraColumn, style = EMPTY_STYLE, className, children, ...props }) => {
92
+ const WeekdayHeatmap = ({ data, weekStart = 0, hours = HOURS, weekdays: displayedWeekdays, use12Hour = false, blockSize: blockSizeProp, blockMargin = 4, blockRadius = 2, blockAspectRatio = 1, levels: levelsProp = 5, isNormalized = false, colors, locale, labels: labelsProp, fontSize = 14, emptyState, totalCount: totalCountProp, extraRow, extraColumn, style = EMPTY_STYLE, className, children, ...props }) => {
88
93
  const levels = Math.max(1, levelsProp);
94
+ const [rootRef, rootWidth] = useElementWidth();
95
+ const weekdays = useMemo(() => displayedWeekdays ?? Array.from({ length: 7 }, (_, i) => (weekStart + i) % 7), [displayedWeekdays, weekStart]);
89
96
  const dataWithLevels = useMemo(() => {
90
97
  if (data.length === 0) return [];
91
98
  const maxRegular = data.reduce((m, d) => Math.max(m, d.value), 1);
@@ -141,7 +148,7 @@ const WeekdayHeatmap = ({ data, weekStart = 0, use12Hour = false, blockSize = 24
141
148
  const weekdayLabels = locale ? generateWeekdayLabels(locale) : DEFAULT_WEEKDAY_LABELS;
142
149
  return {
143
150
  hours: use12Hour ? TWELVE_HOUR_LABELS : DEFAULT_HOUR_LABELS,
144
- endHour: use12Hour ? "12" : "00",
151
+ endHour: hours.at(-1) === 23 ? use12Hour ? "12" : "00" : (use12Hour ? TWELVE_HOUR_LABELS : DEFAULT_HOUR_LABELS)[(hours.at(-1) ?? -1) + 1],
145
152
  weekdays: weekdayLabels,
146
153
  cellLabel: "{{weekday}} {{hour}}: {{value}}",
147
154
  heatmapLabel: "Activity heatmap by weekday and hour",
@@ -152,16 +159,20 @@ const WeekdayHeatmap = ({ data, weekStart = 0, use12Hour = false, blockSize = 24
152
159
  }, [
153
160
  locale,
154
161
  use12Hour,
155
- labelsProp
162
+ labelsProp,
163
+ hours
156
164
  ]);
157
165
  const labelWidth = fontSize * 3.5 + LABEL_MARGIN;
158
166
  const totalCount = typeof totalCountProp === "number" ? totalCountProp : dataWithLevels.reduce((sum, a) => sum + a.value, 0);
167
+ const hasExtraColumn = resolvedExtraColumn !== null;
168
+ const columns = hours.length + (hasExtraColumn ? 2 : 0);
169
+ const fitted = (rootWidth - 24 - labelWidth - columns * blockMargin + (hasExtraColumn ? 0 : blockMargin)) / (columns + (hasExtraColumn ? 1 / (2 * blockAspectRatio) : 0));
170
+ const blockSize = blockSizeProp ?? (rootWidth > 0 ? Math.min(MAX_FITTED_BLOCK, Math.max(MIN_FITTED_BLOCK, fitted)) / blockAspectRatio : DEFAULT_BLOCK);
159
171
  const blockWidth = blockSize * blockAspectRatio;
160
172
  const labelHeight = fontSize + LABEL_MARGIN;
161
- const hasExtraColumn = resolvedExtraColumn !== null;
162
173
  const hasExtraRow = resolvedExtraRow !== null;
163
- const width = 24 * (blockWidth + blockMargin) + (hasExtraColumn ? blockSize / 2 + (blockWidth + blockMargin) * 2 : 0) - blockMargin + labelWidth;
164
- const rowCount = hasExtraRow ? 8 : 7;
174
+ const width = hours.length * (blockWidth + blockMargin) + (hasExtraColumn ? blockSize / 2 + (blockWidth + blockMargin) * 2 : 0) - blockMargin + labelWidth;
175
+ const rowCount = weekdays.length + (hasExtraRow ? 1 : 0);
165
176
  const extraRowGap = hasExtraRow ? blockSize + blockMargin : 0;
166
177
  const height = rowCount * (blockSize + blockMargin) + extraRowGap - blockMargin + labelHeight;
167
178
  const contextValue = useMemo(() => ({
@@ -183,6 +194,8 @@ const WeekdayHeatmap = ({ data, weekStart = 0, use12Hour = false, blockSize = 24
183
194
  width,
184
195
  height,
185
196
  weekStart,
197
+ hours,
198
+ weekdays,
186
199
  colors
187
200
  }), [
188
201
  dataWithLevels,
@@ -203,14 +216,17 @@ const WeekdayHeatmap = ({ data, weekStart = 0, use12Hour = false, blockSize = 24
203
216
  width,
204
217
  height,
205
218
  weekStart,
219
+ hours,
220
+ weekdays,
206
221
  colors
207
222
  ]);
208
223
  if (data.length === 0) return emptyState ? emptyState : null;
209
224
  return /* @__PURE__ */ jsx(WeekdayHeatmapContext, {
210
225
  value: contextValue,
211
226
  children: /* @__PURE__ */ jsx("div", {
227
+ ref: rootRef,
212
228
  "data-slot": "weekday-heatmap",
213
- className: cn("flex w-max max-w-full flex-col gap-2 p-4", className),
229
+ className: cn("flex flex-col gap-2", blockSizeProp === void 0 ? "w-full" : "w-max max-w-full", className),
214
230
  style: {
215
231
  fontSize,
216
232
  ...style
@@ -220,16 +236,18 @@ const WeekdayHeatmap = ({ data, weekStart = 0, use12Hour = false, blockSize = 24
220
236
  })
221
237
  });
222
238
  };
223
- const WeekdayHeatmapBlock = ({ ref, activity, extra, highlighted = false, onCellClick, onCellHover, onClick, onKeyDown, onMouseEnter, onMouseLeave, className, style: styleProp, ...props }) => {
224
- const { blockSize, blockWidth, blockMargin, blockRadius, labelWidth, labelHeight, levels, isNormalized, weekStart, labels, colors } = useWeekdayHeatmap();
239
+ const WeekdayHeatmapBlock = ({ ref, activity, extra, highlighted = false, selected = false, onCellClick, onCellHover, onClick, onKeyDown, onMouseEnter, onMouseLeave, className, style: styleProp, ...props }) => {
240
+ const { blockSize, blockWidth, blockMargin, blockRadius, labelWidth, labelHeight, levels, isNormalized, hours, weekdays, labels, colors } = useWeekdayHeatmap();
225
241
  const level = Math.max(0, Math.min(colorStepCount(levels, isNormalized), activity.level));
226
242
  const isExtraRow = extra === "row";
227
243
  const isExtraColumn = extra === "column";
228
- const rowIndex = isExtraRow ? 7 : (activity.weekday - weekStart + 7) % 7;
244
+ const rowIndex = isExtraRow ? weekdays.length : weekdays.findIndex((day) => day === activity.weekday);
245
+ const hourIndex = isExtraColumn ? hours.length : hours.findIndex((hour) => hour === activity.hour);
246
+ if (rowIndex < 0 || hourIndex < 0) return null;
229
247
  const extraRowGap = isExtraRow ? blockSize + blockMargin : 0;
230
248
  const yPosition = labelHeight + (blockSize + blockMargin) * rowIndex + extraRowGap;
231
249
  const extraColumnGap = isExtraColumn ? blockWidth + blockMargin : 0;
232
- const xPosition = isExtraColumn ? labelWidth + 24 * (blockWidth + blockMargin) + blockSize / 2 + extraColumnGap : labelWidth + (blockWidth + blockMargin) * activity.hour;
250
+ const xPosition = isExtraColumn ? labelWidth + hours.length * (blockWidth + blockMargin) + blockSize / 2 + extraColumnGap : labelWidth + (blockWidth + blockMargin) * hourIndex;
233
251
  const weekdayToken = isExtraRow ? "extra" : labels.weekdays?.[activity.weekday] ?? String(activity.weekday);
234
252
  const hourToken = isExtraColumn ? "extra" : `${String(activity.hour).padStart(2, "0")}:00`;
235
253
  const ariaLabel = (labels.cellLabel ?? "{{weekday}} {{hour}}: {{value}}").replace("{{weekday}}", weekdayToken).replace("{{hour}}", hourToken).replace("{{value}}", String(activity.value));
@@ -237,14 +255,16 @@ const WeekdayHeatmapBlock = ({ ref, activity, extra, highlighted = false, onCell
237
255
  ref,
238
256
  "data-slot": "weekday-heatmap-block",
239
257
  role: onCellClick ? "button" : "img",
258
+ "aria-pressed": onCellClick ? selected : void 0,
240
259
  tabIndex: onCellClick ? 0 : -1,
241
260
  "aria-label": ariaLabel,
242
- 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),
261
+ className: cn("hover:stroke-foreground hover:stroke-1", highlighted && "stroke-foreground stroke-1", selected && "stroke-foreground stroke-2 hover:stroke-2", onCellClick && "cursor-pointer", className),
243
262
  "data-value": activity.value,
244
263
  "data-weekday": isExtraRow ? "extra" : activity.weekday,
245
264
  "data-hour": isExtraColumn ? "extra" : activity.hour,
246
265
  "data-level": level,
247
266
  "data-highlighted": highlighted || void 0,
267
+ "data-selected": selected || void 0,
248
268
  height: blockSize,
249
269
  rx: blockRadius,
250
270
  ry: blockRadius,
@@ -252,7 +272,7 @@ const WeekdayHeatmapBlock = ({ ref, activity, extra, highlighted = false, onCell
252
272
  x: xPosition,
253
273
  y: yPosition,
254
274
  style: {
255
- fill: getLevelFill(level, levels, isNormalized, highlighted, colors),
275
+ fill: getLevelFill(level, levels, isNormalized, colors),
256
276
  ...styleProp
257
277
  },
258
278
  onClick: (event) => {
@@ -279,7 +299,8 @@ const WeekdayHeatmapBlock = ({ ref, activity, extra, highlighted = false, onCell
279
299
  };
280
300
  WeekdayHeatmapBlock.displayName = "WeekdayHeatmapBlock";
281
301
  const WeekdayHeatmapBody = ({ hideHourLabels = false, hideWeekdayLabels = false, className, labelClassName, children, renderExtraRow, renderExtraColumn, ...props }) => {
282
- const { data, extraRow, extraColumn, blockSize, blockWidth, blockMargin, labels, labelWidth, labelHeight, fontSize, weekStart } = useWeekdayHeatmap();
302
+ const navigation = useHeatmapNavigation();
303
+ const { data, extraRow, extraColumn, blockSize, blockWidth, blockMargin, labels, labelWidth, labelHeight, fontSize, hours, weekdays } = useWeekdayHeatmap();
283
304
  const hasExtraRow = extraRow !== null;
284
305
  const hasExtraColumn = extraColumn !== null;
285
306
  const activityMap = useMemo(() => {
@@ -299,24 +320,24 @@ const WeekdayHeatmapBody = ({ hideHourLabels = false, hideWeekdayLabels = false,
299
320
  }, [extraColumn]);
300
321
  const regularActivities = useMemo(() => {
301
322
  const activities = [];
302
- for (let di = 0; di < 7; di++) {
303
- const weekday = (weekStart + di) % 7;
304
- for (let hour = 0; hour < 24; hour++) activities.push({
305
- activity: activityMap.get(`${weekday}-${hour}`) ?? {
306
- weekday,
307
- hour,
308
- value: 0,
309
- level: 0
310
- },
311
- weekdayIndex: di
312
- });
313
- }
323
+ for (const [di, weekday] of weekdays.entries()) for (const hour of hours) activities.push({
324
+ activity: activityMap.get(`${weekday}-${hour}`) ?? {
325
+ weekday,
326
+ hour,
327
+ value: 0,
328
+ level: 0
329
+ },
330
+ weekdayIndex: di
331
+ });
314
332
  return activities;
315
- }, [activityMap, weekStart]);
333
+ }, [
334
+ activityMap,
335
+ weekdays,
336
+ hours
337
+ ]);
316
338
  const extraColumnActivities = useMemo(() => {
317
339
  if (!extraColumnMap) return [];
318
- return Array.from({ length: 7 }, (_, di) => {
319
- const weekday = (weekStart + di) % 7;
340
+ return weekdays.map((weekday, di) => {
320
341
  const entry = extraColumnMap.get(weekday);
321
342
  return entry ? {
322
343
  activity: {
@@ -328,44 +349,53 @@ const WeekdayHeatmapBody = ({ hideHourLabels = false, hideWeekdayLabels = false,
328
349
  weekdayIndex: di
329
350
  } : null;
330
351
  }).filter((a) => a !== null);
331
- }, [extraColumnMap, weekStart]);
352
+ }, [extraColumnMap, weekdays]);
332
353
  const extraRowActivities = useMemo(() => {
333
354
  if (!extraRow) return [];
334
- return extraRow.values.map(({ hour, value, level }) => ({
355
+ return extraRow.values.filter(({ hour }) => hours.includes(hour)).map(({ hour, value, level }) => ({
335
356
  activity: {
336
357
  weekday: 0,
337
358
  hour,
338
359
  value,
339
360
  level
340
361
  },
341
- weekdayIndex: 7
362
+ weekdayIndex: weekdays.length
342
363
  }));
343
- }, [extraRow]);
344
- const rowCount = hasExtraRow ? 8 : 7;
364
+ }, [
365
+ extraRow,
366
+ hours,
367
+ weekdays.length
368
+ ]);
369
+ const rowCount = weekdays.length + (hasExtraRow ? 1 : 0);
345
370
  const extraRowGap = hasExtraRow ? blockSize + blockMargin : 0;
346
371
  const svgHeight = rowCount * (blockSize + blockMargin) + extraRowGap - blockMargin + labelHeight;
347
372
  const extraColumnGap = hasExtraColumn ? blockWidth + blockMargin : 0;
348
- const svgWidth = hasExtraColumn ? labelWidth + 24 * (blockWidth + blockMargin) + blockSize / 2 + (blockWidth + blockMargin) + extraColumnGap : labelWidth + 24 * (blockWidth + blockMargin) - blockMargin;
349
- const orderedWeekdayIndices = Array.from({ length: 7 }, (_, i) => (weekStart + i) % 7);
373
+ const svgWidth = hasExtraColumn ? labelWidth + hours.length * (blockWidth + blockMargin) + blockSize / 2 + (blockWidth + blockMargin) + extraColumnGap : labelWidth + hours.length * (blockWidth + blockMargin) - blockMargin;
374
+ const orderedWeekdayIndices = weekdays;
350
375
  return /* @__PURE__ */ jsx("div", {
351
376
  "data-slot": "weekday-heatmap-body",
377
+ ref: navigation.ref,
352
378
  className: cn("max-w-full overflow-x-auto overflow-y-hidden", className),
353
379
  ...props,
380
+ onKeyDown: (event) => {
381
+ props.onKeyDown?.(event);
382
+ if (!event.defaultPrevented) navigation.onKeyDown(event);
383
+ },
354
384
  children: /* @__PURE__ */ jsxs("svg", {
355
385
  role: "img",
356
386
  "aria-label": labels.heatmapLabel ?? "Activity heatmap by weekday and hour",
357
387
  className: "block overflow-visible rounded-sm focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring",
358
- height: svgHeight + 40,
359
- viewBox: `-20 -20 ${svgWidth + 40} ${svgHeight + 40}`,
360
- width: svgWidth + 40,
388
+ height: svgHeight + 24,
389
+ viewBox: `-12 -12 ${svgWidth + 24} ${svgHeight + 24}`,
390
+ width: svgWidth + 24,
361
391
  children: [
362
392
  !hideHourLabels && /* @__PURE__ */ jsxs("g", {
363
393
  className: cn("fill-current font-mono", labelClassName),
364
394
  children: [
365
- HOURS.map((hour) => {
395
+ hours.map((hour, index) => {
366
396
  const label = labels.hours?.[hour] ?? "";
367
397
  return /* @__PURE__ */ jsx("text", {
368
- x: labelWidth + (blockWidth + blockMargin) * hour,
398
+ x: labelWidth + (blockWidth + blockMargin) * index,
369
399
  y: 0,
370
400
  textAnchor: "middle",
371
401
  dominantBaseline: "hanging",
@@ -374,7 +404,7 @@ const WeekdayHeatmapBody = ({ hideHourLabels = false, hideWeekdayLabels = false,
374
404
  }, `hour-${hour}`);
375
405
  }),
376
406
  labels.endHour != null && /* @__PURE__ */ jsx("text", {
377
- x: labelWidth + (blockWidth + blockMargin) * 24,
407
+ x: labelWidth + (blockWidth + blockMargin) * hours.length,
378
408
  y: 0,
379
409
  textAnchor: "middle",
380
410
  dominantBaseline: "hanging",
@@ -382,7 +412,7 @@ const WeekdayHeatmapBody = ({ hideHourLabels = false, hideWeekdayLabels = false,
382
412
  children: labels.endHour
383
413
  }, "hour-end"),
384
414
  hasExtraColumn && /* @__PURE__ */ jsx("text", {
385
- x: labelWidth + 24 * (blockWidth + blockMargin) + blockSize / 2 + (blockWidth + blockMargin) + blockWidth / 2,
415
+ x: labelWidth + hours.length * (blockWidth + blockMargin) + blockSize / 2 + (blockWidth + blockMargin) + blockWidth / 2,
386
416
  y: 0,
387
417
  textAnchor: "middle",
388
418
  dominantBaseline: "hanging",
@@ -406,7 +436,7 @@ const WeekdayHeatmapBody = ({ hideHourLabels = false, hideWeekdayLabels = false,
406
436
  }, `weekday-${weekday}`);
407
437
  }), hasExtraRow && /* @__PURE__ */ jsx("text", {
408
438
  x: labelWidth - 8,
409
- y: labelHeight + (blockSize + blockMargin) * 7 + (blockSize + blockMargin) + blockSize / 2,
439
+ y: labelHeight + (blockSize + blockMargin) * weekdays.length + (blockSize + blockMargin) + blockSize / 2,
410
440
  dominantBaseline: "middle",
411
441
  textAnchor: "end",
412
442
  style: { fontSize: `${fontSize * .75}px` },
@@ -450,7 +480,7 @@ const WeekdayHeatmapStat = ({ compute, label, className, children, ...props }) =
450
480
  });
451
481
  };
452
482
  const WeekdayHeatmapLegend = ({ labels: labelsProp, className, children, ...props }) => {
453
- const { levels, isNormalized, blockSize, blockWidth, blockRadius, colors, labels } = useWeekdayHeatmap();
483
+ const { levels, isNormalized, blockRadius, colors, labels } = useWeekdayHeatmap();
454
484
  const lessLabel = labelsProp?.less ?? "Less";
455
485
  const moreLabel = labelsProp?.more ?? "More";
456
486
  const legendLevels = Array.from({ length: levels }, (_, i) => isNormalized ? i + 1 : i);
@@ -467,15 +497,15 @@ const WeekdayHeatmapLegend = ({ labels: labelsProp, className, children, ...prop
467
497
  legendLevels.map((level) => children ? /* @__PURE__ */ jsx(Fragment$1, { children: children({ level }) }, `legend-level-${level}`) : /* @__PURE__ */ jsx("svg", {
468
498
  role: "img",
469
499
  "aria-label": (labels.legendLevelLabel ?? "{{level}} contributions").replace("{{level}}", String(level)),
470
- height: blockSize,
471
- width: blockWidth,
500
+ height: LEGEND_SWATCH,
501
+ width: LEGEND_SWATCH,
472
502
  children: /* @__PURE__ */ jsx("rect", {
473
503
  "data-level": level,
474
- height: blockSize,
504
+ height: LEGEND_SWATCH,
475
505
  rx: blockRadius,
476
506
  ry: blockRadius,
477
- width: blockWidth,
478
- style: { fill: getLevelFill(level, levels, isNormalized, false, colors) }
507
+ width: LEGEND_SWATCH,
508
+ style: { fill: getLevelFill(level, levels, isNormalized, colors) }
479
509
  })
480
510
  }, `legend-level-${level}`)),
481
511
  /* @__PURE__ */ jsx("span", {
@@ -91,6 +91,13 @@ type DataTableContextProps<TData extends RowData> = DataTableContextState & {
91
91
  * `null` until the container mounts (or when no `<DataTable>` is used).
92
92
  */
93
93
  scrollContainer: HTMLElement | null;
94
+ /** True below 40rem of table space; use for compact toolbar and record layouts. */
95
+ isCompact: boolean;
96
+ /**
97
+ * Set while some columns do not fit and the table has `meta.compact`
98
+ * columns: they hide, rightmost first, until the reader asks for all.
99
+ */
100
+ compactColumns: CompactColumns | null;
94
101
  /** Internal: `<DataTable>` registers its scroll container element here. */
95
102
  registerScrollContainer: (el: HTMLElement | null) => void;
96
103
  /**
@@ -146,12 +153,22 @@ export declare enum DataTableActions {
146
153
  SET = 0,
147
154
  SET_IS_LOADING = 1
148
155
  }
156
+ export interface CompactColumns {
157
+ /** True while columns are hidden to fit; false once the reader shows them all. */
158
+ collapsed: boolean;
159
+ /** The columns hidden to fit right now, for a cell to fold one under a kept figure. */
160
+ hidden: ReadonlySet<string>;
161
+ setCollapsed: (collapsed: boolean) => void;
162
+ }
149
163
  interface DataTableProviderProps<TData extends RowData> {
150
164
  children: React.ReactNode;
151
165
  table: DataTableInstance<TData>;
152
166
  columns?: DataTableColumnDef<TData>[];
153
167
  isLoading?: boolean;
168
+ isCompact: boolean;
169
+ onWidthChange: (width: number) => void;
170
+ compactColumns: CompactColumns | null;
154
171
  }
155
- export declare function DataTableProvider<TData extends RowData>({ children, table, columns, isLoading: externalIsLoading }: DataTableProviderProps<TData>): React.JSX.Element;
172
+ export declare function DataTableProvider<TData extends RowData>({ children, table, columns, isLoading: externalIsLoading, isCompact, onWidthChange, compactColumns }: DataTableProviderProps<TData>): React.JSX.Element;
156
173
  //#endregion
157
174
  export { DataTableContext };
@@ -1,4 +1,5 @@
1
1
  "use client";
2
+ import { useTableWidth } from "../../../../lib/compact-columns.js";
2
3
  import { useGeneratedOptions } from "../hooks/use-generated-options.js";
3
4
  import { useHeaderMinWidths } from "../lib/use-header-min-widths.js";
4
5
  import { jsx, jsxs } from "react/jsx-runtime";
@@ -113,7 +114,7 @@ function useFlashSet() {
113
114
  }
114
115
  }, [])];
115
116
  }
116
- function DataTableProvider({ children, table, columns, isLoading: externalIsLoading }) {
117
+ function DataTableProvider({ children, table, columns, isLoading: externalIsLoading, isCompact, onWidthChange, compactColumns }) {
117
118
  const [state, dispatch] = useReducer(dataTableReducer, deriveInitialState(externalIsLoading));
118
119
  const setIsLoading = useCallback((value) => {
119
120
  dispatch({
@@ -127,6 +128,7 @@ function DataTableProvider({ children, table, columns, isLoading: externalIsLoad
127
128
  }, []);
128
129
  const [scrollContainer, setScrollContainer] = React.useState(null);
129
130
  const registerScrollContainer = useCallback((el) => setScrollContainer(el), []);
131
+ useTableWidth(scrollContainer, onWidthChange);
130
132
  const scrollRowIntoView = useCallback((index, opts) => {
131
133
  if (rowScrollerRef.current) {
132
134
  rowScrollerRef.current(index, opts);
@@ -269,6 +271,8 @@ function DataTableProvider({ children, table, columns, isLoading: externalIsLoad
269
271
  scrollRowIntoView,
270
272
  registerRowScroller,
271
273
  scrollContainer,
274
+ isCompact,
275
+ compactColumns,
272
276
  registerScrollContainer,
273
277
  headerMinWidths,
274
278
  setColumnResizePreview: setManualResizePreview,
@@ -286,6 +290,8 @@ function DataTableProvider({ children, table, columns, isLoading: externalIsLoad
286
290
  scrollRowIntoView,
287
291
  registerRowScroller,
288
292
  scrollContainer,
293
+ isCompact,
294
+ compactColumns,
289
295
  registerScrollContainer,
290
296
  headerMinWidths,
291
297
  setManualResizePreview,
@@ -1,5 +1,6 @@
1
1
  import { Button } from "../../../ui/button.js";
2
2
  import { cn } from "../../../../lib/utils.js";
3
+ import { useDataTable } from "./data-table-context.js";
3
4
  import { DataTableGroupRowProvider, useDataTableGroupRow } from "../components/data-table-grouped-rows.js";
4
5
  import { TableCell, TableRow } from "../ui/table.js";
5
6
  import { isInteractiveClickTarget } from "../lib/row-click.js";
@@ -18,12 +19,13 @@ import { flexRender } from "@tanstack/react-table";
18
19
  * groups you don't want to special-case.
19
20
  */
20
21
  function DataTableGroupedRowCells() {
22
+ const { isCompact } = useDataTable();
21
23
  const { row, groupLabel, count, isExpanded, toggle, columnWidths } = useDataTableGroupRow();
22
24
  const countLabel = `${count} ${count === 1 ? "row" : "rows"}`;
23
25
  return /* @__PURE__ */ jsx(Fragment, { children: row.getVisibleCells().map((cell) => {
24
26
  const cellStyle = {
25
27
  width: columnWidths.get(cell.column.id),
26
- ...getCommonPinningStyles(cell.column, false)
28
+ ...getCommonPinningStyles(cell.column, false, !isCompact)
27
29
  };
28
30
  let content = null;
29
31
  if (cell.getIsGrouped()) content = /* @__PURE__ */ jsxs("div", {
@@ -1,5 +1,6 @@
1
1
  import { TooltipProvider } from "../../../ui/tooltip.js";
2
2
  import { cn } from "../../../../lib/utils.js";
3
+ import { fitColumns, isCompactWidth } from "../../../../lib/compact-columns.js";
3
4
  import { FILTER_VARIANTS, SYSTEM_COLUMN_IDS, SYSTEM_COLUMN_ID_LIST } from "../lib/constants.js";
4
5
  import { DataTableProvider } from "./data-table-context.js";
5
6
  import { detectFeaturesFromChildren } from "../config/feature-detection.js";
@@ -216,7 +217,23 @@ function DataTableRootInternal({ columns, data, children, className, config, get
216
217
  ...detectFeatures.enableColumnResizing ? { minSize: 40 } : {}
217
218
  }), [detectFeatures.enableColumnResizing, detectFeatures.enableSorting]);
218
219
  const controlledSorting = restState?.sorting ?? sorting;
219
- const controlledColumnVisibility = restState?.columnVisibility ?? columnVisibility;
220
+ const [tableWidth, setTableWidth] = React.useState(0);
221
+ const isCompact = isCompactWidth(tableWidth);
222
+ const [showAllColumns, setShowAllColumns] = React.useState(false);
223
+ const requestedColumnVisibility = restState?.columnVisibility ?? columnVisibility;
224
+ const requestedColumnOrder = restState?.columnOrder ?? columnOrder;
225
+ const fitted = React.useMemo(() => fitColumns(columns, requestedColumnOrder, requestedColumnVisibility, tableWidth), [
226
+ columns,
227
+ requestedColumnOrder,
228
+ requestedColumnVisibility,
229
+ tableWidth
230
+ ]);
231
+ const controlledColumnVisibility = fitted && !showAllColumns ? fitted.visibility : requestedColumnVisibility;
232
+ const compactColumns = React.useMemo(() => fitted && fitted.hidden.size > 0 ? {
233
+ collapsed: !showAllColumns,
234
+ hidden: showAllColumns ? NOTHING_HIDDEN : fitted.hidden,
235
+ setCollapsed: (value) => setShowAllColumns(!value)
236
+ } : null, [fitted, showAllColumns]);
220
237
  const controlledRowSelection = restState?.rowSelection ?? rowSelection;
221
238
  const controlledColumnFilters = restState?.columnFilters ?? columnFilters;
222
239
  const controlledGlobalFilter = restState?.globalFilter !== void 0 ? restState.globalFilter : globalFilter$1;
@@ -369,6 +386,9 @@ function DataTableRootInternal({ columns, data, children, className, config, get
369
386
  table,
370
387
  columns: processedColumns,
371
388
  isLoading,
389
+ isCompact,
390
+ onWidthChange: setTableWidth,
391
+ compactColumns,
372
392
  children: /* @__PURE__ */ jsx(TooltipProvider, {
373
393
  ...tooltipProviderDelay,
374
394
  children: /* @__PURE__ */ jsx("div", {
@@ -378,11 +398,16 @@ function DataTableRootInternal({ columns, data, children, className, config, get
378
398
  })
379
399
  });
380
400
  }
381
- function DataTableRoot({ table: externalTable, columns, data, children, className, isLoading, ...rest }) {
382
- if (externalTable) return /* @__PURE__ */ jsx(DataTableProvider, {
383
- table: externalTable,
401
+ function ExternalTableRoot({ table, columns, children, className, isLoading }) {
402
+ const [tableWidth, setTableWidth] = React.useState(0);
403
+ const isCompact = isCompactWidth(tableWidth);
404
+ return /* @__PURE__ */ jsx(DataTableProvider, {
405
+ table,
384
406
  columns,
385
407
  isLoading,
408
+ isCompact,
409
+ onWidthChange: setTableWidth,
410
+ compactColumns: null,
386
411
  children: /* @__PURE__ */ jsx(TooltipProvider, {
387
412
  ...tooltipProviderDelay,
388
413
  children: /* @__PURE__ */ jsx("div", {
@@ -391,6 +416,16 @@ function DataTableRoot({ table: externalTable, columns, data, children, classNam
391
416
  })
392
417
  })
393
418
  });
419
+ }
420
+ const NOTHING_HIDDEN = /* @__PURE__ */ new Set();
421
+ function DataTableRoot({ table: externalTable, columns, data, children, className, isLoading, ...rest }) {
422
+ if (externalTable) return /* @__PURE__ */ jsx(ExternalTableRoot, {
423
+ table: externalTable,
424
+ columns,
425
+ className,
426
+ isLoading,
427
+ children
428
+ });
394
429
  if (!columns || !data) throw new Error("DataTableRoot: Either provide a 'table' prop or both 'columns' and 'data' props");
395
430
  return /* @__PURE__ */ jsx(DataTableRootInternal, {
396
431
  columns,
@@ -20,11 +20,11 @@ import React from "react";
20
20
  import { flexRender } from "@tanstack/react-table";
21
21
  //#region src/components/registry/niko-table/core/data-table-structure.tsx
22
22
  const DataTableHeader = React.memo(function DataTableHeader({ className, sticky = true }) {
23
- const { table, headerMinWidths, setColumnResizePreview } = useDataTable();
23
+ const { table, headerMinWidths, setColumnResizePreview, isCompact } = useDataTable();
24
24
  const resizing = table?.options.enableColumnResizing ?? false;
25
25
  const headerGroups = table?.getHeaderGroups() ?? [];
26
26
  if (headerGroups.length === 0) return null;
27
- const flexColumnIds = resolveFlexColumnIds(table);
27
+ const flexColumnIds = resolveFlexColumnIds(table, !isCompact);
28
28
  const columnSizing = table.state.columnSizing;
29
29
  return /* @__PURE__ */ jsx(TableHeader, {
30
30
  className: cn(sticky && "sticky top-0 z-30 bg-card", sticky && "after:absolute after:right-0 after:bottom-0 after:left-0 after:h-px after:bg-border", className),
@@ -37,12 +37,13 @@ const DataTableHeader = React.memo(function DataTableHeader({ className, sticky
37
37
  columnSizing,
38
38
  headerMinWidths
39
39
  }),
40
- ...getCommonPinningStyles(header.column, true)
40
+ ...getCommonPinningStyles(header.column, true, !isCompact)
41
41
  };
42
42
  return /* @__PURE__ */ jsxs(TableHead, {
43
43
  "data-col-id": header.column.id,
44
+ "data-numeric": header.column.columnDef.meta?.variant === "number" || void 0,
44
45
  style: headerStyle,
45
- className: cn(header.column.getIsPinned() && "bg-background", resizing && "relative overflow-hidden"),
46
+ className: cn(!isCompact && header.column.getIsPinned() && "bg-background", resizing && "relative overflow-hidden"),
46
47
  children: [header.isPlaceholder ? null : /* @__PURE__ */ jsx(DataTableColumnHeaderRoot, {
47
48
  column: header.column,
48
49
  children: resizing && typeof header.column.columnDef.header === "string" ? /* @__PURE__ */ jsx("span", {
@@ -61,7 +62,7 @@ const DataTableHeader = React.memo(function DataTableHeader({ className, sticky
61
62
  DataTableHeader.displayName = "DataTableHeader";
62
63
  /** Fade-pulse animation applied to a flashing cell (keyframe in the provider). */
63
64
  const FLASH_ANIMATION = "niko-row-flash 1.2s ease-out";
64
- const BodyRow = React.memo(function BodyRow({ row, displayIndex, expandColumnId, isClickable, isExpanded, isSelected, columnWidths, isRowFlashing, flashingCellKeys, renderRowContextMenu }) {
65
+ const BodyRow = React.memo(function BodyRow({ row, displayIndex, expandColumnId, isCompact, isClickable, isExpanded, isSelected, columnWidths, isRowFlashing, flashingCellKeys, renderRowContextMenu }) {
65
66
  const expandCell = isExpanded && expandColumnId ? row.getAllCells().find((c) => c.column.id === expandColumnId) : void 0;
66
67
  const visibleCells = row.getVisibleCells();
67
68
  const rowElement = /* @__PURE__ */ jsx(TableRow, {
@@ -76,14 +77,15 @@ const BodyRow = React.memo(function BodyRow({ row, displayIndex, expandColumnId,
76
77
  const flashing = isRowFlashing || flashingCellKeys.has(flashCellKey(row.id, cell.column.id));
77
78
  const cellStyle = {
78
79
  width: columnWidths.get(cell.column.id),
79
- ...getCommonPinningStyles(cell.column, false),
80
+ ...getCommonPinningStyles(cell.column, false, !isCompact),
80
81
  ...flashing ? { animation: FLASH_ANIMATION } : {}
81
82
  };
82
83
  return /* @__PURE__ */ jsx(TableCell, {
83
84
  "data-flash": flashing ? "true" : void 0,
84
85
  "data-col-id": cell.column.id,
86
+ "data-numeric": cell.column.columnDef.meta?.variant === "number" || void 0,
85
87
  style: cellStyle,
86
- className: cn(!cell.getIsGrouped() && "truncate", cell.column.getIsPinned() && "bg-linear-to-r group-hover:from-muted/50 group-hover:to-muted/50 group-data-[context-menu-open]:from-muted/50 group-data-[context-menu-open]:to-muted/50 group-data-[state=selected]:from-muted group-data-[state=selected]:to-muted"),
88
+ className: cn(!cell.getIsGrouped() && "truncate", !isCompact && cell.column.getIsPinned() && "bg-linear-to-r group-hover:from-muted/50 group-hover:to-muted/50 group-data-[context-menu-open]:from-muted/50 group-data-[context-menu-open]:to-muted/50 group-data-[state=selected]:from-muted group-data-[state=selected]:to-muted"),
87
89
  children: renderCellContent(cell)
88
90
  }, cell.id);
89
91
  })
@@ -101,7 +103,7 @@ const BodyRow = React.memo(function BodyRow({ row, displayIndex, expandColumnId,
101
103
  });
102
104
  BodyRow.displayName = "BodyRow";
103
105
  function DataTableBody({ children, className, onScroll, onScrolledTop, onScrolledBottom, scrollThreshold = 50, onRowClick, getRowMemoKey, renderRowContextMenu }) {
104
- const { table, columns, isLoading, flashingRowIds, flashingCellKeys, registerRowScroller, headerMinWidths } = useDataTable();
106
+ const { table, columns, isLoading, flashingRowIds, flashingCellKeys, registerRowScroller, headerMinWidths, isCompact } = useDataTable();
105
107
  const { rows } = table.getRowModel();
106
108
  const containerRef = React.useRef(null);
107
109
  React.useEffect(() => {
@@ -139,13 +141,14 @@ function DataTableBody({ children, className, onScroll, onScrolledTop, onScrolle
139
141
  const expandColumnId = React.useMemo(() => table.getAllColumns().find((col) => col.columnDef.meta?.expandedContent)?.id, [table, columns]);
140
142
  const { columnVisibility, columnOrder, columnPinning, columnSizing } = table.state;
141
143
  const resizing = table.options.enableColumnResizing ?? false;
142
- const flexColumnIds = React.useMemo(() => resolveFlexColumnIds(table), [
144
+ const flexColumnIds = React.useMemo(() => resolveFlexColumnIds(table, !isCompact), [
143
145
  table,
144
146
  columnVisibility,
145
147
  columnOrder,
146
148
  columnPinning,
147
149
  columnSizing,
148
- resizing
150
+ resizing,
151
+ isCompact
149
152
  ]);
150
153
  const columnWidths = React.useMemo(() => {
151
154
  const widths = /* @__PURE__ */ new Map();
@@ -166,14 +169,15 @@ function DataTableBody({ children, className, onScroll, onScrolledTop, onScrolle
166
169
  resizing
167
170
  ]);
168
171
  const columnLayoutSignature = React.useMemo(() => table.getVisibleLeafColumns().map((c) => {
169
- const pinned = c.getIsPinned();
172
+ const pinned = !isCompact && c.getIsPinned();
170
173
  const base = pinned ? `${c.id}:${pinned}` : c.id;
171
174
  return resizing ? `${base}:${columnWidths.get(c.id) ?? "flex"}` : base;
172
175
  }).join(","), [
173
176
  table,
174
177
  columns,
175
178
  columnWidths,
176
- resizing
179
+ resizing,
180
+ isCompact
177
181
  ]);
178
182
  const isClickable = !!onRowClick;
179
183
  const resolvedRenderRowContextMenu = useResolvedRowContextMenuRenderer(renderRowContextMenu, children);
@@ -232,6 +236,7 @@ function DataTableBody({ children, className, onScroll, onScrolledTop, onScrolle
232
236
  row,
233
237
  displayIndex,
234
238
  expandColumnId,
239
+ isCompact,
235
240
  isClickable,
236
241
  isExpanded: row.getIsExpanded(),
237
242
  isSelected: row.getIsSelected(),
@@ -1,6 +1,6 @@
1
1
  import React from "react";
2
2
  //#region src/components/registry/niko-table/core/data-table.d.ts
3
- export interface DataTableContainerProps {
3
+ export interface DataTableContainerProps extends React.AriaAttributes {
4
4
  children: React.ReactNode;
5
5
  /**
6
6
  * Additional CSS classes for the container.
@@ -23,7 +23,7 @@ export interface DataTableContainerProps {
23
23
  */
24
24
  maxHeight?: number | string;
25
25
  }
26
- export declare function DataTable({ children, className, height, maxHeight }: DataTableContainerProps): React.JSX.Element;
26
+ export declare function DataTable({ children, className, height, maxHeight, "aria-label": label, "aria-labelledby": labelledBy }: DataTableContainerProps): React.JSX.Element;
27
27
  export declare namespace DataTable {
28
28
  var displayName: string;
29
29
  }
@@ -105,7 +105,7 @@ function ColumnResizePreviewLine() {
105
105
  }
106
106
  });
107
107
  }
108
- function DataTable({ children, className, height, maxHeight }) {
108
+ function DataTable({ children, className, height, maxHeight, "aria-label": label = "Data table", "aria-labelledby": labelledBy }) {
109
109
  const parsed = React.useMemo(() => parseHeightFromClassName(className), [className]);
110
110
  const finalHeight = height ?? parsed.height;
111
111
  const finalMaxHeight = maxHeight ?? parsed.maxHeight ?? finalHeight;
@@ -113,6 +113,10 @@ function DataTable({ children, className, height, maxHeight }) {
113
113
  return /* @__PURE__ */ jsxs("div", {
114
114
  ref: registerScrollContainer,
115
115
  "data-slot": "table-container",
116
+ role: "region",
117
+ "aria-label": labelledBy ? void 0 : label,
118
+ "aria-labelledby": labelledBy,
119
+ tabIndex: 0,
116
120
  className: cn("relative isolate w-full overflow-auto rounded-lg border", "[&::-webkit-scrollbar]:h-2.5 [&::-webkit-scrollbar]:w-2.5", "[&::-webkit-scrollbar-track]:bg-transparent", "[&::-webkit-scrollbar-thumb]:rounded-full [&::-webkit-scrollbar-thumb]:bg-border/40", "hover:[&::-webkit-scrollbar-thumb]:bg-border", "[&::-webkit-scrollbar-thumb:hover]:bg-border/80!", "scrollbar-thin scrollbar-thumb-border/40 scrollbar-track-transparent", "hover:scrollbar-thumb-border", parsed.safeClassName),
117
121
  style: {
118
122
  height: finalHeight,