Files
AFFiNE-Mirror/libs/components/board-commands/src/translate-shapes.ts
2022-07-22 15:49:21 +08:00

114 lines
3.2 KiB
TypeScript

import { Vec } from '@tldraw/vec';
import { TLDR } from '@toeverything/components/board-state';
import type {
TldrawCommand,
PagePartial,
} from '@toeverything/components/board-types';
import type { TldrawApp } from '@toeverything/components/board-state';
export function translateShapes(
app: TldrawApp,
ids: string[],
delta: number[]
): TldrawCommand {
const { currentPageId, selectedIds } = app;
// Clear session cache
app.rotationInfo.selectedIds = [...selectedIds];
const before: PagePartial = {
shapes: {},
bindings: {},
};
const after: PagePartial = {
shapes: {},
bindings: {},
};
const idsToMutate = ids
.flatMap(id => {
const shape = app.getShape(id);
return shape.children ? shape.children : shape.id;
})
.filter(id => !app.getShape(id).isLocked);
const change = TLDR.mutate_shapes(
app.state,
idsToMutate,
shape => ({
point: Vec.toFixed(Vec.add(shape.point, delta)),
}),
currentPageId
);
before.shapes = change.before;
after.shapes = change.after;
// Delete bindings from nudged shapes, unless both bound and bound-to shapes are selected
const bindingsToDelete = TLDR.get_bindings(app.state, currentPageId).filter(
binding => ids.includes(binding.fromId) && !ids.includes(binding.toId)
);
bindingsToDelete.forEach(binding => {
before.bindings[binding.id] = binding;
after.bindings[binding.id] = undefined;
for (const id of [binding.toId, binding.fromId]) {
// Let's also look at the bound shape...
const shape = app.getShape(id);
if (!shape.handles) continue;
// If the bound shape has a handle that references the deleted binding, delete that reference
Object.values(shape.handles)
.filter(handle => handle.bindingId === binding.id)
.forEach(handle => {
before.shapes[id] = {
...before.shapes[id],
handles: {
...before.shapes[id]?.handles,
[handle.id]: { bindingId: binding.id },
},
};
after.shapes[id] = {
...after.shapes[id],
handles: {
...after.shapes[id]?.handles,
[handle.id]: { bindingId: undefined },
},
};
});
}
});
return {
id: 'translate',
before: {
document: {
pages: {
[currentPageId]: before,
},
pageStates: {
[currentPageId]: {
selectedIds: ids,
},
},
},
},
after: {
document: {
pages: {
[currentPageId]: after,
},
pageStates: {
[currentPageId]: {
selectedIds: ids,
},
},
},
},
};
}