@ackplus/react-tanstack-data-table 1.1.15 → 1.1.17
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/README.md +0 -8
- package/dist/index.d.ts +4 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +5 -1
- package/dist/lib/components/data-table-view.d.ts +7 -0
- package/dist/lib/components/data-table-view.d.ts.map +1 -0
- package/dist/lib/components/data-table-view.js +151 -0
- package/dist/lib/components/toolbar/data-table-toolbar.d.ts.map +1 -1
- package/dist/lib/components/toolbar/data-table-toolbar.js +14 -1
- package/dist/lib/components/toolbar/table-export-control.d.ts.map +1 -1
- package/dist/lib/components/toolbar/table-export-control.js +0 -2
- package/dist/lib/data-table.d.ts +0 -3
- package/dist/lib/data-table.d.ts.map +1 -1
- package/dist/lib/data-table.js +9 -1646
- package/dist/lib/features/selection.feature.d.ts.map +1 -1
- package/dist/lib/features/selection.feature.js +1 -2
- package/dist/lib/hooks/index.d.ts +3 -0
- package/dist/lib/hooks/index.d.ts.map +1 -0
- package/dist/lib/hooks/index.js +5 -0
- package/dist/lib/hooks/use-data-table-engine.d.ts +104 -0
- package/dist/lib/hooks/use-data-table-engine.d.ts.map +1 -0
- package/dist/lib/hooks/use-data-table-engine.js +961 -0
- package/dist/lib/types/data-table-api.d.ts +1 -1
- package/dist/lib/types/data-table-api.d.ts.map +1 -1
- package/dist/lib/types/data-table.types.d.ts +1 -2
- package/dist/lib/types/data-table.types.d.ts.map +1 -1
- package/package.json +1 -1
- package/src/index.ts +4 -0
- package/src/lib/components/data-table-view.tsx +386 -0
- package/src/lib/components/toolbar/data-table-toolbar.tsx +15 -1
- package/src/lib/components/toolbar/table-export-control.tsx +0 -2
- package/src/lib/data-table.tsx +17 -2201
- package/src/lib/features/selection.feature.ts +1 -3
- package/src/lib/hooks/index.ts +2 -0
- package/src/lib/hooks/use-data-table-engine.ts +1282 -0
- package/src/lib/types/data-table-api.ts +1 -1
- package/src/lib/types/data-table.types.ts +1 -2
|
@@ -0,0 +1,961 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.useDataTableEngine = useDataTableEngine;
|
|
4
|
+
const react_table_1 = require("@tanstack/react-table");
|
|
5
|
+
const react_virtual_1 = require("@tanstack/react-virtual");
|
|
6
|
+
const styles_1 = require("@mui/material/styles");
|
|
7
|
+
const react_1 = require("react");
|
|
8
|
+
// your features / utils
|
|
9
|
+
const column_filter_feature_1 = require("../features/column-filter.feature");
|
|
10
|
+
const features_1 = require("../features");
|
|
11
|
+
const special_columns_utils_1 = require("../utils/special-columns.utils");
|
|
12
|
+
const utils_1 = require("../utils");
|
|
13
|
+
const debounced_fetch_utils_1 = require("../utils/debounced-fetch.utils");
|
|
14
|
+
const DEFAULT_INITIAL_STATE = {
|
|
15
|
+
sorting: [],
|
|
16
|
+
pagination: { pageIndex: 0, pageSize: 10 },
|
|
17
|
+
selectionState: { ids: [], type: "include" },
|
|
18
|
+
globalFilter: "",
|
|
19
|
+
expanded: {},
|
|
20
|
+
columnOrder: [],
|
|
21
|
+
columnPinning: { left: [], right: [] },
|
|
22
|
+
columnVisibility: {},
|
|
23
|
+
columnSizing: {},
|
|
24
|
+
columnFilter: {
|
|
25
|
+
filters: [],
|
|
26
|
+
logic: "AND",
|
|
27
|
+
pendingFilters: [],
|
|
28
|
+
pendingLogic: "AND",
|
|
29
|
+
},
|
|
30
|
+
};
|
|
31
|
+
function uiReducer(state, action) {
|
|
32
|
+
switch (action.type) {
|
|
33
|
+
case "SET_SORTING_RESET_PAGE":
|
|
34
|
+
return { ...state, sorting: action.payload, pagination: { pageIndex: 0, pageSize: state.pagination.pageSize } };
|
|
35
|
+
case "SET_PAGINATION":
|
|
36
|
+
return { ...state, pagination: action.payload };
|
|
37
|
+
case "SET_GLOBAL_FILTER_RESET_PAGE":
|
|
38
|
+
return { ...state, globalFilter: action.payload, pagination: { pageIndex: 0, pageSize: state.pagination.pageSize } };
|
|
39
|
+
case "SET_SELECTION":
|
|
40
|
+
return { ...state, selectionState: action.payload };
|
|
41
|
+
case "SET_COLUMN_FILTER":
|
|
42
|
+
return { ...state, columnFilter: action.payload };
|
|
43
|
+
case "SET_COLUMN_FILTER_RESET_PAGE":
|
|
44
|
+
return { ...state, columnFilter: action.payload, pagination: { pageIndex: 0, pageSize: state.pagination.pageSize } };
|
|
45
|
+
case "SET_EXPANDED":
|
|
46
|
+
return { ...state, expanded: action.payload };
|
|
47
|
+
case "SET_TABLE_SIZE":
|
|
48
|
+
return { ...state, tableSize: action.payload };
|
|
49
|
+
case "SET_COLUMN_ORDER":
|
|
50
|
+
return { ...state, columnOrder: action.payload };
|
|
51
|
+
case "SET_COLUMN_PINNING":
|
|
52
|
+
return { ...state, columnPinning: action.payload };
|
|
53
|
+
case "SET_COLUMN_VISIBILITY":
|
|
54
|
+
return { ...state, columnVisibility: action.payload };
|
|
55
|
+
case "SET_COLUMN_SIZING":
|
|
56
|
+
return { ...state, columnSizing: action.payload };
|
|
57
|
+
case "RESTORE_LAYOUT":
|
|
58
|
+
return { ...state, ...action.payload };
|
|
59
|
+
case "RESET_ALL":
|
|
60
|
+
return { ...state, ...action.payload };
|
|
61
|
+
default:
|
|
62
|
+
return state;
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
function useLatestRef(value) {
|
|
66
|
+
const ref = (0, react_1.useRef)(value);
|
|
67
|
+
(0, react_1.useEffect)(() => {
|
|
68
|
+
ref.current = value;
|
|
69
|
+
}, [value]);
|
|
70
|
+
return ref;
|
|
71
|
+
}
|
|
72
|
+
function useEvent(fn) {
|
|
73
|
+
const fnRef = useLatestRef(fn);
|
|
74
|
+
return (0, react_1.useCallback)(((...args) => fnRef.current(...args)), [fnRef]);
|
|
75
|
+
}
|
|
76
|
+
function useDataTableEngine(props) {
|
|
77
|
+
const { initialState, columns, data = [], totalRow = 0, idKey = "id", dataMode = "client", initialLoadData = true, onFetchData, onFetchStateChange, onDataStateChange, enableRowSelection = false, enableMultiRowSelection = true, selectMode = "page", isRowSelectable, onSelectionChange, enableBulkActions = false, enableColumnResizing = false, columnResizeMode = "onChange", onColumnSizingChange, enableColumnDragging = false, onColumnDragEnd, enableColumnPinning = false, onColumnPinningChange, onColumnVisibilityChange, enableColumnVisibility = true, enableExpanding = false, getRowCanExpand, enablePagination = false, paginationMode = "client", enableGlobalFilter = true, enableColumnFilter = false, filterMode = "client", enableSorting = true, sortingMode = "client", onSortingChange, exportFilename = "export", exportConcurrency = "cancelAndRestart", exportChunkSize = 1000, exportStrictTotalCheck = false, exportSanitizeCSV = true, onExportProgress, onExportComplete, onExportError, onServerExport, onExportCancel, onExportStateChange, fitToScreen = true, tableSize: initialTableSize = "medium", enableVirtualization = false, estimateRowHeight = 52, loading = false, onColumnFiltersChange, onPaginationChange, onGlobalFilterChange, slots = {}, slotProps = {}, } = props;
|
|
78
|
+
const theme = (0, styles_1.useTheme)();
|
|
79
|
+
const isServerMode = dataMode === "server";
|
|
80
|
+
const isServerPagination = paginationMode === "server" || isServerMode;
|
|
81
|
+
const isServerFiltering = filterMode === "server" || isServerMode;
|
|
82
|
+
const isServerSorting = sortingMode === "server" || isServerMode;
|
|
83
|
+
// --- initial config (memo)
|
|
84
|
+
const initialStateConfig = (0, react_1.useMemo)(() => {
|
|
85
|
+
const config = { ...DEFAULT_INITIAL_STATE, ...initialState };
|
|
86
|
+
return config;
|
|
87
|
+
}, [initialState]);
|
|
88
|
+
const initialUIState = (0, react_1.useMemo)(() => {
|
|
89
|
+
var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k;
|
|
90
|
+
return ({
|
|
91
|
+
sorting: (_a = initialStateConfig.sorting) !== null && _a !== void 0 ? _a : DEFAULT_INITIAL_STATE.sorting,
|
|
92
|
+
pagination: (_b = initialStateConfig.pagination) !== null && _b !== void 0 ? _b : DEFAULT_INITIAL_STATE.pagination,
|
|
93
|
+
globalFilter: (_c = initialStateConfig.globalFilter) !== null && _c !== void 0 ? _c : DEFAULT_INITIAL_STATE.globalFilter,
|
|
94
|
+
selectionState: (_d = initialStateConfig.selectionState) !== null && _d !== void 0 ? _d : DEFAULT_INITIAL_STATE.selectionState,
|
|
95
|
+
columnFilter: (_e = initialStateConfig.columnFilter) !== null && _e !== void 0 ? _e : DEFAULT_INITIAL_STATE.columnFilter,
|
|
96
|
+
expanded: (_f = initialStateConfig.expanded) !== null && _f !== void 0 ? _f : {},
|
|
97
|
+
tableSize: (initialTableSize || "medium"),
|
|
98
|
+
columnOrder: (_g = initialStateConfig.columnOrder) !== null && _g !== void 0 ? _g : DEFAULT_INITIAL_STATE.columnOrder,
|
|
99
|
+
columnPinning: (_h = initialStateConfig.columnPinning) !== null && _h !== void 0 ? _h : DEFAULT_INITIAL_STATE.columnPinning,
|
|
100
|
+
columnVisibility: (_j = initialStateConfig.columnVisibility) !== null && _j !== void 0 ? _j : DEFAULT_INITIAL_STATE.columnVisibility,
|
|
101
|
+
columnSizing: (_k = initialStateConfig.columnSizing) !== null && _k !== void 0 ? _k : DEFAULT_INITIAL_STATE.columnSizing,
|
|
102
|
+
});
|
|
103
|
+
}, [initialStateConfig, initialTableSize]);
|
|
104
|
+
// --- UI state (reducer)
|
|
105
|
+
const [ui, dispatch] = (0, react_1.useReducer)(uiReducer, initialUIState);
|
|
106
|
+
// --- server data state (UI-affecting)
|
|
107
|
+
const [serverData, setServerData] = (0, react_1.useState)(null);
|
|
108
|
+
const [serverTotal, setServerTotal] = (0, react_1.useState)(0);
|
|
109
|
+
// --- export UI state
|
|
110
|
+
const [exportPhase, setExportPhase] = (0, react_1.useState)(null);
|
|
111
|
+
const [exportProgress, setExportProgress] = (0, react_1.useState)({});
|
|
112
|
+
const [exportController, setExportController] = (0, react_1.useState)(null);
|
|
113
|
+
const [queuedExportCount, setQueuedExportCount] = (0, react_1.useState)(0);
|
|
114
|
+
// --- refs (no-render control)
|
|
115
|
+
const tableContainerRef = (0, react_1.useRef)(null);
|
|
116
|
+
const apiRef = (0, react_1.useRef)(null);
|
|
117
|
+
const exportControllerRef = (0, react_1.useRef)(null);
|
|
118
|
+
const exportQueueRef = (0, react_1.useRef)(Promise.resolve());
|
|
119
|
+
const lastSentRef = (0, react_1.useRef)("");
|
|
120
|
+
// --- latest refs (prevent stale closures in stable API)
|
|
121
|
+
const uiRef = useLatestRef(ui);
|
|
122
|
+
const dataRef = useLatestRef(data);
|
|
123
|
+
;
|
|
124
|
+
const serverDataRef = useLatestRef(serverData);
|
|
125
|
+
const nextFetchDelayRef = (0, react_1.useRef)(0);
|
|
126
|
+
// callbacks refs (super important)
|
|
127
|
+
const onFetchDataRef = useLatestRef(onFetchData);
|
|
128
|
+
const onFetchStateChangeRef = useLatestRef(onFetchStateChange);
|
|
129
|
+
const onDataStateChangeRef = useLatestRef(onDataStateChange);
|
|
130
|
+
const onSortingChangeRef = useLatestRef(onSortingChange);
|
|
131
|
+
const onPaginationChangeRef = useLatestRef(onPaginationChange);
|
|
132
|
+
const onGlobalFilterChangeRef = useLatestRef(onGlobalFilterChange);
|
|
133
|
+
const onColumnFiltersChangeRef = useLatestRef(onColumnFiltersChange);
|
|
134
|
+
const onColumnDragEndRef = useLatestRef(onColumnDragEnd);
|
|
135
|
+
const onColumnPinningChangeRef = useLatestRef(onColumnPinningChange);
|
|
136
|
+
const onColumnVisibilityChangeRef = useLatestRef(onColumnVisibilityChange);
|
|
137
|
+
const onColumnSizingChangeRef = useLatestRef(onColumnSizingChange);
|
|
138
|
+
const onSelectionChangeRef = useLatestRef(onSelectionChange);
|
|
139
|
+
const onExportProgressRef = useLatestRef(onExportProgress);
|
|
140
|
+
const onExportCompleteRef = useLatestRef(onExportComplete);
|
|
141
|
+
const onExportErrorRef = useLatestRef(onExportError);
|
|
142
|
+
const onExportCancelRef = useLatestRef(onExportCancel);
|
|
143
|
+
const onExportStateChangeRef = useLatestRef(onExportStateChange);
|
|
144
|
+
const onServerExportRef = useLatestRef(onServerExport);
|
|
145
|
+
// --- debounced fetch helper (can stay as-is)
|
|
146
|
+
const fetchHandler = useEvent((filters, opts) => { var _a; return (_a = onFetchDataRef.current) === null || _a === void 0 ? void 0 : _a.call(onFetchDataRef, filters, opts); });
|
|
147
|
+
const { debouncedFetch, isLoading: fetchLoading } = (0, debounced_fetch_utils_1.useDebouncedFetch)(fetchHandler);
|
|
148
|
+
const tableData = (0, react_1.useMemo)(() => {
|
|
149
|
+
return serverData !== null ? serverData : data;
|
|
150
|
+
}, [serverData, data]);
|
|
151
|
+
const tableTotalRow = (0, react_1.useMemo)(() => {
|
|
152
|
+
return serverData !== null ? serverTotal : totalRow || data.length;
|
|
153
|
+
}, [serverData, serverTotal, totalRow, data]);
|
|
154
|
+
const tableLoading = (0, react_1.useMemo)(() => {
|
|
155
|
+
return onFetchData ? loading || fetchLoading : loading;
|
|
156
|
+
}, [onFetchData, loading, fetchLoading]);
|
|
157
|
+
// --- columns enhancement
|
|
158
|
+
const enhancedColumns = (0, react_1.useMemo)(() => {
|
|
159
|
+
let cols = [...columns];
|
|
160
|
+
if (enableExpanding) {
|
|
161
|
+
cols = [
|
|
162
|
+
(0, special_columns_utils_1.createExpandingColumn)({
|
|
163
|
+
...((slotProps === null || slotProps === void 0 ? void 0 : slotProps.expandColumn) && typeof slotProps.expandColumn === "object"
|
|
164
|
+
? slotProps.expandColumn
|
|
165
|
+
: {}),
|
|
166
|
+
}),
|
|
167
|
+
...cols,
|
|
168
|
+
];
|
|
169
|
+
}
|
|
170
|
+
if (enableRowSelection) {
|
|
171
|
+
cols = [
|
|
172
|
+
(0, special_columns_utils_1.createSelectionColumn)({
|
|
173
|
+
...((slotProps === null || slotProps === void 0 ? void 0 : slotProps.selectionColumn) && typeof slotProps.selectionColumn === "object"
|
|
174
|
+
? slotProps.selectionColumn
|
|
175
|
+
: {}),
|
|
176
|
+
multiSelect: enableMultiRowSelection,
|
|
177
|
+
}),
|
|
178
|
+
...cols,
|
|
179
|
+
];
|
|
180
|
+
}
|
|
181
|
+
return (0, utils_1.withIdsDeep)(cols);
|
|
182
|
+
}, [
|
|
183
|
+
columns,
|
|
184
|
+
enableExpanding,
|
|
185
|
+
enableRowSelection,
|
|
186
|
+
enableMultiRowSelection,
|
|
187
|
+
slotProps === null || slotProps === void 0 ? void 0 : slotProps.expandColumn,
|
|
188
|
+
slotProps === null || slotProps === void 0 ? void 0 : slotProps.selectionColumn,
|
|
189
|
+
]);
|
|
190
|
+
// --- fetchData: useEvent so it's stable but reads latest state refs
|
|
191
|
+
const fetchData = useEvent(async (overrides = {}, options) => {
|
|
192
|
+
var _a, _b;
|
|
193
|
+
const s = uiRef.current;
|
|
194
|
+
const filters = {
|
|
195
|
+
globalFilter: s.globalFilter,
|
|
196
|
+
pagination: s.pagination,
|
|
197
|
+
columnFilter: s.columnFilter,
|
|
198
|
+
sorting: s.sorting,
|
|
199
|
+
...overrides,
|
|
200
|
+
};
|
|
201
|
+
(_a = onFetchStateChangeRef.current) === null || _a === void 0 ? void 0 : _a.call(onFetchStateChangeRef, filters, options === null || options === void 0 ? void 0 : options.meta);
|
|
202
|
+
const handler = onFetchDataRef.current;
|
|
203
|
+
if (!handler)
|
|
204
|
+
return;
|
|
205
|
+
const delay = (_b = options === null || options === void 0 ? void 0 : options.delay) !== null && _b !== void 0 ? _b : 0;
|
|
206
|
+
const result = await debouncedFetch(filters, { debounceDelay: delay, meta: options === null || options === void 0 ? void 0 : options.meta });
|
|
207
|
+
if (result && Array.isArray(result.data) && result.total !== undefined) {
|
|
208
|
+
setServerData(result.data);
|
|
209
|
+
setServerTotal(result.total);
|
|
210
|
+
}
|
|
211
|
+
return result;
|
|
212
|
+
});
|
|
213
|
+
// --- derived selection counts
|
|
214
|
+
const isSomeRowsSelected = (0, react_1.useMemo)(() => {
|
|
215
|
+
if (!enableBulkActions || !enableRowSelection)
|
|
216
|
+
return false;
|
|
217
|
+
if (ui.selectionState.type === "exclude")
|
|
218
|
+
return ui.selectionState.ids.length < tableTotalRow;
|
|
219
|
+
return ui.selectionState.ids.length > 0;
|
|
220
|
+
}, [enableBulkActions, enableRowSelection, ui.selectionState, tableTotalRow]);
|
|
221
|
+
const selectedRowCount = (0, react_1.useMemo)(() => {
|
|
222
|
+
if (!enableBulkActions || !enableRowSelection)
|
|
223
|
+
return 0;
|
|
224
|
+
if (ui.selectionState.type === "exclude")
|
|
225
|
+
return tableTotalRow - ui.selectionState.ids.length;
|
|
226
|
+
return ui.selectionState.ids.length;
|
|
227
|
+
}, [enableBulkActions, enableRowSelection, ui.selectionState, tableTotalRow]);
|
|
228
|
+
// --- TanStack Table
|
|
229
|
+
const table = (0, react_table_1.useReactTable)({
|
|
230
|
+
_features: [column_filter_feature_1.ColumnFilterFeature, features_1.SelectionFeature],
|
|
231
|
+
data: tableData,
|
|
232
|
+
columns: enhancedColumns,
|
|
233
|
+
initialState: initialStateConfig,
|
|
234
|
+
state: {
|
|
235
|
+
...(enableSorting ? { sorting: ui.sorting } : {}),
|
|
236
|
+
...(enablePagination ? { pagination: ui.pagination } : {}),
|
|
237
|
+
...(enableGlobalFilter ? { globalFilter: ui.globalFilter } : {}),
|
|
238
|
+
...(enableExpanding ? { expanded: ui.expanded } : {}),
|
|
239
|
+
...(enableColumnDragging ? { columnOrder: ui.columnOrder } : {}),
|
|
240
|
+
...(enableColumnPinning ? { columnPinning: ui.columnPinning } : {}),
|
|
241
|
+
...(enableColumnVisibility ? { columnVisibility: ui.columnVisibility } : {}),
|
|
242
|
+
...(enableColumnResizing ? { columnSizing: ui.columnSizing } : {}),
|
|
243
|
+
...(enableColumnFilter ? { columnFilter: ui.columnFilter } : {}),
|
|
244
|
+
...(enableRowSelection ? { selectionState: ui.selectionState } : {}),
|
|
245
|
+
},
|
|
246
|
+
selectMode,
|
|
247
|
+
enableAdvanceSelection: !!enableRowSelection,
|
|
248
|
+
isRowSelectable: isRowSelectable,
|
|
249
|
+
...(enableRowSelection
|
|
250
|
+
? {
|
|
251
|
+
onSelectionStateChange: (updaterOrValue) => {
|
|
252
|
+
dispatch({
|
|
253
|
+
type: "SET_SELECTION",
|
|
254
|
+
payload: typeof updaterOrValue === "function"
|
|
255
|
+
? updaterOrValue(uiRef.current.selectionState)
|
|
256
|
+
: updaterOrValue,
|
|
257
|
+
});
|
|
258
|
+
},
|
|
259
|
+
}
|
|
260
|
+
: {}),
|
|
261
|
+
enableAdvanceColumnFilter: enableColumnFilter,
|
|
262
|
+
onColumnFilterChange: (updater) => {
|
|
263
|
+
const next = typeof updater === "function" ? updater(uiRef.current.columnFilter) : updater;
|
|
264
|
+
dispatch({ type: "SET_COLUMN_FILTER", payload: next });
|
|
265
|
+
},
|
|
266
|
+
onColumnFilterApply: (state) => {
|
|
267
|
+
dispatch({ type: "SET_COLUMN_FILTER_RESET_PAGE", payload: state });
|
|
268
|
+
},
|
|
269
|
+
...(enableSorting
|
|
270
|
+
? {
|
|
271
|
+
onSortingChange: (updaterOrValue) => {
|
|
272
|
+
var _a;
|
|
273
|
+
const prev = uiRef.current.sorting;
|
|
274
|
+
const next = typeof updaterOrValue === "function" ? updaterOrValue(prev) : updaterOrValue;
|
|
275
|
+
const cleaned = (next || []).filter((s) => s === null || s === void 0 ? void 0 : s.id);
|
|
276
|
+
(_a = onSortingChangeRef.current) === null || _a === void 0 ? void 0 : _a.call(onSortingChangeRef, cleaned);
|
|
277
|
+
dispatch({ type: "SET_SORTING_RESET_PAGE", payload: cleaned });
|
|
278
|
+
},
|
|
279
|
+
}
|
|
280
|
+
: {}),
|
|
281
|
+
...(enablePagination
|
|
282
|
+
? {
|
|
283
|
+
onPaginationChange: (updater) => {
|
|
284
|
+
var _a;
|
|
285
|
+
const prev = uiRef.current.pagination;
|
|
286
|
+
const next = typeof updater === "function" ? updater(prev) : updater;
|
|
287
|
+
(_a = onPaginationChangeRef.current) === null || _a === void 0 ? void 0 : _a.call(onPaginationChangeRef, next);
|
|
288
|
+
dispatch({ type: "SET_PAGINATION", payload: next });
|
|
289
|
+
},
|
|
290
|
+
}
|
|
291
|
+
: {}),
|
|
292
|
+
...(enableGlobalFilter
|
|
293
|
+
? {
|
|
294
|
+
onGlobalFilterChange: (updaterOrValue) => {
|
|
295
|
+
var _a;
|
|
296
|
+
const prev = uiRef.current.globalFilter;
|
|
297
|
+
const next = typeof updaterOrValue === "function" ? updaterOrValue(prev) : updaterOrValue;
|
|
298
|
+
(_a = onGlobalFilterChangeRef.current) === null || _a === void 0 ? void 0 : _a.call(onGlobalFilterChangeRef, next);
|
|
299
|
+
nextFetchDelayRef.current = 400;
|
|
300
|
+
dispatch({ type: "SET_GLOBAL_FILTER_RESET_PAGE", payload: next });
|
|
301
|
+
},
|
|
302
|
+
}
|
|
303
|
+
: {}),
|
|
304
|
+
...(enableExpanding ? { onExpandedChange: (u) => dispatch({ type: "SET_EXPANDED", payload: typeof u === "function" ? u(uiRef.current.expanded) : u }) } : {}),
|
|
305
|
+
...(enableColumnDragging ? { onColumnOrderChange: (u) => dispatch({ type: "SET_COLUMN_ORDER", payload: typeof u === "function" ? u(uiRef.current.columnOrder) : u }) } : {}),
|
|
306
|
+
...(enableColumnPinning ? { onColumnPinningChange: (u) => dispatch({ type: "SET_COLUMN_PINNING", payload: typeof u === "function" ? u(uiRef.current.columnPinning) : u }) } : {}),
|
|
307
|
+
...(enableColumnVisibility ? { onColumnVisibilityChange: (u) => dispatch({ type: "SET_COLUMN_VISIBILITY", payload: typeof u === "function" ? u(uiRef.current.columnVisibility) : u }) } : {}),
|
|
308
|
+
...(enableColumnResizing ? { onColumnSizingChange: (u) => dispatch({ type: "SET_COLUMN_SIZING", payload: typeof u === "function" ? u(uiRef.current.columnSizing) : u }) } : {}),
|
|
309
|
+
getCoreRowModel: (0, react_table_1.getCoreRowModel)(),
|
|
310
|
+
...(enableSorting ? { getSortedRowModel: (0, react_table_1.getSortedRowModel)() } : {}),
|
|
311
|
+
...(enableColumnFilter || enableGlobalFilter ? { getFilteredRowModel: (0, column_filter_feature_1.getCombinedFilteredRowModel)() } : {}),
|
|
312
|
+
...(enablePagination && !isServerPagination ? { getPaginationRowModel: (0, react_table_1.getPaginationRowModel)() } : {}),
|
|
313
|
+
enableSorting,
|
|
314
|
+
manualSorting: isServerSorting,
|
|
315
|
+
manualFiltering: isServerFiltering,
|
|
316
|
+
enableColumnResizing,
|
|
317
|
+
columnResizeMode,
|
|
318
|
+
columnResizeDirection: theme.direction,
|
|
319
|
+
enableColumnPinning,
|
|
320
|
+
...(enableExpanding ? { getRowCanExpand: getRowCanExpand } : {}),
|
|
321
|
+
manualPagination: isServerPagination,
|
|
322
|
+
autoResetPageIndex: false,
|
|
323
|
+
rowCount: enablePagination ? (tableTotalRow !== null && tableTotalRow !== void 0 ? tableTotalRow : tableData.length) : tableData.length,
|
|
324
|
+
getRowId: (row, index) => (0, utils_1.generateRowId)(row, index, idKey),
|
|
325
|
+
});
|
|
326
|
+
// --- layout sizing
|
|
327
|
+
const allLeafColumns = table.getAllLeafColumns();
|
|
328
|
+
const hasExplicitSizing = allLeafColumns.some((col) => {
|
|
329
|
+
const { size, minSize, maxSize } = col.columnDef;
|
|
330
|
+
return size !== undefined || minSize !== undefined || maxSize !== undefined;
|
|
331
|
+
});
|
|
332
|
+
const useFixedLayout = fitToScreen || enableColumnResizing || hasExplicitSizing;
|
|
333
|
+
const tableTotalSize = table.getTotalSize();
|
|
334
|
+
const tableWidth = fitToScreen ? "100%" : useFixedLayout ? tableTotalSize : "100%";
|
|
335
|
+
const tableStyle = {
|
|
336
|
+
width: tableWidth,
|
|
337
|
+
minWidth: fitToScreen ? tableTotalSize : undefined,
|
|
338
|
+
tableLayout: useFixedLayout ? "fixed" : "auto",
|
|
339
|
+
};
|
|
340
|
+
// --- virtualization
|
|
341
|
+
const rows = table.getRowModel().rows;
|
|
342
|
+
const rowVirtualizer = (0, react_virtual_1.useVirtualizer)({
|
|
343
|
+
count: rows.length,
|
|
344
|
+
getScrollElement: () => tableContainerRef.current,
|
|
345
|
+
estimateSize: () => estimateRowHeight,
|
|
346
|
+
overscan: 10,
|
|
347
|
+
enabled: enableVirtualization && !enablePagination && rows.length > 0,
|
|
348
|
+
});
|
|
349
|
+
const serverKey = (0, react_1.useMemo)(() => {
|
|
350
|
+
if (!(isServerMode || isServerPagination || isServerFiltering || isServerSorting))
|
|
351
|
+
return null;
|
|
352
|
+
return JSON.stringify({
|
|
353
|
+
sorting: ui.sorting,
|
|
354
|
+
pagination: ui.pagination,
|
|
355
|
+
globalFilter: ui.globalFilter,
|
|
356
|
+
columnFilter: { filters: ui.columnFilter.filters, logic: ui.columnFilter.logic }, // only applied
|
|
357
|
+
});
|
|
358
|
+
}, [isServerMode, isServerPagination, isServerFiltering, isServerSorting, ui.sorting, ui.pagination, ui.globalFilter, ui.columnFilter]);
|
|
359
|
+
const serverKeyRef = useLatestRef(serverKey);
|
|
360
|
+
const lastServerKeyRef = (0, react_1.useRef)(null);
|
|
361
|
+
// --- initial fetch
|
|
362
|
+
(0, react_1.useEffect)(() => {
|
|
363
|
+
if (!initialLoadData)
|
|
364
|
+
return;
|
|
365
|
+
// If we're in server mode, mark current serverKey as already handled
|
|
366
|
+
// so the serverKey effect doesn't immediately fetch again.
|
|
367
|
+
if (serverKeyRef.current) {
|
|
368
|
+
lastServerKeyRef.current = serverKeyRef.current;
|
|
369
|
+
}
|
|
370
|
+
if (onFetchData || onFetchStateChange) {
|
|
371
|
+
void fetchData({}, { delay: 0, meta: { reason: "initial" } });
|
|
372
|
+
}
|
|
373
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
374
|
+
}, []);
|
|
375
|
+
(0, react_1.useEffect)(() => {
|
|
376
|
+
var _a;
|
|
377
|
+
if (!serverKey)
|
|
378
|
+
return;
|
|
379
|
+
if (serverKey === lastServerKeyRef.current)
|
|
380
|
+
return;
|
|
381
|
+
lastServerKeyRef.current = serverKey;
|
|
382
|
+
const delay = (_a = nextFetchDelayRef.current) !== null && _a !== void 0 ? _a : 0;
|
|
383
|
+
nextFetchDelayRef.current = 0; // reset after using
|
|
384
|
+
void fetchData({}, { delay, meta: { reason: "stateChange" } });
|
|
385
|
+
}, [serverKey, fetchData]);
|
|
386
|
+
// columnFilter apply handler stays explicit (button), but you can also auto-fetch on change if needed
|
|
387
|
+
const handleColumnFilterChangeHandler = (0, react_1.useCallback)((updater, isApply = false) => {
|
|
388
|
+
var _a;
|
|
389
|
+
const prev = uiRef.current.columnFilter;
|
|
390
|
+
const next = typeof updater === "function" ? updater(prev) : updater;
|
|
391
|
+
if (isApply) {
|
|
392
|
+
nextFetchDelayRef.current = 0;
|
|
393
|
+
dispatch({ type: "SET_COLUMN_FILTER_RESET_PAGE", payload: next });
|
|
394
|
+
}
|
|
395
|
+
else {
|
|
396
|
+
dispatch({ type: "SET_COLUMN_FILTER", payload: next });
|
|
397
|
+
}
|
|
398
|
+
(_a = onColumnFiltersChangeRef.current) === null || _a === void 0 ? void 0 : _a.call(onColumnFiltersChangeRef, next, isApply);
|
|
399
|
+
}, [onColumnFiltersChangeRef, uiRef]);
|
|
400
|
+
// --- emit table state (dedupe)
|
|
401
|
+
(0, react_1.useEffect)(() => {
|
|
402
|
+
const cb = onDataStateChangeRef.current;
|
|
403
|
+
if (!cb)
|
|
404
|
+
return;
|
|
405
|
+
const live = table.getState();
|
|
406
|
+
const payload = {
|
|
407
|
+
sorting: live.sorting,
|
|
408
|
+
pagination: live.pagination,
|
|
409
|
+
globalFilter: live.globalFilter,
|
|
410
|
+
columnFilter: live.columnFilter,
|
|
411
|
+
columnVisibility: live.columnVisibility,
|
|
412
|
+
columnSizing: live.columnSizing,
|
|
413
|
+
columnOrder: live.columnOrder,
|
|
414
|
+
columnPinning: live.columnPinning,
|
|
415
|
+
};
|
|
416
|
+
const key = JSON.stringify(payload);
|
|
417
|
+
if (key === lastSentRef.current)
|
|
418
|
+
return;
|
|
419
|
+
lastSentRef.current = key;
|
|
420
|
+
cb(payload);
|
|
421
|
+
}, [table, ui.sorting, ui.pagination, ui.globalFilter, ui.columnFilter, ui.columnVisibility, ui.columnSizing, ui.columnOrder, ui.columnPinning, onDataStateChangeRef]);
|
|
422
|
+
// --- helpers
|
|
423
|
+
const resetPageToFirst = (0, react_1.useCallback)(() => {
|
|
424
|
+
return { pageIndex: 0, pageSize: uiRef.current.pagination.pageSize };
|
|
425
|
+
}, [uiRef]);
|
|
426
|
+
const normalizeRefreshOptions = (0, react_1.useCallback)((options, fallbackReason = "refresh") => {
|
|
427
|
+
var _a, _b, _c;
|
|
428
|
+
if (typeof options === "boolean")
|
|
429
|
+
return { resetPagination: options, force: false, reason: fallbackReason };
|
|
430
|
+
return {
|
|
431
|
+
resetPagination: (_a = options === null || options === void 0 ? void 0 : options.resetPagination) !== null && _a !== void 0 ? _a : false,
|
|
432
|
+
force: (_b = options === null || options === void 0 ? void 0 : options.force) !== null && _b !== void 0 ? _b : false,
|
|
433
|
+
reason: (_c = options === null || options === void 0 ? void 0 : options.reason) !== null && _c !== void 0 ? _c : fallbackReason,
|
|
434
|
+
};
|
|
435
|
+
}, []);
|
|
436
|
+
const triggerRefresh = (0, react_1.useCallback)(async (options, fallbackReason = "refresh") => {
|
|
437
|
+
var _a;
|
|
438
|
+
const n = normalizeRefreshOptions(options, fallbackReason);
|
|
439
|
+
const current = uiRef.current.pagination;
|
|
440
|
+
const nextPagination = enablePagination
|
|
441
|
+
? { pageIndex: n.resetPagination ? 0 : current.pageIndex, pageSize: current.pageSize }
|
|
442
|
+
: undefined;
|
|
443
|
+
if (nextPagination) {
|
|
444
|
+
nextFetchDelayRef.current = 0;
|
|
445
|
+
dispatch({ type: "SET_PAGINATION", payload: nextPagination });
|
|
446
|
+
(_a = onPaginationChangeRef.current) === null || _a === void 0 ? void 0 : _a.call(onPaginationChangeRef, nextPagination);
|
|
447
|
+
}
|
|
448
|
+
const paginationChanged = !!nextPagination &&
|
|
449
|
+
(nextPagination.pageIndex !== current.pageIndex || nextPagination.pageSize !== current.pageSize);
|
|
450
|
+
if (!paginationChanged) {
|
|
451
|
+
await fetchData({}, { delay: 0, meta: { reason: n.reason, force: n.force } });
|
|
452
|
+
}
|
|
453
|
+
}, [enablePagination, fetchData, normalizeRefreshOptions, onPaginationChangeRef, uiRef]);
|
|
454
|
+
const getResetPayload = (0, react_1.useCallback)(() => {
|
|
455
|
+
var _a, _b, _c;
|
|
456
|
+
const resetSorting = initialStateConfig.sorting || [];
|
|
457
|
+
const resetGlobalFilter = (_a = initialStateConfig.globalFilter) !== null && _a !== void 0 ? _a : "";
|
|
458
|
+
const resetColumnFilter = ((_b = initialStateConfig.columnFilter) !== null && _b !== void 0 ? _b : DEFAULT_INITIAL_STATE.columnFilter);
|
|
459
|
+
const resetPagination = enablePagination
|
|
460
|
+
? (initialStateConfig.pagination || { pageIndex: 0, pageSize: 10 })
|
|
461
|
+
: uiRef.current.pagination;
|
|
462
|
+
return {
|
|
463
|
+
sorting: resetSorting,
|
|
464
|
+
globalFilter: resetGlobalFilter,
|
|
465
|
+
columnFilter: resetColumnFilter,
|
|
466
|
+
...(enablePagination ? { pagination: resetPagination } : {}),
|
|
467
|
+
selectionState: (_c = initialStateConfig.selectionState) !== null && _c !== void 0 ? _c : DEFAULT_INITIAL_STATE.selectionState,
|
|
468
|
+
expanded: {},
|
|
469
|
+
columnVisibility: initialStateConfig.columnVisibility || {},
|
|
470
|
+
columnSizing: initialStateConfig.columnSizing || {},
|
|
471
|
+
columnOrder: initialStateConfig.columnOrder || [],
|
|
472
|
+
columnPinning: initialStateConfig.columnPinning || { left: [], right: [] },
|
|
473
|
+
};
|
|
474
|
+
}, [enablePagination, initialStateConfig]);
|
|
475
|
+
const resetAllAndReload = (0, react_1.useCallback)(() => {
|
|
476
|
+
const payload = getResetPayload();
|
|
477
|
+
dispatch({ type: "RESET_ALL", payload });
|
|
478
|
+
void fetchData({
|
|
479
|
+
sorting: payload.sorting,
|
|
480
|
+
globalFilter: payload.globalFilter,
|
|
481
|
+
columnFilter: payload.columnFilter,
|
|
482
|
+
...(enablePagination ? { pagination: payload.pagination } : {}),
|
|
483
|
+
}, { delay: 0, meta: { reason: "reset", force: true } });
|
|
484
|
+
}, [enablePagination, fetchData, getResetPayload]);
|
|
485
|
+
// --- export (refs + small UI state)
|
|
486
|
+
const setExportControllerSafely = (0, react_1.useCallback)((value) => {
|
|
487
|
+
setExportController((current) => {
|
|
488
|
+
const next = typeof value === "function" ? value(current) : value;
|
|
489
|
+
exportControllerRef.current = next;
|
|
490
|
+
return next;
|
|
491
|
+
});
|
|
492
|
+
}, []);
|
|
493
|
+
const handleExportProgressInternal = (0, react_1.useCallback)((p) => {
|
|
494
|
+
var _a;
|
|
495
|
+
setExportProgress(p || {});
|
|
496
|
+
(_a = onExportProgressRef.current) === null || _a === void 0 ? void 0 : _a.call(onExportProgressRef, p);
|
|
497
|
+
}, []);
|
|
498
|
+
const handleExportStateChangeInternal = (0, react_1.useCallback)((s) => {
|
|
499
|
+
var _a;
|
|
500
|
+
setExportPhase(s.phase);
|
|
501
|
+
if (s.processedRows !== undefined || s.totalRows !== undefined || s.percentage !== undefined) {
|
|
502
|
+
setExportProgress({
|
|
503
|
+
processedRows: s.processedRows,
|
|
504
|
+
totalRows: s.totalRows,
|
|
505
|
+
percentage: s.percentage,
|
|
506
|
+
});
|
|
507
|
+
}
|
|
508
|
+
(_a = onExportStateChangeRef.current) === null || _a === void 0 ? void 0 : _a.call(onExportStateChangeRef, s);
|
|
509
|
+
}, []);
|
|
510
|
+
const runExportWithPolicy = (0, react_1.useCallback)(async (options) => {
|
|
511
|
+
var _a;
|
|
512
|
+
const { format, filename, mode, execute } = options;
|
|
513
|
+
const startExecution = async () => {
|
|
514
|
+
const controller = new AbortController();
|
|
515
|
+
setExportProgress({});
|
|
516
|
+
setExportControllerSafely(controller);
|
|
517
|
+
try {
|
|
518
|
+
await execute(controller);
|
|
519
|
+
}
|
|
520
|
+
finally {
|
|
521
|
+
setExportControllerSafely((cur) => (cur === controller ? null : cur));
|
|
522
|
+
}
|
|
523
|
+
};
|
|
524
|
+
if (exportConcurrency === "queue") {
|
|
525
|
+
setQueuedExportCount((p) => p + 1);
|
|
526
|
+
const runQueued = async () => {
|
|
527
|
+
setQueuedExportCount((p) => Math.max(0, p - 1));
|
|
528
|
+
await startExecution();
|
|
529
|
+
};
|
|
530
|
+
const queuedPromise = exportQueueRef.current.catch(() => undefined).then(runQueued);
|
|
531
|
+
exportQueueRef.current = queuedPromise;
|
|
532
|
+
return queuedPromise;
|
|
533
|
+
}
|
|
534
|
+
const active = exportControllerRef.current;
|
|
535
|
+
if (active) {
|
|
536
|
+
if (exportConcurrency === "ignoreIfRunning") {
|
|
537
|
+
handleExportStateChangeInternal({
|
|
538
|
+
phase: "error",
|
|
539
|
+
mode,
|
|
540
|
+
format,
|
|
541
|
+
filename,
|
|
542
|
+
message: "An export is already running",
|
|
543
|
+
code: "EXPORT_IN_PROGRESS",
|
|
544
|
+
endedAt: Date.now(),
|
|
545
|
+
});
|
|
546
|
+
(_a = onExportErrorRef.current) === null || _a === void 0 ? void 0 : _a.call(onExportErrorRef, { message: "An export is already running", code: "EXPORT_IN_PROGRESS" });
|
|
547
|
+
return;
|
|
548
|
+
}
|
|
549
|
+
if (exportConcurrency === "cancelAndRestart")
|
|
550
|
+
active.abort();
|
|
551
|
+
}
|
|
552
|
+
await startExecution();
|
|
553
|
+
}, [exportConcurrency, handleExportStateChangeInternal, onExportErrorRef, setExportControllerSafely]);
|
|
554
|
+
const handleCancelExport = (0, react_1.useCallback)(() => {
|
|
555
|
+
var _a;
|
|
556
|
+
const active = exportControllerRef.current;
|
|
557
|
+
if (!active)
|
|
558
|
+
return;
|
|
559
|
+
active.abort();
|
|
560
|
+
setExportControllerSafely((cur) => (cur === active ? null : cur));
|
|
561
|
+
(_a = onExportCancelRef.current) === null || _a === void 0 ? void 0 : _a.call(onExportCancelRef);
|
|
562
|
+
}, [onExportCancelRef, setExportControllerSafely]);
|
|
563
|
+
const isExporting = exportController !== null;
|
|
564
|
+
// --- stable API (created once)
|
|
565
|
+
if (!apiRef.current) {
|
|
566
|
+
apiRef.current = {};
|
|
567
|
+
// IMPORTANT: do NOT capture `table/ui/data` here. Always read from refs inside methods.
|
|
568
|
+
apiRef.current.table = { getTable: () => table }; // will be updated below via tableRef
|
|
569
|
+
// We'll overwrite getTable below with a ref-backed function.
|
|
570
|
+
}
|
|
571
|
+
// table ref so API always returns latest table instance
|
|
572
|
+
const tableRef = useLatestRef(table);
|
|
573
|
+
(0, react_1.useEffect)(() => {
|
|
574
|
+
const api = apiRef.current;
|
|
575
|
+
api.table = { getTable: () => tableRef.current };
|
|
576
|
+
// --- state getters
|
|
577
|
+
api.state = {
|
|
578
|
+
getTableState: () => tableRef.current.getState(),
|
|
579
|
+
getCurrentFilters: () => tableRef.current.getState().columnFilter,
|
|
580
|
+
getCurrentSorting: () => tableRef.current.getState().sorting,
|
|
581
|
+
getCurrentPagination: () => tableRef.current.getState().pagination,
|
|
582
|
+
getCurrentSelection: () => uiRef.current.selectionState,
|
|
583
|
+
getGlobalFilter: () => tableRef.current.getState().globalFilter,
|
|
584
|
+
};
|
|
585
|
+
// --- data
|
|
586
|
+
api.data = {
|
|
587
|
+
refresh: (options) => void triggerRefresh(options, "refresh"),
|
|
588
|
+
reload: (options = {}) => { var _a; return void triggerRefresh({ ...options, reason: (_a = options.reason) !== null && _a !== void 0 ? _a : "reload" }, "reload"); },
|
|
589
|
+
resetAll: () => resetAllAndReload(),
|
|
590
|
+
getAllData: () => {
|
|
591
|
+
const sData = serverDataRef.current;
|
|
592
|
+
const base = sData !== null ? sData : dataRef.current;
|
|
593
|
+
return [...base];
|
|
594
|
+
},
|
|
595
|
+
getDataCount: () => {
|
|
596
|
+
const sData = serverDataRef.current;
|
|
597
|
+
const base = sData !== null ? sData : dataRef.current;
|
|
598
|
+
return base.length;
|
|
599
|
+
},
|
|
600
|
+
getFilteredDataCount: () => tableRef.current.getFilteredRowModel().rows.length,
|
|
601
|
+
};
|
|
602
|
+
// --- sorting/pagination/filtering - dispatch + callbacks + server fetch policies
|
|
603
|
+
api.sorting = {
|
|
604
|
+
setSorting: (next) => {
|
|
605
|
+
var _a;
|
|
606
|
+
const cleaned = (next || []).filter((s) => s === null || s === void 0 ? void 0 : s.id);
|
|
607
|
+
(_a = onSortingChangeRef.current) === null || _a === void 0 ? void 0 : _a.call(onSortingChangeRef, cleaned);
|
|
608
|
+
nextFetchDelayRef.current = 0;
|
|
609
|
+
dispatch({ type: "SET_SORTING_RESET_PAGE", payload: cleaned });
|
|
610
|
+
},
|
|
611
|
+
clearSorting: () => {
|
|
612
|
+
var _a;
|
|
613
|
+
(_a = onSortingChangeRef.current) === null || _a === void 0 ? void 0 : _a.call(onSortingChangeRef, []);
|
|
614
|
+
nextFetchDelayRef.current = 0;
|
|
615
|
+
dispatch({ type: "SET_SORTING_RESET_PAGE", payload: [] });
|
|
616
|
+
},
|
|
617
|
+
resetSorting: () => {
|
|
618
|
+
var _a;
|
|
619
|
+
const next = (initialStateConfig.sorting || []);
|
|
620
|
+
(_a = onSortingChangeRef.current) === null || _a === void 0 ? void 0 : _a.call(onSortingChangeRef, next);
|
|
621
|
+
nextFetchDelayRef.current = 0;
|
|
622
|
+
dispatch({ type: "SET_SORTING_RESET_PAGE", payload: next });
|
|
623
|
+
},
|
|
624
|
+
};
|
|
625
|
+
api.pagination = {
|
|
626
|
+
goToPage: (pageIndex) => {
|
|
627
|
+
var _a;
|
|
628
|
+
const prev = uiRef.current.pagination;
|
|
629
|
+
const next = { ...prev, pageIndex };
|
|
630
|
+
(_a = onPaginationChangeRef.current) === null || _a === void 0 ? void 0 : _a.call(onPaginationChangeRef, next);
|
|
631
|
+
nextFetchDelayRef.current = 0;
|
|
632
|
+
dispatch({ type: "SET_PAGINATION", payload: next });
|
|
633
|
+
},
|
|
634
|
+
setPageSize: (pageSize) => {
|
|
635
|
+
var _a;
|
|
636
|
+
const next = { pageIndex: 0, pageSize };
|
|
637
|
+
(_a = onPaginationChangeRef.current) === null || _a === void 0 ? void 0 : _a.call(onPaginationChangeRef, next);
|
|
638
|
+
nextFetchDelayRef.current = 0;
|
|
639
|
+
dispatch({ type: "SET_PAGINATION", payload: next });
|
|
640
|
+
},
|
|
641
|
+
resetPagination: () => {
|
|
642
|
+
var _a;
|
|
643
|
+
const next = (initialStateConfig.pagination || { pageIndex: 0, pageSize: 10 });
|
|
644
|
+
(_a = onPaginationChangeRef.current) === null || _a === void 0 ? void 0 : _a.call(onPaginationChangeRef, next);
|
|
645
|
+
nextFetchDelayRef.current = 0;
|
|
646
|
+
dispatch({ type: "SET_PAGINATION", payload: next });
|
|
647
|
+
},
|
|
648
|
+
};
|
|
649
|
+
api.filtering = {
|
|
650
|
+
setGlobalFilter: (filter) => {
|
|
651
|
+
var _a;
|
|
652
|
+
(_a = onGlobalFilterChangeRef.current) === null || _a === void 0 ? void 0 : _a.call(onGlobalFilterChangeRef, filter);
|
|
653
|
+
nextFetchDelayRef.current = 400;
|
|
654
|
+
dispatch({ type: "SET_GLOBAL_FILTER_RESET_PAGE", payload: filter });
|
|
655
|
+
},
|
|
656
|
+
clearGlobalFilter: () => {
|
|
657
|
+
var _a;
|
|
658
|
+
(_a = onGlobalFilterChangeRef.current) === null || _a === void 0 ? void 0 : _a.call(onGlobalFilterChangeRef, "");
|
|
659
|
+
nextFetchDelayRef.current = 400;
|
|
660
|
+
dispatch({ type: "SET_GLOBAL_FILTER_RESET_PAGE", payload: "" });
|
|
661
|
+
},
|
|
662
|
+
setColumnFilters: (filters, isApply = false) => handleColumnFilterChangeHandler(filters, isApply),
|
|
663
|
+
};
|
|
664
|
+
api.columnVisibility = {
|
|
665
|
+
showColumn: (id) => dispatch({ type: "SET_COLUMN_VISIBILITY", payload: { ...uiRef.current.columnVisibility, [id]: true } }),
|
|
666
|
+
hideColumn: (id) => dispatch({ type: "SET_COLUMN_VISIBILITY", payload: { ...uiRef.current.columnVisibility, [id]: false } }),
|
|
667
|
+
resetColumnVisibility: () => dispatch({ type: "SET_COLUMN_VISIBILITY", payload: initialStateConfig.columnVisibility || {} }),
|
|
668
|
+
};
|
|
669
|
+
api.columnOrdering = {
|
|
670
|
+
setColumnOrder: (next) => {
|
|
671
|
+
var _a;
|
|
672
|
+
dispatch({ type: "SET_COLUMN_ORDER", payload: next });
|
|
673
|
+
(_a = onColumnDragEndRef.current) === null || _a === void 0 ? void 0 : _a.call(onColumnDragEndRef, next);
|
|
674
|
+
},
|
|
675
|
+
resetColumnOrder: () => dispatch({ type: "SET_COLUMN_ORDER", payload: initialStateConfig.columnOrder || [] }),
|
|
676
|
+
};
|
|
677
|
+
api.columnPinning = {
|
|
678
|
+
setPinning: (next) => {
|
|
679
|
+
var _a;
|
|
680
|
+
dispatch({ type: "SET_COLUMN_PINNING", payload: next });
|
|
681
|
+
(_a = onColumnPinningChangeRef.current) === null || _a === void 0 ? void 0 : _a.call(onColumnPinningChangeRef, next);
|
|
682
|
+
},
|
|
683
|
+
resetColumnPinning: () => dispatch({ type: "SET_COLUMN_PINNING", payload: initialStateConfig.columnPinning || { left: [], right: [] } }),
|
|
684
|
+
};
|
|
685
|
+
api.columnResizing = {
|
|
686
|
+
resetColumnSizing: () => dispatch({ type: "SET_COLUMN_SIZING", payload: initialStateConfig.columnSizing || {} }),
|
|
687
|
+
};
|
|
688
|
+
api.selection = {
|
|
689
|
+
getSelectionState: () => { var _a, _b; return ((_b = (_a = tableRef.current).getSelectionState) === null || _b === void 0 ? void 0 : _b.call(_a)) || { ids: [], type: "include" }; },
|
|
690
|
+
getSelectedRows: () => tableRef.current.getSelectedRows(),
|
|
691
|
+
getSelectedCount: () => tableRef.current.getSelectedCount(),
|
|
692
|
+
isRowSelected: (rowId) => tableRef.current.getIsRowSelected(rowId) || false,
|
|
693
|
+
// keep using your table extension methods if you have them:
|
|
694
|
+
selectAll: () => { var _a, _b; return (_b = (_a = tableRef.current).selectAll) === null || _b === void 0 ? void 0 : _b.call(_a); },
|
|
695
|
+
deselectAll: () => { var _a, _b; return (_b = (_a = tableRef.current).deselectAll) === null || _b === void 0 ? void 0 : _b.call(_a); },
|
|
696
|
+
};
|
|
697
|
+
// --- export API (use your existing exportClientData/exportServerData)
|
|
698
|
+
api.export = {
|
|
699
|
+
exportCSV: async (options = {}) => {
|
|
700
|
+
var _a, _b, _c, _d;
|
|
701
|
+
const fn = (_a = options.filename) !== null && _a !== void 0 ? _a : exportFilename;
|
|
702
|
+
const chunkSize = (_b = options.chunkSize) !== null && _b !== void 0 ? _b : exportChunkSize;
|
|
703
|
+
const strictTotalCheck = (_c = options.strictTotalCheck) !== null && _c !== void 0 ? _c : exportStrictTotalCheck;
|
|
704
|
+
const sanitizeCSV = (_d = options.sanitizeCSV) !== null && _d !== void 0 ? _d : exportSanitizeCSV;
|
|
705
|
+
const mode = dataMode === "server" && !!onServerExportRef.current ? "server" : "client";
|
|
706
|
+
await runExportWithPolicy({
|
|
707
|
+
format: "csv",
|
|
708
|
+
filename: fn,
|
|
709
|
+
mode,
|
|
710
|
+
execute: async (controller) => {
|
|
711
|
+
var _a, _b;
|
|
712
|
+
// TODO: keep your state-change event mapping (starting/progress/completed/cancel/error)
|
|
713
|
+
if (mode === "server" && onServerExportRef.current) {
|
|
714
|
+
await (0, utils_1.exportServerData)(tableRef.current, {
|
|
715
|
+
format: "csv",
|
|
716
|
+
filename: fn,
|
|
717
|
+
fetchData: (filters, selection, signal) => { var _a; return (_a = onServerExportRef.current) === null || _a === void 0 ? void 0 : _a.call(onServerExportRef, filters, selection, signal); },
|
|
718
|
+
currentFilters: {
|
|
719
|
+
globalFilter: tableRef.current.getState().globalFilter,
|
|
720
|
+
columnFilter: tableRef.current.getState().columnFilter,
|
|
721
|
+
sorting: tableRef.current.getState().sorting,
|
|
722
|
+
pagination: tableRef.current.getState().pagination,
|
|
723
|
+
},
|
|
724
|
+
selection: (_b = (_a = tableRef.current).getSelectionState) === null || _b === void 0 ? void 0 : _b.call(_a),
|
|
725
|
+
onProgress: handleExportProgressInternal,
|
|
726
|
+
onComplete: onExportCompleteRef.current,
|
|
727
|
+
onError: onExportErrorRef.current,
|
|
728
|
+
onStateChange: (s) => handleExportStateChangeInternal({ ...s, mode, format: "csv", filename: fn, queueLength: queuedExportCount }),
|
|
729
|
+
signal: controller.signal,
|
|
730
|
+
chunkSize,
|
|
731
|
+
strictTotalCheck,
|
|
732
|
+
sanitizeCSV,
|
|
733
|
+
});
|
|
734
|
+
return;
|
|
735
|
+
}
|
|
736
|
+
await (0, utils_1.exportClientData)(tableRef.current, {
|
|
737
|
+
format: "csv",
|
|
738
|
+
filename: fn,
|
|
739
|
+
onProgress: handleExportProgressInternal,
|
|
740
|
+
onComplete: onExportCompleteRef.current,
|
|
741
|
+
onError: onExportErrorRef.current,
|
|
742
|
+
onStateChange: (s) => handleExportStateChangeInternal({ ...s, mode, format: "csv", filename: fn, queueLength: queuedExportCount }),
|
|
743
|
+
signal: controller.signal,
|
|
744
|
+
sanitizeCSV,
|
|
745
|
+
});
|
|
746
|
+
},
|
|
747
|
+
});
|
|
748
|
+
},
|
|
749
|
+
exportExcel: async (options = {}) => {
|
|
750
|
+
var _a, _b, _c, _d;
|
|
751
|
+
const fn = (_a = options.filename) !== null && _a !== void 0 ? _a : exportFilename;
|
|
752
|
+
const chunkSize = (_b = options.chunkSize) !== null && _b !== void 0 ? _b : exportChunkSize;
|
|
753
|
+
const strictTotalCheck = (_c = options.strictTotalCheck) !== null && _c !== void 0 ? _c : exportStrictTotalCheck;
|
|
754
|
+
const sanitizeCSV = (_d = options.sanitizeCSV) !== null && _d !== void 0 ? _d : exportSanitizeCSV;
|
|
755
|
+
const mode = dataMode === "server" && !!onServerExportRef.current ? "server" : "client";
|
|
756
|
+
await runExportWithPolicy({
|
|
757
|
+
format: "excel",
|
|
758
|
+
filename: fn,
|
|
759
|
+
mode,
|
|
760
|
+
execute: async (controller) => {
|
|
761
|
+
var _a, _b;
|
|
762
|
+
// TODO: keep your state-change event mapping (starting/progress/completed/cancel/error)
|
|
763
|
+
if (mode === "server" && onServerExportRef.current) {
|
|
764
|
+
await (0, utils_1.exportServerData)(tableRef.current, {
|
|
765
|
+
format: "excel",
|
|
766
|
+
filename: fn,
|
|
767
|
+
fetchData: (filters, selection, signal) => { var _a; return (_a = onServerExportRef.current) === null || _a === void 0 ? void 0 : _a.call(onServerExportRef, filters, selection, signal); },
|
|
768
|
+
currentFilters: {
|
|
769
|
+
globalFilter: tableRef.current.getState().globalFilter,
|
|
770
|
+
columnFilter: tableRef.current.getState().columnFilter,
|
|
771
|
+
sorting: tableRef.current.getState().sorting,
|
|
772
|
+
pagination: tableRef.current.getState().pagination,
|
|
773
|
+
},
|
|
774
|
+
selection: (_b = (_a = tableRef.current).getSelectionState) === null || _b === void 0 ? void 0 : _b.call(_a),
|
|
775
|
+
onProgress: handleExportProgressInternal,
|
|
776
|
+
onComplete: onExportCompleteRef.current,
|
|
777
|
+
onError: onExportErrorRef.current,
|
|
778
|
+
onStateChange: (s) => handleExportStateChangeInternal({ ...s, mode, format: "csv", filename: fn, queueLength: queuedExportCount }),
|
|
779
|
+
signal: controller.signal,
|
|
780
|
+
chunkSize,
|
|
781
|
+
strictTotalCheck,
|
|
782
|
+
sanitizeCSV,
|
|
783
|
+
});
|
|
784
|
+
return;
|
|
785
|
+
}
|
|
786
|
+
await (0, utils_1.exportClientData)(tableRef.current, {
|
|
787
|
+
format: "excel",
|
|
788
|
+
filename: fn,
|
|
789
|
+
onProgress: handleExportProgressInternal,
|
|
790
|
+
onComplete: onExportCompleteRef.current,
|
|
791
|
+
onError: onExportErrorRef.current,
|
|
792
|
+
onStateChange: (s) => handleExportStateChangeInternal({ ...s, mode, format: "csv", filename: fn, queueLength: queuedExportCount }),
|
|
793
|
+
signal: controller.signal,
|
|
794
|
+
sanitizeCSV,
|
|
795
|
+
});
|
|
796
|
+
},
|
|
797
|
+
});
|
|
798
|
+
},
|
|
799
|
+
isExporting: () => exportControllerRef.current != null,
|
|
800
|
+
cancelExport: () => handleCancelExport(),
|
|
801
|
+
};
|
|
802
|
+
}, [dataMode, exportChunkSize, exportFilename, exportSanitizeCSV, exportStrictTotalCheck, fetchData, handleCancelExport, handleColumnFilterChangeHandler, handleExportProgressInternal, handleExportStateChangeInternal, initialStateConfig, isServerMode, isServerPagination, isServerSorting, resetAllAndReload, resetPageToFirst, runExportWithPolicy, triggerRefresh, queuedExportCount, tableRef, uiRef, serverDataRef, dataRef, onSortingChangeRef, onPaginationChangeRef, onGlobalFilterChangeRef, onColumnDragEndRef, onColumnPinningChangeRef, onServerExportRef, onExportCompleteRef, onExportErrorRef]);
|
|
803
|
+
// --- imperative handlers (used by TanStack callbacks above or view)
|
|
804
|
+
const handleSortingChange = (0, react_1.useCallback)((updaterOrValue) => {
|
|
805
|
+
var _a;
|
|
806
|
+
const prev = uiRef.current.sorting;
|
|
807
|
+
const next = typeof updaterOrValue === "function" ? updaterOrValue(prev) : updaterOrValue;
|
|
808
|
+
const cleaned = (next || []).filter((s) => s === null || s === void 0 ? void 0 : s.id);
|
|
809
|
+
(_a = onSortingChangeRef.current) === null || _a === void 0 ? void 0 : _a.call(onSortingChangeRef, cleaned);
|
|
810
|
+
nextFetchDelayRef.current = 0;
|
|
811
|
+
dispatch({ type: "SET_SORTING_RESET_PAGE", payload: cleaned });
|
|
812
|
+
}, [onSortingChangeRef, uiRef]);
|
|
813
|
+
const handlePaginationChange = (0, react_1.useCallback)((updater) => {
|
|
814
|
+
var _a;
|
|
815
|
+
const prev = uiRef.current.pagination;
|
|
816
|
+
const next = typeof updater === "function" ? updater(prev) : updater;
|
|
817
|
+
(_a = onPaginationChangeRef.current) === null || _a === void 0 ? void 0 : _a.call(onPaginationChangeRef, next);
|
|
818
|
+
nextFetchDelayRef.current = 0;
|
|
819
|
+
dispatch({ type: "SET_PAGINATION", payload: next });
|
|
820
|
+
}, [onPaginationChangeRef, uiRef]);
|
|
821
|
+
const handleGlobalFilterChange = (0, react_1.useCallback)((updaterOrValue) => {
|
|
822
|
+
var _a;
|
|
823
|
+
const prev = uiRef.current.globalFilter;
|
|
824
|
+
const next = typeof updaterOrValue === "function" ? updaterOrValue(prev) : updaterOrValue;
|
|
825
|
+
(_a = onGlobalFilterChangeRef.current) === null || _a === void 0 ? void 0 : _a.call(onGlobalFilterChangeRef, next);
|
|
826
|
+
nextFetchDelayRef.current = 400;
|
|
827
|
+
dispatch({ type: "SET_GLOBAL_FILTER_RESET_PAGE", payload: next });
|
|
828
|
+
}, [onGlobalFilterChangeRef, uiRef]);
|
|
829
|
+
const handleColumnOrderChange = (0, react_1.useCallback)((updated) => {
|
|
830
|
+
var _a;
|
|
831
|
+
const prev = uiRef.current.columnOrder;
|
|
832
|
+
const next = typeof updated === "function" ? updated(prev) : updated;
|
|
833
|
+
dispatch({ type: "SET_COLUMN_ORDER", payload: next });
|
|
834
|
+
(_a = onColumnDragEndRef.current) === null || _a === void 0 ? void 0 : _a.call(onColumnDragEndRef, next);
|
|
835
|
+
}, [onColumnDragEndRef, uiRef]);
|
|
836
|
+
const handleColumnPinningChange = (0, react_1.useCallback)((updated) => {
|
|
837
|
+
var _a;
|
|
838
|
+
const prev = uiRef.current.columnPinning;
|
|
839
|
+
const next = typeof updated === "function" ? updated(prev) : updated;
|
|
840
|
+
dispatch({ type: "SET_COLUMN_PINNING", payload: next });
|
|
841
|
+
(_a = onColumnPinningChangeRef.current) === null || _a === void 0 ? void 0 : _a.call(onColumnPinningChangeRef, next);
|
|
842
|
+
}, [onColumnPinningChangeRef, uiRef]);
|
|
843
|
+
const handleColumnVisibilityChange = (0, react_1.useCallback)((updated) => {
|
|
844
|
+
var _a;
|
|
845
|
+
const prev = uiRef.current.columnVisibility;
|
|
846
|
+
const next = typeof updated === "function" ? updated(prev) : updated;
|
|
847
|
+
dispatch({ type: "SET_COLUMN_VISIBILITY", payload: next });
|
|
848
|
+
(_a = onColumnVisibilityChangeRef.current) === null || _a === void 0 ? void 0 : _a.call(onColumnVisibilityChangeRef, next);
|
|
849
|
+
}, [onColumnVisibilityChangeRef, uiRef]);
|
|
850
|
+
const handleColumnSizingChange = (0, react_1.useCallback)((updated) => {
|
|
851
|
+
var _a;
|
|
852
|
+
const prev = uiRef.current.columnSizing;
|
|
853
|
+
const next = typeof updated === "function" ? updated(prev) : updated;
|
|
854
|
+
dispatch({ type: "SET_COLUMN_SIZING", payload: next });
|
|
855
|
+
(_a = onColumnSizingChangeRef.current) === null || _a === void 0 ? void 0 : _a.call(onColumnSizingChangeRef, next);
|
|
856
|
+
}, [onColumnSizingChangeRef, uiRef]);
|
|
857
|
+
const handleColumnReorder = (0, react_1.useCallback)((draggedId, targetId) => {
|
|
858
|
+
const currentOrder = uiRef.current.columnOrder.length > 0
|
|
859
|
+
? uiRef.current.columnOrder
|
|
860
|
+
: enhancedColumns.map((c, idx) => { var _a, _b; return (_b = (_a = c.id) !== null && _a !== void 0 ? _a : c.accessorKey) !== null && _b !== void 0 ? _b : `column_${idx}`; });
|
|
861
|
+
const from = currentOrder.indexOf(draggedId);
|
|
862
|
+
const to = currentOrder.indexOf(targetId);
|
|
863
|
+
if (from === -1 || to === -1)
|
|
864
|
+
return;
|
|
865
|
+
const next = [...currentOrder];
|
|
866
|
+
next.splice(from, 1);
|
|
867
|
+
next.splice(to, 0, draggedId);
|
|
868
|
+
handleColumnOrderChange(next);
|
|
869
|
+
}, [enhancedColumns, handleColumnOrderChange, uiRef]);
|
|
870
|
+
// optional: selection callback
|
|
871
|
+
(0, react_1.useEffect)(() => {
|
|
872
|
+
var _a;
|
|
873
|
+
(_a = onSelectionChangeRef.current) === null || _a === void 0 ? void 0 : _a.call(onSelectionChangeRef, ui.selectionState);
|
|
874
|
+
}, [onSelectionChangeRef, ui.selectionState]);
|
|
875
|
+
// --- provider props
|
|
876
|
+
const providerProps = (0, react_1.useMemo)(() => ({
|
|
877
|
+
table,
|
|
878
|
+
apiRef,
|
|
879
|
+
dataMode,
|
|
880
|
+
tableSize: ui.tableSize,
|
|
881
|
+
onTableSizeChange: (size) => dispatch({ type: "SET_TABLE_SIZE", payload: size }),
|
|
882
|
+
columnFilter: ui.columnFilter,
|
|
883
|
+
onChangeColumnFilter: (f) => handleColumnFilterChangeHandler(f, false),
|
|
884
|
+
slots,
|
|
885
|
+
slotProps,
|
|
886
|
+
isExporting,
|
|
887
|
+
exportController,
|
|
888
|
+
exportPhase,
|
|
889
|
+
exportProgress,
|
|
890
|
+
onCancelExport: handleCancelExport,
|
|
891
|
+
exportFilename,
|
|
892
|
+
onExportProgress,
|
|
893
|
+
onExportComplete,
|
|
894
|
+
onExportError,
|
|
895
|
+
onServerExport,
|
|
896
|
+
}), [
|
|
897
|
+
table,
|
|
898
|
+
dataMode,
|
|
899
|
+
ui.tableSize,
|
|
900
|
+
ui.columnFilter,
|
|
901
|
+
slots,
|
|
902
|
+
slotProps,
|
|
903
|
+
isExporting,
|
|
904
|
+
exportController,
|
|
905
|
+
exportPhase,
|
|
906
|
+
exportProgress,
|
|
907
|
+
handleCancelExport,
|
|
908
|
+
exportFilename,
|
|
909
|
+
onExportProgress,
|
|
910
|
+
onExportComplete,
|
|
911
|
+
onExportError,
|
|
912
|
+
onServerExport,
|
|
913
|
+
handleColumnFilterChangeHandler,
|
|
914
|
+
]);
|
|
915
|
+
return {
|
|
916
|
+
table,
|
|
917
|
+
refs: {
|
|
918
|
+
tableContainerRef,
|
|
919
|
+
apiRef,
|
|
920
|
+
exportControllerRef,
|
|
921
|
+
},
|
|
922
|
+
derived: {
|
|
923
|
+
isServerMode,
|
|
924
|
+
isServerPagination,
|
|
925
|
+
isServerFiltering,
|
|
926
|
+
isServerSorting,
|
|
927
|
+
tableData,
|
|
928
|
+
tableTotalRow,
|
|
929
|
+
tableLoading,
|
|
930
|
+
rows,
|
|
931
|
+
visibleLeafColumns: table.getVisibleLeafColumns,
|
|
932
|
+
useFixedLayout,
|
|
933
|
+
tableStyle,
|
|
934
|
+
isExporting,
|
|
935
|
+
exportPhase,
|
|
936
|
+
exportProgress,
|
|
937
|
+
isSomeRowsSelected,
|
|
938
|
+
selectedRowCount,
|
|
939
|
+
},
|
|
940
|
+
state: ui,
|
|
941
|
+
actions: {
|
|
942
|
+
fetchData,
|
|
943
|
+
handleSortingChange,
|
|
944
|
+
handlePaginationChange,
|
|
945
|
+
handleGlobalFilterChange,
|
|
946
|
+
handleColumnFilterChangeHandler,
|
|
947
|
+
handleColumnOrderChange,
|
|
948
|
+
handleColumnPinningChange,
|
|
949
|
+
handleColumnVisibilityChange,
|
|
950
|
+
handleColumnSizingChange,
|
|
951
|
+
handleColumnReorder,
|
|
952
|
+
resetAllAndReload,
|
|
953
|
+
triggerRefresh,
|
|
954
|
+
setTableSize: (size) => dispatch({ type: "SET_TABLE_SIZE", payload: size }),
|
|
955
|
+
handleCancelExport,
|
|
956
|
+
renderRowModel: { rowVirtualizer },
|
|
957
|
+
},
|
|
958
|
+
api: apiRef.current,
|
|
959
|
+
providerProps,
|
|
960
|
+
};
|
|
961
|
+
}
|