Refactor Editor and module functions (#15)
All checks were successful
continuous-integration/drone/push Build is passing

Moved all module functions to separate utils modules

Replaced standard with standard with typescript

Extracted UI elements to separate component

Reviewed-on: https://git.siklos-chaneru.duckdns.org/Siklos/svg-layout-designer-react/pulls/15
This commit is contained in:
Siklos 2022-08-05 15:38:44 -04:00
parent 8e34d6b72a
commit 293af45144
26 changed files with 477 additions and 367 deletions

65
src/utils/itertools.ts Normal file
View file

@ -0,0 +1,65 @@
import { IContainerModel } from '../Interfaces/ContainerModel';
/**
* Returns a Generator iterating of over the children depth-first
*/
export function * MakeIterator(root: IContainerModel): Generator<IContainerModel, void, unknown> {
const queue: IContainerModel[] = [root];
const visited = new Set<IContainerModel>(queue);
while (queue.length > 0) {
const container = queue.pop() as IContainerModel;
yield container;
// if this reverse() gets costly, replace it by a simple for
container.children.forEach((child) => {
if (visited.has(child)) {
return;
}
visited.add(child);
queue.push(child);
});
}
}
/**
* Returns the depth of the container
* @returns The depth of the container
*/
export function getDepth(parent: IContainerModel): number {
let depth = 0;
let current: IContainerModel | null = parent;
while (current != null) {
depth++;
current = current.parent;
}
return depth;
}
/**
* Returns the absolute position by iterating to the parent
* @returns The absolute position of the container
*/
export function getAbsolutePosition(container: IContainerModel): [number, number] {
let x = Number(container.properties.x);
let y = Number(container.properties.y);
let current = container.parent;
while (current != null) {
x += Number(current.properties.x);
y += Number(current.properties.y);
current = current.parent;
}
return [x, y];
}
export function findContainerById(root: IContainerModel, id: string): IContainerModel | undefined {
const it = MakeIterator(root);
for (const container of it) {
if (container.properties.id === id) {
return container;
}
}
return undefined;
}

54
src/utils/saveload.ts Normal file
View file

@ -0,0 +1,54 @@
import { findContainerById, MakeIterator } from './itertools';
import { IEditorState } from '../Editor';
/**
* Revive the Editor state
* by setting the containers references to their parent
* @param editorState Editor state
*/
export function Revive(editorState: IEditorState): void {
const history = editorState.history;
for (const state of history) {
if (state.MainContainer === null || state.MainContainer === undefined) {
continue;
}
const it = MakeIterator(state.MainContainer);
for (const container of it) {
const parentId = container.properties.parentId;
if (parentId === null) {
container.parent = null;
continue;
}
const parent = findContainerById(state.MainContainer, parentId);
if (parent === undefined) {
continue;
}
container.parent = parent;
}
const selected = findContainerById(state.MainContainer, state.SelectedContainerId);
if (selected === undefined) {
state.SelectedContainer = null;
continue;
}
state.SelectedContainer = selected;
}
}
export const getCircularReplacer = (): (key: any, value: object | null) => object | null | undefined => {
const seen = new WeakSet();
return (key: any, value: object | null) => {
if (key === 'parent') {
return;
}
if (typeof value === 'object' && value !== null) {
if (seen.has(value)) {
return;
}
seen.add(value);
}
return value;
};
};

View file

@ -1,13 +1,13 @@
/* eslint-disable import/export */
import * as React from 'react';
import { cleanup, render } from '@testing-library/react';
import { cleanup, render, RenderResult } from '@testing-library/react';
import { afterEach } from 'vitest';
afterEach(() => {
cleanup();
});
const customRender = (ui: React.ReactElement, options = {}) =>
const customRender = (ui: React.ReactElement, options = {}): RenderResult =>
render(ui, {
// wrap provider(s) here if needed
wrapper: ({ children }) => children,