@getgreenline/blaze-ui 1.0.22 → 1.0.23
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.
|
@@ -4,7 +4,7 @@ import { CheckIcon } from 'lucide-react';
|
|
|
4
4
|
import { cn } from '../lib/utils.js';
|
|
5
5
|
|
|
6
6
|
function Checkbox({ className, ...props }) {
|
|
7
|
-
return (jsx(CheckboxPrimitive.Root, { "data-slot": "checkbox", className: cn("tw:!peer tw:!border-border dark:tw:!bg-input/30 data-[state=checked]
|
|
7
|
+
return (jsx(CheckboxPrimitive.Root, { "data-slot": "checkbox", className: cn("tw:!peer tw:!border-border dark:tw:!bg-input/30 tw:data-[state=checked]:!bg-primary tw:data-[state=checked]:!text-primary-foreground dark:tw:data-[state=checked]:!bg-primary tw:data-[state=checked]:!border-primary tw:focus-visible:!border-ring tw:focus-visible:!ring-ring/50 aria-invalid:tw:!ring-destructive/20 dark:aria-invalid:tw:!ring-destructive/40 aria-invalid:tw:!border-destructive tw:!size-4 tw:!shrink-0 tw:!rounded-[4px] tw:!border tw:!shadow-xs tw:!transition-shadow tw:!outline-none tw:focus-visible:!ring-[3px] disabled:tw:!cursor-not-allowed disabled:tw:!opacity-50 tw:!align-middle", className), ...props, children: jsx(CheckboxPrimitive.Indicator, { "data-slot": "checkbox-indicator", className: "tw:!flex tw:!items-center tw:!justify-center tw:!text-current tw:!transition-none", children: jsx(CheckIcon, { className: "tw:size-3.5" }) }) }));
|
|
8
8
|
}
|
|
9
9
|
|
|
10
10
|
export { Checkbox };
|
|
@@ -28,10 +28,11 @@ export interface DataTableAction<T> {
|
|
|
28
28
|
}
|
|
29
29
|
export type PaginationMode = "offset" | "cursor";
|
|
30
30
|
export interface DataTablePaginationProps {
|
|
31
|
-
currentPage
|
|
32
|
-
totalPages
|
|
33
|
-
onPageChange
|
|
31
|
+
currentPage?: number;
|
|
32
|
+
totalPages?: number;
|
|
33
|
+
onPageChange?: (page: number) => void;
|
|
34
34
|
pageSize?: number;
|
|
35
|
+
defaultPageSize?: number;
|
|
35
36
|
totalItems?: number;
|
|
36
37
|
pageSizeOptions?: number[];
|
|
37
38
|
onPageSizeChange?: (pageSize: number) => void;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"data-table.d.ts","sourceRoot":"","sources":["../../src/components/data-table.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAA;AAC9B,OAAO,EAAyE,KAAK,EAA4C,CAAC,EAAE,MAAM,cAAc,CAAA;AAiBxJ,MAAM,MAAM,aAAa,GAAG,KAAK,GAAG,MAAM,GAAG,IAAI,CAAA;AAEjD,MAAM,WAAW,eAAe,CAAC,CAAC;IAChC,GAAG,EAAE,MAAM,CAAA;IACX,KAAK,EAAE,MAAM,CAAA;IACb,QAAQ,CAAC,EAAE,OAAO,CAAA;IAClB,KAAK,CAAC,EAAE,MAAM,GAAG,QAAQ,GAAG,OAAO,CAAA;IACnC,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB,MAAM,CAAC,EAAE,CAAC,KAAK,EAAE,GAAG,EAAE,GAAG,EAAE,CAAC,EAAE,KAAK,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,KAAK,KAAK,CAAC,SAAS,CAAA;CAC/E;AAED,MAAM,WAAW,YAAY;IAC3B,EAAE,EAAE,MAAM,CAAA;IACV,QAAQ,CAAC,EAAE,YAAY,EAAE,CAAA;IACzB,CAAC,GAAG,EAAE,MAAM,GAAG,GAAG,CAAA;CACnB;AAED,MAAM,WAAW,eAAe,CAAC,CAAC,GAAG,GAAG;IACtC,KAAK,EAAE,MAAM,CAAA;IACb,OAAO,EAAE,CAAC,GAAG,EAAE,CAAC,KAAK,IAAI,CAAA;CAC1B;AAED,MAAM,WAAW,eAAe,CAAC,CAAC;IAChC,KAAK,EAAE,MAAM,CAAA;IACb,IAAI,CAAC,EAAE,KAAK,CAAC,SAAS,CAAA;IACtB,OAAO,EAAE,CAAC,GAAG,EAAE,CAAC,KAAK,IAAI,CAAA;IACzB,OAAO,CAAC,EAAE,SAAS,GAAG,aAAa,CAAA;IACnC,SAAS,CAAC,EAAE,CAAC,GAAG,EAAE,CAAC,KAAK,OAAO,CAAA;CAChC;AAED,MAAM,MAAM,cAAc,GAAG,QAAQ,GAAG,QAAQ,CAAA;AAIhD,MAAM,WAAW,wBAAwB;IACvC,WAAW,EAAE,MAAM,CAAA;
|
|
1
|
+
{"version":3,"file":"data-table.d.ts","sourceRoot":"","sources":["../../src/components/data-table.tsx"],"names":[],"mappings":"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"}
|
|
@@ -14,6 +14,8 @@ function DataTable({ columns, data, onSelectionChange, selectedRowIds, onSort, s
|
|
|
14
14
|
const [internalSelectedRows, setInternalSelectedRows] = React.useState(new Set());
|
|
15
15
|
const [internalExpandedRows, setInternalExpandedRows] = React.useState(new Set());
|
|
16
16
|
const [internalSortConfig, setInternalSortConfig] = React.useState({ key: "", direction: null });
|
|
17
|
+
const [internalPage, setInternalPage] = React.useState(1);
|
|
18
|
+
const [internalPageSize, setInternalPageSize] = React.useState(pagination?.defaultPageSize || 10);
|
|
17
19
|
const [hiddenColumns, setHiddenColumns] = React.useState([]);
|
|
18
20
|
const [draggedRowId, setDraggedRowId] = React.useState(null);
|
|
19
21
|
const [dragOverRowId, setDragOverRowId] = React.useState(null);
|
|
@@ -66,22 +68,6 @@ function DataTable({ columns, data, onSelectionChange, selectedRowIds, onSort, s
|
|
|
66
68
|
const selectedIdsArray = Array.from(newSelected);
|
|
67
69
|
onSelectionChange?.(selectedIdsArray);
|
|
68
70
|
};
|
|
69
|
-
const toggleAllRows = () => {
|
|
70
|
-
const currentPageIds = data.map((row) => row.id);
|
|
71
|
-
const allCurrentPageSelected = currentPageIds.every(id => selectedRows.has(id));
|
|
72
|
-
let newSelected;
|
|
73
|
-
if (allCurrentPageSelected) {
|
|
74
|
-
newSelected = new Set(selectedRows);
|
|
75
|
-
currentPageIds.forEach(id => newSelected.delete(id));
|
|
76
|
-
}
|
|
77
|
-
else {
|
|
78
|
-
newSelected = new Set(selectedRows);
|
|
79
|
-
currentPageIds.forEach(id => newSelected.add(id));
|
|
80
|
-
}
|
|
81
|
-
setSelectedRows(newSelected);
|
|
82
|
-
const selectedIdsArray = Array.from(newSelected);
|
|
83
|
-
onSelectionChange?.(selectedIdsArray);
|
|
84
|
-
};
|
|
85
71
|
const toggleRowExpansion = (rowId) => {
|
|
86
72
|
const newExpanded = new Set(expandedRows);
|
|
87
73
|
if (newExpanded.has(rowId)) {
|
|
@@ -108,6 +94,78 @@ function DataTable({ columns, data, onSelectionChange, selectedRowIds, onSort, s
|
|
|
108
94
|
}
|
|
109
95
|
onSort?.(key, direction);
|
|
110
96
|
};
|
|
97
|
+
const processedData = React.useMemo(() => {
|
|
98
|
+
let result = [...data];
|
|
99
|
+
if (!onSort && sortConfig.key && sortConfig.direction) {
|
|
100
|
+
result.sort((a, b) => {
|
|
101
|
+
const aValue = a[sortConfig.key];
|
|
102
|
+
const bValue = b[sortConfig.key];
|
|
103
|
+
if (aValue === bValue)
|
|
104
|
+
return 0;
|
|
105
|
+
const comparison = aValue < bValue ? -1 : 1;
|
|
106
|
+
return sortConfig.direction === "asc" ? comparison : -comparison;
|
|
107
|
+
});
|
|
108
|
+
}
|
|
109
|
+
return result;
|
|
110
|
+
}, [data, sortConfig, onSort]);
|
|
111
|
+
const effectivePagination = React.useMemo(() => {
|
|
112
|
+
const currentPage = pagination?.currentPage ?? internalPage;
|
|
113
|
+
const pageSize = pagination?.pageSize ?? internalPageSize;
|
|
114
|
+
const onPageChange = (page) => {
|
|
115
|
+
setInternalPage(page);
|
|
116
|
+
pagination?.onPageChange?.(page);
|
|
117
|
+
};
|
|
118
|
+
const onPageSizeChange = (size) => {
|
|
119
|
+
setInternalPageSize(size);
|
|
120
|
+
setInternalPage(1);
|
|
121
|
+
pagination?.onPageSizeChange?.(size);
|
|
122
|
+
};
|
|
123
|
+
const totalPages = pagination?.totalPages ?? Math.ceil(processedData.length / pageSize);
|
|
124
|
+
const totalItems = pagination?.totalItems ?? processedData.length;
|
|
125
|
+
return {
|
|
126
|
+
...pagination,
|
|
127
|
+
currentPage,
|
|
128
|
+
pageSize,
|
|
129
|
+
onPageChange,
|
|
130
|
+
onPageSizeChange,
|
|
131
|
+
totalPages,
|
|
132
|
+
totalItems,
|
|
133
|
+
pageSizeOptions: pagination?.pageSizeOptions ?? DEFAULT_PAGE_SIZE_OPTIONS,
|
|
134
|
+
showTotalItems: pagination?.showTotalItems ?? true,
|
|
135
|
+
mode: pagination?.mode ?? 'offset'
|
|
136
|
+
};
|
|
137
|
+
}, [pagination, processedData, internalPage, internalPageSize]);
|
|
138
|
+
const paginatedData = React.useMemo(() => {
|
|
139
|
+
if (pagination?.currentPage !== undefined) {
|
|
140
|
+
return processedData;
|
|
141
|
+
}
|
|
142
|
+
const start = (effectivePagination.currentPage - 1) * effectivePagination.pageSize;
|
|
143
|
+
return processedData.slice(start, start + effectivePagination.pageSize);
|
|
144
|
+
}, [processedData, pagination?.currentPage, effectivePagination.currentPage, effectivePagination.pageSize]);
|
|
145
|
+
const effectiveData = paginatedData;
|
|
146
|
+
const toggleAllRows = () => {
|
|
147
|
+
const currentPageIds = effectiveData.map((row) => row.id);
|
|
148
|
+
const allCurrentPageSelected = currentPageIds.every(id => selectedRows.has(id));
|
|
149
|
+
let newSelected;
|
|
150
|
+
if (allCurrentPageSelected) {
|
|
151
|
+
newSelected = new Set(selectedRows);
|
|
152
|
+
currentPageIds.forEach(id => newSelected.delete(id));
|
|
153
|
+
}
|
|
154
|
+
else {
|
|
155
|
+
newSelected = new Set(selectedRows);
|
|
156
|
+
currentPageIds.forEach(id => newSelected.add(id));
|
|
157
|
+
}
|
|
158
|
+
setSelectedRows(newSelected);
|
|
159
|
+
const selectedIdsArray = Array.from(newSelected);
|
|
160
|
+
onSelectionChange?.(selectedIdsArray);
|
|
161
|
+
};
|
|
162
|
+
const shouldShowPagination = React.useMemo(() => {
|
|
163
|
+
if (pagination)
|
|
164
|
+
return true;
|
|
165
|
+
if (effectivePagination.totalPages <= 1 && (effectivePagination.totalItems || 0) <= 10)
|
|
166
|
+
return false;
|
|
167
|
+
return true;
|
|
168
|
+
}, [pagination, effectivePagination]);
|
|
111
169
|
const getSortIcon = (columnKey) => {
|
|
112
170
|
if (sortConfig.key !== columnKey) {
|
|
113
171
|
return jsx(ArrowUpDown, { className: "tw:ml-2 tw:!h-[16px] tw:!w-[16px] tw:opacity-50" });
|
|
@@ -157,7 +215,7 @@ function DataTable({ columns, data, onSelectionChange, selectedRowIds, onSort, s
|
|
|
157
215
|
const visibleActionsForRow = getVisibleActions(row);
|
|
158
216
|
const isDragging = draggedRowId === row.id;
|
|
159
217
|
const isDragOver = dragOverRowId === row.id;
|
|
160
|
-
const totalSiblings = siblingCount ??
|
|
218
|
+
const totalSiblings = siblingCount ?? effectiveData.length;
|
|
161
219
|
const handleDragStart = (e) => {
|
|
162
220
|
setDraggedRowId(row.id);
|
|
163
221
|
e.dataTransfer.effectAllowed = 'move';
|
|
@@ -186,16 +244,14 @@ function DataTable({ columns, data, onSelectionChange, selectedRowIds, onSort, s
|
|
|
186
244
|
setDraggedRowId(null);
|
|
187
245
|
setDragOverRowId(null);
|
|
188
246
|
};
|
|
189
|
-
return (jsxs(React.Fragment, { children: [jsxs("tr", { className: cn("tw:border-b tw:transition-colors hover:tw:bg-accent/50", rowBgClass, isDragging && "tw:opacity-50", isDragOver && "tw:ring-2 tw:ring-primary tw:ring-inset"), draggable: reorderable, onDragStart: reorderable ? handleDragStart : undefined, onDragEnd: reorderable ? handleDragEnd : undefined, onDragOver: reorderable ? handleDragOver : undefined, onDragLeave: reorderable ? handleDragLeave : undefined, onDrop: reorderable ? handleDrop : undefined, children: [isExpandable && (jsx("td", { className: cn("tw:p-2 tw:w-12", rowBgClass), children: jsx("div", { style: { paddingLeft: indentPadding }, children: canExpand ? (jsx("button", { onClick: () => toggleRowExpansion(row.id), className: "tw:flex tw:items-center tw:justify-center hover:tw:bg-accent tw:rounded tw:p-1", "aria-label": isExpanded ? "Collapse row" : "Expand row", "aria-expanded": isExpanded, children: isExpanded ? (jsx(ChevronDown, { className: "tw:!h-[16px] tw:!w-[16px]" })) : (jsx(ChevronRight, { className: "tw:!h-[16px] tw:!w-[16px]" })) })) : (jsx("span", { className: "tw:w-6" })) }) })), hasRowSelection && (jsx("td", { className: cn("tw:p-2 tw:w-12", rowBgClass), children: jsx("div", { className: "tw:flex tw:items-center tw:justify-center", children: jsx(Checkbox, { checked: selectedRows.has(row.id), onCheckedChange: () => toggleRowSelection(row.id), "aria-label": `Select row ${rowIndex + 1}` }) }) })), reorderable && (jsx("td", { className: cn("tw:p-2 tw:w-12", rowBgClass), children: jsxs("div", { className: "tw:flex tw:flex-col tw:items-center tw:gap-0.5", children: [jsx("button", { onClick: () => onReorder?.(row.id, "up", parentRow?.id), className: "tw:flex tw:items-center tw:justify-center hover:tw:bg-accent tw:rounded tw:p-0.5 tw:text-muted-foreground hover:tw:text-foreground tw:transition-colors", disabled: rowIndex === 0, "aria-label": "Move row up", children: jsx(ChevronUp, { className: cn("tw:h-4 tw:w-4", rowIndex === 0 && "tw:opacity-30") }) }), jsx("button", { onClick: () => onReorder?.(row.id, "down", parentRow?.id), className: "tw:flex tw:items-center tw:justify-center hover:tw:bg-accent tw:rounded tw:p-0.5 tw:text-muted-foreground hover:tw:text-foreground tw:transition-colors", disabled: rowIndex === totalSiblings - 1, "aria-label": "Move row down", children: jsx(ChevronDown, { className: cn("tw:h-4 tw:w-4", rowIndex === totalSiblings - 1 && "tw:opacity-30") }) })] }) })), visibleColumns.map((column, colIndex) => {
|
|
247
|
+
return (jsxs(React.Fragment, { children: [jsxs("tr", { className: cn("tw:border-b tw:transition-colors hover:tw:bg-accent/50", rowBgClass, isDragging && "tw:opacity-50", isDragOver && "tw:ring-2 tw:ring-primary tw:ring-inset"), draggable: reorderable, onDragStart: reorderable ? handleDragStart : undefined, onDragEnd: reorderable ? handleDragEnd : undefined, onDragOver: reorderable ? handleDragOver : undefined, onDragLeave: reorderable ? handleDragLeave : undefined, onDrop: reorderable ? handleDrop : undefined, children: [isExpandable && (jsx("td", { className: cn("tw:p-2 tw:w-12", rowBgClass), children: jsx("div", { style: { paddingLeft: indentPadding }, children: canExpand ? (jsx("button", { onClick: () => toggleRowExpansion(row.id), className: "tw:flex tw:items-center tw:justify-center hover:tw:bg-accent tw:rounded tw:p-1 tw:!pl-[10px]", "aria-label": isExpanded ? "Collapse row" : "Expand row", "aria-expanded": isExpanded, children: isExpanded ? (jsx(ChevronDown, { className: "tw:!h-[16px] tw:!w-[16px]" })) : (jsx(ChevronRight, { className: "tw:!h-[16px] tw:!w-[16px]" })) })) : (jsx("span", { className: "tw:w-6" })) }) })), hasRowSelection && (jsx("td", { className: cn("tw:p-2 tw:w-12", rowBgClass), children: jsx("div", { className: "tw:flex tw:items-center tw:justify-center", children: jsx(Checkbox, { checked: selectedRows.has(row.id), onCheckedChange: () => toggleRowSelection(row.id), "aria-label": `Select row ${rowIndex + 1}` }) }) })), reorderable && (jsx("td", { className: cn("tw:p-2 tw:w-12", rowBgClass), children: jsxs("div", { className: "tw:flex tw:flex-col tw:items-center tw:gap-0.5", children: [jsx("button", { onClick: () => onReorder?.(row.id, "up", parentRow?.id), className: "tw:flex tw:items-center tw:justify-center hover:tw:bg-accent tw:rounded tw:p-0.5 tw:text-muted-foreground hover:tw:text-foreground tw:transition-colors", disabled: rowIndex === 0, "aria-label": "Move row up", children: jsx(ChevronUp, { className: cn("tw:h-4 tw:w-4", rowIndex === 0 && "tw:opacity-30") }) }), jsx("button", { onClick: () => onReorder?.(row.id, "down", parentRow?.id), className: "tw:flex tw:items-center tw:justify-center hover:tw:bg-accent tw:rounded tw:p-0.5 tw:text-muted-foreground hover:tw:text-foreground tw:transition-colors", disabled: rowIndex === totalSiblings - 1, "aria-label": "Move row down", children: jsx(ChevronDown, { className: cn("tw:h-4 tw:w-4", rowIndex === totalSiblings - 1 && "tw:opacity-30") }) })] }) })), visibleColumns.map((column, colIndex) => {
|
|
190
248
|
const clickableField = getClickableField(column.key);
|
|
191
249
|
const cellContent = column.render ? column.render(row[column.key], row, rowIndex, depth) : row[column.key];
|
|
192
250
|
return (jsx("td", { className: cn("tw:p-4 tw:align-middle tw:max-w-0 tw:overflow-hidden", column.align === "center" && "tw:text-center", column.align === "right" && "tw:text-right", column.className, rowBgClass), children: jsx("div", { className: cn("tw:truncate", clickableField && "tw:!text-primary"), style: { paddingLeft: colIndex === 0 ? (isExpandable ? (depth > 0 ? 16 : 0) : indentPadding) : 0 }, children: clickableField ? (jsx("span", { onClick: () => clickableField.onClick(row), className: "hover:tw:!text-primary/80 hover:tw:underline tw:cursor-pointer tw:transition-colors", children: cellContent })) : (cellContent) }) }, column.key));
|
|
193
251
|
}), showActionsColumn && (jsx("td", { className: cn("tw:p-2 tw:text-right tw:sticky tw:right-0", rowBgClass), children: visibleActionsForRow.length > 0 && (jsxs(Menu.Root, { modal: false, children: [jsx(Menu.Trigger, { id: `base-ui-row-action-${row.id}`, render: (props) => (jsx(Button, { variant: "ghost", size: "icon", className: "tw:h-8 tw:w-8", "aria-label": "Row actions", ...props, id: `base-ui-row-action-${row.id}`, children: jsx(MoreHorizontal, { className: "tw:!h-[16px] tw:!w-[16px]" }) })) }), jsx(Menu.Portal, { children: jsx(Menu.Positioner, { side: "bottom", align: "end", sideOffset: 4, collisionPadding: 8, children: jsx(Menu.Popup, { "aria-labelledby": "base-ui-toggle-columns-trigger", className: cn("tw:bg-popover tw:font-sans tw:text-popover-foreground tw:data-[state=open]:animate-in tw:data-[state=closed]:animate-out tw:data-[state=closed]:fade-out-0 tw:data-[state=open]:fade-in-0 tw:data-[state=closed]:zoom-out-95 tw:data-[state=open]:zoom-in-95 tw:data-[side=bottom]:slide-in-from-top-2 tw:data-[side=left]:slide-in-from-right-2 tw:data-[side=right]:slide-in-from-left-2 tw:data-[side=top]:slide-in-from-bottom-2 tw:z-50 tw:min-w-[8rem] tw:overflow-x-hidden tw:overflow-y-auto tw:rounded-md tw:border tw:p-1 tw:shadow-md"), children: visibleActionsForRow.map((action, index) => (jsxs(Menu.Item, { onClick: () => action.onClick(row), className: cn("tw:focus:bg-accent tw:focus:text-accent-foreground tw:relative tw:flex tw:cursor-default tw:items-center tw:gap-2 tw:rounded-sm tw:px-2 tw:py-1.5 tw:text-[14px] tw:outline-hidden tw:select-none tw:data-[disabled]:pointer-events-none tw:data-[disabled]:opacity-50", action.variant === "destructive" && "tw:text-destructive focus:tw:text-destructive"), children: [action.icon && jsx("span", { className: "tw:mr-2", children: action.icon }), action.label] }, index))) }) }) })] })) }))] }), expandable && !treeData && isExpanded && renderExpandedRow && (jsx("tr", { className: "tw:border-b tw:bg-muted/30", children: jsx("td", { colSpan: visibleColumns.length + (showActionsColumn ? 1 : 0) + (hasRowSelection ? 1 : 0) + (isExpandable ? 1 : 0) + (reorderable ? 1 : 0), className: "tw:p-4", children: renderExpandedRow(row) }) })), treeData && isExpanded && row.children && row.children.map((child, childIndex) => renderRow(child, childIndex, depth + 1, row, row.children?.length))] }, row.id));
|
|
194
252
|
};
|
|
195
253
|
const renderPaginationItems = () => {
|
|
196
|
-
|
|
197
|
-
return null;
|
|
198
|
-
const { currentPage, totalPages, onPageChange } = pagination;
|
|
254
|
+
const { currentPage, totalPages, onPageChange } = effectivePagination;
|
|
199
255
|
const items = [];
|
|
200
256
|
const maxVisiblePages = 5;
|
|
201
257
|
let startPage = Math.max(1, currentPage - Math.floor(maxVisiblePages / 2));
|
|
@@ -263,7 +319,7 @@ function DataTable({ columns, data, onSelectionChange, selectedRowIds, onSort, s
|
|
|
263
319
|
});
|
|
264
320
|
return `${totalWidth}px`;
|
|
265
321
|
};
|
|
266
|
-
return (jsxs("div", { className: cn("tw:w-full tw:h-full tw:flex tw:flex-col", className), children: [jsxs("div", { className: "tw:relative tw:flex-1 tw:flex tw:flex-col tw:min-h-0", children: [jsx("div", { ref: scrollContainerRef, className: "tw:flex-1 tw:overflow-auto [&::-webkit-scrollbar]:tw:h-2 [&::-webkit-scrollbar]:tw:w-2 [&::-webkit-scrollbar-track]:tw:bg-muted [&::-webkit-scrollbar-thumb]:tw:bg-muted-foreground/30 [&::-webkit-scrollbar-thumb]:tw:rounded-full hover:[&::-webkit-scrollbar-thumb]:tw:bg-muted-foreground/50", children: jsxs("table", { className: "tw:w-full tw:table-fixed tw:caption-bottom tw:text-sm", role: "grid", "aria-busy": loading, style: { minWidth: calculateMinTableWidth() }, children: [jsx("thead", { className: "tw:border-b tw:sticky tw:top-0 tw:z-10 tw:bg-background", children: jsxs("tr", { children: [isExpandable && jsx("th", { scope: "col", className: "tw:h-10 tw:w-12 tw:px-2" }), hasRowSelection && (jsx("th", { scope: "col", className: "tw:h-10 tw:w-12 tw:px-2", children: jsx("div", { className: "tw:flex tw:items-center tw:justify-center", children: jsx(Checkbox, { checked:
|
|
322
|
+
return (jsxs("div", { className: cn("tw:w-full tw:h-full tw:flex tw:flex-col", className), children: [jsxs("div", { className: "tw:relative tw:flex-1 tw:flex tw:flex-col tw:min-h-0", children: [jsx("div", { ref: scrollContainerRef, className: "tw:flex-1 tw:overflow-auto [&::-webkit-scrollbar]:tw:h-2 [&::-webkit-scrollbar]:tw:w-2 [&::-webkit-scrollbar-track]:tw:bg-muted [&::-webkit-scrollbar-thumb]:tw:bg-muted-foreground/30 [&::-webkit-scrollbar-thumb]:tw:rounded-full hover:[&::-webkit-scrollbar-thumb]:tw:bg-muted-foreground/50", children: jsxs("table", { className: "tw:w-full tw:table-fixed tw:caption-bottom tw:text-sm", role: "grid", "aria-busy": loading, style: { minWidth: calculateMinTableWidth() }, children: [jsx("thead", { className: "tw:border-b tw:sticky tw:top-0 tw:z-10 tw:bg-background", children: jsxs("tr", { children: [isExpandable && jsx("th", { scope: "col", className: "tw:h-10 tw:w-12 tw:px-2" }), hasRowSelection && (jsx("th", { scope: "col", className: "tw:h-10 tw:w-12 tw:px-2", children: jsx("div", { className: "tw:flex tw:items-center tw:justify-center", children: jsx(Checkbox, { checked: effectiveData.length > 0 && effectiveData.every(row => selectedRows.has(row.id)), onCheckedChange: toggleAllRows, "aria-label": "Select all rows" }) }) })), reorderable && jsx("th", { scope: "col", className: "tw:h-10 tw:w-12 tw:px-2" }), visibleColumns.map((column) => (jsx("th", { scope: "col", "aria-sort": column.sortable && sortConfig.key === column.key
|
|
267
323
|
? sortConfig.direction === "asc"
|
|
268
324
|
? "ascending"
|
|
269
325
|
: sortConfig.direction === "desc"
|
|
@@ -272,22 +328,22 @@ function DataTable({ columns, data, onSelectionChange, selectedRowIds, onSort, s
|
|
|
272
328
|
: undefined, className: cn("tw:!h-[40px] tw:px-4 tw:text-left tw:align-middle tw:font-medium tw:text-foreground tw:whitespace-nowrap", column.align === "center" && "tw:text-center", column.align === "right" && "tw:text-right"), style: { width: column.width }, children: column.sortable && onSort ? (jsxs("button", { onClick: () => !loading && handleSort(column.key), disabled: loading, "aria-label": `Sort by ${column.label}${sortConfig.key === column.key ? (sortConfig.direction === 'asc' ? ', currently sorted ascending' : sortConfig.direction === 'desc' ? ', currently sorted descending' : '') : ''}`, className: cn("tw:flex tw:items-center hover:tw:text-foreground/80 tw:transition-colors", loading && "tw:opacity-50 tw:cursor-not-allowed"), children: [column.label, getSortIcon(column.key)] })) : (column.label) }, column.key))), showActionsColumn && (jsx("th", { scope: "col", className: "tw:h-10 tw:w-20 tw:px-2 tw:sticky tw:right-0 tw:bg-background", children: jsx("div", { className: "tw:flex tw:items-center tw:justify-end tw:pr-1", children: showColumnVisibility && (jsxs(Menu.Root, { modal: false, children: [jsx(Menu.Trigger, { id: "base-ui-toggle-columns-trigger", render: (props) => (jsx(Button, { variant: "ghost", size: "icon", className: "tw:h-8 tw:w-8", "aria-label": "Toggle column visibility", ...props, id: "base-ui-toggle-columns-trigger", children: jsx(Settings, { className: "tw:!h-[20px] tw:!w-[20px] tw:text-muted-foreground" }) })) }), jsx(Menu.Portal, { children: jsx(Menu.Positioner, { side: "bottom", align: "end", sideOffset: 4, collisionPadding: 8, children: jsx(Menu.Popup, { "aria-labelledby": `base-ui-toggle-columns-trigger`, className: cn("tw:bg-popover tw:font-sans tw:text-popover-foreground tw:data-[state=open]:animate-in tw:data-[state=closed]:animate-out tw:data-[state=closed]:fade-out-0 tw:data-[state=open]:fade-in-0 tw:data-[state=closed]:zoom-out-95 tw:data-[state=open]:zoom-in-95 tw:data-[side=bottom]:slide-in-from-top-2 tw:data-[side=left]:slide-in-from-right-2 tw:data-[side=right]:slide-in-from-left-2 tw:data-[side=top]:slide-in-from-bottom-2 tw:z-50 tw:min-w-[8rem] tw:overflow-x-hidden tw:overflow-y-auto tw:rounded-md tw:border tw:p-1 tw:shadow-md"), children: jsxs(Menu.Group, { children: [jsx(Menu.GroupLabel, { className: "tw:px-2 tw:py-1.5 tw:text-[14px] tw:font-medium", children: "Toggle Columns" }), jsx("div", { className: "tw:bg-border tw:-mx-1 tw:my-1 tw:h-px" }), filterableColumns.map((column) => {
|
|
273
329
|
const isVisible = !hiddenColumns.includes(column.key);
|
|
274
330
|
return (jsxs(Menu.Item, { onClick: () => toggleColumnVisibility(column.key), closeOnClick: false, className: cn("tw:focus:bg-accent tw:focus:text-accent-foreground tw:relative tw:flex tw:cursor-default tw:items-center tw:gap-2 tw:rounded-sm tw:py-1.5 tw:pr-2 tw:pl-8 tw:text-[14px] tw:outline-hidden tw:select-none tw:data-[disabled]:pointer-events-none tw:data-[disabled]:opacity-50"), children: [jsx("span", { className: "tw:pointer-events-none tw:absolute tw:left-2 tw:flex tw:size-3.5 tw:items-center tw:justify-center", children: isVisible && jsx(Check, { className: "tw:size-4" }) }), column.label] }, column.key));
|
|
275
|
-
})] }) }) }) })] })) }) }))] }) }), jsx("tbody", { className: "tw:relative", children:
|
|
276
|
-
const options =
|
|
331
|
+
})] }) }) }) })] })) }) }))] }) }), jsx("tbody", { className: "tw:relative", children: effectiveData.length === 0 && !loading ? (jsx("tr", { children: jsx("td", { colSpan: visibleColumns.length + (showActionsColumn ? 1 : 0) + (hasRowSelection ? 1 : 0) + (isExpandable ? 1 : 0) + (reorderable ? 1 : 0), className: "tw:h-48", children: jsxs("div", { className: "tw:flex tw:flex-col tw:items-center tw:justify-center tw:h-full tw:text-center", children: [emptyState?.icon || (jsx("div", { className: "tw:h-12 tw:w-12 tw:rounded-full tw:bg-muted tw:flex tw:items-center tw:justify-center tw:mb-3", children: jsx(Inbox, { className: "tw:h-6 tw:w-6 tw:text-muted-foreground" }) })), jsx("p", { className: "tw:text-base tw:font-medium tw:text-foreground", children: emptyState?.title || "No results found" }), jsx("p", { className: "tw:text-sm tw:text-muted-foreground tw:mt-1", children: emptyState?.description || "There are no items to display." })] }) }) })) : (effectiveData.map((row, rowIndex) => renderRow(row, rowIndex, 0))) })] }) }), loading && (jsx("div", { className: "tw:absolute tw:inset-0 tw:z-20 tw:flex tw:items-center tw:justify-center tw:bg-background/50 tw:backdrop-blur-[1px]", children: jsxs("div", { className: "tw:flex tw:flex-col tw:items-center", children: [jsx(Loader2, { className: "tw:h-8 tw:w-8 tw:animate-spin tw:text-primary" }), effectiveData.length === 0 && jsx("p", { className: "tw:text-sm tw:text-muted-foreground tw:mt-3", children: "Loading..." })] }) }))] }), shouldShowPagination && (jsxs("div", { className: "tw:relative tw:flex tw:items-center tw:justify-between tw:border-t tw:px-4 tw:py-4 tw:bg-background", children: [(() => {
|
|
332
|
+
const options = effectivePagination.pageSizeOptions ?? DEFAULT_PAGE_SIZE_OPTIONS;
|
|
277
333
|
if (options.length === 0)
|
|
278
334
|
return jsx("div", {});
|
|
279
|
-
return (jsxs("div", { className: "tw:flex tw:items-center tw:gap-2 tw:z-10", children: [jsx("span", { className: "tw:text-[14px] tw:text-muted-foreground tw:whitespace-nowrap", id: "rows-per-page-label", children: "Rows per page:" }), jsxs(Select, { value: String(
|
|
280
|
-
})(),
|
|
335
|
+
return (jsxs("div", { className: "tw:flex tw:items-center tw:gap-2 tw:z-10", children: [jsx("span", { className: "tw:text-[14px] tw:text-muted-foreground tw:whitespace-nowrap", id: "rows-per-page-label", children: "Rows per page:" }), jsxs(Select, { value: String(effectivePagination.pageSize ?? options[0]), onValueChange: (val) => !loading && effectivePagination.onPageSizeChange?.(Number(val)), disabled: loading, children: [jsx(SelectTrigger, { id: "base-ui-pagination-trigger", className: "tw:flex tw:h-[32px] tw:w-[70px] tw:items-center tw:justify-between tw:rounded-md tw:border tw:border-input tw:bg-transparent tw:px-3 tw:py-2 tw:text-[14px] tw:shadow-sm tw:ring-offset-background placeholder:tw:text-muted-foreground focus:tw:outline-none focus:tw:ring-1 focus:tw:ring-ring disabled:tw:cursor-not-allowed disabled:tw:opacity-50", children: jsx(SelectValue, {}) }), jsx(SelectContent, { side: "top", align: "end", children: options.map((size) => (jsx(SelectItem, { value: String(size), children: size }, size))) })] })] }));
|
|
336
|
+
})(), effectivePagination.showTotalItems && effectivePagination.totalItems !== undefined && (jsx("div", { className: "tw:absolute tw:left-1/2 tw:-translate-x-1/2 tw:flex tw:justify-center tw:items-center", children: jsxs("span", { className: "tw:text-[14px] tw:text-muted-foreground", children: ["Total: ", effectivePagination.totalItems] }) })), jsx("div", { className: "tw:z-10", children: jsx(Pagination, { className: "tw:!mx-0 tw:!w-auto", "aria-label": "Table pagination", children: jsxs(PaginationContent, { children: [jsx(PaginationItem, { children: jsx(PaginationPrevious, { href: "#", onClick: (e) => {
|
|
281
337
|
e.preventDefault();
|
|
282
|
-
if (!loading && !
|
|
283
|
-
|
|
338
|
+
if (!loading && !effectivePagination.disablePrevious && effectivePagination.currentPage > 1) {
|
|
339
|
+
effectivePagination.onPageChange(effectivePagination.currentPage - 1);
|
|
284
340
|
}
|
|
285
|
-
}, "aria-label": "Go to previous page", "aria-disabled": loading ||
|
|
341
|
+
}, "aria-label": "Go to previous page", "aria-disabled": loading || effectivePagination.disablePrevious || effectivePagination.currentPage <= 1, className: cn((loading || effectivePagination.disablePrevious || effectivePagination.currentPage <= 1) && "tw:pointer-events-none tw:opacity-50") }) }), effectivePagination.mode !== "cursor" && renderPaginationItems(), jsx(PaginationItem, { children: jsx(PaginationNext, { href: "#", onClick: (e) => {
|
|
286
342
|
e.preventDefault();
|
|
287
|
-
if (!loading && !
|
|
288
|
-
|
|
343
|
+
if (!loading && !effectivePagination.disableNext && effectivePagination.currentPage < effectivePagination.totalPages) {
|
|
344
|
+
effectivePagination.onPageChange(effectivePagination.currentPage + 1);
|
|
289
345
|
}
|
|
290
|
-
}, "aria-label": "Go to next page", "aria-disabled": loading ||
|
|
346
|
+
}, "aria-label": "Go to next page", "aria-disabled": loading || effectivePagination.disableNext || effectivePagination.currentPage >= effectivePagination.totalPages, className: cn((loading || effectivePagination.disableNext || effectivePagination.currentPage >= effectivePagination.totalPages) && "tw:pointer-events-none tw:opacity-50") }) })] }) }) })] }))] }));
|
|
291
347
|
}
|
|
292
348
|
|
|
293
349
|
export { DataTable };
|