import * as React from 'react' ; import { DraggableHandle } from './draggableHandle' ; export interface Props { className ? : string ; dockSide ? : DockSide ; defaultLength ? : number ; minLength ? : number ; maxLength ? : number ; isOpen ? : boolean ; onOpenOrClose ? : ( open : boolean ) => void ; onStartResize : ( ) => void ; children ? : React . ReactNode ; } export enum DockSide { Left = 1 , Right , Top , Bottom } export interface State { readonly open ? : boolean ; readonly length ? : number ; } const CLASS_NAME = 'graph-explorer-drag-resizable-column' ; export class ResizableSidebar extends React . Component < Props , State > { static readonly defaultProps : Partial < Props > = { dockSide : DockSide . Left , minLength : 0 , maxLength : 500 , defaultLength : 275 , isOpen : true , } ; private originWidth : number ; constructor ( props ) { super ( props ) ; this . state = { open : this . props . isOpen , length : this . defaultWidth ( ) , } ; } componentDidUpdate ( nextProps ) { if ( this . state . open !== nextProps . isOpen ) { this . toggle ( { open : nextProps . isOpen } ) ; } } private defaultWidth ( ) { const { defaultLength , maxLength } = this . props ; return Math . min ( defaultLength , maxLength ) ; } private getSideClass ( ) { switch ( this . props . dockSide ) { case DockSide . Left : return `${ CLASS_NAME }--docked-left` ; case DockSide . Right : return `${ CLASS_NAME }--docked-right` ; case DockSide . Top : return `${ CLASS_NAME }--docked-top` ; case DockSide . Bottom : return `${ CLASS_NAME }--docked-bottom` ; default : return 'docked-right' ; } } private get isHorizontal ( ) : boolean { return ( this . props . dockSide === DockSide . Top || this . props . dockSide === DockSide . Bottom ) ; } render ( ) { const { open , length } = this . state ; const className = `${ CLASS_NAME } ` + `${ this . getSideClass ( ) } ` + `${ CLASS_NAME }--${ open ? 'opened' : 'closed' } ` + `${ this . props . className || '' }` ; const style = { } ; style [ this . isHorizontal ? 'height' : 'width' ] = open ? length : 0 ; return ( < div className = { className } style = { style } > { open ? this . props . children : null } < DraggableHandle className = { `${ CLASS_NAME }__handle` } onBeginDragHandle = { this . onBeginDragHandle } onDragHandle = { this . onDragHandle } > < div className = { `${ CLASS_NAME }__handle-btn` } onClick = { ( ) => this . toggle ( { open : ! this . state . open } ) } > < /div> < /DraggableHandle> < /div>); } private onBeginDragHandle = ( ) => { this . originWidth = this . state . open ? this . state . length : 0 ; this . props . onStartResize ( ) ; } ; private onDragHandle = ( e , dx , dy ) => { let difference = this . isHorizontal ? dy : dx ; if ( this . props . dockSide === DockSide . Right ) { difference = - difference ; } const newWidth = this . originWidth + difference ; const clampedWidth = Math . max ( Math . min ( newWidth , this . props . maxLength ) , this . props . minLength ) ; const isOpen = this . props . minLength > 0 || clampedWidth > this . props . minLength ; this . toggle ( { open : isOpen , newWidth : clampedWidth } ) ; } ; private toggle ( params ) { const { open , newWidth } = params ; const openChanged = open !== this . state . open ; const onStateChanged = ( ) => { if ( openChanged && this . props . onOpenOrClose ) { this . props . onOpenOrClose ( open ) ; } } ; const useDefaultWidth = open && this . state . length === 0 && newWidth === undefined ; if ( useDefaultWidth ) { this . setState ( { open , length : this . defaultWidth ( ) } , onStateChanged ) ; } else { this . setState ( newWidth === undefined ? { open } : { open , length : newWidth } , onStateChanged ) ; } } }