Tldraw/packages/tldraw/src/state/commands/translateShapes/translateShapes.ts

104 wiersze
2.6 KiB
TypeScript

import { Vec } from '@tldraw/vec'
import { TLDR } from '~state/TLDR'
import type { TldrawCommand, PagePartial } from '~types'
import type { TldrawApp } from '../../internal'
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.mutateShapes(
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.getBindings(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,
},
},
},
},
}
}