@ackplus/react-tanstack-data-table 1.1.19 → 1.1.21

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 (63) hide show
  1. package/dist/lib/hooks/use-data-table-engine.d.ts.map +1 -1
  2. package/dist/lib/hooks/use-data-table-engine.js +54 -15
  3. package/dist/lib/types/data-table.types.d.ts +2 -1
  4. package/dist/lib/types/data-table.types.d.ts.map +1 -1
  5. package/package.json +3 -4
  6. package/src/index.ts +0 -75
  7. package/src/lib/components/data-table-view.tsx +0 -386
  8. package/src/lib/components/droupdown/menu-dropdown.tsx +0 -103
  9. package/src/lib/components/filters/filter-value-input.tsx +0 -225
  10. package/src/lib/components/filters/index.ts +0 -126
  11. package/src/lib/components/headers/draggable-header.tsx +0 -326
  12. package/src/lib/components/headers/index.ts +0 -6
  13. package/src/lib/components/headers/table-header.tsx +0 -175
  14. package/src/lib/components/index.ts +0 -21
  15. package/src/lib/components/pagination/data-table-pagination.tsx +0 -111
  16. package/src/lib/components/pagination/index.ts +0 -5
  17. package/src/lib/components/rows/data-table-row.tsx +0 -218
  18. package/src/lib/components/rows/empty-data-row.tsx +0 -69
  19. package/src/lib/components/rows/index.ts +0 -7
  20. package/src/lib/components/rows/loading-rows.tsx +0 -164
  21. package/src/lib/components/toolbar/bulk-actions-toolbar.tsx +0 -125
  22. package/src/lib/components/toolbar/column-filter-control.tsx +0 -432
  23. package/src/lib/components/toolbar/column-pinning-control.tsx +0 -275
  24. package/src/lib/components/toolbar/column-reset-control.tsx +0 -74
  25. package/src/lib/components/toolbar/column-visibility-control.tsx +0 -105
  26. package/src/lib/components/toolbar/data-table-toolbar.tsx +0 -257
  27. package/src/lib/components/toolbar/index.ts +0 -17
  28. package/src/lib/components/toolbar/table-export-control.tsx +0 -233
  29. package/src/lib/components/toolbar/table-refresh-control.tsx +0 -62
  30. package/src/lib/components/toolbar/table-search-control.tsx +0 -155
  31. package/src/lib/components/toolbar/table-size-control.tsx +0 -102
  32. package/src/lib/contexts/data-table-context.tsx +0 -126
  33. package/src/lib/data-table.tsx +0 -29
  34. package/src/lib/features/README.md +0 -161
  35. package/src/lib/features/column-filter.feature.ts +0 -493
  36. package/src/lib/features/index.ts +0 -23
  37. package/src/lib/features/selection.feature.ts +0 -322
  38. package/src/lib/hooks/index.ts +0 -2
  39. package/src/lib/hooks/use-data-table-engine.ts +0 -1516
  40. package/src/lib/icons/add-icon.tsx +0 -23
  41. package/src/lib/icons/csv-icon.tsx +0 -15
  42. package/src/lib/icons/delete-icon.tsx +0 -30
  43. package/src/lib/icons/excel-icon.tsx +0 -15
  44. package/src/lib/icons/index.ts +0 -7
  45. package/src/lib/icons/unpin-icon.tsx +0 -18
  46. package/src/lib/icons/view-comfortable-icon.tsx +0 -45
  47. package/src/lib/icons/view-compact-icon.tsx +0 -55
  48. package/src/lib/types/column.types.ts +0 -63
  49. package/src/lib/types/data-table-api.ts +0 -191
  50. package/src/lib/types/data-table.types.ts +0 -192
  51. package/src/lib/types/export.types.ts +0 -223
  52. package/src/lib/types/index.ts +0 -24
  53. package/src/lib/types/slots.types.ts +0 -342
  54. package/src/lib/types/table.types.ts +0 -88
  55. package/src/lib/utils/column-helpers.ts +0 -72
  56. package/src/lib/utils/debounced-fetch.utils.ts +0 -131
  57. package/src/lib/utils/export-utils.ts +0 -712
  58. package/src/lib/utils/index.ts +0 -27
  59. package/src/lib/utils/logger.ts +0 -203
  60. package/src/lib/utils/slot-helpers.tsx +0 -194
  61. package/src/lib/utils/special-columns.utils.ts +0 -101
  62. package/src/lib/utils/styling-helpers.ts +0 -126
  63. package/src/lib/utils/table-helpers.ts +0 -106
@@ -1,493 +0,0 @@
1
- /**
2
- * Custom Column Filter Feature for TanStack Table
3
- *
4
- * This feature adds advanced column filtering capabilities to TanStack Table
5
- * following the official custom features pattern introduced in v8.14.0
6
- */
7
- import {
8
- Table,
9
- TableFeature,
10
- RowData,
11
- Updater,
12
- functionalUpdate,
13
- makeStateUpdater,
14
- RowModel,
15
- Row,
16
- getFilteredRowModel as getDefaultFilter,
17
- } from '@tanstack/react-table';
18
-
19
- // Import from types to avoid circular dependency
20
- import type { ColumnFilterState } from '../types/table.types';
21
- import moment from 'moment';
22
-
23
- // Types for the custom column filter feature
24
- export interface ColumnFilterRule {
25
- id: string;
26
- columnId: string;
27
- operator: string;
28
- value: any;
29
- columnType?: string;
30
- }
31
-
32
- export interface ColumnFilterOptions {
33
- enableAdvanceColumnFilter?: boolean;
34
- onColumnFilterChange?: (updater: Updater<ColumnFilterState>) => void;
35
- // Add callback for when filters are applied
36
- onColumnFilterApply?: (state: ColumnFilterState) => void;
37
- }
38
-
39
- // Declaration merging to extend TanStack Table types
40
- declare module '@tanstack/react-table' {
41
- interface TableState {
42
- columnFilter: ColumnFilterState;
43
- }
44
- // eslint-disable-next-line @typescript-eslint/no-unused-vars
45
- interface TableOptionsResolved<TData extends RowData> {
46
- enableAdvanceColumnFilter?: boolean;
47
- onColumnFilterChange?: (updater: Updater<ColumnFilterState>) => void;
48
- onColumnFilterApply?: (state: ColumnFilterState) => void;
49
- }
50
- // eslint-disable-next-line @typescript-eslint/no-unused-vars
51
- interface Table<TData extends RowData> {
52
- setColumnFilterState: (updater: Updater<ColumnFilterState> | ColumnFilterState) => void;
53
-
54
- // Pending filter methods (for draft state)
55
- addPendingColumnFilter: (columnId: string, operator: string, value: any) => void;
56
- updatePendingColumnFilter: (filterId: string, updates: Partial<ColumnFilterRule>) => void;
57
- removePendingColumnFilter: (filterId: string) => void;
58
- clearAllPendingColumnFilters: () => void;
59
- setPendingFilterLogic: (logic: 'AND' | 'OR') => void;
60
-
61
- // Apply pending filters to active filters
62
- applyPendingColumnFilters: () => void;
63
- resetColumnFilter: () => void;
64
-
65
- // Legacy methods (for backward compatibility)
66
- addColumnFilter: (columnId: string, operator: string, value: any) => void;
67
- updateColumnFilter: (filterId: string, updates: Partial<ColumnFilterRule>) => void;
68
- removeColumnFilter: (filterId: string) => void;
69
- clearAllColumnFilters: () => void;
70
- setFilterLogic: (logic: 'AND' | 'OR') => void;
71
-
72
- // Getters
73
- getActiveColumnFilters: () => ColumnFilterRule[];
74
- getPendingColumnFilters: () => ColumnFilterRule[];
75
- getColumnFilterState: () => ColumnFilterState;
76
- }
77
- }
78
-
79
- // Table instance methods for custom column filtering
80
- // export interface ColumnFilterInstance<TData extends RowData> {
81
- // setColumnFilterState: (updater: Updater<ColumnFilterState>) => void;
82
-
83
- // // Pending filter methods (for draft state)
84
- // addPendingColumnFilter: (columnId: string, operator: string, value: any) => void;
85
- // updatePendingColumnFilter: (filterId: string, updates: Partial<ColumnFilterRule>) => void;
86
- // removePendingColumnFilter: (filterId: string) => void;
87
- // clearAllPendingColumnFilters: () => void;
88
- // setPendingFilterLogic: (logic: 'AND' | 'OR') => void;
89
-
90
- // // Apply pending filters to active filters
91
- // applyPendingColumnFilters: () => void;
92
-
93
- // // Legacy methods (for backward compatibility)
94
- // addColumnFilter: (columnId: string, operator: string, value: any) => void;
95
- // updateColumnFilter: (filterId: string, updates: Partial<ColumnFilterRule>) => void;
96
- // removeColumnFilter: (filterId: string) => void;
97
- // clearAllColumnFilters: () => void;
98
- // setFilterLogic: (logic: 'AND' | 'OR') => void;
99
-
100
- // // Getters
101
- // getActiveColumnFilters: () => ColumnFilterRule[];
102
- // getPendingColumnFilters: () => ColumnFilterRule[];
103
- // getColumnFilterState: () => ColumnFilterState;
104
- // }
105
-
106
- // The custom feature implementation
107
- export const ColumnFilterFeature: TableFeature<any> = {
108
- // Define the feature's initial state
109
- getInitialState: (state): { columnFilter: ColumnFilterState } => {
110
- return {
111
- columnFilter: {
112
- filters: [],
113
- logic: 'AND',
114
- pendingFilters: [],
115
- pendingLogic: 'AND',
116
- },
117
- ...state,
118
- };
119
- },
120
-
121
- // Define the feature's default options
122
- getDefaultOptions: <TData extends RowData>(
123
- table: Table<TData>
124
- ): ColumnFilterOptions => {
125
- return {
126
- enableAdvanceColumnFilter: true,
127
- onColumnFilterChange: makeStateUpdater('columnFilter', table),
128
- onColumnFilterApply: () => {
129
- // Implementation of onColumnFilterApply
130
- },
131
- } as ColumnFilterOptions;
132
- },
133
-
134
- // Define the feature's table instance methods
135
- createTable: <TData extends RowData>(table: Table<TData>): void => {
136
- table.setColumnFilterState = (updater) => {
137
- if (!table.options.enableAdvanceColumnFilter) return;
138
- const safeUpdater: Updater<ColumnFilterState> = (old) => {
139
- const newState = functionalUpdate(updater, old);
140
- return newState;
141
- };
142
- return table.options.onColumnFilterChange?.(safeUpdater);
143
- };
144
-
145
- // === PENDING FILTER METHODS (Draft state) ===
146
- table.addPendingColumnFilter = (columnId: string, operator: string, value: any) => {
147
- if (!table.options.enableAdvanceColumnFilter) return;
148
- table.setColumnFilterState((old) => {
149
- const newFilter: ColumnFilterRule = {
150
- id: `filter_${Date.now()}_${Math.random().toString(36).substring(2, 9)}`,
151
- columnId,
152
- operator,
153
- value,
154
- };
155
- return {
156
- ...old,
157
- pendingFilters: [...old.pendingFilters, newFilter],
158
- };
159
- });
160
- };
161
-
162
- table.updatePendingColumnFilter = (filterId: string, updates: Partial<ColumnFilterRule>) => {
163
- if (!table.options.enableAdvanceColumnFilter) return;
164
- table.setColumnFilterState((old) => {
165
- const updatedFilters = old.pendingFilters.map((filter) =>
166
- filter.id === filterId ? { ...filter, ...updates } : filter
167
- );
168
- return {
169
- ...old,
170
- pendingFilters: updatedFilters,
171
- };
172
- });
173
- };
174
-
175
- table.removePendingColumnFilter = (filterId: string) => {
176
- if (!table.options.enableAdvanceColumnFilter) return;
177
- table.setColumnFilterState((old) => ({
178
- ...old,
179
- pendingFilters: old.pendingFilters.filter((filter) => filter.id !== filterId),
180
- }));
181
- };
182
-
183
- table.clearAllPendingColumnFilters = () => {
184
- if (!table.options.enableAdvanceColumnFilter) return;
185
- table.setColumnFilterState((old) => ({
186
- ...old,
187
- pendingFilters: [],
188
- }));
189
- };
190
-
191
- table.resetColumnFilter = () => {
192
- if (!table.options.enableAdvanceColumnFilter) return;
193
- const newState: ColumnFilterState = {
194
- pendingFilters: [],
195
- pendingLogic: 'AND',
196
- filters: [],
197
- logic: 'AND',
198
- };
199
- table.setColumnFilterState(newState);
200
- // Notify engine so it can reset pagination and refetch (server mode)
201
- table.options.onColumnFilterApply?.(newState);
202
- };
203
-
204
- table.setPendingFilterLogic = (logic: 'AND' | 'OR') => {
205
- if (!table.options.enableAdvanceColumnFilter) return;
206
- table.setColumnFilterState((old) => ({
207
- ...old,
208
- pendingLogic: logic,
209
- }));
210
- };
211
-
212
- // === APPLY PENDING FILTERS ===
213
- table.applyPendingColumnFilters = () => {
214
- if (!table.options.enableAdvanceColumnFilter) return;
215
- table.setColumnFilterState((old) => {
216
- const newState = {
217
- ...old,
218
- filters: [...old.pendingFilters],
219
- logic: old.pendingLogic,
220
- };
221
-
222
- // Call the apply callback after state update
223
- setTimeout(() => {
224
- table.options.onColumnFilterApply?.(newState);
225
- }, 0);
226
-
227
- return newState;
228
- });
229
- };
230
-
231
- // === LEGACY METHODS (for backward compatibility) ===
232
- table.addColumnFilter = (columnId: string, operator: string, value: any) => {
233
- if (!table.options.enableAdvanceColumnFilter) return;
234
- // For backward compatibility, add directly to active filters
235
- table.setColumnFilterState((old) => {
236
- const newFilter: ColumnFilterRule = {
237
- id: `filter_${Date.now()}_${Math.random().toString(36).substring(2, 9)}`,
238
- columnId,
239
- operator,
240
- value,
241
- };
242
- return {
243
- ...old,
244
- filters: [...old.filters, newFilter],
245
- };
246
- });
247
- };
248
-
249
- table.updateColumnFilter = (filterId: string, updates: Partial<ColumnFilterRule>) => {
250
- if (!table.options.enableAdvanceColumnFilter) return;
251
- table.setColumnFilterState((old) => {
252
- const updatedFilters = old.filters.map((filter) =>
253
- filter.id === filterId ? { ...filter, ...updates } : filter
254
- );
255
- return {
256
- ...old,
257
- filters: updatedFilters,
258
- };
259
- });
260
- };
261
-
262
- table.removeColumnFilter = (filterId: string) => {
263
- if (!table.options.enableAdvanceColumnFilter) return;
264
- table.setColumnFilterState((old) => ({
265
- ...old,
266
- filters: old.filters.filter((filter) => filter.id !== filterId),
267
- }));
268
- };
269
-
270
- table.clearAllColumnFilters = () => {
271
- if (!table.options.enableAdvanceColumnFilter) return;
272
- table.setColumnFilterState((old) => ({
273
- ...old,
274
- filters: [],
275
- }));
276
- };
277
-
278
- table.setFilterLogic = (logic: 'AND' | 'OR') => {
279
- if (!table.options.enableAdvanceColumnFilter) return;
280
- table.setColumnFilterState((old) => ({
281
- ...old,
282
- logic,
283
- }));
284
- };
285
-
286
- // === GETTERS ===
287
- table.getActiveColumnFilters = () => {
288
- const state = table.getState().columnFilter;
289
- return state.filters.filter((f) => f.columnId && f.operator);
290
- };
291
-
292
- table.getPendingColumnFilters = () => {
293
- const state = table.getState().columnFilter;
294
- return state.pendingFilters.filter((f) => f.columnId && f.operator);
295
- };
296
-
297
- table.getColumnFilterState = () => {
298
- return table.getState().columnFilter;
299
- };
300
- },
301
- };
302
-
303
- /**
304
- * Utility function to check if a row matches the custom column filters
305
- * This can be used for client-side filtering
306
- */
307
- export function matchesCustomColumnFilters(
308
- row: any,
309
- filters: ColumnFilterRule[],
310
- logic: 'AND' | 'OR' = 'AND'
311
- ): boolean {
312
- if (filters.length === 0) return true;
313
-
314
- const activeFilters = filters.filter((f) => f.columnId && f.operator);
315
- if (activeFilters.length === 0) return true;
316
-
317
- const results = activeFilters.map((filter) => {
318
- let columnValue;
319
- let columnType = filter.columnType || 'text';
320
- try {
321
- // Try to get the value safely to avoid infinite loops
322
- const column = row.getAllCells().find((cell: any) => cell.column.id === filter.columnId);
323
- if (column) {
324
- columnValue = column.getValue();
325
- // Try to get type from columnDef if not set
326
- if (!filter.columnType && column.column.columnDef && column.column.columnDef.type) {
327
- columnType = column.column.columnDef.type;
328
- }
329
- }
330
- } catch (error) {
331
- console.warn(`Error getting value for column ${filter.columnId}:`, error);
332
- columnValue = row.original?.[filter.columnId] || '';
333
- }
334
- return evaluateFilterCondition(columnValue, filter.operator, filter.value, columnType);
335
- });
336
-
337
- return logic === 'AND' ? results.every(Boolean) : results.some(Boolean);
338
- }
339
-
340
- export const getCombinedFilteredRowModel = <TData,>() => {
341
- return (table: Table<TData>) => (): RowModel<TData> => {
342
- // Respect server/manual filtering: skip client filtering when manualFiltering is enabled
343
- if (table.options.manualFiltering) {
344
- return table.getCoreRowModel();
345
- }
346
-
347
- // Run the built-in global + column filters first:
348
- const baseFilteredModel = getDefaultFilter<TData>()(table)();
349
-
350
- const { filters, logic } = table.getState().columnFilter ?? {
351
- filters: [],
352
- logic: 'AND',
353
- };
354
-
355
- if (!filters.length || !table.options.enableAdvanceColumnFilter) {
356
- return baseFilteredModel;
357
- }
358
-
359
- // Apply custom column filters to pre-filtered rows
360
- const filteredRows = baseFilteredModel.rows.filter(row =>
361
- matchesCustomColumnFilters(row, filters, logic)
362
- );
363
-
364
- const flatRows: Row<TData>[] = [];
365
- const rowsById: Record<string, Row<TData>> = {};
366
-
367
- const addRow = (row: Row<TData>) => {
368
- flatRows.push(row);
369
- rowsById[row.id] = row;
370
- row.subRows?.forEach(addRow);
371
- };
372
-
373
- filteredRows.forEach(addRow);
374
-
375
- return {
376
- rows: filteredRows,
377
- flatRows,
378
- rowsById,
379
- };
380
- };
381
- };
382
-
383
- /**
384
- * Evaluate a single filter condition
385
- */
386
- function evaluateFilterCondition(columnValue: any, operator: string, filterValue: any, type: string = 'text'): boolean {
387
- // --- Date helpers using moment ---
388
- function toMoment(val: any) {
389
- if (!val) return null;
390
- const m = moment(val);
391
- return m.isValid() ? m : null;
392
- }
393
-
394
- // --- Date type logic ---
395
- if (type === 'date') {
396
- if (operator === 'isEmpty') {
397
- return columnValue === null || columnValue === undefined || columnValue === '';
398
- }
399
- if (operator === 'isNotEmpty') {
400
- return columnValue !== null && columnValue !== undefined && columnValue !== '';
401
- }
402
-
403
- const mCol = columnValue ? toMoment(columnValue) : null;
404
- const mFilter = filterValue ? toMoment(filterValue) : null;
405
- if (!mCol || !mFilter || !mCol.isValid() || !mFilter.isValid()) return false;
406
- switch (operator) {
407
- case 'equals':
408
- return mCol.isSame(mFilter, 'day');
409
- case 'notEquals':
410
- return !mCol.isSame(mFilter, 'day');
411
- case 'after':
412
- return mCol.isAfter(mFilter, 'day');
413
- case 'before':
414
- return mCol.isBefore(mFilter, 'day');
415
- default:
416
- return true;
417
- }
418
- }
419
-
420
- // --- Boolean type logic ---
421
- if (type === 'boolean') {
422
- switch (operator) {
423
- case 'is':
424
- if (filterValue === 'any') return true;
425
- if (filterValue === 'true') return (columnValue === true || columnValue === 'true' || columnValue === 1 || columnValue === '1' || columnValue === 'Yes' || columnValue === 'yes');
426
- if (filterValue === 'false') return (columnValue === false || columnValue === 'false' || columnValue === 0 || columnValue === '0' || columnValue === 'No' || columnValue === 'no');
427
- return false;
428
-
429
- default:
430
- return true;
431
- }
432
- }
433
-
434
- // --- Select type logic (in, notIn, single select) ---
435
- if (type === 'select') {
436
- if (operator === 'in' || operator === 'notIn') {
437
- const values = Array.isArray(filterValue)
438
- ? filterValue
439
- : [filterValue].filter((value) => value !== undefined && value !== null && value !== '');
440
-
441
- if (values.length === 0) {
442
- return operator === 'notIn';
443
- }
444
-
445
- if (operator === 'in') return values.includes(columnValue);
446
- if (operator === 'notIn') return !values.includes(columnValue);
447
- }
448
- if (operator === 'equals' || operator === 'notEquals') {
449
- return operator === 'equals'
450
- ? columnValue === filterValue
451
- : columnValue !== filterValue;
452
- }
453
- }
454
-
455
- // --- Text/Number type logic ---
456
- if (type === 'number') {
457
- switch (operator) {
458
- case 'equals':
459
- return Number(columnValue) === Number(filterValue);
460
- case 'notEquals':
461
- return Number(columnValue) !== Number(filterValue);
462
- case 'greaterThan':
463
- return Number(columnValue) > Number(filterValue);
464
- case 'greaterThanOrEqual':
465
- return Number(columnValue) >= Number(filterValue);
466
- case 'lessThan':
467
- return Number(columnValue) < Number(filterValue);
468
- case 'lessThanOrEqual':
469
- return Number(columnValue) <= Number(filterValue);
470
- }
471
- }
472
-
473
- switch (operator) {
474
- case 'contains':
475
- return String(columnValue).toLowerCase().includes(String(filterValue).toLowerCase());
476
- case 'notContains':
477
- return !String(columnValue).toLowerCase().includes(String(filterValue).toLowerCase());
478
- case 'startsWith':
479
- return String(columnValue).toLowerCase().startsWith(String(filterValue).toLowerCase());
480
- case 'endsWith':
481
- return String(columnValue).toLowerCase().endsWith(String(filterValue).toLowerCase());
482
- case 'equals':
483
- return columnValue === filterValue;
484
- case 'notEquals':
485
- return columnValue !== filterValue;
486
- case 'isEmpty':
487
- return columnValue === null || columnValue === undefined || columnValue === '';
488
- case 'isNotEmpty':
489
- return columnValue !== null && columnValue !== undefined && columnValue !== '';
490
- default:
491
- return true;
492
- }
493
- }
@@ -1,23 +0,0 @@
1
- /**
2
- * Custom TanStack Table Features
3
- *
4
- * This module exports custom features that extend TanStack Table functionality
5
- * following the official custom features pattern introduced in v8.14.0
6
- */
7
-
8
- export {
9
- ColumnFilterFeature,
10
- matchesCustomColumnFilters,
11
- type ColumnFilterRule,
12
- type ColumnFilterOptions,
13
- } from './column-filter.feature';
14
-
15
- // Export custom selection feature
16
- export {
17
- SelectionFeature,
18
- type SelectionState,
19
- type SelectMode,
20
- type SelectionOptions,
21
- type SelectionTableState,
22
- type SelectionInstance,
23
- } from './selection.feature';