@siyahi/ui 0.1.9-next.20 → 0.1.9-next.21
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/DESIGN.md +30 -0
- package/README.md +3 -3
- package/agents/examples/alert.tsx +4 -6
- package/agents/examples/bar-list-sides.tsx +11 -3
- package/agents/examples/button-states.tsx +23 -0
- package/agents/examples/callout.tsx +33 -0
- package/agents/examples/change-bar.tsx +104 -0
- package/agents/examples/chart-area.tsx +5 -4
- package/agents/examples/chart-bar-flows.tsx +3 -2
- package/agents/examples/chart-bar-sectors.tsx +2 -0
- package/agents/examples/data-table-compact.tsx +95 -0
- package/agents/examples/heatmap-calendar.tsx +17 -7
- package/agents/examples/heatmap-status.tsx +17 -11
- package/agents/examples/heatmap-weekday.tsx +33 -11
- package/agents/examples/input-states.tsx +33 -0
- package/agents/examples/metric-strip.tsx +9 -3
- package/agents/examples/overview-dashboard.tsx +18 -0
- package/agents/examples/page-hero.tsx +38 -0
- package/agents/examples/range-position-table.tsx +101 -0
- package/agents/examples/range-position.tsx +53 -0
- package/agents/examples/section-cards-select.tsx +8 -5
- package/agents/examples/surfaces.tsx +3 -2
- package/agents/examples/target-rows.tsx +70 -0
- package/agents/examples/treemap.tsx +2 -1
- package/agents/manifest.json +153 -3
- package/dist/components/registry/charts/area-chart-card.js +25 -7
- package/dist/components/registry/charts/bar-chart-card.d.ts +0 -1
- package/dist/components/registry/charts/bar-chart-card.js +11 -4
- package/dist/components/registry/charts/line-chart-card.js +2 -2
- package/dist/components/registry/dashboardcn/bar-list.js +11 -5
- package/dist/components/registry/dashboardcn/kpi-row-card.js +2 -2
- package/dist/components/registry/dashboardcn/sparkline.d.ts +5 -1
- package/dist/components/registry/dashboardcn/sparkline.js +40 -18
- package/dist/components/registry/heatmap/calendar-heatmap.d.ts +4 -2
- package/dist/components/registry/heatmap/calendar-heatmap.js +67 -33
- package/dist/components/registry/heatmap/status-heatmap.d.ts +5 -3
- package/dist/components/registry/heatmap/status-heatmap.js +30 -15
- package/dist/components/registry/heatmap/weekday-heatmap.d.ts +4 -2
- package/dist/components/registry/heatmap/weekday-heatmap.js +28 -12
- package/dist/components/registry/niko-table/core/data-table-context.d.ts +16 -1
- package/dist/components/registry/niko-table/core/data-table-context.js +5 -20
- package/dist/components/registry/niko-table/core/data-table-root.js +39 -4
- package/dist/components/registry/niko-table/core/data-table-structure.js +2 -0
- package/dist/components/registry/niko-table/lib/styles.js +1 -1
- package/dist/components/registry/niko-table/types/index.d.ts +9 -0
- package/dist/components/registry/sidebar-07/nav-main.d.ts +1 -0
- package/dist/components/registry/sidebar-07/nav-main.js +9 -2
- package/dist/components/siyahi/callout.d.ts +24 -0
- package/dist/components/siyahi/callout.js +40 -0
- package/dist/components/siyahi/change-bar.d.ts +21 -0
- package/dist/components/siyahi/change-bar.js +35 -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/page-hero.d.ts +25 -0
- package/dist/components/siyahi/page-hero.js +41 -0
- package/dist/components/siyahi/page-toc.d.ts +20 -0
- package/dist/components/siyahi/page-toc.js +76 -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/siyahi-provider.d.ts +1 -1
- package/dist/components/siyahi/siyahi-provider.js +1 -1
- package/dist/components/siyahi/target-rows.d.ts +34 -0
- package/dist/components/siyahi/target-rows.js +97 -0
- package/dist/components/siyahi/treemap.d.ts +4 -1
- package/dist/components/siyahi/treemap.js +33 -25
- package/dist/components/siyahi/warning-alert.d.ts +10 -0
- package/dist/components/siyahi/warning-alert.js +20 -0
- package/dist/index.d.ts +15 -4
- package/dist/index.js +12 -1
- package/dist/lib/chart-frame.d.ts +12 -2
- package/dist/lib/chart-frame.js +51 -7
- package/dist/lib/chart-series.d.ts +5 -2
- package/dist/lib/compact-columns.d.ts +19 -0
- package/dist/lib/compact-columns.js +55 -0
- package/dist/lib/format.d.ts +7 -2
- package/dist/lib/format.js +24 -5
- package/dist/lib/treemap.js +6 -1
- package/dist/lib/use-element-width.d.ts +5 -0
- package/dist/lib/use-element-width.js +15 -0
- package/package.json +2 -1
- package/report.css +26 -25
- package/styles/siyahi.css +159 -43
|
@@ -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
|
|
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
|
|
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 +
|
|
378
|
-
viewBox: `-
|
|
379
|
-
width: svgWidth +
|
|
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,
|
|
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:
|
|
490
|
-
width:
|
|
505
|
+
height: LEGEND_SWATCH,
|
|
506
|
+
width: LEGEND_SWATCH,
|
|
491
507
|
children: /* @__PURE__ */ jsx("rect", {
|
|
492
508
|
"data-level": level,
|
|
493
|
-
height:
|
|
509
|
+
height: LEGEND_SWATCH,
|
|
494
510
|
rx: blockRadius,
|
|
495
511
|
ry: blockRadius,
|
|
496
|
-
width:
|
|
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 };
|
|
@@ -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,25 +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), []);
|
|
130
|
-
|
|
131
|
-
React.useLayoutEffect(() => {
|
|
132
|
-
if (!scrollContainer) return;
|
|
133
|
-
const measure = () => {
|
|
134
|
-
const width = scrollContainer.clientWidth;
|
|
135
|
-
if (width > 0) {
|
|
136
|
-
const rem = Number.parseFloat(getComputedStyle(document.documentElement).fontSize);
|
|
137
|
-
setIsCompact(width < 40 * rem);
|
|
138
|
-
}
|
|
139
|
-
};
|
|
140
|
-
measure();
|
|
141
|
-
const observer = new ResizeObserver(measure);
|
|
142
|
-
observer.observe(scrollContainer);
|
|
143
|
-
window.addEventListener("resize", measure);
|
|
144
|
-
return () => {
|
|
145
|
-
observer.disconnect();
|
|
146
|
-
window.removeEventListener("resize", measure);
|
|
147
|
-
};
|
|
148
|
-
}, [scrollContainer]);
|
|
131
|
+
useTableWidth(scrollContainer, onWidthChange);
|
|
149
132
|
const scrollRowIntoView = useCallback((index, opts) => {
|
|
150
133
|
if (rowScrollerRef.current) {
|
|
151
134
|
rowScrollerRef.current(index, opts);
|
|
@@ -289,6 +272,7 @@ function DataTableProvider({ children, table, columns, isLoading: externalIsLoad
|
|
|
289
272
|
registerRowScroller,
|
|
290
273
|
scrollContainer,
|
|
291
274
|
isCompact,
|
|
275
|
+
compactColumns,
|
|
292
276
|
registerScrollContainer,
|
|
293
277
|
headerMinWidths,
|
|
294
278
|
setColumnResizePreview: setManualResizePreview,
|
|
@@ -307,6 +291,7 @@ function DataTableProvider({ children, table, columns, isLoading: externalIsLoad
|
|
|
307
291
|
registerRowScroller,
|
|
308
292
|
scrollContainer,
|
|
309
293
|
isCompact,
|
|
294
|
+
compactColumns,
|
|
310
295
|
registerScrollContainer,
|
|
311
296
|
headerMinWidths,
|
|
312
297
|
setManualResizePreview,
|
|
@@ -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,
|
|
@@ -41,6 +41,7 @@ const DataTableHeader = React.memo(function DataTableHeader({ className, sticky
|
|
|
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
46
|
className: cn(!isCompact && header.column.getIsPinned() && "bg-background", resizing && "relative overflow-hidden"),
|
|
46
47
|
children: [header.isPlaceholder ? null : /* @__PURE__ */ jsx(DataTableColumnHeaderRoot, {
|
|
@@ -82,6 +83,7 @@ const BodyRow = React.memo(function BodyRow({ row, displayIndex, expandColumnId,
|
|
|
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
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)
|
|
@@ -17,7 +17,7 @@ const getCommonPinningStyles = (column, isHeader = false, pinningEnabled = true)
|
|
|
17
17
|
flexShrink: 0,
|
|
18
18
|
zIndex: isHeader ? 20 : 10,
|
|
19
19
|
backgroundColor: "var(--card)",
|
|
20
|
-
|
|
20
|
+
boxShadow: isLeft ? "inset -1px 0 0 0 var(--border)" : "inset 1px 0 0 0 var(--border)"
|
|
21
21
|
};
|
|
22
22
|
};
|
|
23
23
|
//#endregion
|
|
@@ -23,6 +23,15 @@ declare module "@tanstack/react-table" {
|
|
|
23
23
|
* `TableMeta.disableFlexFill`.
|
|
24
24
|
*/
|
|
25
25
|
flex?: boolean;
|
|
26
|
+
/**
|
|
27
|
+
* Never hide this column to fit. Once any column sets it, a table whose
|
|
28
|
+
* columns do not fit its width hides the others, rightmost first, until
|
|
29
|
+
* they do, and `<DataTableCompactColumnsToggle />` shows them all again.
|
|
30
|
+
* Mark the few a reader needs to answer the table's question: the name and
|
|
31
|
+
* its result. Read `useDataTable().compactColumns?.hidden` in a cell to
|
|
32
|
+
* fold a hidden figure under a kept one.
|
|
33
|
+
*/
|
|
34
|
+
compact?: boolean;
|
|
26
35
|
variant?: FilterVariant;
|
|
27
36
|
options?: Option[];
|
|
28
37
|
range?: [number, number];
|
|
@@ -29,14 +29,21 @@ function NavMain({ items, label = "Navigation" }) {
|
|
|
29
29
|
className: "group/collapsible",
|
|
30
30
|
render: /* @__PURE__ */ jsx(SidebarMenuItem, {}),
|
|
31
31
|
children: [/* @__PURE__ */ jsxs(CollapsibleTrigger, {
|
|
32
|
-
render: /* @__PURE__ */ jsx(SidebarMenuButton, {
|
|
32
|
+
render: /* @__PURE__ */ jsx(SidebarMenuButton, {
|
|
33
|
+
tooltip: item.title,
|
|
34
|
+
isActive: item.isActive && !item.items?.some((subItem) => subItem.isActive)
|
|
35
|
+
}),
|
|
33
36
|
children: [
|
|
34
37
|
item.icon,
|
|
35
38
|
/* @__PURE__ */ jsx("span", { children: item.title }),
|
|
36
39
|
/* @__PURE__ */ jsx(ChevronRightIcon, { className: "ml-auto transition-transform duration-200 group-data-open/collapsible:rotate-90" })
|
|
37
40
|
]
|
|
38
41
|
}), /* @__PURE__ */ jsx(CollapsibleContent, { children: /* @__PURE__ */ jsx(SidebarMenuSub, { children: item.items?.map((subItem) => /* @__PURE__ */ jsx(SidebarMenuSubItem, { children: /* @__PURE__ */ jsx(SidebarMenuSubButton, {
|
|
39
|
-
|
|
42
|
+
isActive: subItem.isActive,
|
|
43
|
+
render: /* @__PURE__ */ jsx("a", {
|
|
44
|
+
href: subItem.url,
|
|
45
|
+
"aria-current": subItem.isActive ? "page" : void 0
|
|
46
|
+
}),
|
|
40
47
|
onClick: closeDrawer,
|
|
41
48
|
children: /* @__PURE__ */ jsx("span", { children: subItem.title })
|
|
42
49
|
}) }, subItem.title)) }) })]
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { ComponentProps, ReactNode } from "react";
|
|
2
|
+
//#region src/components/siyahi/callout.d.ts
|
|
3
|
+
declare const TONES: {
|
|
4
|
+
readonly neutral: "border-border bg-muted/50 [&_[data-slot=callout-icon]]:text-muted-foreground";
|
|
5
|
+
readonly accent: "border-chart-1/35 bg-chart-1/8 [&_[data-slot=callout-icon]]:text-link";
|
|
6
|
+
readonly warning: "border-warning/45 bg-warning/10 [&_[data-slot=callout-icon]]:text-warning";
|
|
7
|
+
readonly positive: "border-positive/40 bg-positive/8 [&_[data-slot=callout-icon]]:text-positive";
|
|
8
|
+
readonly negative: "border-negative/40 bg-negative/8 [&_[data-slot=callout-icon]]:text-negative";
|
|
9
|
+
};
|
|
10
|
+
export interface CalloutProps extends Omit<ComponentProps<"aside">, "title"> {
|
|
11
|
+
/** neutral for an aside, accent for a key point, warning for a caution, positive or negative for a gain or a loss. */
|
|
12
|
+
tone?: keyof typeof TONES;
|
|
13
|
+
/** A lucide icon, drawn in the tone's colour. */
|
|
14
|
+
icon?: ReactNode;
|
|
15
|
+
title?: ReactNode;
|
|
16
|
+
}
|
|
17
|
+
/**
|
|
18
|
+
* A point set apart from the prose: a takeaway, a caveat, a definition. The whole box takes the tone, a faint wash
|
|
19
|
+
* inside a border of the same colour; never a single coloured edge. For a notice that interrupts, use Alert or
|
|
20
|
+
* WarningAlert instead.
|
|
21
|
+
*/
|
|
22
|
+
export declare function Callout({ tone, icon, title, className, children, ...props }: CalloutProps): import("react").JSX.Element;
|
|
23
|
+
//#endregion
|
|
24
|
+
export {};
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import { cn } from "cn";
|
|
2
|
+
import { jsx, jsxs } from "react/jsx-runtime";
|
|
3
|
+
//#region src/components/siyahi/callout.tsx
|
|
4
|
+
const TONES = {
|
|
5
|
+
neutral: "border-border bg-muted/50 [&_[data-slot=callout-icon]]:text-muted-foreground",
|
|
6
|
+
accent: "border-chart-1/35 bg-chart-1/8 [&_[data-slot=callout-icon]]:text-link",
|
|
7
|
+
warning: "border-warning/45 bg-warning/10 [&_[data-slot=callout-icon]]:text-warning",
|
|
8
|
+
positive: "border-positive/40 bg-positive/8 [&_[data-slot=callout-icon]]:text-positive",
|
|
9
|
+
negative: "border-negative/40 bg-negative/8 [&_[data-slot=callout-icon]]:text-negative"
|
|
10
|
+
};
|
|
11
|
+
/**
|
|
12
|
+
* A point set apart from the prose: a takeaway, a caveat, a definition. The whole box takes the tone, a faint wash
|
|
13
|
+
* inside a border of the same colour; never a single coloured edge. For a notice that interrupts, use Alert or
|
|
14
|
+
* WarningAlert instead.
|
|
15
|
+
*/
|
|
16
|
+
function Callout({ tone = "neutral", icon, title, className, children, ...props }) {
|
|
17
|
+
return /* @__PURE__ */ jsxs("aside", {
|
|
18
|
+
"data-slot": "callout",
|
|
19
|
+
"data-tone": tone,
|
|
20
|
+
className: cn("flex gap-3 rounded-lg border px-4 py-3 text-sm", TONES[tone], className),
|
|
21
|
+
...props,
|
|
22
|
+
children: [icon && /* @__PURE__ */ jsx("span", {
|
|
23
|
+
"data-slot": "callout-icon",
|
|
24
|
+
"aria-hidden": true,
|
|
25
|
+
className: "mt-0.5 shrink-0 [&>svg]:size-4",
|
|
26
|
+
children: icon
|
|
27
|
+
}), /* @__PURE__ */ jsxs("div", {
|
|
28
|
+
className: "flex min-w-0 flex-col gap-1",
|
|
29
|
+
children: [title && /* @__PURE__ */ jsx("p", {
|
|
30
|
+
className: "font-medium",
|
|
31
|
+
children: title
|
|
32
|
+
}), /* @__PURE__ */ jsx("div", {
|
|
33
|
+
className: "text-pretty text-muted-foreground [&_strong]:text-foreground",
|
|
34
|
+
children
|
|
35
|
+
})]
|
|
36
|
+
})]
|
|
37
|
+
});
|
|
38
|
+
}
|
|
39
|
+
//#endregion
|
|
40
|
+
export { Callout };
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { DeltaProps } from "./delta.js";
|
|
2
|
+
//#region src/components/siyahi/change-bar.d.ts
|
|
3
|
+
export interface ChangeBarProps {
|
|
4
|
+
/** The signed change, as Delta takes it. */
|
|
5
|
+
value: number;
|
|
6
|
+
/** The column's largest change by size: Math.max(...rows.map((row) => Math.abs(row.change))). */
|
|
7
|
+
max: number;
|
|
8
|
+
/**
|
|
9
|
+
* Draws the bar from a centre line, losses leftward and gains rightward. Pass it when the column holds both signs:
|
|
10
|
+
* rows.some((row) => row.change < 0) && rows.some((row) => row.change > 0).
|
|
11
|
+
*/
|
|
12
|
+
diverging?: boolean;
|
|
13
|
+
format?: DeltaProps["format"];
|
|
14
|
+
className?: string;
|
|
15
|
+
}
|
|
16
|
+
/**
|
|
17
|
+
* A table cell's change as a Delta over a 3px bar whose length is the change's size against the column's largest, so
|
|
18
|
+
* the rows rank by eye. The bar is neutral because it shows size; the Delta above it carries the gain or loss colour.
|
|
19
|
+
*/
|
|
20
|
+
export declare function ChangeBar({ value, max, diverging, format, className }: ChangeBarProps): import("react").JSX.Element;
|
|
21
|
+
//#endregion
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import { Delta } from "./delta.js";
|
|
2
|
+
import { cn } from "cn";
|
|
3
|
+
import { jsx, jsxs } from "react/jsx-runtime";
|
|
4
|
+
//#region src/components/siyahi/change-bar.tsx
|
|
5
|
+
/**
|
|
6
|
+
* A table cell's change as a Delta over a 3px bar whose length is the change's size against the column's largest, so
|
|
7
|
+
* the rows rank by eye. The bar is neutral because it shows size; the Delta above it carries the gain or loss colour.
|
|
8
|
+
*/
|
|
9
|
+
function ChangeBar({ value, max, diverging = false, format, className }) {
|
|
10
|
+
const share = max > 0 ? Math.min(1, Math.abs(value) / max) : 0;
|
|
11
|
+
const half = diverging ? 50 : 100;
|
|
12
|
+
const side = diverging && value < 0 ? "right" : "left";
|
|
13
|
+
return /* @__PURE__ */ jsxs("div", {
|
|
14
|
+
"data-slot": "change-bar",
|
|
15
|
+
className: cn("flex w-full flex-col items-end gap-1.5", className),
|
|
16
|
+
children: [/* @__PURE__ */ jsx(Delta, {
|
|
17
|
+
value,
|
|
18
|
+
format,
|
|
19
|
+
className: "font-medium"
|
|
20
|
+
}), /* @__PURE__ */ jsxs("div", {
|
|
21
|
+
"aria-hidden": "true",
|
|
22
|
+
className: "relative h-0.75 w-full rounded-full bg-muted",
|
|
23
|
+
children: [/* @__PURE__ */ jsx("div", {
|
|
24
|
+
"data-slot": "change-bar-fill",
|
|
25
|
+
className: "absolute inset-y-0 rounded-full bg-foreground",
|
|
26
|
+
style: {
|
|
27
|
+
[side]: diverging ? "50%" : 0,
|
|
28
|
+
width: `${share * half}%`
|
|
29
|
+
}
|
|
30
|
+
}), diverging && /* @__PURE__ */ jsx("div", { className: "absolute -inset-y-1 left-1/2 w-px -translate-x-1/2 bg-muted-foreground" })]
|
|
31
|
+
})]
|
|
32
|
+
});
|
|
33
|
+
}
|
|
34
|
+
//#endregion
|
|
35
|
+
export { ChangeBar };
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
//#region src/components/siyahi/data-table-compact-columns-toggle.d.ts
|
|
2
|
+
/** Renders only while some columns are hidden to fit, or the reader has shown them all. */
|
|
3
|
+
export declare function DataTableCompactColumnsToggle(): import("react").JSX.Element | null;
|
|
4
|
+
//#endregion
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { Button } from "../ui/button.js";
|
|
2
|
+
import { useDataTable } from "../registry/niko-table/core/data-table-context.js";
|
|
3
|
+
import { jsx } from "react/jsx-runtime";
|
|
4
|
+
//#region src/components/siyahi/data-table-compact-columns-toggle.tsx
|
|
5
|
+
/** Renders only while some columns are hidden to fit, or the reader has shown them all. */
|
|
6
|
+
function DataTableCompactColumnsToggle() {
|
|
7
|
+
const { compactColumns } = useDataTable();
|
|
8
|
+
if (!compactColumns) return null;
|
|
9
|
+
const { collapsed, setCollapsed } = compactColumns;
|
|
10
|
+
return /* @__PURE__ */ jsx(Button, {
|
|
11
|
+
variant: "outline",
|
|
12
|
+
size: "sm",
|
|
13
|
+
"aria-pressed": !collapsed,
|
|
14
|
+
onClick: () => setCollapsed(!collapsed),
|
|
15
|
+
children: collapsed ? `All columns (+${compactColumns.hidden.size})` : "Key columns"
|
|
16
|
+
});
|
|
17
|
+
}
|
|
18
|
+
//#endregion
|
|
19
|
+
export { DataTableCompactColumnsToggle };
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { ReactNode } from "react";
|
|
2
|
+
//#region src/components/siyahi/data-table-footnote.d.ts
|
|
3
|
+
export interface DataTableFootnoteProps {
|
|
4
|
+
/** One sentence on how to read the table, such as what each bar measures. */
|
|
5
|
+
children: ReactNode;
|
|
6
|
+
}
|
|
7
|
+
/**
|
|
8
|
+
* A full-width last row, inside `DataTable` after its body, that explains the table's encoding. On a table wider than
|
|
9
|
+
* its card the note stays put at the card's width while the columns scroll under it.
|
|
10
|
+
*/
|
|
11
|
+
export declare function DataTableFootnote({ children }: DataTableFootnoteProps): import("react").JSX.Element;
|
|
12
|
+
//#endregion
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import { useDataTable } from "../registry/niko-table/core/data-table-context.js";
|
|
2
|
+
import { jsx } from "react/jsx-runtime";
|
|
3
|
+
import { useEffect, useState } from "react";
|
|
4
|
+
//#region src/components/siyahi/data-table-footnote.tsx
|
|
5
|
+
/**
|
|
6
|
+
* A full-width last row, inside `DataTable` after its body, that explains the table's encoding. On a table wider than
|
|
7
|
+
* its card the note stays put at the card's width while the columns scroll under it.
|
|
8
|
+
*/
|
|
9
|
+
function DataTableFootnote({ children }) {
|
|
10
|
+
const { table, scrollContainer } = useDataTable();
|
|
11
|
+
const [viewport, setViewport] = useState();
|
|
12
|
+
useEffect(() => {
|
|
13
|
+
if (!scrollContainer) return;
|
|
14
|
+
const observer = new ResizeObserver(() => setViewport(scrollContainer.clientWidth));
|
|
15
|
+
observer.observe(scrollContainer);
|
|
16
|
+
return () => observer.disconnect();
|
|
17
|
+
}, [scrollContainer]);
|
|
18
|
+
return /* @__PURE__ */ jsx("tfoot", {
|
|
19
|
+
"data-slot": "data-table-footnote",
|
|
20
|
+
children: /* @__PURE__ */ jsx("tr", {
|
|
21
|
+
className: "border-t",
|
|
22
|
+
children: /* @__PURE__ */ jsx("td", {
|
|
23
|
+
colSpan: table.getVisibleLeafColumns().length,
|
|
24
|
+
className: "p-0",
|
|
25
|
+
children: /* @__PURE__ */ jsx("p", {
|
|
26
|
+
className: "sticky left-0 px-2 py-3 text-sm whitespace-normal text-muted-foreground",
|
|
27
|
+
style: { maxWidth: viewport },
|
|
28
|
+
children
|
|
29
|
+
})
|
|
30
|
+
})
|
|
31
|
+
})
|
|
32
|
+
});
|
|
33
|
+
}
|
|
34
|
+
//#endregion
|
|
35
|
+
export { DataTableFootnote };
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
//#region src/components/siyahi/default-sidebar-open.d.ts
|
|
2
|
+
/**
|
|
3
|
+
* SidebarProvider's `defaultOpen` for an app shell: the reader's last choice, which the provider keeps in the
|
|
4
|
+
* `sidebar_state` cookie, else open — except on a short landscape screen, a phone held sideways, where an open
|
|
5
|
+
* sidebar leaves no room for the page. There it starts as the icon rail.
|
|
6
|
+
*/
|
|
7
|
+
export declare function defaultSidebarOpen(): boolean;
|
|
8
|
+
//#endregion
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
//#region src/components/siyahi/default-sidebar-open.ts
|
|
2
|
+
/**
|
|
3
|
+
* SidebarProvider's `defaultOpen` for an app shell: the reader's last choice, which the provider keeps in the
|
|
4
|
+
* `sidebar_state` cookie, else open — except on a short landscape screen, a phone held sideways, where an open
|
|
5
|
+
* sidebar leaves no room for the page. There it starts as the icon rail.
|
|
6
|
+
*/
|
|
7
|
+
function defaultSidebarOpen() {
|
|
8
|
+
const saved = document.cookie.split("; ").find((entry) => entry.startsWith("sidebar_state="))?.slice(14);
|
|
9
|
+
if (saved !== void 0) return saved === "true";
|
|
10
|
+
return !matchMedia("(orientation: landscape) and (max-height: 30rem)").matches;
|
|
11
|
+
}
|
|
12
|
+
//#endregion
|
|
13
|
+
export { defaultSidebarOpen };
|