@siyahi/ui 0.0.0-stage → 0.1.0-next.3
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/LICENSE +21 -0
- package/README.md +174 -2
- package/THIRD_PARTY_NOTICES.md +51 -0
- package/dist/components/registry/dashboard-01/section-cards.d.ts +17 -0
- package/dist/components/registry/dashboard-01/section-cards.js +39 -0
- package/dist/components/registry/dashboardcn/bar-list.d.ts +24 -0
- package/dist/components/registry/dashboardcn/bar-list.js +71 -0
- package/dist/components/registry/heatmap/calendar-heatmap.d.ts +134 -0
- package/dist/components/registry/heatmap/calendar-heatmap.js +497 -0
- package/dist/components/registry/heatmap/status-heatmap.d.ts +120 -0
- package/dist/components/registry/heatmap/status-heatmap.js +330 -0
- package/dist/components/registry/heatmap/weekday-heatmap.d.ts +145 -0
- package/dist/components/registry/heatmap/weekday-heatmap.js +489 -0
- package/dist/components/registry/niko-table/components/data-table-column-actions.d.ts +26 -0
- package/dist/components/registry/niko-table/components/data-table-column-actions.js +32 -0
- package/dist/components/registry/niko-table/components/data-table-column-filter.d.ts +13 -0
- package/dist/components/registry/niko-table/components/data-table-column-filter.js +17 -0
- package/dist/components/registry/niko-table/components/data-table-column-header.d.ts +30 -0
- package/dist/components/registry/niko-table/components/data-table-column-header.js +35 -0
- package/dist/components/registry/niko-table/components/data-table-column-sort.d.ts +21 -0
- package/dist/components/registry/niko-table/components/data-table-column-sort.js +36 -0
- package/dist/components/registry/niko-table/components/data-table-column-title.d.ts +12 -0
- package/dist/components/registry/niko-table/components/data-table-column-title.js +18 -0
- package/dist/components/registry/niko-table/components/data-table-empty-state.d.ts +108 -0
- package/dist/components/registry/niko-table/components/data-table-empty-state.js +148 -0
- package/dist/components/registry/niko-table/components/data-table-faceted-filter.d.ts +46 -0
- package/dist/components/registry/niko-table/components/data-table-faceted-filter.js +133 -0
- package/dist/components/registry/niko-table/components/data-table-grouped-rows.d.ts +111 -0
- package/dist/components/registry/niko-table/components/data-table-grouped-rows.js +77 -0
- package/dist/components/registry/niko-table/components/data-table-row-context-menu-slot.d.ts +65 -0
- package/dist/components/registry/niko-table/components/data-table-row-context-menu-slot.js +65 -0
- package/dist/components/registry/niko-table/components/data-table-row-context-menu.d.ts +50 -0
- package/dist/components/registry/niko-table/components/data-table-row-context-menu.js +42 -0
- package/dist/components/registry/niko-table/components/data-table-row-menu.d.ts +51 -0
- package/dist/components/registry/niko-table/components/data-table-row-menu.js +65 -0
- package/dist/components/registry/niko-table/components/data-table-toolbar-section.d.ts +7 -0
- package/dist/components/registry/niko-table/components/data-table-toolbar-section.js +63 -0
- package/dist/components/registry/niko-table/config/data-table.d.ts +156 -0
- package/dist/components/registry/niko-table/config/data-table.js +279 -0
- package/dist/components/registry/niko-table/config/feature-detection.d.ts +39 -0
- package/dist/components/registry/niko-table/config/feature-detection.js +174 -0
- package/dist/components/registry/niko-table/core/data-table-context.d.ts +157 -0
- package/dist/components/registry/niko-table/core/data-table-context.js +326 -0
- package/dist/components/registry/niko-table/core/data-table-error-boundary.d.ts +85 -0
- package/dist/components/registry/niko-table/core/data-table-error-boundary.js +116 -0
- package/dist/components/registry/niko-table/core/data-table-grouped-row.d.ts +49 -0
- package/dist/components/registry/niko-table/core/data-table-grouped-row.js +112 -0
- package/dist/components/registry/niko-table/core/data-table-root.d.ts +62 -0
- package/dist/components/registry/niko-table/core/data-table-root.js +406 -0
- package/dist/components/registry/niko-table/core/data-table-structure.d.ts +153 -0
- package/dist/components/registry/niko-table/core/data-table-structure.js +370 -0
- package/dist/components/registry/niko-table/core/data-table.d.ts +30 -0
- package/dist/components/registry/niko-table/core/data-table.js +126 -0
- package/dist/components/registry/niko-table/filters/table-column-actions.d.ts +49 -0
- package/dist/components/registry/niko-table/filters/table-column-actions.js +48 -0
- package/dist/components/registry/niko-table/filters/table-column-sort.d.ts +51 -0
- package/dist/components/registry/niko-table/filters/table-column-sort.js +184 -0
- package/dist/components/registry/niko-table/filters/table-column-title.d.ts +17 -0
- package/dist/components/registry/niko-table/filters/table-column-title.js +20 -0
- package/dist/components/registry/niko-table/filters/table-faceted-filter.d.ts +40 -0
- package/dist/components/registry/niko-table/filters/table-faceted-filter.js +210 -0
- package/dist/components/registry/niko-table/hooks/use-derived-column-title.d.ts +29 -0
- package/dist/components/registry/niko-table/hooks/use-derived-column-title.js +40 -0
- package/dist/components/registry/niko-table/hooks/use-generated-options.d.ts +49 -0
- package/dist/components/registry/niko-table/hooks/use-generated-options.js +144 -0
- package/dist/components/registry/niko-table/lib/build-faceted-options.d.ts +59 -0
- package/dist/components/registry/niko-table/lib/build-faceted-options.js +82 -0
- package/dist/components/registry/niko-table/lib/column-resize-handle.d.ts +33 -0
- package/dist/components/registry/niko-table/lib/column-resize-handle.js +175 -0
- package/dist/components/registry/niko-table/lib/constants.d.ts +128 -0
- package/dist/components/registry/niko-table/lib/constants.js +123 -0
- package/dist/components/registry/niko-table/lib/create-scroll-handler.d.ts +35 -0
- package/dist/components/registry/niko-table/lib/create-scroll-handler.js +63 -0
- package/dist/components/registry/niko-table/lib/data-table-features.d.ts +218 -0
- package/dist/components/registry/niko-table/lib/data-table-features.js +127 -0
- package/dist/components/registry/niko-table/lib/filter-functions.d.ts +47 -0
- package/dist/components/registry/niko-table/lib/filter-functions.js +309 -0
- package/dist/components/registry/niko-table/lib/filter-rows.d.ts +14 -0
- package/dist/components/registry/niko-table/lib/filter-rows.js +28 -0
- package/dist/components/registry/niko-table/lib/flex-columns.d.ts +48 -0
- package/dist/components/registry/niko-table/lib/flex-columns.js +65 -0
- package/dist/components/registry/niko-table/lib/format.d.ts +33 -0
- package/dist/components/registry/niko-table/lib/format.js +99 -0
- package/dist/components/registry/niko-table/lib/render-cell-content.d.ts +17 -0
- package/dist/components/registry/niko-table/lib/render-cell-content.js +65 -0
- package/dist/components/registry/niko-table/lib/row-click.d.ts +67 -0
- package/dist/components/registry/niko-table/lib/row-click.js +28 -0
- package/dist/components/registry/niko-table/lib/styles.d.ts +6 -0
- package/dist/components/registry/niko-table/lib/styles.js +24 -0
- package/dist/components/registry/niko-table/lib/use-header-min-widths.d.ts +17 -0
- package/dist/components/registry/niko-table/lib/use-header-min-widths.js +82 -0
- package/dist/components/registry/niko-table/types/index.d.ts +141 -0
- package/dist/components/registry/niko-table/types/index.js +2 -0
- package/dist/components/registry/niko-table/ui/table.d.ts +13 -0
- package/dist/components/registry/niko-table/ui/table.js +74 -0
- package/dist/components/registry/sidebar-07/app-sidebar.d.ts +18 -0
- package/dist/components/registry/sidebar-07/app-sidebar.js +26 -0
- package/dist/components/registry/sidebar-07/nav-main.d.ts +15 -0
- package/dist/components/registry/sidebar-07/nav-main.js +25 -0
- package/dist/components/registry/sidebar-07/nav-projects.d.ts +9 -0
- package/dist/components/registry/sidebar-07/nav-projects.js +43 -0
- package/dist/components/registry/sidebar-07/nav-user.d.ts +9 -0
- package/dist/components/registry/sidebar-07/nav-user.js +70 -0
- package/dist/components/registry/sidebar-07/team-switcher.d.ts +10 -0
- package/dist/components/registry/sidebar-07/team-switcher.js +70 -0
- package/dist/components/siyahi/delta.d.ts +10 -0
- package/dist/components/siyahi/delta.js +27 -0
- package/dist/components/siyahi/local-time.d.ts +7 -0
- package/dist/components/siyahi/local-time.js +22 -0
- package/dist/components/siyahi/price-chart.d.ts +12 -0
- package/dist/components/siyahi/price-chart.js +80 -0
- package/dist/components/siyahi/siyahi-provider.d.ts +12 -0
- package/dist/components/siyahi/siyahi-provider.js +31 -0
- package/dist/components/siyahi/treemap.d.ts +14 -0
- package/dist/components/siyahi/treemap.js +58 -0
- package/dist/components/ui/alert.d.ts +12 -0
- package/dist/components/ui/alert.js +43 -0
- package/dist/components/ui/avatar.d.ts +13 -0
- package/dist/components/ui/avatar.js +50 -0
- package/dist/components/ui/badge.d.ts +9 -0
- package/dist/components/ui/badge.js +29 -0
- package/dist/components/ui/breadcrumb.d.ts +12 -0
- package/dist/components/ui/breadcrumb.js +72 -0
- package/dist/components/ui/button.d.ts +10 -0
- package/dist/components/ui/button.js +44 -0
- package/dist/components/ui/calendar.d.ts +12 -0
- package/dist/components/ui/calendar.js +107 -0
- package/dist/components/ui/card.d.ts +13 -0
- package/dist/components/ui/card.js +56 -0
- package/dist/components/ui/chart.d.ts +46 -0
- package/dist/components/ui/chart.js +149 -0
- package/dist/components/ui/collapsible.d.ts +7 -0
- package/dist/components/ui/collapsible.js +24 -0
- package/dist/components/ui/command.d.ts +21 -0
- package/dist/components/ui/command.js +88 -0
- package/dist/components/ui/context-menu.d.ts +31 -0
- package/dist/components/ui/context-menu.js +132 -0
- package/dist/components/ui/dialog.d.ts +19 -0
- package/dist/components/ui/dialog.js +91 -0
- package/dist/components/ui/dropdown-menu.d.ts +31 -0
- package/dist/components/ui/dropdown-menu.js +136 -0
- package/dist/components/ui/input-group.d.ts +20 -0
- package/dist/components/ui/input-group.js +79 -0
- package/dist/components/ui/input.d.ts +5 -0
- package/dist/components/ui/input.js +15 -0
- package/dist/components/ui/popover.d.ts +11 -0
- package/dist/components/ui/popover.js +55 -0
- package/dist/components/ui/progress.d.ts +9 -0
- package/dist/components/ui/progress.js +43 -0
- package/dist/components/ui/scroll-area.d.ts +7 -0
- package/dist/components/ui/scroll-area.js +36 -0
- package/dist/components/ui/select.d.ts +17 -0
- package/dist/components/ui/select.js +97 -0
- package/dist/components/ui/separator.d.ts +5 -0
- package/dist/components/ui/separator.js +15 -0
- package/dist/components/ui/sheet.d.ts +16 -0
- package/dist/components/ui/sheet.js +89 -0
- package/dist/components/ui/sidebar.d.ts +65 -0
- package/dist/components/ui/sidebar.js +385 -0
- package/dist/components/ui/skeleton.d.ts +4 -0
- package/dist/components/ui/skeleton.js +12 -0
- package/dist/components/ui/slider.d.ts +5 -0
- package/dist/components/ui/slider.js +33 -0
- package/dist/components/ui/table.d.ts +12 -0
- package/dist/components/ui/table.js +66 -0
- package/dist/components/ui/tabs.d.ts +12 -0
- package/dist/components/ui/tabs.js +45 -0
- package/dist/components/ui/textarea.d.ts +5 -0
- package/dist/components/ui/textarea.js +13 -0
- package/dist/components/ui/toggle-group.d.ts +13 -0
- package/dist/components/ui/toggle-group.js +52 -0
- package/dist/components/ui/toggle.d.ts +10 -0
- package/dist/components/ui/toggle.js +36 -0
- package/dist/components/ui/tooltip.d.ts +8 -0
- package/dist/components/ui/tooltip.js +41 -0
- package/dist/hooks/use-mobile.d.ts +3 -0
- package/dist/hooks/use-mobile.js +18 -0
- package/dist/index.d.ts +73 -0
- package/dist/index.js +71 -0
- package/dist/lib/format.d.ts +24 -0
- package/dist/lib/format.js +58 -0
- package/dist/lib/locale.d.ts +12 -0
- package/dist/lib/locale.js +8 -0
- package/dist/lib/recharts.d.ts +2 -0
- package/dist/lib/recharts.js +1 -0
- package/dist/lib/utils.d.ts +2 -0
- package/dist/lib/utils.js +1 -0
- package/package.json +78 -3
- package/registry.lock.json +413 -0
- package/report.css +129 -0
- package/styles/shadcn.css +643 -0
- package/styles/siyahi.css +189 -0
|
@@ -0,0 +1,370 @@
|
|
|
1
|
+
import { Skeleton } from "../../../ui/skeleton.js";
|
|
2
|
+
import { cn } from "../../../../lib/utils.js";
|
|
3
|
+
import { DataTableColumnHeaderRoot } from "../components/data-table-column-header.js";
|
|
4
|
+
import { flashCellKey, useDataTable } from "./data-table-context.js";
|
|
5
|
+
import { DataTableEmptyState } from "../components/data-table-empty-state.js";
|
|
6
|
+
import { resolveGroupedRowsSlot } from "../components/data-table-grouped-rows.js";
|
|
7
|
+
import { useResolvedRowContextMenuRenderer } from "../components/data-table-row-context-menu-slot.js";
|
|
8
|
+
import { DataTableRowContextMenu } from "../components/data-table-row-context-menu.js";
|
|
9
|
+
import { TableBody, TableCell, TableHead, TableHeader, TableRow } from "../ui/table.js";
|
|
10
|
+
import { resolveRowFromClick } from "../lib/row-click.js";
|
|
11
|
+
import { getCommonPinningStyles } from "../lib/styles.js";
|
|
12
|
+
import { GroupedBodyRow } from "./data-table-grouped-row.js";
|
|
13
|
+
import { isGlobalFilterActive } from "../lib/filter-functions.js";
|
|
14
|
+
import { DataTableColumnResizeHandle } from "../lib/column-resize-handle.js";
|
|
15
|
+
import { createScrollHandler } from "../lib/create-scroll-handler.js";
|
|
16
|
+
import { renderCellContent } from "../lib/render-cell-content.js";
|
|
17
|
+
import { resolveColumnWidth, resolveFlexColumnIds } from "../lib/flex-columns.js";
|
|
18
|
+
import React from "react";
|
|
19
|
+
import { Fragment as Fragment$1, jsx, jsxs } from "react/jsx-runtime";
|
|
20
|
+
import { flexRender } from "@tanstack/react-table";
|
|
21
|
+
//#region src/components/registry/niko-table/core/data-table-structure.tsx
|
|
22
|
+
const DataTableHeader = React.memo(function DataTableHeader({ className, sticky = true }) {
|
|
23
|
+
const { table, headerMinWidths, setColumnResizePreview } = useDataTable();
|
|
24
|
+
const resizing = table?.options.enableColumnResizing ?? false;
|
|
25
|
+
const headerGroups = table?.getHeaderGroups() ?? [];
|
|
26
|
+
if (headerGroups.length === 0) return null;
|
|
27
|
+
const flexColumnIds = resolveFlexColumnIds(table);
|
|
28
|
+
const columnSizing = table.state.columnSizing;
|
|
29
|
+
return /* @__PURE__ */ jsx(TableHeader, {
|
|
30
|
+
className: cn(sticky && "sticky top-0 z-30 bg-background", sticky && "after:absolute after:right-0 after:bottom-0 after:left-0 after:h-px after:bg-border", className),
|
|
31
|
+
children: headerGroups.map((headerGroup) => /* @__PURE__ */ jsx(TableRow, { children: headerGroup.headers.map((header) => {
|
|
32
|
+
const isFlex = flexColumnIds.has(header.column.id);
|
|
33
|
+
const headerStyle = {
|
|
34
|
+
width: resolveColumnWidth(header.column, {
|
|
35
|
+
resizing,
|
|
36
|
+
isFlex,
|
|
37
|
+
columnSizing,
|
|
38
|
+
headerMinWidths
|
|
39
|
+
}),
|
|
40
|
+
...getCommonPinningStyles(header.column, true)
|
|
41
|
+
};
|
|
42
|
+
return /* @__PURE__ */ jsxs(TableHead, {
|
|
43
|
+
"data-col-id": header.column.id,
|
|
44
|
+
style: headerStyle,
|
|
45
|
+
className: cn(header.column.getIsPinned() && "bg-background", resizing && "relative overflow-hidden"),
|
|
46
|
+
children: [header.isPlaceholder ? null : /* @__PURE__ */ jsx(DataTableColumnHeaderRoot, {
|
|
47
|
+
column: header.column,
|
|
48
|
+
children: resizing && typeof header.column.columnDef.header === "string" ? /* @__PURE__ */ jsx("span", {
|
|
49
|
+
className: "inline-block max-w-full truncate",
|
|
50
|
+
children: header.column.columnDef.header
|
|
51
|
+
}) : flexRender(header.column.columnDef.header, header.getContext())
|
|
52
|
+
}), resizing && header.column.getCanResize() && /* @__PURE__ */ jsx(DataTableColumnResizeHandle, {
|
|
53
|
+
header,
|
|
54
|
+
isFlex,
|
|
55
|
+
setResizePreview: setColumnResizePreview
|
|
56
|
+
})]
|
|
57
|
+
}, header.id);
|
|
58
|
+
}) }, headerGroup.id))
|
|
59
|
+
});
|
|
60
|
+
});
|
|
61
|
+
DataTableHeader.displayName = "DataTableHeader";
|
|
62
|
+
/** Fade-pulse animation applied to a flashing cell (keyframe in the provider). */
|
|
63
|
+
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 expandCell = isExpanded && expandColumnId ? row.getAllCells().find((c) => c.column.id === expandColumnId) : void 0;
|
|
66
|
+
const visibleCells = row.getVisibleCells();
|
|
67
|
+
const rowElement = /* @__PURE__ */ jsx(TableRow, {
|
|
68
|
+
"data-row-index": displayIndex,
|
|
69
|
+
"data-row-id": row.id,
|
|
70
|
+
"data-row-type": row.original?.rowType,
|
|
71
|
+
"data-parity": displayIndex % 2 === 0 ? "even" : "odd",
|
|
72
|
+
"data-expanded": isExpanded ? "true" : void 0,
|
|
73
|
+
"data-state": isSelected ? "selected" : void 0,
|
|
74
|
+
className: cn(isClickable && "cursor-pointer", "group data-[context-menu-open]:bg-muted/50"),
|
|
75
|
+
children: visibleCells.map((cell) => {
|
|
76
|
+
const flashing = isRowFlashing || flashingCellKeys.has(flashCellKey(row.id, cell.column.id));
|
|
77
|
+
const cellStyle = {
|
|
78
|
+
width: columnWidths.get(cell.column.id),
|
|
79
|
+
...getCommonPinningStyles(cell.column, false),
|
|
80
|
+
...flashing ? { animation: FLASH_ANIMATION } : {}
|
|
81
|
+
};
|
|
82
|
+
return /* @__PURE__ */ jsx(TableCell, {
|
|
83
|
+
"data-flash": flashing ? "true" : void 0,
|
|
84
|
+
"data-col-id": cell.column.id,
|
|
85
|
+
style: cellStyle,
|
|
86
|
+
className: cn(!cell.getIsGrouped() && "truncate", cell.column.getIsPinned() && "bg-background group-hover:bg-muted/50 group-data-[context-menu-open]:bg-muted/50 group-data-[state=selected]:bg-muted"),
|
|
87
|
+
children: renderCellContent(cell)
|
|
88
|
+
}, cell.id);
|
|
89
|
+
})
|
|
90
|
+
});
|
|
91
|
+
const menuItems = renderRowContextMenu?.(row.original);
|
|
92
|
+
return /* @__PURE__ */ jsxs(Fragment$1, { children: [menuItems ? /* @__PURE__ */ jsx(DataTableRowContextMenu, {
|
|
93
|
+
row: row.original,
|
|
94
|
+
trigger: rowElement,
|
|
95
|
+
children: menuItems
|
|
96
|
+
}) : rowElement, expandCell && /* @__PURE__ */ jsx(TableRow, { children: /* @__PURE__ */ jsx(TableCell, {
|
|
97
|
+
colSpan: visibleCells.length,
|
|
98
|
+
className: "p-0",
|
|
99
|
+
children: expandCell.column.columnDef.meta?.expandedContent?.(row.original)
|
|
100
|
+
}) })] });
|
|
101
|
+
});
|
|
102
|
+
BodyRow.displayName = "BodyRow";
|
|
103
|
+
function DataTableBody({ children, className, onScroll, onScrolledTop, onScrolledBottom, scrollThreshold = 50, onRowClick, getRowMemoKey, renderRowContextMenu }) {
|
|
104
|
+
const { table, columns, isLoading, flashingRowIds, flashingCellKeys, registerRowScroller, headerMinWidths } = useDataTable();
|
|
105
|
+
const { rows } = table.getRowModel();
|
|
106
|
+
const containerRef = React.useRef(null);
|
|
107
|
+
React.useEffect(() => {
|
|
108
|
+
registerRowScroller((index, opts) => {
|
|
109
|
+
const row = (containerRef.current?.closest("[data-slot=\"table-container\"]"))?.querySelector(`[data-row-index="${index}"]`);
|
|
110
|
+
const block = opts?.align === void 0 || opts.align === "auto" ? "nearest" : opts.align;
|
|
111
|
+
row?.scrollIntoView({ block });
|
|
112
|
+
});
|
|
113
|
+
return () => registerRowScroller(null);
|
|
114
|
+
}, [registerRowScroller]);
|
|
115
|
+
React.useEffect(() => {
|
|
116
|
+
const container = containerRef.current?.closest("[data-slot=\"table-container\"]");
|
|
117
|
+
if (!container) return;
|
|
118
|
+
if (!onScroll && !onScrolledTop && !onScrolledBottom) return;
|
|
119
|
+
const handleScroll = createScrollHandler({
|
|
120
|
+
onScroll,
|
|
121
|
+
onScrolledTop,
|
|
122
|
+
onScrolledBottom,
|
|
123
|
+
scrollThreshold
|
|
124
|
+
});
|
|
125
|
+
container.addEventListener("scroll", handleScroll, { passive: true });
|
|
126
|
+
return () => container.removeEventListener("scroll", handleScroll);
|
|
127
|
+
}, [
|
|
128
|
+
onScroll,
|
|
129
|
+
onScrolledTop,
|
|
130
|
+
onScrolledBottom,
|
|
131
|
+
scrollThreshold
|
|
132
|
+
]);
|
|
133
|
+
const handleBodyClick = React.useCallback((event) => {
|
|
134
|
+
if (!onRowClick) return;
|
|
135
|
+
const row = resolveRowFromClick(event.target, table);
|
|
136
|
+
if (!row) return;
|
|
137
|
+
onRowClick(row.original, event);
|
|
138
|
+
}, [onRowClick, table]);
|
|
139
|
+
const expandColumnId = React.useMemo(() => table.getAllColumns().find((col) => col.columnDef.meta?.expandedContent)?.id, [table, columns]);
|
|
140
|
+
const { columnVisibility, columnOrder, columnPinning, columnSizing } = table.state;
|
|
141
|
+
const resizing = table.options.enableColumnResizing ?? false;
|
|
142
|
+
const flexColumnIds = React.useMemo(() => resolveFlexColumnIds(table), [
|
|
143
|
+
table,
|
|
144
|
+
columnVisibility,
|
|
145
|
+
columnOrder,
|
|
146
|
+
columnPinning,
|
|
147
|
+
columnSizing,
|
|
148
|
+
resizing
|
|
149
|
+
]);
|
|
150
|
+
const columnWidths = React.useMemo(() => {
|
|
151
|
+
const widths = /* @__PURE__ */ new Map();
|
|
152
|
+
for (const col of table.getVisibleLeafColumns()) widths.set(col.id, resolveColumnWidth(col, {
|
|
153
|
+
resizing,
|
|
154
|
+
isFlex: flexColumnIds.has(col.id),
|
|
155
|
+
columnSizing,
|
|
156
|
+
headerMinWidths
|
|
157
|
+
}));
|
|
158
|
+
return widths;
|
|
159
|
+
}, [
|
|
160
|
+
table,
|
|
161
|
+
flexColumnIds,
|
|
162
|
+
columnSizing,
|
|
163
|
+
columnVisibility,
|
|
164
|
+
columnOrder,
|
|
165
|
+
headerMinWidths,
|
|
166
|
+
resizing
|
|
167
|
+
]);
|
|
168
|
+
const columnLayoutSignature = React.useMemo(() => table.getVisibleLeafColumns().map((c) => {
|
|
169
|
+
const pinned = c.getIsPinned();
|
|
170
|
+
const base = pinned ? `${c.id}:${pinned}` : c.id;
|
|
171
|
+
return resizing ? `${base}:${columnWidths.get(c.id) ?? "flex"}` : base;
|
|
172
|
+
}).join(","), [
|
|
173
|
+
table,
|
|
174
|
+
columns,
|
|
175
|
+
columnWidths,
|
|
176
|
+
resizing
|
|
177
|
+
]);
|
|
178
|
+
const isClickable = !!onRowClick;
|
|
179
|
+
const resolvedRenderRowContextMenu = useResolvedRowContextMenuRenderer(renderRowContextMenu, children);
|
|
180
|
+
const groupedRowsSlot = React.useMemo(() => resolveGroupedRowsSlot(children), [children]);
|
|
181
|
+
const tableStyleSnapshotRef = React.useRef(null);
|
|
182
|
+
React.useLayoutEffect(() => {
|
|
183
|
+
const tableEl = containerRef.current?.closest("[data-slot=\"table\"]");
|
|
184
|
+
if (!tableEl) return;
|
|
185
|
+
const restore = () => {
|
|
186
|
+
const snap = tableStyleSnapshotRef.current;
|
|
187
|
+
if (!snap) return;
|
|
188
|
+
tableEl.style.tableLayout = snap.tableLayout;
|
|
189
|
+
tableEl.style.width = snap.width;
|
|
190
|
+
tableEl.style.minWidth = snap.minWidth;
|
|
191
|
+
tableStyleSnapshotRef.current = null;
|
|
192
|
+
};
|
|
193
|
+
if (!resizing) {
|
|
194
|
+
restore();
|
|
195
|
+
return;
|
|
196
|
+
}
|
|
197
|
+
if (!tableStyleSnapshotRef.current) tableStyleSnapshotRef.current = {
|
|
198
|
+
tableLayout: tableEl.style.tableLayout,
|
|
199
|
+
width: tableEl.style.width,
|
|
200
|
+
minWidth: tableEl.style.minWidth
|
|
201
|
+
};
|
|
202
|
+
const totalDesiredWidth = table.getVisibleLeafColumns().reduce((sum, col) => {
|
|
203
|
+
const width = columnWidths.get(col.id);
|
|
204
|
+
return sum + (typeof width === "number" ? width : col.getSize());
|
|
205
|
+
}, 0);
|
|
206
|
+
const hasFlex = flexColumnIds.size > 0;
|
|
207
|
+
tableEl.style.tableLayout = "fixed";
|
|
208
|
+
tableEl.style.width = hasFlex ? "100%" : `${totalDesiredWidth}px`;
|
|
209
|
+
tableEl.style.minWidth = `${totalDesiredWidth}px`;
|
|
210
|
+
return restore;
|
|
211
|
+
}, [
|
|
212
|
+
resizing,
|
|
213
|
+
table,
|
|
214
|
+
columnWidths,
|
|
215
|
+
flexColumnIds,
|
|
216
|
+
columnVisibility,
|
|
217
|
+
columnOrder,
|
|
218
|
+
columnPinning
|
|
219
|
+
]);
|
|
220
|
+
return /* @__PURE__ */ jsxs(TableBody, {
|
|
221
|
+
ref: containerRef,
|
|
222
|
+
className,
|
|
223
|
+
onClick: onRowClick ? handleBodyClick : void 0,
|
|
224
|
+
children: [!isLoading && rows?.length ? rows.map((row, displayIndex) => groupedRowsSlot && row.getIsGrouped() ? /* @__PURE__ */ jsx(GroupedBodyRow, {
|
|
225
|
+
row,
|
|
226
|
+
displayIndex,
|
|
227
|
+
isExpanded: row.getIsExpanded(),
|
|
228
|
+
columnWidths,
|
|
229
|
+
columnLayoutSignature,
|
|
230
|
+
slot: groupedRowsSlot
|
|
231
|
+
}, row.id) : /* @__PURE__ */ jsx(BodyRow, {
|
|
232
|
+
row,
|
|
233
|
+
displayIndex,
|
|
234
|
+
expandColumnId,
|
|
235
|
+
isClickable,
|
|
236
|
+
isExpanded: row.getIsExpanded(),
|
|
237
|
+
isSelected: row.getIsSelected(),
|
|
238
|
+
columnWidths,
|
|
239
|
+
columnLayoutSignature,
|
|
240
|
+
rowMemoKey: getRowMemoKey ? getRowMemoKey(row.original) : "",
|
|
241
|
+
isRowFlashing: flashingRowIds.has(row.id),
|
|
242
|
+
flashingCellKeys,
|
|
243
|
+
renderRowContextMenu: resolvedRenderRowContextMenu
|
|
244
|
+
}, row.id)) : null, children]
|
|
245
|
+
});
|
|
246
|
+
}
|
|
247
|
+
DataTableBody.displayName = "DataTableBody";
|
|
248
|
+
/**
|
|
249
|
+
* Empty state component for data tables.
|
|
250
|
+
* Use composition pattern with DataTableEmpty* components for full customization.
|
|
251
|
+
*
|
|
252
|
+
* @example
|
|
253
|
+
* <DataTableEmptyBody>
|
|
254
|
+
* <DataTableEmptyIcon>
|
|
255
|
+
* <PackageOpen className="size-12" />
|
|
256
|
+
* </DataTableEmptyIcon>
|
|
257
|
+
* <DataTableEmptyMessage>
|
|
258
|
+
* <DataTableEmptyTitle>No products found</DataTableEmptyTitle>
|
|
259
|
+
* <DataTableEmptyDescription>
|
|
260
|
+
* Get started by adding your first product
|
|
261
|
+
* </DataTableEmptyDescription>
|
|
262
|
+
* </DataTableEmptyMessage>
|
|
263
|
+
* <DataTableEmptyFilteredMessage>
|
|
264
|
+
* No matches found
|
|
265
|
+
* </DataTableEmptyFilteredMessage>
|
|
266
|
+
* <DataTableEmptyActions>
|
|
267
|
+
* <Button onClick={handleAdd}>Add Product</Button>
|
|
268
|
+
* </DataTableEmptyActions>
|
|
269
|
+
* </DataTableEmptyBody>
|
|
270
|
+
*/
|
|
271
|
+
function DataTableEmptyBody({ children, colSpan, className }) {
|
|
272
|
+
const { table, columns, isLoading } = useDataTable();
|
|
273
|
+
const tableState = table.state;
|
|
274
|
+
const isFiltered = React.useMemo(() => isGlobalFilterActive(tableState.globalFilter) || tableState.columnFilters && tableState.columnFilters.length > 0, [tableState.globalFilter, tableState.columnFilters]);
|
|
275
|
+
const rowCount = table.getRowModel().rows.length;
|
|
276
|
+
if (isLoading || rowCount > 0) return null;
|
|
277
|
+
const visibleCount = table.getVisibleLeafColumns().length;
|
|
278
|
+
return /* @__PURE__ */ jsx(TableRow, { children: /* @__PURE__ */ jsx(TableCell, {
|
|
279
|
+
colSpan: colSpan ?? (visibleCount || columns.length),
|
|
280
|
+
className,
|
|
281
|
+
children: /* @__PURE__ */ jsx(DataTableEmptyState, {
|
|
282
|
+
isFiltered,
|
|
283
|
+
children
|
|
284
|
+
})
|
|
285
|
+
}) });
|
|
286
|
+
}
|
|
287
|
+
DataTableEmptyBody.displayName = "DataTableEmptyBody";
|
|
288
|
+
function DataTableSkeleton({ children, colSpan, rows = 5, className, cellClassName, skeletonClassName }) {
|
|
289
|
+
const { table, columns, isLoading } = useDataTable();
|
|
290
|
+
if (!isLoading) return null;
|
|
291
|
+
const visibleColumns = table.getVisibleLeafColumns();
|
|
292
|
+
const numColumns = colSpan ?? (visibleColumns.length || columns.length);
|
|
293
|
+
if (children) return /* @__PURE__ */ jsx(TableRow, { children: /* @__PURE__ */ jsx(TableCell, {
|
|
294
|
+
colSpan: numColumns,
|
|
295
|
+
className: cn("h-24 text-center", className),
|
|
296
|
+
children
|
|
297
|
+
}) });
|
|
298
|
+
return /* @__PURE__ */ jsx(Fragment$1, { children: Array.from({ length: rows }).map((_, rowIndex) => /* @__PURE__ */ jsx(TableRow, { children: visibleColumns.map((column, colIndex) => {
|
|
299
|
+
const size = column.columnDef.size;
|
|
300
|
+
const cellStyle = size ? { width: `${size}px` } : void 0;
|
|
301
|
+
return /* @__PURE__ */ jsx(TableCell, {
|
|
302
|
+
className: cellClassName,
|
|
303
|
+
style: cellStyle,
|
|
304
|
+
children: /* @__PURE__ */ jsx(Skeleton, { className: cn("h-4 w-full", skeletonClassName) })
|
|
305
|
+
}, colIndex);
|
|
306
|
+
}) }, rowIndex)) });
|
|
307
|
+
}
|
|
308
|
+
DataTableSkeleton.displayName = "DataTableSkeleton";
|
|
309
|
+
function DataTableLoading({ children, colSpan, className }) {
|
|
310
|
+
const { table, columns, isLoading } = useDataTable();
|
|
311
|
+
if (!isLoading) return null;
|
|
312
|
+
const visibleCount = table.getVisibleLeafColumns().length;
|
|
313
|
+
return /* @__PURE__ */ jsx(TableRow, { children: /* @__PURE__ */ jsx(TableCell, {
|
|
314
|
+
colSpan: colSpan ?? (visibleCount || columns.length),
|
|
315
|
+
className: className ?? "h-24 text-center",
|
|
316
|
+
children: children ?? /* @__PURE__ */ jsxs("div", {
|
|
317
|
+
className: "flex items-center justify-center gap-2",
|
|
318
|
+
children: [/* @__PURE__ */ jsx("div", { className: "h-4 w-4 animate-spin rounded-full border-2 border-primary border-t-transparent" }), /* @__PURE__ */ jsx("span", {
|
|
319
|
+
className: "text-sm text-muted-foreground",
|
|
320
|
+
children: "Loading..."
|
|
321
|
+
})]
|
|
322
|
+
})
|
|
323
|
+
}) });
|
|
324
|
+
}
|
|
325
|
+
DataTableLoading.displayName = "DataTableLoading";
|
|
326
|
+
/**
|
|
327
|
+
* Composable "loading more" row for infinite-scroll tables. Renders
|
|
328
|
+
* a spinner + label row at the end of the body when `isFetching` is
|
|
329
|
+
* true, and nothing when false — designed to be dropped as a child
|
|
330
|
+
* of `DataTableBody` alongside `DataTableSkeleton` and
|
|
331
|
+
* `DataTableEmptyBody`.
|
|
332
|
+
*
|
|
333
|
+
* Mirror of `DataTableVirtualizedLoadingMore` for non-virtualized
|
|
334
|
+
* tables — same API, same styling, same self-gating behavior.
|
|
335
|
+
*
|
|
336
|
+
* @example
|
|
337
|
+
* const query = api.thing.list.useInfiniteQuery(...);
|
|
338
|
+
* <DataTableBody
|
|
339
|
+
* onScrolledBottom={() => {
|
|
340
|
+
* if (query.hasNextPage && !query.isFetchingNextPage) {
|
|
341
|
+
* void query.fetchNextPage();
|
|
342
|
+
* }
|
|
343
|
+
* }}
|
|
344
|
+
* >
|
|
345
|
+
* <DataTableSkeleton rows={5} />
|
|
346
|
+
* <DataTableEmptyBody>No results</DataTableEmptyBody>
|
|
347
|
+
* <DataTableLoadingMore isFetching={query.isFetchingNextPage}>
|
|
348
|
+
* Loading more things…
|
|
349
|
+
* </DataTableLoadingMore>
|
|
350
|
+
* </DataTableBody>
|
|
351
|
+
*/
|
|
352
|
+
function DataTableLoadingMore({ isFetching, children, colSpan, className }) {
|
|
353
|
+
const { table, columns } = useDataTable();
|
|
354
|
+
if (!isFetching) return null;
|
|
355
|
+
const visibleCount = table.getVisibleLeafColumns().length;
|
|
356
|
+
return /* @__PURE__ */ jsx(TableRow, {
|
|
357
|
+
"data-slot": "datatable-loading-more-row",
|
|
358
|
+
children: /* @__PURE__ */ jsx(TableCell, {
|
|
359
|
+
colSpan: colSpan ?? (visibleCount || columns.length),
|
|
360
|
+
className: cn("text-center text-xs text-muted-foreground", className),
|
|
361
|
+
children: /* @__PURE__ */ jsxs("span", {
|
|
362
|
+
className: "inline-flex items-center justify-center gap-2 py-3",
|
|
363
|
+
children: [/* @__PURE__ */ jsx("span", { className: "inline-block size-3.5 animate-spin rounded-full border-2 border-muted-foreground/60 border-t-transparent" }), children ?? "Loading more…"]
|
|
364
|
+
})
|
|
365
|
+
})
|
|
366
|
+
});
|
|
367
|
+
}
|
|
368
|
+
DataTableLoadingMore.displayName = "DataTableLoadingMore";
|
|
369
|
+
//#endregion
|
|
370
|
+
export { DataTableBody, DataTableEmptyBody, DataTableHeader, DataTableLoading, DataTableLoadingMore, DataTableSkeleton };
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import React from "react";
|
|
2
|
+
//#region src/components/registry/niko-table/core/data-table.d.ts
|
|
3
|
+
export interface DataTableContainerProps {
|
|
4
|
+
children: React.ReactNode;
|
|
5
|
+
/**
|
|
6
|
+
* Additional CSS classes for the container.
|
|
7
|
+
* Arbitrary height values (e.g., h-[600px], max-h-[400px]) are automatically extracted
|
|
8
|
+
* and applied as inline styles to ensure scroll event callbacks work reliably.
|
|
9
|
+
* For other height utilities, use the height/maxHeight props directly.
|
|
10
|
+
*/
|
|
11
|
+
className?: string;
|
|
12
|
+
/**
|
|
13
|
+
* Sets the height of the table container.
|
|
14
|
+
* When provided, enables vertical scrolling and allows DataTableBody/DataTableVirtualizedBody
|
|
15
|
+
* to use onScroll, onScrolledTop, and onScrolledBottom callbacks.
|
|
16
|
+
* Takes precedence over height utilities in className.
|
|
17
|
+
*/
|
|
18
|
+
height?: number | string;
|
|
19
|
+
/**
|
|
20
|
+
* Sets the maximum height of the table container.
|
|
21
|
+
* Defaults to the height value if not specified.
|
|
22
|
+
* Takes precedence over max-height utilities in className.
|
|
23
|
+
*/
|
|
24
|
+
maxHeight?: number | string;
|
|
25
|
+
}
|
|
26
|
+
export declare function DataTable({ children, className, height, maxHeight }: DataTableContainerProps): React.JSX.Element;
|
|
27
|
+
export declare namespace DataTable {
|
|
28
|
+
var displayName: string;
|
|
29
|
+
}
|
|
30
|
+
//#endregion
|
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { cn } from "../../../../lib/utils.js";
|
|
3
|
+
import { useColumnResizeInfo, useDataTable } from "./data-table-context.js";
|
|
4
|
+
import { TableComponent } from "../ui/table.js";
|
|
5
|
+
import React from "react";
|
|
6
|
+
import { jsx, jsxs } from "react/jsx-runtime";
|
|
7
|
+
//#region src/components/registry/niko-table/core/data-table.tsx
|
|
8
|
+
/**
|
|
9
|
+
* niko-table — created by Semir N. (Semkoo, https://github.com/Semkoo) with AI assistance.
|
|
10
|
+
*
|
|
11
|
+
* Before reporting anything: please check the changelog first.
|
|
12
|
+
* - In-repo: ./CHANGELOG.md
|
|
13
|
+
* - Docs site: https://niko-table.com/changelog
|
|
14
|
+
*
|
|
15
|
+
* Found a bug or have a fix? Open an issue or PR on GitHub so other
|
|
16
|
+
* users (and future LLMs reading this code) benefit:
|
|
17
|
+
* https://github.com/Semkoo/niko-table-registry
|
|
18
|
+
*/
|
|
19
|
+
/**
|
|
20
|
+
* Extracts height from Tailwind arbitrary values (e.g., h-[600px], max-h-[400px]).
|
|
21
|
+
* Converts them to inline styles to ensure scroll events work reliably.
|
|
22
|
+
* For other height utilities, use the height/maxHeight props directly.
|
|
23
|
+
*/
|
|
24
|
+
function parseHeightFromClassName(className) {
|
|
25
|
+
if (!className) return {
|
|
26
|
+
height: void 0,
|
|
27
|
+
maxHeight: void 0,
|
|
28
|
+
safeClassName: className
|
|
29
|
+
};
|
|
30
|
+
const classes = className.split(/\s+/);
|
|
31
|
+
let height;
|
|
32
|
+
let maxHeight;
|
|
33
|
+
const remainingClasses = [];
|
|
34
|
+
for (const cls of classes) {
|
|
35
|
+
const heightMatch = cls.match(/^h-\[([^\]]+)\]$/);
|
|
36
|
+
const maxHeightMatch = cls.match(/^max-h-\[([^\]]+)\]$/);
|
|
37
|
+
if (heightMatch) height = heightMatch[1];
|
|
38
|
+
else if (maxHeightMatch) maxHeight = maxHeightMatch[1];
|
|
39
|
+
else remainingClasses.push(cls);
|
|
40
|
+
}
|
|
41
|
+
return {
|
|
42
|
+
height,
|
|
43
|
+
maxHeight,
|
|
44
|
+
safeClassName: remainingClasses.join(" ")
|
|
45
|
+
};
|
|
46
|
+
}
|
|
47
|
+
/**
|
|
48
|
+
* DataTable container component that wraps the table and provides scrolling behavior.
|
|
49
|
+
*
|
|
50
|
+
* @example
|
|
51
|
+
* Without height - table grows with content, no scroll
|
|
52
|
+
* <DataTable>
|
|
53
|
+
* <DataTableHeader />
|
|
54
|
+
* <DataTableBody />
|
|
55
|
+
* </DataTable>
|
|
56
|
+
*
|
|
57
|
+
* @example
|
|
58
|
+
* With height prop - enables scrolling and scroll event callbacks
|
|
59
|
+
* <DataTable height={600}>
|
|
60
|
+
* <DataTableHeader />
|
|
61
|
+
* <DataTableBody
|
|
62
|
+
* onScroll={(e) => console.log(`Scrolled ${e.percentage}%`)}
|
|
63
|
+
* onScrolledBottom={() => console.log('Load more data')}
|
|
64
|
+
* />
|
|
65
|
+
* </DataTable>
|
|
66
|
+
*
|
|
67
|
+
* @example
|
|
68
|
+
* With arbitrary height in className - automatically extracted and applied as inline style
|
|
69
|
+
* <DataTable className="h-[600px]">
|
|
70
|
+
* <DataTableBody onScroll={...} />
|
|
71
|
+
* </DataTable>
|
|
72
|
+
*
|
|
73
|
+
* @example
|
|
74
|
+
* Prefer using height prop for better type safety and clarity
|
|
75
|
+
* <DataTable height="600px" className="rounded-lg">
|
|
76
|
+
* <DataTableBody onScroll={...} />
|
|
77
|
+
* </DataTable>
|
|
78
|
+
*/
|
|
79
|
+
/**
|
|
80
|
+
* A single vertical guide line that follows the cursor while a column is being
|
|
81
|
+
* resized. Resizing runs in `onEnd` mode, so the columns themselves don't move
|
|
82
|
+
* until the drag ends (that's what keeps heavy tables smooth); this line gives
|
|
83
|
+
* the live "where the edge will land" feedback in the meantime.
|
|
84
|
+
*
|
|
85
|
+
* It subscribes to the dedicated resize-info context, so it — and nothing else
|
|
86
|
+
* in the table — re-renders per pointer move. Positioned in the scroll
|
|
87
|
+
* container's content space so it tracks correctly through horizontal scroll.
|
|
88
|
+
*/
|
|
89
|
+
function ColumnResizePreviewLine() {
|
|
90
|
+
const { resizingColumnId, deltaOffset } = useColumnResizeInfo();
|
|
91
|
+
const { scrollContainer } = useDataTable();
|
|
92
|
+
if (!resizingColumnId || !scrollContainer) return null;
|
|
93
|
+
const escapedId = typeof CSS !== "undefined" && CSS.escape ? CSS.escape(resizingColumnId) : resizingColumnId;
|
|
94
|
+
const cell = scrollContainer.querySelector(`thead [data-col-id="${escapedId}"]`);
|
|
95
|
+
if (!cell) return null;
|
|
96
|
+
const containerRect = scrollContainer.getBoundingClientRect();
|
|
97
|
+
const left = cell.getBoundingClientRect().right - containerRect.left + scrollContainer.scrollLeft + deltaOffset;
|
|
98
|
+
return /* @__PURE__ */ jsx("div", {
|
|
99
|
+
"aria-hidden": true,
|
|
100
|
+
"data-slot": "column-resize-preview",
|
|
101
|
+
className: "bg-primary pointer-events-none absolute top-0 z-40 w-px",
|
|
102
|
+
style: {
|
|
103
|
+
left,
|
|
104
|
+
height: scrollContainer.scrollHeight
|
|
105
|
+
}
|
|
106
|
+
});
|
|
107
|
+
}
|
|
108
|
+
function DataTable({ children, className, height, maxHeight }) {
|
|
109
|
+
const parsed = React.useMemo(() => parseHeightFromClassName(className), [className]);
|
|
110
|
+
const finalHeight = height ?? parsed.height;
|
|
111
|
+
const finalMaxHeight = maxHeight ?? parsed.maxHeight ?? finalHeight;
|
|
112
|
+
const { registerScrollContainer } = useDataTable();
|
|
113
|
+
return /* @__PURE__ */ jsxs("div", {
|
|
114
|
+
ref: registerScrollContainer,
|
|
115
|
+
"data-slot": "table-container",
|
|
116
|
+
className: cn("relative 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
|
+
style: {
|
|
118
|
+
height: finalHeight,
|
|
119
|
+
maxHeight: finalMaxHeight
|
|
120
|
+
},
|
|
121
|
+
children: [/* @__PURE__ */ jsx(TableComponent, { children }), /* @__PURE__ */ jsx(ColumnResizePreviewLine, {})]
|
|
122
|
+
});
|
|
123
|
+
}
|
|
124
|
+
DataTable.displayName = "DataTable";
|
|
125
|
+
//#endregion
|
|
126
|
+
export { DataTable };
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import React from "react";
|
|
2
|
+
//#region src/components/registry/niko-table/filters/table-column-actions.d.ts
|
|
3
|
+
export interface TableColumnActionsProps {
|
|
4
|
+
children: React.ReactNode;
|
|
5
|
+
className?: string;
|
|
6
|
+
/**
|
|
7
|
+
* Optional label shown at the top of the dropdown.
|
|
8
|
+
* @default "Column Actions"
|
|
9
|
+
*/
|
|
10
|
+
label?: string;
|
|
11
|
+
/**
|
|
12
|
+
* Whether to show a visual indicator when actions are active.
|
|
13
|
+
*/
|
|
14
|
+
isActive?: boolean;
|
|
15
|
+
/**
|
|
16
|
+
* Custom trigger element. If not provided, uses a MoreVertical icon button.
|
|
17
|
+
*/
|
|
18
|
+
trigger?: React.ReactElement;
|
|
19
|
+
/**
|
|
20
|
+
* Alignment of the dropdown content.
|
|
21
|
+
* @default "end"
|
|
22
|
+
*/
|
|
23
|
+
align?: "start" | "center" | "end";
|
|
24
|
+
}
|
|
25
|
+
/**
|
|
26
|
+
* A simple dropdown container for composing column actions.
|
|
27
|
+
*
|
|
28
|
+
* Use with `*Options` components to compose actions in a single dropdown:
|
|
29
|
+
*
|
|
30
|
+
* @example
|
|
31
|
+
* ```tsx
|
|
32
|
+
* <TableColumnActions>
|
|
33
|
+
* <TableColumnSortOptions />
|
|
34
|
+
* <TableColumnPinOptions />
|
|
35
|
+
* <TableColumnHideOptions />
|
|
36
|
+
* </TableColumnActions>
|
|
37
|
+
* ```
|
|
38
|
+
*
|
|
39
|
+
* For standalone dropdowns, use the `*Menu` variants instead:
|
|
40
|
+
* ```tsx
|
|
41
|
+
* <TableColumnSortMenu />
|
|
42
|
+
* <TableColumnPin />
|
|
43
|
+
* ```
|
|
44
|
+
*/
|
|
45
|
+
export declare function TableColumnActions({ children, className, label, isActive, trigger, align }: TableColumnActionsProps): React.JSX.Element;
|
|
46
|
+
export declare namespace TableColumnActions {
|
|
47
|
+
var displayName: string;
|
|
48
|
+
}
|
|
49
|
+
//#endregion
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import { Button } from "../../../ui/button.js";
|
|
2
|
+
import { DropdownMenu, DropdownMenuContent, DropdownMenuLabel, DropdownMenuTrigger } from "../../../ui/dropdown-menu.js";
|
|
3
|
+
import { cn } from "../../../../lib/utils.js";
|
|
4
|
+
import "react";
|
|
5
|
+
import { jsx, jsxs } from "react/jsx-runtime";
|
|
6
|
+
import { MoreVertical } from "lucide-react";
|
|
7
|
+
//#region src/components/registry/niko-table/filters/table-column-actions.tsx
|
|
8
|
+
/**
|
|
9
|
+
* A simple dropdown container for composing column actions.
|
|
10
|
+
*
|
|
11
|
+
* Use with `*Options` components to compose actions in a single dropdown:
|
|
12
|
+
*
|
|
13
|
+
* @example
|
|
14
|
+
* ```tsx
|
|
15
|
+
* <TableColumnActions>
|
|
16
|
+
* <TableColumnSortOptions />
|
|
17
|
+
* <TableColumnPinOptions />
|
|
18
|
+
* <TableColumnHideOptions />
|
|
19
|
+
* </TableColumnActions>
|
|
20
|
+
* ```
|
|
21
|
+
*
|
|
22
|
+
* For standalone dropdowns, use the `*Menu` variants instead:
|
|
23
|
+
* ```tsx
|
|
24
|
+
* <TableColumnSortMenu />
|
|
25
|
+
* <TableColumnPin />
|
|
26
|
+
* ```
|
|
27
|
+
*/
|
|
28
|
+
function TableColumnActions({ children, className, label = "Column Actions", isActive = false, trigger, align = "end" }) {
|
|
29
|
+
return /* @__PURE__ */ jsxs(DropdownMenu, { children: [/* @__PURE__ */ jsx(DropdownMenuTrigger, { render: trigger ?? /* @__PURE__ */ jsxs(Button, {
|
|
30
|
+
variant: "ghost",
|
|
31
|
+
size: "icon",
|
|
32
|
+
className: cn("size-7 transition-opacity group-hover:opacity-100 dark:text-muted-foreground", isActive ? "text-primary opacity-100" : "opacity-0", className),
|
|
33
|
+
children: [/* @__PURE__ */ jsx(MoreVertical, { className: "size-4" }), /* @__PURE__ */ jsx("span", {
|
|
34
|
+
className: "sr-only",
|
|
35
|
+
children: label
|
|
36
|
+
})]
|
|
37
|
+
}) }), /* @__PURE__ */ jsxs(DropdownMenuContent, {
|
|
38
|
+
align,
|
|
39
|
+
className: "w-48",
|
|
40
|
+
children: [/* @__PURE__ */ jsx(DropdownMenuLabel, {
|
|
41
|
+
className: "text-xs font-normal text-muted-foreground",
|
|
42
|
+
children: label
|
|
43
|
+
}), children]
|
|
44
|
+
})] });
|
|
45
|
+
}
|
|
46
|
+
TableColumnActions.displayName = "TableColumnActions";
|
|
47
|
+
//#endregion
|
|
48
|
+
export { TableColumnActions };
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import { DataTableColumn, DataTableInstance } from "../types/index.js";
|
|
2
|
+
import { SortIconVariant } from "../config/data-table.js";
|
|
3
|
+
import React from "react";
|
|
4
|
+
import { RowData } from "@tanstack/react-table";
|
|
5
|
+
//#region src/components/registry/niko-table/filters/table-column-sort.d.ts
|
|
6
|
+
/**
|
|
7
|
+
* Sort options menu items for composition inside TableColumnActions.
|
|
8
|
+
*
|
|
9
|
+
* @example
|
|
10
|
+
* ```tsx
|
|
11
|
+
* <TableColumnActions>
|
|
12
|
+
* <TableColumnSortOptions column={column} />
|
|
13
|
+
* </TableColumnActions>
|
|
14
|
+
* ```
|
|
15
|
+
*/
|
|
16
|
+
export declare function TableColumnSortOptions<TData extends RowData, TValue>({ column, table: propTable, variant: propVariant, withSeparator }: {
|
|
17
|
+
column: DataTableColumn<TData, TValue>;
|
|
18
|
+
table?: DataTableInstance<TData>;
|
|
19
|
+
variant?: SortIconVariant;
|
|
20
|
+
/** Whether to render a separator before the options. @default true */
|
|
21
|
+
withSeparator?: boolean;
|
|
22
|
+
}): React.JSX.Element;
|
|
23
|
+
export declare namespace TableColumnSortOptions {
|
|
24
|
+
var displayName: string;
|
|
25
|
+
}
|
|
26
|
+
/**
|
|
27
|
+
* Standalone dropdown menu for sorting.
|
|
28
|
+
*
|
|
29
|
+
* For composition inside TableColumnActions, use TableColumnSortOptions instead.
|
|
30
|
+
*
|
|
31
|
+
* @example
|
|
32
|
+
* ```tsx
|
|
33
|
+
* // Standalone
|
|
34
|
+
* <TableColumnSortMenu column={column} table={table} />
|
|
35
|
+
*
|
|
36
|
+
* // Composed
|
|
37
|
+
* <TableColumnActions>
|
|
38
|
+
* <TableColumnSortOptions column={column} />
|
|
39
|
+
* </TableColumnActions>
|
|
40
|
+
* ```
|
|
41
|
+
*/
|
|
42
|
+
export declare function TableColumnSortMenu<TData extends RowData, TValue>({ column, table: propTable, variant: propVariant, className }: {
|
|
43
|
+
column: DataTableColumn<TData, TValue>;
|
|
44
|
+
table?: DataTableInstance<TData>;
|
|
45
|
+
variant?: SortIconVariant;
|
|
46
|
+
className?: string;
|
|
47
|
+
}): React.JSX.Element | null;
|
|
48
|
+
export declare namespace TableColumnSortMenu {
|
|
49
|
+
var displayName: string;
|
|
50
|
+
}
|
|
51
|
+
//#endregion
|