lynote-ui 0.0.9 → 0.0.11
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/dist/context-menu/index.d.ts +1 -1
- package/dist/context-menu/index.js +2 -1
- package/dist/context-menu/index.js.map +1 -1
- package/dist/context-menu/index.mjs +2 -1
- package/dist/context-menu/index.mjs.map +1 -1
- package/dist/index.js +16 -1
- package/dist/index.mjs +2 -2
- package/dist/sidebar/index.js +0 -1
- package/dist/sidebar/index.mjs +0 -1
- package/dist/style.css +231 -9
- package/dist/table/components/base-table.d.ts +10 -0
- package/dist/table/components/data-table-column-header.d.ts +12 -0
- package/dist/table/components/data-table-pagination.d.ts +12 -0
- package/dist/table/components/data-table-toolbar.d.ts +23 -0
- package/dist/table/components/data-table-view-options.d.ts +18 -0
- package/dist/table/components/data-table-virtual-body.d.ts +19 -0
- package/dist/table/components/data-table.d.ts +15 -0
- package/dist/table/components/row-drag-handle.d.ts +16 -0
- package/dist/table/components/row-expand-toggle.d.ts +21 -0
- package/dist/table/hooks/use-data-table.d.ts +44 -0
- package/dist/table/index.d.ts +13 -10
- package/dist/table/index.js +24 -78
- package/dist/table/index.mjs +2 -69
- package/dist/table/type.d.ts +198 -0
- package/dist/table/utils.d.ts +31 -0
- package/dist/table-BA2BijtZ.mjs +1077 -0
- package/dist/table-BA2BijtZ.mjs.map +1 -0
- package/dist/table-FocfdaF7.js +1216 -0
- package/dist/table-FocfdaF7.js.map +1 -0
- package/package.json +7 -1
- package/dist/table/index.js.map +0 -1
- package/dist/table/index.mjs.map +0 -1
|
@@ -0,0 +1,1077 @@
|
|
|
1
|
+
import { t as cn } from "./utils-Bg4z4cXr.mjs";
|
|
2
|
+
import { Button } from "./button/index.mjs";
|
|
3
|
+
import { Input } from "./input/index.mjs";
|
|
4
|
+
import { DropdownMenu, DropdownMenuCheckboxItem, DropdownMenuContent, DropdownMenuGroup, DropdownMenuLabel, DropdownMenuSeparator, DropdownMenuTrigger } from "./dropdown-menu/index.mjs";
|
|
5
|
+
import { NativeSelect, NativeSelectOption } from "./native-select/index.mjs";
|
|
6
|
+
import { Skeleton } from "./skeleton/index.mjs";
|
|
7
|
+
import { ChevronDownIcon, ChevronLeftIcon, ChevronRightIcon, ChevronUpIcon, ChevronsLeftIcon, ChevronsRightIcon, GripVerticalIcon, SearchIcon, Settings2Icon, XIcon } from "lucide-react";
|
|
8
|
+
import { jsx, jsxs } from "react/jsx-runtime";
|
|
9
|
+
import { Fragment as Fragment$1, createContext, forwardRef, useContext, useEffect, useImperativeHandle, useMemo, useRef, useState } from "react";
|
|
10
|
+
import { DndContext, KeyboardSensor, PointerSensor, closestCenter, useSensor, useSensors } from "@dnd-kit/core";
|
|
11
|
+
import { restrictToVerticalAxis } from "@dnd-kit/modifiers";
|
|
12
|
+
import { SortableContext, arrayMove, sortableKeyboardCoordinates, useSortable, verticalListSortingStrategy } from "@dnd-kit/sortable";
|
|
13
|
+
import { CSS } from "@dnd-kit/utilities";
|
|
14
|
+
import { flexRender, getCoreRowModel, getExpandedRowModel, getFilteredRowModel, getPaginationRowModel, getSortedRowModel, useReactTable } from "@tanstack/react-table";
|
|
15
|
+
import { useVirtualizer } from "@tanstack/react-virtual";
|
|
16
|
+
//#region src/table/components/base-table.tsx
|
|
17
|
+
function Table({ className, ...props }) {
|
|
18
|
+
return /* @__PURE__ */ jsx("div", {
|
|
19
|
+
"data-slot": "table-container",
|
|
20
|
+
className: "relative w-full overflow-x-auto",
|
|
21
|
+
children: /* @__PURE__ */ jsx("table", {
|
|
22
|
+
"data-slot": "table",
|
|
23
|
+
className: cn("w-full caption-bottom text-sm", className),
|
|
24
|
+
...props
|
|
25
|
+
})
|
|
26
|
+
});
|
|
27
|
+
}
|
|
28
|
+
function TableHeader({ className, ...props }) {
|
|
29
|
+
return /* @__PURE__ */ jsx("thead", {
|
|
30
|
+
"data-slot": "table-header",
|
|
31
|
+
className: cn("[&_tr]:border-b", className),
|
|
32
|
+
...props
|
|
33
|
+
});
|
|
34
|
+
}
|
|
35
|
+
function TableBody({ className, ...props }) {
|
|
36
|
+
return /* @__PURE__ */ jsx("tbody", {
|
|
37
|
+
"data-slot": "table-body",
|
|
38
|
+
className: cn("[&_tr:last-child]:border-0", className),
|
|
39
|
+
...props
|
|
40
|
+
});
|
|
41
|
+
}
|
|
42
|
+
function TableFooter({ className, ...props }) {
|
|
43
|
+
return /* @__PURE__ */ jsx("tfoot", {
|
|
44
|
+
"data-slot": "table-footer",
|
|
45
|
+
className: cn("bg-muted/50 border-t font-medium [&>tr]:last:border-b-0", className),
|
|
46
|
+
...props
|
|
47
|
+
});
|
|
48
|
+
}
|
|
49
|
+
function TableRow({ className, ...props }) {
|
|
50
|
+
return /* @__PURE__ */ jsx("tr", {
|
|
51
|
+
"data-slot": "table-row",
|
|
52
|
+
className: cn("hover:bg-muted/50 data-[state=selected]:bg-muted border-b transition-colors", className),
|
|
53
|
+
...props
|
|
54
|
+
});
|
|
55
|
+
}
|
|
56
|
+
function TableHead({ className, ...props }) {
|
|
57
|
+
return /* @__PURE__ */ jsx("th", {
|
|
58
|
+
"data-slot": "table-head",
|
|
59
|
+
className: cn("text-foreground h-10 whitespace-nowrap px-2 text-left align-middle font-medium [&:has([role=checkbox])]:pr-0", className),
|
|
60
|
+
...props
|
|
61
|
+
});
|
|
62
|
+
}
|
|
63
|
+
function TableCell({ className, ...props }) {
|
|
64
|
+
return /* @__PURE__ */ jsx("td", {
|
|
65
|
+
"data-slot": "table-cell",
|
|
66
|
+
className: cn("whitespace-nowrap p-2 align-middle [&:has([role=checkbox])]:pr-0", className),
|
|
67
|
+
...props
|
|
68
|
+
});
|
|
69
|
+
}
|
|
70
|
+
function TableCaption({ className, ...props }) {
|
|
71
|
+
return /* @__PURE__ */ jsx("caption", {
|
|
72
|
+
"data-slot": "table-caption",
|
|
73
|
+
className: cn("text-muted-foreground mt-4 text-sm", className),
|
|
74
|
+
...props
|
|
75
|
+
});
|
|
76
|
+
}
|
|
77
|
+
//#endregion
|
|
78
|
+
//#region src/table/hooks/use-data-table.ts
|
|
79
|
+
var DEFAULT_FEATURES = {
|
|
80
|
+
sorting: true,
|
|
81
|
+
multiSort: false,
|
|
82
|
+
filtering: true,
|
|
83
|
+
globalFilter: false,
|
|
84
|
+
pagination: true,
|
|
85
|
+
rowSelection: false,
|
|
86
|
+
columnVisibility: true,
|
|
87
|
+
columnOrdering: false,
|
|
88
|
+
columnPinning: false,
|
|
89
|
+
columnResizing: false,
|
|
90
|
+
rowDnd: false,
|
|
91
|
+
expanding: false
|
|
92
|
+
};
|
|
93
|
+
function applyUpdater(updater, prev) {
|
|
94
|
+
return typeof updater === "function" ? updater(prev) : updater;
|
|
95
|
+
}
|
|
96
|
+
/**
|
|
97
|
+
* 选取受控值,若未传则回退到非受控
|
|
98
|
+
*
|
|
99
|
+
* setter 同时支持值和函数式 updater,以避免一帧内多次更新拿到旧 snapshot
|
|
100
|
+
*/
|
|
101
|
+
function useControlled(controlled, initial, onChange) {
|
|
102
|
+
const isControlled = controlled !== void 0;
|
|
103
|
+
const [internal, setInternal] = useState(initial);
|
|
104
|
+
const value = isControlled ? controlled : internal;
|
|
105
|
+
const setValue = (updater) => {
|
|
106
|
+
if (isControlled) {
|
|
107
|
+
const next = applyUpdater(updater, controlled);
|
|
108
|
+
onChange?.(next);
|
|
109
|
+
return;
|
|
110
|
+
}
|
|
111
|
+
setInternal((prev) => {
|
|
112
|
+
const next = applyUpdater(updater, prev);
|
|
113
|
+
onChange?.(next);
|
|
114
|
+
return next;
|
|
115
|
+
});
|
|
116
|
+
};
|
|
117
|
+
return [value, setValue];
|
|
118
|
+
}
|
|
119
|
+
/**
|
|
120
|
+
* 构造 TanStack 表格实例,并按需开启各项功能
|
|
121
|
+
*/
|
|
122
|
+
function useDataTable({ data, columns, features, state, initialState, onStateChange, tableOptions }) {
|
|
123
|
+
const mergedFeatures = {
|
|
124
|
+
...DEFAULT_FEATURES,
|
|
125
|
+
...features
|
|
126
|
+
};
|
|
127
|
+
const [sorting, setSorting] = useControlled(state?.sorting, initialState?.sorting ?? [], onStateChange?.onSortingChange);
|
|
128
|
+
const [columnFilters, setColumnFilters] = useControlled(state?.columnFilters, initialState?.columnFilters ?? [], onStateChange?.onColumnFiltersChange);
|
|
129
|
+
const [columnVisibility, setColumnVisibility] = useControlled(state?.columnVisibility, initialState?.columnVisibility ?? {}, onStateChange?.onColumnVisibilityChange);
|
|
130
|
+
const [columnOrder, setColumnOrder] = useControlled(state?.columnOrder, initialState?.columnOrder ?? [], onStateChange?.onColumnOrderChange);
|
|
131
|
+
const [columnPinning, setColumnPinning] = useControlled(state?.columnPinning, initialState?.columnPinning ?? {}, onStateChange?.onColumnPinningChange);
|
|
132
|
+
const [rowSelection, setRowSelection] = useControlled(state?.rowSelection, initialState?.rowSelection ?? {}, onStateChange?.onRowSelectionChange);
|
|
133
|
+
const [pagination, setPagination] = useControlled(state?.pagination, initialState?.pagination ?? {
|
|
134
|
+
pageIndex: 0,
|
|
135
|
+
pageSize: 10
|
|
136
|
+
}, onStateChange?.onPaginationChange);
|
|
137
|
+
const [globalFilter, setGlobalFilter] = useControlled(state?.globalFilter, initialState?.globalFilter ?? "", onStateChange?.onGlobalFilterChange);
|
|
138
|
+
const [expanded, setExpanded] = useControlled(state?.expanded, initialState?.expanded ?? {}, onStateChange?.onExpandedChange);
|
|
139
|
+
return {
|
|
140
|
+
table: useReactTable({
|
|
141
|
+
data,
|
|
142
|
+
columns,
|
|
143
|
+
state: {
|
|
144
|
+
sorting,
|
|
145
|
+
columnFilters,
|
|
146
|
+
columnVisibility,
|
|
147
|
+
columnOrder,
|
|
148
|
+
columnPinning,
|
|
149
|
+
rowSelection,
|
|
150
|
+
pagination,
|
|
151
|
+
globalFilter,
|
|
152
|
+
expanded
|
|
153
|
+
},
|
|
154
|
+
enableSorting: mergedFeatures.sorting,
|
|
155
|
+
enableMultiSort: mergedFeatures.multiSort,
|
|
156
|
+
enableFilters: mergedFeatures.filtering,
|
|
157
|
+
enableGlobalFilter: mergedFeatures.globalFilter,
|
|
158
|
+
enableRowSelection: mergedFeatures.rowSelection,
|
|
159
|
+
enableHiding: mergedFeatures.columnVisibility,
|
|
160
|
+
enableColumnPinning: mergedFeatures.columnPinning,
|
|
161
|
+
enableColumnResizing: mergedFeatures.columnResizing,
|
|
162
|
+
columnResizeMode: "onChange",
|
|
163
|
+
onSortingChange: setSorting,
|
|
164
|
+
onColumnFiltersChange: setColumnFilters,
|
|
165
|
+
onColumnVisibilityChange: setColumnVisibility,
|
|
166
|
+
onColumnOrderChange: setColumnOrder,
|
|
167
|
+
onColumnPinningChange: setColumnPinning,
|
|
168
|
+
onRowSelectionChange: setRowSelection,
|
|
169
|
+
onPaginationChange: setPagination,
|
|
170
|
+
onGlobalFilterChange: setGlobalFilter,
|
|
171
|
+
onExpandedChange: setExpanded,
|
|
172
|
+
getCoreRowModel: getCoreRowModel(),
|
|
173
|
+
getSortedRowModel: mergedFeatures.sorting ? getSortedRowModel() : void 0,
|
|
174
|
+
getFilteredRowModel: mergedFeatures.filtering || mergedFeatures.globalFilter ? getFilteredRowModel() : void 0,
|
|
175
|
+
getPaginationRowModel: mergedFeatures.pagination && !tableOptions?.manualPagination ? getPaginationRowModel() : void 0,
|
|
176
|
+
getExpandedRowModel: mergedFeatures.expanding ? getExpandedRowModel() : void 0,
|
|
177
|
+
...tableOptions
|
|
178
|
+
}),
|
|
179
|
+
features: mergedFeatures
|
|
180
|
+
};
|
|
181
|
+
}
|
|
182
|
+
/**
|
|
183
|
+
* 监听容器横向滚动,返回左右阴影显示状态
|
|
184
|
+
*
|
|
185
|
+
* 用于固定列阴影提示
|
|
186
|
+
*/
|
|
187
|
+
function useScrollShadow(wrapperRef, containerSelector = "[data-slot=\"table-container\"]") {
|
|
188
|
+
const [scrollShadow, setScrollShadow] = useState({
|
|
189
|
+
left: false,
|
|
190
|
+
right: false
|
|
191
|
+
});
|
|
192
|
+
useEffect(() => {
|
|
193
|
+
const scrollContainer = wrapperRef.current?.querySelector(containerSelector);
|
|
194
|
+
if (!scrollContainer) return;
|
|
195
|
+
const update = () => {
|
|
196
|
+
const scrollLeft = scrollContainer.scrollLeft;
|
|
197
|
+
const maxScrollLeft = Math.max(0, scrollContainer.scrollWidth - scrollContainer.clientWidth);
|
|
198
|
+
const next = {
|
|
199
|
+
left: scrollLeft > 1,
|
|
200
|
+
right: maxScrollLeft - scrollLeft > 1
|
|
201
|
+
};
|
|
202
|
+
setScrollShadow((current) => current.left === next.left && current.right === next.right ? current : next);
|
|
203
|
+
};
|
|
204
|
+
update();
|
|
205
|
+
scrollContainer.addEventListener("scroll", update, { passive: true });
|
|
206
|
+
const resizeObserver = new ResizeObserver(update);
|
|
207
|
+
resizeObserver.observe(scrollContainer);
|
|
208
|
+
const tableElement = scrollContainer.querySelector("table");
|
|
209
|
+
if (tableElement) resizeObserver.observe(tableElement);
|
|
210
|
+
return () => {
|
|
211
|
+
scrollContainer.removeEventListener("scroll", update);
|
|
212
|
+
resizeObserver.disconnect();
|
|
213
|
+
};
|
|
214
|
+
}, [wrapperRef, containerSelector]);
|
|
215
|
+
return scrollShadow;
|
|
216
|
+
}
|
|
217
|
+
//#endregion
|
|
218
|
+
//#region src/table/utils.ts
|
|
219
|
+
/**
|
|
220
|
+
* 展开面板 row 的 DOM id 协议
|
|
221
|
+
*
|
|
222
|
+
* `DataTable` 渲染面板 row 时把这个 id 设到 `<tr id>` 上,
|
|
223
|
+
* `RowExpandToggle` 把它写进按钮的 `aria-controls`,二者必须保持一致
|
|
224
|
+
*/
|
|
225
|
+
var panelIdFor = (rowId) => `data-table-row-${rowId}-panel`;
|
|
226
|
+
/**
|
|
227
|
+
* 计算固定列(sticky)需要的样式
|
|
228
|
+
*/
|
|
229
|
+
function getCommonPinningStyles(column) {
|
|
230
|
+
const isPinned = column.getIsPinned();
|
|
231
|
+
return {
|
|
232
|
+
left: isPinned === "left" ? `${column.getStart("left")}px` : void 0,
|
|
233
|
+
opacity: isPinned ? .98 : 1,
|
|
234
|
+
position: isPinned ? "sticky" : "relative",
|
|
235
|
+
right: isPinned === "right" ? `${column.getAfter("right")}px` : void 0,
|
|
236
|
+
width: `${column.getSize()}px`,
|
|
237
|
+
zIndex: isPinned ? 1 : 0
|
|
238
|
+
};
|
|
239
|
+
}
|
|
240
|
+
/**
|
|
241
|
+
* 计算固定列阴影 className
|
|
242
|
+
*/
|
|
243
|
+
function getColumnPinningClassName(column, scrollShadow) {
|
|
244
|
+
const isPinned = column.getIsPinned();
|
|
245
|
+
const isLastLeftPinnedColumn = isPinned === "left" && column.getIsLastColumn("left");
|
|
246
|
+
const isFirstRightPinnedColumn = isPinned === "right" && column.getIsFirstColumn("right");
|
|
247
|
+
let styles = "bg-background after:transition-all";
|
|
248
|
+
if (isLastLeftPinnedColumn) styles = cn(styles, "after:absolute after:bottom-0 after:top-0 after:right-0 after:w-[30px] after:translate-x-full after:content-[''] after:shadow-[inset_15px_0_8px_-8px_#0000000d] dark:after:shadow-[inset_15px_0_8px_-8px_#ffffff0d]");
|
|
249
|
+
if (isLastLeftPinnedColumn && !scrollShadow.left) styles = cn(styles, "after:shadow-[inset_15px_0_8px_-8px_#00000000]");
|
|
250
|
+
if (isFirstRightPinnedColumn) styles = cn(styles, "after:absolute after:bottom-0 after:top-0 after:left-0 after:w-[30px] after:-translate-x-full after:content-[''] after:shadow-[inset_-15px_0_8px_-8px_#0000000d] dark:after:shadow-[inset_-15px_0_8px_-8px_#ffffff0d]");
|
|
251
|
+
if (isFirstRightPinnedColumn && !scrollShadow.right) styles = cn(styles, "after:shadow-[inset_-15px_0_8px_-8px_#00000000]");
|
|
252
|
+
return styles;
|
|
253
|
+
}
|
|
254
|
+
function ensureRow(map, rowIndex) {
|
|
255
|
+
let entry = map.get(rowIndex);
|
|
256
|
+
if (!entry) {
|
|
257
|
+
entry = /* @__PURE__ */ new Map();
|
|
258
|
+
map.set(rowIndex, entry);
|
|
259
|
+
}
|
|
260
|
+
return entry;
|
|
261
|
+
}
|
|
262
|
+
function setSpan(map, rowIndex, columnId, next) {
|
|
263
|
+
const row = ensureRow(map, rowIndex);
|
|
264
|
+
const previous = row.get(columnId) ?? {
|
|
265
|
+
rowSpan: 1,
|
|
266
|
+
colSpan: 1
|
|
267
|
+
};
|
|
268
|
+
row.set(columnId, {
|
|
269
|
+
...previous,
|
|
270
|
+
...next
|
|
271
|
+
});
|
|
272
|
+
}
|
|
273
|
+
/**
|
|
274
|
+
* 根据每列 `meta.rowSpan` / `meta.colSpan` 计算每行每列的合并跨度
|
|
275
|
+
*
|
|
276
|
+
* `0` 表示该单元格不应渲染(被合并掉了)
|
|
277
|
+
*/
|
|
278
|
+
function computeCellSpans(rows, columns) {
|
|
279
|
+
const map = /* @__PURE__ */ new Map();
|
|
280
|
+
if (rows.length === 0) return map;
|
|
281
|
+
columns.forEach((column) => {
|
|
282
|
+
const meta = column.columnDef.meta;
|
|
283
|
+
const rowSpanCfg = meta?.rowSpan;
|
|
284
|
+
if (!rowSpanCfg) return;
|
|
285
|
+
if (rowSpanCfg === true || rowSpanCfg === "auto") {
|
|
286
|
+
const parentKey = meta?.rowSpanParent;
|
|
287
|
+
let index = 0;
|
|
288
|
+
while (index < rows.length) {
|
|
289
|
+
const value = rows[index].getValue(column.id);
|
|
290
|
+
const parentValue = parentKey ? rows[index].getValue(parentKey) : void 0;
|
|
291
|
+
let span = 1;
|
|
292
|
+
while (index + span < rows.length) {
|
|
293
|
+
const nextValue = rows[index + span].getValue(column.id);
|
|
294
|
+
const nextParent = parentKey ? rows[index + span].getValue(parentKey) : void 0;
|
|
295
|
+
if (Object.is(nextValue, value) && (!parentKey || Object.is(nextParent, parentValue))) span += 1;
|
|
296
|
+
else break;
|
|
297
|
+
}
|
|
298
|
+
if (span > 1) {
|
|
299
|
+
setSpan(map, index, column.id, { rowSpan: span });
|
|
300
|
+
for (let offset = 1; offset < span; offset += 1) setSpan(map, index + offset, column.id, {
|
|
301
|
+
rowSpan: 0,
|
|
302
|
+
colSpan: 0
|
|
303
|
+
});
|
|
304
|
+
}
|
|
305
|
+
index += span;
|
|
306
|
+
}
|
|
307
|
+
} else if (typeof rowSpanCfg === "function") rows.forEach((row, rowIndex) => {
|
|
308
|
+
const span = rowSpanCfg({
|
|
309
|
+
row,
|
|
310
|
+
rows,
|
|
311
|
+
rowIndex,
|
|
312
|
+
value: row.getValue(column.id)
|
|
313
|
+
});
|
|
314
|
+
const existing = map.get(rowIndex)?.get(column.id);
|
|
315
|
+
if (existing && existing.rowSpan === 0) return;
|
|
316
|
+
if (span === 0) setSpan(map, rowIndex, column.id, {
|
|
317
|
+
rowSpan: 0,
|
|
318
|
+
colSpan: 0
|
|
319
|
+
});
|
|
320
|
+
else if (span > 1) {
|
|
321
|
+
setSpan(map, rowIndex, column.id, { rowSpan: span });
|
|
322
|
+
for (let offset = 1; offset < span; offset += 1) setSpan(map, rowIndex + offset, column.id, {
|
|
323
|
+
rowSpan: 0,
|
|
324
|
+
colSpan: 0
|
|
325
|
+
});
|
|
326
|
+
}
|
|
327
|
+
});
|
|
328
|
+
});
|
|
329
|
+
rows.forEach((row, rowIndex) => {
|
|
330
|
+
const cells = row.getVisibleCells();
|
|
331
|
+
let skipUntil = -1;
|
|
332
|
+
cells.forEach((cell, cellIndex) => {
|
|
333
|
+
const columnId = cell.column.id;
|
|
334
|
+
const rowMap = ensureRow(map, rowIndex);
|
|
335
|
+
const existing = rowMap.get(columnId);
|
|
336
|
+
if (existing && existing.rowSpan === 0) return;
|
|
337
|
+
if (cellIndex <= skipUntil) {
|
|
338
|
+
rowMap.set(columnId, {
|
|
339
|
+
rowSpan: existing?.rowSpan ?? 1,
|
|
340
|
+
colSpan: 0
|
|
341
|
+
});
|
|
342
|
+
return;
|
|
343
|
+
}
|
|
344
|
+
const colSpanCfg = cell.column.columnDef.meta?.colSpan;
|
|
345
|
+
if (typeof colSpanCfg === "function") {
|
|
346
|
+
const colSpan = colSpanCfg({
|
|
347
|
+
row,
|
|
348
|
+
rows,
|
|
349
|
+
rowIndex,
|
|
350
|
+
column: cell.column
|
|
351
|
+
});
|
|
352
|
+
if (colSpan === 0) rowMap.set(columnId, {
|
|
353
|
+
rowSpan: existing?.rowSpan ?? 1,
|
|
354
|
+
colSpan: 0
|
|
355
|
+
});
|
|
356
|
+
else if (colSpan > 1) {
|
|
357
|
+
rowMap.set(columnId, {
|
|
358
|
+
rowSpan: existing?.rowSpan ?? 1,
|
|
359
|
+
colSpan
|
|
360
|
+
});
|
|
361
|
+
skipUntil = cellIndex + colSpan - 1;
|
|
362
|
+
}
|
|
363
|
+
}
|
|
364
|
+
});
|
|
365
|
+
});
|
|
366
|
+
return map;
|
|
367
|
+
}
|
|
368
|
+
//#endregion
|
|
369
|
+
//#region src/table/components/data-table-column-header.tsx
|
|
370
|
+
/**
|
|
371
|
+
* 表头单元格,封装排序、列宽拖拽、固定列阴影
|
|
372
|
+
*/
|
|
373
|
+
function DataTableColumnHeader({ header, resizable, scrollShadow }) {
|
|
374
|
+
const canSort = header.column.getCanSort();
|
|
375
|
+
const isSorted = header.column.getIsSorted();
|
|
376
|
+
const canResize = resizable && header.column.getCanResize();
|
|
377
|
+
return /* @__PURE__ */ jsx(TableHead, {
|
|
378
|
+
"data-slot": "data-table-column-header",
|
|
379
|
+
colSpan: header.colSpan,
|
|
380
|
+
style: getCommonPinningStyles(header.column),
|
|
381
|
+
className: getColumnPinningClassName(header.column, scrollShadow),
|
|
382
|
+
children: header.isPlaceholder ? null : /* @__PURE__ */ jsxs("div", {
|
|
383
|
+
className: "flex items-center gap-1",
|
|
384
|
+
children: [/* @__PURE__ */ jsxs("div", {
|
|
385
|
+
className: cn("flex flex-1 items-center gap-1", canSort && "cursor-pointer select-none"),
|
|
386
|
+
onClick: canSort ? header.column.getToggleSortingHandler() : void 0,
|
|
387
|
+
children: [flexRender(header.column.columnDef.header, header.getContext()), canSort && /* @__PURE__ */ jsxs("span", {
|
|
388
|
+
className: "flex flex-col items-center",
|
|
389
|
+
children: [/* @__PURE__ */ jsx(ChevronUpIcon, { className: cn("text-muted-foreground -mb-1 size-[1em] transition", isSorted === "asc" && "text-foreground") }), /* @__PURE__ */ jsx(ChevronDownIcon, { className: cn("text-muted-foreground -mt-1 size-[1em] transition", isSorted === "desc" && "text-foreground") })]
|
|
390
|
+
})]
|
|
391
|
+
}), canResize && /* @__PURE__ */ jsx("span", {
|
|
392
|
+
onDoubleClick: header.column.resetSize,
|
|
393
|
+
onMouseDown: header.getResizeHandler(),
|
|
394
|
+
onTouchStart: header.getResizeHandler(),
|
|
395
|
+
className: cn("ml-auto h-[stretch] w-px cursor-col-resize touch-none select-none", "hover:bg-primary/40 data-[resizing=true]:bg-primary"),
|
|
396
|
+
"data-resizing": header.column.getIsResizing() || void 0
|
|
397
|
+
})]
|
|
398
|
+
})
|
|
399
|
+
});
|
|
400
|
+
}
|
|
401
|
+
//#endregion
|
|
402
|
+
//#region src/table/components/data-table-pagination.tsx
|
|
403
|
+
var DEFAULT_PAGE_SIZE_OPTIONS = [
|
|
404
|
+
10,
|
|
405
|
+
20,
|
|
406
|
+
30,
|
|
407
|
+
50,
|
|
408
|
+
100
|
|
409
|
+
];
|
|
410
|
+
/**
|
|
411
|
+
* 表格分页栏:总行数 / 每页数量 / 页码跳转
|
|
412
|
+
*/
|
|
413
|
+
function DataTablePagination({ table, pageSizeOptions = DEFAULT_PAGE_SIZE_OPTIONS, showSelectionCount = true }) {
|
|
414
|
+
const pagination = table.getState().pagination;
|
|
415
|
+
const selectedCount = Object.keys(table.getState().rowSelection).length;
|
|
416
|
+
const totalRows = table.getRowCount();
|
|
417
|
+
const pageCount = table.getPageCount();
|
|
418
|
+
return /* @__PURE__ */ jsxs("div", {
|
|
419
|
+
className: "text-muted-foreground flex flex-wrap items-center justify-between gap-2 py-2 text-sm",
|
|
420
|
+
children: [
|
|
421
|
+
/* @__PURE__ */ jsx("div", {
|
|
422
|
+
className: "flex-1",
|
|
423
|
+
children: showSelectionCount && selectedCount > 0 ? `已选择 ${selectedCount} / ${totalRows} 条` : `共 ${totalRows} 条`
|
|
424
|
+
}),
|
|
425
|
+
/* @__PURE__ */ jsxs("div", {
|
|
426
|
+
className: "flex items-center gap-2",
|
|
427
|
+
children: [/* @__PURE__ */ jsx("span", { children: "每页" }), /* @__PURE__ */ jsx(NativeSelect, {
|
|
428
|
+
size: "sm",
|
|
429
|
+
value: pagination.pageSize,
|
|
430
|
+
onChange: (event) => table.setPageSize(Number(event.target.value)),
|
|
431
|
+
children: pageSizeOptions.map((size) => /* @__PURE__ */ jsx(NativeSelectOption, {
|
|
432
|
+
value: size,
|
|
433
|
+
children: size
|
|
434
|
+
}, size))
|
|
435
|
+
})]
|
|
436
|
+
}),
|
|
437
|
+
/* @__PURE__ */ jsxs("div", {
|
|
438
|
+
className: "flex items-center gap-1",
|
|
439
|
+
children: [
|
|
440
|
+
/* @__PURE__ */ jsxs("span", {
|
|
441
|
+
className: "px-2",
|
|
442
|
+
children: [
|
|
443
|
+
"第 ",
|
|
444
|
+
pagination.pageIndex + 1,
|
|
445
|
+
" / ",
|
|
446
|
+
Math.max(pageCount, 1),
|
|
447
|
+
" 页"
|
|
448
|
+
]
|
|
449
|
+
}),
|
|
450
|
+
/* @__PURE__ */ jsx(Button, {
|
|
451
|
+
variant: "outline",
|
|
452
|
+
size: "icon-sm",
|
|
453
|
+
"aria-label": "第一页",
|
|
454
|
+
onClick: () => table.setPageIndex(0),
|
|
455
|
+
disabled: !table.getCanPreviousPage(),
|
|
456
|
+
children: /* @__PURE__ */ jsx(ChevronsLeftIcon, {})
|
|
457
|
+
}),
|
|
458
|
+
/* @__PURE__ */ jsx(Button, {
|
|
459
|
+
variant: "outline",
|
|
460
|
+
size: "icon-sm",
|
|
461
|
+
"aria-label": "上一页",
|
|
462
|
+
onClick: () => table.previousPage(),
|
|
463
|
+
disabled: !table.getCanPreviousPage(),
|
|
464
|
+
children: /* @__PURE__ */ jsx(ChevronLeftIcon, {})
|
|
465
|
+
}),
|
|
466
|
+
/* @__PURE__ */ jsx(Button, {
|
|
467
|
+
variant: "outline",
|
|
468
|
+
size: "icon-sm",
|
|
469
|
+
"aria-label": "下一页",
|
|
470
|
+
onClick: () => table.nextPage(),
|
|
471
|
+
disabled: !table.getCanNextPage(),
|
|
472
|
+
children: /* @__PURE__ */ jsx(ChevronRightIcon, {})
|
|
473
|
+
}),
|
|
474
|
+
/* @__PURE__ */ jsx(Button, {
|
|
475
|
+
variant: "outline",
|
|
476
|
+
size: "icon-sm",
|
|
477
|
+
"aria-label": "最后一页",
|
|
478
|
+
onClick: () => table.setPageIndex(pageCount - 1),
|
|
479
|
+
disabled: !table.getCanNextPage(),
|
|
480
|
+
children: /* @__PURE__ */ jsx(ChevronsRightIcon, {})
|
|
481
|
+
})
|
|
482
|
+
]
|
|
483
|
+
})
|
|
484
|
+
]
|
|
485
|
+
});
|
|
486
|
+
}
|
|
487
|
+
//#endregion
|
|
488
|
+
//#region src/table/components/data-table-virtual-body.tsx
|
|
489
|
+
var DEFAULT_ROW_HEIGHT = 36;
|
|
490
|
+
var DEFAULT_MAX_HEIGHT = 480;
|
|
491
|
+
var DEFAULT_OVERSCAN = 10;
|
|
492
|
+
/**
|
|
493
|
+
* 行虚拟滚动表格:使用 grid 布局 + `useVirtualizer` 仅渲染可视区域
|
|
494
|
+
*
|
|
495
|
+
* 因表格采用 grid 布局,固定列 / 多级表头暂不支持
|
|
496
|
+
*/
|
|
497
|
+
function DataTableVirtualBody({ table, loading, empty = "暂无数据", options, bordered = false, className }) {
|
|
498
|
+
const estimateRowHeight = options?.estimateRowHeight ?? DEFAULT_ROW_HEIGHT;
|
|
499
|
+
const maxHeight = options?.maxHeight ?? DEFAULT_MAX_HEIGHT;
|
|
500
|
+
const overscan = options?.overscan ?? DEFAULT_OVERSCAN;
|
|
501
|
+
const containerRef = useRef(null);
|
|
502
|
+
const rows = table.getRowModel().rows;
|
|
503
|
+
const totalWidth = table.getTotalSize();
|
|
504
|
+
const virtualizer = useVirtualizer({
|
|
505
|
+
count: rows.length,
|
|
506
|
+
getScrollElement: () => containerRef.current,
|
|
507
|
+
estimateSize: () => estimateRowHeight,
|
|
508
|
+
overscan
|
|
509
|
+
});
|
|
510
|
+
const virtualItems = virtualizer.getVirtualItems();
|
|
511
|
+
const showEmpty = !loading && rows.length === 0;
|
|
512
|
+
const skeletonRowCount = Math.max(1, Math.floor((typeof maxHeight === "number" ? maxHeight : 480) / estimateRowHeight));
|
|
513
|
+
return /* @__PURE__ */ jsx("div", {
|
|
514
|
+
ref: containerRef,
|
|
515
|
+
"data-slot": "table-container",
|
|
516
|
+
className: cn("bg-background relative overflow-auto rounded-md", bordered && "border", className),
|
|
517
|
+
style: { height: typeof maxHeight === "number" ? `${maxHeight}px` : maxHeight },
|
|
518
|
+
children: /* @__PURE__ */ jsxs("table", {
|
|
519
|
+
"data-slot": "table",
|
|
520
|
+
className: "grid text-sm",
|
|
521
|
+
style: {
|
|
522
|
+
width: `${totalWidth}px`,
|
|
523
|
+
minWidth: "100%"
|
|
524
|
+
},
|
|
525
|
+
children: [/* @__PURE__ */ jsx("thead", {
|
|
526
|
+
"data-slot": "table-header",
|
|
527
|
+
className: "bg-background sticky top-0 z-10 grid border-b",
|
|
528
|
+
children: table.getHeaderGroups().map((headerGroup) => /* @__PURE__ */ jsx("tr", {
|
|
529
|
+
className: "flex w-full",
|
|
530
|
+
children: headerGroup.headers.map((header, headerIndex) => {
|
|
531
|
+
const canSort = header.column.getCanSort();
|
|
532
|
+
const isSorted = header.column.getIsSorted();
|
|
533
|
+
const isLast = headerIndex === headerGroup.headers.length - 1;
|
|
534
|
+
return /* @__PURE__ */ jsxs("th", {
|
|
535
|
+
"data-slot": "table-head",
|
|
536
|
+
className: cn("text-foreground flex h-10 shrink-0 items-center gap-1 px-2 text-left font-medium", canSort && "cursor-pointer select-none", bordered && !isLast && "border-r"),
|
|
537
|
+
style: { width: `${header.getSize()}px` },
|
|
538
|
+
onClick: canSort ? header.column.getToggleSortingHandler() : void 0,
|
|
539
|
+
children: [header.isPlaceholder ? null : flexRender(header.column.columnDef.header, header.getContext()), canSort && /* @__PURE__ */ jsxs("span", {
|
|
540
|
+
className: "ml-1 flex flex-col items-center",
|
|
541
|
+
children: [/* @__PURE__ */ jsx(ChevronUpIcon, { className: cn("text-muted-foreground -mb-1 size-3 transition", isSorted === "asc" && "text-foreground") }), /* @__PURE__ */ jsx(ChevronDownIcon, { className: cn("text-muted-foreground -mt-1 size-3 transition", isSorted === "desc" && "text-foreground") })]
|
|
542
|
+
})]
|
|
543
|
+
}, header.id);
|
|
544
|
+
})
|
|
545
|
+
}, headerGroup.id))
|
|
546
|
+
}), /* @__PURE__ */ jsx("tbody", {
|
|
547
|
+
"data-slot": "table-body",
|
|
548
|
+
className: "relative grid",
|
|
549
|
+
style: { height: loading ? `${skeletonRowCount * estimateRowHeight}px` : `${virtualizer.getTotalSize()}px` },
|
|
550
|
+
children: loading ? Array.from({ length: skeletonRowCount }).map((_, rowIndex) => {
|
|
551
|
+
const leafColumns = table.getVisibleLeafColumns();
|
|
552
|
+
return /* @__PURE__ */ jsx("tr", {
|
|
553
|
+
className: "flex w-full border-b",
|
|
554
|
+
style: { height: `${estimateRowHeight}px` },
|
|
555
|
+
children: leafColumns.map((column, columnIndex) => {
|
|
556
|
+
const isLast = columnIndex === leafColumns.length - 1;
|
|
557
|
+
return /* @__PURE__ */ jsx("td", {
|
|
558
|
+
className: cn("flex items-center px-2", bordered && !isLast && "border-r"),
|
|
559
|
+
style: { width: `${column.getSize()}px` },
|
|
560
|
+
children: /* @__PURE__ */ jsx(Skeleton, { className: "h-4 w-full" })
|
|
561
|
+
}, column.id);
|
|
562
|
+
})
|
|
563
|
+
}, `loading-${rowIndex}`);
|
|
564
|
+
}) : showEmpty ? /* @__PURE__ */ jsx("tr", {
|
|
565
|
+
className: "flex w-full",
|
|
566
|
+
children: /* @__PURE__ */ jsx("td", {
|
|
567
|
+
colSpan: table.getVisibleLeafColumns().length,
|
|
568
|
+
className: "text-muted-foreground flex h-24 w-full items-center justify-center",
|
|
569
|
+
children: empty
|
|
570
|
+
})
|
|
571
|
+
}) : virtualItems.map((virtualRow) => {
|
|
572
|
+
const row = rows[virtualRow.index];
|
|
573
|
+
const cells = row.getVisibleCells();
|
|
574
|
+
return /* @__PURE__ */ jsx("tr", {
|
|
575
|
+
"data-index": virtualRow.index,
|
|
576
|
+
"data-state": row.getIsSelected() ? "selected" : void 0,
|
|
577
|
+
ref: (node) => virtualizer.measureElement(node),
|
|
578
|
+
className: "hover:bg-muted/50 data-[state=selected]:bg-muted absolute flex w-full border-b",
|
|
579
|
+
style: { transform: `translateY(${virtualRow.start}px)` },
|
|
580
|
+
children: cells.map((cell, cellIndex) => {
|
|
581
|
+
const isLast = cellIndex === cells.length - 1;
|
|
582
|
+
return /* @__PURE__ */ jsx("td", {
|
|
583
|
+
"data-slot": "table-cell",
|
|
584
|
+
className: cn("text-foreground flex items-center px-2", bordered && !isLast && "border-r"),
|
|
585
|
+
style: {
|
|
586
|
+
width: `${cell.column.getSize()}px`,
|
|
587
|
+
height: `${estimateRowHeight}px`
|
|
588
|
+
},
|
|
589
|
+
children: flexRender(cell.column.columnDef.cell, cell.getContext())
|
|
590
|
+
}, cell.id);
|
|
591
|
+
})
|
|
592
|
+
}, row.id);
|
|
593
|
+
})
|
|
594
|
+
})]
|
|
595
|
+
})
|
|
596
|
+
});
|
|
597
|
+
}
|
|
598
|
+
//#endregion
|
|
599
|
+
//#region src/table/components/row-drag-handle.tsx
|
|
600
|
+
var RowDragHandleContext = createContext(null);
|
|
601
|
+
/** 在 cell 内任意位置放此组件即可成为行拖拽手柄 */
|
|
602
|
+
function RowDragHandle({ className, ...props }) {
|
|
603
|
+
const handle = useContext(RowDragHandleContext);
|
|
604
|
+
if (!handle) return null;
|
|
605
|
+
return /* @__PURE__ */ jsx("button", {
|
|
606
|
+
type: "button",
|
|
607
|
+
ref: handle.setActivatorNodeRef,
|
|
608
|
+
"aria-label": "拖动排序",
|
|
609
|
+
className: cn("text-muted-foreground hover:text-foreground inline-flex size-6 cursor-grab items-center justify-center rounded-md focus-visible:outline-none active:cursor-grabbing", className),
|
|
610
|
+
...handle.attributes,
|
|
611
|
+
...handle.listeners,
|
|
612
|
+
...props,
|
|
613
|
+
children: /* @__PURE__ */ jsx(GripVerticalIcon, { className: "size-4" })
|
|
614
|
+
});
|
|
615
|
+
}
|
|
616
|
+
//#endregion
|
|
617
|
+
//#region src/table/components/data-table.tsx
|
|
618
|
+
var ROW_DND_HANDLE_COLUMN_ID = "__row_dnd_handle__";
|
|
619
|
+
var DEFAULT_SKELETON_ROWS = 8;
|
|
620
|
+
/** ReactNode 但语义上等同于"不渲染"的值(null / undefined / boolean) */
|
|
621
|
+
function isRenderablePanel(value) {
|
|
622
|
+
return value !== null && value !== void 0 && typeof value !== "boolean";
|
|
623
|
+
}
|
|
624
|
+
/**
|
|
625
|
+
* 渲染一行 cells —— 处理列合并 / 跨列 / 固定列样式
|
|
626
|
+
*
|
|
627
|
+
* 抽成共享函数,sortable 与非 sortable 两条路径都用同一份单元格生成逻辑
|
|
628
|
+
*/
|
|
629
|
+
function renderRowCells(row, rowIndex, cellSpans, scrollShadow) {
|
|
630
|
+
return row.getVisibleCells().map((cell) => {
|
|
631
|
+
const span = cellSpans.get(rowIndex)?.get(cell.column.id);
|
|
632
|
+
const rowSpan = span?.rowSpan ?? 1;
|
|
633
|
+
const colSpan = span?.colSpan ?? 1;
|
|
634
|
+
if (rowSpan === 0 || colSpan === 0) return null;
|
|
635
|
+
return /* @__PURE__ */ jsx(TableCell, {
|
|
636
|
+
rowSpan: rowSpan > 1 ? rowSpan : void 0,
|
|
637
|
+
colSpan: colSpan > 1 ? colSpan : void 0,
|
|
638
|
+
style: getCommonPinningStyles(cell.column),
|
|
639
|
+
className: getColumnPinningClassName(cell.column, scrollShadow),
|
|
640
|
+
children: flexRender(cell.column.columnDef.cell, cell.getContext())
|
|
641
|
+
}, cell.id);
|
|
642
|
+
});
|
|
643
|
+
}
|
|
644
|
+
/** 渲染展开面板 row —— 跨满全列的单格 TableRow */
|
|
645
|
+
function renderExpandedPanel({ rowId, panel, visibleColumnCount, isSelected, style, isDragging }) {
|
|
646
|
+
return /* @__PURE__ */ jsx(TableRow, {
|
|
647
|
+
id: panelIdFor(rowId),
|
|
648
|
+
"data-slot": "data-table-expanded-row",
|
|
649
|
+
"data-state": isSelected ? "selected" : void 0,
|
|
650
|
+
style,
|
|
651
|
+
className: cn("bg-muted/30 hover:bg-muted/30", isDragging && "shadow-md"),
|
|
652
|
+
children: /* @__PURE__ */ jsx(TableCell, {
|
|
653
|
+
colSpan: visibleColumnCount,
|
|
654
|
+
className: "p-4",
|
|
655
|
+
children: panel
|
|
656
|
+
})
|
|
657
|
+
});
|
|
658
|
+
}
|
|
659
|
+
function buildRowDndColumn() {
|
|
660
|
+
return {
|
|
661
|
+
id: ROW_DND_HANDLE_COLUMN_ID,
|
|
662
|
+
size: 36,
|
|
663
|
+
enableSorting: false,
|
|
664
|
+
enableHiding: false,
|
|
665
|
+
enableResizing: false,
|
|
666
|
+
enableColumnFilter: false,
|
|
667
|
+
enablePinning: false,
|
|
668
|
+
header: "",
|
|
669
|
+
cell: () => /* @__PURE__ */ jsx(RowDragHandle, {})
|
|
670
|
+
};
|
|
671
|
+
}
|
|
672
|
+
/** 单行 sortable 包装,把 dnd-kit 属性透传到 TableRow + Context */
|
|
673
|
+
function SortableTableRow({ row, rowIndex, cellSpans, scrollShadow, onRowClick, expandedPanel, visibleColumnCount }) {
|
|
674
|
+
const { attributes, listeners, setNodeRef, setActivatorNodeRef, transform, transition, isDragging } = useSortable({ id: row.id });
|
|
675
|
+
const style = {
|
|
676
|
+
transform: CSS.Transform.toString(transform),
|
|
677
|
+
transition,
|
|
678
|
+
position: isDragging ? "relative" : void 0,
|
|
679
|
+
zIndex: isDragging ? 1 : void 0
|
|
680
|
+
};
|
|
681
|
+
const isSelected = row.getIsSelected();
|
|
682
|
+
const showPanel = expandedPanel !== void 0;
|
|
683
|
+
return /* @__PURE__ */ jsxs(RowDragHandleContext.Provider, {
|
|
684
|
+
value: {
|
|
685
|
+
attributes,
|
|
686
|
+
listeners,
|
|
687
|
+
setActivatorNodeRef,
|
|
688
|
+
isDragging
|
|
689
|
+
},
|
|
690
|
+
children: [/* @__PURE__ */ jsx(TableRow, {
|
|
691
|
+
ref: setNodeRef,
|
|
692
|
+
style,
|
|
693
|
+
"data-state": isSelected ? "selected" : void 0,
|
|
694
|
+
className: cn(isDragging && "bg-muted/70 shadow-md", onRowClick && "cursor-pointer"),
|
|
695
|
+
onClick: onRowClick ? () => onRowClick(row.original) : void 0,
|
|
696
|
+
children: renderRowCells(row, rowIndex, cellSpans, scrollShadow)
|
|
697
|
+
}), showPanel ? renderExpandedPanel({
|
|
698
|
+
rowId: row.id,
|
|
699
|
+
panel: expandedPanel,
|
|
700
|
+
visibleColumnCount,
|
|
701
|
+
isSelected,
|
|
702
|
+
style,
|
|
703
|
+
isDragging
|
|
704
|
+
}) : null]
|
|
705
|
+
});
|
|
706
|
+
}
|
|
707
|
+
/**
|
|
708
|
+
* 全功能数据表格
|
|
709
|
+
*
|
|
710
|
+
* 在 `Table` 基础组件之上,基于 `@tanstack/react-table`
|
|
711
|
+
* 提供排序、筛选、分页、行选择、列显隐 / 拖拽 / 固定 / 调宽、行虚拟滚动、行拖拽排序等能力
|
|
712
|
+
*
|
|
713
|
+
* 可通过 `ref` 拿到底层 TanStack `table` 实例 ([[DataTableHandle]]) 进行命令式操作
|
|
714
|
+
*/
|
|
715
|
+
function DataTableInner({ columns, data, loading, state, initialState, onStateChange, features, renderToolbar, renderPagination, empty = "暂无数据", pageSizeOptions, className, tableClassName, onRowClick, onRowOrderChange, rowDndHandle = "auto", tableOptions, virtual = false, bordered = false, expandedRowRender }, ref) {
|
|
716
|
+
const virtualEnabled = Boolean(virtual);
|
|
717
|
+
const virtualOptions = virtual && typeof virtual === "object" ? virtual : void 0;
|
|
718
|
+
const rowDndEnabled = !virtualEnabled && Boolean(features?.rowDnd);
|
|
719
|
+
const autoHandle = rowDndEnabled && rowDndHandle === "auto";
|
|
720
|
+
const expandedRowRenderEffective = virtualEnabled ? void 0 : expandedRowRender;
|
|
721
|
+
const virtualConflicts = virtualEnabled && Boolean(features?.rowDnd || features?.expanding || expandedRowRender);
|
|
722
|
+
const rowDndMissingGetRowId = rowDndEnabled && !tableOptions?.getRowId;
|
|
723
|
+
useEffect(() => {
|
|
724
|
+
if (virtualConflicts) console.warn("[DataTable] virtual 模式与 rowDnd / expanding / expandedRowRender 不兼容,已自动忽略相关功能");
|
|
725
|
+
if (rowDndMissingGetRowId) console.warn("[DataTable] 启用 features.rowDnd 时,请通过 tableOptions.getRowId 提供稳定的行 id,否则拖拽顺序会错乱");
|
|
726
|
+
}, [virtualConflicts, rowDndMissingGetRowId]);
|
|
727
|
+
const effectiveFeatures = virtualEnabled ? {
|
|
728
|
+
...features,
|
|
729
|
+
pagination: false,
|
|
730
|
+
rowDnd: false,
|
|
731
|
+
expanding: false
|
|
732
|
+
} : features;
|
|
733
|
+
const { table, features: mergedFeatures } = useDataTable({
|
|
734
|
+
data,
|
|
735
|
+
columns: useMemo(() => autoHandle && !columns.some((c) => c.id === ROW_DND_HANDLE_COLUMN_ID) ? [buildRowDndColumn(), ...columns] : columns, [columns, autoHandle]),
|
|
736
|
+
features: effectiveFeatures,
|
|
737
|
+
state,
|
|
738
|
+
initialState,
|
|
739
|
+
onStateChange,
|
|
740
|
+
tableOptions: useMemo(() => {
|
|
741
|
+
if (!expandedRowRenderEffective) return tableOptions;
|
|
742
|
+
if (tableOptions?.getRowCanExpand) return tableOptions;
|
|
743
|
+
return {
|
|
744
|
+
...tableOptions,
|
|
745
|
+
getRowCanExpand: () => true
|
|
746
|
+
};
|
|
747
|
+
}, [tableOptions, expandedRowRenderEffective])
|
|
748
|
+
});
|
|
749
|
+
useImperativeHandle(ref, () => table, [table]);
|
|
750
|
+
const wrapperRef = useRef(null);
|
|
751
|
+
const scrollShadow = useScrollShadow(wrapperRef);
|
|
752
|
+
const visibleLeafColumns = table.getVisibleLeafColumns();
|
|
753
|
+
const visibleColumnCount = visibleLeafColumns.length;
|
|
754
|
+
const rows = table.getRowModel().rows;
|
|
755
|
+
const cellSpans = computeCellSpans(rows, visibleLeafColumns);
|
|
756
|
+
const rowIds = rows.map((row) => row.id);
|
|
757
|
+
const sensors = useSensors(useSensor(PointerSensor, { activationConstraint: { distance: 5 } }), useSensor(KeyboardSensor, { coordinateGetter: sortableKeyboardCoordinates }));
|
|
758
|
+
const handleDragEnd = (event) => {
|
|
759
|
+
const { active, over } = event;
|
|
760
|
+
if (!over || active.id === over.id) return;
|
|
761
|
+
const oldIndex = rows.findIndex((row) => row.id === String(active.id));
|
|
762
|
+
const newIndex = rows.findIndex((row) => row.id === String(over.id));
|
|
763
|
+
if (oldIndex === -1 || newIndex === -1) return;
|
|
764
|
+
const nextData = arrayMove(data, oldIndex, newIndex);
|
|
765
|
+
onRowOrderChange?.(nextData, {
|
|
766
|
+
oldIndex,
|
|
767
|
+
newIndex,
|
|
768
|
+
activeId: String(active.id),
|
|
769
|
+
overId: String(over.id)
|
|
770
|
+
});
|
|
771
|
+
};
|
|
772
|
+
const toolbarNode = renderToolbar?.(table);
|
|
773
|
+
const skeletonRowCount = mergedFeatures.pagination ? table.getState().pagination.pageSize : DEFAULT_SKELETON_ROWS;
|
|
774
|
+
const bodyContent = loading ? Array.from({ length: skeletonRowCount }).map((_, rowIndex) => /* @__PURE__ */ jsx(TableRow, { children: table.getVisibleLeafColumns().map((column) => /* @__PURE__ */ jsx(TableCell, {
|
|
775
|
+
style: getCommonPinningStyles(column),
|
|
776
|
+
className: getColumnPinningClassName(column, scrollShadow),
|
|
777
|
+
children: /* @__PURE__ */ jsx(Skeleton, { className: "h-4 w-full" })
|
|
778
|
+
}, column.id)) }, `loading-${rowIndex}`)) : rows.length ? rows.map((row, rowIndex) => {
|
|
779
|
+
const rawPanel = expandedRowRenderEffective && row.getIsExpanded() ? expandedRowRenderEffective(row) : void 0;
|
|
780
|
+
const expandedPanel = isRenderablePanel(rawPanel) ? rawPanel : void 0;
|
|
781
|
+
const isSelected = row.getIsSelected();
|
|
782
|
+
if (rowDndEnabled) return /* @__PURE__ */ jsx(SortableTableRow, {
|
|
783
|
+
row,
|
|
784
|
+
rowIndex,
|
|
785
|
+
cellSpans,
|
|
786
|
+
scrollShadow,
|
|
787
|
+
onRowClick,
|
|
788
|
+
expandedPanel,
|
|
789
|
+
visibleColumnCount
|
|
790
|
+
}, row.id);
|
|
791
|
+
if (expandedPanel === void 0) return /* @__PURE__ */ jsx(TableRow, {
|
|
792
|
+
"data-state": isSelected ? "selected" : void 0,
|
|
793
|
+
className: onRowClick ? "cursor-pointer" : void 0,
|
|
794
|
+
onClick: onRowClick ? () => onRowClick(row.original) : void 0,
|
|
795
|
+
children: renderRowCells(row, rowIndex, cellSpans, scrollShadow)
|
|
796
|
+
}, row.id);
|
|
797
|
+
return /* @__PURE__ */ jsxs(Fragment$1, { children: [/* @__PURE__ */ jsx(TableRow, {
|
|
798
|
+
"data-state": isSelected ? "selected" : void 0,
|
|
799
|
+
className: onRowClick ? "cursor-pointer" : void 0,
|
|
800
|
+
onClick: onRowClick ? () => onRowClick(row.original) : void 0,
|
|
801
|
+
children: renderRowCells(row, rowIndex, cellSpans, scrollShadow)
|
|
802
|
+
}), renderExpandedPanel({
|
|
803
|
+
rowId: row.id,
|
|
804
|
+
panel: expandedPanel,
|
|
805
|
+
visibleColumnCount,
|
|
806
|
+
isSelected
|
|
807
|
+
})] }, row.id);
|
|
808
|
+
}) : /* @__PURE__ */ jsx(TableRow, { children: /* @__PURE__ */ jsx(TableCell, {
|
|
809
|
+
colSpan: visibleColumnCount,
|
|
810
|
+
className: "text-muted-foreground h-24 text-center",
|
|
811
|
+
children: empty
|
|
812
|
+
}) });
|
|
813
|
+
const standardBody = /* @__PURE__ */ jsx("div", {
|
|
814
|
+
ref: wrapperRef,
|
|
815
|
+
className: cn("rounded-md", bordered && "border [&_td]:border-r [&_th]:border-r [&_tr>*:last-child]:border-r-0", tableClassName),
|
|
816
|
+
children: /* @__PURE__ */ jsxs(Table, {
|
|
817
|
+
className: "min-w-max",
|
|
818
|
+
style: mergedFeatures.columnResizing ? { width: table.getTotalSize() } : void 0,
|
|
819
|
+
children: [/* @__PURE__ */ jsx(TableHeader, { children: table.getHeaderGroups().map((headerGroup) => /* @__PURE__ */ jsx(TableRow, { children: headerGroup.headers.map((header) => /* @__PURE__ */ jsx(DataTableColumnHeader, {
|
|
820
|
+
header,
|
|
821
|
+
resizable: mergedFeatures.columnResizing,
|
|
822
|
+
scrollShadow
|
|
823
|
+
}, header.id)) }, headerGroup.id)) }), /* @__PURE__ */ jsx(TableBody, { children: rowDndEnabled ? /* @__PURE__ */ jsx(SortableContext, {
|
|
824
|
+
items: rowIds,
|
|
825
|
+
strategy: verticalListSortingStrategy,
|
|
826
|
+
children: bodyContent
|
|
827
|
+
}) : bodyContent })]
|
|
828
|
+
})
|
|
829
|
+
});
|
|
830
|
+
const bodyNode = virtualEnabled ? /* @__PURE__ */ jsx(DataTableVirtualBody, {
|
|
831
|
+
table,
|
|
832
|
+
loading,
|
|
833
|
+
empty,
|
|
834
|
+
options: virtualOptions,
|
|
835
|
+
bordered,
|
|
836
|
+
className: tableClassName
|
|
837
|
+
}) : rowDndEnabled ? /* @__PURE__ */ jsx(DndContext, {
|
|
838
|
+
sensors,
|
|
839
|
+
collisionDetection: closestCenter,
|
|
840
|
+
modifiers: [restrictToVerticalAxis],
|
|
841
|
+
onDragEnd: handleDragEnd,
|
|
842
|
+
children: standardBody
|
|
843
|
+
}) : standardBody;
|
|
844
|
+
return /* @__PURE__ */ jsxs("div", {
|
|
845
|
+
"data-slot": "data-table",
|
|
846
|
+
className: cn("flex flex-col", className),
|
|
847
|
+
children: [
|
|
848
|
+
toolbarNode,
|
|
849
|
+
bodyNode,
|
|
850
|
+
mergedFeatures.pagination && (renderPagination !== void 0 ? renderPagination(table) : /* @__PURE__ */ jsx(DataTablePagination, {
|
|
851
|
+
table,
|
|
852
|
+
pageSizeOptions
|
|
853
|
+
}))
|
|
854
|
+
]
|
|
855
|
+
});
|
|
856
|
+
}
|
|
857
|
+
/**
|
|
858
|
+
* forwardRef 包装,泛型用 cast 保留 —— 否则会被 forwardRef 的签名擦除成 unknown
|
|
859
|
+
*/
|
|
860
|
+
var DataTable = forwardRef(DataTableInner);
|
|
861
|
+
//#endregion
|
|
862
|
+
//#region src/table/components/data-table-view-options.tsx
|
|
863
|
+
/**
|
|
864
|
+
* 列显隐 / 排序 / 固定 设置面板
|
|
865
|
+
*
|
|
866
|
+
* 通过 DropdownMenu 弹出列表,内置 DnD-Kit 排序与固定按钮
|
|
867
|
+
*/
|
|
868
|
+
function DataTableViewOptions({ table, enableOrdering = false, enablePinning = false, trigger }) {
|
|
869
|
+
const draggableColumns = table.getAllLeafColumns().filter((column) => column.getCanHide());
|
|
870
|
+
const draggableColumnIds = draggableColumns.map((column) => column.id);
|
|
871
|
+
const sensors = useSensors(useSensor(PointerSensor, { activationConstraint: { distance: 5 } }), useSensor(KeyboardSensor, { coordinateGetter: sortableKeyboardCoordinates }));
|
|
872
|
+
const handleDragEnd = ({ active, over }) => {
|
|
873
|
+
if (!over || active.id === over.id) return;
|
|
874
|
+
const currentOrder = table.getState().columnOrder;
|
|
875
|
+
const allColumnIds = table.getAllLeafColumns().map((column) => column.id);
|
|
876
|
+
const orderedColumnIds = currentOrder.length ? currentOrder.filter((columnId) => allColumnIds.includes(columnId)) : allColumnIds;
|
|
877
|
+
const nextOrder = [...orderedColumnIds, ...allColumnIds.filter((columnId) => !orderedColumnIds.includes(columnId))];
|
|
878
|
+
const oldIndex = nextOrder.indexOf(String(active.id));
|
|
879
|
+
const newIndex = nextOrder.indexOf(String(over.id));
|
|
880
|
+
if (oldIndex === -1 || newIndex === -1) return;
|
|
881
|
+
table.setColumnOrder(arrayMove(nextOrder, oldIndex, newIndex));
|
|
882
|
+
};
|
|
883
|
+
return /* @__PURE__ */ jsxs(DropdownMenu, { children: [/* @__PURE__ */ jsx(DropdownMenuTrigger, { render: trigger ?? /* @__PURE__ */ jsxs(Button, {
|
|
884
|
+
variant: "outline",
|
|
885
|
+
size: "sm",
|
|
886
|
+
children: [/* @__PURE__ */ jsx(Settings2Icon, {}), "视图"]
|
|
887
|
+
}) }), /* @__PURE__ */ jsxs(DropdownMenuContent, {
|
|
888
|
+
align: "end",
|
|
889
|
+
className: "min-w-56",
|
|
890
|
+
children: [
|
|
891
|
+
/* @__PURE__ */ jsx(DropdownMenuGroup, { children: /* @__PURE__ */ jsx(DropdownMenuLabel, { children: "显示的列" }) }),
|
|
892
|
+
/* @__PURE__ */ jsx(DropdownMenuSeparator, {}),
|
|
893
|
+
enableOrdering ? /* @__PURE__ */ jsx(DndContext, {
|
|
894
|
+
sensors,
|
|
895
|
+
collisionDetection: closestCenter,
|
|
896
|
+
modifiers: [restrictToVerticalAxis],
|
|
897
|
+
onDragEnd: handleDragEnd,
|
|
898
|
+
children: /* @__PURE__ */ jsx(SortableContext, {
|
|
899
|
+
items: enableOrdering ? draggableColumnIds : [],
|
|
900
|
+
strategy: verticalListSortingStrategy,
|
|
901
|
+
children: draggableColumns.map((column) => /* @__PURE__ */ jsx(SortableColumnItem, {
|
|
902
|
+
column,
|
|
903
|
+
enablePinning
|
|
904
|
+
}, column.id))
|
|
905
|
+
})
|
|
906
|
+
}) : draggableColumns.map((column) => /* @__PURE__ */ jsx(ColumnVisibilityItem, {
|
|
907
|
+
column,
|
|
908
|
+
enablePinning
|
|
909
|
+
}, column.id))
|
|
910
|
+
]
|
|
911
|
+
})] });
|
|
912
|
+
}
|
|
913
|
+
/**
|
|
914
|
+
* 列设置项内部统一渲染:复选 + 列名 + 可选固定操作
|
|
915
|
+
*/
|
|
916
|
+
function ColumnItemBody({ column, enablePinning, dragHandle }) {
|
|
917
|
+
const pinned = column.getIsPinned();
|
|
918
|
+
const canPin = enablePinning && column.getCanPin();
|
|
919
|
+
const handlePinClick = (event, position) => {
|
|
920
|
+
event.preventDefault();
|
|
921
|
+
event.stopPropagation();
|
|
922
|
+
column.pin(position);
|
|
923
|
+
};
|
|
924
|
+
return /* @__PURE__ */ jsxs(DropdownMenuCheckboxItem, {
|
|
925
|
+
className: "capitalize",
|
|
926
|
+
checked: column.getIsVisible(),
|
|
927
|
+
onCheckedChange: (value) => column.toggleVisibility(!!value),
|
|
928
|
+
children: [
|
|
929
|
+
dragHandle,
|
|
930
|
+
/* @__PURE__ */ jsx("span", {
|
|
931
|
+
className: "min-w-20 flex-1",
|
|
932
|
+
children: column.id
|
|
933
|
+
}),
|
|
934
|
+
canPin && /* @__PURE__ */ jsxs("span", {
|
|
935
|
+
className: "ml-auto mr-5 flex items-center gap-1 normal-case",
|
|
936
|
+
onClick: (event) => event.stopPropagation(),
|
|
937
|
+
onPointerDown: (event) => event.stopPropagation(),
|
|
938
|
+
children: [
|
|
939
|
+
/* @__PURE__ */ jsx(Button, {
|
|
940
|
+
type: "button",
|
|
941
|
+
variant: pinned === "left" ? "default" : "ghost",
|
|
942
|
+
size: "xs",
|
|
943
|
+
onClick: (event) => handlePinClick(event, "left"),
|
|
944
|
+
children: "左"
|
|
945
|
+
}),
|
|
946
|
+
/* @__PURE__ */ jsx(Button, {
|
|
947
|
+
type: "button",
|
|
948
|
+
variant: pinned ? "ghost" : "default",
|
|
949
|
+
size: "xs",
|
|
950
|
+
onClick: (event) => handlePinClick(event, false),
|
|
951
|
+
children: "无"
|
|
952
|
+
}),
|
|
953
|
+
/* @__PURE__ */ jsx(Button, {
|
|
954
|
+
type: "button",
|
|
955
|
+
variant: pinned === "right" ? "default" : "ghost",
|
|
956
|
+
size: "xs",
|
|
957
|
+
onClick: (event) => handlePinClick(event, "right"),
|
|
958
|
+
children: "右"
|
|
959
|
+
})
|
|
960
|
+
]
|
|
961
|
+
})
|
|
962
|
+
]
|
|
963
|
+
});
|
|
964
|
+
}
|
|
965
|
+
function ColumnVisibilityItem({ column, enablePinning }) {
|
|
966
|
+
return /* @__PURE__ */ jsx(ColumnItemBody, {
|
|
967
|
+
column,
|
|
968
|
+
enablePinning
|
|
969
|
+
});
|
|
970
|
+
}
|
|
971
|
+
function SortableColumnItem({ column, enablePinning }) {
|
|
972
|
+
const { attributes, listeners, setActivatorNodeRef, setNodeRef, transform, transition, isDragging } = useSortable({ id: column.id });
|
|
973
|
+
return /* @__PURE__ */ jsx("div", {
|
|
974
|
+
ref: setNodeRef,
|
|
975
|
+
style: {
|
|
976
|
+
transform: CSS.Transform.toString(transform),
|
|
977
|
+
transition
|
|
978
|
+
},
|
|
979
|
+
className: cn(isDragging && "relative z-10 opacity-80"),
|
|
980
|
+
children: /* @__PURE__ */ jsx(ColumnItemBody, {
|
|
981
|
+
column,
|
|
982
|
+
enablePinning,
|
|
983
|
+
dragHandle: /* @__PURE__ */ jsx("span", {
|
|
984
|
+
ref: setActivatorNodeRef,
|
|
985
|
+
className: "cursor-grab active:cursor-grabbing",
|
|
986
|
+
"aria-label": `Reorder ${column.id} column`,
|
|
987
|
+
onClick: (event) => event.stopPropagation(),
|
|
988
|
+
...attributes,
|
|
989
|
+
...listeners,
|
|
990
|
+
children: /* @__PURE__ */ jsx(GripVerticalIcon, { className: "size-[1em]" })
|
|
991
|
+
})
|
|
992
|
+
})
|
|
993
|
+
});
|
|
994
|
+
}
|
|
995
|
+
//#endregion
|
|
996
|
+
//#region src/table/components/data-table-toolbar.tsx
|
|
997
|
+
/**
|
|
998
|
+
* 表格工具栏:搜索 + 视图配置 + 自定义扩展
|
|
999
|
+
*/
|
|
1000
|
+
function DataTableToolbar({ table, searchColumnId, searchPlaceholder = "搜索...", showViewOptions = true, enableColumnOrdering, enableColumnPinning, extra, className }) {
|
|
1001
|
+
const searchColumn = searchColumnId ? table.getColumn(searchColumnId) : void 0;
|
|
1002
|
+
const useGlobalFilter = !searchColumn;
|
|
1003
|
+
const value = useGlobalFilter ? table.getState().globalFilter : searchColumn?.getFilterValue();
|
|
1004
|
+
const hasValue = Boolean(value);
|
|
1005
|
+
const handleChange = (next) => {
|
|
1006
|
+
if (useGlobalFilter) table.setGlobalFilter(next);
|
|
1007
|
+
else searchColumn?.setFilterValue(next || void 0);
|
|
1008
|
+
};
|
|
1009
|
+
return /* @__PURE__ */ jsxs("div", {
|
|
1010
|
+
"data-slot": "data-table-toolbar",
|
|
1011
|
+
className: cn("flex flex-wrap items-center gap-2 py-3", className),
|
|
1012
|
+
children: [/* @__PURE__ */ jsxs("div", {
|
|
1013
|
+
className: "relative max-w-sm flex-1",
|
|
1014
|
+
children: [
|
|
1015
|
+
/* @__PURE__ */ jsx(SearchIcon, { className: "text-muted-foreground pointer-events-none absolute left-2.5 top-1/2 size-4 -translate-y-1/2" }),
|
|
1016
|
+
/* @__PURE__ */ jsx(Input, {
|
|
1017
|
+
placeholder: searchPlaceholder,
|
|
1018
|
+
value: value ?? "",
|
|
1019
|
+
onChange: (event) => handleChange(event.target.value),
|
|
1020
|
+
className: "pl-8 pr-8"
|
|
1021
|
+
}),
|
|
1022
|
+
hasValue && /* @__PURE__ */ jsx(Button, {
|
|
1023
|
+
type: "button",
|
|
1024
|
+
variant: "ghost",
|
|
1025
|
+
size: "icon-xs",
|
|
1026
|
+
className: "absolute right-1 top-1/2 -translate-y-1/2",
|
|
1027
|
+
"aria-label": "清除搜索",
|
|
1028
|
+
onClick: () => handleChange(""),
|
|
1029
|
+
children: /* @__PURE__ */ jsx(XIcon, {})
|
|
1030
|
+
})
|
|
1031
|
+
]
|
|
1032
|
+
}), /* @__PURE__ */ jsxs("div", {
|
|
1033
|
+
className: "ml-auto flex items-center gap-2",
|
|
1034
|
+
children: [extra, showViewOptions && /* @__PURE__ */ jsx(DataTableViewOptions, {
|
|
1035
|
+
table,
|
|
1036
|
+
enableOrdering: enableColumnOrdering,
|
|
1037
|
+
enablePinning: enableColumnPinning
|
|
1038
|
+
})]
|
|
1039
|
+
})]
|
|
1040
|
+
});
|
|
1041
|
+
}
|
|
1042
|
+
//#endregion
|
|
1043
|
+
//#region src/table/components/row-expand-toggle.tsx
|
|
1044
|
+
/**
|
|
1045
|
+
* 行展开切换按钮:基于 `row.getToggleExpandedHandler` + `row.depth` 自动缩进
|
|
1046
|
+
*
|
|
1047
|
+
* 配合 `features.expanding` 与 `tableOptions.getSubRows`(嵌套树),或 `expandedRowRender`(展开面板)使用
|
|
1048
|
+
*/
|
|
1049
|
+
function RowExpandToggle({ row, indent = 16, placeholder = true, className, ...props }) {
|
|
1050
|
+
const paddingLeft = indent > 0 ? row.depth * indent : 0;
|
|
1051
|
+
const canExpand = row.getCanExpand();
|
|
1052
|
+
const isExpanded = row.getIsExpanded();
|
|
1053
|
+
if (!canExpand) {
|
|
1054
|
+
if (!placeholder) return null;
|
|
1055
|
+
return /* @__PURE__ */ jsx("span", {
|
|
1056
|
+
"aria-hidden": true,
|
|
1057
|
+
className: "inline-flex size-6 shrink-0",
|
|
1058
|
+
style: paddingLeft ? { marginLeft: paddingLeft } : void 0
|
|
1059
|
+
});
|
|
1060
|
+
}
|
|
1061
|
+
const hasPanelTarget = row.subRows.length === 0;
|
|
1062
|
+
return /* @__PURE__ */ jsx("button", {
|
|
1063
|
+
type: "button",
|
|
1064
|
+
"aria-label": isExpanded ? "收起" : "展开",
|
|
1065
|
+
"aria-expanded": isExpanded,
|
|
1066
|
+
"aria-controls": isExpanded && hasPanelTarget ? panelIdFor(row.id) : void 0,
|
|
1067
|
+
onClick: row.getToggleExpandedHandler(),
|
|
1068
|
+
className: cn("text-muted-foreground hover:text-foreground inline-flex size-6 shrink-0 cursor-pointer items-center justify-center rounded-md transition-colors focus-visible:outline-none", className),
|
|
1069
|
+
style: paddingLeft ? { marginLeft: paddingLeft } : void 0,
|
|
1070
|
+
...props,
|
|
1071
|
+
children: /* @__PURE__ */ jsx(ChevronRightIcon, { className: cn("size-4 transition-transform", isExpanded ? "rotate-90" : "rotate-0") })
|
|
1072
|
+
});
|
|
1073
|
+
}
|
|
1074
|
+
//#endregion
|
|
1075
|
+
export { TableRow as C, TableHeader as S, TableBody as _, RowDragHandle as a, TableFooter as b, DataTablePagination as c, getColumnPinningClassName as d, getCommonPinningStyles as f, Table as g, useScrollShadow as h, DataTable as i, DataTableColumnHeader as l, useDataTable as m, DataTableToolbar as n, RowDragHandleContext as o, panelIdFor as p, DataTableViewOptions as r, DataTableVirtualBody as s, RowExpandToggle as t, computeCellSpans as u, TableCaption as v, TableHead as x, TableCell as y };
|
|
1076
|
+
|
|
1077
|
+
//# sourceMappingURL=table-BA2BijtZ.mjs.map
|