@ackplus/react-tanstack-data-table 1.0.35 → 1.1.1

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 (272) hide show
  1. package/LICENSE +21 -0
  2. package/{src → dist}/index.d.ts +21 -4
  3. package/dist/index.d.ts.map +1 -0
  4. package/dist/index.js +63 -0
  5. package/{src → dist}/lib/components/droupdown/menu-dropdown.d.ts +2 -1
  6. package/dist/lib/components/droupdown/menu-dropdown.d.ts.map +1 -0
  7. package/{src → dist}/lib/components/droupdown/menu-dropdown.js +38 -7
  8. package/{src → dist}/lib/components/filters/filter-value-input.d.ts +3 -1
  9. package/dist/lib/components/filters/filter-value-input.d.ts.map +1 -0
  10. package/dist/lib/components/filters/filter-value-input.js +83 -0
  11. package/{src → dist}/lib/components/filters/index.d.ts +1 -0
  12. package/dist/lib/components/filters/index.d.ts.map +1 -0
  13. package/dist/lib/components/filters/index.js +142 -0
  14. package/{src → dist}/lib/components/headers/draggable-header.d.ts +2 -2
  15. package/dist/lib/components/headers/draggable-header.d.ts.map +1 -0
  16. package/{src → dist}/lib/components/headers/draggable-header.js +81 -17
  17. package/dist/lib/components/headers/index.d.ts +6 -0
  18. package/dist/lib/components/headers/index.d.ts.map +1 -0
  19. package/dist/lib/components/headers/index.js +21 -0
  20. package/{src → dist}/lib/components/headers/table-header.d.ts +15 -1
  21. package/dist/lib/components/headers/table-header.d.ts.map +1 -0
  22. package/{src → dist}/lib/components/headers/table-header.js +50 -17
  23. package/{src → dist}/lib/components/index.d.ts +6 -1
  24. package/dist/lib/components/index.d.ts.map +1 -0
  25. package/dist/lib/components/index.js +32 -0
  26. package/{src → dist}/lib/components/pagination/data-table-pagination.d.ts +2 -1
  27. package/dist/lib/components/pagination/data-table-pagination.d.ts.map +1 -0
  28. package/{src → dist}/lib/components/pagination/data-table-pagination.js +20 -6
  29. package/dist/lib/components/pagination/index.d.ts +5 -0
  30. package/dist/lib/components/pagination/index.d.ts.map +1 -0
  31. package/dist/lib/components/pagination/index.js +20 -0
  32. package/{src → dist}/lib/components/rows/data-table-row.d.ts +15 -2
  33. package/dist/lib/components/rows/data-table-row.d.ts.map +1 -0
  34. package/{src → dist}/lib/components/rows/data-table-row.js +58 -25
  35. package/{src → dist}/lib/components/rows/empty-data-row.d.ts +3 -3
  36. package/dist/lib/components/rows/empty-data-row.d.ts.map +1 -0
  37. package/{src → dist}/lib/components/rows/empty-data-row.js +12 -4
  38. package/dist/lib/components/rows/index.d.ts +7 -0
  39. package/dist/lib/components/rows/index.d.ts.map +1 -0
  40. package/dist/lib/components/rows/index.js +22 -0
  41. package/{src → dist}/lib/components/rows/loading-rows.d.ts +3 -1
  42. package/dist/lib/components/rows/loading-rows.d.ts.map +1 -0
  43. package/{src → dist}/lib/components/rows/loading-rows.js +27 -19
  44. package/{src → dist}/lib/components/toolbar/bulk-actions-toolbar.d.ts +4 -3
  45. package/dist/lib/components/toolbar/bulk-actions-toolbar.d.ts.map +1 -0
  46. package/dist/lib/components/toolbar/bulk-actions-toolbar.js +49 -0
  47. package/{src → dist}/lib/components/toolbar/column-filter-control.d.ts +3 -1
  48. package/dist/lib/components/toolbar/column-filter-control.d.ts.map +1 -0
  49. package/{src → dist}/lib/components/toolbar/column-filter-control.js +73 -4
  50. package/{src → dist}/lib/components/toolbar/column-pinning-control.d.ts +2 -1
  51. package/dist/lib/components/toolbar/column-pinning-control.d.ts.map +1 -0
  52. package/{src → dist}/lib/components/toolbar/column-pinning-control.js +70 -6
  53. package/{src → dist}/lib/components/toolbar/column-reset-control.d.ts +3 -1
  54. package/dist/lib/components/toolbar/column-reset-control.d.ts.map +1 -0
  55. package/{src → dist}/lib/components/toolbar/column-reset-control.js +9 -2
  56. package/{src → dist}/lib/components/toolbar/column-visibility-control.d.ts +2 -1
  57. package/dist/lib/components/toolbar/column-visibility-control.d.ts.map +1 -0
  58. package/dist/lib/components/toolbar/column-visibility-control.js +77 -0
  59. package/{src → dist}/lib/components/toolbar/data-table-toolbar.d.ts +3 -2
  60. package/dist/lib/components/toolbar/data-table-toolbar.d.ts.map +1 -0
  61. package/{src → dist}/lib/components/toolbar/data-table-toolbar.js +17 -4
  62. package/{src → dist}/lib/components/toolbar/index.d.ts +4 -0
  63. package/dist/lib/components/toolbar/index.d.ts.map +1 -0
  64. package/{src → dist}/lib/components/toolbar/index.js +6 -0
  65. package/dist/lib/components/toolbar/table-export-control.d.ts +12 -0
  66. package/dist/lib/components/toolbar/table-export-control.d.ts.map +1 -0
  67. package/dist/lib/components/toolbar/table-export-control.js +67 -0
  68. package/{src → dist}/lib/components/toolbar/table-search-control.d.ts +3 -1
  69. package/dist/lib/components/toolbar/table-search-control.d.ts.map +1 -0
  70. package/{src → dist}/lib/components/toolbar/table-search-control.js +45 -2
  71. package/{src → dist}/lib/components/toolbar/table-size-control.d.ts +3 -1
  72. package/dist/lib/components/toolbar/table-size-control.d.ts.map +1 -0
  73. package/{src → dist}/lib/components/toolbar/table-size-control.js +20 -8
  74. package/{src → dist}/lib/contexts/data-table-context.d.ts +6 -2
  75. package/dist/lib/contexts/data-table-context.d.ts.map +1 -0
  76. package/{src → dist}/lib/contexts/data-table-context.js +34 -1
  77. package/dist/lib/data-table.d.ts +5 -0
  78. package/dist/lib/data-table.d.ts.map +1 -0
  79. package/{src/lib/components/table → dist/lib}/data-table.js +427 -143
  80. package/dist/lib/features/column-filter.feature.d.ts +55 -0
  81. package/dist/lib/features/column-filter.feature.d.ts.map +1 -0
  82. package/{src → dist}/lib/features/column-filter.feature.js +116 -18
  83. package/dist/lib/features/index.d.ts +9 -0
  84. package/dist/lib/features/index.d.ts.map +1 -0
  85. package/{src → dist}/lib/features/index.js +7 -0
  86. package/{src → dist}/lib/features/selection.feature.d.ts +8 -1
  87. package/dist/lib/features/selection.feature.d.ts.map +1 -0
  88. package/{src → dist}/lib/features/selection.feature.js +76 -15
  89. package/dist/lib/icons/add-icon.d.ts +4 -0
  90. package/dist/lib/icons/add-icon.d.ts.map +1 -0
  91. package/dist/lib/icons/add-icon.js +12 -0
  92. package/dist/lib/icons/csv-icon.d.ts +4 -0
  93. package/dist/lib/icons/csv-icon.d.ts.map +1 -0
  94. package/dist/lib/icons/csv-icon.js +12 -0
  95. package/dist/lib/icons/delete-icon.d.ts +4 -0
  96. package/dist/lib/icons/delete-icon.d.ts.map +1 -0
  97. package/dist/lib/icons/delete-icon.js +12 -0
  98. package/dist/lib/icons/excel-icon.d.ts +4 -0
  99. package/dist/lib/icons/excel-icon.d.ts.map +1 -0
  100. package/dist/lib/icons/excel-icon.js +12 -0
  101. package/dist/lib/icons/index.d.ts +8 -0
  102. package/dist/lib/icons/index.d.ts.map +1 -0
  103. package/dist/lib/icons/unpin-icon.d.ts +4 -0
  104. package/dist/lib/icons/unpin-icon.d.ts.map +1 -0
  105. package/dist/lib/icons/unpin-icon.js +12 -0
  106. package/{src → dist}/lib/icons/view-comfortable-icon.d.ts +3 -1
  107. package/dist/lib/icons/view-comfortable-icon.d.ts.map +1 -0
  108. package/dist/lib/icons/view-comfortable-icon.js +12 -0
  109. package/dist/lib/icons/view-compact-icon.d.ts +4 -0
  110. package/dist/lib/icons/view-compact-icon.d.ts.map +1 -0
  111. package/dist/lib/icons/view-compact-icon.js +12 -0
  112. package/{src → dist}/lib/types/column.types.d.ts +10 -1
  113. package/dist/lib/types/column.types.d.ts.map +1 -0
  114. package/{src → dist}/lib/types/data-table-api.d.ts +2 -1
  115. package/dist/lib/types/data-table-api.d.ts.map +1 -0
  116. package/{src/lib/components/table → dist/lib/types}/data-table.types.d.ts +10 -10
  117. package/dist/lib/types/data-table.types.d.ts.map +1 -0
  118. package/{src → dist}/lib/types/export.types.d.ts +38 -0
  119. package/dist/lib/types/export.types.d.ts.map +1 -0
  120. package/dist/lib/types/export.types.js +6 -0
  121. package/{src → dist}/lib/types/index.d.ts +5 -0
  122. package/dist/lib/types/index.d.ts.map +1 -0
  123. package/dist/lib/types/index.js +30 -0
  124. package/{src → dist}/lib/types/slots.types.d.ts +50 -3
  125. package/dist/lib/types/slots.types.d.ts.map +1 -0
  126. package/{src → dist}/lib/types/table.types.d.ts +14 -0
  127. package/dist/lib/types/table.types.d.ts.map +1 -0
  128. package/{src → dist}/lib/utils/column-helpers.d.ts +10 -0
  129. package/dist/lib/utils/column-helpers.d.ts.map +1 -0
  130. package/{src → dist}/lib/utils/column-helpers.js +20 -4
  131. package/{src → dist}/lib/utils/debounced-fetch.utils.d.ts +3 -5
  132. package/dist/lib/utils/debounced-fetch.utils.d.ts.map +1 -0
  133. package/{src → dist}/lib/utils/debounced-fetch.utils.js +12 -6
  134. package/{src → dist}/lib/utils/export-utils.d.ts +13 -0
  135. package/dist/lib/utils/export-utils.d.ts.map +1 -0
  136. package/dist/lib/utils/export-utils.js +252 -0
  137. package/{src → dist}/lib/utils/index.d.ts +4 -0
  138. package/dist/lib/utils/index.d.ts.map +1 -0
  139. package/dist/lib/utils/index.js +35 -0
  140. package/{src → dist}/lib/utils/logger.d.ts +43 -0
  141. package/dist/lib/utils/logger.d.ts.map +1 -0
  142. package/{src → dist}/lib/utils/logger.js +22 -2
  143. package/{src → dist}/lib/utils/slot-helpers.d.ts +39 -1
  144. package/dist/lib/utils/slot-helpers.d.ts.map +1 -0
  145. package/{src → dist}/lib/utils/slot-helpers.js +55 -6
  146. package/{src → dist}/lib/utils/special-columns.utils.d.ts +10 -0
  147. package/dist/lib/utils/special-columns.utils.d.ts.map +1 -0
  148. package/{src → dist}/lib/utils/special-columns.utils.js +41 -5
  149. package/{src → dist}/lib/utils/styling-helpers.d.ts +20 -0
  150. package/dist/lib/utils/styling-helpers.d.ts.map +1 -0
  151. package/dist/lib/utils/styling-helpers.js +108 -0
  152. package/{src → dist}/lib/utils/table-helpers.d.ts +25 -0
  153. package/dist/lib/utils/table-helpers.d.ts.map +1 -0
  154. package/{src → dist}/lib/utils/table-helpers.js +24 -0
  155. package/package.json +36 -11
  156. package/src/index.ts +71 -0
  157. package/src/lib/components/droupdown/menu-dropdown.tsx +97 -0
  158. package/src/lib/components/filters/filter-value-input.tsx +225 -0
  159. package/src/lib/components/filters/{index.js → index.ts} +3 -6
  160. package/src/lib/components/headers/draggable-header.tsx +326 -0
  161. package/src/lib/components/headers/{index.d.ts → index.ts} +4 -0
  162. package/src/lib/components/headers/table-header.tsx +173 -0
  163. package/src/lib/components/index.ts +21 -0
  164. package/src/lib/components/pagination/data-table-pagination.tsx +99 -0
  165. package/src/lib/components/pagination/index.ts +5 -0
  166. package/src/lib/components/rows/data-table-row.tsx +208 -0
  167. package/src/lib/components/rows/empty-data-row.tsx +69 -0
  168. package/src/lib/components/rows/{index.d.ts → index.ts} +4 -0
  169. package/src/lib/components/rows/loading-rows.tsx +160 -0
  170. package/src/lib/components/toolbar/bulk-actions-toolbar.tsx +125 -0
  171. package/src/lib/components/toolbar/column-filter-control.tsx +374 -0
  172. package/src/lib/components/toolbar/column-pinning-control.tsx +275 -0
  173. package/src/lib/components/toolbar/column-reset-control.tsx +74 -0
  174. package/src/lib/components/toolbar/column-visibility-control.tsx +105 -0
  175. package/src/lib/components/toolbar/data-table-toolbar.tsx +229 -0
  176. package/src/lib/components/toolbar/index.ts +17 -0
  177. package/src/lib/components/toolbar/table-export-control.tsx +179 -0
  178. package/src/lib/components/toolbar/table-search-control.tsx +155 -0
  179. package/src/lib/components/toolbar/table-size-control.tsx +102 -0
  180. package/src/lib/contexts/data-table-context.tsx +112 -0
  181. package/src/lib/data-table.tsx +1911 -0
  182. package/src/lib/features/README.md +161 -0
  183. package/src/lib/features/column-filter.feature.ts +456 -0
  184. package/src/lib/features/index.ts +23 -0
  185. package/src/lib/features/selection.feature.ts +318 -0
  186. package/src/lib/icons/add-icon.tsx +23 -0
  187. package/src/lib/icons/csv-icon.tsx +15 -0
  188. package/src/lib/icons/delete-icon.tsx +30 -0
  189. package/src/lib/icons/excel-icon.tsx +15 -0
  190. package/src/lib/icons/unpin-icon.tsx +18 -0
  191. package/src/lib/icons/view-comfortable-icon.tsx +45 -0
  192. package/src/lib/icons/view-compact-icon.tsx +55 -0
  193. package/src/lib/types/column.types.ts +44 -0
  194. package/src/lib/types/data-table-api.ts +169 -0
  195. package/src/lib/types/data-table.types.ts +139 -0
  196. package/src/lib/types/export.types.ts +154 -0
  197. package/src/lib/types/index.ts +22 -0
  198. package/src/lib/types/slots.types.ts +332 -0
  199. package/src/lib/types/table.types.ts +90 -0
  200. package/src/lib/utils/column-helpers.ts +72 -0
  201. package/src/lib/utils/debounced-fetch.utils.ts +54 -0
  202. package/src/lib/utils/export-utils.ts +285 -0
  203. package/src/lib/utils/index.ts +27 -0
  204. package/src/lib/utils/logger.ts +203 -0
  205. package/src/lib/utils/slot-helpers.tsx +194 -0
  206. package/src/lib/utils/special-columns.utils.ts +94 -0
  207. package/src/lib/utils/styling-helpers.ts +126 -0
  208. package/src/lib/utils/table-helpers.ts +106 -0
  209. package/src/index.js +0 -27
  210. package/src/lib/components/filters/filter-value-input.js +0 -41
  211. package/src/lib/components/headers/index.js +0 -5
  212. package/src/lib/components/index.js +0 -10
  213. package/src/lib/components/pagination/index.d.ts +0 -1
  214. package/src/lib/components/pagination/index.js +0 -4
  215. package/src/lib/components/rows/index.js +0 -6
  216. package/src/lib/components/table/data-table.d.ts +0 -4
  217. package/src/lib/components/table/index.d.ts +0 -2
  218. package/src/lib/components/table/index.js +0 -5
  219. package/src/lib/components/toolbar/bulk-actions-toolbar.js +0 -30
  220. package/src/lib/components/toolbar/column-visibility-control.js +0 -31
  221. package/src/lib/components/toolbar/table-export-control.d.ts +0 -31
  222. package/src/lib/components/toolbar/table-export-control.js +0 -56
  223. package/src/lib/examples/advanced-features-example.d.ts +0 -1
  224. package/src/lib/examples/advanced-features-example.js +0 -269
  225. package/src/lib/examples/bulk-actions-test.d.ts +0 -1
  226. package/src/lib/examples/bulk-actions-test.js +0 -44
  227. package/src/lib/examples/custom-column-filter-example.d.ts +0 -1
  228. package/src/lib/examples/custom-column-filter-example.js +0 -60
  229. package/src/lib/examples/index.d.ts +0 -8
  230. package/src/lib/examples/index.js +0 -19
  231. package/src/lib/examples/selection-test-example.d.ts +0 -1
  232. package/src/lib/examples/selection-test-example.js +0 -101
  233. package/src/lib/examples/server-side-fetching-example.d.ts +0 -1
  234. package/src/lib/examples/server-side-fetching-example.js +0 -245
  235. package/src/lib/examples/server-side-test.d.ts +0 -1
  236. package/src/lib/examples/server-side-test.js +0 -9
  237. package/src/lib/examples/simple-local-example.d.ts +0 -1
  238. package/src/lib/examples/simple-local-example.js +0 -95
  239. package/src/lib/examples/simple-slots-example.d.ts +0 -1
  240. package/src/lib/examples/simple-slots-example.js +0 -115
  241. package/src/lib/features/column-filter.feature.d.ts +0 -45
  242. package/src/lib/features/index.d.ts +0 -2
  243. package/src/lib/hooks/index.d.ts +0 -1
  244. package/src/lib/hooks/index.js +0 -4
  245. package/src/lib/hooks/use-data-table-api.d.ts +0 -46
  246. package/src/lib/hooks/use-data-table-api.js +0 -690
  247. package/src/lib/icons/add-icon.d.ts +0 -2
  248. package/src/lib/icons/add-icon.js +0 -8
  249. package/src/lib/icons/csv-icon.d.ts +0 -2
  250. package/src/lib/icons/csv-icon.js +0 -8
  251. package/src/lib/icons/delete-icon.d.ts +0 -2
  252. package/src/lib/icons/delete-icon.js +0 -8
  253. package/src/lib/icons/excel-icon.d.ts +0 -2
  254. package/src/lib/icons/excel-icon.js +0 -8
  255. package/src/lib/icons/unpin-icon.d.ts +0 -2
  256. package/src/lib/icons/unpin-icon.js +0 -8
  257. package/src/lib/icons/view-comfortable-icon.js +0 -8
  258. package/src/lib/icons/view-compact-icon.d.ts +0 -2
  259. package/src/lib/icons/view-compact-icon.js +0 -8
  260. package/src/lib/types/export.types.js +0 -2
  261. package/src/lib/types/index.js +0 -8
  262. package/src/lib/utils/export-utils.js +0 -175
  263. package/src/lib/utils/index.js +0 -11
  264. package/src/lib/utils/styling-helpers.js +0 -70
  265. package/tsconfig.tsbuildinfo +0 -1
  266. /package/{src → dist}/lib/icons/index.js +0 -0
  267. /package/{src → dist}/lib/types/column.types.js +0 -0
  268. /package/{src → dist}/lib/types/data-table-api.js +0 -0
  269. /package/{src/lib/components/table → dist/lib/types}/data-table.types.js +0 -0
  270. /package/{src → dist}/lib/types/slots.types.js +0 -0
  271. /package/{src → dist}/lib/types/table.types.js +0 -0
  272. /package/src/lib/icons/{index.d.ts → index.ts} +0 -0
@@ -0,0 +1,160 @@
1
+ import React, { ReactElement } from 'react';
2
+ import { TableCell, TableRow, Skeleton, TableRowProps, TableCellProps, SxProps } from '@mui/material';
3
+
4
+ import { useDataTableContext } from '../../contexts/data-table-context';
5
+ import { getPinnedColumnStyle } from '../../utils';
6
+ import { getSlotComponent, mergeSlotProps, extractSlotProps } from '../../utils/slot-helpers';
7
+
8
+ export interface LoadingRowsProps {
9
+ rowCount?: number;
10
+ // Enhanced customization props
11
+ rowProps?: TableRowProps;
12
+ cellProps?: TableCellProps;
13
+ skeletonProps?: any;
14
+ containerSx?: SxProps;
15
+ slots?: Record<string, any>;
16
+ slotProps?: Record<string, any>;
17
+ [key: string]: any;
18
+ }
19
+
20
+ export function LoadingRows(props: LoadingRowsProps): ReactElement {
21
+ const {
22
+ rowCount = 5,
23
+ rowProps,
24
+ cellProps,
25
+ skeletonProps,
26
+ containerSx,
27
+ slots,
28
+ slotProps,
29
+ } = props;
30
+
31
+ const { table } = useDataTableContext();
32
+ const visibleColumns = table.getVisibleLeafColumns();
33
+
34
+ // Extract slot-specific props with enhanced merging
35
+ const cellSlotProps = extractSlotProps(slotProps, 'cell');
36
+ const rowSlotProps = extractSlotProps(slotProps, 'row');
37
+
38
+ const CellSlot = getSlotComponent(slots, 'cell', TableCell);
39
+ const TableRowSlot = getSlotComponent(slots, 'row', TableRow);
40
+
41
+ // Merge all props for maximum flexibility
42
+ const mergedRowProps = mergeSlotProps(
43
+ {
44
+ sx: containerSx,
45
+ },
46
+ rowSlotProps,
47
+ rowProps || {}
48
+ );
49
+
50
+ return (
51
+ <>
52
+ {Array.from({ length: rowCount }, (_, rowIndex) => (
53
+ <TableRowSlot
54
+ key={`skeleton-row-${rowIndex}`}
55
+ {...mergedRowProps}
56
+ >
57
+ {visibleColumns.map((column: any, colIndex: number) => {
58
+ const isPinned = column.getIsPinned();
59
+ const pinnedPosition = isPinned ? column.getStart('left') : undefined;
60
+ const pinnedRightPosition = isPinned === 'right' ? column.getAfter('right') : undefined;
61
+
62
+ // Determine skeleton type based on column meta or content
63
+ const columnMeta = column.columnDef?.meta;
64
+ const isDateColumn = columnMeta?.type === 'date';
65
+ const isBooleanColumn = columnMeta?.type === 'boolean';
66
+ const isNumberColumn = columnMeta?.type === 'number';
67
+ const isSelectionColumn = column.id === 'select';
68
+
69
+ const mergedCellProps = mergeSlotProps(
70
+ {
71
+ sx: {
72
+ ...getPinnedColumnStyle({
73
+ width: column.getSize() || 'auto',
74
+ isPinned,
75
+ pinnedPosition,
76
+ pinnedRightPosition,
77
+ zIndex: isPinned ? 9 : 1,
78
+ isLastLeftPinnedColumn: isPinned === 'left' && column.getIsLastColumn('left'),
79
+ isFirstRightPinnedColumn: isPinned === 'right' && column.getIsFirstColumn('right'),
80
+ }),
81
+ },
82
+ },
83
+ cellSlotProps,
84
+ cellProps || {}
85
+ );
86
+
87
+ const getSkeletonContent = () => {
88
+ if (isSelectionColumn) {
89
+ return (
90
+ <Skeleton
91
+ variant="rectangular"
92
+ width={20}
93
+ height={20}
94
+ animation="wave"
95
+ {...skeletonProps}
96
+ />
97
+ );
98
+ }
99
+
100
+ if (isBooleanColumn) {
101
+ return (
102
+ <Skeleton
103
+ variant="circular"
104
+ width={16}
105
+ height={16}
106
+ animation="wave"
107
+ {...skeletonProps}
108
+ />
109
+ );
110
+ }
111
+
112
+ if (isDateColumn) {
113
+ return (
114
+ <Skeleton
115
+ variant="text"
116
+ width="80%"
117
+ height={20}
118
+ animation="wave"
119
+ {...skeletonProps}
120
+ />
121
+ );
122
+ }
123
+
124
+ if (isNumberColumn) {
125
+ return (
126
+ <Skeleton
127
+ variant="text"
128
+ width="60%"
129
+ height={20}
130
+ animation="wave"
131
+ {...skeletonProps}
132
+ />
133
+ );
134
+ }
135
+
136
+ return (
137
+ <Skeleton
138
+ variant="text"
139
+ width={`${Math.random() * 40 + 60}%`}
140
+ height={20}
141
+ animation="wave"
142
+ {...skeletonProps}
143
+ />
144
+ );
145
+ };
146
+
147
+ return (
148
+ <CellSlot
149
+ key={`skeleton-${column.id || colIndex}-${rowIndex}`}
150
+ {...mergedCellProps}
151
+ >
152
+ {getSkeletonContent()}
153
+ </CellSlot>
154
+ );
155
+ })}
156
+ </TableRowSlot>
157
+ ))}
158
+ </>
159
+ );
160
+ }
@@ -0,0 +1,125 @@
1
+ import {
2
+ Box,
3
+ Toolbar,
4
+ Typography,
5
+ Chip,
6
+ Fade,
7
+ alpha,
8
+ Theme,
9
+ ToolbarProps,
10
+ SxProps,
11
+ } from '@mui/material';
12
+ import { ReactNode, useMemo, ReactElement } from 'react';
13
+
14
+ import { useDataTableContext } from '../../contexts/data-table-context';
15
+ import { getSlotComponent, mergeSlotProps, extractSlotProps } from '../../utils/slot-helpers';
16
+ import { SelectionState } from '../../features';
17
+
18
+ export interface BulkActionsToolbarProps extends ToolbarProps {
19
+ selectionState: SelectionState;
20
+ selectedRowCount: number;
21
+ bulkActions?: (selectionState: SelectionState) => ReactNode;
22
+ // Enhanced customization props
23
+ chipProps?: any;
24
+ containerSx?: SxProps;
25
+ leftSectionSx?: SxProps;
26
+ rightSectionSx?: SxProps;
27
+ fadeProps?: any;
28
+ [key: string]: any;
29
+ }
30
+
31
+ export function BulkActionsToolbar(props: BulkActionsToolbarProps): ReactElement {
32
+ const {
33
+ selectionState,
34
+ selectedRowCount,
35
+ bulkActions,
36
+ chipProps,
37
+ containerSx,
38
+ leftSectionSx,
39
+ rightSectionSx,
40
+ fadeProps,
41
+ sx,
42
+ ...otherProps
43
+ } = props;
44
+
45
+ const { slots, slotProps } = useDataTableContext();
46
+
47
+ // Extract slot-specific props with enhanced merging
48
+ const toolbarSlotProps = extractSlotProps(slotProps, 'bulkActionsToolbar');
49
+ const ToolbarSlot = getSlotComponent(slots, 'bulkActionsToolbar', Toolbar);
50
+
51
+ // Memoize the bulk actions rendering to prevent infinite re-renders
52
+ const renderedBulkActions = useMemo(() => {
53
+ if (!bulkActions) return null;
54
+ return bulkActions(selectionState) as any;
55
+ }, [bulkActions, selectionState]);
56
+
57
+ // Merge all props for maximum flexibility
58
+ const mergedToolbarProps = mergeSlotProps(
59
+ {
60
+ sx: {
61
+ pl: { sm: 2 },
62
+ pr: { xs: 1, sm: 1 },
63
+ bgcolor: (theme: Theme) => alpha(theme.palette.primary.main, 0.05),
64
+ mb: 1,
65
+ position: 'relative',
66
+ zIndex: 1,
67
+ ...sx,
68
+ ...containerSx,
69
+ },
70
+ },
71
+ toolbarSlotProps,
72
+ otherProps
73
+ );
74
+
75
+ const mergedChipProps = mergeSlotProps(
76
+ {
77
+ label: `${selectedRowCount} selected`,
78
+ size: 'small',
79
+ color: 'primary',
80
+ variant: 'outlined',
81
+ },
82
+ chipProps || {}
83
+ );
84
+
85
+ return (
86
+ <Fade
87
+ in={selectedRowCount > 0}
88
+ {...fadeProps}
89
+ >
90
+ <ToolbarSlot
91
+ {...mergedToolbarProps}
92
+ >
93
+ {/* Left section - Selection info */}
94
+ <Box
95
+ sx={{
96
+ flex: '1 1 100%',
97
+ ...leftSectionSx,
98
+ }}
99
+ >
100
+ <Typography
101
+ color="inherit"
102
+ variant="subtitle1"
103
+ component="div"
104
+ >
105
+ <Chip
106
+ {...mergedChipProps}
107
+ />
108
+ </Typography>
109
+ </Box>
110
+
111
+ {/* Right section - Actions */}
112
+ <Box
113
+ sx={{
114
+ display: 'flex',
115
+ alignItems: 'center',
116
+ gap: 1,
117
+ ...rightSectionSx,
118
+ }}
119
+ >
120
+ {renderedBulkActions}
121
+ </Box>
122
+ </ToolbarSlot>
123
+ </Fade>
124
+ );
125
+ }
@@ -0,0 +1,374 @@
1
+ import { FilterList } from '@mui/icons-material';
2
+ import {
3
+ Box,
4
+ MenuItem,
5
+ Select,
6
+ FormControl,
7
+ InputLabel,
8
+ Button,
9
+ Stack,
10
+ Typography,
11
+ IconButton,
12
+ Divider,
13
+ Badge,
14
+ IconButtonProps,
15
+ SxProps,
16
+ } from '@mui/material';
17
+ import React, { useMemo, useCallback, useEffect, ReactElement } from 'react';
18
+
19
+ import { MenuDropdown } from '../droupdown/menu-dropdown';
20
+ import { useDataTableContext } from '../../contexts/data-table-context';
21
+ import {
22
+ AddIcon,
23
+ DeleteIcon,
24
+ } from '../../icons';
25
+ import { getColumnType, isColumnFilterable } from '../../utils/column-helpers';
26
+ import { getSlotComponent, mergeSlotProps, extractSlotProps } from '../../utils/slot-helpers';
27
+ import { FILTER_OPERATORS } from '../filters';
28
+ import { FilterValueInput } from '../filters/filter-value-input';
29
+ import { ColumnFilterRule } from '../../features';
30
+
31
+ export interface ColumnFilterControlProps {
32
+ // Allow full customization of any prop
33
+ title?: string;
34
+ titleSx?: SxProps;
35
+ menuSx?: SxProps;
36
+ iconButtonProps?: IconButtonProps;
37
+ badgeProps?: any;
38
+ clearButtonProps?: any;
39
+ applyButtonProps?: any;
40
+ addButtonProps?: any;
41
+ logicSelectProps?: any;
42
+ [key: string]: any;
43
+ }
44
+
45
+ export function ColumnFilterControl(props: ColumnFilterControlProps = {}): ReactElement {
46
+ const { table, slots, slotProps } = useDataTableContext();
47
+
48
+ // Extract slot-specific props with enhanced merging
49
+ const iconSlotProps = extractSlotProps(slotProps, 'filterIcon');
50
+
51
+ const FilterIconSlot = getSlotComponent(slots, 'filterIcon', FilterList);
52
+
53
+ // Use the custom feature state from the table - now using pending filters for UI
54
+ const filterState = table?.getColumnFilterState?.() || {
55
+ filters: [],
56
+ logic: 'AND',
57
+ pendingFilters: [],
58
+ pendingLogic: 'AND'
59
+ };
60
+
61
+ // Use pending filters for the UI (draft state)
62
+ const filters = filterState.pendingFilters;
63
+ const filterLogic = filterState.pendingLogic;
64
+
65
+ // Active filters are the actual applied filters
66
+ const activeFiltersCount = table?.getActiveColumnFilters?.()?.length || 0;
67
+
68
+ const filterableColumns = useMemo(() => {
69
+ return table?.getAllLeafColumns()
70
+ .filter(column => isColumnFilterable(column));
71
+ }, [table]);
72
+
73
+ const addFilter = useCallback((columnId?: string, operator?: string) => {
74
+ // If no column specified, use empty (user will select)
75
+ // If column specified, get its appropriate default operator
76
+ let defaultOperator = operator || '';
77
+
78
+ if (columnId && !operator) {
79
+ const column = filterableColumns?.find(col => col.id === columnId);
80
+ const columnType = getColumnType(column as any);
81
+ const operators = FILTER_OPERATORS[columnType as keyof typeof FILTER_OPERATORS] || FILTER_OPERATORS.text;
82
+ defaultOperator = operators[0]?.value || 'contains';
83
+ }
84
+
85
+ table?.addPendingColumnFilter?.(columnId || '', defaultOperator, '');
86
+ }, [table, filterableColumns]);
87
+
88
+ const handleAddFilter = useCallback(() => {
89
+ addFilter();
90
+ }, [addFilter]);
91
+
92
+ const updateFilter = useCallback((filterId: string, updates: Partial<ColumnFilterRule>) => {
93
+ table?.updatePendingColumnFilter?.(filterId, updates);
94
+ }, [table]);
95
+
96
+ const removeFilter = useCallback((filterId: string) => {
97
+ table?.removePendingColumnFilter?.(filterId);
98
+ }, [table]);
99
+
100
+ const clearAllFilters = useCallback((closeDialog?: () => void) => {
101
+ // Clear all pending filters
102
+ table?.clearAllPendingColumnFilters?.();
103
+ // Immediately apply the clear (which will clear active filters too)
104
+ setTimeout(() => {
105
+ table?.applyPendingColumnFilters?.();
106
+ // Close dialog if callback provided
107
+ if (closeDialog) {
108
+ closeDialog();
109
+ }
110
+ }, 0);
111
+ }, [table]);
112
+
113
+ // Handle filter logic change (AND/OR)
114
+ const handleLogicChange = useCallback((newLogic: 'AND' | 'OR') => {
115
+ table?.setPendingFilterLogic?.(newLogic);
116
+ }, [table]);
117
+
118
+ // Apply all pending filters
119
+ const applyFilters = useCallback(() => {
120
+ table?.applyPendingColumnFilters?.();
121
+ }, [table]);
122
+
123
+ // Handle apply button click
124
+ const handleApplyFilters = useCallback((closeDialog: () => void) => {
125
+ applyFilters();
126
+ closeDialog();
127
+ }, [applyFilters]);
128
+
129
+ const getOperatorsForColumn = useCallback((columnId: string) => {
130
+ const column = filterableColumns?.find(col => col.id === columnId);
131
+ const type = getColumnType(column as any);
132
+ return FILTER_OPERATORS[type as keyof typeof FILTER_OPERATORS] || FILTER_OPERATORS.text;
133
+ }, [filterableColumns]);
134
+
135
+ // Handle column selection change
136
+ const handleColumnChange = useCallback((filterId: string, newColumnId: string, currentFilter: ColumnFilterRule) => {
137
+ const newColumn = filterableColumns?.find(col => col.id === newColumnId);
138
+ const columnType = getColumnType(newColumn as any);
139
+ const operators = FILTER_OPERATORS[columnType as keyof typeof FILTER_OPERATORS] || FILTER_OPERATORS.text;
140
+
141
+ // Only reset operator if current operator is not valid for new column type
142
+ const currentOperatorValid = operators.some(op => op.value === currentFilter.operator);
143
+ const newOperator = currentOperatorValid ? currentFilter.operator : operators[0]?.value || '';
144
+
145
+ updateFilter(filterId, {
146
+ columnId: newColumnId,
147
+ operator: newOperator,
148
+ // Keep the current value unless operator is empty/notEmpty
149
+ value: ['isEmpty', 'isNotEmpty'].includes(newOperator) ? '' : currentFilter.value,
150
+ });
151
+ }, [filterableColumns, updateFilter]);
152
+
153
+ // Handle operator selection change
154
+ const handleOperatorChange = useCallback((filterId: string, newOperator: string, currentFilter: ColumnFilterRule) => {
155
+ updateFilter(filterId, {
156
+ operator: newOperator,
157
+ // Only reset value if operator is empty/notEmpty, otherwise preserve it
158
+ value: ['isEmpty', 'isNotEmpty'].includes(newOperator) ? '' : currentFilter.value,
159
+ });
160
+ }, [updateFilter]);
161
+
162
+ // Handle filter value change
163
+ const handleFilterValueChange = useCallback((filterId: string, value: any) => {
164
+ updateFilter(filterId, { value });
165
+ }, [updateFilter]);
166
+
167
+ // Handle filter removal
168
+ const handleRemoveFilter = useCallback((filterId: string) => {
169
+ removeFilter(filterId);
170
+ }, [removeFilter]);
171
+
172
+ // Count pending filters that are ready to apply (have column, operator, and value OR are empty/notEmpty operators)
173
+ const pendingFiltersCount = filters.filter(f => {
174
+ if (!f.columnId || !f.operator) return false;
175
+ // For empty/notEmpty operators, no value is needed
176
+ if (['isEmpty', 'isNotEmpty'].includes(f.operator)) return true;
177
+ // For other operators, value is required
178
+ return f.value && f.value.toString().trim() !== '';
179
+ }).length;
180
+
181
+ // Check if we need to show "Clear Applied Filters" button
182
+ const hasAppliedFilters = activeFiltersCount > 0;
183
+
184
+ // Determine if there are pending changes that can be applied
185
+ const hasPendingChanges = pendingFiltersCount > 0 || (filters.length === 0 && hasAppliedFilters);
186
+
187
+ // Auto-add default filter when opening if no filters exist AND no applied filters
188
+ useEffect(() => {
189
+ if (filters.length === 0 && filterableColumns && filterableColumns?.length > 0 && activeFiltersCount === 0) {
190
+ const firstColumn = filterableColumns[0];
191
+ const columnType = getColumnType(firstColumn as any);
192
+ const operators = FILTER_OPERATORS[columnType as keyof typeof FILTER_OPERATORS] || FILTER_OPERATORS.text;
193
+ const defaultOperator = operators[0]?.value || 'contains';
194
+ // Add default filter with first column and its first operator
195
+ addFilter(firstColumn?.id, defaultOperator);
196
+ }
197
+ }, [filters.length, filterableColumns, addFilter, activeFiltersCount]);
198
+
199
+ // Merge all props for maximum flexibility
200
+ const mergedProps = mergeSlotProps(
201
+ {
202
+ // Default props
203
+ size: 'small',
204
+ sx: { flexShrink: 0 },
205
+ },
206
+ slotProps?.columnFilterControl || {},
207
+ props
208
+ );
209
+
210
+ return (
211
+ <MenuDropdown
212
+ anchor={(
213
+ <Badge
214
+ badgeContent={activeFiltersCount > 0 ? activeFiltersCount : 0}
215
+ color="primary"
216
+ invisible={activeFiltersCount === 0}
217
+ {...mergedProps.badgeProps}
218
+ >
219
+ <IconButton
220
+ {...mergedProps}
221
+ >
222
+ <FilterIconSlot
223
+ {...iconSlotProps}
224
+ />
225
+ </IconButton>
226
+ </Badge>
227
+ )}
228
+ >
229
+ {({ handleClose }: { handleClose: () => void }) => (
230
+ <Box
231
+ sx={{
232
+ p: 2,
233
+ minWidth: 400,
234
+ maxWidth: 600,
235
+ ...mergedProps.menuSx,
236
+ }}
237
+ >
238
+ <Typography
239
+ variant="subtitle2"
240
+ sx={{
241
+ mb: 1,
242
+ ...mergedProps.titleSx,
243
+ }}
244
+ >
245
+ {mergedProps.title || 'Column Filters'}
246
+ </Typography>
247
+ <Divider sx={{ mb: 2 }} />
248
+
249
+ {/* Filter Logic Selection */}
250
+ {filters.length > 1 && (
251
+ <Box sx={{ mb: 2 }}>
252
+ <FormControl size="small" sx={{ minWidth: 120 }}>
253
+ <InputLabel>Logic</InputLabel>
254
+ <Select
255
+ value={filterLogic}
256
+ label="Logic"
257
+ onChange={(e) => handleLogicChange(e.target.value as 'AND' | 'OR')}
258
+ {...mergedProps.logicSelectProps}
259
+ >
260
+ <MenuItem value="AND">AND</MenuItem>
261
+ <MenuItem value="OR">OR</MenuItem>
262
+ </Select>
263
+ </FormControl>
264
+ </Box>
265
+ )}
266
+
267
+ {/* Filter Rules */}
268
+ <Stack spacing={2} sx={{ mb: 2 }}>
269
+ {filters.map((filter) => {
270
+ const selectedColumn = filterableColumns?.find(col => col.id === filter.columnId);
271
+ const operators = filter.columnId ? getOperatorsForColumn(filter.columnId) : [];
272
+ const needsValue = !['isEmpty', 'isNotEmpty'].includes(filter.operator);
273
+
274
+ return (
275
+ <Stack key={filter.id} direction="row" spacing={1} alignItems="center">
276
+ {/* Column Selection */}
277
+ <FormControl size="small" sx={{ minWidth: 120 }}>
278
+ <InputLabel>Column</InputLabel>
279
+ <Select
280
+ value={filter.columnId || ''}
281
+ label="Column"
282
+ onChange={(e) => handleColumnChange(filter.id, e.target.value, filter)}
283
+ >
284
+ {filterableColumns?.map(column => (
285
+ <MenuItem key={column.id} value={column.id}>
286
+ {typeof column.columnDef.header === 'string'
287
+ ? column.columnDef.header
288
+ : column.id}
289
+ </MenuItem>
290
+ ))}
291
+ </Select>
292
+ </FormControl>
293
+
294
+ {/* Operator Selection */}
295
+ <FormControl size="small" sx={{ minWidth: 120 }}>
296
+ <InputLabel>Operator</InputLabel>
297
+ <Select
298
+ value={filter.operator || ''}
299
+ label="Operator"
300
+ onChange={(e) => handleOperatorChange(filter.id, e.target.value, filter)}
301
+ disabled={!filter.columnId}
302
+ >
303
+ {operators.map(op => (
304
+ <MenuItem key={op.value} value={op.value}>
305
+ {op.label}
306
+ </MenuItem>
307
+ ))}
308
+ </Select>
309
+ </FormControl>
310
+
311
+ {/* Value Input */}
312
+ {needsValue && selectedColumn && (
313
+ <FilterValueInput
314
+ filter={filter}
315
+ column={selectedColumn}
316
+ onValueChange={(value) => handleFilterValueChange(filter.id, value)}
317
+ />
318
+ )}
319
+
320
+ {/* Remove Filter Button */}
321
+ <IconButton
322
+ size="small"
323
+ onClick={() => handleRemoveFilter(filter.id)}
324
+ color="error"
325
+ {...mergedProps.deleteButtonProps}
326
+ >
327
+ <DeleteIcon fontSize="small" />
328
+ </IconButton>
329
+ </Stack>
330
+ );
331
+ })}
332
+ </Stack>
333
+
334
+ {/* Add Filter Button */}
335
+ <Button
336
+ variant="outlined"
337
+ size="small"
338
+ startIcon={<AddIcon />}
339
+ onClick={handleAddFilter}
340
+ disabled={!filterableColumns || filterableColumns.length === 0}
341
+ sx={{ mb: 2 }}
342
+ {...mergedProps.addButtonProps}
343
+ >
344
+ Add Filter
345
+ </Button>
346
+
347
+ {/* Action Buttons */}
348
+ <Stack direction="row" spacing={1} justifyContent="flex-end">
349
+ {hasAppliedFilters && (
350
+ <Button
351
+ variant="outlined"
352
+ size="small"
353
+ onClick={() => clearAllFilters(handleClose)}
354
+ color="error"
355
+ {...mergedProps.clearButtonProps}
356
+ >
357
+ Clear All
358
+ </Button>
359
+ )}
360
+ <Button
361
+ variant="contained"
362
+ size="small"
363
+ onClick={() => handleApplyFilters(handleClose)}
364
+ disabled={!hasPendingChanges}
365
+ {...mergedProps.applyButtonProps}
366
+ >
367
+ Apply
368
+ </Button>
369
+ </Stack>
370
+ </Box>
371
+ )}
372
+ </MenuDropdown>
373
+ );
374
+ }