import { createShapeId } from '@tldraw/editor' import { vi } from 'vitest' import { TestEditor } from '../TestEditor' let editor: TestEditor beforeEach(() => { editor = new TestEditor() }) vi.useFakeTimers() it('animates a shape to its new position', () => { const id = createShapeId('box') editor.createShape({ id, type: 'geo', x: 0, y: 0 }) editor.animateShapes([{ id, type: 'geo', x: 100, y: 100 }], { animation: { duration: 100 } }) editor.emit('tick', 50) expect(editor.getShape(id)).toMatchObject({ x: 50, y: 50 }) editor.emit('tick', 60) expect(editor.getShape(id)).toMatchObject({ x: 100, y: 100 }) }) it('does not move locked shapes', () => { const id = createShapeId('box') editor.createShape({ id, type: 'geo', x: 0, y: 0, isLocked: true }) editor.animateShapes([{ id, type: 'geo', x: 100, y: 100 }], { animation: { duration: 100 } }) // the intermediate frames must respect the lock too, otherwise the shape is moved by every // frame but the last and ends up stranded just short of the target editor.emit('tick', 50) expect(editor.getShape(id)).toMatchObject({ x: 0, y: 0 }) editor.emit('tick', 60) expect(editor.getShape(id)).toMatchObject({ x: 0, y: 0 }) }) it('moves a locked shape all the way when the lock is ignored', () => { const id = createShapeId('box') editor.createShape({ id, type: 'geo', x: 0, y: 0, isLocked: true }) editor.run( () => { editor.animateShapes([{ id, type: 'geo', x: 100, y: 100 }], { animation: { duration: 100 } }) }, { ignoreShapeLock: true } ) editor.emit('tick', 50) expect(editor.getShape(id)).toMatchObject({ x: 50, y: 50 }) // run() has restored the lock setting by the time the final frame lands, so the final update // must remember that this animation was allowed to move the locked shape editor.emit('tick', 60) expect(editor.getShape(id)).toMatchObject({ x: 100, y: 100, isLocked: true }) }) it('does not move a child of a locked frame', () => { const frameId = createShapeId('frame') const id = createShapeId('box') editor.createShape({ id: frameId, type: 'frame', x: 0, y: 0, isLocked: true }) editor.createShape({ id, type: 'geo', x: 0, y: 0, parentId: frameId }) editor.animateShapes([{ id, type: 'geo', x: 100, y: 100 }], { animation: { duration: 100 } }) editor.emit('tick', 50) editor.emit('tick', 60) expect(editor.getShape(id)).toMatchObject({ x: 0, y: 0 }) }) it('moves a locked shape when the animation unlocks it', () => { const id = createShapeId('box') editor.createShape({ id, type: 'geo', x: 0, y: 0, isLocked: true }) editor.animateShapes([{ id, type: 'geo', x: 100, y: 100, isLocked: false }], { animation: { duration: 100 }, }) editor.emit('tick', 50) editor.emit('tick', 60) expect(editor.getShape(id)).toMatchObject({ x: 100, y: 100, isLocked: false }) })