@siyahi/ui 0.1.9-next.20 → 0.1.9-next.22

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 (101) hide show
  1. package/DESIGN.md +42 -0
  2. package/README.md +3 -3
  3. package/agents/examples/alert.tsx +4 -6
  4. package/agents/examples/app-sidebar.tsx +3 -1
  5. package/agents/examples/bar-list-sides.tsx +13 -3
  6. package/agents/examples/button-states.tsx +23 -0
  7. package/agents/examples/calendar.tsx +3 -7
  8. package/agents/examples/callout.tsx +33 -0
  9. package/agents/examples/card.tsx +3 -1
  10. package/agents/examples/change-bar.tsx +104 -0
  11. package/agents/examples/chart-area.tsx +5 -4
  12. package/agents/examples/chart-bar-flows.tsx +3 -2
  13. package/agents/examples/chart-bar-sectors.tsx +2 -0
  14. package/agents/examples/collapsible.tsx +2 -2
  15. package/agents/examples/command.tsx +22 -20
  16. package/agents/examples/context-menu.tsx +4 -2
  17. package/agents/examples/data-table-compact.tsx +95 -0
  18. package/agents/examples/distribution-bar-tug.tsx +24 -22
  19. package/agents/examples/heatmap-calendar.tsx +19 -7
  20. package/agents/examples/heatmap-status.tsx +19 -11
  21. package/agents/examples/heatmap-weekday.tsx +34 -15
  22. package/agents/examples/input-states.tsx +33 -0
  23. package/agents/examples/metric-strip.tsx +9 -3
  24. package/agents/examples/overview-dashboard.tsx +18 -0
  25. package/agents/examples/page-hero.tsx +38 -0
  26. package/agents/examples/price-chart.tsx +2 -2
  27. package/agents/examples/range-position-table.tsx +101 -0
  28. package/agents/examples/range-position.tsx +55 -0
  29. package/agents/examples/scroll-area.tsx +12 -10
  30. package/agents/examples/section-cards-select.tsx +8 -5
  31. package/agents/examples/surfaces.tsx +7 -4
  32. package/agents/examples/target-rows.tsx +72 -0
  33. package/agents/examples/treemap.tsx +13 -10
  34. package/agents/manifest.json +153 -3
  35. package/dist/components/registry/charts/area-chart-card.js +25 -7
  36. package/dist/components/registry/charts/bar-chart-card.d.ts +0 -1
  37. package/dist/components/registry/charts/bar-chart-card.js +15 -4
  38. package/dist/components/registry/charts/line-chart-card.js +2 -2
  39. package/dist/components/registry/dashboard-01/section-cards.js +1 -1
  40. package/dist/components/registry/dashboardcn/bar-list.js +11 -5
  41. package/dist/components/registry/dashboardcn/distribution-bar.js +5 -3
  42. package/dist/components/registry/dashboardcn/kpi-row-card.js +2 -2
  43. package/dist/components/registry/dashboardcn/sparkline.d.ts +5 -1
  44. package/dist/components/registry/dashboardcn/sparkline.js +40 -18
  45. package/dist/components/registry/heatmap/calendar-heatmap.d.ts +4 -2
  46. package/dist/components/registry/heatmap/calendar-heatmap.js +67 -33
  47. package/dist/components/registry/heatmap/status-heatmap.d.ts +5 -3
  48. package/dist/components/registry/heatmap/status-heatmap.js +31 -16
  49. package/dist/components/registry/heatmap/weekday-heatmap.d.ts +4 -2
  50. package/dist/components/registry/heatmap/weekday-heatmap.js +28 -12
  51. package/dist/components/registry/niko-table/core/data-table-context.d.ts +16 -1
  52. package/dist/components/registry/niko-table/core/data-table-context.js +5 -20
  53. package/dist/components/registry/niko-table/core/data-table-root.js +39 -4
  54. package/dist/components/registry/niko-table/core/data-table-structure.js +2 -0
  55. package/dist/components/registry/niko-table/lib/styles.js +1 -1
  56. package/dist/components/registry/niko-table/types/index.d.ts +9 -0
  57. package/dist/components/registry/sidebar-07/nav-main.d.ts +1 -0
  58. package/dist/components/registry/sidebar-07/nav-main.js +9 -2
  59. package/dist/components/siyahi/callout.d.ts +24 -0
  60. package/dist/components/siyahi/callout.js +40 -0
  61. package/dist/components/siyahi/change-bar.d.ts +21 -0
  62. package/dist/components/siyahi/change-bar.js +35 -0
  63. package/dist/components/siyahi/data-table-compact-columns-toggle.d.ts +4 -0
  64. package/dist/components/siyahi/data-table-compact-columns-toggle.js +19 -0
  65. package/dist/components/siyahi/data-table-footnote.d.ts +12 -0
  66. package/dist/components/siyahi/data-table-footnote.js +35 -0
  67. package/dist/components/siyahi/default-sidebar-open.d.ts +8 -0
  68. package/dist/components/siyahi/default-sidebar-open.js +13 -0
  69. package/dist/components/siyahi/delta.d.ts +5 -1
  70. package/dist/components/siyahi/delta.js +14 -9
  71. package/dist/components/siyahi/page-hero.d.ts +25 -0
  72. package/dist/components/siyahi/page-hero.js +41 -0
  73. package/dist/components/siyahi/page-toc.d.ts +20 -0
  74. package/dist/components/siyahi/page-toc.js +76 -0
  75. package/dist/components/siyahi/quote.d.ts +12 -0
  76. package/dist/components/siyahi/quote.js +23 -0
  77. package/dist/components/siyahi/range-position.d.ts +24 -0
  78. package/dist/components/siyahi/range-position.js +105 -0
  79. package/dist/components/siyahi/siyahi-provider.d.ts +1 -1
  80. package/dist/components/siyahi/siyahi-provider.js +1 -1
  81. package/dist/components/siyahi/target-rows.d.ts +34 -0
  82. package/dist/components/siyahi/target-rows.js +97 -0
  83. package/dist/components/siyahi/treemap.d.ts +4 -1
  84. package/dist/components/siyahi/treemap.js +36 -28
  85. package/dist/components/siyahi/warning-alert.d.ts +10 -0
  86. package/dist/components/siyahi/warning-alert.js +20 -0
  87. package/dist/index.d.ts +15 -4
  88. package/dist/index.js +12 -1
  89. package/dist/lib/chart-frame.d.ts +12 -2
  90. package/dist/lib/chart-frame.js +51 -7
  91. package/dist/lib/chart-series.d.ts +5 -2
  92. package/dist/lib/compact-columns.d.ts +19 -0
  93. package/dist/lib/compact-columns.js +55 -0
  94. package/dist/lib/format.d.ts +8 -3
  95. package/dist/lib/format.js +25 -6
  96. package/dist/lib/treemap.js +6 -1
  97. package/dist/lib/use-element-width.d.ts +5 -0
  98. package/dist/lib/use-element-width.js +15 -0
  99. package/package.json +2 -1
  100. package/report.css +37 -36
  101. package/styles/siyahi.css +243 -55
@@ -1,7 +1,8 @@
1
1
  import { cn } from "../../../lib/utils.js";
2
2
  import { useHeatmapNavigation } from "../../../lib/heatmap-navigation.js";
3
+ import { useElementWidth } from "../../../lib/use-element-width.js";
3
4
  import { Fragment, jsx, jsxs } from "react/jsx-runtime";
4
- import { Fragment as Fragment$1, createContext, use, useMemo } from "react";
5
+ import { Fragment as Fragment$1, createContext, use, useLayoutEffect, useMemo } from "react";
5
6
  import { differenceInCalendarDays, eachDayOfInterval, format, formatISO, getDay, getMonth, getYear, nextDay, parseISO, subWeeks } from "date-fns";
6
7
  //#region src/components/registry/heatmap/calendar-heatmap.tsx
7
8
  const colorStepCount = (levels, isNormalized) => Math.max(1, isNormalized ? levels : levels - 1);
@@ -41,6 +42,12 @@ const generateWeekdayLabels = (locale) => {
41
42
  };
42
43
  const EMPTY_STYLE = {};
43
44
  const LABEL_MARGIN = 8;
45
+ const WEEKDAY_LABEL_WIDTH = 40;
46
+ const STROKE_PADDING = 3;
47
+ const LEGEND_SWATCH = 12;
48
+ const MIN_FITTED_BLOCK = 10;
49
+ const MAX_FITTED_BLOCK = 20;
50
+ const DEFAULT_BLOCK = 12;
44
51
  const CalendarHeatmapContext = createContext(null);
45
52
  const useCalendarHeatmap = () => {
46
53
  const context = use(CalendarHeatmapContext);
@@ -132,26 +139,18 @@ const groupContinuous = (activities, weekStart = 0) => {
132
139
  const padded = [...new Array(leadingPad).fill(void 0), ...normalizedActivities];
133
140
  const numberOfWeeks = Math.ceil(padded.length / 7);
134
141
  const allWeeks = new Array(numberOfWeeks).fill(void 0).map((_, i) => padded.slice(i * 7, i * 7 + 7));
135
- const yearMap = /* @__PURE__ */ new Map();
136
- for (const week of allWeeks) {
137
- const firstActivity = week.find((a) => a !== void 0);
138
- const year = firstActivity ? getYear(parseISO(firstActivity.date)) : void 0;
139
- if (year !== void 0) {
140
- if (!yearMap.has(year)) yearMap.set(year, []);
141
- yearMap.get(year)?.push(week);
142
- }
143
- }
144
- return Array.from(yearMap.entries()).sort(([a], [b]) => a - b).map(([year, weeks]) => ({
145
- year,
142
+ return [{
143
+ year: getYear(firstDate),
146
144
  startMonth: 0,
147
- weeks
148
- }));
145
+ weeks: allWeeks
146
+ }];
149
147
  };
150
- const getMonthLabels = (weeks, monthNames = generateMonthLabels()) => {
151
- return weeks.reduce((labels, week, weekIndex) => {
148
+ const getMonthLabels = (weeks, monthNames = generateMonthLabels(), yearTicks = false) => {
149
+ const ticks = weeks.reduce((labels, week, weekIndex) => {
152
150
  const firstActivity = week.find((activity) => activity !== void 0);
153
151
  if (!firstActivity) return labels;
154
- const month = monthNames[getMonth(parseISO(firstActivity.date))];
152
+ const date = parseISO(firstActivity.date);
153
+ const month = monthNames[getMonth(date)];
155
154
  if (!month) {
156
155
  const monthName = new Date(firstActivity.date).toLocaleString("en-US", { month: "short" });
157
156
  throw new Error(`Unexpected error: undefined month label for ${monthName}.`);
@@ -159,7 +158,8 @@ const getMonthLabels = (weeks, monthNames = generateMonthLabels()) => {
159
158
  const prevLabel = labels.at(-1);
160
159
  if (weekIndex === 0 || !prevLabel || prevLabel.label !== month) return labels.concat({
161
160
  weekIndex,
162
- label: month
161
+ label: month,
162
+ year: getMonth(date) === 0 ? getYear(date) : void 0
163
163
  });
164
164
  return labels;
165
165
  }, []).filter(({ weekIndex }, index, labels) => {
@@ -168,6 +168,22 @@ const getMonthLabels = (weeks, monthNames = generateMonthLabels()) => {
168
168
  if (index === labels.length - 1) return weeks.slice(weekIndex).length >= minWeeks;
169
169
  return true;
170
170
  });
171
+ if (!yearTicks) return ticks;
172
+ const hasJanuary = ticks.some(({ year }) => year !== void 0);
173
+ return ticks.map((tick, index) => {
174
+ if (tick.year !== void 0) return {
175
+ ...tick,
176
+ label: String(tick.year)
177
+ };
178
+ if (index === 0 && !hasJanuary) {
179
+ const week = weeks[tick.weekIndex]?.find((activity) => activity !== void 0);
180
+ return week ? {
181
+ ...tick,
182
+ label: `${tick.label} ${getYear(parseISO(week.date))}`
183
+ } : tick;
184
+ }
185
+ return tick;
186
+ });
171
187
  };
172
188
  /**
173
189
  * Calendar Heatmap
@@ -202,8 +218,9 @@ const getMonthLabels = (weeks, monthNames = generateMonthLabels()) => {
202
218
  * @param levels - Total number of legend cells (including empty when not normalized). Default: 5
203
219
  * @param isNormalized - When true, uses min-max normalization across the dataset (suitable for signed values). When false (default), treats 0 as empty and scales from 0 to max.
204
220
  */
205
- const CalendarHeatmap = ({ data, weekStart = 0, continuousMonths = true, hasEmptyColumn = false, blockSize = 12, blockMargin = 4, blockRadius = 2, blockAspectRatio = 1, levels: levelsProp = 5, isNormalized = false, colors, locale, labels: labelsProp, fontSize = 14, emptyState, totalCount: totalCountProp, style = EMPTY_STYLE, className, children, ...props }) => {
221
+ const CalendarHeatmap = ({ data, weekStart = 0, continuousMonths = true, hasEmptyColumn = false, blockSize: blockSizeProp, blockMargin = 4, blockRadius = 2, blockAspectRatio = 1, levels: levelsProp = 5, isNormalized = false, colors, locale, labels: labelsProp, fontSize = 14, emptyState, totalCount: totalCountProp, style = EMPTY_STYLE, className, children, ...props }) => {
206
222
  const levels = Math.max(1, levelsProp);
223
+ const [rootRef, rootWidth] = useElementWidth();
207
224
  const dataWithLevels = useMemo(() => {
208
225
  if (data.length === 0) return [];
209
226
  const maxCount = data.reduce((max, d) => Math.max(max, d.value), 1);
@@ -236,6 +253,8 @@ const CalendarHeatmap = ({ data, weekStart = 0, continuousMonths = true, hasEmpt
236
253
  const labelHeight = fontSize + LABEL_MARGIN;
237
254
  const year = data.length > 0 ? getYear(parseISO(data[0].date)) : (/* @__PURE__ */ new Date()).getFullYear();
238
255
  const totalCount = typeof totalCountProp === "number" ? totalCountProp : dataWithLevels.reduce((sum, activity) => sum + activity.value, 0);
256
+ const fitted = (rootWidth - WEEKDAY_LABEL_WIDTH - 6 + blockMargin) / Math.max(weeks.length, 1) - blockMargin;
257
+ const blockSize = blockSizeProp ?? (rootWidth > 0 ? Math.min(MAX_FITTED_BLOCK, Math.max(MIN_FITTED_BLOCK, fitted)) / blockAspectRatio : DEFAULT_BLOCK);
239
258
  const blockWidth = blockSize * blockAspectRatio;
240
259
  const width = weeks.length * (blockWidth + blockMargin) - blockMargin;
241
260
  const height = labelHeight + (blockSize + blockMargin) * 7 - blockMargin;
@@ -290,8 +309,9 @@ const CalendarHeatmap = ({ data, weekStart = 0, continuousMonths = true, hasEmpt
290
309
  return /* @__PURE__ */ jsx(CalendarHeatmapContext, {
291
310
  value: contextValue,
292
311
  children: /* @__PURE__ */ jsx("div", {
312
+ ref: rootRef,
293
313
  "data-slot": "calendar-heatmap",
294
- className: cn("flex w-max max-w-full flex-col gap-2", className),
314
+ className: cn("flex flex-col gap-2", blockSizeProp === void 0 ? "w-full" : "w-max max-w-full", className),
295
315
  style: {
296
316
  fontSize,
297
317
  ...style
@@ -301,7 +321,7 @@ const CalendarHeatmap = ({ data, weekStart = 0, continuousMonths = true, hasEmpt
301
321
  })
302
322
  });
303
323
  };
304
- const CalendarHeatmapBlock = ({ ref, activity, dayIndex, weekIndex, highlighted = false, onCellClick, onCellHover, onClick, onKeyDown, onMouseEnter, onMouseLeave, className, style: styleProp, ...props }) => {
324
+ const CalendarHeatmapBlock = ({ ref, activity, dayIndex, weekIndex, highlighted = false, selected = false, onCellClick, onCellHover, onClick, onKeyDown, onMouseEnter, onMouseLeave, className, style: styleProp, ...props }) => {
305
325
  const { blockSize, blockWidth, blockMargin, blockRadius, labelHeight, labels, levels, isNormalized, colors } = useCalendarHeatmap();
306
326
  const level = Math.max(0, Math.min(colorStepCount(levels, isNormalized), activity.level));
307
327
  const ariaLabel = (labels.cellLabel ?? "{{date}}: {{value}} contributions").replace("{{date}}", activity.date).replace("{{value}}", String(activity.value));
@@ -309,6 +329,7 @@ const CalendarHeatmapBlock = ({ ref, activity, dayIndex, weekIndex, highlighted
309
329
  ref,
310
330
  "data-slot": "calendar-heatmap-block",
311
331
  role: onCellClick ? "button" : "img",
332
+ "aria-pressed": onCellClick ? selected : void 0,
312
333
  tabIndex: onCellClick ? 0 : -1,
313
334
  "aria-label": ariaLabel,
314
335
  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),
@@ -316,6 +337,7 @@ const CalendarHeatmapBlock = ({ ref, activity, dayIndex, weekIndex, highlighted
316
337
  "data-date": activity.date,
317
338
  "data-level": level,
318
339
  "data-highlighted": highlighted || void 0,
340
+ "data-selected": selected || void 0,
319
341
  height: blockSize,
320
342
  rx: blockRadius,
321
343
  ry: blockRadius,
@@ -324,6 +346,10 @@ const CalendarHeatmapBlock = ({ ref, activity, dayIndex, weekIndex, highlighted
324
346
  y: labelHeight + (blockSize + blockMargin) * dayIndex,
325
347
  style: {
326
348
  fill: getLevelFill(level, levels, isNormalized, highlighted, colors),
349
+ ...selected ? {
350
+ stroke: "var(--foreground)",
351
+ strokeWidth: 2
352
+ } : {},
327
353
  ...styleProp
328
354
  },
329
355
  onClick: (event) => {
@@ -351,17 +377,17 @@ const CalendarHeatmapBlock = ({ ref, activity, dayIndex, weekIndex, highlighted
351
377
  CalendarHeatmapBlock.displayName = "CalendarHeatmapBlock";
352
378
  const CalendarHeatmapBody = ({ hideMonthLabels = false, hideWeekdayLabels = false, hideYearLabels = false, className, labelClassName, yearClassName, children, renderYearFooter, ...props }) => {
353
379
  const navigation = useHeatmapNavigation();
354
- const { yearRows, blockSize, blockWidth, blockMargin, labels, labelHeight, fontSize, weekStart, data } = useCalendarHeatmap();
355
- const weekdayLabelWidth = hideWeekdayLabels ? 0 : 40;
356
- const strokePadding = 3;
380
+ const { yearRows, blockSize, blockWidth, blockMargin, labels, labelHeight, fontSize, weekStart, continuousMonths } = useCalendarHeatmap();
381
+ const weekdayLabelWidth = hideWeekdayLabels ? 0 : WEEKDAY_LABEL_WIDTH;
382
+ const strokePadding = STROKE_PADDING;
357
383
  const rowData = useMemo(() => {
358
384
  return yearRows.map((yearRow) => {
359
385
  return {
360
386
  yearRow,
361
387
  width: yearRow.weeks.length * (blockWidth + blockMargin) - blockMargin,
362
388
  height: labelHeight + (blockSize + blockMargin) * 7 - blockMargin,
363
- monthLabels: getMonthLabels(yearRow.weeks, labels.months),
364
- yearTotalCount: data.filter((activity) => getYear(parseISO(activity.date)) === yearRow.year).reduce((sum, activity) => sum + activity.value, 0)
389
+ monthLabels: getMonthLabels(yearRow.weeks, labels.months, continuousMonths),
390
+ yearTotalCount: yearRow.weeks.flat().reduce((sum, activity) => sum + (activity?.value ?? 0), 0)
365
391
  };
366
392
  });
367
393
  }, [
@@ -371,9 +397,17 @@ const CalendarHeatmapBody = ({ hideMonthLabels = false, hideWeekdayLabels = fals
371
397
  blockMargin,
372
398
  labelHeight,
373
399
  labels.months,
374
- data
400
+ continuousMonths
375
401
  ]);
376
402
  const totalWidth = weekdayLabelWidth + Math.max(...rowData.map((r) => r.width)) + 6;
403
+ const scroller = navigation.ref;
404
+ useLayoutEffect(() => {
405
+ if (continuousMonths && scroller.current) scroller.current.scrollLeft = scroller.current.scrollWidth;
406
+ }, [
407
+ continuousMonths,
408
+ scroller,
409
+ totalWidth
410
+ ]);
377
411
  return /* @__PURE__ */ jsx("div", {
378
412
  "data-slot": "calendar-heatmap-body",
379
413
  ref: navigation.ref,
@@ -384,7 +418,7 @@ const CalendarHeatmapBody = ({ hideMonthLabels = false, hideWeekdayLabels = fals
384
418
  if (!event.defaultPrevented) navigation.onKeyDown(event);
385
419
  },
386
420
  children: rowData.map(({ yearRow, height, monthLabels, yearTotalCount }) => /* @__PURE__ */ jsxs("div", { children: [
387
- !hideYearLabels && /* @__PURE__ */ jsx("div", {
421
+ !hideYearLabels && !continuousMonths && /* @__PURE__ */ jsx("div", {
388
422
  className: cn("mb-2 text-muted-foreground", yearClassName),
389
423
  children: yearRow.year
390
424
  }),
@@ -465,7 +499,7 @@ const CalendarHeatmapStat = ({ compute, label, className, children, ...props })
465
499
  });
466
500
  };
467
501
  const CalendarHeatmapLegend = ({ labels: labelsProp, className, children, ...props }) => {
468
- const { levels, isNormalized, blockSize, blockWidth, blockRadius, colors, labels } = useCalendarHeatmap();
502
+ const { levels, isNormalized, blockRadius, colors, labels } = useCalendarHeatmap();
469
503
  const lessLabel = labelsProp?.less ?? "Less";
470
504
  const moreLabel = labelsProp?.more ?? "More";
471
505
  const legendLevels = Array.from({ length: levels }, (_, i) => isNormalized ? i + 1 : i);
@@ -482,14 +516,14 @@ const CalendarHeatmapLegend = ({ labels: labelsProp, className, children, ...pro
482
516
  legendLevels.map((level) => children ? /* @__PURE__ */ jsx(Fragment$1, { children: children({ level }) }, `legend-level-${level}`) : /* @__PURE__ */ jsx("svg", {
483
517
  role: "img",
484
518
  "aria-label": (labels.legendLevelLabel ?? "{{level}} contributions").replace("{{level}}", String(level)),
485
- height: blockSize,
486
- width: blockWidth,
519
+ height: LEGEND_SWATCH,
520
+ width: LEGEND_SWATCH,
487
521
  children: /* @__PURE__ */ jsx("rect", {
488
522
  "data-level": level,
489
- height: blockSize,
523
+ height: LEGEND_SWATCH,
490
524
  rx: blockRadius,
491
525
  ry: blockRadius,
492
- width: blockWidth,
526
+ width: LEGEND_SWATCH,
493
527
  style: { fill: getLevelFill(level, levels, isNormalized, false, colors) }
494
528
  })
495
529
  }, `legend-level-${level}`)),
@@ -69,11 +69,13 @@ export type StatusHeatmapProps = HTMLAttributes<HTMLDivElement> & {
69
69
  *
70
70
  * @param data - Array of activities with date (YYYY-MM-DD) and status value (0-3)
71
71
  * @param dateFormat - Date format string for tooltips. Default: "MMM d"
72
- * @param blockAspectRatio - Width/height ratio of blocks. Default: 0.2 (narrow vertical bars)
72
+ * @param blockAspectRatio - Width/height ratio of blocks. Default: bars share the full width
73
73
  * @param colors - Custom colors for critical, degraded, and healthy states
74
74
  */
75
- export declare const StatusHeatmap: ({ data, dateFormat, blockSize, blockMargin, blockRadius, blockAspectRatio, colors, locale, labels: labelsProp, fontSize, emptyState, statusValues, healthyValue, style, className, children, ...props }: StatusHeatmapProps) => string | number | bigint | true | import("react").JSX.Element | Iterable<ReactNode> | Promise<string | number | bigint | boolean | Iterable<ReactNode> | import("react").ReactElement<unknown, string | import("react").JSXElementConstructor<any>> | import("react").ReactPortal | null | undefined> | null;
75
+ export declare const StatusHeatmap: ({ data, dateFormat, blockSize, blockMargin, blockRadius, blockAspectRatio: blockAspectRatioProp, colors, locale, labels: labelsProp, fontSize, emptyState, statusValues, healthyValue, style, className, children, ...props }: StatusHeatmapProps) => string | number | bigint | true | import("react").JSX.Element | Iterable<ReactNode> | Promise<string | number | bigint | boolean | Iterable<ReactNode> | import("react").ReactElement<unknown, string | import("react").JSXElementConstructor<any>> | import("react").ReactPortal | null | undefined> | null;
76
76
  export type StatusHeatmapBlockProps = HTMLAttributes<SVGRectElement> & {
77
+ /** The cell the page has picked: drawn with a ring and announced as pressed. */
78
+ selected?: boolean;
77
79
  activity: StatusActivity;
78
80
  dayIndex: number;
79
81
  highlighted?: boolean;
@@ -81,7 +83,7 @@ export type StatusHeatmapBlockProps = HTMLAttributes<SVGRectElement> & {
81
83
  onCellHover?: (activity: StatusActivity | null) => void;
82
84
  className?: string;
83
85
  };
84
- export declare function StatusHeatmapBlock({ ref, activity, dayIndex, highlighted, onCellClick, onCellHover, onClick, onKeyDown, onMouseEnter, onMouseLeave, className, style: styleProp, ...props }: StatusHeatmapBlockProps & {
86
+ export declare function StatusHeatmapBlock({ ref, activity, dayIndex, highlighted, selected, onCellClick, onCellHover, onClick, onKeyDown, onMouseEnter, onMouseLeave, className, style: styleProp, ...props }: StatusHeatmapBlockProps & {
85
87
  ref?: React.RefObject<SVGRectElement | null>;
86
88
  }): import("react").JSX.Element;
87
89
  export declare namespace StatusHeatmapBlock {
@@ -1,14 +1,15 @@
1
1
  import { cn } from "../../../lib/utils.js";
2
2
  import { useHeatmapNavigation } from "../../../lib/heatmap-navigation.js";
3
+ import { useElementWidth } from "../../../lib/use-element-width.js";
3
4
  import { Fragment, jsx, jsxs } from "react/jsx-runtime";
4
5
  import { Fragment as Fragment$1, createContext, use, useMemo } from "react";
5
6
  import { format } from "date-fns";
6
7
  //#region src/components/registry/heatmap/status-heatmap.tsx
7
8
  const DEFAULT_COLORS = {
8
9
  0: "var(--color-secondary)",
9
- 1: "var(--negative)",
10
+ 1: "var(--destructive)",
10
11
  2: "var(--warning)",
11
- 3: "var(--positive)"
12
+ 3: "color-mix(in oklab, var(--muted-foreground) 40%, transparent)"
12
13
  };
13
14
  const SEMANTIC_KEYS = {
14
15
  0: "noData",
@@ -52,6 +53,9 @@ const getStatusFill = (value, colors, highlighted = false) => {
52
53
  return `color-mix(in oklch, ${base} 60%, transparent)`;
53
54
  };
54
55
  const EMPTY_STYLE = {};
56
+ const LEGEND_SWATCH = 10;
57
+ const MIN_FITTED_BAR = 2;
58
+ const DEFAULT_ASPECT_RATIO = .2;
55
59
  const StatusHeatmapContext = createContext(null);
56
60
  const useStatusHeatmap = () => {
57
61
  const context = use(StatusHeatmapContext);
@@ -85,15 +89,16 @@ const useStatusHeatmap = () => {
85
89
  *
86
90
  * @param data - Array of activities with date (YYYY-MM-DD) and status value (0-3)
87
91
  * @param dateFormat - Date format string for tooltips. Default: "MMM d"
88
- * @param blockAspectRatio - Width/height ratio of blocks. Default: 0.2 (narrow vertical bars)
92
+ * @param blockAspectRatio - Width/height ratio of blocks. Default: bars share the full width
89
93
  * @param colors - Custom colors for critical, degraded, and healthy states
90
94
  */
91
- const StatusHeatmap = ({ data, dateFormat = "MMM d", blockSize = 40, blockMargin = 2, blockRadius = 2, blockAspectRatio = .2, colors, locale, labels: labelsProp, fontSize = 14, emptyState, statusValues = [
95
+ const StatusHeatmap = ({ data, dateFormat = "MMM d", blockSize = 40, blockMargin = 2, blockRadius = 2, blockAspectRatio: blockAspectRatioProp, colors, locale, labels: labelsProp, fontSize = 14, emptyState, statusValues = [
92
96
  0,
93
97
  1,
94
98
  2,
95
99
  3
96
100
  ], healthyValue = 3, style = EMPTY_STYLE, className, children, ...props }) => {
101
+ const [rootRef, rootWidth] = useElementWidth();
97
102
  const labels = useMemo(() => ({
98
103
  statuses: {
99
104
  noData: "No Data",
@@ -113,7 +118,10 @@ const StatusHeatmap = ({ data, dateFormat = "MMM d", blockSize = 40, blockMargin
113
118
  });
114
119
  return Array.from(uniqueDates).sort();
115
120
  }, [data]);
116
- const blockWidth = blockSize * blockAspectRatio;
121
+ const fits = blockAspectRatioProp === void 0;
122
+ const fitted = (rootWidth - 6 + blockMargin) / Math.max(dates.length, 1) - blockMargin;
123
+ const blockWidth = fits && rootWidth > 0 ? Math.max(MIN_FITTED_BAR, fitted) : blockSize * (blockAspectRatioProp ?? DEFAULT_ASPECT_RATIO);
124
+ const blockAspectRatio = blockWidth / blockSize;
117
125
  const width = dates.length * (blockWidth + blockMargin) - blockMargin;
118
126
  const height = blockSize;
119
127
  const contextValue = useMemo(() => ({
@@ -155,8 +163,9 @@ const StatusHeatmap = ({ data, dateFormat = "MMM d", blockSize = 40, blockMargin
155
163
  return /* @__PURE__ */ jsx(StatusHeatmapContext, {
156
164
  value: contextValue,
157
165
  children: /* @__PURE__ */ jsx("div", {
166
+ ref: rootRef,
158
167
  "data-slot": "status-heatmap",
159
- className: cn("flex w-max max-w-full flex-col gap-2", className),
168
+ className: cn("flex flex-col gap-2", fits ? "w-full" : "w-max max-w-full", className),
160
169
  style: {
161
170
  fontSize,
162
171
  ...style
@@ -166,7 +175,7 @@ const StatusHeatmap = ({ data, dateFormat = "MMM d", blockSize = 40, blockMargin
166
175
  })
167
176
  });
168
177
  };
169
- const StatusHeatmapBlock = ({ ref, activity, dayIndex, highlighted = false, onCellClick, onCellHover, onClick, onKeyDown, onMouseEnter, onMouseLeave, className, style: styleProp, ...props }) => {
178
+ const StatusHeatmapBlock = ({ ref, activity, dayIndex, highlighted = false, selected = false, onCellClick, onCellHover, onClick, onKeyDown, onMouseEnter, onMouseLeave, className, style: styleProp, ...props }) => {
170
179
  const { blockSize, blockWidth, blockMargin, blockRadius, labels, colors } = useStatusHeatmap();
171
180
  const statusText = resolveStatusLabel(activity.value, labels.statuses);
172
181
  const ariaLabel = (labels.cellLabel ?? "{{date}}: {{status}}").replace("{{date}}", activity.date).replace("{{status}}", statusText);
@@ -175,12 +184,14 @@ const StatusHeatmapBlock = ({ ref, activity, dayIndex, highlighted = false, onCe
175
184
  ref,
176
185
  "data-slot": "status-heatmap-block",
177
186
  role: onCellClick ? "button" : "img",
187
+ "aria-pressed": onCellClick ? selected : void 0,
178
188
  tabIndex: onCellClick ? 0 : -1,
179
189
  "aria-label": ariaLabel,
180
190
  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),
181
191
  "data-value": activity.value,
182
192
  "data-date": activity.date,
183
193
  "data-highlighted": highlighted || void 0,
194
+ "data-selected": selected || void 0,
184
195
  height: blockSize,
185
196
  rx: blockRadius,
186
197
  ry: blockRadius,
@@ -189,6 +200,10 @@ const StatusHeatmapBlock = ({ ref, activity, dayIndex, highlighted = false, onCe
189
200
  y: 0,
190
201
  style: {
191
202
  fill: getStatusFill(activity.value, colors, highlighted),
203
+ ...selected ? {
204
+ stroke: "var(--foreground)",
205
+ strokeWidth: 2
206
+ } : {},
192
207
  ...styleProp
193
208
  },
194
209
  onClick: (event) => {
@@ -247,9 +262,9 @@ const StatusHeatmapBody = ({ hideDateLabels = false, labelInterval = 30, classNa
247
262
  role: "img",
248
263
  "aria-label": labels.heatmapLabel ?? "Status heatmap",
249
264
  className: "block overflow-visible rounded-sm focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring",
250
- height: height + labelHeight + 40,
251
- viewBox: `-20 -20 ${width + 40} ${height + labelHeight + 40}`,
252
- width: width + 40,
265
+ height: height + labelHeight + 6,
266
+ viewBox: `-3 -3 ${width + 6} ${height + labelHeight + 6}`,
267
+ width: width + 6,
253
268
  children: [!hideDateLabels && /* @__PURE__ */ jsx("g", {
254
269
  className: cn("fill-current font-mono", labelClassName),
255
270
  children: dates.map((date, dayIndex) => {
@@ -299,7 +314,7 @@ const StatusHeatmapStat = ({ compute, label, className, children, ...props }) =>
299
314
  });
300
315
  };
301
316
  const StatusHeatmapLegend = ({ labels: labelsProp, className, children, ...props }) => {
302
- const { labels, statusValues, blockSize, blockWidth, blockRadius, colors } = useStatusHeatmap();
317
+ const { labels, statusValues, blockRadius, colors } = useStatusHeatmap();
303
318
  const statuses = statusValues.map((value) => ({
304
319
  value,
305
320
  label: resolveStatusLabel(value, labelsProp ?? labels.statuses)
@@ -307,7 +322,7 @@ const StatusHeatmapLegend = ({ labels: labelsProp, className, children, ...props
307
322
  return /* @__PURE__ */ jsx("fieldset", {
308
323
  "data-slot": "status-heatmap-legend",
309
324
  "aria-label": labels.legendLabel ?? "Status legend",
310
- className: cn("ml-auto flex items-center gap-1", className),
325
+ className: cn("ml-auto flex items-center gap-3", className),
311
326
  ...props,
312
327
  children: statuses.map((status) => children ? /* @__PURE__ */ jsx(Fragment$1, { children: children({
313
328
  value: status.value,
@@ -316,14 +331,14 @@ const StatusHeatmapLegend = ({ labels: labelsProp, className, children, ...props
316
331
  className: "flex items-center gap-1",
317
332
  children: [/* @__PURE__ */ jsx("svg", {
318
333
  "aria-hidden": "true",
319
- height: blockSize / 2,
320
- width: blockWidth,
334
+ height: LEGEND_SWATCH,
335
+ width: LEGEND_SWATCH,
321
336
  children: /* @__PURE__ */ jsx("rect", {
322
337
  "data-value": status.value,
323
- height: blockSize / 2,
338
+ height: LEGEND_SWATCH,
324
339
  rx: blockRadius,
325
340
  ry: blockRadius,
326
- width: blockWidth,
341
+ width: LEGEND_SWATCH,
327
342
  style: { fill: getStatusFill(status.value, colors) }
328
343
  })
329
344
  }), /* @__PURE__ */ jsx("span", {
@@ -90,8 +90,10 @@ export type WeekdayHeatmapProps = HTMLAttributes<HTMLDivElement> & {
90
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`.
91
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`.
92
92
  */
93
- export declare const WeekdayHeatmap: ({ data, weekStart, hours, weekdays: displayedWeekdays, use12Hour, blockSize, blockMargin, blockRadius, blockAspectRatio, levels: levelsProp, isNormalized, colors, locale, labels: labelsProp, fontSize, emptyState, totalCount: totalCountProp, extraRow, extraColumn, style, className, children, ...props }: WeekdayHeatmapProps) => string | number | bigint | true | import("react").JSX.Element | Iterable<ReactNode> | Promise<string | number | bigint | boolean | Iterable<ReactNode> | import("react").ReactElement<unknown, string | import("react").JSXElementConstructor<any>> | import("react").ReactPortal | null | undefined> | null;
93
+ export declare const WeekdayHeatmap: ({ data, weekStart, hours, weekdays: displayedWeekdays, use12Hour, blockSize: blockSizeProp, blockMargin, blockRadius, blockAspectRatio, levels: levelsProp, isNormalized, colors, locale, labels: labelsProp, fontSize, emptyState, totalCount: totalCountProp, extraRow, extraColumn, style, className, children, ...props }: WeekdayHeatmapProps) => string | number | bigint | true | import("react").JSX.Element | Iterable<ReactNode> | Promise<string | number | bigint | boolean | Iterable<ReactNode> | import("react").ReactElement<unknown, string | import("react").JSXElementConstructor<any>> | import("react").ReactPortal | null | undefined> | null;
94
94
  export type WeekdayHeatmapBlockProps = HTMLAttributes<SVGRectElement> & {
95
+ /** The cell the page has picked: drawn with a ring and announced as pressed. */
96
+ selected?: boolean;
95
97
  activity: WeekdayHourlyActivityWithLevel;
96
98
  extra?: "row" | "column";
97
99
  highlighted?: boolean;
@@ -99,7 +101,7 @@ export type WeekdayHeatmapBlockProps = HTMLAttributes<SVGRectElement> & {
99
101
  onCellHover?: (activity: WeekdayHourlyActivityWithLevel | null) => void;
100
102
  className?: string;
101
103
  };
102
- export declare function WeekdayHeatmapBlock({ ref, activity, extra, highlighted, onCellClick, onCellHover, onClick, onKeyDown, onMouseEnter, onMouseLeave, className, style: styleProp, ...props }: WeekdayHeatmapBlockProps & {
104
+ export declare function WeekdayHeatmapBlock({ ref, activity, extra, highlighted, selected, onCellClick, onCellHover, onClick, onKeyDown, onMouseEnter, onMouseLeave, className, style: styleProp, ...props }: WeekdayHeatmapBlockProps & {
103
105
  ref?: React.RefObject<SVGRectElement | null>;
104
106
  }): import("react").JSX.Element | null;
105
107
  export declare namespace WeekdayHeatmapBlock {
@@ -1,5 +1,6 @@
1
1
  import { cn } from "../../../lib/utils.js";
2
2
  import { useHeatmapNavigation } from "../../../lib/heatmap-navigation.js";
3
+ import { useElementWidth } from "../../../lib/use-element-width.js";
3
4
  import { Fragment, jsx, jsxs } from "react/jsx-runtime";
4
5
  import { Fragment as Fragment$1, createContext, use, useMemo } from "react";
5
6
  import { format } from "date-fns";
@@ -48,6 +49,10 @@ const generateWeekdayLabels = (locale) => Array.from({ length: 7 }, (_, i) => {
48
49
  });
49
50
  const EMPTY_STYLE = {};
50
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;
51
56
  const WeekdayHeatmapContext = createContext(null);
52
57
  const useWeekdayHeatmap = () => {
53
58
  const context = use(WeekdayHeatmapContext);
@@ -85,8 +90,9 @@ const useWeekdayHeatmap = () => {
85
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`.
86
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`.
87
92
  */
88
- const WeekdayHeatmap = ({ data, weekStart = 0, hours = HOURS, weekdays: displayedWeekdays, 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 }) => {
89
94
  const levels = Math.max(1, levelsProp);
95
+ const [rootRef, rootWidth] = useElementWidth();
90
96
  const weekdays = useMemo(() => displayedWeekdays ?? Array.from({ length: 7 }, (_, i) => (weekStart + i) % 7), [displayedWeekdays, weekStart]);
91
97
  const dataWithLevels = useMemo(() => {
92
98
  if (data.length === 0) return [];
@@ -159,9 +165,12 @@ const WeekdayHeatmap = ({ data, weekStart = 0, hours = HOURS, weekdays: displaye
159
165
  ]);
160
166
  const labelWidth = fontSize * 3.5 + LABEL_MARGIN;
161
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);
162
172
  const blockWidth = blockSize * blockAspectRatio;
163
173
  const labelHeight = fontSize + LABEL_MARGIN;
164
- const hasExtraColumn = resolvedExtraColumn !== null;
165
174
  const hasExtraRow = resolvedExtraRow !== null;
166
175
  const width = hours.length * (blockWidth + blockMargin) + (hasExtraColumn ? blockSize / 2 + (blockWidth + blockMargin) * 2 : 0) - blockMargin + labelWidth;
167
176
  const rowCount = weekdays.length + (hasExtraRow ? 1 : 0);
@@ -216,8 +225,9 @@ const WeekdayHeatmap = ({ data, weekStart = 0, hours = HOURS, weekdays: displaye
216
225
  return /* @__PURE__ */ jsx(WeekdayHeatmapContext, {
217
226
  value: contextValue,
218
227
  children: /* @__PURE__ */ jsx("div", {
228
+ ref: rootRef,
219
229
  "data-slot": "weekday-heatmap",
220
- className: cn("flex w-max max-w-full flex-col gap-2", className),
230
+ className: cn("flex flex-col gap-2", blockSizeProp === void 0 ? "w-full" : "w-max max-w-full", className),
221
231
  style: {
222
232
  fontSize,
223
233
  ...style
@@ -227,7 +237,7 @@ const WeekdayHeatmap = ({ data, weekStart = 0, hours = HOURS, weekdays: displaye
227
237
  })
228
238
  });
229
239
  };
230
- const WeekdayHeatmapBlock = ({ ref, activity, extra, highlighted = false, onCellClick, onCellHover, onClick, onKeyDown, onMouseEnter, onMouseLeave, className, style: styleProp, ...props }) => {
240
+ const WeekdayHeatmapBlock = ({ ref, activity, extra, highlighted = false, selected = false, onCellClick, onCellHover, onClick, onKeyDown, onMouseEnter, onMouseLeave, className, style: styleProp, ...props }) => {
231
241
  const { blockSize, blockWidth, blockMargin, blockRadius, labelWidth, labelHeight, levels, isNormalized, hours, weekdays, labels, colors } = useWeekdayHeatmap();
232
242
  const level = Math.max(0, Math.min(colorStepCount(levels, isNormalized), activity.level));
233
243
  const isExtraRow = extra === "row";
@@ -246,6 +256,7 @@ const WeekdayHeatmapBlock = ({ ref, activity, extra, highlighted = false, onCell
246
256
  ref,
247
257
  "data-slot": "weekday-heatmap-block",
248
258
  role: onCellClick ? "button" : "img",
259
+ "aria-pressed": onCellClick ? selected : void 0,
249
260
  tabIndex: onCellClick ? 0 : -1,
250
261
  "aria-label": ariaLabel,
251
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),
@@ -254,6 +265,7 @@ const WeekdayHeatmapBlock = ({ ref, activity, extra, highlighted = false, onCell
254
265
  "data-hour": isExtraColumn ? "extra" : activity.hour,
255
266
  "data-level": level,
256
267
  "data-highlighted": highlighted || void 0,
268
+ "data-selected": selected || void 0,
257
269
  height: blockSize,
258
270
  rx: blockRadius,
259
271
  ry: blockRadius,
@@ -262,6 +274,10 @@ const WeekdayHeatmapBlock = ({ ref, activity, extra, highlighted = false, onCell
262
274
  y: yPosition,
263
275
  style: {
264
276
  fill: getLevelFill(level, levels, isNormalized, highlighted, colors),
277
+ ...selected ? {
278
+ stroke: "var(--foreground)",
279
+ strokeWidth: 2
280
+ } : {},
265
281
  ...styleProp
266
282
  },
267
283
  onClick: (event) => {
@@ -374,9 +390,9 @@ const WeekdayHeatmapBody = ({ hideHourLabels = false, hideWeekdayLabels = false,
374
390
  role: "img",
375
391
  "aria-label": labels.heatmapLabel ?? "Activity heatmap by weekday and hour",
376
392
  className: "block overflow-visible rounded-sm focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring",
377
- height: svgHeight + 40,
378
- viewBox: `-20 -20 ${svgWidth + 40} ${svgHeight + 40}`,
379
- width: svgWidth + 40,
393
+ height: svgHeight + 24,
394
+ viewBox: `-12 -12 ${svgWidth + 24} ${svgHeight + 24}`,
395
+ width: svgWidth + 24,
380
396
  children: [
381
397
  !hideHourLabels && /* @__PURE__ */ jsxs("g", {
382
398
  className: cn("fill-current font-mono", labelClassName),
@@ -469,7 +485,7 @@ const WeekdayHeatmapStat = ({ compute, label, className, children, ...props }) =
469
485
  });
470
486
  };
471
487
  const WeekdayHeatmapLegend = ({ labels: labelsProp, className, children, ...props }) => {
472
- const { levels, isNormalized, blockSize, blockWidth, blockRadius, colors, labels } = useWeekdayHeatmap();
488
+ const { levels, isNormalized, blockRadius, colors, labels } = useWeekdayHeatmap();
473
489
  const lessLabel = labelsProp?.less ?? "Less";
474
490
  const moreLabel = labelsProp?.more ?? "More";
475
491
  const legendLevels = Array.from({ length: levels }, (_, i) => isNormalized ? i + 1 : i);
@@ -486,14 +502,14 @@ const WeekdayHeatmapLegend = ({ labels: labelsProp, className, children, ...prop
486
502
  legendLevels.map((level) => children ? /* @__PURE__ */ jsx(Fragment$1, { children: children({ level }) }, `legend-level-${level}`) : /* @__PURE__ */ jsx("svg", {
487
503
  role: "img",
488
504
  "aria-label": (labels.legendLevelLabel ?? "{{level}} contributions").replace("{{level}}", String(level)),
489
- height: blockSize,
490
- width: blockWidth,
505
+ height: LEGEND_SWATCH,
506
+ width: LEGEND_SWATCH,
491
507
  children: /* @__PURE__ */ jsx("rect", {
492
508
  "data-level": level,
493
- height: blockSize,
509
+ height: LEGEND_SWATCH,
494
510
  rx: blockRadius,
495
511
  ry: blockRadius,
496
- width: blockWidth,
512
+ width: LEGEND_SWATCH,
497
513
  style: { fill: getLevelFill(level, levels, isNormalized, false, colors) }
498
514
  })
499
515
  }, `legend-level-${level}`)),
@@ -93,6 +93,11 @@ type DataTableContextProps<TData extends RowData> = DataTableContextState & {
93
93
  scrollContainer: HTMLElement | null;
94
94
  /** True below 40rem of table space; use for compact toolbar and record layouts. */
95
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;
96
101
  /** Internal: `<DataTable>` registers its scroll container element here. */
97
102
  registerScrollContainer: (el: HTMLElement | null) => void;
98
103
  /**
@@ -148,12 +153,22 @@ export declare enum DataTableActions {
148
153
  SET = 0,
149
154
  SET_IS_LOADING = 1
150
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
+ }
151
163
  interface DataTableProviderProps<TData extends RowData> {
152
164
  children: React.ReactNode;
153
165
  table: DataTableInstance<TData>;
154
166
  columns?: DataTableColumnDef<TData>[];
155
167
  isLoading?: boolean;
168
+ isCompact: boolean;
169
+ onWidthChange: (width: number) => void;
170
+ compactColumns: CompactColumns | null;
156
171
  }
157
- 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;
158
173
  //#endregion
159
174
  export { DataTableContext };