UNPKG

tldraw

Version:

A tiny little drawing editor.

256 lines (208 loc) • 7.46 kB
import { IndexKey, PageRecordType, TLShape, createShapeId } from '@tldraw/editor' import { TestEditor } from '../TestEditor' let editor: TestEditor const ids = { box1: createShapeId('box1'), box2: createShapeId('box2'), ellipse1: createShapeId('ellipse1'), ellipse2: createShapeId('ellipse2'), page1: PageRecordType.createId('page1'), page2: PageRecordType.createId('page2'), } beforeEach(() => { editor = new TestEditor() const page0Id = editor.getCurrentPageId() editor.createPage({ name: ids.page1, id: ids.page1 }) expect(editor.getCurrentPageId()).toBe(page0Id) editor.setCurrentPage(ids.page1) expect(editor.getCurrentPageId()).toBe(ids.page1) editor.createShapes([ { id: ids.ellipse1, type: 'geo', x: 0, y: 0, props: { geo: 'ellipse' } }, { id: ids.box1, type: 'geo', x: 0, y: 0 }, { id: ids.box2, parentId: ids.box1, type: 'geo', x: 150, y: 150 }, ]) editor.createPage({ name: ids.page2, id: ids.page2 }) expect(editor.getCurrentPageId()).toBe(ids.page1) expect(editor.getShape(ids.box1)!.parentId).toEqual(ids.page1) expect(editor.getShape(ids.box2)!.parentId).toEqual(ids.box1) }) describe('Editor.moveShapesToPage', () => { it('Moves shapes to page', () => { editor.moveShapesToPage([ids.box2, ids.ellipse1], ids.page2) expect(editor.getCurrentPageId()).toBe(ids.page2) expect(editor.getShape(ids.box2)!.parentId).toBe(ids.page2) expect(editor.getShape(ids.ellipse1)!.parentId).toBe(ids.page2) // box1 didn't get moved, still on page 1 expect(editor.getShape(ids.box1)!.parentId).toBe(ids.page1) expect([...editor.getCurrentPageShapeIds()].sort()).toMatchObject([ids.box2, ids.ellipse1]) expect(editor.getCurrentPageId()).toBe(ids.page2) editor.setCurrentPage(ids.page1) expect([...editor.getCurrentPageShapeIds()]).toEqual([ids.box1]) }) it('Moves children to page', () => { editor.moveShapesToPage([ids.box1], ids.page2) expect(editor.getShape(ids.box2)!.parentId).toBe(ids.box1) expect(editor.getShape(ids.box1)!.parentId).toBe(ids.page2) expect(editor.getShape(ids.ellipse1)!.parentId).toBe(ids.page1) }) it('Adds undo items', () => { editor.getHistory().clear() expect(editor.getHistory().getNumUndos()).toBe(0) editor.moveShapesToPage([ids.box1], ids.page2) expect(editor.getHistory().getNumUndos()).toBe(1) }) it('Does nothing on an empty ids array', () => { editor.getHistory().clear() editor.moveShapesToPage([], ids.page2) expect(editor.getHistory().getNumUndos()).toBe(0) }) it('Does nothing if the new page is not found or is deleted', () => { editor.getHistory().clear() editor.moveShapesToPage([ids.box1], PageRecordType.createId('missing')) expect(editor.getHistory().getNumUndos()).toBe(0) }) it('Does not move shapes to the current page', () => { editor.getHistory().clear() editor.moveShapesToPage([ids.box1], ids.page1) expect(editor.getHistory().getNumUndos()).toBe(0) }) it('Restores on undo / redo', () => { expect(editor.getCurrentPageId()).toBe(ids.page1) expect([...editor.getCurrentPageShapeIds()].sort()).toMatchObject([ ids.box1, ids.box2, ids.ellipse1, ]) editor.markHistoryStoppingPoint('move shapes to page') editor.moveShapesToPage([ids.box2], ids.page2) expect(editor.getCurrentPageId()).toBe(ids.page2) expect([...editor.getCurrentPageShapeIds()].sort()).toMatchObject([ids.box2]) editor.undo() expect(editor.getCurrentPageId()).toBe(ids.page1) expect([...editor.getCurrentPageShapeIds()].sort()).toMatchObject([ ids.box1, ids.box2, ids.ellipse1, ]) editor.redo() expect(editor.getCurrentPageId()).toBe(ids.page2) expect([...editor.getCurrentPageShapeIds()].sort()).toMatchObject([ids.box2]) }) it('Sets the correct indices', () => { editor = new TestEditor() const page2Id = PageRecordType.createId('newPage2') editor.createPage({ name: 'New Page 2', id: page2Id }) editor.setCurrentPage(page2Id) expect(editor.getCurrentPageId()).toBe(page2Id) editor.createShapes([{ id: ids.box1, type: 'geo', x: 0, y: 0, props: { geo: 'ellipse' } }]) editor.expectShapeToMatch({ id: ids.box1, parentId: page2Id, index: 'a1' as IndexKey, }) const page3Id = PageRecordType.createId('newPage3') editor.createPage({ name: 'New Page 3', id: page3Id }) editor.setCurrentPage(page3Id) expect(editor.getCurrentPageId()).toBe(page3Id) editor.createShapes([{ id: ids.box2, type: 'geo', x: 0, y: 0, props: { geo: 'ellipse' } }]) editor.expectShapeToMatch({ id: ids.box2, parentId: page3Id, index: 'a1' as IndexKey, }) editor.setCurrentPage(page2Id) editor.select(ids.box1) editor.moveShapesToPage([ids.box1], page3Id) expect(editor.getCurrentPageId()).toBe(page3Id) editor.expectShapeToMatch( { id: ids.box2, parentId: page3Id, index: 'a1' as IndexKey, }, { id: ids.box1, parentId: page3Id, index: 'a2' as IndexKey, // should be a2 now } ) }) }) describe('arrows', () => { let firstBox: TLShape let secondBox: TLShape beforeEach(() => { editor.selectAll().deleteShapes(editor.getSelectedShapeIds()) // draw a first box editor.createShapes([ { id: ids.box1, type: 'geo', x: 200, y: 200, props: { fill: 'solid', }, }, { id: ids.box2, type: 'geo', x: 400, y: 400, props: { fill: 'solid', }, }, ]) firstBox = editor.getShape(ids.box1)! secondBox = editor.getShape(ids.box2)! }) it("retains an arrow's bound position if it's bound shape is moved to another page", () => { editor.setCurrentTool('arrow') editor.pointerDown(250, 250) editor.pointerMove(255, 255) editor.pointerMove(450, 450) editor.pointerUp(450, 450) const arrow = editor.getOnlySelectedShape()! expect(editor.getShapePageBounds(editor.getOnlySelectedShape()!)).toCloselyMatchObject({ // exiting at the bottom right corner of the first box x: 300, y: 300, }) // move the second box up 200 px editor.select(secondBox.id) editor.translateSelection(0, -200) expect(editor.getArrowsBoundTo(firstBox.id).length).toBe(1) expect(editor.getArrowsBoundTo(secondBox.id).length).toBe(1) // move the second box to another page editor.moveShapesToPage([secondBox.id], ids.page2) expect(editor.getArrowsBoundTo(firstBox.id).length).toBe(1) expect(editor.getArrowsBoundTo(secondBox.id).length).toBe(0) expect(editor.getShapePageBounds(arrow)).toCloselyMatchObject({ x: 300, y: 250, w: 86.5, h: 0, }) }) it('retains the arrow binding if you move the arrow to the other page too', () => { editor .setCurrentTool('arrow') .pointerDown(250, 250) .pointerMove(255, 255) .pointerMove(450, 450) .pointerUp(450, 450) const arrow = editor.getOnlySelectedShape()! expect(editor.getArrowsBoundTo(firstBox.id).length).toBe(1) expect(editor.getArrowsBoundTo(secondBox.id).length).toBe(1) editor.moveShapesToPage([arrow.id, firstBox.id], ids.page2) expect(editor.getArrowsBoundTo(firstBox.id).length).toBe(1) expect(editor.getArrowsBoundTo(secondBox.id).length).toBe(0) }) it('centers the camera on the shapes in the new page', () => { editor.setCurrentTool('arrow').pointerDown(250, 250).pointerMove(450, 450).pointerUp(450, 450) editor.moveShapesToPage([ids.box1, ids.box2], ids.page2) const selectionPageBounds = editor.getSelectionPageBounds() expect(editor.getViewportPageCenter()).toMatchObject(selectionPageBounds!.center) }) })