Big refactoring with properties + Implement Property

This commit is contained in:
Siklos 2022-08-01 16:16:31 +02:00
parent 43fb019e05
commit d2492520b4
5 changed files with 133 additions and 28 deletions

View file

@ -43,16 +43,16 @@ class App extends React.Component<IAppProps> {
const MainContainer = new Container( const MainContainer = new Container(
{ {
parent: null, parent: null,
id: 'main', properties: {
x: 0, id: 'main',
y: 0, x: 0,
width: configuration.MainContainer.Width, y: 0,
height: configuration.MainContainer.Height, width: configuration.MainContainer.Width,
children: [], height: configuration.MainContainer.Height,
style: {
fillOpacity: 0, fillOpacity: 0,
stroke: 'black' stroke: 'black'
} as React.CSSProperties },
children: []
} }
); );
this.setState(prevState => ({ this.setState(prevState => ({
@ -82,6 +82,46 @@ class App extends React.Component<IAppProps> {
} as IAppProps); } as IAppProps);
} }
public OnPropertyChange(key: string, value: string) {
if (this.state.SelectedContainer === null ||
this.state.SelectedContainer === undefined) {
throw new Error('Property was changed before selecting a Container');
}
if (this.state.MainContainer === null ||
this.state.MainContainer === undefined) {
throw new Error('Property was changed before the main container was added');
}
const pair = {} as Record<string, string>;
pair[key] = value;
const properties = Object.assign(this.state.SelectedContainer.props.properties, pair);
const props = {
...this.state.SelectedContainer.props,
properties
};
const newSelectedContainer = new Container(props);
const parent = this.state.SelectedContainer.props.parent;
if (parent === null) {
this.setState({
SelectedContainer: newSelectedContainer,
MainContainer: newSelectedContainer
});
return;
}
const index = parent.props.children.indexOf(this.state.SelectedContainer);
parent.props.children[index] = newSelectedContainer;
const newMainContainer = new Container(Object.assign({}, this.state.MainContainer.props));
this.setState({
SelectedContainer: newSelectedContainer,
MainContainer: newMainContainer
});
}
public AddContainer(type: string): void { public AddContainer(type: string): void {
if (this.state.SelectedContainer === null || if (this.state.SelectedContainer === null ||
this.state.SelectedContainer === undefined) { this.state.SelectedContainer === undefined) {
@ -111,13 +151,15 @@ class App extends React.Component<IAppProps> {
const count = newCounters[type]; const count = newCounters[type];
const container = new Container({ const container = new Container({
parent, parent,
id: `${type}-${count}`, properties: {
x: 0, id: `${type}-${count}`,
y: 0, x: 0,
width: properties?.Width, y: 0,
height: parent.props.height, width: properties?.Width,
height: parent.props.properties.height,
...properties.Style
},
children: [], children: [],
style: properties.Style,
userData: { userData: {
type type
} }
@ -148,6 +190,7 @@ class App extends React.Component<IAppProps> {
SelectedContainer={this.state.SelectedContainer} SelectedContainer={this.state.SelectedContainer}
isOpen={this.state.isSVGSidebarOpen} isOpen={this.state.isSVGSidebarOpen}
onClick={() => this.ToggleSVGSidebar()} onClick={() => this.ToggleSVGSidebar()}
onPropertyChange={(key: string, value: string) => this.OnPropertyChange(key, value)}
selectContainer={(container: Container) => this.SelectContainer(container)} selectContainer={(container: Container) => this.SelectContainer(container)}
/> />
<button className='fixed z-10 top-4 right-12 text-lg bg-slate-200 hover:bg-slate-300 transition-all drop-shadow-md hover:drop-shadow-lg py-2 px-3 rounded-lg' onClick={() => this.ToggleSVGSidebar()}>&#9776; Menu</button> <button className='fixed z-10 top-4 right-12 text-lg bg-slate-200 hover:bg-slate-300 transition-all drop-shadow-md hover:drop-shadow-lg py-2 px-3 rounded-lg' onClick={() => this.ToggleSVGSidebar()}>&#9776; Menu</button>

View file

@ -1,4 +1,5 @@
import * as React from 'react'; import * as React from 'react';
import { Properties } from '../Properties/Properties';
import { Container } from '../SVG/Elements/Container'; import { Container } from '../SVG/Elements/Container';
interface IElementsSidebarProps { interface IElementsSidebarProps {
@ -6,6 +7,7 @@ interface IElementsSidebarProps {
isOpen: boolean, isOpen: boolean,
SelectedContainer: Container | null, SelectedContainer: Container | null,
onClick: () => void, onClick: () => void,
onPropertyChange: (key: string, value: string) => void,
selectContainer: (container: Container) => void selectContainer: (container: Container) => void
} }
@ -39,10 +41,10 @@ export class ElementsSidebar extends React.Component<IElementsSidebarProps> {
const containerRows: React.ReactNode[] = []; const containerRows: React.ReactNode[] = [];
this.iterateChilds((container: Container) => { this.iterateChilds((container: Container) => {
const depth: number = Container.getDepth(container); const depth: number = Container.getDepth(container);
const key = container.props.id.toString(); const key = container.props.properties.id.toString();
const text = '|\t'.repeat(depth) + key; const text = '|\t'.repeat(depth) + key;
const selectedClass: string = this.props.SelectedContainer !== null && const selectedClass: string = this.props.SelectedContainer !== null &&
this.props.SelectedContainer.props.id === container.props.id this.props.SelectedContainer.props.properties.id === container.props.properties.id
? 'bg-blue-500 hover:bg-blue-600' ? 'bg-blue-500 hover:bg-blue-600'
: 'bg-slate-400 hover:bg-slate-600'; : 'bg-slate-400 hover:bg-slate-600';
containerRows.push( containerRows.push(
@ -53,7 +55,7 @@ export class ElementsSidebar extends React.Component<IElementsSidebarProps> {
}); });
return ( return (
<div className={`fixed bg-slate-400 text-white transition-all h-screen w-64 overflow-y-auto z-20 ${isOpenClasses}`}> <div className={`fixed flex flex-col bg-slate-400 text-white transition-all h-screen w-64 overflow-y-auto z-20 ${isOpenClasses}`}>
<button className='close-button hover:bg-slate-600 justify-start' onClick={this.props.onClick}> <button className='close-button hover:bg-slate-600 justify-start' onClick={this.props.onClick}>
&times; Close &times; Close
</button> </button>
@ -63,6 +65,7 @@ export class ElementsSidebar extends React.Component<IElementsSidebarProps> {
<div className='overflow-auto divide-y divide-solid divide-slate-500'> <div className='overflow-auto divide-y divide-solid divide-slate-500'>
{ containerRows } { containerRows }
</div> </div>
<Properties properties={this.props.SelectedContainer?.GetProperties()} onChange={this.props.onPropertyChange}></Properties>
</div> </div>
); );
} }

View file

@ -0,0 +1,48 @@
import * as React from 'react';
import ContainerProperties from '../../Interfaces/Properties';
interface IPropertiesProps {
properties?: ContainerProperties,
onChange: (key: string, value: string) => void
}
interface IPropertiesState {
hasUpdate: boolean
}
export class Properties extends React.Component<IPropertiesProps, IPropertiesState> {
public state: IPropertiesState;
constructor(props: IPropertiesProps) {
super(props);
this.state = {
hasUpdate: false
};
}
public render() {
if (this.props.properties === undefined) {
return <div></div>;
}
const groupInput: React.ReactNode[] = [];
Object.entries(this.props.properties).forEach((pair) => this.handleProperties(pair, groupInput));
return (
<div>
{ groupInput }
</div>
);
}
public handleProperties = ([key, value]: [string, string | number], groupInput: React.ReactNode[]) => {
const id = `property-${key}`;
const type = typeof value === 'number' ? 'number' : 'text';
groupInput.push(
<div key={id}>
<label className='' htmlFor={id}>{key}</label>
<input className='text-black' type={type} id={id} value={value} onChange={(event) => this.props.onChange(key, event.target.value)} />
</div>
);
};
}

View file

@ -1,16 +1,12 @@
import * as React from 'react'; import * as React from 'react';
import Properties from '../../../Interfaces/Properties';
interface IContainerProps { interface IContainerProps {
// eslint-disable-next-line no-use-before-define // eslint-disable-next-line no-use-before-define
parent: Container | null, parent: Container | null,
id: string,
// eslint-disable-next-line no-use-before-define // eslint-disable-next-line no-use-before-define
children: Container[], children: Container[],
x: number, properties: Properties,
y: number,
width: number,
height: number,
style?: React.CSSProperties,
userData?: Record<string, string | number> userData?: Record<string, string | number>
} }
@ -18,17 +14,25 @@ export class Container extends React.Component<IContainerProps> {
componentWillUnMount() { componentWillUnMount() {
} }
public GetProperties(): Properties {
const properties : Properties = {
...this.props.properties
};
return properties;
}
public render(): React.ReactNode { public render(): React.ReactNode {
const containersElements = this.props.children.map(child => child.render()); const containersElements = this.props.children.map(child => child.render());
const style = Object.assign({}, this.props.properties);
style.x = 0;
style.y = 0;
return ( return (
<g <g
transform={`translate(${this.props.x}, ${this.props.y})`} transform={`translate(${this.props.properties.x}, ${this.props.properties.y})`}
key={`container-${this.props.id}`} key={`container-${this.props.properties.id}`}
> >
<rect <rect
width={this.props.width} style={style}
height={this.props.height}
style={this.props.style}
> >
</rect> </rect>
{ containersElements } { containersElements }

View file

@ -0,0 +1,7 @@
import * as React from 'react';
export default interface Properties extends React.CSSProperties {
id: string,
x: number,
y: number,
}