jattac.libs.web.responsive-table 0.2.15 → 0.2.17

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -9,7 +9,7 @@ ResponsiveTable is a powerful, lightweight, and fully responsive React component
9
9
  - **Dynamic Data Handling**: Define columns and footers based on your data or application state.
10
10
  - **Delightful Animations**: Includes an optional skeleton loader and staggered row entrance animations.
11
11
  - **Interactive Elements**: Easily add click handlers for rows, headers, and footer cells.
12
- - **Performant**: Built with performance in mind, including debounced resize handling.
12
+ - **Efficient & Responsive**: Built with efficiency in mind, including debounced resize handling for smooth transitions.
13
13
  - **Easy to Use**: A simple and intuitive API for quick integration.
14
14
  - **Extensible Plugin System**: Easily add new functionalities like filtering, sorting, or infinite scrolling.
15
15
 
@@ -230,15 +230,9 @@ const TableWithFooter = () => {
230
230
  };
231
231
  ```
232
232
 
233
- ### Example 6: Disabling the Page-Level Sticky Header (ELI5)
233
+ ### Example 6: Disabling Page-Level Sticky Header
234
234
 
235
- **Explain Like I'm 5:** Imagine you have a super long grocery list on a piece of paper (the webpage). The titles of the columns are "Item", "Quantity", and "Price" (the table header).
236
-
237
- Normally, as you slide the paper up to see items at the bottom, the titles disappear off the top.
238
-
239
- This table has a special power: by default, the header "sticks" to the top of your view so you never forget which column is which.
240
-
241
- But what if you don't want it to stick? The `enablePageLevelStickyHeader={false}` prop is like a magic switch. Flipping it to `false` tells the header to scroll away normally with the rest of the page.
235
+ By default, the table header remains fixed to the top of the viewport as the user scrolls down the page. This ensures the column titles are always visible. To disable this behavior and have the header scroll away with the rest of the page, set the `enablePageLevelStickyHeader` prop to `false`.
242
236
 
243
237
  ```jsx
244
238
  import React from 'react';
@@ -501,9 +495,11 @@ const FilterableTable = () => {
501
495
 
502
496
  #### `InfiniteScrollPlugin`
503
497
 
504
- Enables high-performance virtualization for displaying large datasets. When enabled, the table will only render the rows currently visible on the screen, loading more data as the user scrolls. This is essential for maintaining a smooth user experience with thousands or millions of rows.
498
+ Enables a simple infinite scroll for loading more data as the user scrolls to the bottom of the table. This is useful for progressively loading data from an API without needing traditional pagination buttons.
499
+
500
+ > **Important:** To enable infinite scroll, you **must** give the table a bounded height. This is done by passing the `maxHeight` prop to the `<ResponsiveTable>`. This prop creates a scrollable container for the table body, which is required for the scroll detection to work.
505
501
 
506
- > **Important:** To enable infinite scrolling, you **must** give the table a bounded height. This is done by passing the `maxHeight` prop to the `<ResponsiveTable>`. This prop creates a scrollable container for the table body, which is required for virtualization to work.
502
+ > **Performance Note:** This implementation renders all loaded rows into the DOM to guarantee correct column alignment and simplicity. It is **not a virtualized list**. For extremely large datasets (many thousands of rows), performance may degrade as more rows are loaded. It is best suited for scenarios where loading a few hundred up to a couple thousand rows is expected.
507
503
 
508
504
  **Configuration (via `infiniteScrollProps` on `ResponsiveTable`):**
509
505
 
@@ -517,10 +513,10 @@ Enables high-performance virtualization for displaying large datasets. When enab
517
513
 
518
514
  **Comprehensive Example:**
519
515
 
520
- Here is a complete example of a component that fetches data from a simulated API and uses the infinite scroll feature.
516
+ Here is a complete example showing how to use the infinite scroll feature. The parent component only needs to provide a function that fetches the next page of data.
521
517
 
522
518
  ```jsx
523
- import React, { useState, useEffect, useCallback } from 'react';
519
+ import React, { useState, useCallback } from 'react';
524
520
  import ResponsiveTable from 'jattac.libs.web.responsive-table';
525
521
 
526
522
  // Define the shape of our data items
@@ -551,35 +547,18 @@ const fetchData = async (page: number): Promise<DataItem[]> => {
551
547
  };
552
548
 
553
549
  const InfiniteScrollExample = () => {
554
- // State for the data items displayed in the table
555
- const [data, setData] = useState<DataItem[]>([]);
556
- // State to track if there is more data to be loaded
557
- const [hasMore, setHasMore] = useState(true);
558
- // State to track the current page number for the API call
550
+ // Keep track of the next page to fetch.
559
551
  const [nextPage, setNextPage] = useState(0);
560
552
 
561
- // The function that the table will call to load more items.
562
- // It's wrapped in useCallback to prevent unnecessary re-renders.
553
+ // The onLoadMore function is now much simpler.
554
+ // It just needs to fetch the data and return it.
555
+ // The table will handle appending the data and managing the `hasMore` state internally.
563
556
  const loadMoreItems = useCallback(async () => {
564
- // Fetch the next page of data
565
557
  const newItems = await fetchData(nextPage);
566
-
567
- if (newItems.length === 0) {
568
- // If the API returns no more items, update hasMore to false
569
- setHasMore(false);
570
- } else {
571
- // Add the new items to the existing data
572
- setData((prevData) => [...prevData, ...newItems]);
573
- // Increment the page number for the next fetch
574
- setNextPage((prevPage) => prevPage + 1);
575
- }
558
+ setNextPage((prevPage) => prevPage + 1);
559
+ return newItems; // <-- Simply return the new items
576
560
  }, [nextPage]);
577
561
 
578
- // Load the initial data when the component mounts
579
- useEffect(() => {
580
- loadMoreItems();
581
- }, []); // The empty dependency array ensures this runs only once on mount
582
-
583
562
  const columns = [
584
563
  { displayLabel: 'ID', dataKey: 'id', cellRenderer: (row) => row.id },
585
564
  { displayLabel: 'Value', dataKey: 'value', cellRenderer: (row) => row.value },
@@ -590,14 +569,12 @@ const InfiniteScrollExample = () => {
590
569
  <div style={{ height: '400px' }}>
591
570
  <ResponsiveTable
592
571
  columnDefinitions={columns}
593
- data={data}
594
- // The maxHeight prop makes the table body scrollable within the container.
572
+ data={[]} // Start with an empty array of initial data
595
573
  maxHeight="100%"
596
- // Pass the infinite scroll configuration
597
574
  infiniteScrollProps={{
598
575
  enableInfiniteScroll: true,
599
576
  onLoadMore: loadMoreItems,
600
- hasMore: hasMore,
577
+ // Note: `hasMore` is not needed! The component infers it.
601
578
  loadingMoreComponent: <h4>Loading more items...</h4>,
602
579
  noMoreDataComponent: <p>You've reached the end!</p>,
603
580
  }}
@@ -3,6 +3,20 @@ import { IResponsiveTableColumnDefinition } from '../Data/IResponsiveTableColumn
3
3
  import IFooterRowDefinition from '../Data/IFooterRowDefinition';
4
4
  import { IResponsiveTablePlugin } from '../Plugins/IResponsiveTablePlugin';
5
5
  export type ColumnDefinition<TData> = IResponsiveTableColumnDefinition<TData> | ((data: TData, rowIndex?: number) => IResponsiveTableColumnDefinition<TData>);
6
+ type InfiniteScrollDisabled = {
7
+ enableInfiniteScroll?: false;
8
+ onLoadMore?: never;
9
+ hasMore?: never;
10
+ loadingMoreComponent?: never;
11
+ noMoreDataComponent?: never;
12
+ };
13
+ type InfiniteScrollEnabled<TData> = {
14
+ enableInfiniteScroll: true;
15
+ onLoadMore: (currentData: TData[]) => Promise<TData[] | null>;
16
+ hasMore?: boolean;
17
+ loadingMoreComponent?: ReactNode;
18
+ noMoreDataComponent?: ReactNode;
19
+ };
6
20
  interface IProps<TData> {
7
21
  columnDefinitions: ColumnDefinition<TData>[];
8
22
  data: TData[];
@@ -13,13 +27,7 @@ interface IProps<TData> {
13
27
  mobileBreakpoint?: number;
14
28
  plugins?: IResponsiveTablePlugin<TData>[];
15
29
  enablePageLevelStickyHeader?: boolean;
16
- infiniteScrollProps?: {
17
- enableInfiniteScroll?: boolean;
18
- onLoadMore?: (currentData: TData[]) => Promise<TData[] | null>;
19
- hasMore?: boolean;
20
- loadingMoreComponent?: ReactNode;
21
- noMoreDataComponent?: ReactNode;
22
- };
30
+ infiniteScrollProps?: InfiniteScrollDisabled | InfiniteScrollEnabled<TData>;
23
31
  filterProps?: {
24
32
  showFilter?: boolean;
25
33
  filterPlaceholder?: string;
@@ -31,31 +39,31 @@ interface IProps<TData> {
31
39
  }
32
40
  interface IState<TData> {
33
41
  isMobile: boolean;
42
+ internalData: TData[];
34
43
  processedData: TData[];
35
44
  isLoadingMore: boolean;
45
+ internalHasMore: boolean;
36
46
  isHeaderSticky: boolean;
37
- columnWidths: number[];
47
+ activePlugins: IResponsiveTablePlugin<TData>[];
38
48
  }
39
49
  declare class InfiniteTable<TData> extends Component<IProps<TData>, IState<TData>> {
40
50
  private debouncedResize;
41
51
  private tableContainerRef;
42
52
  private headerRef;
43
- private resizeObserver;
53
+ private throttledScrollHandler;
44
54
  constructor(props: IProps<TData>);
45
- private get mobileBreakpoint();
46
- private debounce;
47
- private get data();
48
- private get noDataSvg();
49
- private get hasData();
50
- private get noDataComponent();
51
55
  componentDidMount(): void;
52
56
  componentWillUnmount(): void;
53
- componentDidUpdate(prevProps: IProps<TData>): void;
54
- private measureHeader;
57
+ private debounce;
58
+ private throttle;
59
+ handleResize: () => void;
55
60
  private handleScroll;
61
+ private loadMoreData;
56
62
  private initializePlugins;
57
63
  private processData;
58
- handleResize: () => void;
64
+ private get data();
65
+ private get hasData();
66
+ private get noDataComponent();
59
67
  private getColumnDefinition;
60
68
  private getRawColumnDefinition;
61
69
  private onHeaderClickCallback;
@@ -63,13 +71,8 @@ declare class InfiniteTable<TData> extends Component<IProps<TData>, IState<TData
63
71
  private getHeaderProps;
64
72
  private get rowClickFunction();
65
73
  private get rowClickStyle();
66
- private get tableFooter();
67
- private get mobileFooter();
68
- private get skeletonView();
69
74
  private get mobileView();
70
75
  private get largeScreenView();
71
- private renderPluginHeaders;
72
- private renderPluginFooters;
73
- render(): string | number | boolean | Iterable<React.ReactNode> | React.JSX.Element | null | undefined;
76
+ render(): React.JSX.Element;
74
77
  }
75
78
  export default InfiniteTable;
@@ -3,6 +3,20 @@ import { IResponsiveTableColumnDefinition } from '../Data/IResponsiveTableColumn
3
3
  import IFooterRowDefinition from '../Data/IFooterRowDefinition';
4
4
  import { IResponsiveTablePlugin } from '../Plugins/IResponsiveTablePlugin';
5
5
  export type ColumnDefinition<TData> = IResponsiveTableColumnDefinition<TData> | ((data: TData, rowIndex?: number) => IResponsiveTableColumnDefinition<TData>);
6
+ type InfiniteScrollDisabled = {
7
+ enableInfiniteScroll?: false;
8
+ onLoadMore?: never;
9
+ hasMore?: never;
10
+ loadingMoreComponent?: never;
11
+ noMoreDataComponent?: never;
12
+ };
13
+ type InfiniteScrollEnabled<TData> = {
14
+ enableInfiniteScroll: true;
15
+ onLoadMore: (currentData: TData[]) => Promise<TData[] | null>;
16
+ hasMore?: boolean;
17
+ loadingMoreComponent?: ReactNode;
18
+ noMoreDataComponent?: ReactNode;
19
+ };
6
20
  interface IProps<TData> {
7
21
  columnDefinitions: ColumnDefinition<TData>[];
8
22
  data: TData[];
@@ -13,13 +27,7 @@ interface IProps<TData> {
13
27
  mobileBreakpoint?: number;
14
28
  plugins?: IResponsiveTablePlugin<TData>[];
15
29
  enablePageLevelStickyHeader?: boolean;
16
- infiniteScrollProps?: {
17
- enableInfiniteScroll?: boolean;
18
- onLoadMore?: (currentData: TData[]) => Promise<TData[] | null>;
19
- hasMore?: boolean;
20
- loadingMoreComponent?: ReactNode;
21
- noMoreDataComponent?: ReactNode;
22
- };
30
+ infiniteScrollProps?: InfiniteScrollDisabled | InfiniteScrollEnabled<TData>;
23
31
  filterProps?: {
24
32
  showFilter?: boolean;
25
33
  filterPlaceholder?: string;