task(G1): layout data model - LayoutDefinition type, Yjs layouts map, undo-tracked CRUD in CADDocument

This commit is contained in:
Agent Zero
2026-08-29 02:39:30 +02:00
parent d51111fc2c
commit e750a45d7a
4 changed files with 162 additions and 3 deletions
+50 -3
View File
@@ -12,7 +12,7 @@
*/
import * as Y from 'yjs';
import { YjsDocument } from '../../crdt/YjsDocument';
import type { CADElement, CADLayer } from '../../types/cad.types';
import type { CADElement, CADLayer, LayoutDefinition } from '../../types/cad.types';
export class CADDocument {
private readonly ydoc: YjsDocument;
@@ -22,10 +22,10 @@ export class CADDocument {
constructor(ydoc: YjsDocument) {
this.ydoc = ydoc;
// Trackt alle Operationen auf Elements + Layers → gemeinsame Undo-Historie.
// Blocks/Groups/Configs bewusst NICHT tracken: Werkzeuge ändern primär Elemente/Layer.
// Blocks/Groups/Configs bewusst NICHT tracken; Layouts (G1) dazu seit Task G1.
// captureTimeout 0: KEIN automatisches Mergen zeitnaher Transaktionen —
// jede explizite transact() bleibt EIGENER Undo-Schritt (deterministisch für Tools).
this.undoManager = new Y.UndoManager([this.ydoc.data.elements, this.ydoc.data.layers], {
this.undoManager = new Y.UndoManager([this.ydoc.data.elements, this.ydoc.data.layers, this.ydoc.data.layouts], {
captureTimeout: 0,
});
}
@@ -52,6 +52,53 @@ export class CADDocument {
return Array.from(this.ydoc.data.layers.values());
}
// ── Layouts (Task G1) ────────────────────────────────────
/** Ein Layout per ID (oder undefined). */
getLayout(id: string): LayoutDefinition | undefined {
return this.ydoc.data.layouts.get(id);
}
/** Alle Layouts als Array. */
getAllLayouts(): LayoutDefinition[] {
return Array.from(this.ydoc.data.layouts.values());
}
/** Fügt ein Layout hinzu (eigener Undo-Schritt). */
addLayout(layout: LayoutDefinition): void {
this.transact(() => {
this.ydoc.data.layouts.set(layout.id, layout);
});
}
/**
* Aktualisiert ein Layout: Top-Level-Felder ersetzt, viewport SHALLOW gemergt
* (center/scale einzeln änderbar). @throws wenn Layout fehlt.
*/
updateLayout(id: string, patch: Partial<Omit<LayoutDefinition, 'id'>>): void {
const existing = this.ydoc.data.layouts.get(id);
if (!existing) throw new Error(`updateLayout: Layout '${id}' nicht gefunden`);
const merged: LayoutDefinition = {
...existing,
...patch,
viewport: patch.viewport
? { ...existing.viewport, ...patch.viewport, center: { ...existing.viewport.center, ...patch.viewport.center } }
: existing.viewport,
};
this.transact(() => {
this.ydoc.data.layouts.set(id, merged);
});
}
/** Entfernt ein Layout (still bei unbekannter ID, eigener Undo-Schritt). */
deleteLayout(id: string): void {
this.transact(() => {
if (this.ydoc.data.layouts.has(id)) {
this.ydoc.data.layouts.delete(id);
}
});
}
// ── Schreiben ────────────────────────────────────────────
/** Fügt ein Element hinzu (einzelner Aufruf = eigener Undo-Schritt). */