UNPKG

@tldraw/tlschema

Version:

tldraw infinite canvas SDK (schema).

229 lines (228 loc) • 6.72 kB
import { createMigrationSequence } from "@tldraw/store"; import { structuredClone } from "@tldraw/utils"; import { T } from "@tldraw/validate"; import { vecModelValidator } from "../misc/geometry-types.mjs"; import { richTextValidator, toRichText } from "../misc/TLRichText.mjs"; import { createBindingId } from "../records/TLBinding.mjs"; import { createShapePropsMigrationIds } from "../records/TLShape.mjs"; import { createPropsMigration } from "../recordsWithProps.mjs"; import { StyleProp } from "../styles/StyleProp.mjs"; import { DefaultColorStyle, DefaultLabelColorStyle } from "../styles/TLColorStyle.mjs"; import { DefaultDashStyle } from "../styles/TLDashStyle.mjs"; import { DefaultFillStyle } from "../styles/TLFillStyle.mjs"; import { DefaultFontStyle } from "../styles/TLFontStyle.mjs"; import { DefaultSizeStyle } from "../styles/TLSizeStyle.mjs"; const arrowKinds = ["arc", "elbow"]; const ArrowShapeKindStyle = StyleProp.defineEnum("tldraw:arrowKind", { defaultValue: "arc", values: arrowKinds }); const arrowheadTypes = [ "arrow", "triangle", "square", "dot", "pipe", "diamond", "inverted", "bar", "none" ]; const ArrowShapeArrowheadStartStyle = StyleProp.defineEnum("tldraw:arrowheadStart", { defaultValue: "none", values: arrowheadTypes }); const ArrowShapeArrowheadEndStyle = StyleProp.defineEnum("tldraw:arrowheadEnd", { defaultValue: "arrow", values: arrowheadTypes }); const arrowShapeProps = { kind: ArrowShapeKindStyle, labelColor: DefaultLabelColorStyle, color: DefaultColorStyle, fill: DefaultFillStyle, dash: DefaultDashStyle, size: DefaultSizeStyle, arrowheadStart: ArrowShapeArrowheadStartStyle, arrowheadEnd: ArrowShapeArrowheadEndStyle, font: DefaultFontStyle, start: vecModelValidator, end: vecModelValidator, bend: T.number, richText: richTextValidator, labelPosition: T.number, scale: T.nonZeroNumber, elbowMidPoint: T.number }; const arrowShapeVersions = createShapePropsMigrationIds("arrow", { AddLabelColor: 1, AddIsPrecise: 2, AddLabelPosition: 3, ExtractBindings: 4, AddScale: 5, AddElbow: 6, AddRichText: 7, AddRichTextAttrs: 8 }); function propsMigration(migration) { return createPropsMigration("shape", "arrow", migration); } const arrowShapeMigrations = createMigrationSequence({ sequenceId: "com.tldraw.shape.arrow", retroactive: false, sequence: [ propsMigration({ id: arrowShapeVersions.AddLabelColor, up: (props) => { props.labelColor = "black"; }, down: "retired" }), propsMigration({ id: arrowShapeVersions.AddIsPrecise, up: ({ start, end }) => { if (start.type === "binding") { start.isPrecise = !(start.normalizedAnchor.x === 0.5 && start.normalizedAnchor.y === 0.5); } if (end.type === "binding") { end.isPrecise = !(end.normalizedAnchor.x === 0.5 && end.normalizedAnchor.y === 0.5); } }, down: ({ start, end }) => { if (start.type === "binding") { if (!start.isPrecise) { start.normalizedAnchor = { x: 0.5, y: 0.5 }; } delete start.isPrecise; } if (end.type === "binding") { if (!end.isPrecise) { end.normalizedAnchor = { x: 0.5, y: 0.5 }; } delete end.isPrecise; } } }), propsMigration({ id: arrowShapeVersions.AddLabelPosition, up: (props) => { props.labelPosition = 0.5; }, down: (props) => { delete props.labelPosition; } }), { id: arrowShapeVersions.ExtractBindings, scope: "storage", up: (storage) => { const updates = []; for (const record of storage.values()) { if (record.typeName !== "shape" || record.type !== "arrow") continue; const arrow = record; const newArrow = structuredClone(arrow); const { start, end } = arrow.props; if (start.type === "binding") { const id = createBindingId(); const binding = { typeName: "binding", id, type: "arrow", fromId: arrow.id, toId: start.boundShapeId, meta: {}, props: { terminal: "start", normalizedAnchor: start.normalizedAnchor, isExact: start.isExact, isPrecise: start.isPrecise } }; updates.push([id, binding]); newArrow.props.start = { x: 0, y: 0 }; } else { delete newArrow.props.start.type; } if (end.type === "binding") { const id = createBindingId(); const binding = { typeName: "binding", id, type: "arrow", fromId: arrow.id, toId: end.boundShapeId, meta: {}, props: { terminal: "end", normalizedAnchor: end.normalizedAnchor, isExact: end.isExact, isPrecise: end.isPrecise } }; updates.push([id, binding]); newArrow.props.end = { x: 0, y: 0 }; } else { delete newArrow.props.end.type; } updates.push([arrow.id, newArrow]); } for (const [id, record] of updates) { storage.set(id, record); } } }, propsMigration({ id: arrowShapeVersions.AddScale, up: (props) => { props.scale = 1; }, down: (props) => { delete props.scale; } }), propsMigration({ id: arrowShapeVersions.AddElbow, up: (props) => { props.kind = "arc"; props.elbowMidPoint = 0.5; }, down: (props) => { delete props.kind; delete props.elbowMidPoint; } }), propsMigration({ id: arrowShapeVersions.AddRichText, up: (props) => { props.richText = toRichText(props.text); delete props.text; } // N.B. Explicitly no down state so that we force clients to update. // down: (props) => { // delete props.richText // }, }), propsMigration({ id: arrowShapeVersions.AddRichTextAttrs, up: (_props) => { }, down: (props) => { if (props.richText && "attrs" in props.richText) { delete props.richText.attrs; } } }) ] }); export { ArrowShapeArrowheadEndStyle, ArrowShapeArrowheadStartStyle, ArrowShapeKindStyle, arrowShapeMigrations, arrowShapeProps, arrowShapeVersions }; //# sourceMappingURL=TLArrowShape.mjs.map