import classNames from "classnames" ; import * as React from "react" ; import { AbstractComponent2 , Utils as CoreUtils } from "@blueprintjs/core" ; import { ICellCoordinates } from "./common/cell" ; import * as Classes from "./common/classes" ; import { ContextMenuTargetWrapper } from "./common/contextMenuTargetWrapper" ; import { RenderMode } from "./common/renderMode" ; import { ICoordinateData } from "./interactions/dragTypes" ; import { IContextMenuRenderer , MenuContext } from "./interactions/menus" ; import { DragSelectable , ISelectableProps } from "./interactions/selectable" ; import { ILocator } from "./locator" ; import { Region , Regions } from "./regions" ; import { cellClassNames , ITableBodyCellsProps , TableBodyCells } from "./tableBodyCells" ; export interface ITableBodyProps extends ISelectableProps , ITableBodyCellsProps { /**
     * An optional callback for displaying a context menu when right-clicking
     * on the table body. The callback is supplied with an `IMenuContext`
     * containing the `Region`s of interest.
     */ bodyContextMenuRenderer ? : IContextMenuRenderer ; /**
     * Locates the row/column/cell given a mouse event.
     */ locator : ILocator ; /**
     * The number of columns to freeze to the left side of the table, counting from the leftmost column.
     */ numFrozenColumns ? : number ; /**
     * The number of rows to freeze to the top of the table, counting from the topmost row.
     */ numFrozenRows ? : number ; } const DEEP_COMPARE_KEYS = [ "selectedRegions" ] ; export class TableBody extends AbstractComponent2 < ITableBodyProps > { public static defaultProps = { loading : false , renderMode : RenderMode . BATCH , } ; public static cellClassNames ( rowIndex , columnIndex ) { return cellClassNames ( rowIndex , columnIndex ) ; } private activationCell : ICellCoordinates ; public shouldComponentUpdate ( nextProps ) { return ( ! CoreUtils . shallowCompareKeys ( this . props , nextProps , { exclude : DEEP_COMPARE_KEYS } ) || ! CoreUtils . deepCompareKeys ( this . props , nextProps , DEEP_COMPARE_KEYS ) ) ; } public render ( ) { const { grid , numFrozenColumns , numFrozenRows } = this . props ; const defaultStyle = grid . getRect ( ) . sizeStyle ( ) ; const style = { height : numFrozenRows != null ? grid . getCumulativeHeightAt ( numFrozenRows - 1 ) : defaultStyle . height , width : numFrozenColumns != null ? grid . getCumulativeWidthAt ( numFrozenColumns - 1 ) : defaultStyle . width , } ; return ( < DragSelectable enableMultipleSelection = { this . props . enableMultipleSelection } focusedCell = { this . props . focusedCell } locateClick = { this . locateClick } locateDrag = { this . locateDrag } onFocusedCell = { this . props . onFocusedCell } onSelection = { this . props . onSelection } onSelectionEnd = { this . handleSelectionEnd } selectedRegions = { this . props . selectedRegions } selectedRegionTransform = { this . props . selectedRegionTransform } > < ContextMenuTargetWrapper className = { classNames ( Classes . TABLE_BODY_VIRTUAL_CLIENT , Classes . TABLE_CELL_CLIENT ) } renderContextMenu = { this . renderContextMenu } style = { style } > < TableBodyCells cellRenderer = { this . props . cellRenderer } focusedCell = { this . props . focusedCell } grid = { grid } loading = { this . props . loading } onCompleteRender = { this . props . onCompleteRender } renderMode = { this . props . renderMode } columnIndexStart = { this . props . columnIndexStart } columnIndexEnd = { this . props . columnIndexEnd } rowIndexStart = { this . props . rowIndexStart } rowIndexEnd = { this . props . rowIndexEnd } viewportRect = { this . props . viewportRect } / > < /ContextMenuTargetWrapper> < /DragSelectable>); } public renderContextMenu = ( e ) => { const { grid , onFocusedCell , onSelection , bodyContextMenuRenderer , selectedRegions } = this . props ; const { numRows , numCols } = grid ; if ( bodyContextMenuRenderer == null ) { return undefined ; } const targetRegion = this . locateClick ( e . nativeEvent as MouseEvent ) ; let nextSelectedRegions = selectedRegions ; const foundIndex = Regions . findContainingRegion ( selectedRegions , targetRegion ) ; if ( foundIndex < 0 ) { nextSelectedRegions = [ targetRegion ] ; onSelection ( nextSelectedRegions ) ; const nextFocusedCell = { ... Regions . getFocusCellCoordinatesFromRegion ( targetRegion ) , focusSelectionIndex : 0 , } ; onFocusedCell ( nextFocusedCell ) ; } const menuContext = new MenuContext ( targetRegion , nextSelectedRegions , numRows , numCols ) ; const contextMenu = bodyContextMenuRenderer ( menuContext ) ; return contextMenu == null ? undefined : contextMenu ; } ; private handleSelectionEnd = ( ) => { this . activationCell = null ; } ; private locateClick = ( event ) => { this . activationCell = this . props . locator . convertPointToCell ( event . clientX , event . clientY ) ; return Regions . cell ( this . activationCell . row , this . activationCell . col ) ; } ; private locateDrag = ( _event , coords , returnEndOnly = false ) => { const start = this . activationCell ; const end = this . props . locator . convertPointToCell ( coords . current [ 0 ] , coords . current [ 1 ] ) ; return returnEndOnly ? Regions . cell ( end . row , end . col ) : Regions . cell ( start . row , start . col , end . row , end . col ) ; } ; }