jattac.libs.web.responsive-table 0.2.0 → 0.2.2
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 +580 -579
- package/dist/index.js +4 -4
- package/dist/index.js.map +1 -1
- package/gemini/commit_message.txt +1 -0
- package/gemini/index.md +1 -0
- package/gemini/release_git_steps.md +80 -64
- package/package.json +60 -60
- package/src/Data/IResponsiveTableColumnDefinition.tsx +12 -12
- package/src/Plugins/FilterPlugin.tsx +71 -71
- package/src/Plugins/IResponsiveTablePlugin.ts +48 -48
- package/src/Plugins/InfiniteScrollPlugin.tsx +73 -73
- package/src/Styles/ResponsiveTable.module.css +1 -1
- package/src/UI/ResponsiveTable.tsx +25 -26
- package/src/index.tsx +10 -10
|
@@ -1,73 +1,73 @@
|
|
|
1
|
-
import React from 'react';
|
|
2
|
-
import { IResponsiveTablePlugin, IPluginAPI } from './IResponsiveTablePlugin';
|
|
3
|
-
|
|
4
|
-
export class InfiniteScrollPlugin<TData> implements IResponsiveTablePlugin<TData> {
|
|
5
|
-
public id = 'infinite-scroll';
|
|
6
|
-
private api!: IPluginAPI<TData>;
|
|
7
|
-
private isLoadingMore = false;
|
|
8
|
-
|
|
9
|
-
constructor() {
|
|
10
|
-
}
|
|
11
|
-
|
|
12
|
-
public onPluginInit = (api: IPluginAPI<TData>) => {
|
|
13
|
-
this.api = api;
|
|
14
|
-
this.attachScrollListener();
|
|
15
|
-
};
|
|
16
|
-
|
|
17
|
-
private attachScrollListener = () => {
|
|
18
|
-
const scrollableElement = this.api.getScrollableElement?.();
|
|
19
|
-
if (scrollableElement) {
|
|
20
|
-
scrollableElement.addEventListener('scroll', this.handleScroll);
|
|
21
|
-
}
|
|
22
|
-
};
|
|
23
|
-
|
|
24
|
-
private handleScroll = async () => {
|
|
25
|
-
const scrollableElement = this.api.getScrollableElement?.();
|
|
26
|
-
if (!scrollableElement || !this.api.infiniteScrollProps?.enableInfiniteScroll) {
|
|
27
|
-
return;
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
const { scrollTop, scrollHeight, clientHeight } = scrollableElement;
|
|
31
|
-
|
|
32
|
-
const scrollThreshold = 200; // Load more data when 200px from the bottom
|
|
33
|
-
|
|
34
|
-
if (
|
|
35
|
-
scrollHeight - scrollTop - clientHeight < scrollThreshold &&
|
|
36
|
-
this.api.infiniteScrollProps.hasMore &&
|
|
37
|
-
!this.isLoadingMore
|
|
38
|
-
) {
|
|
39
|
-
this.isLoadingMore = true;
|
|
40
|
-
this.api.forceUpdate(); // Trigger re-render to show loading component
|
|
41
|
-
|
|
42
|
-
const newData = await this.api.infiniteScrollProps.onLoadMore?.(this.api.getData());
|
|
43
|
-
|
|
44
|
-
if (newData) {
|
|
45
|
-
// The main component will handle appending data via processData
|
|
46
|
-
} else {
|
|
47
|
-
// No more data, update hasMore in parent if necessary
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
this.isLoadingMore = false;
|
|
51
|
-
this.api.forceUpdate(); // Trigger re-render to hide loading component
|
|
52
|
-
}
|
|
53
|
-
};
|
|
54
|
-
|
|
55
|
-
public processData = (data: TData[]): TData[] => {
|
|
56
|
-
// This plugin doesn't modify the data directly, but rather triggers loading more.
|
|
57
|
-
// The main component's data prop should be updated by the consumer of the table.
|
|
58
|
-
return data;
|
|
59
|
-
};
|
|
60
|
-
|
|
61
|
-
public renderFooter = () => {
|
|
62
|
-
if (!this.api.infiniteScrollProps) {
|
|
63
|
-
return null;
|
|
64
|
-
}
|
|
65
|
-
|
|
66
|
-
if (this.isLoadingMore) {
|
|
67
|
-
return this.api.infiniteScrollProps.loadingMoreComponent || <div>Loading more...</div>;
|
|
68
|
-
} else if (!this.api.infiniteScrollProps.hasMore) {
|
|
69
|
-
return this.api.infiniteScrollProps.noMoreDataComponent || <div>No more data.</div>;
|
|
70
|
-
}
|
|
71
|
-
return null;
|
|
72
|
-
};
|
|
73
|
-
}
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import { IResponsiveTablePlugin, IPluginAPI } from './IResponsiveTablePlugin';
|
|
3
|
+
|
|
4
|
+
export class InfiniteScrollPlugin<TData> implements IResponsiveTablePlugin<TData> {
|
|
5
|
+
public id = 'infinite-scroll';
|
|
6
|
+
private api!: IPluginAPI<TData>;
|
|
7
|
+
private isLoadingMore = false;
|
|
8
|
+
|
|
9
|
+
constructor() {
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
public onPluginInit = (api: IPluginAPI<TData>) => {
|
|
13
|
+
this.api = api;
|
|
14
|
+
this.attachScrollListener();
|
|
15
|
+
};
|
|
16
|
+
|
|
17
|
+
private attachScrollListener = () => {
|
|
18
|
+
const scrollableElement = this.api.getScrollableElement?.();
|
|
19
|
+
if (scrollableElement) {
|
|
20
|
+
scrollableElement.addEventListener('scroll', this.handleScroll);
|
|
21
|
+
}
|
|
22
|
+
};
|
|
23
|
+
|
|
24
|
+
private handleScroll = async () => {
|
|
25
|
+
const scrollableElement = this.api.getScrollableElement?.();
|
|
26
|
+
if (!scrollableElement || !this.api.infiniteScrollProps?.enableInfiniteScroll) {
|
|
27
|
+
return;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
const { scrollTop, scrollHeight, clientHeight } = scrollableElement;
|
|
31
|
+
|
|
32
|
+
const scrollThreshold = 200; // Load more data when 200px from the bottom
|
|
33
|
+
|
|
34
|
+
if (
|
|
35
|
+
scrollHeight - scrollTop - clientHeight < scrollThreshold &&
|
|
36
|
+
this.api.infiniteScrollProps.hasMore &&
|
|
37
|
+
!this.isLoadingMore
|
|
38
|
+
) {
|
|
39
|
+
this.isLoadingMore = true;
|
|
40
|
+
this.api.forceUpdate(); // Trigger re-render to show loading component
|
|
41
|
+
|
|
42
|
+
const newData = await this.api.infiniteScrollProps.onLoadMore?.(this.api.getData());
|
|
43
|
+
|
|
44
|
+
if (newData) {
|
|
45
|
+
// The main component will handle appending data via processData
|
|
46
|
+
} else {
|
|
47
|
+
// No more data, update hasMore in parent if necessary
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
this.isLoadingMore = false;
|
|
51
|
+
this.api.forceUpdate(); // Trigger re-render to hide loading component
|
|
52
|
+
}
|
|
53
|
+
};
|
|
54
|
+
|
|
55
|
+
public processData = (data: TData[]): TData[] => {
|
|
56
|
+
// This plugin doesn't modify the data directly, but rather triggers loading more.
|
|
57
|
+
// The main component's data prop should be updated by the consumer of the table.
|
|
58
|
+
return data;
|
|
59
|
+
};
|
|
60
|
+
|
|
61
|
+
public renderFooter = () => {
|
|
62
|
+
if (!this.api.infiniteScrollProps) {
|
|
63
|
+
return null;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
if (this.isLoadingMore) {
|
|
67
|
+
return this.api.infiniteScrollProps.loadingMoreComponent || <div>Loading more...</div>;
|
|
68
|
+
} else if (!this.api.infiniteScrollProps.hasMore) {
|
|
69
|
+
return this.api.infiniteScrollProps.noMoreDataComponent || <div>No more data.</div>;
|
|
70
|
+
}
|
|
71
|
+
return null;
|
|
72
|
+
};
|
|
73
|
+
}
|
|
@@ -10,30 +10,30 @@ import { FixedSizeList as List } from 'react-window';
|
|
|
10
10
|
export type ColumnDefinition<TData> =
|
|
11
11
|
| IResponsiveTableColumnDefinition<TData>
|
|
12
12
|
| ((data: TData, rowIndex?: number) => IResponsiveTableColumnDefinition<TData>);
|
|
13
|
-
interface IProps<TData> {
|
|
14
|
-
columnDefinitions: ColumnDefinition<TData>[];
|
|
15
|
-
data: TData[];
|
|
16
|
-
noDataComponent?: ReactNode;
|
|
17
|
-
maxHeight?: string;
|
|
18
|
-
onRowClick?: (item: TData) => void;
|
|
19
|
-
footerRows?: IFooterRowDefinition[];
|
|
20
|
-
mobileBreakpoint?: number;
|
|
21
|
-
plugins?: IResponsiveTablePlugin<TData>[];
|
|
22
|
-
infiniteScrollProps?: {
|
|
23
|
-
enableInfiniteScroll?: boolean;
|
|
24
|
-
onLoadMore?: (currentData: TData[]) => Promise<TData[] | null>;
|
|
25
|
-
hasMore?: boolean;
|
|
26
|
-
loadingMoreComponent?: ReactNode;
|
|
27
|
-
noMoreDataComponent?: ReactNode;
|
|
28
|
-
};
|
|
29
|
-
filterProps?: {
|
|
30
|
-
showFilter?: boolean;
|
|
31
|
-
filterPlaceholder?: string;
|
|
32
|
-
};
|
|
33
|
-
animationProps?: {
|
|
34
|
-
isLoading?: boolean;
|
|
35
|
-
animateOnLoad?: boolean;
|
|
36
|
-
};
|
|
13
|
+
interface IProps<TData> {
|
|
14
|
+
columnDefinitions: ColumnDefinition<TData>[];
|
|
15
|
+
data: TData[];
|
|
16
|
+
noDataComponent?: ReactNode;
|
|
17
|
+
maxHeight?: string;
|
|
18
|
+
onRowClick?: (item: TData) => void;
|
|
19
|
+
footerRows?: IFooterRowDefinition[];
|
|
20
|
+
mobileBreakpoint?: number;
|
|
21
|
+
plugins?: IResponsiveTablePlugin<TData>[];
|
|
22
|
+
infiniteScrollProps?: {
|
|
23
|
+
enableInfiniteScroll?: boolean;
|
|
24
|
+
onLoadMore?: (currentData: TData[]) => Promise<TData[] | null>;
|
|
25
|
+
hasMore?: boolean;
|
|
26
|
+
loadingMoreComponent?: ReactNode;
|
|
27
|
+
noMoreDataComponent?: ReactNode;
|
|
28
|
+
};
|
|
29
|
+
filterProps?: {
|
|
30
|
+
showFilter?: boolean;
|
|
31
|
+
filterPlaceholder?: string;
|
|
32
|
+
};
|
|
33
|
+
animationProps?: {
|
|
34
|
+
isLoading?: boolean;
|
|
35
|
+
animateOnLoad?: boolean;
|
|
36
|
+
};
|
|
37
37
|
}
|
|
38
38
|
|
|
39
39
|
interface IState<TData> {
|
|
@@ -426,7 +426,7 @@ class ResponsiveTable<TData> extends Component<IProps<TData>, IState<TData>> {
|
|
|
426
426
|
|
|
427
427
|
return (
|
|
428
428
|
<div style={fixedHeadersStyle} ref={this.tableContainerRef}>
|
|
429
|
-
<table className={styles['responsiveTable']}
|
|
429
|
+
<table className={styles['responsiveTable']}>
|
|
430
430
|
<thead>
|
|
431
431
|
<tr>
|
|
432
432
|
{this.props.columnDefinitions.map((columnDefinition, colIndex) => {
|
|
@@ -439,7 +439,6 @@ class ResponsiveTable<TData> extends Component<IProps<TData>, IState<TData>> {
|
|
|
439
439
|
<th
|
|
440
440
|
key={colIndex}
|
|
441
441
|
className={`${clickableHeaderClassName}`}
|
|
442
|
-
style={{ zIndex: 0 }}
|
|
443
442
|
onClick={
|
|
444
443
|
onHeaderClickCallback
|
|
445
444
|
? () => onHeaderClickCallback(this.getColumnDefinition(columnDefinition, 0).interactivity!.id)
|
package/src/index.tsx
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
|
-
import IFooterColumnDefinition from './Data/IFooterColumnDefinition';
|
|
2
|
-
import IFooterRowDefinition from './Data/IFooterRowDefinition';
|
|
3
|
-
import IResponsiveTableColumnDefinition from './Data/IResponsiveTableColumnDefinition';
|
|
4
|
-
import ResponsiveTable, { ColumnDefinition } from './UI/ResponsiveTable';
|
|
5
|
-
import { FilterPlugin } from './Plugins/FilterPlugin';
|
|
6
|
-
import { InfiniteScrollPlugin } from './Plugins/InfiniteScrollPlugin';
|
|
7
|
-
import { IResponsiveTablePlugin } from './Plugins/IResponsiveTablePlugin';
|
|
8
|
-
|
|
9
|
-
export { IResponsiveTableColumnDefinition, ColumnDefinition, IFooterColumnDefinition, IFooterRowDefinition, FilterPlugin, InfiniteScrollPlugin, IResponsiveTablePlugin };
|
|
10
|
-
export default ResponsiveTable;
|
|
1
|
+
import IFooterColumnDefinition from './Data/IFooterColumnDefinition';
|
|
2
|
+
import IFooterRowDefinition from './Data/IFooterRowDefinition';
|
|
3
|
+
import IResponsiveTableColumnDefinition from './Data/IResponsiveTableColumnDefinition';
|
|
4
|
+
import ResponsiveTable, { ColumnDefinition } from './UI/ResponsiveTable';
|
|
5
|
+
import { FilterPlugin } from './Plugins/FilterPlugin';
|
|
6
|
+
import { InfiniteScrollPlugin } from './Plugins/InfiniteScrollPlugin';
|
|
7
|
+
import { IResponsiveTablePlugin } from './Plugins/IResponsiveTablePlugin';
|
|
8
|
+
|
|
9
|
+
export { IResponsiveTableColumnDefinition, ColumnDefinition, IFooterColumnDefinition, IFooterRowDefinition, FilterPlugin, InfiniteScrollPlugin, IResponsiveTablePlugin };
|
|
10
|
+
export default ResponsiveTable;
|