Merged PR 163: Remove the static form + rename some components for clarity
All checks were successful
continuous-integration/drone/push Build is passing
All checks were successful
continuous-integration/drone/push Build is passing
The static form is hard to maintain so I am removing it + rename some components for clarity + moved some utils files
This commit is contained in:
parent
7e3ccdee99
commit
66ea3b1b64
21 changed files with 150 additions and 523 deletions
BIN
docs/ComponentStructure.drawio
(Stored with Git LFS)
BIN
docs/ComponentStructure.drawio
(Stored with Git LFS)
Binary file not shown.
|
@ -1,6 +1,6 @@
|
||||||
import { Dispatch, SetStateAction } from 'react';
|
import { Dispatch, SetStateAction } from 'react';
|
||||||
import { Revive } from '../../utils/saveload';
|
import { IEditorState } from '../../../Interfaces/IEditorState';
|
||||||
import { IEditorState } from '../../Interfaces/IEditorState';
|
import { Revive } from '../../../utils/saveload';
|
||||||
|
|
||||||
export function LoadState(
|
export function LoadState(
|
||||||
editorState: IEditorState,
|
editorState: IEditorState,
|
|
@ -1,10 +1,10 @@
|
||||||
import { Dispatch, SetStateAction } from 'react';
|
import { Dispatch, SetStateAction } from 'react';
|
||||||
import { IConfiguration } from '../../Interfaces/IConfiguration';
|
import { IConfiguration } from '../../../Interfaces/IConfiguration';
|
||||||
import { ContainerModel } from '../../Interfaces/IContainerModel';
|
import { ContainerModel } from '../../../Interfaces/IContainerModel';
|
||||||
import { fetchConfiguration } from '../API/api';
|
import { fetchConfiguration } from '../../API/api';
|
||||||
import { IEditorState } from '../../Interfaces/IEditorState';
|
import { IEditorState } from '../../../Interfaces/IEditorState';
|
||||||
import { LoadState } from './Load';
|
import { LoadState } from './Load';
|
||||||
import { DEFAULT_MAINCONTAINER_PROPS } from '../../utils/default';
|
import { DEFAULT_MAINCONTAINER_PROPS } from '../../../utils/default';
|
||||||
|
|
||||||
export function NewEditor(
|
export function NewEditor(
|
||||||
setEditorState: Dispatch<SetStateAction<IEditorState>>,
|
setEditorState: Dispatch<SetStateAction<IEditorState>>,
|
|
@ -4,8 +4,8 @@ import { MainMenu } from '../MainMenu/MainMenu';
|
||||||
import { ContainerModel } from '../../Interfaces/IContainerModel';
|
import { ContainerModel } from '../../Interfaces/IContainerModel';
|
||||||
import Editor from '../Editor/Editor';
|
import Editor from '../Editor/Editor';
|
||||||
import { IEditorState } from '../../Interfaces/IEditorState';
|
import { IEditorState } from '../../Interfaces/IEditorState';
|
||||||
import { LoadState } from './Load';
|
import { LoadState } from './Actions/Load';
|
||||||
import { LoadEditor, NewEditor } from './MenuActions';
|
import { LoadEditor, NewEditor } from './Actions/MenuActions';
|
||||||
import { DEFAULT_CONFIG, DEFAULT_MAINCONTAINER_PROPS } from '../../utils/default';
|
import { DEFAULT_CONFIG, DEFAULT_MAINCONTAINER_PROPS } from '../../utils/default';
|
||||||
|
|
||||||
// App will never have props
|
// App will never have props
|
||||||
|
|
|
@ -8,7 +8,7 @@ import { InputGroup } from '../InputGroup/InputGroup';
|
||||||
import { RadioGroupButtons } from '../RadioGroupButtons/RadioGroupButtons';
|
import { RadioGroupButtons } from '../RadioGroupButtons/RadioGroupButtons';
|
||||||
import { Select } from '../Select/Select';
|
import { Select } from '../Select/Select';
|
||||||
|
|
||||||
interface IDynamicFormProps {
|
interface IContainerFormProps {
|
||||||
properties: IContainerProperties
|
properties: IContainerProperties
|
||||||
symbols: Map<string, ISymbolModel>
|
symbols: Map<string, ISymbolModel>
|
||||||
onChange: (key: string, value: string | number | boolean, isStyle?: boolean) => void
|
onChange: (key: string, value: string | number | boolean, isStyle?: boolean) => void
|
||||||
|
@ -34,7 +34,7 @@ const getCSSInputs = (
|
||||||
return groupInput;
|
return groupInput;
|
||||||
};
|
};
|
||||||
|
|
||||||
const DynamicForm: React.FunctionComponent<IDynamicFormProps> = (props) => {
|
const ContainerForm: React.FunctionComponent<IContainerFormProps> = (props) => {
|
||||||
return (
|
return (
|
||||||
<div className='grid grid-cols-2 gap-y-4'>
|
<div className='grid grid-cols-2 gap-y-4'>
|
||||||
<InputGroup
|
<InputGroup
|
||||||
|
@ -181,5 +181,4 @@ const DynamicForm: React.FunctionComponent<IDynamicFormProps> = (props) => {
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export default ContainerForm;
|
||||||
export default DynamicForm;
|
|
|
@ -3,14 +3,13 @@ import * as React from 'react';
|
||||||
import { expect, describe, it, vi } from 'vitest';
|
import { expect, describe, it, vi } from 'vitest';
|
||||||
import { XPositionReference } from '../../Enums/XPositionReference';
|
import { XPositionReference } from '../../Enums/XPositionReference';
|
||||||
import IContainerProperties from '../../Interfaces/IContainerProperties';
|
import IContainerProperties from '../../Interfaces/IContainerProperties';
|
||||||
import { Properties } from './Properties';
|
import { Properties } from './ContainerProperties';
|
||||||
|
|
||||||
describe.concurrent('Properties', () => {
|
describe.concurrent('Properties', () => {
|
||||||
it('No properties', () => {
|
it('No properties', () => {
|
||||||
render(<Properties
|
render(<Properties
|
||||||
properties={undefined}
|
properties={undefined}
|
||||||
onChange={() => {}}
|
onChange={() => {}}
|
||||||
onSubmit={() => {}}
|
|
||||||
symbols={new Map()}
|
symbols={new Map()}
|
||||||
/>);
|
/>);
|
||||||
|
|
||||||
|
@ -43,7 +42,6 @@ describe.concurrent('Properties', () => {
|
||||||
const { container, rerender } = render(<Properties
|
const { container, rerender } = render(<Properties
|
||||||
properties={prop}
|
properties={prop}
|
||||||
onChange={handleChange}
|
onChange={handleChange}
|
||||||
onSubmit={() => {}}
|
|
||||||
symbols={new Map()}
|
symbols={new Map()}
|
||||||
/>);
|
/>);
|
||||||
|
|
||||||
|
@ -78,7 +76,6 @@ describe.concurrent('Properties', () => {
|
||||||
rerender(<Properties
|
rerender(<Properties
|
||||||
properties={Object.assign({}, prop)}
|
properties={Object.assign({}, prop)}
|
||||||
onChange={handleChange}
|
onChange={handleChange}
|
||||||
onSubmit={() => {}}
|
|
||||||
symbols={new Map()}
|
symbols={new Map()}
|
||||||
/>);
|
/>);
|
||||||
|
|
|
@ -1,38 +1,25 @@
|
||||||
import React, { useState } from 'react';
|
import React from 'react';
|
||||||
import IContainerProperties from '../../Interfaces/IContainerProperties';
|
import IContainerProperties from '../../Interfaces/IContainerProperties';
|
||||||
import { ISymbolModel } from '../../Interfaces/ISymbolModel';
|
import { ISymbolModel } from '../../Interfaces/ISymbolModel';
|
||||||
import { ToggleButton } from '../ToggleButton/ToggleButton';
|
import ContainerForm from './ContainerForm';
|
||||||
import { Form } from './Form';
|
|
||||||
|
|
||||||
interface IPropertiesProps {
|
interface IPropertiesProps {
|
||||||
properties?: IContainerProperties
|
properties?: IContainerProperties
|
||||||
symbols: Map<string, ISymbolModel>
|
symbols: Map<string, ISymbolModel>
|
||||||
onChange: (key: string, value: string | number | boolean, isStyle?: boolean) => void
|
onChange: (key: string, value: string | number | boolean, isStyle?: boolean) => void
|
||||||
onSubmit: (event: React.FormEvent<HTMLFormElement>) => void
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export const Properties: React.FC<IPropertiesProps> = (props: IPropertiesProps) => {
|
export const Properties: React.FC<IPropertiesProps> = (props: IPropertiesProps) => {
|
||||||
const [isDynamicInput, setIsDynamicInput] = useState<boolean>(true);
|
|
||||||
|
|
||||||
if (props.properties === undefined) {
|
if (props.properties === undefined) {
|
||||||
return <div></div>;
|
return <div></div>;
|
||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className='h-3/5 p-3 bg-slate-200 overflow-y-auto'>
|
<div className='h-3/5 p-3 bg-slate-200 overflow-y-auto'>
|
||||||
<ToggleButton
|
<ContainerForm
|
||||||
id='isDynamic'
|
|
||||||
text='Dynamic update'
|
|
||||||
title='Enable dynamic svg update'
|
|
||||||
checked={isDynamicInput}
|
|
||||||
onChange={() => setIsDynamicInput(!isDynamicInput)}
|
|
||||||
/>
|
|
||||||
<Form
|
|
||||||
properties={props.properties}
|
properties={props.properties}
|
||||||
symbols={props.symbols}
|
symbols={props.symbols}
|
||||||
isDynamicInput={isDynamicInput}
|
|
||||||
onChange={props.onChange}
|
onChange={props.onChange}
|
||||||
onSubmit={props.onSubmit}
|
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
|
@ -1,14 +1,14 @@
|
||||||
import { Dispatch, SetStateAction } from 'react';
|
import { Dispatch, SetStateAction } from 'react';
|
||||||
import { IHistoryState } from '../../Interfaces/IHistoryState';
|
import { IHistoryState } from '../../../Interfaces/IHistoryState';
|
||||||
import { IConfiguration } from '../../Interfaces/IConfiguration';
|
import { IConfiguration } from '../../../Interfaces/IConfiguration';
|
||||||
import { ContainerModel, IContainerModel } from '../../Interfaces/IContainerModel';
|
import { ContainerModel, IContainerModel } from '../../../Interfaces/IContainerModel';
|
||||||
import { findContainerById, MakeIterator } from '../../utils/itertools';
|
import { findContainerById, MakeIterator } from '../../../utils/itertools';
|
||||||
import { getCurrentHistory, UpdateCounters } from './Editor';
|
import { getCurrentHistory, UpdateCounters } from '../Editor';
|
||||||
import { AddMethod } from '../../Enums/AddMethod';
|
import { AddMethod } from '../../../Enums/AddMethod';
|
||||||
import { IAvailableContainer } from '../../Interfaces/IAvailableContainer';
|
import { IAvailableContainer } from '../../../Interfaces/IAvailableContainer';
|
||||||
import { GetDefaultContainerProps, DEFAULTCHILDTYPE_ALLOW_CYCLIC, DEFAULTCHILDTYPE_MAX_DEPTH } from '../../utils/default';
|
import { GetDefaultContainerProps, DEFAULTCHILDTYPE_ALLOW_CYCLIC, DEFAULTCHILDTYPE_MAX_DEPTH } from '../../../utils/default';
|
||||||
import { ApplyBehaviors } from './Behaviors/Behaviors';
|
import { ApplyBehaviors } from '../Behaviors/Behaviors';
|
||||||
import { ISymbolModel } from '../../Interfaces/ISymbolModel';
|
import { ISymbolModel } from '../../../Interfaces/ISymbolModel';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Select a container
|
* Select a container
|
||||||
|
@ -71,7 +71,8 @@ export function DeleteContainer(
|
||||||
if (container === null || container === undefined) {
|
if (container === null || container === undefined) {
|
||||||
throw new Error('[DeleteContainer] Container model was not found among children of the main container!');
|
throw new Error('[DeleteContainer] Container model was not found among children of the main container!');
|
||||||
}
|
}
|
||||||
const newSymbols = structuredClone(current.Symbols)
|
|
||||||
|
const newSymbols = structuredClone(current.Symbols);
|
||||||
UnlinkSymbol(newSymbols, container);
|
UnlinkSymbol(newSymbols, container);
|
||||||
|
|
||||||
const index = container.parent.children.indexOf(container);
|
const index = container.parent.children.indexOf(container);
|
||||||
|
@ -83,10 +84,12 @@ export function DeleteContainer(
|
||||||
|
|
||||||
// Select the previous container
|
// Select the previous container
|
||||||
// or select the one above
|
// or select the one above
|
||||||
const SelectedContainer = findContainerById(mainContainerClone, current.SelectedContainerId) ??
|
const SelectedContainerId = GetSelectedContainerOnDelete(
|
||||||
container.parent.children.at(index - 1) ??
|
mainContainerClone,
|
||||||
container.parent;
|
current.SelectedContainerId,
|
||||||
const SelectedContainerId = SelectedContainer.properties.id;
|
container.parent,
|
||||||
|
index
|
||||||
|
);
|
||||||
|
|
||||||
history.push({
|
history.push({
|
||||||
LastAction: `Delete ${containerId}`,
|
LastAction: `Delete ${containerId}`,
|
||||||
|
@ -100,6 +103,14 @@ export function DeleteContainer(
|
||||||
setHistoryCurrentStep(history.length - 1);
|
setHistoryCurrentStep(history.length - 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function GetSelectedContainerOnDelete(mainContainerClone: IContainerModel, selectedContainerId: string, parent: IContainerModel, index: number): string {
|
||||||
|
const SelectedContainer = findContainerById(mainContainerClone, selectedContainerId) ??
|
||||||
|
parent.children.at(index - 1) ??
|
||||||
|
parent;
|
||||||
|
const SelectedContainerId = SelectedContainer.properties.id;
|
||||||
|
return SelectedContainerId;
|
||||||
|
}
|
||||||
|
|
||||||
function UnlinkSymbol(symbols: Map<string, ISymbolModel>, container: IContainerModel): void {
|
function UnlinkSymbol(symbols: Map<string, ISymbolModel>, container: IContainerModel): void {
|
||||||
const it = MakeIterator(container);
|
const it = MakeIterator(container);
|
||||||
for (const child of it) {
|
for (const child of it) {
|
||||||
|
@ -327,3 +338,82 @@ function ApplyAddMethod(index: number, containerConfig: IAvailableContainer, par
|
||||||
}
|
}
|
||||||
return x;
|
return x;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Handled the property change event in the properties form
|
||||||
|
* @param key Property name
|
||||||
|
* @param value New value of the property
|
||||||
|
* @returns void
|
||||||
|
*/
|
||||||
|
export function OnPropertyChange(
|
||||||
|
key: string,
|
||||||
|
value: string | number | boolean,
|
||||||
|
isStyle: boolean = false,
|
||||||
|
selected: IContainerModel | undefined,
|
||||||
|
fullHistory: IHistoryState[],
|
||||||
|
historyCurrentStep: number,
|
||||||
|
setHistory: Dispatch<SetStateAction<IHistoryState[]>>,
|
||||||
|
setHistoryCurrentStep: Dispatch<SetStateAction<number>>
|
||||||
|
): void {
|
||||||
|
const history = getCurrentHistory(fullHistory, historyCurrentStep);
|
||||||
|
const current = history[history.length - 1];
|
||||||
|
|
||||||
|
if (selected === null ||
|
||||||
|
selected === undefined) {
|
||||||
|
throw new Error('[OnPropertyChange] Property was changed before selecting a Container');
|
||||||
|
}
|
||||||
|
|
||||||
|
const mainContainerClone: IContainerModel = structuredClone(current.MainContainer);
|
||||||
|
const container: ContainerModel | undefined = findContainerById(mainContainerClone, selected.properties.id);
|
||||||
|
|
||||||
|
if (container === null || container === undefined) {
|
||||||
|
throw new Error('[OnPropertyChange] Container model was not found among children of the main container!');
|
||||||
|
}
|
||||||
|
|
||||||
|
const oldSymbolId = container.properties.linkedSymbolId;
|
||||||
|
|
||||||
|
if (isStyle) {
|
||||||
|
(container.properties.style as any)[key] = value;
|
||||||
|
} else {
|
||||||
|
(container.properties as any)[key] = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
LinkSymbol(
|
||||||
|
container.properties.id,
|
||||||
|
oldSymbolId,
|
||||||
|
container.properties.linkedSymbolId,
|
||||||
|
current.Symbols
|
||||||
|
);
|
||||||
|
|
||||||
|
ApplyBehaviors(container, current.Symbols);
|
||||||
|
|
||||||
|
history.push({
|
||||||
|
LastAction: `Change ${key} of ${container.properties.id}`,
|
||||||
|
MainContainer: mainContainerClone,
|
||||||
|
SelectedContainerId: container.properties.id,
|
||||||
|
TypeCounters: Object.assign({}, current.TypeCounters),
|
||||||
|
Symbols: structuredClone(current.Symbols),
|
||||||
|
SelectedSymbolId: current.SelectedSymbolId
|
||||||
|
});
|
||||||
|
setHistory(history);
|
||||||
|
setHistoryCurrentStep(history.length - 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
function LinkSymbol(
|
||||||
|
containerId: string,
|
||||||
|
oldSymbolId: string,
|
||||||
|
newSymbolId: string,
|
||||||
|
symbols: Map<string, ISymbolModel>
|
||||||
|
): void {
|
||||||
|
const oldSymbol = symbols.get(oldSymbolId);
|
||||||
|
const newSymbol = symbols.get(newSymbolId);
|
||||||
|
|
||||||
|
if (newSymbol === undefined) {
|
||||||
|
if (oldSymbol !== undefined) {
|
||||||
|
oldSymbol.linkedContainers.delete(containerId);
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
newSymbol.linkedContainers.add(containerId);
|
||||||
|
}
|
|
@ -1,8 +1,8 @@
|
||||||
import { IHistoryState } from '../../Interfaces/IHistoryState';
|
import { IHistoryState } from '../../../Interfaces/IHistoryState';
|
||||||
import { IConfiguration } from '../../Interfaces/IConfiguration';
|
import { IConfiguration } from '../../../Interfaces/IConfiguration';
|
||||||
import { getCircularReplacer } from '../../utils/saveload';
|
import { getCircularReplacer } from '../../../utils/saveload';
|
||||||
import { ID } from '../SVG/SVG';
|
import { ID } from '../../SVG/SVG';
|
||||||
import { IEditorState } from '../../Interfaces/IEditorState';
|
import { IEditorState } from '../../../Interfaces/IEditorState';
|
||||||
|
|
||||||
export function SaveEditorAsJSON(
|
export function SaveEditorAsJSON(
|
||||||
history: IHistoryState[],
|
history: IHistoryState[],
|
|
@ -1,6 +1,6 @@
|
||||||
import { Dispatch, SetStateAction } from 'react';
|
import { Dispatch, SetStateAction } from 'react';
|
||||||
import { IHistoryState } from '../../Interfaces/IHistoryState';
|
import { IHistoryState } from '../../../Interfaces/IHistoryState';
|
||||||
import { ENABLE_SHORTCUTS } from '../../utils/default';
|
import { ENABLE_SHORTCUTS } from '../../../utils/default';
|
||||||
|
|
||||||
export function onKeyDown(
|
export function onKeyDown(
|
||||||
event: KeyboardEvent,
|
event: KeyboardEvent,
|
|
@ -1,13 +1,13 @@
|
||||||
import { Dispatch, SetStateAction } from 'react';
|
import { Dispatch, SetStateAction } from 'react';
|
||||||
import { IConfiguration } from '../../Interfaces/IConfiguration';
|
import { IConfiguration } from '../../../Interfaces/IConfiguration';
|
||||||
import { IContainerModel } from '../../Interfaces/IContainerModel';
|
import { IContainerModel } from '../../../Interfaces/IContainerModel';
|
||||||
import { IHistoryState } from '../../Interfaces/IHistoryState';
|
import { IHistoryState } from '../../../Interfaces/IHistoryState';
|
||||||
import { ISymbolModel } from '../../Interfaces/ISymbolModel';
|
import { ISymbolModel } from '../../../Interfaces/ISymbolModel';
|
||||||
import { DEFAULT_SYMBOL_HEIGHT, DEFAULT_SYMBOL_WIDTH } from '../../utils/default';
|
import { DEFAULT_SYMBOL_HEIGHT, DEFAULT_SYMBOL_WIDTH } from '../../../utils/default';
|
||||||
import { findContainerById } from '../../utils/itertools';
|
import { findContainerById } from '../../../utils/itertools';
|
||||||
import { restoreX } from '../../utils/svg';
|
import { restoreX } from '../../../utils/svg';
|
||||||
import { ApplyBehaviors } from './Behaviors/Behaviors';
|
import { ApplyBehaviors } from '../Behaviors/Behaviors';
|
||||||
import { getCurrentHistory, UpdateCounters } from './Editor';
|
import { getCurrentHistory, UpdateCounters } from '../Editor';
|
||||||
|
|
||||||
export function AddSymbol(
|
export function AddSymbol(
|
||||||
name: string,
|
name: string,
|
|
@ -4,14 +4,13 @@ import { IConfiguration } from '../../Interfaces/IConfiguration';
|
||||||
import { SVG } from '../SVG/SVG';
|
import { SVG } from '../SVG/SVG';
|
||||||
import { IHistoryState } from '../../Interfaces/IHistoryState';
|
import { IHistoryState } from '../../Interfaces/IHistoryState';
|
||||||
import { UI } from '../UI/UI';
|
import { UI } from '../UI/UI';
|
||||||
import { SelectContainer, DeleteContainer, AddContainerToSelectedContainer, AddContainer } from './ContainerOperations';
|
import { SelectContainer, DeleteContainer, AddContainerToSelectedContainer, AddContainer, OnPropertyChange } from './Actions/ContainerOperations';
|
||||||
import { SaveEditorAsJSON, SaveEditorAsSVG } from './Save';
|
import { SaveEditorAsJSON, SaveEditorAsSVG } from './Actions/Save';
|
||||||
import { onKeyDown } from './Shortcuts';
|
import { onKeyDown } from './Actions/Shortcuts';
|
||||||
import { OnPropertyChange, OnPropertiesSubmit } from './PropertiesOperations';
|
|
||||||
import EditorEvents from '../../Events/EditorEvents';
|
import EditorEvents from '../../Events/EditorEvents';
|
||||||
import { IEditorState } from '../../Interfaces/IEditorState';
|
import { IEditorState } from '../../Interfaces/IEditorState';
|
||||||
import { MAX_HISTORY } from '../../utils/default';
|
import { MAX_HISTORY } from '../../utils/default';
|
||||||
import { AddSymbol, OnPropertyChange as OnSymbolPropertyChange, DeleteSymbol, SelectSymbol } from './SymbolOperations';
|
import { AddSymbol, OnPropertyChange as OnSymbolPropertyChange, DeleteSymbol, SelectSymbol } from './Actions/SymbolOperations';
|
||||||
import { findContainerById } from '../../utils/itertools';
|
import { findContainerById } from '../../utils/itertools';
|
||||||
|
|
||||||
interface IEditorProps {
|
interface IEditorProps {
|
||||||
|
@ -113,14 +112,6 @@ const Editor: React.FunctionComponent<IEditorProps> = (props) => {
|
||||||
setHistory,
|
setHistory,
|
||||||
setHistoryCurrentStep
|
setHistoryCurrentStep
|
||||||
)}
|
)}
|
||||||
OnPropertiesSubmit={(event) => OnPropertiesSubmit(
|
|
||||||
event,
|
|
||||||
selected,
|
|
||||||
history,
|
|
||||||
historyCurrentStep,
|
|
||||||
setHistory,
|
|
||||||
setHistoryCurrentStep
|
|
||||||
)}
|
|
||||||
AddContainerToSelectedContainer={(type) => AddContainerToSelectedContainer(
|
AddContainerToSelectedContainer={(type) => AddContainerToSelectedContainer(
|
||||||
type,
|
type,
|
||||||
selected,
|
selected,
|
||||||
|
|
|
@ -1,223 +0,0 @@
|
||||||
import { Dispatch, SetStateAction } from 'react';
|
|
||||||
import { IContainerModel, ContainerModel } from '../../Interfaces/IContainerModel';
|
|
||||||
import { IHistoryState } from '../../Interfaces/IHistoryState';
|
|
||||||
import { findContainerById } from '../../utils/itertools';
|
|
||||||
import { getCurrentHistory } from './Editor';
|
|
||||||
import { ApplyBehaviors } from './Behaviors/Behaviors';
|
|
||||||
import { restoreX } from '../../utils/svg';
|
|
||||||
import { ISymbolModel } from '../../Interfaces/ISymbolModel';
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Handled the property change event in the properties form
|
|
||||||
* @param key Property name
|
|
||||||
* @param value New value of the property
|
|
||||||
* @returns void
|
|
||||||
*/
|
|
||||||
export function OnPropertyChange(
|
|
||||||
key: string,
|
|
||||||
value: string | number | boolean,
|
|
||||||
isStyle: boolean = false,
|
|
||||||
selected: IContainerModel | undefined,
|
|
||||||
fullHistory: IHistoryState[],
|
|
||||||
historyCurrentStep: number,
|
|
||||||
setHistory: Dispatch<SetStateAction<IHistoryState[]>>,
|
|
||||||
setHistoryCurrentStep: Dispatch<SetStateAction<number>>
|
|
||||||
): void {
|
|
||||||
const history = getCurrentHistory(fullHistory, historyCurrentStep);
|
|
||||||
const current = history[history.length - 1];
|
|
||||||
|
|
||||||
if (selected === null ||
|
|
||||||
selected === undefined) {
|
|
||||||
throw new Error('[OnPropertyChange] Property was changed before selecting a Container');
|
|
||||||
}
|
|
||||||
|
|
||||||
const mainContainerClone: IContainerModel = structuredClone(current.MainContainer);
|
|
||||||
const container: ContainerModel | undefined = findContainerById(mainContainerClone, selected.properties.id);
|
|
||||||
|
|
||||||
if (container === null || container === undefined) {
|
|
||||||
throw new Error('[OnPropertyChange] Container model was not found among children of the main container!');
|
|
||||||
}
|
|
||||||
|
|
||||||
const oldSymbolId = container.properties.linkedSymbolId;
|
|
||||||
|
|
||||||
if (isStyle) {
|
|
||||||
(container.properties.style as any)[key] = value;
|
|
||||||
} else {
|
|
||||||
(container.properties as any)[key] = value;
|
|
||||||
}
|
|
||||||
|
|
||||||
LinkSymbol(
|
|
||||||
container.properties.id,
|
|
||||||
oldSymbolId,
|
|
||||||
container.properties.linkedSymbolId,
|
|
||||||
current.Symbols
|
|
||||||
);
|
|
||||||
|
|
||||||
ApplyBehaviors(container, current.Symbols);
|
|
||||||
|
|
||||||
history.push({
|
|
||||||
LastAction: `Change ${key} of ${container.properties.id}`,
|
|
||||||
MainContainer: mainContainerClone,
|
|
||||||
SelectedContainerId: container.properties.id,
|
|
||||||
TypeCounters: Object.assign({}, current.TypeCounters),
|
|
||||||
Symbols: structuredClone(current.Symbols),
|
|
||||||
SelectedSymbolId: current.SelectedSymbolId
|
|
||||||
});
|
|
||||||
setHistory(history);
|
|
||||||
setHistoryCurrentStep(history.length - 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
function LinkSymbol(
|
|
||||||
containerId: string,
|
|
||||||
oldSymbolId: string,
|
|
||||||
newSymbolId: string,
|
|
||||||
symbols: Map<string, ISymbolModel>
|
|
||||||
): void {
|
|
||||||
const oldSymbol = symbols.get(oldSymbolId);
|
|
||||||
const newSymbol = symbols.get(newSymbolId);
|
|
||||||
|
|
||||||
if (newSymbol === undefined) {
|
|
||||||
if (oldSymbol !== undefined) {
|
|
||||||
oldSymbol.linkedContainers.delete(containerId);
|
|
||||||
}
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
newSymbol.linkedContainers.add(containerId);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Handled the property change event in the properties form
|
|
||||||
* @param key Property name
|
|
||||||
* @param properties Properties of the selected container
|
|
||||||
* @returns void
|
|
||||||
*/
|
|
||||||
export function OnPropertiesSubmit(
|
|
||||||
event: React.SyntheticEvent<HTMLFormElement>,
|
|
||||||
selected: IContainerModel | undefined,
|
|
||||||
fullHistory: IHistoryState[],
|
|
||||||
historyCurrentStep: number,
|
|
||||||
setHistory: Dispatch<SetStateAction<IHistoryState[]>>,
|
|
||||||
setHistoryCurrentStep: Dispatch<SetStateAction<number>>
|
|
||||||
): void {
|
|
||||||
event.preventDefault();
|
|
||||||
const history = getCurrentHistory(fullHistory, historyCurrentStep);
|
|
||||||
const current = history[history.length - 1];
|
|
||||||
|
|
||||||
if (selected === null ||
|
|
||||||
selected === undefined) {
|
|
||||||
throw new Error('[OnPropertyChange] Property was changed before selecting a Container');
|
|
||||||
}
|
|
||||||
|
|
||||||
const mainContainerClone: IContainerModel = structuredClone(current.MainContainer);
|
|
||||||
const container: ContainerModel | undefined = findContainerById(mainContainerClone, selected.properties.id);
|
|
||||||
|
|
||||||
if (container === null || container === undefined) {
|
|
||||||
throw new Error('[OnPropertyChange] Container model was not found among children of the main container!');
|
|
||||||
}
|
|
||||||
|
|
||||||
// Assign container properties
|
|
||||||
const form: HTMLFormElement = event.target as HTMLFormElement;
|
|
||||||
for (const property in container.properties) {
|
|
||||||
const input: HTMLInputElement | HTMLDivElement | null = form.querySelector(`#${property}`);
|
|
||||||
|
|
||||||
if (input === null) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (input instanceof HTMLInputElement) {
|
|
||||||
submitHTMLInput(input, container, property, form);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (input instanceof HTMLDivElement) {
|
|
||||||
submitRadioButtons(input, container, property);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Assign cssproperties
|
|
||||||
for (const styleProperty in container.properties.style) {
|
|
||||||
submitCSSForm(form, styleProperty, container);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Apply the behaviors
|
|
||||||
ApplyBehaviors(container, current.Symbols);
|
|
||||||
|
|
||||||
history.push({
|
|
||||||
LastAction: `Change properties of ${container.properties.id}`,
|
|
||||||
MainContainer: mainContainerClone,
|
|
||||||
SelectedContainerId: container.properties.id,
|
|
||||||
TypeCounters: Object.assign({}, current.TypeCounters),
|
|
||||||
Symbols: structuredClone(current.Symbols),
|
|
||||||
SelectedSymbolId: current.SelectedSymbolId
|
|
||||||
});
|
|
||||||
setHistory(history);
|
|
||||||
setHistoryCurrentStep(history.length - 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
const submitHTMLInput = (
|
|
||||||
input: HTMLInputElement,
|
|
||||||
container: IContainerModel,
|
|
||||||
property: string,
|
|
||||||
form: HTMLFormElement
|
|
||||||
): void => {
|
|
||||||
if (input.type !== 'number') {
|
|
||||||
(container.properties as any)[property] = input.value;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (property === 'x') {
|
|
||||||
// Hardcoded fix for XPositionReference
|
|
||||||
const x = RestoreX(form, input);
|
|
||||||
(container.properties as any)[property] = x;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
(container.properties as any)[property] = Number(input.value);
|
|
||||||
};
|
|
||||||
|
|
||||||
const submitCSSForm = (form: HTMLFormElement, styleProperty: string, container: ContainerModel): void => {
|
|
||||||
const input: HTMLInputElement | null = form.querySelector(`#${styleProperty}`);
|
|
||||||
if (input === null) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
(container.properties.style as any)[styleProperty] = input.value;
|
|
||||||
};
|
|
||||||
|
|
||||||
const RestoreX = (
|
|
||||||
form: HTMLFormElement,
|
|
||||||
input: HTMLInputElement
|
|
||||||
): number => {
|
|
||||||
const inputWidth: HTMLInputElement | null = form.querySelector('#width');
|
|
||||||
const inputRadio: HTMLDivElement | null = form.querySelector('#XPositionReference');
|
|
||||||
if (inputWidth === null || inputRadio === null) {
|
|
||||||
throw new Error('[OnPropertiesSubmit] Missing inputs for width or XPositionReference');
|
|
||||||
}
|
|
||||||
|
|
||||||
const radiobutton: HTMLInputElement | null = inputRadio.querySelector('input[name="XPositionReference"]:checked');
|
|
||||||
if (radiobutton === null) {
|
|
||||||
throw new Error('[OnPropertiesSubmit] Missing inputs for XPositionReference');
|
|
||||||
}
|
|
||||||
|
|
||||||
return restoreX(Number(input.value), Number(inputWidth.value), Number(radiobutton.value));
|
|
||||||
};
|
|
||||||
|
|
||||||
const submitRadioButtons = (
|
|
||||||
div: HTMLDivElement,
|
|
||||||
container: IContainerModel,
|
|
||||||
property: string
|
|
||||||
): void => {
|
|
||||||
const radiobutton: HTMLInputElement | null = div.querySelector(`input[name="${property}"]:checked`);
|
|
||||||
if (radiobutton === null) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (radiobutton.type === 'radio') {
|
|
||||||
(container.properties as any)[property] = Number(radiobutton.value);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
(container.properties as any)[property] = radiobutton.value;
|
|
||||||
};
|
|
||||||
|
|
|
@ -33,7 +33,6 @@ describe.concurrent('Elements sidebar', () => {
|
||||||
isHistoryOpen={false}
|
isHistoryOpen={false}
|
||||||
SelectedContainer={undefined}
|
SelectedContainer={undefined}
|
||||||
OnPropertyChange={() => {}}
|
OnPropertyChange={() => {}}
|
||||||
OnPropertiesSubmit={() => {}}
|
|
||||||
SelectContainer={() => {}}
|
SelectContainer={() => {}}
|
||||||
DeleteContainer={() => {}}
|
DeleteContainer={() => {}}
|
||||||
AddContainer={() => {}}
|
AddContainer={() => {}}
|
||||||
|
@ -72,7 +71,6 @@ describe.concurrent('Elements sidebar', () => {
|
||||||
isHistoryOpen={false}
|
isHistoryOpen={false}
|
||||||
SelectedContainer={MainContainer}
|
SelectedContainer={MainContainer}
|
||||||
OnPropertyChange={() => {}}
|
OnPropertyChange={() => {}}
|
||||||
OnPropertiesSubmit={() => {}}
|
|
||||||
SelectContainer={() => {}}
|
SelectContainer={() => {}}
|
||||||
DeleteContainer={() => {}}
|
DeleteContainer={() => {}}
|
||||||
AddContainer={() => {}}
|
AddContainer={() => {}}
|
||||||
|
@ -178,7 +176,6 @@ describe.concurrent('Elements sidebar', () => {
|
||||||
isHistoryOpen={false}
|
isHistoryOpen={false}
|
||||||
SelectedContainer={MainContainer}
|
SelectedContainer={MainContainer}
|
||||||
OnPropertyChange={() => {}}
|
OnPropertyChange={() => {}}
|
||||||
OnPropertiesSubmit={() => {}}
|
|
||||||
SelectContainer={() => {}}
|
SelectContainer={() => {}}
|
||||||
DeleteContainer={() => {}}
|
DeleteContainer={() => {}}
|
||||||
AddContainer={() => {}}
|
AddContainer={() => {}}
|
||||||
|
@ -246,7 +243,6 @@ describe.concurrent('Elements sidebar', () => {
|
||||||
isHistoryOpen={false}
|
isHistoryOpen={false}
|
||||||
SelectedContainer={SelectedContainer}
|
SelectedContainer={SelectedContainer}
|
||||||
OnPropertyChange={() => {}}
|
OnPropertyChange={() => {}}
|
||||||
OnPropertiesSubmit={() => {}}
|
|
||||||
SelectContainer={selectContainer}
|
SelectContainer={selectContainer}
|
||||||
DeleteContainer={() => {}}
|
DeleteContainer={() => {}}
|
||||||
AddContainer={() => {}}
|
AddContainer={() => {}}
|
||||||
|
@ -271,7 +267,6 @@ describe.concurrent('Elements sidebar', () => {
|
||||||
isHistoryOpen={false}
|
isHistoryOpen={false}
|
||||||
SelectedContainer={SelectedContainer}
|
SelectedContainer={SelectedContainer}
|
||||||
OnPropertyChange={() => {}}
|
OnPropertyChange={() => {}}
|
||||||
OnPropertiesSubmit={() => {}}
|
|
||||||
SelectContainer={selectContainer}
|
SelectContainer={selectContainer}
|
||||||
DeleteContainer={() => {}}
|
DeleteContainer={() => {}}
|
||||||
AddContainer={() => {}}
|
AddContainer={() => {}}
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
import * as React from 'react';
|
import * as React from 'react';
|
||||||
import { FixedSizeList as List } from 'react-window';
|
import { FixedSizeList as List } from 'react-window';
|
||||||
import { Properties } from '../Properties/Properties';
|
import { Properties } from '../ContainerProperties/ContainerProperties';
|
||||||
import { IContainerModel } from '../../Interfaces/IContainerModel';
|
import { IContainerModel } from '../../Interfaces/IContainerModel';
|
||||||
import { getDepth, MakeIterator } from '../../utils/itertools';
|
import { getDepth, MakeIterator } from '../../utils/itertools';
|
||||||
import { Menu } from '../Menu/Menu';
|
import { Menu } from '../Menu/Menu';
|
||||||
|
@ -16,7 +16,6 @@ interface IElementsSidebarProps {
|
||||||
isHistoryOpen: boolean
|
isHistoryOpen: boolean
|
||||||
SelectedContainer: IContainerModel | undefined
|
SelectedContainer: IContainerModel | undefined
|
||||||
OnPropertyChange: (key: string, value: string | number | boolean, isStyle?: boolean) => void
|
OnPropertyChange: (key: string, value: string | number | boolean, isStyle?: boolean) => void
|
||||||
OnPropertiesSubmit: (event: React.FormEvent<HTMLFormElement>) => void
|
|
||||||
SelectContainer: (containerId: string) => void
|
SelectContainer: (containerId: string) => void
|
||||||
DeleteContainer: (containerid: string) => void
|
DeleteContainer: (containerid: string) => void
|
||||||
AddContainer: (index: number, type: string, parent: string) => void
|
AddContainer: (index: number, type: string, parent: string) => void
|
||||||
|
@ -144,7 +143,6 @@ export const ElementsSidebar: React.FC<IElementsSidebarProps> = (props: IElement
|
||||||
properties={props.SelectedContainer?.properties}
|
properties={props.SelectedContainer?.properties}
|
||||||
symbols={props.symbols}
|
symbols={props.symbols}
|
||||||
onChange={props.OnPropertyChange}
|
onChange={props.OnPropertyChange}
|
||||||
onSubmit={props.OnPropertiesSubmit}
|
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
|
|
@ -1,27 +0,0 @@
|
||||||
import * as React from 'react';
|
|
||||||
import IContainerProperties from '../../Interfaces/IContainerProperties';
|
|
||||||
import { ISymbolModel } from '../../Interfaces/ISymbolModel';
|
|
||||||
import DynamicForm from './DynamicForm';
|
|
||||||
import StaticForm from './StaticForm';
|
|
||||||
|
|
||||||
interface IFormProps {
|
|
||||||
properties: IContainerProperties
|
|
||||||
symbols: Map<string, ISymbolModel>
|
|
||||||
isDynamicInput: boolean
|
|
||||||
onChange: (key: string, value: string | number | boolean, isStyle?: boolean) => void
|
|
||||||
onSubmit: (event: React.FormEvent<HTMLFormElement>) => void
|
|
||||||
}
|
|
||||||
|
|
||||||
export const Form: React.FunctionComponent<IFormProps> = (props) => {
|
|
||||||
if (props.isDynamicInput) {
|
|
||||||
return <DynamicForm
|
|
||||||
properties={props.properties}
|
|
||||||
symbols={props.symbols}
|
|
||||||
onChange={props.onChange}
|
|
||||||
/>;
|
|
||||||
}
|
|
||||||
return <StaticForm
|
|
||||||
properties={props.properties}
|
|
||||||
onSubmit={props.onSubmit}
|
|
||||||
/>;
|
|
||||||
};
|
|
|
@ -1,159 +0,0 @@
|
||||||
import { MenuAlt2Icon, MenuIcon, MenuAlt3Icon } from '@heroicons/react/outline';
|
|
||||||
import * as React from 'react';
|
|
||||||
import { XPositionReference } from '../../Enums/XPositionReference';
|
|
||||||
import IContainerProperties from '../../Interfaces/IContainerProperties';
|
|
||||||
import { transformX } from '../../utils/svg';
|
|
||||||
import { InputGroup } from '../InputGroup/InputGroup';
|
|
||||||
import { RadioGroupButtons } from '../RadioGroupButtons/RadioGroupButtons';
|
|
||||||
|
|
||||||
interface IStaticFormProps {
|
|
||||||
properties: IContainerProperties
|
|
||||||
onSubmit: (event: React.FormEvent<HTMLFormElement>) => void
|
|
||||||
}
|
|
||||||
|
|
||||||
const getCSSInputs = (properties: IContainerProperties): JSX.Element[] => {
|
|
||||||
const groupInput: JSX.Element[] = [];
|
|
||||||
for (const key in properties.style) {
|
|
||||||
groupInput.push(<InputGroup
|
|
||||||
key={key}
|
|
||||||
labelText={key}
|
|
||||||
inputKey={key}
|
|
||||||
labelClassName=''
|
|
||||||
inputClassName=''
|
|
||||||
type='string'
|
|
||||||
defaultValue={(properties.style as any)[key]}
|
|
||||||
/>);
|
|
||||||
}
|
|
||||||
return groupInput;
|
|
||||||
};
|
|
||||||
|
|
||||||
const StaticForm: React.FunctionComponent<IStaticFormProps> = (props) => {
|
|
||||||
return (<form
|
|
||||||
key={props.properties.id}
|
|
||||||
onSubmit={(event) => props.onSubmit(event)}
|
|
||||||
>
|
|
||||||
<input type='submit' className='normal-btn block mx-auto mb-4 border-2 border-blue-400 cursor-pointer' value='Submit'/>
|
|
||||||
<div className='grid grid-cols-2 gap-y-4'>
|
|
||||||
<InputGroup
|
|
||||||
labelText='Name'
|
|
||||||
inputKey='id'
|
|
||||||
labelClassName=''
|
|
||||||
inputClassName=''
|
|
||||||
type='string'
|
|
||||||
defaultValue={props.properties.id.toString()}
|
|
||||||
isDisabled={true}
|
|
||||||
/>
|
|
||||||
<InputGroup
|
|
||||||
labelText='Parent name'
|
|
||||||
inputKey='parentId'
|
|
||||||
labelClassName=''
|
|
||||||
inputClassName=''
|
|
||||||
type='string'
|
|
||||||
defaultValue={props.properties.parentId?.toString()}
|
|
||||||
isDisabled={true}
|
|
||||||
/>
|
|
||||||
<InputGroup
|
|
||||||
labelText='Displayed text'
|
|
||||||
inputKey='displayedText'
|
|
||||||
labelClassName=''
|
|
||||||
inputClassName=''
|
|
||||||
type='string'
|
|
||||||
defaultValue={props.properties.displayedText?.toString()}
|
|
||||||
/>
|
|
||||||
<InputGroup
|
|
||||||
labelText='x'
|
|
||||||
inputKey='x'
|
|
||||||
labelClassName=''
|
|
||||||
inputClassName=''
|
|
||||||
type='number'
|
|
||||||
defaultValue={transformX(props.properties.x, props.properties.width, props.properties.XPositionReference).toString()}
|
|
||||||
/>
|
|
||||||
<InputGroup
|
|
||||||
labelText='y'
|
|
||||||
inputKey='y'
|
|
||||||
labelClassName=''
|
|
||||||
inputClassName=''
|
|
||||||
type='number'
|
|
||||||
defaultValue={props.properties.y.toString()}
|
|
||||||
/>
|
|
||||||
<InputGroup
|
|
||||||
labelText='Minimum width'
|
|
||||||
inputKey='minWidth'
|
|
||||||
labelClassName=''
|
|
||||||
inputClassName=''
|
|
||||||
type='number'
|
|
||||||
min={0}
|
|
||||||
defaultValue={props.properties.minWidth.toString()}
|
|
||||||
/>
|
|
||||||
<InputGroup
|
|
||||||
labelText='Width'
|
|
||||||
inputKey='width'
|
|
||||||
labelClassName=''
|
|
||||||
inputClassName=''
|
|
||||||
type='number'
|
|
||||||
min={props.properties.minWidth}
|
|
||||||
defaultValue={props.properties.width.toString()}
|
|
||||||
/>
|
|
||||||
<InputGroup
|
|
||||||
labelText='Height'
|
|
||||||
inputKey='height'
|
|
||||||
labelClassName=''
|
|
||||||
inputClassName=''
|
|
||||||
type='number'
|
|
||||||
min={1}
|
|
||||||
defaultValue={props.properties.height.toString()}
|
|
||||||
/>
|
|
||||||
<InputGroup
|
|
||||||
labelText='Rigid'
|
|
||||||
inputKey='isRigidBody'
|
|
||||||
labelClassName=''
|
|
||||||
inputClassName=''
|
|
||||||
type='checkbox'
|
|
||||||
defaultChecked={props.properties.isRigidBody}
|
|
||||||
/>
|
|
||||||
<InputGroup
|
|
||||||
labelText='Anchor'
|
|
||||||
inputKey='isAnchor'
|
|
||||||
labelClassName=''
|
|
||||||
inputClassName=''
|
|
||||||
type='checkbox'
|
|
||||||
defaultChecked={props.properties.isAnchor}
|
|
||||||
/>
|
|
||||||
<RadioGroupButtons
|
|
||||||
name='XPositionReference'
|
|
||||||
defaultValue={props.properties.XPositionReference.toString()}
|
|
||||||
inputClassName='hidden'
|
|
||||||
labelText='Horizontal alignment'
|
|
||||||
inputGroups={[
|
|
||||||
{
|
|
||||||
text: (
|
|
||||||
<div title='Left' aria-label='left' className='radio-button-icon'>
|
|
||||||
<MenuAlt2Icon className='heroicon' />
|
|
||||||
</div>
|
|
||||||
),
|
|
||||||
value: XPositionReference.Left.toString()
|
|
||||||
},
|
|
||||||
{
|
|
||||||
text: (
|
|
||||||
<div title='Center' aria-label='center' className='radio-button-icon'>
|
|
||||||
<MenuIcon className='heroicon' />
|
|
||||||
</div>
|
|
||||||
),
|
|
||||||
value: XPositionReference.Center.toString()
|
|
||||||
},
|
|
||||||
{
|
|
||||||
text: (
|
|
||||||
<div title='Right' aria-label='right' className='radio-button-icon'>
|
|
||||||
<MenuAlt3Icon className='heroicon' />
|
|
||||||
</div>
|
|
||||||
),
|
|
||||||
value: XPositionReference.Right.toString()
|
|
||||||
}
|
|
||||||
]}
|
|
||||||
/>
|
|
||||||
{ getCSSInputs(props.properties) }
|
|
||||||
</div>
|
|
||||||
</form>);
|
|
||||||
};
|
|
||||||
|
|
||||||
export default StaticForm;
|
|
|
@ -1,17 +0,0 @@
|
||||||
import * as React from 'react';
|
|
||||||
import { ISymbolModel } from '../../Interfaces/ISymbolModel';
|
|
||||||
import DynamicForm from './DynamicForm';
|
|
||||||
|
|
||||||
interface IFormProps {
|
|
||||||
symbol: ISymbolModel
|
|
||||||
symbols: Map<string, ISymbolModel>
|
|
||||||
onChange: (key: string, value: string | number | boolean, isStyle?: boolean) => void
|
|
||||||
}
|
|
||||||
|
|
||||||
export const Form: React.FunctionComponent<IFormProps> = (props) => {
|
|
||||||
return <DynamicForm
|
|
||||||
symbol={props.symbol}
|
|
||||||
symbols={props.symbols}
|
|
||||||
onChange={props.onChange}
|
|
||||||
/>;
|
|
||||||
};
|
|
|
@ -3,12 +3,12 @@ import { ISymbolModel } from '../../Interfaces/ISymbolModel';
|
||||||
import { restoreX, transformX } from '../../utils/svg';
|
import { restoreX, transformX } from '../../utils/svg';
|
||||||
import { InputGroup } from '../InputGroup/InputGroup';
|
import { InputGroup } from '../InputGroup/InputGroup';
|
||||||
|
|
||||||
interface IDynamicFormProps {
|
interface ISymbolFormProps {
|
||||||
symbol: ISymbolModel
|
symbol: ISymbolModel
|
||||||
symbols: Map<string, ISymbolModel>
|
symbols: Map<string, ISymbolModel>
|
||||||
onChange: (key: string, value: string | number | boolean) => void
|
onChange: (key: string, value: string | number | boolean) => void
|
||||||
}
|
}
|
||||||
const DynamicForm: React.FunctionComponent<IDynamicFormProps> = (props) => {
|
const SymbolForm: React.FunctionComponent<ISymbolFormProps> = (props) => {
|
||||||
return (
|
return (
|
||||||
<div className='grid grid-cols-2 gap-y-4'>
|
<div className='grid grid-cols-2 gap-y-4'>
|
||||||
<InputGroup
|
<InputGroup
|
||||||
|
@ -53,4 +53,4 @@ const DynamicForm: React.FunctionComponent<IDynamicFormProps> = (props) => {
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
export default DynamicForm;
|
export default SymbolForm;
|
|
@ -1,8 +1,6 @@
|
||||||
import React, { useState } from 'react';
|
import React from 'react';
|
||||||
import IContainerProperties from '../../Interfaces/IContainerProperties';
|
|
||||||
import { ISymbolModel } from '../../Interfaces/ISymbolModel';
|
import { ISymbolModel } from '../../Interfaces/ISymbolModel';
|
||||||
import { ToggleButton } from '../ToggleButton/ToggleButton';
|
import SymbolForm from './SymbolForm';
|
||||||
import { Form } from './Form';
|
|
||||||
|
|
||||||
interface ISymbolPropertiesProps {
|
interface ISymbolPropertiesProps {
|
||||||
symbol?: ISymbolModel
|
symbol?: ISymbolModel
|
||||||
|
@ -17,7 +15,7 @@ export const SymbolProperties: React.FC<ISymbolPropertiesProps> = (props: ISymbo
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className='h-3/5 p-3 bg-slate-200 overflow-y-auto'>
|
<div className='h-3/5 p-3 bg-slate-200 overflow-y-auto'>
|
||||||
<Form
|
<SymbolForm
|
||||||
symbol={props.symbol}
|
symbol={props.symbol}
|
||||||
symbols={props.symbols}
|
symbols={props.symbols}
|
||||||
onChange={props.onChange}
|
onChange={props.onChange}
|
||||||
|
|
|
@ -22,7 +22,6 @@ interface IUIProps {
|
||||||
SelectContainer: (containerId: string) => void
|
SelectContainer: (containerId: string) => void
|
||||||
DeleteContainer: (containerId: string) => void
|
DeleteContainer: (containerId: string) => void
|
||||||
OnPropertyChange: (key: string, value: string | number | boolean, isStyle?: boolean) => void
|
OnPropertyChange: (key: string, value: string | number | boolean, isStyle?: boolean) => void
|
||||||
OnPropertiesSubmit: (event: React.FormEvent<HTMLFormElement>) => void
|
|
||||||
AddContainerToSelectedContainer: (type: string) => void
|
AddContainerToSelectedContainer: (type: string) => void
|
||||||
AddContainer: (index: number, type: string, parentId: string) => void
|
AddContainer: (index: number, type: string, parentId: string) => void
|
||||||
AddSymbol: (type: string) => void
|
AddSymbol: (type: string) => void
|
||||||
|
@ -90,7 +89,6 @@ export const UI: React.FunctionComponent<IUIProps> = (props: IUIProps) => {
|
||||||
isOpen={isSidebarOpen}
|
isOpen={isSidebarOpen}
|
||||||
isHistoryOpen={isHistoryOpen}
|
isHistoryOpen={isHistoryOpen}
|
||||||
OnPropertyChange={props.OnPropertyChange}
|
OnPropertyChange={props.OnPropertyChange}
|
||||||
OnPropertiesSubmit={props.OnPropertiesSubmit}
|
|
||||||
SelectContainer={props.SelectContainer}
|
SelectContainer={props.SelectContainer}
|
||||||
DeleteContainer={props.DeleteContainer}
|
DeleteContainer={props.DeleteContainer}
|
||||||
AddContainer={props.AddContainer}
|
AddContainer={props.AddContainer}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue