UNPKG

tldraw

Version:

A tiny little drawing editor.

119 lines (101 loc) • 10.2 kB
import { TLContent, createShapeId, structuredClone } from '@tldraw/editor' import { TestEditor } from '../TestEditor' let editor: TestEditor const clipboardContent: TLContent = JSON.parse( `{"assets":[],"shapes":[{"x":927.9906463623047,"y":725.71875,"rotation":0,"index":"aD","type":"geo","props":{"w":215.34375,"h":195.28750610351562,"geo":"rectangle","color":"black","fill":"none","dash":"draw","size":"m","opacity":"1","font":"draw","text":"","align":"middle","growY":0,"url":""},"parentId":"page:Zh9Z-7-cUdRqfGbNL092o","id":"shape:YvYcQ5pd6eYfcJVtAaUzx","typeName":"shape"},{"x":1178.971908569336,"y":763.6687622070312,"rotation":0,"index":"aE","type":"geo","props":{"w":56.559356689453125,"h":31.740631103515625,"geo":"rectangle","color":"black","fill":"none","dash":"draw","size":"m","opacity":"1","font":"draw","text":"","align":"middle","growY":0,"url":""},"parentId":"page:Zh9Z-7-cUdRqfGbNL092o","id":"shape:qGCazmD9WsedCv1qYPBVu","typeName":"shape"},{"x":1265.2625274658203,"y":780.8187561035156,"rotation":0,"index":"aF","type":"geo","props":{"w":67.7437744140625,"h":78.15313720703125,"geo":"rectangle","color":"black","fill":"none","dash":"draw","size":"m","opacity":"1","font":"draw","text":"","align":"middle","growY":0,"url":""},"parentId":"page:Zh9Z-7-cUdRqfGbNL092o","id":"shape:X9-rd27k2ZDdaHV-hsqtu","typeName":"shape"},{"x":1380.418788909912,"y":819.4562530517578,"rotation":0,"index":"aG","type":"text","props":{"opacity":"1","color":"black","size":"m","w":60.931251525878906,"text":"hello","font":"draw","align":"middle","autoSize":true,"scale":1},"parentId":"page:Zh9Z-7-cUdRqfGbNL092o","id":"shape:5FoI2ueEiMAAkxLkrHN3T","typeName":"shape"},{"x":1055.409408569336,"y":853.0687561035156,"rotation":0,"index":"aH","type":"arrow","parentId":"page:Zh9Z-7-cUdRqfGbNL092o","props":{"opacity":"1","dash":"draw","size":"m","fill":"none","color":"black","bend":0,"start":{"type":"binding","boundShapeId":"shape:YvYcQ5pd6eYfcJVtAaUzx","normalizedAnchor":{"x":0.5916993746372079,"y":0.6521154816530428},"isExact":false},"end":{"type":"binding","boundShapeId":"shape:X9-rd27k2ZDdaHV-hsqtu","normalizedAnchor":{"x":0.5,"y":0.5},"isExact":false},"arrowheadStart":"none","arrowheadEnd":"arrow","text":"","font":"draw"},"id":"shape:XMSpBf6f7pL5aW1LSQyaw","typeName":"shape"},{"x":1216.471908569336,"y":932.7437744140625,"rotation":0,"index":"aI","type":"draw","props":{"segments":[{"type":"free","points":[{"x":0,"y":0,"z":0.5},{"x":1.00311279296875,"y":-0.54376220703125,"z":0.5},{"x":7.3343505859375,"y":-4.3531494140625,"z":0.5},{"x":23.246856689453125,"y":-14.25,"z":0.5},{"x":41.484344482421875,"y":-25.706268310546875,"z":0.5},{"x":57.887481689453125,"y":-37.46250915527344,"z":0.5},{"x":70.60934448242188,"y":-48.11564636230469,"z":0.5},{"x":76.70309448242188,"y":-54.43751525878906,"z":0.5},{"x":79.51559448242188,"y":-58.25627136230469,"z":0.5},{"x":80.20309448242188,"y":-60.56877136230469,"z":0.5},{"x":72.57809448242188,"y":-60.51564025878906,"z":0.5},{"x":61.175018310546875,"y":-58.28126525878906,"z":0.5},{"x":50.137481689453125,"y":-51.80938720703125,"z":0.5},{"x":41.612518310546875,"y":-42.89064025878906,"z":0.5},{"x":37.837493896484375,"y":-34.56877136230469,"z":0.5},{"x":37.506256103515625,"y":-27.525009155273438,"z":0.5},{"x":43.350006103515625,"y":-22.406265258789062,"z":0.5},{"x":55.228118896484375,"y":-20.506271362304688,"z":0.5},{"x":72.70938110351562,"y":-24.693771362304688,"z":0.5},{"x":93.02810668945312,"y":-36.38751220703125,"z":0.5},{"x":106.99063110351562,"y":-49.09063720703125,"z":0.5},{"x":115.16561889648438,"y":-59.25001525878906,"z":0.5},{"x":120.29061889648438,"y":-66.65939331054688,"z":0.5},{"x":122.21249389648438,"y":-70.01251220703125,"z":0.5},{"x":121.01248168945312,"y":-70.11564636230469,"z":0.5},{"x":116.71560668945312,"y":-65.25938415527344,"z":0.5},{"x":111.81875610351562,"y":-56.35939025878906,"z":0.5},{"x":109.52188110351562,"y":-48.18438720703125,"z":0.5},{"x":109.10000610351562,"y":-41.89064025878906,"z":0.5},{"x":112.64999389648438,"y":-38.07501220703125,"z":0.5},{"x":121.82809448242188,"y":-39.159393310546875,"z":0.5},{"x":132.42501831054688,"y":-46.518768310546875,"z":0.5},{"x":141.89376831054688,"y":-59.88127136230469,"z":0.5},{"x":148.40621948242188,"y":-74.43751525878906,"z":0.5},{"x":150.76559448242188,"y":-83.91252136230469,"z":0.5},{"x":151.16873168945312,"y":-88.77500915527344,"z":0.5},{"x":150.39688110351562,"y":-91.09063720703125,"z":0.5},{"x":147.40621948242188,"y":-90.03126525878906,"z":0.5},{"x":142.63125610351562,"y":-83.81564331054688,"z":0.5},{"x":138.87814331054688,"y":-74.77500915527344,"z":0.5},{"x":137.00625610351562,"y":-67.02813720703125,"z":0.5},{"x":136.30624389648438,"y":-60.79689025878906,"z":0.5},{"x":137.94375610351562,"y":-57.74375915527344,"z":0.5},{"x":142.95309448242188,"y":-58.01251220703125,"z":0.5},{"x":150.82498168945312,"y":-63.815643310546875,"z":0.5},{"x":157.37496948242188,"y":-72.54376220703125,"z":0.5},{"x":160.91873168945312,"y":-79.04689025878906,"z":0.5},{"x":162.82809448242188,"y":-83.13127136230469,"z":0.5},{"x":163.27188110351562,"y":-84.72189331054688,"z":0.5},{"x":159.78121948242188,"y":-80.45314025878906,"z":0.5},{"x":155.98434448242188,"y":-70.89376831054688,"z":0.5},{"x":154.01559448242188,"y":-57.06251525878906,"z":0.5},{"x":155.79684448242188,"y":-44.25001525878906,"z":0.5},{"x":163.32498168945312,"y":-35.41252136230469,"z":0.5},{"x":175.12814331054688,"y":-30.921890258789062,"z":0.5},{"x":186.04061889648438,"y":-30.71563720703125,"z":0.5},{"x":193.04373168945312,"y":-33.35313415527344,"z":0.5},{"x":197.56564331054688,"y":-38.48439025878906,"z":0.5},{"x":200.49996948242188,"y":-43.14689636230469,"z":0.5},{"x":201.47189331054688,"y":-45.28752136230469,"z":0.5}]}],"isComplete":true,"isClosed":false,"color":"black","fill":"none","dash":"draw","size":"m","opacity":"1"},"parentId":"page:Zh9Z-7-cUdRqfGbNL092o","id":"shape:OyubUm-qwOaDbvzNoa_g0","typeName":"shape"},{"x":1465.7375030517578,"y":706.3968811035156,"rotation":0,"index":"aJ","type":"note","parentId":"page:Zh9Z-7-cUdRqfGbNL092o","props":{"opacity":"1","color":"black","size":"m","text":"v","font":"draw","align":"middle","growY":0,"url":""},"id":"shape:0D2ZNbqxTKi4d6Q3BbEls","typeName":"shape"},{"x":1324.9500274658203,"y":930.1781311035156,"rotation":0,"index":"aK","type":"frame","props":{"opacity":"1","w":85.3499755859375,"h":56.3125,"name":""},"parentId":"page:Zh9Z-7-cUdRqfGbNL092o","id":"shape:ACKcls6rrAOAgkTX_sCdm","typeName":"shape"}],"rootShapeIds":["shape:YvYcQ5pd6eYfcJVtAaUzx","shape:qGCazmD9WsedCv1qYPBVu","shape:X9-rd27k2ZDdaHV-hsqtu","shape:5FoI2ueEiMAAkxLkrHN3T","shape:XMSpBf6f7pL5aW1LSQyaw","shape:OyubUm-qwOaDbvzNoa_g0","shape:0D2ZNbqxTKi4d6Q3BbEls","shape:ACKcls6rrAOAgkTX_sCdm","shape:o3P2c-wWaerZLcWso3sYF","shape:rZe9vg-I2X7O-n58mkq0M","shape:UlgYlA5ZzNZtpZRqgABbq","shape:uabMKQtbtNDL6teToq_6D","shape:uWFz_gmKo6NscSSazs4WF","shape:TNY5G4OSvHp_wZ4eqUll9","shape:xMMH0bZqs-y6Iabio8gMT","shape:nWe_I7doDo6HgGfAFE5wu"],"schema":{"schemaVersion":1,"storeVersion":1,"recordVersions":{"asset":{"version":0,"subTypeKey":"type","subTypeVersions":{"image":1,"video":1,"bookmark":0}},"camera":{"version":0},"document":{"version":0},"instance":{"version":2},"instance_page_state":{"version":0},"page":{"version":0},"shape":{"version":0,"subTypeKey":"type","subTypeVersions":{"arrow":0,"bookmark":0,"draw":0,"embed":0,"frame":0,"geo":1,"group":0,"icon":0,"image":1,"line":0,"note":1,"text":0,"video":1}},"user":{"version":0},"user_document":{"version":0},"user_presence":{"version":0}}}}` ) beforeEach(() => { editor = new TestEditor() }) describe('Migrations', () => { it('Throws error if content does not have a schema', () => { const withoutSchema = structuredClone(clipboardContent) // @ts-expect-error delete withoutSchema.schema expect(() => editor.putContentOntoCurrentPage(withoutSchema)).toThrow() }) it('Does not throw error if content has a schema', () => { expect(() => editor.putContentOntoCurrentPage(clipboardContent)).not.toThrow() }) it('Throws error if any shape is invalid due to wrong type', () => { const withInvalidShapeType = structuredClone(clipboardContent) // @ts-expect-error withInvalidShapeType.shapes[0].type = 'invalid' expect(() => editor.putContentOntoCurrentPage(withInvalidShapeType)).toThrow() }) // we temporarily disabled validations it.skip('Throws error if any shape is invalid due to wrong model', () => { const withInvalidShapeModel = structuredClone(clipboardContent) // @ts-expect-error withInvalidShapeModel.shapes[0].x = 'invalid' expect(() => editor.putContentOntoCurrentPage(withInvalidShapeModel)).toThrow() }) }) describe('Paste parent selection with explicit point', () => { it('falls back to the page when the cursor is outside the original parent', () => { const frameId = createShapeId('frame') const childId = createShapeId('child') editor.createShapes([ { id: frameId, type: 'frame', x: 0, y: 0, props: { w: 200, h: 200 }, }, { id: childId, type: 'geo', parentId: frameId, x: 40, y: 40, props: { w: 60, h: 60 }, }, ]) editor.select(childId) editor.copy() editor.putContentOntoCurrentPage(editor.clipboard!, { point: { x: 500, y: 500 }, select: true, }) const [pastedId] = editor.getSelectedShapeIds() expect(editor.getShape(pastedId)?.parentId).toBe(editor.getCurrentPageId()) }) it('uses the parent under the cursor when it can accept the pasted shapes', () => { const frameAId = createShapeId('frameA') const frameBId = createShapeId('frameB') const childId = createShapeId('child') editor.createShapes([ { id: frameAId, type: 'frame', x: 0, y: 0, props: { w: 200, h: 200 }, }, { id: frameBId, type: 'frame', x: 400, y: 0, props: { w: 200, h: 200 }, }, { id: childId, type: 'geo', parentId: frameAId, x: 40, y: 40, props: { w: 60, h: 60 }, }, ]) editor.select(childId) editor.copy() editor.putContentOntoCurrentPage(editor.clipboard!, { point: { x: 450, y: 50 }, select: true, }) const [pastedId] = editor.getSelectedShapeIds() expect(editor.getShape(pastedId)?.parentId).toBe(frameBId) }) })