diff --git a/src/Components/Editor/ContainerOperations.ts b/src/Components/Editor/ContainerOperations.ts index 3d9e91e..95a0889 100644 --- a/src/Components/Editor/ContainerOperations.ts +++ b/src/Components/Editor/ContainerOperations.ts @@ -7,6 +7,7 @@ import { getCurrentHistory } from './Editor'; import IProperties from '../../Interfaces/IProperties'; import { AddMethod } from '../../Enums/AddMethod'; import { IAvailableContainer } from '../../Interfaces/IAvailableContainer'; +import { transformPosition } from '../SVG/Elements/Container'; import { XPositionReference } from '../../Enums/XPositionReference'; /** @@ -57,7 +58,7 @@ export function DeleteContainer( setHistoryCurrentStep: Dispatch> ): void { const history = getCurrentHistory(fullHistory, historyCurrentStep); - const current = history[history.length - 1]; + const current = history[historyCurrentStep]; const mainContainerClone: IContainerModel = structuredClone(current.MainContainer); const container = findContainerById(mainContainerClone, containerId); @@ -266,7 +267,14 @@ function ApplyAddMethod(index: number, containerConfig: IAvailableContainer, par const lastChild: IContainerModel | undefined = parent.children.at(index - 1); if (lastChild !== undefined) { - x += (lastChild.properties.x + lastChild.properties.width); + const [transformedX] = transformPosition( + lastChild.properties.x, + lastChild.properties.y, + lastChild.properties.width, + lastChild.properties.XPositionReference + ); + + x += transformedX + lastChild.properties.width; } } return x; diff --git a/src/Components/Editor/PropertiesOperations.ts b/src/Components/Editor/PropertiesOperations.ts index 0e3802c..9f35e63 100644 --- a/src/Components/Editor/PropertiesOperations.ts +++ b/src/Components/Editor/PropertiesOperations.ts @@ -3,10 +3,9 @@ import { IContainerModel, ContainerModel } from '../../Interfaces/IContainerMode import { IHistoryState } from '../../Interfaces/IHistoryState'; import { findContainerById } from '../../utils/itertools'; import { getCurrentHistory } from './Editor'; -import { constraintBodyInsideUnallocatedWidth, RecalculatePhysics } from './Behaviors/RigidBodyBehaviors'; +import { RecalculatePhysics } from './Behaviors/RigidBodyBehaviors'; import { INPUT_TYPES } from '../Properties/PropertiesInputTypes'; import { ImposePosition } from './Behaviors/AnchorBehaviors'; -import { restoreX } from '../SVG/Elements/Container'; /** * Handled the property change event in the properties form @@ -41,7 +40,11 @@ export function OnPropertyChange( if (isStyle) { (container.properties.style as any)[key] = value; } else { - (container.properties as any)[key] = value; + if (INPUT_TYPES[key] === 'number') { + (container.properties as any)[key] = Number(value); + } else { + (container.properties as any)[key] = value; + } } if (container.properties.isAnchor) { @@ -93,28 +96,39 @@ export function OnPropertiesSubmit( } // Assign container properties - const form: HTMLFormElement = event.target as HTMLFormElement; for (const property in container.properties) { - const input: HTMLInputElement | HTMLDivElement | null = form.querySelector(`#${property}`); + const input: HTMLInputElement | HTMLDivElement | null = (event.target as HTMLFormElement).querySelector(`#${property}`); if (input === null) { continue; } if (input instanceof HTMLInputElement) { - submitHTMLInput(input, container, property, form); - continue; - } + (container.properties as any)[property] = input.value; + if (INPUT_TYPES[property] === 'number') { + (container.properties as any)[property] = Number(input.value); + } + } else if (input instanceof HTMLDivElement) { + const radiobutton: HTMLInputElement | null = input.querySelector(`input[name="${property}"]:checked`); - if (input instanceof HTMLDivElement) { - submitRadioButtons(input, container, property); - continue; + if (radiobutton === null) { + continue; + } + + (container.properties as any)[property] = radiobutton.value; + if (INPUT_TYPES[property] === 'number') { + (container.properties as any)[property] = Number(radiobutton.value); + } } } // Assign cssproperties for (const styleProperty in container.properties.style) { - submitCSSForm(form, styleProperty, container); + const input: HTMLInputElement | null = (event.target as HTMLFormElement).querySelector(`#${styleProperty}`); + if (input === null) { + continue; + } + (container.properties.style as any)[styleProperty] = input.value; } if (container.properties.isRigidBody) { @@ -131,67 +145,3 @@ export function OnPropertiesSubmit( setHistory(history); setHistoryCurrentStep(history.length - 1); } - -const submitHTMLInput = ( - input: HTMLInputElement, - container: IContainerModel, - property: string, - form: HTMLFormElement -): void => { - if (INPUT_TYPES[property] !== 'number') { - (container.properties as any)[property] = input.value; - } - - 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 (INPUT_TYPES[property] === 'number') { - (container.properties as any)[property] = Number(radiobutton.value); - return; - } - - (container.properties as any)[property] = radiobutton.value; -}; diff --git a/src/Components/Properties/DynamicForm.tsx b/src/Components/Properties/DynamicForm.tsx index b5665b6..0be155d 100644 --- a/src/Components/Properties/DynamicForm.tsx +++ b/src/Components/Properties/DynamicForm.tsx @@ -4,7 +4,6 @@ import { XPositionReference } from '../../Enums/XPositionReference'; import IProperties from '../../Interfaces/IProperties'; import { InputGroup } from '../InputGroup/InputGroup'; import { RadioGroupButtons } from '../RadioGroupButtons/RadioGroupButtons'; -import { restoreX, transformX } from '../SVG/Elements/Container'; interface IDynamicFormProps { properties: IProperties @@ -58,8 +57,8 @@ const DynamicForm: React.FunctionComponent = (props) => { labelClassName='' inputClassName='' type='number' - value={transformX(props.properties.x, props.properties.width, props.properties.XPositionReference).toString()} - onChange={(event) => props.onChange('x', restoreX(Number(event.target.value), props.properties.width, props.properties.XPositionReference))} + value={props.properties.x.toString()} + onChange={(event) => props.onChange('x', event.target.value)} /> = (props) => { inputClassName='' type='number' value={props.properties.y.toString()} - onChange={(event) => props.onChange('y', Number(event.target.value))} + onChange={(event) => props.onChange('y', event.target.value)} /> = (props) => { inputClassName='' type='number' value={props.properties.width.toString()} - onChange={(event) => props.onChange('width', Number(event.target.value))} + onChange={(event) => props.onChange('width', event.target.value)} /> = (props) => { inputClassName='' type='number' value={props.properties.height.toString()} - onChange={(event) => props.onChange('height', Number(event.target.value))} + onChange={(event) => props.onChange('height', event.target.value)} /> = (props) => { value: XPositionReference.Right.toString() } ]} - onChange={(event) => props.onChange('XPositionReference', Number(event.target.value))} + onChange={(event) => props.onChange('XPositionReference', event.target.value)} /> { getCSSInputs(props.properties, props.onChange) } diff --git a/src/Components/Properties/Properties.test.tsx b/src/Components/Properties/Properties.test.tsx index dc9473e..61441f8 100644 --- a/src/Components/Properties/Properties.test.tsx +++ b/src/Components/Properties/Properties.test.tsx @@ -68,8 +68,8 @@ describe.concurrent('Properties', () => { expect(prop.id).toBe('stuff'); expect(prop.parentId).toBe('parentId'); - expect(prop.x).toBe(2); - expect(prop.y).toBe(2); + expect(prop.x).toBe('2'); + expect(prop.y).toBe('2'); rerender( = (props) => { labelClassName='' inputClassName='' type='number' - defaultValue={transformX(props.properties.x, props.properties.width, props.properties.XPositionReference).toString()} + defaultValue={props.properties.x.toString()} /> = (props: IContainerProps) => const xText = props.model.properties.width / 2; const yText = props.model.properties.height / 2; - const transform = `translate(${props.model.properties.x}, ${props.model.properties.y})`; + const [transformedX, transformedY] = transformPosition( + props.model.properties.x, + props.model.properties.y, + props.model.properties.width, + props.model.properties.XPositionReference + ); + const transform = `translate(${transformedX}, ${transformedY})`; // g style const defaultStyle: React.CSSProperties = { @@ -101,17 +107,17 @@ function GetChildrenDimensionProps(props: IContainerProps, dimensionMargin: numb const childrenId = `dim-children-${props.model.properties.id}`; const lastChild = props.model.children[props.model.children.length - 1]; - let xChildrenStart = transformX(lastChild.properties.x, lastChild.properties.width, lastChild.properties.XPositionReference); - let xChildrenEnd = transformX(lastChild.properties.x, lastChild.properties.width, lastChild.properties.XPositionReference); + let xChildrenStart = lastChild.properties.x; + let xChildrenEnd = lastChild.properties.x; // Find the min and max for (let i = props.model.children.length - 2; i >= 0; i--) { const child = props.model.children[i]; - const left = transformX(child.properties.x, child.properties.width, child.properties.XPositionReference); + const left = child.properties.x; if (left < xChildrenStart) { xChildrenStart = left; } - const right = transformX(child.properties.x, child.properties.width, child.properties.XPositionReference); + const right = child.properties.x; if (right > xChildrenEnd) { xChildrenEnd = right; } @@ -122,22 +128,12 @@ function GetChildrenDimensionProps(props: IContainerProps, dimensionMargin: numb return { childrenId, xChildrenStart, xChildrenEnd, yChildren, textChildren }; } -export function transformX(x: number, width: number, xPositionReference = XPositionReference.Left): number { - let transformedX = x; - if (xPositionReference === XPositionReference.Center) { - transformedX += width / 2; - } else if (xPositionReference === XPositionReference.Right) { - transformedX += width; - } - return transformedX; -} - -export function restoreX(x: number, width: number, xPositionReference = XPositionReference.Left): number { +export function transformPosition(x: number, y: number, width: number, xPositionReference = XPositionReference.Left): [number, number] { let transformedX = x; if (xPositionReference === XPositionReference.Center) { transformedX -= width / 2; } else if (xPositionReference === XPositionReference.Right) { transformedX -= width; } - return transformedX; + return [transformedX, y]; } diff --git a/src/Components/SVG/Elements/Selector.tsx b/src/Components/SVG/Elements/Selector.tsx index e70ca79..101f19a 100644 --- a/src/Components/SVG/Elements/Selector.tsx +++ b/src/Components/SVG/Elements/Selector.tsx @@ -1,6 +1,7 @@ import * as React from 'react'; import { IContainerModel } from '../../../Interfaces/IContainerModel'; import { getAbsolutePosition } from '../../../utils/itertools'; +import { transformPosition } from './Container'; interface ISelectorProps { selected: IContainerModel | null @@ -15,6 +16,12 @@ export const Selector: React.FC = (props) => { } const [x, y] = getAbsolutePosition(props.selected); + const [transformedX, transformedY] = transformPosition( + x, + y, + props.selected.properties.width, + props.selected.properties.XPositionReference + ); const [width, height] = [ props.selected.properties.width, props.selected.properties.height @@ -31,8 +38,8 @@ export const Selector: React.FC = (props) => { return (