@wallarm-org/design-system 0.50.1 → 0.51.0-rc-feature-AS-1026.1
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/components/Table/TableBody/TableBodyVirtualizedContainer.js +5 -2
- package/dist/components/Table/TableBody/TableBodyVirtualizedWindow.js +5 -2
- package/dist/components/Table/TableBody/useResetVirtualizerOnDataChange.d.ts +3 -3
- package/dist/components/Table/TableBody/useResetVirtualizerOnDataChange.js +8 -6
- package/dist/components/Table/TableContext/TableProvider.js +7 -1
- package/dist/components/Table/TableContext/types.d.ts +3 -0
- package/dist/components/Table/TableInner/TableInnerContainer.js +9 -4
- package/dist/components/Table/TableInner/TableInnerWindow.js +9 -4
- package/dist/components/Table/hooks/index.d.ts +1 -1
- package/dist/components/Table/hooks/index.js +2 -2
- package/dist/components/Table/hooks/infiniteScroll/index.d.ts +1 -0
- package/dist/components/Table/hooks/infiniteScroll/index.js +2 -0
- package/dist/components/Table/hooks/infiniteScroll/useInfiniteScroll.d.ts +18 -0
- package/dist/components/Table/hooks/infiniteScroll/useInfiniteScroll.js +34 -0
- package/dist/components/Table/hooks/infiniteScroll/useInitialAnchor.d.ts +16 -0
- package/dist/components/Table/hooks/infiniteScroll/useInitialAnchor.js +28 -0
- package/dist/components/Table/hooks/infiniteScroll/usePrependScrollAnchor.d.ts +15 -0
- package/dist/components/Table/hooks/infiniteScroll/usePrependScrollAnchor.js +28 -0
- package/dist/components/Table/hooks/infiniteScroll/useScrollEdge.d.ts +20 -0
- package/dist/components/Table/hooks/{useEndReached.js → infiniteScroll/useScrollEdge.js} +15 -11
- package/dist/components/Table/lib/constants.d.ts +3 -0
- package/dist/components/Table/lib/constants.js +3 -1
- package/dist/components/Table/lib/detectDataChange.d.ts +4 -0
- package/dist/components/Table/lib/detectDataChange.js +7 -0
- package/dist/components/Table/lib/getRowKey.d.ts +4 -0
- package/dist/components/Table/lib/getRowKey.js +2 -0
- package/dist/components/Table/lib/index.d.ts +3 -1
- package/dist/components/Table/lib/index.js +4 -2
- package/dist/components/Table/mocks.d.ts +13 -0
- package/dist/components/Table/mocks.js +59 -1
- package/dist/components/Table/types.d.ts +11 -1
- package/dist/metadata/components.json +12 -2
- package/package.json +1 -1
- package/dist/components/Table/hooks/useEndReached.d.ts +0 -19
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { jsx } from "react/jsx-runtime";
|
|
2
2
|
import { useCallback, useEffect } from "react";
|
|
3
3
|
import { useVirtualizer } from "@tanstack/react-virtual";
|
|
4
|
-
import { TABLE_VIRTUALIZATION_OVERSCAN } from "../lib/index.js";
|
|
4
|
+
import { TABLE_VIRTUALIZATION_OVERSCAN, getRowKey } from "../lib/index.js";
|
|
5
5
|
import { useTableContext } from "../TableContext/index.js";
|
|
6
6
|
import { TableBodyVirtualizedCore } from "./TableBodyVirtualizedCore.js";
|
|
7
7
|
import { useResetVirtualizerOnDataChange } from "./useResetVirtualizerOnDataChange.js";
|
|
@@ -15,7 +15,10 @@ const TableBodyVirtualizedContainer = ()=>{
|
|
|
15
15
|
count: table.getRowModel().rows.length,
|
|
16
16
|
getScrollElement,
|
|
17
17
|
estimateSize: estimateRowHeight ?? (()=>40),
|
|
18
|
-
overscan: overscan ?? TABLE_VIRTUALIZATION_OVERSCAN
|
|
18
|
+
overscan: overscan ?? TABLE_VIRTUALIZATION_OVERSCAN,
|
|
19
|
+
getItemKey: useCallback((index)=>getRowKey(table.getRowModel().rows, index), [
|
|
20
|
+
table
|
|
21
|
+
])
|
|
19
22
|
});
|
|
20
23
|
virtualizerRef.current = virtualizer;
|
|
21
24
|
useEffect(()=>()=>{
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { jsx } from "react/jsx-runtime";
|
|
2
2
|
import { useCallback, useEffect } from "react";
|
|
3
3
|
import { useWindowVirtualizer } from "@tanstack/react-virtual";
|
|
4
|
-
import { TABLE_VIRTUALIZATION_OVERSCAN } from "../lib/index.js";
|
|
4
|
+
import { TABLE_VIRTUALIZATION_OVERSCAN, getRowKey } from "../lib/index.js";
|
|
5
5
|
import { useTableContext } from "../TableContext/index.js";
|
|
6
6
|
import { getDocumentOffsetTop } from "./lib/getDocumentOffsetTop.js";
|
|
7
7
|
import { TableBodyVirtualizedCore } from "./TableBodyVirtualizedCore.js";
|
|
@@ -13,7 +13,10 @@ const TableBodyVirtualizedWindow = ()=>{
|
|
|
13
13
|
count: table.getRowModel().rows.length,
|
|
14
14
|
estimateSize: estimateRowHeight ?? (()=>40),
|
|
15
15
|
overscan: overscan ?? TABLE_VIRTUALIZATION_OVERSCAN,
|
|
16
|
-
scrollMargin: tbodyRef.current ? getDocumentOffsetTop(tbodyRef.current) : 0
|
|
16
|
+
scrollMargin: tbodyRef.current ? getDocumentOffsetTop(tbodyRef.current) : 0,
|
|
17
|
+
getItemKey: useCallback((index)=>getRowKey(table.getRowModel().rows, index), [
|
|
18
|
+
table
|
|
19
|
+
])
|
|
17
20
|
});
|
|
18
21
|
virtualizerRef.current = virtualizer;
|
|
19
22
|
useEffect(()=>()=>{
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import type { Table } from '@tanstack/react-table';
|
|
2
2
|
import type { Virtualizer } from '@tanstack/react-virtual';
|
|
3
3
|
/**
|
|
4
|
-
* Reset cached measurements
|
|
5
|
-
*
|
|
6
|
-
*
|
|
4
|
+
* Reset cached measurements only on a full dataset replacement. On a prepend
|
|
5
|
+
* (infinite scroll up) measurements are kept — usePrependScrollAnchor handles
|
|
6
|
+
* the position — so the virtualizer does not re-measure and jump.
|
|
7
7
|
*/
|
|
8
8
|
export declare const useResetVirtualizerOnDataChange: (table: Table<unknown>, virtualizer: Virtualizer<Element, Element> | Virtualizer<Window, Element> | Virtualizer<HTMLElement, Element>) => void;
|
|
@@ -1,15 +1,17 @@
|
|
|
1
1
|
import { useEffect, useRef } from "react";
|
|
2
|
+
import { detectDataChange } from "../lib/index.js";
|
|
2
3
|
const useResetVirtualizerOnDataChange = (table, virtualizer)=>{
|
|
3
|
-
const
|
|
4
|
-
const firstRowId = rows[0]?.id;
|
|
4
|
+
const firstRowId = table.getRowModel().rows[0]?.id;
|
|
5
5
|
const prevFirstRowIdRef = useRef(firstRowId);
|
|
6
6
|
useEffect(()=>{
|
|
7
|
-
if (prevFirstRowIdRef.current
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
7
|
+
if (prevFirstRowIdRef.current === firstRowId) return;
|
|
8
|
+
const rows = table.getRowModel().rows;
|
|
9
|
+
const change = detectDataChange(prevFirstRowIdRef.current, rows);
|
|
10
|
+
prevFirstRowIdRef.current = firstRowId;
|
|
11
|
+
if ('replace' === change) virtualizer.measure();
|
|
11
12
|
}, [
|
|
12
13
|
firstRowId,
|
|
14
|
+
table,
|
|
13
15
|
virtualizer
|
|
14
16
|
]);
|
|
15
17
|
};
|
|
@@ -8,7 +8,7 @@ import { useTableState } from "../hooks/index.js";
|
|
|
8
8
|
import { TABLE_EXPAND_COLUMN_ID, TABLE_MIN_COLUMN_WIDTH, TABLE_SELECT_COLUMN_ID, TABLE_SKELETON_ROWS, TABLE_VIRTUALIZATION_OVERSCAN, createExpandColumn, createSelectionColumn } from "../lib/index.js";
|
|
9
9
|
import { TableContext } from "./TableContext.js";
|
|
10
10
|
const TableProvider = (props)=>{
|
|
11
|
-
const { data, columns, isLoading = false, skeletonCount = TABLE_SKELETON_ROWS, children, getRowId, sorting: sortingProp, onSortingChange, manualSorting = false, rowSelection: rowSelectionProp, onRowSelectionChange, columnSizing: columnSizingProp, onColumnSizingChange, columnPinning: columnPinningProp, onColumnPinningChange, columnOrder: columnOrderProp, onColumnOrderChange, grouping: groupingProp, onGroupingChange, expanded: expandedProp, onExpandedChange, renderGroupRow, getSubRows, renderExpandedRow, columnVisibility: columnVisibilityProp, onColumnVisibilityChange, defaultColumnVisibility, defaultColumnOrder, virtualized, estimateRowHeight, overscan = TABLE_VIRTUALIZATION_OVERSCAN, onEndReached, onEndReachedThreshold, onMasterCellClick, activeRowId: activeRowIdProp } = props;
|
|
11
|
+
const { data, columns, isLoading = false, skeletonCount = TABLE_SKELETON_ROWS, children, getRowId, sorting: sortingProp, onSortingChange, manualSorting = false, rowSelection: rowSelectionProp, onRowSelectionChange, columnSizing: columnSizingProp, onColumnSizingChange, columnPinning: columnPinningProp, onColumnPinningChange, columnOrder: columnOrderProp, onColumnOrderChange, grouping: groupingProp, onGroupingChange, expanded: expandedProp, onExpandedChange, renderGroupRow, getSubRows, renderExpandedRow, columnVisibility: columnVisibilityProp, onColumnVisibilityChange, defaultColumnVisibility, defaultColumnOrder, virtualized, estimateRowHeight, overscan = TABLE_VIRTUALIZATION_OVERSCAN, onEndReached, onEndReachedThreshold, onStartReached, onStartReachedThreshold, initialScrollToRowId, onMasterCellClick, activeRowId: activeRowIdProp } = props;
|
|
12
12
|
const masterCellActiveRowId = activeRowIdProp ?? null;
|
|
13
13
|
const sortingEnabled = !!onSortingChange;
|
|
14
14
|
const selectionEnabled = !!onRowSelectionChange;
|
|
@@ -215,6 +215,9 @@ const TableProvider = (props)=>{
|
|
|
215
215
|
virtualizerRef,
|
|
216
216
|
onEndReached,
|
|
217
217
|
onEndReachedThreshold,
|
|
218
|
+
onStartReached,
|
|
219
|
+
onStartReachedThreshold,
|
|
220
|
+
initialScrollToRowId,
|
|
218
221
|
onMasterCellClick,
|
|
219
222
|
activeRowId: masterCellActiveRowId
|
|
220
223
|
}), [
|
|
@@ -241,6 +244,9 @@ const TableProvider = (props)=>{
|
|
|
241
244
|
masterColumnId,
|
|
242
245
|
onEndReached,
|
|
243
246
|
onEndReachedThreshold,
|
|
247
|
+
onStartReached,
|
|
248
|
+
onStartReachedThreshold,
|
|
249
|
+
initialScrollToRowId,
|
|
244
250
|
masterCellActiveRowId,
|
|
245
251
|
onMasterCellClick
|
|
246
252
|
]);
|
|
@@ -37,6 +37,9 @@ export interface TableContextValue<T> {
|
|
|
37
37
|
virtualizerRef: RefObject<TableVirtualizerInstance | null>;
|
|
38
38
|
onEndReached?: () => void;
|
|
39
39
|
onEndReachedThreshold?: number;
|
|
40
|
+
onStartReached?: () => void;
|
|
41
|
+
onStartReachedThreshold?: number;
|
|
42
|
+
initialScrollToRowId?: string;
|
|
40
43
|
onMasterCellClick?: (rowId: string) => void;
|
|
41
44
|
activeRowId: string | null;
|
|
42
45
|
}
|
|
@@ -4,7 +4,7 @@ import { cn } from "../../../utils/cn.js";
|
|
|
4
4
|
import { useTestId } from "../../../utils/testId.js";
|
|
5
5
|
import { ScrollArea, ScrollAreaCorner, ScrollAreaScrollbar, ScrollAreaViewport } from "../../ScrollArea/index.js";
|
|
6
6
|
import { tableContainerVariants } from "../classes.js";
|
|
7
|
-
import {
|
|
7
|
+
import { useInfiniteScroll } from "../hooks/index.js";
|
|
8
8
|
import { useContainerWidth } from "../lib/index.js";
|
|
9
9
|
import { TableBody } from "../TableBody/index.js";
|
|
10
10
|
import { TableColGroup } from "../TableColGroup.js";
|
|
@@ -12,15 +12,20 @@ import { useTableContext } from "../TableContext/index.js";
|
|
|
12
12
|
import { TableHead } from "../TableHead.js";
|
|
13
13
|
import { TableSettingsMenu } from "../TableSettingsMenu/index.js";
|
|
14
14
|
const TableInnerContainer = ({ isEmpty, virtualized, showSettings, ariaLabel, children })=>{
|
|
15
|
-
const { containerRef, table, onEndReached, onEndReachedThreshold } = useTableContext();
|
|
15
|
+
const { containerRef, table, virtualizerRef, onEndReached, onEndReachedThreshold, onStartReached, onStartReachedThreshold, initialScrollToRowId } = useTableContext();
|
|
16
16
|
const testId = useTestId('container');
|
|
17
17
|
const scrollRootRef = useRef(null);
|
|
18
18
|
const containerWidth = useContainerWidth(containerRef);
|
|
19
|
-
|
|
19
|
+
useInfiniteScroll({
|
|
20
20
|
mode: 'container',
|
|
21
21
|
scrollRef: containerRef,
|
|
22
|
+
table,
|
|
23
|
+
virtualizerRef,
|
|
22
24
|
onEndReached,
|
|
23
|
-
|
|
25
|
+
onEndReachedThreshold,
|
|
26
|
+
onStartReached,
|
|
27
|
+
onStartReachedThreshold,
|
|
28
|
+
initialScrollToRowId
|
|
24
29
|
});
|
|
25
30
|
useEffect(()=>{
|
|
26
31
|
const viewport = containerRef.current;
|
|
@@ -2,7 +2,7 @@ import { jsx, jsxs } from "react/jsx-runtime";
|
|
|
2
2
|
import { useEffect, useRef } from "react";
|
|
3
3
|
import { useTestId } from "../../../utils/testId.js";
|
|
4
4
|
import { ScrollArea, ScrollAreaScrollbar, ScrollAreaViewport } from "../../ScrollArea/index.js";
|
|
5
|
-
import {
|
|
5
|
+
import { useInfiniteScroll } from "../hooks/index.js";
|
|
6
6
|
import { useContainerWidth } from "../lib/index.js";
|
|
7
7
|
import { TableBody } from "../TableBody/index.js";
|
|
8
8
|
import { TableColGroup } from "../TableColGroup.js";
|
|
@@ -10,15 +10,20 @@ import { useTableContext } from "../TableContext/index.js";
|
|
|
10
10
|
import { TableHead } from "../TableHead.js";
|
|
11
11
|
import { TableSettingsMenu } from "../TableSettingsMenu/index.js";
|
|
12
12
|
const TableInnerWindow = ({ isEmpty, showSettings, ariaLabel, children })=>{
|
|
13
|
-
const { table, onEndReached, onEndReachedThreshold } = useTableContext();
|
|
13
|
+
const { table, virtualizerRef, onEndReached, onEndReachedThreshold, onStartReached, onStartReachedThreshold, initialScrollToRowId } = useTableContext();
|
|
14
14
|
const testId = useTestId('window');
|
|
15
15
|
const rootRef = useRef(null);
|
|
16
16
|
const scrollRef = useRef(null);
|
|
17
17
|
const containerWidth = useContainerWidth(rootRef);
|
|
18
|
-
|
|
18
|
+
useInfiniteScroll({
|
|
19
19
|
mode: 'window',
|
|
20
|
+
table,
|
|
21
|
+
virtualizerRef,
|
|
20
22
|
onEndReached,
|
|
21
|
-
|
|
23
|
+
onEndReachedThreshold,
|
|
24
|
+
onStartReached,
|
|
25
|
+
onStartReachedThreshold,
|
|
26
|
+
initialScrollToRowId
|
|
22
27
|
});
|
|
23
28
|
useEffect(()=>{
|
|
24
29
|
const scrollEl = scrollRef.current;
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
export {
|
|
1
|
+
export { useInfiniteScroll } from './infiniteScroll';
|
|
2
2
|
export { useHorizontalScrollState } from './useHorizontalScrollState';
|
|
3
3
|
export { useMasterCell } from './useMasterCell';
|
|
4
4
|
export { useTableState } from './useTableState';
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { useInfiniteScroll } from "./infiniteScroll/index.js";
|
|
2
2
|
import { useHorizontalScrollState } from "./useHorizontalScrollState.js";
|
|
3
3
|
import { useMasterCell } from "./useMasterCell.js";
|
|
4
4
|
import { useTableState } from "./useTableState.js";
|
|
5
|
-
export {
|
|
5
|
+
export { useHorizontalScrollState, useInfiniteScroll, useMasterCell, useTableState };
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { useInfiniteScroll } from './useInfiniteScroll';
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import type { RefObject } from 'react';
|
|
2
|
+
import type { Table } from '@tanstack/react-table';
|
|
3
|
+
import type { TableVirtualizerInstance } from '../../TableContext/types';
|
|
4
|
+
interface UseInfiniteScrollOptions<T> {
|
|
5
|
+
mode: 'container' | 'window';
|
|
6
|
+
/** Scroll element ref — required for `container` mode */
|
|
7
|
+
scrollRef?: RefObject<HTMLElement | null>;
|
|
8
|
+
table: Table<T>;
|
|
9
|
+
virtualizerRef: RefObject<TableVirtualizerInstance | null>;
|
|
10
|
+
onStartReached?: () => void;
|
|
11
|
+
onStartReachedThreshold?: number;
|
|
12
|
+
onEndReached?: () => void;
|
|
13
|
+
onEndReachedThreshold?: number;
|
|
14
|
+
initialScrollToRowId?: string;
|
|
15
|
+
}
|
|
16
|
+
/** Single entry point for bidirectional infinite scroll behavior. */
|
|
17
|
+
export declare const useInfiniteScroll: <T>({ mode, scrollRef, table, virtualizerRef, onStartReached, onStartReachedThreshold, onEndReached, onEndReachedThreshold, initialScrollToRowId, }: UseInfiniteScrollOptions<T>) => void;
|
|
18
|
+
export {};
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import { TABLE_END_REACHED_THRESHOLD, TABLE_START_REACHED_THRESHOLD } from "../../lib/index.js";
|
|
2
|
+
import { useInitialAnchor } from "./useInitialAnchor.js";
|
|
3
|
+
import { usePrependScrollAnchor } from "./usePrependScrollAnchor.js";
|
|
4
|
+
import { useScrollEdge } from "./useScrollEdge.js";
|
|
5
|
+
const useInfiniteScroll = ({ mode, scrollRef, table, virtualizerRef, onStartReached, onStartReachedThreshold, onEndReached, onEndReachedThreshold, initialScrollToRowId })=>{
|
|
6
|
+
const rows = table.getRowModel().rows;
|
|
7
|
+
const ready = useInitialAnchor({
|
|
8
|
+
initialScrollToRowId,
|
|
9
|
+
rows,
|
|
10
|
+
virtualizerRef
|
|
11
|
+
});
|
|
12
|
+
usePrependScrollAnchor({
|
|
13
|
+
mode,
|
|
14
|
+
scrollRef,
|
|
15
|
+
rows
|
|
16
|
+
});
|
|
17
|
+
useScrollEdge({
|
|
18
|
+
edge: 'start',
|
|
19
|
+
mode,
|
|
20
|
+
scrollRef,
|
|
21
|
+
onReached: onStartReached,
|
|
22
|
+
threshold: onStartReachedThreshold ?? TABLE_START_REACHED_THRESHOLD,
|
|
23
|
+
enabled: ready
|
|
24
|
+
});
|
|
25
|
+
useScrollEdge({
|
|
26
|
+
edge: 'end',
|
|
27
|
+
mode,
|
|
28
|
+
scrollRef,
|
|
29
|
+
onReached: onEndReached,
|
|
30
|
+
threshold: onEndReachedThreshold ?? TABLE_END_REACHED_THRESHOLD,
|
|
31
|
+
enabled: ready
|
|
32
|
+
});
|
|
33
|
+
};
|
|
34
|
+
export { useInfiniteScroll };
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { type RefObject } from 'react';
|
|
2
|
+
import type { TableVirtualizerInstance } from '../../TableContext/types';
|
|
3
|
+
interface UseInitialAnchorOptions {
|
|
4
|
+
initialScrollToRowId?: string;
|
|
5
|
+
rows: {
|
|
6
|
+
id: string;
|
|
7
|
+
}[];
|
|
8
|
+
virtualizerRef: RefObject<TableVirtualizerInstance | null>;
|
|
9
|
+
}
|
|
10
|
+
/**
|
|
11
|
+
* Scrolls to the anchor row once on mount and returns `ready`, which gates the
|
|
12
|
+
* edge detectors until the initial scroll has settled. Without this, a table
|
|
13
|
+
* mounted at scrollTop 0 would fire `onStartReached` immediately.
|
|
14
|
+
*/
|
|
15
|
+
export declare const useInitialAnchor: ({ initialScrollToRowId, rows, virtualizerRef, }: UseInitialAnchorOptions) => boolean;
|
|
16
|
+
export {};
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import { useEffect, useRef, useState } from "react";
|
|
2
|
+
const useInitialAnchor = ({ initialScrollToRowId, rows, virtualizerRef })=>{
|
|
3
|
+
const [ready, setReady] = useState(!initialScrollToRowId);
|
|
4
|
+
const doneRef = useRef(false);
|
|
5
|
+
useEffect(()=>{
|
|
6
|
+
if (doneRef.current || !initialScrollToRowId) return;
|
|
7
|
+
const virtualizer = virtualizerRef.current;
|
|
8
|
+
if (!virtualizer) {
|
|
9
|
+
doneRef.current = true;
|
|
10
|
+
setReady(true);
|
|
11
|
+
return;
|
|
12
|
+
}
|
|
13
|
+
const index = rows.findIndex((r)=>r.id === initialScrollToRowId);
|
|
14
|
+
if (index < 0) return;
|
|
15
|
+
virtualizer.scrollToIndex(index, {
|
|
16
|
+
align: 'center'
|
|
17
|
+
});
|
|
18
|
+
doneRef.current = true;
|
|
19
|
+
const raf = requestAnimationFrame(()=>setReady(true));
|
|
20
|
+
return ()=>cancelAnimationFrame(raf);
|
|
21
|
+
}, [
|
|
22
|
+
initialScrollToRowId,
|
|
23
|
+
rows,
|
|
24
|
+
virtualizerRef
|
|
25
|
+
]);
|
|
26
|
+
return ready;
|
|
27
|
+
};
|
|
28
|
+
export { useInitialAnchor };
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { type RefObject } from 'react';
|
|
2
|
+
interface UsePrependScrollAnchorOptions {
|
|
3
|
+
mode: 'container' | 'window';
|
|
4
|
+
scrollRef?: RefObject<HTMLElement | null>;
|
|
5
|
+
rows: {
|
|
6
|
+
id: string;
|
|
7
|
+
}[];
|
|
8
|
+
}
|
|
9
|
+
/**
|
|
10
|
+
* Keeps the viewport visually stable when rows are prepended: measures the
|
|
11
|
+
* scrollHeight delta and adds it to scrollTop. Runs in a layout effect so the
|
|
12
|
+
* adjustment lands before paint (no flicker).
|
|
13
|
+
*/
|
|
14
|
+
export declare const usePrependScrollAnchor: ({ mode, scrollRef, rows, }: UsePrependScrollAnchorOptions) => void;
|
|
15
|
+
export {};
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import { useLayoutEffect, useRef } from "react";
|
|
2
|
+
import { detectDataChange } from "../../lib/index.js";
|
|
3
|
+
const usePrependScrollAnchor = ({ mode, scrollRef, rows })=>{
|
|
4
|
+
const prevFirstRowIdRef = useRef(rows[0]?.id);
|
|
5
|
+
const prevScrollHeightRef = useRef(null);
|
|
6
|
+
useLayoutEffect(()=>{
|
|
7
|
+
const getScrollHeight = ()=>'window' === mode ? document.documentElement.scrollHeight : scrollRef?.current?.scrollHeight ?? 0;
|
|
8
|
+
if (null === prevScrollHeightRef.current) {
|
|
9
|
+
prevScrollHeightRef.current = getScrollHeight();
|
|
10
|
+
prevFirstRowIdRef.current = rows[0]?.id;
|
|
11
|
+
return;
|
|
12
|
+
}
|
|
13
|
+
if ('prepend' === detectDataChange(prevFirstRowIdRef.current, rows)) {
|
|
14
|
+
const delta = getScrollHeight() - prevScrollHeightRef.current;
|
|
15
|
+
if (delta > 0) {
|
|
16
|
+
if ('window' === mode) window.scrollBy(0, delta);
|
|
17
|
+
else if (scrollRef?.current) scrollRef.current.scrollTop += delta;
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
prevFirstRowIdRef.current = rows[0]?.id;
|
|
21
|
+
prevScrollHeightRef.current = getScrollHeight();
|
|
22
|
+
}, [
|
|
23
|
+
rows,
|
|
24
|
+
mode,
|
|
25
|
+
scrollRef
|
|
26
|
+
]);
|
|
27
|
+
};
|
|
28
|
+
export { usePrependScrollAnchor };
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { type RefObject } from 'react';
|
|
2
|
+
type ScrollMode = 'container' | 'window';
|
|
3
|
+
type ScrollEdge = 'start' | 'end';
|
|
4
|
+
interface UseScrollEdgeOptions {
|
|
5
|
+
edge: ScrollEdge;
|
|
6
|
+
mode: ScrollMode;
|
|
7
|
+
/** Scroll element ref — required for `container` mode */
|
|
8
|
+
scrollRef?: RefObject<HTMLElement | null>;
|
|
9
|
+
onReached?: () => void;
|
|
10
|
+
threshold: number;
|
|
11
|
+
/** When false, suppresses firing (e.g. while the initial anchor scroll settles) */
|
|
12
|
+
enabled?: boolean;
|
|
13
|
+
}
|
|
14
|
+
/**
|
|
15
|
+
* Fires `onReached` once when the user scrolls within `threshold` px of the
|
|
16
|
+
* given edge. Re-arms after scrolling back past the threshold. A cooldown
|
|
17
|
+
* guard prevents rapid re-fires when prepended/appended rows grow the content.
|
|
18
|
+
*/
|
|
19
|
+
export declare const useScrollEdge: ({ edge, mode, scrollRef, onReached, threshold, enabled, }: UseScrollEdgeOptions) => void;
|
|
20
|
+
export {};
|
|
@@ -1,17 +1,20 @@
|
|
|
1
1
|
import { useEffect, useRef } from "react";
|
|
2
|
-
import {
|
|
3
|
-
const
|
|
4
|
-
const useEndReached = ({ mode, scrollRef, onEndReached, threshold = TABLE_END_REACHED_THRESHOLD })=>{
|
|
2
|
+
import { SCROLL_EDGE_COOLDOWN_MS } from "../../lib/index.js";
|
|
3
|
+
const useScrollEdge = ({ edge, mode, scrollRef, onReached, threshold, enabled = true })=>{
|
|
5
4
|
const firedRef = useRef(false);
|
|
6
5
|
const lastFiredAtRef = useRef(0);
|
|
7
|
-
const
|
|
6
|
+
const onReachedRef = useRef(onReached);
|
|
8
7
|
useEffect(()=>{
|
|
9
|
-
|
|
8
|
+
onReachedRef.current = onReached;
|
|
9
|
+
});
|
|
10
|
+
const enabledRef = useRef(enabled);
|
|
11
|
+
useEffect(()=>{
|
|
12
|
+
enabledRef.current = enabled;
|
|
10
13
|
});
|
|
11
14
|
useEffect(()=>{
|
|
12
15
|
const check = ()=>{
|
|
13
|
-
const callback =
|
|
14
|
-
if (!callback) return;
|
|
16
|
+
const callback = onReachedRef.current;
|
|
17
|
+
if (!callback || !enabledRef.current) return;
|
|
15
18
|
let scrollTop;
|
|
16
19
|
let clientHeight;
|
|
17
20
|
let scrollHeight;
|
|
@@ -26,10 +29,10 @@ const useEndReached = ({ mode, scrollRef, onEndReached, threshold = TABLE_END_RE
|
|
|
26
29
|
clientHeight = el.clientHeight;
|
|
27
30
|
scrollHeight = el.scrollHeight;
|
|
28
31
|
}
|
|
29
|
-
const
|
|
30
|
-
if (
|
|
32
|
+
const distance = 'start' === edge ? scrollTop : scrollHeight - scrollTop - clientHeight;
|
|
33
|
+
if (distance <= threshold) {
|
|
31
34
|
const now = Date.now();
|
|
32
|
-
if (!firedRef.current && now - lastFiredAtRef.current >=
|
|
35
|
+
if (!firedRef.current && now - lastFiredAtRef.current >= SCROLL_EDGE_COOLDOWN_MS) {
|
|
33
36
|
firedRef.current = true;
|
|
34
37
|
lastFiredAtRef.current = now;
|
|
35
38
|
callback();
|
|
@@ -46,9 +49,10 @@ const useEndReached = ({ mode, scrollRef, onEndReached, threshold = TABLE_END_RE
|
|
|
46
49
|
target.removeEventListener('scroll', check);
|
|
47
50
|
};
|
|
48
51
|
}, [
|
|
52
|
+
edge,
|
|
49
53
|
mode,
|
|
50
54
|
scrollRef,
|
|
51
55
|
threshold
|
|
52
56
|
]);
|
|
53
57
|
};
|
|
54
|
-
export {
|
|
58
|
+
export { useScrollEdge };
|
|
@@ -6,6 +6,9 @@ export declare const TABLE_SELECT_COLUMN_WIDTH = 33;
|
|
|
6
6
|
export declare const TABLE_EXPAND_COLUMN_ID = "_expand";
|
|
7
7
|
export declare const TABLE_EXPAND_COLUMN_WIDTH = 33;
|
|
8
8
|
export declare const TABLE_END_REACHED_THRESHOLD = 200;
|
|
9
|
+
export declare const TABLE_START_REACHED_THRESHOLD = 200;
|
|
10
|
+
/** Minimum time (ms) between successive edge-reached callbacks. */
|
|
11
|
+
export declare const SCROLL_EDGE_COOLDOWN_MS = 200;
|
|
9
12
|
/** Resolve text-align class from column meta */
|
|
10
13
|
export declare const getAlignClass: (meta?: {
|
|
11
14
|
align?: string;
|
|
@@ -6,6 +6,8 @@ const TABLE_SELECT_COLUMN_WIDTH = 33;
|
|
|
6
6
|
const TABLE_EXPAND_COLUMN_ID = '_expand';
|
|
7
7
|
const TABLE_EXPAND_COLUMN_WIDTH = 33;
|
|
8
8
|
const TABLE_END_REACHED_THRESHOLD = 200;
|
|
9
|
+
const TABLE_START_REACHED_THRESHOLD = 200;
|
|
10
|
+
const SCROLL_EDGE_COOLDOWN_MS = 200;
|
|
9
11
|
const RIGHT_ALIGNED_SORT_TYPES = new Set([
|
|
10
12
|
'number',
|
|
11
13
|
'score',
|
|
@@ -56,4 +58,4 @@ const SORT_LABELS = {
|
|
|
56
58
|
'Smallest on top'
|
|
57
59
|
]
|
|
58
60
|
};
|
|
59
|
-
export { SORT_LABELS, TABLE_END_REACHED_THRESHOLD, TABLE_EXPAND_COLUMN_ID, TABLE_EXPAND_COLUMN_WIDTH, TABLE_MIN_COLUMN_WIDTH, TABLE_SELECT_COLUMN_ID, TABLE_SELECT_COLUMN_WIDTH, TABLE_SKELETON_ROWS, TABLE_VIRTUALIZATION_OVERSCAN, getAlignClass, getExpandBorderClass };
|
|
61
|
+
export { SCROLL_EDGE_COOLDOWN_MS, SORT_LABELS, TABLE_END_REACHED_THRESHOLD, TABLE_EXPAND_COLUMN_ID, TABLE_EXPAND_COLUMN_WIDTH, TABLE_MIN_COLUMN_WIDTH, TABLE_SELECT_COLUMN_ID, TABLE_SELECT_COLUMN_WIDTH, TABLE_SKELETON_ROWS, TABLE_START_REACHED_THRESHOLD, TABLE_VIRTUALIZATION_OVERSCAN, getAlignClass, getExpandBorderClass };
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
const detectDataChange = (prevFirstRowId, rows)=>{
|
|
2
|
+
const currentFirstId = rows[0]?.id;
|
|
3
|
+
if (void 0 === prevFirstRowId) return 'none';
|
|
4
|
+
if (currentFirstId === prevFirstRowId) return 'none';
|
|
5
|
+
return rows.some((r)=>r.id === prevFirstRowId) ? 'prepend' : 'replace';
|
|
6
|
+
};
|
|
7
|
+
export { detectDataChange };
|
|
@@ -1,9 +1,11 @@
|
|
|
1
|
-
export { getAlignClass, getExpandBorderClass, SORT_LABELS, TABLE_END_REACHED_THRESHOLD, TABLE_EXPAND_COLUMN_ID, TABLE_EXPAND_COLUMN_WIDTH, TABLE_MIN_COLUMN_WIDTH, TABLE_SELECT_COLUMN_ID, TABLE_SELECT_COLUMN_WIDTH, TABLE_SKELETON_ROWS, TABLE_VIRTUALIZATION_OVERSCAN, } from './constants';
|
|
1
|
+
export { getAlignClass, getExpandBorderClass, SCROLL_EDGE_COOLDOWN_MS, SORT_LABELS, TABLE_END_REACHED_THRESHOLD, TABLE_EXPAND_COLUMN_ID, TABLE_EXPAND_COLUMN_WIDTH, TABLE_MIN_COLUMN_WIDTH, TABLE_SELECT_COLUMN_ID, TABLE_SELECT_COLUMN_WIDTH, TABLE_SKELETON_ROWS, TABLE_START_REACHED_THRESHOLD, TABLE_VIRTUALIZATION_OVERSCAN, } from './constants';
|
|
2
2
|
export { createExpandColumn } from './createExpandColumn';
|
|
3
3
|
export { createSelectionColumn } from './createSelectionColumn';
|
|
4
4
|
export { createTableColumnHelper } from './createTableColumnHelper';
|
|
5
|
+
export { detectDataChange } from './detectDataChange';
|
|
5
6
|
export { getDndStyles } from './getDndStyles';
|
|
6
7
|
export { getPinningStyles } from './getPinningStyles';
|
|
8
|
+
export { getRowKey } from './getRowKey';
|
|
7
9
|
export { isLastPinnedLeft } from './isLastPinnedLeft';
|
|
8
10
|
export { useColumnDnd } from './useColumnDnd';
|
|
9
11
|
export { useContainerWidth } from './useContainerWidth';
|
|
@@ -1,10 +1,12 @@
|
|
|
1
|
-
import { SORT_LABELS, TABLE_END_REACHED_THRESHOLD, TABLE_EXPAND_COLUMN_ID, TABLE_EXPAND_COLUMN_WIDTH, TABLE_MIN_COLUMN_WIDTH, TABLE_SELECT_COLUMN_ID, TABLE_SELECT_COLUMN_WIDTH, TABLE_SKELETON_ROWS, TABLE_VIRTUALIZATION_OVERSCAN, getAlignClass, getExpandBorderClass } from "./constants.js";
|
|
1
|
+
import { SCROLL_EDGE_COOLDOWN_MS, SORT_LABELS, TABLE_END_REACHED_THRESHOLD, TABLE_EXPAND_COLUMN_ID, TABLE_EXPAND_COLUMN_WIDTH, TABLE_MIN_COLUMN_WIDTH, TABLE_SELECT_COLUMN_ID, TABLE_SELECT_COLUMN_WIDTH, TABLE_SKELETON_ROWS, TABLE_START_REACHED_THRESHOLD, TABLE_VIRTUALIZATION_OVERSCAN, getAlignClass, getExpandBorderClass } from "./constants.js";
|
|
2
2
|
import { createExpandColumn } from "./createExpandColumn.js";
|
|
3
3
|
import { createSelectionColumn } from "./createSelectionColumn.js";
|
|
4
4
|
import { createTableColumnHelper } from "./createTableColumnHelper.js";
|
|
5
|
+
import { detectDataChange } from "./detectDataChange.js";
|
|
5
6
|
import { getDndStyles } from "./getDndStyles.js";
|
|
6
7
|
import { getPinningStyles } from "./getPinningStyles.js";
|
|
8
|
+
import { getRowKey } from "./getRowKey.js";
|
|
7
9
|
import { isLastPinnedLeft } from "./isLastPinnedLeft.js";
|
|
8
10
|
import { useColumnDnd } from "./useColumnDnd.js";
|
|
9
11
|
import { useContainerWidth } from "./useContainerWidth.js";
|
|
10
|
-
export { SORT_LABELS, TABLE_END_REACHED_THRESHOLD, TABLE_EXPAND_COLUMN_ID, TABLE_EXPAND_COLUMN_WIDTH, TABLE_MIN_COLUMN_WIDTH, TABLE_SELECT_COLUMN_ID, TABLE_SELECT_COLUMN_WIDTH, TABLE_SKELETON_ROWS, TABLE_VIRTUALIZATION_OVERSCAN, createExpandColumn, createSelectionColumn, createTableColumnHelper, getAlignClass, getDndStyles, getExpandBorderClass, getPinningStyles, isLastPinnedLeft, useColumnDnd, useContainerWidth };
|
|
12
|
+
export { SCROLL_EDGE_COOLDOWN_MS, SORT_LABELS, TABLE_END_REACHED_THRESHOLD, TABLE_EXPAND_COLUMN_ID, TABLE_EXPAND_COLUMN_WIDTH, TABLE_MIN_COLUMN_WIDTH, TABLE_SELECT_COLUMN_ID, TABLE_SELECT_COLUMN_WIDTH, TABLE_SKELETON_ROWS, TABLE_START_REACHED_THRESHOLD, TABLE_VIRTUALIZATION_OVERSCAN, createExpandColumn, createSelectionColumn, createTableColumnHelper, detectDataChange, getAlignClass, getDndStyles, getExpandBorderClass, getPinningStyles, getRowKey, isLastPinnedLeft, useColumnDnd, useContainerWidth };
|
|
@@ -59,3 +59,16 @@ export declare const useInfiniteData: () => {
|
|
|
59
59
|
totalItems: number;
|
|
60
60
|
fetchNextPage: () => void;
|
|
61
61
|
};
|
|
62
|
+
/**
|
|
63
|
+
* Mock for bidirectional infinite scroll: opens a window around an anchor row
|
|
64
|
+
* and exposes cursor-style fetchers for both directions.
|
|
65
|
+
*/
|
|
66
|
+
export declare const useBidirectionalData: () => {
|
|
67
|
+
data: SecurityEvent[];
|
|
68
|
+
anchorId: string | undefined;
|
|
69
|
+
isFetching: boolean;
|
|
70
|
+
hasPrev: boolean;
|
|
71
|
+
hasNext: boolean;
|
|
72
|
+
fetchPrevPage: () => void;
|
|
73
|
+
fetchNextPage: () => void;
|
|
74
|
+
};
|
|
@@ -953,6 +953,9 @@ const fullFeaturedColumns = headerColumns.map((col)=>{
|
|
|
953
953
|
});
|
|
954
954
|
const INFINITE_PAGE_SIZE = 50;
|
|
955
955
|
const INFINITE_MAX_ITEMS = 500;
|
|
956
|
+
const BIDIRECTIONAL_TOTAL = 500;
|
|
957
|
+
const BIDIRECTIONAL_PAGE_SIZE = 50;
|
|
958
|
+
const BIDIRECTIONAL_INITIAL_ANCHOR_INDEX = 250;
|
|
956
959
|
const useInfiniteData = ()=>{
|
|
957
960
|
const allData = useMemo(()=>createLargeSecurityEvents(INFINITE_MAX_ITEMS), []);
|
|
958
961
|
const [data, setData] = useState(()=>allData.slice(0, INFINITE_PAGE_SIZE));
|
|
@@ -978,4 +981,59 @@ const useInfiniteData = ()=>{
|
|
|
978
981
|
fetchNextPage
|
|
979
982
|
};
|
|
980
983
|
};
|
|
981
|
-
|
|
984
|
+
const useBidirectionalData = ()=>{
|
|
985
|
+
const allData = useMemo(()=>createLargeSecurityEvents(BIDIRECTIONAL_TOTAL), []);
|
|
986
|
+
const initialStart = Math.max(0, BIDIRECTIONAL_INITIAL_ANCHOR_INDEX - BIDIRECTIONAL_PAGE_SIZE);
|
|
987
|
+
const initialEnd = Math.min(allData.length, BIDIRECTIONAL_INITIAL_ANCHOR_INDEX + BIDIRECTIONAL_PAGE_SIZE);
|
|
988
|
+
const [range, setRange] = useState({
|
|
989
|
+
start: initialStart,
|
|
990
|
+
end: initialEnd
|
|
991
|
+
});
|
|
992
|
+
const [isFetching, setIsFetching] = useState(false);
|
|
993
|
+
const data = useMemo(()=>allData.slice(range.start, range.end), [
|
|
994
|
+
allData,
|
|
995
|
+
range
|
|
996
|
+
]);
|
|
997
|
+
const anchorId = allData[BIDIRECTIONAL_INITIAL_ANCHOR_INDEX]?.id;
|
|
998
|
+
const hasPrev = range.start > 0;
|
|
999
|
+
const hasNext = range.end < allData.length;
|
|
1000
|
+
const fetchPrevPage = useCallback(()=>{
|
|
1001
|
+
if (isFetching || range.start <= 0) return;
|
|
1002
|
+
setIsFetching(true);
|
|
1003
|
+
setTimeout(()=>{
|
|
1004
|
+
setRange((prev)=>({
|
|
1005
|
+
...prev,
|
|
1006
|
+
start: Math.max(0, prev.start - BIDIRECTIONAL_PAGE_SIZE)
|
|
1007
|
+
}));
|
|
1008
|
+
setIsFetching(false);
|
|
1009
|
+
}, 400);
|
|
1010
|
+
}, [
|
|
1011
|
+
isFetching,
|
|
1012
|
+
range.start
|
|
1013
|
+
]);
|
|
1014
|
+
const fetchNextPage = useCallback(()=>{
|
|
1015
|
+
if (isFetching || range.end >= allData.length) return;
|
|
1016
|
+
setIsFetching(true);
|
|
1017
|
+
setTimeout(()=>{
|
|
1018
|
+
setRange((prev)=>({
|
|
1019
|
+
...prev,
|
|
1020
|
+
end: Math.min(allData.length, prev.end + BIDIRECTIONAL_PAGE_SIZE)
|
|
1021
|
+
}));
|
|
1022
|
+
setIsFetching(false);
|
|
1023
|
+
}, 400);
|
|
1024
|
+
}, [
|
|
1025
|
+
isFetching,
|
|
1026
|
+
range.end,
|
|
1027
|
+
allData.length
|
|
1028
|
+
]);
|
|
1029
|
+
return {
|
|
1030
|
+
data,
|
|
1031
|
+
anchorId,
|
|
1032
|
+
isFetching,
|
|
1033
|
+
hasPrev,
|
|
1034
|
+
hasNext,
|
|
1035
|
+
fetchPrevPage,
|
|
1036
|
+
fetchNextPage
|
|
1037
|
+
};
|
|
1038
|
+
};
|
|
1039
|
+
export { createLargeGroupedData, createLargeSecurityEvents, fullFeaturedColumns, groupedHeaderData, headerColumnHelper, headerColumnIds, headerColumns, multiplySecurityEvents, renderSecurityPreviewContent, renderSecurityPreviewHeader, securityColumnHelper, securityColumnIds, securityColumns, securityEvents, useBidirectionalData, useInfiniteData };
|
|
@@ -188,10 +188,20 @@ export interface TableProps<T> extends TestableProps {
|
|
|
188
188
|
virtualized?: TableVirtualized;
|
|
189
189
|
estimateRowHeight?: (index: number) => number;
|
|
190
190
|
overscan?: number;
|
|
191
|
-
/** Callback fired when the user scrolls near the end of the table */
|
|
191
|
+
/** Callback fired when the user scrolls near the end (bottom) of the table */
|
|
192
192
|
onEndReached?: () => void;
|
|
193
193
|
/** Distance from the bottom (in px) to trigger onEndReached (default: 200) */
|
|
194
194
|
onEndReachedThreshold?: number;
|
|
195
|
+
/** Callback fired when the user scrolls near the start (top) of the table */
|
|
196
|
+
onStartReached?: () => void;
|
|
197
|
+
/** Distance from the top (in px) to trigger onStartReached (default: 200) */
|
|
198
|
+
onStartReachedThreshold?: number;
|
|
199
|
+
/**
|
|
200
|
+
* Row id to anchor the initial scroll position to. The table scrolls this row
|
|
201
|
+
* into view on mount and arms the edge detectors only after that initial
|
|
202
|
+
* scroll settles. Use for deep-linking into the middle of a dataset.
|
|
203
|
+
*/
|
|
204
|
+
initialScrollToRowId?: string;
|
|
195
205
|
/** Callback fired when the master cell is clicked. Receives the row ID. */
|
|
196
206
|
onMasterCellClick?: (rowId: string) => void;
|
|
197
207
|
/** ID of the currently active (highlighted) row, or null. Controls row highlighting via data-preview-active attribute. */
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
|
-
"version": "0.50.
|
|
3
|
-
"generatedAt": "2026-05-
|
|
2
|
+
"version": "0.50.1",
|
|
3
|
+
"generatedAt": "2026-05-29T14:31:01.309Z",
|
|
4
4
|
"components": [
|
|
5
5
|
{
|
|
6
6
|
"name": "Accordion",
|
|
@@ -51854,6 +51854,12 @@
|
|
|
51854
51854
|
"type": "number | undefined",
|
|
51855
51855
|
"required": false
|
|
51856
51856
|
},
|
|
51857
|
+
{
|
|
51858
|
+
"name": "initialScrollToRowId",
|
|
51859
|
+
"type": "string | undefined",
|
|
51860
|
+
"required": false,
|
|
51861
|
+
"description": "Row id to anchor the initial scroll position to. The table scrolls this row\ninto view on mount and arms the edge detectors only after that initial\nscroll settles. Use for deep-linking into the middle of a dataset."
|
|
51862
|
+
},
|
|
51857
51863
|
{
|
|
51858
51864
|
"name": "activeRowId",
|
|
51859
51865
|
"type": "string | null | undefined",
|
|
@@ -52009,6 +52015,10 @@
|
|
|
52009
52015
|
"name": "InfiniteScrollWindow",
|
|
52010
52016
|
"code": "() => {\n const { data, isFetching, hasMore, totalItems, fetchNextPage } = useInfiniteData();\n\n return (\n <VStack gap={8}>\n <Text size='sm' color='secondary'>\n Loaded {data.length} of {totalItems} rows {isFetching && '— loading...'}\n {!hasMore && ' — all loaded'}\n </Text>\n <Table\n data={data}\n columns={securityColumns}\n getRowId={row => row.id}\n virtualized='window'\n isLoading={isFetching}\n onEndReached={fetchNextPage}\n onEndReachedThreshold={300}\n />\n </VStack>\n );\n}"
|
|
52011
52017
|
},
|
|
52018
|
+
{
|
|
52019
|
+
"name": "BidirectionalInfiniteScroll",
|
|
52020
|
+
"code": "() => {\n const { data, anchorId, isFetching, hasPrev, hasNext, fetchPrevPage, fetchNextPage } =\n useBidirectionalData();\n\n return (\n <VStack gap={8}>\n <Text size='sm' color='secondary'>\n Window of {data.length} rows around the anchor {isFetching && '— loading...'}\n {!hasPrev && ' — top reached'}\n {!hasNext && ' — bottom reached'}\n </Text>\n <Table\n className='h-500'\n data={data}\n columns={securityColumns}\n getRowId={row => row.id}\n virtualized='container'\n isLoading={isFetching}\n initialScrollToRowId={anchorId}\n onStartReached={fetchPrevPage}\n onStartReachedThreshold={200}\n onEndReached={fetchNextPage}\n onEndReachedThreshold={200}\n />\n </VStack>\n );\n}"
|
|
52021
|
+
},
|
|
52012
52022
|
{
|
|
52013
52023
|
"name": "HeaderColumnDescription",
|
|
52014
52024
|
"code": "() => {\n const [sorting, setSorting] = useState<TableSortingState>([]);\n\n const columns = useMemo<TableColumnDef<(typeof securityEvents)[number]>[]>(\n () =>\n securityColumns.map(col => {\n const key = 'accessorKey' in col ? col.accessorKey : undefined;\n if (key === 'objectName') {\n return {\n ...col,\n meta: {\n ...col.meta,\n description: { type: 'text' as const, content: 'Target resource' },\n },\n };\n }\n if (key === 'sourceIp') {\n return {\n ...col,\n meta: {\n ...col.meta,\n description: { type: 'tooltip' as const, content: 'Request origin IP' },\n },\n };\n }\n if (key === 'requests') {\n return {\n ...col,\n meta: { ...col.meta, description: { type: 'tooltip' as const, content: 'Total hits' } },\n };\n }\n if (key === 'parameter') {\n return {\n ...col,\n meta: {\n ...col.meta,\n description: { type: 'text' as const, content: 'Affected param' },\n },\n };\n }\n return col;\n }),\n [],\n );\n\n return (\n <Table\n data={securityEvents}\n columns={columns}\n getRowId={row => row.id}\n sorting={sorting}\n onSortingChange={setSorting}\n />\n );\n}"
|
package/package.json
CHANGED
|
@@ -1,19 +0,0 @@
|
|
|
1
|
-
import { type RefObject } from 'react';
|
|
2
|
-
type ScrollMode = 'container' | 'window';
|
|
3
|
-
interface UseEndReachedOptions {
|
|
4
|
-
mode: ScrollMode;
|
|
5
|
-
/** Scroll element ref — required for `container` mode */
|
|
6
|
-
scrollRef?: RefObject<HTMLElement | null>;
|
|
7
|
-
onEndReached?: () => void;
|
|
8
|
-
threshold?: number;
|
|
9
|
-
}
|
|
10
|
-
/**
|
|
11
|
-
* Fires `onEndReached` once when the user scrolls within `threshold` px
|
|
12
|
-
* of the bottom. Re-arms automatically after the user scrolls back up
|
|
13
|
-
* past the threshold or when the scroll height grows (new data loaded).
|
|
14
|
-
*
|
|
15
|
-
* A cooldown guard prevents rapid re-fires that can occur when new rows
|
|
16
|
-
* are appended (scrollHeight grows → firedRef resets → still at bottom).
|
|
17
|
-
*/
|
|
18
|
-
export declare const useEndReached: ({ mode, scrollRef, onEndReached, threshold, }: UseEndReachedOptions) => void;
|
|
19
|
-
export {};
|