fix: HIGH issues #13,#14,#18,#19,#20 — frontend state/sync: copy-paste selection, dynamic activeLayer, group creation, Yjs awareness protocol, connect sync
This commit is contained in:
+24
-8
@@ -111,6 +111,7 @@ const CADEditor: React.FC<CADEditorProps> = ({ projectId, token, onNavigateBack
|
||||
// Right sidebar
|
||||
const [activeRightPanel, setActiveRightPanel] = useState<RightPanel>('tool');
|
||||
const [selectedElement, setSelectedElement] = useState<CADElement | null>(null);
|
||||
const [selectedElementIds, setSelectedElementIds] = useState<string[]>([]);
|
||||
const [layers, setLayers] = useState<CADLayer[]>(initialLayers);
|
||||
const [activeLayerId, setActiveLayerId] = useState<string>('layer-0');
|
||||
const [blocks, setBlocks] = useState<BlockDefinition[]>(initialBlocks);
|
||||
@@ -191,6 +192,8 @@ const CADEditor: React.FC<CADEditorProps> = ({ projectId, token, onNavigateBack
|
||||
bgConfigRef.current = bgConfig;
|
||||
const activeLayerIdRef = useRef(activeLayerId);
|
||||
activeLayerIdRef.current = activeLayerId;
|
||||
const selectedElementIdsRef = useRef(selectedElementIds);
|
||||
selectedElementIdsRef.current = selectedElementIds;
|
||||
|
||||
// Clipboard (for copy/paste)
|
||||
const clipboardRef = React.useRef<CADElement[] | null>(null);
|
||||
@@ -642,11 +645,16 @@ const CADEditor: React.FC<CADEditorProps> = ({ projectId, token, onNavigateBack
|
||||
}, [blocks, activeLayerId, collab, drawingId, token]);
|
||||
|
||||
const handleSelectionChange = useCallback((selectedIds: string[]) => {
|
||||
setSelectedElementIds(selectedIds);
|
||||
if (selectedIds.length === 1) {
|
||||
const el = elements.find(e => e.id === selectedIds[0]);
|
||||
setSelectedElement(el ?? null);
|
||||
} else {
|
||||
} else if (selectedIds.length === 0) {
|
||||
setSelectedElement(null);
|
||||
} else {
|
||||
// Multiple elements selected — keep the first one as a representative for the properties panel
|
||||
const el = elements.find(e => e.id === selectedIds[0]);
|
||||
setSelectedElement(el ?? null);
|
||||
}
|
||||
}, [elements]);
|
||||
|
||||
@@ -776,7 +784,8 @@ const CADEditor: React.FC<CADEditorProps> = ({ projectId, token, onNavigateBack
|
||||
if (action === 'undo') { handleUndo(); return; }
|
||||
if (action === 'redo') { handleRedo(); return; }
|
||||
if (action === 'copy') {
|
||||
const selected = selectedElement ? [selectedElement] : [];
|
||||
const ids = selectedElementIdsRef.current;
|
||||
const selected = ids.length > 0 ? elements.filter(e => ids.includes(e.id)) : [];
|
||||
const clip = selected.length > 0 ? selected : elements.slice(0, 1);
|
||||
clipboardRef.current = clip;
|
||||
setCommandHistory((prev) => [...prev, { prefix: '·', text: `${clip.length} Element(e) kopiert`, type: 'info' }]);
|
||||
@@ -1136,10 +1145,17 @@ const CADEditor: React.FC<CADEditorProps> = ({ projectId, token, onNavigateBack
|
||||
// Group command: create group from currently selected elements
|
||||
if (upper === 'GROUP' || upper === 'GRP') {
|
||||
const gm = groupManagerRef.current;
|
||||
// For now, group all elements (selection state is in InteractionEngine, not accessible here)
|
||||
// In a full implementation, we'd need selected IDs from the interaction engine
|
||||
setCommandHistory((prev) => [...prev, { prefix: '·', text: 'Gruppe erstellt (Auswahl im Canvas erforderlich)', type: 'info' }]);
|
||||
setGroups(gm.getGroups());
|
||||
const ids = selectedElementIdsRef.current;
|
||||
if (ids.length < 2) {
|
||||
setCommandHistory((prev) => [...prev, { prefix: '·', text: 'Gruppe: Mindestens 2 Elemente auswählen', type: 'info' }]);
|
||||
return;
|
||||
}
|
||||
const group = gm.createGroup(ids);
|
||||
const newGroups = gm.getGroups();
|
||||
setGroups(newGroups);
|
||||
// Sync group to Yjs CRDT for real-time collaboration
|
||||
collab.setGroup(group);
|
||||
setCommandHistory((prev) => [...prev, { prefix: '·', text: `Gruppe erstellt: ${group.name} (${ids.length} Elemente)`, type: 'info' }]);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -1194,7 +1210,7 @@ const CADEditor: React.FC<CADEditorProps> = ({ projectId, token, onNavigateBack
|
||||
setCommandHistory((prev) => [...prev, { prefix: '·', text: `Unbekannter Befehl: ${cmd}`, type: 'info' }]);
|
||||
}
|
||||
}
|
||||
}, [handleUndo, handleRedo, handleRibbonAction]);
|
||||
}, [handleUndo, handleRedo, handleRibbonAction, collab]);
|
||||
|
||||
const handleKISend = useCallback(async (text: string) => {
|
||||
const userMsg: KIMessage = { id: `ki-${Date.now()}`, role: 'user', content: text };
|
||||
@@ -1249,7 +1265,7 @@ const CADEditor: React.FC<CADEditorProps> = ({ projectId, token, onNavigateBack
|
||||
handleKISend(suggestion.label);
|
||||
}, [handleKISend]);
|
||||
|
||||
const activeLayerName = layers.find((l) => l.id === 'layer-0')?.name ?? '—';
|
||||
const activeLayerName = layers.find((l) => l.id === activeLayerId)?.name ?? '—';
|
||||
|
||||
// ─── Render ─────────────────────────────────────────────
|
||||
return (
|
||||
|
||||
Reference in New Issue
Block a user