@siyahi/ui 0.1.9-next.3 → 0.1.9-next.31
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/DESIGN.md +251 -0
- package/README.md +94 -177
- package/THIRD_PARTY_NOTICES.md +11 -11
- package/agents/examples/accordion.tsx +39 -0
- package/agents/examples/alert.tsx +24 -0
- package/agents/examples/app-sidebar.tsx +40 -0
- package/agents/examples/avatar.tsx +24 -0
- package/agents/examples/badge.tsx +26 -0
- package/agents/examples/bar-list-labels.tsx +22 -0
- package/agents/examples/bar-list-sides.tsx +40 -0
- package/agents/examples/bar-list.tsx +24 -0
- package/agents/examples/breadcrumb.tsx +28 -0
- package/agents/examples/button-states.tsx +23 -0
- package/agents/examples/button.tsx +21 -0
- package/agents/examples/calendar.tsx +11 -0
- package/agents/examples/callout.tsx +33 -0
- package/agents/examples/card.tsx +36 -0
- package/agents/examples/change-bar.tsx +104 -0
- package/agents/examples/change-grid-money.tsx +36 -0
- package/agents/examples/change-grid.tsx +43 -0
- package/agents/examples/chart-area-log.tsx +45 -0
- package/agents/examples/chart-area.tsx +39 -0
- package/agents/examples/chart-bar-flows.tsx +32 -0
- package/agents/examples/chart-bar-hourly.tsx +28 -0
- package/agents/examples/chart-bar-losses.tsx +29 -0
- package/agents/examples/chart-bar-teams.tsx +72 -0
- package/agents/examples/chart-bar-years.tsx +42 -0
- package/agents/examples/chart-bar.tsx +56 -0
- package/agents/examples/chart-category-ticks.tsx +50 -0
- package/agents/examples/chart-line-events.tsx +47 -0
- package/agents/examples/chart-line-forecast.tsx +36 -0
- package/agents/examples/chart-line-log.tsx +39 -0
- package/agents/examples/chart-line-quiet.tsx +114 -0
- package/agents/examples/chart-line-timeline.tsx +41 -0
- package/agents/examples/chart-line.tsx +57 -0
- package/agents/examples/chart-panels.tsx +94 -0
- package/agents/examples/code-block.tsx +40 -0
- package/agents/examples/collapsible.tsx +18 -0
- package/agents/examples/command.tsx +29 -0
- package/agents/examples/context-menu.tsx +17 -0
- package/agents/examples/copy-button.tsx +8 -0
- package/agents/examples/data-bar.tsx +114 -0
- package/agents/examples/data-table-compact.tsx +93 -0
- package/agents/examples/data-table-filters.tsx +103 -0
- package/agents/examples/data-table.tsx +96 -0
- package/agents/examples/delta.tsx +18 -0
- package/agents/examples/dialog.tsx +28 -0
- package/agents/examples/distribution-bar-budget.tsx +30 -0
- package/agents/examples/distribution-bar-tug.tsx +74 -0
- package/agents/examples/drawdown-chart.tsx +35 -0
- package/agents/examples/dropdown-menu.tsx +31 -0
- package/agents/examples/field.tsx +108 -0
- package/agents/examples/formatters.tsx +42 -0
- package/agents/examples/heatmap-calendar-signed.tsx +67 -0
- package/agents/examples/heatmap-calendar.tsx +62 -0
- package/agents/examples/heatmap-status.tsx +61 -0
- package/agents/examples/heatmap-weekday.tsx +72 -0
- package/agents/examples/histogram-chart.tsx +28 -0
- package/agents/examples/input-states.tsx +23 -0
- package/agents/examples/input.tsx +17 -0
- package/agents/examples/local-time.tsx +14 -0
- package/agents/examples/metric-strip.tsx +46 -0
- package/agents/examples/overview-dashboard.tsx +180 -0
- package/agents/examples/page-hero.tsx +38 -0
- package/agents/examples/page-section.tsx +52 -0
- package/agents/examples/popover.tsx +23 -0
- package/agents/examples/price-chart.tsx +32 -0
- package/agents/examples/progress-tone.tsx +29 -0
- package/agents/examples/progress.tsx +10 -0
- package/agents/examples/range-position-table.tsx +113 -0
- package/agents/examples/range-position.tsx +55 -0
- package/agents/examples/scatter-chart-quadrants.tsx +63 -0
- package/agents/examples/scatter-chart-scales.tsx +46 -0
- package/agents/examples/scatter-chart.tsx +78 -0
- package/agents/examples/scroll-area.tsx +22 -0
- package/agents/examples/section-cards-select.tsx +28 -0
- package/agents/examples/section-cards-trend.tsx +32 -0
- package/agents/examples/section-cards.tsx +48 -0
- package/agents/examples/select.tsx +27 -0
- package/agents/examples/separator.tsx +13 -0
- package/agents/examples/sheet.tsx +15 -0
- package/agents/examples/skeleton.tsx +11 -0
- package/agents/examples/slider.tsx +5 -0
- package/agents/examples/slope-chart-market.tsx +33 -0
- package/agents/examples/slope-chart.tsx +26 -0
- package/agents/examples/stale-blocks.tsx +56 -0
- package/agents/examples/surfaces.tsx +116 -0
- package/agents/examples/table.tsx +60 -0
- package/agents/examples/tabs.tsx +16 -0
- package/agents/examples/target-rows.tsx +74 -0
- package/agents/examples/toggle-group.tsx +12 -0
- package/agents/examples/toggle.tsx +11 -0
- package/agents/examples/tooltip.tsx +13 -0
- package/agents/examples/treemap.tsx +93 -0
- package/agents/examples/waterfall-chart-stores.tsx +27 -0
- package/agents/examples/waterfall-chart.tsx +37 -0
- package/agents/manifest.json +1391 -0
- package/agents/report-rules.json +7 -0
- package/dist/components/registry/charts/area-chart-card.d.ts +7 -3
- package/dist/components/registry/charts/area-chart-card.js +56 -10
- package/dist/components/registry/charts/bar-chart-card.d.ts +1 -1
- package/dist/components/registry/charts/bar-chart-card.js +20 -22
- package/dist/components/registry/charts/line-chart-card.d.ts +3 -3
- package/dist/components/registry/charts/line-chart-card.js +44 -9
- package/dist/components/registry/dashboard-01/section-cards.d.ts +6 -0
- package/dist/components/registry/dashboard-01/section-cards.js +51 -35
- package/dist/components/registry/dashboardcn/bar-list.js +17 -10
- package/dist/components/registry/dashboardcn/distribution-bar.js +6 -4
- package/dist/components/registry/dashboardcn/kpi-row-card.d.ts +29 -0
- package/dist/components/registry/dashboardcn/kpi-row-card.js +81 -0
- package/dist/components/registry/dashboardcn/sparkline.d.ts +22 -0
- package/dist/components/registry/dashboardcn/sparkline.js +117 -0
- package/dist/components/registry/heatmap/calendar-heatmap.d.ts +11 -3
- package/dist/components/registry/heatmap/calendar-heatmap.js +164 -45
- package/dist/components/registry/heatmap/status-heatmap.d.ts +5 -3
- package/dist/components/registry/heatmap/status-heatmap.js +115 -54
- package/dist/components/registry/heatmap/weekday-heatmap.d.ts +9 -3
- package/dist/components/registry/heatmap/weekday-heatmap.js +83 -53
- package/dist/components/registry/niko-table/core/data-table-context.d.ts +18 -1
- package/dist/components/registry/niko-table/core/data-table-context.js +7 -1
- package/dist/components/registry/niko-table/core/data-table-grouped-row.js +3 -1
- package/dist/components/registry/niko-table/core/data-table-root.js +39 -4
- package/dist/components/registry/niko-table/core/data-table-structure.js +17 -12
- package/dist/components/registry/niko-table/core/data-table.d.ts +2 -2
- package/dist/components/registry/niko-table/core/data-table.js +5 -1
- package/dist/components/registry/niko-table/filters/table-faceted-filter.js +5 -5
- package/dist/components/registry/niko-table/filters/table-search-filter.js +1 -1
- package/dist/components/registry/niko-table/lib/flex-columns.d.ts +1 -1
- package/dist/components/registry/niko-table/lib/flex-columns.js +3 -3
- package/dist/components/registry/niko-table/lib/styles.d.ts +1 -1
- package/dist/components/registry/niko-table/lib/styles.js +3 -3
- package/dist/components/registry/niko-table/types/index.d.ts +9 -0
- package/dist/components/registry/niko-table/ui/table.js +2 -2
- package/dist/components/registry/sidebar-07/app-sidebar.d.ts +1 -1
- package/dist/components/registry/sidebar-07/app-sidebar.js +3 -1
- package/dist/components/registry/sidebar-07/nav-main.d.ts +2 -1
- package/dist/components/registry/sidebar-07/nav-main.js +16 -3
- package/dist/components/siyahi/callout.d.ts +17 -0
- package/dist/components/siyahi/callout.js +34 -0
- package/dist/components/siyahi/change-bar.d.ts +21 -0
- package/dist/components/siyahi/change-bar.js +35 -0
- package/dist/components/siyahi/change-grid.d.ts +31 -0
- package/dist/components/siyahi/change-grid.js +74 -0
- package/dist/components/siyahi/data-bar.d.ts +19 -0
- package/dist/components/siyahi/data-bar.js +29 -0
- package/dist/components/siyahi/data-table-compact-columns-toggle.d.ts +4 -0
- package/dist/components/siyahi/data-table-compact-columns-toggle.js +19 -0
- package/dist/components/siyahi/data-table-footnote.d.ts +12 -0
- package/dist/components/siyahi/data-table-footnote.js +35 -0
- package/dist/components/siyahi/default-sidebar-open.d.ts +8 -0
- package/dist/components/siyahi/default-sidebar-open.js +13 -0
- package/dist/components/siyahi/delta.d.ts +5 -1
- package/dist/components/siyahi/delta.js +14 -9
- package/dist/components/siyahi/drawdown-chart.d.ts +34 -0
- package/dist/components/siyahi/drawdown-chart.js +102 -0
- package/dist/components/siyahi/histogram-chart.d.ts +57 -0
- package/dist/components/siyahi/histogram-chart.js +134 -0
- package/dist/components/siyahi/page-hero.d.ts +23 -0
- package/dist/components/siyahi/page-hero.js +43 -0
- package/dist/components/siyahi/page-section.d.ts +4 -1
- package/dist/components/siyahi/page-section.js +6 -3
- package/dist/components/siyahi/page-toc.d.ts +20 -0
- package/dist/components/siyahi/page-toc.js +76 -0
- package/dist/components/siyahi/panel-grid.d.ts +24 -0
- package/dist/components/siyahi/panel-grid.js +37 -0
- package/dist/components/siyahi/quote.d.ts +12 -0
- package/dist/components/siyahi/quote.js +23 -0
- package/dist/components/siyahi/range-position.d.ts +24 -0
- package/dist/components/siyahi/range-position.js +105 -0
- package/dist/components/siyahi/scale-toggle.d.ts +32 -0
- package/dist/components/siyahi/scale-toggle.js +61 -0
- package/dist/components/siyahi/scatter-chart.d.ts +69 -0
- package/dist/components/siyahi/scatter-chart.js +395 -0
- package/dist/components/siyahi/siyahi-provider.d.ts +15 -2
- package/dist/components/siyahi/siyahi-provider.js +17 -4
- package/dist/components/siyahi/slope-chart.d.ts +35 -0
- package/dist/components/siyahi/slope-chart.js +159 -0
- package/dist/components/siyahi/stale-note.d.ts +9 -0
- package/dist/components/siyahi/stale-note.js +12 -0
- package/dist/components/siyahi/status-alert.d.ts +15 -0
- package/dist/components/siyahi/status-alert.js +29 -0
- package/dist/components/siyahi/status-badge.d.ts +15 -0
- package/dist/components/siyahi/status-badge.js +24 -0
- package/dist/components/siyahi/target-rows.d.ts +34 -0
- package/dist/components/siyahi/target-rows.js +97 -0
- package/dist/components/siyahi/tone-progress.d.ts +1 -1
- package/dist/components/siyahi/tone-progress.js +1 -1
- package/dist/components/siyahi/treemap.d.ts +8 -5
- package/dist/components/siyahi/treemap.js +80 -34
- package/dist/components/siyahi/waterfall-chart.d.ts +51 -0
- package/dist/components/siyahi/waterfall-chart.js +147 -0
- package/dist/components/ui/accordion.js +5 -5
- package/dist/components/ui/alert.js +2 -2
- package/dist/components/ui/badge.js +1 -1
- package/dist/components/ui/breadcrumb.js +2 -2
- package/dist/components/ui/button.js +10 -10
- package/dist/components/ui/calendar.js +1 -1
- package/dist/components/ui/card.js +4 -4
- package/dist/components/ui/chart.js +1 -1
- package/dist/components/ui/code-block.js +13 -12
- package/dist/components/ui/command.js +7 -6
- package/dist/components/ui/context-menu.js +7 -7
- package/dist/components/ui/dialog.js +5 -5
- package/dist/components/ui/dropdown-menu.js +8 -8
- package/dist/components/ui/field.d.ts +26 -0
- package/dist/components/ui/field.js +109 -0
- package/dist/components/ui/input-group.js +11 -11
- package/dist/components/ui/input.js +1 -1
- package/dist/components/ui/label.d.ts +5 -0
- package/dist/components/ui/label.js +13 -0
- package/dist/components/ui/popover.js +3 -3
- package/dist/components/ui/progress.js +1 -1
- package/dist/components/ui/select.js +6 -6
- package/dist/components/ui/sheet.js +5 -5
- package/dist/components/ui/sidebar.js +17 -18
- package/dist/components/ui/skeleton.js +1 -1
- package/dist/components/ui/slider.js +2 -2
- package/dist/components/ui/table.js +2 -2
- package/dist/components/ui/tabs.js +2 -2
- package/dist/components/ui/textarea.js +1 -1
- package/dist/components/ui/toggle-group.js +2 -2
- package/dist/components/ui/toggle.js +4 -4
- package/dist/components/ui/tooltip.js +2 -2
- package/dist/index.d.ts +35 -8
- package/dist/index.js +30 -4
- package/dist/lib/chart-frame.d.ts +51 -7
- package/dist/lib/chart-frame.js +390 -133
- package/dist/lib/chart-marks.d.ts +83 -0
- package/dist/lib/chart-marks.js +216 -0
- package/dist/lib/chart-series.d.ts +42 -10
- package/dist/lib/compact-columns.d.ts +19 -0
- package/dist/lib/compact-columns.js +55 -0
- package/dist/lib/fit-text.d.ts +6 -0
- package/dist/lib/fit-text.js +11 -0
- package/dist/lib/format.d.ts +8 -3
- package/dist/lib/format.js +55 -17
- package/dist/lib/heat.d.ts +7 -0
- package/dist/lib/heat.js +14 -0
- package/dist/lib/heatmap-navigation.d.ts +8 -0
- package/dist/lib/heatmap-navigation.js +49 -0
- package/dist/lib/scatter.d.ts +88 -0
- package/dist/lib/scatter.js +179 -0
- package/dist/lib/ticks.d.ts +27 -0
- package/dist/lib/ticks.js +67 -0
- package/dist/lib/tone.d.ts +36 -0
- package/dist/lib/tone.js +35 -0
- package/dist/lib/treemap.d.ts +0 -5
- package/dist/lib/treemap.js +1 -11
- package/dist/lib/use-element-width.d.ts +5 -0
- package/dist/lib/use-element-width.js +15 -0
- package/package.json +5 -1
- package/registry.lock.json +16 -0
- package/report.css +63 -47
- package/styles/siyahi.css +708 -55
|
@@ -1,4 +1,6 @@
|
|
|
1
1
|
import { cn } from "../../../lib/utils.js";
|
|
2
|
+
import { useElementWidth } from "../../../lib/use-element-width.js";
|
|
3
|
+
import { useHeatmapNavigation } from "../../../lib/heatmap-navigation.js";
|
|
2
4
|
import { Fragment, jsx, jsxs } from "react/jsx-runtime";
|
|
3
5
|
import { Fragment as Fragment$1, createContext, use, useMemo } from "react";
|
|
4
6
|
import { format } from "date-fns";
|
|
@@ -16,13 +18,12 @@ const calculateLevel = (value, minValue, maxValue, levels, isNormalized) => {
|
|
|
16
18
|
const percentage = value / maxValue;
|
|
17
19
|
return Math.max(1, Math.min(steps, Math.ceil(percentage * steps)));
|
|
18
20
|
};
|
|
19
|
-
const getLevelFill = (level, levels, isNormalized,
|
|
21
|
+
const getLevelFill = (level, levels, isNormalized, colors) => {
|
|
20
22
|
const emptyColor = colors?.empty ?? "var(--color-secondary)";
|
|
21
23
|
const scaleColor = colors?.scale ?? "var(--color-chart-1)";
|
|
22
24
|
if (level === 0) return emptyColor;
|
|
23
25
|
const steps = colorStepCount(levels, isNormalized);
|
|
24
|
-
|
|
25
|
-
return `color-mix(in oklch, ${scaleColor} ${highlighted ? Math.round(opacity * .6) : opacity}%, transparent)`;
|
|
26
|
+
return `color-mix(in oklch, ${scaleColor} ${steps === 1 ? 100 : Math.round(20 + (level - 1) * 80 / (steps - 1))}%, transparent)`;
|
|
26
27
|
};
|
|
27
28
|
const DEFAULT_HOUR_LABELS = Array.from({ length: 24 }, (_, i) => i.toString().padStart(2, "0"));
|
|
28
29
|
const TWELVE_HOUR_LABELS = Array.from({ length: 24 }, (_, i) => {
|
|
@@ -47,6 +48,10 @@ const generateWeekdayLabels = (locale) => Array.from({ length: 7 }, (_, i) => {
|
|
|
47
48
|
});
|
|
48
49
|
const EMPTY_STYLE = {};
|
|
49
50
|
const LABEL_MARGIN = 8;
|
|
51
|
+
const LEGEND_SWATCH = 12;
|
|
52
|
+
const MIN_FITTED_BLOCK = 14;
|
|
53
|
+
const MAX_FITTED_BLOCK = 44;
|
|
54
|
+
const DEFAULT_BLOCK = 24;
|
|
50
55
|
const WeekdayHeatmapContext = createContext(null);
|
|
51
56
|
const useWeekdayHeatmap = () => {
|
|
52
57
|
const context = use(WeekdayHeatmapContext);
|
|
@@ -84,8 +89,10 @@ const useWeekdayHeatmap = () => {
|
|
|
84
89
|
* @param extraRow - Appends an aggregated row below the grid. `compute` receives all activities and must return 24 values (one per hour). Rendered through `renderExtraRow` on the body, or falls back to `children`.
|
|
85
90
|
* @param extraColumn - Appends an aggregated column to the right of the grid. `compute` receives all activities and must return 7 values indexed by weekday 0–6. Rendered through `renderExtraColumn` on the body, or falls back to `children`.
|
|
86
91
|
*/
|
|
87
|
-
const WeekdayHeatmap = ({ data, weekStart = 0, use12Hour = false, blockSize
|
|
92
|
+
const WeekdayHeatmap = ({ data, weekStart = 0, hours = HOURS, weekdays: displayedWeekdays, use12Hour = false, blockSize: blockSizeProp, blockMargin = 4, blockRadius = 2, blockAspectRatio = 1, levels: levelsProp = 5, isNormalized = false, colors, locale, labels: labelsProp, fontSize = 14, emptyState, totalCount: totalCountProp, extraRow, extraColumn, style = EMPTY_STYLE, className, children, ...props }) => {
|
|
88
93
|
const levels = Math.max(1, levelsProp);
|
|
94
|
+
const [rootRef, rootWidth] = useElementWidth();
|
|
95
|
+
const weekdays = useMemo(() => displayedWeekdays ?? Array.from({ length: 7 }, (_, i) => (weekStart + i) % 7), [displayedWeekdays, weekStart]);
|
|
89
96
|
const dataWithLevels = useMemo(() => {
|
|
90
97
|
if (data.length === 0) return [];
|
|
91
98
|
const maxRegular = data.reduce((m, d) => Math.max(m, d.value), 1);
|
|
@@ -141,7 +148,7 @@ const WeekdayHeatmap = ({ data, weekStart = 0, use12Hour = false, blockSize = 24
|
|
|
141
148
|
const weekdayLabels = locale ? generateWeekdayLabels(locale) : DEFAULT_WEEKDAY_LABELS;
|
|
142
149
|
return {
|
|
143
150
|
hours: use12Hour ? TWELVE_HOUR_LABELS : DEFAULT_HOUR_LABELS,
|
|
144
|
-
endHour: use12Hour ? "12" : "00",
|
|
151
|
+
endHour: hours.at(-1) === 23 ? use12Hour ? "12" : "00" : (use12Hour ? TWELVE_HOUR_LABELS : DEFAULT_HOUR_LABELS)[(hours.at(-1) ?? -1) + 1],
|
|
145
152
|
weekdays: weekdayLabels,
|
|
146
153
|
cellLabel: "{{weekday}} {{hour}}: {{value}}",
|
|
147
154
|
heatmapLabel: "Activity heatmap by weekday and hour",
|
|
@@ -152,16 +159,20 @@ const WeekdayHeatmap = ({ data, weekStart = 0, use12Hour = false, blockSize = 24
|
|
|
152
159
|
}, [
|
|
153
160
|
locale,
|
|
154
161
|
use12Hour,
|
|
155
|
-
labelsProp
|
|
162
|
+
labelsProp,
|
|
163
|
+
hours
|
|
156
164
|
]);
|
|
157
165
|
const labelWidth = fontSize * 3.5 + LABEL_MARGIN;
|
|
158
166
|
const totalCount = typeof totalCountProp === "number" ? totalCountProp : dataWithLevels.reduce((sum, a) => sum + a.value, 0);
|
|
167
|
+
const hasExtraColumn = resolvedExtraColumn !== null;
|
|
168
|
+
const columns = hours.length + (hasExtraColumn ? 2 : 0);
|
|
169
|
+
const fitted = (rootWidth - 24 - labelWidth - columns * blockMargin + (hasExtraColumn ? 0 : blockMargin)) / (columns + (hasExtraColumn ? 1 / (2 * blockAspectRatio) : 0));
|
|
170
|
+
const blockSize = blockSizeProp ?? (rootWidth > 0 ? Math.min(MAX_FITTED_BLOCK, Math.max(MIN_FITTED_BLOCK, fitted)) / blockAspectRatio : DEFAULT_BLOCK);
|
|
159
171
|
const blockWidth = blockSize * blockAspectRatio;
|
|
160
172
|
const labelHeight = fontSize + LABEL_MARGIN;
|
|
161
|
-
const hasExtraColumn = resolvedExtraColumn !== null;
|
|
162
173
|
const hasExtraRow = resolvedExtraRow !== null;
|
|
163
|
-
const width =
|
|
164
|
-
const rowCount = hasExtraRow ?
|
|
174
|
+
const width = hours.length * (blockWidth + blockMargin) + (hasExtraColumn ? blockSize / 2 + (blockWidth + blockMargin) * 2 : 0) - blockMargin + labelWidth;
|
|
175
|
+
const rowCount = weekdays.length + (hasExtraRow ? 1 : 0);
|
|
165
176
|
const extraRowGap = hasExtraRow ? blockSize + blockMargin : 0;
|
|
166
177
|
const height = rowCount * (blockSize + blockMargin) + extraRowGap - blockMargin + labelHeight;
|
|
167
178
|
const contextValue = useMemo(() => ({
|
|
@@ -183,6 +194,8 @@ const WeekdayHeatmap = ({ data, weekStart = 0, use12Hour = false, blockSize = 24
|
|
|
183
194
|
width,
|
|
184
195
|
height,
|
|
185
196
|
weekStart,
|
|
197
|
+
hours,
|
|
198
|
+
weekdays,
|
|
186
199
|
colors
|
|
187
200
|
}), [
|
|
188
201
|
dataWithLevels,
|
|
@@ -203,14 +216,17 @@ const WeekdayHeatmap = ({ data, weekStart = 0, use12Hour = false, blockSize = 24
|
|
|
203
216
|
width,
|
|
204
217
|
height,
|
|
205
218
|
weekStart,
|
|
219
|
+
hours,
|
|
220
|
+
weekdays,
|
|
206
221
|
colors
|
|
207
222
|
]);
|
|
208
223
|
if (data.length === 0) return emptyState ? emptyState : null;
|
|
209
224
|
return /* @__PURE__ */ jsx(WeekdayHeatmapContext, {
|
|
210
225
|
value: contextValue,
|
|
211
226
|
children: /* @__PURE__ */ jsx("div", {
|
|
227
|
+
ref: rootRef,
|
|
212
228
|
"data-slot": "weekday-heatmap",
|
|
213
|
-
className: cn("flex
|
|
229
|
+
className: cn("flex flex-col gap-2", blockSizeProp === void 0 ? "w-full" : "w-max max-w-full", className),
|
|
214
230
|
style: {
|
|
215
231
|
fontSize,
|
|
216
232
|
...style
|
|
@@ -220,16 +236,18 @@ const WeekdayHeatmap = ({ data, weekStart = 0, use12Hour = false, blockSize = 24
|
|
|
220
236
|
})
|
|
221
237
|
});
|
|
222
238
|
};
|
|
223
|
-
const WeekdayHeatmapBlock = ({ ref, activity, extra, highlighted = false, onCellClick, onCellHover, onClick, onKeyDown, onMouseEnter, onMouseLeave, className, style: styleProp, ...props }) => {
|
|
224
|
-
const { blockSize, blockWidth, blockMargin, blockRadius, labelWidth, labelHeight, levels, isNormalized,
|
|
239
|
+
const WeekdayHeatmapBlock = ({ ref, activity, extra, highlighted = false, selected = false, onCellClick, onCellHover, onClick, onKeyDown, onMouseEnter, onMouseLeave, className, style: styleProp, ...props }) => {
|
|
240
|
+
const { blockSize, blockWidth, blockMargin, blockRadius, labelWidth, labelHeight, levels, isNormalized, hours, weekdays, labels, colors } = useWeekdayHeatmap();
|
|
225
241
|
const level = Math.max(0, Math.min(colorStepCount(levels, isNormalized), activity.level));
|
|
226
242
|
const isExtraRow = extra === "row";
|
|
227
243
|
const isExtraColumn = extra === "column";
|
|
228
|
-
const rowIndex = isExtraRow ?
|
|
244
|
+
const rowIndex = isExtraRow ? weekdays.length : weekdays.findIndex((day) => day === activity.weekday);
|
|
245
|
+
const hourIndex = isExtraColumn ? hours.length : hours.findIndex((hour) => hour === activity.hour);
|
|
246
|
+
if (rowIndex < 0 || hourIndex < 0) return null;
|
|
229
247
|
const extraRowGap = isExtraRow ? blockSize + blockMargin : 0;
|
|
230
248
|
const yPosition = labelHeight + (blockSize + blockMargin) * rowIndex + extraRowGap;
|
|
231
249
|
const extraColumnGap = isExtraColumn ? blockWidth + blockMargin : 0;
|
|
232
|
-
const xPosition = isExtraColumn ? labelWidth +
|
|
250
|
+
const xPosition = isExtraColumn ? labelWidth + hours.length * (blockWidth + blockMargin) + blockSize / 2 + extraColumnGap : labelWidth + (blockWidth + blockMargin) * hourIndex;
|
|
233
251
|
const weekdayToken = isExtraRow ? "extra" : labels.weekdays?.[activity.weekday] ?? String(activity.weekday);
|
|
234
252
|
const hourToken = isExtraColumn ? "extra" : `${String(activity.hour).padStart(2, "0")}:00`;
|
|
235
253
|
const ariaLabel = (labels.cellLabel ?? "{{weekday}} {{hour}}: {{value}}").replace("{{weekday}}", weekdayToken).replace("{{hour}}", hourToken).replace("{{value}}", String(activity.value));
|
|
@@ -237,14 +255,16 @@ const WeekdayHeatmapBlock = ({ ref, activity, extra, highlighted = false, onCell
|
|
|
237
255
|
ref,
|
|
238
256
|
"data-slot": "weekday-heatmap-block",
|
|
239
257
|
role: onCellClick ? "button" : "img",
|
|
258
|
+
"aria-pressed": onCellClick ? selected : void 0,
|
|
240
259
|
tabIndex: onCellClick ? 0 : -1,
|
|
241
260
|
"aria-label": ariaLabel,
|
|
242
|
-
className: cn("
|
|
261
|
+
className: cn("hover:stroke-foreground hover:stroke-1", highlighted && "stroke-foreground stroke-1", selected && "stroke-foreground stroke-2 hover:stroke-2", onCellClick && "cursor-pointer", className),
|
|
243
262
|
"data-value": activity.value,
|
|
244
263
|
"data-weekday": isExtraRow ? "extra" : activity.weekday,
|
|
245
264
|
"data-hour": isExtraColumn ? "extra" : activity.hour,
|
|
246
265
|
"data-level": level,
|
|
247
266
|
"data-highlighted": highlighted || void 0,
|
|
267
|
+
"data-selected": selected || void 0,
|
|
248
268
|
height: blockSize,
|
|
249
269
|
rx: blockRadius,
|
|
250
270
|
ry: blockRadius,
|
|
@@ -252,7 +272,7 @@ const WeekdayHeatmapBlock = ({ ref, activity, extra, highlighted = false, onCell
|
|
|
252
272
|
x: xPosition,
|
|
253
273
|
y: yPosition,
|
|
254
274
|
style: {
|
|
255
|
-
fill: getLevelFill(level, levels, isNormalized,
|
|
275
|
+
fill: getLevelFill(level, levels, isNormalized, colors),
|
|
256
276
|
...styleProp
|
|
257
277
|
},
|
|
258
278
|
onClick: (event) => {
|
|
@@ -279,7 +299,8 @@ const WeekdayHeatmapBlock = ({ ref, activity, extra, highlighted = false, onCell
|
|
|
279
299
|
};
|
|
280
300
|
WeekdayHeatmapBlock.displayName = "WeekdayHeatmapBlock";
|
|
281
301
|
const WeekdayHeatmapBody = ({ hideHourLabels = false, hideWeekdayLabels = false, className, labelClassName, children, renderExtraRow, renderExtraColumn, ...props }) => {
|
|
282
|
-
const
|
|
302
|
+
const navigation = useHeatmapNavigation();
|
|
303
|
+
const { data, extraRow, extraColumn, blockSize, blockWidth, blockMargin, labels, labelWidth, labelHeight, fontSize, hours, weekdays } = useWeekdayHeatmap();
|
|
283
304
|
const hasExtraRow = extraRow !== null;
|
|
284
305
|
const hasExtraColumn = extraColumn !== null;
|
|
285
306
|
const activityMap = useMemo(() => {
|
|
@@ -299,24 +320,24 @@ const WeekdayHeatmapBody = ({ hideHourLabels = false, hideWeekdayLabels = false,
|
|
|
299
320
|
}, [extraColumn]);
|
|
300
321
|
const regularActivities = useMemo(() => {
|
|
301
322
|
const activities = [];
|
|
302
|
-
for (
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
weekdayIndex: di
|
|
312
|
-
});
|
|
313
|
-
}
|
|
323
|
+
for (const [di, weekday] of weekdays.entries()) for (const hour of hours) activities.push({
|
|
324
|
+
activity: activityMap.get(`${weekday}-${hour}`) ?? {
|
|
325
|
+
weekday,
|
|
326
|
+
hour,
|
|
327
|
+
value: 0,
|
|
328
|
+
level: 0
|
|
329
|
+
},
|
|
330
|
+
weekdayIndex: di
|
|
331
|
+
});
|
|
314
332
|
return activities;
|
|
315
|
-
}, [
|
|
333
|
+
}, [
|
|
334
|
+
activityMap,
|
|
335
|
+
weekdays,
|
|
336
|
+
hours
|
|
337
|
+
]);
|
|
316
338
|
const extraColumnActivities = useMemo(() => {
|
|
317
339
|
if (!extraColumnMap) return [];
|
|
318
|
-
return
|
|
319
|
-
const weekday = (weekStart + di) % 7;
|
|
340
|
+
return weekdays.map((weekday, di) => {
|
|
320
341
|
const entry = extraColumnMap.get(weekday);
|
|
321
342
|
return entry ? {
|
|
322
343
|
activity: {
|
|
@@ -328,44 +349,53 @@ const WeekdayHeatmapBody = ({ hideHourLabels = false, hideWeekdayLabels = false,
|
|
|
328
349
|
weekdayIndex: di
|
|
329
350
|
} : null;
|
|
330
351
|
}).filter((a) => a !== null);
|
|
331
|
-
}, [extraColumnMap,
|
|
352
|
+
}, [extraColumnMap, weekdays]);
|
|
332
353
|
const extraRowActivities = useMemo(() => {
|
|
333
354
|
if (!extraRow) return [];
|
|
334
|
-
return extraRow.values.map(({ hour, value, level }) => ({
|
|
355
|
+
return extraRow.values.filter(({ hour }) => hours.includes(hour)).map(({ hour, value, level }) => ({
|
|
335
356
|
activity: {
|
|
336
357
|
weekday: 0,
|
|
337
358
|
hour,
|
|
338
359
|
value,
|
|
339
360
|
level
|
|
340
361
|
},
|
|
341
|
-
weekdayIndex:
|
|
362
|
+
weekdayIndex: weekdays.length
|
|
342
363
|
}));
|
|
343
|
-
}, [
|
|
344
|
-
|
|
364
|
+
}, [
|
|
365
|
+
extraRow,
|
|
366
|
+
hours,
|
|
367
|
+
weekdays.length
|
|
368
|
+
]);
|
|
369
|
+
const rowCount = weekdays.length + (hasExtraRow ? 1 : 0);
|
|
345
370
|
const extraRowGap = hasExtraRow ? blockSize + blockMargin : 0;
|
|
346
371
|
const svgHeight = rowCount * (blockSize + blockMargin) + extraRowGap - blockMargin + labelHeight;
|
|
347
372
|
const extraColumnGap = hasExtraColumn ? blockWidth + blockMargin : 0;
|
|
348
|
-
const svgWidth = hasExtraColumn ? labelWidth +
|
|
349
|
-
const orderedWeekdayIndices =
|
|
373
|
+
const svgWidth = hasExtraColumn ? labelWidth + hours.length * (blockWidth + blockMargin) + blockSize / 2 + (blockWidth + blockMargin) + extraColumnGap : labelWidth + hours.length * (blockWidth + blockMargin) - blockMargin;
|
|
374
|
+
const orderedWeekdayIndices = weekdays;
|
|
350
375
|
return /* @__PURE__ */ jsx("div", {
|
|
351
376
|
"data-slot": "weekday-heatmap-body",
|
|
377
|
+
ref: navigation.ref,
|
|
352
378
|
className: cn("max-w-full overflow-x-auto overflow-y-hidden", className),
|
|
353
379
|
...props,
|
|
380
|
+
onKeyDown: (event) => {
|
|
381
|
+
props.onKeyDown?.(event);
|
|
382
|
+
if (!event.defaultPrevented) navigation.onKeyDown(event);
|
|
383
|
+
},
|
|
354
384
|
children: /* @__PURE__ */ jsxs("svg", {
|
|
355
385
|
role: "img",
|
|
356
386
|
"aria-label": labels.heatmapLabel ?? "Activity heatmap by weekday and hour",
|
|
357
387
|
className: "block overflow-visible rounded-sm focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring",
|
|
358
|
-
height: svgHeight +
|
|
359
|
-
viewBox: `-
|
|
360
|
-
width: svgWidth +
|
|
388
|
+
height: svgHeight + 24,
|
|
389
|
+
viewBox: `-12 -12 ${svgWidth + 24} ${svgHeight + 24}`,
|
|
390
|
+
width: svgWidth + 24,
|
|
361
391
|
children: [
|
|
362
392
|
!hideHourLabels && /* @__PURE__ */ jsxs("g", {
|
|
363
393
|
className: cn("fill-current font-mono", labelClassName),
|
|
364
394
|
children: [
|
|
365
|
-
|
|
395
|
+
hours.map((hour, index) => {
|
|
366
396
|
const label = labels.hours?.[hour] ?? "";
|
|
367
397
|
return /* @__PURE__ */ jsx("text", {
|
|
368
|
-
x: labelWidth + (blockWidth + blockMargin) *
|
|
398
|
+
x: labelWidth + (blockWidth + blockMargin) * index,
|
|
369
399
|
y: 0,
|
|
370
400
|
textAnchor: "middle",
|
|
371
401
|
dominantBaseline: "hanging",
|
|
@@ -374,7 +404,7 @@ const WeekdayHeatmapBody = ({ hideHourLabels = false, hideWeekdayLabels = false,
|
|
|
374
404
|
}, `hour-${hour}`);
|
|
375
405
|
}),
|
|
376
406
|
labels.endHour != null && /* @__PURE__ */ jsx("text", {
|
|
377
|
-
x: labelWidth + (blockWidth + blockMargin) *
|
|
407
|
+
x: labelWidth + (blockWidth + blockMargin) * hours.length,
|
|
378
408
|
y: 0,
|
|
379
409
|
textAnchor: "middle",
|
|
380
410
|
dominantBaseline: "hanging",
|
|
@@ -382,7 +412,7 @@ const WeekdayHeatmapBody = ({ hideHourLabels = false, hideWeekdayLabels = false,
|
|
|
382
412
|
children: labels.endHour
|
|
383
413
|
}, "hour-end"),
|
|
384
414
|
hasExtraColumn && /* @__PURE__ */ jsx("text", {
|
|
385
|
-
x: labelWidth +
|
|
415
|
+
x: labelWidth + hours.length * (blockWidth + blockMargin) + blockSize / 2 + (blockWidth + blockMargin) + blockWidth / 2,
|
|
386
416
|
y: 0,
|
|
387
417
|
textAnchor: "middle",
|
|
388
418
|
dominantBaseline: "hanging",
|
|
@@ -406,7 +436,7 @@ const WeekdayHeatmapBody = ({ hideHourLabels = false, hideWeekdayLabels = false,
|
|
|
406
436
|
}, `weekday-${weekday}`);
|
|
407
437
|
}), hasExtraRow && /* @__PURE__ */ jsx("text", {
|
|
408
438
|
x: labelWidth - 8,
|
|
409
|
-
y: labelHeight + (blockSize + blockMargin) *
|
|
439
|
+
y: labelHeight + (blockSize + blockMargin) * weekdays.length + (blockSize + blockMargin) + blockSize / 2,
|
|
410
440
|
dominantBaseline: "middle",
|
|
411
441
|
textAnchor: "end",
|
|
412
442
|
style: { fontSize: `${fontSize * .75}px` },
|
|
@@ -450,7 +480,7 @@ const WeekdayHeatmapStat = ({ compute, label, className, children, ...props }) =
|
|
|
450
480
|
});
|
|
451
481
|
};
|
|
452
482
|
const WeekdayHeatmapLegend = ({ labels: labelsProp, className, children, ...props }) => {
|
|
453
|
-
const { levels, isNormalized,
|
|
483
|
+
const { levels, isNormalized, blockRadius, colors, labels } = useWeekdayHeatmap();
|
|
454
484
|
const lessLabel = labelsProp?.less ?? "Less";
|
|
455
485
|
const moreLabel = labelsProp?.more ?? "More";
|
|
456
486
|
const legendLevels = Array.from({ length: levels }, (_, i) => isNormalized ? i + 1 : i);
|
|
@@ -467,15 +497,15 @@ const WeekdayHeatmapLegend = ({ labels: labelsProp, className, children, ...prop
|
|
|
467
497
|
legendLevels.map((level) => children ? /* @__PURE__ */ jsx(Fragment$1, { children: children({ level }) }, `legend-level-${level}`) : /* @__PURE__ */ jsx("svg", {
|
|
468
498
|
role: "img",
|
|
469
499
|
"aria-label": (labels.legendLevelLabel ?? "{{level}} contributions").replace("{{level}}", String(level)),
|
|
470
|
-
height:
|
|
471
|
-
width:
|
|
500
|
+
height: LEGEND_SWATCH,
|
|
501
|
+
width: LEGEND_SWATCH,
|
|
472
502
|
children: /* @__PURE__ */ jsx("rect", {
|
|
473
503
|
"data-level": level,
|
|
474
|
-
height:
|
|
504
|
+
height: LEGEND_SWATCH,
|
|
475
505
|
rx: blockRadius,
|
|
476
506
|
ry: blockRadius,
|
|
477
|
-
width:
|
|
478
|
-
style: { fill: getLevelFill(level, levels, isNormalized,
|
|
507
|
+
width: LEGEND_SWATCH,
|
|
508
|
+
style: { fill: getLevelFill(level, levels, isNormalized, colors) }
|
|
479
509
|
})
|
|
480
510
|
}, `legend-level-${level}`)),
|
|
481
511
|
/* @__PURE__ */ jsx("span", {
|
|
@@ -91,6 +91,13 @@ type DataTableContextProps<TData extends RowData> = DataTableContextState & {
|
|
|
91
91
|
* `null` until the container mounts (or when no `<DataTable>` is used).
|
|
92
92
|
*/
|
|
93
93
|
scrollContainer: HTMLElement | null;
|
|
94
|
+
/** True below 40rem of table space; use for compact toolbar and record layouts. */
|
|
95
|
+
isCompact: boolean;
|
|
96
|
+
/**
|
|
97
|
+
* Set while some columns do not fit and the table has `meta.compact`
|
|
98
|
+
* columns: they hide, rightmost first, until the reader asks for all.
|
|
99
|
+
*/
|
|
100
|
+
compactColumns: CompactColumns | null;
|
|
94
101
|
/** Internal: `<DataTable>` registers its scroll container element here. */
|
|
95
102
|
registerScrollContainer: (el: HTMLElement | null) => void;
|
|
96
103
|
/**
|
|
@@ -146,12 +153,22 @@ export declare enum DataTableActions {
|
|
|
146
153
|
SET = 0,
|
|
147
154
|
SET_IS_LOADING = 1
|
|
148
155
|
}
|
|
156
|
+
export interface CompactColumns {
|
|
157
|
+
/** True while columns are hidden to fit; false once the reader shows them all. */
|
|
158
|
+
collapsed: boolean;
|
|
159
|
+
/** The columns hidden to fit right now, for a cell to fold one under a kept figure. */
|
|
160
|
+
hidden: ReadonlySet<string>;
|
|
161
|
+
setCollapsed: (collapsed: boolean) => void;
|
|
162
|
+
}
|
|
149
163
|
interface DataTableProviderProps<TData extends RowData> {
|
|
150
164
|
children: React.ReactNode;
|
|
151
165
|
table: DataTableInstance<TData>;
|
|
152
166
|
columns?: DataTableColumnDef<TData>[];
|
|
153
167
|
isLoading?: boolean;
|
|
168
|
+
isCompact: boolean;
|
|
169
|
+
onWidthChange: (width: number) => void;
|
|
170
|
+
compactColumns: CompactColumns | null;
|
|
154
171
|
}
|
|
155
|
-
export declare function DataTableProvider<TData extends RowData>({ children, table, columns, isLoading: externalIsLoading }: DataTableProviderProps<TData>): React.JSX.Element;
|
|
172
|
+
export declare function DataTableProvider<TData extends RowData>({ children, table, columns, isLoading: externalIsLoading, isCompact, onWidthChange, compactColumns }: DataTableProviderProps<TData>): React.JSX.Element;
|
|
156
173
|
//#endregion
|
|
157
174
|
export { DataTableContext };
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
"use client";
|
|
2
|
+
import { useTableWidth } from "../../../../lib/compact-columns.js";
|
|
2
3
|
import { useGeneratedOptions } from "../hooks/use-generated-options.js";
|
|
3
4
|
import { useHeaderMinWidths } from "../lib/use-header-min-widths.js";
|
|
4
5
|
import { jsx, jsxs } from "react/jsx-runtime";
|
|
@@ -113,7 +114,7 @@ function useFlashSet() {
|
|
|
113
114
|
}
|
|
114
115
|
}, [])];
|
|
115
116
|
}
|
|
116
|
-
function DataTableProvider({ children, table, columns, isLoading: externalIsLoading }) {
|
|
117
|
+
function DataTableProvider({ children, table, columns, isLoading: externalIsLoading, isCompact, onWidthChange, compactColumns }) {
|
|
117
118
|
const [state, dispatch] = useReducer(dataTableReducer, deriveInitialState(externalIsLoading));
|
|
118
119
|
const setIsLoading = useCallback((value) => {
|
|
119
120
|
dispatch({
|
|
@@ -127,6 +128,7 @@ function DataTableProvider({ children, table, columns, isLoading: externalIsLoad
|
|
|
127
128
|
}, []);
|
|
128
129
|
const [scrollContainer, setScrollContainer] = React.useState(null);
|
|
129
130
|
const registerScrollContainer = useCallback((el) => setScrollContainer(el), []);
|
|
131
|
+
useTableWidth(scrollContainer, onWidthChange);
|
|
130
132
|
const scrollRowIntoView = useCallback((index, opts) => {
|
|
131
133
|
if (rowScrollerRef.current) {
|
|
132
134
|
rowScrollerRef.current(index, opts);
|
|
@@ -269,6 +271,8 @@ function DataTableProvider({ children, table, columns, isLoading: externalIsLoad
|
|
|
269
271
|
scrollRowIntoView,
|
|
270
272
|
registerRowScroller,
|
|
271
273
|
scrollContainer,
|
|
274
|
+
isCompact,
|
|
275
|
+
compactColumns,
|
|
272
276
|
registerScrollContainer,
|
|
273
277
|
headerMinWidths,
|
|
274
278
|
setColumnResizePreview: setManualResizePreview,
|
|
@@ -286,6 +290,8 @@ function DataTableProvider({ children, table, columns, isLoading: externalIsLoad
|
|
|
286
290
|
scrollRowIntoView,
|
|
287
291
|
registerRowScroller,
|
|
288
292
|
scrollContainer,
|
|
293
|
+
isCompact,
|
|
294
|
+
compactColumns,
|
|
289
295
|
registerScrollContainer,
|
|
290
296
|
headerMinWidths,
|
|
291
297
|
setManualResizePreview,
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { Button } from "../../../ui/button.js";
|
|
2
2
|
import { cn } from "../../../../lib/utils.js";
|
|
3
|
+
import { useDataTable } from "./data-table-context.js";
|
|
3
4
|
import { DataTableGroupRowProvider, useDataTableGroupRow } from "../components/data-table-grouped-rows.js";
|
|
4
5
|
import { TableCell, TableRow } from "../ui/table.js";
|
|
5
6
|
import { isInteractiveClickTarget } from "../lib/row-click.js";
|
|
@@ -18,12 +19,13 @@ import { flexRender } from "@tanstack/react-table";
|
|
|
18
19
|
* groups you don't want to special-case.
|
|
19
20
|
*/
|
|
20
21
|
function DataTableGroupedRowCells() {
|
|
22
|
+
const { isCompact } = useDataTable();
|
|
21
23
|
const { row, groupLabel, count, isExpanded, toggle, columnWidths } = useDataTableGroupRow();
|
|
22
24
|
const countLabel = `${count} ${count === 1 ? "row" : "rows"}`;
|
|
23
25
|
return /* @__PURE__ */ jsx(Fragment, { children: row.getVisibleCells().map((cell) => {
|
|
24
26
|
const cellStyle = {
|
|
25
27
|
width: columnWidths.get(cell.column.id),
|
|
26
|
-
...getCommonPinningStyles(cell.column, false)
|
|
28
|
+
...getCommonPinningStyles(cell.column, false, !isCompact)
|
|
27
29
|
};
|
|
28
30
|
let content = null;
|
|
29
31
|
if (cell.getIsGrouped()) content = /* @__PURE__ */ jsxs("div", {
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { TooltipProvider } from "../../../ui/tooltip.js";
|
|
2
2
|
import { cn } from "../../../../lib/utils.js";
|
|
3
|
+
import { fitColumns, isCompactWidth } from "../../../../lib/compact-columns.js";
|
|
3
4
|
import { FILTER_VARIANTS, SYSTEM_COLUMN_IDS, SYSTEM_COLUMN_ID_LIST } from "../lib/constants.js";
|
|
4
5
|
import { DataTableProvider } from "./data-table-context.js";
|
|
5
6
|
import { detectFeaturesFromChildren } from "../config/feature-detection.js";
|
|
@@ -216,7 +217,23 @@ function DataTableRootInternal({ columns, data, children, className, config, get
|
|
|
216
217
|
...detectFeatures.enableColumnResizing ? { minSize: 40 } : {}
|
|
217
218
|
}), [detectFeatures.enableColumnResizing, detectFeatures.enableSorting]);
|
|
218
219
|
const controlledSorting = restState?.sorting ?? sorting;
|
|
219
|
-
const
|
|
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
|
|
382
|
-
|
|
383
|
-
|
|
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,
|