jattac.libs.web.responsive-table 0.2.1 → 0.2.3
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/README.md +626 -581
- package/dist/UI/ResponsiveTable.d.ts +4 -0
- package/dist/index.js +20 -3
- package/dist/index.js.map +1 -1
- package/gemini/project_memos.md +3 -0
- package/gemini/release_git_steps.md +79 -79
- package/package.json +1 -1
- package/src/Styles/ResponsiveTable.module.css +260 -253
- package/src/UI/ResponsiveTable.tsx +552 -532
package/README.md
CHANGED
|
@@ -1,581 +1,626 @@
|
|
|
1
|
-
# ResponsiveTable: A Modern and Flexible React Table Component
|
|
2
|
-
|
|
3
|
-
ResponsiveTable is a powerful, lightweight, and fully responsive React component for creating beautiful and functional tables. It’s designed to look great on any device, adapting from a traditional table layout on desktops to a clean, card-based view on mobile screens.
|
|
4
|
-
|
|
5
|
-
## Features
|
|
6
|
-
|
|
7
|
-
- **Mobile-First Design**: Automatically switches to a card layout on smaller screens for optimal readability.
|
|
8
|
-
- **Highly Customizable**: Tailor the look and feel of columns, headers, and footers.
|
|
9
|
-
- **Dynamic Data Handling**: Define columns and footers based on your data or application state.
|
|
10
|
-
- **Delightful Animations**: Includes an optional skeleton loader and staggered row entrance animations.
|
|
11
|
-
- **Interactive Elements**: Easily add click handlers for rows, headers, and footer cells.
|
|
12
|
-
- **Performant**: Built with performance in mind, including debounced resize handling.
|
|
13
|
-
- **Easy to Use**: A simple and intuitive API for quick integration.
|
|
14
|
-
- **Extensible Plugin System**: Easily add new functionalities like filtering, infinite scrolling, or custom behaviors.
|
|
15
|
-
|
|
16
|
-
## Installation
|
|
17
|
-
|
|
18
|
-
To get started, install the package from npm:
|
|
19
|
-
|
|
20
|
-
```bash
|
|
21
|
-
npm install jattac.libs.web.responsive-table
|
|
22
|
-
```
|
|
23
|
-
|
|
24
|
-
## Getting Started
|
|
25
|
-
|
|
26
|
-
Here’s a basic example to get you up and running in minutes.
|
|
27
|
-
|
|
28
|
-
```jsx
|
|
29
|
-
import React from 'react';
|
|
30
|
-
import ResponsiveTable from 'jattac.libs.web.responsive-table';
|
|
31
|
-
|
|
32
|
-
const GettingStarted = () => {
|
|
33
|
-
const columns = [
|
|
34
|
-
{ displayLabel: 'Name', dataKey: 'name', cellRenderer: (row) => row.name },
|
|
35
|
-
{ displayLabel: 'Age', dataKey: 'age', cellRenderer: (row) => row.age },
|
|
36
|
-
{ displayLabel: 'City', dataKey: 'city', cellRenderer: (row) => row.city },
|
|
37
|
-
];
|
|
38
|
-
|
|
39
|
-
const data = [
|
|
40
|
-
{ name: 'Alice', age: 32, city: 'New York' },
|
|
41
|
-
{ name: 'Bob', age: 28, city: 'Los Angeles' },
|
|
42
|
-
{ name: 'Charlie', age: 45, city: 'Chicago' },
|
|
43
|
-
];
|
|
44
|
-
|
|
45
|
-
return <ResponsiveTable columnDefinitions={columns} data={data} />;
|
|
46
|
-
};
|
|
47
|
-
|
|
48
|
-
export default GettingStarted;
|
|
49
|
-
```
|
|
50
|
-
|
|
51
|
-
This will render a table that automatically adapts to the screen size. On a desktop, it will look like a standard table, and on mobile, it will switch to a card-based layout.
|
|
52
|
-
|
|
53
|
-
---
|
|
54
|
-
|
|
55
|
-
## Comprehensive Examples
|
|
56
|
-
|
|
57
|
-
### Example 1: Loading State and Animations
|
|
58
|
-
|
|
59
|
-
You can provide a seamless user experience by showing a skeleton loader while your data is being fetched, and then animating the rows in when the data is ready.
|
|
60
|
-
|
|
61
|
-
```jsx
|
|
62
|
-
import React, { useState, useEffect } from 'react';
|
|
63
|
-
import ResponsiveTable from 'jattac.libs.web.responsive-table';
|
|
64
|
-
|
|
65
|
-
const AnimatedTable = () => {
|
|
66
|
-
const [data, setData] = useState([]);
|
|
67
|
-
const [isLoading, setIsLoading] = useState(true);
|
|
68
|
-
|
|
69
|
-
const columns = [
|
|
70
|
-
{ displayLabel: 'User', cellRenderer: (row) => row.name },
|
|
71
|
-
{ displayLabel: 'Email', cellRenderer: (row) => row.email },
|
|
72
|
-
];
|
|
73
|
-
|
|
74
|
-
useEffect(() => {
|
|
75
|
-
// Simulate a network request
|
|
76
|
-
setTimeout(() => {
|
|
77
|
-
setData([
|
|
78
|
-
{ name: 'Grace', email: 'grace@example.com' },
|
|
79
|
-
{ name: 'Henry', email: 'henry@example.com' },
|
|
80
|
-
]);
|
|
81
|
-
setIsLoading(false);
|
|
82
|
-
}, 2000);
|
|
83
|
-
}, []);
|
|
84
|
-
|
|
85
|
-
return <ResponsiveTable columnDefinitions={columns} data={data} animationProps={{ isLoading, animateOnLoad: true }} />;
|
|
86
|
-
};
|
|
87
|
-
```
|
|
88
|
-
|
|
89
|
-
### Example 2: Adding a Clickable Row Action
|
|
90
|
-
|
|
91
|
-
You can make rows clickable to perform actions, such as navigating to a details page or opening a modal.
|
|
92
|
-
|
|
93
|
-
```jsx
|
|
94
|
-
import React from 'react';
|
|
95
|
-
import ResponsiveTable from 'jattac.libs.web.responsive-table';
|
|
96
|
-
|
|
97
|
-
const ClickableRows = () => {
|
|
98
|
-
const columns = [
|
|
99
|
-
{ displayLabel: 'Product', cellRenderer: (row) => row.product },
|
|
100
|
-
{ displayLabel: 'Price', cellRenderer: (row) => `${row.price.toFixed(2)}` },
|
|
101
|
-
];
|
|
102
|
-
|
|
103
|
-
const data = [
|
|
104
|
-
{ id: 1, product: 'Laptop', price: 1200 },
|
|
105
|
-
{ id: 2, product: 'Keyboard', price: 75 },
|
|
106
|
-
];
|
|
107
|
-
|
|
108
|
-
const handleRowClick = (item) => {
|
|
109
|
-
alert(`You clicked on product ID: ${item.id}`);
|
|
110
|
-
};
|
|
111
|
-
|
|
112
|
-
return <ResponsiveTable columnDefinitions={columns} data={data} onRowClick={handleRowClick} />;
|
|
113
|
-
};
|
|
114
|
-
```
|
|
115
|
-
|
|
116
|
-
### Example 3: Custom Cell Rendering
|
|
117
|
-
|
|
118
|
-
You can render any React component inside a cell, allowing for rich content like buttons, links, or status badges.
|
|
119
|
-
|
|
120
|
-
```jsx
|
|
121
|
-
import React from 'react';
|
|
122
|
-
import ResponsiveTable from 'jattac.libs.web.responsive-table';
|
|
123
|
-
|
|
124
|
-
const CustomCells = () => {
|
|
125
|
-
const columns = [
|
|
126
|
-
{ displayLabel: 'User', cellRenderer: (row) => <strong>{row.user}</strong> },
|
|
127
|
-
{
|
|
128
|
-
displayLabel: 'Status',
|
|
129
|
-
cellRenderer: (row) => (
|
|
130
|
-
<span
|
|
131
|
-
style={{
|
|
132
|
-
color: row.status === 'Active' ? 'green' : 'red',
|
|
133
|
-
fontWeight: 'bold',
|
|
134
|
-
}}
|
|
135
|
-
>
|
|
136
|
-
{row.status}
|
|
137
|
-
</span>
|
|
138
|
-
),
|
|
139
|
-
},
|
|
140
|
-
{
|
|
141
|
-
displayLabel: 'Action',
|
|
142
|
-
cellRenderer: (row) => <button onClick={() => alert(`Editing ${row.user}`)}>Edit</button>,
|
|
143
|
-
},
|
|
144
|
-
];
|
|
145
|
-
|
|
146
|
-
const data = [
|
|
147
|
-
{ user: 'Eve', status: 'Active' },
|
|
148
|
-
{ user: 'Frank', status: 'Inactive' },
|
|
149
|
-
];
|
|
150
|
-
|
|
151
|
-
return <ResponsiveTable columnDefinitions={columns} data={data} />;
|
|
152
|
-
};
|
|
153
|
-
```
|
|
154
|
-
|
|
155
|
-
### Example 4: Dynamic and Conditional Columns
|
|
156
|
-
|
|
157
|
-
Columns can be generated dynamically based on your data or application state. This is useful for creating flexible tables that adapt to different datasets.
|
|
158
|
-
|
|
159
|
-
```jsx
|
|
160
|
-
import React from 'react';
|
|
161
|
-
import ResponsiveTable from 'jattac.libs.web.responsive-table';
|
|
162
|
-
|
|
163
|
-
const DynamicColumns = ({ isAdmin }) => {
|
|
164
|
-
// Base columns for all users
|
|
165
|
-
const columns = [
|
|
166
|
-
{ displayLabel: 'File Name', cellRenderer: (row) => row.fileName },
|
|
167
|
-
{ displayLabel: 'Size', cellRenderer: (row) => `${row.size} KB` },
|
|
168
|
-
];
|
|
169
|
-
|
|
170
|
-
// Add an admin-only column conditionally
|
|
171
|
-
if (isAdmin) {
|
|
172
|
-
columns.push({
|
|
173
|
-
displayLabel: 'Admin Actions',
|
|
174
|
-
cellRenderer: (row) => <button onClick={() => alert(`Deleting ${row.fileName}`)}>Delete</button>,
|
|
175
|
-
});
|
|
176
|
-
}
|
|
177
|
-
|
|
178
|
-
const data = [
|
|
179
|
-
{ fileName: 'document.pdf', size: 1024 },
|
|
180
|
-
{ fileName: 'image.jpg', size: 512 },
|
|
181
|
-
];
|
|
182
|
-
|
|
183
|
-
return <ResponsiveTable columnDefinitions={columns} data={data} />;
|
|
184
|
-
};
|
|
185
|
-
```
|
|
186
|
-
|
|
187
|
-
### Example 5: Advanced Footer with Labels and Interactivity
|
|
188
|
-
|
|
189
|
-
You can add a footer to display summary information, such as totals or averages. The footer is also responsive and will appear correctly in both desktop and mobile views. With the enhanced footer functionality, you can provide explicit labels for mobile view and add click handlers to footer cells.
|
|
190
|
-
|
|
191
|
-
```jsx
|
|
192
|
-
import React from 'react';
|
|
193
|
-
import ResponsiveTable from 'jattac.libs.web.responsive-table';
|
|
194
|
-
|
|
195
|
-
const TableWithFooter = () => {
|
|
196
|
-
const columns = [
|
|
197
|
-
{ displayLabel: 'Item', cellRenderer: (row) => row.item },
|
|
198
|
-
{ displayLabel: 'Quantity', cellRenderer: (row) => row.quantity },
|
|
199
|
-
{ displayLabel: 'Price', cellRenderer: (row) => `${row.price.toFixed(2)}` },
|
|
200
|
-
];
|
|
201
|
-
|
|
202
|
-
const data = [
|
|
203
|
-
{ item: 'Apples', quantity: 10, price: 1.5 },
|
|
204
|
-
{ item: 'Oranges', quantity: 5, price: 2.0 },
|
|
205
|
-
{ item: 'Bananas', quantity: 15, price: 0.5 },
|
|
206
|
-
];
|
|
207
|
-
|
|
208
|
-
const total = data.reduce((sum, row) => sum + row.quantity * row.price, 0);
|
|
209
|
-
|
|
210
|
-
const footerRows = [
|
|
211
|
-
{
|
|
212
|
-
columns: [
|
|
213
|
-
{
|
|
214
|
-
colSpan: 2,
|
|
215
|
-
cellRenderer: () => <strong>Total:</strong>,
|
|
216
|
-
},
|
|
217
|
-
{
|
|
218
|
-
colSpan: 1,
|
|
219
|
-
displayLabel: 'Total',
|
|
220
|
-
cellRenderer: () => <strong>${total.toFixed(2)}</strong>,
|
|
221
|
-
onCellClick: () => alert('Total clicked!'),
|
|
222
|
-
},
|
|
223
|
-
],
|
|
224
|
-
},
|
|
225
|
-
];
|
|
226
|
-
|
|
227
|
-
return <ResponsiveTable columnDefinitions={columns} data={data} footerRows={footerRows} />;
|
|
228
|
-
};
|
|
229
|
-
```
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
```jsx
|
|
242
|
-
import React from 'react';
|
|
243
|
-
import ResponsiveTable from 'jattac.libs.web.responsive-table';
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
const
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
{
|
|
255
|
-
{
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
import
|
|
288
|
-
import
|
|
289
|
-
|
|
290
|
-
const
|
|
291
|
-
const
|
|
292
|
-
{
|
|
293
|
-
{
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
{
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
|
324
|
-
|
|
|
325
|
-
| `
|
|
326
|
-
| `
|
|
327
|
-
|
|
328
|
-
**Example with `
|
|
329
|
-
|
|
330
|
-
```jsx
|
|
331
|
-
import React, { useState
|
|
332
|
-
import ResponsiveTable from 'jattac.libs.web.responsive-table';
|
|
333
|
-
|
|
334
|
-
const
|
|
335
|
-
const
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
};
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
)
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
this.
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
##
|
|
580
|
-
|
|
581
|
-
|
|
1
|
+
# ResponsiveTable: A Modern and Flexible React Table Component
|
|
2
|
+
|
|
3
|
+
ResponsiveTable is a powerful, lightweight, and fully responsive React component for creating beautiful and functional tables. It’s designed to look great on any device, adapting from a traditional table layout on desktops to a clean, card-based view on mobile screens.
|
|
4
|
+
|
|
5
|
+
## Features
|
|
6
|
+
|
|
7
|
+
- **Mobile-First Design**: Automatically switches to a card layout on smaller screens for optimal readability.
|
|
8
|
+
- **Highly Customizable**: Tailor the look and feel of columns, headers, and footers.
|
|
9
|
+
- **Dynamic Data Handling**: Define columns and footers based on your data or application state.
|
|
10
|
+
- **Delightful Animations**: Includes an optional skeleton loader and staggered row entrance animations.
|
|
11
|
+
- **Interactive Elements**: Easily add click handlers for rows, headers, and footer cells.
|
|
12
|
+
- **Performant**: Built with performance in mind, including debounced resize handling.
|
|
13
|
+
- **Easy to Use**: A simple and intuitive API for quick integration.
|
|
14
|
+
- **Extensible Plugin System**: Easily add new functionalities like filtering, infinite scrolling, or custom behaviors.
|
|
15
|
+
|
|
16
|
+
## Installation
|
|
17
|
+
|
|
18
|
+
To get started, install the package from npm:
|
|
19
|
+
|
|
20
|
+
```bash
|
|
21
|
+
npm install jattac.libs.web.responsive-table
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
## Getting Started
|
|
25
|
+
|
|
26
|
+
Here’s a basic example to get you up and running in minutes.
|
|
27
|
+
|
|
28
|
+
```jsx
|
|
29
|
+
import React from 'react';
|
|
30
|
+
import ResponsiveTable from 'jattac.libs.web.responsive-table';
|
|
31
|
+
|
|
32
|
+
const GettingStarted = () => {
|
|
33
|
+
const columns = [
|
|
34
|
+
{ displayLabel: 'Name', dataKey: 'name', cellRenderer: (row) => row.name },
|
|
35
|
+
{ displayLabel: 'Age', dataKey: 'age', cellRenderer: (row) => row.age },
|
|
36
|
+
{ displayLabel: 'City', dataKey: 'city', cellRenderer: (row) => row.city },
|
|
37
|
+
];
|
|
38
|
+
|
|
39
|
+
const data = [
|
|
40
|
+
{ name: 'Alice', age: 32, city: 'New York' },
|
|
41
|
+
{ name: 'Bob', age: 28, city: 'Los Angeles' },
|
|
42
|
+
{ name: 'Charlie', age: 45, city: 'Chicago' },
|
|
43
|
+
];
|
|
44
|
+
|
|
45
|
+
return <ResponsiveTable columnDefinitions={columns} data={data} />;
|
|
46
|
+
};
|
|
47
|
+
|
|
48
|
+
export default GettingStarted;
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
This will render a table that automatically adapts to the screen size. On a desktop, it will look like a standard table, and on mobile, it will switch to a card-based layout.
|
|
52
|
+
|
|
53
|
+
---
|
|
54
|
+
|
|
55
|
+
## Comprehensive Examples
|
|
56
|
+
|
|
57
|
+
### Example 1: Loading State and Animations
|
|
58
|
+
|
|
59
|
+
You can provide a seamless user experience by showing a skeleton loader while your data is being fetched, and then animating the rows in when the data is ready.
|
|
60
|
+
|
|
61
|
+
```jsx
|
|
62
|
+
import React, { useState, useEffect } from 'react';
|
|
63
|
+
import ResponsiveTable from 'jattac.libs.web.responsive-table';
|
|
64
|
+
|
|
65
|
+
const AnimatedTable = () => {
|
|
66
|
+
const [data, setData] = useState([]);
|
|
67
|
+
const [isLoading, setIsLoading] = useState(true);
|
|
68
|
+
|
|
69
|
+
const columns = [
|
|
70
|
+
{ displayLabel: 'User', cellRenderer: (row) => row.name },
|
|
71
|
+
{ displayLabel: 'Email', cellRenderer: (row) => row.email },
|
|
72
|
+
];
|
|
73
|
+
|
|
74
|
+
useEffect(() => {
|
|
75
|
+
// Simulate a network request
|
|
76
|
+
setTimeout(() => {
|
|
77
|
+
setData([
|
|
78
|
+
{ name: 'Grace', email: 'grace@example.com' },
|
|
79
|
+
{ name: 'Henry', email: 'henry@example.com' },
|
|
80
|
+
]);
|
|
81
|
+
setIsLoading(false);
|
|
82
|
+
}, 2000);
|
|
83
|
+
}, []);
|
|
84
|
+
|
|
85
|
+
return <ResponsiveTable columnDefinitions={columns} data={data} animationProps={{ isLoading, animateOnLoad: true }} />;
|
|
86
|
+
};
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
### Example 2: Adding a Clickable Row Action
|
|
90
|
+
|
|
91
|
+
You can make rows clickable to perform actions, such as navigating to a details page or opening a modal.
|
|
92
|
+
|
|
93
|
+
```jsx
|
|
94
|
+
import React from 'react';
|
|
95
|
+
import ResponsiveTable from 'jattac.libs.web.responsive-table';
|
|
96
|
+
|
|
97
|
+
const ClickableRows = () => {
|
|
98
|
+
const columns = [
|
|
99
|
+
{ displayLabel: 'Product', cellRenderer: (row) => row.product },
|
|
100
|
+
{ displayLabel: 'Price', cellRenderer: (row) => `${row.price.toFixed(2)}` },
|
|
101
|
+
];
|
|
102
|
+
|
|
103
|
+
const data = [
|
|
104
|
+
{ id: 1, product: 'Laptop', price: 1200 },
|
|
105
|
+
{ id: 2, product: 'Keyboard', price: 75 },
|
|
106
|
+
];
|
|
107
|
+
|
|
108
|
+
const handleRowClick = (item) => {
|
|
109
|
+
alert(`You clicked on product ID: ${item.id}`);
|
|
110
|
+
};
|
|
111
|
+
|
|
112
|
+
return <ResponsiveTable columnDefinitions={columns} data={data} onRowClick={handleRowClick} />;
|
|
113
|
+
};
|
|
114
|
+
```
|
|
115
|
+
|
|
116
|
+
### Example 3: Custom Cell Rendering
|
|
117
|
+
|
|
118
|
+
You can render any React component inside a cell, allowing for rich content like buttons, links, or status badges.
|
|
119
|
+
|
|
120
|
+
```jsx
|
|
121
|
+
import React from 'react';
|
|
122
|
+
import ResponsiveTable from 'jattac.libs.web.responsive-table';
|
|
123
|
+
|
|
124
|
+
const CustomCells = () => {
|
|
125
|
+
const columns = [
|
|
126
|
+
{ displayLabel: 'User', cellRenderer: (row) => <strong>{row.user}</strong> },
|
|
127
|
+
{
|
|
128
|
+
displayLabel: 'Status',
|
|
129
|
+
cellRenderer: (row) => (
|
|
130
|
+
<span
|
|
131
|
+
style={{
|
|
132
|
+
color: row.status === 'Active' ? 'green' : 'red',
|
|
133
|
+
fontWeight: 'bold',
|
|
134
|
+
}}
|
|
135
|
+
>
|
|
136
|
+
{row.status}
|
|
137
|
+
</span>
|
|
138
|
+
),
|
|
139
|
+
},
|
|
140
|
+
{
|
|
141
|
+
displayLabel: 'Action',
|
|
142
|
+
cellRenderer: (row) => <button onClick={() => alert(`Editing ${row.user}`)}>Edit</button>,
|
|
143
|
+
},
|
|
144
|
+
];
|
|
145
|
+
|
|
146
|
+
const data = [
|
|
147
|
+
{ user: 'Eve', status: 'Active' },
|
|
148
|
+
{ user: 'Frank', status: 'Inactive' },
|
|
149
|
+
];
|
|
150
|
+
|
|
151
|
+
return <ResponsiveTable columnDefinitions={columns} data={data} />;
|
|
152
|
+
};
|
|
153
|
+
```
|
|
154
|
+
|
|
155
|
+
### Example 4: Dynamic and Conditional Columns
|
|
156
|
+
|
|
157
|
+
Columns can be generated dynamically based on your data or application state. This is useful for creating flexible tables that adapt to different datasets.
|
|
158
|
+
|
|
159
|
+
```jsx
|
|
160
|
+
import React from 'react';
|
|
161
|
+
import ResponsiveTable from 'jattac.libs.web.responsive-table';
|
|
162
|
+
|
|
163
|
+
const DynamicColumns = ({ isAdmin }) => {
|
|
164
|
+
// Base columns for all users
|
|
165
|
+
const columns = [
|
|
166
|
+
{ displayLabel: 'File Name', cellRenderer: (row) => row.fileName },
|
|
167
|
+
{ displayLabel: 'Size', cellRenderer: (row) => `${row.size} KB` },
|
|
168
|
+
];
|
|
169
|
+
|
|
170
|
+
// Add an admin-only column conditionally
|
|
171
|
+
if (isAdmin) {
|
|
172
|
+
columns.push({
|
|
173
|
+
displayLabel: 'Admin Actions',
|
|
174
|
+
cellRenderer: (row) => <button onClick={() => alert(`Deleting ${row.fileName}`)}>Delete</button>,
|
|
175
|
+
});
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
const data = [
|
|
179
|
+
{ fileName: 'document.pdf', size: 1024 },
|
|
180
|
+
{ fileName: 'image.jpg', size: 512 },
|
|
181
|
+
];
|
|
182
|
+
|
|
183
|
+
return <ResponsiveTable columnDefinitions={columns} data={data} />;
|
|
184
|
+
};
|
|
185
|
+
```
|
|
186
|
+
|
|
187
|
+
### Example 5: Advanced Footer with Labels and Interactivity
|
|
188
|
+
|
|
189
|
+
You can add a footer to display summary information, such as totals or averages. The footer is also responsive and will appear correctly in both desktop and mobile views. With the enhanced footer functionality, you can provide explicit labels for mobile view and add click handlers to footer cells.
|
|
190
|
+
|
|
191
|
+
```jsx
|
|
192
|
+
import React from 'react';
|
|
193
|
+
import ResponsiveTable from 'jattac.libs.web.responsive-table';
|
|
194
|
+
|
|
195
|
+
const TableWithFooter = () => {
|
|
196
|
+
const columns = [
|
|
197
|
+
{ displayLabel: 'Item', cellRenderer: (row) => row.item },
|
|
198
|
+
{ displayLabel: 'Quantity', cellRenderer: (row) => row.quantity },
|
|
199
|
+
{ displayLabel: 'Price', cellRenderer: (row) => `${row.price.toFixed(2)}` },
|
|
200
|
+
];
|
|
201
|
+
|
|
202
|
+
const data = [
|
|
203
|
+
{ item: 'Apples', quantity: 10, price: 1.5 },
|
|
204
|
+
{ item: 'Oranges', quantity: 5, price: 2.0 },
|
|
205
|
+
{ item: 'Bananas', quantity: 15, price: 0.5 },
|
|
206
|
+
];
|
|
207
|
+
|
|
208
|
+
const total = data.reduce((sum, row) => sum + row.quantity * row.price, 0);
|
|
209
|
+
|
|
210
|
+
const footerRows = [
|
|
211
|
+
{
|
|
212
|
+
columns: [
|
|
213
|
+
{
|
|
214
|
+
colSpan: 2,
|
|
215
|
+
cellRenderer: () => <strong>Total:</strong>,
|
|
216
|
+
},
|
|
217
|
+
{
|
|
218
|
+
colSpan: 1,
|
|
219
|
+
displayLabel: 'Total',
|
|
220
|
+
cellRenderer: () => <strong>${total.toFixed(2)}</strong>,
|
|
221
|
+
onCellClick: () => alert('Total clicked!'),
|
|
222
|
+
},
|
|
223
|
+
],
|
|
224
|
+
},
|
|
225
|
+
];
|
|
226
|
+
|
|
227
|
+
return <ResponsiveTable columnDefinitions={columns} data={data} footerRows={footerRows} />;
|
|
228
|
+
};
|
|
229
|
+
```
|
|
230
|
+
|
|
231
|
+
### Example 6: Disabling the Page-Level Sticky Header (ELI5)
|
|
232
|
+
|
|
233
|
+
**Explain Like I'm 5:** Imagine you have a super long grocery list on a piece of paper (the webpage). The titles of the columns are "Item", "Quantity", and "Price" (the table header).
|
|
234
|
+
|
|
235
|
+
Normally, as you slide the paper up to see items at the bottom, the titles disappear off the top.
|
|
236
|
+
|
|
237
|
+
This table has a special power: by default, the header "sticks" to the top of your view so you never forget which column is which.
|
|
238
|
+
|
|
239
|
+
But what if you don't want it to stick? The `enablePageLevelStickyHeader={false}` prop is like a magic switch. Flipping it to `false` tells the header to scroll away normally with the rest of the page.
|
|
240
|
+
|
|
241
|
+
```jsx
|
|
242
|
+
import React from 'react';
|
|
243
|
+
import ResponsiveTable from 'jattac.libs.web.responsive-table';
|
|
244
|
+
|
|
245
|
+
const NonStickyHeaderTable = () => {
|
|
246
|
+
// We need enough data to make the page scroll
|
|
247
|
+
const data = Array.from({ length: 50 }, (_, i) => ({
|
|
248
|
+
id: i + 1,
|
|
249
|
+
item: `Item #${i + 1}`,
|
|
250
|
+
description: 'This is a sample item.',
|
|
251
|
+
}));
|
|
252
|
+
|
|
253
|
+
const columns = [
|
|
254
|
+
{ displayLabel: 'ID', cellRenderer: (row) => row.id },
|
|
255
|
+
{ displayLabel: 'Item', cellRenderer: (row) => row.item },
|
|
256
|
+
{ displayLabel: 'Description', cellRenderer: (row) => row.description },
|
|
257
|
+
];
|
|
258
|
+
|
|
259
|
+
return (
|
|
260
|
+
<div>
|
|
261
|
+
<h1 style={{ height: '50vh', display: 'flex', alignItems: 'center' }}>
|
|
262
|
+
Scroll down to see the table
|
|
263
|
+
</h1>
|
|
264
|
+
<ResponsiveTable
|
|
265
|
+
columnDefinitions={columns}
|
|
266
|
+
data={data}
|
|
267
|
+
enablePageLevelStickyHeader={false} // <-- Here's the magic switch!
|
|
268
|
+
/>
|
|
269
|
+
<div style={{ height: '50vh' }} />
|
|
270
|
+
</div>
|
|
271
|
+
);
|
|
272
|
+
};
|
|
273
|
+
```
|
|
274
|
+
|
|
275
|
+
---
|
|
276
|
+
|
|
277
|
+
## Plugin System
|
|
278
|
+
|
|
279
|
+
ResponsiveTable is designed with an extensible plugin system, allowing developers to easily add new functionalities or modify existing behaviors without altering the core component. Plugins can interact with the table's data, render custom UI elements (like headers or footers), and respond to table events.
|
|
280
|
+
|
|
281
|
+
### How to Use Plugins
|
|
282
|
+
|
|
283
|
+
Plugins are passed to the `ResponsiveTable` component via the `plugins` prop, which accepts an array of `IResponsiveTablePlugin` instances. Some common functionalities, like filtering and infinite scrolling, are provided as built-in plugins that can be enabled via specific props (`filterProps` and `infiniteScrollProps`). When these props are used, the corresponding built-in plugins are automatically initialized if not already provided in the `plugins` array.
|
|
284
|
+
|
|
285
|
+
```jsx
|
|
286
|
+
import React from 'react';
|
|
287
|
+
import ResponsiveTable from 'jattac.libs.web.responsive-table';
|
|
288
|
+
import { FilterPlugin } from 'jattac.libs.web.responsive-table/dist/Plugins/FilterPlugin'; // Adjust path as needed
|
|
289
|
+
|
|
290
|
+
const MyTableWithPlugins = () => {
|
|
291
|
+
const columns = [
|
|
292
|
+
{ displayLabel: 'Name', dataKey: 'name', cellRenderer: (row) => row.name, getFilterableValue: (row) => row.name },
|
|
293
|
+
{ displayLabel: 'Age', dataKey: 'age', cellRenderer: (row) => row.age, getFilterableValue: (row) => row.age.toString() },
|
|
294
|
+
];
|
|
295
|
+
|
|
296
|
+
const data = [
|
|
297
|
+
{ name: 'Alice', age: 32 },
|
|
298
|
+
{ name: 'Bob', age: 28 },
|
|
299
|
+
{ name: 'Charlie', age: 45 },
|
|
300
|
+
];
|
|
301
|
+
|
|
302
|
+
return (
|
|
303
|
+
<ResponsiveTable
|
|
304
|
+
columnDefinitions={columns}
|
|
305
|
+
data={data}
|
|
306
|
+
// Enable built-in filter plugin via props
|
|
307
|
+
filterProps={{ showFilter: true, filterPlaceholder: "Search by name or age..." }}
|
|
308
|
+
// Or provide a custom instance of the plugin
|
|
309
|
+
// plugins={[new FilterPlugin()]}
|
|
310
|
+
/>
|
|
311
|
+
);
|
|
312
|
+
};
|
|
313
|
+
```
|
|
314
|
+
|
|
315
|
+
### Built-in Plugins
|
|
316
|
+
|
|
317
|
+
#### `FilterPlugin`
|
|
318
|
+
|
|
319
|
+
Provides a search input to filter table data. It can be enabled by setting `filterProps.showFilter` to `true` on the `ResponsiveTable` component. For columns to be filterable, you must provide a `getFilterableValue` function in their `IResponsiveTableColumnDefinition`.
|
|
320
|
+
|
|
321
|
+
**Props for `FilterPlugin` (via `filterProps` on `ResponsiveTable`):**
|
|
322
|
+
|
|
323
|
+
| Prop | Type | Description |
|
|
324
|
+
| ----------------- | -------- | --------------------------------------------------------------------------- |
|
|
325
|
+
| `showFilter` | `boolean`| If `true`, displays a filter input field above the table. |
|
|
326
|
+
| `filterPlaceholder`| `string` | Placeholder text for the filter input. Defaults to "Search...". |
|
|
327
|
+
|
|
328
|
+
**Example with `FilterPlugin`:**
|
|
329
|
+
|
|
330
|
+
```jsx
|
|
331
|
+
import React, { useState } from 'react';
|
|
332
|
+
import ResponsiveTable from 'jattac.libs.web.responsive-table';
|
|
333
|
+
|
|
334
|
+
const FilterableTable = () => {
|
|
335
|
+
const initialData = [
|
|
336
|
+
{ id: 1, name: 'Alice', email: 'alice@example.com' },
|
|
337
|
+
{ id: 2, name: 'Bob', email: 'bob@example.com' },
|
|
338
|
+
{ id: 3, name: 'Charlie', email: 'charlie@example.com' },
|
|
339
|
+
{ id: 4, name: 'David', email: 'david@example.com' },
|
|
340
|
+
];
|
|
341
|
+
|
|
342
|
+
const columns = [
|
|
343
|
+
{ displayLabel: 'ID', cellRenderer: (row) => row.id, getFilterableValue: (row) => row.id.toString() },
|
|
344
|
+
{ displayLabel: 'Name', cellRenderer: (row) => row.name, getFilterableValue: (row) => row.name },
|
|
345
|
+
{ displayLabel: 'Email', cellRenderer: (row) => row.email, getFilterableValue: (row) => row.email },
|
|
346
|
+
];
|
|
347
|
+
|
|
348
|
+
return (
|
|
349
|
+
<ResponsiveTable
|
|
350
|
+
columnDefinitions={columns}
|
|
351
|
+
data={initialData}
|
|
352
|
+
filterProps={{ showFilter: true, filterPlaceholder: "Filter users..." }}
|
|
353
|
+
/>
|
|
354
|
+
);
|
|
355
|
+
};
|
|
356
|
+
```
|
|
357
|
+
|
|
358
|
+
#### `InfiniteScrollPlugin`
|
|
359
|
+
|
|
360
|
+
Enables infinite scrolling for the table, loading more data as the user scrolls to the bottom. This plugin requires the `maxHeight` prop to be set on the `ResponsiveTable` to define a scrollable area.
|
|
361
|
+
|
|
362
|
+
**Props for `InfiniteScrollPlugin` (via `infiniteScrollProps` on `ResponsiveTable`):**
|
|
363
|
+
|
|
364
|
+
| Prop | Type | Description |
|
|
365
|
+
| --------------------- | ------------------------------------ | --------------------------------------------------------------------------- |
|
|
366
|
+
| `enableInfiniteScroll`| `boolean` | If `true`, enables infinite scrolling. |
|
|
367
|
+
| `onLoadMore` | `(currentData: TData[]) => Promise<TData[] | null>` | Callback function to load more data. Should return a Promise resolving to new data or `null`. |
|
|
368
|
+
| `hasMore` | `boolean` | Indicates if there is more data to load. |
|
|
369
|
+
| `loadingMoreComponent`| `ReactNode` | Custom component to display while loading more data. Defaults to "Loading more...". |
|
|
370
|
+
| `noMoreDataComponent` | `ReactNode` | Custom component to display when no more data is available. Defaults to "No more data.". |
|
|
371
|
+
|
|
372
|
+
**Example with `InfiniteScrollPlugin`:**
|
|
373
|
+
|
|
374
|
+
```jsx
|
|
375
|
+
import React, { useState, useEffect } from 'react';
|
|
376
|
+
import ResponsiveTable from 'jattac.libs.web.responsive-table';
|
|
377
|
+
|
|
378
|
+
const InfiniteScrollTable = () => {
|
|
379
|
+
const [data, setData] = useState([]);
|
|
380
|
+
const [hasMore, setHasMore] = useState(true);
|
|
381
|
+
const [page, setPage] = useState(0);
|
|
382
|
+
|
|
383
|
+
const fetchData = async (currentPage) => {
|
|
384
|
+
// Simulate API call
|
|
385
|
+
return new Promise((resolve) => {
|
|
386
|
+
setTimeout(() => {
|
|
387
|
+
const newData = [];
|
|
388
|
+
for (let i = 0; i < 10; i++) {
|
|
389
|
+
newData.push({ id: currentPage * 10 + i, value: `Item ${currentPage * 10 + i}` });
|
|
390
|
+
}
|
|
391
|
+
resolve(newData);
|
|
392
|
+
}, 500);
|
|
393
|
+
});
|
|
394
|
+
};
|
|
395
|
+
|
|
396
|
+
useEffect(() => {
|
|
397
|
+
fetchData(0).then(initialData => {
|
|
398
|
+
setData(initialData);
|
|
399
|
+
setPage(1);
|
|
400
|
+
});
|
|
401
|
+
}, []);
|
|
402
|
+
|
|
403
|
+
const onLoadMore = async (currentData) => {
|
|
404
|
+
if (!hasMore) return null;
|
|
405
|
+
|
|
406
|
+
const newItems = await fetchData(page);
|
|
407
|
+
if (newItems.length === 0) {
|
|
408
|
+
setHasMore(false);
|
|
409
|
+
return null;
|
|
410
|
+
}
|
|
411
|
+
setData((prevData) => [...prevData, ...newItems]);
|
|
412
|
+
setPage((prevPage) => prevPage + 1);
|
|
413
|
+
return newItems; // Return new items for the plugin to know data was loaded
|
|
414
|
+
};
|
|
415
|
+
|
|
416
|
+
const columns = [
|
|
417
|
+
{ displayLabel: 'ID', cellRenderer: (row) => row.id },
|
|
418
|
+
{ displayLabel: 'Value', cellRenderer: (row) => row.value },
|
|
419
|
+
];
|
|
420
|
+
|
|
421
|
+
return (
|
|
422
|
+
<div style={{ height: '300px' }}> {/* Container for scrollable table */}
|
|
423
|
+
<ResponsiveTable
|
|
424
|
+
columnDefinitions={columns}
|
|
425
|
+
data={data}
|
|
426
|
+
maxHeight="100%"
|
|
427
|
+
infiniteScrollProps={{
|
|
428
|
+
enableInfiniteScroll: true,
|
|
429
|
+
onLoadMore: onLoadMore,
|
|
430
|
+
hasMore: hasMore,
|
|
431
|
+
loadingMoreComponent: <div>Loading more items...</div>,
|
|
432
|
+
noMoreDataComponent: <div>All items loaded.</div>,
|
|
433
|
+
}}
|
|
434
|
+
/>
|
|
435
|
+
</div>
|
|
436
|
+
);
|
|
437
|
+
};
|
|
438
|
+
```
|
|
439
|
+
|
|
440
|
+
### Extending Functionality with Custom Plugins
|
|
441
|
+
|
|
442
|
+
Developers can create their own custom plugins to add unique features to the `ResponsiveTable`. This is achieved by implementing the `IResponsiveTablePlugin` interface.
|
|
443
|
+
|
|
444
|
+
**`IResponsiveTablePlugin<TData>` Interface:**
|
|
445
|
+
|
|
446
|
+
| Property | Type | Description |
|
|
447
|
+
| -------------- | ------------------------------------ | --------------------------------------------------------------------------- |
|
|
448
|
+
| `id` | `string` | A unique identifier for the plugin. |
|
|
449
|
+
| `renderHeader?`| `() => ReactNode` | Optional. A function that returns a React component to be rendered above the table. |
|
|
450
|
+
| `renderFooter?`| `() => ReactNode` | Optional. A function that returns a React component to be rendered below the table. |
|
|
451
|
+
| `processData?` | `(data: TData[]) => TData[]` | Optional. A function that processes the table data before it is rendered. Useful for sorting, filtering, or transforming data. |
|
|
452
|
+
| `onPluginInit?`| `(api: IPluginAPI<TData>) => void` | Optional. A callback function that provides the plugin with an API to interact with the `ResponsiveTable` component. |
|
|
453
|
+
|
|
454
|
+
**`IPluginAPI<TData>` Interface:**
|
|
455
|
+
|
|
456
|
+
This interface provides methods and properties for plugins to interact with the `ResponsiveTable` component.
|
|
457
|
+
|
|
458
|
+
| Property | Type | Description |
|
|
459
|
+
| -------------------- | ------------------------------------ | --------------------------------------------------------------------------- |
|
|
460
|
+
| `getData` | `() => TData[]` | Returns the current raw data array being used by the table. |
|
|
461
|
+
| `forceUpdate` | `() => void` | Forces the `ResponsiveTable` component to re-render. Useful after a plugin modifies internal state that affects rendering. |
|
|
462
|
+
| `columnDefinitions` | `ColumnDefinition<TData>[]` | Provides access to the table's column definitions. |
|
|
463
|
+
| `getScrollableElement?`| `() => HTMLElement | null` | Optional. Returns the HTML element that is scrollable, if `maxHeight` is set. Useful for implementing scroll-based features. |
|
|
464
|
+
| `infiniteScrollProps?`| `object` | Optional. Provides access to the `infiniteScrollProps` passed to the `ResponsiveTable`. |
|
|
465
|
+
| `filterProps?` | `object` | Optional. Provides access to the `filterProps` passed to the `ResponsiveTable`. |
|
|
466
|
+
|
|
467
|
+
**Example: Custom Sorting Plugin**
|
|
468
|
+
|
|
469
|
+
This example demonstrates a simple sorting plugin that allows sorting by a specified column.
|
|
470
|
+
|
|
471
|
+
```typescript
|
|
472
|
+
// src/Plugins/SortPlugin.ts
|
|
473
|
+
import React from 'react';
|
|
474
|
+
import { IResponsiveTablePlugin, IPluginAPI } from './IResponsiveTablePlugin';
|
|
475
|
+
import IResponsiveTableColumnDefinition from '../Data/IResponsiveTableColumnDefinition';
|
|
476
|
+
|
|
477
|
+
export class SortPlugin<TData> implements IResponsiveTablePlugin<TData> {
|
|
478
|
+
public id = 'sort';
|
|
479
|
+
private api!: IPluginAPI<TData>;
|
|
480
|
+
private sortColumn: string | null = null;
|
|
481
|
+
private sortDirection: 'asc' | 'desc' = 'asc';
|
|
482
|
+
|
|
483
|
+
public onPluginInit = (api: IPluginAPI<TData>) => {
|
|
484
|
+
this.api = api;
|
|
485
|
+
};
|
|
486
|
+
|
|
487
|
+
public renderHeader = () => {
|
|
488
|
+
return (
|
|
489
|
+
<div style={{ marginBottom: '1rem' }}>
|
|
490
|
+
Sort by:
|
|
491
|
+
<select onChange={this.handleColumnChange} style={{ marginLeft: '0.5rem' }}>
|
|
492
|
+
<option value="">None</option>
|
|
493
|
+
{this.api.columnDefinitions.map((colDef) => {
|
|
494
|
+
const rawColDef = colDef as IResponsiveTableColumnDefinition<TData>;
|
|
495
|
+
if (rawColDef.dataKey) {
|
|
496
|
+
return <option key={rawColDef.dataKey} value={rawColDef.dataKey}>{rawColDef.displayLabel}</option>;
|
|
497
|
+
}
|
|
498
|
+
return null;
|
|
499
|
+
})}
|
|
500
|
+
</select>
|
|
501
|
+
{this.sortColumn && (
|
|
502
|
+
<button onClick={this.toggleSortDirection} style={{ marginLeft: '0.5rem' }}>
|
|
503
|
+
{this.sortDirection === 'asc' ? 'Ascending' : 'Descending'}
|
|
504
|
+
</button>
|
|
505
|
+
)}
|
|
506
|
+
</div>
|
|
507
|
+
);
|
|
508
|
+
};
|
|
509
|
+
|
|
510
|
+
public processData = (data: TData[]): TData[] => {
|
|
511
|
+
if (!this.sortColumn) {
|
|
512
|
+
return data;
|
|
513
|
+
}
|
|
514
|
+
|
|
515
|
+
const sortedData = [...data].sort((a, b) => {
|
|
516
|
+
const aValue = a[this.sortColumn as keyof TData];
|
|
517
|
+
const bValue = b[this.sortColumn as keyof TData];
|
|
518
|
+
|
|
519
|
+
if (aValue < bValue) return this.sortDirection === 'asc' ? -1 : 1;
|
|
520
|
+
if (aValue > bValue) return this.sortDirection === 'asc' ? 1 : -1;
|
|
521
|
+
return 0;
|
|
522
|
+
});
|
|
523
|
+
|
|
524
|
+
return sortedData;
|
|
525
|
+
};
|
|
526
|
+
|
|
527
|
+
private handleColumnChange = (e: React.ChangeEvent<HTMLSelectElement>) => {
|
|
528
|
+
this.sortColumn = e.target.value || null;
|
|
529
|
+
this.api.forceUpdate();
|
|
530
|
+
};
|
|
531
|
+
|
|
532
|
+
private toggleSortDirection = () => {
|
|
533
|
+
this.sortDirection = this.sortDirection === 'asc' ? 'desc' : 'asc';
|
|
534
|
+
this.api.forceUpdate();
|
|
535
|
+
};
|
|
536
|
+
}
|
|
537
|
+
|
|
538
|
+
// Usage in your component:
|
|
539
|
+
```jsx
|
|
540
|
+
import React from 'react';
|
|
541
|
+
import ResponsiveTable from 'jattac.libs.web.responsive-table';
|
|
542
|
+
import { SortPlugin } from './SortPlugin'; // Assuming SortPlugin.ts is in the same directory
|
|
543
|
+
|
|
544
|
+
const SortableTable = () => {
|
|
545
|
+
const data = [
|
|
546
|
+
{ id: 1, name: 'Alice', age: 30 },
|
|
547
|
+
{ id: 2, name: 'Bob', age: 25 },
|
|
548
|
+
{ id: 3, name: 'Charlie', age: 35 },
|
|
549
|
+
];
|
|
550
|
+
|
|
551
|
+
const columns = [
|
|
552
|
+
{ displayLabel: 'ID', dataKey: 'id', cellRenderer: (row) => row.id },
|
|
553
|
+
{ displayLabel: 'Name', dataKey: 'name', cellRenderer: (row) => row.name },
|
|
554
|
+
{ displayLabel: 'Age', dataKey: 'age', cellRenderer: (row) => row.age },
|
|
555
|
+
];
|
|
556
|
+
|
|
557
|
+
return (
|
|
558
|
+
<ResponsiveTable
|
|
559
|
+
columnDefinitions={columns}
|
|
560
|
+
data={data}
|
|
561
|
+
plugins={[new SortPlugin()]}
|
|
562
|
+
/>
|
|
563
|
+
);
|
|
564
|
+
};
|
|
565
|
+
```
|
|
566
|
+
|
|
567
|
+
**Other Plugin Ideas (beyond Filtering and Infinite Scroll):**
|
|
568
|
+
|
|
569
|
+
- **Column Resizing Plugin:** Allows users to drag column headers to resize columns.
|
|
570
|
+
- **Row Selection Plugin:** Adds checkboxes to rows for multi-row selection.
|
|
571
|
+
- **Export Data Plugin:** Provides buttons to export table data to CSV, Excel, or PDF.
|
|
572
|
+
- **Drag-and-Drop Reordering Plugin:** Enables reordering of rows or columns via drag and drop.
|
|
573
|
+
- **Column Visibility Toggle Plugin:** Allows users to show/hide specific columns.
|
|
574
|
+
|
|
575
|
+
---
|
|
576
|
+
|
|
577
|
+
---
|
|
578
|
+
|
|
579
|
+
## API Reference
|
|
580
|
+
|
|
581
|
+
### `ResponsiveTable` Props
|
|
582
|
+
|
|
583
|
+
| Prop | Type | Required | Description |
|
|
584
|
+
| ----------------------------- | ------------------------------------ | -------- | ----------------------------------------------------------------------------------------------------------- |
|
|
585
|
+
| `columnDefinitions` | `IResponsiveTableColumnDefinition[]` | Yes | An array of objects defining the table columns. |
|
|
586
|
+
| `data` | `TData[]` | Yes | An array of data objects to populate the table rows. |
|
|
587
|
+
| `footerRows` | `IFooterRowDefinition[]` | No | An array of objects defining the table footer. |
|
|
588
|
+
| `onRowClick` | `(item: TData) => void` | No | A callback function that is triggered when a row is clicked. |
|
|
589
|
+
| `noDataComponent` | `ReactNode` | No | A custom component to display when there is no data. |
|
|
590
|
+
| `maxHeight` | `string` | No | Sets a maximum height for the table body, making it scrollable. |
|
|
591
|
+
| `mobileBreakpoint` | `number` | No | The pixel width at which the table switches to the mobile view. Defaults to `600`. |
|
|
592
|
+
| `enablePageLevelStickyHeader` | `boolean` | No | If `false`, disables the header from sticking to the top of the page on scroll. Defaults to `true`. |
|
|
593
|
+
| `plugins` | `IResponsiveTablePlugin<TData>[]` | No | An array of plugin instances to extend table functionality. |
|
|
594
|
+
| `infiniteScrollProps` | `object` | No | Configuration for the built-in infinite scroll plugin. |
|
|
595
|
+
| `filterProps` | `object` | No | Configuration for the built-in filter plugin. |
|
|
596
|
+
| `animationProps` | `object` | No | Configuration for animations, including `isLoading` and `animateOnLoad`. |
|
|
597
|
+
|
|
598
|
+
### `IResponsiveTableColumnDefinition`
|
|
599
|
+
|
|
600
|
+
| Property | Type | Required | Description |
|
|
601
|
+
| --------------- | --------------------------- | -------- | ------------------------------------------------------------------------------ |
|
|
602
|
+
| `displayLabel` | `string` | Yes | The label displayed in the table header. |
|
|
603
|
+
| `cellRenderer` | `(row: TData) => ReactNode` | Yes | A function that returns the content to be rendered in the cell. |
|
|
604
|
+
| `dataKey` | `string` | No | A key to match the column to a property in the data object (optional). |
|
|
605
|
+
| `interactivity` | `object` | No | An object to define header interactivity (`onHeaderClick`, `id`, `className`). |
|
|
606
|
+
| `getFilterableValue`| `(row: TData) => string` | No | A function that returns the string value to be used for filtering this column. Required for `FilterPlugin`. |
|
|
607
|
+
|
|
608
|
+
### `IFooterRowDefinition`
|
|
609
|
+
|
|
610
|
+
| Property | Type | Required | Description |
|
|
611
|
+
| --------- | --------------------------- | -------- | -------------------------------------------------- |
|
|
612
|
+
| `columns` | `IFooterColumnDefinition[]` | Yes | An array of column definitions for the footer row. |
|
|
613
|
+
|
|
614
|
+
### `IFooterColumnDefinition`
|
|
615
|
+
|
|
616
|
+
| Property | Type | Required | Description |
|
|
617
|
+
| -------------- | ----------------- | -------- | ------------------------------------------------------------------------------ |
|
|
618
|
+
| `colSpan` | `number` | Yes | The number of columns the footer cell should span. |
|
|
619
|
+
| `cellRenderer` | `() => ReactNode` | Yes | A function that returns the content for the footer cell. |
|
|
620
|
+
| `displayLabel` | `ReactNode` | No | An optional, explicit label for the footer cell. In mobile view, if `colSpan` is 1 and this is not provided, the corresponding column header will be used as a fallback. This is required for `colSpan` > 1 if you want a label to be displayed. |
|
|
621
|
+
| `onCellClick` | `() => void` | No | An optional click handler for the footer cell. |
|
|
622
|
+
| `className` | `string` | No | Optional class name for custom styling of the footer cell. |
|
|
623
|
+
|
|
624
|
+
## License
|
|
625
|
+
|
|
626
|
+
This project is licensed under the MIT License.
|