Merged PR 162: Implement symbols and other stuff (see desc)

Implement symbols
- Add, Remove, Select Container
- Form
- Link with container
- Symbol behavior application to container (move to x with xpositionreference)

Important changes
- Remove SelectedContainer from HistoryState, meaning that it will be slower for each load but will be faster for each operations* (SetHistory, SelectContainer, DeleteContainer, SymbolOperations)
- ElementsSidebar now opens with isSidebarOpen meaning that both sidebar will open on toggle
- Moved camelize, transformX, restoreX to different modules (stringtools.ts, svg.ts)
This commit is contained in:
Eric Nguyen 2022-08-22 13:58:32 +00:00
parent 58ef28fe89
commit 8b8d88f885
48 changed files with 1453 additions and 188 deletions

View file

@ -3,8 +3,9 @@ import { IContainerModel, ContainerModel } from '../../Interfaces/IContainerMode
import { IHistoryState } from '../../Interfaces/IHistoryState';
import { findContainerById } from '../../utils/itertools';
import { getCurrentHistory } from './Editor';
import { restoreX } from '../SVG/Elements/Container';
import { ApplyBehaviors } from './Behaviors/Behaviors';
import { restoreX } from '../../utils/svg';
import { ISymbolModel } from '../../Interfaces/ISymbolModel';
/**
* Handled the property change event in the properties form
@ -16,6 +17,7 @@ export function OnPropertyChange(
key: string,
value: string | number | boolean,
isStyle: boolean = false,
selected: IContainerModel | undefined,
fullHistory: IHistoryState[],
historyCurrentStep: number,
setHistory: Dispatch<SetStateAction<IHistoryState[]>>,
@ -24,37 +26,66 @@ export function OnPropertyChange(
const history = getCurrentHistory(fullHistory, historyCurrentStep);
const current = history[history.length - 1];
if (current.SelectedContainer === null ||
current.SelectedContainer === undefined) {
if (selected === null ||
selected === undefined) {
throw new Error('[OnPropertyChange] Property was changed before selecting a Container');
}
const mainContainerClone: IContainerModel = structuredClone(current.MainContainer);
const container: ContainerModel | undefined = findContainerById(mainContainerClone, current.SelectedContainer.properties.id);
const container: ContainerModel | undefined = findContainerById(mainContainerClone, selected.properties.id);
if (container === null || container === undefined) {
throw new Error('[OnPropertyChange] Container model was not found among children of the main container!');
}
const oldSymbolId = container.properties.linkedSymbolId;
if (isStyle) {
(container.properties.style as any)[key] = value;
} else {
(container.properties as any)[key] = value;
}
ApplyBehaviors(container);
LinkSymbol(
container.properties.id,
oldSymbolId,
container.properties.linkedSymbolId,
current.Symbols
);
ApplyBehaviors(container, current.Symbols);
history.push({
LastAction: `Change ${key} of ${container.properties.id}`,
MainContainer: mainContainerClone,
SelectedContainer: container,
SelectedContainerId: container.properties.id,
TypeCounters: Object.assign({}, current.TypeCounters)
TypeCounters: Object.assign({}, current.TypeCounters),
Symbols: structuredClone(current.Symbols),
SelectedSymbolId: current.SelectedSymbolId
});
setHistory(history);
setHistoryCurrentStep(history.length - 1);
}
function LinkSymbol(
containerId: string,
oldSymbolId: string,
newSymbolId: string,
symbols: Map<string, ISymbolModel>
): void {
const oldSymbol = symbols.get(oldSymbolId);
const newSymbol = symbols.get(newSymbolId);
if (newSymbol === undefined) {
if (oldSymbol !== undefined) {
oldSymbol.linkedContainers.delete(containerId);
}
return;
}
newSymbol.linkedContainers.add(containerId);
}
/**
* Handled the property change event in the properties form
* @param key Property name
@ -63,6 +94,7 @@ export function OnPropertyChange(
*/
export function OnPropertiesSubmit(
event: React.SyntheticEvent<HTMLFormElement>,
selected: IContainerModel | undefined,
fullHistory: IHistoryState[],
historyCurrentStep: number,
setHistory: Dispatch<SetStateAction<IHistoryState[]>>,
@ -72,13 +104,13 @@ export function OnPropertiesSubmit(
const history = getCurrentHistory(fullHistory, historyCurrentStep);
const current = history[history.length - 1];
if (current.SelectedContainer === null ||
current.SelectedContainer === undefined) {
if (selected === null ||
selected === undefined) {
throw new Error('[OnPropertyChange] Property was changed before selecting a Container');
}
const mainContainerClone: IContainerModel = structuredClone(current.MainContainer);
const container: ContainerModel | undefined = findContainerById(mainContainerClone, current.SelectedContainer.properties.id);
const container: ContainerModel | undefined = findContainerById(mainContainerClone, selected.properties.id);
if (container === null || container === undefined) {
throw new Error('[OnPropertyChange] Container model was not found among children of the main container!');
@ -110,14 +142,15 @@ export function OnPropertiesSubmit(
}
// Apply the behaviors
ApplyBehaviors(container);
ApplyBehaviors(container, current.Symbols);
history.push({
LastAction: `Change properties of ${container.properties.id}`,
MainContainer: mainContainerClone,
SelectedContainer: container,
SelectedContainerId: container.properties.id,
TypeCounters: Object.assign({}, current.TypeCounters)
TypeCounters: Object.assign({}, current.TypeCounters),
Symbols: structuredClone(current.Symbols),
SelectedSymbolId: current.SelectedSymbolId
});
setHistory(history);
setHistoryCurrentStep(history.length - 1);
@ -187,3 +220,4 @@ const submitRadioButtons = (
(container.properties as any)[property] = radiobutton.value;
};