import * as React from 'react' ; import * as styles from '../VirtualTable.scss' ; import { IVirtualTableProps , VirtualTableDataType , VirtualTableHeaderObjectType , } from '../VirtualTable' ; import { IVirtualTableRowProps } from '../components/VirtualTableRow' ; import { memoizeOne } from '@getflywheel/memoize-one-ts' ; export interface VirtualTableHelperCalculations { columnClassNames : VirtualTableHeaderObjectType [ 'className' ] [ ] ; columnFlexWidths : string [ ] ; dataKeysOrderedColumns : ( string | number ) [ ] ; dataKeyToColIndexLookup : Map < string | number , number > ; headersNormalized : VirtualTableDataType | undefined ; } export class VirtualTableHelper { public getRowHeight ( ref ) { return new Promise ( resolve => { const rowHeight = this . _getRowHeight ( ref ) ; if ( rowHeight !== null ) { resolve ( rowHeight ) ; } else { setTimeout ( ( ) => { resolve ( this . _getRowHeight ( ref ) ) ; } ) ; } } ) ; } public _getRowHeight ( ref ) { if ( ref . current ) { const tableEl = ref . current . querySelector ( `.${ styles . VirtualTable }` ) ; if ( tableEl ) { const cssRowHeight = parseInt ( getComputedStyle ( tableEl ) . getPropertyValue ( styles . CSSVARNAME_ROWHEIGHT ) ) ; if ( isNaN ( cssRowHeight ) ) { return null ; } return cssRowHeight ; } else { } } else { } return null ; } @ memoizeOne public getDataCalculationsMemoized ( props ) { const headersNormalized = this . normalizeHeadersMemoized ( props . headers ) ; const dataKeyToColIndexLookup = this . createColumnIndexLookupMemoized ( props . data , headersNormalized ) ; const dataKeysOrderedColumns = Array . from ( ( dataKeyToColIndexLookup . keys ( ) as any ) as ( string | number ) [ ] ) ; const { columnFlexWidths , columnClassNames } = this . getColumnFlexWidthsMemoized ( props . headers , dataKeysOrderedColumns ) ; return { columnFlexWidths , dataKeysOrderedColumns , dataKeyToColIndexLookup , headersNormalized , columnClassNames , } ; } @ memoizeOne public getColumnFlexWidthsMemoized ( headers , dataKeysOrderedColumns ) { if ( ! headers || ( headers . length && typeof ( headers [ 0 ] ) === 'string' ) ) { return { columnClassNames : [ ] , columnFlexWidths : [ ] } ; } const columnClassNames = [ ] ; const columnFlexWidths = [ ] ; let header ; let key ; for ( const index in headers ) { header = headers [ index ] as VirtualTableHeaderObjectType ; key = dataKeysOrderedColumns . indexOf ( header . key ) ; if ( header . flex && header . key && dataKeysOrderedColumns . includes ( header . key ) ) { columnFlexWidths [ key ] = header . flex ; } if ( header . className && header . className && dataKeysOrderedColumns . includes ( header . key ) ) { columnClassNames [ key ] = header . className || '' ; } } return { columnFlexWidths , columnClassNames } ; } @ memoizeOne public normalizeHeadersMemoized ( headers ) { if ( ! headers || ( headers . length && typeof ( headers [ 0 ] ) === 'string' ) ) { return headers ; } const headersNormalized = ( headers || [ ] ) . reduce ( ( accumulator , currentValue ) => { accumulator [ currentValue . key ] = currentValue . value ; return accumulator ; } , { } ) ; return headersNormalized ; } @ memoizeOne public createColumnIndexLookupMemoized ( data , headersNormalized ) { const dataKeyToColIndexLookup = new Map ( ) ; if ( data && data . length ) { let firstRowData ; if ( headersNormalized ) { firstRowData = headersNormalized ; } else { firstRowData = data [ 0 ] ; } if ( Array . isArray ( firstRowData ) ) { for ( let i = 0 ; i < firstRowData . length ; i ++ ) { dataKeyToColIndexLookup . set ( i , i ) ; } } else { let i = 0 ; for ( const key in firstRowData ) { dataKeyToColIndexLookup . set ( key , i ++ ) ; } } } return dataKeyToColIndexLookup ; } public getOrderedData ( rowData , headers , dataKeyToColIndexLookup ) { const rowDataOrdered = [ ] ; if ( Array . isArray ( rowData ) ) { for ( let i = 0 ; i < rowData . length ; i ++ ) { if ( dataKeyToColIndexLookup . has ( i ) ) { rowDataOrdered [ dataKeyToColIndexLookup . get ( i ) as any ] = rowData [ i ] ; } } } else { if ( headers ) { for ( let i = 0 ; i < headers . length ; i ++ ) { const key = typeof ( headers [ i ] ) === 'string' ? headers [ i ] as string : ( headers [ i ] as { [ key ] : string ; } ) . key ; rowDataOrdered . push ( rowData [ key ] || '' ) ; } } else { for ( const key in rowData ) { if ( dataKeyToColIndexLookup . has ( key ) ) { rowDataOrdered [ dataKeyToColIndexLookup . get ( key ) as any ] = rowData [ key ] ; } } } } if ( Array . isArray ( rowData ) && rowData . length < dataKeyToColIndexLookup . size ) { for ( let i = rowData . length ; i < dataKeyToColIndexLookup . size ; i ++ ) { rowDataOrdered [ i ] = '' ; } } else if ( rowDataOrdered . includes ( undefined ) ) { for ( let i = rowDataOrdered . length - 1 ; i > - 1 ; i -- ) { if ( typeof ( rowDataOrdered [ i ] ) === "undefined" ) { rowDataOrdered [ i ] = '' ; } } } return rowDataOrdered ; } }