|
|
@@ -33,21 +33,6 @@ const isValidURL = (url: string) => {
|
|
|
}
|
|
|
}
|
|
|
|
|
|
-const safeParseJson = (json: string) => {
|
|
|
- try {
|
|
|
- return JSON.parse(json)
|
|
|
- } catch {
|
|
|
- return null
|
|
|
- }
|
|
|
-}
|
|
|
-
|
|
|
-const getWhiteboardsTldrFromText = (text: string) => {
|
|
|
- const innerText = text.match(/<whiteboard-tldr>(.*)<\/whiteboard-tldr>/)?.[1]
|
|
|
- if (innerText) {
|
|
|
- return safeParseJson(decodeURIComponent(innerText))
|
|
|
- }
|
|
|
-}
|
|
|
-
|
|
|
interface VideoImageAsset extends TLAsset {
|
|
|
size?: number[]
|
|
|
}
|
|
|
@@ -71,7 +56,7 @@ function getFileType(filename: string) {
|
|
|
return 'unknown'
|
|
|
}
|
|
|
|
|
|
-type MaybeShapes = Shape['props'][] | null | undefined
|
|
|
+type MaybeShapes = TLShapeModel[] | null | undefined
|
|
|
|
|
|
type CreateShapeFN<Args extends any[]> = (...args: Args) => Promise<MaybeShapes> | MaybeShapes
|
|
|
|
|
|
@@ -263,67 +248,12 @@ export function usePaste() {
|
|
|
}
|
|
|
|
|
|
function tryCreateClonedShapesFromJSON(rawText: string) {
|
|
|
- const data = getWhiteboardsTldrFromText(rawText)
|
|
|
- try {
|
|
|
- if (data) {
|
|
|
- const shapes = data.shapes as TLShapeModel[]
|
|
|
- assetsToClone = data.assets as TLAsset[]
|
|
|
- const commonBounds = BoundsUtils.getCommonBounds(
|
|
|
- shapes.map(shape => ({
|
|
|
- minX: shape.point?.[0] ?? point[0],
|
|
|
- minY: shape.point?.[1] ?? point[1],
|
|
|
- width: shape.size?.[0] ?? 4,
|
|
|
- height: shape.size?.[1] ?? 4,
|
|
|
- maxX: (shape.point?.[0] ?? point[0]) + (shape.size?.[0] ?? 4),
|
|
|
- maxY: (shape.point?.[1] ?? point[1]) + (shape.size?.[1] ?? 4),
|
|
|
- }))
|
|
|
- )
|
|
|
- const bindings = data.bindings as Record<string, TLBinding>
|
|
|
- const shapesToCreate = shapes.map(shape => {
|
|
|
- return {
|
|
|
- ...shape,
|
|
|
- id: uniqueId(),
|
|
|
- point: [
|
|
|
- point[0] + shape.point![0] - commonBounds.minX,
|
|
|
- point[1] + shape.point![1] - commonBounds.minY,
|
|
|
- ],
|
|
|
- }
|
|
|
- })
|
|
|
-
|
|
|
- // Try to rebinding the shapes to the new assets
|
|
|
- shapesToCreate
|
|
|
- .flatMap(s => Object.values(s.handles ?? {}))
|
|
|
- .forEach(h => {
|
|
|
- if (!h.bindingId) {
|
|
|
- return
|
|
|
- }
|
|
|
- // try to bind the new shape
|
|
|
- const binding = bindings[h.bindingId]
|
|
|
- if (binding) {
|
|
|
- // if the copied binding from/to is in the source
|
|
|
- const oldFromIdx = shapes.findIndex(s => s.id === binding.fromId)
|
|
|
- const oldToIdx = shapes.findIndex(s => s.id === binding.toId)
|
|
|
- if (binding && oldFromIdx !== -1 && oldToIdx !== -1) {
|
|
|
- const newBinding: TLBinding = {
|
|
|
- ...binding,
|
|
|
- id: uniqueId(),
|
|
|
- fromId: shapesToCreate[oldFromIdx].id,
|
|
|
- toId: shapesToCreate[oldToIdx].id,
|
|
|
- }
|
|
|
- bindingsToCreate.push(newBinding)
|
|
|
- h.bindingId = newBinding.id
|
|
|
- } else {
|
|
|
- h.bindingId = undefined
|
|
|
- }
|
|
|
- } else {
|
|
|
- console.warn('binding not found', h.bindingId)
|
|
|
- }
|
|
|
- })
|
|
|
-
|
|
|
- return shapesToCreate as Shape['props'][]
|
|
|
- }
|
|
|
- } catch (err) {
|
|
|
- console.error(err)
|
|
|
+ const result = app.api.getClonedShapesFromTldrString(rawText, point)
|
|
|
+ if (result) {
|
|
|
+ const { shapes, assets, bindings } = result
|
|
|
+ assetsToClone.push(...assets)
|
|
|
+ bindingsToCreate.push(...bindings)
|
|
|
+ return shapes
|
|
|
}
|
|
|
return null
|
|
|
}
|
|
|
@@ -420,7 +350,7 @@ export function usePaste() {
|
|
|
|
|
|
app.cursors.setCursor(TLCursor.Progress)
|
|
|
|
|
|
- let newShapes: Shape['props'][] = []
|
|
|
+ let newShapes: TLShapeModel[] = []
|
|
|
try {
|
|
|
if (dataTransfer) {
|
|
|
newShapes.push(...((await tryCreateShapesFromDataTransfer(dataTransfer)) ?? []))
|
|
|
@@ -442,13 +372,13 @@ export function usePaste() {
|
|
|
})
|
|
|
|
|
|
app.wrapUpdate(() => {
|
|
|
- const allAssets = [...imageAssetsToCreate, ...assetsToClone]
|
|
|
- if (allAssets.length > 0) {
|
|
|
- app.createAssets(allAssets)
|
|
|
+ if (assetsToClone.length > 0) {
|
|
|
+ app.createAssets(assetsToClone)
|
|
|
}
|
|
|
- if (allShapesToAdd.length > 0) {
|
|
|
- app.createShapes(allShapesToAdd)
|
|
|
+ if (newShapes.length > 0) {
|
|
|
+ app.createShapes(newShapes)
|
|
|
}
|
|
|
+ app.currentPage.updateBindings(Object.fromEntries(bindingsToCreate.map(b => [b.id, b])))
|
|
|
|
|
|
if (app.selectedShapesArray.length === 1 && allShapesToAdd.length === 1 && !fromDrop) {
|
|
|
const source = app.selectedShapesArray[0]
|
|
|
@@ -456,7 +386,6 @@ export function usePaste() {
|
|
|
app.createNewLineBinding(source, target)
|
|
|
}
|
|
|
|
|
|
- app.currentPage.updateBindings(Object.fromEntries(bindingsToCreate.map(b => [b.id, b])))
|
|
|
app.setSelectedShapes(allShapesToAdd.map(s => s.id))
|
|
|
app.selectedTool.transition('idle') // clears possible editing states
|
|
|
app.cursors.setCursor(TLCursor.Default)
|