175 lines
4.7 KiB
TypeScript
175 lines
4.7 KiB
TypeScript
import React, { RefObject, Dispatch, SetStateAction, useEffect } from 'react';
|
|
import { IContainerModel } from '../../Interfaces/IContainerModel';
|
|
import { IPoint } from '../../Interfaces/IPoint';
|
|
import { findContainerById } from '../../utils/itertools';
|
|
|
|
export function useMouseEvents(
|
|
isContextMenuOpen: boolean,
|
|
elementRef: RefObject<HTMLDivElement>,
|
|
setIsContextMenuOpen: Dispatch<SetStateAction<boolean>>,
|
|
setOnClickContainerId: Dispatch<SetStateAction<string>>,
|
|
setContextMenuPosition: Dispatch<SetStateAction<IPoint>>
|
|
): void {
|
|
useEffect(() => {
|
|
const onContextMenu = (event: MouseEvent): void => handleRightClick(
|
|
event,
|
|
setIsContextMenuOpen,
|
|
setOnClickContainerId,
|
|
setContextMenuPosition
|
|
);
|
|
|
|
const onLeftClick = (): void => handleLeftClick(
|
|
isContextMenuOpen,
|
|
setIsContextMenuOpen,
|
|
setOnClickContainerId
|
|
);
|
|
|
|
elementRef.current?.addEventListener(
|
|
'contextmenu',
|
|
onContextMenu
|
|
);
|
|
|
|
window.addEventListener(
|
|
'click',
|
|
onLeftClick
|
|
);
|
|
|
|
return () => {
|
|
elementRef.current?.removeEventListener(
|
|
'contextmenu',
|
|
onContextMenu
|
|
);
|
|
|
|
window.removeEventListener(
|
|
'click',
|
|
onLeftClick
|
|
);
|
|
};
|
|
});
|
|
}
|
|
|
|
export function handleRightClick(
|
|
event: MouseEvent,
|
|
setIsContextMenuOpen: React.Dispatch<React.SetStateAction<boolean>>,
|
|
setOnClickContainerId: React.Dispatch<React.SetStateAction<string>>,
|
|
setContextMenuPosition: React.Dispatch<React.SetStateAction<IPoint>>
|
|
): void {
|
|
event.preventDefault();
|
|
|
|
if (!(event.target instanceof HTMLButtonElement)) {
|
|
setIsContextMenuOpen(false);
|
|
setOnClickContainerId('');
|
|
return;
|
|
}
|
|
|
|
const contextMenuPosition: IPoint = { x: event.pageX, y: event.pageY };
|
|
setIsContextMenuOpen(true);
|
|
setOnClickContainerId(event.target.id);
|
|
setContextMenuPosition(contextMenuPosition);
|
|
}
|
|
|
|
export function handleLeftClick(
|
|
isContextMenuOpen: boolean,
|
|
setIsContextMenuOpen: React.Dispatch<React.SetStateAction<boolean>>,
|
|
setOnClickContainerId: React.Dispatch<React.SetStateAction<string>>
|
|
): void {
|
|
if (!isContextMenuOpen) {
|
|
return;
|
|
}
|
|
|
|
setIsContextMenuOpen(false);
|
|
setOnClickContainerId('');
|
|
}
|
|
|
|
export function removeBorderClasses(target: HTMLButtonElement): void {
|
|
const bordersClasses = ['border-t-8', 'border-8', 'border-b-8'];
|
|
target.classList.remove(...bordersClasses);
|
|
}
|
|
|
|
export function handleDragLeave(event: React.DragEvent): void {
|
|
const target: HTMLButtonElement = event.target as HTMLButtonElement;
|
|
removeBorderClasses(target);
|
|
}
|
|
|
|
export function handleDragOver(
|
|
event: React.DragEvent,
|
|
mainContainer: IContainerModel
|
|
): void {
|
|
event.preventDefault();
|
|
const target: HTMLButtonElement = event.target as HTMLButtonElement;
|
|
const rect = target.getBoundingClientRect();
|
|
const y = event.clientY - rect.top; // y position within the element.
|
|
removeBorderClasses(target);
|
|
|
|
if (target.id === mainContainer.properties.id) {
|
|
target.classList.add('border-8');
|
|
return;
|
|
}
|
|
|
|
if (y < 12) {
|
|
target.classList.add('border-t-8');
|
|
} else if (y < 24) {
|
|
target.classList.add('border-8');
|
|
} else {
|
|
target.classList.add('border-b-8');
|
|
}
|
|
}
|
|
|
|
export function handleOnDrop(
|
|
event: React.DragEvent,
|
|
mainContainer: IContainerModel,
|
|
addContainer: (index: number, type: string, parent: string) => void
|
|
): void {
|
|
event.preventDefault();
|
|
const type = event.dataTransfer.getData('type');
|
|
const target: HTMLButtonElement = event.target as HTMLButtonElement;
|
|
removeBorderClasses(target);
|
|
|
|
const targetContainer: IContainerModel | undefined = findContainerById(
|
|
mainContainer,
|
|
target.id
|
|
);
|
|
|
|
if (targetContainer === undefined) {
|
|
throw new Error('[handleOnDrop] Tried to drop onto a unknown container!');
|
|
}
|
|
|
|
if (targetContainer === mainContainer) {
|
|
// if the container is the root, only add type as child
|
|
addContainer(
|
|
targetContainer.children.length,
|
|
type,
|
|
targetContainer.properties.id);
|
|
return;
|
|
}
|
|
|
|
if (targetContainer.parent === null ||
|
|
targetContainer.parent === undefined) {
|
|
throw new Error('[handleDrop] Tried to drop into a child container without a parent!');
|
|
}
|
|
|
|
const rect = target.getBoundingClientRect();
|
|
const y = event.clientY - rect.top; // y position within the element.
|
|
|
|
// locate the hitboxes
|
|
if (y < 12) {
|
|
const index = targetContainer.parent.children.indexOf(targetContainer);
|
|
addContainer(
|
|
index,
|
|
type,
|
|
targetContainer.parent.properties.id
|
|
);
|
|
} else if (y < 24) {
|
|
addContainer(
|
|
targetContainer.children.length,
|
|
type,
|
|
targetContainer.properties.id);
|
|
} else {
|
|
const index = targetContainer.parent.children.indexOf(targetContainer);
|
|
addContainer(
|
|
index + 1,
|
|
type,
|
|
targetContainer.parent.properties.id
|
|
);
|
|
}
|
|
}
|