11import { ItemType } from "@gephi/gephi-lite-sdk" ;
2- import { Row , Table , flexRender , getCoreRowModel , getSortedRowModel , useReactTable } from "@tanstack/react-table" ;
2+ import { Row , flexRender , getCoreRowModel , getSortedRowModel , useReactTable } from "@tanstack/react-table" ;
33import { VirtualItem , Virtualizer , useVirtualizer } from "@tanstack/react-virtual" ;
44import cx from "classnames" ;
5- import { FC , RefObject , useEffect , useMemo , useRef } from "react" ;
5+ import { FC , useEffect , useMemo , useRef } from "react" ;
66import { ScrollSyncPane } from "react-scroll-sync" ;
77
88import {
@@ -44,78 +44,8 @@ const TableBodyRow: FC<{
4444 ) ;
4545} ;
4646
47- const TableBody : FC < {
48- table : Table < ItemRow > ;
49- tableContainerRef : RefObject < HTMLDivElement > ;
50- } > = ( { table, tableContainerRef } ) => {
51- const { rows } = table . getRowModel ( ) ;
52- const { emitter } = useEventsContext ( ) ;
53- const { type } = useDataTable ( ) ;
54- const { setSort } = useDataTableActions ( ) ;
55-
56- const rowVirtualizer = useVirtualizer < HTMLDivElement , HTMLTableRowElement > ( {
57- overscan : 5 ,
58- count : rows . length ,
59- estimateSize : ( ) => 41 ,
60- getScrollElement : ( ) => tableContainerRef . current ,
61- measureElement :
62- typeof window !== "undefined" && navigator . userAgent . indexOf ( "Firefox" ) === - 1
63- ? ( element ) => element ?. getBoundingClientRect ( ) . height
64- : undefined ,
65- } ) ;
66-
67- useEffect ( ( ) => {
68- const scrollToID = ( id : string ) => {
69- const sortedRows = table . getRowModel ( ) . rows ;
70- const sortedIndex = sortedRows . findIndex ( ( r ) => r . id === id ) ;
71- rowVirtualizer . scrollToIndex ( sortedIndex , { align : "center" } ) ;
72- } ;
73-
74- // Handle scrolling to newly created nodes and edges:
75- const newItemEvent = type === "nodes" ? EVENTS . nodeCreated : EVENTS . edgeCreated ;
76- const newItemHandler = ( { id } : { id : string } ) => {
77- scrollToID ( id ) ;
78- } ;
79-
80- // Handle scrolling to searched items:
81- const searchedItemsHandler = ( { type : eventItemType , ids } : { type : ItemType ; ids : string [ ] } ) => {
82- if ( type !== eventItemType ) return ;
83-
84- if ( ids . length === 1 ) {
85- scrollToID ( ids [ 0 ] ) ;
86- } else {
87- setSort ( [ { id : SPECIFIC_COLUMNS . selected , desc : true } ] ) ;
88- rowVirtualizer . scrollToIndex ( 0 ) ;
89- }
90- } ;
91-
92- emitter . on ( newItemEvent , newItemHandler ) ;
93- emitter . on ( EVENTS . searchResultsSelected , searchedItemsHandler ) ;
94- return ( ) => {
95- emitter . off ( newItemEvent , newItemHandler ) ;
96- emitter . off ( EVENTS . searchResultsSelected , searchedItemsHandler ) ;
97- } ;
98- } , [ emitter , rowVirtualizer , setSort , table , type ] ) ;
99-
100- return (
101- < tbody
102- style = { {
103- height : `${ rowVirtualizer . getTotalSize ( ) } px` ,
104- } }
105- >
106- { rowVirtualizer . getVirtualItems ( ) . map ( ( virtualRow ) => (
107- < TableBodyRow
108- key = { rows [ virtualRow . index ] . id }
109- row = { rows [ virtualRow . index ] as Row < ItemRow > }
110- virtualRow = { virtualRow }
111- rowVirtualizer = { rowVirtualizer }
112- />
113- ) ) }
114- </ tbody >
115- ) ;
116- } ;
117-
11847export const DataTable : FC < { itemIDs : string [ ] } > = ( { itemIDs } ) => {
48+ const { emitter } = useEventsContext ( ) ;
11949 const { nodeData, edgeData, fullGraph } = useGraphDataset ( ) ;
12050 const { dynamicNodeData, dynamicEdgeData } = useDynamicItemData ( ) ;
12151 const { type : selectionType , items } = useSelection ( ) ;
@@ -129,7 +59,7 @@ export const DataTable: FC<{ itemIDs: string[] }> = ({ itemIDs }) => {
12959 ( ) => ( type === "nodes" ? dynamicNodeData : dynamicEdgeData ) ,
13060 [ dynamicNodeData , dynamicEdgeData , type ] ,
13161 ) ;
132- const rows = useMemo < ItemRow [ ] > (
62+ const dataRows = useMemo < ItemRow [ ] > (
13363 ( ) =>
13464 itemIDs . map ( ( id ) =>
13565 type === "nodes"
@@ -152,7 +82,7 @@ export const DataTable: FC<{ itemIDs: string[] }> = ({ itemIDs }) => {
15282
15383 const tableContainerRef = useRef < HTMLTableElement > ( null ) ;
15484 const table = useReactTable ( {
155- data : rows ,
85+ data : dataRows ,
15686 columns,
15787 getRowId : ( row ) => row . id ,
15888 getCoreRowModel : getCoreRowModel ( ) ,
@@ -170,6 +100,51 @@ export const DataTable: FC<{ itemIDs: string[] }> = ({ itemIDs }) => {
170100 onColumnSizingChange : updateColumnSizing ,
171101 onColumnSizingInfoChange : updateColumnSizingInfo ,
172102 } ) ;
103+ const { rows : tableRows } = table . getRowModel ( ) ;
104+
105+ const rowVirtualizer = useVirtualizer < HTMLDivElement , HTMLTableRowElement > ( {
106+ overscan : 5 ,
107+ count : dataRows . length ,
108+ estimateSize : ( ) => 41 ,
109+ getScrollElement : ( ) => tableContainerRef . current ,
110+ measureElement :
111+ typeof window !== "undefined" && navigator . userAgent . indexOf ( "Firefox" ) === - 1
112+ ? ( element ) => element ?. getBoundingClientRect ( ) . height
113+ : undefined ,
114+ } ) ;
115+
116+ useEffect ( ( ) => {
117+ const scrollToID = ( id : string ) => {
118+ const sortedRows = table . getRowModel ( ) . rows ;
119+ const sortedIndex = sortedRows . findIndex ( ( r ) => r . id === id ) ;
120+ rowVirtualizer . scrollToIndex ( sortedIndex , { align : "center" } ) ;
121+ } ;
122+
123+ // Handle scrolling to newly created nodes and edges:
124+ const newItemEvent = type === "nodes" ? EVENTS . nodeCreated : EVENTS . edgeCreated ;
125+ const newItemHandler = ( { id } : { id : string } ) => {
126+ scrollToID ( id ) ;
127+ } ;
128+
129+ // Handle scrolling to searched items:
130+ const searchedItemsHandler = ( { type : eventItemType , ids } : { type : ItemType ; ids : string [ ] } ) => {
131+ if ( type !== eventItemType ) return ;
132+
133+ if ( ids . length === 1 ) {
134+ scrollToID ( ids [ 0 ] ) ;
135+ } else {
136+ setSort ( [ { id : SPECIFIC_COLUMNS . selected , desc : true } ] ) ;
137+ rowVirtualizer . scrollToIndex ( 0 ) ;
138+ }
139+ } ;
140+
141+ emitter . on ( newItemEvent , newItemHandler ) ;
142+ emitter . on ( EVENTS . searchResultsSelected , searchedItemsHandler ) ;
143+ return ( ) => {
144+ emitter . off ( newItemEvent , newItemHandler ) ;
145+ emitter . off ( EVENTS . searchResultsSelected , searchedItemsHandler ) ;
146+ } ;
147+ } , [ emitter , rowVirtualizer , setSort , table , type ] ) ;
173148
174149 return (
175150 < div className = "position-absolute inset-0" >
@@ -218,7 +193,20 @@ export const DataTable: FC<{ itemIDs: string[] }> = ({ itemIDs }) => {
218193 </ tr >
219194 ) ) }
220195 </ thead >
221- < TableBody table = { table } tableContainerRef = { tableContainerRef } />
196+ < tbody
197+ style = { {
198+ height : `${ rowVirtualizer . getTotalSize ( ) } px` ,
199+ } }
200+ >
201+ { rowVirtualizer . getVirtualItems ( ) . map ( ( virtualRow ) => (
202+ < TableBodyRow
203+ key = { tableRows [ virtualRow . index ] . id }
204+ row = { tableRows [ virtualRow . index ] }
205+ virtualRow = { virtualRow }
206+ rowVirtualizer = { rowVirtualizer }
207+ />
208+ ) ) }
209+ </ tbody >
222210 </ table >
223211 </ ScrollSyncPane >
224212 </ div >
0 commit comments