svg-layout-designer-react/src/Components/ElementsSidebar/MouseEventHandlers.ts
Eric Nguyen ec3fddec9d Merged PR 165: Move useEffects to named functions
Move useEffects to named functions
2022-08-22 15:52:40 +00:00

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
);
}
}