diff --git a/.eslintrc.cjs b/.eslintrc.cjs
index 807e39a..108a875 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/csharp/SVGLDLibs/SVGLDLibs/Models/DimensionOptions.cs b/csharp/SVGLDLibs/SVGLDLibs/Models/DimensionOptions.cs
index a98e500..10c6542 100644
--- a/csharp/SVGLDLibs/SVGLDLibs/Models/DimensionOptions.cs
+++ b/csharp/SVGLDLibs/SVGLDLibs/Models/DimensionOptions.cs
@@ -1,28 +1,31 @@
-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 string color;
+
+ /** width */
+ [DataMember(EmitDefaultValue = false)]
+ public double width;
+
+ /** color */
+ [DataMember(EmitDefaultValue = false)]
+ public string dashArray;
+ }
+}
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'}
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/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
}
@@ -62,6 +66,10 @@ export function Components(props: IComponentsProps): JSX.Element {
disabled = config.Blacklist?.find(type => type === componentOption.Type) !== undefined ?? false;
}
+ if (props.replaceContainer.isReplacing && componentOption.Category !== props.replaceContainer.category) {
+ disabled = true;
+ }
+
if (disabled && hideDisabled) {
return;
}
@@ -96,6 +104,15 @@ export function Components(props: IComponentsProps): JSX.Element {
return (
+ {props.replaceContainer.isReplacing &&
+ }
);
-};
+}
diff --git a/src/Components/ContainerProperties/ContainerForm.tsx b/src/Components/ContainerProperties/ContainerForm.tsx
index 4bdc262..8b7a505 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.SelfDimension); }}/>
+ { props.onChange('width', Number(value), PropertyType.SelfDimension); }}/>
+ { props.onChange('dashArray', value, PropertyType.SelfDimension); }}/>
+
}
{
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.SelfMarginDimension); }}/>
+ { props.onChange('width', Number(value), PropertyType.SelfMarginDimension); }}/>
+ { props.onChange('dashArray', value, PropertyType.SelfMarginDimension); }}/>
+
}
{
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.ChildrenDimensions); }}/>
+ { props.onChange('width', Number(value), PropertyType.ChildrenDimensions); }}/>
+ { props.onChange('dashArray', value, PropertyType.ChildrenDimensions); }}/>
+
}
{
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.DimensionWithMarks); }}/>
+ { props.onChange('width', Number(value), PropertyType.DimensionWithMarks); }}/>
+ { props.onChange('dashArray', value, PropertyType.DimensionWithMarks); }}/>
+
+ >
}
{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/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/Editor/Actions/ContainerOperations.ts b/src/Components/Editor/Actions/ContainerOperations.ts
index 82162e3..684b443 100644
--- a/src/Components/Editor/Actions/ContainerOperations.ts
+++ b/src/Components/Editor/Actions/ContainerOperations.ts
@@ -8,6 +8,8 @@ import Swal from 'sweetalert2';
import { PropertyType } from '../../../Enums/PropertyType';
import { TransformX, TransformY } from '../../../utils/svg';
import { Orientation } from '../../../Enums/Orientation';
+import { AddContainers } from './AddContainer';
+import { IConfiguration } from '../../../Interfaces/IConfiguration';
/**
* Select a container
@@ -133,6 +135,58 @@ export function DeleteContainer(
return history;
}
+/**
+ * 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,
+ configuration: IConfiguration,
+ fullHistory: IHistoryState[],
+ historyCurrentStep: number
+): IHistoryState[] {
+ const history = GetCurrentHistory(fullHistory, historyCurrentStep);
+ const current = history[history.length - 1];
+
+ const containerToReplace = FindContainerById(current.containers, containerId);
+ if (containerToReplace === undefined) {
+ 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
+ );
+
+ 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;
+}
+
/**
* Returns the next container that will be selected
* after the selectedContainer is removed.
diff --git a/src/Components/Editor/Actions/ContextMenuActions.ts b/src/Components/Editor/Actions/ContextMenuActions.ts
index 69a3121..9fb86f4 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(
'',
@@ -56,9 +58,24 @@ export function InitActions(
menuActions.set(
'elements-sidebar-row',
[{
+ text: Text({ textId: '@ReplaceByContainer' }),
+ title: Text({ textId: '@ReplaceByContainerTitle' }),
+ shortcut: 'R',
+ action: (target: HTMLElement) => {
+ 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' }),
title: Text({ textId: '@DeleteContainerTitle' }),
shortcut: 'Suppr',
+
action: (target: HTMLElement) => {
const id = target.id;
const newHistory = DeleteContainer(
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) {
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 372ab06..095f644 100644
--- a/src/Components/Editor/Editor.tsx
+++ b/src/Components/Editor/Editor.tsx
@@ -1,9 +1,9 @@
-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 } 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 { type IReplaceContainer } from '../../Interfaces/IReplaceContainer';
interface IEditorProps {
root: Element | Document
@@ -25,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
);
}
@@ -62,13 +65,20 @@ function UseNewHistoryState(
};
}
+
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);
+ function ResetState(): void {
+ setReplaceContainer({ isReplacing: false, id: undefined, category: undefined });
+ }
+
// Events
UseShortcuts(
history,
@@ -79,7 +89,8 @@ export function Editor(props: IEditorProps): JSX.Element {
setNewHistory(
DeleteContainer(current.selectedContainerId, history, historyCurrentStep)
);
- }
+ },
+ ResetState
);
UseCustomEvents(
props.root,
@@ -104,7 +115,8 @@ export function Editor(props: IEditorProps): JSX.Element {
history,
historyCurrentStep,
setNewHistory,
- setHistoryCurrentStep
+ setHistoryCurrentStep,
+ setReplaceContainer
);
// Render
@@ -113,87 +125,118 @@ export function Editor(props: IEditorProps): JSX.Element {
const selected = FindContainerById(current.containers, current.selectedContainerId);
return (
-
+
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
- ))}
- addContainer={(type) => {
+ 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
+ ));
+ }}
+ 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(
- 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}
/>
);
+
+ 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..840f1dd 100644
--- a/src/Components/UI/UI.tsx
+++ b/src/Components/UI/UI.tsx
@@ -4,26 +4,29 @@ 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';
+import { IReplaceContainer } from '../../Interfaces/IReplaceContainer';
+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
- 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 +35,8 @@ export interface IUIProps {
saveEditorAsJSON: () => void
saveEditorAsSVG: () => void
loadState: (move: number) => void
+ setReplaceContainer: Dispatch
>
+
}
export enum SidebarType {
@@ -59,7 +64,7 @@ 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([]);
@@ -96,16 +101,19 @@ 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:
leftSidebarTitle = Text({ textId: '@Components' });
+
leftChildren = ;
+ buttonOnClick={methods.addOrReplaceContainer}
+ replaceContainer={replaceContainer}
+ setReplaceContainer={setReplaceContainer}/>;
rightSidebarTitle = Text({ textId: '@Elements' });
rightChildren = setOrToggleSidebar(SidebarType.ComponentsExpanded) }
+ onExpandChange={() => { setOrToggleSidebar(SidebarType.ComponentsExpanded); } }
/>;
break;
case SidebarType.ComponentsExpanded:
@@ -125,8 +133,9 @@ export function UI({ editorState, ...methods }: IUIProps): JSX.Element {
selectedContainer={selectedContainer}
componentOptions={configuration.AvailableContainers}
categories={configuration.Categories}
- buttonOnClick={methods.addContainer}
- />;
+ buttonOnClick={methods.addOrReplaceContainer}
+ replaceContainer={replaceContainer}
+ setReplaceContainer={setReplaceContainer}/>;
rightSidebarTitle = Text({ textId: '@Elements' });
rightChildren = setOrToggleSidebar(SidebarType.Components) }
+ onExpandChange={() => { setOrToggleSidebar(SidebarType.Components); } }
/>;
break;
case SidebarType.Symbols:
@@ -153,7 +162,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 +178,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 +196,7 @@ export function UI({ editorState, ...methods }: IUIProps): JSX.Element {
leftChildren = setMessages([])}
+ clearMessage={() => { setMessages([]); }}
/>;
break;
@@ -242,11 +251,16 @@ export function UI({ editorState, ...methods }: IUIProps): JSX.Element {
isLeftSidebarOpenClasses.add('left-sidebar-single');
}
+ const clickRestrictionsClasses = replaceContainer.isReplacing ? 'pointer-events-none opacity-50' : '';
+ const isComponentsOpen = selectedSidebar === SidebarType.Components || selectedSidebar === SidebarType.ComponentsExpanded;
+ const isSymbolsOpen = selectedSidebar === SidebarType.Symbols || selectedSidebar === SidebarType.SymbolsExpanded;
+
return (
<>
{ rightChildren }
diff --git a/src/Components/Viewer/Viewer.tsx b/src/Components/Viewer/Viewer.tsx
index cdf630e..a6092c4 100644
--- a/src/Components/Viewer/Viewer.tsx
+++ b/src/Components/Viewer/Viewer.tsx
@@ -1,23 +1,27 @@
import * as React from 'react';
-import { IContainerModel } from '../../Interfaces/IContainerModel';
-import { IHistoryState } from '../../Interfaces/IHistoryState';
-import { IPoint } from '../../Interfaces/IPoint';
+import { type IContainerModel } from '../../Interfaces/IContainerModel';
+import { type IHistoryState } from '../../Interfaces/IHistoryState';
+import { type IPoint } from '../../Interfaces/IPoint';
import { DIMENSION_MARGIN, USE_EXPERIMENTAL_CANVAS_API } from '../../utils/default';
import { FindContainerById, MakeRecursionDFSIterator } from '../../utils/itertools';
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';
interface IViewerProps {
- className?: string
+ className: string
current: IHistoryState
selectedContainer: IContainerModel | undefined
selectContainer: (containerId: string) => 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);
@@ -64,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) {
@@ -119,7 +133,7 @@ export function Viewer({
return (
@@ -134,11 +148,12 @@ export function Viewer({
width={mainContainer.properties.width}
height={mainContainer.properties.height}
containers={current.containers}
- selected={selectedContainer}
+ selectedContainer={selectedContainer}
symbols={current.symbols}
+ selectedSymbol={selectedSymbol}
+ selectorMode={selectorMode}
selectContainer={selectContainer}
>
-
{mainContainer}
);
diff --git a/src/Enums/PropertyType.ts b/src/Enums/PropertyType.ts
index edd78ff..f57d2b9 100644
--- a/src/Enums/PropertyType.ts
+++ b/src/Enums/PropertyType.ts
@@ -27,6 +27,6 @@ export enum PropertyType {
SelfMarginDimension,
ChildrenDimensions,
DimensionWithMarks,
- DimensionOptions
+ 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..a12865a 100644
--- a/src/Interfaces/IDimensionOptions.ts
+++ b/src/Interfaces/IDimensionOptions.ts
@@ -1,10 +1,17 @@
-import { Position } from '../Enums/Position';
+import { type Position } from '../Enums/Position';
export interface IDimensionOptions {
positions: Position[]
+
/**
- * Stroke color
- */
- color: string
+ * Stroke color
+ */
+ color?: string
+
+ /** stroke-width */
+ width?: number
+
+ /** stroke-dasharray */
+ dashArray?: string
}
diff --git a/src/Interfaces/IReplaceContainer.ts b/src/Interfaces/IReplaceContainer.ts
new file mode 100644
index 0000000..c1c8a71
--- /dev/null
+++ b/src/Interfaces/IReplaceContainer.ts
@@ -0,0 +1,5 @@
+export interface IReplaceContainer {
+ id: string | undefined
+ isReplacing: boolean
+ category: string | undefined
+}
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..5977edd 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 ///
@@ -65,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;
@@ -187,6 +187,12 @@ const DEFAULT_CONTAINER_STYLE = {
strokeWidth: 2
};
+export const DEFAULT_DIMENSION_OPTION: IDimensionOptions = {
+ positions: [],
+ color: '#000000',
+ width: 2
+};
+
/**
* Default Main container properties
*/
@@ -211,23 +217,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,20 +270,20 @@ export function GetDefaultContainerProps(type: string,
hideChildrenInTreeview: containerConfig.HideChildrenInTreeview ?? false,
dimensionOptions: {
childrenDimensions: {
- color: containerConfig.DimensionOptions?.childrenDimensions.color ?? '#000000',
+ ...containerConfig.DimensionOptions?.selfDimensions,
positions: containerConfig.DimensionOptions?.childrenDimensions.positions ?? []
},
selfDimensions: {
- color: containerConfig.DimensionOptions?.selfDimensions.color ?? '#000000',
+ ...containerConfig.DimensionOptions?.selfDimensions,
positions: containerConfig.DimensionOptions?.selfDimensions.positions ?? []
},
selfMarginsDimensions: {
- color: containerConfig.DimensionOptions?.selfMarginsDimensions.color ?? '#000000',
+ ...containerConfig.DimensionOptions?.selfMarginsDimensions,
positions: containerConfig.DimensionOptions?.selfMarginsDimensions.positions ?? []
},
markPosition: containerConfig.DimensionOptions?.markPosition ?? [],
dimensionWithMarks: {
- color: containerConfig.DimensionOptions?.dimensionWithMarks.color ?? '#000000',
+ ...containerConfig.DimensionOptions?.dimensionWithMarks,
positions: containerConfig.DimensionOptions?.dimensionWithMarks.positions ?? []
}
},
@@ -317,3 +311,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));
+}