From 62abd3ff037cd857189601f88fa44c275bcd62e8 Mon Sep 17 00:00:00 2001 From: Carl Fuchs Date: Fri, 3 Feb 2023 16:58:54 +0100 Subject: [PATCH 01/18] WIP --- src/Components/Components/Components.tsx | 5 ++ .../Editor/Actions/ContainerOperations.ts | 68 ++++++++++++++++++- .../Editor/Actions/ContextMenuActions.ts | 12 +++- src/Components/UI/UI.tsx | 4 ++ 4 files changed, 85 insertions(+), 4 deletions(-) diff --git a/src/Components/Components/Components.tsx b/src/Components/Components/Components.tsx index 53a3dd9..314ecff 100644 --- a/src/Components/Components/Components.tsx +++ b/src/Components/Components/Components.tsx @@ -11,6 +11,7 @@ interface IComponentsProps { selectedContainer: IContainerModel | undefined componentOptions: IAvailableContainer[] categories: ICategory[] + replaceableCategoryName: string | undefined buttonOnClick: (type: string) => void } @@ -62,6 +63,10 @@ export function Components(props: IComponentsProps): JSX.Element { disabled = config.Blacklist?.find(type => type === componentOption.Type) !== undefined ?? false; } + if (componentOption.Category !== props.replaceableCategoryName) { + disabled = true; + } + if (disabled && hideDisabled) { return; } diff --git a/src/Components/Editor/Actions/ContainerOperations.ts b/src/Components/Editor/Actions/ContainerOperations.ts index 131df82..dc5bfb5 100644 --- a/src/Components/Editor/Actions/ContainerOperations.ts +++ b/src/Components/Editor/Actions/ContainerOperations.ts @@ -8,6 +8,7 @@ import Swal from 'sweetalert2'; import { PropertyType } from '../../../Enums/PropertyType'; import { TransformX, TransformY } from '../../../utils/svg'; import { Orientation } from '../../../Enums/Orientation'; +import { AddContainers, AddContainerToSelectedContainer } from './AddContainer'; /** * Select a container @@ -109,6 +110,68 @@ export function DeleteContainer( return history; } +/** + * Replace a container + * @param containerId containerId of the container to delete + * @param fullHistory History of the editor + * @param historyCurrentStep Current step + * @returns New history + */ +// export function ReplaceByContainer( +// containerId: string, +// newContainerId: string, +// fullHistory: IHistoryState[], +// historyCurrentStep: number +// ): IHistoryState[] { +// const history = GetCurrentHistory(fullHistory, historyCurrentStep); +// const current = history[history.length - 1]; +// +// +// const containers = structuredClone(current.containers); +// const container = FindContainerById(containers, containerId); +// if (container === undefined) { +// throw new Error(`[ReplaceContainer] Tried to delete a container that is not present in the main container: ${containerId}`); +// } +// /// +// const parent = FindContainerById(containers, container.properties.parentId); +// if (parent === undefined || parent === null) { +// throw new Error('[ReplaceContainer] Cannot replace a container that does not exists'); +// } +// +// const index = parent.children.indexOf(container.properties.id); +// +// const newHistoryAfterDelete = DeleteContainer( +// container.properties.id, +// history, +// historyCurrentStep +// ); +// +// const newContainer = FindContainerById(containers, container.properties.parentId); +// +// AddContainerToSelectedContainer( +// ne, +// selected, +// configuration, +// history, +// historyCurrentStep +// ); +// +// +// /// / +// +// +// history.push({ +// lastAction: `Replace ${containerId} By InsertnewId`, +// mainContainer: current.mainContainer, +// containers, +// newContainerId, +// typeCounters: Object.assign({}, current.typeCounters), +// symbols: newSymbols, +// selectedSymbolId: current.selectedSymbolId +// }); +// return history; +// } + /** * Returns the next container that will be selected * after the selectedContainer is removed. @@ -371,9 +434,8 @@ function AssignProperty(container: IContainerModel, key: string, value: string | /** * Link a symbol to a container * @param containerId Container id - * @param oldSymbolId Old Symbol id - * @param newSymbolId New Symbol id - * @param symbols Current list of symbols + * @param oldSymbol + * @param newSymbol * @returns */ export function LinkSymbol( diff --git a/src/Components/Editor/Actions/ContextMenuActions.ts b/src/Components/Editor/Actions/ContextMenuActions.ts index 69a3121..2781d1e 100644 --- a/src/Components/Editor/Actions/ContextMenuActions.ts +++ b/src/Components/Editor/Actions/ContextMenuActions.ts @@ -56,9 +56,18 @@ export function InitActions( menuActions.set( 'elements-sidebar-row', [{ + text: Text({ textId: '@ReplaceByContainer' }), + title: Text({ textId: '@ReplaceByContainerTitle' }), + shortcut: 'R', + action: (target: HTMLElement) => { + const id = target.id; + console.log('replace'); + } + }, { text: Text({ textId: '@DeleteContainer' }), title: Text({ textId: '@DeleteContainerTitle' }), shortcut: 'Suppr', + action: (target: HTMLElement) => { const id = target.id; const newHistory = DeleteContainer( @@ -68,7 +77,8 @@ export function InitActions( ); setNewHistory(newHistory); } - }] + } + ] ); menuActions.set( diff --git a/src/Components/UI/UI.tsx b/src/Components/UI/UI.tsx index d80e869..5e7a6a4 100644 --- a/src/Components/UI/UI.tsx +++ b/src/Components/UI/UI.tsx @@ -97,11 +97,15 @@ export function UI({ editorState, ...methods }: IUIProps): JSX.Element { switch (selectedSidebar) { case SidebarType.Components: leftSidebarTitle = Text({ textId: '@Components' }); + + const AllowedReplaceCategory = undefined; + leftChildren = ; rightSidebarTitle = Text({ textId: '@Elements' }); rightChildren = Date: Mon, 6 Feb 2023 16:45:34 +0100 Subject: [PATCH 02/18] Implemtation in progress, UIX working , replacing in ContainerOperations.ts working but not properly need fix --- src/Components/Bar/Bar.tsx | 3 +- src/Components/Components/Components.tsx | 20 ++- .../Editor/Actions/ContainerOperations.ts | 118 ++++++++---------- .../Editor/Actions/ContextMenuActions.ts | 14 ++- src/Components/Editor/Editor.tsx | 42 +++++-- src/Components/Menu/Menu.tsx | 5 +- src/Components/UI/UI.tsx | 24 ++-- src/Components/Viewer/Viewer.tsx | 6 +- src/Interfaces/IReplaceContainer.ts | 5 + 9 files changed, 139 insertions(+), 98 deletions(-) create mode 100644 src/Interfaces/IReplaceContainer.ts diff --git a/src/Components/Bar/Bar.tsx b/src/Components/Bar/Bar.tsx index 8f28635..a693fc2 100644 --- a/src/Components/Bar/Bar.tsx +++ b/src/Components/Bar/Bar.tsx @@ -17,6 +17,7 @@ import { BarIcon } from './BarIcon'; import { Text } from '../Text/Text'; interface IBarProps { + className: string isComponentsOpen: boolean isSymbolsOpen: boolean isHistoryOpen: boolean @@ -33,7 +34,7 @@ export const BAR_WIDTH = 64; // 4rem export function Bar(props: IBarProps): JSX.Element { return ( -
+
> buttonOnClick: (type: string) => void } @@ -63,7 +66,7 @@ export function Components(props: IComponentsProps): JSX.Element { disabled = config.Blacklist?.find(type => type === componentOption.Type) !== undefined ?? false; } - if (componentOption.Category !== props.replaceableCategoryName) { + if (props.replaceContainer.isReplacing && componentOption.Category !== props.replaceContainer.category) { disabled = true; } @@ -101,6 +104,15 @@ export function Components(props: IComponentsProps): JSX.Element { return (
+ {props.replaceContainer.isReplacing && + }
); -}; +} diff --git a/src/Components/Editor/Actions/ContainerOperations.ts b/src/Components/Editor/Actions/ContainerOperations.ts index dc5bfb5..57a0d72 100644 --- a/src/Components/Editor/Actions/ContainerOperations.ts +++ b/src/Components/Editor/Actions/ContainerOperations.ts @@ -8,7 +8,8 @@ import Swal from 'sweetalert2'; import { PropertyType } from '../../../Enums/PropertyType'; import { TransformX, TransformY } from '../../../utils/svg'; import { Orientation } from '../../../Enums/Orientation'; -import { AddContainers, AddContainerToSelectedContainer } from './AddContainer'; +import { AddContainerToSelectedContainer } from './AddContainer'; +import { IConfiguration } from '../../../Interfaces/IConfiguration'; /** * Select a container @@ -113,64 +114,44 @@ export function DeleteContainer( /** * Replace a container * @param containerId containerId of the container to delete + * @param newContainerId + * @param configuration * @param fullHistory History of the editor * @param historyCurrentStep Current step * @returns New history */ -// export function ReplaceByContainer( -// containerId: string, -// newContainerId: string, -// fullHistory: IHistoryState[], -// historyCurrentStep: number -// ): IHistoryState[] { -// const history = GetCurrentHistory(fullHistory, historyCurrentStep); -// const current = history[history.length - 1]; -// -// -// const containers = structuredClone(current.containers); -// const container = FindContainerById(containers, containerId); -// if (container === undefined) { -// throw new Error(`[ReplaceContainer] Tried to delete a container that is not present in the main container: ${containerId}`); -// } -// /// -// const parent = FindContainerById(containers, container.properties.parentId); -// if (parent === undefined || parent === null) { -// throw new Error('[ReplaceContainer] Cannot replace a container that does not exists'); -// } -// -// const index = parent.children.indexOf(container.properties.id); -// -// const newHistoryAfterDelete = DeleteContainer( -// container.properties.id, -// history, -// historyCurrentStep -// ); -// -// const newContainer = FindContainerById(containers, container.properties.parentId); -// -// AddContainerToSelectedContainer( -// ne, -// selected, -// configuration, -// history, -// historyCurrentStep -// ); -// -// -// /// / -// -// -// history.push({ -// lastAction: `Replace ${containerId} By InsertnewId`, -// mainContainer: current.mainContainer, -// containers, -// newContainerId, -// typeCounters: Object.assign({}, current.typeCounters), -// symbols: newSymbols, -// selectedSymbolId: current.selectedSymbolId -// }); -// return history; -// } +export function ReplaceByContainer( + containerId: string, + newContainerId: string, + configuration: IConfiguration, + fullHistory: IHistoryState[], + historyCurrentStep: number +): IHistoryState[] { + const history = GetCurrentHistory(fullHistory, historyCurrentStep); + const current = history[history.length - 1]; + + const historyDelete = DeleteContainer(containerId, fullHistory, historyCurrentStep); + const currentDelete = historyDelete[historyDelete.length - 1]; + const selectedContainer = FindContainerById(currentDelete.containers, currentDelete.selectedContainerId); + if (selectedContainer != null) { + const historyAdd = AddContainerToSelectedContainer(newContainerId, selectedContainer, configuration, fullHistory, historyCurrentStep); + + const currentAdd = historyAdd[historyAdd.length - 1]; + + fullHistory.push({ + lastAction: `Replace ${containerId} by ${newContainerId}`, + mainContainer: currentAdd.mainContainer, + containers: currentAdd.containers, + selectedContainerId: currentAdd.selectedContainerId, + typeCounters: Object.assign({}, currentAdd.typeCounters), + symbols: current.symbols, + selectedSymbolId: current.selectedSymbolId + }); + + return fullHistory; + } + return history; +} /** * Returns the next container that will be selected @@ -178,7 +159,7 @@ export function DeleteContainer( * If the selected container is removed, select the sibling after, * If there is no sibling, select the parent, * - * @param mainContainerClone Main container + * @param containers * @param selectedContainerId Current selected container * @param parent Parent of the selected/deleted container * @param index Index of the selected/deleted container @@ -190,11 +171,10 @@ function GetSelectedContainerOnDelete( parent: IContainerModel, index: number ): string { - const newSelectedContainerId = FindContainerById(containers, selectedContainerId)?.properties.id ?? - parent.children.at(index) ?? - parent.children.at(index - 1) ?? - parent.properties.id; - return newSelectedContainerId; + return FindContainerById(containers, selectedContainerId)?.properties.id ?? + parent.children.at(index) ?? + parent.children.at(index - 1) ?? + parent.properties.id; } /** @@ -220,11 +200,15 @@ function UnlinkContainerFromSymbols( } /** - * Handled the property change event in the properties form - * @param key Property name - * @param value New value of the property - * @returns void - */ + * Handled the property change event in the properties form + * @param key Property name + * @param value New value of the property + * @param type + * @param selected + * @param fullHistory + * @param historyCurrentStep + * @returns void + */ export function OnPropertyChange( key: string, value: string | number | boolean | number[], @@ -264,6 +248,7 @@ export function OnPropertyChange( /** * Sort the parent children by x + * @param containers * @param parent The clone used for the sort * @returns void */ @@ -328,6 +313,7 @@ export function SortChildren( /** * Set the container with properties and behaviors (mutate) + * @param containers * @param container Container to update * @param key Key of the property to update * @param value Value of the property to update diff --git a/src/Components/Editor/Actions/ContextMenuActions.ts b/src/Components/Editor/Actions/ContextMenuActions.ts index 2781d1e..5b2a546 100644 --- a/src/Components/Editor/Actions/ContextMenuActions.ts +++ b/src/Components/Editor/Actions/ContextMenuActions.ts @@ -16,6 +16,7 @@ import { AddContainers } from './AddContainer'; import { DeleteContainer } from './ContainerOperations'; import { DeleteSymbol } from './SymbolOperations'; import { Text } from '../../Text/Text'; +import { IReplaceContainer } from '../../../Interfaces/IReplaceContainer'; export function InitActions( menuActions: Map, @@ -23,7 +24,8 @@ export function InitActions( history: IHistoryState[], historyCurrentStep: number, setNewHistory: (newHistory: IHistoryState[]) => void, - setHistoryCurrentStep: Dispatch> + setHistoryCurrentStep: Dispatch>, + setIsReplacingContainer: Dispatch> ): void { menuActions.set( '', @@ -60,8 +62,14 @@ export function InitActions( title: Text({ textId: '@ReplaceByContainerTitle' }), shortcut: 'R', action: (target: HTMLElement) => { - const id = target.id; - console.log('replace'); + const targetContainer = FindContainerById(history[historyCurrentStep].containers, target.id); + const targetAvailableContainer = configuration.AvailableContainers.find((availableContainer) => availableContainer.Type === targetContainer?.properties.type); + + if (targetAvailableContainer === undefined) { + return; + } + + setIsReplacingContainer({ isReplacing: true, id: target.id, category: targetAvailableContainer.Category }); } }, { text: Text({ textId: '@DeleteContainer' }), diff --git a/src/Components/Editor/Editor.tsx b/src/Components/Editor/Editor.tsx index 372ab06..6644bed 100644 --- a/src/Components/Editor/Editor.tsx +++ b/src/Components/Editor/Editor.tsx @@ -3,7 +3,7 @@ import './Editor.scss'; import { IConfiguration } from '../../Interfaces/IConfiguration'; import { IHistoryState } from '../../Interfaces/IHistoryState'; import { UI } from '../UI/UI'; -import { SelectContainer, DeleteContainer, OnPropertyChange } from './Actions/ContainerOperations'; +import { SelectContainer, DeleteContainer, OnPropertyChange, ReplaceByContainer } from './Actions/ContainerOperations'; import { SaveEditorAsJSON, SaveEditorAsSVG } from './Actions/Save'; import { OnKey } from './Actions/Shortcuts'; import { UseCustomEvents, UseEditorListener } from '../../Events/EditorEvents'; @@ -13,6 +13,7 @@ import { FindContainerById } from '../../utils/itertools'; import { Menu } from '../Menu/Menu'; import { InitActions } from './Actions/ContextMenuActions'; import { AddContainerToSelectedContainer, AddContainer } from './Actions/AddContainer'; +import { IReplaceContainer } from '../../Interfaces/IReplaceContainer'; interface IEditorProps { root: Element | Document @@ -66,6 +67,8 @@ export function Editor(props: IEditorProps): JSX.Element { // States const [history, setHistory] = React.useState(structuredClone(props.history)); const [historyCurrentStep, setHistoryCurrentStep] = React.useState(props.historyCurrentStep); + const [replaceContainer, setReplaceContainer] = React.useState({ isReplacing: false, id: undefined, category: undefined }); + const editorRef = useRef(null); const setNewHistory = UseNewHistoryState(setHistory, setHistoryCurrentStep); @@ -104,7 +107,8 @@ export function Editor(props: IEditorProps): JSX.Element { history, historyCurrentStep, setNewHistory, - setHistoryCurrentStep + setHistoryCurrentStep, + setReplaceContainer ); // Render @@ -113,7 +117,7 @@ export function Editor(props: IEditorProps): JSX.Element { const selected = FindContainerById(current.containers, current.selectedContainerId); return ( -
+
{ + addOrReplaceContainer={(type) => { if (selected === null || selected === undefined) { return; } - - setNewHistory(AddContainerToSelectedContainer( - type, - selected, - configuration, - history, - historyCurrentStep - )); + if (replaceContainer.isReplacing && replaceContainer.id !== undefined) { + const newHistory = ReplaceByContainer( + replaceContainer.id, + type, + configuration, + history, + historyCurrentStep + ); + setReplaceContainer({ isReplacing: false, id: undefined, category: undefined }); + setNewHistory(newHistory); + } else { + setNewHistory(AddContainerToSelectedContainer( + type, + selected, + configuration, + history, + historyCurrentStep + )); + } }} addContainerAt={(index, type, parent) => setNewHistory( AddContainer( @@ -194,9 +209,10 @@ export function Editor(props: IEditorProps): JSX.Element { )} saveEditorAsSVG={() => SaveEditorAsSVG()} loadState={(move) => setHistoryCurrentStep(move)} - /> + replaceContainer ={replaceContainer} setReplaceContainer={setReplaceContainer}/> editorRef.current} + configuration={configuration} actions={menuActions} className="z-30 transition-opacity rounded bg-slate-200 drop-shadow-xl" /> diff --git a/src/Components/Menu/Menu.tsx b/src/Components/Menu/Menu.tsx index a0fbc03..c8da101 100644 --- a/src/Components/Menu/Menu.tsx +++ b/src/Components/Menu/Menu.tsx @@ -2,11 +2,13 @@ import useSize from '@react-hook/size'; import * as React from 'react'; import { IPoint } from '../../Interfaces/IPoint'; import { MenuItem } from './MenuItem'; +import { IConfiguration } from '../../Interfaces/IConfiguration'; interface IMenuProps { getListener: () => HTMLElement | null actions: Map className?: string + configuration: IConfiguration } export interface IMenuAction { @@ -21,6 +23,7 @@ export interface IMenuAction { /** function to be called on button click */ action: (target: HTMLElement) => void + } function UseMouseEvents( @@ -139,7 +142,7 @@ function AddClassSpecificActions( onClick={() => action.action(target)} />); }); children.push(
); - }; + } return count; } diff --git a/src/Components/UI/UI.tsx b/src/Components/UI/UI.tsx index 5e7a6a4..cab0e17 100644 --- a/src/Components/UI/UI.tsx +++ b/src/Components/UI/UI.tsx @@ -17,13 +17,15 @@ import { FindContainerById } from '../../utils/itertools'; import { IEditorState } from '../../Interfaces/IEditorState'; import { GetCurrentHistoryState } from '../Editor/Editor'; import { Text } from '../Text/Text'; +import { IReplaceContainer } from '../../Interfaces/IReplaceContainer'; +import { Dispatch } from 'react'; export interface IUIProps { editorState: IEditorState selectContainer: (containerId: string) => void deleteContainer: (containerId: string) => void onPropertyChange: (key: string, value: string | number | boolean | number[], type?: PropertyType) => void - addContainer: (type: string) => void + addOrReplaceContainer: (type: string) => void addContainerAt: (index: number, type: string, parent: string) => void addSymbol: (type: string) => void onSymbolPropertyChange: (key: string, value: string | number | boolean) => void @@ -32,6 +34,9 @@ export interface IUIProps { saveEditorAsJSON: () => void saveEditorAsSVG: () => void loadState: (move: number) => void + replaceContainer: IReplaceContainer + setReplaceContainer: Dispatch> + } export enum SidebarType { @@ -57,8 +62,9 @@ function UseSetOrToggleSidebar( }; } -export function UI({ editorState, ...methods }: IUIProps): JSX.Element { +export function UI({ editorState, replaceContainer, setReplaceContainer, ...methods }: IUIProps): JSX.Element { const [selectedSidebar, setSelectedSidebar] = React.useState(SidebarType.Components); + const [messages, setMessages] = React.useState([]); const current = GetCurrentHistoryState(editorState.history, editorState.historyCurrentStep); const configuration = editorState.configuration; @@ -98,15 +104,13 @@ export function UI({ editorState, ...methods }: IUIProps): JSX.Element { case SidebarType.Components: leftSidebarTitle = Text({ textId: '@Components' }); - const AllowedReplaceCategory = undefined; - leftChildren = ; + buttonOnClick={methods.addOrReplaceContainer} + replaceContainer={replaceContainer} + setReplaceContainer={setReplaceContainer}/>; rightSidebarTitle = Text({ textId: '@Elements' }); rightChildren = { rightChildren } diff --git a/src/Components/Viewer/Viewer.tsx b/src/Components/Viewer/Viewer.tsx index ba0560b..474ac57 100644 --- a/src/Components/Viewer/Viewer.tsx +++ b/src/Components/Viewer/Viewer.tsx @@ -12,6 +12,7 @@ import { SVG } from '../SVG/SVG'; import { RenderSymbol } from '../Canvas/Symbol'; interface IViewerProps { + className: string isLeftSidebarOpen: boolean isRightSidebarOpen: boolean current: IHistoryState @@ -73,6 +74,7 @@ function UseSVGAutoResizerOnSidebar( } export function Viewer({ + className, isLeftSidebarOpen, isRightSidebarOpen, current, selectedContainer, @@ -160,7 +162,7 @@ export function Viewer({ return ( @@ -169,7 +171,7 @@ export function Viewer({ return ( Date: Tue, 7 Feb 2023 16:07:51 +0100 Subject: [PATCH 03/18] [WIP] ReplaceBy in ContainerOperations.ts --- .../Editor/Actions/ContainerOperations.ts | 50 +++++++++++-------- 1 file changed, 29 insertions(+), 21 deletions(-) diff --git a/src/Components/Editor/Actions/ContainerOperations.ts b/src/Components/Editor/Actions/ContainerOperations.ts index 57a0d72..43b14b0 100644 --- a/src/Components/Editor/Actions/ContainerOperations.ts +++ b/src/Components/Editor/Actions/ContainerOperations.ts @@ -8,7 +8,7 @@ import Swal from 'sweetalert2'; import { PropertyType } from '../../../Enums/PropertyType'; import { TransformX, TransformY } from '../../../utils/svg'; import { Orientation } from '../../../Enums/Orientation'; -import { AddContainerToSelectedContainer } from './AddContainer'; +import { AddContainers } from './AddContainer'; import { IConfiguration } from '../../../Interfaces/IConfiguration'; /** @@ -130,27 +130,35 @@ export function ReplaceByContainer( const history = GetCurrentHistory(fullHistory, historyCurrentStep); const current = history[history.length - 1]; - const historyDelete = DeleteContainer(containerId, fullHistory, historyCurrentStep); - const currentDelete = historyDelete[historyDelete.length - 1]; - const selectedContainer = FindContainerById(currentDelete.containers, currentDelete.selectedContainerId); - if (selectedContainer != null) { - const historyAdd = AddContainerToSelectedContainer(newContainerId, selectedContainer, configuration, fullHistory, historyCurrentStep); - - const currentAdd = historyAdd[historyAdd.length - 1]; - - fullHistory.push({ - lastAction: `Replace ${containerId} by ${newContainerId}`, - mainContainer: currentAdd.mainContainer, - containers: currentAdd.containers, - selectedContainerId: currentAdd.selectedContainerId, - typeCounters: Object.assign({}, currentAdd.typeCounters), - symbols: current.symbols, - selectedSymbolId: current.selectedSymbolId - }); - - return fullHistory; + const containerToReplace = FindContainerById(current.containers, containerId); + if (containerToReplace === undefined) { + return history; } - return history; + const containerParent = FindContainerById(current.containers,containerToReplace.properties.parentId); + if (containerParent=== undefined) { + return history; + } + const historyAdd = AddContainers(containerParent.children.indexOf(containerId), [{ Type: newContainerId }], containerParent.properties.id, configuration, fullHistory, historyCurrentStep); + // Copy des possibles enfants + if (historyAdd.newContainers[0] === undefined) { + return history; + } + historyAdd.newContainers[0].children = containerToReplace.children; + + const historyDelete = DeleteContainer(containerId, historyAdd.history, historyCurrentStep + 1); + const currentDelete = historyDelete[historyDelete.length - 1]; + + fullHistory.push({ + lastAction: `Replace ${containerId} by ${newContainerId}`, + mainContainer: currentDelete.mainContainer, + containers: currentDelete.containers, + selectedContainerId: currentDelete.selectedContainerId, + typeCounters: Object.assign({}, currentDelete.typeCounters), + symbols: current.symbols, + selectedSymbolId: current.selectedSymbolId + }); + + return fullHistory; } /** From 579422653b6acb00bf0451a2a248d7390acb08ac Mon Sep 17 00:00:00 2001 From: Carl Fuchs Date: Thu, 9 Feb 2023 15:30:31 +0100 Subject: [PATCH 04/18] Implement Highlight on symbols --- .../SVG/Elements/{Selector => }/Selector.scss | 0 .../SelectorContainer.tsx} | 8 +-- .../SelectorSymbol/SelectorSymbol.tsx | 65 +++++++++++++++++++ src/Components/SVG/SVG.tsx | 21 +++--- src/Components/SymbolsList/SymbolsSidebar.tsx | 46 ++++++------- src/Components/UI/UI.tsx | 27 +++++--- src/Components/Viewer/Viewer.tsx | 21 ++++-- 7 files changed, 138 insertions(+), 50 deletions(-) rename src/Components/SVG/Elements/{Selector => }/Selector.scss (100%) rename src/Components/SVG/Elements/{Selector/Selector.tsx => SelectorContainer/SelectorContainer.tsx} (88%) create mode 100644 src/Components/SVG/Elements/SelectorSymbol/SelectorSymbol.tsx diff --git a/src/Components/SVG/Elements/Selector/Selector.scss b/src/Components/SVG/Elements/Selector.scss similarity index 100% rename from src/Components/SVG/Elements/Selector/Selector.scss rename to src/Components/SVG/Elements/Selector.scss diff --git a/src/Components/SVG/Elements/Selector/Selector.tsx b/src/Components/SVG/Elements/SelectorContainer/SelectorContainer.tsx similarity index 88% rename from src/Components/SVG/Elements/Selector/Selector.tsx rename to src/Components/SVG/Elements/SelectorContainer/SelectorContainer.tsx index c7baf92..c85f2b3 100644 --- a/src/Components/SVG/Elements/Selector/Selector.tsx +++ b/src/Components/SVG/Elements/SelectorContainer/SelectorContainer.tsx @@ -1,17 +1,17 @@ -import './Selector.scss'; +import '../Selector.scss'; import * as React from 'react'; -import { IContainerModel } from '../../../../Interfaces/IContainerModel'; +import { type IContainerModel } from '../../../../Interfaces/IContainerModel'; import { SHOW_SELECTOR_TEXT } from '../../../../utils/default'; import { GetAbsolutePosition } from '../../../../utils/itertools'; import { RemoveMargin } from '../../../../utils/svg'; -interface ISelectorProps { +interface ISelectorContainerProps { containers: Map selected?: IContainerModel scale?: number } -export function Selector(props: ISelectorProps): JSX.Element { +export function SelectorContainer(props: ISelectorContainerProps): JSX.Element { if (props.selected === undefined || props.selected === null) { return ( diff --git a/src/Components/SVG/Elements/SelectorSymbol/SelectorSymbol.tsx b/src/Components/SVG/Elements/SelectorSymbol/SelectorSymbol.tsx new file mode 100644 index 0000000..2cdce3b --- /dev/null +++ b/src/Components/SVG/Elements/SelectorSymbol/SelectorSymbol.tsx @@ -0,0 +1,65 @@ +import '../Selector.scss'; +import * as React from 'react'; +import { SHOW_SELECTOR_TEXT, SYMBOL_MARGIN } from '../../../../utils/default'; +import { type ISymbolModel } from '../../../../Interfaces/ISymbolModel'; + +interface ISelectorSymbolProps { + symbols: Map + selected?: ISymbolModel + scale?: number +} + +export function SelectorSymbol(props: ISelectorSymbolProps): JSX.Element { + if (props.selected === undefined || props.selected === null) { + return ( + + + ); + } + + const scale = (props.scale ?? 1); + const [width, height] = [ + props.selected.width, + props.selected.height / scale + ]; + + const [x, y] = [props.selected.x, -SYMBOL_MARGIN - height]; + + const xText = x + width / 2; + const yText = y + height / 2; + + const style: React.CSSProperties = { + stroke: '#3B82F6', + strokeWidth: 4 / scale, + fillOpacity: 0, + transitionProperty: 'all', + transitionTimingFunction: 'cubic-bezier(0.4, 0, 0.2, 1)', + transitionDuration: '150ms', + animation: 'fadein 750ms ease-in alternate infinite' + }; + + return ( + <> + + + {SHOW_SELECTOR_TEXT + ? + {props.selected.displayedText} + + : null} + + ); +} diff --git a/src/Components/SVG/SVG.tsx b/src/Components/SVG/SVG.tsx index cdb11de..738a0da 100644 --- a/src/Components/SVG/SVG.tsx +++ b/src/Components/SVG/SVG.tsx @@ -1,13 +1,14 @@ import * as React from 'react'; -import { ReactSVGPanZoom, Tool, TOOL_PAN, Value } from 'react-svg-pan-zoom'; +import { ReactSVGPanZoom, type Tool, TOOL_PAN, type Value } from 'react-svg-pan-zoom'; import { Container } from './Elements/Container'; -import { IContainerModel } from '../../Interfaces/IContainerModel'; -import { Selector } from './Elements/Selector/Selector'; +import { type IContainerModel } from '../../Interfaces/IContainerModel'; +import { SelectorContainer } from './Elements/SelectorContainer/SelectorContainer'; import { DepthDimensionLayer } from './Elements/DepthDimensionLayer'; import { MAX_FRAMERATE, SHOW_DIMENSIONS_PER_DEPTH } from '../../utils/default'; import { SymbolLayer } from './Elements/SymbolLayer'; -import { ISymbolModel } from '../../Interfaces/ISymbolModel'; +import { type ISymbolModel } from '../../Interfaces/ISymbolModel'; import { DimensionLayer } from './Elements/DimensionLayer'; +import { SelectorSymbol } from './Elements/SelectorSymbol/SelectorSymbol'; interface ISVGProps { className?: string @@ -17,9 +18,12 @@ interface ISVGProps { height: number containers: Map children: IContainerModel - selected?: IContainerModel + selectedContainer?: IContainerModel symbols: Map + selectedSymbol?: ISymbolModel selectContainer: (containerId: string) => void + isComponentsOpen: boolean + isSymbolsOpen: boolean } export const ID = 'svg'; @@ -49,8 +53,7 @@ export function SVG(props: ISVGProps): JSX.Element { xmlns }; - let children: React.ReactNode | React.ReactNode[] = []; - children = - {/* leave this at the end so it can be removed during the svg export */} + {/* leave this at the end so it can be removed during the svg export */} + { props.isComponentsOpen ? : null } + { props.isSymbolsOpen ? : null }
diff --git a/src/Components/SymbolsList/SymbolsSidebar.tsx b/src/Components/SymbolsList/SymbolsSidebar.tsx index a43e8ae..300dcf9 100644 --- a/src/Components/SymbolsList/SymbolsSidebar.tsx +++ b/src/Components/SymbolsList/SymbolsSidebar.tsx @@ -1,7 +1,7 @@ import * as React from 'react'; import useSize from '@react-hook/size'; import { FixedSizeList as List } from 'react-window'; -import { ISymbolModel } from '../../Interfaces/ISymbolModel'; +import { type ISymbolModel } from '../../Interfaces/ISymbolModel'; import { SymbolProperties } from '../SymbolProperties/SymbolProperties'; import { ToggleSideBar } from '../Sidebar/ToggleSideBar/ToggleSideBar'; import { Text } from '../Text/Text'; @@ -23,28 +23,7 @@ export function SymbolsSidebar(props: ISymbolsSidebarProps): JSX.Element { const [showProperties, setShowProperties] = useState(props.isExpanded); // Render const symbols = [...props.symbols.values()]; - function Row({ index, style }: { index: number, style: React.CSSProperties }): JSX.Element { - const symbol = symbols[index]; - const key = symbol.id; - const text = symbol.displayedText; - const selectedClass: string = props.selectedSymbolId !== '' && - props.selectedSymbolId === symbol.id - ? 'border-l-4 bg-slate-400/60 hover:bg-slate-400' - : 'bg-slate-300/60 hover:bg-slate-300'; - return ( - - ); - } const selectedSymbol = props.symbols.get(props.selectedSymbolId); return (
@@ -71,4 +50,27 @@ export function SymbolsSidebar(props: ISymbolsSidebarProps): JSX.Element {
); + + function Row({ index, style }: { index: number, style: React.CSSProperties }): JSX.Element { + const symbol = symbols[index]; + const key = symbol.id; + const text = symbol.displayedText; + const selectedClass: string = props.selectedSymbolId !== '' && + props.selectedSymbolId === symbol.id + ? 'border-l-4 bg-slate-400/60 hover:bg-slate-400' + : 'bg-slate-300/60 hover:bg-slate-300'; + + return ( + + ); + } } diff --git a/src/Components/UI/UI.tsx b/src/Components/UI/UI.tsx index f85b63c..01d5407 100644 --- a/src/Components/UI/UI.tsx +++ b/src/Components/UI/UI.tsx @@ -4,17 +4,17 @@ import { History } from '../History/History'; import { Bar, BAR_WIDTH } from '../Bar/Bar'; import { Symbols } from '../Symbols/Symbols'; import { SymbolsSidebar } from '../SymbolsList/SymbolsSidebar'; -import { PropertyType } from '../../Enums/PropertyType'; +import { type PropertyType } from '../../Enums/PropertyType'; import { Messages } from '../Messages/Messages'; import { Sidebar } from '../Sidebar/Sidebar'; import { Components } from '../Components/Components'; import { Viewer } from '../Viewer/Viewer'; import { Settings } from '../Settings/Settings'; -import { IMessage } from '../../Interfaces/IMessage'; +import { type IMessage } from '../../Interfaces/IMessage'; import { DISABLE_API } from '../../utils/default'; import { UseWorker, UseAsync } from './UseWorker'; import { FindContainerById } from '../../utils/itertools'; -import { IEditorState } from '../../Interfaces/IEditorState'; +import { type IEditorState } from '../../Interfaces/IEditorState'; import { GetCurrentHistoryState } from '../Editor/Editor'; import { Text } from '../Text/Text'; @@ -96,6 +96,7 @@ export function UI({ editorState, ...methods }: IUIProps): JSX.Element { } const selectedContainer = FindContainerById(current.containers, current.selectedContainerId); + const selectedSymbol = current.symbols.get(current.selectedSymbolId); switch (selectedSidebar) { case SidebarType.Components: @@ -116,7 +117,7 @@ export function UI({ editorState, ...methods }: IUIProps): JSX.Element { selectContainer={methods.selectContainer} addContainer={methods.addContainerAt} isExpanded ={false} - onExpandChange={() => setOrToggleSidebar(SidebarType.ComponentsExpanded) } + onExpandChange={() => { setOrToggleSidebar(SidebarType.ComponentsExpanded); } } />; break; case SidebarType.ComponentsExpanded: @@ -137,7 +138,7 @@ export function UI({ editorState, ...methods }: IUIProps): JSX.Element { selectContainer={methods.selectContainer} addContainer={methods.addContainerAt} isExpanded ={true} - onExpandChange={() => setOrToggleSidebar(SidebarType.Components) } + onExpandChange={() => { setOrToggleSidebar(SidebarType.Components); } } />; break; case SidebarType.Symbols: @@ -153,7 +154,7 @@ export function UI({ editorState, ...methods }: IUIProps): JSX.Element { onPropertyChange={methods.onSymbolPropertyChange} selectSymbol={methods.selectSymbol} isExpanded ={false} - onExpandChange={() => setOrToggleSidebar(SidebarType.SymbolsExpanded) } + onExpandChange={() => { setOrToggleSidebar(SidebarType.SymbolsExpanded); } } />; break; case SidebarType.SymbolsExpanded: @@ -169,7 +170,7 @@ export function UI({ editorState, ...methods }: IUIProps): JSX.Element { onPropertyChange={methods.onSymbolPropertyChange} selectSymbol={methods.selectSymbol} isExpanded ={true} - onExpandChange={() => setOrToggleSidebar(SidebarType.Symbols)} + onExpandChange={() => { setOrToggleSidebar(SidebarType.Symbols); }} />; break; @@ -187,7 +188,7 @@ export function UI({ editorState, ...methods }: IUIProps): JSX.Element { leftChildren = setMessages([])} + clearMessage={() => { setMessages([]); }} />; break; @@ -242,11 +243,14 @@ export function UI({ editorState, ...methods }: IUIProps): JSX.Element { isLeftSidebarOpenClasses.add('left-sidebar-single'); } + const isComponentsOpen = selectedSidebar === SidebarType.Components || selectedSidebar === SidebarType.ComponentsExpanded; + const isSymbolsOpen = selectedSidebar === SidebarType.Symbols || selectedSidebar === SidebarType.SymbolsExpanded; + return ( <> void + selectedSymbol: ISymbolModel | undefined margin: number + isComponentsOpen: boolean + isSymbolsOpen: boolean } export function Viewer({ @@ -25,7 +29,10 @@ export function Viewer({ current, selectedContainer, selectContainer, - margin + selectedSymbol, + margin, + isComponentsOpen, + isSymbolsOpen }: IViewerProps): JSX.Element { function computeWidth(margin: number): number { return window.innerWidth - (window.innerWidth < 768 ? BAR_WIDTH : margin); @@ -134,11 +141,13 @@ export function Viewer({ width={mainContainer.properties.width} height={mainContainer.properties.height} containers={current.containers} - selected={selectedContainer} + selectedContainer={selectedContainer} symbols={current.symbols} + selectedSymbol={selectedSymbol} selectContainer={selectContainer} + isComponentsOpen={isComponentsOpen} + isSymbolsOpen={isSymbolsOpen} > - {mainContainer} ); From 9797ada55a0dbe50fc6ea5c12ed5f95862db3132 Mon Sep 17 00:00:00 2001 From: Eric NGUYEN Date: Fri, 10 Feb 2023 17:07:26 +0100 Subject: [PATCH 05/18] Replace isComponentsOpen, isSymbolsOpen by SelectorMode in SVG.tsx --- src/Components/SVG/SVG.tsx | 32 +++++++++++++++++++++++++++----- src/Components/Viewer/Viewer.tsx | 12 +++++++++--- 2 files changed, 36 insertions(+), 8 deletions(-) diff --git a/src/Components/SVG/SVG.tsx b/src/Components/SVG/SVG.tsx index 738a0da..8e79f93 100644 --- a/src/Components/SVG/SVG.tsx +++ b/src/Components/SVG/SVG.tsx @@ -21,9 +21,14 @@ interface ISVGProps { selectedContainer?: IContainerModel symbols: Map selectedSymbol?: ISymbolModel + selectorMode: SelectorMode selectContainer: (containerId: string) => void - isComponentsOpen: boolean - isSymbolsOpen: boolean +} + +export enum SelectorMode { + Nothing, + Containers, + Symbols } export const ID = 'svg'; @@ -62,6 +67,25 @@ export function SVG(props: ISVGProps): JSX.Element { selectContainer={props.selectContainer} />; + function Selector(): JSX.Element { + switch (props.selectorMode) { + case SelectorMode.Containers: + return ; + case SelectorMode.Symbols: + return ; + default: + return <>; + } + } + return (
- {/* leave this at the end so it can be removed during the svg export */} - { props.isComponentsOpen ? : null } - { props.isSymbolsOpen ? : null } +
diff --git a/src/Components/Viewer/Viewer.tsx b/src/Components/Viewer/Viewer.tsx index a0b342e..3c97354 100644 --- a/src/Components/Viewer/Viewer.tsx +++ b/src/Components/Viewer/Viewer.tsx @@ -8,7 +8,7 @@ import { BAR_WIDTH } from '../Bar/Bar'; import { Canvas } from '../Canvas/Canvas'; import { AddDimensions } from '../Canvas/DimensionLayer'; import { RenderSelector } from '../Canvas/Selector'; -import { SVG } from '../SVG/SVG'; +import { SelectorMode, SVG } from '../SVG/SVG'; import { RenderSymbol } from '../Canvas/Symbol'; import { useState } from 'react'; import { type ISymbolModel } from '../../Interfaces/ISymbolModel'; @@ -71,6 +71,13 @@ export function Viewer({ return <>; } + let selectorMode = SelectorMode.Nothing; + if (isComponentsOpen) { + selectorMode = SelectorMode.Containers; + } else if (isSymbolsOpen) { + selectorMode = SelectorMode.Symbols; + } + if (USE_EXPERIMENTAL_CANVAS_API) { function Draw(ctx: CanvasRenderingContext2D, frameCount: number, scale: number, translatePos: IPoint): void { if (mainContainer === undefined) { @@ -144,9 +151,8 @@ export function Viewer({ selectedContainer={selectedContainer} symbols={current.symbols} selectedSymbol={selectedSymbol} + selectorMode={selectorMode} selectContainer={selectContainer} - isComponentsOpen={isComponentsOpen} - isSymbolsOpen={isSymbolsOpen} > {mainContainer} From 2b7ff3a202b2521433c9ff4f97d507077ff3529f Mon Sep 17 00:00:00 2001 From: Eric NGUYEN Date: Fri, 10 Feb 2023 17:20:02 +0100 Subject: [PATCH 06/18] Fix selectorSymbol not horizontally centered on the symbol --- .../SVG/Elements/SelectorSymbol/SelectorSymbol.tsx | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/src/Components/SVG/Elements/SelectorSymbol/SelectorSymbol.tsx b/src/Components/SVG/Elements/SelectorSymbol/SelectorSymbol.tsx index 2cdce3b..fd45870 100644 --- a/src/Components/SVG/Elements/SelectorSymbol/SelectorSymbol.tsx +++ b/src/Components/SVG/Elements/SelectorSymbol/SelectorSymbol.tsx @@ -19,11 +19,13 @@ export function SelectorSymbol(props: ISelectorSymbolProps): JSX.Element { const scale = (props.scale ?? 1); const [width, height] = [ - props.selected.width, + props.selected.width / scale, props.selected.height / scale ]; - const [x, y] = [props.selected.x, -SYMBOL_MARGIN - height]; + const [x, y] = [ + props.selected.x + props.selected.width / 2, + -SYMBOL_MARGIN - height]; const xText = x + width / 2; const yText = y + height / 2; @@ -35,7 +37,9 @@ export function SelectorSymbol(props: ISelectorSymbolProps): JSX.Element { transitionProperty: 'all', transitionTimingFunction: 'cubic-bezier(0.4, 0, 0.2, 1)', transitionDuration: '150ms', - animation: 'fadein 750ms ease-in alternate infinite' + animation: 'fadein 750ms ease-in alternate infinite', + transform: 'translateX(-50%)', + transformBox: 'fill-box' }; return ( From b35fa924229a25347827fedda63d8f17915fb1fe Mon Sep 17 00:00:00 2001 From: Eric NGUYEN Date: Fri, 10 Feb 2023 17:24:53 +0100 Subject: [PATCH 07/18] Add todo to fix to SaveEditorAsSVG --- src/Components/Editor/Actions/Save.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/src/Components/Editor/Actions/Save.ts b/src/Components/Editor/Actions/Save.ts index ae7b4e9..2dc2f95 100644 --- a/src/Components/Editor/Actions/Save.ts +++ b/src/Components/Editor/Actions/Save.ts @@ -53,6 +53,7 @@ export function SaveEditorAsSVG(): void { svg.replaceChildren(...mainSvg); // remove the selector + // TODO: Fix this with SelectorMode != Nothing or with some html magic const group = svg.children[svg.children.length - 1]; group.removeChild(group.children[group.children.length - 1]); if (SHOW_SELECTOR_TEXT) { From 338a2c157c8830d532aa3cad61cfa1e78fac94cc Mon Sep 17 00:00:00 2001 From: Eric Nguyen Date: Mon, 13 Feb 2023 14:54:50 +0000 Subject: [PATCH 08/18] Merged PR 330: Add DimensionStyle + Refactor dimensionLayer + Add width and dashArray to style Add DimensionStyle + Refactor dimensionLayer + Add width and dashArray to style Related work items: #7977 --- .../SVGLDLibs/Models/DimensionOptions.cs | 51 +- .../SVGLDLibs/Models/DimensionStyle.cs | 27 ++ .../ContainerProperties/ContainerForm.tsx | 452 +++++++++++------- .../Editor/Actions/ContainerOperations.ts | 12 + src/Components/SVG/Elements/Dimension.tsx | 12 +- .../SVG/Elements/DimensionLayer.tsx | 111 ++--- src/Enums/PropertyType.ts | 15 +- src/Interfaces/IAvailableContainer.ts | 16 +- src/Interfaces/IDimensionOptions.ts | 9 +- src/Interfaces/IDimensionStyle.ts | 12 + src/Interfaces/ISymbolModel.ts | 2 +- src/Translations/translation.en.json | 9 +- src/Translations/translation.fr.json | 3 + src/utils/default.ts | 68 +-- 14 files changed, 475 insertions(+), 324 deletions(-) create mode 100644 csharp/SVGLDLibs/SVGLDLibs/Models/DimensionStyle.cs create mode 100644 src/Interfaces/IDimensionStyle.ts diff --git a/csharp/SVGLDLibs/SVGLDLibs/Models/DimensionOptions.cs b/csharp/SVGLDLibs/SVGLDLibs/Models/DimensionOptions.cs index a98e500..42aafd7 100644 --- a/csharp/SVGLDLibs/SVGLDLibs/Models/DimensionOptions.cs +++ b/csharp/SVGLDLibs/SVGLDLibs/Models/DimensionOptions.cs @@ -1,28 +1,23 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Runtime.Serialization; -using System.Text; -using System.Threading.Tasks; - -namespace SVGLDLibs.Models -{ - - [DataContract] - public class DimensionOptions - { - - /** positions of the dimension */ - [DataMember(EmitDefaultValue = false)] - public Position[] positions; - - /** color */ - [DataMember(EmitDefaultValue = false)] - public string color; - - - - - } - -} +using System; +using System.Collections.Generic; +using System.Linq; +using System.Runtime.Serialization; +using System.Text; +using System.Threading.Tasks; + +namespace SVGLDLibs.Models +{ + + [DataContract] + public class DimensionOptions + { + + /** positions of the dimension */ + [DataMember(EmitDefaultValue = false)] + public Position[] positions; + + /** color */ + [DataMember(EmitDefaultValue = false)] + public DimensionStyle style; + } +} diff --git a/csharp/SVGLDLibs/SVGLDLibs/Models/DimensionStyle.cs b/csharp/SVGLDLibs/SVGLDLibs/Models/DimensionStyle.cs new file mode 100644 index 0000000..c35cd5f --- /dev/null +++ b/csharp/SVGLDLibs/SVGLDLibs/Models/DimensionStyle.cs @@ -0,0 +1,27 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Runtime.Serialization; +using System.Text; +using System.Threading.Tasks; + +namespace SVGLDLibs.Models +{ + + [DataContract] + public class DimensionStyle + { + /** color */ + [DataMember(EmitDefaultValue = false)] + public string color; + + /** width */ + + [DataMember(EmitDefaultValue = false)] + public double width; + + /** color */ + [DataMember(EmitDefaultValue = false)] + public string dashArray; + } +} diff --git a/src/Components/ContainerProperties/ContainerForm.tsx b/src/Components/ContainerProperties/ContainerForm.tsx index 4bdc262..6781302 100644 --- a/src/Components/ContainerProperties/ContainerForm.tsx +++ b/src/Components/ContainerProperties/ContainerForm.tsx @@ -1,7 +1,7 @@ import * as React from 'react'; import { PropertyType } from '../../Enums/PropertyType'; -import { IContainerProperties } from '../../Interfaces/IContainerProperties'; -import { ISymbolModel } from '../../Interfaces/ISymbolModel'; +import { type IContainerProperties } from '../../Interfaces/IContainerProperties'; +import { type ISymbolModel } from '../../Interfaces/ISymbolModel'; import { SHOW_BORROWER_DIMENSIONS, SHOW_CHILDREN_DIMENSIONS, @@ -46,7 +46,7 @@ export function ContainerForm(props: IContainerFormProps): JSX.Element { inputClassName='' type='string' value={props.properties.displayedText?.toString()} - onChange={(value) => props.onChange('displayedText', value)}/> + onChange={(value) => { props.onChange('displayedText', value); }}/> props.onChange( - 'x', - ApplyXMargin( - RestoreX( - Number(value), - props.properties.width, - props.properties.positionReference - ), - props.properties.margin.left - ) - )}/> + onChange={(value) => { + props.onChange( + 'x', + ApplyXMargin( + RestoreX( + Number(value), + props.properties.width, + props.properties.positionReference + ), + props.properties.margin.left + ) + ); + }}/> props.onChange( - 'y', - ApplyXMargin( - RestoreY( - Number(value), - props.properties.height, - props.properties.positionReference - ), - props.properties.margin.top - ) - )}/> + onChange={(value) => { + props.onChange( + 'y', + ApplyXMargin( + RestoreY( + Number(value), + props.properties.height, + props.properties.positionReference + ), + props.properties.margin.top + ) + ); + }}/>
@@ -171,7 +175,7 @@ export function ContainerForm(props: IContainerFormProps): JSX.Element { type='number' min={1} value={props.properties.minWidth.toString()} - onChange={(value) => props.onChange('minWidth', Number(value))}/> + onChange={(value) => { props.onChange('minWidth', Number(value)); }}/> props.onChange('width', ApplyWidthMargin(Number(value), props.properties.margin.left, props.properties.margin.right))} + onChange={(value) => { props.onChange('width', ApplyWidthMargin(Number(value), props.properties.margin.left, props.properties.margin.right)); }} isDisabled={props.properties.isFlex}/> props.onChange('maxWidth', Number(value))}/> + onChange={(value) => { props.onChange('maxWidth', Number(value)); }}/>
props.onChange('minHeight', Number(value))}/> + onChange={(value) => { props.onChange('minHeight', Number(value)); }}/> props.onChange('height', ApplyWidthMargin(Number(value), props.properties.margin.top, props.properties.margin.bottom))} + onChange={(value) => { props.onChange('height', ApplyWidthMargin(Number(value), props.properties.margin.top, props.properties.margin.bottom)); }} isDisabled={props.properties.isFlex} /> props.onChange('maxHeight', Number(value))}/> + onChange={(value) => { props.onChange('maxHeight', Number(value)); }}/>
@@ -247,7 +251,7 @@ export function ContainerForm(props: IContainerFormProps): JSX.Element { type='number' min={0} value={(props.properties.margin.left ?? 0).toString()} - onChange={(value) => props.onChange('left', Number(value), PropertyType.Margin)}/> + onChange={(value) => { props.onChange('left', Number(value), PropertyType.Margin); }}/> props.onChange('bottom', Number(value), PropertyType.Margin)}/> + onChange={(value) => { props.onChange('bottom', Number(value), PropertyType.Margin); }}/> props.onChange('top', Number(value), PropertyType.Margin)}/> + onChange={(value) => { props.onChange('top', Number(value), PropertyType.Margin); }}/> props.onChange('right', Number(value), PropertyType.Margin)}/> + onChange={(value) => { props.onChange('right', Number(value), PropertyType.Margin); }}/> @@ -295,7 +299,7 @@ export function ContainerForm(props: IContainerFormProps): JSX.Element { inputClassName='ml-auto mr-auto block' type={ToggleType.Full} checked={props.properties.isFlex} - onChange={(event) => props.onChange('isFlex', event.target.checked)} + onChange={(event) => { props.onChange('isFlex', event.target.checked); }} /> props.onChange('isAnchor', event.target.checked)}/> + onChange={(event) => { props.onChange('isAnchor', event.target.checked); }}/> @@ -334,7 +338,7 @@ export function ContainerForm(props: IContainerFormProps): JSX.Element { value: symbol.id }))} value={props.properties.linkedSymbolId ?? ''} - onChange={(event) => props.onChange('linkedSymbolId', event.target.value)}/> + onChange={(event) => { props.onChange('linkedSymbolId', event.target.value); }}/> @@ -347,168 +351,244 @@ export function ContainerForm(props: IContainerFormProps): JSX.Element {
{ SHOW_SELF_DIMENSIONS && -
- props.onChange(key, value, PropertyType.SelfDimension)} - /> - props.onChange('color', e.target.value, PropertyType.SelfDimension)}/> -
+
+ { props.onChange(key, value, PropertyType.SelfDimension); }} + /> + { props.onChange('color', e.target.value, PropertyType.SelfDimensionStyle); }}/> + { props.onChange('width', Number(value), PropertyType.SelfDimensionStyle); }}/> + { props.onChange('dashArray', value, PropertyType.SelfDimensionStyle); }}/> +
} { SHOW_SELF_MARGINS_DIMENSIONS && -
- props.onChange(key, value, PropertyType.SelfMarginDimension)} - /> - props.onChange('color', e.target.value, PropertyType.SelfMarginDimension)}/> -
+
+ { props.onChange(key, value, PropertyType.SelfMarginDimension); }} + /> + { props.onChange('color', e.target.value, PropertyType.SelfMarginDimensionStyle); }}/> + { props.onChange('width', Number(value), PropertyType.SelfMarginDimensionStyle); }}/> + { props.onChange('dashArray', value, PropertyType.SelfMarginDimensionStyle); }}/> +
} { SHOW_CHILDREN_DIMENSIONS && -
- props.onChange(key, value, PropertyType.ChildrenDimensions)} - /> - props.onChange('color', e.target.value, PropertyType.ChildrenDimensions)}/> -
+
+ { props.onChange(key, value, PropertyType.ChildrenDimensions); }} + /> + { props.onChange('color', e.target.value, PropertyType.ChildrenDimensionsStyle); }}/> + { props.onChange('width', Number(value), PropertyType.ChildrenDimensionsStyle); }}/> + { props.onChange('dashArray', value, PropertyType.ChildrenDimensionsStyle); }}/> +
} { SHOW_BORROWER_DIMENSIONS && - <> -
- props.onChange(key, value, PropertyType.DimensionOptions)} - /> -
-
- props.onChange(key, value, PropertyType.DimensionWithMarks)} - /> - props.onChange('color', e.target.value, PropertyType.DimensionWithMarks)}/> -
- + <> +
+ { props.onChange(key, value, PropertyType.DimensionOptions); }} + /> +
+
+ { props.onChange(key, value, PropertyType.DimensionWithMarks); }} + /> + { props.onChange('color', e.target.value, PropertyType.DimensionWithMarksStyle); }}/> + { props.onChange('width', Number(value), PropertyType.DimensionWithMarksStyle); }}/> + { props.onChange('dashArray', value, PropertyType.DimensionWithMarksStyle); }}/> +
+ }
{props.properties.style !== undefined && - -
- props.onChange('stroke', value, PropertyType.Style)} - /> - props.onChange('strokeOpacity', Number(event.target.value), PropertyType.Style)} - /> - props.onChange('strokeWidth', Number(value), PropertyType.Style)} - /> - props.onChange('fill', value, PropertyType.Style)} - /> - props.onChange('fillOpacity', Number(event.target.value), PropertyType.Style)} - /> -
-
+ +
+ { props.onChange('stroke', value, PropertyType.Style); }} + /> + { props.onChange('strokeOpacity', Number(event.target.value), PropertyType.Style); }} + /> + { props.onChange('strokeWidth', Number(value), PropertyType.Style); }} + /> + { props.onChange('fill', value, PropertyType.Style); }} + /> + { props.onChange('fillOpacity', Number(event.target.value), PropertyType.Style); }} + /> +
+
} ); diff --git a/src/Components/Editor/Actions/ContainerOperations.ts b/src/Components/Editor/Actions/ContainerOperations.ts index 82162e3..4d5490a 100644 --- a/src/Components/Editor/Actions/ContainerOperations.ts +++ b/src/Components/Editor/Actions/ContainerOperations.ts @@ -362,6 +362,18 @@ function AssignProperty(container: IContainerModel, key: string, value: string | case PropertyType.DimensionWithMarks: (container.properties.dimensionOptions.dimensionWithMarks as any)[key] = value; break; + case PropertyType.SelfDimensionStyle: + (container.properties.dimensionOptions.selfDimensions.style as any)[key] = value; + break; + case PropertyType.SelfMarginDimensionStyle: + (container.properties.dimensionOptions.selfMarginsDimensions.style as any)[key] = value; + break; + case PropertyType.ChildrenDimensionsStyle: + (container.properties.dimensionOptions.childrenDimensions.style as any)[key] = value; + break; + case PropertyType.DimensionWithMarksStyle: + (container.properties.dimensionOptions.dimensionWithMarks.style as any)[key] = value; + break; case PropertyType.DimensionOptions: (container.properties.dimensionOptions as any)[key] = value; break; diff --git a/src/Components/SVG/Elements/Dimension.tsx b/src/Components/SVG/Elements/Dimension.tsx index 0848bea..88f7c99 100644 --- a/src/Components/SVG/Elements/Dimension.tsx +++ b/src/Components/SVG/Elements/Dimension.tsx @@ -1,4 +1,5 @@ import * as React from 'react'; +import { type IDimensionStyle } from '../../../Interfaces/IDimensionStyle'; import { NOTCHES_LENGTH } from '../../../utils/default'; interface IDimensionProps { @@ -8,7 +9,7 @@ interface IDimensionProps { xEnd: number yEnd: number text: string - color: string + style: IDimensionStyle scale?: number } @@ -28,8 +29,9 @@ function ApplyParametric(x0: number, t: number, vx: number): number { export function Dimension(props: IDimensionProps): JSX.Element { const scale = props.scale ?? 1; const style: React.CSSProperties = { - stroke: props.color, - strokeWidth: 2 / scale + stroke: props.style.color, + strokeWidth: (props.style.width ?? 2) / scale, + strokeDasharray: props.style.dashArray }; /// We need to find the points of the notches @@ -79,9 +81,11 @@ export function Dimension(props: IDimensionProps): JSX.Element { x2={endBottomX} y2={endBottomY} style={style}/> - @@ -37,8 +38,7 @@ function ActionByPosition( horizontalAction: (dim: number, ...params: any[]) => void, verticalAction: (dim: number, isRight: boolean, ...params: any[]) => void, params: any[] -): boolean { - let incrementDepthSymbols = false; +): void { positions.forEach((position: Position) => { const dim = dimMapped[position]; switch (position) { @@ -50,12 +50,10 @@ function ActionByPosition( } case Position.Down: case Position.Up: - incrementDepthSymbols = true; horizontalAction(dim, ...params); break; } }); - return incrementDepthSymbols; } /** @@ -74,7 +72,6 @@ function Dimensions({ containers, symbols, root, scale }: IDimensionLayerProps): if (!SHOW_SELF_DIMENSIONS) { return []; } - let startDepthSymbols: number = 0; for (const { container, depth, currentTransform } of it) { const offset = (DIMENSION_MARGIN * (depth + 1)) / scale; @@ -84,7 +81,7 @@ function Dimensions({ containers, symbols, root, scale }: IDimensionLayerProps): const containerRightDim = rightDim + offset; const dimMapped = [containerLeftDim, containerBottomDim, containerTopDim, containerRightDim]; if (SHOW_SELF_DIMENSIONS && container.properties.dimensionOptions.selfDimensions.positions.length > 0) { - const incrementDepthSymbol = ActionByPosition( + ActionByPosition( dimMapped, container.properties.dimensionOptions.selfDimensions.positions, AddHorizontalSelfDimension, @@ -93,14 +90,13 @@ function Dimensions({ containers, symbols, root, scale }: IDimensionLayerProps): container, currentTransform, dimensions, - scale, - container.properties.dimensionOptions.selfDimensions.color] + scale + ] ); - if (incrementDepthSymbol) { startDepthSymbols++; } } if (SHOW_SELF_MARGINS_DIMENSIONS && container.properties.dimensionOptions.selfMarginsDimensions.positions.length > 0) { - const incrementDepthSymbol = ActionByPosition( + ActionByPosition( dimMapped, container.properties.dimensionOptions.selfMarginsDimensions.positions, AddHorizontalSelfMarginsDimension, @@ -109,14 +105,13 @@ function Dimensions({ containers, symbols, root, scale }: IDimensionLayerProps): container, currentTransform, dimensions, - scale, - container.properties.dimensionOptions.selfMarginsDimensions.color] + scale + ] ); - if (incrementDepthSymbol) { startDepthSymbols++; } } if (SHOW_BORROWER_DIMENSIONS && container.properties.dimensionOptions.dimensionWithMarks.positions.length > 0) { - const incrementDepthSymbol = ActionByPosition( + ActionByPosition( dimMapped, container.properties.dimensionOptions.dimensionWithMarks.positions, @@ -128,14 +123,13 @@ function Dimensions({ containers, symbols, root, scale }: IDimensionLayerProps): depth, currentTransform, dimensions, - scale, - container.properties.dimensionOptions.dimensionWithMarks.color] + scale + ] ); - if (incrementDepthSymbol) { startDepthSymbols++; } } if (SHOW_CHILDREN_DIMENSIONS && container.properties.dimensionOptions.childrenDimensions.positions.length > 0 && container.children.length >= 2) { - const incrementDepthSymbol = ActionByPosition( + ActionByPosition( dimMapped, container.properties.dimensionOptions.childrenDimensions.positions, AddHorizontalChildrenDimension, @@ -145,28 +139,32 @@ function Dimensions({ containers, symbols, root, scale }: IDimensionLayerProps): container, currentTransform, dimensions, - scale, - container.properties.dimensionOptions.childrenDimensions.color] + scale + ] ); - - if (incrementDepthSymbol) { startDepthSymbols++; } } } + let startDepthSymbols: number = 0; for (const symbol of symbols) { if (symbol[1].showDimension) { startDepthSymbols++; - AddHorizontalSymbolDimension(symbol[1], dimensions, scale, 'black', startDepthSymbols); + AddHorizontalSymbolDimension( + symbol[1], + dimensions, + scale, + startDepthSymbols + ); } } return dimensions; } -function AddHorizontalSymbolDimension(symbol: ISymbolModel, +function AddHorizontalSymbolDimension( + symbol: ISymbolModel, dimensions: React.ReactNode[], scale: number, - color: string, depth: number ): void { const width = symbol.x + (symbol.width / 2); @@ -177,6 +175,11 @@ function AddHorizontalSymbolDimension(symbol: ISymbolModel, const text = width .toFixed(0) .toString(); + + // TODO: Put this in default.ts + const defaultDimensionSymbolStyle: IDimensionStyle = { + color: 'black' + }; dimensions.push( + style={defaultDimensionSymbolStyle}/> ); } } @@ -213,10 +216,10 @@ function AddHorizontalChildrenDimension( container: IContainerModel, currentTransform: [number, number], dimensions: React.ReactNode[], - scale: number, - color: string + scale: number ): void { const childrenId = `dim-y${yDim.toFixed(0)}-children-${container.properties.id}`; + const style = container.properties.dimensionOptions.childrenDimensions.style; const lastChildId = container.children[container.children.length - 1]; const lastChild = FindContainerById(containers, lastChildId); @@ -266,7 +269,7 @@ function AddHorizontalChildrenDimension( yEnd={yDim} text={textChildren} scale={scale} - color={color}/>); + style={style}/>); } function AddVerticalChildrenDimension( @@ -276,10 +279,10 @@ function AddVerticalChildrenDimension( container: IContainerModel, currentTransform: [number, number], dimensions: React.ReactNode[], - scale: number, - color: string + scale: number ): void { const childrenId = `dim-x${xDim.toFixed(0)}-children-${container.properties.id}`; + const style = container.properties.dimensionOptions.childrenDimensions.style; const lastChildId = container.children[container.children.length - 1]; const lastChild = FindContainerById(containers, lastChildId); @@ -334,7 +337,7 @@ function AddVerticalChildrenDimension( yEnd={yChildrenEnd + offset} text={textChildren} scale={scale} - color={color} + style={style} />); } @@ -345,9 +348,9 @@ function AddHorizontalBorrowerDimension( depth: number, currentTransform: [number, number], dimensions: React.ReactNode[], - scale: number, - color: string + scale: number ): void { + const style = container.properties.dimensionOptions.dimensionWithMarks.style; const it = MakeRecursionDFSIterator(container, containers, depth, currentTransform); const marks = []; // list of vertical lines for the dimension for (const { @@ -392,7 +395,7 @@ function AddHorizontalBorrowerDimension( yEnd={yDim} text={value.toFixed(0)} scale={scale} - color={color}/>); + style={style}/>); count++; } } @@ -405,9 +408,9 @@ function AddVerticalBorrowerDimension( depth: number, currentTransform: [number, number], dimensions: React.ReactNode[], - scale: number, - color: string + scale: number ): void { + const style = container.properties.dimensionOptions.dimensionWithMarks.style; const it = MakeRecursionDFSIterator(container, containers, depth, currentTransform); const marks = []; // list of vertical lines for the dimension for (const { @@ -457,7 +460,7 @@ function AddVerticalBorrowerDimension( yEnd={next} text={value.toFixed(0)} scale={scale} - color={color}/>); + style={style}/>); count++; } } @@ -468,9 +471,9 @@ function AddVerticalSelfDimension( container: IContainerModel, currentTransform: [number, number], dimensions: React.ReactNode[], - scale: number, - color: string + scale: number ): void { + const style = container.properties.dimensionOptions.selfDimensions.style; const height = container.properties.height; const idVert = `dim-x${xDim.toFixed(0)}-${container.properties.id}`; let yStart = container.properties.y + currentTransform[1] + height; @@ -493,7 +496,7 @@ function AddVerticalSelfDimension( yEnd={yEnd} text={textVert} scale={scale} - color={color}/> + style={style}/> ); } @@ -502,9 +505,9 @@ function AddHorizontalSelfDimension( container: IContainerModel, currentTransform: [number, number], dimensions: React.ReactNode[], - scale: number, - color: string + scale: number ): void { + const style = container.properties.dimensionOptions.selfDimensions.style; const width = container.properties.width; const id = `dim-y${yDim.toFixed(0)}-${container.properties.id}`; const xStart = container.properties.x + currentTransform[0]; @@ -522,7 +525,7 @@ function AddHorizontalSelfDimension( yEnd={yDim} text={text} scale={scale} - color={color}/> + style={style}/> ); } @@ -531,9 +534,9 @@ function AddHorizontalSelfMarginsDimension( container: IContainerModel, currentTransform: [number, number], dimensions: React.ReactNode[], - scale: number, - color: string + scale: number ): void { + const style = container.properties.dimensionOptions.selfMarginsDimensions.style; const left = container.properties.margin.left; if (left != null) { const id = `dim-y-margin-left${yDim.toFixed(0)}-${container.properties.id}`; @@ -552,7 +555,7 @@ function AddHorizontalSelfMarginsDimension( yEnd={yDim} text={text} scale={scale} - color={color}/> + style={style}/> ); } @@ -574,7 +577,7 @@ function AddHorizontalSelfMarginsDimension( yEnd={yDim} text={text} scale={scale} - color={color}/> + style={style}/> ); } } @@ -585,9 +588,9 @@ function AddVerticalSelfMarginDimension( container: IContainerModel, currentTransform: [number, number], dimensions: React.ReactNode[], - scale: number, - color: string + scale: number ): void { + const style = container.properties.dimensionOptions.selfMarginsDimensions.style; const top = container.properties.margin.top; if (top != null) { const idVert = `dim-x-margin-top${xDim.toFixed(0)}-${container.properties.id}`; @@ -611,7 +614,7 @@ function AddVerticalSelfMarginDimension( yEnd={yEnd} text={textVert} scale={scale} - color={color}/> + style={style}/> ); } const bottom = container.properties.margin.bottom; @@ -637,7 +640,7 @@ function AddVerticalSelfMarginDimension( yEnd={yEnd} text={textVert} scale={scale} - color={color}/> + style={style}/> ); } } diff --git a/src/Enums/PropertyType.ts b/src/Enums/PropertyType.ts index edd78ff..7c133b1 100644 --- a/src/Enums/PropertyType.ts +++ b/src/Enums/PropertyType.ts @@ -24,9 +24,16 @@ export enum PropertyType { * Dimension options */ SelfDimension, - SelfMarginDimension, - ChildrenDimensions, - DimensionWithMarks, - DimensionOptions + SelfDimensionStyle, + SelfMarginDimension, + SelfMarginDimensionStyle, + + ChildrenDimensions, + ChildrenDimensionsStyle, + + DimensionWithMarks, + DimensionWithMarksStyle, + + DimensionOptions } diff --git a/src/Interfaces/IAvailableContainer.ts b/src/Interfaces/IAvailableContainer.ts index dab4e59..d655ab2 100644 --- a/src/Interfaces/IAvailableContainer.ts +++ b/src/Interfaces/IAvailableContainer.ts @@ -1,12 +1,12 @@ /* eslint-disable @typescript-eslint/naming-convention */ -import { AddMethod } from '../Enums/AddMethod'; -import { PositionReference } from '../Enums/PositionReference'; -import { IAction } from './IAction'; -import { IMargin } from './IMargin'; -import { Orientation } from '../Enums/Orientation'; -import { IKeyValue } from './IKeyValue'; -import { IStyle } from './IStyle'; -import { IDimensions } from './IDimensions'; +import { type AddMethod } from '../Enums/AddMethod'; +import { type PositionReference } from '../Enums/PositionReference'; +import { type IAction } from './IAction'; +import { type IMargin } from './IMargin'; +import { type Orientation } from '../Enums/Orientation'; +import { type IKeyValue } from './IKeyValue'; +import { type IStyle } from './IStyle'; +import { type IDimensions } from './IDimensions'; /** Model of available container used in application configuration */ export interface IAvailableContainer { diff --git a/src/Interfaces/IDimensionOptions.ts b/src/Interfaces/IDimensionOptions.ts index 4c44adf..b847626 100644 --- a/src/Interfaces/IDimensionOptions.ts +++ b/src/Interfaces/IDimensionOptions.ts @@ -1,10 +1,9 @@ -import { Position } from '../Enums/Position'; +import { type Position } from '../Enums/Position'; +import { type IDimensionStyle } from './IDimensionStyle'; export interface IDimensionOptions { positions: Position[] - /** - * Stroke color - */ - color: string + + style: IDimensionStyle } diff --git a/src/Interfaces/IDimensionStyle.ts b/src/Interfaces/IDimensionStyle.ts new file mode 100644 index 0000000..80e33a9 --- /dev/null +++ b/src/Interfaces/IDimensionStyle.ts @@ -0,0 +1,12 @@ +export interface IDimensionStyle { + /** + * Stroke color + */ + color?: string + + /** stroke-width */ + width?: number + + /** stroke-dasharray */ + dashArray?: string +} diff --git a/src/Interfaces/ISymbolModel.ts b/src/Interfaces/ISymbolModel.ts index 3a71290..ca0604b 100644 --- a/src/Interfaces/ISymbolModel.ts +++ b/src/Interfaces/ISymbolModel.ts @@ -1,4 +1,4 @@ -import { IAvailableSymbol } from './IAvailableSymbol'; +import { type IAvailableSymbol } from './IAvailableSymbol'; export interface ISymbolModel { /** Identifier */ diff --git a/src/Translations/translation.en.json b/src/Translations/translation.en.json index b9d78ed..65d7410 100644 --- a/src/Translations/translation.en.json +++ b/src/Translations/translation.en.json @@ -59,11 +59,14 @@ "@ContainerAlignmentInput": "Alignment", "@ContainerAlignWithSymbol": "Align to symbol", "@ContainerDimensions": "Dimensions", - "@ContainerShowDimension": "Show Dimension", - "@ContainerShowChildrenDimension": "Show surrounding dimension of children", + "@ContainerShowDimension": "Show dimensions", + "@ContainerShowChildrenDimension": "Show surrounding dimensions of children", "@ContainerMarkPosition": "Mark the position for the parents", - "@ContainerShowDimensionWithMarks": "Show dimension with marked children", + "@ContainerShowDimensionWithMarks": "Show dimensions with marked children", + "@ContainerShowMarginsDimension": "Show margins dimensions", "@ContainerStyle": "Style", + "@StyleStrokeColor": "Stroke Color", + "@StyleStrokeDashArray": "Stroke Dash Array", "@StyleStroke": "Stroke", "@StyleStrokeOpacity": "Stroke Opacity", "@StyleStrokeWidth": "Stroke Width", diff --git a/src/Translations/translation.fr.json b/src/Translations/translation.fr.json index 3d71f2c..3d2ce91 100644 --- a/src/Translations/translation.fr.json +++ b/src/Translations/translation.fr.json @@ -63,7 +63,10 @@ "@ContainerShowChildrenDimension": "Afficher les cotations englobante des enfants", "@ContainerMarkPosition": "Marquer la position pour les parents", "@ContainerShowDimensionWithMarks": "Afficher les cotations avec les enfants marqués", + "@ContainerShowMarginsDimension": "Afficher les cotations des marges", "@ContainerStyle": "Style", + "@StyleStrokeColor": "Couleur du tracé", + "@StyleStrokeDashArray": "Tableau de traits", "@StyleStroke": "Tracé", "@StyleStrokeOpacity": "Opacité du tracé", "@StyleStrokeWidth": "Epaisseur du tracé", diff --git a/src/utils/default.ts b/src/utils/default.ts index 632c12a..1b02c4f 100644 --- a/src/utils/default.ts +++ b/src/utils/default.ts @@ -1,13 +1,14 @@ import { PositionReference } from '../Enums/PositionReference'; -import { IAvailableContainer } from '../Interfaces/IAvailableContainer'; -import { IAvailableSymbol } from '../Interfaces/IAvailableSymbol'; -import { IConfiguration } from '../Interfaces/IConfiguration'; -import { ContainerModel, IContainerModel } from '../Interfaces/IContainerModel'; -import { IContainerProperties } from '../Interfaces/IContainerProperties'; -import { IEditorState } from '../Interfaces/IEditorState'; -import { ISymbolModel } from '../Interfaces/ISymbolModel'; +import { type IAvailableContainer } from '../Interfaces/IAvailableContainer'; +import { type IAvailableSymbol } from '../Interfaces/IAvailableSymbol'; +import { type IConfiguration } from '../Interfaces/IConfiguration'; +import { ContainerModel, type IContainerModel } from '../Interfaces/IContainerModel'; +import { type IContainerProperties } from '../Interfaces/IContainerProperties'; +import { type IEditorState } from '../Interfaces/IEditorState'; +import { type ISymbolModel } from '../Interfaces/ISymbolModel'; import { Orientation } from '../Enums/Orientation'; import { AppState } from '../Enums/AppState'; +import { type IDimensionOptions } from '../Interfaces/IDimensionOptions'; /// EDITOR DEFAULTS /// @@ -187,6 +188,16 @@ const DEFAULT_CONTAINER_STYLE = { strokeWidth: 2 }; +const DEFAULT_DIMENSION_STYLE = { + color: '#000000', + width: 2 +}; + +const DEFAULT_DIMENSION_OPTION: IDimensionOptions = { + positions: [], + style: DEFAULT_DIMENSION_STYLE +}; + /** * Default Main container properties */ @@ -211,23 +222,11 @@ export const DEFAULT_MAINCONTAINER_PROPS: IContainerProperties = { positionReference: PositionReference.TopLeft, hideChildrenInTreeview: false, dimensionOptions: { - childrenDimensions: { - color: '#000000', - positions: [] - }, - selfDimensions: { - color: '#000000', - positions: [] - }, - selfMarginsDimensions: { - color: '#000000', - positions: [] - }, + childrenDimensions: clone(DEFAULT_DIMENSION_OPTION), + selfDimensions: clone(DEFAULT_DIMENSION_OPTION), + selfMarginsDimensions: clone(DEFAULT_DIMENSION_OPTION), markPosition: [], - dimensionWithMarks: { - color: '#000000', - positions: [] - } + dimensionWithMarks: clone(DEFAULT_DIMENSION_OPTION) }, warning: '', style: DEFAULT_CONTAINER_STYLE @@ -276,21 +275,21 @@ export function GetDefaultContainerProps(type: string, hideChildrenInTreeview: containerConfig.HideChildrenInTreeview ?? false, dimensionOptions: { childrenDimensions: { - color: containerConfig.DimensionOptions?.childrenDimensions.color ?? '#000000', - positions: containerConfig.DimensionOptions?.childrenDimensions.positions ?? [] + positions: containerConfig.DimensionOptions?.childrenDimensions.positions ?? [], + style: containerConfig.DimensionOptions?.dimensionWithMarks.style ?? clone(DEFAULT_DIMENSION_STYLE) }, selfDimensions: { - color: containerConfig.DimensionOptions?.selfDimensions.color ?? '#000000', - positions: containerConfig.DimensionOptions?.selfDimensions.positions ?? [] + positions: containerConfig.DimensionOptions?.selfDimensions.positions ?? [], + style: containerConfig.DimensionOptions?.dimensionWithMarks.style ?? clone(DEFAULT_DIMENSION_STYLE) }, selfMarginsDimensions: { - color: containerConfig.DimensionOptions?.selfMarginsDimensions.color ?? '#000000', - positions: containerConfig.DimensionOptions?.selfMarginsDimensions.positions ?? [] + positions: containerConfig.DimensionOptions?.selfMarginsDimensions.positions ?? [], + style: containerConfig.DimensionOptions?.dimensionWithMarks.style ?? clone(DEFAULT_DIMENSION_STYLE) }, markPosition: containerConfig.DimensionOptions?.markPosition ?? [], dimensionWithMarks: { - color: containerConfig.DimensionOptions?.dimensionWithMarks.color ?? '#000000', - positions: containerConfig.DimensionOptions?.dimensionWithMarks.positions ?? [] + positions: containerConfig.DimensionOptions?.dimensionWithMarks.positions ?? [], + style: containerConfig.DimensionOptions?.dimensionWithMarks.style ?? clone(DEFAULT_DIMENSION_STYLE) } }, warning: '', @@ -317,3 +316,10 @@ export function GetDefaultSymbolModel(name: string, showDimension: false }; } + +/** + * Macro function for JSON.parse(JSON.stringify(obj)) + */ +function clone(object: T): T { + return JSON.parse(JSON.stringify(object)); +} From a123407b3a83e0eda800f96718092d4069a4feca Mon Sep 17 00:00:00 2001 From: Eric Nguyen Date: Mon, 13 Feb 2023 15:18:53 +0000 Subject: [PATCH 09/18] Merged PR 331: Remove DepthDimensionLayer + Add fixes from !330 --- src/Components/API/api.test.tsx | 22 +--- .../ContainerProperties.test.tsx | 21 +--- .../SVG/Elements/DepthDimensionLayer.tsx | 100 ------------------ src/Components/SVG/SVG.tsx | 6 +- src/utils/default.ts | 5 +- 5 files changed, 13 insertions(+), 141 deletions(-) delete mode 100644 src/Components/SVG/Elements/DepthDimensionLayer.tsx diff --git a/src/Components/API/api.test.tsx b/src/Components/API/api.test.tsx index 53f3ae0..08fcbad 100644 --- a/src/Components/API/api.test.tsx +++ b/src/Components/API/api.test.tsx @@ -10,7 +10,7 @@ import { IConfiguration } from '../../Interfaces/IConfiguration'; import { IContainerModel, ContainerModel } from '../../Interfaces/IContainerModel'; import { IHistoryState } from '../../Interfaces/IHistoryState'; import { IPattern } from '../../Interfaces/IPattern'; -import { DEFAULT_MAINCONTAINER_PROPS, GetDefaultContainerProps } from '../../utils/default'; +import { DEFAULT_DIMENSION_OPTION, DEFAULT_MAINCONTAINER_PROPS, GetDefaultContainerProps } from '../../utils/default'; import { FetchConfiguration } from './api'; const CSHARP_WEB_API_BASE_URL = 'http://localhost:5209/'; @@ -144,23 +144,11 @@ describe.concurrent('Models test suite', () => { PositionReference: 0, HideChildrenInTreeview: true, DimensionOptions: { - childrenDimensions: { - color: '#000000', - positions: [] - }, - selfDimensions: { - color: '#000000', - positions: [] - }, - selfMarginsDimensions: { - color: '#000000', - positions: [] - }, + childrenDimensions: DEFAULT_DIMENSION_OPTION, + selfDimensions: DEFAULT_DIMENSION_OPTION, + selfMarginsDimensions: DEFAULT_DIMENSION_OPTION, markPosition: [], - dimensionWithMarks: { - color: '#000000', - positions: [] - } + dimensionWithMarks: DEFAULT_DIMENSION_OPTION }, IsHidden: true, Blacklist: [ diff --git a/src/Components/ContainerProperties/ContainerProperties.test.tsx b/src/Components/ContainerProperties/ContainerProperties.test.tsx index cd2da15..01c36bd 100644 --- a/src/Components/ContainerProperties/ContainerProperties.test.tsx +++ b/src/Components/ContainerProperties/ContainerProperties.test.tsx @@ -5,6 +5,7 @@ import { PositionReference } from '../../Enums/PositionReference'; import { IContainerProperties } from '../../Interfaces/IContainerProperties'; import { Orientation } from '../../Enums/Orientation'; import { ContainerProperties } from './ContainerProperties'; +import { DEFAULT_DIMENSION_OPTION } from '../../utils/default'; describe.concurrent('Properties', () => { it('No properties', () => { @@ -43,23 +44,11 @@ describe.concurrent('Properties', () => { warning: '', hideChildrenInTreeview: false, dimensionOptions: { - childrenDimensions: { - color: '#000000', - positions: [] - }, - selfDimensions: { - color: '#000000', - positions: [] - }, - selfMarginsDimensions: { - color: '#000000', - positions: [] - }, + childrenDimensions: DEFAULT_DIMENSION_OPTION, + selfDimensions: DEFAULT_DIMENSION_OPTION, + selfMarginsDimensions: DEFAULT_DIMENSION_OPTION, markPosition: [], - dimensionWithMarks: { - color: '#000000', - positions: [] - } + dimensionWithMarks: DEFAULT_DIMENSION_OPTION } }; diff --git a/src/Components/SVG/Elements/DepthDimensionLayer.tsx b/src/Components/SVG/Elements/DepthDimensionLayer.tsx deleted file mode 100644 index f4bff37..0000000 --- a/src/Components/SVG/Elements/DepthDimensionLayer.tsx +++ /dev/null @@ -1,100 +0,0 @@ -import * as React from 'react'; -import { IContainerModel } from '../../../Interfaces/IContainerModel'; -import { DIMENSION_MARGIN } from '../../../utils/default'; -import { GetAbsolutePosition, MakeBFSIterator } from '../../../utils/itertools'; -import { TransformX } from '../../../utils/svg'; -import { Dimension } from './Dimension'; - -interface IDimensionLayerProps { - containers: Map - roots: IContainerModel | IContainerModel[] | null - scale?: number -} - -function GetDimensionsNodes( - containers: Map, - root: IContainerModel, - scale: number -): React.ReactNode[] { - const it = MakeBFSIterator(root, containers); - const dimensions: React.ReactNode[] = []; - let currentDepth = 0; - let min = Infinity; - let max = -Infinity; - let lastY = 0; - for (const { container, depth } of it) { - if (currentDepth !== depth) { - AddNewDimension(currentDepth, min, max, lastY, scale, '#000000', dimensions); - - currentDepth = depth; - min = Infinity; - max = -Infinity; - } - - const absoluteX = GetAbsolutePosition(containers, container)[0]; - const x = TransformX(absoluteX, container.properties.width, container.properties.positionReference); - lastY = container.properties.y + container.properties.height; - if (x < min) { - min = x; - } - - if (x > max) { - max = x; - } - } - - AddNewDimension(currentDepth, min, max, lastY, scale, '#000000', dimensions); - - return dimensions; -} - -/** - * A layer containing all dimension - * @param props - * @returns - */ -export function DepthDimensionLayer(props: IDimensionLayerProps): JSX.Element { - let dimensions: React.ReactNode[] = []; - const scale = props.scale ?? 1; - if (Array.isArray(props.roots)) { - props.roots.forEach(child => { - dimensions.concat(GetDimensionsNodes(props.containers, child, scale)); - }); - } else if (props.roots !== null) { - dimensions = GetDimensionsNodes(props.containers, props.roots, scale); - } - return ( - - {dimensions} - - ); -} - -function AddNewDimension(currentDepth: number, min: number, max: number, lastY: number, scale: number, color: string, dimensions: React.ReactNode[]): void { - const id = `dim-depth-${currentDepth}`; - const xStart = min; - const xEnd = max; - const y = lastY + (DIMENSION_MARGIN * (currentDepth + 1)) / scale; - const width = xEnd - xStart; - const text = width - .toFixed(0) - .toString(); - - if (width === 0) { - return; - } - - dimensions.push( - - ); -} diff --git a/src/Components/SVG/SVG.tsx b/src/Components/SVG/SVG.tsx index cdb11de..dc80773 100644 --- a/src/Components/SVG/SVG.tsx +++ b/src/Components/SVG/SVG.tsx @@ -3,8 +3,7 @@ import { ReactSVGPanZoom, Tool, TOOL_PAN, Value } from 'react-svg-pan-zoom'; import { Container } from './Elements/Container'; import { IContainerModel } from '../../Interfaces/IContainerModel'; import { Selector } from './Elements/Selector/Selector'; -import { DepthDimensionLayer } from './Elements/DepthDimensionLayer'; -import { MAX_FRAMERATE, SHOW_DIMENSIONS_PER_DEPTH } from '../../utils/default'; +import { MAX_FRAMERATE } from '../../utils/default'; import { SymbolLayer } from './Elements/SymbolLayer'; import { ISymbolModel } from '../../Interfaces/ISymbolModel'; import { DimensionLayer } from './Elements/DimensionLayer'; @@ -94,9 +93,6 @@ export function SVG(props: ISVGProps): JSX.Element { > {children} - {SHOW_DIMENSIONS_PER_DEPTH - ? - : null} {/* leave this at the end so it can be removed during the svg export */} diff --git a/src/utils/default.ts b/src/utils/default.ts index 1b02c4f..a5a6271 100644 --- a/src/utils/default.ts +++ b/src/utils/default.ts @@ -66,7 +66,6 @@ export const SHOW_SELF_DIMENSIONS = true; export const SHOW_SELF_MARGINS_DIMENSIONS = true; export const SHOW_CHILDREN_DIMENSIONS = true; export const SHOW_BORROWER_DIMENSIONS = true; -export const SHOW_DIMENSIONS_PER_DEPTH = false; export const DIMENSION_MARGIN = 50; export const SYMBOL_MARGIN = 25; export const NOTCHES_LENGTH = 10; @@ -188,12 +187,12 @@ const DEFAULT_CONTAINER_STYLE = { strokeWidth: 2 }; -const DEFAULT_DIMENSION_STYLE = { +export const DEFAULT_DIMENSION_STYLE = { color: '#000000', width: 2 }; -const DEFAULT_DIMENSION_OPTION: IDimensionOptions = { +export const DEFAULT_DIMENSION_OPTION: IDimensionOptions = { positions: [], style: DEFAULT_DIMENSION_STYLE }; From 7ad866fc94ed3d07983fd8dfbb422ee092626e2b Mon Sep 17 00:00:00 2001 From: Eric NGUYEN Date: Mon, 13 Feb 2023 16:38:00 +0100 Subject: [PATCH 10/18] Refactor selector --- .../SVG/Elements/Selector/Selector.tsx | 54 +++++++++++++++++++ .../SelectorContainer/SelectorContainer.tsx | 45 ++++------------ .../SelectorSymbol/SelectorSymbol.tsx | 44 ++++----------- 3 files changed, 74 insertions(+), 69 deletions(-) create mode 100644 src/Components/SVG/Elements/Selector/Selector.tsx diff --git a/src/Components/SVG/Elements/Selector/Selector.tsx b/src/Components/SVG/Elements/Selector/Selector.tsx new file mode 100644 index 0000000..1a8fb3e --- /dev/null +++ b/src/Components/SVG/Elements/Selector/Selector.tsx @@ -0,0 +1,54 @@ +import '../Selector.scss'; +import * as React from 'react'; +import { SHOW_SELECTOR_TEXT } from '../../../../utils/default'; + +interface ISelectorProps { + text: string + x: number + y: number + width: number + height: number + scale: number + style?: React.CSSProperties +} + +export function Selector({ text, x, y, width, height, scale, style: overrideStyle }: ISelectorProps): JSX.Element { + const xText = x + width / 2; + const yText = y + height / 2; + + const style: React.CSSProperties = { + stroke: '#3B82F6', + strokeWidth: 4 / scale, + fillOpacity: 0, + transitionProperty: 'all', + transitionTimingFunction: 'cubic-bezier(0.4, 0, 0.2, 1)', + transitionDuration: '150ms', + animation: 'fadein 750ms ease-in alternate infinite', + ...overrideStyle + }; + + return ( + <> + + + {SHOW_SELECTOR_TEXT + ? + { text } + + : null} + + ); +} diff --git a/src/Components/SVG/Elements/SelectorContainer/SelectorContainer.tsx b/src/Components/SVG/Elements/SelectorContainer/SelectorContainer.tsx index c85f2b3..c2ad3e2 100644 --- a/src/Components/SVG/Elements/SelectorContainer/SelectorContainer.tsx +++ b/src/Components/SVG/Elements/SelectorContainer/SelectorContainer.tsx @@ -1,9 +1,9 @@ import '../Selector.scss'; import * as React from 'react'; import { type IContainerModel } from '../../../../Interfaces/IContainerModel'; -import { SHOW_SELECTOR_TEXT } from '../../../../utils/default'; import { GetAbsolutePosition } from '../../../../utils/itertools'; import { RemoveMargin } from '../../../../utils/svg'; +import { Selector } from '../Selector/Selector'; interface ISelectorContainerProps { containers: Map @@ -33,41 +33,14 @@ export function SelectorContainer(props: ISelectorContainerProps): JSX.Element { props.selected.properties.margin.right )); - const xText = x + width / 2; - const yText = y + height / 2; - - const style: React.CSSProperties = { - stroke: '#3B82F6', - strokeWidth: 4 / scale, - fillOpacity: 0, - transitionProperty: 'all', - transitionTimingFunction: 'cubic-bezier(0.4, 0, 0.2, 1)', - transitionDuration: '150ms', - animation: 'fadein 750ms ease-in alternate infinite' - }; - return ( - <> - - - {SHOW_SELECTOR_TEXT - ? - {props.selected.properties.displayedText} - - : null} - + ); } diff --git a/src/Components/SVG/Elements/SelectorSymbol/SelectorSymbol.tsx b/src/Components/SVG/Elements/SelectorSymbol/SelectorSymbol.tsx index fd45870..01133fb 100644 --- a/src/Components/SVG/Elements/SelectorSymbol/SelectorSymbol.tsx +++ b/src/Components/SVG/Elements/SelectorSymbol/SelectorSymbol.tsx @@ -1,7 +1,8 @@ import '../Selector.scss'; import * as React from 'react'; -import { SHOW_SELECTOR_TEXT, SYMBOL_MARGIN } from '../../../../utils/default'; +import { SYMBOL_MARGIN } from '../../../../utils/default'; import { type ISymbolModel } from '../../../../Interfaces/ISymbolModel'; +import { Selector } from '../Selector/Selector'; interface ISelectorSymbolProps { symbols: Map @@ -27,43 +28,20 @@ export function SelectorSymbol(props: ISelectorSymbolProps): JSX.Element { props.selected.x + props.selected.width / 2, -SYMBOL_MARGIN - height]; - const xText = x + width / 2; - const yText = y + height / 2; - const style: React.CSSProperties = { - stroke: '#3B82F6', - strokeWidth: 4 / scale, - fillOpacity: 0, - transitionProperty: 'all', - transitionTimingFunction: 'cubic-bezier(0.4, 0, 0.2, 1)', - transitionDuration: '150ms', - animation: 'fadein 750ms ease-in alternate infinite', transform: 'translateX(-50%)', transformBox: 'fill-box' }; return ( - <> - - - {SHOW_SELECTOR_TEXT - ? - {props.selected.displayedText} - - : null} - + ); } From 3b99d0a0203d722871b5951c371a2b1c661c6728 Mon Sep 17 00:00:00 2001 From: Eric NGUYEN Date: Tue, 14 Feb 2023 10:13:51 +0100 Subject: [PATCH 11/18] Revert dimensionStyle --- .../SVGLDLibs/Models/DimensionOptions.cs | 10 +++- .../SVGLDLibs/Models/DimensionStyle.cs | 27 ----------- .../ContainerProperties/ContainerForm.tsx | 48 +++++++++---------- .../Editor/Actions/ContainerOperations.ts | 12 ----- src/Components/SVG/Elements/Dimension.tsx | 4 +- .../SVG/Elements/DimensionLayer.tsx | 19 ++++---- src/Enums/PropertyType.ts | 7 --- src/Interfaces/IDimensionOptions.ts | 12 ++++- src/Interfaces/IDimensionStyle.ts | 12 ----- src/utils/default.ts | 24 ++++------ 10 files changed, 65 insertions(+), 110 deletions(-) delete mode 100644 csharp/SVGLDLibs/SVGLDLibs/Models/DimensionStyle.cs delete mode 100644 src/Interfaces/IDimensionStyle.ts diff --git a/csharp/SVGLDLibs/SVGLDLibs/Models/DimensionOptions.cs b/csharp/SVGLDLibs/SVGLDLibs/Models/DimensionOptions.cs index 42aafd7..10c6542 100644 --- a/csharp/SVGLDLibs/SVGLDLibs/Models/DimensionOptions.cs +++ b/csharp/SVGLDLibs/SVGLDLibs/Models/DimensionOptions.cs @@ -18,6 +18,14 @@ namespace SVGLDLibs.Models /** color */ [DataMember(EmitDefaultValue = false)] - public DimensionStyle style; + public string color; + + /** width */ + [DataMember(EmitDefaultValue = false)] + public double width; + + /** color */ + [DataMember(EmitDefaultValue = false)] + public string dashArray; } } diff --git a/csharp/SVGLDLibs/SVGLDLibs/Models/DimensionStyle.cs b/csharp/SVGLDLibs/SVGLDLibs/Models/DimensionStyle.cs deleted file mode 100644 index c35cd5f..0000000 --- a/csharp/SVGLDLibs/SVGLDLibs/Models/DimensionStyle.cs +++ /dev/null @@ -1,27 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Runtime.Serialization; -using System.Text; -using System.Threading.Tasks; - -namespace SVGLDLibs.Models -{ - - [DataContract] - public class DimensionStyle - { - /** color */ - [DataMember(EmitDefaultValue = false)] - public string color; - - /** width */ - - [DataMember(EmitDefaultValue = false)] - public double width; - - /** color */ - [DataMember(EmitDefaultValue = false)] - public string dashArray; - } -} diff --git a/src/Components/ContainerProperties/ContainerForm.tsx b/src/Components/ContainerProperties/ContainerForm.tsx index 6781302..8b7a505 100644 --- a/src/Components/ContainerProperties/ContainerForm.tsx +++ b/src/Components/ContainerProperties/ContainerForm.tsx @@ -366,8 +366,8 @@ export function ContainerForm(props: IContainerFormProps): JSX.Element { labelClassName='' inputClassName='' type='color' - value={props.properties.dimensionOptions.selfDimensions.style.color} - onChange={(e) => { props.onChange('color', e.target.value, PropertyType.SelfDimensionStyle); }}/> + value={props.properties.dimensionOptions.selfDimensions.color} + onChange={(e) => { props.onChange('color', e.target.value, PropertyType.SelfDimension); }}/> { props.onChange('width', Number(value), PropertyType.SelfDimensionStyle); }}/> + value={(props.properties.dimensionOptions.selfDimensions.width ?? 0).toString()} + onChange={(value) => { props.onChange('width', Number(value), PropertyType.SelfDimension); }}/> { props.onChange('dashArray', value, PropertyType.SelfDimensionStyle); }}/> + value={props.properties.dimensionOptions.selfDimensions.dashArray ?? ''} + onChange={(value) => { props.onChange('dashArray', value, PropertyType.SelfDimension); }}/> } { @@ -406,8 +406,8 @@ export function ContainerForm(props: IContainerFormProps): JSX.Element { labelClassName='' inputClassName='' type='color' - value={props.properties.dimensionOptions.selfMarginsDimensions.style.color} - onChange={(e) => { props.onChange('color', e.target.value, PropertyType.SelfMarginDimensionStyle); }}/> + value={props.properties.dimensionOptions.selfMarginsDimensions.color} + onChange={(e) => { props.onChange('color', e.target.value, PropertyType.SelfMarginDimension); }}/> { props.onChange('width', Number(value), PropertyType.SelfMarginDimensionStyle); }}/> + value={(props.properties.dimensionOptions.selfMarginsDimensions.width ?? 0).toString()} + onChange={(value) => { props.onChange('width', Number(value), PropertyType.SelfMarginDimension); }}/> { props.onChange('dashArray', value, PropertyType.SelfMarginDimensionStyle); }}/> + value={props.properties.dimensionOptions.selfMarginsDimensions.dashArray ?? ''} + onChange={(value) => { props.onChange('dashArray', value, PropertyType.SelfMarginDimension); }}/> } { @@ -446,8 +446,8 @@ export function ContainerForm(props: IContainerFormProps): JSX.Element { labelClassName='' inputClassName='' type='color' - value={props.properties.dimensionOptions.childrenDimensions.style.color} - onChange={(e) => { props.onChange('color', e.target.value, PropertyType.ChildrenDimensionsStyle); }}/> + value={props.properties.dimensionOptions.childrenDimensions.color} + onChange={(e) => { props.onChange('color', e.target.value, PropertyType.ChildrenDimensions); }}/> { props.onChange('width', Number(value), PropertyType.ChildrenDimensionsStyle); }}/> + value={(props.properties.dimensionOptions.childrenDimensions.width ?? 0).toString()} + onChange={(value) => { props.onChange('width', Number(value), PropertyType.ChildrenDimensions); }}/> { props.onChange('dashArray', value, PropertyType.ChildrenDimensionsStyle); }}/> + value={props.properties.dimensionOptions.childrenDimensions.dashArray ?? ''} + onChange={(value) => { props.onChange('dashArray', value, PropertyType.ChildrenDimensions); }}/> } { @@ -496,8 +496,8 @@ export function ContainerForm(props: IContainerFormProps): JSX.Element { labelClassName='' inputClassName='' type='color' - value={props.properties.dimensionOptions.dimensionWithMarks.style.color} - onChange={(e) => { props.onChange('color', e.target.value, PropertyType.DimensionWithMarksStyle); }}/> + value={props.properties.dimensionOptions.dimensionWithMarks.color} + onChange={(e) => { props.onChange('color', e.target.value, PropertyType.DimensionWithMarks); }}/> { props.onChange('width', Number(value), PropertyType.DimensionWithMarksStyle); }}/> + value={(props.properties.dimensionOptions.dimensionWithMarks.width ?? 0).toString()} + onChange={(value) => { props.onChange('width', Number(value), PropertyType.DimensionWithMarks); }}/> { props.onChange('dashArray', value, PropertyType.DimensionWithMarksStyle); }}/> + value={props.properties.dimensionOptions.dimensionWithMarks.dashArray ?? ''} + onChange={(value) => { props.onChange('dashArray', value, PropertyType.DimensionWithMarks); }}/> } diff --git a/src/Components/Editor/Actions/ContainerOperations.ts b/src/Components/Editor/Actions/ContainerOperations.ts index 4d5490a..82162e3 100644 --- a/src/Components/Editor/Actions/ContainerOperations.ts +++ b/src/Components/Editor/Actions/ContainerOperations.ts @@ -362,18 +362,6 @@ function AssignProperty(container: IContainerModel, key: string, value: string | case PropertyType.DimensionWithMarks: (container.properties.dimensionOptions.dimensionWithMarks as any)[key] = value; break; - case PropertyType.SelfDimensionStyle: - (container.properties.dimensionOptions.selfDimensions.style as any)[key] = value; - break; - case PropertyType.SelfMarginDimensionStyle: - (container.properties.dimensionOptions.selfMarginsDimensions.style as any)[key] = value; - break; - case PropertyType.ChildrenDimensionsStyle: - (container.properties.dimensionOptions.childrenDimensions.style as any)[key] = value; - break; - case PropertyType.DimensionWithMarksStyle: - (container.properties.dimensionOptions.dimensionWithMarks.style as any)[key] = value; - break; case PropertyType.DimensionOptions: (container.properties.dimensionOptions as any)[key] = value; break; diff --git a/src/Components/SVG/Elements/Dimension.tsx b/src/Components/SVG/Elements/Dimension.tsx index 88f7c99..30469be 100644 --- a/src/Components/SVG/Elements/Dimension.tsx +++ b/src/Components/SVG/Elements/Dimension.tsx @@ -1,7 +1,9 @@ import * as React from 'react'; -import { type IDimensionStyle } from '../../../Interfaces/IDimensionStyle'; +import { type IDimensionOptions } from '../../../Interfaces/IDimensionOptions'; import { NOTCHES_LENGTH } from '../../../utils/default'; +export type IDimensionStyle = Omit; + interface IDimensionProps { id: string xStart: number diff --git a/src/Components/SVG/Elements/DimensionLayer.tsx b/src/Components/SVG/Elements/DimensionLayer.tsx index 2e0b978..3a2b679 100644 --- a/src/Components/SVG/Elements/DimensionLayer.tsx +++ b/src/Components/SVG/Elements/DimensionLayer.tsx @@ -10,10 +10,9 @@ import { } from '../../../utils/default'; import { FindContainerById, MakeRecursionDFSIterator, Pairwise } from '../../../utils/itertools'; import { TransformX, TransformY } from '../../../utils/svg'; -import { Dimension } from './Dimension'; +import { Dimension, type IDimensionStyle } from './Dimension'; import { type IContainerModel } from '../../../Interfaces/IContainerModel'; import { type ISymbolModel } from '../../../Interfaces/ISymbolModel'; -import { type IDimensionStyle } from '../../../Interfaces/IDimensionStyle'; interface IDimensionLayerProps { containers: Map @@ -219,7 +218,7 @@ function AddHorizontalChildrenDimension( scale: number ): void { const childrenId = `dim-y${yDim.toFixed(0)}-children-${container.properties.id}`; - const style = container.properties.dimensionOptions.childrenDimensions.style; + const style = container.properties.dimensionOptions.childrenDimensions; const lastChildId = container.children[container.children.length - 1]; const lastChild = FindContainerById(containers, lastChildId); @@ -282,7 +281,7 @@ function AddVerticalChildrenDimension( scale: number ): void { const childrenId = `dim-x${xDim.toFixed(0)}-children-${container.properties.id}`; - const style = container.properties.dimensionOptions.childrenDimensions.style; + const style = container.properties.dimensionOptions.childrenDimensions; const lastChildId = container.children[container.children.length - 1]; const lastChild = FindContainerById(containers, lastChildId); @@ -350,7 +349,7 @@ function AddHorizontalBorrowerDimension( dimensions: React.ReactNode[], scale: number ): void { - const style = container.properties.dimensionOptions.dimensionWithMarks.style; + const style = container.properties.dimensionOptions.dimensionWithMarks; const it = MakeRecursionDFSIterator(container, containers, depth, currentTransform); const marks = []; // list of vertical lines for the dimension for (const { @@ -410,7 +409,7 @@ function AddVerticalBorrowerDimension( dimensions: React.ReactNode[], scale: number ): void { - const style = container.properties.dimensionOptions.dimensionWithMarks.style; + const style = container.properties.dimensionOptions.dimensionWithMarks; const it = MakeRecursionDFSIterator(container, containers, depth, currentTransform); const marks = []; // list of vertical lines for the dimension for (const { @@ -473,7 +472,7 @@ function AddVerticalSelfDimension( dimensions: React.ReactNode[], scale: number ): void { - const style = container.properties.dimensionOptions.selfDimensions.style; + const style = container.properties.dimensionOptions.selfDimensions; const height = container.properties.height; const idVert = `dim-x${xDim.toFixed(0)}-${container.properties.id}`; let yStart = container.properties.y + currentTransform[1] + height; @@ -507,7 +506,7 @@ function AddHorizontalSelfDimension( dimensions: React.ReactNode[], scale: number ): void { - const style = container.properties.dimensionOptions.selfDimensions.style; + const style = container.properties.dimensionOptions.selfDimensions; const width = container.properties.width; const id = `dim-y${yDim.toFixed(0)}-${container.properties.id}`; const xStart = container.properties.x + currentTransform[0]; @@ -536,7 +535,7 @@ function AddHorizontalSelfMarginsDimension( dimensions: React.ReactNode[], scale: number ): void { - const style = container.properties.dimensionOptions.selfMarginsDimensions.style; + const style = container.properties.dimensionOptions.selfMarginsDimensions; const left = container.properties.margin.left; if (left != null) { const id = `dim-y-margin-left${yDim.toFixed(0)}-${container.properties.id}`; @@ -590,7 +589,7 @@ function AddVerticalSelfMarginDimension( dimensions: React.ReactNode[], scale: number ): void { - const style = container.properties.dimensionOptions.selfMarginsDimensions.style; + const style = container.properties.dimensionOptions.selfMarginsDimensions; const top = container.properties.margin.top; if (top != null) { const idVert = `dim-x-margin-top${xDim.toFixed(0)}-${container.properties.id}`; diff --git a/src/Enums/PropertyType.ts b/src/Enums/PropertyType.ts index 7c133b1..f57d2b9 100644 --- a/src/Enums/PropertyType.ts +++ b/src/Enums/PropertyType.ts @@ -24,16 +24,9 @@ export enum PropertyType { * Dimension options */ SelfDimension, - SelfDimensionStyle, - SelfMarginDimension, - SelfMarginDimensionStyle, - ChildrenDimensions, - ChildrenDimensionsStyle, - DimensionWithMarks, - DimensionWithMarksStyle, DimensionOptions } diff --git a/src/Interfaces/IDimensionOptions.ts b/src/Interfaces/IDimensionOptions.ts index b847626..a12865a 100644 --- a/src/Interfaces/IDimensionOptions.ts +++ b/src/Interfaces/IDimensionOptions.ts @@ -1,9 +1,17 @@ import { type Position } from '../Enums/Position'; -import { type IDimensionStyle } from './IDimensionStyle'; export interface IDimensionOptions { positions: Position[] - style: IDimensionStyle + /** + * Stroke color + */ + color?: string + + /** stroke-width */ + width?: number + + /** stroke-dasharray */ + dashArray?: string } diff --git a/src/Interfaces/IDimensionStyle.ts b/src/Interfaces/IDimensionStyle.ts deleted file mode 100644 index 80e33a9..0000000 --- a/src/Interfaces/IDimensionStyle.ts +++ /dev/null @@ -1,12 +0,0 @@ -export interface IDimensionStyle { - /** - * Stroke color - */ - color?: string - - /** stroke-width */ - width?: number - - /** stroke-dasharray */ - dashArray?: string -} diff --git a/src/utils/default.ts b/src/utils/default.ts index a5a6271..5977edd 100644 --- a/src/utils/default.ts +++ b/src/utils/default.ts @@ -187,14 +187,10 @@ const DEFAULT_CONTAINER_STYLE = { strokeWidth: 2 }; -export const DEFAULT_DIMENSION_STYLE = { - color: '#000000', - width: 2 -}; - export const DEFAULT_DIMENSION_OPTION: IDimensionOptions = { positions: [], - style: DEFAULT_DIMENSION_STYLE + color: '#000000', + width: 2 }; /** @@ -274,21 +270,21 @@ export function GetDefaultContainerProps(type: string, hideChildrenInTreeview: containerConfig.HideChildrenInTreeview ?? false, dimensionOptions: { childrenDimensions: { - positions: containerConfig.DimensionOptions?.childrenDimensions.positions ?? [], - style: containerConfig.DimensionOptions?.dimensionWithMarks.style ?? clone(DEFAULT_DIMENSION_STYLE) + ...containerConfig.DimensionOptions?.selfDimensions, + positions: containerConfig.DimensionOptions?.childrenDimensions.positions ?? [] }, selfDimensions: { - positions: containerConfig.DimensionOptions?.selfDimensions.positions ?? [], - style: containerConfig.DimensionOptions?.dimensionWithMarks.style ?? clone(DEFAULT_DIMENSION_STYLE) + ...containerConfig.DimensionOptions?.selfDimensions, + positions: containerConfig.DimensionOptions?.selfDimensions.positions ?? [] }, selfMarginsDimensions: { - positions: containerConfig.DimensionOptions?.selfMarginsDimensions.positions ?? [], - style: containerConfig.DimensionOptions?.dimensionWithMarks.style ?? clone(DEFAULT_DIMENSION_STYLE) + ...containerConfig.DimensionOptions?.selfMarginsDimensions, + positions: containerConfig.DimensionOptions?.selfMarginsDimensions.positions ?? [] }, markPosition: containerConfig.DimensionOptions?.markPosition ?? [], dimensionWithMarks: { - positions: containerConfig.DimensionOptions?.dimensionWithMarks.positions ?? [], - style: containerConfig.DimensionOptions?.dimensionWithMarks.style ?? clone(DEFAULT_DIMENSION_STYLE) + ...containerConfig.DimensionOptions?.dimensionWithMarks, + positions: containerConfig.DimensionOptions?.dimensionWithMarks.positions ?? [] } }, warning: '', From e19d17c3253f462cf00719038e7d00e4d4f456e8 Mon Sep 17 00:00:00 2001 From: Eric Nguyen Date: Tue, 14 Feb 2023 10:06:36 +0000 Subject: [PATCH 12/18] Merged PR 333: Add mprocs + nodemon + fix eslint tsconfig not found --- .eslintrc.cjs | 3 +- CONTRIBUTING.md | 21 ++++++++++++ mprocs.yaml | 7 ++++ package.json | 4 ++- pnpm-lock.yaml | 86 +++++++++++++++++++++++++++++++++++++++++++++++++ 5 files changed, 119 insertions(+), 2 deletions(-) create mode 100644 mprocs.yaml diff --git a/.eslintrc.cjs b/.eslintrc.cjs index 748a5bb..14eeda7 100644 --- a/.eslintrc.cjs +++ b/.eslintrc.cjs @@ -19,7 +19,8 @@ module.exports = { }, ecmaVersion: 'latest', sourceType: 'module', - project: './tsconfig.json' + project: './tsconfig.json', + tsconfigRootDir: __dirname }, plugins: [ 'only-warn', diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 446b61f..0ee06e3 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -9,7 +9,20 @@ You will be able to navigate through this document with the table of contents. - [Table of contents](#table-of-contents) - [I want to contribute](#i-want-to-contribute) - [I want to contribute to the .NETFramework API](#i-want-to-contribute-to-the-netframework-api) + - [Getting Started](#getting-started) + - [Before developing](#before-developing) + - [Testing](#testing) + - [Releasing](#releasing) - [I want to contribute to the React component](#i-want-to-contribute-to-the-react-component) + - [Getting Started](#getting-started-1) + - [Before developing](#before-developing-1) + - [CORS](#cors) + - [Develop with Vite and pnpm](#develop-with-vite-and-pnpm) + - [Develop with mprocs](#develop-with-mprocs) + - [Testing the external API without .NETFramework or Windows](#testing-the-external-api-without-netframework-or-windows) + - [Setup debugging with chrome](#setup-debugging-with-chrome) + - [Testing](#testing-1) + - [Releasing](#releasing-1) - [I want to report a bug](#i-want-to-report-a-bug) - [Before submitting a bug report](#before-submitting-a-bug-report) - [How do i submit a good bug report?](#how-do-i-submit-a-good-bug-report) @@ -102,6 +115,14 @@ Then run the following command to run the projet in a dev environment: pnpm dev ``` +### Develop with mprocs + +[Mprocs](https://github.com/pvolok/mprocs) runs multiple commands in parallel and shows output of each command separately. + +It is useful to run `vite` and the test server at the same time with `mprocs`. + +Run `pnpm d` or `pnpm mprocs` to run mprocs. + ### Testing the external API without .NETFramework or Windows Use the Node.js server in `/test-server` to simulate the api. diff --git a/mprocs.yaml b/mprocs.yaml new file mode 100644 index 0000000..fa0511f --- /dev/null +++ b/mprocs.yaml @@ -0,0 +1,7 @@ +procs: + nvim: + shell: "nvim ." + vite: + shell: "npx vite" + test-server: + shell: "npx nodemon ./test-server/http.js" diff --git a/package.json b/package.json index 8fe114a..ff96249 100644 --- a/package.json +++ b/package.json @@ -4,10 +4,10 @@ "version": "v1.0.0", "type": "module", "scripts": { + "d": "mprocs", "dev": "vite", "build": "tsc && vite build", "build:dotnet": "dotnet build ./csharp/SVGLDLibs/SVGLDLibs/SVGLDLibs.csproj", - "preview": "vite preview", "linter": "eslint src", "test": "vitest", "test:ui": "vitest --ui", @@ -52,6 +52,8 @@ "eslint-plugin-react": "^7.32.2", "eslint-plugin-react-hooks": "^4.6.0", "jsdom": "^21.1.0", + "mprocs": "^0.6.4", + "nodemon": "^2.0.20", "postcss": "^8.4.21", "sass": "^1.58.0", "tailwindcss": "^3.2.4", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index cc7fbe9..212f797 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -28,6 +28,8 @@ specifiers: eslint-plugin-react-hooks: ^4.6.0 interweave: ^13.0.0 jsdom: ^21.1.0 + mprocs: ^0.6.4 + nodemon: ^2.0.20 postcss: ^8.4.21 react: ^18.2.0 react-dom: ^18.2.0 @@ -77,6 +79,8 @@ devDependencies: eslint-plugin-react: 7.32.2_eslint@8.33.0 eslint-plugin-react-hooks: 4.6.0_eslint@8.33.0 jsdom: 21.1.0 + mprocs: 0.6.4 + nodemon: 2.0.20 postcss: 8.4.21 sass: 1.58.0 tailwindcss: 3.2.4_postcss@8.4.21 @@ -1172,6 +1176,10 @@ packages: resolution: {integrity: sha512-j2afSsaIENvHZN2B8GOpF566vZ5WVk5opAiMTvWgaQT8DkbOqsTfvNAvHoRGU2zzP8cPoqys+xHTRDWW8L+/BA==} dev: true + /abbrev/1.1.1: + resolution: {integrity: sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==} + dev: true + /acorn-globals/7.0.1: resolution: {integrity: sha512-umOSDSDrfHbTNPuNpC2NSnnA3LUrqpevPb4T9jRx4MagXNS0rs+gwiTcAvqCRmsD6utzsrzNt+ebm00SNWiC3Q==} dependencies: @@ -1600,6 +1608,18 @@ packages: ms: 2.1.3 dev: true + /debug/3.2.7_supports-color@5.5.0: + resolution: {integrity: sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==} + peerDependencies: + supports-color: '*' + peerDependenciesMeta: + supports-color: + optional: true + dependencies: + ms: 2.1.3 + supports-color: 5.5.0 + dev: true + /debug/4.3.4: resolution: {integrity: sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==} engines: {node: '>=6.0'} @@ -2507,6 +2527,10 @@ packages: safer-buffer: 2.1.2 dev: true + /ignore-by-default/1.0.1: + resolution: {integrity: sha512-Ius2VYcGNk7T90CppJqcIkS5ooHUZyIQK+ClZfMfMNFEF9VSE73Fq+906u/CWu92x4gzZMWOwfFYckPObzdEbA==} + dev: true + /ignore/5.2.4: resolution: {integrity: sha512-MAb38BcSbH0eHNBxn7ql2NH/kX33OkB3lZ1BNdh7ENeRChHTYsTvWrMubiIAMNS2llXEEgZ1MUOBtXChP3kaFQ==} engines: {node: '>= 4'} @@ -3010,6 +3034,12 @@ packages: ufo: 1.0.1 dev: true + /mprocs/0.6.4: + resolution: {integrity: sha512-Y4eqnAjp3mjy0eT+zPoMQ+P/ISOzjgRG/4kh4I5cRA4Tv0rPxTCBRadn3+j+boMF5id7IoLhrVq9NFWFPuzD9A==} + engines: {node: '>=0.10.0'} + hasBin: true + dev: true + /mrmime/1.0.1: resolution: {integrity: sha512-hzzEagAgDyoU1Q6yg5uI+AorQgdvMCur3FcKf7NhMKWsaYg+RnbTyHRa/9IlLF9rf455MOCtcqqrQQ83pPP7Uw==} engines: {node: '>=10'} @@ -3041,6 +3071,30 @@ packages: resolution: {integrity: sha512-5GFldHPXVG/YZmFzJvKK2zDSzPKhEp0+ZR5SVaoSag9fsL5YgHbUHDfnG5494ISANDcK4KwPXAx2xqVEydmd7w==} dev: true + /nodemon/2.0.20: + resolution: {integrity: sha512-Km2mWHKKY5GzRg6i1j5OxOHQtuvVsgskLfigG25yTtbyfRGn/GNvIbRyOf1PSCKJ2aT/58TiuUsuOU5UToVViw==} + engines: {node: '>=8.10.0'} + hasBin: true + dependencies: + chokidar: 3.5.3 + debug: 3.2.7_supports-color@5.5.0 + ignore-by-default: 1.0.1 + minimatch: 3.1.2 + pstree.remy: 1.1.8 + semver: 5.7.1 + simple-update-notifier: 1.1.0 + supports-color: 5.5.0 + touch: 3.1.0 + undefsafe: 2.0.5 + dev: true + + /nopt/1.0.10: + resolution: {integrity: sha512-NWmpvLSqUrgrAC9HCuxEvb+PSloHpqVu+FqcO4eeF2h5qYRhA7ev6KvelyQAKtegUbC6RypJnlEOhd8vloNKYg==} + hasBin: true + dependencies: + abbrev: 1.1.1 + dev: true + /normalize-path/3.0.0: resolution: {integrity: sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==} engines: {node: '>=0.10.0'} @@ -3352,6 +3406,10 @@ packages: resolution: {integrity: sha512-E/ZsdU4HLs/68gYzgGTkMicWTLPdAftJLfJFlLUAAKZGkStNU72sZjT66SnMDVOfOWY/YAoiD7Jxa9iHvngcag==} dev: true + /pstree.remy/1.1.8: + resolution: {integrity: sha512-77DZwxQmxKnu3aR542U+X8FypNzbfJ+C5XQDk3uWjWxn6151aIMGthWYRXTqT1E5oJvg+ljaa2OJi+VfvCOQ8w==} + dev: true + /punycode/2.3.0: resolution: {integrity: sha512-rRV+zQD8tVFys26lAGR9WUuS4iUAngJScM+ZRSKtvl5tKeZ2t5bvdNFdNHBW9FWR4guGHlgmsZ1G7BSm2wTbuA==} engines: {node: '>=6'} @@ -3549,11 +3607,21 @@ packages: dependencies: loose-envify: 1.4.0 + /semver/5.7.1: + resolution: {integrity: sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==} + hasBin: true + dev: true + /semver/6.3.0: resolution: {integrity: sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==} hasBin: true dev: true + /semver/7.0.0: + resolution: {integrity: sha512-+GB6zVA9LWh6zovYQLALHwv5rb2PHGlJi3lfiqIHxR0uuwCgefcOJc59v9fv1w8GbStwxuuqqAjI9NMAOOgq1A==} + hasBin: true + dev: true + /semver/7.3.8: resolution: {integrity: sha512-NB1ctGL5rlHrPJtFDVIVzTyQylMLu9N9VICA6HSFJo8MCGVTMW6gfpicwKmmK/dAjTOrqu5l63JJOpDSrAis3A==} engines: {node: '>=10'} @@ -3586,6 +3654,13 @@ packages: resolution: {integrity: sha512-ybx0WO1/8bSBLEWXZvEd7gMW3Sn3JFlW3TvX1nREbDLRNQNaeNN8WK0meBwPdAaOI7TtRRRJn/Es1zhrrCHu7g==} dev: true + /simple-update-notifier/1.1.0: + resolution: {integrity: sha512-VpsrsJSUcJEseSbMHkrsrAVSdvVS5I96Qo1QAQ4FxQ9wXFcB+pjj7FB7/us9+GcgfW4ziHtYMc1J0PLczb55mg==} + engines: {node: '>=8.10.0'} + dependencies: + semver: 7.0.0 + dev: true + /sirv/2.0.2: resolution: {integrity: sha512-4Qog6aE29nIjAOKe/wowFTxOdmbEZKb+3tsLljaBRzJwtqto0BChD2zzH0LhgCSXiI+V7X+Y45v14wBZQ1TK3w==} engines: {node: '>= 10'} @@ -3831,6 +3906,13 @@ packages: engines: {node: '>=6'} dev: true + /touch/3.1.0: + resolution: {integrity: sha512-WBx8Uy5TLtOSRtIq+M03/sKDrXCLHxwDcquSP2c43Le03/9serjQBIztjRz6FkJez9D/hleyAXTBGLwwZUw9lA==} + hasBin: true + dependencies: + nopt: 1.0.10 + dev: true + /tough-cookie/4.1.2: resolution: {integrity: sha512-G9fqXWoYFZgTc2z8Q5zaHy/vJMjm+WV0AkAeHxVCQiEB1b+dGvWzFW6QV07cY5jQ5gRkeid2qIkzkxUnmoQZUQ==} engines: {node: '>=6'} @@ -3926,6 +4008,10 @@ packages: which-boxed-primitive: 1.0.2 dev: true + /undefsafe/2.0.5: + resolution: {integrity: sha512-WxONCrssBM8TSPRqN5EmsjVrsv4A8X12J4ArBiiayv3DyyG3ZlIg6yysuuSYdZsVz3TKcTg2fd//Ujd4CHV1iA==} + dev: true + /universalify/0.2.0: resolution: {integrity: sha512-CJ1QgKmNg3CwvAv/kOFmtnEN05f0D/cn9QntgNOQlQF9dgvVTHj3t+8JPdjqawCHk7V/KA+fbUqzZ9XWhcqPUg==} engines: {node: '>= 4.0.0'} From 01059aa2f737de7eb5d2e5537684cb2ded449956 Mon Sep 17 00:00:00 2001 From: Eric NGUYEN Date: Tue, 14 Feb 2023 15:53:55 +0100 Subject: [PATCH 13/18] Reorder some parameters in Editor and UI --- src/Components/Editor/Editor.tsx | 4 +++- src/Components/UI/UI.tsx | 2 +- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/src/Components/Editor/Editor.tsx b/src/Components/Editor/Editor.tsx index 6644bed..70f2350 100644 --- a/src/Components/Editor/Editor.tsx +++ b/src/Components/Editor/Editor.tsx @@ -124,6 +124,7 @@ export function Editor(props: IEditorProps): JSX.Element { history, historyCurrentStep }} + replaceContainer={replaceContainer} selectContainer={(container) => setNewHistory( SelectContainer( container, @@ -209,7 +210,8 @@ export function Editor(props: IEditorProps): JSX.Element { )} saveEditorAsSVG={() => SaveEditorAsSVG()} loadState={(move) => setHistoryCurrentStep(move)} - replaceContainer ={replaceContainer} setReplaceContainer={setReplaceContainer}/> + setReplaceContainer={setReplaceContainer} + /> editorRef.current} configuration={configuration} diff --git a/src/Components/UI/UI.tsx b/src/Components/UI/UI.tsx index cab0e17..20c17b5 100644 --- a/src/Components/UI/UI.tsx +++ b/src/Components/UI/UI.tsx @@ -22,6 +22,7 @@ import { Dispatch } from 'react'; export interface IUIProps { editorState: IEditorState + replaceContainer: IReplaceContainer selectContainer: (containerId: string) => void deleteContainer: (containerId: string) => void onPropertyChange: (key: string, value: string | number | boolean | number[], type?: PropertyType) => void @@ -34,7 +35,6 @@ export interface IUIProps { saveEditorAsJSON: () => void saveEditorAsSVG: () => void loadState: (move: number) => void - replaceContainer: IReplaceContainer setReplaceContainer: Dispatch> } From c4bf4586acb1e89a875859f0e870a1225117790d Mon Sep 17 00:00:00 2001 From: Eric Nguyen Date: Tue, 14 Feb 2023 15:00:18 +0000 Subject: [PATCH 14/18] Remove unused configuration from Menu --- src/Components/Editor/Editor.tsx | 1 - src/Components/Menu/Menu.tsx | 2 -- 2 files changed, 3 deletions(-) diff --git a/src/Components/Editor/Editor.tsx b/src/Components/Editor/Editor.tsx index 70f2350..14fd26b 100644 --- a/src/Components/Editor/Editor.tsx +++ b/src/Components/Editor/Editor.tsx @@ -214,7 +214,6 @@ export function Editor(props: IEditorProps): JSX.Element { /> editorRef.current} - configuration={configuration} actions={menuActions} className="z-30 transition-opacity rounded bg-slate-200 drop-shadow-xl" /> diff --git a/src/Components/Menu/Menu.tsx b/src/Components/Menu/Menu.tsx index c8da101..57c3445 100644 --- a/src/Components/Menu/Menu.tsx +++ b/src/Components/Menu/Menu.tsx @@ -2,13 +2,11 @@ import useSize from '@react-hook/size'; import * as React from 'react'; import { IPoint } from '../../Interfaces/IPoint'; import { MenuItem } from './MenuItem'; -import { IConfiguration } from '../../Interfaces/IConfiguration'; interface IMenuProps { getListener: () => HTMLElement | null actions: Map className?: string - configuration: IConfiguration } export interface IMenuAction { From b4c9c3440345847d4e50b1574c348b44126a6aeb Mon Sep 17 00:00:00 2001 From: Eric Nguyen Date: Tue, 14 Feb 2023 15:01:39 +0000 Subject: [PATCH 15/18] Apply suggestions from code review --- src/Components/Editor/Actions/ContextMenuActions.ts | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/Components/Editor/Actions/ContextMenuActions.ts b/src/Components/Editor/Actions/ContextMenuActions.ts index 5b2a546..9fb86f4 100644 --- a/src/Components/Editor/Actions/ContextMenuActions.ts +++ b/src/Components/Editor/Actions/ContextMenuActions.ts @@ -85,8 +85,7 @@ export function InitActions( ); setNewHistory(newHistory); } - } - ] + }] ); menuActions.set( From 2d1e5c94d7e50083f7f6a11f28834edd7a096ea7 Mon Sep 17 00:00:00 2001 From: Eric NGUYEN Date: Tue, 14 Feb 2023 16:10:00 +0100 Subject: [PATCH 16/18] Add Escape to shortcut to deselect replaceContainer --- src/Components/Editor/Actions/Shortcuts.ts | 5 +- src/Components/Editor/Editor.tsx | 162 ++++++++++++--------- 2 files changed, 98 insertions(+), 69 deletions(-) diff --git a/src/Components/Editor/Actions/Shortcuts.ts b/src/Components/Editor/Actions/Shortcuts.ts index a81660c..082770e 100644 --- a/src/Components/Editor/Actions/Shortcuts.ts +++ b/src/Components/Editor/Actions/Shortcuts.ts @@ -7,7 +7,8 @@ export function OnKey( history: IHistoryState[], historyCurrentStep: number, setHistoryCurrentStep: Dispatch>, - deleteAction: () => void + deleteAction: () => void, + resetState: () => void ): void { if (!ENABLE_SHORTCUTS) { return; @@ -27,5 +28,7 @@ export function OnKey( setHistoryCurrentStep(historyCurrentStep + 1); } else if (event.key === 'Delete') { deleteAction(); + } else if (event.key === 'Escape') { + resetState(); } } diff --git a/src/Components/Editor/Editor.tsx b/src/Components/Editor/Editor.tsx index 14fd26b..095f644 100644 --- a/src/Components/Editor/Editor.tsx +++ b/src/Components/Editor/Editor.tsx @@ -1,7 +1,7 @@ -import React, { Dispatch, SetStateAction, useEffect, useRef } from 'react'; +import React, { type Dispatch, type SetStateAction, useEffect, useRef } from 'react'; import './Editor.scss'; -import { IConfiguration } from '../../Interfaces/IConfiguration'; -import { IHistoryState } from '../../Interfaces/IHistoryState'; +import { type IConfiguration } from '../../Interfaces/IConfiguration'; +import { type IHistoryState } from '../../Interfaces/IHistoryState'; import { UI } from '../UI/UI'; import { SelectContainer, DeleteContainer, OnPropertyChange, ReplaceByContainer } from './Actions/ContainerOperations'; import { SaveEditorAsJSON, SaveEditorAsSVG } from './Actions/Save'; @@ -13,7 +13,7 @@ import { FindContainerById } from '../../utils/itertools'; import { Menu } from '../Menu/Menu'; import { InitActions } from './Actions/ContextMenuActions'; import { AddContainerToSelectedContainer, AddContainer } from './Actions/AddContainer'; -import { IReplaceContainer } from '../../Interfaces/IReplaceContainer'; +import { type IReplaceContainer } from '../../Interfaces/IReplaceContainer'; interface IEditorProps { root: Element | Document @@ -26,16 +26,18 @@ function UseShortcuts( history: IHistoryState[], historyCurrentStep: number, setHistoryCurrentStep: Dispatch>, - deleteAction: () => void + deleteAction: () => void, + resetState: () => void ): void { useEffect(() => { function OnKeyUp(event: KeyboardEvent): void { - return OnKey( + OnKey( event, history, historyCurrentStep, setHistoryCurrentStep, - deleteAction + deleteAction, + resetState ); } @@ -63,6 +65,7 @@ function UseNewHistoryState( }; } + export function Editor(props: IEditorProps): JSX.Element { // States const [history, setHistory] = React.useState(structuredClone(props.history)); @@ -72,6 +75,10 @@ export function Editor(props: IEditorProps): JSX.Element { const editorRef = useRef(null); const setNewHistory = UseNewHistoryState(setHistory, setHistoryCurrentStep); + function ResetState(): void { + setReplaceContainer({ isReplacing: false, id: undefined, category: undefined }); + } + // Events UseShortcuts( history, @@ -82,7 +89,8 @@ export function Editor(props: IEditorProps): JSX.Element { setNewHistory( DeleteContainer(current.selectedContainerId, history, historyCurrentStep) ); - } + }, + ResetState ); UseCustomEvents( props.root, @@ -125,25 +133,31 @@ export function Editor(props: IEditorProps): JSX.Element { historyCurrentStep }} replaceContainer={replaceContainer} - selectContainer={(container) => setNewHistory( - SelectContainer( - container, - history, - historyCurrentStep - ))} - deleteContainer={(containerId: string) => setNewHistory( - DeleteContainer( - containerId, - history, - historyCurrentStep - ))} - onPropertyChange={(key, value, type) => setNewHistory( - OnPropertyChange( - key, value, type, - selected, - history, - historyCurrentStep - ))} + selectContainer={(container) => { + setNewHistory( + SelectContainer( + container, + history, + historyCurrentStep + )); + }} + deleteContainer={(containerId: string) => { + setNewHistory( + DeleteContainer( + containerId, + history, + historyCurrentStep + )); + }} + onPropertyChange={(key, value, type) => { + setNewHistory( + OnPropertyChange( + key, value, type, + selected, + history, + historyCurrentStep + )); + }} addOrReplaceContainer={(type) => { if (selected === null || selected === undefined) { return; @@ -168,48 +182,60 @@ export function Editor(props: IEditorProps): JSX.Element { )); } }} - addContainerAt={(index, type, parent) => setNewHistory( - AddContainer( - index, - type, - parent, - configuration, + addContainerAt={(index, type, parent) => { + setNewHistory( + AddContainer( + index, + type, + parent, + configuration, + history, + historyCurrentStep + ) + ); + }} + addSymbol={(type) => { + setNewHistory( + AddSymbol( + type, + configuration, + history, + historyCurrentStep + )); + }} + onSymbolPropertyChange={(key, value) => { + setNewHistory( + OnSymbolPropertyChange( + key, value, + history, + historyCurrentStep + )); + }} + selectSymbol={(symbolId) => { + setNewHistory( + SelectSymbol( + symbolId, + history, + historyCurrentStep + )); + }} + deleteSymbol={(symbolId) => { + setNewHistory( + DeleteSymbol( + symbolId, + history, + historyCurrentStep + )); + }} + saveEditorAsJSON={() => { + SaveEditorAsJSON( history, - historyCurrentStep - ) - )} - addSymbol={(type) => setNewHistory( - AddSymbol( - type, - configuration, - history, - historyCurrentStep - ))} - onSymbolPropertyChange={(key, value) => setNewHistory( - OnSymbolPropertyChange( - key, value, - history, - historyCurrentStep - ))} - selectSymbol={(symbolId) => setNewHistory( - SelectSymbol( - symbolId, - history, - historyCurrentStep - ))} - deleteSymbol={(symbolId) => setNewHistory( - DeleteSymbol( - symbolId, - history, - historyCurrentStep - ))} - saveEditorAsJSON={() => SaveEditorAsJSON( - history, - historyCurrentStep, - configuration - )} - saveEditorAsSVG={() => SaveEditorAsSVG()} - loadState={(move) => setHistoryCurrentStep(move)} + historyCurrentStep, + configuration + ); + }} + saveEditorAsSVG={() => { SaveEditorAsSVG(); }} + loadState={(move) => { setHistoryCurrentStep(move); }} setReplaceContainer={setReplaceContainer} /> Date: Tue, 14 Feb 2023 16:29:05 +0000 Subject: [PATCH 17/18] Merged PR 335: Updated .eslintrc.cjs: Add max-len 120 Updated .eslintrc.cjs: Add max-len 120 --- .eslintrc.cjs | 1 + 1 file changed, 1 insertion(+) diff --git a/.eslintrc.cjs b/.eslintrc.cjs index 14eeda7..7f605ec 100644 --- a/.eslintrc.cjs +++ b/.eslintrc.cjs @@ -32,6 +32,7 @@ module.exports = { 'prefer-arrow-callback': 'error', 'func-style': ['error', 'declaration'], 'space-before-function-paren': ['error', 'never'], + 'max-len': ['error', { 'code': 120 }], // Import/export 'import/no-default-export': 'error', From 65ca7fa10cae841f6fb1dab653e4f44c59ff28f1 Mon Sep 17 00:00:00 2001 From: Eric NGUYEN Date: Fri, 17 Feb 2023 09:58:51 +0100 Subject: [PATCH 18/18] Remove children replacement --- .../Editor/Actions/ContainerOperations.ts | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/src/Components/Editor/Actions/ContainerOperations.ts b/src/Components/Editor/Actions/ContainerOperations.ts index 3dd1e74..684b443 100644 --- a/src/Components/Editor/Actions/ContainerOperations.ts +++ b/src/Components/Editor/Actions/ContainerOperations.ts @@ -158,16 +158,18 @@ export function ReplaceByContainer( if (containerToReplace === undefined) { return history; } - const containerParent = FindContainerById(current.containers,containerToReplace.properties.parentId); - if (containerParent=== undefined) { + + const containerParent = FindContainerById(current.containers, containerToReplace.properties.parentId); + if (containerParent === undefined) { return history; } - const historyAdd = AddContainers(containerParent.children.indexOf(containerId), [{ Type: newContainerId }], containerParent.properties.id, configuration, fullHistory, historyCurrentStep); - // Copy des possibles enfants - if (historyAdd.newContainers[0] === undefined) { - return history; - } - historyAdd.newContainers[0].children = containerToReplace.children; + + const historyAdd = AddContainers( + containerParent.children.indexOf(containerId), + [{ Type: newContainerId }], + containerParent.properties.id, + configuration, fullHistory, historyCurrentStep + ); const historyDelete = DeleteContainer(containerId, historyAdd.history, historyCurrentStep + 1); const currentDelete = historyDelete[historyDelete.length - 1];