nitro-react/src/layout/draggable-window/DraggableWindow.tsx

90 lines
2.4 KiB
TypeScript

import { FC, MouseEvent, useCallback, useEffect, useMemo, useRef } from 'react';
import Draggable from 'react-draggable';
import { DraggableWindowProps } from './DraggableWindow.types';
const currentWindows: HTMLDivElement[] = [];
export const DraggableWindow: FC<DraggableWindowProps> = props =>
{
const { disableDrag = false, noCenter = false, handle = '.drag-handler', draggableOptions = {}, children = null } = props;
const elementRef = useRef<HTMLDivElement>();
const bringToTop = useCallback(() =>
{
let zIndex = 400;
for(const existingWindow of currentWindows)
{
zIndex += 1;
existingWindow.style.zIndex = zIndex.toString();
}
}, []);
const onMouseDown = useCallback((event: MouseEvent) =>
{
const index = currentWindows.indexOf(elementRef.current);
if(index === -1)
{
currentWindows.push(elementRef.current);
}
else if(index === (currentWindows.length - 1)) return;
else if(index >= 0)
{
currentWindows.splice(index, 1);
currentWindows.push(elementRef.current);
}
bringToTop();
}, [ bringToTop ]);
useEffect(() =>
{
if(!elementRef) return;
const element = elementRef.current;
currentWindows.push(element);
bringToTop();
if(!noCenter)
{
const left = ((document.body.clientWidth / 2) - (element.clientWidth / 2));
const top = ((document.body.clientHeight / 2) - (element.clientHeight / 2));
element.style.left = `${ left }px`;
element.style.top = `${ top }px`;
}
else
{
element.style.left = `0px`;
element.style.top = `0px`;
}
element.style.visibility = 'visible';
return () =>
{
const index = currentWindows.indexOf(element);
if(index >= 0) currentWindows.splice(index, 1);
}
}, [ elementRef, noCenter, bringToTop ]);
const getWindowContent = useMemo(() =>
{
return (
<div ref={ elementRef } className="position-absolute draggable-window" onMouseDownCapture={ onMouseDown }>
{ children }
</div>
);
}, [ children, onMouseDown ]);
return disableDrag ? getWindowContent : <Draggable handle={ handle } { ...draggableOptions }>{ getWindowContent }</Draggable>;
}