fix: undo, redo, add shape to tree

This commit is contained in:
Judicael 2022-08-23 14:32:59 +03:00
parent 18e47ad56b
commit 0d923b4700
5 changed files with 69 additions and 51 deletions

View file

@ -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(

View file

@ -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
}
}) })
} }

View file

@ -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) => {

View file

@ -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])
}) })
}) })

View file

@ -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 {