Separated the model and the Container entity in order to remove any mutation operation
This commit is contained in:
parent
964d9a0e57
commit
e2a099457c
7 changed files with 206 additions and 178 deletions
119
src/App.tsx
119
src/App.tsx
|
@ -1,19 +1,20 @@
|
|||
import React, { Children } from 'react';
|
||||
import React from 'react';
|
||||
import './App.scss';
|
||||
import Sidebar from './Components/Sidebar/Sidebar';
|
||||
import { ElementsSidebar } from './Components/ElementsSidebar/ElementsSidebar';
|
||||
import { AvailableContainer } from './Interfaces/AvailableContainer';
|
||||
import { Configuration } from './Interfaces/Configuration';
|
||||
import { Container } from './Components/SVG/Elements/Container';
|
||||
import { SVG } from './Components/SVG/SVG';
|
||||
import { History } from './Components/History/History';
|
||||
import { ContainerModel, IContainerModel, MakeIterator } from './Components/SVG/Elements/ContainerModel';
|
||||
import Properties from './Interfaces/Properties';
|
||||
|
||||
interface IAppProps {
|
||||
}
|
||||
|
||||
export interface IHistoryState {
|
||||
MainContainer: Container | null,
|
||||
SelectedContainer: Container | null,
|
||||
MainContainer: IContainerModel | null,
|
||||
SelectedContainer: IContainerModel | null,
|
||||
TypeCounters: Record<string, number>
|
||||
}
|
||||
|
||||
|
@ -56,19 +57,16 @@ class App extends React.Component<IAppProps> {
|
|||
// Fetch the configuration from the API
|
||||
fetchConfiguration().then((configuration: Configuration) => {
|
||||
// Set the main container from the given properties of the API
|
||||
const MainContainer = new Container(
|
||||
const MainContainer = new ContainerModel(
|
||||
null,
|
||||
{
|
||||
parent: null,
|
||||
properties: {
|
||||
id: 'main',
|
||||
x: 0,
|
||||
y: 0,
|
||||
width: configuration.MainContainer.Width,
|
||||
height: configuration.MainContainer.Height,
|
||||
fillOpacity: 0,
|
||||
stroke: 'black'
|
||||
},
|
||||
children: []
|
||||
id: 'main',
|
||||
x: 0,
|
||||
y: 0,
|
||||
width: configuration.MainContainer.Width,
|
||||
height: configuration.MainContainer.Height,
|
||||
fillOpacity: 0,
|
||||
stroke: 'black'
|
||||
}
|
||||
);
|
||||
|
||||
|
@ -116,7 +114,7 @@ class App extends React.Component<IAppProps> {
|
|||
* Select a container
|
||||
* @param container Selected container
|
||||
*/
|
||||
public SelectContainer(container: Container) {
|
||||
public SelectContainer(container: ContainerModel) {
|
||||
const history = this.getCurrentHistory();
|
||||
const current = history[history.length - 1];
|
||||
this.setState({
|
||||
|
@ -141,30 +139,21 @@ class App extends React.Component<IAppProps> {
|
|||
|
||||
if (current.SelectedContainer === null ||
|
||||
current.SelectedContainer === undefined) {
|
||||
throw new Error('Property was changed before selecting a Container');
|
||||
throw new Error('[OnPropertyChange] Property was changed before selecting a Container');
|
||||
}
|
||||
|
||||
if (current.MainContainer === null ||
|
||||
current.MainContainer === undefined) {
|
||||
throw new Error('Property was changed before the main container was added');
|
||||
throw new Error('[OnPropertyChange] Property was changed before the main container was added');
|
||||
}
|
||||
|
||||
const pair = {} as Record<string, string | number>;
|
||||
pair[key] = value;
|
||||
const properties = Object.assign(current.SelectedContainer.props.properties, pair);
|
||||
const props = {
|
||||
...current.SelectedContainer.props,
|
||||
properties
|
||||
};
|
||||
|
||||
const newSelectedContainer = new Container(props);
|
||||
|
||||
const parent = current.SelectedContainer.props.parent;
|
||||
if (parent === null) {
|
||||
const clone: IContainerModel = structuredClone(current.SelectedContainer);
|
||||
(clone.properties as any)[key] = value;
|
||||
this.setState({
|
||||
history: history.concat([{
|
||||
SelectedContainer: newSelectedContainer,
|
||||
MainContainer: newSelectedContainer,
|
||||
SelectedContainer: clone,
|
||||
MainContainer: clone,
|
||||
TypeCounters: current.TypeCounters
|
||||
}]),
|
||||
historyCurrentStep: history.length
|
||||
|
@ -172,15 +161,27 @@ class App extends React.Component<IAppProps> {
|
|||
return;
|
||||
}
|
||||
|
||||
const index = parent.props.children.indexOf(current.SelectedContainer);
|
||||
parent.props.children[index] = newSelectedContainer;
|
||||
const clone: IContainerModel = structuredClone(current.MainContainer);
|
||||
const it = MakeIterator(clone);
|
||||
let container: ContainerModel | null = null;
|
||||
for (const child of it) {
|
||||
if (child.properties.id === current.SelectedContainer.properties.id) {
|
||||
container = child as ContainerModel;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (container === null) {
|
||||
throw new Error('[OnPropertyChange] Container model was not found among children of the main container!');
|
||||
}
|
||||
|
||||
(container.properties as any)[key] = value;
|
||||
|
||||
const newMainContainer = new Container(Object.assign({}, current.MainContainer.props));
|
||||
this.setState(
|
||||
{
|
||||
history: history.concat([{
|
||||
SelectedContainer: newSelectedContainer,
|
||||
MainContainer: newMainContainer,
|
||||
SelectedContainer: container,
|
||||
MainContainer: clone,
|
||||
TypeCounters: current.TypeCounters
|
||||
}]),
|
||||
historyCurrentStep: history.length
|
||||
|
@ -221,36 +222,52 @@ class App extends React.Component<IAppProps> {
|
|||
} else {
|
||||
newCounters[type]++;
|
||||
}
|
||||
const count = newCounters[type];
|
||||
|
||||
// Create maincontainer model
|
||||
const structure: IContainerModel = structuredClone(current.MainContainer);
|
||||
const clone = Object.assign(new ContainerModel(null, {} as Properties), structure);
|
||||
|
||||
// Find the parent
|
||||
const it = MakeIterator(clone);
|
||||
let parent: ContainerModel | null = null;
|
||||
for (const child of it) {
|
||||
if (child.properties.id === current.SelectedContainer.properties.id) {
|
||||
parent = child as ContainerModel;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (parent === null) {
|
||||
throw new Error('[OnPropertyChange] Container model was not found among children of the main container!');
|
||||
}
|
||||
|
||||
// Create the container
|
||||
const parent = current.SelectedContainer;
|
||||
const count = newCounters[type];
|
||||
const container = new Container({
|
||||
const newContainer = new ContainerModel(
|
||||
parent,
|
||||
properties: {
|
||||
{
|
||||
id: `${type}-${count}`,
|
||||
x: 0,
|
||||
y: 0,
|
||||
width: properties?.Width,
|
||||
height: parent.props.properties.height,
|
||||
height: parent.properties.height,
|
||||
...properties.Style
|
||||
},
|
||||
children: [],
|
||||
userData: {
|
||||
} as Properties,
|
||||
[],
|
||||
{
|
||||
type
|
||||
}
|
||||
});
|
||||
);
|
||||
|
||||
// And push it the the parent children
|
||||
parent.props.children.push(container);
|
||||
parent.children.push(newContainer);
|
||||
|
||||
// Update the state
|
||||
const newMainContainer = new Container(Object.assign({}, current.MainContainer.props));
|
||||
this.setState({
|
||||
history: history.concat([{
|
||||
MainContainer: newMainContainer,
|
||||
MainContainer: clone,
|
||||
TypeCounters: newCounters,
|
||||
SelectedContainer: current.SelectedContainer
|
||||
SelectedContainer: parent
|
||||
}]),
|
||||
historyCurrentStep: history.length
|
||||
} as IAppState);
|
||||
|
@ -283,7 +300,7 @@ class App extends React.Component<IAppProps> {
|
|||
isOpen={this.state.isSVGSidebarOpen}
|
||||
onClick={() => this.ToggleElementsSidebar()}
|
||||
onPropertyChange={(key: string, value: string) => this.OnPropertyChange(key, value)}
|
||||
selectContainer={(container: Container) => this.SelectContainer(container)}
|
||||
selectContainer={(container: ContainerModel) => this.SelectContainer(container)}
|
||||
/>
|
||||
<button className='fixed z-10 top-4 right-12 text-lg bg-slate-200 hover:bg-slate-300 transition-all drop-shadow-md hover:drop-shadow-lg py-2 px-3 rounded-lg' onClick={() => this.ToggleElementsSidebar()}>☰ Elements</button>
|
||||
<SVG selected={current.SelectedContainer}>
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue