@ackplus/react-tanstack-data-table 1.1.16 → 1.1.18

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.
Files changed (42) hide show
  1. package/README.md +0 -8
  2. package/dist/index.d.ts +4 -0
  3. package/dist/index.d.ts.map +1 -1
  4. package/dist/index.js +5 -1
  5. package/dist/lib/components/data-table-view.d.ts +7 -0
  6. package/dist/lib/components/data-table-view.d.ts.map +1 -0
  7. package/dist/lib/components/data-table-view.js +151 -0
  8. package/dist/lib/components/toolbar/column-filter-control.d.ts +3 -2
  9. package/dist/lib/components/toolbar/column-filter-control.d.ts.map +1 -1
  10. package/dist/lib/components/toolbar/column-filter-control.js +91 -92
  11. package/dist/lib/components/toolbar/data-table-toolbar.d.ts.map +1 -1
  12. package/dist/lib/components/toolbar/data-table-toolbar.js +14 -1
  13. package/dist/lib/components/toolbar/table-export-control.d.ts.map +1 -1
  14. package/dist/lib/components/toolbar/table-export-control.js +0 -2
  15. package/dist/lib/components/toolbar/table-refresh-control.d.ts.map +1 -1
  16. package/dist/lib/components/toolbar/table-refresh-control.js +3 -1
  17. package/dist/lib/data-table.d.ts +0 -3
  18. package/dist/lib/data-table.d.ts.map +1 -1
  19. package/dist/lib/data-table.js +9 -1638
  20. package/dist/lib/features/column-filter.feature.d.ts +2 -1
  21. package/dist/lib/features/column-filter.feature.d.ts.map +1 -1
  22. package/dist/lib/features/column-filter.feature.js +14 -0
  23. package/dist/lib/hooks/index.d.ts +3 -0
  24. package/dist/lib/hooks/index.d.ts.map +1 -0
  25. package/dist/lib/hooks/index.js +5 -0
  26. package/dist/lib/hooks/use-data-table-engine.d.ts +104 -0
  27. package/dist/lib/hooks/use-data-table-engine.d.ts.map +1 -0
  28. package/dist/lib/hooks/use-data-table-engine.js +964 -0
  29. package/dist/lib/types/data-table.types.d.ts +0 -1
  30. package/dist/lib/types/data-table.types.d.ts.map +1 -1
  31. package/package.json +1 -1
  32. package/src/index.ts +4 -0
  33. package/src/lib/components/data-table-view.tsx +386 -0
  34. package/src/lib/components/toolbar/column-filter-control.tsx +270 -212
  35. package/src/lib/components/toolbar/data-table-toolbar.tsx +15 -1
  36. package/src/lib/components/toolbar/table-export-control.tsx +0 -2
  37. package/src/lib/components/toolbar/table-refresh-control.tsx +11 -7
  38. package/src/lib/data-table.tsx +17 -2183
  39. package/src/lib/features/column-filter.feature.ts +15 -1
  40. package/src/lib/hooks/index.ts +2 -0
  41. package/src/lib/hooks/use-data-table-engine.ts +1285 -0
  42. package/src/lib/types/data-table.types.ts +0 -1
@@ -36,1646 +36,17 @@ Object.defineProperty(exports, "__esModule", { value: true });
36
36
  exports.DataTable = void 0;
37
37
  const jsx_runtime_1 = require("react/jsx-runtime");
38
38
  /**
39
- * Main DataTable Component
39
+ * Main DataTable Component (thin wrapper)
40
40
  *
41
- * A comprehensive, highly customizable data table component built with:
42
- * - Material-UI (MUI) for styling
43
- * - TanStack Table for table logic
44
- * - TypeScript for type safety
41
+ * Composes useDataTableEngine + DataTableProvider + DataTableView.
42
+ * Preserves forwardRef API and DataTableApi surface.
45
43
  */
46
- const material_1 = require("@mui/material");
47
- const react_table_1 = require("@tanstack/react-table");
48
- // Import custom features
49
- const column_filter_feature_1 = require("./features/column-filter.feature");
50
- const features_1 = require("./features");
51
- const react_virtual_1 = require("@tanstack/react-virtual");
52
44
  const react_1 = __importStar(require("react"));
53
- // Import from new organized structure
54
45
  const data_table_context_1 = require("./contexts/data-table-context");
55
- const utils_1 = require("./utils");
56
- const debounced_fetch_utils_1 = require("./utils/debounced-fetch.utils");
57
- const slot_helpers_1 = require("./utils/slot-helpers");
58
- const headers_1 = require("./components/headers");
59
- const pagination_1 = require("./components/pagination");
60
- const rows_1 = require("./components/rows");
61
- const toolbar_1 = require("./components/toolbar");
62
- const special_columns_utils_1 = require("./utils/special-columns.utils");
63
- // Static default initial state - defined outside component
64
- const DEFAULT_INITIAL_STATE = {
65
- sorting: [],
66
- pagination: {
67
- pageIndex: 0,
68
- pageSize: 10,
69
- },
70
- selectionState: { ids: [], type: 'include' },
71
- globalFilter: '',
72
- expanded: {},
73
- columnOrder: [],
74
- columnPinning: {
75
- left: [],
76
- right: [],
77
- },
78
- columnVisibility: {},
79
- columnSizing: {},
80
- columnFilter: {
81
- filters: [],
82
- logic: 'AND',
83
- pendingFilters: [],
84
- pendingLogic: 'AND',
85
- },
86
- };
87
- /**
88
- * Main DataTable component with all features
89
- */
90
- exports.DataTable = (0, react_1.forwardRef)(function DataTable({ initialState, columns, data = [], totalRow = 0, idKey = 'id', extraFilter = null, footerFilter = null,
91
- // Data management mode (MUI DataGrid style)
92
- dataMode = 'client', initialLoadData = true, onFetchData, // callback to fetch data from the server need to with response { data: T[], total: number }
93
- onFetchStateChange, // callback to fetch data from the server no need to resonce , this for filter data
94
- onDataChange, // callback to change data
95
- onDataStateChange, // callback to change data state
96
- // Selection props
97
- enableRowSelection = false, enableMultiRowSelection = true, selectMode = 'page', isRowSelectable, onSelectionChange,
98
- // Row click props
99
- onRowClick, selectOnRowClick = false,
100
- // Bulk action props
101
- enableBulkActions = false, bulkActions,
102
- // Column resizing props
103
- enableColumnResizing = false, columnResizeMode = 'onChange', onColumnSizingChange,
104
- // Column ordering props
105
- enableColumnDragging = false, onColumnDragEnd,
106
- // Column pinning props
107
- enableColumnPinning = false, onColumnPinningChange,
108
- // Column visibility props
109
- onColumnVisibilityChange, enableColumnVisibility = true,
110
- // Expandable rows props
111
- enableExpanding = false, getRowCanExpand, renderSubComponent,
112
- // Pagination props
113
- enablePagination = false, paginationMode = 'client',
114
- // Filtering props
115
- enableGlobalFilter = true, enableColumnFilter = false, filterMode = 'client',
116
- // Sorting props
117
- enableSorting = true, sortingMode = 'client', onSortingChange,
118
- //export props
119
- exportFilename = 'export', exportConcurrency = 'cancelAndRestart', exportChunkSize = 1000, exportStrictTotalCheck = false, exportSanitizeCSV = true, onExportProgress, onExportComplete, onExportError, onServerExport, onExportCancel, onExportStateChange,
120
- // Styling props
121
- enableHover = true, enableStripes = false, tableProps = {}, fitToScreen = true, tableSize: initialTableSize = 'medium',
122
- // Sticky header/footer props
123
- enableStickyHeaderOrFooter = false, maxHeight = '400px',
124
- // Virtualization props
125
- enableVirtualization = false, estimateRowHeight = 52,
126
- // Toolbar props
127
- enableTableSizeControl = true, enableExport = false, enableReset = true, enableRefresh = false,
128
- // Loading and empty states
129
- loading = false, emptyMessage = 'No data available', skeletonRows = 5,
130
- // Column filters props
131
- onColumnFiltersChange, onPaginationChange, onGlobalFilterChange,
132
- // Slots
133
- slots = {}, slotProps = {},
134
- // Logging
135
- logging, }, ref) {
136
- // Convert mode-based props to boolean flags for internal use
137
- const isServerMode = dataMode === 'server';
138
- const isServerPagination = paginationMode === 'server' || isServerMode;
139
- const isServerFiltering = filterMode === 'server' || isServerMode;
140
- const isServerSorting = sortingMode === 'server' || isServerMode;
141
- const theme = (0, material_1.useTheme)();
142
- const logger = (0, react_1.useMemo)(() => (0, utils_1.createLogger)('DataTable', logging), [logging]);
143
- (0, react_1.useEffect)(() => {
144
- if (logger.isLevelEnabled('info')) {
145
- logger.info('mounted', {
146
- dataMode,
147
- paginationMode,
148
- filterMode,
149
- sortingMode,
150
- });
151
- }
152
- return () => {
153
- if (logger.isLevelEnabled('info')) {
154
- logger.info('unmounted');
155
- }
156
- };
157
- }, [logger, dataMode, paginationMode, filterMode, sortingMode]);
158
- // -------------------------------
159
- // Memoized values (grouped together)
160
- // -------------------------------
161
- const initialStateConfig = (0, react_1.useMemo)(() => {
162
- const config = {
163
- ...DEFAULT_INITIAL_STATE,
164
- ...initialState,
165
- };
166
- if (logger.isLevelEnabled('info')) {
167
- logger.info('initialStateConfig', { config });
168
- }
169
- return config;
170
- }, [initialState, logger]);
171
- const initialSelectionState = (0, react_1.useMemo)(() => {
172
- return initialStateConfig.selectionState || DEFAULT_INITIAL_STATE.selectionState;
173
- }, [initialStateConfig.selectionState]);
174
- // -------------------------------
175
- // State hooks (grouped together)
176
- // -------------------------------
177
- // const [fetchLoading, setFetchLoading] = useState(false);
178
- const [sorting, setSorting] = (0, react_1.useState)((initialState === null || initialState === void 0 ? void 0 : initialState.sorting) || DEFAULT_INITIAL_STATE.sorting);
179
- const [pagination, setPagination] = (0, react_1.useState)((initialState === null || initialState === void 0 ? void 0 : initialState.pagination) || DEFAULT_INITIAL_STATE.pagination);
180
- const [globalFilter, setGlobalFilter] = (0, react_1.useState)((initialState === null || initialState === void 0 ? void 0 : initialState.globalFilter) || DEFAULT_INITIAL_STATE.globalFilter);
181
- const [selectionState, setSelectionState] = (0, react_1.useState)((initialState === null || initialState === void 0 ? void 0 : initialState.selectionState) || DEFAULT_INITIAL_STATE.selectionState);
182
- const [columnFilter, setColumnFilter] = (0, react_1.useState)((initialState === null || initialState === void 0 ? void 0 : initialState.columnFilter) || DEFAULT_INITIAL_STATE.columnFilter);
183
- const [expanded, setExpanded] = (0, react_1.useState)({});
184
- const [tableSize, setTableSize] = (0, react_1.useState)(initialTableSize || 'medium');
185
- const [columnOrder, setColumnOrder] = (0, react_1.useState)((initialState === null || initialState === void 0 ? void 0 : initialState.columnOrder) || DEFAULT_INITIAL_STATE.columnOrder);
186
- const [columnPinning, setColumnPinning] = (0, react_1.useState)((initialState === null || initialState === void 0 ? void 0 : initialState.columnPinning) || DEFAULT_INITIAL_STATE.columnPinning);
187
- const [columnVisibility, setColumnVisibility] = (0, react_1.useState)((initialState === null || initialState === void 0 ? void 0 : initialState.columnVisibility) || DEFAULT_INITIAL_STATE.columnVisibility);
188
- const [columnSizing, setColumnSizing] = (0, react_1.useState)((initialState === null || initialState === void 0 ? void 0 : initialState.columnSizing) || DEFAULT_INITIAL_STATE.columnSizing);
189
- const [serverData, setServerData] = (0, react_1.useState)(null);
190
- const [serverTotal, setServerTotal] = (0, react_1.useState)(0);
191
- const [exportController, setExportController] = (0, react_1.useState)(null);
192
- const [exportProgress, setExportProgress] = (0, react_1.useState)({});
193
- const [exportPhase, setExportPhase] = (0, react_1.useState)(null);
194
- const [queuedExportCount, setQueuedExportCount] = (0, react_1.useState)(0);
195
- // -------------------------------
196
- // Ref hooks (grouped together)
197
- // -------------------------------
198
- const tableContainerRef = (0, react_1.useRef)(null);
199
- const internalApiRef = (0, react_1.useRef)(null);
200
- const exportControllerRef = (0, react_1.useRef)(null);
201
- const exportQueueRef = (0, react_1.useRef)(Promise.resolve());
202
- const isExternallyControlledData = (0, react_1.useMemo)(() => !onFetchData && (!!onDataChange || !!onFetchStateChange), [onFetchData, onDataChange, onFetchStateChange]);
203
- const { debouncedFetch, isLoading: fetchLoading } = (0, debounced_fetch_utils_1.useDebouncedFetch)(onFetchData);
204
- const tableData = (0, react_1.useMemo)(() => {
205
- if (isExternallyControlledData)
206
- return data;
207
- return serverData !== null ? serverData : data;
208
- }, [isExternallyControlledData, serverData, data]);
209
- const tableTotalRow = (0, react_1.useMemo)(() => (isExternallyControlledData ? (totalRow || data.length) : (serverData !== null ? serverTotal : totalRow || data.length)), [isExternallyControlledData, serverData, serverTotal, totalRow, data]);
210
- const tableLoading = (0, react_1.useMemo)(() => onFetchData ? (loading || fetchLoading) : loading, [onFetchData, loading, fetchLoading]);
211
- const enhancedColumns = (0, react_1.useMemo)(() => {
212
- let columnsMap = [...columns];
213
- if (enableExpanding) {
214
- const expandingColumnMap = (0, special_columns_utils_1.createExpandingColumn)({
215
- ...((slotProps === null || slotProps === void 0 ? void 0 : slotProps.expandColumn) && typeof slotProps.expandColumn === 'object' ? slotProps.expandColumn : {}),
216
- });
217
- columnsMap = [expandingColumnMap, ...columnsMap];
218
- }
219
- if (enableRowSelection) {
220
- const selectionColumnMap = (0, special_columns_utils_1.createSelectionColumn)({
221
- ...((slotProps === null || slotProps === void 0 ? void 0 : slotProps.selectionColumn) && typeof slotProps.selectionColumn === 'object' ? slotProps.selectionColumn : {}),
222
- multiSelect: enableMultiRowSelection,
223
- });
224
- columnsMap = [selectionColumnMap, ...columnsMap];
225
- }
226
- const enhancedColumns = (0, utils_1.withIdsDeep)(columnsMap);
227
- if (logger.isLevelEnabled('info')) {
228
- logger.info('enhancedColumns', { enhancedColumns });
229
- }
230
- return enhancedColumns;
231
- }, [columns, enableExpanding, enableRowSelection, logger, slotProps.expandColumn, slotProps.selectionColumn, enableMultiRowSelection]);
232
- const isExporting = (0, react_1.useMemo)(() => exportController !== null, [exportController]);
233
- const isSomeRowsSelected = (0, react_1.useMemo)(() => {
234
- if (!enableBulkActions || !enableRowSelection)
235
- return false;
236
- if (selectionState.type === 'exclude') {
237
- return selectionState.ids.length < tableTotalRow;
238
- }
239
- else {
240
- return selectionState.ids.length > 0;
241
- }
242
- }, [enableBulkActions, enableRowSelection, selectionState, tableTotalRow]);
243
- const selectedRowCount = (0, react_1.useMemo)(() => {
244
- if (!enableBulkActions || !enableRowSelection)
245
- return 0;
246
- if (selectionState.type === 'exclude') {
247
- return tableTotalRow - selectionState.ids.length;
248
- }
249
- else {
250
- return selectionState.ids.length;
251
- }
252
- }, [enableBulkActions, enableRowSelection, selectionState, tableTotalRow]);
253
- // -------------------------------
254
- // Callback hooks (grouped together)
255
- // -------------------------------
256
- const fetchData = (0, react_1.useCallback)(async (overrides = {}, options) => {
257
- var _a, _b, _c, _d, _e;
258
- const filters = {
259
- globalFilter,
260
- pagination,
261
- columnFilter,
262
- sorting,
263
- ...overrides,
264
- };
265
- if (onFetchStateChange) {
266
- onFetchStateChange(filters, options === null || options === void 0 ? void 0 : options.meta);
267
- }
268
- if (!onFetchData) {
269
- if (logger.isLevelEnabled('debug')) {
270
- logger.debug('onFetchData not provided, skipping fetch', { overrides, columnFilter, sorting, pagination });
271
- }
272
- return;
273
- }
274
- if (logger.isLevelEnabled('info')) {
275
- logger.info('Requesting data', {
276
- filters,
277
- reason: (_a = options === null || options === void 0 ? void 0 : options.meta) === null || _a === void 0 ? void 0 : _a.reason,
278
- force: (_b = options === null || options === void 0 ? void 0 : options.meta) === null || _b === void 0 ? void 0 : _b.force,
279
- });
280
- }
281
- try {
282
- const delay = (_c = options === null || options === void 0 ? void 0 : options.delay) !== null && _c !== void 0 ? _c : 300; // respects 0
283
- const result = await debouncedFetch(filters, {
284
- debounceDelay: delay,
285
- meta: options === null || options === void 0 ? void 0 : options.meta,
286
- });
287
- if (logger.isLevelEnabled('info')) {
288
- logger.info('Fetch resolved', {
289
- rows: (_e = (_d = result === null || result === void 0 ? void 0 : result.data) === null || _d === void 0 ? void 0 : _d.length) !== null && _e !== void 0 ? _e : 0,
290
- total: result === null || result === void 0 ? void 0 : result.total,
291
- });
292
- }
293
- if (result && Array.isArray(result.data) && result.total !== undefined) {
294
- setServerData(result.data);
295
- setServerTotal(result.total);
296
- }
297
- else if (logger.isLevelEnabled('warn')) {
298
- logger.warn('Fetch handler returned unexpected shape', result);
299
- }
300
- return result;
301
- }
302
- catch (error) {
303
- logger.error('Fetch failed', error);
304
- throw error;
305
- }
306
- }, [
307
- onFetchData,
308
- globalFilter,
309
- pagination,
310
- columnFilter,
311
- sorting,
312
- debouncedFetch,
313
- logger,
314
- onFetchStateChange,
315
- ]);
316
- const normalizeRefreshOptions = (0, react_1.useCallback)((options, fallbackReason = 'refresh') => {
317
- var _a, _b, _c;
318
- if (typeof options === 'boolean') {
319
- return {
320
- resetPagination: options,
321
- force: false,
322
- reason: fallbackReason,
323
- };
324
- }
325
- return {
326
- resetPagination: (_a = options === null || options === void 0 ? void 0 : options.resetPagination) !== null && _a !== void 0 ? _a : false,
327
- force: (_b = options === null || options === void 0 ? void 0 : options.force) !== null && _b !== void 0 ? _b : false,
328
- reason: (_c = options === null || options === void 0 ? void 0 : options.reason) !== null && _c !== void 0 ? _c : fallbackReason,
329
- };
330
- }, []);
331
- const handleSelectionStateChange = (0, react_1.useCallback)((updaterOrValue) => {
332
- setSelectionState((prevState) => {
333
- const next = typeof updaterOrValue === 'function' ? updaterOrValue(prevState) : updaterOrValue;
334
- onSelectionChange === null || onSelectionChange === void 0 ? void 0 : onSelectionChange(next);
335
- return next;
336
- });
337
- }, [onSelectionChange]);
338
- const resetPageToFirst = (0, react_1.useCallback)(() => {
339
- if (logger.isLevelEnabled('info')) {
340
- logger.info('Resetting to first page due to state change', {
341
- previousPageIndex: pagination.pageIndex,
342
- pageSize: pagination.pageSize,
343
- });
344
- }
345
- const newPagination = { pageIndex: 0, pageSize: pagination.pageSize };
346
- setPagination(newPagination);
347
- onPaginationChange === null || onPaginationChange === void 0 ? void 0 : onPaginationChange(newPagination);
348
- return newPagination;
349
- }, [pagination, logger, onPaginationChange]);
350
- const handleSortingChange = (0, react_1.useCallback)((updaterOrValue) => {
351
- setSorting((prev) => {
352
- const next = typeof updaterOrValue === 'function' ? updaterOrValue(prev) : updaterOrValue;
353
- const cleaned = next.filter((s) => s === null || s === void 0 ? void 0 : s.id);
354
- onSortingChange === null || onSortingChange === void 0 ? void 0 : onSortingChange(cleaned);
355
- const nextPagination = resetPageToFirst();
356
- if (isServerMode || isServerSorting) {
357
- fetchData({ sorting: cleaned, pagination: nextPagination }, { delay: 0 });
358
- }
359
- return cleaned;
360
- });
361
- }, [onSortingChange, isServerMode, isServerSorting, resetPageToFirst, fetchData]);
362
- const handleColumnOrderChange = (0, react_1.useCallback)((updatedColumnOrder) => {
363
- const newColumnOrder = typeof updatedColumnOrder === 'function'
364
- ? updatedColumnOrder(columnOrder)
365
- : updatedColumnOrder;
366
- setColumnOrder(newColumnOrder);
367
- if (onColumnDragEnd) {
368
- onColumnDragEnd(newColumnOrder);
369
- }
370
- }, [onColumnDragEnd, columnOrder]);
371
- const handleColumnPinningChange = (0, react_1.useCallback)((updater) => {
372
- setColumnPinning((prev) => {
373
- const next = typeof updater === "function" ? updater(prev) : updater;
374
- // keep direct callback here (optional)
375
- onColumnPinningChange === null || onColumnPinningChange === void 0 ? void 0 : onColumnPinningChange(next);
376
- return next;
377
- });
378
- }, [onColumnPinningChange]);
379
- // Column visibility change handler - same pattern as column order
380
- const handleColumnVisibilityChange = (0, react_1.useCallback)((updater) => {
381
- setColumnVisibility((prev) => {
382
- const next = typeof updater === 'function' ? updater(prev) : updater;
383
- onColumnVisibilityChange === null || onColumnVisibilityChange === void 0 ? void 0 : onColumnVisibilityChange(next);
384
- return next;
385
- });
386
- }, [onColumnVisibilityChange]);
387
- // Column sizing change handler - same pattern as column order
388
- const handleColumnSizingChange = (0, react_1.useCallback)((updater) => {
389
- setColumnSizing((prev) => {
390
- const next = typeof updater === 'function' ? updater(prev) : updater;
391
- onColumnSizingChange === null || onColumnSizingChange === void 0 ? void 0 : onColumnSizingChange(next);
392
- return next;
393
- });
394
- }, [onColumnSizingChange]);
395
- const handlePaginationChange = (0, react_1.useCallback)((updater) => {
396
- setPagination((prev) => {
397
- const next = typeof updater === 'function' ? updater(prev) : updater;
398
- onPaginationChange === null || onPaginationChange === void 0 ? void 0 : onPaginationChange(next);
399
- if (isServerMode || isServerPagination) {
400
- fetchData({ pagination: next }, { delay: 0 });
401
- }
402
- return next;
403
- });
404
- }, [isServerMode, isServerPagination, fetchData, onPaginationChange]);
405
- const handleGlobalFilterChange = (0, react_1.useCallback)((updaterOrValue) => {
406
- setGlobalFilter((prev) => {
407
- const next = typeof updaterOrValue === 'function' ? updaterOrValue(prev) : updaterOrValue;
408
- onGlobalFilterChange === null || onGlobalFilterChange === void 0 ? void 0 : onGlobalFilterChange(next);
409
- if (isServerMode || isServerFiltering) {
410
- const nextPagination = { pageIndex: 0, pageSize: pagination.pageSize };
411
- setPagination(nextPagination);
412
- fetchData({ globalFilter: next, pagination: nextPagination }, { delay: 0 });
413
- }
414
- return next;
415
- });
416
- }, [isServerMode, isServerFiltering, onGlobalFilterChange, fetchData, pagination === null || pagination === void 0 ? void 0 : pagination.pageSize]);
417
- const handleColumnFilterChangeHandler = (0, react_1.useCallback)((updater, isApply = false) => {
418
- setColumnFilter((prev) => {
419
- const newState = typeof updater === 'function' ? updater(prev) : updater;
420
- if (isApply) {
421
- if (isServerMode || isServerFiltering) {
422
- const nextPagination = { pageIndex: 0, pageSize: pagination.pageSize };
423
- setPagination(nextPagination);
424
- fetchData({ columnFilter: newState, pagination: nextPagination }, { delay: 0 });
425
- }
426
- }
427
- onColumnFiltersChange === null || onColumnFiltersChange === void 0 ? void 0 : onColumnFiltersChange(newState, isApply);
428
- return newState;
429
- });
430
- }, [fetchData, isServerFiltering, isServerMode, onColumnFiltersChange, pagination.pageSize]);
431
- // -------------------------------
432
- // Table creation (after callbacks/memo)
433
- // -------------------------------
434
- const table = (0, react_table_1.useReactTable)({
435
- _features: [column_filter_feature_1.ColumnFilterFeature, features_1.SelectionFeature],
436
- data: tableData,
437
- columns: enhancedColumns,
438
- // Use merged initial state so built-in reset helpers align with our controlled state defaults
439
- initialState: initialStateConfig,
440
- state: {
441
- ...(enableSorting ? { sorting } : {}),
442
- ...(enablePagination ? { pagination } : {}),
443
- ...(enableGlobalFilter ? { globalFilter } : {}),
444
- ...(enableExpanding ? { expanded } : {}),
445
- ...(enableColumnDragging ? { columnOrder } : {}),
446
- ...(enableColumnPinning ? { columnPinning } : {}),
447
- ...(enableColumnVisibility ? { columnVisibility } : {}),
448
- ...(enableColumnResizing ? { columnSizing } : {}),
449
- ...(enableColumnFilter ? { columnFilter } : {}),
450
- ...(enableRowSelection ? { selectionState } : {}),
451
- },
452
- // Selection options (same pattern as column filter)
453
- // Add custom features
454
- selectMode: selectMode,
455
- enableAdvanceSelection: !!enableRowSelection,
456
- isRowSelectable: isRowSelectable,
457
- ...(enableRowSelection ? { onSelectionStateChange: handleSelectionStateChange } : {}),
458
- // Column filter
459
- enableAdvanceColumnFilter: enableColumnFilter,
460
- onColumnFilterChange: handleColumnFilterChangeHandler, // Handle column filters change
461
- onColumnFilterApply: (state) => handleColumnFilterChangeHandler(state, true), // Handle when filters are actually applied
462
- ...(enableSorting ? { onSortingChange: handleSortingChange } : {}),
463
- ...(enablePagination ? { onPaginationChange: handlePaginationChange } : {}),
464
- ...(enableGlobalFilter ? { onGlobalFilterChange: handleGlobalFilterChange } : {}),
465
- ...(enableExpanding ? { onExpandedChange: setExpanded } : {}),
466
- ...(enableColumnDragging ? { onColumnOrderChange: handleColumnOrderChange } : {}),
467
- ...(enableColumnPinning ? { onColumnPinningChange: handleColumnPinningChange } : {}),
468
- ...(enableColumnVisibility ? { onColumnVisibilityChange: handleColumnVisibilityChange } : {}),
469
- ...(enableColumnResizing ? { onColumnSizingChange: handleColumnSizingChange } : {}),
470
- // Row model
471
- getCoreRowModel: (0, react_table_1.getCoreRowModel)(),
472
- ...(enableSorting ? { getSortedRowModel: (0, react_table_1.getSortedRowModel)() } : {}),
473
- ...(enableColumnFilter || enableGlobalFilter ? { getFilteredRowModel: (0, column_filter_feature_1.getCombinedFilteredRowModel)() } : {}),
474
- // Only use getPaginationRowModel for client-side pagination
475
- ...(enablePagination && !isServerPagination ? { getPaginationRowModel: (0, react_table_1.getPaginationRowModel)() } : {}),
476
- // Sorting
477
- enableSorting: enableSorting,
478
- manualSorting: isServerSorting,
479
- // Filtering
480
- manualFiltering: isServerFiltering,
481
- // Column resizing
482
- enableColumnResizing: enableColumnResizing,
483
- columnResizeMode: columnResizeMode,
484
- columnResizeDirection: theme.direction,
485
- // Column pinning
486
- enableColumnPinning: enableColumnPinning,
487
- // Expanding
488
- ...(enableExpanding ? { getRowCanExpand: getRowCanExpand } : {}),
489
- // Pagination
490
- manualPagination: isServerPagination,
491
- autoResetPageIndex: false, // Prevent automatic page reset on state changes
492
- // pageCount: enablePagination ? Math.ceil(tableTotalRow / pagination.pageSize) : -1,
493
- rowCount: enablePagination ? (tableTotalRow !== null && tableTotalRow !== void 0 ? tableTotalRow : tableData.length) : tableData.length,
494
- // Row ID
495
- getRowId: (row, index) => (0, utils_1.generateRowId)(row, index, idKey),
496
- // Debug
497
- debugAll: false, // Disabled for production
498
- });
499
- // Compute width after table is created so column resizing is safe and reflects changes
500
- const allLeafColumns = table.getAllLeafColumns();
501
- const visibleLeafColumns = table.getVisibleLeafColumns();
502
- const hasExplicitSizing = allLeafColumns.some((column) => {
503
- const { size, minSize, maxSize } = column.columnDef;
504
- return size !== undefined || minSize !== undefined || maxSize !== undefined;
505
- });
506
- const useFixedLayout = fitToScreen || enableColumnResizing || hasExplicitSizing;
507
- const tableTotalSize = table.getTotalSize();
508
- const tableWidth = fitToScreen ? '100%' : (useFixedLayout ? tableTotalSize : '100%');
509
- const tableStyle = {
510
- width: tableWidth,
511
- minWidth: fitToScreen ? tableTotalSize : undefined,
512
- tableLayout: useFixedLayout ? 'fixed' : 'auto',
513
- };
514
- // -------------------------------
515
- // Virtualization and row memo
516
- // -------------------------------
517
- // Note: globalFilter is needed in dependencies to trigger recalculation when filter changes
518
- // The table object is stable, so we need to depend on the filter state directly
519
- const rows = table.getRowModel().rows;
520
- const rowVirtualizer = (0, react_virtual_1.useVirtualizer)({
521
- count: rows.length,
522
- getScrollElement: () => tableContainerRef.current,
523
- estimateSize: () => estimateRowHeight,
524
- overscan: 10,
525
- enabled: enableVirtualization && !enablePagination && rows.length > 0,
526
- });
527
- // -------------------------------
528
- // Callbacks (after table creation)
529
- // -------------------------------
530
- const handleColumnReorder = (0, react_1.useCallback)((draggedColumnId, targetColumnId) => {
531
- const currentOrder = columnOrder.length > 0 ? columnOrder : enhancedColumns.map((col, index) => {
532
- if (col.id)
533
- return col.id;
534
- const anyCol = col;
535
- if (anyCol.accessorKey && typeof anyCol.accessorKey === 'string') {
536
- return anyCol.accessorKey;
537
- }
538
- return `column_${index}`;
539
- });
540
- const draggedIndex = currentOrder.indexOf(draggedColumnId);
541
- const targetIndex = currentOrder.indexOf(targetColumnId);
542
- if (draggedIndex === -1 || targetIndex === -1)
543
- return;
544
- const newOrder = [...currentOrder];
545
- newOrder.splice(draggedIndex, 1);
546
- newOrder.splice(targetIndex, 0, draggedColumnId);
547
- handleColumnOrderChange(newOrder);
548
- }, [columnOrder, enhancedColumns, handleColumnOrderChange]);
549
- // -------------------------------
550
- // Effects (after callbacks)
551
- // -------------------------------
552
- (0, react_1.useEffect)(() => {
553
- if (!isExternallyControlledData || serverData === null)
554
- return;
555
- setServerData(null);
556
- setServerTotal(0);
557
- }, [isExternallyControlledData, serverData]);
558
- (0, react_1.useEffect)(() => {
559
- if (initialLoadData && (onFetchData || onFetchStateChange)) {
560
- if (logger.isLevelEnabled('info')) {
561
- logger.info('Initial data load triggered', { initialLoadData });
562
- }
563
- fetchData({}, {
564
- delay: 0,
565
- meta: { reason: 'initial' },
566
- });
567
- }
568
- else if (logger.isLevelEnabled('debug')) {
569
- logger.debug('Skipping initial data load', {
570
- initialLoadData,
571
- hasOnFetchData: !!onFetchData
572
- });
573
- }
574
- // eslint-disable-next-line react-hooks/exhaustive-deps
575
- }, []);
576
- (0, react_1.useEffect)(() => {
577
- if (enableColumnDragging && columnOrder.length === 0) {
578
- const initialOrder = enhancedColumns.map((col, index) => {
579
- if (col.id)
580
- return col.id;
581
- const anyCol = col;
582
- if (anyCol.accessorKey && typeof anyCol.accessorKey === 'string') {
583
- return anyCol.accessorKey;
584
- }
585
- return `column_${index}`;
586
- });
587
- setColumnOrder(initialOrder);
588
- }
589
- }, [enableColumnDragging, enhancedColumns, columnOrder.length]);
590
- const lastSentRef = (0, react_1.useRef)("");
591
- const emitTableState = (0, react_1.useCallback)(() => {
592
- if (!onDataStateChange)
593
- return;
594
- const live = table.getState();
595
- const liveColumnFilter = live.columnFilter;
596
- // only keep what you persist/store
597
- const payload = {
598
- sorting: live.sorting,
599
- pagination: live.pagination,
600
- globalFilter: live.globalFilter,
601
- columnFilter: liveColumnFilter,
602
- columnVisibility: live.columnVisibility,
603
- columnSizing: live.columnSizing,
604
- columnOrder: live.columnOrder,
605
- columnPinning: live.columnPinning,
606
- };
607
- const key = JSON.stringify(payload);
608
- if (key === lastSentRef.current)
609
- return;
610
- lastSentRef.current = key;
611
- onDataStateChange(payload);
612
- }, [onDataStateChange, table]);
613
- (0, react_1.useEffect)(() => {
614
- emitTableState();
615
- }, [
616
- emitTableState,
617
- sorting,
618
- pagination,
619
- globalFilter,
620
- columnFilter,
621
- columnVisibility,
622
- columnSizing,
623
- columnOrder,
624
- columnPinning,
625
- ]);
626
- const getResetState = (0, react_1.useCallback)(() => {
627
- var _a;
628
- const resetSorting = initialStateConfig.sorting || [];
629
- const resetGlobalFilter = (_a = initialStateConfig.globalFilter) !== null && _a !== void 0 ? _a : '';
630
- const resetColumnFilter = initialStateConfig.columnFilter;
631
- const resetPagination = enablePagination
632
- ? (initialStateConfig.pagination || { pageIndex: 0, pageSize: 10 })
633
- : undefined;
634
- return {
635
- sorting: resetSorting,
636
- globalFilter: resetGlobalFilter,
637
- columnFilter: resetColumnFilter,
638
- ...(resetPagination ? { pagination: resetPagination } : {}),
639
- };
640
- }, [initialStateConfig, enablePagination]);
641
- const applyDataMutation = (0, react_1.useCallback)((action, updater, details = {}) => {
642
- const previousData = [...tableData];
643
- const nextData = updater(previousData);
644
- if (nextData === previousData)
645
- return nextData;
646
- const nextTotal = Math.max(0, tableTotalRow + (nextData.length - previousData.length));
647
- if (!isExternallyControlledData) {
648
- setServerData(nextData);
649
- setServerTotal(nextTotal);
650
- }
651
- onDataChange === null || onDataChange === void 0 ? void 0 : onDataChange(nextData, {
652
- action,
653
- previousData,
654
- nextData,
655
- totalRow: nextTotal,
656
- ...details,
657
- });
658
- if (logger.isLevelEnabled('debug')) {
659
- logger.debug('Applied data mutation', {
660
- action,
661
- previousCount: previousData.length,
662
- nextCount: nextData.length,
663
- totalRow: nextTotal,
664
- });
665
- }
666
- return nextData;
667
- }, [isExternallyControlledData, logger, onDataChange, tableData, tableTotalRow]);
668
- const triggerRefresh = (0, react_1.useCallback)(async (options, fallbackReason = 'refresh') => {
669
- const normalizedOptions = normalizeRefreshOptions(options, fallbackReason);
670
- const nextPagination = enablePagination
671
- ? {
672
- pageIndex: normalizedOptions.resetPagination ? 0 : pagination.pageIndex,
673
- pageSize: pagination.pageSize,
674
- }
675
- : undefined;
676
- const shouldUpdatePagination = !!nextPagination
677
- && (nextPagination.pageIndex !== pagination.pageIndex || nextPagination.pageSize !== pagination.pageSize);
678
- if (nextPagination && shouldUpdatePagination) {
679
- setPagination(nextPagination);
680
- onPaginationChange === null || onPaginationChange === void 0 ? void 0 : onPaginationChange(nextPagination);
681
- }
682
- await fetchData(nextPagination ? { pagination: nextPagination } : {}, {
683
- delay: 0,
684
- meta: {
685
- reason: normalizedOptions.reason,
686
- force: normalizedOptions.force,
687
- },
688
- });
689
- return;
690
- }, [normalizeRefreshOptions, enablePagination, pagination, onPaginationChange, fetchData]);
691
- const resetAllAndReload = (0, react_1.useCallback)(() => {
692
- var _a;
693
- const resetState = getResetState();
694
- setSorting(resetState.sorting || []);
695
- setGlobalFilter((_a = resetState.globalFilter) !== null && _a !== void 0 ? _a : '');
696
- setColumnFilter(resetState.columnFilter);
697
- if (resetState.pagination) {
698
- setPagination(resetState.pagination);
699
- onPaginationChange === null || onPaginationChange === void 0 ? void 0 : onPaginationChange(resetState.pagination);
700
- }
701
- setSelectionState(initialSelectionState);
702
- setExpanded({});
703
- // layout state
704
- setColumnVisibility(initialStateConfig.columnVisibility || {});
705
- setColumnSizing(initialStateConfig.columnSizing || {});
706
- setColumnOrder(initialStateConfig.columnOrder || []);
707
- setColumnPinning(initialStateConfig.columnPinning || { left: [], right: [] });
708
- const resetOptions = normalizeRefreshOptions({
709
- resetPagination: true,
710
- force: true,
711
- reason: 'reset',
712
- }, 'reset');
713
- void fetchData(resetState, {
714
- delay: 0,
715
- meta: {
716
- reason: resetOptions.reason,
717
- force: resetOptions.force,
718
- },
719
- });
720
- }, [getResetState, initialSelectionState, initialStateConfig, onPaginationChange, normalizeRefreshOptions, fetchData]);
721
- const setExportControllerSafely = (0, react_1.useCallback)((value) => {
722
- setExportController((current) => {
723
- const next = typeof value === 'function' ? value(current) : value;
724
- exportControllerRef.current = next;
725
- return next;
726
- });
727
- }, []);
728
- const handleExportProgressInternal = (0, react_1.useCallback)((progress) => {
729
- setExportProgress(progress || {});
730
- onExportProgress === null || onExportProgress === void 0 ? void 0 : onExportProgress(progress);
731
- }, [onExportProgress]);
732
- const handleExportStateChangeInternal = (0, react_1.useCallback)((state) => {
733
- setExportPhase(state.phase);
734
- if (state.processedRows !== undefined
735
- || state.totalRows !== undefined
736
- || state.percentage !== undefined) {
737
- setExportProgress({
738
- processedRows: state.processedRows,
739
- totalRows: state.totalRows,
740
- percentage: state.percentage,
741
- });
742
- }
743
- onExportStateChange === null || onExportStateChange === void 0 ? void 0 : onExportStateChange(state);
744
- }, [onExportStateChange]);
745
- const runExportWithPolicy = (0, react_1.useCallback)(async (options) => {
746
- const { format, filename, mode, execute } = options;
747
- const startExecution = async () => {
748
- const controller = new AbortController();
749
- setExportProgress({});
750
- setExportControllerSafely(controller);
751
- try {
752
- await execute(controller);
753
- }
754
- finally {
755
- setExportControllerSafely((current) => (current === controller ? null : current));
756
- }
757
- };
758
- if (exportConcurrency === 'queue') {
759
- setQueuedExportCount((prev) => prev + 1);
760
- const runQueued = async () => {
761
- setQueuedExportCount((prev) => Math.max(0, prev - 1));
762
- await startExecution();
763
- };
764
- const queuedPromise = exportQueueRef.current
765
- .catch(() => undefined)
766
- .then(runQueued);
767
- exportQueueRef.current = queuedPromise;
768
- return queuedPromise;
769
- }
770
- const activeController = exportControllerRef.current;
771
- if (activeController) {
772
- if (exportConcurrency === 'ignoreIfRunning') {
773
- handleExportStateChangeInternal({
774
- phase: 'error',
775
- mode,
776
- format,
777
- filename,
778
- message: 'An export is already running',
779
- code: 'EXPORT_IN_PROGRESS',
780
- endedAt: Date.now(),
781
- });
782
- onExportError === null || onExportError === void 0 ? void 0 : onExportError({
783
- message: 'An export is already running',
784
- code: 'EXPORT_IN_PROGRESS',
785
- });
786
- return;
787
- }
788
- if (exportConcurrency === 'cancelAndRestart') {
789
- activeController.abort();
790
- }
791
- }
792
- await startExecution();
793
- }, [
794
- exportConcurrency,
795
- handleExportStateChangeInternal,
796
- onExportError,
797
- setExportControllerSafely,
798
- ]);
799
- const dataTableApi = (0, react_1.useMemo)(() => {
800
- // helpers (avoid repeating boilerplate)
801
- const buildInitialOrder = () => enhancedColumns.map((col, index) => {
802
- if (col.id)
803
- return col.id;
804
- const anyCol = col;
805
- if (anyCol.accessorKey && typeof anyCol.accessorKey === "string")
806
- return anyCol.accessorKey;
807
- return `column_${index}`;
808
- });
809
- const applyColumnOrder = (next) => {
810
- // handleColumnOrderChange supports both Updater<ColumnOrderState> and array in your impl
811
- handleColumnOrderChange(next);
812
- };
813
- const applyPinning = (next) => {
814
- handleColumnPinningChange(next);
815
- };
816
- const applyVisibility = (next) => {
817
- handleColumnVisibilityChange(next);
818
- };
819
- const applySizing = (next) => {
820
- handleColumnSizingChange(next);
821
- };
822
- const applyPagination = (next) => {
823
- handlePaginationChange(next);
824
- };
825
- const applySorting = (next) => {
826
- handleSortingChange(next);
827
- };
828
- const applyGlobalFilter = (next) => {
829
- handleGlobalFilterChange(next);
830
- };
831
- const getRowIndexById = (rowsToSearch, rowId) => rowsToSearch.findIndex((row, index) => String((0, utils_1.generateRowId)(row, index, idKey)) === rowId);
832
- const clampInsertIndex = (rowsToMutate, insertIndex) => {
833
- if (insertIndex === undefined)
834
- return rowsToMutate.length;
835
- return Math.max(0, Math.min(insertIndex, rowsToMutate.length));
836
- };
837
- return {
838
- table: {
839
- getTable: () => table,
840
- },
841
- // -------------------------------
842
- // Column Management
843
- // -------------------------------
844
- columnVisibility: {
845
- showColumn: (columnId) => {
846
- applyVisibility({ ...table.getState().columnVisibility, [columnId]: true });
847
- },
848
- hideColumn: (columnId) => {
849
- applyVisibility({ ...table.getState().columnVisibility, [columnId]: false });
850
- },
851
- toggleColumn: (columnId) => {
852
- var _a, _b;
853
- const curr = (_b = (_a = table.getState().columnVisibility) === null || _a === void 0 ? void 0 : _a[columnId]) !== null && _b !== void 0 ? _b : true;
854
- applyVisibility({ ...table.getState().columnVisibility, [columnId]: !curr });
855
- },
856
- showAllColumns: () => {
857
- // set all known columns true
858
- const all = {};
859
- table.getAllLeafColumns().forEach((c) => (all[c.id] = true));
860
- applyVisibility(all);
861
- },
862
- hideAllColumns: () => {
863
- const all = {};
864
- table.getAllLeafColumns().forEach((c) => (all[c.id] = false));
865
- applyVisibility(all);
866
- },
867
- resetColumnVisibility: () => {
868
- const initialVisibility = initialStateConfig.columnVisibility || {};
869
- applyVisibility(initialVisibility);
870
- },
871
- },
872
- // -------------------------------
873
- // Column Ordering
874
- // -------------------------------
875
- columnOrdering: {
876
- setColumnOrder: (nextOrder) => {
877
- applyColumnOrder(nextOrder);
878
- },
879
- moveColumn: (columnId, toIndex) => {
880
- var _a;
881
- const currentOrder = (((_a = table.getState().columnOrder) === null || _a === void 0 ? void 0 : _a.length) ? table.getState().columnOrder : buildInitialOrder()) || [];
882
- const fromIndex = currentOrder.indexOf(columnId);
883
- if (fromIndex === -1)
884
- return;
885
- const next = [...currentOrder];
886
- next.splice(fromIndex, 1);
887
- next.splice(toIndex, 0, columnId);
888
- applyColumnOrder(next);
889
- },
890
- resetColumnOrder: () => {
891
- applyColumnOrder(buildInitialOrder());
892
- },
893
- },
894
- // -------------------------------
895
- // Column Pinning
896
- // -------------------------------
897
- columnPinning: {
898
- pinColumnLeft: (columnId) => {
899
- const current = table.getState().columnPinning || { left: [], right: [] };
900
- const next = {
901
- left: [...(current.left || []).filter((id) => id !== columnId), columnId],
902
- right: (current.right || []).filter((id) => id !== columnId),
903
- };
904
- applyPinning(next);
905
- },
906
- pinColumnRight: (columnId) => {
907
- const current = table.getState().columnPinning || { left: [], right: [] };
908
- const next = {
909
- left: (current.left || []).filter((id) => id !== columnId),
910
- // keep your "prepend" behavior
911
- right: [columnId, ...(current.right || []).filter((id) => id !== columnId)],
912
- };
913
- applyPinning(next);
914
- },
915
- unpinColumn: (columnId) => {
916
- const current = table.getState().columnPinning || { left: [], right: [] };
917
- const next = {
918
- left: (current.left || []).filter((id) => id !== columnId),
919
- right: (current.right || []).filter((id) => id !== columnId),
920
- };
921
- applyPinning(next);
922
- },
923
- setPinning: (pinning) => {
924
- applyPinning(pinning);
925
- },
926
- resetColumnPinning: () => {
927
- const initialPinning = initialStateConfig.columnPinning || { left: [], right: [] };
928
- applyPinning(initialPinning);
929
- },
930
- },
931
- // -------------------------------
932
- // Column Resizing
933
- // -------------------------------
934
- columnResizing: {
935
- resizeColumn: (columnId, width) => {
936
- const currentSizing = table.getState().columnSizing || {};
937
- applySizing({ ...currentSizing, [columnId]: width });
938
- },
939
- autoSizeColumn: (columnId) => {
940
- // safe to call tanstack helper; it will feed into onColumnSizingChange if wired,
941
- // but since you're controlled, we still prefer to update through handler:
942
- const col = table.getColumn(columnId);
943
- if (!col)
944
- return;
945
- col.resetSize();
946
- // after resetSize, read state and emit via handler so controlled stays synced
947
- applySizing({ ...(table.getState().columnSizing || {}) });
948
- },
949
- autoSizeAllColumns: () => {
950
- const initialSizing = initialStateConfig.columnSizing || {};
951
- applySizing(initialSizing);
952
- },
953
- resetColumnSizing: () => {
954
- const initialSizing = initialStateConfig.columnSizing || {};
955
- applySizing(initialSizing);
956
- },
957
- },
958
- // -------------------------------
959
- // Filtering
960
- // -------------------------------
961
- filtering: {
962
- setGlobalFilter: (filter) => {
963
- applyGlobalFilter(filter);
964
- },
965
- clearGlobalFilter: () => {
966
- applyGlobalFilter("");
967
- },
968
- setColumnFilters: (filters, isApply = false) => {
969
- handleColumnFilterChangeHandler(filters, isApply);
970
- },
971
- addColumnFilter: (columnId, operator, value) => {
972
- const newFilter = {
973
- id: `filter_${Date.now()}`,
974
- columnId,
975
- operator,
976
- value,
977
- };
978
- const current = table.getState().columnFilter;
979
- const currentFilters = (current === null || current === void 0 ? void 0 : current.filters) || [];
980
- const nextFilters = [...currentFilters, newFilter];
981
- const nextPendingFilters = [...((current === null || current === void 0 ? void 0 : current.pendingFilters) || []), newFilter];
982
- handleColumnFilterChangeHandler({
983
- filters: nextFilters,
984
- logic: current === null || current === void 0 ? void 0 : current.logic,
985
- pendingFilters: nextPendingFilters,
986
- pendingLogic: (current === null || current === void 0 ? void 0 : current.pendingLogic) || "AND",
987
- }, true);
988
- if (logger.isLevelEnabled("debug")) {
989
- logger.debug(`Adding column filter ${columnId} ${operator} ${value}`, nextFilters);
990
- }
991
- },
992
- removeColumnFilter: (filterId) => {
993
- var _a, _b;
994
- const current = table.getState().columnFilter;
995
- const currentFilters = (current === null || current === void 0 ? void 0 : current.filters) || [];
996
- const isApplied = (_a = current === null || current === void 0 ? void 0 : current.pendingFilters) === null || _a === void 0 ? void 0 : _a.some((f) => f.id === filterId);
997
- const nextFilters = currentFilters.filter((f) => f.id !== filterId);
998
- const nextPendingFilters = ((_b = current === null || current === void 0 ? void 0 : current.pendingFilters) === null || _b === void 0 ? void 0 : _b.filter((f) => f.id !== filterId)) || [];
999
- handleColumnFilterChangeHandler({
1000
- filters: nextFilters,
1001
- logic: current === null || current === void 0 ? void 0 : current.logic,
1002
- pendingFilters: nextPendingFilters,
1003
- pendingLogic: (current === null || current === void 0 ? void 0 : current.pendingLogic) || "AND",
1004
- }, isApplied);
1005
- if (logger.isLevelEnabled("debug")) {
1006
- logger.debug(`Removing column filter ${filterId}`, nextFilters);
1007
- }
1008
- },
1009
- clearAllFilters: () => {
1010
- var _a, _b;
1011
- applyGlobalFilter("");
1012
- const isApplied = ((_b = (_a = table.getState().columnFilter) === null || _a === void 0 ? void 0 : _a.filters) === null || _b === void 0 ? void 0 : _b.length) > 0;
1013
- handleColumnFilterChangeHandler({
1014
- filters: [],
1015
- logic: "AND",
1016
- pendingFilters: [],
1017
- pendingLogic: "AND",
1018
- }, isApplied);
1019
- },
1020
- resetFilters: () => {
1021
- var _a, _b;
1022
- const isApplied = ((_b = (_a = table.getState().columnFilter) === null || _a === void 0 ? void 0 : _a.filters) === null || _b === void 0 ? void 0 : _b.length) > 0;
1023
- handleColumnFilterChangeHandler({
1024
- filters: [],
1025
- logic: "AND",
1026
- pendingFilters: [],
1027
- pendingLogic: "AND",
1028
- }, isApplied);
1029
- if (logger.isLevelEnabled("debug")) {
1030
- logger.debug("Resetting filters");
1031
- }
1032
- },
1033
- },
1034
- // -------------------------------
1035
- // Sorting
1036
- // -------------------------------
1037
- sorting: {
1038
- setSorting: (sortingState) => {
1039
- applySorting(sortingState);
1040
- if (logger.isLevelEnabled("debug"))
1041
- logger.debug("Setting sorting", sortingState);
1042
- },
1043
- // NOTE: toggleSorting is okay, but can become "one behind" in controlled server mode.
1044
- // So we implement deterministic sorting through handler.
1045
- sortColumn: (columnId, direction) => {
1046
- const current = table.getState().sorting || [];
1047
- const filtered = current.filter((s) => s.id !== columnId);
1048
- if (direction === false) {
1049
- applySorting(filtered);
1050
- return;
1051
- }
1052
- applySorting([{ id: columnId, desc: direction === "desc" }, ...filtered]);
1053
- },
1054
- clearSorting: () => {
1055
- applySorting([]);
1056
- },
1057
- resetSorting: () => {
1058
- const initialSorting = initialStateConfig.sorting || [];
1059
- applySorting(initialSorting);
1060
- },
1061
- },
1062
- // -------------------------------
1063
- // Pagination
1064
- // -------------------------------
1065
- pagination: {
1066
- goToPage: (pageIndex) => {
1067
- applyPagination((prev) => ({ ...prev, pageIndex }));
1068
- if (logger.isLevelEnabled("debug"))
1069
- logger.debug(`Going to page ${pageIndex}`);
1070
- },
1071
- nextPage: () => {
1072
- applyPagination((prev) => { var _a; return ({ ...prev, pageIndex: ((_a = prev === null || prev === void 0 ? void 0 : prev.pageIndex) !== null && _a !== void 0 ? _a : 0) + 1 }); });
1073
- if (logger.isLevelEnabled("debug"))
1074
- logger.debug("Next page");
1075
- },
1076
- previousPage: () => {
1077
- applyPagination((prev) => { var _a; return ({ ...prev, pageIndex: Math.max(0, ((_a = prev === null || prev === void 0 ? void 0 : prev.pageIndex) !== null && _a !== void 0 ? _a : 0) - 1) }); });
1078
- if (logger.isLevelEnabled("debug"))
1079
- logger.debug("Previous page");
1080
- },
1081
- setPageSize: (pageSize) => {
1082
- // usually want pageIndex reset
1083
- applyPagination(() => ({ pageIndex: 0, pageSize }));
1084
- if (logger.isLevelEnabled("debug"))
1085
- logger.debug(`Setting page size to ${pageSize}`);
1086
- },
1087
- goToFirstPage: () => {
1088
- applyPagination((prev) => ({ ...prev, pageIndex: 0 }));
1089
- if (logger.isLevelEnabled("debug"))
1090
- logger.debug("Going to first page");
1091
- },
1092
- goToLastPage: () => {
1093
- var _a, _b;
1094
- // pageCount can be derived; keep safe fallback
1095
- const pageCount = (_b = (_a = table.getPageCount) === null || _a === void 0 ? void 0 : _a.call(table)) !== null && _b !== void 0 ? _b : 0;
1096
- if (pageCount > 0) {
1097
- applyPagination((prev) => ({ ...prev, pageIndex: pageCount - 1 }));
1098
- if (logger.isLevelEnabled("debug"))
1099
- logger.debug(`Going to last page ${pageCount - 1}`);
1100
- }
1101
- },
1102
- resetPagination: () => {
1103
- const initialPagination = initialStateConfig.pagination || { pageIndex: 0, pageSize: 10 };
1104
- applyPagination(initialPagination);
1105
- },
1106
- },
1107
- // -------------------------------
1108
- // Selection
1109
- // -------------------------------
1110
- selection: {
1111
- selectRow: (rowId) => { var _a; return (_a = table.selectRow) === null || _a === void 0 ? void 0 : _a.call(table, rowId); },
1112
- deselectRow: (rowId) => { var _a; return (_a = table.deselectRow) === null || _a === void 0 ? void 0 : _a.call(table, rowId); },
1113
- toggleRowSelection: (rowId) => { var _a; return (_a = table.toggleRowSelected) === null || _a === void 0 ? void 0 : _a.call(table, rowId); },
1114
- selectAll: () => { var _a; return (_a = table.selectAll) === null || _a === void 0 ? void 0 : _a.call(table); },
1115
- deselectAll: () => { var _a; return (_a = table.deselectAll) === null || _a === void 0 ? void 0 : _a.call(table); },
1116
- toggleSelectAll: () => { var _a; return (_a = table.toggleAllRowsSelected) === null || _a === void 0 ? void 0 : _a.call(table); },
1117
- getSelectionState: () => { var _a; return ((_a = table.getSelectionState) === null || _a === void 0 ? void 0 : _a.call(table)) || { ids: [], type: "include" }; },
1118
- getSelectedRows: () => table.getSelectedRows(),
1119
- getSelectedCount: () => table.getSelectedCount(),
1120
- isRowSelected: (rowId) => table.getIsRowSelected(rowId) || false,
1121
- },
1122
- // -------------------------------
1123
- // Data Management (kept same, but ensure state changes go through handlers)
1124
- // -------------------------------
1125
- data: {
1126
- refresh: (options) => {
1127
- void triggerRefresh(options, 'refresh');
1128
- },
1129
- reload: (options = {}) => {
1130
- var _a, _b;
1131
- void triggerRefresh({
1132
- ...options,
1133
- resetPagination: (_a = options.resetPagination) !== null && _a !== void 0 ? _a : false,
1134
- reason: (_b = options.reason) !== null && _b !== void 0 ? _b : 'reload',
1135
- }, 'reload');
1136
- },
1137
- resetAll: () => resetAllAndReload(),
1138
- getAllData: () => [...tableData],
1139
- getRowData: (rowId) => {
1140
- const rowIndex = getRowIndexById(tableData, rowId);
1141
- return rowIndex === -1 ? undefined : tableData[rowIndex];
1142
- },
1143
- getRowByIndex: (index) => tableData[index],
1144
- updateRow: (rowId, updates) => {
1145
- applyDataMutation('updateRow', (rowsToMutate) => {
1146
- const rowIndex = getRowIndexById(rowsToMutate, rowId);
1147
- if (rowIndex === -1)
1148
- return rowsToMutate;
1149
- const nextData = [...rowsToMutate];
1150
- nextData[rowIndex] = { ...nextData[rowIndex], ...updates };
1151
- return nextData;
1152
- }, { rowId });
1153
- },
1154
- updateRowByIndex: (index, updates) => {
1155
- applyDataMutation('updateRowByIndex', (rowsToMutate) => {
1156
- if (!rowsToMutate[index])
1157
- return rowsToMutate;
1158
- const nextData = [...rowsToMutate];
1159
- nextData[index] = { ...nextData[index], ...updates };
1160
- return nextData;
1161
- }, { index });
1162
- },
1163
- insertRow: (newRow, index) => {
1164
- applyDataMutation('insertRow', (rowsToMutate) => {
1165
- const nextData = [...rowsToMutate];
1166
- nextData.splice(clampInsertIndex(nextData, index), 0, newRow);
1167
- return nextData;
1168
- }, { index });
1169
- },
1170
- deleteRow: (rowId) => {
1171
- applyDataMutation('deleteRow', (rowsToMutate) => {
1172
- const rowIndex = getRowIndexById(rowsToMutate, rowId);
1173
- if (rowIndex === -1)
1174
- return rowsToMutate;
1175
- const nextData = [...rowsToMutate];
1176
- nextData.splice(rowIndex, 1);
1177
- return nextData;
1178
- }, { rowId });
1179
- },
1180
- deleteRowByIndex: (index) => {
1181
- applyDataMutation('deleteRowByIndex', (rowsToMutate) => {
1182
- if (index < 0 || index >= rowsToMutate.length)
1183
- return rowsToMutate;
1184
- const nextData = [...rowsToMutate];
1185
- nextData.splice(index, 1);
1186
- return nextData;
1187
- }, { index });
1188
- },
1189
- deleteSelectedRows: () => {
1190
- var _a, _b, _c;
1191
- const currentSelection = ((_a = table.getSelectionState) === null || _a === void 0 ? void 0 : _a.call(table)) || selectionState;
1192
- const selectedIds = new Set((currentSelection.ids || []).map((id) => String(id)));
1193
- const loadedRowIds = tableData.map((row, index) => String((0, utils_1.generateRowId)(row, index, idKey)));
1194
- const deletableRowIds = currentSelection.type === 'exclude'
1195
- ? loadedRowIds.filter((rowId) => !selectedIds.has(rowId))
1196
- : loadedRowIds.filter((rowId) => selectedIds.has(rowId));
1197
- if (deletableRowIds.length === 0)
1198
- return;
1199
- if (currentSelection.type === 'exclude'
1200
- && table.getRowCount() > loadedRowIds.length
1201
- && logger.isLevelEnabled('info')) {
1202
- logger.info('deleteSelectedRows in exclude mode removed currently loaded rows only', {
1203
- removedRows: deletableRowIds.length,
1204
- totalSelected: (_b = table.getSelectedCount) === null || _b === void 0 ? void 0 : _b.call(table),
1205
- });
1206
- }
1207
- const deletableRowIdSet = new Set(deletableRowIds);
1208
- applyDataMutation('deleteSelectedRows', (rowsToMutate) => rowsToMutate.filter((row, index) => !deletableRowIdSet.has(String((0, utils_1.generateRowId)(row, index, idKey)))), { rowIds: deletableRowIds });
1209
- (_c = table.deselectAll) === null || _c === void 0 ? void 0 : _c.call(table);
1210
- },
1211
- replaceAllData: (newData) => {
1212
- applyDataMutation('replaceAllData', () => [...newData]);
1213
- },
1214
- updateMultipleRows: (updates) => {
1215
- const updateMap = new Map(updates.map((update) => [update.rowId, update.data]));
1216
- applyDataMutation('updateMultipleRows', (rowsToMutate) => rowsToMutate.map((row, index) => {
1217
- const currentRowId = String((0, utils_1.generateRowId)(row, index, idKey));
1218
- const updateData = updateMap.get(currentRowId);
1219
- return updateData ? { ...row, ...updateData } : row;
1220
- }));
1221
- },
1222
- insertMultipleRows: (newRows, startIndex) => {
1223
- applyDataMutation('insertMultipleRows', (rowsToMutate) => {
1224
- const nextData = [...rowsToMutate];
1225
- nextData.splice(clampInsertIndex(nextData, startIndex), 0, ...newRows);
1226
- return nextData;
1227
- }, { index: startIndex });
1228
- },
1229
- deleteMultipleRows: (rowIds) => {
1230
- const idsToDelete = new Set(rowIds);
1231
- applyDataMutation('deleteMultipleRows', (rowsToMutate) => rowsToMutate.filter((row, index) => !idsToDelete.has(String((0, utils_1.generateRowId)(row, index, idKey)))), { rowIds });
1232
- },
1233
- updateField: (rowId, fieldName, value) => {
1234
- applyDataMutation('updateField', (rowsToMutate) => {
1235
- const rowIndex = getRowIndexById(rowsToMutate, rowId);
1236
- if (rowIndex === -1)
1237
- return rowsToMutate;
1238
- const nextData = [...rowsToMutate];
1239
- nextData[rowIndex] = { ...nextData[rowIndex], [fieldName]: value };
1240
- return nextData;
1241
- }, { rowId });
1242
- },
1243
- updateFieldByIndex: (index, fieldName, value) => {
1244
- applyDataMutation('updateFieldByIndex', (rowsToMutate) => {
1245
- if (!rowsToMutate[index])
1246
- return rowsToMutate;
1247
- const nextData = [...rowsToMutate];
1248
- nextData[index] = { ...nextData[index], [fieldName]: value };
1249
- return nextData;
1250
- }, { index });
1251
- },
1252
- findRows: (predicate) => tableData.filter(predicate),
1253
- findRowIndex: (predicate) => tableData.findIndex(predicate),
1254
- getDataCount: () => tableData.length,
1255
- getFilteredDataCount: () => table.getFilteredRowModel().rows.length,
1256
- },
1257
- // -------------------------------
1258
- // Layout Management
1259
- // -------------------------------
1260
- layout: {
1261
- resetLayout: () => {
1262
- var _a;
1263
- // go through handlers so controlled state updates + emit works
1264
- applySizing(initialStateConfig.columnSizing || {});
1265
- applyVisibility(initialStateConfig.columnVisibility || {});
1266
- applySorting(initialStateConfig.sorting || []);
1267
- applyGlobalFilter((_a = initialStateConfig.globalFilter) !== null && _a !== void 0 ? _a : "");
1268
- },
1269
- resetAll: () => resetAllAndReload(),
1270
- saveLayout: () => ({
1271
- columnVisibility: table.getState().columnVisibility,
1272
- columnSizing: table.getState().columnSizing,
1273
- columnOrder: table.getState().columnOrder,
1274
- columnPinning: table.getState().columnPinning,
1275
- sorting: table.getState().sorting,
1276
- pagination: table.getState().pagination,
1277
- globalFilter: table.getState().globalFilter,
1278
- columnFilter: table.getState().columnFilter,
1279
- }),
1280
- restoreLayout: (layout) => {
1281
- var _a, _b;
1282
- if (layout.columnVisibility)
1283
- applyVisibility(layout.columnVisibility);
1284
- if (layout.columnSizing)
1285
- applySizing(layout.columnSizing);
1286
- if (layout.columnOrder)
1287
- applyColumnOrder(layout.columnOrder);
1288
- if (layout.columnPinning)
1289
- applyPinning(layout.columnPinning);
1290
- if (layout.sorting)
1291
- applySorting(layout.sorting);
1292
- if (layout.pagination && enablePagination)
1293
- applyPagination(layout.pagination);
1294
- if (layout.globalFilter !== undefined)
1295
- applyGlobalFilter(layout.globalFilter);
1296
- if (layout.columnFilter)
1297
- handleColumnFilterChangeHandler(layout.columnFilter, ((_b = (_a = layout.columnFilter) === null || _a === void 0 ? void 0 : _a.filters) === null || _b === void 0 ? void 0 : _b.length) > 0);
1298
- },
1299
- },
1300
- // -------------------------------
1301
- // Table State
1302
- // -------------------------------
1303
- state: {
1304
- getTableState: () => table.getState(),
1305
- getCurrentFilters: () => table.getState().columnFilter,
1306
- getCurrentSorting: () => table.getState().sorting,
1307
- getCurrentPagination: () => table.getState().pagination,
1308
- getCurrentSelection: () => { var _a; return (_a = table.getSelectionState) === null || _a === void 0 ? void 0 : _a.call(table); },
1309
- },
1310
- // -------------------------------
1311
- // Export (unchanged mostly)
1312
- // -------------------------------
1313
- export: {
1314
- exportCSV: async (options = {}) => {
1315
- const { filename = exportFilename, chunkSize = exportChunkSize, strictTotalCheck = exportStrictTotalCheck, sanitizeCSV = exportSanitizeCSV, } = options;
1316
- const mode = dataMode === "server" && !!onServerExport ? 'server' : 'client';
1317
- await runExportWithPolicy({
1318
- format: 'csv',
1319
- filename,
1320
- mode,
1321
- execute: async (controller) => {
1322
- var _a;
1323
- const toStateChange = (state) => {
1324
- const isFinalPhase = state.phase === 'completed' || state.phase === 'cancelled' || state.phase === 'error';
1325
- handleExportStateChangeInternal({
1326
- phase: state.phase,
1327
- mode,
1328
- format: 'csv',
1329
- filename,
1330
- processedRows: state.processedRows,
1331
- totalRows: state.totalRows,
1332
- percentage: state.percentage,
1333
- message: state.message,
1334
- code: state.code,
1335
- startedAt: state.phase === 'starting' ? Date.now() : undefined,
1336
- endedAt: isFinalPhase ? Date.now() : undefined,
1337
- queueLength: queuedExportCount,
1338
- });
1339
- if (state.phase === 'cancelled') {
1340
- onExportCancel === null || onExportCancel === void 0 ? void 0 : onExportCancel();
1341
- }
1342
- };
1343
- if (mode === 'server' && onServerExport) {
1344
- const currentFilters = {
1345
- globalFilter: table.getState().globalFilter,
1346
- columnFilter: table.getState().columnFilter,
1347
- sorting: table.getState().sorting,
1348
- pagination: table.getState().pagination,
1349
- };
1350
- if (logger.isLevelEnabled("debug"))
1351
- logger.debug("Server export CSV", { currentFilters });
1352
- await (0, utils_1.exportServerData)(table, {
1353
- format: "csv",
1354
- filename,
1355
- fetchData: (filters, selection, signal) => onServerExport(filters, selection, signal),
1356
- currentFilters,
1357
- selection: (_a = table.getSelectionState) === null || _a === void 0 ? void 0 : _a.call(table),
1358
- onProgress: handleExportProgressInternal,
1359
- onComplete: onExportComplete,
1360
- onError: onExportError,
1361
- onStateChange: toStateChange,
1362
- signal: controller.signal,
1363
- chunkSize,
1364
- strictTotalCheck,
1365
- sanitizeCSV,
1366
- });
1367
- return;
1368
- }
1369
- await (0, utils_1.exportClientData)(table, {
1370
- format: "csv",
1371
- filename,
1372
- onProgress: handleExportProgressInternal,
1373
- onComplete: onExportComplete,
1374
- onError: onExportError,
1375
- onStateChange: toStateChange,
1376
- signal: controller.signal,
1377
- sanitizeCSV,
1378
- });
1379
- if (logger.isLevelEnabled("debug"))
1380
- logger.debug("Client export CSV", filename);
1381
- }
1382
- });
1383
- },
1384
- exportExcel: async (options = {}) => {
1385
- const { filename = exportFilename, chunkSize = exportChunkSize, strictTotalCheck = exportStrictTotalCheck, sanitizeCSV = exportSanitizeCSV, } = options;
1386
- const mode = dataMode === "server" && !!onServerExport ? 'server' : 'client';
1387
- await runExportWithPolicy({
1388
- format: 'excel',
1389
- filename,
1390
- mode,
1391
- execute: async (controller) => {
1392
- var _a;
1393
- const toStateChange = (state) => {
1394
- const isFinalPhase = state.phase === 'completed' || state.phase === 'cancelled' || state.phase === 'error';
1395
- handleExportStateChangeInternal({
1396
- phase: state.phase,
1397
- mode,
1398
- format: 'excel',
1399
- filename,
1400
- processedRows: state.processedRows,
1401
- totalRows: state.totalRows,
1402
- percentage: state.percentage,
1403
- message: state.message,
1404
- code: state.code,
1405
- startedAt: state.phase === 'starting' ? Date.now() : undefined,
1406
- endedAt: isFinalPhase ? Date.now() : undefined,
1407
- queueLength: queuedExportCount,
1408
- });
1409
- if (state.phase === 'cancelled') {
1410
- onExportCancel === null || onExportCancel === void 0 ? void 0 : onExportCancel();
1411
- }
1412
- };
1413
- if (mode === 'server' && onServerExport) {
1414
- const currentFilters = {
1415
- globalFilter: table.getState().globalFilter,
1416
- columnFilter: table.getState().columnFilter,
1417
- sorting: table.getState().sorting,
1418
- pagination: table.getState().pagination,
1419
- };
1420
- if (logger.isLevelEnabled("debug"))
1421
- logger.debug("Server export Excel", { currentFilters });
1422
- await (0, utils_1.exportServerData)(table, {
1423
- format: "excel",
1424
- filename,
1425
- fetchData: (filters, selection, signal) => onServerExport(filters, selection, signal),
1426
- currentFilters,
1427
- selection: (_a = table.getSelectionState) === null || _a === void 0 ? void 0 : _a.call(table),
1428
- onProgress: handleExportProgressInternal,
1429
- onComplete: onExportComplete,
1430
- onError: onExportError,
1431
- onStateChange: toStateChange,
1432
- signal: controller.signal,
1433
- chunkSize,
1434
- strictTotalCheck,
1435
- sanitizeCSV,
1436
- });
1437
- return;
1438
- }
1439
- await (0, utils_1.exportClientData)(table, {
1440
- format: "excel",
1441
- filename,
1442
- onProgress: handleExportProgressInternal,
1443
- onComplete: onExportComplete,
1444
- onError: onExportError,
1445
- onStateChange: toStateChange,
1446
- signal: controller.signal,
1447
- sanitizeCSV,
1448
- });
1449
- if (logger.isLevelEnabled("debug"))
1450
- logger.debug("Client export Excel", filename);
1451
- }
1452
- });
1453
- },
1454
- exportServerData: async (options) => {
1455
- const { format, filename = exportFilename, fetchData: fetchFn = onServerExport, chunkSize = exportChunkSize, strictTotalCheck = exportStrictTotalCheck, sanitizeCSV = exportSanitizeCSV, } = options;
1456
- if (!fetchFn) {
1457
- onExportError === null || onExportError === void 0 ? void 0 : onExportError({ message: "No server export function provided", code: "NO_SERVER_EXPORT" });
1458
- if (logger.isLevelEnabled("debug"))
1459
- logger.debug("Server export data failed", "No server export function provided");
1460
- return;
1461
- }
1462
- await runExportWithPolicy({
1463
- format,
1464
- filename,
1465
- mode: 'server',
1466
- execute: async (controller) => {
1467
- var _a;
1468
- const currentFilters = {
1469
- globalFilter: table.getState().globalFilter,
1470
- columnFilter: table.getState().columnFilter,
1471
- sorting: table.getState().sorting,
1472
- pagination: table.getState().pagination,
1473
- };
1474
- if (logger.isLevelEnabled("debug"))
1475
- logger.debug("Server export data", { currentFilters });
1476
- await (0, utils_1.exportServerData)(table, {
1477
- format,
1478
- filename,
1479
- fetchData: (filters, selection, signal) => fetchFn(filters, selection, signal),
1480
- currentFilters,
1481
- selection: (_a = table.getSelectionState) === null || _a === void 0 ? void 0 : _a.call(table),
1482
- onProgress: handleExportProgressInternal,
1483
- onComplete: onExportComplete,
1484
- onError: onExportError,
1485
- onStateChange: (state) => {
1486
- const isFinalPhase = state.phase === 'completed' || state.phase === 'cancelled' || state.phase === 'error';
1487
- handleExportStateChangeInternal({
1488
- phase: state.phase,
1489
- mode: 'server',
1490
- format,
1491
- filename,
1492
- processedRows: state.processedRows,
1493
- totalRows: state.totalRows,
1494
- percentage: state.percentage,
1495
- message: state.message,
1496
- code: state.code,
1497
- startedAt: state.phase === 'starting' ? Date.now() : undefined,
1498
- endedAt: isFinalPhase ? Date.now() : undefined,
1499
- queueLength: queuedExportCount,
1500
- });
1501
- if (state.phase === 'cancelled') {
1502
- onExportCancel === null || onExportCancel === void 0 ? void 0 : onExportCancel();
1503
- }
1504
- },
1505
- signal: controller.signal,
1506
- chunkSize,
1507
- strictTotalCheck,
1508
- sanitizeCSV,
1509
- });
1510
- }
1511
- });
1512
- },
1513
- isExporting: () => isExporting || false,
1514
- cancelExport: () => {
1515
- const activeController = exportControllerRef.current;
1516
- if (!activeController) {
1517
- return;
1518
- }
1519
- activeController.abort();
1520
- setExportControllerSafely((current) => (current === activeController ? null : current));
1521
- if (logger.isLevelEnabled("debug"))
1522
- logger.debug("Export cancelled");
1523
- },
1524
- },
1525
- };
1526
- }, [
1527
- table,
1528
- enhancedColumns,
1529
- handleColumnOrderChange,
1530
- handleColumnPinningChange,
1531
- handleColumnVisibilityChange,
1532
- handleColumnSizingChange,
1533
- handlePaginationChange,
1534
- handleSortingChange,
1535
- handleGlobalFilterChange,
1536
- handleColumnFilterChangeHandler,
1537
- initialStateConfig,
1538
- enablePagination,
1539
- idKey,
1540
- triggerRefresh,
1541
- applyDataMutation,
1542
- tableData,
1543
- selectionState,
1544
- // export
1545
- exportFilename,
1546
- exportChunkSize,
1547
- exportStrictTotalCheck,
1548
- exportSanitizeCSV,
1549
- onExportComplete,
1550
- onExportError,
1551
- onExportCancel,
1552
- onServerExport,
1553
- queuedExportCount,
1554
- isExporting,
1555
- dataMode,
1556
- handleExportProgressInternal,
1557
- handleExportStateChangeInternal,
1558
- runExportWithPolicy,
1559
- setExportControllerSafely,
1560
- logger,
1561
- resetAllAndReload,
1562
- ]);
1563
- internalApiRef.current = dataTableApi;
1564
- (0, react_1.useImperativeHandle)(ref, () => dataTableApi, [dataTableApi]);
1565
- // -------------------------------
1566
- // Render table rows with slot support (callback)
1567
- // -------------------------------
1568
- const renderTableRows = (0, react_1.useCallback)(() => {
1569
- var _a, _b, _c, _d;
1570
- if (tableLoading) {
1571
- const { component: LoadingRowComponent, props: loadingRowProps } = (0, slot_helpers_1.getSlotComponentWithProps)(slots, slotProps || {}, 'loadingRow', rows_1.LoadingRows, {});
1572
- return ((0, jsx_runtime_1.jsx)(LoadingRowComponent, { rowCount: enablePagination ? Math.min(pagination.pageSize, skeletonRows) : skeletonRows, colSpan: table.getAllColumns().length, slots: slots, slotProps: slotProps, ...loadingRowProps }));
1573
- }
1574
- if (rows.length === 0) {
1575
- const { component: EmptyRowComponent, props: emptyRowProps } = (0, slot_helpers_1.getSlotComponentWithProps)(slots, slotProps || {}, 'emptyRow', rows_1.EmptyDataRow, {});
1576
- return ((0, jsx_runtime_1.jsx)(EmptyRowComponent, { colSpan: table.getAllColumns().length, message: emptyMessage, slots: slots, slotProps: slotProps, ...emptyRowProps }));
1577
- }
1578
- if (enableVirtualization && !enablePagination && rows.length > 0) {
1579
- const virtualItems = rowVirtualizer.getVirtualItems();
1580
- return ((0, jsx_runtime_1.jsxs)(jsx_runtime_1.Fragment, { children: [virtualItems.length > 0 && ((0, jsx_runtime_1.jsx)("tr", { children: (0, jsx_runtime_1.jsx)("td", { colSpan: table.getAllColumns().length, style: {
1581
- height: `${(_b = (_a = virtualItems[0]) === null || _a === void 0 ? void 0 : _a.start) !== null && _b !== void 0 ? _b : 0}px`,
1582
- padding: 0,
1583
- border: 0,
1584
- } }) })), virtualItems.map((virtualRow) => {
1585
- const row = rows[virtualRow.index];
1586
- if (!row)
1587
- return null;
1588
- return ((0, jsx_runtime_1.jsx)(rows_1.DataTableRow, { row: row, enableHover: enableHover, enableStripes: enableStripes, isOdd: virtualRow.index % 2 === 1, renderSubComponent: renderSubComponent, disableStickyHeader: enableStickyHeaderOrFooter, onRowClick: onRowClick, selectOnRowClick: selectOnRowClick, slots: slots, slotProps: slotProps }, row.id));
1589
- }), virtualItems.length > 0 && ((0, jsx_runtime_1.jsx)("tr", { children: (0, jsx_runtime_1.jsx)("td", { colSpan: table.getAllColumns().length, style: {
1590
- height: `${rowVirtualizer.getTotalSize() -
1591
- ((_d = (_c = virtualItems[virtualItems.length - 1]) === null || _c === void 0 ? void 0 : _c.end) !== null && _d !== void 0 ? _d : 0)}px`,
1592
- padding: 0,
1593
- border: 0,
1594
- } }) }))] }));
1595
- }
1596
- return rows.map((row, index) => ((0, jsx_runtime_1.jsx)(rows_1.DataTableRow, { row: row, enableHover: enableHover, enableStripes: enableStripes, isOdd: index % 2 === 1, renderSubComponent: renderSubComponent, disableStickyHeader: enableStickyHeaderOrFooter, onRowClick: onRowClick, selectOnRowClick: selectOnRowClick, slots: slots, slotProps: slotProps }, row.id)));
1597
- }, [
1598
- tableLoading,
1599
- rows,
1600
- enableVirtualization,
1601
- enablePagination,
1602
- pagination.pageSize,
1603
- skeletonRows,
1604
- table,
1605
- slotProps,
1606
- emptyMessage,
1607
- rowVirtualizer,
1608
- enableHover,
1609
- enableStripes,
1610
- renderSubComponent,
1611
- enableStickyHeaderOrFooter,
1612
- onRowClick,
1613
- selectOnRowClick,
1614
- slots,
1615
- ]);
1616
- // -------------------------------
1617
- // Export cancel callback
1618
- // -------------------------------
1619
- const handleCancelExport = (0, react_1.useCallback)(() => {
1620
- const activeController = exportControllerRef.current;
1621
- if (activeController) {
1622
- activeController.abort();
1623
- setExportControllerSafely((current) => (current === activeController ? null : current));
1624
- }
1625
- }, [setExportControllerSafely]);
1626
- // -------------------------------
1627
- // Slot components
1628
- // -------------------------------
1629
- const { component: RootComponent, props: rootSlotProps } = (0, slot_helpers_1.getSlotComponentWithProps)(slots, slotProps || {}, 'root', material_1.Box, {});
1630
- const { component: ToolbarComponent, props: toolbarSlotProps } = (0, slot_helpers_1.getSlotComponentWithProps)(slots, slotProps || {}, 'toolbar', toolbar_1.DataTableToolbar, {});
1631
- const { component: BulkActionsComponent, props: bulkActionsSlotProps } = (0, slot_helpers_1.getSlotComponentWithProps)(slots, slotProps || {}, 'bulkActionsToolbar', toolbar_1.BulkActionsToolbar, {});
1632
- const { component: TableContainerComponent, props: tableContainerSlotProps } = (0, slot_helpers_1.getSlotComponentWithProps)(slots, slotProps || {}, 'tableContainer', material_1.TableContainer, {});
1633
- const { component: TableComponent, props: tableComponentSlotProps } = (0, slot_helpers_1.getSlotComponentWithProps)(slots, slotProps || {}, 'table', material_1.Table, {});
1634
- const { component: BodyComponent, props: bodySlotProps } = (0, slot_helpers_1.getSlotComponentWithProps)(slots, slotProps || {}, 'body', material_1.TableBody, {});
1635
- const { component: FooterComponent, props: footerSlotProps } = (0, slot_helpers_1.getSlotComponentWithProps)(slots, slotProps || {}, 'footer', material_1.Box, {});
1636
- const { component: PaginationComponent, props: paginationSlotProps } = (0, slot_helpers_1.getSlotComponentWithProps)(slots, slotProps || {}, 'pagination', pagination_1.DataTablePagination, {});
1637
- // -------------------------------
1638
- // Render
1639
- // -------------------------------
1640
- return ((0, jsx_runtime_1.jsx)(data_table_context_1.DataTableProvider, { table: table, apiRef: internalApiRef, dataMode: dataMode, tableSize: tableSize, onTableSizeChange: (size) => {
1641
- setTableSize(size);
1642
- }, columnFilter: columnFilter, onChangeColumnFilter: handleColumnFilterChangeHandler, slots: slots, slotProps: slotProps, isExporting: isExporting, exportController: exportController, exportPhase: exportPhase, exportProgress: exportProgress, onCancelExport: handleCancelExport, exportFilename: exportFilename, onExportProgress: onExportProgress, onExportComplete: onExportComplete, onExportError: onExportError, onServerExport: onServerExport, children: (0, jsx_runtime_1.jsxs)(RootComponent, { ...rootSlotProps, children: [(enableGlobalFilter || extraFilter) ? ((0, jsx_runtime_1.jsx)(ToolbarComponent, { extraFilter: extraFilter, enableGlobalFilter: enableGlobalFilter, enableColumnVisibility: enableColumnVisibility, enableColumnFilter: enableColumnFilter, enableExport: enableExport, enableReset: enableReset, enableTableSizeControl: enableTableSizeControl, enableColumnPinning: enableColumnPinning, enableRefresh: enableRefresh, ...toolbarSlotProps, refreshButtonProps: {
1643
- loading: tableLoading, // disable while fetching
1644
- showSpinnerWhileLoading: false,
1645
- onRefresh: () => { var _a, _b, _c; return (_c = (_b = (_a = internalApiRef.current) === null || _a === void 0 ? void 0 : _a.data) === null || _b === void 0 ? void 0 : _b.refresh) === null || _c === void 0 ? void 0 : _c.call(_b, true); },
1646
- ...toolbarSlotProps.refreshButtonProps,
1647
- } })) : null, enableBulkActions && enableRowSelection && isSomeRowsSelected ? ((0, jsx_runtime_1.jsx)(BulkActionsComponent, { selectionState: selectionState, selectedRowCount: selectedRowCount, bulkActions: bulkActions, sx: {
1648
- position: 'relative',
1649
- zIndex: 2,
1650
- ...bulkActionsSlotProps.sx,
1651
- }, ...bulkActionsSlotProps })) : null, (0, jsx_runtime_1.jsx)(TableContainerComponent, { component: material_1.Paper, ref: tableContainerRef, sx: {
1652
- width: '100%',
1653
- overflowX: 'auto',
1654
- ...(enableStickyHeaderOrFooter && {
1655
- maxHeight: maxHeight,
1656
- overflowY: 'auto',
1657
- }),
1658
- ...(enableVirtualization && {
1659
- maxHeight: maxHeight,
1660
- overflowY: 'auto',
1661
- }),
1662
- ...tableContainerSlotProps === null || tableContainerSlotProps === void 0 ? void 0 : tableContainerSlotProps.sx,
1663
- }, ...tableContainerSlotProps, children: (0, jsx_runtime_1.jsxs)(TableComponent, { size: tableSize, stickyHeader: enableStickyHeaderOrFooter, style: {
1664
- ...tableStyle,
1665
- ...tableProps === null || tableProps === void 0 ? void 0 : tableProps.style,
1666
- }, ...(0, slot_helpers_1.mergeSlotProps)(tableProps || {}, tableComponentSlotProps), children: [useFixedLayout ? ((0, jsx_runtime_1.jsx)("colgroup", { children: visibleLeafColumns.map((column) => ((0, jsx_runtime_1.jsx)("col", { style: {
1667
- width: column.getSize(),
1668
- minWidth: column.columnDef.minSize,
1669
- maxWidth: column.columnDef.maxSize,
1670
- } }, column.id))) })) : null, (0, jsx_runtime_1.jsx)(headers_1.TableHeader, { draggable: enableColumnDragging, enableColumnResizing: enableColumnResizing, enableStickyHeader: enableStickyHeaderOrFooter, onColumnReorder: handleColumnReorder, slots: slots, slotProps: slotProps }), (0, jsx_runtime_1.jsx)(BodyComponent, { ...bodySlotProps, children: renderTableRows() })] }) }), enablePagination ? ((0, jsx_runtime_1.jsx)(FooterComponent, { sx: {
1671
- ...(enableStickyHeaderOrFooter && {
1672
- position: 'sticky',
1673
- bottom: 0,
1674
- backgroundColor: 'background.paper',
1675
- borderTop: '1px solid',
1676
- borderColor: 'divider',
1677
- zIndex: 1,
1678
- }),
1679
- ...footerSlotProps.sx,
1680
- }, ...footerSlotProps, children: (0, jsx_runtime_1.jsx)(PaginationComponent, { footerFilter: footerFilter, pagination: pagination, totalRow: tableTotalRow, ...paginationSlotProps }) })) : null] }) }));
46
+ const use_data_table_engine_1 = require("./hooks/use-data-table-engine");
47
+ const data_table_view_1 = require("./components/data-table-view");
48
+ exports.DataTable = (0, react_1.forwardRef)(function DataTable(props, ref) {
49
+ const engine = (0, use_data_table_engine_1.useDataTableEngine)(props);
50
+ (0, react_1.useImperativeHandle)(ref, () => engine.refs.apiRef.current, []);
51
+ return ((0, jsx_runtime_1.jsx)(data_table_context_1.DataTableProvider, { ...engine.providerProps, children: (0, jsx_runtime_1.jsx)(data_table_view_1.DataTableView, { engine: engine, ...props }) }));
1681
52
  });