Refactor usage of EditorState + Add version to editorState + increment editorState to "v2.0.0"

This commit is contained in:
Eric NGUYEN 2023-03-01 11:46:22 +01:00
parent 460669987d
commit afd303f8cb
13 changed files with 136 additions and 179 deletions

View file

@ -1,7 +1,7 @@
{
"name": "svg-layout-designer-react",
"private": true,
"version": "v1.0.0",
"version": "v2.0.0",
"type": "module",
"postinstall": "npx patch-package",
"scripts": {

View file

@ -63,7 +63,8 @@ export function App(props: IAppProps): JSX.Element {
typeCounters: {},
symbols: new Map()
}],
historyCurrentStep: 0
historyCurrentStep: 0,
version: APP_VERSION
});
UseCustomEvents(
@ -86,9 +87,7 @@ export function App(props: IAppProps): JSX.Element {
>
<Editor
root={props.root}
configuration={editorState.configuration}
history={editorState.history}
historyCurrentStep={editorState.historyCurrentStep}
editorState={editorState}
/>
</div>
);

View file

@ -15,6 +15,7 @@ import { FindContainerById } from '../../../utils/itertools';
import { ApplyMargin, RestoreX, RestoreY } from '../../../utils/svg';
import { ApplyBehaviors, ApplyBehaviorsOnSiblingsChildren } from '../Behaviors/Behaviors';
import { GetCurrentHistory, UpdateCounters } from '../Editor';
import { type IEditorState } from '../../../Interfaces/IEditorState';
import { SortChildren } from './ContainerOperations';
/**
@ -28,17 +29,13 @@ import { SortChildren } from './ContainerOperations';
export function AddContainerToSelectedContainer(
type: string,
selected: IContainerModel,
configuration: IConfiguration,
fullHistory: IHistoryState[],
historyCurrentStep: number
editorState: IEditorState
): IHistoryState[] {
return AddContainer(
selected.children.length,
type,
selected.properties.id,
configuration,
fullHistory,
historyCurrentStep
editorState
);
}
@ -56,9 +53,11 @@ export function AddContainers(
index: number,
availableContainers: IAvailableContainer[],
parentId: string,
configuration: IConfiguration,
fullHistory: IHistoryState[],
historyCurrentStep: number
{
configuration,
history: fullHistory,
historyCurrentStep
}: IEditorState
): {
history: IHistoryState[]
newContainers: IContainerModel[]
@ -240,9 +239,7 @@ export function AddContainer(
index: number,
type: string,
parentId: string,
configuration: IConfiguration,
fullHistory: IHistoryState[],
historyCurrentStep: number
editorState: IEditorState
): IHistoryState[] {
// just call AddContainers with an array on a single element
const { history } = AddContainers(
@ -250,9 +247,7 @@ export function AddContainer(
// eslint-disable-next-line @typescript-eslint/naming-convention
[{ Type: type }],
parentId,
configuration,
fullHistory,
historyCurrentStep
editorState
);
return history;
}

View file

@ -8,7 +8,7 @@ import { type ISymbolModel } from '../../../Interfaces/ISymbolModel';
import { PropertyType } from '../../../Enums/PropertyType';
import { TransformX, TransformY } from '../../../utils/svg';
import { Orientation } from '../../../Enums/Orientation';
import { type IConfiguration } from '../../../Interfaces/IConfiguration';
import { type IEditorState } from '../../../Interfaces/IEditorState';
import { AddContainers } from './AddContainer';
/**
@ -17,8 +17,10 @@ import { AddContainers } from './AddContainer';
*/
export function DeselectContainer(
containerId: string,
fullHistory: IHistoryState[],
historyCurrentStep: number
{
history: fullHistory,
historyCurrentStep
}: IEditorState
): IHistoryState[] {
const history = GetCurrentHistory(fullHistory, historyCurrentStep);
const current = history[history.length - 1];
@ -42,8 +44,10 @@ export function DeselectContainer(
*/
export function DeleteContainer(
containerId: string,
fullHistory: IHistoryState[],
historyCurrentStep: number
{
history: fullHistory,
historyCurrentStep
}: IEditorState
): IHistoryState[] {
const history = GetCurrentHistory(fullHistory, historyCurrentStep);
const current = history[history.length - 1];
@ -109,10 +113,10 @@ export function DeleteContainer(
export function ReplaceByContainer(
containerId: string,
newContainerId: string,
configuration: IConfiguration,
fullHistory: IHistoryState[],
historyCurrentStep: number
editorState: IEditorState
): IHistoryState[] {
const fullHistory = editorState.history;
const historyCurrentStep = editorState.historyCurrentStep;
const history = GetCurrentHistory(fullHistory, historyCurrentStep);
const current = history[history.length - 1];
@ -130,12 +134,18 @@ export function ReplaceByContainer(
containerParent.children.indexOf(containerId),
[{ Type: newContainerId }],
containerParent.properties.id,
configuration,
fullHistory,
historyCurrentStep
editorState
);
const historyDelete = DeleteContainer(containerId, historyAdd.history, historyCurrentStep + 1);
const historyDelete = DeleteContainer(
containerId,
{
configuration: editorState.configuration,
history: historyAdd.history,
historyCurrentStep: historyCurrentStep + 1,
version: editorState.version
}
);
const currentDelete = historyDelete[historyDelete.length - 1];
fullHistory.push({
@ -186,8 +196,10 @@ export function OnPropertyChange(
value: string | number | boolean | number[],
type: PropertyType = PropertyType.Simple,
selected: IContainerModel | undefined,
fullHistory: IHistoryState[],
historyCurrentStep: number
{
history: fullHistory,
historyCurrentStep
}: IEditorState
): IHistoryState[] {
const history = GetCurrentHistory(fullHistory, historyCurrentStep);
const current = history[history.length - 1];

View file

@ -2,7 +2,6 @@ import Swal from 'sweetalert2';
import { type Dispatch, type SetStateAction } from 'react';
import { AddMethod } from '../../../Enums/AddMethod';
import { type IAction } from '../../../Interfaces/IAction';
import { type IConfiguration } from '../../../Interfaces/IConfiguration';
import { type IContainerModel } from '../../../Interfaces/IContainerModel';
import { type IHistoryState } from '../../../Interfaces/IHistoryState';
import { type ISetContainerListRequest } from '../../../Interfaces/ISetContainerListRequest';
@ -14,19 +13,21 @@ import { type IMenuAction } from '../../Menu/Menu';
import { GetCurrentHistoryState } from '../Editor';
import { Text } from '../../Text/Text';
import { type IReplaceContainer } from '../../../Interfaces/IReplaceContainer';
import { type IEditorState } from '../../../Interfaces/IEditorState';
import { AddContainers } from './AddContainer';
import { DeleteContainer } from './ContainerOperations';
import { DeleteSymbol } from './SymbolOperations';
export function InitActions(
menuActions: Map<string, IMenuAction[]>,
configuration: IConfiguration,
history: IHistoryState[],
historyCurrentStep: number,
editorState: IEditorState,
setNewHistory: (newHistory: IHistoryState[]) => void,
setHistoryCurrentStep: Dispatch<SetStateAction<number>>,
setIsReplacingContainer: Dispatch<SetStateAction<IReplaceContainer>>
): void {
const configuration = editorState.configuration;
const history = editorState.history;
const historyCurrentStep = editorState.historyCurrentStep;
menuActions.set(
'',
[
@ -82,8 +83,7 @@ export function InitActions(
const id = target.id;
const newHistory = DeleteContainer(
id,
history,
historyCurrentStep
editorState
);
setNewHistory(newHistory);
}
@ -100,8 +100,7 @@ export function InitActions(
const id = target.id;
const newHistory = DeleteSymbol(
id,
history,
historyCurrentStep
editorState
);
setNewHistory(newHistory);
}
@ -130,9 +129,7 @@ export function InitActions(
action: GetAction(
action,
currentState,
configuration,
history,
historyCurrentStep,
editorState,
setNewHistory
)
};
@ -145,9 +142,7 @@ export function InitActions(
function GetAction(
action: IAction,
currentState: IHistoryState,
configuration: IConfiguration,
history: IHistoryState[],
historyCurrentStep: number,
editorState: IEditorState,
setNewHistory: (newHistory: IHistoryState[]) => void
): (target: HTMLElement) => void {
return (target: HTMLElement) => {
@ -175,15 +170,16 @@ function GetAction(
};
/* eslint-enable */
SetContainerList(request, configuration.APIConfiguration?.apiSetContainerListUrl)
SetContainerList(
request,
editorState.configuration.APIConfiguration?.apiSetContainerListUrl
)
.then((response: ISetContainerListResponse) => {
HandleSetContainerList(
action,
container,
response,
configuration,
history,
historyCurrentStep,
editorState,
setNewHistory
);
});
@ -215,13 +211,14 @@ function HandleSetContainerList(
action: IAction,
selectedContainer: IContainerModel,
response: ISetContainerListResponse,
configuration: IConfiguration,
history: IHistoryState[],
historyCurrentStep: number,
editorState: IEditorState,
setNewHistory: (newHistory: IHistoryState[]) => void
): void {
const addingBehavior = response.AddingBehavior ?? action.AddingBehavior;
const current = GetCurrentHistoryState(history, historyCurrentStep);
const current = GetCurrentHistoryState(
editorState.history,
editorState.historyCurrentStep
);
const containers = current.containers;
switch (addingBehavior) {
case AddMethod.Insert:
@ -233,9 +230,7 @@ function HandleSetContainerList(
selectedContainer.children.length,
response.Containers,
selectedContainer.properties.id,
configuration,
history,
historyCurrentStep
editorState
);
setNewHistory(newHistory);
@ -246,9 +241,7 @@ function HandleSetContainerList(
containers,
selectedContainer,
response,
configuration,
history,
historyCurrentStep
editorState
));
break;
case AddMethod.ReplaceParent: {
@ -265,9 +258,7 @@ function HandleSetContainerList(
containers,
parent,
response,
configuration,
history,
historyCurrentStep
editorState
));
break;
}
@ -278,9 +269,7 @@ function HandleReplace(
containers: Map<string, IContainerModel>,
selectedContainer: IContainerModel,
response: ISetContainerListResponse,
configuration: IConfiguration,
history: IHistoryState[],
historyCurrentStep: number
editorState: IEditorState
): IHistoryState[] {
const parent = FindContainerById(containers, selectedContainer.properties.parentId);
if (parent === undefined || parent === null) {
@ -291,17 +280,21 @@ function HandleReplace(
const newHistoryAfterDelete = DeleteContainer(
selectedContainer.properties.id,
history,
historyCurrentStep
editorState
);
const newEditorStateAfterDelete: IEditorState = {
configuration: editorState.configuration,
history: newHistoryAfterDelete,
historyCurrentStep: newHistoryAfterDelete.length - 1,
version: editorState.version
};
const { history: newHistoryBeforeDelete } = AddContainers(
index,
response.Containers,
selectedContainer.properties.parentId,
configuration,
newHistoryAfterDelete,
newHistoryAfterDelete.length - 1
newEditorStateAfterDelete
);
// Remove AddContainers from history

View file

@ -1,24 +1,15 @@
import { type IHistoryState } from '../../../Interfaces/IHistoryState';
import { type IConfiguration } from '../../../Interfaces/IConfiguration';
import { GetCircularReplacer } from '../../../utils/saveload';
import { ID } from '../../SVG/SVG';
import { type IEditorState } from '../../../Interfaces/IEditorState';
import { SHOW_SELECTOR_TEXT } from '../../../utils/default';
export function SaveEditorAsJSON(
history: IHistoryState[],
historyCurrentStep: number,
configuration: IConfiguration
editorState: IEditorState
): void {
const exportName = 'state.json';
const spaces = import.meta.env.DEV
? 4
: 0;
const editorState: IEditorState = {
history,
historyCurrentStep,
configuration
};
// eslint-disable-next-line @typescript-eslint/strict-boolean-expressions
if (window.Worker) {

View file

@ -1,5 +1,5 @@
import { type IConfiguration } from '../../../Interfaces/IConfiguration';
import { type IContainerModel } from '../../../Interfaces/IContainerModel';
import { type IEditorState } from '../../../Interfaces/IEditorState';
import { type IHistoryState } from '../../../Interfaces/IHistoryState';
import { type ISymbolModel } from '../../../Interfaces/ISymbolModel';
import { GetDefaultSymbolModel } from '../../../utils/default';
@ -12,9 +12,12 @@ import { LinkSymbol } from './ContainerOperations';
export function AddSymbol(
name: string,
configuration: IConfiguration,
fullHistory: IHistoryState[],
historyCurrentStep: number
{
configuration,
history: fullHistory,
historyCurrentStep,
version
}: IEditorState
): IHistoryState[] {
let history = GetCurrentHistory(fullHistory, historyCurrentStep);
const current = history[history.length - 1];
@ -57,9 +60,12 @@ export function AddSymbol(
0,
[symbolConfig.AssociatedContainer],
current.mainContainer,
configuration,
history,
historyCurrentStep + 1
{
configuration,
history,
historyCurrentStep: historyCurrentStep + 1,
version
}
);
history = newHistory;
@ -76,8 +82,10 @@ export function AddSymbol(
export function DeleteSymbol(
symbolId: string,
fullHistory: IHistoryState[],
historyCurrentStep: number
{
history: fullHistory,
historyCurrentStep
}: IEditorState
): IHistoryState[] {
const history = GetCurrentHistory(fullHistory, historyCurrentStep);
const current = history[history.length - 1];
@ -131,8 +139,10 @@ export function OnPropertyChange(
key: string,
value: string | number | boolean,
selectedSymbolId: string,
fullHistory: IHistoryState[],
historyCurrentStep: number
{
history: fullHistory,
historyCurrentStep
}: IEditorState
): IHistoryState[] {
const history = GetCurrentHistory(fullHistory, historyCurrentStep);
const current = history[history.length - 1];

View file

@ -1,6 +1,5 @@
import React, { type Dispatch, type SetStateAction, useEffect, useRef } from 'react';
import './Editor.scss';
import { type IConfiguration } from '../../Interfaces/IConfiguration';
import { type IHistoryState } from '../../Interfaces/IHistoryState';
import { UI } from '../UI/UI';
import { UseCustomEvents, UseEditorListener } from '../../Events/EditorEvents';
@ -8,6 +7,7 @@ import { MAX_HISTORY } from '../../utils/default';
import { FindContainerById } from '../../utils/itertools';
import { Menu } from '../Menu/Menu';
import { type IReplaceContainer } from '../../Interfaces/IReplaceContainer';
import { type IEditorState } from '../../Interfaces/IEditorState';
import { DeleteContainer, OnPropertyChange, ReplaceByContainer } from './Actions/ContainerOperations';
import { SaveEditorAsJSON, SaveEditorAsSVG } from './Actions/Save';
import { OnKey } from './Actions/Shortcuts';
@ -21,9 +21,7 @@ import { AddContainerToSelectedContainer, AddContainer } from './Actions/AddCont
interface IEditorProps {
root: Element | Document
configuration: IConfiguration
history: IHistoryState[]
historyCurrentStep: number
editorState: IEditorState
}
function UseShortcuts(
@ -73,8 +71,8 @@ function UseNewHistoryState(
export function Editor(props: IEditorProps): JSX.Element {
// States
const [history, setHistory] = React.useState<IHistoryState[]>(structuredClone(props.history));
const [historyCurrentStep, setHistoryCurrentStep] = React.useState<number>(props.historyCurrentStep);
const [history, setHistory] = React.useState<IHistoryState[]>(structuredClone(props.editorState.history));
const [historyCurrentStep, setHistoryCurrentStep] = React.useState<number>(props.editorState.historyCurrentStep);
const [
replaceContainer,
setReplaceContainer
@ -86,6 +84,13 @@ export function Editor(props: IEditorProps): JSX.Element {
const eventCallbackQueue = useRef<CustomEvent[]>([]);
const setNewHistory = UseNewHistoryState(setHistory, setHistoryCurrentStep);
const editorState: IEditorState = {
configuration: props.editorState.configuration,
history,
historyCurrentStep,
version: props.editorState.version
};
function ResetState(): void {
setReplaceContainer({ isReplacing: false, id: undefined, category: undefined });
}
@ -96,51 +101,40 @@ export function Editor(props: IEditorProps): JSX.Element {
historyCurrentStep,
setHistoryCurrentStep,
() => {
setNewHistory(DeleteContainer(selectedContainerId, history, historyCurrentStep));
setNewHistory(DeleteContainer(selectedContainerId, editorState));
},
ResetState
);
UseCustomEvents(
eventCallbackQueue,
props.root,
history,
historyCurrentStep,
props.configuration,
editorState,
editorRef,
setNewHistory
);
UseEditorListener(
props.root,
history,
historyCurrentStep,
props.configuration
editorState
);
// Context Menu
const menuActions = new Map();
InitActions(
menuActions,
props.configuration,
history,
historyCurrentStep,
editorState,
setNewHistory,
setHistoryCurrentStep,
setReplaceContainer
);
// Render
const configuration = props.configuration;
const current = GetCurrentHistoryState(history, historyCurrentStep);
const selected = FindContainerById(current.containers, selectedContainerId);
return (
<div ref={editorRef} className="Editor font-sans h-full ">
<UI
editorState={{
configuration: props.configuration,
history,
historyCurrentStep
}}
editorState={editorState}
replaceContainer={replaceContainer}
selectedContainerId={selectedContainerId}
selectedSymbolId={selectedSymbolId}
@ -150,8 +144,7 @@ export function Editor(props: IEditorProps): JSX.Element {
deleteContainer={(containerId: string) => {
setNewHistory(DeleteContainer(
containerId,
history,
historyCurrentStep
editorState
));
}}
onPropertyChange={(key, value, type) => {
@ -160,8 +153,7 @@ export function Editor(props: IEditorProps): JSX.Element {
value,
type,
selected,
history,
historyCurrentStep
editorState
));
}}
addOrReplaceContainer={(type) => {
@ -172,9 +164,7 @@ export function Editor(props: IEditorProps): JSX.Element {
const newHistory = ReplaceByContainer(
replaceContainer.id,
type,
configuration,
history,
historyCurrentStep
editorState
);
setReplaceContainer({ isReplacing: false, id: undefined, category: undefined });
setNewHistory(newHistory);
@ -182,9 +172,7 @@ export function Editor(props: IEditorProps): JSX.Element {
setNewHistory(AddContainerToSelectedContainer(
type,
selected,
configuration,
history,
historyCurrentStep
editorState
));
}
}}
@ -193,17 +181,13 @@ export function Editor(props: IEditorProps): JSX.Element {
index,
type,
parent,
configuration,
history,
historyCurrentStep
editorState
));
}}
addSymbol={(type) => {
setNewHistory(AddSymbol(
type,
configuration,
history,
historyCurrentStep
editorState
));
}}
onSymbolPropertyChange={(key, value) => {
@ -211,8 +195,7 @@ export function Editor(props: IEditorProps): JSX.Element {
key,
value,
selectedSymbolId,
history,
historyCurrentStep
editorState
));
}}
selectSymbol={(symbolId) => {
@ -221,16 +204,11 @@ export function Editor(props: IEditorProps): JSX.Element {
deleteSymbol={(symbolId) => {
setNewHistory(DeleteSymbol(
symbolId,
history,
historyCurrentStep
editorState
));
}}
saveEditorAsJSON={() => {
SaveEditorAsJSON(
history,
historyCurrentStep,
configuration
);
SaveEditorAsJSON(editorState);
}}
saveEditorAsSVG={() => { SaveEditorAsSVG(); }}
loadState={(move) => { setHistoryCurrentStep(move); }}

View file

@ -43,18 +43,11 @@ export const events: IEditorEvent[] = [
export function UseCustomEvents(
callbackQueue: React.RefObject<CustomEvent[]>,
root: Element | Document,
history: IHistoryState[],
historyCurrentStep: number,
configuration: IConfiguration,
editorState: IEditorState,
editorRef: React.RefObject<HTMLDivElement>,
setNewHistory: (newHistory: IHistoryState[], historyCurrentStep?: number) => void
): void {
useEffect(() => {
const editorState: IEditorState = {
history,
historyCurrentStep,
configuration
};
const current = editorRef.current;
if (current === null) {
@ -110,16 +103,9 @@ export function UseCustomEvents(
export function UseEditorListener(
root: Element | Document,
history: IHistoryState[],
historyCurrentStep: number,
configuration: IConfiguration
editorState: IEditorState
): void {
useEffect(() => {
const editorState: IEditorState = {
history,
historyCurrentStep,
configuration
};
const event = new CustomEvent('editorListener', { detail: editorState });
root.dispatchEvent(event);
});
@ -209,14 +195,11 @@ function AddContainer({
parentId
} = eventInitDict?.detail;
const history = GetCurrentHistory(editorState.history, editorState.historyCurrentStep);
const newHistory = AddContainerAction(
index,
type,
parentId,
editorState.configuration,
history,
editorState.historyCurrentStep
editorState
);
setNewHistory(newHistory);
@ -249,9 +232,7 @@ function AppendContainer({
parent?.children.length ?? 0,
type,
parentId,
editorState.configuration,
history,
editorState.historyCurrentStep
editorState
);
setNewHistory(newHistory);
@ -273,13 +254,9 @@ function DeleteContainer({
const {
containerId
} = eventInitDict?.detail;
const history = GetCurrentHistory(editorState.history, editorState.historyCurrentStep);
const newHistory = DeleteContainerAction(
containerId,
history,
editorState.historyCurrentStep
editorState
);
setNewHistory(newHistory);
@ -302,13 +279,9 @@ function AddSymbol({
name
} = eventInitDict?.detail;
const history = GetCurrentHistory(editorState.history, editorState.historyCurrentStep);
const newHistory = AddSymbolAction(
name,
editorState.configuration,
history,
editorState.historyCurrentStep
editorState
);
setNewHistory(newHistory);
@ -331,11 +304,9 @@ function DeleteSymbol({
symbolId
} = eventInitDict?.detail;
const history = GetCurrentHistory(editorState.history, editorState.historyCurrentStep);
const newHistory = DeleteSymbolAction(
symbolId,
history,
editorState.historyCurrentStep
editorState
);
setNewHistory(newHistory);

View file

@ -5,4 +5,5 @@ export interface IEditorState {
history: IHistoryState[]
historyCurrentStep: number
configuration: IConfiguration
version: string
}

View file

@ -10,6 +10,7 @@ import { Orientation } from '../Enums/Orientation';
import { AppState } from '../Enums/AppState';
import { type IDimensionOptions } from '../Interfaces/IDimensionOptions';
import { type IDimensionStyle } from '../Components/SVG/Elements/Dimension';
import { version } from 'react';
/// EDITOR DEFAULTS ///
@ -151,7 +152,8 @@ export function GetDefaultEditorState(configuration: IConfiguration): IEditorSta
symbols: new Map()
}
],
historyCurrentStep: 0
historyCurrentStep: 0,
version: APP_VERSION
};
}

2
src/vite-env.d.ts vendored
View file

@ -11,3 +11,5 @@ interface ImportMetaEnv {
interface ImportMeta {
readonly env: ImportMetaEnv
}
declare const APP_VERSION: string;

View file

@ -6,5 +6,8 @@ export default defineConfig({
plugins: [
react()
],
base: './'
base: './',
define: {
APP_VERSION: JSON.stringify(process.env.npm_package_version)
}
});