jattac.libs.web.responsive-table 0.2.2 → 0.2.4

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.
@@ -1,11 +1,15 @@
1
1
  import { ReactNode } from 'react';
2
+ export type SortDirection = 'asc' | 'desc';
2
3
  export default interface IResponsiveTableColumnDefinition<TData> {
3
4
  displayLabel: ReactNode;
4
5
  cellRenderer: (data: TData) => ReactNode;
6
+ dataKey?: string;
5
7
  interactivity?: {
6
8
  id: string;
7
9
  onHeaderClick?: (id: string) => void;
8
10
  className?: string;
9
11
  };
10
12
  getFilterableValue?: (data: TData) => string | number;
13
+ getSortableValue?: (row: TData) => any;
14
+ sortComparer?: (a: TData, b: TData, direction: SortDirection) => number;
11
15
  }
@@ -0,0 +1,29 @@
1
+ import { IResponsiveTablePlugin, IPluginAPI } from './IResponsiveTablePlugin';
2
+ import IResponsiveTableColumnDefinition, { SortDirection } from '../Data/IResponsiveTableColumnDefinition';
3
+ export interface ISortPluginOptions<TData> {
4
+ initialSortColumn?: keyof TData;
5
+ initialSortDirection?: SortDirection;
6
+ }
7
+ export declare class SortPlugin<TData> implements IResponsiveTablePlugin<TData> {
8
+ id: string;
9
+ private api;
10
+ private sortColumn;
11
+ private sortDirection;
12
+ readonly comparers: {
13
+ numeric: (key: keyof TData) => (a: TData, b: TData, direction: SortDirection) => number;
14
+ caseInsensitiveString: (key: keyof TData) => (a: TData, b: TData, direction: SortDirection) => 0 | 1 | -1;
15
+ date: (key: keyof TData) => (a: TData, b: TData, direction: SortDirection) => number;
16
+ };
17
+ constructor(options?: ISortPluginOptions<TData>);
18
+ onPluginInit: (api: IPluginAPI<TData>) => void;
19
+ processData: (data: TData[]) => TData[];
20
+ getHeaderProps: (columnDef: IResponsiveTableColumnDefinition<TData>) => {
21
+ onClick?: undefined;
22
+ className?: undefined;
23
+ 'aria-sort'?: undefined;
24
+ } | {
25
+ onClick: () => void;
26
+ className: string;
27
+ 'aria-sort': string;
28
+ };
29
+ }
@@ -12,6 +12,7 @@ interface IProps<TData> {
12
12
  footerRows?: IFooterRowDefinition[];
13
13
  mobileBreakpoint?: number;
14
14
  plugins?: IResponsiveTablePlugin<TData>[];
15
+ enablePageLevelStickyHeader?: boolean;
15
16
  infiniteScrollProps?: {
16
17
  enableInfiniteScroll?: boolean;
17
18
  onLoadMore?: (currentData: TData[]) => Promise<TData[] | null>;
@@ -32,10 +33,12 @@ interface IState<TData> {
32
33
  isMobile: boolean;
33
34
  processedData: TData[];
34
35
  isLoadingMore: boolean;
36
+ isHeaderSticky: boolean;
35
37
  }
36
38
  declare class ResponsiveTable<TData> extends Component<IProps<TData>, IState<TData>> {
37
39
  private debouncedResize;
38
40
  private tableContainerRef;
41
+ private headerRef;
39
42
  constructor(props: IProps<TData>);
40
43
  private get mobileBreakpoint();
41
44
  private debounce;
@@ -46,6 +49,7 @@ declare class ResponsiveTable<TData> extends Component<IProps<TData>, IState<TDa
46
49
  componentDidMount(): void;
47
50
  componentWillUnmount(): void;
48
51
  componentDidUpdate(prevProps: IProps<TData>): void;
52
+ private handleScroll;
49
53
  private initializePlugins;
50
54
  private processData;
51
55
  handleResize: () => void;
@@ -53,6 +57,7 @@ declare class ResponsiveTable<TData> extends Component<IProps<TData>, IState<TDa
53
57
  private getRawColumnDefinition;
54
58
  private onHeaderClickCallback;
55
59
  private getClickableHeaderClassName;
60
+ private getHeaderProps;
56
61
  private get rowClickFunction();
57
62
  private get rowClickStyle();
58
63
  private get tableFooter();
package/dist/index.d.ts CHANGED
@@ -5,5 +5,6 @@ import ResponsiveTable, { ColumnDefinition } from './UI/ResponsiveTable';
5
5
  import { FilterPlugin } from './Plugins/FilterPlugin';
6
6
  import { InfiniteScrollPlugin } from './Plugins/InfiniteScrollPlugin';
7
7
  import { IResponsiveTablePlugin } from './Plugins/IResponsiveTablePlugin';
8
- export { IResponsiveTableColumnDefinition, ColumnDefinition, IFooterColumnDefinition, IFooterRowDefinition, FilterPlugin, InfiniteScrollPlugin, IResponsiveTablePlugin };
8
+ import { SortPlugin } from './Plugins/SortPlugin';
9
+ export { IResponsiveTableColumnDefinition, ColumnDefinition, IFooterColumnDefinition, IFooterRowDefinition, FilterPlugin, InfiniteScrollPlugin, IResponsiveTablePlugin, SortPlugin };
9
10
  export default ResponsiveTable;
package/dist/index.js CHANGED
@@ -31,8 +31,8 @@ function styleInject(css, ref) {
31
31
  }
32
32
  }
33
33
 
34
- var css_248z = "/* Using CSS variables for a more maintainable and themeable design */\n.ResponsiveTable-module_responsiveTable__4y-Od {\n --table-border-color: #e0e0e0;\n --table-header-bg: #f8f9fa;\n --table-row-hover-bg: #e9ecef;\n --table-row-stripe-bg: #f2f2f2;\n --card-bg: #ffffff;\n --card-border-color: #e0e0e0;\n --card-shadow: 0 2px 8px rgba(0, 0, 0, 0.06);\n --text-color: #212529;\n --text-color-muted: #6c757d;\n --interactive-color: #0056b3;\n}\n\n/* Mobile Card View */\n.ResponsiveTable-module_card__b-U2v {\n background-color: var(--card-bg);\n border: 1px solid var(--card-border-color);\n margin-bottom: 1rem;\n border-radius: 8px;\n overflow: hidden;\n box-shadow: var(--card-shadow);\n transition: box-shadow 0.2s ease-in-out;\n}\n\n.ResponsiveTable-module_card__b-U2v:hover {\n box-shadow: 0 4px 12px rgba(0, 0, 0, 0.1);\n}\n\n/* This is not used in the component, but keeping it styled in case it's added back */\n.ResponsiveTable-module_card-header__Ttk51 {\n background-color: var(--table-header-bg);\n padding: 0.75rem 1rem;\n font-weight: 600; /* Bolder */\n border-bottom: 1px solid var(--table-border-color);\n}\n\n.ResponsiveTable-module_card-body__XIy0h {\n padding: 1rem;\n font-size: 0.9rem;\n}\n\n.ResponsiveTable-module_card-body__XIy0h p {\n margin: 0 0 0.75rem;\n display: flex;\n justify-content: space-between;\n}\n\n.ResponsiveTable-module_card-body__XIy0h p:last-child {\n margin-bottom: 0;\n}\n\n.ResponsiveTable-module_card-label__v9L71 {\n font-weight: 600;\n color: var(--text-color);\n margin-right: 0.5rem;\n}\n\n/* Desktop Table View */\n.ResponsiveTable-module_responsiveTable__4y-Od {\n width: 100%;\n border-collapse: collapse;\n color: var(--text-color);\n}\n\n.ResponsiveTable-module_responsiveTable__4y-Od thead th {\n background-color: var(--table-header-bg);\n position: sticky;\n top: 0;\n z-index: 2;\n font-weight: 600;\n text-align: left;\n padding: 1rem;\n border-bottom: 2px solid var(--table-border-color);\n}\n\n.ResponsiveTable-module_responsiveTable__4y-Od td {\n padding: 1rem;\n border-bottom: 1px solid var(--table-border-color);\n text-align: left;\n}\n\n.ResponsiveTable-module_responsiveTable__4y-Od tr {\n background-color: var(--card-bg);\n transition: background-color 0.2s ease-in-out;\n}\n\n/* Subtle striping for better readability */\n.ResponsiveTable-module_responsiveTable__4y-Od tr:nth-child(even) {\n background-color: var(--table-row-stripe-bg);\n}\n\n/* Modern hover effect */\n.ResponsiveTable-module_responsiveTable__4y-Od tr:hover {\n background-color: var(--table-row-hover-bg);\n}\n\n/* Clickable Header Style */\n.ResponsiveTable-module_clickableHeader__xHQhF {\n cursor: pointer;\n color: var(--interactive-color);\n}\n\n.ResponsiveTable-module_clickableHeader__xHQhF:hover {\n text-decoration: underline;\n}\n\n.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";
35
- var styles = {"responsiveTable":"ResponsiveTable-module_responsiveTable__4y-Od","card":"ResponsiveTable-module_card__b-U2v","card-header":"ResponsiveTable-module_card-header__Ttk51","card-body":"ResponsiveTable-module_card-body__XIy0h","card-label":"ResponsiveTable-module_card-label__v9L71","clickableHeader":"ResponsiveTable-module_clickableHeader__xHQhF","footerCell":"ResponsiveTable-module_footerCell__8H-uG","clickableFooterCell":"ResponsiveTable-module_clickableFooterCell__WB9Ss","footerCard":"ResponsiveTable-module_footerCard__-NE2M","footer-card-body":"ResponsiveTable-module_footer-card-body__CtBMv","footer-card-row":"ResponsiveTable-module_footer-card-row__Vv6Ur","animatedRow":"ResponsiveTable-module_animatedRow__SFjrJ","skeleton":"ResponsiveTable-module_skeleton__XxsXW","skeletonText":"ResponsiveTable-module_skeletonText__T-Lgq","skeletonCard":"ResponsiveTable-module_skeletonCard__AYVwL","noDataWrapper":"ResponsiveTable-module_noDataWrapper__Rj-k3","noData":"ResponsiveTable-module_noData__IpwNq"};
34
+ var css_248z = "/* Using CSS variables for a more maintainable and themeable design */\r\n.ResponsiveTable-module_responsiveTable__4y-Od {\r\n --table-border-color: #e0e0e0;\r\n --table-header-bg: #f8f9fa;\r\n --table-row-hover-bg: #e9ecef;\r\n --table-row-stripe-bg: #f2f2f2;\r\n --card-bg: #ffffff;\r\n --card-border-color: #e0e0e0;\r\n --card-shadow: 0 2px 8px rgba(0, 0, 0, 0.06);\r\n --text-color: #212529;\r\n --text-color-muted: #6c757d;\r\n --interactive-color: #0056b3;\r\n}\r\n\r\n/* Mobile Card View */\r\n.ResponsiveTable-module_card__b-U2v {\r\n background-color: var(--card-bg);\r\n border: 1px solid var(--card-border-color);\r\n margin-bottom: 1rem;\r\n border-radius: 8px;\r\n overflow: hidden;\r\n box-shadow: var(--card-shadow);\r\n transition: box-shadow 0.2s ease-in-out;\r\n}\r\n\r\n.ResponsiveTable-module_card__b-U2v:hover {\r\n box-shadow: 0 4px 12px rgba(0, 0, 0, 0.1);\r\n}\r\n\r\n/* This is not used in the component, but keeping it styled in case it's added back */\r\n.ResponsiveTable-module_card-header__Ttk51 {\r\n background-color: var(--table-header-bg);\r\n padding: 0.75rem 1rem;\r\n font-weight: 600; /* Bolder */\r\n border-bottom: 1px solid var(--table-border-color);\r\n}\r\n\r\n.ResponsiveTable-module_card-body__XIy0h {\r\n padding: 1rem;\r\n font-size: 0.9rem;\r\n}\r\n\r\n.ResponsiveTable-module_card-body__XIy0h p {\r\n margin: 0 0 0.75rem;\r\n display: flex;\r\n justify-content: space-between;\r\n}\r\n\r\n.ResponsiveTable-module_card-body__XIy0h p:last-child {\r\n margin-bottom: 0;\r\n}\r\n\r\n.ResponsiveTable-module_card-label__v9L71 {\r\n font-weight: 600;\r\n color: var(--text-color);\r\n margin-right: 0.5rem;\r\n}\r\n\r\n/* Desktop Table View */\r\n.ResponsiveTable-module_responsiveTable__4y-Od {\r\n width: 100%;\r\n border-collapse: collapse;\r\n color: var(--text-color);\r\n}\r\n\r\n.ResponsiveTable-module_responsiveTable__4y-Od thead th {\r\n background-color: var(--table-header-bg);\r\n position: sticky;\r\n top: 0;\r\n z-index: 1;\r\n font-weight: 600;\r\n text-align: left;\r\n padding: 1rem;\r\n border-bottom: 2px solid var(--table-border-color);\r\n}\r\n\r\n.ResponsiveTable-module_responsiveTable__4y-Od td {\r\n padding: 1rem;\r\n border-bottom: 1px solid var(--table-border-color);\r\n text-align: left;\r\n}\r\n\r\n.ResponsiveTable-module_responsiveTable__4y-Od tr {\r\n background-color: var(--card-bg);\r\n transition: background-color 0.2s ease-in-out;\r\n}\r\n\r\n/* Subtle striping for better readability */\r\n.ResponsiveTable-module_responsiveTable__4y-Od tr:nth-child(even) {\r\n background-color: var(--table-row-stripe-bg);\r\n}\r\n\r\n/* Modern hover effect */\r\n.ResponsiveTable-module_responsiveTable__4y-Od tr:hover {\r\n background-color: var(--table-row-hover-bg);\r\n}\r\n\r\n/* Clickable Header Style */\r\n.ResponsiveTable-module_clickableHeader__xHQhF {\r\n cursor: pointer;\r\n color: var(--interactive-color);\r\n}\r\n\r\n.ResponsiveTable-module_clickableHeader__xHQhF:hover {\r\n text-decoration: underline;\r\n}\r\n\r\n/* Sortable Header Styles */\r\n.ResponsiveTable-module_responsiveTable__4y-Od th.ResponsiveTable-module_sortable__yvA60 {\r\n cursor: pointer;\r\n position: relative;\r\n padding-right: 2rem; /* Space for the icon */\r\n}\r\n\r\n.ResponsiveTable-module_responsiveTable__4y-Od th .ResponsiveTable-module_sortIcon__A9WtD {\r\n position: absolute;\r\n right: 0.5rem;\r\n top: 50%;\r\n transform: translateY(-50%);\r\n width: 1rem;\r\n height: 1rem;\r\n opacity: 0.4;\r\n transition: opacity 0.2s ease-in-out, transform 0.2s ease-in-out;\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/* Default unsorted icon (up and down arrows) */\r\n.ResponsiveTable-module_responsiveTable__4y-Od th.ResponsiveTable-module_sortable__yvA60 .ResponsiveTable-module_sortIcon__A9WtD::before,\r\n.ResponsiveTable-module_responsiveTable__4y-Od th.ResponsiveTable-module_sortable__yvA60 .ResponsiveTable-module_sortIcon__A9WtD::after {\r\n content: '';\r\n position: absolute;\r\n display: block;\r\n width: 0;\r\n height: 0;\r\n border-left: 0.4em solid transparent;\r\n border-right: 0.4em solid transparent;\r\n}\r\n\r\n.ResponsiveTable-module_responsiveTable__4y-Od th.ResponsiveTable-module_sortable__yvA60 .ResponsiveTable-module_sortIcon__A9WtD::before {\r\n border-bottom: 0.4em solid var(--text-color);\r\n top: 0.1em;\r\n}\r\n\r\n.ResponsiveTable-module_responsiveTable__4y-Od th.ResponsiveTable-module_sortable__yvA60 .ResponsiveTable-module_sortIcon__A9WtD::after {\r\n border-top: 0.4em solid var(--text-color);\r\n bottom: 0.1em;\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.ResponsiveTable-module_responsiveTable__4y-Od th.ResponsiveTable-module_sorted-desc__7WCFK .ResponsiveTable-module_sortIcon__A9WtD {\r\n opacity: 1;\r\n}\r\n\r\n.ResponsiveTable-module_responsiveTable__4y-Od th.ResponsiveTable-module_sorted-asc__jzOIa .ResponsiveTable-module_sortIcon__A9WtD::before {\r\n border-bottom-color: var(--interactive-color);\r\n}\r\n\r\n.ResponsiveTable-module_responsiveTable__4y-Od th.ResponsiveTable-module_sorted-asc__jzOIa .ResponsiveTable-module_sortIcon__A9WtD::after {\r\n opacity: 0.4;\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::after {\r\n border-top-color: var(--interactive-color);\r\n}\r\n\r\n.ResponsiveTable-module_responsiveTable__4y-Od th.ResponsiveTable-module_sorted-desc__7WCFK .ResponsiveTable-module_sortIcon__A9WtD::before {\r\n opacity: 0.4;\r\n}\r\n\r\n\r\n.ResponsiveTable-module_responsiveTable__4y-Od tfoot {\r\n background-color: var(--table-header-bg);\r\n border-top: 2px solid var(--table-border-color);\r\n font-weight: 600;\r\n}\r\n\r\n.ResponsiveTable-module_footerCell__8H-uG {\r\n padding: 1rem;\r\n text-align: right;\r\n font-weight: 600;\r\n}\r\n\r\n.ResponsiveTable-module_clickableFooterCell__WB9Ss {\r\n cursor: pointer;\r\n color: var(--interactive-color);\r\n}\r\n\r\n.ResponsiveTable-module_clickableFooterCell__WB9Ss:hover {\r\n text-decoration: underline;\r\n}\r\n\r\n.ResponsiveTable-module_footerCard__-NE2M {\r\n background-color: var(--table-header-bg);\r\n border: 1px solid var(--card-border-color);\r\n border-top: 2px solid var(--table-border-color);\r\n margin-bottom: 1rem;\r\n border-radius: 8px;\r\n overflow: hidden;\r\n box-shadow: none;\r\n}\r\n\r\n.ResponsiveTable-module_footer-card-body__CtBMv {\r\n padding: 1rem;\r\n font-size: 0.9rem;\r\n}\r\n\r\n.ResponsiveTable-module_footer-card-row__Vv6Ur {\r\n margin: 0 0 0.75rem;\r\n display: flex;\r\n justify-content: space-between;\r\n font-weight: 600;\r\n}\r\n\r\n/* No Data State */\r\n\r\n/* Staggered Entrance Animation */\r\n.ResponsiveTable-module_animatedRow__SFjrJ {\r\n animation: ResponsiveTable-module_fadeInUp__jMCS7 0.5s ease-out forwards;\r\n opacity: 0;\r\n}\r\n\r\n@keyframes ResponsiveTable-module_fadeInUp__jMCS7 {\r\n from {\r\n opacity: 0;\r\n transform: translateY(20px);\r\n }\r\n to {\r\n opacity: 1;\r\n transform: translateY(0);\r\n }\r\n}\r\n\r\n/* Skeleton Loader */\r\n.ResponsiveTable-module_skeleton__XxsXW {\r\n background-color: #e0e0e0;\r\n border-radius: 4px;\r\n position: relative;\r\n overflow: hidden;\r\n}\r\n\r\n.ResponsiveTable-module_skeleton__XxsXW::after {\r\n content: '';\r\n position: absolute;\r\n top: 0;\r\n left: -150%;\r\n width: 150%;\r\n height: 100%;\r\n background: linear-gradient(90deg, transparent, rgba(255, 255, 255, 0.4), transparent);\r\n animation: ResponsiveTable-module_shimmer__H8PhC 1.5s infinite;\r\n}\r\n\r\n.ResponsiveTable-module_skeletonText__T-Lgq {\r\n height: 1.2em;\r\n width: 100%;\r\n}\r\n\r\n.ResponsiveTable-module_skeletonCard__AYVwL {\r\n background-color: var(--card-bg);\r\n border: 1px solid var(--card-border-color);\r\n margin-bottom: 1rem;\r\n border-radius: 8px;\r\n overflow: hidden;\r\n padding: 1rem;\r\n}\r\n\r\n@keyframes ResponsiveTable-module_shimmer__H8PhC {\r\n 0% {\r\n transform: translateX(0);\r\n }\r\n 100% {\r\n transform: translateX(100%);\r\n }\r\n}\r\n.ResponsiveTable-module_noDataWrapper__Rj-k3 {\r\n color: var(--text-color-muted); /* Softer color */\r\n display: flex;\r\n justify-content: center;\r\n align-items: center;\r\n height: 100%;\r\n gap: 10px;\r\n padding: 40px;\r\n background-color: var(--table-header-bg);\r\n border: 1px dashed var(--table-border-color);\r\n border-radius: 8px;\r\n}\r\n\r\n.ResponsiveTable-module_noData__IpwNq {\r\n text-align: center;\r\n font-weight: 500; /* Less aggressive than bold */\r\n font-size: 1rem;\r\n}\r\n\r\n.ResponsiveTable-module_row-exit__EVX6T {\r\n opacity: 0;\r\n transform: scaleY(0);\r\n transition: transform 0.3s ease-out, opacity 0.3s ease-out;\r\n}\r\n\r\n.ResponsiveTable-module_row-enter__YKgI4 {\r\n opacity: 0;\r\n transform: translateY(20px);\r\n transition: transform 0.5s ease-out, opacity 0.5s ease-out;\r\n}\r\n\r\n.ResponsiveTable-module_row-flash__a4NOm {\r\n animation: ResponsiveTable-module_flash__nxeAX 0.5s ease-out;\r\n}\r\n\r\n@keyframes ResponsiveTable-module_flash__nxeAX {\r\n 0% {\r\n background-color: var(--table-row-hover-bg);\r\n }\r\n 100% {\r\n background-color: transparent;\r\n }\r\n}\r\n\r\n.ResponsiveTable-module_stickyHeader__-jjN- {\r\n position: sticky;\r\n top: 0;\r\n z-index: 1;\r\n box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);\r\n}\r\n";
35
+ var styles = {"responsiveTable":"ResponsiveTable-module_responsiveTable__4y-Od","card":"ResponsiveTable-module_card__b-U2v","card-header":"ResponsiveTable-module_card-header__Ttk51","card-body":"ResponsiveTable-module_card-body__XIy0h","card-label":"ResponsiveTable-module_card-label__v9L71","clickableHeader":"ResponsiveTable-module_clickableHeader__xHQhF","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","skeleton":"ResponsiveTable-module_skeleton__XxsXW","skeletonText":"ResponsiveTable-module_skeletonText__T-Lgq","skeletonCard":"ResponsiveTable-module_skeletonCard__AYVwL","noDataWrapper":"ResponsiveTable-module_noDataWrapper__Rj-k3","noData":"ResponsiveTable-module_noData__IpwNq","stickyHeader":"ResponsiveTable-module_stickyHeader__-jjN-"};
36
36
  styleInject(css_248z);
37
37
 
38
38
  class FilterPlugin {
@@ -972,6 +972,16 @@ class ResponsiveTable extends React.Component {
972
972
  constructor(props) {
973
973
  super(props);
974
974
  this.tableContainerRef = React.createRef();
975
+ this.headerRef = React.createRef();
976
+ this.handleScroll = () => {
977
+ if (this.headerRef.current && !this.props.maxHeight) {
978
+ const { top } = this.headerRef.current.getBoundingClientRect();
979
+ const isSticky = top <= 0;
980
+ if (isSticky !== this.state.isHeaderSticky) {
981
+ this.setState({ isHeaderSticky: isSticky });
982
+ }
983
+ }
984
+ };
975
985
  this.handleResize = () => {
976
986
  this.setState({
977
987
  isMobile: window.innerWidth <= this.mobileBreakpoint,
@@ -981,6 +991,7 @@ class ResponsiveTable extends React.Component {
981
991
  isMobile: false,
982
992
  processedData: props.data,
983
993
  isLoadingMore: false,
994
+ isHeaderSticky: false,
984
995
  };
985
996
  this.debouncedResize = this.debounce(this.handleResize, 200);
986
997
  }
@@ -1017,10 +1028,16 @@ class ResponsiveTable extends React.Component {
1017
1028
  componentDidMount() {
1018
1029
  this.handleResize(); // Initial check
1019
1030
  window.addEventListener('resize', this.debouncedResize);
1031
+ if (this.props.enablePageLevelStickyHeader !== false) {
1032
+ window.addEventListener('scroll', this.handleScroll);
1033
+ }
1020
1034
  this.initializePlugins();
1021
1035
  }
1022
1036
  componentWillUnmount() {
1023
1037
  window.removeEventListener('resize', this.debouncedResize);
1038
+ if (this.props.enablePageLevelStickyHeader !== false) {
1039
+ window.removeEventListener('scroll', this.handleScroll);
1040
+ }
1024
1041
  }
1025
1042
  componentDidUpdate(prevProps) {
1026
1043
  var _a, _b, _c;
@@ -1109,6 +1126,17 @@ class ResponsiveTable extends React.Component {
1109
1126
  : '';
1110
1127
  return clickableHeaderClassName;
1111
1128
  }
1129
+ getHeaderProps(columnDefinition) {
1130
+ let headerProps = {};
1131
+ if (this.props.plugins) {
1132
+ this.props.plugins.forEach((plugin) => {
1133
+ if (plugin.getHeaderProps) {
1134
+ Object.assign(headerProps, plugin.getHeaderProps(this.getRawColumnDefinition(columnDefinition)));
1135
+ }
1136
+ });
1137
+ }
1138
+ return headerProps;
1139
+ }
1112
1140
  get rowClickFunction() {
1113
1141
  if (this.props.onRowClick) {
1114
1142
  return this.props.onRowClick;
@@ -1204,13 +1232,14 @@ class ResponsiveTable extends React.Component {
1204
1232
  };
1205
1233
  return (React.createElement("div", { style: fixedHeadersStyle, ref: this.tableContainerRef },
1206
1234
  React.createElement("table", { className: styles['responsiveTable'] },
1207
- React.createElement("thead", null,
1235
+ React.createElement("thead", { ref: this.headerRef, className: this.state.isHeaderSticky ? styles.stickyHeader : '' },
1208
1236
  React.createElement("tr", null, this.props.columnDefinitions.map((columnDefinition, colIndex) => {
1209
1237
  const onHeaderClickCallback = this.onHeaderClickCallback(columnDefinition);
1210
1238
  const clickableHeaderClassName = this.getClickableHeaderClassName(onHeaderClickCallback, columnDefinition);
1211
- return (React.createElement("th", { key: colIndex, className: `${clickableHeaderClassName}`, onClick: onHeaderClickCallback
1212
- ? () => onHeaderClickCallback(this.getColumnDefinition(columnDefinition, 0).interactivity.id)
1213
- : undefined }, this.getColumnDefinition(columnDefinition, 0).displayLabel));
1239
+ const headerProps = this.getHeaderProps(columnDefinition);
1240
+ return (React.createElement("th", Object.assign({ key: colIndex, className: `${clickableHeaderClassName}` }, headerProps),
1241
+ this.getColumnDefinition(columnDefinition, 0).displayLabel,
1242
+ React.createElement("span", { className: styles.sortIcon })));
1214
1243
  }))),
1215
1244
  React.createElement("tbody", null, ((_a = this.props.infiniteScrollProps) === null || _a === void 0 ? void 0 : _a.enableInfiniteScroll) ? (React.createElement(FixedSizeList, { height: fixedHeadersStyle.maxHeight ? (typeof fixedHeadersStyle.maxHeight === 'string' ? parseFloat(fixedHeadersStyle.maxHeight) : fixedHeadersStyle.maxHeight) : 500, itemCount: this.data.length, itemSize: 50, width: '100%', outerRef: this.tableContainerRef }, Row)) : (this.data.map((row, rowIndex) => {
1216
1245
  var _a;
@@ -1226,6 +1255,10 @@ class ResponsiveTable extends React.Component {
1226
1255
  }
1227
1256
  return this.props.plugins.map((plugin) => {
1228
1257
  if (plugin.renderHeader) {
1258
+ // For sort plugin, only render header in mobile view
1259
+ if (plugin.id === 'sort' && !this.state.isMobile) {
1260
+ return null;
1261
+ }
1229
1262
  return React.createElement("div", { key: plugin.id }, plugin.renderHeader());
1230
1263
  }
1231
1264
  return null;
@@ -1255,7 +1288,104 @@ class ResponsiveTable extends React.Component {
1255
1288
  }
1256
1289
  }
1257
1290
 
1291
+ // Type-safe sort comparer helpers
1292
+ const createSortComparers = () => ({
1293
+ numeric: (key) => (a, b, direction) => {
1294
+ const valA = a[key];
1295
+ const valB = b[key];
1296
+ return direction === 'asc' ? valA - valB : valB - valA;
1297
+ },
1298
+ caseInsensitiveString: (key) => (a, b, direction) => {
1299
+ const valA = a[key].toLowerCase();
1300
+ const valB = b[key].toLowerCase();
1301
+ if (valA < valB)
1302
+ return direction === 'asc' ? -1 : 1;
1303
+ if (valA > valB)
1304
+ return direction === 'asc' ? 1 : -1;
1305
+ return 0;
1306
+ },
1307
+ date: (key) => (a, b, direction) => {
1308
+ const dateA = new Date(a[key]).getTime();
1309
+ const dateB = new Date(b[key]).getTime();
1310
+ return direction === 'asc' ? dateA - dateB : dateB - dateA;
1311
+ },
1312
+ });
1313
+ class SortPlugin {
1314
+ constructor(options) {
1315
+ var _a, _b;
1316
+ this.id = 'sort';
1317
+ this.comparers = createSortComparers();
1318
+ this.onPluginInit = (api) => {
1319
+ this.api = api;
1320
+ };
1321
+ this.processData = (data) => {
1322
+ if (!this.sortColumn || !this.sortDirection) {
1323
+ return data;
1324
+ }
1325
+ const columnDef = this.api.columnDefinitions.find((col) => col.dataKey === this.sortColumn);
1326
+ if (!columnDef) {
1327
+ return data;
1328
+ }
1329
+ const sortedData = [...data].sort((a, b) => {
1330
+ if (columnDef.sortComparer) {
1331
+ return columnDef.sortComparer(a, b, this.sortDirection);
1332
+ }
1333
+ let aValue, bValue;
1334
+ if (columnDef.getSortableValue) {
1335
+ aValue = columnDef.getSortableValue(a);
1336
+ bValue = columnDef.getSortableValue(b);
1337
+ }
1338
+ else {
1339
+ aValue = a[this.sortColumn];
1340
+ bValue = b[this.sortColumn];
1341
+ }
1342
+ if (aValue < bValue)
1343
+ return this.sortDirection === 'asc' ? -1 : 1;
1344
+ if (aValue > bValue)
1345
+ return this.sortDirection === 'asc' ? 1 : -1;
1346
+ return 0;
1347
+ });
1348
+ return sortedData;
1349
+ };
1350
+ this.getHeaderProps = (columnDef) => {
1351
+ const { dataKey, sortComparer, getSortableValue } = columnDef;
1352
+ const isSortable = !!(sortComparer || getSortableValue);
1353
+ if (!isSortable || !dataKey) {
1354
+ return {};
1355
+ }
1356
+ const onHeaderClick = () => {
1357
+ if (this.sortColumn === dataKey) {
1358
+ if (this.sortDirection === 'desc') {
1359
+ this.sortColumn = null;
1360
+ this.sortDirection = null;
1361
+ }
1362
+ else {
1363
+ this.sortDirection = 'desc';
1364
+ }
1365
+ }
1366
+ else {
1367
+ this.sortColumn = dataKey;
1368
+ this.sortDirection = 'asc';
1369
+ }
1370
+ this.api.forceUpdate();
1371
+ };
1372
+ let sortClassName = 'sortable';
1373
+ if (this.sortColumn === dataKey) {
1374
+ sortClassName = `sorted-${this.sortDirection}`;
1375
+ }
1376
+ return {
1377
+ onClick: onHeaderClick,
1378
+ className: sortClassName,
1379
+ 'aria-sort': this.sortColumn === dataKey ? (this.sortDirection === 'asc' ? 'ascending' : 'descending') : 'none',
1380
+ };
1381
+ };
1382
+ this.sortColumn = (_a = options === null || options === void 0 ? void 0 : options.initialSortColumn) !== null && _a !== void 0 ? _a : null;
1383
+ this.sortDirection = (_b = options === null || options === void 0 ? void 0 : options.initialSortDirection) !== null && _b !== void 0 ? _b : null;
1384
+ }
1385
+ }
1386
+
1258
1387
  exports.FilterPlugin = FilterPlugin;
1259
1388
  exports.InfiniteScrollPlugin = InfiniteScrollPlugin;
1389
+ exports.SortPlugin = SortPlugin;
1260
1390
  exports.default = ResponsiveTable;
1261
1391
  //# sourceMappingURL=index.js.map