87 lines
2.8 KiB
TypeScript
87 lines
2.8 KiB
TypeScript
import {
|
|
cascadePosition,
|
|
centerPosition,
|
|
isWindowOutsideBounds,
|
|
WINDOW_OFFSCREEN_BUFFER_PX,
|
|
} from "components/system/Window/functions";
|
|
import useMinMaxRef from "components/system/Window/RndWindow/useMinMaxRef";
|
|
import type { Size } from "components/system/Window/RndWindow/useResizable";
|
|
import { useProcesses } from "contexts/process";
|
|
import { useSession } from "contexts/session";
|
|
import { useEffect, useLayoutEffect, useMemo, useState } from "react";
|
|
import type { Position } from "react-rnd";
|
|
import { useTheme } from "styled-components";
|
|
import { calcInitialPosition, getWindowViewport } from "utils/functions";
|
|
|
|
type Draggable = [Position, React.Dispatch<React.SetStateAction<Position>>];
|
|
|
|
const useDraggable = (id: string, size: Size): Draggable => {
|
|
const {
|
|
sizes: {
|
|
window: { cascadeOffset },
|
|
},
|
|
} = useTheme();
|
|
const { processes } = useProcesses();
|
|
const { autoSizing, closing, componentWindow, initialRelativePosition } =
|
|
processes[id] || {};
|
|
const { stackOrder, windowStates: { [id]: windowState } = {} } = useSession();
|
|
const { position: sessionPosition, size: sessionSize } = windowState || {};
|
|
const isOffscreen = useMemo(
|
|
() => isWindowOutsideBounds(windowState, getWindowViewport()),
|
|
[windowState]
|
|
);
|
|
const [position, setPosition] = useState<Position>(
|
|
() =>
|
|
(!isOffscreen && sessionPosition) ||
|
|
cascadePosition(id, processes, stackOrder, cascadeOffset) ||
|
|
centerPosition(size)
|
|
);
|
|
const blockAutoPositionRef = useMinMaxRef(id);
|
|
|
|
useEffect(() => {
|
|
const monitorViewportResize = (): void => {
|
|
const vwSize = getWindowViewport();
|
|
|
|
if (isWindowOutsideBounds({ position, size }, vwSize, true)) {
|
|
setPosition(({ x, y }) => {
|
|
const xOffset = vwSize.x - WINDOW_OFFSCREEN_BUFFER_PX.RIGHT;
|
|
const yOffset = vwSize.y - WINDOW_OFFSCREEN_BUFFER_PX.BOTTOM;
|
|
|
|
return {
|
|
x: x > xOffset ? xOffset : x,
|
|
y: y > yOffset ? yOffset : y,
|
|
};
|
|
});
|
|
}
|
|
};
|
|
|
|
window.addEventListener("resize", monitorViewportResize, { passive: true });
|
|
|
|
return () => window.removeEventListener("resize", monitorViewportResize);
|
|
}, [position, size]);
|
|
|
|
useLayoutEffect(() => {
|
|
if (
|
|
autoSizing &&
|
|
!closing &&
|
|
sessionSize &&
|
|
!sessionPosition &&
|
|
!blockAutoPositionRef.current
|
|
) {
|
|
setPosition(centerPosition(sessionSize));
|
|
}
|
|
}, [autoSizing, blockAutoPositionRef, closing, sessionPosition, sessionSize]);
|
|
|
|
useLayoutEffect(() => {
|
|
if (initialRelativePosition && componentWindow) {
|
|
setPosition(
|
|
calcInitialPosition(initialRelativePosition, componentWindow)
|
|
);
|
|
}
|
|
}, [componentWindow, initialRelativePosition]);
|
|
|
|
return [position, setPosition];
|
|
};
|
|
|
|
export default useDraggable;
|