react-live-data-table 1.0.15 → 1.0.16

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 CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "react-live-data-table",
3
- "version": "1.0.15",
3
+ "version": "1.0.16",
4
4
  "description": "Your React component package with Tailwind",
5
5
  "main": "src/index.js",
6
6
  "module": "dist/index.esm.js",
package/readme.md CHANGED
@@ -8,7 +8,7 @@ A highly customizable and efficient data grid table for React. It supports featu
8
8
 
9
9
  To install the package, run one of the following commands:
10
10
 
11
- ```bash
11
+ bash
12
12
  npm install react-data-grid-table
13
13
 
14
14
  # React Data Grid
@@ -41,40 +41,4 @@ A flexible React data grid component with support for pagination, row selection,
41
41
  | `rowHeights` | `number` | `40` | Height of each row |
42
42
  | `headerProps` | `object` | `{}` | Custom header properties |
43
43
 
44
-
45
-
46
-
47
- ### Column Definition
48
-
49
- ```typescript
50
- interface ColumnDefinition {
51
- field: string; // Key of the data field to display
52
- headerName: string; // Text to show in column header
53
- width?: number; // Column width in pixels
54
- sortable?: boolean; // Enable column sorting
55
- render?: (value: any, rowData: Object) => React.ReactNode; // Custom cell renderer
56
-
57
-
58
44
  ## Basic Usage
59
-
60
- ```jsx
61
- import { ReactDataTable } from 'react-data-grid';
62
-
63
- const App = () => {
64
- const columns = [
65
- { field: 'id', headerName: 'ID' },
66
- { field: 'name', headerName: 'Name' }
67
- ];
68
-
69
- const data = [
70
- { id: 1, name: 'John' },
71
- { id: 2, name: 'Jane' }
72
- ];
73
-
74
- return (
75
- <ReactDataTable
76
- columns={columns}
77
- dataSource={data}
78
- />
79
- );
80
- };
@@ -15,13 +15,26 @@ function ReactDataTable({
15
15
  staticData = null,
16
16
  emptyText,
17
17
  rowHeights = 40,
18
- headerProps = {} // Added default value
18
+ headerProps = {},
19
+ selected = {},
20
+ showSelectAllCheckbox = true,
21
+ rowStyle = {},
22
+ rowClassName = ""
19
23
  }) {
20
24
  const tableContainerRef = React.useRef(null);
21
25
  const [data, setData] = React.useState({ pages: [], meta: { totalPages: 1 } });
22
26
  const [isFetching, setIsFetching] = React.useState(false);
23
27
  const [pageParam, setPageParam] = React.useState(1);
24
- const [selectedRows, setSelectedRows] = React.useState({});
28
+ const [selectedRows, setSelectedRows] = React.useState(selected);
29
+ const previousSelected = React.useRef(selected);
30
+
31
+
32
+ useEffect(() => {
33
+ if (JSON.stringify(previousSelected.current) !== JSON.stringify(selected)) {
34
+ setSelectedRows({...selected});
35
+ previousSelected.current = selected;
36
+ }
37
+ }, [selected]);
25
38
 
26
39
 
27
40
  useEffect(() => {
@@ -164,117 +177,191 @@ function ReactDataTable({
164
177
  size: 50,
165
178
  minWidth: 50,
166
179
  textAlign: "center",
167
- header: ({ data }) => (
168
- <div className="flex items-center justify-center h-[40px]">
169
- <input
170
- type="checkbox"
171
- checked={Object.keys(selectedRows).length > 0 && data.every(row => selectedRows[row.id])}
172
- onChange={(e) => handleSelectAll(e.target.checked, flatData)}
173
- />
174
- </div>
175
- ),
176
- cell: ({ row }) => (
177
- <div className="flex items-center justify-center h-[40px]">
178
- <input
179
- type="checkbox"
180
- checked={!!selectedRows[row.id]}
181
- onChange={(e) => handleSelectRow(e.target.checked, row, flatData)}
182
- />
183
- </div>
184
- ),
180
+ header: ({ data }) => {
181
+ const allSelected = flatData.length > 0 && flatData.every(row => selectedRows[row.id]);
182
+ const someSelected = flatData.some(row => selectedRows[row.id]) && !allSelected;
183
+
184
+
185
+ return (
186
+ <div className="flex items-center justify-center h-[40px]">
187
+ {showSelectAllCheckbox && (
188
+ <div className="relative">
189
+ <input
190
+ id={data.id}
191
+ type="checkbox"
192
+ className='bg-gray-700 rounded-4 border-gray-200 text-blue-400 focus:ring-0 focus:ring-white'
193
+ checked={allSelected}
194
+ onChange={(e) => handleSelectAll(e.target.checked, flatData)}
195
+ />
196
+ {allSelected ? (
197
+ <svg
198
+ className="absolute top-1/2 left-1/2 transform -translate-x-1/2 -translate-y-1/2 w-3 h-3 pointer-events-none text-white"
199
+ viewBox="0 0 20 20"
200
+ fill="currentColor"
201
+ >
202
+ <path
203
+ fillRule="evenodd"
204
+ d="M16.707 5.293a1 1 0 010 1.414l-8 8a1 1 0 01-1.414 0l-4-4a1 1 0 011.414-1.414L8 12.586l7.293-7.293a1 1 0 011.414 0z"
205
+ clipRule="evenodd"
206
+ />
207
+ </svg>
208
+ ) : (
209
+ someSelected &&
210
+ <svg
211
+ className="absolute top-1/2 left-1/2 transform -translate-x-1/2 -translate-y-1/2 w-3 h-3 pointer-events-none "
212
+ viewBox="0 0 20 20"
213
+ fill="currentColor"
214
+ >
215
+ <path
216
+ fillRule="evenodd"
217
+ d="M3 10a1 1 0 011-1h12a1 1 0 110 2H4a1 1 0 01-1-1z"
218
+ clipRule="evenodd"
219
+ />
220
+ </svg>
221
+ )}
222
+ </div>
223
+ )}
224
+ </div>
225
+ );
226
+ },
227
+ cell: ({ row }) => {
228
+ return (
229
+ <div className="flex items-center justify-center h-[40px]" onClick={(e) => e.stopPropagation()}>
230
+ <input
231
+ id={row.id}
232
+ type="checkbox"
233
+ className='bg-gray-700 rounded-4 border-gray-200 text-blue-400 focus:ring-0 focus:ring-white'
234
+ checked={!!selectedRows[row.id]}
235
+ onClick={(e) => e.stopPropagation()}
236
+ onChange={(e) => { e.stopPropagation(); handleSelectRow(e.target.checked, row, flatData) }}
237
+ />
238
+ </div>
239
+ )
240
+ }
185
241
  };
186
242
 
187
243
  const enhancedColumns = showCheckbox ? [checkboxColumn, ...columns] : columns;
188
244
 
189
245
  return (
190
- <div className="bg-white relative w-full">
191
- {loading && <div className="absolute inset-0 bg-white/50 z-20 flex items-center justify-center">
192
- <div data-testid="loading-spinner" role="status" className="p-2">
193
- <svg
194
- aria-hidden="true"
195
- className="inline w-8 h-8 mr-2 text-gray-200 animate-spin dark:text-gray-600 fill-green-500"
196
- viewBox="0 0 100 101"
197
- fill="none"
198
- xmlns="http://www.w3.org/2000/svg"
199
- >
200
- <path
201
- d="M100 50.5908C100 78.2051 77.6142 100.591 50 100.591C22.3858 100.591 0 78.2051 0 50.5908C0 22.9766 22.3858 0.59082 50 0.59082C77.6142 0.59082 100 22.9766 100 50.5908Z"
202
- fill="currentColor"
203
- />
204
- </svg>
205
- </div>
206
- </div>}
207
- {flatData.length === 0 && !loading ? (
208
- <div className="flex items-center justify-center" style={{ height }}>
209
- <div className="text-gray-500">
210
- {emptyText || 'No data available'}
211
- </div>
212
- </div>
213
- ) : (
214
- <div className="overflow-hidden">
215
- <div
216
- ref={tableContainerRef}
217
- className="overflow-auto w-full"
218
- style={{ maxHeight, height }}
219
- onScroll={(e) => handleScroll(e.currentTarget)}
246
+ <div className="bg-white relative w-full react-live-data-table" >
247
+ {loading && (
248
+ <div className="absolute inset-0 bg-white/50 z-20 flex items-center justify-center">
249
+ <svg
250
+ style={{
251
+ animation: 'spin 1s linear infinite',
252
+ width: '24px',
253
+ height: '24px'
254
+ }}
255
+ viewBox="0 0 24 24"
256
+ fill="none"
257
+ xmlns="http://www.w3.org/2000/svg"
220
258
  >
221
- <table className="w-full border-collapse">
222
- <thead
223
- className="sticky top-0 z-1 bg-blue-300"
224
- style={{ ...headerProps.style }}
225
- >
226
- <tr>
227
- {enhancedColumns.map(column => (
228
- <th
229
- key={column.accessorKey || column.id}
230
- className="text-left font-normal h-[40px]"
231
- style={{
232
- width: column.size,
233
- minWidth: column.minWidth,
234
- textAlign: column.textAlign,
235
- }}
236
- >
237
- {typeof column.header === 'function' ? column.header({ data: flatData }) : column.header}
238
- </th>
239
- ))}
240
- </tr>
241
- </thead>
242
- <tbody>
243
- {flatData.length > 0 ? (
244
- flatData.map((row, index) => (
245
- <tr
246
- key={row.id}
247
- className={`border-t border-x border-gray-200 hover:bg-[#dee1f2] h-[${rowHeights}px] ${selectedRows[row.id] ? 'bg-[#dee1f2]' : ''}`}
248
- onClick={() => handleRowClick(row, index, flatData)}
249
- >
250
- {enhancedColumns.map(column => (
251
- <td
252
- key={column.accessorKey || column.id}
253
- className={`text-left font-normal border-r ${column?.cellProps?.className || ''}`}
259
+ <style>
260
+ {`@keyframes spin {from {transform: rotate(0deg)} to {transform: rotate(360deg)}}`}
261
+ </style>
262
+ <circle
263
+ style={{ opacity: 0.25 }}
264
+ cx="12"
265
+ cy="12"
266
+ r="10"
267
+ stroke="currentColor"
268
+ strokeWidth="4"
269
+ />
270
+ <path
271
+ style={{ opacity: 0.75 }}
272
+ fill="currentColor"
273
+ d="M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4zm2 5.291A7.962 7.962 0 014 12H0c0 3.042 1.135 5.824 3 7.938l3-2.647z"
274
+ />
275
+ </svg>
276
+
277
+ </div>
278
+ )}
279
+
280
+ {
281
+ flatData.length === 0 && !loading ? (
282
+ <div className="flex items-center justify-center" style={{ height }}>
283
+ <div className="text-gray-500">
284
+ {emptyText || 'No data available'}
285
+ </div>
286
+ </div>
287
+ ) : (
288
+ <div className="overflow-hidden">
289
+ <div
290
+ ref={tableContainerRef}
291
+ className="overflow-auto w-full"
292
+ style={{ maxHeight, height }}
293
+ onScroll={(e) => handleScroll(e.currentTarget)}
294
+ >
295
+ <table className="w-full border-collapse">
296
+ <thead
297
+ className="sticky top-0 z-1 bg-blue-300"
298
+ style={{ ...headerProps.style }}
299
+ >
300
+ <tr>
301
+ {enhancedColumns.map((column, columnIndex) => (
302
+ <th
303
+ key={column.accessorKey || column.id}
304
+ className={`text-left font-normal h-[40px] border-b border-t border-solid border-[#e4e3e2] ${
305
+ columnIndex < enhancedColumns.length - 1 ? 'border-r' : ''
306
+ }`}
307
+ style={{
308
+ width: column.size,
309
+ minWidth: column.minWidth,
310
+ textAlign: column.textAlign,
311
+ }}
312
+ >
313
+ {typeof column.header === 'function' ? column.header({ data: flatData }) : column.header}
314
+ </th>
315
+ ))}
316
+ </tr>
317
+ </thead>
318
+ <tbody>
319
+ {flatData.length > 0 ? (
320
+ flatData.map((row, index) => {
321
+ const isLastRow = index === flatData.length - 1;
322
+ return (
323
+ <tr
324
+ key={row.id}
325
+ className={`border-t ${isLastRow ? 'border-b' : ''} border-gray-200 hover:bg-[#dee1f2] ${selectedRows[row.id] ? 'bg-[#dee1f2]' : ''} ${rowClassName}`}
254
326
  style={{
255
- minWidth: `${column.minWidth}px`,
256
- textAlign: column?.textAlign,
257
- ...column?.cellProps?.style,
327
+ height: `${rowHeights}px`,
328
+ ...rowStyle,
329
+ ...(typeof rowStyle === 'function' ? rowStyle(row, index) : {})
258
330
  }}
331
+ onClick={() => handleRowClick(row, index, flatData)}
259
332
  >
260
- {typeof column.cell === 'function' ? column.cell({ row }) : null}
261
- </td>
262
- ))}
333
+ {enhancedColumns.map((column, cellIndex) => (
334
+ <td
335
+ key={column.accessorKey || column.id}
336
+ className={`text-left font-normal ${
337
+ cellIndex < enhancedColumns.length-1 ? 'border-r' : ''
338
+ } ${column?.cellProps?.className || ''}`}
339
+ style={{
340
+ minWidth: `${column.minWidth}px`,
341
+ textAlign: column?.textAlign,
342
+ ...column?.cellProps?.style,
343
+ }}
344
+ >
345
+ {typeof column.cell === 'function' ? column.cell({ row }) : null}
346
+ </td>
347
+ ))}
348
+ </tr>
349
+ );
350
+ })
351
+ ) : (
352
+ <tr>
353
+ <td colSpan={enhancedColumns.length} className="text-center py-4">
354
+ {emptyText || 'No data available'}
355
+ </td>
263
356
  </tr>
264
- ))
265
- ) : (
266
- <tr>
267
- <td colSpan={enhancedColumns.length} className="text-center py-4">
268
- {emptyText || 'No data available'}
269
- </td>
270
- </tr>
271
- )}
272
- </tbody>
273
- </table>
357
+ )}
358
+ </tbody>
359
+ </table>
360
+ </div>
274
361
  </div>
275
- </div>
276
- )}
277
- </div>
362
+ )
363
+ }
364
+ </div >
278
365
  );
279
366
  }
280
367