2020-09-15 15:01:07 +02:00
import * as React from 'react' ;
2020-11-13 19:09:28 +02:00
import { useRef , useState , useEffect } from 'react' ;
import useWindowResizeEvent from './utils/useWindowResizeEvent' ;
import setLayoutItemProps from './utils/setLayoutItemProps' ;
2021-05-22 19:30:11 +02:00
import useLayoutItemSizes , { LayoutItemSizes , itemSize , calculateMaxSizeAvailableForItem , itemMinWidth , itemMinHeight } from './utils/useLayoutItemSizes' ;
2020-11-13 19:09:28 +02:00
import validateLayout from './utils/validateLayout' ;
import { Size , LayoutItem } from './utils/types' ;
import { canMove , MoveDirection } from './utils/movements' ;
import MoveButtons , { MoveButtonClickEvent } from './MoveButtons' ;
import { StyledWrapperRoot , StyledMoveOverlay , MoveModeRootWrapper , MoveModeRootMessage } from './utils/style' ;
import { Resizable } from 're-resizable' ;
2020-09-15 15:01:07 +02:00
const EventEmitter = require ( 'events' ) ;
2021-08-18 17:21:48 +02:00
interface OnResizeEvent {
2020-11-12 21:29:22 +02:00
layout : LayoutItem ;
2020-09-15 15:01:07 +02:00
}
interface Props {
2020-11-12 21:29:22 +02:00
layout : LayoutItem ;
2021-08-18 17:21:48 +02:00
onResize ( event : OnResizeEvent ) : void ;
2020-11-12 21:29:22 +02:00
width? : number ;
height? : number ;
2023-06-30 11:30:29 +02:00
// eslint-disable-next-line @typescript-eslint/ban-types -- Old code before rule was applied
2020-11-12 21:29:22 +02:00
renderItem : Function ;
2020-11-13 19:09:28 +02:00
onMoveButtonClick ( event : MoveButtonClickEvent ) : void ;
moveMode : boolean ;
moveModeMessage : string ;
2020-10-09 19:35:46 +02:00
}
2020-11-13 19:09:28 +02:00
function itemVisible ( item : LayoutItem , moveMode : boolean ) {
if ( moveMode ) return true ;
if ( item . children && ! item . children . length ) return false ;
return item . visible !== false ;
2020-09-15 15:01:07 +02:00
}
2024-04-05 13:16:49 +02:00
// eslint-disable-next-line @typescript-eslint/ban-types, @typescript-eslint/no-explicit-any -- Old code before rule was applied, Old code before rule was applied
2021-05-22 19:30:11 +02:00
function renderContainer ( item : LayoutItem , parent : LayoutItem | null , sizes : LayoutItemSizes , resizedItemMaxSize : Size | null , onResizeStart : Function , onResize : Function , onResizeStop : Function , children : any [ ] , isLastChild : boolean , moveMode : boolean ) : any {
2024-04-05 13:16:49 +02:00
// eslint-disable-next-line @typescript-eslint/no-explicit-any -- Old code before rule was applied
2020-11-12 21:13:28 +02:00
const style : any = {
2020-11-13 19:09:28 +02:00
display : itemVisible ( item , moveMode ) ? 'flex' : 'none' ,
2020-09-15 15:01:07 +02:00
flexDirection : item.direction ,
} ;
2020-11-13 19:09:28 +02:00
const size : Size = itemSize ( item , parent , sizes , true ) ;
2020-09-15 15:01:07 +02:00
const className = ` resizableLayoutItem rli- ${ item . key } ` ;
2020-10-09 19:35:46 +02:00
if ( item . resizableRight || item . resizableBottom ) {
const enable = {
top : false ,
right : ! ! item . resizableRight && ! isLastChild ,
bottom : ! ! item . resizableBottom && ! isLastChild ,
left : false ,
topRight : false ,
bottomRight : false ,
bottomLeft : false ,
topLeft : false ,
} ;
2020-09-15 15:01:07 +02:00
return (
< Resizable
key = { item . key }
className = { className }
style = { style }
size = { size }
2024-04-05 13:16:49 +02:00
// eslint-disable-next-line @typescript-eslint/no-explicit-any -- Old code before rule was applied
2020-11-13 19:09:28 +02:00
onResizeStart = { onResizeStart as any }
2024-04-05 13:16:49 +02:00
// eslint-disable-next-line @typescript-eslint/no-explicit-any -- Old code before rule was applied
2020-11-13 19:09:28 +02:00
onResize = { onResize as any }
2024-04-05 13:16:49 +02:00
// eslint-disable-next-line @typescript-eslint/no-explicit-any -- Old code before rule was applied
2020-11-13 19:09:28 +02:00
onResizeStop = { onResizeStop as any }
2020-09-15 15:01:07 +02:00
enable = { enable }
2020-11-13 19:09:28 +02:00
minWidth = { 'minWidth' in item ? item.minWidth : itemMinWidth }
minHeight = { 'minHeight' in item ? item.minHeight : itemMinHeight }
2021-05-22 19:30:11 +02:00
maxWidth = { resizedItemMaxSize ? . width }
maxHeight = { resizedItemMaxSize ? . height }
2020-09-15 15:01:07 +02:00
>
{ children }
< / Resizable >
) ;
} else {
return (
< div key = { item . key } className = { className } style = { { . . . style , . . . size } } >
{ children }
< / div >
) ;
}
}
2020-11-12 21:13:28 +02:00
function ResizableLayout ( props : Props ) {
2020-09-15 15:01:07 +02:00
const eventEmitter = useRef ( new EventEmitter ( ) ) ;
2024-04-05 13:16:49 +02:00
// eslint-disable-next-line @typescript-eslint/no-explicit-any -- Old code before rule was applied
2020-09-15 15:01:07 +02:00
const [ resizedItem , setResizedItem ] = useState < any > ( null ) ;
2024-04-05 13:16:49 +02:00
// eslint-disable-next-line @typescript-eslint/no-explicit-any -- Old code before rule was applied
2020-11-13 19:09:28 +02:00
function renderItemWrapper ( comp : any , item : LayoutItem , parent : LayoutItem | null , size : Size , moveMode : boolean ) {
const moveOverlay = moveMode ? (
< StyledMoveOverlay >
< MoveButtons
itemKey = { item . key }
onClick = { props . onMoveButtonClick }
canMoveLeft = { canMove ( MoveDirection . Left , item , parent ) }
canMoveRight = { canMove ( MoveDirection . Right , item , parent ) }
canMoveUp = { canMove ( MoveDirection . Up , item , parent ) }
canMoveDown = { canMove ( MoveDirection . Down , item , parent ) }
/ >
< / StyledMoveOverlay >
) : null ;
2020-09-15 15:01:07 +02:00
2020-11-13 19:09:28 +02:00
return (
< StyledWrapperRoot key = { item . key } size = { size } >
{ moveOverlay }
{ comp }
< / StyledWrapperRoot >
) ;
}
2024-04-05 13:16:49 +02:00
// eslint-disable-next-line @typescript-eslint/no-explicit-any -- Old code before rule was applied
2020-11-13 19:09:28 +02:00
function renderLayoutItem ( item : LayoutItem , parent : LayoutItem | null , sizes : LayoutItemSizes , isVisible : boolean , isLastChild : boolean ) : any {
2020-09-15 15:01:07 +02:00
function onResizeStart() {
setResizedItem ( {
key : item.key ,
initialWidth : sizes [ item . key ] . width ,
initialHeight : sizes [ item . key ] . height ,
2021-05-22 19:30:11 +02:00
maxSize : calculateMaxSizeAvailableForItem ( item , parent , sizes ) ,
2020-09-15 15:01:07 +02:00
} ) ;
}
2024-04-05 13:16:49 +02:00
// eslint-disable-next-line @typescript-eslint/no-explicit-any -- Old code before rule was applied
2020-11-13 19:09:28 +02:00
function onResize ( _event : any , direction : string , _refToElement : any , delta : any ) {
const newWidth = Math . max ( itemMinWidth , resizedItem . initialWidth + delta . width ) ;
const newHeight = Math . max ( itemMinHeight , resizedItem . initialHeight + delta . height ) ;
2024-04-05 13:16:49 +02:00
// eslint-disable-next-line @typescript-eslint/no-explicit-any -- Old code before rule was applied
2020-11-13 19:09:28 +02:00
const newSize : any = { } ;
if ( item . width ) newSize . width = item . width ;
if ( item . height ) newSize . height = item . height ;
if ( direction === 'bottom' ) {
newSize . height = newHeight ;
} else {
newSize . width = newWidth ;
}
const newLayout = setLayoutItemProps ( props . layout , item . key , newSize ) ;
2020-09-15 15:01:07 +02:00
props . onResize ( { layout : newLayout } ) ;
eventEmitter . current . emit ( 'resize' ) ;
}
2024-04-05 13:16:49 +02:00
// eslint-disable-next-line @typescript-eslint/no-explicit-any -- Old code before rule was applied
2020-11-13 19:09:28 +02:00
function onResizeStop ( _event : any , _direction : any , _refToElement : any , delta : any ) {
2020-09-15 15:01:07 +02:00
onResize ( _event , _direction , _refToElement , delta ) ;
setResizedItem ( null ) ;
}
2021-07-06 14:57:48 +02:00
const resizedItemMaxSize = resizedItem && item . key === resizedItem . key ? resizedItem.maxSize : null ;
2020-09-15 15:01:07 +02:00
if ( ! item . children ) {
2020-11-13 19:09:28 +02:00
const size = itemSize ( item , parent , sizes , false ) ;
2020-09-15 15:01:07 +02:00
const comp = props . renderItem ( item . key , {
item : item ,
eventEmitter : eventEmitter.current ,
2020-11-13 19:09:28 +02:00
size : size ,
2020-09-15 15:01:07 +02:00
visible : isVisible ,
} ) ;
2020-11-13 19:09:28 +02:00
const wrapper = renderItemWrapper ( comp , item , parent , size , props . moveMode ) ;
2021-05-22 19:30:11 +02:00
return renderContainer ( item , parent , sizes , resizedItemMaxSize , onResizeStart , onResize , onResizeStop , [ wrapper ] , isLastChild , props . moveMode ) ;
2020-09-15 15:01:07 +02:00
} else {
const childrenComponents = [ ] ;
2020-10-09 19:35:46 +02:00
for ( let i = 0 ; i < item . children . length ; i ++ ) {
const child = item . children [ i ] ;
2020-11-13 19:09:28 +02:00
childrenComponents . push ( renderLayoutItem ( child , item , sizes , isVisible && itemVisible ( child , props . moveMode ) , i === item . children . length - 1 ) ) ;
2020-09-15 15:01:07 +02:00
}
2021-05-22 19:30:11 +02:00
return renderContainer ( item , parent , sizes , resizedItemMaxSize , onResizeStart , onResize , onResizeStop , childrenComponents , isLastChild , props . moveMode ) ;
2020-09-15 15:01:07 +02:00
}
}
2020-11-13 19:09:28 +02:00
useEffect ( ( ) = > {
validateLayout ( props . layout ) ;
} , [ props . layout ] ) ;
2020-09-15 15:01:07 +02:00
useWindowResizeEvent ( eventEmitter ) ;
2020-11-13 19:09:28 +02:00
const sizes = useLayoutItemSizes ( props . layout , props . moveMode ) ;
2020-09-15 15:01:07 +02:00
2024-04-05 13:16:49 +02:00
// eslint-disable-next-line @typescript-eslint/no-explicit-any -- Old code before rule was applied
2020-11-13 19:09:28 +02:00
function renderMoveModeBox ( rootComp : any ) {
return (
< MoveModeRootWrapper >
< MoveModeRootMessage > { props . moveModeMessage } < / MoveModeRootMessage >
{ rootComp }
< / MoveModeRootWrapper >
) ;
}
const rootComp = renderLayoutItem ( props . layout , null , sizes , itemVisible ( props . layout , props . moveMode ) , true ) ;
if ( props . moveMode ) {
return renderMoveModeBox ( rootComp ) ;
} else {
return rootComp ;
}
2020-09-15 15:01:07 +02:00
}
export default ResizableLayout ;