react-live-data-table 1.0.17 → 1.0.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.
- package/package.json +1 -1
- package/src/ReactDataTable.jsx +88 -12
package/package.json
CHANGED
package/src/ReactDataTable.jsx
CHANGED
@@ -19,7 +19,8 @@ function ReactDataTable({
|
|
19
19
|
selected = {},
|
20
20
|
showSelectAllCheckbox = true,
|
21
21
|
rowStyle = {},
|
22
|
-
rowClassName = ""
|
22
|
+
rowClassName = "",
|
23
|
+
columnReorder = false,
|
23
24
|
}) {
|
24
25
|
const tableContainerRef = React.useRef(null);
|
25
26
|
const [data, setData] = React.useState({ pages: [], meta: { totalPages: 1 } });
|
@@ -32,6 +33,12 @@ function ReactDataTable({
|
|
32
33
|
const [startX, setStartX] = useState(null);
|
33
34
|
const [initialWidth, setInitialWidth] = useState(null);
|
34
35
|
const [tableWidth, setTableWidth] = useState(0);
|
36
|
+
|
37
|
+
// Column reordering state - only used when columnReorder is true
|
38
|
+
const [orderedColumns, setOrderedColumns] = useState(columns);
|
39
|
+
const [draggedColumn, setDraggedColumn] = useState(null);
|
40
|
+
const [dragOverColumn, setDragOverColumn] = useState(null);
|
41
|
+
|
35
42
|
// Ref to store column widths to ensure persistence during data loading
|
36
43
|
const persistedColumnWidthsRef = React.useRef([]);
|
37
44
|
|
@@ -42,6 +49,7 @@ function ReactDataTable({
|
|
42
49
|
size: 50,
|
43
50
|
minWidth: 50,
|
44
51
|
resizable: false,
|
52
|
+
reorderable: false, // Prevent checkbox column from being reordered
|
45
53
|
textAlign: "center",
|
46
54
|
header: ({ data }) => {
|
47
55
|
const allSelected = flatData.length > 0 && flatData.every(row => selectedRows[row.id]);
|
@@ -105,7 +113,12 @@ function ReactDataTable({
|
|
105
113
|
}
|
106
114
|
};
|
107
115
|
|
108
|
-
const enhancedColumns = showCheckbox ? [checkboxColumn, ...
|
116
|
+
const enhancedColumns = showCheckbox ? [checkboxColumn, ...orderedColumns] : orderedColumns;
|
117
|
+
|
118
|
+
// Update ordered columns when columns prop changes
|
119
|
+
useEffect(() => {
|
120
|
+
setOrderedColumns(columns);
|
121
|
+
}, [columns]);
|
109
122
|
|
110
123
|
useEffect(() => {
|
111
124
|
if (JSON.stringify(previousSelected.current) !== JSON.stringify(selected)) {
|
@@ -116,7 +129,7 @@ function ReactDataTable({
|
|
116
129
|
|
117
130
|
// Initialize column widths array only once when component mounts or columns change
|
118
131
|
useEffect(() => {
|
119
|
-
const allColumns = showCheckbox ? [{ id: 'select', size: 50 }, ...
|
132
|
+
const allColumns = showCheckbox ? [{ id: 'select', size: 50 }, ...orderedColumns] : orderedColumns;
|
120
133
|
|
121
134
|
// If we have persisted widths and the number of columns matches, use those
|
122
135
|
if (persistedColumnWidthsRef.current.length === allColumns.length) {
|
@@ -130,7 +143,7 @@ function ReactDataTable({
|
|
130
143
|
// Store in our ref for persistence
|
131
144
|
persistedColumnWidthsRef.current = [...initialWidths];
|
132
145
|
}
|
133
|
-
}, [
|
146
|
+
}, [orderedColumns, showCheckbox]);
|
134
147
|
|
135
148
|
useEffect(() => {
|
136
149
|
setData({ pages: [], meta: { totalPages: 1 } });
|
@@ -155,6 +168,61 @@ function ReactDataTable({
|
|
155
168
|
}
|
156
169
|
}, [dataSource, staticData]);
|
157
170
|
|
171
|
+
// Column reordering handlers - only work when columnReorder is true
|
172
|
+
const handleDragStart = (e, columnIndex) => {
|
173
|
+
if (!columnReorder || enhancedColumns[columnIndex].reorderable === false) {
|
174
|
+
e.preventDefault();
|
175
|
+
return;
|
176
|
+
}
|
177
|
+
setDraggedColumn(columnIndex);
|
178
|
+
e.dataTransfer.effectAllowed = 'move';
|
179
|
+
};
|
180
|
+
|
181
|
+
const handleDragOver = (e, columnIndex) => {
|
182
|
+
e.preventDefault();
|
183
|
+
if (!columnReorder || enhancedColumns[columnIndex].reorderable === false) return;
|
184
|
+
setDragOverColumn(columnIndex);
|
185
|
+
};
|
186
|
+
|
187
|
+
const handleDrop = (e, dropIndex) => {
|
188
|
+
e.preventDefault();
|
189
|
+
|
190
|
+
if (!columnReorder || draggedColumn === null || draggedColumn === dropIndex) {
|
191
|
+
setDraggedColumn(null);
|
192
|
+
setDragOverColumn(null);
|
193
|
+
return;
|
194
|
+
}
|
195
|
+
|
196
|
+
if (enhancedColumns[dropIndex].reorderable === false) {
|
197
|
+
setDraggedColumn(null);
|
198
|
+
setDragOverColumn(null);
|
199
|
+
return;
|
200
|
+
}
|
201
|
+
|
202
|
+
const newColumns = [...enhancedColumns];
|
203
|
+
const draggedColumnData = newColumns[draggedColumn];
|
204
|
+
|
205
|
+
newColumns.splice(draggedColumn, 1);
|
206
|
+
const adjustedDropIndex = draggedColumn < dropIndex ? dropIndex - 1 : dropIndex;
|
207
|
+
newColumns.splice(adjustedDropIndex, 0, draggedColumnData);
|
208
|
+
|
209
|
+
const updatedOrderedColumns = showCheckbox ? newColumns.slice(1) : newColumns;
|
210
|
+
setOrderedColumns(updatedOrderedColumns);
|
211
|
+
|
212
|
+
// Reorder column widths
|
213
|
+
const newColumnWidths = [...columnWidths];
|
214
|
+
const draggedWidth = newColumnWidths[draggedColumn];
|
215
|
+
newColumnWidths.splice(draggedColumn, 1);
|
216
|
+
newColumnWidths.splice(adjustedDropIndex, 0, draggedWidth);
|
217
|
+
setColumnWidths(newColumnWidths);
|
218
|
+
persistedColumnWidthsRef.current = newColumnWidths;
|
219
|
+
|
220
|
+
// onColumnReorder?.(updatedOrderedColumns);
|
221
|
+
|
222
|
+
setDraggedColumn(null);
|
223
|
+
setDragOverColumn(null);
|
224
|
+
};
|
225
|
+
|
158
226
|
const handleMouseMove = useCallback((e) => {
|
159
227
|
if (resizingIndex === null || startX === null || initialWidth === null) return;
|
160
228
|
|
@@ -378,22 +446,30 @@ function ReactDataTable({
|
|
378
446
|
className="sticky top-0 z-10 bg-blue-300"
|
379
447
|
style={{ ...headerProps.style }}
|
380
448
|
>
|
381
|
-
<tr>
|
449
|
+
<tr className='react-live-data-table-row-header'>
|
382
450
|
{enhancedColumns.map((column, columnIndex) => {
|
383
|
-
// Use persisted column widths to ensure consistency
|
384
451
|
const width = columnWidths[columnIndex] || column.size || column.minWidth || 150;
|
452
|
+
const isReorderable = columnReorder && column.reorderable !== false;
|
453
|
+
const isDropTarget = dragOverColumn === columnIndex && draggedColumn !== columnIndex;
|
385
454
|
|
386
455
|
return (
|
387
456
|
<th
|
388
457
|
key={column.accessorKey || column.id}
|
389
|
-
className={`text-left font-normal h-[40px] border-b border-t border-solid border-[#e4e3e2] relative select-none ${
|
390
|
-
|
458
|
+
className={`text-left font-normal h-[40px] border-b border-t border-solid border-[#e4e3e2] relative select-none ${
|
459
|
+
columnIndex < enhancedColumns.length - 1 ? 'border-r' : ''
|
460
|
+
} ${isReorderable ? 'cursor-move' : ''} ${
|
461
|
+
isDropTarget ? 'bg-blue-400' : ''
|
462
|
+
}`}
|
391
463
|
style={{
|
392
464
|
width: `${width}px`,
|
393
465
|
minWidth: `${width}px`,
|
394
466
|
maxWidth: `${width}px`,
|
395
467
|
textAlign: column.textAlign,
|
396
468
|
}}
|
469
|
+
draggable={isReorderable}
|
470
|
+
onDragStart={(e) => handleDragStart(e, columnIndex)}
|
471
|
+
onDragOver={(e) => handleDragOver(e, columnIndex)}
|
472
|
+
onDrop={(e) => handleDrop(e, columnIndex)}
|
397
473
|
>
|
398
474
|
<div className="flex items-center h-full overflow-hidden justify-center pl-[17px]">
|
399
475
|
<span className="truncate">
|
@@ -404,8 +480,9 @@ function ReactDataTable({
|
|
404
480
|
{/* Resize handle - Only show if column is resizable */}
|
405
481
|
{column.resizable !== false && (
|
406
482
|
<div
|
407
|
-
className={`absolute top-0 right-0 h-full w-4 flex items-center justify-center group ${
|
408
|
-
|
483
|
+
className={`absolute top-0 right-0 h-full w-4 flex items-center justify-center group ${
|
484
|
+
resizingIndex === columnIndex ? 'bg-blue-100' : 'hover:bg-blue-100'
|
485
|
+
} transition-colors duration-200`}
|
409
486
|
onMouseDown={(e) => handleResizeStart(e, columnIndex)}
|
410
487
|
style={{
|
411
488
|
touchAction: 'none',
|
@@ -427,7 +504,7 @@ function ReactDataTable({
|
|
427
504
|
return (
|
428
505
|
<tr
|
429
506
|
key={row.id}
|
430
|
-
className={`border-t ${isLastRow ? 'border-b' : ''} border-gray-200 hover:bg-[#dee1f2] ${selectedRows[row.id] ? 'bg-[#dee1f2]' : ''} ${rowClassName} cursor-pointer`}
|
507
|
+
className={`react-live-data-table-row-${index} border-t ${isLastRow ? 'border-b' : ''} border-gray-200 hover:bg-[#dee1f2] ${selectedRows[row.id] ? 'bg-[#dee1f2]' : ''} ${rowClassName} cursor-pointer`}
|
431
508
|
style={{
|
432
509
|
height: `${rowHeights}px`,
|
433
510
|
...rowStyle,
|
@@ -436,7 +513,6 @@ function ReactDataTable({
|
|
436
513
|
onClick={() => handleRowClick(row, rowIndex, flatData)}
|
437
514
|
>
|
438
515
|
{enhancedColumns.map((column, columnIndex) => {
|
439
|
-
// Use persisted column widths for cells as well
|
440
516
|
const width = columnWidths[columnIndex] || column.size || column.minWidth || 150;
|
441
517
|
|
442
518
|
return (
|