fix: undo, redo, add shape to tree
This commit is contained in:
parent
18e47ad56b
commit
0d923b4700
5 changed files with 69 additions and 51 deletions
|
@ -54,7 +54,7 @@ function addToShapeTree<T extends TLShape, M extends Record<string, unknown>>(
|
||||||
|
|
||||||
shape.children
|
shape.children
|
||||||
.map((id) => shapes[id])
|
.map((id) => shapes[id])
|
||||||
.filter(Boolean) // TODO: Find cases where shapes would be missing.
|
.filter((childShape) => shapes[childShape.id]) // TODO: Find cases where shapes would be missing.
|
||||||
.sort((a, b) => a.childIndex - b.childIndex)
|
.sort((a, b) => a.childIndex - b.childIndex)
|
||||||
.forEach((childShape) =>
|
.forEach((childShape) =>
|
||||||
addToShapeTree(
|
addToShapeTree(
|
||||||
|
|
|
@ -382,8 +382,9 @@ export class TLDR {
|
||||||
static mutateShapes<T extends TDShape>(
|
static mutateShapes<T extends TDShape>(
|
||||||
data: TDSnapshot,
|
data: TDSnapshot,
|
||||||
ids: string[],
|
ids: string[],
|
||||||
fn: (shape: T, i: number) => Partial<T> | void,
|
fn: (shape: T, i: number) => any | void,
|
||||||
pageId: string
|
pageId: string,
|
||||||
|
isFlipping?: boolean
|
||||||
): {
|
): {
|
||||||
before: Record<string, Partial<T>>
|
before: Record<string, Partial<T>>
|
||||||
after: Record<string, Partial<T>>
|
after: Record<string, Partial<T>>
|
||||||
|
@ -394,36 +395,46 @@ export class TLDR {
|
||||||
|
|
||||||
const shapes = data.document.pages?.[data.appState.currentPageId].shapes
|
const shapes = data.document.pages?.[data.appState.currentPageId].shapes
|
||||||
const groupShape = shapes?.[ids[0]]
|
const groupShape = shapes?.[ids[0]]
|
||||||
|
const isSingle = ids.length === 1
|
||||||
|
|
||||||
if (ids.length === 1 && groupShape?.type === 'group') {
|
const mirror = (data: TDSnapshot, shapeId: string, pageId: string, index: number) => {
|
||||||
groupShape.children.forEach((id, i) => {
|
const shape = TLDR.getShape<T>(data, shapeId, pageId)
|
||||||
const shape = TLDR.getShape<T>(data, id, pageId)
|
if (shape.isLocked) return
|
||||||
if (shape.isLocked) return
|
const change = fn(shape, index)
|
||||||
const change = fn(shape, i)
|
if (change) {
|
||||||
if (change) {
|
if (shape.children && isFlipping) {
|
||||||
beforeShapes[id] = TLDR.getBeforeShape(shape, change)
|
console.log('hello')
|
||||||
afterShapes[id] = change
|
|
||||||
|
shape.children.forEach((childId, i) => {
|
||||||
|
const childShape = TLDR.getShape<T>(data, childId, pageId)
|
||||||
|
const changeChild = fn(shape, i)
|
||||||
|
const pointY = change.dy ? change.dy + childShape.point[1] : childShape.point[1]
|
||||||
|
const pointX = change.dx ? change.dx + childShape.point[0] : childShape.point[0]
|
||||||
|
const nextChange: Partial<T> = {
|
||||||
|
...changeChild,
|
||||||
|
point: [pointX, pointY],
|
||||||
|
}
|
||||||
|
|
||||||
|
beforeShapes[childId] = {
|
||||||
|
point: childShape.point,
|
||||||
|
} as Partial<T>
|
||||||
|
afterShapes[childId] = nextChange
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
const nextChange = 'transformedValue' in change ? change.transformedValue : change
|
||||||
|
beforeShapes[shapeId] = TLDR.getBeforeShape(shape, nextChange)
|
||||||
|
afterShapes[shapeId] = nextChange
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isSingle && groupShape?.children && isFlipping) {
|
||||||
|
groupShape.children.forEach((id, i) => {
|
||||||
|
mirror(data, id, pageId, i)
|
||||||
})
|
})
|
||||||
} else {
|
} else {
|
||||||
ids.forEach((id, i) => {
|
ids.forEach((id, i) => {
|
||||||
const shape = TLDR.getShape<T>(data, id, pageId)
|
mirror(data, id, pageId, i)
|
||||||
if (shape.isLocked) return
|
|
||||||
if (shape.children) {
|
|
||||||
for (const [index, child] of shape.children.entries()) {
|
|
||||||
const childShape = TLDR.getShape<T>(data, child, pageId)
|
|
||||||
const change = fn(childShape, Number(index))
|
|
||||||
if (change) {
|
|
||||||
beforeShapes[child] = TLDR.getBeforeShape(shape, change)
|
|
||||||
afterShapes[child] = change
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
const change = fn(shape, i)
|
|
||||||
if (change) {
|
|
||||||
beforeShapes[id] = TLDR.getBeforeShape(shape, change)
|
|
||||||
afterShapes[id] = change
|
|
||||||
}
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -48,7 +48,8 @@ export function alignShapes(app: TldrawApp, ids: string[], type: AlignType): Tld
|
||||||
if (!deltaMap[shape.id]) return shape
|
if (!deltaMap[shape.id]) return shape
|
||||||
return { point: deltaMap[shape.id].next }
|
return { point: deltaMap[shape.id].next }
|
||||||
},
|
},
|
||||||
currentPageId
|
currentPageId,
|
||||||
|
false
|
||||||
)
|
)
|
||||||
|
|
||||||
initialShapes.forEach((shape) => {
|
initialShapes.forEach((shape) => {
|
||||||
|
|
|
@ -100,11 +100,11 @@ describe('Flip command', () => {
|
||||||
|
|
||||||
app.flipHorizontal()
|
app.flipHorizontal()
|
||||||
|
|
||||||
expect(app.getShape<RectangleShape>('rect1').point).toStrictEqual([100, 0])
|
expect(app.getShape<RectangleShape>('rect1').point).toStrictEqual([0, 0])
|
||||||
expect(app.getShape<RectangleShape>('rect2').point).toStrictEqual([0, 100])
|
expect(app.getShape<RectangleShape>('rect2').point).toStrictEqual([100, 100])
|
||||||
|
|
||||||
app.flipVertical()
|
app.flipVertical()
|
||||||
expect(app.getShape<RectangleShape>('rect1').point).toStrictEqual([100, 100])
|
expect(app.getShape<RectangleShape>('rect1').point).toStrictEqual([0, 0])
|
||||||
expect(app.getShape<RectangleShape>('rect2').point).toStrictEqual([0, 0])
|
expect(app.getShape<RectangleShape>('rect2').point).toStrictEqual([100, 100])
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
|
@ -1,8 +1,8 @@
|
||||||
|
import { TLBoundsCorner, Utils } from '@tldraw/core'
|
||||||
import { TLDR } from '~state/TLDR'
|
import { TLDR } from '~state/TLDR'
|
||||||
import type { TldrawApp } from '~state/TldrawApp'
|
import type { TldrawApp } from '~state/TldrawApp'
|
||||||
import { FlipType } from '~types'
|
import { FlipType } from '~types'
|
||||||
import type { TldrawCommand } from '~types'
|
import type { TldrawCommand } from '~types'
|
||||||
import { TLBoundsCorner, Utils } from '@tldraw/core'
|
|
||||||
|
|
||||||
export function flipShapes(app: TldrawApp, ids: string[], type: FlipType): TldrawCommand {
|
export function flipShapes(app: TldrawApp, ids: string[], type: FlipType): TldrawCommand {
|
||||||
const {
|
const {
|
||||||
|
@ -29,14 +29,17 @@ export function flipShapes(app: TldrawApp, ids: string[], type: FlipType): Tldra
|
||||||
true,
|
true,
|
||||||
false
|
false
|
||||||
)
|
)
|
||||||
|
const dx = newShapeBounds.minX - shapeBounds.minX
|
||||||
return TLDR.getShapeUtil(shape).transform(shape, newShapeBounds, {
|
return {
|
||||||
type: TLBoundsCorner.TopLeft,
|
dx,
|
||||||
scaleX: -1,
|
transformedValue: TLDR.getShapeUtil(shape).transform(shape, newShapeBounds, {
|
||||||
scaleY: 1,
|
type: TLBoundsCorner.TopLeft,
|
||||||
initialShape: shape,
|
scaleX: -1,
|
||||||
transformOrigin: [0.5, 0.5],
|
scaleY: 1,
|
||||||
})
|
initialShape: shape,
|
||||||
|
transformOrigin: [0.5, 0.5],
|
||||||
|
}),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
case FlipType.Vertical: {
|
case FlipType.Vertical: {
|
||||||
const newShapeBounds = Utils.getRelativeTransformedBoundingBox(
|
const newShapeBounds = Utils.getRelativeTransformedBoundingBox(
|
||||||
|
@ -46,18 +49,21 @@ export function flipShapes(app: TldrawApp, ids: string[], type: FlipType): Tldra
|
||||||
false,
|
false,
|
||||||
true
|
true
|
||||||
)
|
)
|
||||||
|
return {
|
||||||
return TLDR.getShapeUtil(shape).transform(shape, newShapeBounds, {
|
dy: newShapeBounds.minY - shapeBounds.minY,
|
||||||
type: TLBoundsCorner.TopLeft,
|
transformedValue: TLDR.getShapeUtil(shape).transform(shape, newShapeBounds, {
|
||||||
scaleX: 1,
|
type: TLBoundsCorner.TopLeft,
|
||||||
scaleY: -1,
|
scaleX: 1,
|
||||||
initialShape: shape,
|
scaleY: -1,
|
||||||
transformOrigin: [0.5, 0.5],
|
initialShape: shape,
|
||||||
})
|
transformOrigin: [0.5, 0.5],
|
||||||
|
}),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
currentPageId
|
currentPageId,
|
||||||
|
true
|
||||||
)
|
)
|
||||||
|
|
||||||
return {
|
return {
|
||||||
|
|
Loading…
Reference in a new issue