@agilant/toga-blox 1.0.165 → 1.0.167

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.
@@ -17,6 +17,7 @@ export interface TableRowProps<T extends DataWithUUID> {
17
17
  loadingIndicator?: ReactNode;
18
18
  errorIndicator?: (error: Error) => ReactNode;
19
19
  expandedContent?: ReactNode;
20
+ linkText?: string;
20
21
  }
21
- declare const TableRow: <T extends DataWithUUID>({ row, prepareRow, activeIndex, activeRowColor, rowHoverClasses, globalTrimActive, hasInfiniteScroll, rowUuid, columnInputs, onRowClick, hasDropDown, onFetchRowData, loadingIndicator, errorIndicator, expandedContent, }: TableRowProps<T>) => import("react/jsx-runtime").JSX.Element;
22
+ declare const TableRow: <T extends DataWithUUID>({ row, prepareRow, activeIndex, activeRowColor, rowHoverClasses, globalTrimActive, hasInfiniteScroll, rowUuid, columnInputs, onRowClick, hasDropDown, onFetchRowData, loadingIndicator, errorIndicator, expandedContent, linkText, }: TableRowProps<T>) => import("react/jsx-runtime").JSX.Element;
22
23
  export default TableRow;
@@ -18,7 +18,7 @@ rowUuid, columnInputs,
18
18
  /* click handler */
19
19
  onRowClick,
20
20
  /* dropdown */
21
- hasDropDown = false, onFetchRowData, loadingIndicator, errorIndicator, expandedContent, }) => {
21
+ hasDropDown = false, onFetchRowData, loadingIndicator, errorIndicator, expandedContent, linkText = "text-blue-500", }) => {
22
22
  /* prepare react-table row */
23
23
  prepareRow(row);
24
24
  const isActive = activeIndex === row.index;
@@ -53,7 +53,7 @@ hasDropDown = false, onFetchRowData, loadingIndicator, errorIndicator, expandedC
53
53
  return (_jsxs(Fragment, { children: [_jsx("tr", { "data-testid": "table-row", className: `border-b border-b-navy-200 ${rowHoverClasses} ${rowClasses}`, ...(row.getRowProps ? row.getRowProps() : {}), onClick: handleRowClick, children: row.cells.map((cell, idx) => {
54
54
  const isLastCell = idx === row.cells.length - 1;
55
55
  const cellProps = cell.getCellProps();
56
- return (_jsx(Fragment, { children: _jsx(TableCell, { cell: cell, isLastCell: isLastCell, globalTrimActive: globalTrimActive, columnInputs: columnInputs, rowUuid: rowUuid, hasInfiniteScroll: hasInfiniteScroll }) }, cellProps.key));
56
+ return (_jsx(Fragment, { children: _jsx(TableCell, { cell: cell, isLastCell: isLastCell, globalTrimActive: globalTrimActive, columnInputs: columnInputs, rowUuid: rowUuid, hasInfiniteScroll: hasInfiniteScroll, linkText: linkText }) }, cellProps.key));
57
57
  }) }, rowUuid), hasDropDown && (_jsx(AnimatePresence, { children: isExpanded && (_jsx("tr", { "data-testid": "expanded-row", children: _jsx("td", { colSpan: row.cells.length, className: "p-0", children: _jsx(motion.div, { initial: { height: 0, opacity: 0 }, animate: { height: "auto", opacity: 1 }, exit: { height: 0, opacity: 0 }, transition: { duration: 0.3 }, className: "overflow-hidden w-full", children: isLoading ? (loadingIndicator ?? (_jsx("span", { children: "Loading..." }))) : error ? (errorIndicator ? (errorIndicator(error)) : (_jsxs("span", { className: "text-red-700", children: ["Error: ", error.message] }))) : (expandedContent ?? (_jsxs("span", { children: ["drop down \u2013 ", rowUuid] }))) }, "expanded-dropdown-content") }) })) }))] }));
58
58
  };
59
59
  export default TableRow;
@@ -1,2 +1,2 @@
1
1
  export { useTableInfiniteScroll } from "./useTableInfiniteScroll";
2
- export type { UseTableInfiniteScrollOpts } from "./useTableInfiniteScroll";
2
+ export type { useTableInfiniteScrollOptions } from "./useTableInfiniteScroll";
@@ -1,16 +1,23 @@
1
- /** Options the consumer must pass in */
2
- export type UseTableInfiniteScrollOpts = {
3
- rows: number;
1
+ import type { VirtualItem } from "@tanstack/react-virtual";
2
+ export interface useTableInfiniteScrollOptions {
3
+ /** Enable only when true */
4
4
  hasInfiniteScroll: boolean;
5
- isLoadingMore: boolean;
6
- onNeedMore: () => void;
7
- rootMarginPx?: number;
8
- };
5
+ /** Flag from context/store indicating a load is already in progress */
6
+ infiniteScrollIsLoadingMore: boolean;
7
+ /** Number of rows currently loaded */
8
+ pageLength: number;
9
+ /** Total record count from the server (optional) */
10
+ totalRecords?: number;
11
+ /** Virtual items returned from useVirtualizer */
12
+ virtualItems: VirtualItem<HTMLDivElement>[];
13
+ /** Callback to fetch the next page */
14
+ loadNextPage: () => void;
15
+ /** How close to the end (in rows) before triggering load */
16
+ threshold?: number;
17
+ }
9
18
  /**
10
- * Reusable hook no app‑specific imports.
11
- * Returns { scrollRef, sentinelRef }.
19
+ * Triggers loadNextPage() when the last visible virtual row
20
+ * gets within `threshold` of `pageLength`, but stops once
21
+ * we've loaded all `totalRecords`.
12
22
  */
13
- export declare const useTableInfiniteScroll: ({ rows, hasInfiniteScroll, isLoadingMore, onNeedMore, rootMarginPx, }: UseTableInfiniteScrollOpts) => {
14
- scrollRef: import("react").MutableRefObject<HTMLDivElement>;
15
- sentinelRef: import("react").MutableRefObject<HTMLDivElement>;
16
- };
23
+ export declare function useTableInfiniteScroll({ hasInfiniteScroll, infiniteScrollIsLoadingMore, pageLength, totalRecords, virtualItems, loadNextPage, threshold, }: useTableInfiniteScrollOptions): void;
@@ -1,39 +1,28 @@
1
- import { useRef, useEffect, useLayoutEffect } from "react";
1
+ import { useEffect } from "react";
2
2
  /**
3
- * Reusable hook no app‑specific imports.
4
- * Returns { scrollRef, sentinelRef }.
3
+ * Triggers loadNextPage() when the last visible virtual row
4
+ * gets within `threshold` of `pageLength`, but stops once
5
+ * we've loaded all `totalRecords`.
5
6
  */
6
- export const useTableInfiniteScroll = ({ rows, hasInfiniteScroll, isLoadingMore, onNeedMore, rootMarginPx = 800, }) => {
7
- const scrollRef = useRef(null);
8
- const sentinelRef = useRef(null);
9
- const scrollTop = useRef(0);
10
- /* remember pixel offset */
7
+ export function useTableInfiniteScroll({ hasInfiniteScroll, infiniteScrollIsLoadingMore, pageLength, totalRecords, virtualItems, loadNextPage, threshold = 5, }) {
11
8
  useEffect(() => {
12
- const el = scrollRef.current;
13
- if (!el)
9
+ if (!hasInfiniteScroll || infiniteScrollIsLoadingMore) {
14
10
  return;
15
- const save = () => (scrollTop.current = el.scrollTop);
16
- el.addEventListener("scroll", save);
17
- return () => el.removeEventListener("scroll", save);
18
- }, []);
19
- /* observe sentinel */
20
- useEffect(() => {
21
- if (!hasInfiniteScroll)
11
+ }
12
+ if (totalRecords !== undefined && pageLength >= totalRecords) {
22
13
  return;
23
- const observer = new IntersectionObserver(([e]) => {
24
- if (e.isIntersecting && !isLoadingMore)
25
- onNeedMore();
26
- }, { root: scrollRef.current, rootMargin: `${rootMarginPx}px` });
27
- const el = sentinelRef.current;
28
- if (el)
29
- observer.observe(el);
30
- return () => observer.disconnect();
31
- }, [hasInfiniteScroll, isLoadingMore, onNeedMore, rootMarginPx]);
32
- /* restore offset after rows change */
33
- useLayoutEffect(() => {
34
- const el = scrollRef.current;
35
- if (el)
36
- el.scrollTop = scrollTop.current;
37
- }, [rows]);
38
- return { scrollRef, sentinelRef };
39
- };
14
+ }
15
+ const lastItem = virtualItems[virtualItems.length - 1];
16
+ if (lastItem && lastItem.index >= pageLength - threshold) {
17
+ loadNextPage();
18
+ }
19
+ }, [
20
+ hasInfiniteScroll,
21
+ infiniteScrollIsLoadingMore,
22
+ virtualItems,
23
+ pageLength,
24
+ totalRecords,
25
+ loadNextPage,
26
+ threshold,
27
+ ]);
28
+ }
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@agilant/toga-blox",
3
3
  "private": false,
4
- "version": "1.0.165",
4
+ "version": "1.0.167",
5
5
  "description": "",
6
6
  "main": "dist/index.js",
7
7
  "types": "dist/index.d.ts",