@ackplus/react-tanstack-data-table 1.1.11 → 1.1.13

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 (61) hide show
  1. package/README.md +143 -11
  2. package/dist/lib/components/droupdown/menu-dropdown.d.ts.map +1 -1
  3. package/dist/lib/components/droupdown/menu-dropdown.js +8 -1
  4. package/dist/lib/components/filters/filter-value-input.js +2 -2
  5. package/dist/lib/components/pagination/data-table-pagination.d.ts.map +1 -1
  6. package/dist/lib/components/pagination/data-table-pagination.js +10 -1
  7. package/dist/lib/components/toolbar/data-table-toolbar.d.ts.map +1 -1
  8. package/dist/lib/components/toolbar/data-table-toolbar.js +5 -2
  9. package/dist/lib/components/toolbar/table-export-control.d.ts.map +1 -1
  10. package/dist/lib/components/toolbar/table-export-control.js +46 -12
  11. package/dist/lib/components/toolbar/table-refresh-control.d.ts +15 -0
  12. package/dist/lib/components/toolbar/table-refresh-control.d.ts.map +1 -0
  13. package/dist/lib/components/toolbar/table-refresh-control.js +61 -0
  14. package/dist/lib/contexts/data-table-context.d.ts +7 -10
  15. package/dist/lib/contexts/data-table-context.d.ts.map +1 -1
  16. package/dist/lib/contexts/data-table-context.js +5 -1
  17. package/dist/lib/data-table.d.ts.map +1 -1
  18. package/dist/lib/data-table.js +1110 -946
  19. package/dist/lib/features/column-filter.feature.js +38 -21
  20. package/dist/lib/features/selection.feature.d.ts.map +1 -1
  21. package/dist/lib/features/selection.feature.js +11 -3
  22. package/dist/lib/types/column.types.d.ts +19 -0
  23. package/dist/lib/types/column.types.d.ts.map +1 -1
  24. package/dist/lib/types/data-table-api.d.ts +25 -18
  25. package/dist/lib/types/data-table-api.d.ts.map +1 -1
  26. package/dist/lib/types/data-table.types.d.ts +37 -10
  27. package/dist/lib/types/data-table.types.d.ts.map +1 -1
  28. package/dist/lib/types/export.types.d.ts +57 -13
  29. package/dist/lib/types/export.types.d.ts.map +1 -1
  30. package/dist/lib/types/slots.types.d.ts +12 -1
  31. package/dist/lib/types/slots.types.d.ts.map +1 -1
  32. package/dist/lib/types/table.types.d.ts +1 -3
  33. package/dist/lib/types/table.types.d.ts.map +1 -1
  34. package/dist/lib/utils/debounced-fetch.utils.d.ts +8 -4
  35. package/dist/lib/utils/debounced-fetch.utils.d.ts.map +1 -1
  36. package/dist/lib/utils/debounced-fetch.utils.js +63 -14
  37. package/dist/lib/utils/export-utils.d.ts +14 -4
  38. package/dist/lib/utils/export-utils.d.ts.map +1 -1
  39. package/dist/lib/utils/export-utils.js +362 -66
  40. package/dist/lib/utils/slot-helpers.d.ts +1 -1
  41. package/dist/lib/utils/slot-helpers.d.ts.map +1 -1
  42. package/package.json +4 -2
  43. package/src/lib/components/droupdown/menu-dropdown.tsx +9 -3
  44. package/src/lib/components/filters/filter-value-input.tsx +2 -2
  45. package/src/lib/components/pagination/data-table-pagination.tsx +14 -2
  46. package/src/lib/components/toolbar/data-table-toolbar.tsx +15 -1
  47. package/src/lib/components/toolbar/table-export-control.tsx +65 -9
  48. package/src/lib/components/toolbar/table-refresh-control.tsx +58 -0
  49. package/src/lib/contexts/data-table-context.tsx +16 -2
  50. package/src/lib/data-table.tsx +1282 -932
  51. package/src/lib/features/column-filter.feature.ts +40 -19
  52. package/src/lib/features/selection.feature.ts +11 -5
  53. package/src/lib/types/column.types.ts +20 -1
  54. package/src/lib/types/data-table-api.ts +37 -15
  55. package/src/lib/types/data-table.types.ts +59 -3
  56. package/src/lib/types/export.types.ts +79 -10
  57. package/src/lib/types/slots.types.ts +11 -1
  58. package/src/lib/types/table.types.ts +1 -3
  59. package/src/lib/utils/debounced-fetch.utils.ts +90 -18
  60. package/src/lib/utils/export-utils.ts +496 -69
  61. package/src/lib/utils/slot-helpers.tsx +1 -1
@@ -1,53 +1,125 @@
1
1
  import { useCallback, useEffect, useRef, useState } from 'react';
2
2
 
3
- import { TableFiltersForFetch } from '../types';
3
+ import { DataFetchMeta, TableFilters } from '../types';
4
4
 
5
5
  const DEFAULT_DEBOUNCE_DELAY = 300;
6
6
 
7
- interface useDebouncedFetchReturn<T extends Record<string, any>> {
8
- debouncedFetch: (filters: TableFiltersForFetch, debounceDelay?: number) => Promise<{ data: T[]; total: number }>;
7
+ interface DebouncedFetchOptions {
8
+ debounceDelay?: number;
9
+ meta?: DataFetchMeta;
10
+ }
11
+
12
+ interface useDebouncedFetchReturn<T extends Record<string, any>> {
13
+ debouncedFetch: (
14
+ filters: Partial<TableFilters>,
15
+ optionsOrDelay?: number | DebouncedFetchOptions
16
+ ) => Promise<{ data: T[]; total: number } | null>;
9
17
  isLoading: boolean;
10
18
  }
11
19
 
20
+ interface PendingRequest<T extends Record<string, any>> {
21
+ id: number;
22
+ resolve: (value: { data: T[]; total: number } | null) => void;
23
+ reject: (reason?: unknown) => void;
24
+ }
25
+
12
26
  export function useDebouncedFetch<T extends Record<string, any>>(
13
- onFetchData: ((filters: TableFiltersForFetch) => Promise<{ data: T[]; total: number }>) | undefined
27
+ onFetchData: ((
28
+ filters: Partial<TableFilters>,
29
+ meta?: DataFetchMeta
30
+ ) => Promise<{ data: T[]; total: number }>) | undefined
14
31
  ): useDebouncedFetchReturn<T> {
15
32
  const [isLoading, setIsLoading] = useState(false);
16
33
  const debounceTimer = useRef<ReturnType<typeof setTimeout> | null>(null);
34
+ const pendingRequestRef = useRef<PendingRequest<T> | null>(null);
35
+ const latestRequestIdRef = useRef(0);
36
+ const activeRequestCountRef = useRef(0);
37
+ const isMountedRef = useRef(true);
17
38
 
18
- const debouncedFetch = useCallback(async (filters: TableFiltersForFetch, debounceDelay = DEFAULT_DEBOUNCE_DELAY) => {
39
+ const resetLoadingIfIdle = useCallback(() => {
40
+ if (!isMountedRef.current) return;
41
+ if (!debounceTimer.current && !pendingRequestRef.current && activeRequestCountRef.current === 0) {
42
+ setIsLoading(false);
43
+ }
44
+ }, []);
45
+
46
+ const debouncedFetch = useCallback(async (
47
+ filters: Partial<TableFilters>,
48
+ optionsOrDelay: number | DebouncedFetchOptions = DEFAULT_DEBOUNCE_DELAY
49
+ ) => {
19
50
  if (!onFetchData) return null;
20
51
 
21
- // Create a unique key for the current fetch parameters
22
- // const currentParams = JSON.stringify(filters);
23
- // Clear existing timer
52
+ const options = typeof optionsOrDelay === 'number'
53
+ ? { debounceDelay: optionsOrDelay }
54
+ : optionsOrDelay;
55
+ const debounceDelay = options.debounceDelay ?? DEFAULT_DEBOUNCE_DELAY;
56
+ const requestId = latestRequestIdRef.current + 1;
57
+ latestRequestIdRef.current = requestId;
58
+
59
+ // Clear existing timer and resolve pending debounced request.
24
60
  if (debounceTimer.current) {
25
61
  clearTimeout(debounceTimer.current);
62
+ debounceTimer.current = null;
26
63
  }
64
+ if (pendingRequestRef.current) {
65
+ pendingRequestRef.current.resolve(null);
66
+ pendingRequestRef.current = null;
67
+ }
68
+
69
+ setIsLoading(true);
70
+
71
+ return new Promise<{ data: T[]; total: number } | null>((resolve, reject) => {
72
+ pendingRequestRef.current = {
73
+ id: requestId,
74
+ resolve,
75
+ reject,
76
+ };
27
77
 
28
- return new Promise<{ data: T[]; total: number } | null>((resolve) => {
29
78
  debounceTimer.current = setTimeout(async () => {
30
- setIsLoading(true);
79
+ const pendingRequest = pendingRequestRef.current;
80
+ if (!pendingRequest || pendingRequest.id !== requestId) {
81
+ return;
82
+ }
83
+
84
+ pendingRequestRef.current = null;
85
+ debounceTimer.current = null;
86
+ activeRequestCountRef.current += 1;
87
+
31
88
  try {
32
- const result = await onFetchData(filters);
33
- resolve(result);
89
+ const result = await onFetchData(filters, options.meta);
90
+
91
+ // Ignore stale responses if a newer request was queued.
92
+ if (requestId === latestRequestIdRef.current) {
93
+ resolve(result);
94
+ } else {
95
+ resolve(null);
96
+ }
34
97
  } catch (error) {
35
- // Handle fetch error silently or could be passed to onError callback
36
- console.error('Error fetching data:', error);
37
- resolve(null);
98
+ if (requestId === latestRequestIdRef.current) {
99
+ reject(error);
100
+ } else {
101
+ resolve(null);
102
+ }
38
103
  } finally {
39
- setIsLoading(false);
104
+ activeRequestCountRef.current = Math.max(0, activeRequestCountRef.current - 1);
105
+ resetLoadingIfIdle();
40
106
  }
41
107
  }, debounceDelay);
42
108
  });
43
- }, [onFetchData]);
109
+ }, [onFetchData, resetLoadingIfIdle]);
44
110
 
45
111
  // Cleanup timer on unmount
46
112
  useEffect(() => {
47
- // Fetch data when dependencies change
113
+ isMountedRef.current = true;
48
114
  return () => {
115
+ isMountedRef.current = false;
49
116
  if (debounceTimer.current) {
50
117
  clearTimeout(debounceTimer.current);
118
+ debounceTimer.current = null;
119
+ }
120
+ if (pendingRequestRef.current) {
121
+ pendingRequestRef.current.resolve(null);
122
+ pendingRequestRef.current = null;
51
123
  }
52
124
  };
53
125
  }, []);