feat: click-drag drawing, layer tree, settings modal, UI improvements

- interaction: click-drag drawing for 2-point tools (line, rect, circle, dimension, leader)
- interaction: preview rendering during drag with setPreviewElement
- interaction: handleDrawDown only sets phase=drawing on first point
- CanvasArea: sync activeLayerId to LayerManager
- CanvasArea: callback refresh useEffect prevents stale closures
- App.tsx: functional setElements updates for handleElementCreated/Deleted/Modified
- LayerPanel: tree structure with sub-layers (onReorder, onAddSubLayer)
- TreeView: drag-and-drop reordering support
- RightSidebar: onReorder, onAddSubLayer, onUpdateElement props
- PropertiesPanel: onUpdateElement prop
- SettingsModal: personal/password/language/theme/users/plugins/AI tabs
- styles.css: extensive UI styling additions
- types: updated RightSidebarProps, CanvasAreaProps, LayerPanelProps
This commit is contained in:
2026-06-27 14:12:37 +02:00
parent 39422a4348
commit 4303076ce4
17 changed files with 929 additions and 144 deletions
+22 -7
View File
@@ -349,6 +349,21 @@ export class InteractionEngine {
this.selectionEngine.finishBoxSelect(this.allElements);
this.emitSelectionChange();
this.requestRender();
return;
}
// Click-drag: confirm draw on mouseup for 2-point tools
if (this.state.phase === 'drawing' && this.state.points.length >= 1) {
const raw = this.getWorldCoords(e);
const snapped = this.applySnap(raw.x, raw.y);
const final = this.applyOrtho(snapped.x, snapped.y);
const tool = this.state.activeTool;
// For 2-point tools: use mouseup position as second point
if (tool === 'line' || tool === 'rect' || tool === 'circle' || tool === 'dimension' || tool === 'leader') {
this.state.points.push(final);
this.confirmDraw();
return;
}
}
}
@@ -466,7 +481,10 @@ export class InteractionEngine {
}
private handleDrawDown(pt: { x: number; y: number }): void {
this.state.phase = 'drawing';
// Clear any previous points when starting a new draw operation
if (this.state.points.length === 0) {
this.state.phase = 'drawing';
}
this.state.points.push(pt);
// Arc: auto-confirm after 3 points (center, start, end)
@@ -481,12 +499,8 @@ export class InteractionEngine {
return;
}
// Line, rect, circle, dimension, leader: auto-confirm after 2 points
if ((this.state.activeTool === 'line' || this.state.activeTool === 'rect' || this.state.activeTool === 'circle' || this.state.activeTool === 'dimension' || this.state.activeTool === 'leader') && this.state.points.length >= 2) {
this.updatePreview(pt);
this.confirmDraw();
return;
}
// Line, rect, circle, dimension, leader: wait for mouseup (click-drag behavior)
// Points are collected on mousedown, confirmed on mouseup
this.updatePreview(pt);
this.notifyToolStateChanged();
@@ -1000,6 +1014,7 @@ export class InteractionEngine {
if (this.animationFrame !== null) return;
this.animationFrame = requestAnimationFrame(() => {
this.animationFrame = null;
this.renderEngine.setPreviewElement(this.state.previewElement);
this.renderEngine.render();
});
}