@siyahi/ui 0.1.9-next.2 → 0.1.9-next.21

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 (196) hide show
  1. package/DESIGN.md +30 -0
  2. package/README.md +82 -176
  3. package/THIRD_PARTY_NOTICES.md +11 -11
  4. package/agents/examples/accordion.tsx +39 -0
  5. package/agents/examples/alert.tsx +23 -0
  6. package/agents/examples/app-sidebar.tsx +38 -0
  7. package/agents/examples/avatar.tsx +14 -0
  8. package/agents/examples/badge.tsx +18 -0
  9. package/agents/examples/bar-list-labels.tsx +22 -0
  10. package/agents/examples/bar-list-sides.tsx +38 -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 +15 -0
  16. package/agents/examples/callout.tsx +33 -0
  17. package/agents/examples/card.tsx +34 -0
  18. package/agents/examples/change-bar.tsx +104 -0
  19. package/agents/examples/chart-area.tsx +39 -0
  20. package/agents/examples/chart-bar-flows.tsx +32 -0
  21. package/agents/examples/chart-bar-hourly.tsx +28 -0
  22. package/agents/examples/chart-bar-losses.tsx +29 -0
  23. package/agents/examples/chart-bar-sectors.tsx +72 -0
  24. package/agents/examples/chart-bar-years.tsx +40 -0
  25. package/agents/examples/chart-bar.tsx +56 -0
  26. package/agents/examples/chart-category-ticks.tsx +50 -0
  27. package/agents/examples/chart-line-events.tsx +47 -0
  28. package/agents/examples/chart-line-timeline.tsx +41 -0
  29. package/agents/examples/chart-line.tsx +57 -0
  30. package/agents/examples/code-block.tsx +38 -0
  31. package/agents/examples/collapsible.tsx +16 -0
  32. package/agents/examples/command.tsx +27 -0
  33. package/agents/examples/context-menu.tsx +15 -0
  34. package/agents/examples/copy-button.tsx +8 -0
  35. package/agents/examples/data-bar.tsx +121 -0
  36. package/agents/examples/data-table-compact.tsx +95 -0
  37. package/agents/examples/data-table-filters.tsx +103 -0
  38. package/agents/examples/data-table.tsx +98 -0
  39. package/agents/examples/delta.tsx +13 -0
  40. package/agents/examples/dialog.tsx +28 -0
  41. package/agents/examples/distribution-bar-budget.tsx +30 -0
  42. package/agents/examples/distribution-bar-tug.tsx +72 -0
  43. package/agents/examples/dropdown-menu.tsx +31 -0
  44. package/agents/examples/formatters.tsx +42 -0
  45. package/agents/examples/heatmap-calendar.tsx +60 -0
  46. package/agents/examples/heatmap-status.tsx +57 -0
  47. package/agents/examples/heatmap-weekday.tsx +75 -0
  48. package/agents/examples/input-states.tsx +33 -0
  49. package/agents/examples/input.tsx +17 -0
  50. package/agents/examples/local-time.tsx +14 -0
  51. package/agents/examples/metric-strip.tsx +46 -0
  52. package/agents/examples/overview-dashboard.tsx +18 -0
  53. package/agents/examples/page-hero.tsx +38 -0
  54. package/agents/examples/page-section.tsx +52 -0
  55. package/agents/examples/popover.tsx +23 -0
  56. package/agents/examples/price-chart.tsx +32 -0
  57. package/agents/examples/progress-tone.tsx +28 -0
  58. package/agents/examples/progress.tsx +10 -0
  59. package/agents/examples/range-position-table.tsx +101 -0
  60. package/agents/examples/range-position.tsx +53 -0
  61. package/agents/examples/scroll-area.tsx +20 -0
  62. package/agents/examples/section-cards-select.tsx +30 -0
  63. package/agents/examples/section-cards-trend.tsx +30 -0
  64. package/agents/examples/section-cards.tsx +48 -0
  65. package/agents/examples/select.tsx +27 -0
  66. package/agents/examples/separator.tsx +13 -0
  67. package/agents/examples/sheet.tsx +15 -0
  68. package/agents/examples/skeleton.tsx +11 -0
  69. package/agents/examples/slider.tsx +5 -0
  70. package/agents/examples/surfaces.tsx +116 -0
  71. package/agents/examples/table.tsx +50 -0
  72. package/agents/examples/tabs.tsx +16 -0
  73. package/agents/examples/target-rows.tsx +70 -0
  74. package/agents/examples/toggle-group.tsx +12 -0
  75. package/agents/examples/toggle.tsx +11 -0
  76. package/agents/examples/tooltip.tsx +13 -0
  77. package/agents/examples/treemap.tsx +88 -0
  78. package/agents/manifest.json +1081 -0
  79. package/agents/report-rules.json +7 -0
  80. package/dist/components/registry/charts/area-chart-card.js +25 -7
  81. package/dist/components/registry/charts/bar-chart-card.d.ts +0 -1
  82. package/dist/components/registry/charts/bar-chart-card.js +40 -26
  83. package/dist/components/registry/charts/line-chart-card.js +2 -2
  84. package/dist/components/registry/dashboard-01/section-cards.d.ts +2 -0
  85. package/dist/components/registry/dashboard-01/section-cards.js +42 -35
  86. package/dist/components/registry/dashboardcn/bar-list.js +18 -11
  87. package/dist/components/registry/dashboardcn/distribution-bar.js +1 -1
  88. package/dist/components/registry/dashboardcn/kpi-row-card.d.ts +29 -0
  89. package/dist/components/registry/dashboardcn/kpi-row-card.js +81 -0
  90. package/dist/components/registry/dashboardcn/sparkline.d.ts +22 -0
  91. package/dist/components/registry/dashboardcn/sparkline.js +117 -0
  92. package/dist/components/registry/heatmap/calendar-heatmap.d.ts +4 -2
  93. package/dist/components/registry/heatmap/calendar-heatmap.js +74 -33
  94. package/dist/components/registry/heatmap/status-heatmap.d.ts +5 -3
  95. package/dist/components/registry/heatmap/status-heatmap.js +37 -15
  96. package/dist/components/registry/heatmap/weekday-heatmap.d.ts +9 -3
  97. package/dist/components/registry/heatmap/weekday-heatmap.js +82 -47
  98. package/dist/components/registry/niko-table/core/data-table-context.d.ts +18 -1
  99. package/dist/components/registry/niko-table/core/data-table-context.js +7 -1
  100. package/dist/components/registry/niko-table/core/data-table-grouped-row.js +3 -1
  101. package/dist/components/registry/niko-table/core/data-table-root.js +39 -4
  102. package/dist/components/registry/niko-table/core/data-table-structure.js +17 -12
  103. package/dist/components/registry/niko-table/core/data-table.d.ts +2 -2
  104. package/dist/components/registry/niko-table/core/data-table.js +5 -1
  105. package/dist/components/registry/niko-table/filters/table-faceted-filter.js +4 -4
  106. package/dist/components/registry/niko-table/filters/table-search-filter.js +1 -1
  107. package/dist/components/registry/niko-table/lib/flex-columns.d.ts +1 -1
  108. package/dist/components/registry/niko-table/lib/flex-columns.js +3 -3
  109. package/dist/components/registry/niko-table/lib/styles.d.ts +1 -1
  110. package/dist/components/registry/niko-table/lib/styles.js +3 -3
  111. package/dist/components/registry/niko-table/types/index.d.ts +9 -0
  112. package/dist/components/registry/niko-table/ui/table.js +2 -2
  113. package/dist/components/registry/sidebar-07/app-sidebar.d.ts +1 -1
  114. package/dist/components/registry/sidebar-07/app-sidebar.js +3 -1
  115. package/dist/components/registry/sidebar-07/nav-main.d.ts +2 -1
  116. package/dist/components/registry/sidebar-07/nav-main.js +16 -3
  117. package/dist/components/siyahi/callout.d.ts +24 -0
  118. package/dist/components/siyahi/callout.js +40 -0
  119. package/dist/components/siyahi/change-bar.d.ts +21 -0
  120. package/dist/components/siyahi/change-bar.js +35 -0
  121. package/dist/components/siyahi/data-bar.d.ts +19 -0
  122. package/dist/components/siyahi/data-bar.js +29 -0
  123. package/dist/components/siyahi/data-table-compact-columns-toggle.d.ts +4 -0
  124. package/dist/components/siyahi/data-table-compact-columns-toggle.js +19 -0
  125. package/dist/components/siyahi/data-table-footnote.d.ts +12 -0
  126. package/dist/components/siyahi/data-table-footnote.js +35 -0
  127. package/dist/components/siyahi/default-sidebar-open.d.ts +8 -0
  128. package/dist/components/siyahi/default-sidebar-open.js +13 -0
  129. package/dist/components/siyahi/page-hero.d.ts +25 -0
  130. package/dist/components/siyahi/page-hero.js +41 -0
  131. package/dist/components/siyahi/page-section.d.ts +4 -1
  132. package/dist/components/siyahi/page-section.js +6 -3
  133. package/dist/components/siyahi/page-toc.d.ts +20 -0
  134. package/dist/components/siyahi/page-toc.js +76 -0
  135. package/dist/components/siyahi/panel-grid.d.ts +22 -0
  136. package/dist/components/siyahi/panel-grid.js +34 -0
  137. package/dist/components/siyahi/quote.d.ts +12 -0
  138. package/dist/components/siyahi/quote.js +23 -0
  139. package/dist/components/siyahi/range-position.d.ts +24 -0
  140. package/dist/components/siyahi/range-position.js +105 -0
  141. package/dist/components/siyahi/siyahi-provider.d.ts +13 -2
  142. package/dist/components/siyahi/siyahi-provider.js +17 -4
  143. package/dist/components/siyahi/target-rows.d.ts +34 -0
  144. package/dist/components/siyahi/target-rows.js +97 -0
  145. package/dist/components/siyahi/treemap.d.ts +4 -1
  146. package/dist/components/siyahi/treemap.js +78 -28
  147. package/dist/components/siyahi/warning-alert.d.ts +10 -0
  148. package/dist/components/siyahi/warning-alert.js +20 -0
  149. package/dist/components/ui/accordion.js +5 -5
  150. package/dist/components/ui/alert.js +2 -2
  151. package/dist/components/ui/badge.js +1 -1
  152. package/dist/components/ui/breadcrumb.js +2 -2
  153. package/dist/components/ui/button.js +10 -10
  154. package/dist/components/ui/calendar.js +1 -1
  155. package/dist/components/ui/card.js +4 -4
  156. package/dist/components/ui/chart.js +1 -1
  157. package/dist/components/ui/code-block.js +13 -12
  158. package/dist/components/ui/command.js +7 -6
  159. package/dist/components/ui/context-menu.js +7 -7
  160. package/dist/components/ui/dialog.js +5 -5
  161. package/dist/components/ui/dropdown-menu.js +8 -8
  162. package/dist/components/ui/input-group.js +11 -11
  163. package/dist/components/ui/input.js +1 -1
  164. package/dist/components/ui/popover.js +3 -3
  165. package/dist/components/ui/progress.js +1 -1
  166. package/dist/components/ui/select.js +6 -6
  167. package/dist/components/ui/sheet.js +5 -5
  168. package/dist/components/ui/sidebar.js +17 -18
  169. package/dist/components/ui/skeleton.js +1 -1
  170. package/dist/components/ui/slider.js +2 -2
  171. package/dist/components/ui/table.js +2 -2
  172. package/dist/components/ui/tabs.js +2 -2
  173. package/dist/components/ui/textarea.js +1 -1
  174. package/dist/components/ui/toggle-group.js +2 -2
  175. package/dist/components/ui/toggle.js +4 -4
  176. package/dist/components/ui/tooltip.js +2 -2
  177. package/dist/index.d.ts +21 -7
  178. package/dist/index.js +18 -4
  179. package/dist/lib/chart-frame.d.ts +25 -7
  180. package/dist/lib/chart-frame.js +251 -127
  181. package/dist/lib/chart-series.d.ts +12 -6
  182. package/dist/lib/compact-columns.d.ts +19 -0
  183. package/dist/lib/compact-columns.js +55 -0
  184. package/dist/lib/format.d.ts +7 -2
  185. package/dist/lib/format.js +54 -16
  186. package/dist/lib/heatmap-navigation.d.ts +8 -0
  187. package/dist/lib/heatmap-navigation.js +49 -0
  188. package/dist/lib/treemap.js +6 -1
  189. package/dist/lib/use-element-width.d.ts +5 -0
  190. package/dist/lib/use-element-width.js +15 -0
  191. package/package.json +4 -1
  192. package/registry.lock.json +16 -0
  193. package/report.css +33 -32
  194. package/styles/siyahi.css +221 -39
  195. package/dist/lib/recharts.d.ts +0 -2
  196. package/dist/lib/recharts.js +0 -1
@@ -1,4 +1,6 @@
1
1
  import { cn } from "../../../lib/utils.js";
2
+ import { useHeatmapNavigation } from "../../../lib/heatmap-navigation.js";
3
+ import { useElementWidth } from "../../../lib/use-element-width.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";
@@ -47,6 +49,10 @@ const generateWeekdayLabels = (locale) => Array.from({ length: 7 }, (_, i) => {
47
49
  });
48
50
  const EMPTY_STYLE = {};
49
51
  const LABEL_MARGIN = 8;
52
+ const LEGEND_SWATCH = 12;
53
+ const MIN_FITTED_BLOCK = 14;
54
+ const MAX_FITTED_BLOCK = 44;
55
+ const DEFAULT_BLOCK = 24;
50
56
  const WeekdayHeatmapContext = createContext(null);
51
57
  const useWeekdayHeatmap = () => {
52
58
  const context = use(WeekdayHeatmapContext);
@@ -84,8 +90,10 @@ const useWeekdayHeatmap = () => {
84
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`.
85
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`.
86
92
  */
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 }) => {
93
+ 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
94
  const levels = Math.max(1, levelsProp);
95
+ const [rootRef, rootWidth] = useElementWidth();
96
+ const weekdays = useMemo(() => displayedWeekdays ?? Array.from({ length: 7 }, (_, i) => (weekStart + i) % 7), [displayedWeekdays, weekStart]);
89
97
  const dataWithLevels = useMemo(() => {
90
98
  if (data.length === 0) return [];
91
99
  const maxRegular = data.reduce((m, d) => Math.max(m, d.value), 1);
@@ -141,7 +149,7 @@ const WeekdayHeatmap = ({ data, weekStart = 0, use12Hour = false, blockSize = 24
141
149
  const weekdayLabels = locale ? generateWeekdayLabels(locale) : DEFAULT_WEEKDAY_LABELS;
142
150
  return {
143
151
  hours: use12Hour ? TWELVE_HOUR_LABELS : DEFAULT_HOUR_LABELS,
144
- endHour: use12Hour ? "12" : "00",
152
+ endHour: hours.at(-1) === 23 ? use12Hour ? "12" : "00" : (use12Hour ? TWELVE_HOUR_LABELS : DEFAULT_HOUR_LABELS)[(hours.at(-1) ?? -1) + 1],
145
153
  weekdays: weekdayLabels,
146
154
  cellLabel: "{{weekday}} {{hour}}: {{value}}",
147
155
  heatmapLabel: "Activity heatmap by weekday and hour",
@@ -152,16 +160,20 @@ const WeekdayHeatmap = ({ data, weekStart = 0, use12Hour = false, blockSize = 24
152
160
  }, [
153
161
  locale,
154
162
  use12Hour,
155
- labelsProp
163
+ labelsProp,
164
+ hours
156
165
  ]);
157
166
  const labelWidth = fontSize * 3.5 + LABEL_MARGIN;
158
167
  const totalCount = typeof totalCountProp === "number" ? totalCountProp : dataWithLevels.reduce((sum, a) => sum + a.value, 0);
168
+ const hasExtraColumn = resolvedExtraColumn !== null;
169
+ const columns = hours.length + (hasExtraColumn ? 2 : 0);
170
+ const fitted = (rootWidth - 24 - labelWidth - columns * blockMargin + (hasExtraColumn ? 0 : blockMargin)) / (columns + (hasExtraColumn ? 1 / (2 * blockAspectRatio) : 0));
171
+ const blockSize = blockSizeProp ?? (rootWidth > 0 ? Math.min(MAX_FITTED_BLOCK, Math.max(MIN_FITTED_BLOCK, fitted)) / blockAspectRatio : DEFAULT_BLOCK);
159
172
  const blockWidth = blockSize * blockAspectRatio;
160
173
  const labelHeight = fontSize + LABEL_MARGIN;
161
- const hasExtraColumn = resolvedExtraColumn !== null;
162
174
  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;
175
+ const width = hours.length * (blockWidth + blockMargin) + (hasExtraColumn ? blockSize / 2 + (blockWidth + blockMargin) * 2 : 0) - blockMargin + labelWidth;
176
+ const rowCount = weekdays.length + (hasExtraRow ? 1 : 0);
165
177
  const extraRowGap = hasExtraRow ? blockSize + blockMargin : 0;
166
178
  const height = rowCount * (blockSize + blockMargin) + extraRowGap - blockMargin + labelHeight;
167
179
  const contextValue = useMemo(() => ({
@@ -183,6 +195,8 @@ const WeekdayHeatmap = ({ data, weekStart = 0, use12Hour = false, blockSize = 24
183
195
  width,
184
196
  height,
185
197
  weekStart,
198
+ hours,
199
+ weekdays,
186
200
  colors
187
201
  }), [
188
202
  dataWithLevels,
@@ -203,14 +217,17 @@ const WeekdayHeatmap = ({ data, weekStart = 0, use12Hour = false, blockSize = 24
203
217
  width,
204
218
  height,
205
219
  weekStart,
220
+ hours,
221
+ weekdays,
206
222
  colors
207
223
  ]);
208
224
  if (data.length === 0) return emptyState ? emptyState : null;
209
225
  return /* @__PURE__ */ jsx(WeekdayHeatmapContext, {
210
226
  value: contextValue,
211
227
  children: /* @__PURE__ */ jsx("div", {
228
+ ref: rootRef,
212
229
  "data-slot": "weekday-heatmap",
213
- className: cn("flex w-max max-w-full flex-col gap-2 p-4", className),
230
+ className: cn("flex flex-col gap-2", blockSizeProp === void 0 ? "w-full" : "w-max max-w-full", className),
214
231
  style: {
215
232
  fontSize,
216
233
  ...style
@@ -220,16 +237,18 @@ const WeekdayHeatmap = ({ data, weekStart = 0, use12Hour = false, blockSize = 24
220
237
  })
221
238
  });
222
239
  };
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();
240
+ const WeekdayHeatmapBlock = ({ ref, activity, extra, highlighted = false, selected = false, onCellClick, onCellHover, onClick, onKeyDown, onMouseEnter, onMouseLeave, className, style: styleProp, ...props }) => {
241
+ const { blockSize, blockWidth, blockMargin, blockRadius, labelWidth, labelHeight, levels, isNormalized, hours, weekdays, labels, colors } = useWeekdayHeatmap();
225
242
  const level = Math.max(0, Math.min(colorStepCount(levels, isNormalized), activity.level));
226
243
  const isExtraRow = extra === "row";
227
244
  const isExtraColumn = extra === "column";
228
- const rowIndex = isExtraRow ? 7 : (activity.weekday - weekStart + 7) % 7;
245
+ const rowIndex = isExtraRow ? weekdays.length : weekdays.findIndex((day) => day === activity.weekday);
246
+ const hourIndex = isExtraColumn ? hours.length : hours.findIndex((hour) => hour === activity.hour);
247
+ if (rowIndex < 0 || hourIndex < 0) return null;
229
248
  const extraRowGap = isExtraRow ? blockSize + blockMargin : 0;
230
249
  const yPosition = labelHeight + (blockSize + blockMargin) * rowIndex + extraRowGap;
231
250
  const extraColumnGap = isExtraColumn ? blockWidth + blockMargin : 0;
232
- const xPosition = isExtraColumn ? labelWidth + 24 * (blockWidth + blockMargin) + blockSize / 2 + extraColumnGap : labelWidth + (blockWidth + blockMargin) * activity.hour;
251
+ const xPosition = isExtraColumn ? labelWidth + hours.length * (blockWidth + blockMargin) + blockSize / 2 + extraColumnGap : labelWidth + (blockWidth + blockMargin) * hourIndex;
233
252
  const weekdayToken = isExtraRow ? "extra" : labels.weekdays?.[activity.weekday] ?? String(activity.weekday);
234
253
  const hourToken = isExtraColumn ? "extra" : `${String(activity.hour).padStart(2, "0")}:00`;
235
254
  const ariaLabel = (labels.cellLabel ?? "{{weekday}} {{hour}}: {{value}}").replace("{{weekday}}", weekdayToken).replace("{{hour}}", hourToken).replace("{{value}}", String(activity.value));
@@ -237,6 +256,7 @@ const WeekdayHeatmapBlock = ({ ref, activity, extra, highlighted = false, onCell
237
256
  ref,
238
257
  "data-slot": "weekday-heatmap-block",
239
258
  role: onCellClick ? "button" : "img",
259
+ "aria-pressed": onCellClick ? selected : void 0,
240
260
  tabIndex: onCellClick ? 0 : -1,
241
261
  "aria-label": ariaLabel,
242
262
  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),
@@ -245,6 +265,7 @@ const WeekdayHeatmapBlock = ({ ref, activity, extra, highlighted = false, onCell
245
265
  "data-hour": isExtraColumn ? "extra" : activity.hour,
246
266
  "data-level": level,
247
267
  "data-highlighted": highlighted || void 0,
268
+ "data-selected": selected || void 0,
248
269
  height: blockSize,
249
270
  rx: blockRadius,
250
271
  ry: blockRadius,
@@ -253,6 +274,10 @@ const WeekdayHeatmapBlock = ({ ref, activity, extra, highlighted = false, onCell
253
274
  y: yPosition,
254
275
  style: {
255
276
  fill: getLevelFill(level, levels, isNormalized, highlighted, colors),
277
+ ...selected ? {
278
+ stroke: "var(--foreground)",
279
+ strokeWidth: 2
280
+ } : {},
256
281
  ...styleProp
257
282
  },
258
283
  onClick: (event) => {
@@ -279,7 +304,8 @@ const WeekdayHeatmapBlock = ({ ref, activity, extra, highlighted = false, onCell
279
304
  };
280
305
  WeekdayHeatmapBlock.displayName = "WeekdayHeatmapBlock";
281
306
  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();
307
+ const navigation = useHeatmapNavigation();
308
+ const { data, extraRow, extraColumn, blockSize, blockWidth, blockMargin, labels, labelWidth, labelHeight, fontSize, hours, weekdays } = useWeekdayHeatmap();
283
309
  const hasExtraRow = extraRow !== null;
284
310
  const hasExtraColumn = extraColumn !== null;
285
311
  const activityMap = useMemo(() => {
@@ -299,24 +325,24 @@ const WeekdayHeatmapBody = ({ hideHourLabels = false, hideWeekdayLabels = false,
299
325
  }, [extraColumn]);
300
326
  const regularActivities = useMemo(() => {
301
327
  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
- }
328
+ for (const [di, weekday] of weekdays.entries()) for (const hour of hours) activities.push({
329
+ activity: activityMap.get(`${weekday}-${hour}`) ?? {
330
+ weekday,
331
+ hour,
332
+ value: 0,
333
+ level: 0
334
+ },
335
+ weekdayIndex: di
336
+ });
314
337
  return activities;
315
- }, [activityMap, weekStart]);
338
+ }, [
339
+ activityMap,
340
+ weekdays,
341
+ hours
342
+ ]);
316
343
  const extraColumnActivities = useMemo(() => {
317
344
  if (!extraColumnMap) return [];
318
- return Array.from({ length: 7 }, (_, di) => {
319
- const weekday = (weekStart + di) % 7;
345
+ return weekdays.map((weekday, di) => {
320
346
  const entry = extraColumnMap.get(weekday);
321
347
  return entry ? {
322
348
  activity: {
@@ -328,44 +354,53 @@ const WeekdayHeatmapBody = ({ hideHourLabels = false, hideWeekdayLabels = false,
328
354
  weekdayIndex: di
329
355
  } : null;
330
356
  }).filter((a) => a !== null);
331
- }, [extraColumnMap, weekStart]);
357
+ }, [extraColumnMap, weekdays]);
332
358
  const extraRowActivities = useMemo(() => {
333
359
  if (!extraRow) return [];
334
- return extraRow.values.map(({ hour, value, level }) => ({
360
+ return extraRow.values.filter(({ hour }) => hours.includes(hour)).map(({ hour, value, level }) => ({
335
361
  activity: {
336
362
  weekday: 0,
337
363
  hour,
338
364
  value,
339
365
  level
340
366
  },
341
- weekdayIndex: 7
367
+ weekdayIndex: weekdays.length
342
368
  }));
343
- }, [extraRow]);
344
- const rowCount = hasExtraRow ? 8 : 7;
369
+ }, [
370
+ extraRow,
371
+ hours,
372
+ weekdays.length
373
+ ]);
374
+ const rowCount = weekdays.length + (hasExtraRow ? 1 : 0);
345
375
  const extraRowGap = hasExtraRow ? blockSize + blockMargin : 0;
346
376
  const svgHeight = rowCount * (blockSize + blockMargin) + extraRowGap - blockMargin + labelHeight;
347
377
  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);
378
+ const svgWidth = hasExtraColumn ? labelWidth + hours.length * (blockWidth + blockMargin) + blockSize / 2 + (blockWidth + blockMargin) + extraColumnGap : labelWidth + hours.length * (blockWidth + blockMargin) - blockMargin;
379
+ const orderedWeekdayIndices = weekdays;
350
380
  return /* @__PURE__ */ jsx("div", {
351
381
  "data-slot": "weekday-heatmap-body",
382
+ ref: navigation.ref,
352
383
  className: cn("max-w-full overflow-x-auto overflow-y-hidden", className),
353
384
  ...props,
385
+ onKeyDown: (event) => {
386
+ props.onKeyDown?.(event);
387
+ if (!event.defaultPrevented) navigation.onKeyDown(event);
388
+ },
354
389
  children: /* @__PURE__ */ jsxs("svg", {
355
390
  role: "img",
356
391
  "aria-label": labels.heatmapLabel ?? "Activity heatmap by weekday and hour",
357
392
  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,
393
+ height: svgHeight + 24,
394
+ viewBox: `-12 -12 ${svgWidth + 24} ${svgHeight + 24}`,
395
+ width: svgWidth + 24,
361
396
  children: [
362
397
  !hideHourLabels && /* @__PURE__ */ jsxs("g", {
363
398
  className: cn("fill-current font-mono", labelClassName),
364
399
  children: [
365
- HOURS.map((hour) => {
400
+ hours.map((hour, index) => {
366
401
  const label = labels.hours?.[hour] ?? "";
367
402
  return /* @__PURE__ */ jsx("text", {
368
- x: labelWidth + (blockWidth + blockMargin) * hour,
403
+ x: labelWidth + (blockWidth + blockMargin) * index,
369
404
  y: 0,
370
405
  textAnchor: "middle",
371
406
  dominantBaseline: "hanging",
@@ -374,7 +409,7 @@ const WeekdayHeatmapBody = ({ hideHourLabels = false, hideWeekdayLabels = false,
374
409
  }, `hour-${hour}`);
375
410
  }),
376
411
  labels.endHour != null && /* @__PURE__ */ jsx("text", {
377
- x: labelWidth + (blockWidth + blockMargin) * 24,
412
+ x: labelWidth + (blockWidth + blockMargin) * hours.length,
378
413
  y: 0,
379
414
  textAnchor: "middle",
380
415
  dominantBaseline: "hanging",
@@ -382,7 +417,7 @@ const WeekdayHeatmapBody = ({ hideHourLabels = false, hideWeekdayLabels = false,
382
417
  children: labels.endHour
383
418
  }, "hour-end"),
384
419
  hasExtraColumn && /* @__PURE__ */ jsx("text", {
385
- x: labelWidth + 24 * (blockWidth + blockMargin) + blockSize / 2 + (blockWidth + blockMargin) + blockWidth / 2,
420
+ x: labelWidth + hours.length * (blockWidth + blockMargin) + blockSize / 2 + (blockWidth + blockMargin) + blockWidth / 2,
386
421
  y: 0,
387
422
  textAnchor: "middle",
388
423
  dominantBaseline: "hanging",
@@ -406,7 +441,7 @@ const WeekdayHeatmapBody = ({ hideHourLabels = false, hideWeekdayLabels = false,
406
441
  }, `weekday-${weekday}`);
407
442
  }), hasExtraRow && /* @__PURE__ */ jsx("text", {
408
443
  x: labelWidth - 8,
409
- y: labelHeight + (blockSize + blockMargin) * 7 + (blockSize + blockMargin) + blockSize / 2,
444
+ y: labelHeight + (blockSize + blockMargin) * weekdays.length + (blockSize + blockMargin) + blockSize / 2,
410
445
  dominantBaseline: "middle",
411
446
  textAnchor: "end",
412
447
  style: { fontSize: `${fontSize * .75}px` },
@@ -450,7 +485,7 @@ const WeekdayHeatmapStat = ({ compute, label, className, children, ...props }) =
450
485
  });
451
486
  };
452
487
  const WeekdayHeatmapLegend = ({ labels: labelsProp, className, children, ...props }) => {
453
- const { levels, isNormalized, blockSize, blockWidth, blockRadius, colors, labels } = useWeekdayHeatmap();
488
+ const { levels, isNormalized, blockRadius, colors, labels } = useWeekdayHeatmap();
454
489
  const lessLabel = labelsProp?.less ?? "Less";
455
490
  const moreLabel = labelsProp?.more ?? "More";
456
491
  const legendLevels = Array.from({ length: levels }, (_, i) => isNormalized ? i + 1 : i);
@@ -467,14 +502,14 @@ const WeekdayHeatmapLegend = ({ labels: labelsProp, className, children, ...prop
467
502
  legendLevels.map((level) => children ? /* @__PURE__ */ jsx(Fragment$1, { children: children({ level }) }, `legend-level-${level}`) : /* @__PURE__ */ jsx("svg", {
468
503
  role: "img",
469
504
  "aria-label": (labels.legendLevelLabel ?? "{{level}} contributions").replace("{{level}}", String(level)),
470
- height: blockSize,
471
- width: blockWidth,
505
+ height: LEGEND_SWATCH,
506
+ width: LEGEND_SWATCH,
472
507
  children: /* @__PURE__ */ jsx("rect", {
473
508
  "data-level": level,
474
- height: blockSize,
509
+ height: LEGEND_SWATCH,
475
510
  rx: blockRadius,
476
511
  ry: blockRadius,
477
- width: blockWidth,
512
+ width: LEGEND_SWATCH,
478
513
  style: { fill: getLevelFill(level, levels, isNormalized, false, colors) }
479
514
  })
480
515
  }, `legend-level-${level}`)),
@@ -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,