diff --git a/azure-pipelines.yml b/azure-pipelines.yml index 365a3d3..5c52dac 100644 --- a/azure-pipelines.yml +++ b/azure-pipelines.yml @@ -21,7 +21,7 @@ steps: path: $(pnpm_config_cache) displayName: Cache pnpm -- bash: | +- script: | curl -f https://get.pnpm.io/v6.16.js | node - add --global pnpm@7 pnpm config set store-dir $(pnpm_config_cache) displayName: "Setup pnpm" @@ -31,8 +31,7 @@ steps: versionSpec: '16.x' displayName: 'Install Node.js 16.x LTS' -- bash: | - set -euo pipefail +- script: | node --version node ./test-server/node-http.js & jobs @@ -47,8 +46,7 @@ steps: versionSpec: '>=18.7.0' displayName: 'Install Node.js Latest' -- bash: | - set -euo pipefail +- script: | node --version node ./test-server/node-http.js & jobs diff --git a/public/workers/worker.js b/public/workers/worker.js index 9260405..c11fa7d 100644 --- a/public/workers/worker.js +++ b/public/workers/worker.js @@ -4,19 +4,22 @@ onmessage = (e) => { }; const getCircularReplacer = () => { + const seen = new WeakSet(); return (key, value) => { if (key === 'parent') { return; } - if (key === 'Symbols') { - return Array.from(value.entries()); + if (key === 'SelectedContainer') { + return; } - if (key === 'linkedContainers') { - return Array.from(value); + if (typeof value === 'object' && value !== null) { + if (seen.has(value)) { + return; + } + seen.add(value); } - return value; }; }; diff --git a/src/Components/App/App.tsx b/src/Components/App/App.tsx index 1041814..c85d322 100644 --- a/src/Components/App/App.tsx +++ b/src/Components/App/App.tsx @@ -26,10 +26,9 @@ export const App: React.FunctionComponent = (props) => { history: [{ LastAction: '', MainContainer: defaultMainContainer, + SelectedContainer: defaultMainContainer, SelectedContainerId: defaultMainContainer.properties.id, - TypeCounters: {}, - Symbols: new Map(), - SelectedSymbolId: '' + TypeCounters: {} }], historyCurrentStep: 0 }); diff --git a/src/Components/App/MenuActions.ts b/src/Components/App/MenuActions.ts index 4c0c8aa..601e4c7 100644 --- a/src/Components/App/MenuActions.ts +++ b/src/Components/App/MenuActions.ts @@ -4,6 +4,7 @@ import { ContainerModel } from '../../Interfaces/IContainerModel'; import { fetchConfiguration } from '../API/api'; import { IEditorState } from '../../Interfaces/IEditorState'; import { LoadState } from './Load'; +import { XPositionReference } from '../../Enums/XPositionReference'; import { DEFAULT_MAINCONTAINER_PROPS } from '../../utils/default'; export function NewEditor( @@ -25,7 +26,6 @@ export function NewEditor( // Save the configuration and the new MainContainer // and default the selected container to it - // TODO: Put this in default.ts const editorState: IEditorState = { configuration, history: @@ -33,10 +33,9 @@ export function NewEditor( { LastAction: '', MainContainer, + SelectedContainer: MainContainer, SelectedContainerId: MainContainer.properties.id, - TypeCounters: {}, - Symbols: new Map(), - SelectedSymbolId: '' + TypeCounters: {} } ], historyCurrentStep: 0 diff --git a/src/Components/Bar/Bar.tsx b/src/Components/Bar/Bar.tsx index 22c617a..77cb259 100644 --- a/src/Components/Bar/Bar.tsx +++ b/src/Components/Bar/Bar.tsx @@ -1,14 +1,13 @@ -import { ClockIcon, CubeIcon, LinkIcon, MapIcon } from '@heroicons/react/outline'; +import { ClockIcon, CubeIcon, MapIcon } from '@heroicons/react/outline'; import * as React from 'react'; import { BarIcon } from './BarIcon'; interface IBarProps { isSidebarOpen: boolean - isSymbolsOpen: boolean isElementsSidebarOpen: boolean isHistoryOpen: boolean ToggleSidebar: () => void - ToggleSymbols: () => void + ToggleElementsSidebar: () => void ToggleTimeline: () => void } @@ -24,10 +23,10 @@ export const Bar: React.FC = (props) => { props.ToggleSymbols()}> - + isActive={props.isElementsSidebarOpen} + title='Map' + onClick={() => props.ToggleElementsSidebar()}> + ): IContainerModel { +export function ApplyBehaviors(container: IContainerModel): IContainerModel { if (container.properties.isAnchor) { - ApplyAnchor(container); + ImposePosition(container); } if (container.properties.isRigidBody) { - ApplyRigidBody(container); - } - - const symbol = symbols.get(container.properties.linkedSymbolId); - if (container.properties.linkedSymbolId !== '' && symbol !== undefined) { - ApplySymbol(container, symbol); + RecalculatePhysics(container); } if (APPLY_BEHAVIORS_ON_CHILDREN) { // Apply DFS by recursion for (const child of container.children) { - ApplyBehaviors(child, symbols); + ApplyBehaviors(child); } } diff --git a/src/Components/Editor/Behaviors/RigidBodyBehaviors.ts b/src/Components/Editor/Behaviors/RigidBodyBehaviors.ts index f6bcf65..1ba10a0 100644 --- a/src/Components/Editor/Behaviors/RigidBodyBehaviors.ts +++ b/src/Components/Editor/Behaviors/RigidBodyBehaviors.ts @@ -19,7 +19,7 @@ import { ISizePointer } from '../../../Interfaces/ISizePointer'; * @param container Container to apply its rigid body properties * @returns A rigid body container */ -export function ApplyRigidBody( +export function RecalculatePhysics( container: IContainerModel ): IContainerModel { container = constraintBodyInsideParent(container); diff --git a/src/Components/Editor/Behaviors/SymbolBehaviors.ts b/src/Components/Editor/Behaviors/SymbolBehaviors.ts deleted file mode 100644 index 2997e01..0000000 --- a/src/Components/Editor/Behaviors/SymbolBehaviors.ts +++ /dev/null @@ -1,9 +0,0 @@ -import { IContainerModel } from '../../../Interfaces/IContainerModel'; -import { ISymbolModel } from '../../../Interfaces/ISymbolModel'; -import { restoreX, transformX } from '../../../utils/svg'; - -export function ApplySymbol(container: IContainerModel, symbol: ISymbolModel): IContainerModel { - container.properties.x = transformX(symbol.x, symbol.width, symbol.config.XPositionReference); - container.properties.x = restoreX(container.properties.x, container.properties.width, container.properties.XPositionReference); - return container; -} diff --git a/src/Components/Editor/ContainerOperations.ts b/src/Components/Editor/ContainerOperations.ts index 018c39d..8c327e8 100644 --- a/src/Components/Editor/ContainerOperations.ts +++ b/src/Components/Editor/ContainerOperations.ts @@ -2,20 +2,19 @@ import { Dispatch, SetStateAction } from 'react'; import { IHistoryState } from '../../Interfaces/IHistoryState'; import { IConfiguration } from '../../Interfaces/IConfiguration'; import { ContainerModel, IContainerModel } from '../../Interfaces/IContainerModel'; -import { findContainerById, MakeIterator } from '../../utils/itertools'; -import { getCurrentHistory, UpdateCounters } from './Editor'; +import { findContainerById } from '../../utils/itertools'; +import { getCurrentHistory } from './Editor'; import { AddMethod } from '../../Enums/AddMethod'; import { IAvailableContainer } from '../../Interfaces/IAvailableContainer'; import { GetDefaultContainerProps, DEFAULTCHILDTYPE_ALLOW_CYCLIC, DEFAULTCHILDTYPE_MAX_DEPTH } from '../../utils/default'; import { ApplyBehaviors } from './Behaviors/Behaviors'; -import { ISymbolModel } from '../../Interfaces/ISymbolModel'; /** * Select a container * @param container Selected container */ export function SelectContainer( - containerId: string, + container: ContainerModel, fullHistory: IHistoryState[], historyCurrentStep: number, setHistory: Dispatch>, @@ -24,13 +23,19 @@ export function SelectContainer( const history = getCurrentHistory(fullHistory, historyCurrentStep); const current = history[history.length - 1]; + const mainContainerClone = structuredClone(current.MainContainer); + const selectedContainer = findContainerById(mainContainerClone, container.properties.id); + + if (selectedContainer === undefined) { + throw new Error('[SelectContainer] Cannot find container among children of main container!'); + } + history.push({ - LastAction: `Select ${containerId}`, - MainContainer: structuredClone(current.MainContainer), - SelectedContainerId: containerId, - TypeCounters: Object.assign({}, current.TypeCounters), - Symbols: structuredClone(current.Symbols), - SelectedSymbolId: current.SelectedSymbolId + LastAction: `Select ${selectedContainer.properties.id}`, + MainContainer: mainContainerClone, + SelectedContainer: selectedContainer, + SelectedContainerId: selectedContainer.properties.id, + TypeCounters: Object.assign({}, current.TypeCounters) }); setHistory(history); setHistoryCurrentStep(history.length - 1); @@ -71,8 +76,6 @@ export function DeleteContainer( if (container === null || container === undefined) { throw new Error('[DeleteContainer] Container model was not found among children of the main container!'); } - const newSymbols = structuredClone(current.Symbols) - UnlinkSymbol(newSymbols, container); const index = container.parent.children.indexOf(container); if (index > -1) { @@ -91,26 +94,14 @@ export function DeleteContainer( history.push({ LastAction: `Delete ${containerId}`, MainContainer: mainContainerClone, + SelectedContainer, SelectedContainerId, - TypeCounters: Object.assign({}, current.TypeCounters), - Symbols: newSymbols, - SelectedSymbolId: current.SelectedSymbolId + TypeCounters: Object.assign({}, current.TypeCounters) }); setHistory(history); setHistoryCurrentStep(history.length - 1); } -function UnlinkSymbol(symbols: Map, container: IContainerModel): void { - const it = MakeIterator(container); - for (const child of it) { - const symbol = symbols.get(child.properties.linkedSymbolId); - if (symbol === undefined) { - continue; - } - symbol.linkedContainers.delete(child.properties.id); - } -} - /** * Add a new container to a selected container * @param type The type of container @@ -123,19 +114,21 @@ function UnlinkSymbol(symbols: Map, container: IContainerM */ export function AddContainerToSelectedContainer( type: string, - selected: IContainerModel | undefined, configuration: IConfiguration, fullHistory: IHistoryState[], historyCurrentStep: number, setHistory: Dispatch>, setHistoryCurrentStep: Dispatch> ): void { - if (selected === null || - selected === undefined) { + const history = getCurrentHistory(fullHistory, historyCurrentStep); + const current = history[history.length - 1]; + + if (current.SelectedContainer === null || + current.SelectedContainer === undefined) { return; } - const parent = selected; + const parent = current.SelectedContainer; AddContainer( parent.children.length, type, @@ -173,6 +166,11 @@ export function AddContainer( const history = getCurrentHistory(fullHistory, historyCurrentStep); const current = history[history.length - 1]; + if (current.MainContainer === null || + current.MainContainer === undefined) { + return; + } + // Get the preset properties from the API const containerConfig = configuration.AvailableContainers .find(option => option.Type === type); @@ -222,7 +220,7 @@ export function AddContainer( } ); - ApplyBehaviors(newContainer, current.Symbols); + ApplyBehaviors(newContainer); // And push it the the parent children if (index === parentClone.children.length) { @@ -237,15 +235,23 @@ export function AddContainer( history.push({ LastAction: `Add ${newContainer.properties.id} in ${parentClone.properties.id}`, MainContainer: clone, + SelectedContainer: parentClone, SelectedContainerId: parentClone.properties.id, - TypeCounters: newCounters, - Symbols: structuredClone(current.Symbols), - SelectedSymbolId: current.SelectedSymbolId + TypeCounters: newCounters }); setHistory(history); setHistoryCurrentStep(history.length - 1); } +function UpdateCounters(counters: Record, type: string): void { + if (counters[type] === null || + counters[type] === undefined) { + counters[type] = 0; + } else { + counters[type]++; + } +} + function InitializeDefaultChild( configuration: IConfiguration, containerConfig: IAvailableContainer, diff --git a/src/Components/Editor/Editor.tsx b/src/Components/Editor/Editor.tsx index f7df902..75bf90c 100644 --- a/src/Components/Editor/Editor.tsx +++ b/src/Components/Editor/Editor.tsx @@ -11,8 +11,6 @@ import { OnPropertyChange, OnPropertiesSubmit } from './PropertiesOperations'; import EditorEvents from '../../Events/EditorEvents'; import { IEditorState } from '../../Interfaces/IEditorState'; import { MAX_HISTORY } from '../../utils/default'; -import { AddSymbol, OnPropertyChange as OnSymbolPropertyChange, DeleteSymbol, SelectSymbol } from './SymbolOperations'; -import { findContainerById } from '../../utils/itertools'; interface IEditorProps { configuration: IConfiguration @@ -20,15 +18,6 @@ interface IEditorProps { historyCurrentStep: number } -export function UpdateCounters(counters: Record, type: string): void { - if (counters[type] === null || - counters[type] === undefined) { - counters[type] = 0; - } else { - counters[type]++; - } -} - export const getCurrentHistory = (history: IHistoryState[], historyCurrentStep: number): IHistoryState[] => history.slice( Math.max(0, history.length - MAX_HISTORY), // change this to 0 for unlimited (not recommanded because of overflow) @@ -81,16 +70,13 @@ const Editor: React.FunctionComponent = (props) => { const configuration = props.configuration; const current = getCurrentHistoryState(history, historyCurrentStep); - const selected = findContainerById(current.MainContainer, current.SelectedContainerId); return (
SelectContainer( container, history, @@ -107,7 +93,6 @@ const Editor: React.FunctionComponent = (props) => { )} OnPropertyChange={(key, value, isStyle) => OnPropertyChange( key, value, isStyle, - selected, history, historyCurrentStep, setHistory, @@ -115,7 +100,6 @@ const Editor: React.FunctionComponent = (props) => { )} OnPropertiesSubmit={(event) => OnPropertiesSubmit( event, - selected, history, historyCurrentStep, setHistory, @@ -123,7 +107,6 @@ const Editor: React.FunctionComponent = (props) => { )} AddContainerToSelectedContainer={(type) => AddContainerToSelectedContainer( type, - selected, configuration, history, historyCurrentStep, @@ -140,35 +123,6 @@ const Editor: React.FunctionComponent = (props) => { setHistory, setHistoryCurrentStep )} - AddSymbol={(type) => AddSymbol( - type, - configuration, - history, - historyCurrentStep, - setHistory, - setHistoryCurrentStep - )} - OnSymbolPropertyChange={(key, value) => OnSymbolPropertyChange( - key, value, - history, - historyCurrentStep, - setHistory, - setHistoryCurrentStep - )} - SelectSymbol={(symbolId) => SelectSymbol( - symbolId, - history, - historyCurrentStep, - setHistory, - setHistoryCurrentStep - )} - DeleteSymbol={(symbolId) => DeleteSymbol( - symbolId, - history, - historyCurrentStep, - setHistory, - setHistoryCurrentStep - )} SaveEditorAsJSON={() => SaveEditorAsJSON( history, historyCurrentStep, @@ -180,8 +134,7 @@ const Editor: React.FunctionComponent = (props) => { { current.MainContainer } diff --git a/src/Components/Editor/PropertiesOperations.ts b/src/Components/Editor/PropertiesOperations.ts index d939213..70984da 100644 --- a/src/Components/Editor/PropertiesOperations.ts +++ b/src/Components/Editor/PropertiesOperations.ts @@ -3,9 +3,8 @@ 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 @@ -17,7 +16,6 @@ export function OnPropertyChange( key: string, value: string | number | boolean, isStyle: boolean = false, - selected: IContainerModel | undefined, fullHistory: IHistoryState[], historyCurrentStep: number, setHistory: Dispatch>, @@ -26,66 +24,37 @@ export function OnPropertyChange( const history = getCurrentHistory(fullHistory, historyCurrentStep); const current = history[history.length - 1]; - if (selected === null || - selected === undefined) { + if (current.SelectedContainer === null || + current.SelectedContainer === undefined) { throw new Error('[OnPropertyChange] Property was changed before selecting a Container'); } const mainContainerClone: IContainerModel = structuredClone(current.MainContainer); - const container: ContainerModel | undefined = findContainerById(mainContainerClone, selected.properties.id); + const container: ContainerModel | undefined = findContainerById(mainContainerClone, current.SelectedContainer.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; } - LinkSymbol( - container.properties.id, - oldSymbolId, - container.properties.linkedSymbolId, - current.Symbols - ); - - ApplyBehaviors(container, current.Symbols); + ApplyBehaviors(container); history.push({ LastAction: `Change ${key} of ${container.properties.id}`, MainContainer: mainContainerClone, + SelectedContainer: container, SelectedContainerId: container.properties.id, - TypeCounters: Object.assign({}, current.TypeCounters), - Symbols: structuredClone(current.Symbols), - SelectedSymbolId: current.SelectedSymbolId + TypeCounters: Object.assign({}, current.TypeCounters) }); setHistory(history); setHistoryCurrentStep(history.length - 1); } -function LinkSymbol( - containerId: string, - oldSymbolId: string, - newSymbolId: string, - symbols: Map -): 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 @@ -94,7 +63,6 @@ function LinkSymbol( */ export function OnPropertiesSubmit( event: React.SyntheticEvent, - selected: IContainerModel | undefined, fullHistory: IHistoryState[], historyCurrentStep: number, setHistory: Dispatch>, @@ -104,13 +72,13 @@ export function OnPropertiesSubmit( const history = getCurrentHistory(fullHistory, historyCurrentStep); const current = history[history.length - 1]; - if (selected === null || - selected === undefined) { + if (current.SelectedContainer === null || + current.SelectedContainer === undefined) { throw new Error('[OnPropertyChange] Property was changed before selecting a Container'); } const mainContainerClone: IContainerModel = structuredClone(current.MainContainer); - const container: ContainerModel | undefined = findContainerById(mainContainerClone, selected.properties.id); + const container: ContainerModel | undefined = findContainerById(mainContainerClone, current.SelectedContainer.properties.id); if (container === null || container === undefined) { throw new Error('[OnPropertyChange] Container model was not found among children of the main container!'); @@ -142,15 +110,14 @@ export function OnPropertiesSubmit( } // Apply the behaviors - ApplyBehaviors(container, current.Symbols); + ApplyBehaviors(container); history.push({ LastAction: `Change properties of ${container.properties.id}`, MainContainer: mainContainerClone, + SelectedContainer: container, SelectedContainerId: container.properties.id, - TypeCounters: Object.assign({}, current.TypeCounters), - Symbols: structuredClone(current.Symbols), - SelectedSymbolId: current.SelectedSymbolId + TypeCounters: Object.assign({}, current.TypeCounters) }); setHistory(history); setHistoryCurrentStep(history.length - 1); @@ -220,4 +187,3 @@ const submitRadioButtons = ( (container.properties as any)[property] = radiobutton.value; }; - diff --git a/src/Components/Editor/SymbolOperations.ts b/src/Components/Editor/SymbolOperations.ts deleted file mode 100644 index 01844ab..0000000 --- a/src/Components/Editor/SymbolOperations.ts +++ /dev/null @@ -1,180 +0,0 @@ -import { Dispatch, SetStateAction } from 'react'; -import { IConfiguration } from '../../Interfaces/IConfiguration'; -import { IContainerModel } from '../../Interfaces/IContainerModel'; -import { IHistoryState } from '../../Interfaces/IHistoryState'; -import { ISymbolModel } from '../../Interfaces/ISymbolModel'; -import { DEFAULT_SYMBOL_HEIGHT, DEFAULT_SYMBOL_WIDTH } from '../../utils/default'; -import { findContainerById } from '../../utils/itertools'; -import { restoreX } from '../../utils/svg'; -import { ApplyBehaviors } from './Behaviors/Behaviors'; -import { getCurrentHistory, UpdateCounters } from './Editor'; - -export function AddSymbol( - name: string, - configuration: IConfiguration, - fullHistory: IHistoryState[], - historyCurrentStep: number, - setHistory: Dispatch>, - setHistoryCurrentStep: Dispatch> -): void { - const history = getCurrentHistory(fullHistory, historyCurrentStep); - const current = history[history.length - 1]; - - const symbolConfig = configuration.AvailableSymbols - .find(option => option.Name === name); - - if (symbolConfig === undefined) { - throw new Error('[AddSymbol] Symbol could not be found in the config'); - } - const type = `symbol-${name}`; - const newCounters = structuredClone(current.TypeCounters); - UpdateCounters(newCounters, type); - - const newSymbols = structuredClone(current.Symbols); - // TODO: Put this in default.ts as GetDefaultConfig - const newSymbol: ISymbolModel = { - id: `${name}-${newCounters[type]}`, - type: name, - config: structuredClone(symbolConfig), - x: 0, - width: symbolConfig.Width ?? DEFAULT_SYMBOL_WIDTH, - height: symbolConfig.Height ?? DEFAULT_SYMBOL_HEIGHT, - linkedContainers: new Set() - }; - newSymbol.x = restoreX(newSymbol.x, newSymbol.width, newSymbol.config.XPositionReference); - - newSymbols.set(newSymbol.id, newSymbol); - - history.push({ - LastAction: `Add ${name}`, - MainContainer: structuredClone(current.MainContainer), - SelectedContainerId: current.SelectedContainerId, - TypeCounters: newCounters, - Symbols: newSymbols, - SelectedSymbolId: newSymbol.id - }); - setHistory(history); - setHistoryCurrentStep(history.length - 1); -} - -export function SelectSymbol( - symbolId: string, - fullHistory: IHistoryState[], - historyCurrentStep: number, - setHistory: Dispatch>, - setHistoryCurrentStep: Dispatch> -): void { - const history = getCurrentHistory(fullHistory, historyCurrentStep); - const current = history[history.length - 1]; - - history.push({ - LastAction: `Select ${symbolId}`, - MainContainer: structuredClone(current.MainContainer), - SelectedContainerId: current.SelectedContainerId, - TypeCounters: structuredClone(current.TypeCounters), - Symbols: structuredClone(current.Symbols), - SelectedSymbolId: symbolId - }); - setHistory(history); - setHistoryCurrentStep(history.length - 1); -} - -export function DeleteSymbol( - symbolId: string, - fullHistory: IHistoryState[], - historyCurrentStep: number, - setHistory: Dispatch>, - setHistoryCurrentStep: Dispatch> -): void { - const history = getCurrentHistory(fullHistory, historyCurrentStep); - const current = history[history.length - 1]; - - const newSymbols = structuredClone(current.Symbols); - const symbol = newSymbols.get(symbolId); - - if (symbol === undefined) { - throw new Error(`[DeleteSymbol] Could not find symbol in the current state!: ${symbolId}`); - } - - const newMainContainer = structuredClone(current.MainContainer); - - UnlinkContainers(symbol, newMainContainer); - - newSymbols.delete(symbolId); - - history.push({ - LastAction: `Select ${symbolId}`, - MainContainer: newMainContainer, - SelectedContainerId: current.SelectedContainerId, - TypeCounters: structuredClone(current.TypeCounters), - Symbols: newSymbols, - SelectedSymbolId: symbolId - }); - setHistory(history); - setHistoryCurrentStep(history.length - 1); -} - -function UnlinkContainers(symbol: ISymbolModel, newMainContainer: IContainerModel) { - symbol.linkedContainers.forEach((containerId) => { - const container = findContainerById(newMainContainer, containerId); - - if (container === undefined) { - return; - } - - container.properties.linkedSymbolId = ''; - }); -} - -/** - * Handled the property change event in the properties form - * @param key Property name - * @param value New value of the property - * @returns void - */ -export function OnPropertyChange( - key: string, - value: string | number | boolean, - fullHistory: IHistoryState[], - historyCurrentStep: number, - setHistory: Dispatch>, - setHistoryCurrentStep: Dispatch> -): void { - const history = getCurrentHistory(fullHistory, historyCurrentStep); - const current = history[history.length - 1]; - - if (current.SelectedSymbolId === '') { - throw new Error('[OnSymbolPropertyChange] Property was changed before selecting a symbol'); - } - - const newSymbols: Map = structuredClone(current.Symbols); - const symbol = newSymbols.get(current.SelectedSymbolId); - - if (symbol === null || symbol === undefined) { - throw new Error('[OnSymbolPropertyChange] Symbol model was not found in state!'); - } - - (symbol as any)[key] = value; - - const newMainContainer = structuredClone(current.MainContainer); - symbol.linkedContainers.forEach((containerId) => { - const container = findContainerById(newMainContainer, containerId); - - if (container === undefined) { - return; - } - - ApplyBehaviors(container, newSymbols); - }); - - history.push({ - LastAction: `Change ${key} of ${symbol.id}`, - MainContainer: newMainContainer, - SelectedContainerId: current.SelectedContainerId, - TypeCounters: Object.assign({}, current.TypeCounters), - Symbols: newSymbols, - SelectedSymbolId: symbol.id - }); - setHistory(history); - setHistoryCurrentStep(history.length - 1); -} diff --git a/src/Components/ElementsSidebar/ElementsSidebar.test.tsx b/src/Components/ElementsSidebar/ElementsSidebar.test.tsx index 8badea7..4f3b042 100644 --- a/src/Components/ElementsSidebar/ElementsSidebar.test.tsx +++ b/src/Components/ElementsSidebar/ElementsSidebar.test.tsx @@ -4,19 +4,16 @@ import { fireEvent, render, screen } from '../../utils/test-utils'; import { ElementsSidebar } from './ElementsSidebar'; import { IContainerModel } from '../../Interfaces/IContainerModel'; import { XPositionReference } from '../../Enums/XPositionReference'; -import { findContainerById } from '../../utils/itertools'; describe.concurrent('Elements sidebar', () => { it('With a MainContainer', () => { render( { }} isOpen={true} isHistoryOpen={false} - SelectedContainer={undefined} + SelectedContainer={null} OnPropertyChange={() => {}} OnPropertiesSubmit={() => {}} SelectContainer={() => {}} @@ -45,13 +42,12 @@ describe.concurrent('Elements sidebar', () => { }); it('With a selected MainContainer', () => { - const MainContainer: IContainerModel = { + const MainContainer = { children: [], parent: null, properties: { id: 'main', parentId: '', - linkedSymbolId: '', displayedText: 'main', x: 0, y: 0, @@ -66,7 +62,6 @@ describe.concurrent('Elements sidebar', () => { }; const { container } = render( { it('With multiple containers', () => { const children: IContainerModel[] = []; - const MainContainer: IContainerModel = { + const MainContainer = { children, parent: null, properties: { id: 'main', parentId: '', - linkedSymbolId: '', displayedText: 'main', x: 0, y: 0, @@ -134,7 +128,6 @@ describe.concurrent('Elements sidebar', () => { properties: { id: 'child-1', parentId: 'main', - linkedSymbolId: '', displayedText: 'child-1', x: 0, y: 0, @@ -156,7 +149,6 @@ describe.concurrent('Elements sidebar', () => { properties: { id: 'child-2', parentId: 'main', - linkedSymbolId: '', displayedText: 'child-2', x: 0, y: 0, @@ -172,7 +164,6 @@ describe.concurrent('Elements sidebar', () => { ); render( { properties: { id: 'main', parentId: '', - linkedSymbolId: '', displayedText: 'main', x: 0, y: 0, @@ -219,7 +209,6 @@ describe.concurrent('Elements sidebar', () => { properties: { id: 'child-1', parentId: 'main', - linkedSymbolId: '', displayedText: 'child-1', x: 0, y: 0, @@ -234,13 +223,12 @@ describe.concurrent('Elements sidebar', () => { }; children.push(child1Model); - let SelectedContainer: IContainerModel | undefined = MainContainer; - const selectContainer = vi.fn((containerId: string) => { - SelectedContainer = findContainerById(MainContainer, containerId); + let SelectedContainer = MainContainer; + const selectContainer = vi.fn((container: IContainerModel) => { + SelectedContainer = container; }); const { container, rerender } = render( { fireEvent.click(child1); rerender( isOpen: boolean isHistoryOpen: boolean - SelectedContainer: IContainerModel | undefined + SelectedContainer: IContainerModel | null OnPropertyChange: (key: string, value: string | number | boolean, isStyle?: boolean) => void OnPropertiesSubmit: (event: React.FormEvent) => void - SelectContainer: (containerId: string) => void + SelectContainer: (container: IContainerModel) => void DeleteContainer: (containerid: string) => void AddContainer: (index: number, type: string, parent: string) => void } @@ -106,7 +104,7 @@ export const ElementsSidebar: React.FC = (props: IElement onDrop={(event) => handleOnDrop(event, props.MainContainer, props.AddContainer)} onDragOver={(event) => handleDragOver(event, props.MainContainer)} onDragLeave={(event) => handleDragLeave(event)} - onClick={() => props.SelectContainer(container.properties.id)} + onClick={() => props.SelectContainer(container)} > { text } @@ -142,7 +140,6 @@ export const ElementsSidebar: React.FC = (props: IElement diff --git a/src/Components/Properties/DynamicForm.tsx b/src/Components/Properties/DynamicForm.tsx index be59200..a34b5bf 100644 --- a/src/Components/Properties/DynamicForm.tsx +++ b/src/Components/Properties/DynamicForm.tsx @@ -1,21 +1,18 @@ import { MenuAlt2Icon, MenuAlt3Icon, MenuIcon } from '@heroicons/react/outline'; import * as React from 'react'; import { XPositionReference } from '../../Enums/XPositionReference'; -import IContainerProperties from '../../Interfaces/IContainerProperties'; -import { ISymbolModel } from '../../Interfaces/ISymbolModel'; -import { restoreX, transformX } from '../../utils/svg'; +import IProperties from '../../Interfaces/IProperties'; import { InputGroup } from '../InputGroup/InputGroup'; import { RadioGroupButtons } from '../RadioGroupButtons/RadioGroupButtons'; -import { Select } from '../Select/Select'; +import { restoreX, transformX } from '../SVG/Elements/Container'; interface IDynamicFormProps { - properties: IContainerProperties - symbols: Map + properties: IProperties onChange: (key: string, value: string | number | boolean, isStyle?: boolean) => void } const getCSSInputs = ( - properties: IContainerProperties, + properties: IProperties, onChange: (key: string, value: string | number | boolean, isStyle?: boolean) => void ): JSX.Element[] => { const groupInput: JSX.Element[] = []; @@ -70,7 +67,6 @@ const DynamicForm: React.FunctionComponent = (props) => { labelClassName='' inputClassName='' type='number' - isDisabled={props.properties.linkedSymbolId !== ''} value={transformX(props.properties.x, props.properties.width, props.properties.XPositionReference).toString()} onChange={(event) => props.onChange('x', restoreX(Number(event.target.value), props.properties.width, props.properties.XPositionReference))} /> @@ -164,22 +160,9 @@ const DynamicForm: React.FunctionComponent = (props) => { ]} onChange={(event) => props.onChange('XPositionReference', Number(event.target.value))} /> - - { options } - - - ); -}; diff --git a/src/Components/SymbolProperties/DynamicForm.tsx b/src/Components/SymbolProperties/DynamicForm.tsx deleted file mode 100644 index 8e969b5..0000000 --- a/src/Components/SymbolProperties/DynamicForm.tsx +++ /dev/null @@ -1,56 +0,0 @@ -import * as React from 'react'; -import { ISymbolModel } from '../../Interfaces/ISymbolModel'; -import { restoreX, transformX } from '../../utils/svg'; -import { InputGroup } from '../InputGroup/InputGroup'; - -interface IDynamicFormProps { - symbol: ISymbolModel - symbols: Map - onChange: (key: string, value: string | number | boolean) => void -} -const DynamicForm: React.FunctionComponent = (props) => { - return ( -
- - props.onChange('x', restoreX(Number(event.target.value), props.symbol.width, props.symbol.config.XPositionReference))} - /> - props.onChange('height', Number(event.target.value))} - /> - props.onChange('width', Number(event.target.value))} - /> -
- ); -}; - -export default DynamicForm; diff --git a/src/Components/SymbolProperties/Form.tsx b/src/Components/SymbolProperties/Form.tsx deleted file mode 100644 index a70c7dc..0000000 --- a/src/Components/SymbolProperties/Form.tsx +++ /dev/null @@ -1,17 +0,0 @@ -import * as React from 'react'; -import { ISymbolModel } from '../../Interfaces/ISymbolModel'; -import DynamicForm from './DynamicForm'; - -interface IFormProps { - symbol: ISymbolModel - symbols: Map - onChange: (key: string, value: string | number | boolean, isStyle?: boolean) => void -} - -export const Form: React.FunctionComponent = (props) => { - return ; -}; diff --git a/src/Components/SymbolProperties/SymbolProperties.tsx b/src/Components/SymbolProperties/SymbolProperties.tsx deleted file mode 100644 index b58e3cf..0000000 --- a/src/Components/SymbolProperties/SymbolProperties.tsx +++ /dev/null @@ -1,27 +0,0 @@ -import React, { useState } from 'react'; -import IContainerProperties from '../../Interfaces/IContainerProperties'; -import { ISymbolModel } from '../../Interfaces/ISymbolModel'; -import { ToggleButton } from '../ToggleButton/ToggleButton'; -import { Form } from './Form'; - -interface ISymbolPropertiesProps { - symbol?: ISymbolModel - symbols: Map - onChange: (key: string, value: string | number | boolean) => void -} - -export const SymbolProperties: React.FC = (props: ISymbolPropertiesProps) => { - if (props.symbol === undefined) { - return
; - } - - return ( -
-
-
- ); -}; diff --git a/src/Components/Symbols/Symbols.tsx b/src/Components/Symbols/Symbols.tsx deleted file mode 100644 index a514a9d..0000000 --- a/src/Components/Symbols/Symbols.tsx +++ /dev/null @@ -1,68 +0,0 @@ -import * as React from 'react'; -import { IAvailableSymbol } from '../../Interfaces/IAvailableSymbol'; -import { truncateString } from '../../utils/stringtools'; - -interface ISymbolsProps { - componentOptions: IAvailableSymbol[] - isOpen: boolean - buttonOnClick: (type: string) => void -} - -function handleDragStart(event: React.DragEvent): void { - event.dataTransfer.setData('type', (event.target as HTMLButtonElement).id); -} - -export const Symbols: React.FC = (props: ISymbolsProps) => { - const listElements = props.componentOptions.map(componentOption => { - if (componentOption.Image.Url !== undefined || componentOption.Image.Base64Image !== undefined) { - const url = componentOption.Image.Base64Image ?? componentOption.Image.Url; - return (); - } - - return (); - }); - - const isOpenClasses = props.isOpen ? 'left-16' : '-left-64'; - return ( -
-
- Symbols -
-
- {listElements} -
-
- ); -}; diff --git a/src/Components/SymbolsSidebar/MouseEventHandlers.ts b/src/Components/SymbolsSidebar/MouseEventHandlers.ts deleted file mode 100644 index 8a8b5b6..0000000 --- a/src/Components/SymbolsSidebar/MouseEventHandlers.ts +++ /dev/null @@ -1,34 +0,0 @@ -import { IPoint } from '../../Interfaces/IPoint'; - -export function handleRightClick( - event: MouseEvent, - setIsContextMenuOpen: React.Dispatch>, - setOnClickSymbolId: React.Dispatch>, - setContextMenuPosition: React.Dispatch> -): void { - event.preventDefault(); - - if (!(event.target instanceof HTMLButtonElement)) { - setIsContextMenuOpen(false); - setOnClickSymbolId(''); - return; - } - - const contextMenuPosition: IPoint = { x: event.pageX, y: event.pageY }; - setIsContextMenuOpen(true); - setOnClickSymbolId(event.target.id); - setContextMenuPosition(contextMenuPosition); -} - -export function handleLeftClick( - isContextMenuOpen: boolean, - setIsContextMenuOpen: React.Dispatch>, - setOnClickContainerId: React.Dispatch> -): void { - if (!isContextMenuOpen) { - return; - } - - setIsContextMenuOpen(false); - setOnClickContainerId(''); -} diff --git a/src/Components/SymbolsSidebar/SymbolsSidebar.tsx b/src/Components/SymbolsSidebar/SymbolsSidebar.tsx deleted file mode 100644 index 2285f47..0000000 --- a/src/Components/SymbolsSidebar/SymbolsSidebar.tsx +++ /dev/null @@ -1,137 +0,0 @@ -import * as React from 'react'; -import { FixedSizeList as List } from 'react-window'; -import { Menu } from '../Menu/Menu'; -import { MenuItem } from '../Menu/MenuItem'; -import { handleLeftClick, handleRightClick } from './MouseEventHandlers'; -import { IPoint } from '../../Interfaces/IPoint'; -import { ISymbolModel } from '../../Interfaces/ISymbolModel'; -import { SymbolProperties } from '../SymbolProperties/SymbolProperties'; - -interface ISymbolsSidebarProps { - SelectedSymbolId: string - symbols: Map - isOpen: boolean - isHistoryOpen: boolean - OnPropertyChange: (key: string, value: string | number | boolean) => void - SelectSymbol: (symbolId: string) => void - DeleteSymbol: (containerid: string) => void -} - -export const SymbolsSidebar: React.FC = (props: ISymbolsSidebarProps): JSX.Element => { - // States - const [isContextMenuOpen, setIsContextMenuOpen] = React.useState(false); - const [onClickSymbolId, setOnClickSymbolId] = React.useState(''); - const [contextMenuPosition, setContextMenuPosition] = React.useState({ - x: 0, - y: 0 - }); - - const elementRef = React.useRef(null); - - // Event listeners - React.useEffect(() => { - const onContextMenu = (event: MouseEvent): void => handleRightClick( - event, - setIsContextMenuOpen, - setOnClickSymbolId, - setContextMenuPosition - ); - - const onLeftClick = (): void => handleLeftClick( - isContextMenuOpen, - setIsContextMenuOpen, - setOnClickSymbolId - ); - - elementRef.current?.addEventListener( - 'contextmenu', - onContextMenu - ); - - window.addEventListener( - 'click', - onLeftClick - ); - - return () => { - elementRef.current?.removeEventListener( - 'contextmenu', - onContextMenu - ); - - window.removeEventListener( - 'click', - onLeftClick - ); - }; - }); - - // Render - let isOpenClasses = '-right-64'; - if (props.isOpen) { - isOpenClasses = props.isHistoryOpen - ? 'right-64' - : 'right-0'; - } - - const containers = [...props.symbols.values()]; - const Row = ({ index, style }: {index: number, style: React.CSSProperties}): JSX.Element => { - const container = containers[index]; - const key = container.id.toString(); - const text = key; - const selectedClass: string = props.SelectedSymbolId !== '' && - props.SelectedSymbolId === container.id - ? 'border-l-4 bg-slate-400/60 hover:bg-slate-400' - : 'bg-slate-300/60 hover:bg-slate-300'; - - return ( - - ); - }; - - return ( -
-
- Elements -
-
- - { Row } - -
- - { - setIsContextMenuOpen(false); - props.DeleteSymbol(onClickSymbolId); - }} /> - - -
- ); -}; diff --git a/src/Components/UI/UI.tsx b/src/Components/UI/UI.tsx index db27312..c57daee 100644 --- a/src/Components/UI/UI.tsx +++ b/src/Components/UI/UI.tsx @@ -3,55 +3,38 @@ import { ElementsSidebar } from '../ElementsSidebar/ElementsSidebar'; import { Sidebar } from '../Sidebar/Sidebar'; import { History } from '../History/History'; import { IAvailableContainer } from '../../Interfaces/IAvailableContainer'; -import { IContainerModel } from '../../Interfaces/IContainerModel'; +import { ContainerModel } from '../../Interfaces/IContainerModel'; import { IHistoryState } from '../../Interfaces/IHistoryState'; import { PhotographIcon, UploadIcon } from '@heroicons/react/outline'; import { FloatingButton } from '../FloatingButton/FloatingButton'; import { Bar } from '../Bar/Bar'; -import { IAvailableSymbol } from '../../Interfaces/IAvailableSymbol'; -import { Symbols } from '../Symbols/Symbols'; -import { SymbolsSidebar } from '../SymbolsSidebar/SymbolsSidebar'; interface IUIProps { - SelectedContainer: IContainerModel | undefined current: IHistoryState history: IHistoryState[] historyCurrentStep: number AvailableContainers: IAvailableContainer[] - AvailableSymbols: IAvailableSymbol[] - SelectContainer: (containerId: string) => void + SelectContainer: (container: ContainerModel) => void DeleteContainer: (containerId: string) => void OnPropertyChange: (key: string, value: string | number | boolean, isStyle?: boolean) => void OnPropertiesSubmit: (event: React.FormEvent) => void AddContainerToSelectedContainer: (type: string) => void AddContainer: (index: number, type: string, parentId: string) => void - AddSymbol: (type: string) => void - OnSymbolPropertyChange: (key: string, value: string | number | boolean) => void - SelectSymbol: (symbolId: string) => void - DeleteSymbol: (symbolId: string) => void SaveEditorAsJSON: () => void SaveEditorAsSVG: () => void LoadState: (move: number) => void } -function CloseOtherSidebars( - setIsSidebarOpen: React.Dispatch>, - setIsSymbolsOpen: React.Dispatch> -): void { - setIsSidebarOpen(false); - setIsSymbolsOpen(false); -} - export const UI: React.FunctionComponent = (props: IUIProps) => { const [isSidebarOpen, setIsSidebarOpen] = React.useState(true); - const [isSymbolsOpen, setIsSymbolsOpen] = React.useState(false); + const [isElementsSidebarOpen, setIsElementsSidebarOpen] = React.useState(false); const [isHistoryOpen, setIsHistoryOpen] = React.useState(false); let buttonRightOffsetClasses = 'right-12'; - if (isSidebarOpen || isHistoryOpen) { + if (isElementsSidebarOpen || isHistoryOpen) { buttonRightOffsetClasses = 'right-72'; } - if (isHistoryOpen && isSidebarOpen) { + if (isHistoryOpen && isElementsSidebarOpen) { buttonRightOffsetClasses = 'right-[544px]'; } @@ -59,35 +42,22 @@ export const UI: React.FunctionComponent = (props: IUIProps) => { <> { - CloseOtherSidebars(setIsSidebarOpen, setIsSymbolsOpen); - setIsSidebarOpen(!isSidebarOpen); - }} - ToggleSymbols={() => { - CloseOtherSidebars(setIsSidebarOpen, setIsSymbolsOpen); - setIsSymbolsOpen(!isSymbolsOpen); - }} + ToggleElementsSidebar={() => setIsElementsSidebarOpen(!isElementsSidebarOpen)} + ToggleSidebar={() => setIsSidebarOpen(!isSidebarOpen)} ToggleTimeline={() => setIsHistoryOpen(!isHistoryOpen)} /> - props.AddContainerToSelectedContainer(type)} /> = (props: IUIProps) => { DeleteContainer={props.DeleteContainer} AddContainer={props.AddContainer} /> - } -/** - * Macro for creating the interface - * Do not add methods since they will be lost during serialization - */ export class ContainerModel implements IContainerModel { public children: IContainerModel[]; public parent: IContainerModel | null; - public properties: IContainerProperties; + public properties: IProperties; public userData: Record; constructor( parent: IContainerModel | null, - properties: IContainerProperties, + properties: IProperties, children: IContainerModel[] = [], userData = {}) { this.parent = parent; diff --git a/src/Interfaces/IHistoryState.ts b/src/Interfaces/IHistoryState.ts index f906af3..fd46fbc 100644 --- a/src/Interfaces/IHistoryState.ts +++ b/src/Interfaces/IHistoryState.ts @@ -1,22 +1,9 @@ import { IContainerModel } from './IContainerModel'; -import { ISymbolModel } from './ISymbolModel'; export interface IHistoryState { - /** Last editor action */ LastAction: string - - /** Reference to the main container */ MainContainer: IContainerModel - - /** Id of the selected container */ + SelectedContainer: IContainerModel | null SelectedContainerId: string - - /** Counter of type of container. Used for ids. */ TypeCounters: Record - - /** List of symbols */ - Symbols: Map - - /** Selected symbols id */ - SelectedSymbolId: string } diff --git a/src/Interfaces/IImage.ts b/src/Interfaces/IImage.ts index d22c2e1..7432440 100644 --- a/src/Interfaces/IImage.ts +++ b/src/Interfaces/IImage.ts @@ -1,20 +1,7 @@ -/** - * Model of an image with multiple source - * It must at least have one source. - * - * If Url/Base64Image and Svg are set, - * Url/Base64Image will be shown in the menu while SVG will be drawn - */ +/** Model of an image with multiple source */ export interface IImage { - /** Name of the image */ Name: string - - /** (optional) Url of the image */ - Url?: string - - /** (optional) base64 data of the image */ - Base64Image?: string - - /** (optional) SVG string */ - Svg?: string + Url: string + Base64Image: string + Svg: string } diff --git a/src/Interfaces/IContainerProperties.ts b/src/Interfaces/IProperties.ts similarity index 91% rename from src/Interfaces/IContainerProperties.ts rename to src/Interfaces/IProperties.ts index d5f7ae7..205d93f 100644 --- a/src/Interfaces/IContainerProperties.ts +++ b/src/Interfaces/IProperties.ts @@ -4,17 +4,13 @@ import { XPositionReference } from '../Enums/XPositionReference'; /** * Properties of a container */ -export default interface IContainerProperties { +export default interface IProperties { /** id of the container */ id: string - // TODO: replace null by empty string /** id of the parent container (null when there is no parent) */ parentId: string | null - /** id of the linked symbol ('' when there is no parent) */ - linkedSymbolId: string - /** Text displayed in the container */ displayedText: string diff --git a/src/Interfaces/ISymbolModel.ts b/src/Interfaces/ISymbolModel.ts deleted file mode 100644 index a99966f..0000000 --- a/src/Interfaces/ISymbolModel.ts +++ /dev/null @@ -1,24 +0,0 @@ -import { IAvailableSymbol } from './IAvailableSymbol'; - -export interface ISymbolModel { - /** Identifier */ - id: string - - /** Type */ - type: string - - /** Configuration of the symbol */ - config: IAvailableSymbol - - /** Horizontal offset */ - x: number - - /** Width */ - width: number - - /** Height */ - height: number - - /** List of linked container id */ - linkedContainers: Set -} diff --git a/src/index.scss b/src/index.scss index c7d716d..d9712f5 100644 --- a/src/index.scss +++ b/src/index.scss @@ -11,10 +11,6 @@ @apply transition-all px-2 py-6 text-sm rounded-lg bg-slate-300/60 hover:bg-slate-300 } - .sidebar-component-card { - @apply transition-all overflow-hidden text-sm rounded-lg bg-slate-300/60 hover:bg-slate-300 - } - .elements-sidebar-row { @apply pl-6 pr-6 pt-2 pb-2 w-full } diff --git a/src/utils/default.ts b/src/utils/default.ts index f30323f..e2778be 100644 --- a/src/utils/default.ts +++ b/src/utils/default.ts @@ -2,7 +2,7 @@ import { XPositionReference } from '../Enums/XPositionReference'; import { IAvailableContainer } from '../Interfaces/IAvailableContainer'; import { IConfiguration } from '../Interfaces/IConfiguration'; import { IContainerModel } from '../Interfaces/IContainerModel'; -import IContainerProperties from '../Interfaces/IContainerProperties'; +import IProperties from '../Interfaces/IProperties'; /// CONTAINER DEFAULTS /// @@ -18,11 +18,6 @@ export const SHOW_DIMENSIONS_PER_DEPTH = true; export const DIMENSION_MARGIN = 50; export const NOTCHES_LENGTH = 4; -/// SYMBOL DEFAULTS /// - -export const DEFAULT_SYMBOL_WIDTH = 32; -export const DEFAULT_SYMBOL_HEIGHT = 32; - /// EDITOR DEFAULTS /// export const ENABLE_SHORTCUTS = true; @@ -53,10 +48,9 @@ export const DEFAULT_CONFIG: IConfiguration = { } }; -export const DEFAULT_MAINCONTAINER_PROPS: IContainerProperties = { +export const DEFAULT_MAINCONTAINER_PROPS: IProperties = { id: 'main', parentId: 'null', - linkedSymbolId: '', displayedText: 'main', x: 0, y: 0, @@ -79,10 +73,9 @@ export const GetDefaultContainerProps = ( x: number, y: number, containerConfig: IAvailableContainer -): IContainerProperties => ({ +): IProperties => ({ id: `${type}-${typeCount}`, parentId: parent.properties.id, - linkedSymbolId: '', displayedText: `${type}-${typeCount}`, x, y, diff --git a/src/utils/saveload.ts b/src/utils/saveload.ts index fcfd022..6867ea3 100644 --- a/src/utils/saveload.ts +++ b/src/utils/saveload.ts @@ -18,11 +18,6 @@ export function Revive(editorState: IEditorState): void { continue; } - state.Symbols = new Map(state.Symbols); - for (const symbol of state.Symbols.values()) { - symbol.linkedContainers = new Set(symbol.linkedContainers); - } - const it = MakeIterator(state.MainContainer); for (const container of it) { const parentId = container.properties.parentId; @@ -36,21 +31,24 @@ export function Revive(editorState: IEditorState): void { } 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 | Map | null) => object | null | undefined => { +export const getCircularReplacer = (): (key: any, value: object | null) => object | null | undefined => { return (key: any, value: object | null) => { if (key === 'parent') { return; } - if (key === 'Symbols') { - return Array.from((value as Map).entries()); - } - - if (key === 'linkedContainers') { - return Array.from(value as Set); + if (key === 'SelectedContainer') { + return; } return value; diff --git a/src/utils/stringtools.ts b/src/utils/stringtools.ts index 2c858c0..349e34a 100644 --- a/src/utils/stringtools.ts +++ b/src/utils/stringtools.ts @@ -4,7 +4,3 @@ export function truncateString(str: string, num: number): string { } return `${str.slice(0, num)}...`; } - -export function camelize(str: string): any { - return str.split('-').map((word, index) => index > 0 ? word.charAt(0).toUpperCase() + word.slice(1) : word).join(''); -} diff --git a/src/utils/svg.ts b/src/utils/svg.ts deleted file mode 100644 index 0248df8..0000000 --- a/src/utils/svg.ts +++ /dev/null @@ -1,21 +0,0 @@ -import { XPositionReference } from '../Enums/XPositionReference'; - -export function transformX(x: number, width: number, xPositionReference = XPositionReference.Left): number { - let transformedX = x; - if (xPositionReference === XPositionReference.Center) { - transformedX += width / 2; - } else if (xPositionReference === XPositionReference.Right) { - transformedX += width; - } - return transformedX; -} - -export function restoreX(x: number, width: number, xPositionReference = XPositionReference.Left): number { - let transformedX = x; - if (xPositionReference === XPositionReference.Center) { - transformedX -= width / 2; - } else if (xPositionReference === XPositionReference.Right) { - transformedX -= width; - } - return transformedX; -} diff --git a/test-server/http.js b/test-server/http.js index 167ff2d..8053660 100644 --- a/test-server/http.js +++ b/test-server/http.js @@ -112,8 +112,7 @@ const GetSVGLayoutConfiguration = () => { ], AvailableSymbols: [ { - Width: 32, - Height: 32, + Height: 0, Image: { Base64Image: null, Name: null, @@ -121,11 +120,11 @@ const GetSVGLayoutConfiguration = () => { Url: 'https://www.manutan.fr/img/S/GRP/ST/AIG3930272.jpg' }, Name: 'Poteau structure', + Width: 0, XPositionReference: 1 }, { - Width: 32, - Height: 32, + Height: 0, Image: { Base64Image: null, Name: null, @@ -133,6 +132,7 @@ const GetSVGLayoutConfiguration = () => { Url: 'https://e7.pngegg.com/pngimages/647/127/png-clipart-svg-working-group-information-world-wide-web-internet-structure.png' }, Name: 'Joint de structure', + Width: 0, XPositionReference: 0 } ],