task(A4.6): migrate move/copy tools to v2 with selection-based workflow
This commit is contained in:
@@ -348,6 +348,91 @@ describe('A4.5 pilot: hatch tool', () => {
|
||||
});
|
||||
});
|
||||
|
||||
describe('A4.6 pilot: move/copy tools', () => {
|
||||
it('move verschiebt selektierte Elemente in EINER Transaktion (undo entfernt Versatz)', () => {
|
||||
const { ydoc } = createInMemoryDoc();
|
||||
const doc = new CADDocument(ydoc);
|
||||
doc.addElement(makeEl('m1'));
|
||||
doc.addElement(makeEl('m2'));
|
||||
let selIds = ['m1', 'm2'];
|
||||
const bridge = {
|
||||
getIds: () => selIds,
|
||||
setIds: (ids: string[]) => {
|
||||
selIds = ids;
|
||||
},
|
||||
hitTest: () => null,
|
||||
};
|
||||
const ctx = makeCtx({ doc, selection: bridge });
|
||||
const move = coreModifyPlugin.tools!.find((t) => t.manifest.id === 'move')!;
|
||||
const origM1x = doc.getElement('m1')!.x;
|
||||
const origY = doc.getElement('m1')!.y;
|
||||
|
||||
move.handlers.down!(pe(0, 0), ctx); // Basispunkt
|
||||
move.handlers.down!(pe(50, -20), ctx); // Zielklick → Commit
|
||||
|
||||
expect(doc.getElement('m1')!.x).toBe(origM1x + 50);
|
||||
expect(doc.getElement('m2')!.y).toBe(origY - 20);
|
||||
// EINE Transaktion für beide → ein undo stellt beide wieder her:
|
||||
expect(doc.undo()).toBe(true);
|
||||
expect(doc.getElement('m1')!.x).toBe(origM1x);
|
||||
expect(doc.getElement('m2')!.y).toBe(origY);
|
||||
});
|
||||
|
||||
it('copy erzeugt neue Elemente (IDs neu) ohne Original zu veraendern', () => {
|
||||
const { ydoc } = createInMemoryDoc();
|
||||
const doc = new CADDocument(ydoc);
|
||||
doc.addElement(makeEl('o1'));
|
||||
let selIds = ['o1'];
|
||||
const bridge = {
|
||||
getIds: () => selIds,
|
||||
setIds: (ids: string[]) => {
|
||||
selIds = ids;
|
||||
},
|
||||
hitTest: () => null,
|
||||
};
|
||||
const ctx = makeCtx({ doc, selection: bridge });
|
||||
const copy = coreModifyPlugin.tools!.find((t) => t.manifest.id === 'copy')!;
|
||||
|
||||
copy.handlers.down!(pe(0, 0), ctx);
|
||||
copy.handlers.down!(pe(100, 100), ctx);
|
||||
|
||||
const all = doc.getAllElements();
|
||||
expect(all.length).toBe(2); // Original + Kopie
|
||||
expect(all[0].id).toBe('o1'); // Original unberührt
|
||||
expect(all[0].x).not.toBe(all[1].x); // Kopie versetzt
|
||||
expect(all[1].id).not.toBe('o1'); // neue ID
|
||||
expect(all[1].type).toBe(all[0].type); // gleicher Typ
|
||||
|
||||
expect(doc.undo()).toBe(true);
|
||||
expect(doc.getAllElements().length).toBe(1); // nur Original bleibt
|
||||
});
|
||||
|
||||
it('Komfort: bei leerer Selektion wird Element unter Klick auto-gewählt', () => {
|
||||
const { ydoc } = createInMemoryDoc();
|
||||
const doc = new CADDocument(ydoc);
|
||||
const target = makeEl('auto');
|
||||
target.x = 10;
|
||||
target.y = 10;
|
||||
doc.addElement(target);
|
||||
let selIds2: string[] = [];
|
||||
const bridge = {
|
||||
getIds: () => selIds2,
|
||||
setIds: (ids: string[]) => {
|
||||
selIds2 = ids;
|
||||
},
|
||||
hitTest: () => target,
|
||||
};
|
||||
const ctx = makeCtx({ doc, selection: bridge });
|
||||
const move = coreModifyPlugin.tools!.find((t) => t.manifest.id === 'move')!;
|
||||
|
||||
move.handlers.down!(pe(10, 10), ctx); // Basis + Auto-Select
|
||||
expect(selIds2).toEqual(['auto']);
|
||||
move.handlers.down!(pe(30, 30), ctx); // Zielklick (Δ=+20)
|
||||
|
||||
expect(doc.getElement('auto')!.x).toBe(30); // 10+Δ20
|
||||
});
|
||||
});
|
||||
|
||||
describe('A3 pilot: select tool', () => {
|
||||
function makeBridge(elements: CADElement[]) {
|
||||
let ids: string[] = [];
|
||||
|
||||
Reference in New Issue
Block a user