2021-06-23 10:05:23 +02:00
|
|
|
import { FC, MouseEvent, useCallback, useEffect, useMemo, useRef } from 'react';
|
2021-04-19 18:34:31 +02:00
|
|
|
import Draggable from 'react-draggable';
|
|
|
|
import { DraggableWindowProps } from './DraggableWindow.types';
|
|
|
|
|
2021-04-21 22:32:31 +02:00
|
|
|
const currentWindows: HTMLDivElement[] = [];
|
|
|
|
|
2021-05-10 19:11:16 +02:00
|
|
|
export const DraggableWindow: FC<DraggableWindowProps> = props =>
|
2021-04-19 18:34:31 +02:00
|
|
|
{
|
2021-06-23 10:05:23 +02:00
|
|
|
const { disableDrag = false, noCenter = false, handle = '.drag-handler', draggableOptions = {}, children = null } = props;
|
2021-05-10 19:11:16 +02:00
|
|
|
const elementRef = useRef<HTMLDivElement>();
|
2021-04-21 22:32:31 +02:00
|
|
|
|
2021-06-23 10:05:23 +02:00
|
|
|
const bringToTop = useCallback(() =>
|
2021-04-21 22:32:31 +02:00
|
|
|
{
|
|
|
|
let zIndex = 400;
|
|
|
|
|
|
|
|
for(const existingWindow of currentWindows)
|
|
|
|
{
|
|
|
|
zIndex += 1;
|
|
|
|
|
|
|
|
existingWindow.style.zIndex = zIndex.toString();
|
|
|
|
}
|
2021-06-23 10:05:23 +02:00
|
|
|
}, []);
|
2021-04-21 22:32:31 +02:00
|
|
|
|
2021-06-23 10:05:23 +02:00
|
|
|
const onMouseDown = useCallback((event: MouseEvent) =>
|
2021-04-21 22:32:31 +02:00
|
|
|
{
|
2021-04-23 07:16:09 +02:00
|
|
|
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);
|
|
|
|
}
|
|
|
|
|
2021-04-21 22:32:31 +02:00
|
|
|
bringToTop();
|
2021-06-23 10:05:23 +02:00
|
|
|
}, [ bringToTop ]);
|
2021-04-21 22:32:31 +02:00
|
|
|
|
|
|
|
useEffect(() =>
|
|
|
|
{
|
2021-04-24 03:05:56 +02:00
|
|
|
if(!elementRef) return;
|
|
|
|
|
2021-04-21 22:32:31 +02:00
|
|
|
const element = elementRef.current;
|
|
|
|
|
|
|
|
currentWindows.push(element);
|
|
|
|
|
|
|
|
bringToTop();
|
|
|
|
|
2021-05-12 00:11:22 +02:00
|
|
|
if(!noCenter)
|
|
|
|
{
|
|
|
|
const left = ((document.body.clientWidth / 2) - (element.clientWidth / 2));
|
|
|
|
const top = ((document.body.clientHeight / 2) - (element.clientHeight / 2));
|
2021-04-28 19:47:57 +02:00
|
|
|
|
2021-05-12 00:11:22 +02:00
|
|
|
element.style.left = `${ left }px`;
|
|
|
|
element.style.top = `${ top }px`;
|
|
|
|
}
|
2021-04-28 19:47:57 +02:00
|
|
|
|
2021-06-12 04:53:56 +02:00
|
|
|
element.style.visibility = 'visible';
|
|
|
|
|
2021-04-21 22:32:31 +02:00
|
|
|
return () =>
|
|
|
|
{
|
|
|
|
const index = currentWindows.indexOf(element);
|
|
|
|
|
|
|
|
if(index >= 0) currentWindows.splice(index, 1);
|
|
|
|
}
|
2021-06-23 10:05:23 +02:00
|
|
|
}, [ elementRef, noCenter, bringToTop ]);
|
2021-04-21 22:32:31 +02:00
|
|
|
|
2021-06-23 10:05:23 +02:00
|
|
|
const getWindowContent = useMemo(() =>
|
2021-05-10 19:11:16 +02:00
|
|
|
{
|
|
|
|
return (
|
2021-04-28 19:47:57 +02:00
|
|
|
<div ref={ elementRef } className="position-absolute draggable-window" onMouseDownCapture={ onMouseDown }>
|
2021-06-23 10:05:23 +02:00
|
|
|
{ children }
|
2021-04-21 22:32:31 +02:00
|
|
|
</div>
|
2021-05-10 19:11:16 +02:00
|
|
|
);
|
2021-06-23 10:05:23 +02:00
|
|
|
}, [ children, onMouseDown ]);
|
2021-05-10 19:11:16 +02:00
|
|
|
|
2021-06-23 10:05:23 +02:00
|
|
|
return disableDrag ? getWindowContent : <Draggable handle={ handle } { ...draggableOptions }>{ getWindowContent }</Draggable>;
|
2021-04-19 18:34:31 +02:00
|
|
|
}
|