jattac.libs.web.responsive-table 0.2.1 → 0.2.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +626 -581
- package/dist/UI/ResponsiveTable.d.ts +4 -0
- package/dist/index.js +20 -3
- package/dist/index.js.map +1 -1
- package/gemini/project_memos.md +3 -0
- package/gemini/release_git_steps.md +79 -79
- package/package.json +1 -1
- package/src/Styles/ResponsiveTable.module.css +260 -253
- package/src/UI/ResponsiveTable.tsx +552 -532
|
@@ -12,6 +12,7 @@ interface IProps<TData> {
|
|
|
12
12
|
footerRows?: IFooterRowDefinition[];
|
|
13
13
|
mobileBreakpoint?: number;
|
|
14
14
|
plugins?: IResponsiveTablePlugin<TData>[];
|
|
15
|
+
enablePageLevelStickyHeader?: boolean;
|
|
15
16
|
infiniteScrollProps?: {
|
|
16
17
|
enableInfiniteScroll?: boolean;
|
|
17
18
|
onLoadMore?: (currentData: TData[]) => Promise<TData[] | null>;
|
|
@@ -32,10 +33,12 @@ interface IState<TData> {
|
|
|
32
33
|
isMobile: boolean;
|
|
33
34
|
processedData: TData[];
|
|
34
35
|
isLoadingMore: boolean;
|
|
36
|
+
isHeaderSticky: boolean;
|
|
35
37
|
}
|
|
36
38
|
declare class ResponsiveTable<TData> extends Component<IProps<TData>, IState<TData>> {
|
|
37
39
|
private debouncedResize;
|
|
38
40
|
private tableContainerRef;
|
|
41
|
+
private headerRef;
|
|
39
42
|
constructor(props: IProps<TData>);
|
|
40
43
|
private get mobileBreakpoint();
|
|
41
44
|
private debounce;
|
|
@@ -46,6 +49,7 @@ declare class ResponsiveTable<TData> extends Component<IProps<TData>, IState<TDa
|
|
|
46
49
|
componentDidMount(): void;
|
|
47
50
|
componentWillUnmount(): void;
|
|
48
51
|
componentDidUpdate(prevProps: IProps<TData>): void;
|
|
52
|
+
private handleScroll;
|
|
49
53
|
private initializePlugins;
|
|
50
54
|
private processData;
|
|
51
55
|
handleResize: () => void;
|
package/dist/index.js
CHANGED
|
@@ -31,8 +31,8 @@ function styleInject(css, ref) {
|
|
|
31
31
|
}
|
|
32
32
|
}
|
|
33
33
|
|
|
34
|
-
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:
|
|
35
|
-
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","clickableHeader":"ResponsiveTable-module_clickableHeader__xHQhF","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","skeleton":"ResponsiveTable-module_skeleton__XxsXW","skeletonText":"ResponsiveTable-module_skeletonText__T-Lgq","skeletonCard":"ResponsiveTable-module_skeletonCard__AYVwL","noDataWrapper":"ResponsiveTable-module_noDataWrapper__Rj-k3","noData":"ResponsiveTable-module_noData__IpwNq"};
|
|
34
|
+
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;\r\n border-bottom: 2px solid var(--table-border-color);\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.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";
|
|
35
|
+
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","clickableHeader":"ResponsiveTable-module_clickableHeader__xHQhF","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","skeleton":"ResponsiveTable-module_skeleton__XxsXW","skeletonText":"ResponsiveTable-module_skeletonText__T-Lgq","skeletonCard":"ResponsiveTable-module_skeletonCard__AYVwL","noDataWrapper":"ResponsiveTable-module_noDataWrapper__Rj-k3","noData":"ResponsiveTable-module_noData__IpwNq","stickyHeader":"ResponsiveTable-module_stickyHeader__-jjN-"};
|
|
36
36
|
styleInject(css_248z);
|
|
37
37
|
|
|
38
38
|
class FilterPlugin {
|
|
@@ -972,6 +972,16 @@ class ResponsiveTable extends React.Component {
|
|
|
972
972
|
constructor(props) {
|
|
973
973
|
super(props);
|
|
974
974
|
this.tableContainerRef = React.createRef();
|
|
975
|
+
this.headerRef = React.createRef();
|
|
976
|
+
this.handleScroll = () => {
|
|
977
|
+
if (this.headerRef.current && !this.props.maxHeight) {
|
|
978
|
+
const { top } = this.headerRef.current.getBoundingClientRect();
|
|
979
|
+
const isSticky = top <= 0;
|
|
980
|
+
if (isSticky !== this.state.isHeaderSticky) {
|
|
981
|
+
this.setState({ isHeaderSticky: isSticky });
|
|
982
|
+
}
|
|
983
|
+
}
|
|
984
|
+
};
|
|
975
985
|
this.handleResize = () => {
|
|
976
986
|
this.setState({
|
|
977
987
|
isMobile: window.innerWidth <= this.mobileBreakpoint,
|
|
@@ -981,6 +991,7 @@ class ResponsiveTable extends React.Component {
|
|
|
981
991
|
isMobile: false,
|
|
982
992
|
processedData: props.data,
|
|
983
993
|
isLoadingMore: false,
|
|
994
|
+
isHeaderSticky: false,
|
|
984
995
|
};
|
|
985
996
|
this.debouncedResize = this.debounce(this.handleResize, 200);
|
|
986
997
|
}
|
|
@@ -1017,10 +1028,16 @@ class ResponsiveTable extends React.Component {
|
|
|
1017
1028
|
componentDidMount() {
|
|
1018
1029
|
this.handleResize(); // Initial check
|
|
1019
1030
|
window.addEventListener('resize', this.debouncedResize);
|
|
1031
|
+
if (this.props.enablePageLevelStickyHeader !== false) {
|
|
1032
|
+
window.addEventListener('scroll', this.handleScroll);
|
|
1033
|
+
}
|
|
1020
1034
|
this.initializePlugins();
|
|
1021
1035
|
}
|
|
1022
1036
|
componentWillUnmount() {
|
|
1023
1037
|
window.removeEventListener('resize', this.debouncedResize);
|
|
1038
|
+
if (this.props.enablePageLevelStickyHeader !== false) {
|
|
1039
|
+
window.removeEventListener('scroll', this.handleScroll);
|
|
1040
|
+
}
|
|
1024
1041
|
}
|
|
1025
1042
|
componentDidUpdate(prevProps) {
|
|
1026
1043
|
var _a, _b, _c;
|
|
@@ -1204,7 +1221,7 @@ class ResponsiveTable extends React.Component {
|
|
|
1204
1221
|
};
|
|
1205
1222
|
return (React.createElement("div", { style: fixedHeadersStyle, ref: this.tableContainerRef },
|
|
1206
1223
|
React.createElement("table", { className: styles['responsiveTable'] },
|
|
1207
|
-
React.createElement("thead",
|
|
1224
|
+
React.createElement("thead", { ref: this.headerRef, className: this.state.isHeaderSticky ? styles.stickyHeader : '' },
|
|
1208
1225
|
React.createElement("tr", null, this.props.columnDefinitions.map((columnDefinition, colIndex) => {
|
|
1209
1226
|
const onHeaderClickCallback = this.onHeaderClickCallback(columnDefinition);
|
|
1210
1227
|
const clickableHeaderClassName = this.getClickableHeaderClassName(onHeaderClickCallback, columnDefinition);
|