Compare commits
No commits in common. "7c16d6c97dd63a06e9ec08056daddc348d7b4c59" and "170800a1c70ea6d83c4bee1a5317b640057685ee" have entirely different histories.
7c16d6c97d
...
170800a1c7
21 changed files with 96 additions and 803 deletions
|
@ -17,7 +17,6 @@ module.exports = {
|
||||||
project: './tsconfig.json'
|
project: './tsconfig.json'
|
||||||
},
|
},
|
||||||
plugins: [
|
plugins: [
|
||||||
'only-warn',
|
|
||||||
'react',
|
'react',
|
||||||
'@typescript-eslint'
|
'@typescript-eslint'
|
||||||
],
|
],
|
||||||
|
|
|
@ -37,7 +37,6 @@
|
||||||
"eslint-config-standard-with-typescript": "^22.0.0",
|
"eslint-config-standard-with-typescript": "^22.0.0",
|
||||||
"eslint-plugin-import": "^2.26.0",
|
"eslint-plugin-import": "^2.26.0",
|
||||||
"eslint-plugin-n": "^15.2.4",
|
"eslint-plugin-n": "^15.2.4",
|
||||||
"eslint-plugin-only-warn": "^1.0.3",
|
|
||||||
"eslint-plugin-promise": "^6.0.0",
|
"eslint-plugin-promise": "^6.0.0",
|
||||||
"eslint-plugin-react": "^7.30.1",
|
"eslint-plugin-react": "^7.30.1",
|
||||||
"jsdom": "^20.0.0",
|
"jsdom": "^20.0.0",
|
||||||
|
|
7
pnpm-lock.yaml
generated
7
pnpm-lock.yaml
generated
|
@ -19,7 +19,6 @@ specifiers:
|
||||||
eslint-config-standard-with-typescript: ^22.0.0
|
eslint-config-standard-with-typescript: ^22.0.0
|
||||||
eslint-plugin-import: ^2.26.0
|
eslint-plugin-import: ^2.26.0
|
||||||
eslint-plugin-n: ^15.2.4
|
eslint-plugin-n: ^15.2.4
|
||||||
eslint-plugin-only-warn: ^1.0.3
|
|
||||||
eslint-plugin-promise: ^6.0.0
|
eslint-plugin-promise: ^6.0.0
|
||||||
eslint-plugin-react: ^7.30.1
|
eslint-plugin-react: ^7.30.1
|
||||||
framer-motion: ^6.5.1
|
framer-motion: ^6.5.1
|
||||||
|
@ -59,7 +58,6 @@ devDependencies:
|
||||||
eslint-config-standard-with-typescript: 22.0.0_mfupvx5msz6are6ggwiepter3m
|
eslint-config-standard-with-typescript: 22.0.0_mfupvx5msz6are6ggwiepter3m
|
||||||
eslint-plugin-import: 2.26.0_wuikv5nqgdfyng42xxm7lklfmi
|
eslint-plugin-import: 2.26.0_wuikv5nqgdfyng42xxm7lklfmi
|
||||||
eslint-plugin-n: 15.2.4_eslint@8.21.0
|
eslint-plugin-n: 15.2.4_eslint@8.21.0
|
||||||
eslint-plugin-only-warn: 1.0.3
|
|
||||||
eslint-plugin-promise: 6.0.0_eslint@8.21.0
|
eslint-plugin-promise: 6.0.0_eslint@8.21.0
|
||||||
eslint-plugin-react: 7.30.1_eslint@8.21.0
|
eslint-plugin-react: 7.30.1_eslint@8.21.0
|
||||||
jsdom: 20.0.0
|
jsdom: 20.0.0
|
||||||
|
@ -1726,11 +1724,6 @@ packages:
|
||||||
semver: 7.3.7
|
semver: 7.3.7
|
||||||
dev: true
|
dev: true
|
||||||
|
|
||||||
/eslint-plugin-only-warn/1.0.3:
|
|
||||||
resolution: {integrity: sha512-XQOX/TfLoLw6h8ky51d29uUjXRTQHqBGXPylDEmy5fe/w7LIOnp8MA24b1OSMEn9BQoKow1q3g1kLe5/9uBTvw==}
|
|
||||||
engines: {node: '>=6'}
|
|
||||||
dev: true
|
|
||||||
|
|
||||||
/eslint-plugin-promise/6.0.0_eslint@8.21.0:
|
/eslint-plugin-promise/6.0.0_eslint@8.21.0:
|
||||||
resolution: {integrity: sha512-7GPezalm5Bfi/E22PnQxDWH2iW9GTvAlUNTztemeHb6c1BniSyoeTrM87JkC0wYdi6aQrZX9p2qEiAno8aTcbw==}
|
resolution: {integrity: sha512-7GPezalm5Bfi/E22PnQxDWH2iW9GTvAlUNTztemeHb6c1BniSyoeTrM87JkC0wYdi6aQrZX9p2qEiAno8aTcbw==}
|
||||||
engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
|
engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
|
||||||
|
|
|
@ -23,7 +23,6 @@ export const App: React.FunctionComponent<IAppProps> = (props) => {
|
||||||
const [editorState, setEditorState] = useState<IEditorState>({
|
const [editorState, setEditorState] = useState<IEditorState>({
|
||||||
configuration: DEFAULT_CONFIG,
|
configuration: DEFAULT_CONFIG,
|
||||||
history: [{
|
history: [{
|
||||||
LastAction: '',
|
|
||||||
MainContainer: defaultMainContainer,
|
MainContainer: defaultMainContainer,
|
||||||
SelectedContainer: defaultMainContainer,
|
SelectedContainer: defaultMainContainer,
|
||||||
SelectedContainerId: defaultMainContainer.properties.id,
|
SelectedContainerId: defaultMainContainer.properties.id,
|
||||||
|
@ -41,7 +40,6 @@ export const App: React.FunctionComponent<IAppProps> = (props) => {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!isLoaded) {
|
|
||||||
fetch(state)
|
fetch(state)
|
||||||
.then(
|
.then(
|
||||||
async(response) => await response.json(),
|
async(response) => await response.json(),
|
||||||
|
@ -50,7 +48,6 @@ export const App: React.FunctionComponent<IAppProps> = (props) => {
|
||||||
.then((data: IEditorState) => {
|
.then((data: IEditorState) => {
|
||||||
LoadState(data, setEditorState, setLoaded);
|
LoadState(data, setEditorState, setLoaded);
|
||||||
}, (error) => { throw new Error(error); });
|
}, (error) => { throw new Error(error); });
|
||||||
}
|
|
||||||
});
|
});
|
||||||
|
|
||||||
if (isLoaded) {
|
if (isLoaded) {
|
||||||
|
|
|
@ -22,7 +22,6 @@ export function NewEditor(
|
||||||
y: 0,
|
y: 0,
|
||||||
width: configuration.MainContainer.Width,
|
width: configuration.MainContainer.Width,
|
||||||
height: configuration.MainContainer.Height,
|
height: configuration.MainContainer.Height,
|
||||||
isRigidBody: false,
|
|
||||||
fillOpacity: 0,
|
fillOpacity: 0,
|
||||||
stroke: 'black'
|
stroke: 'black'
|
||||||
}
|
}
|
||||||
|
@ -35,7 +34,6 @@ export function NewEditor(
|
||||||
history:
|
history:
|
||||||
[
|
[
|
||||||
{
|
{
|
||||||
LastAction: '',
|
|
||||||
MainContainer,
|
MainContainer,
|
||||||
SelectedContainer: MainContainer,
|
SelectedContainer: MainContainer,
|
||||||
SelectedContainerId: MainContainer.properties.id,
|
SelectedContainerId: MainContainer.properties.id,
|
||||||
|
|
|
@ -1,10 +1,9 @@
|
||||||
import { Dispatch, SetStateAction } from 'react';
|
import { Dispatch, SetStateAction } from 'react';
|
||||||
import { HistoryState } from '../../Interfaces/HistoryState';
|
import { HistoryState } from "../../Interfaces/HistoryState";
|
||||||
import { Configuration } from '../../Interfaces/Configuration';
|
import { Configuration } from '../../Interfaces/Configuration';
|
||||||
import { ContainerModel, IContainerModel } from '../../Interfaces/ContainerModel';
|
import { ContainerModel, IContainerModel } from '../../Interfaces/ContainerModel';
|
||||||
import { findContainerById } from '../../utils/itertools';
|
import { findContainerById } from '../../utils/itertools';
|
||||||
import { getCurrentHistory } from './Editor';
|
import { getCurrentHistory } from './Editor';
|
||||||
import { SizePointer } from '../../Interfaces/SizePointer';
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Select a container
|
* Select a container
|
||||||
|
@ -20,19 +19,22 @@ export function SelectContainer(
|
||||||
const history = getCurrentHistory(fullHistory, historyCurrentStep);
|
const history = getCurrentHistory(fullHistory, historyCurrentStep);
|
||||||
const current = history[history.length - 1];
|
const current = history[history.length - 1];
|
||||||
|
|
||||||
const mainContainerClone = structuredClone(current.MainContainer);
|
if (current.MainContainer === null) {
|
||||||
const selectedContainer = findContainerById(mainContainerClone, container.properties.id);
|
throw new Error('[SelectContainer] Tried to select a container while there is no main container!');
|
||||||
|
}
|
||||||
|
|
||||||
if (selectedContainer === undefined) {
|
const mainContainerClone = structuredClone(current.MainContainer);
|
||||||
|
const SelectedContainer = findContainerById(mainContainerClone, container.properties.id);
|
||||||
|
|
||||||
|
if (SelectedContainer === undefined) {
|
||||||
throw new Error('[SelectContainer] Cannot find container among children of main container!');
|
throw new Error('[SelectContainer] Cannot find container among children of main container!');
|
||||||
}
|
}
|
||||||
|
|
||||||
setHistory(history.concat([{
|
setHistory(history.concat([{
|
||||||
LastAction: `Select container ${selectedContainer.properties.id}`,
|
|
||||||
MainContainer: mainContainerClone,
|
MainContainer: mainContainerClone,
|
||||||
SelectedContainer: selectedContainer,
|
TypeCounters: Object.assign({}, current.TypeCounters),
|
||||||
SelectedContainerId: selectedContainer.properties.id,
|
SelectedContainer,
|
||||||
TypeCounters: Object.assign({}, current.TypeCounters)
|
SelectedContainerId: SelectedContainer.properties.id
|
||||||
}]));
|
}]));
|
||||||
setHistoryCurrentStep(history.length);
|
setHistoryCurrentStep(history.length);
|
||||||
}
|
}
|
||||||
|
@ -47,6 +49,10 @@ export function DeleteContainer(
|
||||||
const history = getCurrentHistory(fullHistory, historyCurrentStep);
|
const history = getCurrentHistory(fullHistory, historyCurrentStep);
|
||||||
const current = history[historyCurrentStep];
|
const current = history[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 mainContainerClone: IContainerModel = structuredClone(current.MainContainer);
|
||||||
const container = findContainerById(mainContainerClone, containerId);
|
const container = findContainerById(mainContainerClone, containerId);
|
||||||
|
|
||||||
|
@ -71,10 +77,9 @@ export function DeleteContainer(
|
||||||
}
|
}
|
||||||
|
|
||||||
setHistory(history.concat([{
|
setHistory(history.concat([{
|
||||||
LastAction: `Delete container ${containerId}`,
|
|
||||||
MainContainer: mainContainerClone,
|
|
||||||
SelectedContainer: null,
|
SelectedContainer: null,
|
||||||
SelectedContainerId: '',
|
SelectedContainerId: '',
|
||||||
|
MainContainer: mainContainerClone,
|
||||||
TypeCounters: Object.assign({}, current.TypeCounters)
|
TypeCounters: Object.assign({}, current.TypeCounters)
|
||||||
}]));
|
}]));
|
||||||
setHistoryCurrentStep(history.length);
|
setHistoryCurrentStep(history.length);
|
||||||
|
@ -163,7 +168,7 @@ export function AddContainer(
|
||||||
}
|
}
|
||||||
|
|
||||||
let x = 0;
|
let x = 0;
|
||||||
if (index > 0) {
|
if (index !== 0) {
|
||||||
const lastChild: IContainerModel | undefined = parentClone.children.at(index - 1);
|
const lastChild: IContainerModel | undefined = parentClone.children.at(index - 1);
|
||||||
if (lastChild !== undefined) {
|
if (lastChild !== undefined) {
|
||||||
x = lastChild.properties.x + Number(lastChild.properties.width);
|
x = lastChild.properties.x + Number(lastChild.properties.width);
|
||||||
|
@ -180,7 +185,6 @@ export function AddContainer(
|
||||||
y: 0,
|
y: 0,
|
||||||
width: properties?.Width,
|
width: properties?.Width,
|
||||||
height: parentClone.properties.height,
|
height: parentClone.properties.height,
|
||||||
isRigidBody: false,
|
|
||||||
...properties.Style
|
...properties.Style
|
||||||
},
|
},
|
||||||
[],
|
[],
|
||||||
|
@ -198,11 +202,10 @@ export function AddContainer(
|
||||||
|
|
||||||
// Update the state
|
// Update the state
|
||||||
setHistory(history.concat([{
|
setHistory(history.concat([{
|
||||||
LastAction: 'Add container',
|
|
||||||
MainContainer: clone,
|
MainContainer: clone,
|
||||||
|
TypeCounters: newCounters,
|
||||||
SelectedContainer: parentClone,
|
SelectedContainer: parentClone,
|
||||||
SelectedContainerId: parentClone.properties.id,
|
SelectedContainerId: parentClone.properties.id
|
||||||
TypeCounters: newCounters
|
|
||||||
}]));
|
}]));
|
||||||
setHistoryCurrentStep(history.length);
|
setHistoryCurrentStep(history.length);
|
||||||
}
|
}
|
||||||
|
@ -215,7 +218,7 @@ export function AddContainer(
|
||||||
*/
|
*/
|
||||||
export function OnPropertyChange(
|
export function OnPropertyChange(
|
||||||
key: string,
|
key: string,
|
||||||
value: string | number | boolean,
|
value: string | number,
|
||||||
fullHistory: HistoryState[],
|
fullHistory: HistoryState[],
|
||||||
historyCurrentStep: number,
|
historyCurrentStep: number,
|
||||||
setHistory: Dispatch<SetStateAction<HistoryState[]>>,
|
setHistory: Dispatch<SetStateAction<HistoryState[]>>,
|
||||||
|
@ -229,14 +232,18 @@ export function OnPropertyChange(
|
||||||
throw new Error('[OnPropertyChange] Property was changed before selecting a Container');
|
throw new Error('[OnPropertyChange] Property was changed before selecting a Container');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (current.MainContainer === null ||
|
||||||
|
current.MainContainer === undefined) {
|
||||||
|
throw new Error('[OnPropertyChange] Property was changed before the main container was added');
|
||||||
|
}
|
||||||
|
|
||||||
if (parent === null) {
|
if (parent === null) {
|
||||||
const selectedContainerClone: IContainerModel = structuredClone(current.SelectedContainer);
|
const selectedContainerClone: IContainerModel = structuredClone(current.SelectedContainer);
|
||||||
(selectedContainerClone.properties as any)[key] = value;
|
(selectedContainerClone.properties as any)[key] = value;
|
||||||
setHistory(history.concat([{
|
setHistory(history.concat([{
|
||||||
LastAction: 'Change property of main',
|
|
||||||
MainContainer: selectedContainerClone,
|
|
||||||
SelectedContainer: selectedContainerClone,
|
SelectedContainer: selectedContainerClone,
|
||||||
SelectedContainerId: selectedContainerClone.properties.id,
|
SelectedContainerId: selectedContainerClone.properties.id,
|
||||||
|
MainContainer: selectedContainerClone,
|
||||||
TypeCounters: Object.assign({}, current.TypeCounters)
|
TypeCounters: Object.assign({}, current.TypeCounters)
|
||||||
}]));
|
}]));
|
||||||
setHistoryCurrentStep(history.length);
|
setHistoryCurrentStep(history.length);
|
||||||
|
@ -252,223 +259,11 @@ export function OnPropertyChange(
|
||||||
|
|
||||||
(container.properties as any)[key] = value;
|
(container.properties as any)[key] = value;
|
||||||
|
|
||||||
if (container.properties.isRigidBody) {
|
|
||||||
RecalculatePhysics(container);
|
|
||||||
}
|
|
||||||
|
|
||||||
setHistory(history.concat([{
|
setHistory(history.concat([{
|
||||||
LastAction: `Change property of container ${container.properties.id}`,
|
|
||||||
MainContainer: mainContainerClone,
|
|
||||||
SelectedContainer: container,
|
SelectedContainer: container,
|
||||||
SelectedContainerId: container.properties.id,
|
SelectedContainerId: container.properties.id,
|
||||||
|
MainContainer: mainContainerClone,
|
||||||
TypeCounters: Object.assign({}, current.TypeCounters)
|
TypeCounters: Object.assign({}, current.TypeCounters)
|
||||||
}]));
|
}]));
|
||||||
setHistoryCurrentStep(history.length);
|
setHistoryCurrentStep(history.length);
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO put this in a different file
|
|
||||||
|
|
||||||
export function RecalculatePhysics(container: IContainerModel): IContainerModel {
|
|
||||||
container = constraintBodyInsideParent(container);
|
|
||||||
container = constraintBodyInsideUnallocatedWidth(container);
|
|
||||||
return container;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Limit a rect inside a parent rect by applying the following rules :
|
|
||||||
* it cannot be bigger than the parent
|
|
||||||
* it cannot go out of bound
|
|
||||||
* @param container
|
|
||||||
* @returns
|
|
||||||
*/
|
|
||||||
function constraintBodyInsideParent(container: IContainerModel): IContainerModel {
|
|
||||||
if (container.parent === null || container.parent === undefined) {
|
|
||||||
return container;
|
|
||||||
}
|
|
||||||
|
|
||||||
const parentProperties = container.parent.properties;
|
|
||||||
const parentWidth = Number(parentProperties.width);
|
|
||||||
const parentHeight = Number(parentProperties.height);
|
|
||||||
|
|
||||||
return constraintBodyInsideSpace(container, 0, 0, parentWidth, parentHeight);
|
|
||||||
}
|
|
||||||
|
|
||||||
function constraintBodyInsideSpace(
|
|
||||||
container: IContainerModel,
|
|
||||||
x: number,
|
|
||||||
y: number,
|
|
||||||
width: number,
|
|
||||||
height: number
|
|
||||||
): IContainerModel {
|
|
||||||
const containerProperties = container.properties;
|
|
||||||
const containerX = Number(containerProperties.x);
|
|
||||||
const containerY = Number(containerProperties.y);
|
|
||||||
const containerWidth = Number(containerProperties.width);
|
|
||||||
const containerHeight = Number(containerProperties.height);
|
|
||||||
|
|
||||||
// Check size bigger than parent
|
|
||||||
const isBodyLargerThanParent = containerWidth > width;
|
|
||||||
const isBodyTallerThanParentHeight = containerHeight > height;
|
|
||||||
if (isBodyLargerThanParent || isBodyTallerThanParentHeight) {
|
|
||||||
if (isBodyLargerThanParent) {
|
|
||||||
containerProperties.x = x;
|
|
||||||
containerProperties.width = width;
|
|
||||||
}
|
|
||||||
if (isBodyTallerThanParentHeight) {
|
|
||||||
containerProperties.y = y;
|
|
||||||
containerProperties.height = height;
|
|
||||||
}
|
|
||||||
return container;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Check horizontal out of bound
|
|
||||||
if (containerX < x) {
|
|
||||||
containerProperties.x = x;
|
|
||||||
}
|
|
||||||
if (containerX + containerWidth > width) {
|
|
||||||
containerProperties.x = x + width - containerWidth;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Check vertical out of bound
|
|
||||||
if (containerY < y) {
|
|
||||||
containerProperties.y = y;
|
|
||||||
}
|
|
||||||
if (containerY + containerHeight > height) {
|
|
||||||
containerProperties.y = y + height - containerHeight;
|
|
||||||
}
|
|
||||||
|
|
||||||
return container;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get the unallocated widths inside a container
|
|
||||||
* An allocated width is defined by its the widths of the children that are rigid bodies.
|
|
||||||
* An example of this allocation system is the disk space
|
|
||||||
* (except the fact that disk space is divided by block).
|
|
||||||
* @param container
|
|
||||||
* @returns {SizePointer[]} Array of unallocated widths (x=position of the unallocated space, width=size of the allocated space)
|
|
||||||
*/
|
|
||||||
function getAvailableWidths(container: IContainerModel, exception: IContainerModel): SizePointer[] {
|
|
||||||
const x = 0;
|
|
||||||
const width = Number(container.properties.width);
|
|
||||||
let unallocatedSpaces: SizePointer[] = [{ x, width }];
|
|
||||||
|
|
||||||
const rigidBodies = container.children.filter(child => child.properties.isRigidBody);
|
|
||||||
for (const child of rigidBodies) {
|
|
||||||
if (child === exception) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
// get the space of the child that is inside the parent
|
|
||||||
let newUnallocatedSpace: SizePointer[] = [];
|
|
||||||
for (const unallocatedSpace of unallocatedSpaces) {
|
|
||||||
const newUnallocatedWidths = getAvailableWidthsTwoLines(
|
|
||||||
unallocatedSpace.x,
|
|
||||||
unallocatedSpace.x + unallocatedSpace.width,
|
|
||||||
child.properties.x,
|
|
||||||
child.properties.x + Number(child.properties.width));
|
|
||||||
newUnallocatedSpace = newUnallocatedSpace.concat(newUnallocatedWidths);
|
|
||||||
}
|
|
||||||
unallocatedSpaces = newUnallocatedSpace;
|
|
||||||
}
|
|
||||||
|
|
||||||
return unallocatedSpaces;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns the unallocated widths between two lines in 1D
|
|
||||||
* @param min1 left of the first line
|
|
||||||
* @param max1 rigth of the first line
|
|
||||||
* @param min2 left of the second line
|
|
||||||
* @param max2 right of the second line
|
|
||||||
* @returns Available widths
|
|
||||||
*/
|
|
||||||
function getAvailableWidthsTwoLines(min1: number, max1: number, min2: number, max2: number): SizePointer[] {
|
|
||||||
if (min2 < min1 && max2 > max1) {
|
|
||||||
// object 2 is overlapping full width
|
|
||||||
return [];
|
|
||||||
}
|
|
||||||
|
|
||||||
if (min1 >= min2) {
|
|
||||||
// object 2 is partially overlapping on the left
|
|
||||||
return [{
|
|
||||||
x: max2,
|
|
||||||
width: max1 - max2
|
|
||||||
}];
|
|
||||||
}
|
|
||||||
|
|
||||||
if (max2 >= max1) {
|
|
||||||
// object 2 is partially overlapping on the right
|
|
||||||
return [{
|
|
||||||
x: min2,
|
|
||||||
width: max2 - min1
|
|
||||||
}];
|
|
||||||
}
|
|
||||||
|
|
||||||
// object 2 is overlapping in the middle
|
|
||||||
return [
|
|
||||||
{
|
|
||||||
x: min1,
|
|
||||||
width: min2 - min1
|
|
||||||
},
|
|
||||||
{
|
|
||||||
x: min2,
|
|
||||||
width: max1 - max2
|
|
||||||
}
|
|
||||||
];
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
*
|
|
||||||
* @param container
|
|
||||||
* @returns
|
|
||||||
*/
|
|
||||||
function constraintBodyInsideUnallocatedWidth(container: IContainerModel): IContainerModel {
|
|
||||||
if (container.parent === null) {
|
|
||||||
return container;
|
|
||||||
}
|
|
||||||
|
|
||||||
const availableWidths = getAvailableWidths(container.parent, container);
|
|
||||||
const containerX = Number(container.properties.x);
|
|
||||||
|
|
||||||
// Sort the available width
|
|
||||||
availableWidths
|
|
||||||
.sort((width1, width2) => Math.abs(width1.x - containerX) - Math.abs(width2.x - containerX));
|
|
||||||
|
|
||||||
if (availableWidths.length === 0) {
|
|
||||||
throw new Error('No available space found on the parent container. Try to free the parent a little before placing it inside.');
|
|
||||||
}
|
|
||||||
|
|
||||||
const availableWidthFound = availableWidths.find(
|
|
||||||
width => isFitting(container, width)
|
|
||||||
);
|
|
||||||
|
|
||||||
if (availableWidthFound === undefined) {
|
|
||||||
// There is two way to reach this part of the code
|
|
||||||
// 1) toggle the isRigidBody such as width > availableWidth.width
|
|
||||||
// 2) resize a container such as width > availableWidth.width
|
|
||||||
// We want the container to fit automatically inside the available space
|
|
||||||
// even if it means to resize the container
|
|
||||||
// The end goal is that the code never show the error message no matter what action is done
|
|
||||||
// TODO: Actually give an option to not fit and show the error message shown below
|
|
||||||
const availableWidth = availableWidths[0];
|
|
||||||
container.properties.x = availableWidth.x;
|
|
||||||
container.properties.width = availableWidth.width;
|
|
||||||
// throw new Error('[constraintBodyInsideUnallocatedWidth] BIGERR: No available space found on the parent container, even though there is some.');
|
|
||||||
return container;
|
|
||||||
}
|
|
||||||
|
|
||||||
return constraintBodyInsideSpace(
|
|
||||||
container,
|
|
||||||
availableWidthFound.x,
|
|
||||||
0,
|
|
||||||
availableWidthFound.width,
|
|
||||||
Number(container.parent.properties.height)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
function isFitting(container: IContainerModel, sizePointer: SizePointer): boolean {
|
|
||||||
const containerWidth = Number(container.properties.width);
|
|
||||||
|
|
||||||
return containerWidth <= sizePointer.width;
|
|
||||||
}
|
|
||||||
|
|
|
@ -24,21 +24,24 @@ export const getCurrentHistory = (history: HistoryState[], historyCurrentStep: n
|
||||||
export const getCurrentHistoryState = (history: HistoryState[], historyCurrentStep: number): HistoryState => history[historyCurrentStep];
|
export const getCurrentHistoryState = (history: HistoryState[], historyCurrentStep: number): HistoryState => history[historyCurrentStep];
|
||||||
|
|
||||||
const Editor: React.FunctionComponent<IEditorProps> = (props) => {
|
const Editor: React.FunctionComponent<IEditorProps> = (props) => {
|
||||||
const [history, setHistory] = React.useState<HistoryState[]>(structuredClone(props.history));
|
const [history, setHistory] = React.useState<HistoryState[]>([...props.history]);
|
||||||
const [historyCurrentStep, setHistoryCurrentStep] = React.useState<number>(props.historyCurrentStep);
|
const [historyCurrentStep, setHistoryCurrentStep] = React.useState<number>(0);
|
||||||
|
|
||||||
React.useEffect(() => {
|
React.useEffect(() => {
|
||||||
const onKeyUp = (event: KeyboardEvent): void => onKeyDown(
|
window.addEventListener('keyup', (event) => onKeyDown(
|
||||||
event,
|
event,
|
||||||
history,
|
history,
|
||||||
historyCurrentStep,
|
historyCurrentStep,
|
||||||
setHistoryCurrentStep
|
setHistoryCurrentStep
|
||||||
);
|
));
|
||||||
|
|
||||||
window.addEventListener('keyup', onKeyUp);
|
|
||||||
|
|
||||||
return () => {
|
return () => {
|
||||||
window.removeEventListener('keyup', onKeyUp);
|
window.removeEventListener('keyup', (event) => onKeyDown(
|
||||||
|
event,
|
||||||
|
history,
|
||||||
|
historyCurrentStep,
|
||||||
|
setHistoryCurrentStep
|
||||||
|
));
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
import { Dispatch, SetStateAction } from 'react';
|
import { Dispatch, SetStateAction } from 'react';
|
||||||
import { HistoryState } from '../../Interfaces/HistoryState';
|
import { HistoryState } from "../../Interfaces/HistoryState";
|
||||||
|
|
||||||
export function onKeyDown(
|
export function onKeyDown(
|
||||||
event: KeyboardEvent,
|
event: KeyboardEvent,
|
||||||
|
|
|
@ -16,15 +16,14 @@ describe.concurrent('Elements sidebar', () => {
|
||||||
x: 0,
|
x: 0,
|
||||||
y: 0,
|
y: 0,
|
||||||
width: 2000,
|
width: 2000,
|
||||||
height: 100,
|
height: 100
|
||||||
isRigidBody: false
|
|
||||||
},
|
},
|
||||||
userData: {}
|
userData: {}
|
||||||
}}
|
}}
|
||||||
isOpen={true}
|
isOpen={true}
|
||||||
isHistoryOpen={false}
|
isHistoryOpen={false}
|
||||||
SelectedContainer={null}
|
SelectedContainer={null}
|
||||||
OnPropertyChange={() => {}}
|
onPropertyChange={() => {}}
|
||||||
SelectContainer={() => {}}
|
SelectContainer={() => {}}
|
||||||
DeleteContainer={() => {}}
|
DeleteContainer={() => {}}
|
||||||
AddContainer={() => {}}
|
AddContainer={() => {}}
|
||||||
|
@ -45,8 +44,7 @@ describe.concurrent('Elements sidebar', () => {
|
||||||
x: 0,
|
x: 0,
|
||||||
y: 0,
|
y: 0,
|
||||||
width: 2000,
|
width: 2000,
|
||||||
height: 100,
|
height: 100
|
||||||
isRigidBody: false
|
|
||||||
},
|
},
|
||||||
userData: {}
|
userData: {}
|
||||||
};
|
};
|
||||||
|
@ -56,7 +54,7 @@ describe.concurrent('Elements sidebar', () => {
|
||||||
isOpen={true}
|
isOpen={true}
|
||||||
isHistoryOpen={false}
|
isHistoryOpen={false}
|
||||||
SelectedContainer={MainContainer}
|
SelectedContainer={MainContainer}
|
||||||
OnPropertyChange={() => {}}
|
onPropertyChange={() => {}}
|
||||||
SelectContainer={() => {}}
|
SelectContainer={() => {}}
|
||||||
DeleteContainer={() => {}}
|
DeleteContainer={() => {}}
|
||||||
AddContainer={() => {}}
|
AddContainer={() => {}}
|
||||||
|
@ -100,8 +98,7 @@ describe.concurrent('Elements sidebar', () => {
|
||||||
x: 0,
|
x: 0,
|
||||||
y: 0,
|
y: 0,
|
||||||
width: 2000,
|
width: 2000,
|
||||||
height: 100,
|
height: 100
|
||||||
isRigidBody: false
|
|
||||||
},
|
},
|
||||||
userData: {}
|
userData: {}
|
||||||
};
|
};
|
||||||
|
@ -116,8 +113,7 @@ describe.concurrent('Elements sidebar', () => {
|
||||||
x: 0,
|
x: 0,
|
||||||
y: 0,
|
y: 0,
|
||||||
width: 0,
|
width: 0,
|
||||||
height: 0,
|
height: 0
|
||||||
isRigidBody: false
|
|
||||||
},
|
},
|
||||||
userData: {}
|
userData: {}
|
||||||
}
|
}
|
||||||
|
@ -133,8 +129,7 @@ describe.concurrent('Elements sidebar', () => {
|
||||||
x: 0,
|
x: 0,
|
||||||
y: 0,
|
y: 0,
|
||||||
width: 0,
|
width: 0,
|
||||||
height: 0,
|
height: 0
|
||||||
isRigidBody: false
|
|
||||||
},
|
},
|
||||||
userData: {}
|
userData: {}
|
||||||
}
|
}
|
||||||
|
@ -145,7 +140,7 @@ describe.concurrent('Elements sidebar', () => {
|
||||||
isOpen={true}
|
isOpen={true}
|
||||||
isHistoryOpen={false}
|
isHistoryOpen={false}
|
||||||
SelectedContainer={MainContainer}
|
SelectedContainer={MainContainer}
|
||||||
OnPropertyChange={() => {}}
|
onPropertyChange={() => {}}
|
||||||
SelectContainer={() => {}}
|
SelectContainer={() => {}}
|
||||||
DeleteContainer={() => {}}
|
DeleteContainer={() => {}}
|
||||||
AddContainer={() => {}}
|
AddContainer={() => {}}
|
||||||
|
@ -169,8 +164,7 @@ describe.concurrent('Elements sidebar', () => {
|
||||||
x: 0,
|
x: 0,
|
||||||
y: 0,
|
y: 0,
|
||||||
width: 2000,
|
width: 2000,
|
||||||
height: 100,
|
height: 100
|
||||||
isRigidBody: false
|
|
||||||
},
|
},
|
||||||
userData: {}
|
userData: {}
|
||||||
};
|
};
|
||||||
|
@ -184,8 +178,7 @@ describe.concurrent('Elements sidebar', () => {
|
||||||
x: 0,
|
x: 0,
|
||||||
y: 0,
|
y: 0,
|
||||||
width: 0,
|
width: 0,
|
||||||
height: 0,
|
height: 0
|
||||||
isRigidBody: false
|
|
||||||
},
|
},
|
||||||
userData: {}
|
userData: {}
|
||||||
};
|
};
|
||||||
|
@ -201,7 +194,7 @@ describe.concurrent('Elements sidebar', () => {
|
||||||
isOpen={true}
|
isOpen={true}
|
||||||
isHistoryOpen={false}
|
isHistoryOpen={false}
|
||||||
SelectedContainer={SelectedContainer}
|
SelectedContainer={SelectedContainer}
|
||||||
OnPropertyChange={() => {}}
|
onPropertyChange={() => {}}
|
||||||
SelectContainer={selectContainer}
|
SelectContainer={selectContainer}
|
||||||
DeleteContainer={() => {}}
|
DeleteContainer={() => {}}
|
||||||
AddContainer={() => {}}
|
AddContainer={() => {}}
|
||||||
|
@ -224,7 +217,7 @@ describe.concurrent('Elements sidebar', () => {
|
||||||
isOpen={true}
|
isOpen={true}
|
||||||
isHistoryOpen={false}
|
isHistoryOpen={false}
|
||||||
SelectedContainer={SelectedContainer}
|
SelectedContainer={SelectedContainer}
|
||||||
OnPropertyChange={() => {}}
|
onPropertyChange={() => {}}
|
||||||
SelectContainer={selectContainer}
|
SelectContainer={selectContainer}
|
||||||
DeleteContainer={() => {}}
|
DeleteContainer={() => {}}
|
||||||
AddContainer={() => {}}
|
AddContainer={() => {}}
|
||||||
|
|
|
@ -13,7 +13,7 @@ interface IElementsSidebarProps {
|
||||||
isOpen: boolean
|
isOpen: boolean
|
||||||
isHistoryOpen: boolean
|
isHistoryOpen: boolean
|
||||||
SelectedContainer: IContainerModel | null
|
SelectedContainer: IContainerModel | null
|
||||||
OnPropertyChange: (key: string, value: string | number | boolean) => void
|
onPropertyChange: (key: string, value: string) => void
|
||||||
SelectContainer: (container: IContainerModel) => void
|
SelectContainer: (container: IContainerModel) => 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
|
||||||
|
@ -71,39 +71,40 @@ export const ElementsSidebar: React.FC<IElementsSidebarProps> = (props: IElement
|
||||||
|
|
||||||
// Event listeners
|
// Event listeners
|
||||||
React.useEffect(() => {
|
React.useEffect(() => {
|
||||||
const onContextMenu = (event: MouseEvent): void => handleRightClick(
|
elementRef.current?.addEventListener(
|
||||||
|
'contextmenu',
|
||||||
|
(event) => handleRightClick(
|
||||||
event,
|
event,
|
||||||
setIsContextMenuOpen,
|
setIsContextMenuOpen,
|
||||||
setOnClickContainerId,
|
setOnClickContainerId,
|
||||||
setContextMenuPosition
|
setContextMenuPosition
|
||||||
);
|
));
|
||||||
|
|
||||||
const onLeftClick = (): void => handleLeftClick(
|
|
||||||
isContextMenuOpen,
|
|
||||||
setIsContextMenuOpen,
|
|
||||||
setOnClickContainerId
|
|
||||||
);
|
|
||||||
|
|
||||||
elementRef.current?.addEventListener(
|
|
||||||
'contextmenu',
|
|
||||||
onContextMenu
|
|
||||||
);
|
|
||||||
|
|
||||||
window.addEventListener(
|
window.addEventListener(
|
||||||
'click',
|
'click',
|
||||||
onLeftClick
|
(event) => handleLeftClick(
|
||||||
);
|
isContextMenuOpen,
|
||||||
|
setIsContextMenuOpen,
|
||||||
|
setOnClickContainerId
|
||||||
|
));
|
||||||
|
|
||||||
return () => {
|
return () => {
|
||||||
elementRef.current?.removeEventListener(
|
elementRef.current?.addEventListener(
|
||||||
'contextmenu',
|
'contextmenu',
|
||||||
onContextMenu
|
(event) => handleRightClick(
|
||||||
);
|
event,
|
||||||
|
setIsContextMenuOpen,
|
||||||
|
setOnClickContainerId,
|
||||||
|
setContextMenuPosition
|
||||||
|
));
|
||||||
|
|
||||||
window.removeEventListener(
|
window.removeEventListener(
|
||||||
'click',
|
'click',
|
||||||
onLeftClick
|
(event) => handleLeftClick(
|
||||||
);
|
isContextMenuOpen,
|
||||||
|
setIsContextMenuOpen,
|
||||||
|
setOnClickContainerId
|
||||||
|
));
|
||||||
};
|
};
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
|
@ -140,12 +141,9 @@ export const ElementsSidebar: React.FC<IElementsSidebarProps> = (props: IElement
|
||||||
y={contextMenuPosition.y}
|
y={contextMenuPosition.y}
|
||||||
isOpen={isContextMenuOpen}
|
isOpen={isContextMenuOpen}
|
||||||
>
|
>
|
||||||
<MenuItem className='contextmenu-item' text='Delete' onClick={() => {
|
<MenuItem className='contextmenu-item' text='Delete' onClick={() => props.DeleteContainer(onClickContainerId)} />
|
||||||
setIsContextMenuOpen(false);
|
|
||||||
props.DeleteContainer(onClickContainerId);
|
|
||||||
}} />
|
|
||||||
</Menu>
|
</Menu>
|
||||||
<Properties properties={props.SelectedContainer?.properties} onChange={props.OnPropertyChange}></Properties>
|
<Properties properties={props.SelectedContainer?.properties} onChange={props.onPropertyChange}></Properties>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
|
@ -21,8 +21,7 @@ describe.concurrent('Properties', () => {
|
||||||
id: 'stuff',
|
id: 'stuff',
|
||||||
parentId: 'parentId',
|
parentId: 'parentId',
|
||||||
x: 1,
|
x: 1,
|
||||||
y: 1,
|
y: 1
|
||||||
isRigidBody: false
|
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleChange = vi.fn((key, value) => {
|
const handleChange = vi.fn((key, value) => {
|
||||||
|
|
|
@ -1,10 +1,9 @@
|
||||||
import * as React from 'react';
|
import * as React from 'react';
|
||||||
import ContainerProperties from '../../Interfaces/Properties';
|
import ContainerProperties from '../../Interfaces/Properties';
|
||||||
import { INPUT_TYPES } from './PropertiesInputTypes';
|
|
||||||
|
|
||||||
interface IPropertiesProps {
|
interface IPropertiesProps {
|
||||||
properties?: ContainerProperties
|
properties?: ContainerProperties
|
||||||
onChange: (key: string, value: string | number | boolean) => void
|
onChange: (key: string, value: string) => void
|
||||||
}
|
}
|
||||||
|
|
||||||
export const Properties: React.FC<IPropertiesProps> = (props: IPropertiesProps) => {
|
export const Properties: React.FC<IPropertiesProps> = (props: IPropertiesProps) => {
|
||||||
|
@ -27,24 +26,11 @@ export const Properties: React.FC<IPropertiesProps> = (props: IPropertiesProps)
|
||||||
const handleProperties = (
|
const handleProperties = (
|
||||||
[key, value]: [string, string | number],
|
[key, value]: [string, string | number],
|
||||||
groupInput: React.ReactNode[],
|
groupInput: React.ReactNode[],
|
||||||
onChange: (key: string, value: string | number | boolean) => void
|
onChange: (key: string, value: string) => void
|
||||||
): void => {
|
): void => {
|
||||||
const id = `property-${key}`;
|
const id = `property-${key}`;
|
||||||
let type = 'text';
|
const type = 'text';
|
||||||
let checked;
|
const isDisabled = key === 'id' || key === 'parentId'; // hardcoded
|
||||||
|
|
||||||
/// hardcoded stuff for ergonomy ///
|
|
||||||
if (typeof value === 'boolean') {
|
|
||||||
checked = value;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (key in INPUT_TYPES) {
|
|
||||||
type = INPUT_TYPES[key];
|
|
||||||
}
|
|
||||||
|
|
||||||
const isDisabled = ['id', 'parentId'].includes(key);
|
|
||||||
///
|
|
||||||
|
|
||||||
groupInput.push(
|
groupInput.push(
|
||||||
<div key={id} className='mt-4'>
|
<div key={id} className='mt-4'>
|
||||||
<label className='text-sm font-medium text-gray-800' htmlFor={id}>{key}</label>
|
<label className='text-sm font-medium text-gray-800' htmlFor={id}>{key}</label>
|
||||||
|
@ -57,14 +43,7 @@ const handleProperties = (
|
||||||
type={type}
|
type={type}
|
||||||
id={id}
|
id={id}
|
||||||
value={value}
|
value={value}
|
||||||
checked={checked}
|
onChange={(event) => onChange(key, event.target.value)}
|
||||||
onChange={(event) => {
|
|
||||||
if (type === 'checkbox') {
|
|
||||||
onChange(key, event.target.checked);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
onChange(key, event.target.value);
|
|
||||||
}}
|
|
||||||
disabled={isDisabled}
|
disabled={isDisabled}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -1,7 +0,0 @@
|
||||||
export const INPUT_TYPES: Record<string, string> = {
|
|
||||||
x: 'number',
|
|
||||||
y: 'number',
|
|
||||||
width: 'number',
|
|
||||||
height: 'number',
|
|
||||||
isRigidBody: 'checkbox'
|
|
||||||
};
|
|
|
@ -35,11 +35,10 @@ export const SVG: React.FC<ISVGProps> = (props: ISVGProps) => {
|
||||||
});
|
});
|
||||||
|
|
||||||
React.useEffect(() => {
|
React.useEffect(() => {
|
||||||
const onResize = (): void => resizeViewBox(setViewer);
|
window.addEventListener('resize', () => resizeViewBox(setViewer));
|
||||||
window.addEventListener('resize', onResize);
|
|
||||||
|
|
||||||
return () => {
|
return () => {
|
||||||
window.removeEventListener('resize', onResize);
|
window.addEventListener('resize', () => resizeViewBox(setViewer));
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
@ -4,7 +4,7 @@ import { Sidebar } from '../Sidebar/Sidebar';
|
||||||
import { History } from '../History/History';
|
import { History } from '../History/History';
|
||||||
import { AvailableContainer } from '../../Interfaces/AvailableContainer';
|
import { AvailableContainer } from '../../Interfaces/AvailableContainer';
|
||||||
import { ContainerModel } from '../../Interfaces/ContainerModel';
|
import { ContainerModel } from '../../Interfaces/ContainerModel';
|
||||||
import { HistoryState } from '../../Interfaces/HistoryState';
|
import { HistoryState } from "../../Interfaces/HistoryState";
|
||||||
import { PhotographIcon, UploadIcon } from '@heroicons/react/outline';
|
import { PhotographIcon, UploadIcon } from '@heroicons/react/outline';
|
||||||
import { FloatingButton } from '../FloatingButton/FloatingButton';
|
import { FloatingButton } from '../FloatingButton/FloatingButton';
|
||||||
import { Bar } from '../Bar/Bar';
|
import { Bar } from '../Bar/Bar';
|
||||||
|
@ -16,7 +16,7 @@ interface IUIProps {
|
||||||
AvailableContainers: AvailableContainer[]
|
AvailableContainers: AvailableContainer[]
|
||||||
SelectContainer: (container: ContainerModel) => void
|
SelectContainer: (container: ContainerModel) => void
|
||||||
DeleteContainer: (containerId: string) => void
|
DeleteContainer: (containerId: string) => void
|
||||||
OnPropertyChange: (key: string, value: string | number | boolean) => void
|
OnPropertyChange: (key: string, value: string) => 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
|
||||||
SaveEditorAsJSON: () => void
|
SaveEditorAsJSON: () => void
|
||||||
|
@ -58,7 +58,7 @@ export const UI: React.FunctionComponent<IUIProps> = (props: IUIProps) => {
|
||||||
SelectedContainer={props.current.SelectedContainer}
|
SelectedContainer={props.current.SelectedContainer}
|
||||||
isOpen={isElementsSidebarOpen}
|
isOpen={isElementsSidebarOpen}
|
||||||
isHistoryOpen={isHistoryOpen}
|
isHistoryOpen={isHistoryOpen}
|
||||||
OnPropertyChange={props.OnPropertyChange}
|
onPropertyChange={props.OnPropertyChange}
|
||||||
SelectContainer={props.SelectContainer}
|
SelectContainer={props.SelectContainer}
|
||||||
DeleteContainer={props.DeleteContainer}
|
DeleteContainer={props.DeleteContainer}
|
||||||
AddContainer={props.AddContainer}
|
AddContainer={props.AddContainer}
|
||||||
|
|
|
@ -1,7 +1,6 @@
|
||||||
import { IContainerModel } from './ContainerModel';
|
import { IContainerModel } from './ContainerModel';
|
||||||
|
|
||||||
export interface HistoryState {
|
export interface HistoryState {
|
||||||
LastAction: string
|
|
||||||
MainContainer: IContainerModel
|
MainContainer: IContainerModel
|
||||||
SelectedContainer: IContainerModel | null
|
SelectedContainer: IContainerModel | null
|
||||||
SelectedContainerId: string
|
SelectedContainerId: string
|
||||||
|
|
|
@ -5,5 +5,4 @@ export default interface Properties extends React.CSSProperties {
|
||||||
parentId: string | null
|
parentId: string | null
|
||||||
x: number
|
x: number
|
||||||
y: number
|
y: number
|
||||||
isRigidBody: boolean
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,4 +0,0 @@
|
||||||
export interface SizePointer {
|
|
||||||
x: number
|
|
||||||
width: number
|
|
||||||
}
|
|
|
@ -1,436 +0,0 @@
|
||||||
{
|
|
||||||
"history": [
|
|
||||||
{
|
|
||||||
"MainContainer": {
|
|
||||||
"children": [],
|
|
||||||
"properties": {
|
|
||||||
"id": "main",
|
|
||||||
"parentId": "null",
|
|
||||||
"x": 0,
|
|
||||||
"y": 0,
|
|
||||||
"width": 2000,
|
|
||||||
"height": 100,
|
|
||||||
"fillOpacity": 0,
|
|
||||||
"stroke": "black"
|
|
||||||
},
|
|
||||||
"userData": {}
|
|
||||||
},
|
|
||||||
"SelectedContainerId": "main",
|
|
||||||
"TypeCounters": {}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"LastAction": "Add container",
|
|
||||||
"MainContainer": {
|
|
||||||
"children": [
|
|
||||||
{
|
|
||||||
"children": [],
|
|
||||||
"properties": {
|
|
||||||
"id": "Container-0",
|
|
||||||
"parentId": "main",
|
|
||||||
"x": 0,
|
|
||||||
"y": 0,
|
|
||||||
"width": 75,
|
|
||||||
"height": 100,
|
|
||||||
"isRigidBody": false,
|
|
||||||
"fillOpacity": 0,
|
|
||||||
"stroke": "green"
|
|
||||||
},
|
|
||||||
"userData": {
|
|
||||||
"type": "Container"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"properties": {
|
|
||||||
"id": "main",
|
|
||||||
"parentId": "null",
|
|
||||||
"x": 0,
|
|
||||||
"y": 0,
|
|
||||||
"width": 2000,
|
|
||||||
"height": 100,
|
|
||||||
"fillOpacity": 0,
|
|
||||||
"stroke": "black"
|
|
||||||
},
|
|
||||||
"userData": {}
|
|
||||||
},
|
|
||||||
"SelectedContainerId": "main",
|
|
||||||
"TypeCounters": {
|
|
||||||
"Container": 0
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"LastAction": "Select container Container-0",
|
|
||||||
"MainContainer": {
|
|
||||||
"children": [
|
|
||||||
{
|
|
||||||
"children": [],
|
|
||||||
"properties": {
|
|
||||||
"id": "Container-0",
|
|
||||||
"parentId": "main",
|
|
||||||
"x": 0,
|
|
||||||
"y": 0,
|
|
||||||
"width": 75,
|
|
||||||
"height": 100,
|
|
||||||
"isRigidBody": false,
|
|
||||||
"fillOpacity": 0,
|
|
||||||
"stroke": "green"
|
|
||||||
},
|
|
||||||
"userData": {
|
|
||||||
"type": "Container"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"properties": {
|
|
||||||
"id": "main",
|
|
||||||
"parentId": "null",
|
|
||||||
"x": 0,
|
|
||||||
"y": 0,
|
|
||||||
"width": 2000,
|
|
||||||
"height": 100,
|
|
||||||
"fillOpacity": 0,
|
|
||||||
"stroke": "black"
|
|
||||||
},
|
|
||||||
"userData": {}
|
|
||||||
},
|
|
||||||
"SelectedContainerId": "Container-0",
|
|
||||||
"TypeCounters": {
|
|
||||||
"Container": 0
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"LastAction": "Change property of container Container-0",
|
|
||||||
"MainContainer": {
|
|
||||||
"children": [
|
|
||||||
{
|
|
||||||
"children": [],
|
|
||||||
"properties": {
|
|
||||||
"id": "Container-0",
|
|
||||||
"parentId": "main",
|
|
||||||
"x": 0,
|
|
||||||
"y": 0,
|
|
||||||
"width": "7",
|
|
||||||
"height": 100,
|
|
||||||
"isRigidBody": false,
|
|
||||||
"fillOpacity": 0,
|
|
||||||
"stroke": "green"
|
|
||||||
},
|
|
||||||
"userData": {
|
|
||||||
"type": "Container"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"properties": {
|
|
||||||
"id": "main",
|
|
||||||
"parentId": "null",
|
|
||||||
"x": 0,
|
|
||||||
"y": 0,
|
|
||||||
"width": 2000,
|
|
||||||
"height": 100,
|
|
||||||
"fillOpacity": 0,
|
|
||||||
"stroke": "black"
|
|
||||||
},
|
|
||||||
"userData": {}
|
|
||||||
},
|
|
||||||
"SelectedContainerId": "Container-0",
|
|
||||||
"TypeCounters": {
|
|
||||||
"Container": 0
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"LastAction": "Change property of container Container-0",
|
|
||||||
"MainContainer": {
|
|
||||||
"children": [
|
|
||||||
{
|
|
||||||
"children": [],
|
|
||||||
"properties": {
|
|
||||||
"id": "Container-0",
|
|
||||||
"parentId": "main",
|
|
||||||
"x": 0,
|
|
||||||
"y": 0,
|
|
||||||
"width": "",
|
|
||||||
"height": 100,
|
|
||||||
"isRigidBody": false,
|
|
||||||
"fillOpacity": 0,
|
|
||||||
"stroke": "green"
|
|
||||||
},
|
|
||||||
"userData": {
|
|
||||||
"type": "Container"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"properties": {
|
|
||||||
"id": "main",
|
|
||||||
"parentId": "null",
|
|
||||||
"x": 0,
|
|
||||||
"y": 0,
|
|
||||||
"width": 2000,
|
|
||||||
"height": 100,
|
|
||||||
"fillOpacity": 0,
|
|
||||||
"stroke": "black"
|
|
||||||
},
|
|
||||||
"userData": {}
|
|
||||||
},
|
|
||||||
"SelectedContainerId": "Container-0",
|
|
||||||
"TypeCounters": {
|
|
||||||
"Container": 0
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"LastAction": "Change property of container Container-0",
|
|
||||||
"MainContainer": {
|
|
||||||
"children": [
|
|
||||||
{
|
|
||||||
"children": [],
|
|
||||||
"properties": {
|
|
||||||
"id": "Container-0",
|
|
||||||
"parentId": "main",
|
|
||||||
"x": 0,
|
|
||||||
"y": 0,
|
|
||||||
"width": "2",
|
|
||||||
"height": 100,
|
|
||||||
"isRigidBody": false,
|
|
||||||
"fillOpacity": 0,
|
|
||||||
"stroke": "green"
|
|
||||||
},
|
|
||||||
"userData": {
|
|
||||||
"type": "Container"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"properties": {
|
|
||||||
"id": "main",
|
|
||||||
"parentId": "null",
|
|
||||||
"x": 0,
|
|
||||||
"y": 0,
|
|
||||||
"width": 2000,
|
|
||||||
"height": 100,
|
|
||||||
"fillOpacity": 0,
|
|
||||||
"stroke": "black"
|
|
||||||
},
|
|
||||||
"userData": {}
|
|
||||||
},
|
|
||||||
"SelectedContainerId": "Container-0",
|
|
||||||
"TypeCounters": {
|
|
||||||
"Container": 0
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"LastAction": "Change property of container Container-0",
|
|
||||||
"MainContainer": {
|
|
||||||
"children": [
|
|
||||||
{
|
|
||||||
"children": [],
|
|
||||||
"properties": {
|
|
||||||
"id": "Container-0",
|
|
||||||
"parentId": "main",
|
|
||||||
"x": 0,
|
|
||||||
"y": 0,
|
|
||||||
"width": "20",
|
|
||||||
"height": 100,
|
|
||||||
"isRigidBody": false,
|
|
||||||
"fillOpacity": 0,
|
|
||||||
"stroke": "green"
|
|
||||||
},
|
|
||||||
"userData": {
|
|
||||||
"type": "Container"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"properties": {
|
|
||||||
"id": "main",
|
|
||||||
"parentId": "null",
|
|
||||||
"x": 0,
|
|
||||||
"y": 0,
|
|
||||||
"width": 2000,
|
|
||||||
"height": 100,
|
|
||||||
"fillOpacity": 0,
|
|
||||||
"stroke": "black"
|
|
||||||
},
|
|
||||||
"userData": {}
|
|
||||||
},
|
|
||||||
"SelectedContainerId": "Container-0",
|
|
||||||
"TypeCounters": {
|
|
||||||
"Container": 0
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"LastAction": "Change property of container Container-0",
|
|
||||||
"MainContainer": {
|
|
||||||
"children": [
|
|
||||||
{
|
|
||||||
"children": [],
|
|
||||||
"properties": {
|
|
||||||
"id": "Container-0",
|
|
||||||
"parentId": "main",
|
|
||||||
"x": 0,
|
|
||||||
"y": 0,
|
|
||||||
"width": "200",
|
|
||||||
"height": 100,
|
|
||||||
"isRigidBody": false,
|
|
||||||
"fillOpacity": 0,
|
|
||||||
"stroke": "green"
|
|
||||||
},
|
|
||||||
"userData": {
|
|
||||||
"type": "Container"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"properties": {
|
|
||||||
"id": "main",
|
|
||||||
"parentId": "null",
|
|
||||||
"x": 0,
|
|
||||||
"y": 0,
|
|
||||||
"width": 2000,
|
|
||||||
"height": 100,
|
|
||||||
"fillOpacity": 0,
|
|
||||||
"stroke": "black"
|
|
||||||
},
|
|
||||||
"userData": {}
|
|
||||||
},
|
|
||||||
"SelectedContainerId": "Container-0",
|
|
||||||
"TypeCounters": {
|
|
||||||
"Container": 0
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"LastAction": "Change property of container Container-0",
|
|
||||||
"MainContainer": {
|
|
||||||
"children": [
|
|
||||||
{
|
|
||||||
"children": [],
|
|
||||||
"properties": {
|
|
||||||
"id": "Container-0",
|
|
||||||
"parentId": "main",
|
|
||||||
"x": 0,
|
|
||||||
"y": 0,
|
|
||||||
"width": "2000",
|
|
||||||
"height": 100,
|
|
||||||
"isRigidBody": false,
|
|
||||||
"fillOpacity": 0,
|
|
||||||
"stroke": "green"
|
|
||||||
},
|
|
||||||
"userData": {
|
|
||||||
"type": "Container"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"properties": {
|
|
||||||
"id": "main",
|
|
||||||
"parentId": "null",
|
|
||||||
"x": 0,
|
|
||||||
"y": 0,
|
|
||||||
"width": 2000,
|
|
||||||
"height": 100,
|
|
||||||
"fillOpacity": 0,
|
|
||||||
"stroke": "black"
|
|
||||||
},
|
|
||||||
"userData": {}
|
|
||||||
},
|
|
||||||
"SelectedContainerId": "Container-0",
|
|
||||||
"TypeCounters": {
|
|
||||||
"Container": 0
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"LastAction": "Change property of container Container-0",
|
|
||||||
"MainContainer": {
|
|
||||||
"children": [
|
|
||||||
{
|
|
||||||
"children": [],
|
|
||||||
"properties": {
|
|
||||||
"id": "Container-0",
|
|
||||||
"parentId": "main",
|
|
||||||
"x": 0,
|
|
||||||
"y": 0,
|
|
||||||
"width": "20000",
|
|
||||||
"height": 100,
|
|
||||||
"isRigidBody": false,
|
|
||||||
"fillOpacity": 0,
|
|
||||||
"stroke": "green"
|
|
||||||
},
|
|
||||||
"userData": {
|
|
||||||
"type": "Container"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"properties": {
|
|
||||||
"id": "main",
|
|
||||||
"parentId": "null",
|
|
||||||
"x": 0,
|
|
||||||
"y": 0,
|
|
||||||
"width": 2000,
|
|
||||||
"height": 100,
|
|
||||||
"fillOpacity": 0,
|
|
||||||
"stroke": "black"
|
|
||||||
},
|
|
||||||
"userData": {}
|
|
||||||
},
|
|
||||||
"SelectedContainerId": "Container-0",
|
|
||||||
"TypeCounters": {
|
|
||||||
"Container": 0
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"LastAction": "Change property of container Container-0",
|
|
||||||
"MainContainer": {
|
|
||||||
"children": [
|
|
||||||
{
|
|
||||||
"children": [],
|
|
||||||
"properties": {
|
|
||||||
"id": "Container-0",
|
|
||||||
"parentId": "main",
|
|
||||||
"x": 0,
|
|
||||||
"y": 0,
|
|
||||||
"width": 2000,
|
|
||||||
"height": 100,
|
|
||||||
"isRigidBody": true,
|
|
||||||
"fillOpacity": 0,
|
|
||||||
"stroke": "green"
|
|
||||||
},
|
|
||||||
"userData": {
|
|
||||||
"type": "Container"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"properties": {
|
|
||||||
"id": "main",
|
|
||||||
"parentId": "null",
|
|
||||||
"x": 0,
|
|
||||||
"y": 0,
|
|
||||||
"width": 2000,
|
|
||||||
"height": 100,
|
|
||||||
"fillOpacity": 0,
|
|
||||||
"stroke": "black"
|
|
||||||
},
|
|
||||||
"userData": {}
|
|
||||||
},
|
|
||||||
"SelectedContainerId": "Container-0",
|
|
||||||
"TypeCounters": {
|
|
||||||
"Container": 0
|
|
||||||
}
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"historyCurrentStep": 10,
|
|
||||||
"configuration": {
|
|
||||||
"AvailableContainers": [
|
|
||||||
{
|
|
||||||
"Type": "Container",
|
|
||||||
"Width": 75,
|
|
||||||
"Height": 100,
|
|
||||||
"Style": {
|
|
||||||
"fillOpacity": 0,
|
|
||||||
"stroke": "green"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"AvailableSymbols": [],
|
|
||||||
"MainContainer": {
|
|
||||||
"Type": "Container",
|
|
||||||
"Width": 2000,
|
|
||||||
"Height": 100,
|
|
||||||
"Style": {
|
|
||||||
"fillOpacity": 0,
|
|
||||||
"stroke": "black"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -30,7 +30,6 @@ export const DEFAULT_MAINCONTAINER_PROPS: Properties = {
|
||||||
parentId: 'null',
|
parentId: 'null',
|
||||||
x: 0,
|
x: 0,
|
||||||
y: 0,
|
y: 0,
|
||||||
isRigidBody: false,
|
|
||||||
width: DEFAULT_CONFIG.MainContainer.Width,
|
width: DEFAULT_CONFIG.MainContainer.Width,
|
||||||
height: DEFAULT_CONFIG.MainContainer.Height,
|
height: DEFAULT_CONFIG.MainContainer.Height,
|
||||||
fillOpacity: 0,
|
fillOpacity: 0,
|
||||||
|
|
|
@ -8,11 +8,6 @@ import { IEditorState } from '../Components/Editor/Editor';
|
||||||
*/
|
*/
|
||||||
export function Revive(editorState: IEditorState): void {
|
export function Revive(editorState: IEditorState): void {
|
||||||
const history = editorState.history;
|
const history = editorState.history;
|
||||||
|
|
||||||
// restore last step
|
|
||||||
editorState.historyCurrentStep = history.length - 1;
|
|
||||||
|
|
||||||
// restore the parents and the selected container
|
|
||||||
for (const state of history) {
|
for (const state of history) {
|
||||||
if (state.MainContainer === null || state.MainContainer === undefined) {
|
if (state.MainContainer === null || state.MainContainer === undefined) {
|
||||||
continue;
|
continue;
|
||||||
|
@ -48,10 +43,6 @@ export const getCircularReplacer = (): (key: any, value: object | null) => objec
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (key === 'SelectedContainer') {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (typeof value === 'object' && value !== null) {
|
if (typeof value === 'object' && value !== null) {
|
||||||
if (seen.has(value)) {
|
if (seen.has(value)) {
|
||||||
return;
|
return;
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue