fix excalidraw paste (#3822)
it broke for a few things, so this fixes it and adds some tests ### Change Type - [x] `sdk` — Changes the tldraw SDK - [x] `bugfix` — Bug fix
This commit is contained in:
parent
58104c1a4c
commit
6c9ead0309
5 changed files with 3102 additions and 57 deletions
File diff suppressed because it is too large
Load diff
|
@ -0,0 +1,107 @@
|
|||
{
|
||||
"type": "excalidraw/clipboard",
|
||||
"elements": [
|
||||
{
|
||||
"type": "rectangle",
|
||||
"version": 1626,
|
||||
"versionNonce": 64820303,
|
||||
"index": "a0",
|
||||
"isDeleted": false,
|
||||
"id": "PZcAULwVLLyQ4Z9av5DmV",
|
||||
"fillStyle": "solid",
|
||||
"strokeWidth": 2,
|
||||
"strokeStyle": "solid",
|
||||
"roughness": 1,
|
||||
"opacity": 100,
|
||||
"angle": 0,
|
||||
"x": -2101.46484375,
|
||||
"y": 275.8671875,
|
||||
"strokeColor": "#1e1e1e",
|
||||
"backgroundColor": "transparent",
|
||||
"width": 149.70703125,
|
||||
"height": 116.80078125,
|
||||
"seed": 429665350,
|
||||
"groupIds": [],
|
||||
"frameId": null,
|
||||
"roundness": { "type": 3 },
|
||||
"boundElements": [{ "id": "kaL7WbxkiKT-RKqorwtRm", "type": "arrow" }],
|
||||
"updated": 1716494684633,
|
||||
"link": null,
|
||||
"locked": false
|
||||
},
|
||||
{
|
||||
"id": "3g3MQdG7t5-VkoMU4W4wh",
|
||||
"type": "rectangle",
|
||||
"x": -1852.40234375,
|
||||
"y": 240.8046875,
|
||||
"width": 156.33984375,
|
||||
"height": 129.7109375,
|
||||
"angle": 0,
|
||||
"strokeColor": "#1e1e1e",
|
||||
"backgroundColor": "transparent",
|
||||
"fillStyle": "solid",
|
||||
"strokeWidth": 2,
|
||||
"strokeStyle": "solid",
|
||||
"roughness": 1,
|
||||
"opacity": 100,
|
||||
"groupIds": [],
|
||||
"frameId": null,
|
||||
"index": "a1",
|
||||
"roundness": { "type": 3 },
|
||||
"seed": 115875375,
|
||||
"version": 201,
|
||||
"versionNonce": 331141167,
|
||||
"isDeleted": false,
|
||||
"boundElements": [{ "id": "kaL7WbxkiKT-RKqorwtRm", "type": "arrow" }],
|
||||
"updated": 1716494669928,
|
||||
"link": null,
|
||||
"locked": false
|
||||
},
|
||||
{
|
||||
"id": "kaL7WbxkiKT-RKqorwtRm",
|
||||
"type": "arrow",
|
||||
"x": -1942.37890625,
|
||||
"y": 304.1567904612487,
|
||||
"width": 77.18359375,
|
||||
"height": 13.573000528631098,
|
||||
"angle": 0,
|
||||
"strokeColor": "#1e1e1e",
|
||||
"backgroundColor": "transparent",
|
||||
"fillStyle": "solid",
|
||||
"strokeWidth": 2,
|
||||
"strokeStyle": "solid",
|
||||
"roughness": 1,
|
||||
"opacity": 100,
|
||||
"groupIds": [],
|
||||
"frameId": null,
|
||||
"index": "a2",
|
||||
"roundness": { "type": 2 },
|
||||
"seed": 1254418753,
|
||||
"version": 3490,
|
||||
"versionNonce": 1305578639,
|
||||
"isDeleted": false,
|
||||
"boundElements": null,
|
||||
"updated": 1716494684634,
|
||||
"link": null,
|
||||
"locked": false,
|
||||
"points": [
|
||||
[0, 0],
|
||||
[77.18359375, 13.573000528631098]
|
||||
],
|
||||
"lastCommittedPoint": null,
|
||||
"startBinding": {
|
||||
"elementId": "PZcAULwVLLyQ4Z9av5DmV",
|
||||
"focus": -0.6277363915690484,
|
||||
"gap": 9.37890625
|
||||
},
|
||||
"endBinding": {
|
||||
"elementId": "3g3MQdG7t5-VkoMU4W4wh",
|
||||
"focus": -0.3570621758346426,
|
||||
"gap": 12.79296875
|
||||
},
|
||||
"startArrowhead": null,
|
||||
"endArrowhead": "arrow"
|
||||
}
|
||||
],
|
||||
"files": {}
|
||||
}
|
File diff suppressed because it is too large
Load diff
|
@ -0,0 +1,43 @@
|
|||
import { readdirSync } from 'fs'
|
||||
import { readFile } from 'fs/promises'
|
||||
import { join } from 'path'
|
||||
import { TestEditor } from '../../../../test/TestEditor'
|
||||
import { pasteExcalidrawContent } from './pasteExcalidrawContent'
|
||||
|
||||
jest.mock('nanoid', () => {
|
||||
let nextNanoId = 0
|
||||
|
||||
const nanoid = () => {
|
||||
nextNanoId++
|
||||
return `${nextNanoId}`
|
||||
}
|
||||
|
||||
return {
|
||||
nanoid,
|
||||
default: nanoid,
|
||||
__reset: () => {
|
||||
nextNanoId = 0
|
||||
},
|
||||
}
|
||||
})
|
||||
|
||||
beforeEach(() => {
|
||||
// eslint-disable-next-line
|
||||
require('nanoid').__reset()
|
||||
})
|
||||
|
||||
describe('pasteExcalidrawContent test fixtures', () => {
|
||||
const files = readdirSync(join(__dirname, 'excalidraw-test-fixtures')).filter((fileName) =>
|
||||
fileName.endsWith('.json')
|
||||
)
|
||||
|
||||
test.each(files)('%s', async (fileName) => {
|
||||
const filePath = join(__dirname, 'excalidraw-test-fixtures', fileName)
|
||||
const fileContent = JSON.parse(await readFile(filePath, 'utf-8'))
|
||||
|
||||
const editor = new TestEditor()
|
||||
pasteExcalidrawContent(editor, fileContent)
|
||||
|
||||
expect(editor.store.serialize()).toMatchSnapshot()
|
||||
})
|
||||
})
|
|
@ -18,11 +18,11 @@ import {
|
|||
VecLike,
|
||||
ZERO_INDEX_KEY,
|
||||
compact,
|
||||
createBindingId,
|
||||
createShapeId,
|
||||
getIndexAbove,
|
||||
getIndices,
|
||||
isShapeId,
|
||||
uniqueId,
|
||||
} from '@tldraw/editor'
|
||||
|
||||
/**
|
||||
|
@ -38,7 +38,6 @@ export async function pasteExcalidrawContent(editor: Editor, clipboard: any, poi
|
|||
|
||||
const tldrawContent: TLContent = {
|
||||
shapes: [],
|
||||
// todo(alex) #write these properly
|
||||
bindings: [],
|
||||
rootShapeIds: [],
|
||||
assets: [],
|
||||
|
@ -165,8 +164,10 @@ export async function pasteExcalidrawContent(editor: Editor, clipboard: any, poi
|
|||
break
|
||||
}
|
||||
case 'line': {
|
||||
const start = element.points[0]
|
||||
const end = element.points[element.points.length - 1]
|
||||
const points = element.points.slice()
|
||||
if (points.length < 2) {
|
||||
break
|
||||
}
|
||||
const indices = getIndices(element.points.length)
|
||||
|
||||
tldrawContent.shapes.push({
|
||||
|
@ -177,39 +178,17 @@ export async function pasteExcalidrawContent(editor: Editor, clipboard: any, poi
|
|||
size: strokeWidthsToSizes[element.strokeWidth],
|
||||
color: colorsToColors[element.strokeColor] ?? 'black',
|
||||
spline: element.roundness ? 'cubic' : 'line',
|
||||
handles: {
|
||||
start: {
|
||||
id: 'start',
|
||||
type: 'vertex',
|
||||
index: indices[0],
|
||||
x: start[0],
|
||||
y: start[1],
|
||||
},
|
||||
end: {
|
||||
id: 'end',
|
||||
type: 'vertex',
|
||||
index: indices[indices.length - 1],
|
||||
x: end[0],
|
||||
y: end[1],
|
||||
},
|
||||
points: {
|
||||
...Object.fromEntries(
|
||||
element.points.slice(1, -1).map(([x, y]: number[], i: number) => {
|
||||
const id = uniqueId()
|
||||
return [
|
||||
id,
|
||||
{
|
||||
id,
|
||||
type: 'vertex',
|
||||
index: indices[i + 1],
|
||||
x,
|
||||
y,
|
||||
},
|
||||
]
|
||||
element.points.map(([x, y]: number[], i: number) => {
|
||||
const index = indices[i]
|
||||
return [index, { id: index, index, x, y }]
|
||||
})
|
||||
),
|
||||
},
|
||||
},
|
||||
})
|
||||
|
||||
break
|
||||
}
|
||||
case 'arrow': {
|
||||
|
@ -241,36 +220,45 @@ export async function pasteExcalidrawContent(editor: Editor, clipboard: any, poi
|
|||
dash: getDash(element),
|
||||
size: strokeWidthsToSizes[element.strokeWidth] ?? 'm',
|
||||
color: colorsToColors[element.strokeColor] ?? 'black',
|
||||
start: startTargetId
|
||||
? {
|
||||
type: 'binding',
|
||||
boundShapeId: startTargetId,
|
||||
normalizedAnchor: { x: 0.5, y: 0.5 },
|
||||
isPrecise: false,
|
||||
isExact: false,
|
||||
}
|
||||
: {
|
||||
type: 'point',
|
||||
x: start[0],
|
||||
y: start[1],
|
||||
},
|
||||
end: endTargetId
|
||||
? {
|
||||
type: 'binding',
|
||||
boundShapeId: endTargetId,
|
||||
normalizedAnchor: { x: 0.5, y: 0.5 },
|
||||
isPrecise: false,
|
||||
isExact: false,
|
||||
}
|
||||
: {
|
||||
type: 'point',
|
||||
x: end[0],
|
||||
y: end[1],
|
||||
},
|
||||
start: { x: start[0], y: start[1] },
|
||||
end: { x: end[0], y: end[1] },
|
||||
arrowheadEnd: arrowheadsToArrowheadTypes[element.endArrowhead] ?? 'none',
|
||||
arrowheadStart: arrowheadsToArrowheadTypes[element.startArrowhead] ?? 'none',
|
||||
},
|
||||
})
|
||||
|
||||
if (startTargetId) {
|
||||
tldrawContent.bindings!.push({
|
||||
id: createBindingId(),
|
||||
typeName: 'binding',
|
||||
type: 'arrow',
|
||||
fromId: id,
|
||||
toId: startTargetId,
|
||||
props: {
|
||||
terminal: 'start',
|
||||
normalizedAnchor: { x: 0.5, y: 0.5 },
|
||||
isPrecise: false,
|
||||
isExact: false,
|
||||
},
|
||||
meta: {},
|
||||
})
|
||||
}
|
||||
if (endTargetId) {
|
||||
tldrawContent.bindings!.push({
|
||||
id: createBindingId(),
|
||||
typeName: 'binding',
|
||||
type: 'arrow',
|
||||
fromId: id,
|
||||
toId: endTargetId,
|
||||
props: {
|
||||
terminal: 'end',
|
||||
normalizedAnchor: { x: 0.5, y: 0.5 },
|
||||
isPrecise: false,
|
||||
isExact: false,
|
||||
},
|
||||
meta: {},
|
||||
})
|
||||
}
|
||||
break
|
||||
}
|
||||
case 'text': {
|
||||
|
|
Loading…
Reference in a new issue