2020-09-15 14:01:07 +01:00
import * as React from 'react' ;
2020-11-13 17:09:28 +00: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 17:09:28 +00: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 14:01:07 +01:00
const EventEmitter = require ( 'events' );
2021-08-18 16:21:48 +01:00
interface OnResizeEvent {
2020-11-12 19:29:22 +00:00
layout : LayoutItem ;
2020-09-15 14:01:07 +01:00
}
interface Props {
2020-11-12 19:29:22 +00:00
layout : LayoutItem ;
2021-08-18 16:21:48 +01:00
onResize ( event : OnResizeEvent ) : void ;
2020-11-12 19:29:22 +00:00
width? : number ;
height? : number ;
2023-06-30 10:30:29 +01:00
// eslint-disable-next-line @typescript-eslint/ban-types -- Old code before rule was applied
2020-11-12 19:29:22 +00:00
renderItem : Function ;
2020-11-13 17:09:28 +00:00
onMoveButtonClick ( event : MoveButtonClickEvent ) : void ;
moveMode : boolean ;
moveModeMessage : string ;
2020-10-09 18:35:46 +01:00
}
2020-11-13 17:09:28 +00: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 14:01:07 +01:00
}
2024-04-05 12:16:49 +01: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 12:16:49 +01:00
// eslint-disable-next-line @typescript-eslint/no-explicit-any -- Old code before rule was applied
2020-11-12 19:13:28 +00:00
const style : any = {
2020-11-13 17:09:28 +00:00
display : itemVisible ( item , moveMode ) ? 'flex' : 'none' ,
2020-09-15 14:01:07 +01:00
flexDirection : item.direction ,
};
2020-11-13 17:09:28 +00:00
const size : Size = itemSize ( item , parent , sizes , true );
2020-09-15 14:01:07 +01:00
const className = `resizableLayoutItem rli- ${ item . key } ` ;
2020-10-09 18:35:46 +01: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 14:01:07 +01:00
return (
< Resizable
key = { item . key }
className = { className }
style = { style }
size = { size }
2024-04-05 12:16:49 +01:00
// eslint-disable-next-line @typescript-eslint/no-explicit-any -- Old code before rule was applied
2020-11-13 17:09:28 +00:00
onResizeStart = { onResizeStart as any }
2024-04-05 12:16:49 +01:00
// eslint-disable-next-line @typescript-eslint/no-explicit-any -- Old code before rule was applied
2020-11-13 17:09:28 +00:00
onResize = { onResize as any }
2024-04-05 12:16:49 +01:00
// eslint-disable-next-line @typescript-eslint/no-explicit-any -- Old code before rule was applied
2020-11-13 17:09:28 +00:00
onResizeStop = { onResizeStop as any }
2020-09-15 14:01:07 +01:00
enable = { enable }
2020-11-13 17:09:28 +00: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 14:01:07 +01:00
>
{ children }
</ Resizable >
);
} else {
return (
< div key = { item . key } className = { className } style = {{ ... style , ... size }}>
{ children }
</ div >
);
}
}
2020-11-12 19:13:28 +00:00
function ResizableLayout ( props : Props ) {
2020-09-15 14:01:07 +01:00
const eventEmitter = useRef ( new EventEmitter ());
2024-04-05 12:16:49 +01:00
// eslint-disable-next-line @typescript-eslint/no-explicit-any -- Old code before rule was applied
2020-09-15 14:01:07 +01:00
const [ resizedItem , setResizedItem ] = useState < any >( null );
2024-04-05 12:16:49 +01:00
// eslint-disable-next-line @typescript-eslint/no-explicit-any -- Old code before rule was applied
2020-11-13 17:09:28 +00: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 14:01:07 +01:00
2020-11-13 17:09:28 +00:00
return (
< StyledWrapperRoot key = { item . key } size = { size }>
{ moveOverlay }
{ comp }
</ StyledWrapperRoot >
);
}
2024-04-05 12:16:49 +01:00
// eslint-disable-next-line @typescript-eslint/no-explicit-any -- Old code before rule was applied
2020-11-13 17:09:28 +00:00
function renderLayoutItem ( item : LayoutItem , parent : LayoutItem | null , sizes : LayoutItemSizes , isVisible : boolean , isLastChild : boolean ) : any {
2020-09-15 14:01:07 +01: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 14:01:07 +01:00
});
}
2024-04-05 12:16:49 +01:00
// eslint-disable-next-line @typescript-eslint/no-explicit-any -- Old code before rule was applied
2020-11-13 17:09:28 +00: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 12:16:49 +01:00
// eslint-disable-next-line @typescript-eslint/no-explicit-any -- Old code before rule was applied
2020-11-13 17:09:28 +00: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 14:01:07 +01:00
props . onResize ({ layout : newLayout });
eventEmitter . current . emit ( 'resize' );
}
2024-04-05 12:16:49 +01:00
// eslint-disable-next-line @typescript-eslint/no-explicit-any -- Old code before rule was applied
2020-11-13 17:09:28 +00:00
function onResizeStop ( _event : any , _direction : any , _refToElement : any , delta : any ) {
2020-09-15 14:01:07 +01:00
onResize ( _event , _direction , _refToElement , delta );
setResizedItem ( null );
}
2021-07-06 15:57:48 +03:00
const resizedItemMaxSize = resizedItem && item . key === resizedItem . key ? resizedItem.maxSize : null ;
2020-09-15 14:01:07 +01:00
if ( ! item . children ) {
2020-11-13 17:09:28 +00:00
const size = itemSize ( item , parent , sizes , false );
2020-09-15 14:01:07 +01:00
const comp = props . renderItem ( item . key , {
item : item ,
eventEmitter : eventEmitter.current ,
2020-11-13 17:09:28 +00:00
size : size ,
2020-09-15 14:01:07 +01:00
visible : isVisible ,
});
2020-11-13 17:09:28 +00: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 14:01:07 +01:00
} else {
const childrenComponents = [];
2020-10-09 18:35:46 +01:00
for ( let i = 0 ; i < item . children . length ; i ++ ) {
const child = item . children [ i ];
2020-11-13 17:09:28 +00:00
childrenComponents . push ( renderLayoutItem ( child , item , sizes , isVisible && itemVisible ( child , props . moveMode ), i === item . children . length - 1 ));
2020-09-15 14:01:07 +01: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 14:01:07 +01:00
}
}
2020-11-13 17:09:28 +00:00
useEffect (() => {
validateLayout ( props . layout );
}, [ props . layout ]);
2020-09-15 14:01:07 +01:00
2020-11-13 17:09:28 +00:00
useWindowResizeEvent ( eventEmitter );
const sizes = useLayoutItemSizes ( props . layout , props . moveMode );
2024-04-05 12:16:49 +01:00
// eslint-disable-next-line @typescript-eslint/no-explicit-any -- Old code before rule was applied
2020-11-13 17:09:28 +00: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 14:01:07 +01:00
}
export default ResizableLayout ;