Add optional generic to `updateShapes` / `createShapes` (#1579)

This PR adds a generic that we can use with `updateShapes` and
`createShapes` in order to type the partials being passed into those
methods. By default, the partials are typed as `TLUnknownShape`, which
accepts any props.

### Change Type

- [x] `minor` — New feature

### Test Plan

- [x] Unit Tests

### Release Notes

- [editor] adds an optional shape generic to `updateShapes` and
`createShapes`
pull/1583/head
Steve Ruiz 2023-06-13 19:02:17 +01:00 zatwierdzone przez GitHub
rodzic 69e5b248ca
commit ce1cf82029
Nie znaleziono w bazie danych klucza dla tego podpisu
ID klucza GPG: 4AEE18F83AFDEB23
20 zmienionych plików z 436 dodań i 274 usunięć

Wyświetl plik

@ -1,4 +1,11 @@
import { createShapeId, Editor, Tldraw, TLGeoShape, useEditor } from '@tldraw/tldraw'
import {
createShapeId,
Editor,
Tldraw,
TLGeoShape,
TLShapePartial,
useEditor,
} from '@tldraw/tldraw'
import '@tldraw/tldraw/editor.css'
import '@tldraw/tldraw/ui.css'
import { useEffect } from 'react'
@ -18,7 +25,7 @@ export default function APIExample() {
editor.focus()
// Create a shape
editor.createShapes([
editor.createShapes<TLGeoShape>([
{
id,
type: 'geo',
@ -38,17 +45,17 @@ export default function APIExample() {
// Get the created shape
const shape = editor.getShapeById<TLGeoShape>(id)!
// Update the shape
editor.updateShapes([
{
id,
type: 'geo',
props: {
h: shape.props.h * 3,
text: 'hello world!',
},
const shapeUpdate: TLShapePartial<TLGeoShape> = {
id,
type: 'geo',
props: {
h: shape.props.h * 3,
text: 'hello world!',
},
])
}
// Update the shape
editor.updateShapes([shapeUpdate])
// Select the shape
editor.select(id)

Wyświetl plik

@ -1,4 +1,4 @@
import { createShapeId, Tldraw } from '@tldraw/tldraw'
import { createShapeId, Tldraw, TLShapePartial } from '@tldraw/tldraw'
import '@tldraw/tldraw/editor.css'
import '@tldraw/tldraw/ui.css'
import { ErrorShape } from './ErrorShape'
@ -16,16 +16,16 @@ export default function ErrorBoundaryExample() {
ShapeErrorFallback: ({ error }) => <div>Shape error! {String(error)}</div>, // use a custom error fallback for shapes
}}
onMount={(editor) => {
const errorShapePartial: TLShapePartial<ErrorShape> = {
type: 'error',
id: createShapeId(),
x: 0,
y: 0,
props: { message: 'Something has gone wrong' },
}
// When the app starts, create our error shape so we can see.
editor.createShapes([
{
type: 'error',
id: createShapeId(),
x: 0,
y: 0,
props: { message: 'Something has gone wrong' },
},
])
editor.createShapes<ErrorShape>([errorShapePartial])
// Center the camera on the error shape
editor.zoomToFit()

Wyświetl plik

@ -424,7 +424,7 @@ export class Editor extends EventEmitter<TLEventMap> {
};
};
createPage(title: string, id?: TLPageId, belowPageIndex?: string): this;
createShapes(partials: TLShapePartial[], select?: boolean): this;
createShapes<T extends TLUnknownShape>(partials: TLShapePartial<T>[], select?: boolean): this;
get croppingId(): null | TLShapeId;
get cullingBounds(): Box2d;
// @internal (undocumented)
@ -760,7 +760,7 @@ export class Editor extends EventEmitter<TLEventMap> {
updateDocumentSettings(settings: Partial<TLDocument>): void;
updateInstanceState(partial: Partial<Omit<TLInstance, 'currentPageId'>>, ephemeral?: boolean, squashing?: boolean): this;
updatePage(partial: RequiredKeys<TLPage, 'id'>, squashing?: boolean): this;
updateShapes(partials: (null | TLShapePartial | undefined)[], squashing?: boolean): this;
updateShapes<T extends TLUnknownShape>(partials: (null | TLShapePartial<T> | undefined)[], squashing?: boolean): this;
updateViewportScreenBounds(center?: boolean): this;
// (undocumented)
readonly user: UserPreferencesManager;

Wyświetl plik

@ -1348,7 +1348,7 @@ export class Editor extends EventEmitter<TLEventMap> {
}
if (finalIndex !== reparentedArrow.index) {
this.updateShapes([{ id: arrowId, type: 'arrow', index: finalIndex }])
this.updateShapes<TLArrowShape>([{ id: arrowId, type: 'arrow', index: finalIndex }])
}
}
@ -4636,14 +4636,14 @@ export class Editor extends EventEmitter<TLEventMap> {
* @example
*
* ```ts
* editor.createShapes([{ id: 'box1', type: 'box' }])
* editor.createShapes([{ id: 'box1', type: 'text', props: { text: "ok" } }])
* ```
*
* @param partials - The shape partials to create.
* @param select - Whether to select the created shapes. Defaults to false.
* @public
*/
createShapes(partials: TLShapePartial[], select = false) {
createShapes<T extends TLUnknownShape>(partials: TLShapePartial<T>[], select = false) {
this._createShapes(partials, select)
return this
}
@ -4934,14 +4934,17 @@ export class Editor extends EventEmitter<TLEventMap> {
* @example
*
* ```ts
* editor.updateShapes([{ id: 'box1', type: 'box', x: 100, y: 100 }])
* editor.updateShapes([{ id: 'box1', type: 'geo', props: { w: 100, h: 100 } }])
* ```
*
* @param partials - The shape partials to update.
* @param squashing - Whether the change is ephemeral.
* @public
*/
updateShapes(partials: (TLShapePartial | null | undefined)[], squashing = false) {
updateShapes<T extends TLUnknownShape>(
partials: (TLShapePartial<T> | null | undefined)[],
squashing = false
) {
let compactedPartials = compact(partials)
if (this.animatingShapes.size > 0) {
compactedPartials.forEach((p) => this.animatingShapes.delete(p.id))
@ -8985,7 +8988,7 @@ export class Editor extends EventEmitter<TLEventMap> {
const highestIndex = shapesWithRootParent[shapesWithRootParent.length - 1]?.index
this.batch(() => {
this.createShapes([
this.createShapes<TLGroupShape>([
{
id: groupId,
type: 'group',

Wyświetl plik

@ -1,4 +1,4 @@
import { TLShapeId } from '@tldraw/tlschema'
import { TLArrowShape, TLShapeId } from '@tldraw/tlschema'
import { TestEditor } from '../../test/TestEditor'
import { TL } from '../../test/jsx'
@ -212,7 +212,7 @@ describe('arrowBindingsIndex', () => {
)
// move arrowA from box2 to box3
editor.updateShapes([
editor.updateShapes<TLArrowShape>([
{
id: arrowAId,
type: 'arrow',

Wyświetl plik

@ -6,6 +6,8 @@ import {
TLAssetId,
TLEmbedShape,
TLShapePartial,
TLTextShape,
TLTextShapeProps,
createShapeId,
} from '@tldraw/tlschema'
import { compact, getHashForString } from '@tldraw/utils'
@ -248,7 +250,7 @@ export class ExternalContentManager {
let w: number
let h: number
let autoSize: boolean
let align = 'middle'
let align = 'middle' as TLTextShapeProps['align']
const isMultiLine = textToPaste.split('\n').length > 1
@ -293,7 +295,7 @@ export class ExternalContentManager {
p.y = editor.viewportPageBounds.minY + 40 + h / 2
}
editor.createShapes([
editor.createShapes<TLTextShape>([
{
id: createShapeId(),
type: 'text',

Wyświetl plik

@ -907,7 +907,7 @@ export class ArrowShapeUtil extends ShapeUtil<TLArrowShape> {
} = shape
if (text.trimEnd() !== shape.props.text) {
this.editor.updateShapes([
this.editor.updateShapes<TLArrowShape>([
{
id,
type,

Wyświetl plik

@ -2,7 +2,6 @@ import { createShapeId, TLArrowShape } from '@tldraw/tlschema'
import { ArrowShapeUtil } from '../../../shapes/arrow/ArrowShapeUtil'
import { StateNode } from '../../../tools/StateNode'
import { TLEventHandlers } from '../../../types/event-types'
import { ArrowShapeTool } from '../ArrowShapeTool'
export class Pointing extends StateNode {
static override id = 'pointing'
@ -31,16 +30,14 @@ export class Pointing extends StateNode {
this.didTimeout = false
const shapeType = (this.parent as ArrowShapeTool).shapeType
this.editor.mark('creating')
const id = createShapeId()
this.editor.createShapes([
this.editor.createShapes<TLArrowShape>([
{
id,
type: shapeType,
type: 'arrow',
x: currentPagePoint.x,
y: currentPagePoint.y,
},

Wyświetl plik

@ -139,7 +139,7 @@ function updateBookmarkAssetOnUrlChange(editor: Editor, shape: TLBookmarkShape)
if (editor.getAssetById(assetId)) {
// Existing asset for this URL?
if (shape.props.assetId !== assetId) {
editor.updateShapes([
editor.updateShapes<TLBookmarkShape>([
{
id: shape.id,
type: shape.type,
@ -151,7 +151,7 @@ function updateBookmarkAssetOnUrlChange(editor: Editor, shape: TLBookmarkShape)
// No asset for this URL?
// First, clear out the existing asset reference
editor.updateShapes([
editor.updateShapes<TLBookmarkShape>([
{
id: shape.id,
type: shape.type,
@ -181,7 +181,7 @@ const createBookmarkAssetOnUrlChange = debounce(async (editor: Editor, shape: TL
editor.createAssets([asset])
// And update the shape
editor.updateShapes([
editor.updateShapes<TLBookmarkShape>([
{
id: shape.id,
type: shape.type,

Wyświetl plik

@ -4,6 +4,7 @@ import {
TLDrawShape,
TLDrawShapeSegment,
TLHighlightShape,
TLShapePartial,
TLSizeType,
Vec2dModel,
} from '@tldraw/tlschema'
@ -25,7 +26,7 @@ export class Drawing extends StateNode {
initialShape?: DrawableShape
shapeType: 'draw' | 'highlight' = this.parent.id === 'highlight' ? 'highlight' : 'draw'
shapeType: DrawableShape['type'] = this.parent.id === 'highlight' ? 'highlight' : 'draw'
util =
this.shapeType === 'highlight'
@ -219,16 +220,22 @@ export class Drawing extends StateNode {
this.currentLineLength = this.getLineLength(segments)
this.editor.updateShapes([
{
id: shape.id,
type: this.shapeType,
props: {
segments,
isClosed: this.canClose() ? this.getIsClosed(segments, shape.props.size) : undefined,
},
const shapePartial: TLShapePartial<DrawableShape> = {
id: shape.id,
type: this.shapeType,
props: {
segments,
},
])
}
if (this.canClose()) {
;(shapePartial as TLShapePartial<TLDrawShape>).props!.isClosed = this.getIsClosed(
segments,
shape.props.size
)
}
this.editor.updateShapes<TLDrawShape | TLHighlightShape>([shapePartial])
return
}
@ -238,7 +245,8 @@ export class Drawing extends StateNode {
this.pagePointWhereCurrentSegmentChanged = originPagePoint.clone()
const id = createShapeId()
this.editor.createShapes([
this.editor.createShapes<DrawableShape>([
{
id,
type: this.shapeType,
@ -261,7 +269,6 @@ export class Drawing extends StateNode {
},
},
])
this.currentLineLength = 0
this.initialShape = this.editor.getShapeById<DrawableShape>(id)
}
@ -343,19 +350,22 @@ export class Drawing extends StateNode {
}
}
this.editor.updateShapes(
[
{
id,
type: this.shapeType,
props: {
segments: [...segments, newSegment],
isClosed: this.canClose() ? this.getIsClosed(segments, size) : undefined,
},
},
],
true
)
const shapePartial: TLShapePartial<DrawableShape> = {
id,
type: this.shapeType,
props: {
segments: [...segments, newSegment],
},
}
if (this.canClose()) {
;(shapePartial as TLShapePartial<TLDrawShape>).props!.isClosed = this.getIsClosed(
segments,
size
)
}
this.editor.updateShapes<TLDrawShape | TLHighlightShape>([shapePartial], true)
}
break
}
@ -400,19 +410,22 @@ export class Drawing extends StateNode {
const finalSegments = [...newSegments, newFreeSegment]
this.currentLineLength = this.getLineLength(finalSegments)
this.editor.updateShapes(
[
{
id,
type: this.shapeType,
props: {
segments: finalSegments,
isClosed: this.canClose() ? this.getIsClosed(finalSegments, size) : undefined,
},
},
],
true
)
const shapePartial: TLShapePartial<DrawableShape> = {
id,
type: this.shapeType,
props: {
segments: finalSegments,
},
}
if (this.canClose()) {
;(shapePartial as TLShapePartial<TLDrawShape>).props!.isClosed = this.getIsClosed(
finalSegments,
size
)
}
this.editor.updateShapes([shapePartial], true)
}
break
@ -539,19 +552,22 @@ export class Drawing extends StateNode {
points: [newSegment.points[0], newPoint],
}
this.editor.updateShapes(
[
{
id,
type: this.shapeType,
props: {
segments: newSegments,
isClosed: this.canClose() ? this.getIsClosed(segments, size) : undefined,
},
},
],
true
)
const shapePartial: TLShapePartial<DrawableShape> = {
id,
type: this.shapeType,
props: {
segments: newSegments,
},
}
if (this.canClose()) {
;(shapePartial as TLShapePartial<TLDrawShape>).props!.isClosed = this.getIsClosed(
segments,
size
)
}
this.editor.updateShapes([shapePartial], true)
break
}
@ -581,19 +597,22 @@ export class Drawing extends StateNode {
this.currentLineLength = this.getLineLength(newSegments)
this.editor.updateShapes(
[
{
id,
type: this.shapeType,
props: {
segments: newSegments,
isClosed: this.canClose() ? this.getIsClosed(segments, size) : undefined,
},
},
],
true
)
const shapePartial: TLShapePartial<DrawableShape> = {
id,
type: this.shapeType,
props: {
segments: newSegments,
},
}
if (this.canClose()) {
;(shapePartial as TLShapePartial<TLDrawShape>).props!.isClosed = this.getIsClosed(
newSegments,
size
)
}
this.editor.updateShapes([shapePartial], true)
// Set a maximum length for the lines array; after 200 points, complete the line.
if (newPoints.length > 500) {
@ -603,7 +622,7 @@ export class Drawing extends StateNode {
const newShapeId = createShapeId()
this.editor.createShapes([
this.editor.createShapes<DrawableShape>([
{
id: newShapeId,
type: this.shapeType,

Wyświetl plik

@ -14,7 +14,7 @@ export class Pointing extends StateNode {
this.editor.mark('creating')
this.editor.createShapes([
this.editor.createShapes<TLGeoShape>([
{
id,
type: 'geo',
@ -63,7 +63,7 @@ export class Pointing extends StateNode {
this.editor.mark('creating')
this.editor.createShapes([
this.editor.createShapes<TLGeoShape>([
{
id,
type: 'geo',
@ -85,7 +85,7 @@ export class Pointing extends StateNode {
const delta = this.editor.getDeltaInParentSpace(shape, bounds.center)
this.editor.select(id)
this.editor.updateShapes([
this.editor.updateShapes<TLGeoShape>([
{
id: shape.id,
type: 'geo',

Wyświetl plik

@ -4,7 +4,6 @@ import { TLHandle, TLLineShape, TLShapeId, createShapeId } from '@tldraw/tlschem
import { last, structuredClone } from '@tldraw/utils'
import { StateNode } from '../../../tools/StateNode'
import { TLEventHandlers, TLInterruptEvent } from '../../../types/event-types'
import { LineShapeTool } from '../LineShapeTool'
export class Pointing extends StateNode {
static override id = 'pointing'
@ -79,10 +78,10 @@ export class Pointing extends StateNode {
} else {
const id = createShapeId()
this.editor.createShapes([
this.editor.createShapes<TLLineShape>([
{
id,
type: (this.parent as LineShapeTool).shapeType,
type: 'line',
x: currentPagePoint.x,
y: currentPagePoint.y,
},

Wyświetl plik

@ -1,5 +1,5 @@
/* eslint-disable no-inner-declarations */
import { TLShape } from '@tldraw/tlschema'
import { TLShape, TLUnknownShape } from '@tldraw/tlschema'
import React, { useCallback, useEffect, useRef } from 'react'
import { useValue } from 'signia-react'
import { useEditor } from '../../../hooks/useEditor'
@ -145,7 +145,9 @@ export function useEditableText<T extends Extract<TLShape, { props: { text: stri
}
// ----------------------------
editor.updateShapes([{ id, type, props: { text } }])
editor.updateShapes<TLUnknownShape & { props: { text: string } }>([
{ id, type, props: { text } },
])
},
[editor, id, type]
)

Wyświetl plik

@ -21,7 +21,7 @@ export class Pointing extends StateNode {
this.editor.mark('creating')
this.editor.createShapes([
this.editor.createShapes<TLTextShape>([
{
id,
type: 'text',

Wyświetl plik

@ -27,20 +27,21 @@ export class Pointing extends StateNode {
this.editor.mark(this.markId)
this.editor.createShapes([
{
id,
type: shapeType,
x: originPagePoint.x,
y: originPagePoint.y,
props: {
w: 1,
h: 1,
this.editor.createShapes<TLBaseBoxShape>(
[
{
id,
type: shapeType,
x: originPagePoint.x,
y: originPagePoint.y,
props: {
w: 1,
h: 1,
},
},
},
])
this.editor.setSelectedIds([id])
],
true
)
this.editor.setSelectedTool('select.resizing', {
...info,
target: 'selection',
@ -83,7 +84,7 @@ export class Pointing extends StateNode {
this.editor.mark(this.markId)
this.editor.createShapes([
this.editor.createShapes<TLBaseBoxShape>([
{
id,
type: shapeType,
@ -96,7 +97,7 @@ export class Pointing extends StateNode {
const { w, h } = this.editor.getShapeUtil(shape).defaultProps() as TLBaseBoxShape['props']
const delta = this.editor.getDeltaInParentSpace(shape, new Vec2d(w / 2, h / 2))
this.editor.updateShapes([
this.editor.updateShapes<TLBaseBoxShape>([
{
id,
type: shapeType,

Wyświetl plik

@ -185,7 +185,7 @@ export class Idle extends StateNode {
this.editor.mark('translate crop')
}
this.editor.updateShapes([partial])
this.editor.updateShapes<ShapeWithCrop>([partial])
}
}
}

Wyświetl plik

@ -1,5 +1,5 @@
import { Vec2d } from '@tldraw/primitives'
import { TLGeoShape, TLShape, createShapeId } from '@tldraw/tlschema'
import { TLGeoShape, TLShape, TLTextShape, createShapeId } from '@tldraw/tlschema'
import { debugFlags } from '../../../../utils/debug-flags'
import {
TLClickEventInfo,
@ -382,7 +382,7 @@ export class Idle extends StateNode {
const { x, y } = this.editor.inputs.currentPagePoint
this.editor.createShapes([
this.editor.createShapes<TLTextShape>([
{
id,
type: 'text',

Wyświetl plik

@ -1,4 +1,4 @@
import { TLGeoShape, createShapeId } from '@tldraw/tlschema'
import { TLArrowShape, TLGeoShape, createShapeId } from '@tldraw/tlschema'
import { TestEditor } from '../TestEditor'
let editor: TestEditor
@ -16,6 +16,72 @@ beforeEach(() => {
editor = new TestEditor()
})
it('Uses typescript generics', () => {
expect(() => {
// No error here because no generic, the editor doesn't know what this guy is
editor.createShapes([
{
id: ids.box1,
type: 'geo',
props: { w: 'OH NO' },
},
])
// Yep error here because we are giving the wrong props to the shape
editor.createShapes<TLGeoShape>([
{
id: ids.box1,
type: 'geo',
//@ts-expect-error
props: { w: 'OH NO' },
},
])
// Yep error here because we are giving the wrong generic
editor.createShapes<TLArrowShape>([
{
id: ids.box1,
//@ts-expect-error
type: 'geo',
//@ts-expect-error
props: { w: 'OH NO' },
},
])
// All good, correct match of generic and shape type
editor.createShapes<TLGeoShape>([
{
id: ids.box1,
type: 'geo',
props: { w: 100 },
},
])
editor.createShapes<TLGeoShape>([
{
id: ids.box1,
type: 'geo',
},
{
id: ids.box1,
// @ts-expect-error - wrong type
type: 'arrow',
},
])
// Unions are supported just fine
editor.createShapes<TLGeoShape | TLArrowShape>([
{
id: ids.box1,
type: 'geo',
},
{
id: ids.box1,
type: 'arrow',
},
])
}).toThrowError()
})
it('Parents shapes to the current page if the parent is not found', () => {
editor.createShapes([{ id: ids.box1, parentId: ids.missing, type: 'geo' }])
expect(editor.getShapeById(ids.box1)!.parentId).toEqual(editor.currentPageId)

Wyświetl plik

@ -1,4 +1,4 @@
import { createShapeId } from '@tldraw/tlschema'
import { createShapeId, TLArrowShape, TLGeoShape } from '@tldraw/tlschema'
import { createDefaultShapes, TestEditor } from '../TestEditor'
let editor: TestEditor
@ -13,6 +13,73 @@ beforeEach(() => {
editor.createShapes(createDefaultShapes())
})
it('Uses typescript generics', () => {
expect(() => {
// No error here because no generic, the editor doesn't know what this guy is
editor.updateShapes([
{
id: ids.box1,
type: 'geo',
props: { w: 'OH NO' },
},
])
// Yep error here because we are giving the wrong props to the shape
editor.updateShapes<TLGeoShape>([
{
id: ids.box1,
type: 'geo',
//@ts-expect-error
props: { w: 'OH NO' },
},
])
// Yep error here because we are giving the wrong generic
editor.updateShapes<TLArrowShape>([
{
id: ids.box1,
//@ts-expect-error
type: 'geo',
//@ts-expect-error
props: { w: 'OH NO' },
},
])
// All good, correct match of generic and shape type
editor.updateShapes<TLGeoShape>([
{
id: ids.box1,
type: 'geo',
props: { w: 100 },
},
])
editor.updateShapes<TLGeoShape>([
{
id: ids.box1,
type: 'geo',
},
{
id: ids.box1,
// @ts-expect-error - wrong type
type: 'arrow',
},
])
// Unions are supported just fine
editor.updateShapes<TLGeoShape | TLArrowShape>([
{
id: ids.box1,
type: 'geo',
},
{
id: ids.box1,
type: 'arrow',
},
])
}).toThrowError()
})
it('updates shapes', () => {
editor.mark('update shapes')
editor.updateShapes([

Wyświetl plik

@ -19,7 +19,6 @@ import {
TLNoteShape,
TLPageId,
TLShapeId,
TLShapePartial,
TLSizeType,
TLTextShape,
TLVideoShape,
@ -182,41 +181,41 @@ export function buildFromV1Document(editor: Editor, document: LegacyTldrawDocume
switch (v1Shape.type) {
case TDShapeType.Sticky: {
const partial: TLShapePartial<TLNoteShape> = {
...inCommon,
type: 'note',
props: {
text: v1Shape.text ?? '',
color: getV2Color(v1Shape.style.color),
size: getV2Size(v1Shape.style.size),
font: getV2Font(v1Shape.style.font),
align: getV2Align(v1Shape.style.textAlign),
editor.createShapes<TLNoteShape>([
{
...inCommon,
type: 'note',
props: {
text: v1Shape.text ?? '',
color: getV2Color(v1Shape.style.color),
size: getV2Size(v1Shape.style.size),
font: getV2Font(v1Shape.style.font),
align: getV2Align(v1Shape.style.textAlign),
},
},
}
editor.createShapes([partial])
])
break
}
case TDShapeType.Rectangle: {
const partial: TLShapePartial<TLGeoShape> = {
...inCommon,
type: 'geo',
props: {
geo: 'rectangle',
w: coerceDimension(v1Shape.size[0]),
h: coerceDimension(v1Shape.size[1]),
text: v1Shape.label ?? '',
fill: getV2Fill(v1Shape.style.isFilled, v1Shape.style.color),
labelColor: getV2Color(v1Shape.style.color),
color: getV2Color(v1Shape.style.color),
size: getV2Size(v1Shape.style.size),
font: getV2Font(v1Shape.style.font),
dash: getV2Dash(v1Shape.style.dash),
align: 'middle',
editor.createShapes<TLGeoShape>([
{
...inCommon,
type: 'geo',
props: {
geo: 'rectangle',
w: coerceDimension(v1Shape.size[0]),
h: coerceDimension(v1Shape.size[1]),
text: v1Shape.label ?? '',
fill: getV2Fill(v1Shape.style.isFilled, v1Shape.style.color),
labelColor: getV2Color(v1Shape.style.color),
color: getV2Color(v1Shape.style.color),
size: getV2Size(v1Shape.style.size),
font: getV2Font(v1Shape.style.font),
dash: getV2Dash(v1Shape.style.dash),
align: 'middle',
},
},
}
editor.createShapes([partial])
])
const pageBoundsBeforeLabel = editor.getPageBoundsById(inCommon.id)!
@ -254,24 +253,24 @@ export function buildFromV1Document(editor: Editor, document: LegacyTldrawDocume
break
}
case TDShapeType.Triangle: {
const partial: TLShapePartial<TLGeoShape> = {
...inCommon,
type: 'geo',
props: {
geo: 'triangle',
w: coerceDimension(v1Shape.size[0]),
h: coerceDimension(v1Shape.size[1]),
fill: getV2Fill(v1Shape.style.isFilled, v1Shape.style.color),
labelColor: getV2Color(v1Shape.style.color),
color: getV2Color(v1Shape.style.color),
size: getV2Size(v1Shape.style.size),
font: getV2Font(v1Shape.style.font),
dash: getV2Dash(v1Shape.style.dash),
align: 'middle',
editor.createShapes<TLGeoShape>([
{
...inCommon,
type: 'geo',
props: {
geo: 'triangle',
w: coerceDimension(v1Shape.size[0]),
h: coerceDimension(v1Shape.size[1]),
fill: getV2Fill(v1Shape.style.isFilled, v1Shape.style.color),
labelColor: getV2Color(v1Shape.style.color),
color: getV2Color(v1Shape.style.color),
size: getV2Size(v1Shape.style.size),
font: getV2Font(v1Shape.style.font),
dash: getV2Dash(v1Shape.style.dash),
align: 'middle',
},
},
}
editor.createShapes([partial])
])
const pageBoundsBeforeLabel = editor.getPageBoundsById(inCommon.id)!
@ -309,24 +308,24 @@ export function buildFromV1Document(editor: Editor, document: LegacyTldrawDocume
break
}
case TDShapeType.Ellipse: {
const partial: TLShapePartial<TLGeoShape> = {
...inCommon,
type: 'geo',
props: {
geo: 'ellipse',
w: coerceDimension(v1Shape.radius[0]) * 2,
h: coerceDimension(v1Shape.radius[1]) * 2,
fill: getV2Fill(v1Shape.style.isFilled, v1Shape.style.color),
labelColor: getV2Color(v1Shape.style.color),
color: getV2Color(v1Shape.style.color),
size: getV2Size(v1Shape.style.size),
font: getV2Font(v1Shape.style.font),
dash: getV2Dash(v1Shape.style.dash),
align: 'middle',
editor.createShapes<TLGeoShape>([
{
...inCommon,
type: 'geo',
props: {
geo: 'ellipse',
w: coerceDimension(v1Shape.radius[0]) * 2,
h: coerceDimension(v1Shape.radius[1]) * 2,
fill: getV2Fill(v1Shape.style.isFilled, v1Shape.style.color),
labelColor: getV2Color(v1Shape.style.color),
color: getV2Color(v1Shape.style.color),
size: getV2Size(v1Shape.style.size),
font: getV2Font(v1Shape.style.font),
dash: getV2Dash(v1Shape.style.dash),
align: 'middle',
},
},
}
editor.createShapes([partial])
])
const pageBoundsBeforeLabel = editor.getPageBoundsById(inCommon.id)!
@ -370,21 +369,21 @@ export function buildFromV1Document(editor: Editor, document: LegacyTldrawDocume
break
}
const partial: TLShapePartial<TLDrawShape> = {
...inCommon,
type: 'draw',
props: {
fill: getV2Fill(v1Shape.style.isFilled, v1Shape.style.color),
color: getV2Color(v1Shape.style.color),
size: getV2Size(v1Shape.style.size),
dash: getV2Dash(v1Shape.style.dash),
isPen: false,
isComplete: v1Shape.isComplete,
segments: [{ type: 'free', points: v1Shape.points.map(getV2Point) }],
editor.createShapes<TLDrawShape>([
{
...inCommon,
type: 'draw',
props: {
fill: getV2Fill(v1Shape.style.isFilled, v1Shape.style.color),
color: getV2Color(v1Shape.style.color),
size: getV2Size(v1Shape.style.size),
dash: getV2Dash(v1Shape.style.dash),
isPen: false,
isComplete: v1Shape.isComplete,
segments: [{ type: 'free', points: v1Shape.points.map(getV2Point) }],
},
},
}
editor.createShapes([partial])
])
break
}
case TDShapeType.Arrow: {
@ -395,51 +394,51 @@ export function buildFromV1Document(editor: Editor, document: LegacyTldrawDocume
const v2Bend = (dist * -v1Bend) / 2
// Could also be a line... but we'll use it as an arrow anyway
const partial: TLShapePartial<TLArrowShape> = {
...inCommon,
type: 'arrow',
props: {
text: v1Shape.label ?? '',
color: getV2Color(v1Shape.style.color),
labelColor: getV2Color(v1Shape.style.color),
size: getV2Size(v1Shape.style.size),
font: getV2Font(v1Shape.style.font),
dash: getV2Dash(v1Shape.style.dash),
arrowheadStart: getV2Arrowhead(v1Shape.decorations?.start),
arrowheadEnd: getV2Arrowhead(v1Shape.decorations?.end),
start: {
type: 'point',
x: coerceNumber(v1Shape.handles.start.point[0]),
y: coerceNumber(v1Shape.handles.start.point[1]),
editor.createShapes<TLArrowShape>([
{
...inCommon,
type: 'arrow',
props: {
text: v1Shape.label ?? '',
color: getV2Color(v1Shape.style.color),
labelColor: getV2Color(v1Shape.style.color),
size: getV2Size(v1Shape.style.size),
font: getV2Font(v1Shape.style.font),
dash: getV2Dash(v1Shape.style.dash),
arrowheadStart: getV2Arrowhead(v1Shape.decorations?.start),
arrowheadEnd: getV2Arrowhead(v1Shape.decorations?.end),
start: {
type: 'point',
x: coerceNumber(v1Shape.handles.start.point[0]),
y: coerceNumber(v1Shape.handles.start.point[1]),
},
end: {
type: 'point',
x: coerceNumber(v1Shape.handles.end.point[0]),
y: coerceNumber(v1Shape.handles.end.point[1]),
},
bend: v2Bend,
},
end: {
type: 'point',
x: coerceNumber(v1Shape.handles.end.point[0]),
y: coerceNumber(v1Shape.handles.end.point[1]),
},
bend: v2Bend,
},
}
editor.createShapes([partial])
])
break
}
case TDShapeType.Text: {
const partial: TLShapePartial<TLTextShape> = {
...inCommon,
type: 'text',
props: {
text: v1Shape.text ?? ' ',
color: getV2Color(v1Shape.style.color),
size: getV2TextSize(v1Shape.style.size),
font: getV2Font(v1Shape.style.font),
align: getV2Align(v1Shape.style.textAlign),
scale: v1Shape.style.scale ?? 1,
editor.createShapes<TLTextShape>([
{
...inCommon,
type: 'text',
props: {
text: v1Shape.text ?? ' ',
color: getV2Color(v1Shape.style.color),
size: getV2TextSize(v1Shape.style.size),
font: getV2Font(v1Shape.style.font),
align: getV2Align(v1Shape.style.textAlign),
scale: v1Shape.style.scale ?? 1,
},
},
}
editor.createShapes([partial])
])
break
}
case TDShapeType.Image: {
@ -450,17 +449,17 @@ export function buildFromV1Document(editor: Editor, document: LegacyTldrawDocume
return
}
const partial: TLShapePartial<TLImageShape> = {
...inCommon,
type: 'image',
props: {
w: coerceDimension(v1Shape.size[0]),
h: coerceDimension(v1Shape.size[1]),
assetId,
editor.createShapes<TLImageShape>([
{
...inCommon,
type: 'image',
props: {
w: coerceDimension(v1Shape.size[0]),
h: coerceDimension(v1Shape.size[1]),
assetId,
},
},
}
editor.createShapes([partial])
])
break
}
case TDShapeType.Video: {
@ -471,17 +470,17 @@ export function buildFromV1Document(editor: Editor, document: LegacyTldrawDocume
return
}
const partial: TLShapePartial<TLVideoShape> = {
...inCommon,
type: 'video',
props: {
w: coerceDimension(v1Shape.size[0]),
h: coerceDimension(v1Shape.size[1]),
assetId,
editor.createShapes<TLVideoShape>([
{
...inCommon,
type: 'video',
props: {
w: coerceDimension(v1Shape.size[0]),
h: coerceDimension(v1Shape.size[1]),
assetId,
},
},
}
editor.createShapes([partial])
])
break
}
}