jattac.libs.web.responsive-table 0.2.3 → 0.2.5
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 +203 -192
- package/dist/Data/IResponsiveTableColumnDefinition.d.ts +4 -0
- package/dist/Plugins/SortPlugin.d.ts +29 -0
- package/dist/UI/ResponsiveTable.d.ts +1 -0
- package/dist/index.d.ts +2 -1
- package/dist/index.js +118 -5
- package/dist/index.js.map +1 -1
- package/package.json +11 -5
- package/.eslintrc.json +0 -8
- package/.prettierrc +0 -5
- package/gemini/index.md +0 -1
- package/gemini/project_analysis.md +0 -41
- package/gemini/project_memos.md +0 -3
- package/gemini/release_git_steps.md +0 -80
- package/rollup.config.js +0 -23
- package/set-origin-urls.sh +0 -32
- package/src/Data/IFooterColumnDefinition.ts +0 -21
- package/src/Data/IFooterRowDefinition.ts +0 -5
- package/src/Data/IResponsiveTableColumnDefinition.tsx +0 -12
- package/src/Plugins/FilterPlugin.tsx +0 -71
- package/src/Plugins/IResponsiveTablePlugin.ts +0 -48
- package/src/Plugins/InfiniteScrollPlugin.tsx +0 -73
- package/src/Styles/ResponsiveTable.module.css +0 -260
- package/src/UI/ResponsiveTable.tsx +0 -552
- package/src/index.tsx +0 -10
- package/src/typings.d.ts +0 -14
- package/tsconfig.json +0 -22
- package/update-dependancies.sh +0 -4
package/README.md
CHANGED
|
@@ -11,7 +11,7 @@ ResponsiveTable is a powerful, lightweight, and fully responsive React component
|
|
|
11
11
|
- **Interactive Elements**: Easily add click handlers for rows, headers, and footer cells.
|
|
12
12
|
- **Performant**: Built with performance in mind, including debounced resize handling.
|
|
13
13
|
- **Easy to Use**: A simple and intuitive API for quick integration.
|
|
14
|
-
- **Extensible Plugin System**: Easily add new functionalities like filtering,
|
|
14
|
+
- **Extensible Plugin System**: Easily add new functionalities like filtering, sorting, or infinite scrolling.
|
|
15
15
|
|
|
16
16
|
## Installation
|
|
17
17
|
|
|
@@ -82,7 +82,9 @@ const AnimatedTable = () => {
|
|
|
82
82
|
}, 2000);
|
|
83
83
|
}, []);
|
|
84
84
|
|
|
85
|
-
return
|
|
85
|
+
return (
|
|
86
|
+
<ResponsiveTable columnDefinitions={columns} data={data} animationProps={{ isLoading, animateOnLoad: true }} />
|
|
87
|
+
);
|
|
86
88
|
};
|
|
87
89
|
```
|
|
88
90
|
|
|
@@ -123,7 +125,7 @@ import ResponsiveTable from 'jattac.libs.web.responsive-table';
|
|
|
123
125
|
|
|
124
126
|
const CustomCells = () => {
|
|
125
127
|
const columns = [
|
|
126
|
-
{ displayLabel:
|
|
128
|
+
{ displayLabel: <strong>User</strong>, cellRenderer: (row) => <strong>{row.user}</strong> },
|
|
127
129
|
{
|
|
128
130
|
displayLabel: 'Status',
|
|
129
131
|
cellRenderer: (row) => (
|
|
@@ -258,9 +260,7 @@ const NonStickyHeaderTable = () => {
|
|
|
258
260
|
|
|
259
261
|
return (
|
|
260
262
|
<div>
|
|
261
|
-
<h1 style={{ height: '50vh', display: 'flex', alignItems: 'center' }}>
|
|
262
|
-
Scroll down to see the table
|
|
263
|
-
</h1>
|
|
263
|
+
<h1 style={{ height: '50vh', display: 'flex', alignItems: 'center' }}>Scroll down to see the table</h1>
|
|
264
264
|
<ResponsiveTable
|
|
265
265
|
columnDefinitions={columns}
|
|
266
266
|
data={data}
|
|
@@ -284,13 +284,18 @@ Plugins are passed to the `ResponsiveTable` component via the `plugins` prop, wh
|
|
|
284
284
|
|
|
285
285
|
```jsx
|
|
286
286
|
import React from 'react';
|
|
287
|
-
|
|
288
|
-
import { FilterPlugin } from 'jattac.libs.web.responsive-table
|
|
287
|
+
// Note: All plugins are exported from the main package entry point.
|
|
288
|
+
import ResponsiveTable, { FilterPlugin } from 'jattac.libs.web.responsive-table';
|
|
289
289
|
|
|
290
290
|
const MyTableWithPlugins = () => {
|
|
291
291
|
const columns = [
|
|
292
292
|
{ displayLabel: 'Name', dataKey: 'name', cellRenderer: (row) => row.name, getFilterableValue: (row) => row.name },
|
|
293
|
-
{
|
|
293
|
+
{
|
|
294
|
+
displayLabel: 'Age',
|
|
295
|
+
dataKey: 'age',
|
|
296
|
+
cellRenderer: (row) => row.age,
|
|
297
|
+
getFilterableValue: (row) => row.age.toString(),
|
|
298
|
+
},
|
|
294
299
|
];
|
|
295
300
|
|
|
296
301
|
const data = [
|
|
@@ -304,7 +309,7 @@ const MyTableWithPlugins = () => {
|
|
|
304
309
|
columnDefinitions={columns}
|
|
305
310
|
data={data}
|
|
306
311
|
// Enable built-in filter plugin via props
|
|
307
|
-
filterProps={{ showFilter: true, filterPlaceholder:
|
|
312
|
+
filterProps={{ showFilter: true, filterPlaceholder: 'Search by name or age...' }}
|
|
308
313
|
// Or provide a custom instance of the plugin
|
|
309
314
|
// plugins={[new FilterPlugin()]}
|
|
310
315
|
/>
|
|
@@ -314,21 +319,160 @@ const MyTableWithPlugins = () => {
|
|
|
314
319
|
|
|
315
320
|
### Built-in Plugins
|
|
316
321
|
|
|
322
|
+
#### `SortPlugin`
|
|
323
|
+
|
|
324
|
+
The `SortPlugin` provides powerful, type-safe, and highly customizable column sorting. It adds intuitive UI cues, allowing users to click column headers to sort the data in ascending, descending, or original order.
|
|
325
|
+
|
|
326
|
+
**Enabling the `SortPlugin`:**
|
|
327
|
+
|
|
328
|
+
To use the plugin, you must first import it and provide a generic instance of it to the `plugins` prop. The real power comes from making the plugin instance generic with your data type, which provides type-safety and IDE autocompletion for the sort comparer helpers.
|
|
329
|
+
|
|
330
|
+
```jsx
|
|
331
|
+
import React from 'react';
|
|
332
|
+
import ResponsiveTable, { IResponsiveTableColumnDefinition, SortPlugin } from 'jattac.libs.web.responsive-table';
|
|
333
|
+
|
|
334
|
+
// Define the shape of your data
|
|
335
|
+
interface User {
|
|
336
|
+
id: number;
|
|
337
|
+
name: string;
|
|
338
|
+
signupDate: string;
|
|
339
|
+
logins: number;
|
|
340
|
+
}
|
|
341
|
+
|
|
342
|
+
// 1. Create a single, generic instance of the plugin.
|
|
343
|
+
// This is the ONLY setup step required.
|
|
344
|
+
const sortPlugin = new SortPlugin<User>({
|
|
345
|
+
initialSortColumn: 'logins',
|
|
346
|
+
initialSortDirection: 'desc',
|
|
347
|
+
});
|
|
348
|
+
|
|
349
|
+
// 2. Define the columns, using the helpers directly from the plugin instance.
|
|
350
|
+
const columnDefinitions: IResponsiveTableColumnDefinition<User>[] = [
|
|
351
|
+
// ... see examples below
|
|
352
|
+
];
|
|
353
|
+
|
|
354
|
+
const UserTable = ({ users }) => (
|
|
355
|
+
<ResponsiveTable
|
|
356
|
+
columnDefinitions={columnDefinitions}
|
|
357
|
+
data={users}
|
|
358
|
+
// 3. Pass the already-configured plugin to the table.
|
|
359
|
+
plugins={[sortPlugin]}
|
|
360
|
+
/>
|
|
361
|
+
);
|
|
362
|
+
```
|
|
363
|
+
|
|
364
|
+
**How to Make Columns Sortable (Opt-In):**
|
|
365
|
+
|
|
366
|
+
A column is made sortable by adding either a `sortComparer` or a `getSortableValue` property to its definition.
|
|
367
|
+
|
|
368
|
+
- `sortComparer`: A function that defines the exact comparison logic. This is the most powerful option and should be used for complex data types or custom logic.
|
|
369
|
+
- `getSortableValue`: A simpler function that just returns the primitive value (string, number, etc.) to be used in a default comparison.
|
|
370
|
+
|
|
371
|
+
**Example 1: Using Type-Safe Comparer Helpers**
|
|
372
|
+
|
|
373
|
+
The `SortPlugin` instance provides a `comparers` object with pre-built, type-safe helper functions to eliminate boilerplate for common sorting scenarios. This is the recommended approach.
|
|
374
|
+
|
|
375
|
+
```jsx
|
|
376
|
+
const columnDefinitions: IResponsiveTableColumnDefinition<User>[] = [
|
|
377
|
+
{
|
|
378
|
+
displayLabel: 'Name',
|
|
379
|
+
dataKey: 'name',
|
|
380
|
+
cellRenderer: (user) => user.name,
|
|
381
|
+
// The plugin instance itself provides the type-safe helpers.
|
|
382
|
+
// The string 'name' is fully type-checked against the User interface.
|
|
383
|
+
sortComparer: sortPlugin.comparers.caseInsensitiveString('name'),
|
|
384
|
+
},
|
|
385
|
+
{
|
|
386
|
+
displayLabel: 'Signup Date',
|
|
387
|
+
dataKey: 'signupDate',
|
|
388
|
+
cellRenderer: (user) => new Date(user.signupDate).toLocaleDateString(),
|
|
389
|
+
// IDE autocompletion for 'signupDate' works perfectly.
|
|
390
|
+
sortComparer: sortPlugin.comparers.date('signupDate'),
|
|
391
|
+
},
|
|
392
|
+
{
|
|
393
|
+
displayLabel: 'Logins',
|
|
394
|
+
dataKey: 'logins',
|
|
395
|
+
cellRenderer: (user) => user.logins,
|
|
396
|
+
sortComparer: sortPlugin.comparers.numeric('logins'),
|
|
397
|
+
},
|
|
398
|
+
{
|
|
399
|
+
displayLabel: 'Actions',
|
|
400
|
+
// This column is NOT sortable because it has no sort-related properties.
|
|
401
|
+
cellRenderer: (user) => <button>View</button>,
|
|
402
|
+
},
|
|
403
|
+
];
|
|
404
|
+
```
|
|
405
|
+
|
|
406
|
+
**Example 2: Writing a Custom `sortComparer`**
|
|
407
|
+
|
|
408
|
+
For unique requirements, you can write your own comparison function from scratch.
|
|
409
|
+
|
|
410
|
+
```jsx
|
|
411
|
+
const columnDefinitions: IResponsiveTableColumnDefinition<User>[] = [
|
|
412
|
+
{
|
|
413
|
+
displayLabel: 'Name',
|
|
414
|
+
dataKey: 'name',
|
|
415
|
+
cellRenderer: (user) => user.name,
|
|
416
|
+
// Writing custom logic for a case-sensitive sort
|
|
417
|
+
sortComparer: (a, b, direction) => {
|
|
418
|
+
const nameA = a.name; // No .toLowerCase()
|
|
419
|
+
const nameB = b.name;
|
|
420
|
+
if (nameA < nameB) return direction === 'asc' ? -1 : 1;
|
|
421
|
+
if (nameA > nameB) return direction === 'asc' ? 1 : -1;
|
|
422
|
+
return 0;
|
|
423
|
+
},
|
|
424
|
+
},
|
|
425
|
+
];
|
|
426
|
+
```
|
|
427
|
+
|
|
428
|
+
**Example 3: Using `getSortableValue` for Simple Cases**
|
|
429
|
+
|
|
430
|
+
If you don't need special logic, `getSortableValue` is a concise way to enable default sorting on a property.
|
|
431
|
+
|
|
432
|
+
```jsx
|
|
433
|
+
const columnDefinitions: IResponsiveTableColumnDefinition<User>[] = [
|
|
434
|
+
{
|
|
435
|
+
displayLabel: 'Logins',
|
|
436
|
+
dataKey: 'logins',
|
|
437
|
+
cellRenderer: (user) => user.logins,
|
|
438
|
+
// This enables a simple, default numerical sort on the 'logins' property.
|
|
439
|
+
getSortableValue: (user) => user.logins,
|
|
440
|
+
},
|
|
441
|
+
];
|
|
442
|
+
```
|
|
443
|
+
|
|
444
|
+
**Plugin Options (via `new SortPlugin(options)`):**
|
|
445
|
+
|
|
446
|
+
| Prop | Type (`keyof TData`) | Description |
|
|
447
|
+
| ---------------------- | -------------------- | ------------------------------------------------- |
|
|
448
|
+
| `initialSortColumn` | `string` | The `dataKey` of the column to sort by initially. |
|
|
449
|
+
| `initialSortDirection` | `'asc' \| 'desc'` | The direction for the initial sort. |
|
|
450
|
+
|
|
451
|
+
**`SortPlugin.comparers` API:**
|
|
452
|
+
|
|
453
|
+
The `comparers` object on your `SortPlugin` instance provides the following helper methods. Each method is a factory that takes a `dataKey` (which is type-checked against your data model) and returns a `sortComparer` function.
|
|
454
|
+
|
|
455
|
+
| Method | Description |
|
|
456
|
+
| -------------------------------- | ----------------------------------------------------------------------------- |
|
|
457
|
+
| `numeric(dataKey)` | Performs a standard numerical sort. |
|
|
458
|
+
| `caseInsensitiveString(dataKey)` | Performs a case-insensitive alphabetical sort. |
|
|
459
|
+
| `date(dataKey)` | Correctly sorts dates, assuming the data is a valid date string or timestamp. |
|
|
460
|
+
|
|
317
461
|
#### `FilterPlugin`
|
|
318
462
|
|
|
319
463
|
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
464
|
|
|
321
465
|
**Props for `FilterPlugin` (via `filterProps` on `ResponsiveTable`):**
|
|
322
466
|
|
|
323
|
-
| Prop
|
|
324
|
-
|
|
|
325
|
-
| `showFilter`
|
|
326
|
-
| `filterPlaceholder
|
|
467
|
+
| Prop | Type | Description |
|
|
468
|
+
| ------------------- | --------- | --------------------------------------------------------------- |
|
|
469
|
+
| `showFilter` | `boolean` | If `true`, displays a filter input field above the table. |
|
|
470
|
+
| `filterPlaceholder` | `string` | Placeholder text for the filter input. Defaults to "Search...". |
|
|
327
471
|
|
|
328
472
|
**Example with `FilterPlugin`:**
|
|
329
473
|
|
|
330
474
|
```jsx
|
|
331
|
-
import React
|
|
475
|
+
import React from 'react';
|
|
332
476
|
import ResponsiveTable from 'jattac.libs.web.responsive-table';
|
|
333
477
|
|
|
334
478
|
const FilterableTable = () => {
|
|
@@ -349,7 +493,7 @@ const FilterableTable = () => {
|
|
|
349
493
|
<ResponsiveTable
|
|
350
494
|
columnDefinitions={columns}
|
|
351
495
|
data={initialData}
|
|
352
|
-
filterProps={{ showFilter: true, filterPlaceholder:
|
|
496
|
+
filterProps={{ showFilter: true, filterPlaceholder: 'Filter users...' }}
|
|
353
497
|
/>
|
|
354
498
|
);
|
|
355
499
|
};
|
|
@@ -361,13 +505,13 @@ Enables infinite scrolling for the table, loading more data as the user scrolls
|
|
|
361
505
|
|
|
362
506
|
**Props for `InfiniteScrollPlugin` (via `infiniteScrollProps` on `ResponsiveTable`):**
|
|
363
507
|
|
|
364
|
-
| Prop
|
|
365
|
-
|
|
|
366
|
-
| `enableInfiniteScroll
|
|
367
|
-
| `onLoadMore`
|
|
368
|
-
| `hasMore`
|
|
369
|
-
| `loadingMoreComponent
|
|
370
|
-
| `noMoreDataComponent`
|
|
508
|
+
| Prop | Type | Description |
|
|
509
|
+
| ---------------------- | ------------------------------------------ | ---------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------- |
|
|
510
|
+
| `enableInfiniteScroll` | `boolean` | If `true`, enables infinite scrolling. |
|
|
511
|
+
| `onLoadMore` | `(currentData: TData[]) => Promise<TData[] | null>` | Callback function to load more data. Should return a Promise resolving to new data or `null`. |
|
|
512
|
+
| `hasMore` | `boolean` | Indicates if there is more data to load. |
|
|
513
|
+
| `loadingMoreComponent` | `ReactNode` | Custom component to display while loading more data. Defaults to "Loading more...". |
|
|
514
|
+
| `noMoreDataComponent` | `ReactNode` | Custom component to display when no more data is available. Defaults to "No more data.". |
|
|
371
515
|
|
|
372
516
|
**Example with `InfiniteScrollPlugin`:**
|
|
373
517
|
|
|
@@ -394,7 +538,7 @@ const InfiniteScrollTable = () => {
|
|
|
394
538
|
};
|
|
395
539
|
|
|
396
540
|
useEffect(() => {
|
|
397
|
-
fetchData(0).then(initialData => {
|
|
541
|
+
fetchData(0).then((initialData) => {
|
|
398
542
|
setData(initialData);
|
|
399
543
|
setPage(1);
|
|
400
544
|
});
|
|
@@ -419,7 +563,9 @@ const InfiniteScrollTable = () => {
|
|
|
419
563
|
];
|
|
420
564
|
|
|
421
565
|
return (
|
|
422
|
-
<div style={{ height: '300px' }}>
|
|
566
|
+
<div style={{ height: '300px' }}>
|
|
567
|
+
{' '}
|
|
568
|
+
{/* Container for scrollable table */}
|
|
423
569
|
<ResponsiveTable
|
|
424
570
|
columnDefinitions={columns}
|
|
425
571
|
data={data}
|
|
@@ -437,173 +583,38 @@ const InfiniteScrollTable = () => {
|
|
|
437
583
|
};
|
|
438
584
|
```
|
|
439
585
|
|
|
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
586
|
---
|
|
578
587
|
|
|
579
588
|
## API Reference
|
|
580
589
|
|
|
581
590
|
### `ResponsiveTable` Props
|
|
582
591
|
|
|
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
|
|
601
|
-
|
|
|
602
|
-
| `displayLabel`
|
|
603
|
-
| `cellRenderer`
|
|
604
|
-
| `dataKey`
|
|
605
|
-
| `interactivity`
|
|
606
|
-
| `getFilterableValue
|
|
592
|
+
| Prop | Type | Required | Description |
|
|
593
|
+
| ----------------------------- | ------------------------------------ | -------- | --------------------------------------------------------------------------------------------------- |
|
|
594
|
+
| `columnDefinitions` | `IResponsiveTableColumnDefinition[]` | Yes | An array of objects defining the table columns. |
|
|
595
|
+
| `data` | `TData[]` | Yes | An array of data objects to populate the table rows. |
|
|
596
|
+
| `footerRows` | `IFooterRowDefinition[]` | No | An array of objects defining the table footer. |
|
|
597
|
+
| `onRowClick` | `(item: TData) => void` | No | A callback function that is triggered when a row is clicked. |
|
|
598
|
+
| `noDataComponent` | `ReactNode` | No | A custom component to display when there is no data. |
|
|
599
|
+
| `maxHeight` | `string` | No | Sets a maximum height for the table body, making it scrollable. |
|
|
600
|
+
| `mobileBreakpoint` | `number` | No | The pixel width at which the table switches to the mobile view. Defaults to `600`. |
|
|
601
|
+
| `enablePageLevelStickyHeader` | `boolean` | No | If `false`, disables the header from sticking to the top of the page on scroll. Defaults to `true`. |
|
|
602
|
+
| `plugins` | `IResponsiveTablePlugin<TData>[]` | No | An array of plugin instances to extend table functionality. |
|
|
603
|
+
| `infiniteScrollProps` | `object` | No | Configuration for the built-in infinite scroll plugin. |
|
|
604
|
+
| `filterProps` | `object` | No | Configuration for the built-in filter plugin. |
|
|
605
|
+
| `animationProps` | `object` | No | Configuration for animations, including `isLoading` and `animateOnLoad`. |
|
|
606
|
+
|
|
607
|
+
### `IResponsiveTableColumnDefinition<TData>`
|
|
608
|
+
|
|
609
|
+
| Property | Type | Required | Description |
|
|
610
|
+
| -------------------- | ------------------------------------------------------------ | -------- | ---------------------------------------------------------------------------------------- |
|
|
611
|
+
| `displayLabel` | `ReactNode` | Yes | The label displayed in the table header (can be a string or any React component). |
|
|
612
|
+
| `cellRenderer` | `(row: TData) => ReactNode` | Yes | A function that returns the content to be rendered in the cell. |
|
|
613
|
+
| `dataKey` | `string` | No | A key to match the column to a property in the data object (required for sorting). |
|
|
614
|
+
| `interactivity` | `object` | No | An object to define header interactivity (`onHeaderClick`, `id`, `className`). |
|
|
615
|
+
| `getFilterableValue` | `(row: TData) => string \| number` | No | A function that returns the string or number value to be used for filtering this column. |
|
|
616
|
+
| `getSortableValue` | `(row: TData) => any` | No | A function that returns a primitive value from a row to be used for default sorting. |
|
|
617
|
+
| `sortComparer` | `(a: TData, b: TData, direction: 'asc' \| 'desc') => number` | No | A function that provides the precise comparison logic for sorting a column. |
|
|
607
618
|
|
|
608
619
|
### `IFooterRowDefinition`
|
|
609
620
|
|
|
@@ -613,13 +624,13 @@ const SortableTable = () => {
|
|
|
613
624
|
|
|
614
625
|
### `IFooterColumnDefinition`
|
|
615
626
|
|
|
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.
|
|
627
|
+
| Property | Type | Required | Description |
|
|
628
|
+
| -------------- | ----------------- | -------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
|
|
629
|
+
| `colSpan` | `number` | Yes | The number of columns the footer cell should span. |
|
|
630
|
+
| `cellRenderer` | `() => ReactNode` | Yes | A function that returns the content for the footer cell. |
|
|
620
631
|
| `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.
|
|
632
|
+
| `onCellClick` | `() => void` | No | An optional click handler for the footer cell. |
|
|
633
|
+
| `className` | `string` | No | Optional class name for custom styling of the footer cell. |
|
|
623
634
|
|
|
624
635
|
## License
|
|
625
636
|
|
|
@@ -1,11 +1,15 @@
|
|
|
1
1
|
import { ReactNode } from 'react';
|
|
2
|
+
export type SortDirection = 'asc' | 'desc';
|
|
2
3
|
export default interface IResponsiveTableColumnDefinition<TData> {
|
|
3
4
|
displayLabel: ReactNode;
|
|
4
5
|
cellRenderer: (data: TData) => ReactNode;
|
|
6
|
+
dataKey?: string;
|
|
5
7
|
interactivity?: {
|
|
6
8
|
id: string;
|
|
7
9
|
onHeaderClick?: (id: string) => void;
|
|
8
10
|
className?: string;
|
|
9
11
|
};
|
|
10
12
|
getFilterableValue?: (data: TData) => string | number;
|
|
13
|
+
getSortableValue?: (row: TData) => any;
|
|
14
|
+
sortComparer?: (a: TData, b: TData, direction: SortDirection) => number;
|
|
11
15
|
}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import { IResponsiveTablePlugin, IPluginAPI } from './IResponsiveTablePlugin';
|
|
2
|
+
import IResponsiveTableColumnDefinition, { SortDirection } from '../Data/IResponsiveTableColumnDefinition';
|
|
3
|
+
export interface ISortPluginOptions<TData> {
|
|
4
|
+
initialSortColumn?: keyof TData;
|
|
5
|
+
initialSortDirection?: SortDirection;
|
|
6
|
+
}
|
|
7
|
+
export declare class SortPlugin<TData> implements IResponsiveTablePlugin<TData> {
|
|
8
|
+
id: string;
|
|
9
|
+
private api;
|
|
10
|
+
private sortColumn;
|
|
11
|
+
private sortDirection;
|
|
12
|
+
readonly comparers: {
|
|
13
|
+
numeric: (key: keyof TData) => (a: TData, b: TData, direction: SortDirection) => number;
|
|
14
|
+
caseInsensitiveString: (key: keyof TData) => (a: TData, b: TData, direction: SortDirection) => 0 | 1 | -1;
|
|
15
|
+
date: (key: keyof TData) => (a: TData, b: TData, direction: SortDirection) => number;
|
|
16
|
+
};
|
|
17
|
+
constructor(options?: ISortPluginOptions<TData>);
|
|
18
|
+
onPluginInit: (api: IPluginAPI<TData>) => void;
|
|
19
|
+
processData: (data: TData[]) => TData[];
|
|
20
|
+
getHeaderProps: (columnDef: IResponsiveTableColumnDefinition<TData>) => {
|
|
21
|
+
onClick?: undefined;
|
|
22
|
+
className?: undefined;
|
|
23
|
+
'aria-sort'?: undefined;
|
|
24
|
+
} | {
|
|
25
|
+
onClick: () => void;
|
|
26
|
+
className: string;
|
|
27
|
+
'aria-sort': string;
|
|
28
|
+
};
|
|
29
|
+
}
|
|
@@ -57,6 +57,7 @@ declare class ResponsiveTable<TData> extends Component<IProps<TData>, IState<TDa
|
|
|
57
57
|
private getRawColumnDefinition;
|
|
58
58
|
private onHeaderClickCallback;
|
|
59
59
|
private getClickableHeaderClassName;
|
|
60
|
+
private getHeaderProps;
|
|
60
61
|
private get rowClickFunction();
|
|
61
62
|
private get rowClickStyle();
|
|
62
63
|
private get tableFooter();
|
package/dist/index.d.ts
CHANGED
|
@@ -5,5 +5,6 @@ import ResponsiveTable, { ColumnDefinition } from './UI/ResponsiveTable';
|
|
|
5
5
|
import { FilterPlugin } from './Plugins/FilterPlugin';
|
|
6
6
|
import { InfiniteScrollPlugin } from './Plugins/InfiniteScrollPlugin';
|
|
7
7
|
import { IResponsiveTablePlugin } from './Plugins/IResponsiveTablePlugin';
|
|
8
|
-
|
|
8
|
+
import { SortPlugin } from './Plugins/SortPlugin';
|
|
9
|
+
export { IResponsiveTableColumnDefinition, ColumnDefinition, IFooterColumnDefinition, IFooterRowDefinition, FilterPlugin, InfiniteScrollPlugin, IResponsiveTablePlugin, SortPlugin };
|
|
9
10
|
export default ResponsiveTable;
|