import * as React from "react" ; import { Utils as CoreUtils } from "@blueprintjs/core" ; import { FocusedCellCoordinates } from "../common/cell" ; import { Utils } from "../common/utils" ; import { Region , RegionCardinality , Regions } from "../regions" ; import { Draggable , IDraggableProps } from "./draggable" ; import { ICoordinateData } from "./dragTypes" ; export interface IReorderableProps { param oldIndex param newIndex param length onReordering : ( oldIndex : number , newIndex : number , length : number ) => void ; param oldIndex param newIndex param length onReordered : ( oldIndex : number , newIndex : number , length : number ) => void ; /**
     * When the user reorders something, this callback is called with a new
     * array of `Region`s. This array should be considered the new selection
     * state for the entire table.
     */ onSelection : ( regions : Region [ ] ) => void ; /**
     * When the user reorders something, this callback is called with the new
     * focus cell for the newly selected set of regions.
     */ onFocusedCell : ( focusedCell : FocusedCellCoordinates ) => void ; default selectedRegions ? : Region [ ] ; } export interface IDragReorderable extends IReorderableProps { default disabled ? : boolean | ( ( event : MouseEvent ) => boolean ) ; /**
     * A callback that determines a `Region` for the single `MouseEvent`. If
     * no valid region can be found, `null` may be returned.
     */ locateClick : ( event : MouseEvent ) => Region ; /**
     * A callback that determines the index at which to show the preview guide.
     * This is equivalent to the absolute index in the old ordering where the
     * reordered element will move.
     */ locateDrag : ( event : MouseEvent , coords : ICoordinateData ) => number ; /**
     * A callback that converts the provided index into a region. The returned
     * region will be used to update the current selection after drag-reordering.
     */ toRegion : ( index1 : number , index2 ? : number ) => Region ; } export class DragReorderable extends React . PureComponent < IDragReorderable > { public static defaultProps : Partial < IDragReorderable > = { selectedRegions : [ ] , } ; private selectedRegionStartIndex : number ; private selectedRegionLength : number ; public render ( ) { const draggableProps = this . getDraggableProps ( ) ; return ( < Draggable { ... draggableProps } preventDefault = { false } > { this . props . children } < /Draggable>); } private getDraggableProps ( ) { return this . props . onReordered == null ? { } : { onActivate : this . handleActivate , onDragEnd : this . handleDragEnd , onDragMove : this . handleDragMove , } ; } private handleActivate = ( event ) => { if ( this . shouldIgnoreMouseDown ( event ) ) { return false ; } const region = this . props . locateClick ( event ) ; if ( ! Regions . isValid ( region ) ) { return false ; } const cardinality = Regions . getRegionCardinality ( region ) ; const isColumnHeader = cardinality === RegionCardinality . FULL_COLUMNS ; const isRowHeader = cardinality === RegionCardinality . FULL_ROWS ; if ( ! isColumnHeader && ! isRowHeader ) { return false ; } const { selectedRegions } = this . props ; const selectedRegionIndex = Regions . findContainingRegion ( selectedRegions , region ) ; if ( selectedRegionIndex >= 0 ) { const selectedRegion = selectedRegions [ selectedRegionIndex ] ; if ( Regions . getRegionCardinality ( selectedRegion ) !== cardinality ) { return false ; } const selectedInterval = isRowHeader ? selectedRegion . rows : selectedRegion . cols ; this . selectedRegionStartIndex = selectedInterval [ 0 ] ; this . selectedRegionLength = selectedInterval [ 1 ] - selectedInterval [ 0 ] + 1 ; } else { this . maybeSelectRegion ( region ) ; const regionRange = isRowHeader ? region . rows : region . cols ; this . selectedRegionStartIndex = regionRange [ 0 ] ; this . selectedRegionLength = regionRange [ 1 ] - regionRange [ 0 ] + 1 ; } return true ; } ; private handleDragMove = ( event , coords ) => { const oldIndex = this . selectedRegionStartIndex ; const guideIndex = this . props . locateDrag ( event , coords ) ; const length = this . selectedRegionLength ; const reorderedIndex = Utils . guideIndexToReorderedIndex ( oldIndex , guideIndex , length ) ; this . props . onReordering ( oldIndex , reorderedIndex , length ) ; } ; private handleDragEnd = ( event , coords ) => { const oldIndex = this . selectedRegionStartIndex ; const guideIndex = this . props . locateDrag ( event , coords ) ; const length = this . selectedRegionLength ; const reorderedIndex = Utils . guideIndexToReorderedIndex ( oldIndex , guideIndex , length ) ; this . props . onReordered ( oldIndex , reorderedIndex , length ) ; const newRegion = this . props . toRegion ( reorderedIndex , reorderedIndex + length - 1 ) ; this . maybeSelectRegion ( newRegion ) ; this . selectedRegionStartIndex = undefined ; this . selectedRegionLength = undefined ; } ; private shouldIgnoreMouseDown ( event ) { const { disabled } = this . props ; const isDisabled = CoreUtils . isFunction ( disabled ) ? disabled ?. ( event ) : disabled ; return ! Utils . isLeftClick ( event ) || isDisabled ; } private maybeSelectRegion ( region ) { const nextSelectedRegions = [ region ] ; if ( ! CoreUtils . deepCompareKeys ( nextSelectedRegions , this . props . selectedRegions ) ) { this . props . onSelection ( nextSelectedRegions ) ; this . props . onFocusedCell ( { ... Regions . getFocusCellCoordinatesFromRegion ( region ) , focusSelectionIndex : 0 , } ) ; } } }