jattac.libs.web.responsive-table 0.2.12 → 0.2.14
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 +661 -637
- package/dist/Data/IResponsiveTableColumnDefinition.d.ts +1 -1
- package/dist/UI/InfiniteTable.d.ts +75 -0
- package/dist/index.d.ts +2 -2
- package/dist/index.js +362 -15
- package/dist/index.js.map +1 -1
- package/package.json +66 -66
|
@@ -11,7 +11,7 @@ export type IResponsiveTableColumnDefinition<TData> = {
|
|
|
11
11
|
} & ({
|
|
12
12
|
dataKey: keyof TData;
|
|
13
13
|
getFilterableValue?: (data: TData) => string | number;
|
|
14
|
-
getSortableValue?: (row: TData) =>
|
|
14
|
+
getSortableValue?: (row: TData) => string | number;
|
|
15
15
|
sortComparer?: (a: TData, b: TData, direction: SortDirection) => number;
|
|
16
16
|
} | {
|
|
17
17
|
dataKey?: keyof TData;
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
import React, { Component, ReactNode } from 'react';
|
|
2
|
+
import { IResponsiveTableColumnDefinition } from '../Data/IResponsiveTableColumnDefinition';
|
|
3
|
+
import IFooterRowDefinition from '../Data/IFooterRowDefinition';
|
|
4
|
+
import { IResponsiveTablePlugin } from '../Plugins/IResponsiveTablePlugin';
|
|
5
|
+
export type ColumnDefinition<TData> = IResponsiveTableColumnDefinition<TData> | ((data: TData, rowIndex?: number) => IResponsiveTableColumnDefinition<TData>);
|
|
6
|
+
interface IProps<TData> {
|
|
7
|
+
columnDefinitions: ColumnDefinition<TData>[];
|
|
8
|
+
data: TData[];
|
|
9
|
+
noDataComponent?: ReactNode;
|
|
10
|
+
maxHeight?: string;
|
|
11
|
+
onRowClick?: (item: TData) => void;
|
|
12
|
+
footerRows?: IFooterRowDefinition[];
|
|
13
|
+
mobileBreakpoint?: number;
|
|
14
|
+
plugins?: IResponsiveTablePlugin<TData>[];
|
|
15
|
+
enablePageLevelStickyHeader?: boolean;
|
|
16
|
+
infiniteScrollProps?: {
|
|
17
|
+
enableInfiniteScroll?: boolean;
|
|
18
|
+
onLoadMore?: (currentData: TData[]) => Promise<TData[] | null>;
|
|
19
|
+
hasMore?: boolean;
|
|
20
|
+
loadingMoreComponent?: ReactNode;
|
|
21
|
+
noMoreDataComponent?: ReactNode;
|
|
22
|
+
};
|
|
23
|
+
filterProps?: {
|
|
24
|
+
showFilter?: boolean;
|
|
25
|
+
filterPlaceholder?: string;
|
|
26
|
+
};
|
|
27
|
+
animationProps?: {
|
|
28
|
+
isLoading?: boolean;
|
|
29
|
+
animateOnLoad?: boolean;
|
|
30
|
+
};
|
|
31
|
+
}
|
|
32
|
+
interface IState<TData> {
|
|
33
|
+
isMobile: boolean;
|
|
34
|
+
processedData: TData[];
|
|
35
|
+
isLoadingMore: boolean;
|
|
36
|
+
isHeaderSticky: boolean;
|
|
37
|
+
columnWidths: number[];
|
|
38
|
+
}
|
|
39
|
+
declare class InfiniteTable<TData> extends Component<IProps<TData>, IState<TData>> {
|
|
40
|
+
private debouncedResize;
|
|
41
|
+
private tableContainerRef;
|
|
42
|
+
private headerRef;
|
|
43
|
+
private resizeObserver;
|
|
44
|
+
constructor(props: IProps<TData>);
|
|
45
|
+
private get mobileBreakpoint();
|
|
46
|
+
private debounce;
|
|
47
|
+
private get data();
|
|
48
|
+
private get noDataSvg();
|
|
49
|
+
private get hasData();
|
|
50
|
+
private get noDataComponent();
|
|
51
|
+
componentDidMount(): void;
|
|
52
|
+
componentWillUnmount(): void;
|
|
53
|
+
componentDidUpdate(prevProps: IProps<TData>): void;
|
|
54
|
+
private measureHeader;
|
|
55
|
+
private handleScroll;
|
|
56
|
+
private initializePlugins;
|
|
57
|
+
private processData;
|
|
58
|
+
handleResize: () => void;
|
|
59
|
+
private getColumnDefinition;
|
|
60
|
+
private getRawColumnDefinition;
|
|
61
|
+
private onHeaderClickCallback;
|
|
62
|
+
private getClickableHeaderClassName;
|
|
63
|
+
private getHeaderProps;
|
|
64
|
+
private get rowClickFunction();
|
|
65
|
+
private get rowClickStyle();
|
|
66
|
+
private get tableFooter();
|
|
67
|
+
private get mobileFooter();
|
|
68
|
+
private get skeletonView();
|
|
69
|
+
private get mobileView();
|
|
70
|
+
private get largeScreenView();
|
|
71
|
+
private renderPluginHeaders;
|
|
72
|
+
private renderPluginFooters;
|
|
73
|
+
render(): string | number | boolean | Iterable<React.ReactNode> | React.JSX.Element | null | undefined;
|
|
74
|
+
}
|
|
75
|
+
export default InfiniteTable;
|
package/dist/index.d.ts
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
import IFooterColumnDefinition from './Data/IFooterColumnDefinition';
|
|
2
2
|
import IFooterRowDefinition from './Data/IFooterRowDefinition';
|
|
3
|
-
import { IResponsiveTableColumnDefinition } from './Data/IResponsiveTableColumnDefinition';
|
|
3
|
+
import { IResponsiveTableColumnDefinition, SortDirection } from './Data/IResponsiveTableColumnDefinition';
|
|
4
4
|
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
|
+
export { SortDirection, IResponsiveTableColumnDefinition, ColumnDefinition, IFooterColumnDefinition, IFooterRowDefinition, FilterPlugin, InfiniteScrollPlugin, IResponsiveTablePlugin, SortPlugin, };
|
|
10
10
|
export default ResponsiveTable;
|
package/dist/index.js
CHANGED
|
@@ -75,7 +75,7 @@ function styleInject(css, ref) {
|
|
|
75
75
|
}
|
|
76
76
|
}
|
|
77
77
|
|
|
78
|
-
var css_248z = "/* Using CSS variables for a more maintainable and themeable design */\n.ResponsiveTable-module_responsiveTable__4y-Od {\n --table-border-color: #e0e0e0;\n --table-header-bg: #f8f9fa;\n --table-row-hover-bg: #e9ecef;\n --table-row-stripe-bg: #f2f2f2;\n --card-bg: #ffffff;\n --card-border-color: #e0e0e0;\n --card-shadow: 0 2px 8px rgba(0, 0, 0, 0.06);\n --text-color: #212529;\n --text-color-muted: #6c757d;\n --interactive-color: #0056b3;\n}\n\n/* Mobile Card View */\n.ResponsiveTable-module_card__b-U2v {\n background-color: var(--card-bg);\n border: 1px solid var(--card-border-color);\n margin-bottom: 1rem;\n border-radius: 8px;\n overflow: hidden;\n box-shadow: var(--card-shadow);\n transition: box-shadow 0.2s ease-in-out;\n}\n\n.ResponsiveTable-module_card__b-U2v:hover {\n box-shadow: 0 4px 12px rgba(0, 0, 0, 0.1);\n}\n\n/* This is not used in the component, but keeping it styled in case it's added back */\n.ResponsiveTable-module_card-header__Ttk51 {\n background-color: var(--table-header-bg);\n padding: 0.75rem 1rem;\n font-weight: 600; /* Bolder */\n border-bottom: 1px solid var(--table-border-color);\n}\n\n.ResponsiveTable-module_card-body__XIy0h {\n padding: 1rem;\n font-size: 0.9rem;\n}\n\n.ResponsiveTable-module_card-body__XIy0h p {\n margin: 0 0 0.75rem;\n display: flex;\n justify-content: space-between;\n}\n\n.ResponsiveTable-module_card-body__XIy0h p:last-child {\n margin-bottom: 0;\n}\n\n.ResponsiveTable-module_card-label__v9L71 {\n font-weight: 600;\n color: var(--text-color);\n margin-right: 0.5rem;\n}\n\n/* Desktop Table View */\n.ResponsiveTable-module_responsiveTable__4y-Od {\n width: 100%;\n border-collapse: collapse;\n color: var(--text-color);\n}\n\n.ResponsiveTable-module_responsiveTable__4y-Od thead th {\n background-color: var(--table-header-bg);\n position: sticky;\n top: 0;\n z-index: 1;\n font-weight: 600;\n text-align: left;\n padding: 1rem; /* Keep padding for the th itself */\n border-bottom: 2px solid var(--table-border-color);\n}\n\n.ResponsiveTable-module_headerInnerWrapper__3VAhD {\n display: flex; /* Use flexbox for alignment within the th */\n align-items: center; /* Vertically center content */\n justify-content: space-between; /* Push icon to the right */\n width: 100%; /* Ensure it takes full width of th */\n}\n\n.ResponsiveTable-module_headerContent__ODMzS {\n flex-grow: 1; /* Allow content to take available space */\n overflow: hidden; /* Hide overflowing content */\n text-overflow: ellipsis; /* Show ellipsis for truncated text */\n white-space: nowrap; /* Prevent text from wrapping */\n padding-right: 0.5rem; /* Subtle space between text and icon */\n}\n\n.ResponsiveTable-module_responsiveTable__4y-Od td {\n padding: 1rem;\n border-bottom: 1px solid var(--table-border-color);\n text-align: left;\n}\n\n.ResponsiveTable-module_responsiveTable__4y-Od tr {\n background-color: var(--card-bg);\n transition: background-color 0.2s ease-in-out;\n}\n\n/* Subtle striping for better readability */\n.ResponsiveTable-module_responsiveTable__4y-Od tr:nth-child(even) {\n background-color: var(--table-row-stripe-bg);\n}\n\n/* Modern hover effect */\n.ResponsiveTable-module_responsiveTable__4y-Od tr:hover {\n background-color: var(--table-row-hover-bg);\n}\n\n/* Clickable Header Style */\n.ResponsiveTable-module_clickableHeader__xHQhF {\n cursor: pointer;\n color: var(--interactive-color);\n}\n\n.ResponsiveTable-module_clickableHeader__xHQhF:hover {\n text-decoration: underline;\n}\n\n/* Sortable Header Styles */\n.ResponsiveTable-module_responsiveTable__4y-Od th.ResponsiveTable-module_sortable__yvA60,\n.ResponsiveTable-module_responsiveTable__4y-Od th.ResponsiveTable-module_sorted-asc__jzOIa,\n.ResponsiveTable-module_responsiveTable__4y-Od th.ResponsiveTable-module_sorted-desc__7WCFK {\n cursor: pointer;\n position: relative;\n padding-right: 2.5rem; /* Space for the icon (1rem icon + 1rem margin + 0.5rem right offset) */\n transition: transform 0.2s ease-in-out; /* Add transition for smooth scaling */\n}\n\n.ResponsiveTable-module_responsiveTable__4y-Od th.ResponsiveTable-module_sortable__yvA60:hover,\n.ResponsiveTable-module_responsiveTable__4y-Od th.ResponsiveTable-module_sorted-asc__jzOIa:hover,\n.ResponsiveTable-module_responsiveTable__4y-Od th.ResponsiveTable-module_sorted-desc__7WCFK:hover {\n transform: scale(1.01); /* Subtle zoom effect on hover */\n}\n\n.ResponsiveTable-module_responsiveTable__4y-Od th .ResponsiveTable-module_sortIcon__A9WtD {\n position: absolute;\n right: 0.5rem;\n top: 50%;\n transform: translateY(-50%);\n width: 1rem;\n height: 1rem;\n background-size: contain;\n background-repeat: no-repeat;\n background-position: center;\n opacity: 0.4; /* Ghosted by default */\n transition: opacity 0.2s ease-in-out;\n}\n\n/* Default unsorted icon (funnel) */\n.ResponsiveTable-module_responsiveTable__4y-Od th.ResponsiveTable-module_sortable__yvA60 .ResponsiveTable-module_sortIcon__A9WtD {\n background-image: url(\"data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='%236c757d'%3E%3Cpath d='M10 18h4v-2h-4v2zm-6-8v2h16V8H4zm3-6h10v2H7V2z'/%3E%3C/svg%3E\");\n}\n\n.ResponsiveTable-module_responsiveTable__4y-Od th.ResponsiveTable-module_sortable__yvA60:hover .ResponsiveTable-module_sortIcon__A9WtD {\n opacity: 1;\n}\n\n/* Ensure cursor applies to content within sortable header */\n.ResponsiveTable-module_responsiveTable__4y-Od th.ResponsiveTable-module_sortable__yvA60 > * {\n cursor: inherit;\n}\n\n/* Sorted Ascending Icon */\n.ResponsiveTable-module_responsiveTable__4y-Od th.ResponsiveTable-module_sorted-asc__jzOIa .ResponsiveTable-module_sortIcon__A9WtD {\n opacity: 1; /* Always prominent when sorted */\n background-image: url(\"data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='%230056b3'%3E%3Cpath d='M7 14l5-5 5 5z'/%3E%3C/svg%3E\");\n}\n\n/* Sorted Descending Icon */\n.ResponsiveTable-module_responsiveTable__4y-Od th.ResponsiveTable-module_sorted-desc__7WCFK .ResponsiveTable-module_sortIcon__A9WtD {\n opacity: 1; /* Always prominent when sorted */\n background-image: url(\"data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='%230056b3'%3E%3Cpath d='M7 10l5 5 5-5z'/%3E%3C/svg%3E\");\n}\n\n.ResponsiveTable-module_responsiveTable__4y-Od tfoot {\n background-color: var(--table-header-bg);\n border-top: 2px solid var(--table-border-color);\n font-weight: 600;\n}\n\n.ResponsiveTable-module_footerCell__8H-uG {\n padding: 1rem;\n text-align: right;\n font-weight: 600;\n}\n\n.ResponsiveTable-module_clickableFooterCell__WB9Ss {\n cursor: pointer;\n color: var(--interactive-color);\n}\n\n.ResponsiveTable-module_clickableFooterCell__WB9Ss:hover {\n text-decoration: underline;\n}\n\n.ResponsiveTable-module_footerCard__-NE2M {\n background-color: var(--table-header-bg);\n border: 1px solid var(--card-border-color);\n border-top: 2px solid var(--table-border-color);\n margin-bottom: 1rem;\n border-radius: 8px;\n overflow: hidden;\n box-shadow: none;\n}\n\n.ResponsiveTable-module_footer-card-body__CtBMv {\n padding: 1rem;\n font-size: 0.9rem;\n}\n\n.ResponsiveTable-module_footer-card-row__Vv6Ur {\n margin: 0 0 0.75rem;\n display: flex;\n justify-content: space-between;\n font-weight: 600;\n}\n\n/* No Data State */\n\n/* Staggered Entrance Animation */\n.ResponsiveTable-module_animatedRow__SFjrJ {\n animation: ResponsiveTable-module_fadeInUp__jMCS7 0.5s ease-out forwards;\n opacity: 0;\n}\n\n@keyframes ResponsiveTable-module_fadeInUp__jMCS7 {\n from {\n opacity: 0;\n transform: translateY(20px);\n }\n to {\n opacity: 1;\n transform: translateY(0);\n }\n}\n\n/* Skeleton Loader */\n.ResponsiveTable-module_skeleton__XxsXW {\n background-color: #e0e0e0;\n border-radius: 4px;\n position: relative;\n overflow: hidden;\n}\n\n.ResponsiveTable-module_skeleton__XxsXW::after {\n content: '';\n position: absolute;\n top: 0;\n left: -150%;\n width: 150%;\n height: 100%;\n background: linear-gradient(90deg, transparent, rgba(255, 255, 255, 0.4), transparent);\n animation: ResponsiveTable-module_shimmer__H8PhC 1.5s infinite;\n}\n\n.ResponsiveTable-module_skeletonText__T-Lgq {\n height: 1.2em;\n width: 100%;\n}\n\n.ResponsiveTable-module_skeletonCard__AYVwL {\n background-color: var(--card-bg);\n border: 1px solid var(--card-border-color);\n margin-bottom: 1rem;\n border-radius: 8px;\n overflow: hidden;\n padding: 1rem;\n}\n\n@keyframes ResponsiveTable-module_shimmer__H8PhC {\n 0% {\n transform: translateX(0);\n }\n 100% {\n transform: translateX(100%);\n }\n}\n.ResponsiveTable-module_noDataWrapper__Rj-k3 {\n color: var(--text-color-muted); /* Softer color */\n display: flex;\n justify-content: center;\n align-items: center;\n height: 100%;\n gap: 10px;\n padding: 40px;\n background-color: var(--table-header-bg);\n border: 1px dashed var(--table-border-color);\n border-radius: 8px;\n}\n\n.ResponsiveTable-module_noData__IpwNq {\n text-align: center;\n font-weight: 500; /* Less aggressive than bold */\n font-size: 1rem;\n}\n\n.ResponsiveTable-module_row-exit__EVX6T {\n opacity: 0;\n transform: scaleY(0);\n transition: transform 0.3s ease-out, opacity 0.3s ease-out;\n}\n\n.ResponsiveTable-module_row-enter__YKgI4 {\n opacity: 0;\n transform: translateY(20px);\n transition: transform 0.5s ease-out, opacity 0.5s ease-out;\n}\n\n.ResponsiveTable-module_row-flash__a4NOm {\n animation: ResponsiveTable-module_flash__nxeAX 0.5s ease-out;\n}\n\n@keyframes ResponsiveTable-module_flash__nxeAX {\n 0% {\n background-color: var(--table-row-hover-bg);\n }\n 100% {\n background-color: transparent;\n }\n}\n\n.ResponsiveTable-module_stickyHeader__-jjN- {\n position: sticky;\n top: 0;\n z-index: 1;\n box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);\n}\n";
|
|
78
|
+
var css_248z = "/* Using CSS variables for a more maintainable and themeable design */\r\n.ResponsiveTable-module_responsiveTable__4y-Od {\r\n --table-border-color: #e0e0e0;\r\n --table-header-bg: #f8f9fa;\r\n --table-row-hover-bg: #e9ecef;\r\n --table-row-stripe-bg: #f2f2f2;\r\n --card-bg: #ffffff;\r\n --card-border-color: #e0e0e0;\r\n --card-shadow: 0 2px 8px rgba(0, 0, 0, 0.06);\r\n --text-color: #212529;\r\n --text-color-muted: #6c757d;\r\n --interactive-color: #0056b3;\r\n}\r\n\r\n/* Mobile Card View */\r\n.ResponsiveTable-module_card__b-U2v {\r\n background-color: var(--card-bg);\r\n border: 1px solid var(--card-border-color);\r\n margin-bottom: 1rem;\r\n border-radius: 8px;\r\n overflow: hidden;\r\n box-shadow: var(--card-shadow);\r\n transition: box-shadow 0.2s ease-in-out;\r\n}\r\n\r\n.ResponsiveTable-module_card__b-U2v:hover {\r\n box-shadow: 0 4px 12px rgba(0, 0, 0, 0.1);\r\n}\r\n\r\n/* This is not used in the component, but keeping it styled in case it's added back */\r\n.ResponsiveTable-module_card-header__Ttk51 {\r\n background-color: var(--table-header-bg);\r\n padding: 0.75rem 1rem;\r\n font-weight: 600; /* Bolder */\r\n border-bottom: 1px solid var(--table-border-color);\r\n}\r\n\r\n.ResponsiveTable-module_card-body__XIy0h {\r\n padding: 1rem;\r\n font-size: 0.9rem;\r\n}\r\n\r\n.ResponsiveTable-module_card-body__XIy0h p {\r\n margin: 0 0 0.75rem;\r\n display: flex;\r\n justify-content: space-between;\r\n}\r\n\r\n.ResponsiveTable-module_card-body__XIy0h p:last-child {\r\n margin-bottom: 0;\r\n}\r\n\r\n.ResponsiveTable-module_card-label__v9L71 {\r\n font-weight: 600;\r\n color: var(--text-color);\r\n margin-right: 0.5rem;\r\n}\r\n\r\n/* Desktop Table View */\r\n.ResponsiveTable-module_responsiveTable__4y-Od {\r\n width: 100%;\r\n border-collapse: collapse;\r\n color: var(--text-color);\r\n}\r\n\r\n.ResponsiveTable-module_responsiveTable__4y-Od thead th {\r\n background-color: var(--table-header-bg);\r\n position: sticky;\r\n top: 0;\r\n z-index: 1;\r\n font-weight: 600;\r\n text-align: left;\r\n padding: 1rem; /* Keep padding for the th itself */\r\n border-bottom: 2px solid var(--table-border-color);\r\n}\r\n\r\n.ResponsiveTable-module_headerInnerWrapper__3VAhD {\r\n display: flex; /* Use flexbox for alignment within the th */\r\n align-items: center; /* Vertically center content */\r\n justify-content: space-between; /* Push icon to the right */\r\n width: 100%; /* Ensure it takes full width of th */\r\n}\r\n\r\n.ResponsiveTable-module_headerContent__ODMzS {\r\n flex-grow: 1; /* Allow content to take available space */\r\n overflow: hidden; /* Hide overflowing content */\r\n text-overflow: ellipsis; /* Show ellipsis for truncated text */\r\n white-space: nowrap; /* Prevent text from wrapping */\r\n padding-right: 0.5rem; /* Subtle space between text and icon */\r\n}\r\n\r\n.ResponsiveTable-module_responsiveTable__4y-Od td {\r\n padding: 1rem;\r\n border-bottom: 1px solid var(--table-border-color);\r\n text-align: left;\r\n}\r\n\r\n.ResponsiveTable-module_responsiveTable__4y-Od tr {\r\n background-color: var(--card-bg);\r\n transition: background-color 0.2s ease-in-out;\r\n}\r\n\r\n/* Subtle striping for better readability */\r\n.ResponsiveTable-module_responsiveTable__4y-Od tr:nth-child(even) {\r\n background-color: var(--table-row-stripe-bg);\r\n}\r\n\r\n/* Modern hover effect */\r\n.ResponsiveTable-module_responsiveTable__4y-Od tr:hover {\r\n background-color: var(--table-row-hover-bg);\r\n}\r\n\r\n/* Clickable Header Style */\r\n.ResponsiveTable-module_clickableHeader__xHQhF {\r\n cursor: pointer;\r\n color: var(--interactive-color);\r\n}\r\n\r\n.ResponsiveTable-module_clickableHeader__xHQhF:hover {\r\n text-decoration: underline;\r\n}\r\n\r\n/* Sortable Header Styles */\r\n.ResponsiveTable-module_responsiveTable__4y-Od th.ResponsiveTable-module_sortable__yvA60,\r\n.ResponsiveTable-module_responsiveTable__4y-Od th.ResponsiveTable-module_sorted-asc__jzOIa,\r\n.ResponsiveTable-module_responsiveTable__4y-Od th.ResponsiveTable-module_sorted-desc__7WCFK {\r\n cursor: pointer;\r\n position: relative;\r\n padding-right: 2.5rem; /* Space for the icon (1rem icon + 1rem margin + 0.5rem right offset) */\r\n transition: transform 0.2s ease-in-out; /* Add transition for smooth scaling */\r\n}\r\n\r\n.ResponsiveTable-module_responsiveTable__4y-Od th.ResponsiveTable-module_sortable__yvA60:hover,\r\n.ResponsiveTable-module_responsiveTable__4y-Od th.ResponsiveTable-module_sorted-asc__jzOIa:hover,\r\n.ResponsiveTable-module_responsiveTable__4y-Od th.ResponsiveTable-module_sorted-desc__7WCFK:hover {\r\n transform: scale(1.01); /* Subtle zoom effect on hover */\r\n}\r\n\r\n.ResponsiveTable-module_responsiveTable__4y-Od th .ResponsiveTable-module_sortIcon__A9WtD {\r\n position: absolute;\r\n right: 0.5rem;\r\n top: 50%;\r\n transform: translateY(-50%);\r\n width: 1rem;\r\n height: 1rem;\r\n background-size: contain;\r\n background-repeat: no-repeat;\r\n background-position: center;\r\n opacity: 0.4; /* Ghosted by default */\r\n transition: opacity 0.2s ease-in-out;\r\n}\r\n\r\n/* Default unsorted icon (funnel) */\r\n.ResponsiveTable-module_responsiveTable__4y-Od th.ResponsiveTable-module_sortable__yvA60 .ResponsiveTable-module_sortIcon__A9WtD {\r\n background-image: url(\"data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='%236c757d'%3E%3Cpath d='M10 18h4v-2h-4v2zm-6-8v2h16V8H4zm3-6h10v2H7V2z'/%3E%3C/svg%3E\");\r\n}\r\n\r\n.ResponsiveTable-module_responsiveTable__4y-Od th.ResponsiveTable-module_sortable__yvA60:hover .ResponsiveTable-module_sortIcon__A9WtD {\r\n opacity: 1;\r\n}\r\n\r\n/* Ensure cursor applies to content within sortable header */\r\n.ResponsiveTable-module_responsiveTable__4y-Od th.ResponsiveTable-module_sortable__yvA60 > * {\r\n cursor: inherit;\r\n}\r\n\r\n/* Sorted Ascending Icon */\r\n.ResponsiveTable-module_responsiveTable__4y-Od th.ResponsiveTable-module_sorted-asc__jzOIa .ResponsiveTable-module_sortIcon__A9WtD {\r\n opacity: 1; /* Always prominent when sorted */\r\n background-image: url(\"data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='%230056b3'%3E%3Cpath d='M7 14l5-5 5 5z'/%3E%3C/svg%3E\");\r\n}\r\n\r\n/* Sorted Descending Icon */\r\n.ResponsiveTable-module_responsiveTable__4y-Od th.ResponsiveTable-module_sorted-desc__7WCFK .ResponsiveTable-module_sortIcon__A9WtD {\r\n opacity: 1; /* Always prominent when sorted */\r\n background-image: url(\"data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='%230056b3'%3E%3Cpath d='M7 10l5 5 5-5z'/%3E%3C/svg%3E\");\r\n}\r\n\r\n.ResponsiveTable-module_responsiveTable__4y-Od tfoot {\r\n background-color: var(--table-header-bg);\r\n border-top: 2px solid var(--table-border-color);\r\n font-weight: 600;\r\n}\r\n\r\n.ResponsiveTable-module_footerCell__8H-uG {\r\n padding: 1rem;\r\n text-align: right;\r\n font-weight: 600;\r\n}\r\n\r\n.ResponsiveTable-module_clickableFooterCell__WB9Ss {\r\n cursor: pointer;\r\n color: var(--interactive-color);\r\n}\r\n\r\n.ResponsiveTable-module_clickableFooterCell__WB9Ss:hover {\r\n text-decoration: underline;\r\n}\r\n\r\n.ResponsiveTable-module_footerCard__-NE2M {\r\n background-color: var(--table-header-bg);\r\n border: 1px solid var(--card-border-color);\r\n border-top: 2px solid var(--table-border-color);\r\n margin-bottom: 1rem;\r\n border-radius: 8px;\r\n overflow: hidden;\r\n box-shadow: none;\r\n}\r\n\r\n.ResponsiveTable-module_footer-card-body__CtBMv {\r\n padding: 1rem;\r\n font-size: 0.9rem;\r\n}\r\n\r\n.ResponsiveTable-module_footer-card-row__Vv6Ur {\r\n margin: 0 0 0.75rem;\r\n display: flex;\r\n justify-content: space-between;\r\n font-weight: 600;\r\n}\r\n\r\n/* No Data State */\r\n\r\n/* Staggered Entrance Animation */\r\n.ResponsiveTable-module_animatedRow__SFjrJ {\r\n animation: ResponsiveTable-module_fadeInUp__jMCS7 0.5s ease-out forwards;\r\n opacity: 0;\r\n}\r\n\r\n@keyframes ResponsiveTable-module_fadeInUp__jMCS7 {\r\n from {\r\n opacity: 0;\r\n transform: translateY(20px);\r\n }\r\n to {\r\n opacity: 1;\r\n transform: translateY(0);\r\n }\r\n}\r\n\r\n/* Skeleton Loader */\r\n.ResponsiveTable-module_skeleton__XxsXW {\r\n background-color: #e0e0e0;\r\n border-radius: 4px;\r\n position: relative;\r\n overflow: hidden;\r\n}\r\n\r\n.ResponsiveTable-module_skeleton__XxsXW::after {\r\n content: '';\r\n position: absolute;\r\n top: 0;\r\n left: -150%;\r\n width: 150%;\r\n height: 100%;\r\n background: linear-gradient(90deg, transparent, rgba(255, 255, 255, 0.4), transparent);\r\n animation: ResponsiveTable-module_shimmer__H8PhC 1.5s infinite;\r\n}\r\n\r\n.ResponsiveTable-module_skeletonText__T-Lgq {\r\n height: 1.2em;\r\n width: 100%;\r\n}\r\n\r\n.ResponsiveTable-module_skeletonCard__AYVwL {\r\n background-color: var(--card-bg);\r\n border: 1px solid var(--card-border-color);\r\n margin-bottom: 1rem;\r\n border-radius: 8px;\r\n overflow: hidden;\r\n padding: 1rem;\r\n}\r\n\r\n@keyframes ResponsiveTable-module_shimmer__H8PhC {\r\n 0% {\r\n transform: translateX(0);\r\n }\r\n 100% {\r\n transform: translateX(100%);\r\n }\r\n}\r\n.ResponsiveTable-module_noDataWrapper__Rj-k3 {\r\n color: var(--text-color-muted); /* Softer color */\r\n display: flex;\r\n justify-content: center;\r\n align-items: center;\r\n height: 100%;\r\n gap: 10px;\r\n padding: 40px;\r\n background-color: var(--table-header-bg);\r\n border: 1px dashed var(--table-border-color);\r\n border-radius: 8px;\r\n}\r\n\r\n.ResponsiveTable-module_noData__IpwNq {\r\n text-align: center;\r\n font-weight: 500; /* Less aggressive than bold */\r\n font-size: 1rem;\r\n}\r\n\r\n.ResponsiveTable-module_row-exit__EVX6T {\r\n opacity: 0;\r\n transform: scaleY(0);\r\n transition: transform 0.3s ease-out, opacity 0.3s ease-out;\r\n}\r\n\r\n.ResponsiveTable-module_row-enter__YKgI4 {\r\n opacity: 0;\r\n transform: translateY(20px);\r\n transition: transform 0.5s ease-out, opacity 0.5s ease-out;\r\n}\r\n\r\n.ResponsiveTable-module_row-flash__a4NOm {\r\n animation: ResponsiveTable-module_flash__nxeAX 0.5s ease-out;\r\n}\r\n\r\n@keyframes ResponsiveTable-module_flash__nxeAX {\r\n 0% {\r\n background-color: var(--table-row-hover-bg);\r\n }\r\n 100% {\r\n background-color: transparent;\r\n }\r\n}\r\n\r\n.ResponsiveTable-module_stickyHeader__-jjN- {\r\n position: sticky;\r\n top: 0;\r\n z-index: 1;\r\n box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);\r\n}\r\n";
|
|
79
79
|
var styles = {"responsiveTable":"ResponsiveTable-module_responsiveTable__4y-Od","card":"ResponsiveTable-module_card__b-U2v","card-header":"ResponsiveTable-module_card-header__Ttk51","card-body":"ResponsiveTable-module_card-body__XIy0h","card-label":"ResponsiveTable-module_card-label__v9L71","headerInnerWrapper":"ResponsiveTable-module_headerInnerWrapper__3VAhD","headerContent":"ResponsiveTable-module_headerContent__ODMzS","clickableHeader":"ResponsiveTable-module_clickableHeader__xHQhF","sortable":"ResponsiveTable-module_sortable__yvA60","sorted-asc":"ResponsiveTable-module_sorted-asc__jzOIa","sorted-desc":"ResponsiveTable-module_sorted-desc__7WCFK","sortIcon":"ResponsiveTable-module_sortIcon__A9WtD","footerCell":"ResponsiveTable-module_footerCell__8H-uG","clickableFooterCell":"ResponsiveTable-module_clickableFooterCell__WB9Ss","footerCard":"ResponsiveTable-module_footerCard__-NE2M","footer-card-body":"ResponsiveTable-module_footer-card-body__CtBMv","footer-card-row":"ResponsiveTable-module_footer-card-row__Vv6Ur","animatedRow":"ResponsiveTable-module_animatedRow__SFjrJ","fadeInUp":"ResponsiveTable-module_fadeInUp__jMCS7","skeleton":"ResponsiveTable-module_skeleton__XxsXW","shimmer":"ResponsiveTable-module_shimmer__H8PhC","skeletonText":"ResponsiveTable-module_skeletonText__T-Lgq","skeletonCard":"ResponsiveTable-module_skeletonCard__AYVwL","noDataWrapper":"ResponsiveTable-module_noDataWrapper__Rj-k3","noData":"ResponsiveTable-module_noData__IpwNq","row-exit":"ResponsiveTable-module_row-exit__EVX6T","row-enter":"ResponsiveTable-module_row-enter__YKgI4","row-flash":"ResponsiveTable-module_row-flash__a4NOm","flash":"ResponsiveTable-module_flash__nxeAX","stickyHeader":"ResponsiveTable-module_stickyHeader__-jjN-"};
|
|
80
80
|
styleInject(css_248z);
|
|
81
81
|
|
|
@@ -980,11 +980,21 @@ var FixedSizeList = /*#__PURE__*/createListComponent({
|
|
|
980
980
|
});
|
|
981
981
|
|
|
982
982
|
// Class component
|
|
983
|
-
class
|
|
983
|
+
class InfiniteTable extends React.Component {
|
|
984
984
|
constructor(props) {
|
|
985
985
|
super(props);
|
|
986
986
|
this.tableContainerRef = React.createRef();
|
|
987
987
|
this.headerRef = React.createRef();
|
|
988
|
+
this.resizeObserver = null;
|
|
989
|
+
this.measureHeader = () => {
|
|
990
|
+
if (this.headerRef.current) {
|
|
991
|
+
const ths = Array.from(this.headerRef.current.querySelectorAll('th'));
|
|
992
|
+
const widths = ths.map((th) => th.getBoundingClientRect().width);
|
|
993
|
+
if (widths.some((w) => w > 0)) {
|
|
994
|
+
this.setState({ columnWidths: widths });
|
|
995
|
+
}
|
|
996
|
+
}
|
|
997
|
+
};
|
|
988
998
|
this.handleScroll = () => {
|
|
989
999
|
if (this.headerRef.current && !this.props.maxHeight) {
|
|
990
1000
|
const { top } = this.headerRef.current.getBoundingClientRect();
|
|
@@ -1004,6 +1014,7 @@ class ResponsiveTable extends React.Component {
|
|
|
1004
1014
|
processedData: props.data,
|
|
1005
1015
|
isLoadingMore: false,
|
|
1006
1016
|
isHeaderSticky: false,
|
|
1017
|
+
columnWidths: [],
|
|
1007
1018
|
};
|
|
1008
1019
|
this.debouncedResize = this.debounce(this.handleResize, 200);
|
|
1009
1020
|
}
|
|
@@ -1044,18 +1055,29 @@ class ResponsiveTable extends React.Component {
|
|
|
1044
1055
|
window.addEventListener('scroll', this.handleScroll);
|
|
1045
1056
|
}
|
|
1046
1057
|
this.initializePlugins();
|
|
1058
|
+
if (this.headerRef.current) {
|
|
1059
|
+
this.measureHeader();
|
|
1060
|
+
this.resizeObserver = new ResizeObserver(this.measureHeader);
|
|
1061
|
+
this.resizeObserver.observe(this.headerRef.current);
|
|
1062
|
+
}
|
|
1047
1063
|
}
|
|
1048
1064
|
componentWillUnmount() {
|
|
1049
1065
|
window.removeEventListener('resize', this.debouncedResize);
|
|
1050
1066
|
if (this.props.enablePageLevelStickyHeader !== false) {
|
|
1051
1067
|
window.removeEventListener('scroll', this.handleScroll);
|
|
1052
1068
|
}
|
|
1069
|
+
if (this.resizeObserver && this.headerRef.current) {
|
|
1070
|
+
this.resizeObserver.unobserve(this.headerRef.current);
|
|
1071
|
+
}
|
|
1053
1072
|
}
|
|
1054
1073
|
componentDidUpdate(prevProps) {
|
|
1055
1074
|
var _a, _b, _c;
|
|
1056
1075
|
if (prevProps.data !== this.props.data) {
|
|
1057
1076
|
this.processData();
|
|
1058
1077
|
}
|
|
1078
|
+
if (prevProps.columnDefinitions.length !== this.props.columnDefinitions.length) {
|
|
1079
|
+
this.measureHeader();
|
|
1080
|
+
}
|
|
1059
1081
|
// Handle infinite scroll loading
|
|
1060
1082
|
if (((_a = this.props.infiniteScrollProps) === null || _a === void 0 ? void 0 : _a.enableInfiniteScroll) && ((_b = this.props.infiniteScrollProps) === null || _b === void 0 ? void 0 : _b.hasMore) && !this.state.isLoadingMore && ((_c = this.props.infiniteScrollProps) === null || _c === void 0 ? void 0 : _c.onLoadMore)) ;
|
|
1061
1083
|
}
|
|
@@ -1139,7 +1161,7 @@ class ResponsiveTable extends React.Component {
|
|
|
1139
1161
|
return clickableHeaderClassName;
|
|
1140
1162
|
}
|
|
1141
1163
|
getHeaderProps(columnDefinition) {
|
|
1142
|
-
|
|
1164
|
+
const headerProps = {};
|
|
1143
1165
|
if (this.props.plugins) {
|
|
1144
1166
|
this.props.plugins.forEach((plugin) => {
|
|
1145
1167
|
if (plugin.getHeaderProps) {
|
|
@@ -1229,19 +1251,340 @@ class ResponsiveTable extends React.Component {
|
|
|
1229
1251
|
this.mobileFooter));
|
|
1230
1252
|
}
|
|
1231
1253
|
get largeScreenView() {
|
|
1232
|
-
var _a;
|
|
1233
1254
|
const useFixedHeaders = this.props.maxHeight ? true : false;
|
|
1234
1255
|
const fixedHeadersStyle = useFixedHeaders
|
|
1235
1256
|
? { maxHeight: this.props.maxHeight, overflowY: 'auto' }
|
|
1236
1257
|
: {};
|
|
1237
|
-
const
|
|
1238
|
-
|
|
1239
|
-
|
|
1240
|
-
|
|
1241
|
-
|
|
1242
|
-
|
|
1243
|
-
|
|
1258
|
+
const itemData = {
|
|
1259
|
+
rows: this.data,
|
|
1260
|
+
columnWidths: this.state.columnWidths,
|
|
1261
|
+
columnDefinitions: this.props.columnDefinitions,
|
|
1262
|
+
animationProps: this.props.animationProps,
|
|
1263
|
+
getColumnDefinition: this.getColumnDefinition.bind(this),
|
|
1264
|
+
rowClickFunction: this.rowClickFunction,
|
|
1265
|
+
rowClickStyle: this.rowClickStyle,
|
|
1244
1266
|
};
|
|
1267
|
+
return (React.createElement("div", { style: fixedHeadersStyle, ref: this.tableContainerRef },
|
|
1268
|
+
React.createElement("table", { className: styles['responsiveTable'], style: { tableLayout: 'fixed' } },
|
|
1269
|
+
React.createElement("thead", { ref: this.headerRef, className: this.state.isHeaderSticky ? styles.stickyHeader : '' },
|
|
1270
|
+
React.createElement("tr", null, this.props.columnDefinitions.map((columnDefinition, colIndex) => {
|
|
1271
|
+
const onHeaderClickCallback = this.onHeaderClickCallback(columnDefinition);
|
|
1272
|
+
const clickableHeaderClassName = this.getClickableHeaderClassName(onHeaderClickCallback, columnDefinition);
|
|
1273
|
+
const headerProps = this.getHeaderProps(columnDefinition);
|
|
1274
|
+
// Combine class names: existing clickable, and plugin-provided (mapped to CSS Modules)
|
|
1275
|
+
const combinedClassName = `${clickableHeaderClassName} ${headerProps.className ? styles[headerProps.className] : ''}`.trim();
|
|
1276
|
+
// Remove className from headerProps to avoid duplication
|
|
1277
|
+
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
1278
|
+
const { className } = headerProps, restHeaderProps = __rest(headerProps, ["className"]);
|
|
1279
|
+
return (React.createElement("th", Object.assign({ key: colIndex, className: combinedClassName }, restHeaderProps),
|
|
1280
|
+
React.createElement("div", { className: styles.headerInnerWrapper },
|
|
1281
|
+
React.createElement("div", { className: styles.headerContent }, this.getColumnDefinition(columnDefinition, 0).displayLabel),
|
|
1282
|
+
React.createElement("span", { className: styles.sortIcon }))));
|
|
1283
|
+
}))),
|
|
1284
|
+
React.createElement(FixedSizeList, { height: fixedHeadersStyle.maxHeight ? (typeof fixedHeadersStyle.maxHeight === 'string' ? parseFloat(fixedHeadersStyle.maxHeight) : fixedHeadersStyle.maxHeight) : 500, itemCount: this.data.length, itemSize: 50, width: '100%', itemData: itemData, outerRef: this.tableContainerRef, outerElementType: React.forwardRef((props, ref) => React.createElement("tbody", Object.assign({ ref: ref }, props))) }, ({ index, style, data }) => {
|
|
1285
|
+
const { rows, columnWidths, getColumnDefinition, rowClickFunction, rowClickStyle, columnDefinitions, animationProps, } = data;
|
|
1286
|
+
const row = rows[index];
|
|
1287
|
+
if (!row)
|
|
1288
|
+
return null;
|
|
1289
|
+
return (React.createElement("tr", { key: index, className: (animationProps === null || animationProps === void 0 ? void 0 : animationProps.animateOnLoad) ? styles.animatedRow : '', style: Object.assign(Object.assign({}, style), { animationDelay: `${index * 0.05}s` }) }, columnDefinitions.map((columnDefinition, colIndex) => (React.createElement("td", { onClick: () => rowClickFunction(row), key: colIndex, style: { width: columnWidths[colIndex], boxSizing: 'border-box' } },
|
|
1290
|
+
React.createElement("span", { style: Object.assign({}, rowClickStyle) }, getColumnDefinition(columnDefinition, index).cellRenderer(row)))))));
|
|
1291
|
+
}),
|
|
1292
|
+
this.tableFooter),
|
|
1293
|
+
this.renderPluginFooters()));
|
|
1294
|
+
}
|
|
1295
|
+
renderPluginHeaders() {
|
|
1296
|
+
if (!this.props.plugins) {
|
|
1297
|
+
return null;
|
|
1298
|
+
}
|
|
1299
|
+
return this.props.plugins.map((plugin) => {
|
|
1300
|
+
if (plugin.renderHeader) {
|
|
1301
|
+
// For sort plugin, only render header in mobile view
|
|
1302
|
+
if (plugin.id === 'sort' && !this.state.isMobile) {
|
|
1303
|
+
return null;
|
|
1304
|
+
}
|
|
1305
|
+
return React.createElement("div", { key: plugin.id }, plugin.renderHeader());
|
|
1306
|
+
}
|
|
1307
|
+
return null;
|
|
1308
|
+
});
|
|
1309
|
+
}
|
|
1310
|
+
renderPluginFooters() {
|
|
1311
|
+
if (!this.props.plugins) {
|
|
1312
|
+
return null;
|
|
1313
|
+
}
|
|
1314
|
+
return this.props.plugins.map((plugin) => {
|
|
1315
|
+
if (plugin.renderFooter) {
|
|
1316
|
+
return React.createElement("div", { key: plugin.id + '-footer' }, plugin.renderFooter());
|
|
1317
|
+
}
|
|
1318
|
+
return null;
|
|
1319
|
+
});
|
|
1320
|
+
}
|
|
1321
|
+
render() {
|
|
1322
|
+
var _a;
|
|
1323
|
+
if ((_a = this.props.animationProps) === null || _a === void 0 ? void 0 : _a.isLoading) {
|
|
1324
|
+
return this.skeletonView;
|
|
1325
|
+
}
|
|
1326
|
+
return (React.createElement("div", null,
|
|
1327
|
+
this.renderPluginHeaders(),
|
|
1328
|
+
!this.hasData && this.noDataComponent,
|
|
1329
|
+
this.hasData && this.state.isMobile && this.mobileView,
|
|
1330
|
+
this.hasData && !this.state.isMobile && this.largeScreenView));
|
|
1331
|
+
}
|
|
1332
|
+
}
|
|
1333
|
+
|
|
1334
|
+
// Class component
|
|
1335
|
+
class ResponsiveTable extends React.Component {
|
|
1336
|
+
constructor(props) {
|
|
1337
|
+
super(props);
|
|
1338
|
+
this.tableContainerRef = React.createRef();
|
|
1339
|
+
this.headerRef = React.createRef();
|
|
1340
|
+
this.handleScroll = () => {
|
|
1341
|
+
if (this.headerRef.current && !this.props.maxHeight) {
|
|
1342
|
+
const { top } = this.headerRef.current.getBoundingClientRect();
|
|
1343
|
+
const isSticky = top <= 0;
|
|
1344
|
+
if (isSticky !== this.state.isHeaderSticky) {
|
|
1345
|
+
this.setState({ isHeaderSticky: isSticky });
|
|
1346
|
+
}
|
|
1347
|
+
}
|
|
1348
|
+
};
|
|
1349
|
+
this.handleResize = () => {
|
|
1350
|
+
this.setState({
|
|
1351
|
+
isMobile: window.innerWidth <= this.mobileBreakpoint,
|
|
1352
|
+
});
|
|
1353
|
+
};
|
|
1354
|
+
this.state = {
|
|
1355
|
+
isMobile: false,
|
|
1356
|
+
processedData: props.data,
|
|
1357
|
+
isLoadingMore: false,
|
|
1358
|
+
isHeaderSticky: false,
|
|
1359
|
+
};
|
|
1360
|
+
this.debouncedResize = this.debounce(this.handleResize, 200);
|
|
1361
|
+
}
|
|
1362
|
+
get mobileBreakpoint() {
|
|
1363
|
+
return this.props.mobileBreakpoint || 600;
|
|
1364
|
+
}
|
|
1365
|
+
debounce(func, delay) {
|
|
1366
|
+
let timeout;
|
|
1367
|
+
return () => {
|
|
1368
|
+
clearTimeout(timeout);
|
|
1369
|
+
timeout = setTimeout(() => func(), delay);
|
|
1370
|
+
};
|
|
1371
|
+
}
|
|
1372
|
+
get data() {
|
|
1373
|
+
if (Array.isArray(this.state.processedData) && this.state.processedData.length > 0) {
|
|
1374
|
+
return this.state.processedData;
|
|
1375
|
+
}
|
|
1376
|
+
else {
|
|
1377
|
+
return [];
|
|
1378
|
+
}
|
|
1379
|
+
}
|
|
1380
|
+
get noDataSvg() {
|
|
1381
|
+
return (React.createElement("svg", { xmlns: "http://www.w3.org/2000/svg", fill: "#ccc", height: "40", width: "40", viewBox: "0 0 24 24" },
|
|
1382
|
+
React.createElement("path", { d: "M12 2C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2zm0 18c-4.41 0-8-3.59-8-8s3.59-8 8-8 8 3.59 8 8-3.59 8-8 8zm-1-14h2v6h-2zm0 8h2v2h-2z" })));
|
|
1383
|
+
}
|
|
1384
|
+
get hasData() {
|
|
1385
|
+
return this.data.length > 0;
|
|
1386
|
+
}
|
|
1387
|
+
get noDataComponent() {
|
|
1388
|
+
return (this.props.noDataComponent || (React.createElement("div", { className: styles.noDataWrapper },
|
|
1389
|
+
this.noDataSvg,
|
|
1390
|
+
React.createElement("div", { className: styles.noData }, "No data"))));
|
|
1391
|
+
}
|
|
1392
|
+
componentDidMount() {
|
|
1393
|
+
this.handleResize(); // Initial check
|
|
1394
|
+
window.addEventListener('resize', this.debouncedResize);
|
|
1395
|
+
if (this.props.enablePageLevelStickyHeader !== false) {
|
|
1396
|
+
window.addEventListener('scroll', this.handleScroll);
|
|
1397
|
+
}
|
|
1398
|
+
this.initializePlugins();
|
|
1399
|
+
}
|
|
1400
|
+
componentWillUnmount() {
|
|
1401
|
+
window.removeEventListener('resize', this.debouncedResize);
|
|
1402
|
+
if (this.props.enablePageLevelStickyHeader !== false) {
|
|
1403
|
+
window.removeEventListener('scroll', this.handleScroll);
|
|
1404
|
+
}
|
|
1405
|
+
}
|
|
1406
|
+
componentDidUpdate(prevProps) {
|
|
1407
|
+
var _a, _b, _c;
|
|
1408
|
+
if (prevProps.data !== this.props.data) {
|
|
1409
|
+
this.processData();
|
|
1410
|
+
}
|
|
1411
|
+
// Handle infinite scroll loading
|
|
1412
|
+
if (((_a = this.props.infiniteScrollProps) === null || _a === void 0 ? void 0 : _a.enableInfiniteScroll) && ((_b = this.props.infiniteScrollProps) === null || _b === void 0 ? void 0 : _b.hasMore) && !this.state.isLoadingMore && ((_c = this.props.infiniteScrollProps) === null || _c === void 0 ? void 0 : _c.onLoadMore)) ;
|
|
1413
|
+
}
|
|
1414
|
+
initializePlugins() {
|
|
1415
|
+
var _a, _b;
|
|
1416
|
+
const activePlugins = [];
|
|
1417
|
+
// Add explicitly provided plugins first
|
|
1418
|
+
if (this.props.plugins) {
|
|
1419
|
+
activePlugins.push(...this.props.plugins);
|
|
1420
|
+
}
|
|
1421
|
+
// Automatically add FilterPlugin if filterProps are provided and not already present
|
|
1422
|
+
if (((_a = this.props.filterProps) === null || _a === void 0 ? void 0 : _a.showFilter) && !activePlugins.some(p => p.id === 'filter')) {
|
|
1423
|
+
activePlugins.push(new FilterPlugin());
|
|
1424
|
+
}
|
|
1425
|
+
// Automatically add InfiniteScrollPlugin if infiniteScrollProps are provided and not already present
|
|
1426
|
+
if (((_b = this.props.infiniteScrollProps) === null || _b === void 0 ? void 0 : _b.enableInfiniteScroll) && !activePlugins.some(p => p.id === 'infinite-scroll')) {
|
|
1427
|
+
activePlugins.push(new InfiniteScrollPlugin());
|
|
1428
|
+
}
|
|
1429
|
+
activePlugins.forEach((plugin) => {
|
|
1430
|
+
if (plugin.onPluginInit) {
|
|
1431
|
+
plugin.onPluginInit({
|
|
1432
|
+
getData: () => this.props.data,
|
|
1433
|
+
forceUpdate: () => this.processData(),
|
|
1434
|
+
getScrollableElement: () => this.tableContainerRef.current,
|
|
1435
|
+
infiniteScrollProps: this.props.infiniteScrollProps,
|
|
1436
|
+
filterProps: this.props.filterProps,
|
|
1437
|
+
columnDefinitions: this.props.columnDefinitions,
|
|
1438
|
+
});
|
|
1439
|
+
}
|
|
1440
|
+
});
|
|
1441
|
+
// Process data with all active plugins
|
|
1442
|
+
let processedData = [...this.props.data];
|
|
1443
|
+
activePlugins.forEach((plugin) => {
|
|
1444
|
+
if (plugin.processData) {
|
|
1445
|
+
processedData = plugin.processData(processedData);
|
|
1446
|
+
}
|
|
1447
|
+
});
|
|
1448
|
+
this.setState({ processedData });
|
|
1449
|
+
}
|
|
1450
|
+
processData() {
|
|
1451
|
+
let processedData = [...this.props.data];
|
|
1452
|
+
if (this.props.plugins) {
|
|
1453
|
+
this.props.plugins.forEach((plugin) => {
|
|
1454
|
+
if (plugin.processData) {
|
|
1455
|
+
processedData = plugin.processData(processedData);
|
|
1456
|
+
}
|
|
1457
|
+
});
|
|
1458
|
+
}
|
|
1459
|
+
this.setState({ processedData });
|
|
1460
|
+
}
|
|
1461
|
+
getColumnDefinition(columnDefinition, rowIndex) {
|
|
1462
|
+
if (!this.hasData) {
|
|
1463
|
+
return { displayLabel: '', cellRenderer: () => '' };
|
|
1464
|
+
}
|
|
1465
|
+
return columnDefinition instanceof Function ? columnDefinition(this.data[0], rowIndex) : columnDefinition;
|
|
1466
|
+
}
|
|
1467
|
+
getRawColumnDefinition(columnDefinition) {
|
|
1468
|
+
let rawColumnDefinition = {};
|
|
1469
|
+
if (columnDefinition instanceof Function) {
|
|
1470
|
+
rawColumnDefinition = columnDefinition(this.data[0], 0);
|
|
1471
|
+
}
|
|
1472
|
+
else {
|
|
1473
|
+
rawColumnDefinition = columnDefinition;
|
|
1474
|
+
}
|
|
1475
|
+
return rawColumnDefinition;
|
|
1476
|
+
}
|
|
1477
|
+
onHeaderClickCallback(columnDefinition) {
|
|
1478
|
+
const rawColumnDefinition = this.getRawColumnDefinition(columnDefinition);
|
|
1479
|
+
if (rawColumnDefinition.interactivity && rawColumnDefinition.interactivity.onHeaderClick) {
|
|
1480
|
+
return rawColumnDefinition.interactivity.onHeaderClick;
|
|
1481
|
+
}
|
|
1482
|
+
else {
|
|
1483
|
+
return undefined;
|
|
1484
|
+
}
|
|
1485
|
+
}
|
|
1486
|
+
getClickableHeaderClassName(onHeaderClickCallback, colDef) {
|
|
1487
|
+
const rawColumnDefinition = this.getRawColumnDefinition(colDef);
|
|
1488
|
+
const clickableHeaderClassName = onHeaderClickCallback
|
|
1489
|
+
? rawColumnDefinition.interactivity.className || styles.clickableHeader
|
|
1490
|
+
: '';
|
|
1491
|
+
return clickableHeaderClassName;
|
|
1492
|
+
}
|
|
1493
|
+
getHeaderProps(columnDefinition) {
|
|
1494
|
+
const headerProps = {};
|
|
1495
|
+
if (this.props.plugins) {
|
|
1496
|
+
this.props.plugins.forEach((plugin) => {
|
|
1497
|
+
if (plugin.getHeaderProps) {
|
|
1498
|
+
Object.assign(headerProps, plugin.getHeaderProps(this.getRawColumnDefinition(columnDefinition)));
|
|
1499
|
+
}
|
|
1500
|
+
});
|
|
1501
|
+
}
|
|
1502
|
+
return headerProps;
|
|
1503
|
+
}
|
|
1504
|
+
get rowClickFunction() {
|
|
1505
|
+
if (this.props.onRowClick) {
|
|
1506
|
+
return this.props.onRowClick;
|
|
1507
|
+
}
|
|
1508
|
+
else {
|
|
1509
|
+
return () => { };
|
|
1510
|
+
}
|
|
1511
|
+
}
|
|
1512
|
+
get rowClickStyle() {
|
|
1513
|
+
if (this.props.onRowClick) {
|
|
1514
|
+
return { cursor: 'pointer' };
|
|
1515
|
+
}
|
|
1516
|
+
else {
|
|
1517
|
+
return {};
|
|
1518
|
+
}
|
|
1519
|
+
}
|
|
1520
|
+
get tableFooter() {
|
|
1521
|
+
if (!this.props.footerRows || this.props.footerRows.length === 0) {
|
|
1522
|
+
return null;
|
|
1523
|
+
}
|
|
1524
|
+
return (React.createElement("tfoot", null, this.props.footerRows.map((row, rowIndex) => (React.createElement("tr", { key: rowIndex }, row.columns.map((col, colIndex) => (React.createElement("td", { key: colIndex, colSpan: col.colSpan, className: `${styles.footerCell} ${col.className || ''} ${col.onCellClick ? styles.clickableFooterCell : ''}`, onClick: col.onCellClick }, col.cellRenderer()))))))));
|
|
1525
|
+
}
|
|
1526
|
+
get mobileFooter() {
|
|
1527
|
+
if (!this.props.footerRows || this.props.footerRows.length === 0) {
|
|
1528
|
+
return null;
|
|
1529
|
+
}
|
|
1530
|
+
return (React.createElement("div", { className: styles.footerCard },
|
|
1531
|
+
React.createElement("div", { className: styles['footer-card-body'] }, this.props.footerRows.map((row, rowIndex) => {
|
|
1532
|
+
let currentColumnIndex = 0;
|
|
1533
|
+
return (React.createElement("div", { key: rowIndex }, row.columns.map((col, colIndex) => {
|
|
1534
|
+
let label = col.displayLabel;
|
|
1535
|
+
if (!label && col.colSpan === 1) {
|
|
1536
|
+
const header = this.props.columnDefinitions[currentColumnIndex];
|
|
1537
|
+
if (header) {
|
|
1538
|
+
label = this.getRawColumnDefinition(header).displayLabel;
|
|
1539
|
+
}
|
|
1540
|
+
}
|
|
1541
|
+
currentColumnIndex += col.colSpan;
|
|
1542
|
+
return (React.createElement("p", { key: colIndex, className: `${styles['footer-card-row']} ${col.className || ''} ${col.onCellClick ? styles.clickableFooterCell : ''}`, onClick: col.onCellClick },
|
|
1543
|
+
label && React.createElement("span", { className: styles['card-label'] }, label),
|
|
1544
|
+
React.createElement("span", { className: styles['card-value'] }, col.cellRenderer())));
|
|
1545
|
+
})));
|
|
1546
|
+
}))));
|
|
1547
|
+
}
|
|
1548
|
+
get skeletonView() {
|
|
1549
|
+
const skeletonRowCount = 5; // Or make this configurable
|
|
1550
|
+
const columnCount = this.props.columnDefinitions.length;
|
|
1551
|
+
if (this.state.isMobile) {
|
|
1552
|
+
return (React.createElement("div", null, [...Array(skeletonRowCount)].map((_, i) => (React.createElement("div", { key: i, className: styles.skeletonCard }, [...Array(columnCount)].map((_, j) => (React.createElement("div", { key: j, className: `${styles.skeleton} ${styles.skeletonText}`, style: { marginBottom: '0.5rem' } }))))))));
|
|
1553
|
+
}
|
|
1554
|
+
return (React.createElement("table", { className: styles.responsiveTable },
|
|
1555
|
+
React.createElement("thead", null,
|
|
1556
|
+
React.createElement("tr", null, [...Array(columnCount)].map((_, i) => (React.createElement("th", { key: i },
|
|
1557
|
+
React.createElement("div", { className: `${styles.skeleton} ${styles.skeletonText}` })))))),
|
|
1558
|
+
React.createElement("tbody", null, [...Array(skeletonRowCount)].map((_, i) => (React.createElement("tr", { key: i }, [...Array(columnCount)].map((_, j) => (React.createElement("td", { key: j },
|
|
1559
|
+
React.createElement("div", { className: `${styles.skeleton} ${styles.skeletonText}` }))))))))));
|
|
1560
|
+
}
|
|
1561
|
+
get mobileView() {
|
|
1562
|
+
return (React.createElement("div", null,
|
|
1563
|
+
this.data.map((row, rowIndex) => {
|
|
1564
|
+
var _a;
|
|
1565
|
+
return (React.createElement("div", { key: rowIndex, className: `${styles['card']} ${((_a = this.props.animationProps) === null || _a === void 0 ? void 0 : _a.animateOnLoad) ? styles.animatedRow : ''}`, style: { animationDelay: `${rowIndex * 0.05}s` }, onClick: (e) => {
|
|
1566
|
+
this.rowClickFunction(row);
|
|
1567
|
+
e.stopPropagation();
|
|
1568
|
+
e.preventDefault();
|
|
1569
|
+
} },
|
|
1570
|
+
React.createElement("div", { className: styles['card-header'] }, " "),
|
|
1571
|
+
React.createElement("div", { className: styles['card-body'] }, this.props.columnDefinitions.map((columnDefinition, colIndex) => {
|
|
1572
|
+
const colDef = this.getColumnDefinition(columnDefinition, rowIndex);
|
|
1573
|
+
const onHeaderClickCallback = this.onHeaderClickCallback(colDef);
|
|
1574
|
+
const clickableHeaderClassName = this.getClickableHeaderClassName(onHeaderClickCallback, colDef);
|
|
1575
|
+
return (React.createElement("div", { key: colIndex, className: styles['card-row'] },
|
|
1576
|
+
React.createElement("p", null,
|
|
1577
|
+
React.createElement("span", { className: `${styles['card-label']} ${clickableHeaderClassName}`, onClick: onHeaderClickCallback ? () => onHeaderClickCallback(colDef.interactivity.id) : undefined }, colDef.displayLabel),
|
|
1578
|
+
React.createElement("span", { className: styles['card-value'] }, colDef.cellRenderer(row)))));
|
|
1579
|
+
}))));
|
|
1580
|
+
}),
|
|
1581
|
+
this.mobileFooter));
|
|
1582
|
+
}
|
|
1583
|
+
get largeScreenView() {
|
|
1584
|
+
const useFixedHeaders = this.props.maxHeight ? true : false;
|
|
1585
|
+
const fixedHeadersStyle = useFixedHeaders
|
|
1586
|
+
? { maxHeight: this.props.maxHeight, overflowY: 'auto' }
|
|
1587
|
+
: {};
|
|
1245
1588
|
return (React.createElement("div", { style: fixedHeadersStyle, ref: this.tableContainerRef },
|
|
1246
1589
|
React.createElement("table", { className: styles['responsiveTable'] },
|
|
1247
1590
|
React.createElement("thead", { ref: this.headerRef, className: this.state.isHeaderSticky ? styles.stickyHeader : '' },
|
|
@@ -1252,17 +1595,18 @@ class ResponsiveTable extends React.Component {
|
|
|
1252
1595
|
// Combine class names: existing clickable, and plugin-provided (mapped to CSS Modules)
|
|
1253
1596
|
const combinedClassName = `${clickableHeaderClassName} ${headerProps.className ? styles[headerProps.className] : ''}`.trim();
|
|
1254
1597
|
// Remove className from headerProps to avoid duplication
|
|
1598
|
+
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
1255
1599
|
const { className } = headerProps, restHeaderProps = __rest(headerProps, ["className"]);
|
|
1256
1600
|
return (React.createElement("th", Object.assign({ key: colIndex, className: combinedClassName }, restHeaderProps),
|
|
1257
1601
|
React.createElement("div", { className: styles.headerInnerWrapper },
|
|
1258
1602
|
React.createElement("div", { className: styles.headerContent }, this.getColumnDefinition(columnDefinition, 0).displayLabel),
|
|
1259
1603
|
React.createElement("span", { className: styles.sortIcon }))));
|
|
1260
1604
|
}))),
|
|
1261
|
-
React.createElement("tbody", null,
|
|
1605
|
+
React.createElement("tbody", null, this.data.map((row, rowIndex) => {
|
|
1262
1606
|
var _a;
|
|
1263
1607
|
return (React.createElement("tr", { key: rowIndex, className: ((_a = this.props.animationProps) === null || _a === void 0 ? void 0 : _a.animateOnLoad) ? styles.animatedRow : '', style: { animationDelay: `${rowIndex * 0.05}s` } }, this.props.columnDefinitions.map((columnDefinition, colIndex) => (React.createElement("td", { onClick: () => this.rowClickFunction(row), key: colIndex },
|
|
1264
1608
|
React.createElement("span", { style: Object.assign({}, this.rowClickStyle) }, this.getColumnDefinition(columnDefinition, rowIndex).cellRenderer(row)))))));
|
|
1265
|
-
}))
|
|
1609
|
+
})),
|
|
1266
1610
|
this.tableFooter),
|
|
1267
1611
|
this.renderPluginFooters()));
|
|
1268
1612
|
}
|
|
@@ -1293,8 +1637,11 @@ class ResponsiveTable extends React.Component {
|
|
|
1293
1637
|
});
|
|
1294
1638
|
}
|
|
1295
1639
|
render() {
|
|
1296
|
-
var _a;
|
|
1297
|
-
if ((_a = this.props.
|
|
1640
|
+
var _a, _b;
|
|
1641
|
+
if ((_a = this.props.infiniteScrollProps) === null || _a === void 0 ? void 0 : _a.enableInfiniteScroll) {
|
|
1642
|
+
return React.createElement(InfiniteTable, Object.assign({}, this.props));
|
|
1643
|
+
}
|
|
1644
|
+
if ((_b = this.props.animationProps) === null || _b === void 0 ? void 0 : _b.isLoading) {
|
|
1298
1645
|
return this.skeletonView;
|
|
1299
1646
|
}
|
|
1300
1647
|
return (React.createElement("div", null,
|