jattac.libs.web.responsive-table 0.7.5 → 0.8.0

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/dist/index.js CHANGED
@@ -75,10 +75,189 @@ function styleInject(css, ref) {
75
75
  }
76
76
  }
77
77
 
78
- var css_248z$2 = "/* 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; <-- REMOVED to prevent conflict with transform */\n /* top: 0; <-- REMOVED */\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 position: relative; /* Contain the absolutely positioned sort icon */\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}\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/* Add a transition for the card view as well */\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, background-color 0.2s ease-in-out;\n border-left: 5px solid transparent; /* Add transparent border for smooth transition */\n}\n\n/* Style for selected rows */\n.ResponsiveTable-module_selectedRow__-JyNW {\n /* Use a variable for the selection color to allow theming */\n --table-row-selected-bg: #ddeaff;\n background-color: var(--table-row-selected-bg) !important; /* Use important to override hover and stripe styles */\n}\n\n/* In mobile view, we use the border for selection indication */\n.ResponsiveTable-module_card__b-U2v.ResponsiveTable-module_selectedRow__-JyNW {\n border-left: 5px solid var(--interactive-color);\n background-color: var(--table-row-selected-bg);\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\n/* Modern hover effect */\n.ResponsiveTable-module_responsiveTable__4y-Od tr:hover {\n background-color: var(--table-row-hover-bg);\n}\n\n/* Clickable Row Style */\n.ResponsiveTable-module_clickableRow__0kjWm {\n cursor: pointer;\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; <-- REMOVED to fix sticky header bug */\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 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 margin-left: 0.5rem; /* Add a small gap between text and icon */\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- th {\n position: sticky;\n top: 0;\n z-index: 1;\n box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);\n}\n\n.ResponsiveTable-module_internalStickyHeader__idiJY th {\n position: sticky;\n top: 0;\n z-index: 1;\n}\n/* Spinner for Loading More */\n.ResponsiveTable-module_spinner__Pn-3D {\n border: 4px solid rgba(0, 0, 0, 0.1);\n border-left-color: var(--interactive-color); /* Use theme color */\n border-radius: 50%;\n width: 24px;\n height: 24px;\n animation: ResponsiveTable-module_spin__i3NHn 1s linear infinite;\n display: inline-block;\n vertical-align: middle;\n margin-right: 8px;\n}\n\n@keyframes ResponsiveTable-module_spin__i3NHn {\n 0% { transform: rotate(0deg); }\n 100% { transform: rotate(360deg); }\n}\n\n/* Loading/No More Data Container */\n.ResponsiveTable-module_infoContainer__b9IF5 {\n display: flex;\n justify-content: center;\n align-items: center;\n padding: 20px;\n color: var(--text-color-muted);\n font-size: 0.9rem;\n gap: 8px;\n background-color: var(--table-header-bg);\n border-top: 1px solid var(--table-border-color);\n}\n\n.ResponsiveTable-module_infoContainer__b9IF5.ResponsiveTable-module_noMoreData__he1rZ {\n font-weight: 500;\n}";
78
+ var css_248z$2 = "/* 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; <-- REMOVED to prevent conflict with transform */\r\n /* top: 0; <-- REMOVED */\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 position: relative; /* Contain the absolutely positioned sort icon */\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}\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/* Add a transition for the card view as well */\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, background-color 0.2s ease-in-out;\r\n border-left: 5px solid transparent; /* Add transparent border for smooth transition */\r\n}\r\n\r\n/* Style for selected rows */\r\n.ResponsiveTable-module_selectedRow__-JyNW {\r\n /* Use a variable for the selection color to allow theming */\r\n --table-row-selected-bg: #ddeaff;\r\n background-color: var(--table-row-selected-bg) !important; /* Use important to override hover and stripe styles */\r\n}\r\n\r\n/* In mobile view, we use the border for selection indication */\r\n.ResponsiveTable-module_card__b-U2v.ResponsiveTable-module_selectedRow__-JyNW {\r\n border-left: 5px solid var(--interactive-color);\r\n background-color: var(--table-row-selected-bg);\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\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 Row Style */\r\n.ResponsiveTable-module_clickableRow__0kjWm {\r\n cursor: pointer;\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; <-- REMOVED to fix sticky header bug */\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 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 margin-left: 0.5rem; /* Add a small gap between text and icon */\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- th {\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\r\n.ResponsiveTable-module_internalStickyHeader__idiJY th {\r\n position: sticky;\r\n top: 0;\r\n z-index: 1;\r\n}\r\n/* Spinner for Loading More */\r\n.ResponsiveTable-module_spinner__Pn-3D {\r\n border: 4px solid rgba(0, 0, 0, 0.1);\r\n border-left-color: var(--interactive-color); /* Use theme color */\r\n border-radius: 50%;\r\n width: 24px;\r\n height: 24px;\r\n animation: ResponsiveTable-module_spin__i3NHn 1s linear infinite;\r\n display: inline-block;\r\n vertical-align: middle;\r\n margin-right: 8px;\r\n}\r\n\r\n@keyframes ResponsiveTable-module_spin__i3NHn {\r\n 0% { transform: rotate(0deg); }\r\n 100% { transform: rotate(360deg); }\r\n}\r\n\r\n/* Loading/No More Data Container */\r\n.ResponsiveTable-module_infoContainer__b9IF5 {\r\n display: flex;\r\n justify-content: center;\r\n align-items: center;\r\n padding: 20px;\r\n color: var(--text-color-muted);\r\n font-size: 0.9rem;\r\n gap: 8px;\r\n background-color: var(--table-header-bg);\r\n border-top: 1px solid var(--table-border-color);\r\n}\r\n\r\n.ResponsiveTable-module_infoContainer__b9IF5.ResponsiveTable-module_noMoreData__he1rZ {\r\n font-weight: 500;\r\n}";
79
79
  var styles$2 = {"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","selectedRow":"ResponsiveTable-module_selectedRow__-JyNW","clickableRow":"ResponsiveTable-module_clickableRow__0kjWm","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-","internalStickyHeader":"ResponsiveTable-module_internalStickyHeader__idiJY","spinner":"ResponsiveTable-module_spinner__Pn-3D","spin":"ResponsiveTable-module_spin__i3NHn","infoContainer":"ResponsiveTable-module_infoContainer__b9IF5","noMoreData":"ResponsiveTable-module_noMoreData__he1rZ"};
80
80
  styleInject(css_248z$2);
81
81
 
82
+ function DesktopView(props) {
83
+ const { columnDefinitions, originalColumnDefinitions, currentData, maxHeight, isHeaderSticky, tableContainerRef, headerRef, getRowProps, getHeaderProps, onHeaderClickCallback, getClickableHeaderClassName, getRawColumnDefinition, getColumnDefinition, renderCell, rowClickFunction, footerRows, renderPluginFooters, animationProps, onRowClick, selectionProps, onScroll, } = props;
84
+ const getEffectiveColSpan = React.useCallback((footerCol, startIndex) => {
85
+ const originalSpan = footerCol.colSpan || 1;
86
+ const endIndex = startIndex + originalSpan;
87
+ let visibleCount = 0;
88
+ for (let i = startIndex; i < endIndex; i++) {
89
+ const col = originalColumnDefinitions[i];
90
+ if (col && getRawColumnDefinition(col).visible !== false) {
91
+ visibleCount++;
92
+ }
93
+ }
94
+ return visibleCount;
95
+ }, [originalColumnDefinitions, getRawColumnDefinition]);
96
+ const tableFooter = React.useMemo(() => {
97
+ if (!footerRows || footerRows.length === 0) {
98
+ return null;
99
+ }
100
+ return (React.createElement("tfoot", null, footerRows.map((row, rowIndex) => {
101
+ let currentOriginalIndex = 0;
102
+ return (React.createElement("tr", { key: rowIndex }, row.columns.map((col, colIndex) => {
103
+ const effectiveColSpan = getEffectiveColSpan(col, currentOriginalIndex);
104
+ currentOriginalIndex += (col.colSpan || 1);
105
+ if (effectiveColSpan === 0)
106
+ return null;
107
+ return (React.createElement("td", { key: colIndex, colSpan: effectiveColSpan, className: `${styles$2.footerCell} ${col.className || ''} ${col.onCellClick ? styles$2.clickableFooterCell : ''}`, onClick: col.onCellClick }, col.cellRenderer()));
108
+ })));
109
+ })));
110
+ }, [footerRows, getEffectiveColSpan]);
111
+ const useFixedHeaders = maxHeight ? true : false;
112
+ const isClickable = onRowClick || selectionProps;
113
+ const fixedHeadersStyle = useFixedHeaders
114
+ ? { maxHeight, overflowY: 'auto' }
115
+ : {};
116
+ const headerClassName = useFixedHeaders
117
+ ? styles$2.internalStickyHeader
118
+ : (isHeaderSticky ? styles$2.stickyHeader : '');
119
+ return (React.createElement("div", { style: fixedHeadersStyle, ref: tableContainerRef, onScroll: onScroll },
120
+ React.createElement("table", { className: styles$2['responsiveTable'] },
121
+ React.createElement("thead", { ref: headerRef, className: headerClassName },
122
+ React.createElement("tr", null, columnDefinitions.map((columnDefinition, colIndex) => {
123
+ const onHeaderClick = onHeaderClickCallback(columnDefinition);
124
+ const clickableHeaderClassName = getClickableHeaderClassName(onHeaderClick, columnDefinition);
125
+ const headerProps = getHeaderProps(columnDefinition);
126
+ const combinedClassName = `${clickableHeaderClassName} ${headerProps.className ? styles$2[headerProps.className] : ''}`.trim();
127
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
128
+ const { className } = headerProps, restHeaderProps = __rest(headerProps, ["className"]);
129
+ return (React.createElement("th", Object.assign({ key: colIndex, className: combinedClassName }, restHeaderProps, { onClick: onHeaderClick ? () => onHeaderClick(getRawColumnDefinition(columnDefinition).interactivity.id) : restHeaderProps.onClick }),
130
+ React.createElement("div", { className: styles$2.headerInnerWrapper },
131
+ React.createElement("div", { className: styles$2.headerContent }, getColumnDefinition(columnDefinition, 0).displayLabel),
132
+ React.createElement("span", { className: styles$2.sortIcon }))));
133
+ }))),
134
+ React.createElement("tbody", null, currentData.map((row, rowIndex) => {
135
+ const rowProps = getRowProps(row);
136
+ const pluginOnClick = rowProps.onClick;
137
+ return (React.createElement("tr", { key: rowIndex, className: `${isClickable ? styles$2.clickableRow : ''} ${(animationProps === null || animationProps === void 0 ? void 0 : animationProps.animateOnLoad) ? styles$2.animatedRow : ''} ${rowProps.className || ''}`.trim(), style: { animationDelay: `${rowIndex * 0.05}s` }, "aria-selected": rowProps['aria-selected'], onClick: (e) => {
138
+ if (pluginOnClick) {
139
+ pluginOnClick(e);
140
+ }
141
+ rowClickFunction(row);
142
+ } }, columnDefinitions.map((columnDefinition, colIndex) => {
143
+ const colDef = getColumnDefinition(columnDefinition, rowIndex);
144
+ const cellContent = colDef.cellRenderer(row);
145
+ return (React.createElement("td", { key: colIndex }, renderCell(cellContent, row, colDef)));
146
+ })));
147
+ })),
148
+ tableFooter),
149
+ renderPluginFooters()));
150
+ }
151
+
152
+ function MobileView(props) {
153
+ const { currentData, columnDefinitions, onRowClick, selectionProps, animationProps, getRowProps, getRowId, getColumnDefinition, onHeaderClickCallback, getClickableHeaderClassName, renderCell, rowClickFunction, mobileFooter, } = props;
154
+ const isClickable = onRowClick || selectionProps;
155
+ return (React.createElement("div", null,
156
+ currentData.map((row, rowIndex) => {
157
+ const rowProps = getRowProps(row);
158
+ const pluginOnClick = rowProps.onClick;
159
+ return (React.createElement("div", { key: getRowId(row, rowIndex), className: `${styles$2.card} ${isClickable ? styles$2.clickableRow : ''} ${(animationProps === null || animationProps === void 0 ? void 0 : animationProps.animateOnLoad) ? styles$2.animatedRow : ''} ${rowProps.className || ''}`.trim(), style: { animationDelay: `${rowIndex * 0.05}s` }, "aria-selected": rowProps['aria-selected'], onClick: (e) => {
160
+ if (pluginOnClick)
161
+ pluginOnClick(e);
162
+ rowClickFunction(row);
163
+ } },
164
+ React.createElement("div", { className: styles$2['card-header'] }, " "),
165
+ React.createElement("div", { className: styles$2['card-body'] }, columnDefinitions.map((columnDefinition, colIndex) => {
166
+ const colDef = getColumnDefinition(columnDefinition, rowIndex);
167
+ const onHeaderClick = onHeaderClickCallback(colDef);
168
+ const clickableHeaderClassName = getClickableHeaderClassName(onHeaderClick, colDef);
169
+ return (React.createElement("div", { key: colIndex, className: styles$2['card-row'] },
170
+ React.createElement("p", null,
171
+ React.createElement("span", { className: `${styles$2['card-label']} ${clickableHeaderClassName}`, onClick: (e) => {
172
+ if (onHeaderClick) {
173
+ e.stopPropagation();
174
+ onHeaderClick(colDef.interactivity.id);
175
+ }
176
+ } }, colDef.displayLabel),
177
+ React.createElement("span", { className: styles$2['card-value'] }, renderCell(colDef.cellRenderer(row), row, colDef)))));
178
+ }))));
179
+ }),
180
+ mobileFooter));
181
+ }
182
+
183
+ function SkeletonView(props) {
184
+ const { isMobile, columnDefinitions } = props;
185
+ const skeletonRowCount = 5;
186
+ const columnCount = columnDefinitions.length;
187
+ if (isMobile) {
188
+ return (React.createElement("div", null, [...Array(skeletonRowCount)].map((_, i) => (React.createElement("div", { key: i, className: styles$2.skeletonCard }, [...Array(columnCount)].map((_, j) => (React.createElement("div", { key: j, className: `${styles$2.skeleton} ${styles$2.skeletonText}`, style: { marginBottom: '0.5rem' } }))))))));
189
+ }
190
+ return (React.createElement("table", { className: styles$2.responsiveTable },
191
+ React.createElement("thead", null,
192
+ React.createElement("tr", null, [...Array(columnCount)].map((_, i) => (React.createElement("th", { key: i },
193
+ React.createElement("div", { className: `${styles$2.skeleton} ${styles$2.skeletonText}` })))))),
194
+ React.createElement("tbody", null, [...Array(skeletonRowCount)].map((_, i) => (React.createElement("tr", { key: i }, [...Array(columnCount)].map((_, j) => (React.createElement("td", { key: j },
195
+ React.createElement("div", { className: `${styles$2.skeleton} ${styles$2.skeletonText}` }))))))))));
196
+ }
197
+
198
+ var css_248z$1 = "/* Spinner for Loading More */\r\n.LoadingSpinner-module_spinner__F9V3x {\r\n border: 4px solid rgba(0, 0, 0, 0.1);\r\n border-left-color: var(--interactive-color); /* Use theme color */\r\n border-radius: 50%;\r\n width: 24px;\r\n height: 24px;\r\n animation: LoadingSpinner-module_spin__VkBDO 1s linear infinite;\r\n display: inline-block;\r\n vertical-align: middle;\r\n margin-right: 8px;\r\n}\r\n\r\n@keyframes LoadingSpinner-module_spin__VkBDO {\r\n 0% { transform: rotate(0deg); }\r\n 100% { transform: rotate(360deg); }\r\n}";
199
+ var styles$1 = {"spinner":"LoadingSpinner-module_spinner__F9V3x"};
200
+ styleInject(css_248z$1);
201
+
202
+ var css_248z = "/* Loading/No More Data Container */\r\n.NoMoreDataMessage-module_infoContainer__dk1r5 {\r\n display: flex;\r\n justify-content: center;\r\n align-items: center;\r\n padding: 20px;\r\n color: var(--text-color-muted);\r\n font-size: 0.9rem;\r\n gap: 8px;\r\n background-color: var(--table-header-bg);\r\n border-top: 1px solid var(--table-border-color);\r\n}\r\n\r\n.NoMoreDataMessage-module_infoContainer__dk1r5.NoMoreDataMessage-module_noMoreData__ATuIg {\r\n font-weight: 500;\r\n}";
203
+ var styles = {"infoContainer":"NoMoreDataMessage-module_infoContainer__dk1r5","noMoreData":"NoMoreDataMessage-module_noMoreData__ATuIg"};
204
+ styleInject(css_248z);
205
+
206
+ const LoadingSpinner = () => {
207
+ return (React.createElement("div", { className: styles.infoContainer },
208
+ React.createElement("div", { className: styles$1.spinner }),
209
+ React.createElement("span", null, "Loading more items...")));
210
+ };
211
+
212
+ const NoMoreDataMessage = () => {
213
+ return (React.createElement("div", { className: `${styles.infoContainer} ${styles.noMoreData}` },
214
+ React.createElement("p", null, "You've reached the end!")));
215
+ };
216
+
217
+ function debounce(func, delay) {
218
+ let timeout;
219
+ return function (...args) {
220
+ clearTimeout(timeout);
221
+ timeout = setTimeout(() => {
222
+ func.apply(this, args);
223
+ }, delay);
224
+ };
225
+ }
226
+ const useResponsiveTable = (props) => {
227
+ const { mobileBreakpoint = 600, enablePageLevelStickyHeader = true, maxHeight, headerRef, scrollableRef } = props;
228
+ const [isMobile, setIsMobile] = React.useState(false);
229
+ const [isHeaderSticky, setIsHeaderSticky] = React.useState(false);
230
+ const handleResize = React.useCallback(() => {
231
+ setIsMobile(window.innerWidth <= mobileBreakpoint);
232
+ }, [mobileBreakpoint]);
233
+ const handleScroll = React.useCallback((currentTarget) => {
234
+ // Page-level sticky header logic
235
+ if (enablePageLevelStickyHeader && !maxHeight && (headerRef === null || headerRef === void 0 ? void 0 : headerRef.current)) {
236
+ const { top } = headerRef.current.getBoundingClientRect();
237
+ const sticky = top <= 0;
238
+ if (sticky !== isHeaderSticky) {
239
+ setIsHeaderSticky(sticky);
240
+ }
241
+ }
242
+ }, [enablePageLevelStickyHeader, maxHeight, headerRef, isHeaderSticky]);
243
+ const debouncedScrollHandler = React.useRef(debounce(handleScroll, 200)).current;
244
+ React.useEffect(() => {
245
+ handleResize(); // Initial check
246
+ window.addEventListener('resize', handleResize);
247
+ const scrollTarget = (scrollableRef === null || scrollableRef === void 0 ? void 0 : scrollableRef.current) || window;
248
+ if (enablePageLevelStickyHeader || maxHeight) { // Only add scroll listener if sticky header or internal scroll is enabled
249
+ scrollTarget.addEventListener('scroll', (e) => debouncedScrollHandler(e.currentTarget));
250
+ }
251
+ return () => {
252
+ window.removeEventListener('resize', handleResize);
253
+ if (enablePageLevelStickyHeader || maxHeight) {
254
+ scrollTarget.removeEventListener('scroll', (e) => debouncedScrollHandler(e.currentTarget));
255
+ }
256
+ };
257
+ }, [handleResize, debouncedScrollHandler, enablePageLevelStickyHeader, maxHeight, scrollableRef]);
258
+ return { isMobile, isHeaderSticky, debouncedScrollHandler: debouncedScrollHandler };
259
+ };
260
+
82
261
  class FilterPlugin {
83
262
  constructor() {
84
263
  this.id = 'filter';
@@ -121,7 +300,11 @@ class FilterPlugin {
121
300
  });
122
301
  });
123
302
  };
124
- this.renderCell = (content, _row, _column) => {
303
+ this.renderCell = (content,
304
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
305
+ _row,
306
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
307
+ _column) => {
125
308
  if (!this.filterText || typeof content !== 'string') {
126
309
  return content;
127
310
  }
@@ -224,474 +407,560 @@ class SelectionPlugin {
224
407
  }
225
408
  }
226
409
 
227
- var css_248z$1 = "/* Spinner for Loading More */\r\n.LoadingSpinner-module_spinner__F9V3x {\r\n border: 4px solid rgba(0, 0, 0, 0.1);\r\n border-left-color: var(--interactive-color); /* Use theme color */\r\n border-radius: 50%;\r\n width: 24px;\r\n height: 24px;\r\n animation: LoadingSpinner-module_spin__VkBDO 1s linear infinite;\r\n display: inline-block;\r\n vertical-align: middle;\r\n margin-right: 8px;\r\n}\r\n\r\n@keyframes LoadingSpinner-module_spin__VkBDO {\r\n 0% { transform: rotate(0deg); }\r\n 100% { transform: rotate(360deg); }\r\n}";
228
- var styles$1 = {"spinner":"LoadingSpinner-module_spinner__F9V3x"};
229
- styleInject(css_248z$1);
230
-
231
- var css_248z = "/* Loading/No More Data Container */\r\n.NoMoreDataMessage-module_infoContainer__dk1r5 {\r\n display: flex;\r\n justify-content: center;\r\n align-items: center;\r\n padding: 20px;\r\n color: var(--text-color-muted);\r\n font-size: 0.9rem;\r\n gap: 8px;\r\n background-color: var(--table-header-bg);\r\n border-top: 1px solid var(--table-border-color);\r\n}\r\n\r\n.NoMoreDataMessage-module_infoContainer__dk1r5.NoMoreDataMessage-module_noMoreData__ATuIg {\r\n font-weight: 500;\r\n}";
232
- var styles = {"infoContainer":"NoMoreDataMessage-module_infoContainer__dk1r5","noMoreData":"NoMoreDataMessage-module_noMoreData__ATuIg"};
233
- styleInject(css_248z);
234
-
235
- const LoadingSpinner = () => {
236
- return (React.createElement("div", { className: styles.infoContainer },
237
- React.createElement("div", { className: styles$1.spinner }),
238
- React.createElement("span", null, "Loading more items...")));
239
- };
240
-
241
- const NoMoreDataMessage = () => {
242
- return (React.createElement("div", { className: `${styles.infoContainer} ${styles.noMoreData}` },
243
- React.createElement("p", null, "You've reached the end!")));
244
- };
245
-
246
- class InfiniteTable extends React.Component {
247
- constructor(props) {
248
- super(props);
249
- this.tableContainerRef = React.createRef();
250
- this.headerRef = React.createRef();
251
- this.handleResize = () => {
252
- this.setState({
253
- isMobile: window.innerWidth <= (this.props.mobileBreakpoint || 600),
254
- });
410
+ // Type-safe sort comparer helpers
411
+ const createSortComparers = () => ({
412
+ numeric: (key) => (a, b, direction) => {
413
+ const numA = parseFloat(String(a[key]));
414
+ const numB = parseFloat(String(b[key]));
415
+ const aIsNaN = isNaN(numA);
416
+ const bIsNaN = isNaN(numB);
417
+ if (aIsNaN && bIsNaN)
418
+ return 0;
419
+ if (aIsNaN)
420
+ return 1; // Put non-numbers at the end
421
+ if (bIsNaN)
422
+ return -1;
423
+ return direction === 'asc' ? numA - numB : numB - numA;
424
+ },
425
+ caseInsensitiveString: (key) => (a, b, direction) => {
426
+ var _a, _b;
427
+ const valA = String((_a = a[key]) !== null && _a !== void 0 ? _a : '').toLowerCase();
428
+ const valB = String((_b = b[key]) !== null && _b !== void 0 ? _b : '').toLowerCase();
429
+ if (valA < valB)
430
+ return direction === 'asc' ? -1 : 1;
431
+ if (valA > valB)
432
+ return direction === 'asc' ? 1 : -1;
433
+ return 0;
434
+ },
435
+ date: (key) => (a, b, direction) => {
436
+ const dateA = new Date(String(a[key])).getTime();
437
+ const dateB = new Date(String(b[key])).getTime();
438
+ const aIsNaN = isNaN(dateA);
439
+ const bIsNaN = isNaN(dateB);
440
+ if (aIsNaN && bIsNaN)
441
+ return 0;
442
+ if (aIsNaN)
443
+ return 1; // Put invalid dates at the end
444
+ if (bIsNaN)
445
+ return -1;
446
+ return direction === 'asc' ? dateA - dateB : dateB - dateA;
447
+ },
448
+ });
449
+ class SortPlugin {
450
+ constructor(options) {
451
+ var _a, _b;
452
+ this.id = 'sort';
453
+ this.comparers = createSortComparers();
454
+ this.onPluginInit = (api) => {
455
+ this.api = api;
255
456
  };
256
- this.loadMoreData = () => {
257
- const { infiniteScrollProps } = this.props;
258
- if (!infiniteScrollProps)
259
- return;
260
- this.setState({ isLoadingMore: true }, () => __awaiter(this, void 0, void 0, function* () {
261
- var _a, _b;
262
- try {
263
- const newItems = yield ((_a = infiniteScrollProps === null || infiniteScrollProps === void 0 ? void 0 : infiniteScrollProps.onLoadMore) === null || _a === void 0 ? void 0 : _a.call(infiniteScrollProps, this.state.internalData));
264
- if (((_b = this.props.infiniteScrollProps) === null || _b === void 0 ? void 0 : _b.hasMore) === undefined) {
265
- if (!newItems || newItems.length === 0) {
266
- this.setState({ internalHasMore: false });
267
- }
268
- }
269
- if (newItems && newItems.length > 0) {
270
- const newInternalData = [...this.state.internalData, ...newItems];
271
- this.setState({ internalData: newInternalData }, () => {
272
- this.processData(); // Re-process data after new items are added
273
- });
457
+ this.processData = (data) => {
458
+ if (!this.sortColumn || !this.sortDirection) {
459
+ return data;
460
+ }
461
+ const columnDef = this.api.columnDefinitions.find((col) => (typeof col === 'object' && col.columnId === this.sortColumn));
462
+ if (!columnDef) {
463
+ return data;
464
+ }
465
+ const sortedData = [...data].sort((a, b) => {
466
+ if ('sortComparer' in columnDef && columnDef.sortComparer) {
467
+ if (columnDef.sortComparer.length < 3) {
468
+ console.warn(`The custom sortComparer for column '${this.sortColumn}' should accept all three parameters (a, b, direction) to ensure correct sorting behavior. You provided a function with ${columnDef.sortComparer.length} parameters.`);
274
469
  }
470
+ return columnDef.sortComparer(a, b, this.sortDirection);
275
471
  }
276
- catch (error) {
277
- console.error("Failed to load more items for infinite scroll:", error);
278
- // Optionally, you could add a state to show an error message to the user
279
- }
280
- finally {
281
- this.setState({ isLoadingMore: false });
472
+ if ('getSortableValue' in columnDef && columnDef.getSortableValue) {
473
+ const aValue = columnDef.getSortableValue(a);
474
+ const bValue = columnDef.getSortableValue(b);
475
+ if (aValue < bValue)
476
+ return this.sortDirection === 'asc' ? -1 : 1;
477
+ if (aValue > bValue)
478
+ return this.sortDirection === 'asc' ? 1 : -1;
479
+ return 0;
282
480
  }
283
- }));
284
- };
285
- this.processData = () => {
286
- let processed = [...this.state.internalData];
287
- this.state.activePlugins.forEach((plugin) => {
288
- if (plugin.processData) {
289
- processed = plugin.processData(processed);
481
+ // Fallback to dataKey if it exists and no other sorter is provided
482
+ if ('dataKey' in columnDef && columnDef.dataKey) {
483
+ const key = columnDef.dataKey;
484
+ const aValue = a[key];
485
+ const bValue = b[key];
486
+ if (aValue < bValue)
487
+ return this.sortDirection === 'asc' ? -1 : 1;
488
+ if (aValue > bValue)
489
+ return this.sortDirection === 'asc' ? 1 : -1;
490
+ return 0;
290
491
  }
492
+ return 0;
291
493
  });
292
- this.setState({ processedData: processed });
293
- };
294
- this.getColumnDefinition = (colDef, rowIndex) => {
295
- if (typeof colDef === 'function') {
296
- return colDef(this.data[rowIndex], rowIndex);
297
- }
298
- return colDef;
494
+ return sortedData;
299
495
  };
300
- this.getRawColumnDefinition = (colDef) => {
301
- if (typeof colDef === 'function') {
302
- return colDef(this.data[0], 0);
496
+ this.getHeaderProps = (columnDef) => {
497
+ const { columnId } = columnDef;
498
+ const isSortable = ('sortComparer' in columnDef && !!columnDef.sortComparer) || ('getSortableValue' in columnDef && !!columnDef.getSortableValue);
499
+ // A column must have a columnId and a sort function to be sortable
500
+ if (!isSortable || !columnId) {
501
+ return {};
303
502
  }
304
- return colDef;
305
- };
306
- this.onHeaderClickCallback = (colDef) => {
307
- var _a;
308
- const raw = this.getRawColumnDefinition(colDef);
309
- return (_a = raw.interactivity) === null || _a === void 0 ? void 0 : _a.onHeaderClick;
310
- };
311
- this.getClickableHeaderClassName = (colDef) => {
312
- var _a;
313
- const raw = this.getRawColumnDefinition(colDef);
314
- return ((_a = raw.interactivity) === null || _a === void 0 ? void 0 : _a.onHeaderClick) ? raw.interactivity.className || styles$2.clickableHeader : '';
315
- };
316
- this.getHeaderProps = (colDef) => {
317
- const headerProps = {};
318
- this.state.activePlugins.forEach(plugin => {
319
- if (plugin.getHeaderProps) {
320
- Object.assign(headerProps, plugin.getHeaderProps(this.getRawColumnDefinition(colDef)));
503
+ const onHeaderClick = (e) => {
504
+ const target = e.target;
505
+ console.log('SortPlugin: Header clicked. Target:', target);
506
+ // If the click is on an interactive element, don't sort
507
+ if (target.closest('input, button, a, [onclick]')) {
508
+ console.log('SortPlugin: Interactive element clicked, ignoring sort.');
509
+ return;
321
510
  }
322
- });
323
- return headerProps;
324
- };
325
- this.state = {
326
- isMobile: false,
327
- internalData: props.data || [],
328
- processedData: props.data || [],
329
- isLoadingMore: false,
330
- internalHasMore: true,
331
- isHeaderSticky: false,
332
- activePlugins: [],
511
+ console.log('SortPlugin: Non-interactive element clicked, proceeding with sort.');
512
+ if (this.sortColumn === columnId) {
513
+ if (this.sortDirection === 'desc') {
514
+ this.sortColumn = null;
515
+ this.sortDirection = null;
516
+ }
517
+ else {
518
+ this.sortDirection = 'desc';
519
+ }
520
+ }
521
+ else {
522
+ this.sortColumn = columnId;
523
+ this.sortDirection = 'asc';
524
+ }
525
+ this.api.forceUpdate();
526
+ };
527
+ let sortClassName = 'sortable';
528
+ if (this.sortColumn === columnId) {
529
+ sortClassName = `sorted-${this.sortDirection}`;
530
+ }
531
+ return {
532
+ onClick: onHeaderClick,
533
+ className: sortClassName,
534
+ 'aria-sort': (this.sortColumn === columnId ? (this.sortDirection === 'asc' ? 'ascending' : 'descending') : 'none'),
535
+ };
333
536
  };
334
- this.debouncedResize = this.debounce(this.handleResize, 200);
335
- this.debouncedScrollHandler = this.debounce(this.handleScroll, 200);
537
+ this.sortColumn = (_a = options === null || options === void 0 ? void 0 : options.initialSortColumn) !== null && _a !== void 0 ? _a : null;
538
+ this.sortDirection = (_b = options === null || options === void 0 ? void 0 : options.initialSortDirection) !== null && _b !== void 0 ? _b : null;
336
539
  }
337
- componentDidUpdate(prevProps) {
338
- const propsHaveChanged = prevProps.plugins !== this.props.plugins ||
339
- prevProps.filterProps !== this.props.filterProps;
340
- if (prevProps.data !== this.props.data) {
341
- // If initial data prop changes, reset internal state and re-initialize plugins
342
- this.setState({ internalData: this.props.data }, () => this.initializePlugins());
343
- }
344
- else if (propsHaveChanged) {
345
- // If only plugins or filter props change, just re-initialize them
346
- this.initializePlugins();
540
+ }
541
+
542
+ const useTablePlugins = (props) => {
543
+ const { data, plugins, filterProps, selectionProps, sortProps, columnDefinitions, getScrollableElement, infiniteScrollProps, } = props;
544
+ const [processedData, setProcessedData] = React.useState(data);
545
+ const [activePlugins, setActivePlugins] = React.useState([]);
546
+ // Persist internal plugins using refs to prevent state loss
547
+ const filterPluginRef = React.useRef(null);
548
+ const selectionPluginRef = React.useRef(null);
549
+ const sortPluginRef = React.useRef(null);
550
+ const getRawColumnDefinition = React.useCallback((columnDefinition) => {
551
+ if (typeof columnDefinition === 'function') {
552
+ return columnDefinition(data[0] || {}, 0);
347
553
  }
348
- }
349
- componentDidMount() {
350
- this.handleResize();
351
- window.addEventListener('resize', this.debouncedResize);
352
- this.initializePlugins();
353
- if (this.props.data.length === 0) {
354
- this.loadMoreData();
554
+ return columnDefinition;
555
+ }, [data]);
556
+ const visibleColumns = React.useMemo(() => {
557
+ return columnDefinitions.filter(col => {
558
+ const raw = getRawColumnDefinition(col);
559
+ return raw.visible !== false;
560
+ });
561
+ }, [columnDefinitions, getRawColumnDefinition]);
562
+ const initializePlugins = React.useCallback(() => {
563
+ const newActivePlugins = [];
564
+ // 1. Add external plugins
565
+ if (plugins) {
566
+ newActivePlugins.push(...plugins);
355
567
  }
356
- }
357
- componentWillUnmount() {
358
- window.removeEventListener('resize', this.debouncedResize);
359
- }
360
- debounce(func, delay) {
361
- let timeout;
362
- return function (...args) {
363
- clearTimeout(timeout);
364
- timeout = setTimeout(() => {
365
- func.apply(this, args);
366
- }, delay);
367
- };
368
- }
369
- handleScroll(currentTarget) {
370
- var _a;
371
- if (!currentTarget)
372
- return;
373
- const { scrollHeight, scrollTop, clientHeight } = currentTarget;
374
- const { isLoadingMore } = this.state;
375
- const hasMore = ((_a = this.props.infiniteScrollProps) === null || _a === void 0 ? void 0 : _a.hasMore) !== undefined
376
- ? this.props.infiniteScrollProps.hasMore
377
- : this.state.internalHasMore;
378
- // When maxHeight is set, we use CSS position:sticky and don't need JS-based detection.
379
- // The isHeaderSticky state is only for page-level stickiness.
380
- if (this.props.enablePageLevelStickyHeader !== false && !this.props.maxHeight && this.headerRef.current) {
381
- const { top } = this.headerRef.current.getBoundingClientRect();
382
- const isSticky = top <= 0;
383
- if (isSticky !== this.state.isHeaderSticky) {
384
- this.setState({ isHeaderSticky: isSticky });
568
+ // 2. Manage internal FilterPlugin
569
+ if (filterProps === null || filterProps === void 0 ? void 0 : filterProps.showFilter) {
570
+ if (!filterPluginRef.current) {
571
+ filterPluginRef.current = new FilterPlugin();
572
+ }
573
+ if (!newActivePlugins.some(p => p.id === 'filter')) {
574
+ newActivePlugins.push(filterPluginRef.current);
385
575
  }
386
576
  }
387
- if (hasMore && !isLoadingMore && scrollHeight - scrollTop - clientHeight < 100) {
388
- this.loadMoreData();
577
+ else {
578
+ filterPluginRef.current = null;
389
579
  }
390
- }
391
- initializePlugins() {
392
- var _a;
393
- const plugins = [];
394
- if (this.props.plugins)
395
- plugins.push(...this.props.plugins);
396
- if (((_a = this.props.filterProps) === null || _a === void 0 ? void 0 : _a.showFilter) && !plugins.some(p => p.id === 'filter')) {
397
- plugins.push(new FilterPlugin());
580
+ // 3. Manage internal SelectionPlugin
581
+ if (selectionProps === null || selectionProps === void 0 ? void 0 : selectionProps.onSelectionChange) {
582
+ if (!selectionPluginRef.current) {
583
+ selectionPluginRef.current = new SelectionPlugin();
584
+ }
585
+ if (!newActivePlugins.some(p => p.id === 'selection')) {
586
+ newActivePlugins.push(selectionPluginRef.current);
587
+ }
398
588
  }
399
- this.setState({ activePlugins: plugins }, () => {
400
- plugins.forEach(plugin => {
401
- var _a;
402
- (_a = plugin.onPluginInit) === null || _a === void 0 ? void 0 : _a.call(plugin, Object.assign({ getData: () => this.state.internalData, forceUpdate: () => this.processData(), getScrollableElement: () => this.tableContainerRef.current }, this.props));
403
- });
404
- this.processData();
405
- });
406
- }
407
- get data() {
408
- return this.state.processedData || [];
409
- }
410
- get hasData() {
411
- return this.data.length > 0;
412
- }
413
- get noDataComponent() {
414
- return this.props.noDataComponent || React.createElement("div", { className: styles$2.noData }, "No data");
415
- }
416
- get defaultLoadingComponent() {
417
- return React.createElement(LoadingSpinner, null);
418
- }
419
- get defaultNoMoreDataComponent() {
420
- return React.createElement(NoMoreDataMessage, null);
421
- }
422
- get rowClickFunction() {
423
- return this.props.onRowClick || (() => { });
424
- }
425
- get rowClickStyle() {
426
- return this.props.onRowClick ? { cursor: 'pointer' } : {};
427
- }
428
- get mobileView() {
429
- var _a;
430
- const { infiniteScrollProps } = this.props;
431
- const { isLoadingMore } = this.state;
432
- const hasMore = ((_a = this.props.infiniteScrollProps) === null || _a === void 0 ? void 0 : _a.hasMore) !== undefined ? this.props.infiniteScrollProps.hasMore : this.state.internalHasMore;
433
- return (React.createElement("div", null,
434
- this.data.map((row, rowIndex) => {
435
- var _a;
436
- return (React.createElement("div", { key: rowIndex, className: `${styles$2['card']} ${((_a = this.props.animationProps) === null || _a === void 0 ? void 0 : _a.animateOnLoad) ? styles$2.animatedRow : ''}`, style: { animationDelay: `${rowIndex * 0.05}s` }, onClick: () => this.rowClickFunction(row) },
437
- React.createElement("div", { className: styles$2['card-body'] }, this.props.columnDefinitions.map((colDef, colIndex) => {
438
- const column = this.getColumnDefinition(colDef, rowIndex);
439
- return (React.createElement("div", { key: colIndex, className: styles$2['card-row'] },
440
- React.createElement("p", null,
441
- React.createElement("span", { className: styles$2['card-label'] }, column.displayLabel),
442
- React.createElement("span", { className: styles$2['card-value'] }, column.cellRenderer(row)))));
443
- }))));
444
- }),
445
- isLoadingMore && ((infiniteScrollProps === null || infiniteScrollProps === void 0 ? void 0 : infiniteScrollProps.loadingMoreComponent) || this.defaultLoadingComponent),
446
- !isLoadingMore && !hasMore && ((infiniteScrollProps === null || infiniteScrollProps === void 0 ? void 0 : infiniteScrollProps.noMoreDataComponent) || this.defaultNoMoreDataComponent)));
447
- }
448
- get largeScreenView() {
449
- var _a;
450
- const { infiniteScrollProps } = this.props;
451
- const { isLoadingMore } = this.state;
452
- const hasMore = ((_a = this.props.infiniteScrollProps) === null || _a === void 0 ? void 0 : _a.hasMore) !== undefined ? this.props.infiniteScrollProps.hasMore : this.state.internalHasMore;
453
- const headerClassName = this.props.maxHeight
454
- ? styles$2.internalStickyHeader
455
- : this.state.isHeaderSticky
456
- ? styles$2.stickyHeader
457
- : '';
458
- return (React.createElement("div", { ref: this.tableContainerRef, onScroll: (e) => this.debouncedScrollHandler(e.currentTarget), style: { maxHeight: this.props.maxHeight, overflowY: 'auto' } },
459
- React.createElement("table", { className: styles$2['responsiveTable'] },
460
- React.createElement("thead", { ref: this.headerRef, className: headerClassName },
461
- React.createElement("tr", null, this.props.columnDefinitions.map((colDef, colIndex) => {
462
- const rawColDef = this.getRawColumnDefinition(colDef);
463
- const headerProps = this.getHeaderProps(rawColDef);
464
- const onHeaderClickCallback = this.onHeaderClickCallback(rawColDef);
465
- const combinedClassName = `${this.getClickableHeaderClassName(rawColDef)} ${headerProps.className ? styles$2[headerProps.className] : ''}`.trim();
466
- // eslint-disable-next-line @typescript-eslint/no-unused-vars
467
- const { className } = headerProps, restHeaderProps = __rest(headerProps, ["className"]);
468
- return (React.createElement("th", Object.assign({ key: colIndex, className: combinedClassName }, restHeaderProps, { onClick: onHeaderClickCallback ? () => onHeaderClickCallback(rawColDef.interactivity.id) : undefined }),
469
- React.createElement("div", { className: styles$2.headerInnerWrapper },
470
- React.createElement("div", { className: styles$2.headerContent }, rawColDef.displayLabel),
471
- React.createElement("span", { className: styles$2.sortIcon }))));
472
- }))),
473
- React.createElement("tbody", null, this.data.map((row, rowIndex) => {
474
- var _a;
475
- return (React.createElement("tr", { key: rowIndex, className: ((_a = this.props.animationProps) === null || _a === void 0 ? void 0 : _a.animateOnLoad) ? styles$2.animatedRow : '', style: { animationDelay: `${rowIndex * 0.05}s` } }, this.props.columnDefinitions.map((colDef, colIndex) => (React.createElement("td", { key: colIndex, onClick: () => this.rowClickFunction(row), style: this.rowClickStyle }, this.getColumnDefinition(colDef, rowIndex).cellRenderer(row))))));
476
- }))),
477
- isLoadingMore && ((infiniteScrollProps === null || infiniteScrollProps === void 0 ? void 0 : infiniteScrollProps.loadingMoreComponent) || this.defaultLoadingComponent),
478
- !isLoadingMore && !hasMore && ((infiniteScrollProps === null || infiniteScrollProps === void 0 ? void 0 : infiniteScrollProps.noMoreDataComponent) || this.defaultNoMoreDataComponent)));
479
- }
480
- render() {
481
- var _a;
482
- if (((_a = this.props.animationProps) === null || _a === void 0 ? void 0 : _a.isLoading) && !this.hasData) {
483
- return React.createElement("div", null, "Skeleton View Placeholder");
589
+ else {
590
+ selectionPluginRef.current = null;
484
591
  }
485
- return (React.createElement("div", null,
486
- !this.hasData && this.noDataComponent,
487
- this.hasData && (this.state.isMobile ? this.mobileView : this.largeScreenView)));
488
- }
489
- }
490
-
491
- // Class component
492
- class ResponsiveTable extends React.Component {
493
- constructor(props) {
494
- var _a;
495
- super(props);
496
- this.tableContainerRef = React.createRef();
497
- this.headerRef = React.createRef();
498
- this.filterPlugin = null;
499
- this.handleScroll = () => {
500
- if (this.headerRef.current && !this.props.maxHeight) {
501
- const { top } = this.headerRef.current.getBoundingClientRect();
502
- const isSticky = top <= 0;
503
- if (isSticky !== this.state.isHeaderSticky) {
504
- this.setState({ isHeaderSticky: isSticky });
505
- }
592
+ // 4. Manage internal SortPlugin
593
+ const isAnyColumnSortable = columnDefinitions.some(col => {
594
+ const rawCol = getRawColumnDefinition(col);
595
+ return rawCol.sortComparer || rawCol.getSortableValue;
596
+ });
597
+ if (isAnyColumnSortable) {
598
+ if (!sortPluginRef.current) {
599
+ sortPluginRef.current = new SortPlugin(sortProps);
600
+ }
601
+ if (!newActivePlugins.some(p => p.id === 'sort')) {
602
+ newActivePlugins.push(sortPluginRef.current);
506
603
  }
507
- };
508
- this.handleResize = () => {
509
- this.setState({
510
- isMobile: window.innerWidth <= this.mobileBreakpoint,
511
- });
512
- };
513
- if ((_a = props.filterProps) === null || _a === void 0 ? void 0 : _a.showFilter) {
514
- this.filterPlugin = new FilterPlugin();
515
- }
516
- this.state = {
517
- isMobile: false,
518
- processedData: props.data,
519
- isLoadingMore: false,
520
- isHeaderSticky: false,
521
- activePlugins: [],
522
- };
523
- this.debouncedResize = this.debounce(this.handleResize, 200);
524
- }
525
- get mobileBreakpoint() {
526
- return this.props.mobileBreakpoint || 600;
527
- }
528
- debounce(func, delay) {
529
- let timeout;
530
- return () => {
531
- clearTimeout(timeout);
532
- timeout = setTimeout(() => func(), delay);
533
- };
534
- }
535
- get data() {
536
- if (Array.isArray(this.state.processedData) && this.state.processedData.length > 0) {
537
- return this.state.processedData;
538
604
  }
539
605
  else {
540
- return [];
606
+ sortPluginRef.current = null;
541
607
  }
542
- }
543
- get noDataSvg() {
544
- return (React.createElement("svg", { xmlns: "http://www.w3.org/2000/svg", fill: "#ccc", height: "40", width: "40", viewBox: "0 0 24 24" },
545
- 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" })));
546
- }
547
- get hasData() {
548
- return this.data.length > 0;
549
- }
550
- get noDataComponent() {
551
- return (this.props.noDataComponent || (React.createElement("div", { className: styles$2.noDataWrapper },
552
- this.noDataSvg,
553
- React.createElement("div", { className: styles$2.noData }, "No data"))));
554
- }
555
- componentDidMount() {
556
- this.handleResize(); // Initial check
557
- window.addEventListener('resize', this.debouncedResize);
558
- if (this.props.enablePageLevelStickyHeader !== false) {
559
- window.addEventListener('scroll', this.handleScroll);
608
+ setActivePlugins(newActivePlugins);
609
+ const api = {
610
+ getData: () => data,
611
+ forceUpdate: forceUpdatePlugins,
612
+ getScrollableElement: getScrollableElement,
613
+ infiniteScrollProps: infiniteScrollProps,
614
+ filterProps: filterProps,
615
+ selectionProps: selectionProps,
616
+ columnDefinitions: columnDefinitions,
617
+ };
618
+ // Initialize/Refresh all active plugins with the current API
619
+ newActivePlugins.forEach((plugin) => {
620
+ if (plugin.onPluginInit) {
621
+ plugin.onPluginInit(api);
622
+ }
623
+ });
624
+ // Run the data processing pipeline
625
+ let currentProcessedData = [...data];
626
+ newActivePlugins.forEach((plugin) => {
627
+ if (plugin.processData) {
628
+ currentProcessedData = plugin.processData(currentProcessedData);
629
+ }
630
+ });
631
+ return currentProcessedData;
632
+ }, [
633
+ data,
634
+ plugins,
635
+ filterProps,
636
+ selectionProps,
637
+ sortProps,
638
+ columnDefinitions,
639
+ getScrollableElement,
640
+ infiniteScrollProps,
641
+ getRawColumnDefinition,
642
+ ]);
643
+ const forceUpdatePlugins = React.useCallback(() => {
644
+ setProcessedData(initializePlugins());
645
+ }, [initializePlugins]);
646
+ // Handle re-initialization when props change
647
+ React.useEffect(() => {
648
+ setProcessedData(initializePlugins());
649
+ }, [initializePlugins]);
650
+ return { processedData, activePlugins, visibleColumns, forceUpdatePlugins };
651
+ };
652
+
653
+ function InfiniteTable(props) {
654
+ const { columnDefinitions, data, noDataComponent, maxHeight, onRowClick, footerRows, mobileBreakpoint, plugins, enablePageLevelStickyHeader, infiniteScrollProps, filterProps, selectionProps, animationProps, sortProps, } = props;
655
+ const tableContainerRef = React.useRef(null);
656
+ const headerRef = React.useRef(null);
657
+ const { isMobile, isHeaderSticky, debouncedScrollHandler } = useResponsiveTable({
658
+ mobileBreakpoint,
659
+ enablePageLevelStickyHeader,
660
+ maxHeight,
661
+ headerRef,
662
+ scrollableRef: tableContainerRef,
663
+ });
664
+ const [internalData, setInternalData] = React.useState(data || []);
665
+ const [isLoadingMore, setIsLoadingMore] = React.useState(false);
666
+ const [internalHasMore, setInternalHasMore] = React.useState(true);
667
+ const getScrollableElement = React.useCallback(() => tableContainerRef.current, []);
668
+ const { processedData, activePlugins, visibleColumns } = useTablePlugins({
669
+ data: internalData,
670
+ plugins,
671
+ filterProps,
672
+ selectionProps,
673
+ sortProps,
674
+ columnDefinitions,
675
+ getScrollableElement,
676
+ infiniteScrollProps,
677
+ });
678
+ const currentHasMore = (infiniteScrollProps === null || infiniteScrollProps === void 0 ? void 0 : infiniteScrollProps.hasMore) !== undefined
679
+ ? infiniteScrollProps.hasMore
680
+ : internalHasMore;
681
+ const currentData = React.useMemo(() => {
682
+ if (Array.isArray(processedData) && processedData.length > 0) {
683
+ return processedData;
560
684
  }
561
- const { processedData, activePlugins } = this.initializePlugins();
562
- this.setState({ processedData, activePlugins });
563
- }
564
- componentWillUnmount() {
565
- window.removeEventListener('resize', this.debouncedResize);
566
- if (this.props.enablePageLevelStickyHeader !== false) {
567
- window.removeEventListener('scroll', this.handleScroll);
685
+ else {
686
+ return [];
568
687
  }
569
- }
570
- componentDidUpdate(prevProps) {
571
- var _a, _b, _c;
572
- if (((_a = prevProps.filterProps) === null || _a === void 0 ? void 0 : _a.showFilter) !== ((_b = this.props.filterProps) === null || _b === void 0 ? void 0 : _b.showFilter)) {
573
- if ((_c = this.props.filterProps) === null || _c === void 0 ? void 0 : _c.showFilter) {
574
- this.filterPlugin = new FilterPlugin();
688
+ }, [processedData]);
689
+ const hasData = React.useMemo(() => currentData.length > 0, [currentData]);
690
+ const noDataComponentNode = noDataComponent || React.createElement("div", { className: styles$2.noData }, "No data");
691
+ const defaultLoadingComponent = React.createElement(LoadingSpinner, null);
692
+ const defaultNoMoreDataComponent = React.createElement(NoMoreDataMessage, null);
693
+ const getRawColumnDefinition = (columnDefinition) => {
694
+ if (typeof columnDefinition === 'function') {
695
+ if (currentData.length === 0) {
696
+ return { displayLabel: '', cellRenderer: () => '' };
575
697
  }
576
- else {
577
- this.filterPlugin = null;
698
+ return columnDefinition(currentData[0], 0);
699
+ }
700
+ return columnDefinition;
701
+ };
702
+ const getColumnDefinition = (columnDefinition, rowIndex) => {
703
+ if (!hasData) {
704
+ return { displayLabel: '', cellRenderer: () => '' };
705
+ }
706
+ return columnDefinition instanceof Function ? columnDefinition(currentData[rowIndex], rowIndex) : columnDefinition;
707
+ };
708
+ const loadMoreData = React.useCallback(() => __awaiter(this, void 0, void 0, function* () {
709
+ var _a;
710
+ if (!infiniteScrollProps || isLoadingMore)
711
+ return;
712
+ setIsLoadingMore(true);
713
+ try {
714
+ const newItems = yield ((_a = infiniteScrollProps.onLoadMore) === null || _a === void 0 ? void 0 : _a.call(infiniteScrollProps, internalData));
715
+ if (infiniteScrollProps.hasMore === undefined) {
716
+ if (!newItems || newItems.length === 0) {
717
+ setInternalHasMore(false);
718
+ }
719
+ }
720
+ if (newItems && newItems.length > 0) {
721
+ setInternalData(prevData => [...prevData, ...newItems]);
578
722
  }
579
723
  }
580
- // Re-initialize if data or plugin configuration changes.
581
- if (prevProps.data !== this.props.data ||
582
- prevProps.plugins !== this.props.plugins ||
583
- prevProps.filterProps !== this.props.filterProps ||
584
- prevProps.selectionProps !== this.props.selectionProps) {
585
- const { processedData, activePlugins } = this.initializePlugins();
586
- this.setState({ processedData, activePlugins });
724
+ catch (error) {
725
+ console.error("Failed to load more items for infinite scroll:", error);
587
726
  }
588
- }
589
- initializePlugins() {
590
- var _a, _b;
591
- const activePlugins = [];
592
- // Add explicitly provided plugins first
593
- if (this.props.plugins) {
594
- activePlugins.push(...this.props.plugins);
727
+ finally {
728
+ setIsLoadingMore(false);
595
729
  }
596
- // Automatically add FilterPlugin if filterProps are provided and not already present
597
- if (((_a = this.props.filterProps) === null || _a === void 0 ? void 0 : _a.showFilter) && this.filterPlugin && !activePlugins.some(p => p.id === 'filter')) {
598
- activePlugins.push(this.filterPlugin);
730
+ }), [infiniteScrollProps, isLoadingMore, internalData]);
731
+ React.useEffect(() => {
732
+ setInternalData(data || []);
733
+ }, [data]);
734
+ React.useEffect(() => {
735
+ if (data.length === 0) {
736
+ loadMoreData();
599
737
  }
600
- // Automatically add SelectionPlugin if selectionProps are provided and not already present
601
- if (((_b = this.props.selectionProps) === null || _b === void 0 ? void 0 : _b.onSelectionChange) && !activePlugins.some(p => p.id === 'selection')) {
602
- activePlugins.push(new SelectionPlugin());
738
+ }, [data.length, loadMoreData]);
739
+ const handleScrollForInfinite = React.useCallback((currentTarget) => {
740
+ if (!currentTarget)
741
+ return;
742
+ const { scrollHeight, scrollTop, clientHeight } = currentTarget;
743
+ if (currentHasMore && !isLoadingMore && scrollHeight - scrollTop - clientHeight < 100) {
744
+ loadMoreData();
603
745
  }
746
+ }, [currentHasMore, isLoadingMore, loadMoreData]);
747
+ const onHeaderClickCallback = (colDef) => {
748
+ var _a;
749
+ const rawColumnDefinition = getRawColumnDefinition(colDef);
750
+ return (_a = rawColumnDefinition.interactivity) === null || _a === void 0 ? void 0 : _a.onHeaderClick;
751
+ };
752
+ const getClickableHeaderClassName = (onHeaderClickCallback, colDef) => {
753
+ var _a;
754
+ const rawColumnDefinition = getRawColumnDefinition(colDef);
755
+ return onHeaderClickCallback
756
+ ? ((_a = rawColumnDefinition.interactivity) === null || _a === void 0 ? void 0 : _a.className) || styles$2.clickableHeader
757
+ : '';
758
+ };
759
+ const getHeaderProps = (colDef) => {
760
+ const headerProps = {};
604
761
  activePlugins.forEach((plugin) => {
605
- if (plugin.onPluginInit) {
606
- plugin.onPluginInit({
607
- getData: () => this.props.data,
608
- forceUpdate: () => {
609
- const { processedData, activePlugins } = this.initializePlugins();
610
- this.setState({ processedData, activePlugins });
611
- },
612
- getScrollableElement: () => this.tableContainerRef.current,
613
- infiniteScrollProps: this.props.infiniteScrollProps,
614
- filterProps: this.props.filterProps,
615
- selectionProps: this.props.selectionProps,
616
- columnDefinitions: this.props.columnDefinitions,
617
- });
762
+ if (plugin.getHeaderProps) {
763
+ Object.assign(headerProps, plugin.getHeaderProps(getRawColumnDefinition(colDef)));
618
764
  }
619
765
  });
620
- // Process data with all active plugins
621
- let processedData = [...this.props.data];
766
+ return headerProps;
767
+ };
768
+ const getRowId = (row, index) => {
769
+ if (selectionProps && selectionProps.rowIdKey) {
770
+ return row[selectionProps.rowIdKey];
771
+ }
772
+ return index;
773
+ };
774
+ const getRowProps = (row) => {
775
+ const rowProps = {};
776
+ const clickHandlers = [];
622
777
  activePlugins.forEach((plugin) => {
623
- if (plugin.processData) {
624
- processedData = plugin.processData(processedData);
778
+ if (plugin.getRowProps) {
779
+ const props = plugin.getRowProps(row);
780
+ if (props.className) {
781
+ rowProps.className = `${rowProps.className || ''} ${props.className}`.trim();
782
+ }
783
+ if (props.onClick) {
784
+ clickHandlers.push(props.onClick);
785
+ }
786
+ const rest = __rest(props, []);
787
+ Object.assign(rowProps, rest);
625
788
  }
626
789
  });
627
- return { processedData, activePlugins };
628
- }
629
- getColumnDefinition(columnDefinition, rowIndex) {
630
- if (!this.hasData) {
631
- return { displayLabel: '', cellRenderer: () => '' };
790
+ if (clickHandlers.length > 0) {
791
+ rowProps.onClick = (e) => {
792
+ clickHandlers.forEach(handler => handler(e));
793
+ };
794
+ }
795
+ return rowProps;
796
+ };
797
+ const renderCell = (content, row, colDef) => {
798
+ let processedContent = content;
799
+ activePlugins.forEach((plugin) => {
800
+ if (plugin.renderCell) {
801
+ processedContent = plugin.renderCell(processedContent, row, colDef);
802
+ }
803
+ });
804
+ return processedContent;
805
+ };
806
+ const rowClickFunction = onRowClick || (() => { });
807
+ const mobileFooter = React.useMemo(() => {
808
+ if (!footerRows || footerRows.length === 0) {
809
+ return null;
632
810
  }
633
- return columnDefinition instanceof Function ? columnDefinition(this.data[0], rowIndex) : columnDefinition;
811
+ return (React.createElement("div", { className: styles$2.footerCard },
812
+ React.createElement("div", { className: styles$2['footer-card-body'] }, footerRows.map((row, rowIndex) => {
813
+ let currentColumnIndex = 0;
814
+ return (React.createElement("div", { key: rowIndex }, row.columns.map((col, colIndex) => {
815
+ let label = col.displayLabel;
816
+ if (!label && col.colSpan === 1) {
817
+ const header = columnDefinitions[currentColumnIndex];
818
+ if (header) {
819
+ label = getRawColumnDefinition(header).displayLabel;
820
+ }
821
+ }
822
+ currentColumnIndex += col.colSpan;
823
+ return (React.createElement("p", { key: colIndex, className: `${styles$2['footer-card-row']} ${col.className || ''} ${col.onCellClick ? styles$2.clickableFooterCell : ''}`, onClick: col.onCellClick },
824
+ label && React.createElement("span", { className: styles$2['card-label'] }, label),
825
+ React.createElement("span", { className: styles$2['card-value'] }, col.cellRenderer())));
826
+ })));
827
+ }))));
828
+ }, [footerRows, columnDefinitions]);
829
+ const renderPluginHeaders = React.useCallback(() => {
830
+ if (!activePlugins) {
831
+ return null;
832
+ }
833
+ return activePlugins.map((plugin) => {
834
+ if (plugin.renderHeader) {
835
+ if (plugin.id === 'sort' && !isMobile) {
836
+ return null;
837
+ }
838
+ return React.createElement("div", { key: plugin.id }, plugin.renderHeader());
839
+ }
840
+ return null;
841
+ });
842
+ }, [activePlugins, isMobile]);
843
+ const renderPluginFooters = React.useCallback(() => {
844
+ if (!plugins) {
845
+ return null;
846
+ }
847
+ return plugins.map((plugin) => {
848
+ if (plugin.renderFooter) {
849
+ return React.createElement("div", { key: plugin.id + '-footer' }, plugin.renderFooter());
850
+ }
851
+ return null;
852
+ });
853
+ }, [plugins]);
854
+ const infiniteStatusUI = (React.createElement(React.Fragment, null,
855
+ isLoadingMore && ((infiniteScrollProps === null || infiniteScrollProps === void 0 ? void 0 : infiniteScrollProps.loadingMoreComponent) || defaultLoadingComponent),
856
+ !isLoadingMore && !currentHasMore && ((infiniteScrollProps === null || infiniteScrollProps === void 0 ? void 0 : infiniteScrollProps.noMoreDataComponent) || defaultNoMoreDataComponent)));
857
+ const desktopView = (React.createElement(DesktopView, { columnDefinitions: visibleColumns, originalColumnDefinitions: columnDefinitions, currentData: currentData, maxHeight: maxHeight, isHeaderSticky: isHeaderSticky, tableContainerRef: tableContainerRef, headerRef: headerRef, getRowProps: getRowProps, getHeaderProps: getHeaderProps, onHeaderClickCallback: onHeaderClickCallback, getClickableHeaderClassName: getClickableHeaderClassName, getRawColumnDefinition: getRawColumnDefinition, getColumnDefinition: getColumnDefinition, renderCell: renderCell, rowClickFunction: rowClickFunction, footerRows: footerRows, renderPluginFooters: renderPluginFooters, animationProps: animationProps, onRowClick: onRowClick, selectionProps: selectionProps, onScroll: (e) => {
858
+ debouncedScrollHandler(e.currentTarget); // For sticky header
859
+ handleScrollForInfinite(e.currentTarget); // For infinite scroll
860
+ } }));
861
+ const mobileView = (React.createElement(MobileView, { currentData: currentData, columnDefinitions: visibleColumns, onRowClick: onRowClick, selectionProps: selectionProps, animationProps: animationProps, getRowProps: getRowProps, getRowId: getRowId, getColumnDefinition: getColumnDefinition, onHeaderClickCallback: onHeaderClickCallback, getClickableHeaderClassName: getClickableHeaderClassName, renderCell: renderCell, rowClickFunction: rowClickFunction, mobileFooter: mobileFooter }));
862
+ const skeletonView = (React.createElement(SkeletonView, { isMobile: isMobile, columnDefinitions: visibleColumns }));
863
+ if ((animationProps === null || animationProps === void 0 ? void 0 : animationProps.isLoading) && !hasData) {
864
+ return skeletonView;
634
865
  }
635
- getRawColumnDefinition(columnDefinition) {
866
+ return (React.createElement("div", null,
867
+ React.createElement("div", { style: { display: 'flex', justifyContent: 'flex-end' } }, renderPluginHeaders()),
868
+ !hasData && noDataComponentNode,
869
+ hasData && (isMobile ? mobileView : desktopView),
870
+ hasData && infiniteStatusUI));
871
+ }
872
+
873
+ function ResponsiveTable(props) {
874
+ const { columnDefinitions, data, noDataComponent, maxHeight, onRowClick, footerRows, mobileBreakpoint, plugins, enablePageLevelStickyHeader, infiniteScrollProps, filterProps, selectionProps, animationProps, sortProps, } = props;
875
+ const tableContainerRef = React.useRef(null);
876
+ const headerRef = React.useRef(null);
877
+ const { isMobile, isHeaderSticky } = useResponsiveTable({
878
+ mobileBreakpoint,
879
+ enablePageLevelStickyHeader,
880
+ maxHeight,
881
+ headerRef,
882
+ scrollableRef: tableContainerRef,
883
+ });
884
+ const getScrollableElement = React.useCallback(() => tableContainerRef.current, []);
885
+ const { processedData, activePlugins, visibleColumns } = useTablePlugins({
886
+ data,
887
+ plugins,
888
+ filterProps,
889
+ selectionProps,
890
+ sortProps,
891
+ columnDefinitions,
892
+ getScrollableElement,
893
+ infiniteScrollProps,
894
+ });
895
+ const currentData = React.useMemo(() => {
896
+ if (Array.isArray(processedData) && processedData.length > 0) {
897
+ return processedData;
898
+ }
899
+ else {
900
+ return [];
901
+ }
902
+ }, [processedData]);
903
+ const hasData = React.useMemo(() => currentData.length > 0, [currentData]);
904
+ const noDataSvg = (React.createElement("svg", { xmlns: "http://www.w3.org/2000/svg", fill: "#ccc", height: "40", width: "40", viewBox: "0 0 24 24" },
905
+ 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" })));
906
+ const noDataComponentNode = noDataComponent || (React.createElement("div", { className: styles$2.noDataWrapper },
907
+ noDataSvg,
908
+ React.createElement("div", { className: styles$2.noData }, "No data")));
909
+ const getRawColumnDefinition = (columnDefinition) => {
636
910
  if (typeof columnDefinition === 'function') {
637
- // If data is empty, we can't execute the function.
638
- // Return a placeholder, as the table body won't be rendered anyway.
639
- if (this.data.length === 0) {
911
+ if (currentData.length === 0) {
640
912
  return { displayLabel: '', cellRenderer: () => '' };
641
913
  }
642
- return columnDefinition(this.data[0], 0);
914
+ return columnDefinition(currentData[0], 0);
643
915
  }
644
916
  return columnDefinition;
645
- }
646
- onHeaderClickCallback(columnDefinition) {
647
- const rawColumnDefinition = this.getRawColumnDefinition(columnDefinition);
648
- if (rawColumnDefinition.interactivity && rawColumnDefinition.interactivity.onHeaderClick) {
649
- return rawColumnDefinition.interactivity.onHeaderClick;
650
- }
651
- else {
652
- return undefined;
917
+ };
918
+ const getColumnDefinition = (columnDefinition, rowIndex) => {
919
+ if (!hasData) {
920
+ return { displayLabel: '', cellRenderer: () => '' };
653
921
  }
654
- }
655
- getClickableHeaderClassName(onHeaderClickCallback, colDef) {
656
- const rawColumnDefinition = this.getRawColumnDefinition(colDef);
657
- const clickableHeaderClassName = onHeaderClickCallback
658
- ? rawColumnDefinition.interactivity.className || styles$2.clickableHeader
922
+ return columnDefinition instanceof Function ? columnDefinition(currentData[0], rowIndex) : columnDefinition;
923
+ };
924
+ const onHeaderClickCallback = (colDef) => {
925
+ var _a;
926
+ const rawColumnDefinition = getRawColumnDefinition(colDef);
927
+ return (_a = rawColumnDefinition.interactivity) === null || _a === void 0 ? void 0 : _a.onHeaderClick;
928
+ };
929
+ const getClickableHeaderClassName = (onHeaderClickCallback, colDef) => {
930
+ var _a;
931
+ const rawColumnDefinition = getRawColumnDefinition(colDef);
932
+ return onHeaderClickCallback
933
+ ? ((_a = rawColumnDefinition.interactivity) === null || _a === void 0 ? void 0 : _a.className) || styles$2.clickableHeader
659
934
  : '';
660
- return clickableHeaderClassName;
661
- }
662
- getHeaderProps(columnDefinition) {
935
+ };
936
+ const getHeaderProps = (colDef) => {
663
937
  const headerProps = {};
664
- if (this.state.activePlugins) {
665
- this.state.activePlugins.forEach((plugin) => {
666
- if (plugin.getHeaderProps) {
667
- Object.assign(headerProps, plugin.getHeaderProps(this.getRawColumnDefinition(columnDefinition)));
668
- }
669
- });
670
- }
938
+ activePlugins.forEach((plugin) => {
939
+ if (plugin.getHeaderProps) {
940
+ Object.assign(headerProps, plugin.getHeaderProps(getRawColumnDefinition(colDef)));
941
+ }
942
+ });
671
943
  return headerProps;
672
- }
673
- getRowId(row, index) {
674
- const { selectionProps } = this.props;
944
+ };
945
+ const getRowId = (row, index) => {
675
946
  if (selectionProps && selectionProps.rowIdKey) {
676
947
  return row[selectionProps.rowIdKey];
677
948
  }
678
949
  return index;
679
- }
680
- getRowProps(row) {
950
+ };
951
+ const getRowProps = (row) => {
681
952
  const rowProps = {};
682
953
  const clickHandlers = [];
683
- this.state.activePlugins.forEach(plugin => {
954
+ activePlugins.forEach((plugin) => {
684
955
  if (plugin.getRowProps) {
685
956
  const props = plugin.getRowProps(row);
686
- if (plugin.id === 'selection') ;
687
957
  if (props.className) {
688
958
  rowProps.className = `${rowProps.className || ''} ${props.className}`.trim();
689
959
  }
690
960
  if (props.onClick) {
691
961
  clickHandlers.push(props.onClick);
692
962
  }
693
- // Assign all other props except className and onClick
694
- const { className, onClick } = props, rest = __rest(props, ["className", "onClick"]);
963
+ const rest = __rest(props, []);
695
964
  Object.assign(rowProps, rest);
696
965
  }
697
966
  });
@@ -701,43 +970,30 @@ class ResponsiveTable extends React.Component {
701
970
  };
702
971
  }
703
972
  return rowProps;
704
- }
705
- renderCell(content, row, colDef) {
973
+ };
974
+ const renderCell = (content, row, colDef) => {
706
975
  let processedContent = content;
707
- this.state.activePlugins.forEach((plugin) => {
976
+ activePlugins.forEach((plugin) => {
708
977
  if (plugin.renderCell) {
709
978
  processedContent = plugin.renderCell(processedContent, row, colDef);
710
979
  }
711
980
  });
712
981
  return processedContent;
713
- }
714
- get rowClickFunction() {
715
- if (this.props.onRowClick) {
716
- return this.props.onRowClick;
717
- }
718
- else {
719
- return () => { };
720
- }
721
- }
722
- get tableFooter() {
723
- if (!this.props.footerRows || this.props.footerRows.length === 0) {
724
- return null;
725
- }
726
- 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$2.footerCell} ${col.className || ''} ${col.onCellClick ? styles$2.clickableFooterCell : ''}`, onClick: col.onCellClick }, col.cellRenderer()))))))));
727
- }
728
- get mobileFooter() {
729
- if (!this.props.footerRows || this.props.footerRows.length === 0) {
982
+ };
983
+ const rowClickFunction = onRowClick || (() => { });
984
+ const mobileFooter = React.useMemo(() => {
985
+ if (!footerRows || footerRows.length === 0) {
730
986
  return null;
731
987
  }
732
988
  return (React.createElement("div", { className: styles$2.footerCard },
733
- React.createElement("div", { className: styles$2['footer-card-body'] }, this.props.footerRows.map((row, rowIndex) => {
989
+ React.createElement("div", { className: styles$2['footer-card-body'] }, footerRows.map((row, rowIndex) => {
734
990
  let currentColumnIndex = 0;
735
991
  return (React.createElement("div", { key: rowIndex }, row.columns.map((col, colIndex) => {
736
992
  let label = col.displayLabel;
737
993
  if (!label && col.colSpan === 1) {
738
- const header = this.props.columnDefinitions[currentColumnIndex];
994
+ const header = columnDefinitions[currentColumnIndex];
739
995
  if (header) {
740
- label = this.getRawColumnDefinition(header).displayLabel;
996
+ label = getRawColumnDefinition(header).displayLabel;
741
997
  }
742
998
  }
743
999
  currentColumnIndex += col.colSpan;
@@ -746,134 +1002,46 @@ class ResponsiveTable extends React.Component {
746
1002
  React.createElement("span", { className: styles$2['card-value'] }, col.cellRenderer())));
747
1003
  })));
748
1004
  }))));
749
- }
750
- get skeletonView() {
751
- const skeletonRowCount = 5; // Or make this configurable
752
- const columnCount = this.props.columnDefinitions.length;
753
- if (this.state.isMobile) {
754
- return (React.createElement("div", null, [...Array(skeletonRowCount)].map((_, i) => (React.createElement("div", { key: i, className: styles$2.skeletonCard }, [...Array(columnCount)].map((_, j) => (React.createElement("div", { key: j, className: `${styles$2.skeleton} ${styles$2.skeletonText}`, style: { marginBottom: '0.5rem' } }))))))));
755
- }
756
- return (React.createElement("table", { className: styles$2.responsiveTable },
757
- React.createElement("thead", null,
758
- React.createElement("tr", null, [...Array(columnCount)].map((_, i) => (React.createElement("th", { key: i },
759
- React.createElement("div", { className: `${styles$2.skeleton} ${styles$2.skeletonText}` })))))),
760
- React.createElement("tbody", null, [...Array(skeletonRowCount)].map((_, i) => (React.createElement("tr", { key: i }, [...Array(columnCount)].map((_, j) => (React.createElement("td", { key: j },
761
- React.createElement("div", { className: `${styles$2.skeleton} ${styles$2.skeletonText}` }))))))))));
762
- }
763
- get mobileView() {
764
- const isClickable = this.props.onRowClick || this.props.selectionProps;
765
- return (React.createElement("div", null,
766
- this.data.map((row, rowIndex) => {
767
- var _a;
768
- const rowProps = this.getRowProps(row);
769
- const pluginOnClick = rowProps.onClick;
770
- return (React.createElement("div", { key: this.getRowId(row, rowIndex), className: `${styles$2.card} ${isClickable ? styles$2.clickableRow : ''} ${((_a = this.props.animationProps) === null || _a === void 0 ? void 0 : _a.animateOnLoad) ? styles$2.animatedRow : ''} ${rowProps.className || ''}`.trim(), style: { animationDelay: `${rowIndex * 0.05}s` }, "aria-selected": rowProps['aria-selected'], onClick: (e) => {
771
- if (pluginOnClick)
772
- pluginOnClick(e);
773
- this.rowClickFunction(row);
774
- } },
775
- React.createElement("div", { className: styles$2['card-header'] }, " "),
776
- React.createElement("div", { className: styles$2['card-body'] }, this.props.columnDefinitions.map((columnDefinition, colIndex) => {
777
- const colDef = this.getColumnDefinition(columnDefinition, rowIndex);
778
- const onHeaderClickCallback = this.onHeaderClickCallback(colDef);
779
- const clickableHeaderClassName = this.getClickableHeaderClassName(onHeaderClickCallback, colDef);
780
- return (React.createElement("div", { key: colIndex, className: styles$2['card-row'] },
781
- React.createElement("p", null,
782
- React.createElement("span", { className: `${styles$2['card-label']} ${clickableHeaderClassName}`, onClick: (e) => {
783
- if (onHeaderClickCallback) {
784
- e.stopPropagation();
785
- onHeaderClickCallback(colDef.interactivity.id);
786
- }
787
- } }, colDef.displayLabel),
788
- React.createElement("span", { className: styles$2['card-value'] }, this.renderCell(colDef.cellRenderer(row), row, colDef)))));
789
- }))));
790
- }),
791
- this.mobileFooter));
792
- }
793
- get largeScreenView() {
794
- const useFixedHeaders = this.props.maxHeight ? true : false;
795
- const isClickable = this.props.onRowClick || this.props.selectionProps;
796
- const fixedHeadersStyle = useFixedHeaders
797
- ? { maxHeight: this.props.maxHeight, overflowY: 'auto' }
798
- : {};
799
- const headerClassName = useFixedHeaders
800
- ? styles$2.internalStickyHeader
801
- : (this.state.isHeaderSticky ? styles$2.stickyHeader : '');
802
- return (React.createElement("div", { style: fixedHeadersStyle, ref: this.tableContainerRef },
803
- React.createElement("table", { className: styles$2['responsiveTable'] },
804
- React.createElement("thead", { ref: this.headerRef, className: headerClassName },
805
- React.createElement("tr", null, this.props.columnDefinitions.map((columnDefinition, colIndex) => {
806
- const onHeaderClickCallback = this.onHeaderClickCallback(columnDefinition);
807
- const clickableHeaderClassName = this.getClickableHeaderClassName(onHeaderClickCallback, columnDefinition);
808
- const headerProps = this.getHeaderProps(columnDefinition);
809
- // Combine class names: existing clickable, and plugin-provided (mapped to CSS Modules)
810
- const combinedClassName = `${clickableHeaderClassName} ${headerProps.className ? styles$2[headerProps.className] : ''}`.trim();
811
- // Remove className from headerProps to avoid duplication
812
- // eslint-disable-next-line @typescript-eslint/no-unused-vars
813
- const { className } = headerProps, restHeaderProps = __rest(headerProps, ["className"]);
814
- return (React.createElement("th", Object.assign({ key: colIndex, className: combinedClassName }, restHeaderProps),
815
- React.createElement("div", { className: styles$2.headerInnerWrapper },
816
- React.createElement("div", { className: styles$2.headerContent }, this.getColumnDefinition(columnDefinition, 0).displayLabel),
817
- React.createElement("span", { className: styles$2.sortIcon }))));
818
- }))),
819
- React.createElement("tbody", null, this.data.map((row, rowIndex) => {
820
- var _a;
821
- const rowProps = this.getRowProps(row);
822
- const pluginOnClick = rowProps.onClick;
823
- return (React.createElement("tr", { key: this.getRowId(row, rowIndex), className: `${isClickable ? styles$2.clickableRow : ''} ${((_a = this.props.animationProps) === null || _a === void 0 ? void 0 : _a.animateOnLoad) ? styles$2.animatedRow : ''} ${rowProps.className || ''}`.trim(), style: { animationDelay: `${rowIndex * 0.05}s` }, "aria-selected": rowProps['aria-selected'], onClick: (e) => {
824
- if (pluginOnClick) {
825
- pluginOnClick(e);
826
- }
827
- this.rowClickFunction(row);
828
- } }, this.props.columnDefinitions.map((columnDefinition, colIndex) => {
829
- const colDef = this.getColumnDefinition(columnDefinition, rowIndex);
830
- const cellContent = colDef.cellRenderer(row);
831
- return (React.createElement("td", { key: colIndex }, this.renderCell(cellContent, row, colDef)));
832
- })));
833
- })),
834
- this.tableFooter),
835
- this.renderPluginFooters()));
836
- }
837
- renderPluginHeaders() {
838
- if (!this.state.activePlugins) {
1005
+ }, [footerRows, columnDefinitions]);
1006
+ const skeletonView = (React.createElement(SkeletonView, { isMobile: isMobile, columnDefinitions: visibleColumns }));
1007
+ const renderPluginHeaders = React.useCallback(() => {
1008
+ if (!activePlugins) {
839
1009
  return null;
840
1010
  }
841
- return this.state.activePlugins.map((plugin) => {
1011
+ return activePlugins.map((plugin) => {
842
1012
  if (plugin.renderHeader) {
843
- // For sort plugin, only render header in mobile view
844
- if (plugin.id === 'sort' && !this.state.isMobile) {
1013
+ if (plugin.id === 'sort' && !isMobile) {
845
1014
  return null;
846
1015
  }
847
1016
  return React.createElement("div", { key: plugin.id }, plugin.renderHeader());
848
1017
  }
849
1018
  return null;
850
1019
  });
851
- }
852
- renderPluginFooters() {
853
- if (!this.props.plugins) {
1020
+ }, [activePlugins, isMobile]);
1021
+ const renderPluginFooters = React.useCallback(() => {
1022
+ if (!plugins) {
854
1023
  return null;
855
1024
  }
856
- return this.props.plugins.map((plugin) => {
1025
+ return plugins.map((plugin) => {
857
1026
  if (plugin.renderFooter) {
858
1027
  return React.createElement("div", { key: plugin.id + '-footer' }, plugin.renderFooter());
859
1028
  }
860
1029
  return null;
861
1030
  });
1031
+ }, [plugins]);
1032
+ const mobileView = (React.createElement(MobileView, { currentData: currentData, columnDefinitions: visibleColumns, onRowClick: onRowClick, selectionProps: selectionProps, animationProps: animationProps, getRowProps: getRowProps, getRowId: getRowId, getColumnDefinition: getColumnDefinition, onHeaderClickCallback: onHeaderClickCallback, getClickableHeaderClassName: getClickableHeaderClassName, renderCell: renderCell, rowClickFunction: rowClickFunction, mobileFooter: mobileFooter }));
1033
+ const largeScreenView = (React.createElement(DesktopView, { columnDefinitions: visibleColumns, originalColumnDefinitions: columnDefinitions, currentData: currentData, maxHeight: maxHeight, isHeaderSticky: isHeaderSticky, tableContainerRef: tableContainerRef, headerRef: headerRef, getRowProps: getRowProps, getHeaderProps: getHeaderProps, onHeaderClickCallback: onHeaderClickCallback, getClickableHeaderClassName: getClickableHeaderClassName, getRawColumnDefinition: getRawColumnDefinition, getColumnDefinition: getColumnDefinition, renderCell: renderCell, rowClickFunction: rowClickFunction, footerRows: footerRows, renderPluginFooters: renderPluginFooters, animationProps: animationProps, onRowClick: onRowClick, selectionProps: selectionProps }));
1034
+ if (infiniteScrollProps) {
1035
+ return React.createElement(InfiniteTable, Object.assign({}, props));
862
1036
  }
863
- render() {
864
- var _a;
865
- if (this.props.infiniteScrollProps) {
866
- return React.createElement(InfiniteTable, Object.assign({}, this.props));
867
- }
868
- if ((_a = this.props.animationProps) === null || _a === void 0 ? void 0 : _a.isLoading) {
869
- return this.skeletonView;
870
- }
871
- return (React.createElement("div", null,
872
- React.createElement("div", { style: { display: 'flex', justifyContent: 'flex-end' } }, this.renderPluginHeaders()),
873
- !this.hasData && this.noDataComponent,
874
- this.hasData && this.state.isMobile && this.mobileView,
875
- this.hasData && !this.state.isMobile && this.largeScreenView));
1037
+ if (animationProps === null || animationProps === void 0 ? void 0 : animationProps.isLoading) {
1038
+ return skeletonView;
876
1039
  }
1040
+ return (React.createElement("div", null,
1041
+ React.createElement("div", { style: { display: 'flex', justifyContent: 'flex-end' } }, renderPluginHeaders()),
1042
+ !hasData && noDataComponentNode,
1043
+ hasData && isMobile && mobileView,
1044
+ hasData && !isMobile && largeScreenView));
877
1045
  }
878
1046
 
879
1047
  class InfiniteScrollPlugin {
@@ -929,138 +1097,6 @@ class InfiniteScrollPlugin {
929
1097
  }
930
1098
  }
931
1099
 
932
- // Type-safe sort comparer helpers
933
- const createSortComparers = () => ({
934
- numeric: (key) => (a, b, direction) => {
935
- const numA = parseFloat(String(a[key]));
936
- const numB = parseFloat(String(b[key]));
937
- const aIsNaN = isNaN(numA);
938
- const bIsNaN = isNaN(numB);
939
- if (aIsNaN && bIsNaN)
940
- return 0;
941
- if (aIsNaN)
942
- return 1; // Put non-numbers at the end
943
- if (bIsNaN)
944
- return -1;
945
- return direction === 'asc' ? numA - numB : numB - numA;
946
- },
947
- caseInsensitiveString: (key) => (a, b, direction) => {
948
- var _a, _b;
949
- const valA = String((_a = a[key]) !== null && _a !== void 0 ? _a : '').toLowerCase();
950
- const valB = String((_b = b[key]) !== null && _b !== void 0 ? _b : '').toLowerCase();
951
- if (valA < valB)
952
- return direction === 'asc' ? -1 : 1;
953
- if (valA > valB)
954
- return direction === 'asc' ? 1 : -1;
955
- return 0;
956
- },
957
- date: (key) => (a, b, direction) => {
958
- const dateA = new Date(String(a[key])).getTime();
959
- const dateB = new Date(String(b[key])).getTime();
960
- const aIsNaN = isNaN(dateA);
961
- const bIsNaN = isNaN(dateB);
962
- if (aIsNaN && bIsNaN)
963
- return 0;
964
- if (aIsNaN)
965
- return 1; // Put invalid dates at the end
966
- if (bIsNaN)
967
- return -1;
968
- return direction === 'asc' ? dateA - dateB : dateB - dateA;
969
- },
970
- });
971
- class SortPlugin {
972
- constructor(options) {
973
- var _a, _b;
974
- this.id = 'sort';
975
- this.comparers = createSortComparers();
976
- this.onPluginInit = (api) => {
977
- this.api = api;
978
- };
979
- this.processData = (data) => {
980
- if (!this.sortColumn || !this.sortDirection) {
981
- return data;
982
- }
983
- const columnDef = this.api.columnDefinitions.find((col) => (typeof col === 'object' && col.columnId === this.sortColumn));
984
- if (!columnDef) {
985
- return data;
986
- }
987
- const sortedData = [...data].sort((a, b) => {
988
- if ('sortComparer' in columnDef && columnDef.sortComparer) {
989
- if (columnDef.sortComparer.length < 3) {
990
- console.warn(`The custom sortComparer for column '${this.sortColumn}' should accept all three parameters (a, b, direction) to ensure correct sorting behavior. You provided a function with ${columnDef.sortComparer.length} parameters.`);
991
- }
992
- return columnDef.sortComparer(a, b, this.sortDirection);
993
- }
994
- if ('getSortableValue' in columnDef && columnDef.getSortableValue) {
995
- const aValue = columnDef.getSortableValue(a);
996
- const bValue = columnDef.getSortableValue(b);
997
- if (aValue < bValue)
998
- return this.sortDirection === 'asc' ? -1 : 1;
999
- if (aValue > bValue)
1000
- return this.sortDirection === 'asc' ? 1 : -1;
1001
- return 0;
1002
- }
1003
- // Fallback to dataKey if it exists and no other sorter is provided
1004
- if ('dataKey' in columnDef && columnDef.dataKey) {
1005
- const key = columnDef.dataKey;
1006
- const aValue = a[key];
1007
- const bValue = b[key];
1008
- if (aValue < bValue)
1009
- return this.sortDirection === 'asc' ? -1 : 1;
1010
- if (aValue > bValue)
1011
- return this.sortDirection === 'asc' ? 1 : -1;
1012
- return 0;
1013
- }
1014
- return 0;
1015
- });
1016
- return sortedData;
1017
- };
1018
- this.getHeaderProps = (columnDef) => {
1019
- const { columnId } = columnDef;
1020
- const isSortable = ('sortComparer' in columnDef && !!columnDef.sortComparer) || ('getSortableValue' in columnDef && !!columnDef.getSortableValue);
1021
- // A column must have a columnId and a sort function to be sortable
1022
- if (!isSortable || !columnId) {
1023
- return {};
1024
- }
1025
- const onHeaderClick = (e) => {
1026
- const target = e.target;
1027
- console.log('SortPlugin: Header clicked. Target:', target);
1028
- // If the click is on an interactive element, don't sort
1029
- if (target.closest('input, button, a, [onclick]')) {
1030
- console.log('SortPlugin: Interactive element clicked, ignoring sort.');
1031
- return;
1032
- }
1033
- console.log('SortPlugin: Non-interactive element clicked, proceeding with sort.');
1034
- if (this.sortColumn === columnId) {
1035
- if (this.sortDirection === 'desc') {
1036
- this.sortColumn = null;
1037
- this.sortDirection = null;
1038
- }
1039
- else {
1040
- this.sortDirection = 'desc';
1041
- }
1042
- }
1043
- else {
1044
- this.sortColumn = columnId;
1045
- this.sortDirection = 'asc';
1046
- }
1047
- this.api.forceUpdate();
1048
- };
1049
- let sortClassName = 'sortable';
1050
- if (this.sortColumn === columnId) {
1051
- sortClassName = `sorted-${this.sortDirection}`;
1052
- }
1053
- return {
1054
- onClick: onHeaderClick,
1055
- className: sortClassName,
1056
- 'aria-sort': (this.sortColumn === columnId ? (this.sortDirection === 'asc' ? 'ascending' : 'descending') : 'none'),
1057
- };
1058
- };
1059
- this.sortColumn = (_a = options === null || options === void 0 ? void 0 : options.initialSortColumn) !== null && _a !== void 0 ? _a : null;
1060
- this.sortDirection = (_b = options === null || options === void 0 ? void 0 : options.initialSortDirection) !== null && _b !== void 0 ? _b : null;
1061
- }
1062
- }
1063
-
1064
1100
  exports.FilterPlugin = FilterPlugin;
1065
1101
  exports.InfiniteScrollPlugin = InfiniteScrollPlugin;
1066
1102
  exports.SelectionPlugin = SelectionPlugin;