import React , { ReactNode } from 'react' ; import { VariableSizeList , VariableSizeListProps } from 'react-window' ; import Tree , { createTreeComputer , NodeData , NodePublicState , OpennessState , TreeProps , TreeState , } from './Tree' ; import { createBasicRecord , getIdByIndex } from './utils' ; export type VariableSizeNodeData = Readonly < { /** Default node height. Can be used only with VariableSizeTree */ defaultHeight : number ; } > & NodeData ; export type VariableSizeNodePublicState < T extends VariableSizeNodeData > = NodePublicState < T > & { height : number ; readonly resize : ( height : number , shouldForceUpdate ? : boolean ) => void ; } ; export type VariableSizeTreeProps < TData extends VariableSizeNodeData > = TreeProps < TData , VariableSizeNodePublicState < TData > , VariableSizeList > & Readonly < { itemSize ? : VariableSizeListProps [ 'itemSize' ] ; } > ; export type VariableSizeTreeState < T extends VariableSizeNodeData > = TreeState < T , VariableSizeNodePublicState < T > , VariableSizeList > & Readonly < { resetAfterId : ( id : string , shouldForceUpdate ? : boolean ) => void ; } > ; const computeTree = createTreeComputer < VariableSizeNodeData , VariableSizeNodePublicState < VariableSizeNodeData > , VariableSizeTreeProps < VariableSizeNodeData > , VariableSizeTreeState < VariableSizeNodeData > > ( { createRecord : ( data , { recomputeTree , resetAfterId } , parent , previousRecord ) => { const record = createBasicRecord ( { data , height : previousRecord ? previousRecord . public . height : data . defaultHeight , isOpen : previousRecord ? previousRecord . public . isOpen : data . isOpenByDefault , resize : ( height , shouldForceUpdate ? ) : void => { record . public . height = height ; resetAfterId ( record . public . data . id , shouldForceUpdate ) ; } , setOpen : ( state ) : Promise < void > => recomputeTree ( { [ data . id ] : state , } ) , } , parent ) ; return record ; } , } ) ; export class VariableSizeTree < TData extends VariableSizeNodeData > extends Tree < TData , VariableSizeNodePublicState < TData > , VariableSizeTreeProps < TData > , VariableSizeTreeState < TData > , VariableSizeList > { public constructor ( props , context ) { super ( props , context ) ; this . getItemSize = this . getItemSize . bind ( this ) ; this . state = { ... this . state , computeTree , resetAfterId : this . resetAfterId . bind ( this ) , } ; } public resetAfterId ( id , shouldForceUpdate = false ) { const { list , order } = this . state ; list . current ?. resetAfterIndex ( order ! . indexOf ( id ) , shouldForceUpdate ) ; } public recomputeTree ( state ) { return super . recomputeTree ( state ) . then ( ( ) => { this . state . list . current ?. resetAfterIndex ( 0 , true ) ; } ) ; } public render ( ) { const { children , placeholder , itemSize , rowComponent , treeWalker , ... rest } = this . props ; const { attachRefs , order } = this . state ; return placeholder && order ! . length === 0 ? ( placeholder ) : ( < VariableSizeList { ... rest } itemCount = { order ! . length } itemData = { this . getItemData ( ) } itemKey = { getIdByIndex } itemSize = { itemSize ?? this . getItemSize } ref = { attachRefs } > { rowComponent ! } < /VariableSizeList>); } private getItemSize ( index ) { return this . getRecordData ( index ) . height ; } }