import * as React from 'react'; import { FixedSizeList as List } from 'react-window'; import { Properties } from '../ContainerProperties/ContainerProperties'; import { IContainerModel } from '../../Interfaces/IContainerModel'; import { FindContainerById, MakeRecursionDFSIterator } from '../../utils/itertools'; import { ISymbolModel } from '../../Interfaces/ISymbolModel'; import { PropertyType } from '../../Enums/PropertyType'; import { ExclamationTriangleIcon } from '@heroicons/react/24/outline'; interface IElementsListProps { mainContainer: IContainerModel symbols: Map selectedContainer: IContainerModel | undefined onPropertyChange: ( key: string, value: string | number | boolean | number[], type?: PropertyType ) => void selectContainer: (containerId: string) => void addContainer: (index: number, type: string, parent: string) => void } function RemoveBorderClasses(target: HTMLButtonElement, exception: string = ''): void { const bordersClasses = ['border-t-8', 'border-8', 'border-b-8'].filter(className => className !== exception); target.classList.remove(...bordersClasses); } function HandleDragLeave(event: React.DragEvent): void { const target: HTMLButtonElement = event.target as HTMLButtonElement; RemoveBorderClasses(target); } 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. if (target.id === mainContainer.properties.id) { target.classList.add('border-8'); return; } if (y < 12) { RemoveBorderClasses(target, 'border-t-8'); target.classList.add('border-t-8'); } else if (y < 24) { RemoveBorderClasses(target, 'border-8'); target.classList.add('border-8'); } else { RemoveBorderClasses(target, 'border-b-8'); target.classList.add('border-b-8'); } } 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 ); } } export function ElementsList(props: IElementsListProps): JSX.Element { // Render const it = MakeRecursionDFSIterator(props.mainContainer, 0, [0, 0], true); const containers = [...it]; function Row({ index, style }: { index: number style: React.CSSProperties }): JSX.Element { const { container, depth } = containers[index]; const key = container.properties.id.toString(); const tabs = '|\t'.repeat(depth); const text = container.properties.displayedText === key ? `${key}` : `${container.properties.displayedText}`; const isSelected = props.selectedContainer !== undefined && props.selectedContainer !== null && props.selectedContainer.properties.id === container.properties.id; const selectedClass: string = isSelected ? 'border-l-4 bg-blue-500 shadow-lg shadow-blue-500/60 hover:bg-blue-600 hover:shadow-blue-500 text-slate-50' : 'bg-slate-300/60 hover:bg-slate-400 hover:shadow-slate-400'; return ( ); } return (
{Row}
); }