feat: units system — mm/cm/m switchable, configurable grid, real measurements, formatted display

This commit is contained in:
A0 Orchestrator
2026-07-02 08:46:07 +02:00
parent 72e3d1da24
commit 0463a793bc
14 changed files with 661 additions and 76 deletions
+16 -13
View File
@@ -136,8 +136,9 @@ describe('StatusBar', () => {
it('should render cursor coordinates', () => {
render(<StatusBar {...defaultProps} />);
// Default unit is mm, scaleFactor=1: 123.456 → '123', 78.9 → '79'
expect(screen.getByText(/123/)).toBeInTheDocument();
expect(screen.getByText(/78/)).toBeInTheDocument();
expect(screen.getByText(/79/)).toBeInTheDocument();
});
it('should render active layer and tool', () => {
@@ -352,29 +353,31 @@ describe('PropertiesPanel', () => {
const layers = [makeLayer({ id: 'layer-1', name: 'Layer 1' })];
const element = makeElement({ id: 'elem-1', type: 'rect', x: 10, y: 20, width: 100, height: 50 });
it('should show default values when no element selected', () => {
it('should show empty inputs when no element selected', () => {
render(<PropertiesPanel selectedElement={null} layers={layers} onUpdateProperty={() => {}} />);
// Default values are in inputs with aria-labels
expect(screen.getByLabelText('Position X')).toHaveDisplayValue('0.000 m');
expect(screen.getByLabelText('Position Y')).toHaveDisplayValue('0.000 m');
// When no element is selected, input fields are empty
expect(screen.getByLabelText('Position X')).toHaveDisplayValue('');
expect(screen.getByLabelText('Position Y')).toHaveDisplayValue('');
});
it('should display element coordinates when element is selected', () => {
it('should display element coordinates in mm by default', () => {
render(<PropertiesPanel selectedElement={element} layers={layers} onUpdateProperty={() => {}} />);
expect(screen.getByLabelText('Position X')).toHaveDisplayValue('10.000 m');
expect(screen.getByLabelText('Position Y')).toHaveDisplayValue('20.000 m');
// Default unit is mm with scaleFactor=1, so world units are displayed as mm
expect(screen.getByLabelText('Position X')).toHaveDisplayValue('10');
expect(screen.getByLabelText('Position Y')).toHaveDisplayValue('20');
});
it('should display element dimensions', () => {
it('should display element dimensions in mm by default', () => {
render(<PropertiesPanel selectedElement={element} layers={layers} onUpdateProperty={() => {}} />);
expect(screen.getByLabelText('Breite')).toHaveDisplayValue('100.00 m');
expect(screen.getByLabelText('Tiefe')).toHaveDisplayValue('50.00 m');
expect(screen.getByLabelText('Breite')).toHaveDisplayValue('100');
expect(screen.getByLabelText('Tiefe')).toHaveDisplayValue('50');
});
it('should call onUpdateProperty when changing a property input', () => {
it('should call onUpdateProperty with world-unit number when changing a property input', () => {
const onUpdateProperty = vi.fn();
render(<PropertiesPanel selectedElement={element} layers={layers} onUpdateProperty={onUpdateProperty} />);
fireEvent.change(screen.getByLabelText('Position X'), { target: { value: '999' } });
expect(onUpdateProperty).toHaveBeenCalledWith('x', '999');
// In mm mode with scaleFactor=1, input '999' → 999 world units
expect(onUpdateProperty).toHaveBeenCalledWith('x', 999);
});
});