Compare commits
No commits in common. "49a558589c94e5bf2bbbc02244fd63aab923497b" and "ddb483fff54bd332b0442aa26577c59d96b4b4c0" have entirely different histories.
49a558589c
...
ddb483fff5
7 changed files with 4 additions and 172 deletions
|
@ -3,8 +3,6 @@ import { motion } from 'framer-motion';
|
||||||
import { Properties } from '../Properties/Properties';
|
import { Properties } from '../Properties/Properties';
|
||||||
import { IContainerModel } from '../../Interfaces/ContainerModel';
|
import { IContainerModel } from '../../Interfaces/ContainerModel';
|
||||||
import { getDepth, MakeIterator } from '../../utils/itertools';
|
import { getDepth, MakeIterator } from '../../utils/itertools';
|
||||||
import { Menu } from '../Menu/Menu';
|
|
||||||
import { MenuItem } from '../Menu/MenuItem';
|
|
||||||
|
|
||||||
interface IElementsSidebarProps {
|
interface IElementsSidebarProps {
|
||||||
MainContainer: IContainerModel | null
|
MainContainer: IContainerModel | null
|
||||||
|
@ -13,77 +11,9 @@ interface IElementsSidebarProps {
|
||||||
SelectedContainer: IContainerModel | null
|
SelectedContainer: IContainerModel | null
|
||||||
onPropertyChange: (key: string, value: string) => void
|
onPropertyChange: (key: string, value: string) => void
|
||||||
selectContainer: (container: IContainerModel) => void
|
selectContainer: (container: IContainerModel) => void
|
||||||
deleteContainer: (containerid: string) => void
|
|
||||||
}
|
|
||||||
|
|
||||||
interface Point {
|
|
||||||
x: number
|
|
||||||
y: number
|
|
||||||
}
|
|
||||||
|
|
||||||
interface IElementsSidebarState {
|
|
||||||
isContextMenuOpen: boolean
|
|
||||||
contextMenuPosition: Point
|
|
||||||
onClickContainerId: string
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export class ElementsSidebar extends React.PureComponent<IElementsSidebarProps> {
|
export class ElementsSidebar extends React.PureComponent<IElementsSidebarProps> {
|
||||||
public state: IElementsSidebarState;
|
|
||||||
public elementRef: React.RefObject<HTMLDivElement>;
|
|
||||||
|
|
||||||
constructor(props: IElementsSidebarProps) {
|
|
||||||
super(props);
|
|
||||||
this.state = {
|
|
||||||
isContextMenuOpen: false,
|
|
||||||
contextMenuPosition: {
|
|
||||||
x: 0,
|
|
||||||
y: 0
|
|
||||||
},
|
|
||||||
onClickContainerId: ''
|
|
||||||
};
|
|
||||||
this.elementRef = React.createRef();
|
|
||||||
}
|
|
||||||
|
|
||||||
componentDidMount(): void {
|
|
||||||
this.elementRef.current?.addEventListener('contextmenu', (event) => this.handleRightClick(event));
|
|
||||||
window.addEventListener('click', (event) => this.handleLeftClick(event));
|
|
||||||
}
|
|
||||||
|
|
||||||
componentWillUnmount(): void {
|
|
||||||
this.elementRef.current?.removeEventListener('contextmenu', (event) => this.handleRightClick(event));
|
|
||||||
window.removeEventListener('click', (event) => this.handleLeftClick(event));
|
|
||||||
}
|
|
||||||
|
|
||||||
public handleRightClick(event: MouseEvent): void {
|
|
||||||
event.preventDefault();
|
|
||||||
|
|
||||||
if (!(event.target instanceof HTMLButtonElement)) {
|
|
||||||
this.setState({
|
|
||||||
isContextMenuOpen: false,
|
|
||||||
onClickContainerId: ''
|
|
||||||
});
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
const contextMenuPosition: Point = { x: event.pageX, y: event.pageY };
|
|
||||||
this.setState({
|
|
||||||
isContextMenuOpen: true,
|
|
||||||
contextMenuPosition,
|
|
||||||
onClickContainerId: event.target.id
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
public handleLeftClick(event: MouseEvent): void {
|
|
||||||
if (!this.state.isContextMenuOpen) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
this.setState({
|
|
||||||
isContextMenuOpen: false,
|
|
||||||
onClickContainerId: ''
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
public iterateChilds(handleContainer: (container: IContainerModel) => void): React.ReactNode {
|
public iterateChilds(handleContainer: (container: IContainerModel) => void): React.ReactNode {
|
||||||
if (this.props.MainContainer == null) {
|
if (this.props.MainContainer == null) {
|
||||||
return null;
|
return null;
|
||||||
|
@ -126,7 +56,6 @@ export class ElementsSidebar extends React.PureComponent<IElementsSidebarProps>
|
||||||
`w-full elements-sidebar-row whitespace-pre
|
`w-full elements-sidebar-row whitespace-pre
|
||||||
text-left text-sm font-medium transition-all ${selectedClass}`
|
text-left text-sm font-medium transition-all ${selectedClass}`
|
||||||
}
|
}
|
||||||
id={key}
|
|
||||||
key={key}
|
key={key}
|
||||||
onClick={() => this.props.selectContainer(container)}>
|
onClick={() => this.props.selectContainer(container)}>
|
||||||
{ text }
|
{ text }
|
||||||
|
@ -139,17 +68,9 @@ export class ElementsSidebar extends React.PureComponent<IElementsSidebarProps>
|
||||||
<div className='bg-slate-100 font-bold sidebar-title'>
|
<div className='bg-slate-100 font-bold sidebar-title'>
|
||||||
Elements
|
Elements
|
||||||
</div>
|
</div>
|
||||||
<div ref={this.elementRef} className='overflow-y-auto overflow-x-hidden text-gray-800 flex-grow'>
|
<div className='overflow-y-auto overflow-x-hidden text-gray-800 flex-grow'>
|
||||||
{ containerRows }
|
{ containerRows }
|
||||||
</div>
|
</div>
|
||||||
<Menu
|
|
||||||
className='transition-opacity rounded bg-slate-200 py-1 drop-shadow-xl'
|
|
||||||
x={this.state.contextMenuPosition.x}
|
|
||||||
y={this.state.contextMenuPosition.y}
|
|
||||||
isOpen={this.state.isContextMenuOpen}
|
|
||||||
>
|
|
||||||
<MenuItem className='contextmenu-item' text='Delete' onClick={() => this.props.deleteContainer(this.state.onClickContainerId)} />
|
|
||||||
</Menu>
|
|
||||||
<Properties properties={this.props.SelectedContainer?.properties} onChange={this.props.onPropertyChange}></Properties>
|
<Properties properties={this.props.SelectedContainer?.properties} onChange={this.props.onPropertyChange}></Properties>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
|
|
@ -1,23 +0,0 @@
|
||||||
import * as React from 'react';
|
|
||||||
|
|
||||||
interface IMenuProps {
|
|
||||||
className?: string
|
|
||||||
x: number
|
|
||||||
y: number
|
|
||||||
isOpen: boolean
|
|
||||||
children: React.ReactNode[] | React.ReactNode
|
|
||||||
}
|
|
||||||
|
|
||||||
export const Menu: React.FC<IMenuProps> = (props) => {
|
|
||||||
const visible = props.isOpen ? 'visible opacity-1' : 'invisible opacity-0';
|
|
||||||
return (
|
|
||||||
<div
|
|
||||||
className={`fixed ${props.className ?? ''} ${visible}`}
|
|
||||||
style={{
|
|
||||||
left: props.x,
|
|
||||||
top: props.y
|
|
||||||
}}>
|
|
||||||
{ props.children }
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
};
|
|
|
@ -1,16 +0,0 @@
|
||||||
import * as React from 'react';
|
|
||||||
|
|
||||||
interface IMenuItemProps {
|
|
||||||
className?: string
|
|
||||||
text: string
|
|
||||||
onClick: () => void
|
|
||||||
}
|
|
||||||
|
|
||||||
export const MenuItem: React.FC<IMenuItemProps> = (props) => {
|
|
||||||
return (
|
|
||||||
<button
|
|
||||||
className={props.className}
|
|
||||||
onClick={() => props.onClick()}>{props.text}
|
|
||||||
</button>
|
|
||||||
);
|
|
||||||
};
|
|
|
@ -15,7 +15,6 @@ interface IUIProps {
|
||||||
historyCurrentStep: number
|
historyCurrentStep: number
|
||||||
AvailableContainers: AvailableContainer[]
|
AvailableContainers: AvailableContainer[]
|
||||||
SelectContainer: (container: ContainerModel) => void
|
SelectContainer: (container: ContainerModel) => void
|
||||||
DeleteContainer: (containerId: string) => void
|
|
||||||
OnPropertyChange: (key: string, value: string) => void
|
OnPropertyChange: (key: string, value: string) => void
|
||||||
AddContainer: (type: string) => void
|
AddContainer: (type: string) => void
|
||||||
SaveEditorAsJSON: () => void
|
SaveEditorAsJSON: () => void
|
||||||
|
@ -98,7 +97,6 @@ export class UI extends React.PureComponent<IUIProps, IUIState> {
|
||||||
isHistoryOpen={this.state.isHistoryOpen}
|
isHistoryOpen={this.state.isHistoryOpen}
|
||||||
onPropertyChange={this.props.OnPropertyChange}
|
onPropertyChange={this.props.OnPropertyChange}
|
||||||
selectContainer={this.props.SelectContainer}
|
selectContainer={this.props.SelectContainer}
|
||||||
deleteContainer={this.props.DeleteContainer}
|
|
||||||
/>
|
/>
|
||||||
<History
|
<History
|
||||||
history={this.props.history}
|
history={this.props.history}
|
||||||
|
|
|
@ -91,49 +91,6 @@ class Editor extends React.Component<IEditorProps> {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
public DeleteContainer(containerId: string): void {
|
|
||||||
const history = this.getCurrentHistory();
|
|
||||||
const current = history[this.state.historyCurrentStep];
|
|
||||||
|
|
||||||
if (current.MainContainer === null) {
|
|
||||||
throw new Error('[DeleteContainer] Error: Tried to delete a container without a main container');
|
|
||||||
}
|
|
||||||
|
|
||||||
const mainContainerClone: IContainerModel = structuredClone(current.MainContainer);
|
|
||||||
const container = findContainerById(mainContainerClone, containerId);
|
|
||||||
|
|
||||||
if (container === undefined) {
|
|
||||||
throw new Error(`[DeleteContainer] Tried to delete a container that is not present in the main container: ${containerId}`);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (container === mainContainerClone) {
|
|
||||||
// TODO: Implement alert
|
|
||||||
throw new Error('[DeleteContainer] Tried to delete the main container! Deleting the main container is not allowed !');
|
|
||||||
}
|
|
||||||
|
|
||||||
if (container === null || container === undefined) {
|
|
||||||
throw new Error('[OnPropertyChange] Container model was not found among children of the main container!');
|
|
||||||
}
|
|
||||||
|
|
||||||
if (container.parent != null) {
|
|
||||||
const index = container.parent.children.indexOf(container);
|
|
||||||
if (index > -1) {
|
|
||||||
container.parent.children.splice(index, 1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
this.setState(
|
|
||||||
{
|
|
||||||
history: history.concat([{
|
|
||||||
SelectedContainer: null,
|
|
||||||
SelectedContainerId: '',
|
|
||||||
MainContainer: mainContainerClone,
|
|
||||||
TypeCounters: Object.assign({}, current.TypeCounters)
|
|
||||||
}]),
|
|
||||||
historyCurrentStep: history.length
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Handled the property change event in the properties form
|
* Handled the property change event in the properties form
|
||||||
* @param key Property name
|
* @param key Property name
|
||||||
|
@ -329,7 +286,6 @@ class Editor extends React.Component<IEditorProps> {
|
||||||
historyCurrentStep={this.state.historyCurrentStep}
|
historyCurrentStep={this.state.historyCurrentStep}
|
||||||
AvailableContainers={this.state.configuration.AvailableContainers}
|
AvailableContainers={this.state.configuration.AvailableContainers}
|
||||||
SelectContainer={(container) => this.SelectContainer(container)}
|
SelectContainer={(container) => this.SelectContainer(container)}
|
||||||
DeleteContainer={(containerId: string) => this.DeleteContainer(containerId)}
|
|
||||||
OnPropertyChange={(key, value) => this.OnPropertyChange(key, value)}
|
OnPropertyChange={(key, value) => this.OnPropertyChange(key, value)}
|
||||||
AddContainer={(type) => this.AddContainer(type)}
|
AddContainer={(type) => this.AddContainer(type)}
|
||||||
SaveEditorAsJSON={() => this.SaveEditorAsJSON()}
|
SaveEditorAsJSON={() => this.SaveEditorAsJSON()}
|
||||||
|
|
|
@ -44,8 +44,4 @@
|
||||||
text-xs font-bold
|
text-xs font-bold
|
||||||
transition-all duration-100 scale-0 origin-left;
|
transition-all duration-100 scale-0 origin-left;
|
||||||
}
|
}
|
||||||
|
|
||||||
.contextmenu-item {
|
|
||||||
@apply px-2 py-1 hover:bg-slate-300 text-left
|
|
||||||
}
|
|
||||||
}
|
}
|
|
@ -11,14 +11,14 @@ export function * MakeIterator(root: IContainerModel): Generator<IContainerModel
|
||||||
|
|
||||||
yield container;
|
yield container;
|
||||||
|
|
||||||
for (let i = container.children.length - 1; i >= 0; i--) {
|
// if this reverse() gets costly, replace it by a simple for
|
||||||
const child = container.children[i];
|
container.children.forEach((child) => {
|
||||||
if (visited.has(child)) {
|
if (visited.has(child)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
visited.add(child);
|
visited.add(child);
|
||||||
queue.push(child);
|
queue.push(child);
|
||||||
}
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue