@tldraw/tlschema 4.3.0-next.2d181ae353a2 → 4.3.0-next.40e4536afc8e

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (97) hide show
  1. package/dist-cjs/index.d.ts +82 -34
  2. package/dist-cjs/index.js +4 -1
  3. package/dist-cjs/index.js.map +2 -2
  4. package/dist-cjs/misc/TLOpacity.js +1 -5
  5. package/dist-cjs/misc/TLOpacity.js.map +2 -2
  6. package/dist-cjs/misc/TLRichText.js +5 -1
  7. package/dist-cjs/misc/TLRichText.js.map +2 -2
  8. package/dist-cjs/misc/b64Vecs.js +224 -0
  9. package/dist-cjs/misc/b64Vecs.js.map +7 -0
  10. package/dist-cjs/shapes/TLArrowShape.js +30 -13
  11. package/dist-cjs/shapes/TLArrowShape.js.map +2 -2
  12. package/dist-cjs/shapes/TLDrawShape.js +37 -4
  13. package/dist-cjs/shapes/TLDrawShape.js.map +2 -2
  14. package/dist-cjs/shapes/TLEmbedShape.js +17 -0
  15. package/dist-cjs/shapes/TLEmbedShape.js.map +2 -2
  16. package/dist-cjs/shapes/TLGeoShape.js +12 -1
  17. package/dist-cjs/shapes/TLGeoShape.js.map +2 -2
  18. package/dist-cjs/shapes/TLHighlightShape.js +29 -2
  19. package/dist-cjs/shapes/TLHighlightShape.js.map +2 -2
  20. package/dist-cjs/shapes/TLNoteShape.js +12 -1
  21. package/dist-cjs/shapes/TLNoteShape.js.map +2 -2
  22. package/dist-cjs/shapes/TLTextShape.js +12 -1
  23. package/dist-cjs/shapes/TLTextShape.js.map +2 -2
  24. package/dist-cjs/store-migrations.js +14 -14
  25. package/dist-cjs/store-migrations.js.map +2 -2
  26. package/dist-esm/index.d.mts +82 -34
  27. package/dist-esm/index.mjs +5 -1
  28. package/dist-esm/index.mjs.map +2 -2
  29. package/dist-esm/misc/TLOpacity.mjs +1 -5
  30. package/dist-esm/misc/TLOpacity.mjs.map +2 -2
  31. package/dist-esm/misc/TLRichText.mjs +5 -1
  32. package/dist-esm/misc/TLRichText.mjs.map +2 -2
  33. package/dist-esm/misc/b64Vecs.mjs +204 -0
  34. package/dist-esm/misc/b64Vecs.mjs.map +7 -0
  35. package/dist-esm/shapes/TLArrowShape.mjs +30 -13
  36. package/dist-esm/shapes/TLArrowShape.mjs.map +2 -2
  37. package/dist-esm/shapes/TLDrawShape.mjs +37 -4
  38. package/dist-esm/shapes/TLDrawShape.mjs.map +2 -2
  39. package/dist-esm/shapes/TLEmbedShape.mjs +17 -0
  40. package/dist-esm/shapes/TLEmbedShape.mjs.map +2 -2
  41. package/dist-esm/shapes/TLGeoShape.mjs +12 -1
  42. package/dist-esm/shapes/TLGeoShape.mjs.map +2 -2
  43. package/dist-esm/shapes/TLHighlightShape.mjs +29 -2
  44. package/dist-esm/shapes/TLHighlightShape.mjs.map +2 -2
  45. package/dist-esm/shapes/TLNoteShape.mjs +12 -1
  46. package/dist-esm/shapes/TLNoteShape.mjs.map +2 -2
  47. package/dist-esm/shapes/TLTextShape.mjs +12 -1
  48. package/dist-esm/shapes/TLTextShape.mjs.map +2 -2
  49. package/dist-esm/store-migrations.mjs +14 -14
  50. package/dist-esm/store-migrations.mjs.map +2 -2
  51. package/package.json +8 -8
  52. package/src/__tests__/migrationTestUtils.ts +9 -3
  53. package/src/index.ts +3 -0
  54. package/src/migrations.test.ts +149 -1
  55. package/src/misc/TLOpacity.ts +1 -5
  56. package/src/misc/TLRichText.ts +6 -1
  57. package/src/misc/b64Vecs.ts +308 -0
  58. package/src/shapes/TLArrowShape.ts +36 -13
  59. package/src/shapes/TLDrawShape.ts +59 -12
  60. package/src/shapes/TLEmbedShape.ts +17 -0
  61. package/src/shapes/TLGeoShape.ts +14 -1
  62. package/src/shapes/TLHighlightShape.ts +37 -0
  63. package/src/shapes/TLNoteShape.ts +15 -1
  64. package/src/shapes/TLTextShape.ts +16 -2
  65. package/src/store-migrations.ts +15 -15
  66. package/src/assets/TLBookmarkAsset.test.ts +0 -96
  67. package/src/assets/TLImageAsset.test.ts +0 -213
  68. package/src/assets/TLVideoAsset.test.ts +0 -105
  69. package/src/bindings/TLArrowBinding.test.ts +0 -55
  70. package/src/misc/id-validator.test.ts +0 -50
  71. package/src/records/TLAsset.test.ts +0 -234
  72. package/src/records/TLBinding.test.ts +0 -22
  73. package/src/records/TLCamera.test.ts +0 -19
  74. package/src/records/TLDocument.test.ts +0 -35
  75. package/src/records/TLInstance.test.ts +0 -201
  76. package/src/records/TLPage.test.ts +0 -110
  77. package/src/records/TLPageState.test.ts +0 -228
  78. package/src/records/TLPointer.test.ts +0 -63
  79. package/src/records/TLPresence.test.ts +0 -190
  80. package/src/records/TLRecord.test.ts +0 -82
  81. package/src/records/TLShape.test.ts +0 -232
  82. package/src/shapes/ShapeWithCrop.test.ts +0 -18
  83. package/src/shapes/TLArrowShape.test.ts +0 -505
  84. package/src/shapes/TLBaseShape.test.ts +0 -142
  85. package/src/shapes/TLBookmarkShape.test.ts +0 -122
  86. package/src/shapes/TLDrawShape.test.ts +0 -177
  87. package/src/shapes/TLEmbedShape.test.ts +0 -286
  88. package/src/shapes/TLFrameShape.test.ts +0 -71
  89. package/src/shapes/TLGeoShape.test.ts +0 -247
  90. package/src/shapes/TLGroupShape.test.ts +0 -59
  91. package/src/shapes/TLHighlightShape.test.ts +0 -325
  92. package/src/shapes/TLImageShape.test.ts +0 -534
  93. package/src/shapes/TLLineShape.test.ts +0 -269
  94. package/src/shapes/TLNoteShape.test.ts +0 -1568
  95. package/src/shapes/TLTextShape.test.ts +0 -407
  96. package/src/shapes/TLVideoShape.test.ts +0 -112
  97. package/src/styles/TLColorStyle.test.ts +0 -439
@@ -27,6 +27,7 @@ __export(TLArrowShape_exports, {
27
27
  });
28
28
  module.exports = __toCommonJS(TLArrowShape_exports);
29
29
  var import_store = require("@tldraw/store");
30
+ var import_utils = require("@tldraw/utils");
30
31
  var import_validate = require("@tldraw/validate");
31
32
  var import_TLRichText = require("../misc/TLRichText");
32
33
  var import_geometry_types = require("../misc/geometry-types");
@@ -88,7 +89,8 @@ const arrowShapeVersions = (0, import_TLShape.createShapePropsMigrationIds)("arr
88
89
  ExtractBindings: 4,
89
90
  AddScale: 5,
90
91
  AddElbow: 6,
91
- AddRichText: 7
92
+ AddRichText: 7,
93
+ AddRichTextAttrs: 8
92
94
  });
93
95
  function propsMigration(migration) {
94
96
  return (0, import_recordsWithProps.createPropsMigration)("shape", "arrow", migration);
@@ -140,12 +142,13 @@ const arrowShapeMigrations = (0, import_store.createMigrationSequence)({
140
142
  }),
141
143
  {
142
144
  id: arrowShapeVersions.ExtractBindings,
143
- scope: "store",
144
- up: (oldStore) => {
145
- const arrows = Object.values(oldStore).filter(
146
- (r) => r.typeName === "shape" && r.type === "arrow"
147
- );
148
- for (const arrow of arrows) {
145
+ scope: "storage",
146
+ up: (storage) => {
147
+ const updates = [];
148
+ for (const record of storage.values()) {
149
+ if (record.typeName !== "shape" || record.type !== "arrow") continue;
150
+ const arrow = record;
151
+ const newArrow = (0, import_utils.structuredClone)(arrow);
149
152
  const { start, end } = arrow.props;
150
153
  if (start.type === "binding") {
151
154
  const id = (0, import_TLBinding.createBindingId)();
@@ -163,10 +166,10 @@ const arrowShapeMigrations = (0, import_store.createMigrationSequence)({
163
166
  isPrecise: start.isPrecise
164
167
  }
165
168
  };
166
- oldStore[id] = binding;
167
- arrow.props.start = { x: 0, y: 0 };
169
+ updates.push([id, binding]);
170
+ newArrow.props.start = { x: 0, y: 0 };
168
171
  } else {
169
- delete arrow.props.start.type;
172
+ delete newArrow.props.start.type;
170
173
  }
171
174
  if (end.type === "binding") {
172
175
  const id = (0, import_TLBinding.createBindingId)();
@@ -184,11 +187,15 @@ const arrowShapeMigrations = (0, import_store.createMigrationSequence)({
184
187
  isPrecise: end.isPrecise
185
188
  }
186
189
  };
187
- oldStore[id] = binding;
188
- arrow.props.end = { x: 0, y: 0 };
190
+ updates.push([id, binding]);
191
+ newArrow.props.end = { x: 0, y: 0 };
189
192
  } else {
190
- delete arrow.props.end.type;
193
+ delete newArrow.props.end.type;
191
194
  }
195
+ updates.push([arrow.id, newArrow]);
196
+ }
197
+ for (const [id, record] of updates) {
198
+ storage.set(id, record);
192
199
  }
193
200
  }
194
201
  },
@@ -222,6 +229,16 @@ const arrowShapeMigrations = (0, import_store.createMigrationSequence)({
222
229
  // down: (props) => {
223
230
  // delete props.richText
224
231
  // },
232
+ }),
233
+ propsMigration({
234
+ id: arrowShapeVersions.AddRichTextAttrs,
235
+ up: (_props) => {
236
+ },
237
+ down: (props) => {
238
+ if (props.richText && "attrs" in props.richText) {
239
+ delete props.richText.attrs;
240
+ }
241
+ }
225
242
  })
226
243
  ]
227
244
  });
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../src/shapes/TLArrowShape.ts"],
4
- "sourcesContent": ["import { createMigrationSequence } from '@tldraw/store'\nimport { T } from '@tldraw/validate'\nimport { TLRichText, richTextValidator, toRichText } from '../misc/TLRichText'\nimport { VecModel, vecModelValidator } from '../misc/geometry-types'\nimport { createBindingId } from '../records/TLBinding'\nimport { TLShapeId, createShapePropsMigrationIds } from '../records/TLShape'\nimport { RecordProps, TLPropsMigration, createPropsMigration } from '../recordsWithProps'\nimport { StyleProp } from '../styles/StyleProp'\nimport {\n\tDefaultColorStyle,\n\tDefaultLabelColorStyle,\n\tTLDefaultColorStyle,\n} from '../styles/TLColorStyle'\nimport { DefaultDashStyle, TLDefaultDashStyle } from '../styles/TLDashStyle'\nimport { DefaultFillStyle, TLDefaultFillStyle } from '../styles/TLFillStyle'\nimport { DefaultFontStyle, TLDefaultFontStyle } from '../styles/TLFontStyle'\nimport { DefaultSizeStyle, TLDefaultSizeStyle } from '../styles/TLSizeStyle'\nimport { TLBaseShape } from './TLBaseShape'\n\nconst arrowKinds = ['arc', 'elbow'] as const\n/**\n * Style property for arrow shape kind, determining how the arrow is drawn.\n *\n * Arrows can be drawn as arcs (curved) or elbows (angled with straight segments).\n * This affects the visual appearance and behavior of arrow shapes.\n *\n * @example\n * ```ts\n * // Create an arrow with arc style (curved)\n * const arcArrow: TLArrowShape = {\n * // ... other properties\n * props: {\n * kind: 'arc',\n * // ... other props\n * }\n * }\n *\n * // Create an arrow with elbow style (angled)\n * const elbowArrow: TLArrowShape = {\n * // ... other properties\n * props: {\n * kind: 'elbow',\n * // ... other props\n * }\n * }\n * ```\n *\n * @public\n */\nexport const ArrowShapeKindStyle = StyleProp.defineEnum('tldraw:arrowKind', {\n\tdefaultValue: 'arc',\n\tvalues: arrowKinds,\n})\n\n/**\n * The type representing arrow shape kinds.\n *\n * @public\n */\nexport type TLArrowShapeKind = T.TypeOf<typeof ArrowShapeKindStyle>\n\nconst arrowheadTypes = [\n\t'arrow',\n\t'triangle',\n\t'square',\n\t'dot',\n\t'pipe',\n\t'diamond',\n\t'inverted',\n\t'bar',\n\t'none',\n] as const\n\n/**\n * Style property for the arrowhead at the start of an arrow.\n *\n * Defines the visual style of the arrowhead at the beginning of the arrow path.\n * Can be one of several predefined styles or none for no arrowhead.\n *\n * @example\n * ```ts\n * // Arrow with no start arrowhead but triangle end arrowhead\n * const arrow: TLArrowShape = {\n * // ... other properties\n * props: {\n * arrowheadStart: 'none',\n * arrowheadEnd: 'triangle',\n * // ... other props\n * }\n * }\n * ```\n *\n * @public\n */\nexport const ArrowShapeArrowheadStartStyle = StyleProp.defineEnum('tldraw:arrowheadStart', {\n\tdefaultValue: 'none',\n\tvalues: arrowheadTypes,\n})\n\n/**\n * Style property for the arrowhead at the end of an arrow.\n *\n * Defines the visual style of the arrowhead at the end of the arrow path.\n * Defaults to 'arrow' style, giving arrows their characteristic pointed appearance.\n *\n * @example\n * ```ts\n * // Arrow with different start and end arrowheads\n * const doubleArrow: TLArrowShape = {\n * // ... other properties\n * props: {\n * arrowheadStart: 'triangle',\n * arrowheadEnd: 'diamond',\n * // ... other props\n * }\n * }\n * ```\n *\n * @public\n */\nexport const ArrowShapeArrowheadEndStyle = StyleProp.defineEnum('tldraw:arrowheadEnd', {\n\tdefaultValue: 'arrow',\n\tvalues: arrowheadTypes,\n})\n\n/**\n * The type representing arrowhead styles for both start and end of arrows.\n *\n * @public\n */\nexport type TLArrowShapeArrowheadStyle = T.TypeOf<typeof ArrowShapeArrowheadStartStyle>\n\n/**\n * Properties specific to arrow shapes.\n *\n * Defines all the configurable aspects of an arrow shape, including visual styling,\n * geometry, text labeling, and positioning. Arrows can connect two points and\n * optionally display text labels.\n *\n * @example\n * ```ts\n * const arrowProps: TLArrowShapeProps = {\n * kind: 'arc',\n * labelColor: 'black',\n * color: 'blue',\n * fill: 'none',\n * dash: 'solid',\n * size: 'm',\n * arrowheadStart: 'none',\n * arrowheadEnd: 'arrow',\n * font: 'draw',\n * start: { x: 0, y: 0 },\n * end: { x: 100, y: 100 },\n * bend: 0.2,\n * richText: toRichText('Label'),\n * labelPosition: 0.5,\n * scale: 1,\n * elbowMidPoint: 0.5\n * }\n * ```\n *\n * @public\n */\nexport interface TLArrowShapeProps {\n\tkind: TLArrowShapeKind\n\tlabelColor: TLDefaultColorStyle\n\tcolor: TLDefaultColorStyle\n\tfill: TLDefaultFillStyle\n\tdash: TLDefaultDashStyle\n\tsize: TLDefaultSizeStyle\n\tarrowheadStart: TLArrowShapeArrowheadStyle\n\tarrowheadEnd: TLArrowShapeArrowheadStyle\n\tfont: TLDefaultFontStyle\n\tstart: VecModel\n\tend: VecModel\n\tbend: number\n\trichText: TLRichText\n\tlabelPosition: number\n\tscale: number\n\telbowMidPoint: number\n}\n\n/**\n * A complete arrow shape record.\n *\n * Combines the base shape interface with arrow-specific properties to create\n * a full arrow shape that can be stored and manipulated in the editor.\n *\n * @example\n * ```ts\n * const arrowShape: TLArrowShape = {\n * id: 'shape:arrow123',\n * typeName: 'shape',\n * type: 'arrow',\n * x: 100,\n * y: 200,\n * rotation: 0,\n * index: 'a1',\n * parentId: 'page:main',\n * isLocked: false,\n * opacity: 1,\n * props: {\n * kind: 'arc',\n * start: { x: 0, y: 0 },\n * end: { x: 150, y: 100 },\n * // ... other props\n * },\n * meta: {}\n * }\n * ```\n *\n * @public\n */\nexport type TLArrowShape = TLBaseShape<'arrow', TLArrowShapeProps>\n\n/**\n * Validation configuration for arrow shape properties.\n *\n * Defines the validators for each property of an arrow shape, ensuring that\n * arrow shape data is valid and conforms to the expected types and constraints.\n *\n * @example\n * ```ts\n * // The validators ensure proper typing and validation\n * const validator = T.object(arrowShapeProps)\n * const validArrowProps = validator.validate({\n * kind: 'arc',\n * start: { x: 0, y: 0 },\n * end: { x: 100, y: 50 },\n * // ... other required properties\n * })\n * ```\n *\n * @public\n */\nexport const arrowShapeProps: RecordProps<TLArrowShape> = {\n\tkind: ArrowShapeKindStyle,\n\tlabelColor: DefaultLabelColorStyle,\n\tcolor: DefaultColorStyle,\n\tfill: DefaultFillStyle,\n\tdash: DefaultDashStyle,\n\tsize: DefaultSizeStyle,\n\tarrowheadStart: ArrowShapeArrowheadStartStyle,\n\tarrowheadEnd: ArrowShapeArrowheadEndStyle,\n\tfont: DefaultFontStyle,\n\tstart: vecModelValidator,\n\tend: vecModelValidator,\n\tbend: T.number,\n\trichText: richTextValidator,\n\tlabelPosition: T.number,\n\tscale: T.nonZeroNumber,\n\telbowMidPoint: T.number,\n}\n\n/**\n * Migration version identifiers for arrow shape properties.\n *\n * These track the evolution of the arrow shape schema over time, with each\n * version representing a specific change to the arrow shape structure or properties.\n *\n * @example\n * ```ts\n * // Used internally for migration system\n * if (version < arrowShapeVersions.AddLabelColor) {\n * // Apply label color migration\n * }\n * ```\n *\n * @public\n */\nexport const arrowShapeVersions = createShapePropsMigrationIds('arrow', {\n\tAddLabelColor: 1,\n\tAddIsPrecise: 2,\n\tAddLabelPosition: 3,\n\tExtractBindings: 4,\n\tAddScale: 5,\n\tAddElbow: 6,\n\tAddRichText: 7,\n})\n\nfunction propsMigration(migration: TLPropsMigration) {\n\treturn createPropsMigration<TLArrowShape>('shape', 'arrow', migration)\n}\n\n/**\n * Complete migration sequence for arrow shapes.\n *\n * Defines all the migrations needed to transform arrow shape data from older\n * versions to the current version. Each migration handles a specific schema change,\n * ensuring backward compatibility and smooth data evolution.\n *\n * @public\n */\nexport const arrowShapeMigrations = createMigrationSequence({\n\tsequenceId: 'com.tldraw.shape.arrow',\n\tretroactive: false,\n\tsequence: [\n\t\tpropsMigration({\n\t\t\tid: arrowShapeVersions.AddLabelColor,\n\t\t\tup: (props) => {\n\t\t\t\tprops.labelColor = 'black'\n\t\t\t},\n\t\t\tdown: 'retired',\n\t\t}),\n\n\t\tpropsMigration({\n\t\t\tid: arrowShapeVersions.AddIsPrecise,\n\t\t\tup: ({ start, end }) => {\n\t\t\t\tif (start.type === 'binding') {\n\t\t\t\t\tstart.isPrecise = !(start.normalizedAnchor.x === 0.5 && start.normalizedAnchor.y === 0.5)\n\t\t\t\t}\n\t\t\t\tif (end.type === 'binding') {\n\t\t\t\t\tend.isPrecise = !(end.normalizedAnchor.x === 0.5 && end.normalizedAnchor.y === 0.5)\n\t\t\t\t}\n\t\t\t},\n\t\t\tdown: ({ start, end }) => {\n\t\t\t\tif (start.type === 'binding') {\n\t\t\t\t\tif (!start.isPrecise) {\n\t\t\t\t\t\tstart.normalizedAnchor = { x: 0.5, y: 0.5 }\n\t\t\t\t\t}\n\t\t\t\t\tdelete start.isPrecise\n\t\t\t\t}\n\t\t\t\tif (end.type === 'binding') {\n\t\t\t\t\tif (!end.isPrecise) {\n\t\t\t\t\t\tend.normalizedAnchor = { x: 0.5, y: 0.5 }\n\t\t\t\t\t}\n\t\t\t\t\tdelete end.isPrecise\n\t\t\t\t}\n\t\t\t},\n\t\t}),\n\n\t\tpropsMigration({\n\t\t\tid: arrowShapeVersions.AddLabelPosition,\n\t\t\tup: (props) => {\n\t\t\t\tprops.labelPosition = 0.5\n\t\t\t},\n\t\t\tdown: (props) => {\n\t\t\t\tdelete props.labelPosition\n\t\t\t},\n\t\t}),\n\n\t\t{\n\t\t\tid: arrowShapeVersions.ExtractBindings,\n\t\t\tscope: 'store',\n\t\t\tup: (oldStore) => {\n\t\t\t\ttype OldArrowTerminal =\n\t\t\t\t\t| {\n\t\t\t\t\t\t\ttype: 'point'\n\t\t\t\t\t\t\tx: number\n\t\t\t\t\t\t\ty: number\n\t\t\t\t\t }\n\t\t\t\t\t| {\n\t\t\t\t\t\t\ttype: 'binding'\n\t\t\t\t\t\t\tboundShapeId: TLShapeId\n\t\t\t\t\t\t\tnormalizedAnchor: VecModel\n\t\t\t\t\t\t\tisExact: boolean\n\t\t\t\t\t\t\tisPrecise: boolean\n\t\t\t\t\t }\n\t\t\t\t\t// new type:\n\t\t\t\t\t| { type?: undefined; x: number; y: number }\n\n\t\t\t\ttype OldArrow = TLBaseShape<'arrow', { start: OldArrowTerminal; end: OldArrowTerminal }>\n\n\t\t\t\tconst arrows = Object.values(oldStore).filter(\n\t\t\t\t\t(r: any): r is OldArrow => r.typeName === 'shape' && r.type === 'arrow'\n\t\t\t\t)\n\n\t\t\t\tfor (const arrow of arrows) {\n\t\t\t\t\tconst { start, end } = arrow.props\n\t\t\t\t\tif (start.type === 'binding') {\n\t\t\t\t\t\tconst id = createBindingId()\n\t\t\t\t\t\tconst binding = {\n\t\t\t\t\t\t\ttypeName: 'binding',\n\t\t\t\t\t\t\tid,\n\t\t\t\t\t\t\ttype: 'arrow',\n\t\t\t\t\t\t\tfromId: arrow.id,\n\t\t\t\t\t\t\ttoId: start.boundShapeId,\n\t\t\t\t\t\t\tmeta: {},\n\t\t\t\t\t\t\tprops: {\n\t\t\t\t\t\t\t\tterminal: 'start',\n\t\t\t\t\t\t\t\tnormalizedAnchor: start.normalizedAnchor,\n\t\t\t\t\t\t\t\tisExact: start.isExact,\n\t\t\t\t\t\t\t\tisPrecise: start.isPrecise,\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\toldStore[id] = binding\n\t\t\t\t\t\tarrow.props.start = { x: 0, y: 0 }\n\t\t\t\t\t} else {\n\t\t\t\t\t\tdelete arrow.props.start.type\n\t\t\t\t\t}\n\t\t\t\t\tif (end.type === 'binding') {\n\t\t\t\t\t\tconst id = createBindingId()\n\t\t\t\t\t\tconst binding = {\n\t\t\t\t\t\t\ttypeName: 'binding',\n\t\t\t\t\t\t\tid,\n\t\t\t\t\t\t\ttype: 'arrow',\n\t\t\t\t\t\t\tfromId: arrow.id,\n\t\t\t\t\t\t\ttoId: end.boundShapeId,\n\t\t\t\t\t\t\tmeta: {},\n\t\t\t\t\t\t\tprops: {\n\t\t\t\t\t\t\t\tterminal: 'end',\n\t\t\t\t\t\t\t\tnormalizedAnchor: end.normalizedAnchor,\n\t\t\t\t\t\t\t\tisExact: end.isExact,\n\t\t\t\t\t\t\t\tisPrecise: end.isPrecise,\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\toldStore[id] = binding\n\t\t\t\t\t\tarrow.props.end = { x: 0, y: 0 }\n\t\t\t\t\t} else {\n\t\t\t\t\t\tdelete arrow.props.end.type\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t},\n\t\t},\n\t\tpropsMigration({\n\t\t\tid: arrowShapeVersions.AddScale,\n\t\t\tup: (props) => {\n\t\t\t\tprops.scale = 1\n\t\t\t},\n\t\t\tdown: (props) => {\n\t\t\t\tdelete props.scale\n\t\t\t},\n\t\t}),\n\t\tpropsMigration({\n\t\t\tid: arrowShapeVersions.AddElbow,\n\t\t\tup: (props) => {\n\t\t\t\tprops.kind = 'arc'\n\t\t\t\tprops.elbowMidPoint = 0.5\n\t\t\t},\n\t\t\tdown: (props) => {\n\t\t\t\tdelete props.kind\n\t\t\t\tdelete props.elbowMidPoint\n\t\t\t},\n\t\t}),\n\t\tpropsMigration({\n\t\t\tid: arrowShapeVersions.AddRichText,\n\t\t\tup: (props) => {\n\t\t\t\tprops.richText = toRichText(props.text)\n\t\t\t\tdelete props.text\n\t\t\t},\n\t\t\t// N.B. Explicitly no down state so that we force clients to update.\n\t\t\t// down: (props) => {\n\t\t\t// \tdelete props.richText\n\t\t\t// },\n\t\t}),\n\t],\n})\n"],
5
- "mappings": ";;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,mBAAwC;AACxC,sBAAkB;AAClB,wBAA0D;AAC1D,4BAA4C;AAC5C,uBAAgC;AAChC,qBAAwD;AACxD,8BAAoE;AACpE,uBAA0B;AAC1B,0BAIO;AACP,yBAAqD;AACrD,yBAAqD;AACrD,yBAAqD;AACrD,yBAAqD;AAGrD,MAAM,aAAa,CAAC,OAAO,OAAO;AA8B3B,MAAM,sBAAsB,2BAAU,WAAW,oBAAoB;AAAA,EAC3E,cAAc;AAAA,EACd,QAAQ;AACT,CAAC;AASD,MAAM,iBAAiB;AAAA,EACtB;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACD;AAuBO,MAAM,gCAAgC,2BAAU,WAAW,yBAAyB;AAAA,EAC1F,cAAc;AAAA,EACd,QAAQ;AACT,CAAC;AAuBM,MAAM,8BAA8B,2BAAU,WAAW,uBAAuB;AAAA,EACtF,cAAc;AAAA,EACd,QAAQ;AACT,CAAC;AAgHM,MAAM,kBAA6C;AAAA,EACzD,MAAM;AAAA,EACN,YAAY;AAAA,EACZ,OAAO;AAAA,EACP,MAAM;AAAA,EACN,MAAM;AAAA,EACN,MAAM;AAAA,EACN,gBAAgB;AAAA,EAChB,cAAc;AAAA,EACd,MAAM;AAAA,EACN,OAAO;AAAA,EACP,KAAK;AAAA,EACL,MAAM,kBAAE;AAAA,EACR,UAAU;AAAA,EACV,eAAe,kBAAE;AAAA,EACjB,OAAO,kBAAE;AAAA,EACT,eAAe,kBAAE;AAClB;AAkBO,MAAM,yBAAqB,6CAA6B,SAAS;AAAA,EACvE,eAAe;AAAA,EACf,cAAc;AAAA,EACd,kBAAkB;AAAA,EAClB,iBAAiB;AAAA,EACjB,UAAU;AAAA,EACV,UAAU;AAAA,EACV,aAAa;AACd,CAAC;AAED,SAAS,eAAe,WAA6B;AACpD,aAAO,8CAAmC,SAAS,SAAS,SAAS;AACtE;AAWO,MAAM,2BAAuB,sCAAwB;AAAA,EAC3D,YAAY;AAAA,EACZ,aAAa;AAAA,EACb,UAAU;AAAA,IACT,eAAe;AAAA,MACd,IAAI,mBAAmB;AAAA,MACvB,IAAI,CAAC,UAAU;AACd,cAAM,aAAa;AAAA,MACpB;AAAA,MACA,MAAM;AAAA,IACP,CAAC;AAAA,IAED,eAAe;AAAA,MACd,IAAI,mBAAmB;AAAA,MACvB,IAAI,CAAC,EAAE,OAAO,IAAI,MAAM;AACvB,YAAI,MAAM,SAAS,WAAW;AAC7B,gBAAM,YAAY,EAAE,MAAM,iBAAiB,MAAM,OAAO,MAAM,iBAAiB,MAAM;AAAA,QACtF;AACA,YAAI,IAAI,SAAS,WAAW;AAC3B,cAAI,YAAY,EAAE,IAAI,iBAAiB,MAAM,OAAO,IAAI,iBAAiB,MAAM;AAAA,QAChF;AAAA,MACD;AAAA,MACA,MAAM,CAAC,EAAE,OAAO,IAAI,MAAM;AACzB,YAAI,MAAM,SAAS,WAAW;AAC7B,cAAI,CAAC,MAAM,WAAW;AACrB,kBAAM,mBAAmB,EAAE,GAAG,KAAK,GAAG,IAAI;AAAA,UAC3C;AACA,iBAAO,MAAM;AAAA,QACd;AACA,YAAI,IAAI,SAAS,WAAW;AAC3B,cAAI,CAAC,IAAI,WAAW;AACnB,gBAAI,mBAAmB,EAAE,GAAG,KAAK,GAAG,IAAI;AAAA,UACzC;AACA,iBAAO,IAAI;AAAA,QACZ;AAAA,MACD;AAAA,IACD,CAAC;AAAA,IAED,eAAe;AAAA,MACd,IAAI,mBAAmB;AAAA,MACvB,IAAI,CAAC,UAAU;AACd,cAAM,gBAAgB;AAAA,MACvB;AAAA,MACA,MAAM,CAAC,UAAU;AAChB,eAAO,MAAM;AAAA,MACd;AAAA,IACD,CAAC;AAAA,IAED;AAAA,MACC,IAAI,mBAAmB;AAAA,MACvB,OAAO;AAAA,MACP,IAAI,CAAC,aAAa;AAmBjB,cAAM,SAAS,OAAO,OAAO,QAAQ,EAAE;AAAA,UACtC,CAAC,MAA0B,EAAE,aAAa,WAAW,EAAE,SAAS;AAAA,QACjE;AAEA,mBAAW,SAAS,QAAQ;AAC3B,gBAAM,EAAE,OAAO,IAAI,IAAI,MAAM;AAC7B,cAAI,MAAM,SAAS,WAAW;AAC7B,kBAAM,SAAK,kCAAgB;AAC3B,kBAAM,UAAU;AAAA,cACf,UAAU;AAAA,cACV;AAAA,cACA,MAAM;AAAA,cACN,QAAQ,MAAM;AAAA,cACd,MAAM,MAAM;AAAA,cACZ,MAAM,CAAC;AAAA,cACP,OAAO;AAAA,gBACN,UAAU;AAAA,gBACV,kBAAkB,MAAM;AAAA,gBACxB,SAAS,MAAM;AAAA,gBACf,WAAW,MAAM;AAAA,cAClB;AAAA,YACD;AAEA,qBAAS,EAAE,IAAI;AACf,kBAAM,MAAM,QAAQ,EAAE,GAAG,GAAG,GAAG,EAAE;AAAA,UAClC,OAAO;AACN,mBAAO,MAAM,MAAM,MAAM;AAAA,UAC1B;AACA,cAAI,IAAI,SAAS,WAAW;AAC3B,kBAAM,SAAK,kCAAgB;AAC3B,kBAAM,UAAU;AAAA,cACf,UAAU;AAAA,cACV;AAAA,cACA,MAAM;AAAA,cACN,QAAQ,MAAM;AAAA,cACd,MAAM,IAAI;AAAA,cACV,MAAM,CAAC;AAAA,cACP,OAAO;AAAA,gBACN,UAAU;AAAA,gBACV,kBAAkB,IAAI;AAAA,gBACtB,SAAS,IAAI;AAAA,gBACb,WAAW,IAAI;AAAA,cAChB;AAAA,YACD;AAEA,qBAAS,EAAE,IAAI;AACf,kBAAM,MAAM,MAAM,EAAE,GAAG,GAAG,GAAG,EAAE;AAAA,UAChC,OAAO;AACN,mBAAO,MAAM,MAAM,IAAI;AAAA,UACxB;AAAA,QACD;AAAA,MACD;AAAA,IACD;AAAA,IACA,eAAe;AAAA,MACd,IAAI,mBAAmB;AAAA,MACvB,IAAI,CAAC,UAAU;AACd,cAAM,QAAQ;AAAA,MACf;AAAA,MACA,MAAM,CAAC,UAAU;AAChB,eAAO,MAAM;AAAA,MACd;AAAA,IACD,CAAC;AAAA,IACD,eAAe;AAAA,MACd,IAAI,mBAAmB;AAAA,MACvB,IAAI,CAAC,UAAU;AACd,cAAM,OAAO;AACb,cAAM,gBAAgB;AAAA,MACvB;AAAA,MACA,MAAM,CAAC,UAAU;AAChB,eAAO,MAAM;AACb,eAAO,MAAM;AAAA,MACd;AAAA,IACD,CAAC;AAAA,IACD,eAAe;AAAA,MACd,IAAI,mBAAmB;AAAA,MACvB,IAAI,CAAC,UAAU;AACd,cAAM,eAAW,8BAAW,MAAM,IAAI;AACtC,eAAO,MAAM;AAAA,MACd;AAAA;AAAA;AAAA;AAAA;AAAA,IAKD,CAAC;AAAA,EACF;AACD,CAAC;",
4
+ "sourcesContent": ["import { createMigrationSequence } from '@tldraw/store'\nimport { structuredClone } from '@tldraw/utils'\nimport { T } from '@tldraw/validate'\nimport { TLRichText, richTextValidator, toRichText } from '../misc/TLRichText'\nimport { VecModel, vecModelValidator } from '../misc/geometry-types'\nimport { createBindingId } from '../records/TLBinding'\nimport { TLShape, TLShapeId, createShapePropsMigrationIds } from '../records/TLShape'\nimport { RecordProps, TLPropsMigration, createPropsMigration } from '../recordsWithProps'\nimport { StyleProp } from '../styles/StyleProp'\nimport {\n\tDefaultColorStyle,\n\tDefaultLabelColorStyle,\n\tTLDefaultColorStyle,\n} from '../styles/TLColorStyle'\nimport { DefaultDashStyle, TLDefaultDashStyle } from '../styles/TLDashStyle'\nimport { DefaultFillStyle, TLDefaultFillStyle } from '../styles/TLFillStyle'\nimport { DefaultFontStyle, TLDefaultFontStyle } from '../styles/TLFontStyle'\nimport { DefaultSizeStyle, TLDefaultSizeStyle } from '../styles/TLSizeStyle'\nimport { TLBaseShape } from './TLBaseShape'\n\nconst arrowKinds = ['arc', 'elbow'] as const\n/**\n * Style property for arrow shape kind, determining how the arrow is drawn.\n *\n * Arrows can be drawn as arcs (curved) or elbows (angled with straight segments).\n * This affects the visual appearance and behavior of arrow shapes.\n *\n * @example\n * ```ts\n * // Create an arrow with arc style (curved)\n * const arcArrow: TLArrowShape = {\n * // ... other properties\n * props: {\n * kind: 'arc',\n * // ... other props\n * }\n * }\n *\n * // Create an arrow with elbow style (angled)\n * const elbowArrow: TLArrowShape = {\n * // ... other properties\n * props: {\n * kind: 'elbow',\n * // ... other props\n * }\n * }\n * ```\n *\n * @public\n */\nexport const ArrowShapeKindStyle = StyleProp.defineEnum('tldraw:arrowKind', {\n\tdefaultValue: 'arc',\n\tvalues: arrowKinds,\n})\n\n/**\n * The type representing arrow shape kinds.\n *\n * @public\n */\nexport type TLArrowShapeKind = T.TypeOf<typeof ArrowShapeKindStyle>\n\nconst arrowheadTypes = [\n\t'arrow',\n\t'triangle',\n\t'square',\n\t'dot',\n\t'pipe',\n\t'diamond',\n\t'inverted',\n\t'bar',\n\t'none',\n] as const\n\n/**\n * Style property for the arrowhead at the start of an arrow.\n *\n * Defines the visual style of the arrowhead at the beginning of the arrow path.\n * Can be one of several predefined styles or none for no arrowhead.\n *\n * @example\n * ```ts\n * // Arrow with no start arrowhead but triangle end arrowhead\n * const arrow: TLArrowShape = {\n * // ... other properties\n * props: {\n * arrowheadStart: 'none',\n * arrowheadEnd: 'triangle',\n * // ... other props\n * }\n * }\n * ```\n *\n * @public\n */\nexport const ArrowShapeArrowheadStartStyle = StyleProp.defineEnum('tldraw:arrowheadStart', {\n\tdefaultValue: 'none',\n\tvalues: arrowheadTypes,\n})\n\n/**\n * Style property for the arrowhead at the end of an arrow.\n *\n * Defines the visual style of the arrowhead at the end of the arrow path.\n * Defaults to 'arrow' style, giving arrows their characteristic pointed appearance.\n *\n * @example\n * ```ts\n * // Arrow with different start and end arrowheads\n * const doubleArrow: TLArrowShape = {\n * // ... other properties\n * props: {\n * arrowheadStart: 'triangle',\n * arrowheadEnd: 'diamond',\n * // ... other props\n * }\n * }\n * ```\n *\n * @public\n */\nexport const ArrowShapeArrowheadEndStyle = StyleProp.defineEnum('tldraw:arrowheadEnd', {\n\tdefaultValue: 'arrow',\n\tvalues: arrowheadTypes,\n})\n\n/**\n * The type representing arrowhead styles for both start and end of arrows.\n *\n * @public\n */\nexport type TLArrowShapeArrowheadStyle = T.TypeOf<typeof ArrowShapeArrowheadStartStyle>\n\n/**\n * Properties specific to arrow shapes.\n *\n * Defines all the configurable aspects of an arrow shape, including visual styling,\n * geometry, text labeling, and positioning. Arrows can connect two points and\n * optionally display text labels.\n *\n * @example\n * ```ts\n * const arrowProps: TLArrowShapeProps = {\n * kind: 'arc',\n * labelColor: 'black',\n * color: 'blue',\n * fill: 'none',\n * dash: 'solid',\n * size: 'm',\n * arrowheadStart: 'none',\n * arrowheadEnd: 'arrow',\n * font: 'draw',\n * start: { x: 0, y: 0 },\n * end: { x: 100, y: 100 },\n * bend: 0.2,\n * richText: toRichText('Label'),\n * labelPosition: 0.5,\n * scale: 1,\n * elbowMidPoint: 0.5\n * }\n * ```\n *\n * @public\n */\nexport interface TLArrowShapeProps {\n\tkind: TLArrowShapeKind\n\tlabelColor: TLDefaultColorStyle\n\tcolor: TLDefaultColorStyle\n\tfill: TLDefaultFillStyle\n\tdash: TLDefaultDashStyle\n\tsize: TLDefaultSizeStyle\n\tarrowheadStart: TLArrowShapeArrowheadStyle\n\tarrowheadEnd: TLArrowShapeArrowheadStyle\n\tfont: TLDefaultFontStyle\n\tstart: VecModel\n\tend: VecModel\n\tbend: number\n\trichText: TLRichText\n\tlabelPosition: number\n\tscale: number\n\telbowMidPoint: number\n}\n\n/**\n * A complete arrow shape record.\n *\n * Combines the base shape interface with arrow-specific properties to create\n * a full arrow shape that can be stored and manipulated in the editor.\n *\n * @example\n * ```ts\n * const arrowShape: TLArrowShape = {\n * id: 'shape:arrow123',\n * typeName: 'shape',\n * type: 'arrow',\n * x: 100,\n * y: 200,\n * rotation: 0,\n * index: 'a1',\n * parentId: 'page:main',\n * isLocked: false,\n * opacity: 1,\n * props: {\n * kind: 'arc',\n * start: { x: 0, y: 0 },\n * end: { x: 150, y: 100 },\n * // ... other props\n * },\n * meta: {}\n * }\n * ```\n *\n * @public\n */\nexport type TLArrowShape = TLBaseShape<'arrow', TLArrowShapeProps>\n\n/**\n * Validation configuration for arrow shape properties.\n *\n * Defines the validators for each property of an arrow shape, ensuring that\n * arrow shape data is valid and conforms to the expected types and constraints.\n *\n * @example\n * ```ts\n * // The validators ensure proper typing and validation\n * const validator = T.object(arrowShapeProps)\n * const validArrowProps = validator.validate({\n * kind: 'arc',\n * start: { x: 0, y: 0 },\n * end: { x: 100, y: 50 },\n * // ... other required properties\n * })\n * ```\n *\n * @public\n */\nexport const arrowShapeProps: RecordProps<TLArrowShape> = {\n\tkind: ArrowShapeKindStyle,\n\tlabelColor: DefaultLabelColorStyle,\n\tcolor: DefaultColorStyle,\n\tfill: DefaultFillStyle,\n\tdash: DefaultDashStyle,\n\tsize: DefaultSizeStyle,\n\tarrowheadStart: ArrowShapeArrowheadStartStyle,\n\tarrowheadEnd: ArrowShapeArrowheadEndStyle,\n\tfont: DefaultFontStyle,\n\tstart: vecModelValidator,\n\tend: vecModelValidator,\n\tbend: T.number,\n\trichText: richTextValidator,\n\tlabelPosition: T.number,\n\tscale: T.nonZeroNumber,\n\telbowMidPoint: T.number,\n}\n\n/**\n * Migration version identifiers for arrow shape properties.\n *\n * These track the evolution of the arrow shape schema over time, with each\n * version representing a specific change to the arrow shape structure or properties.\n *\n * @example\n * ```ts\n * // Used internally for migration system\n * if (version < arrowShapeVersions.AddLabelColor) {\n * // Apply label color migration\n * }\n * ```\n *\n * @public\n */\nexport const arrowShapeVersions = createShapePropsMigrationIds('arrow', {\n\tAddLabelColor: 1,\n\tAddIsPrecise: 2,\n\tAddLabelPosition: 3,\n\tExtractBindings: 4,\n\tAddScale: 5,\n\tAddElbow: 6,\n\tAddRichText: 7,\n\tAddRichTextAttrs: 8,\n})\n\nfunction propsMigration(migration: TLPropsMigration) {\n\treturn createPropsMigration<TLArrowShape>('shape', 'arrow', migration)\n}\n\n/**\n * Complete migration sequence for arrow shapes.\n *\n * Defines all the migrations needed to transform arrow shape data from older\n * versions to the current version. Each migration handles a specific schema change,\n * ensuring backward compatibility and smooth data evolution.\n *\n * @public\n */\nexport const arrowShapeMigrations = createMigrationSequence({\n\tsequenceId: 'com.tldraw.shape.arrow',\n\tretroactive: false,\n\tsequence: [\n\t\tpropsMigration({\n\t\t\tid: arrowShapeVersions.AddLabelColor,\n\t\t\tup: (props) => {\n\t\t\t\tprops.labelColor = 'black'\n\t\t\t},\n\t\t\tdown: 'retired',\n\t\t}),\n\n\t\tpropsMigration({\n\t\t\tid: arrowShapeVersions.AddIsPrecise,\n\t\t\tup: ({ start, end }) => {\n\t\t\t\tif (start.type === 'binding') {\n\t\t\t\t\tstart.isPrecise = !(start.normalizedAnchor.x === 0.5 && start.normalizedAnchor.y === 0.5)\n\t\t\t\t}\n\t\t\t\tif (end.type === 'binding') {\n\t\t\t\t\tend.isPrecise = !(end.normalizedAnchor.x === 0.5 && end.normalizedAnchor.y === 0.5)\n\t\t\t\t}\n\t\t\t},\n\t\t\tdown: ({ start, end }) => {\n\t\t\t\tif (start.type === 'binding') {\n\t\t\t\t\tif (!start.isPrecise) {\n\t\t\t\t\t\tstart.normalizedAnchor = { x: 0.5, y: 0.5 }\n\t\t\t\t\t}\n\t\t\t\t\tdelete start.isPrecise\n\t\t\t\t}\n\t\t\t\tif (end.type === 'binding') {\n\t\t\t\t\tif (!end.isPrecise) {\n\t\t\t\t\t\tend.normalizedAnchor = { x: 0.5, y: 0.5 }\n\t\t\t\t\t}\n\t\t\t\t\tdelete end.isPrecise\n\t\t\t\t}\n\t\t\t},\n\t\t}),\n\n\t\tpropsMigration({\n\t\t\tid: arrowShapeVersions.AddLabelPosition,\n\t\t\tup: (props) => {\n\t\t\t\tprops.labelPosition = 0.5\n\t\t\t},\n\t\t\tdown: (props) => {\n\t\t\t\tdelete props.labelPosition\n\t\t\t},\n\t\t}),\n\n\t\t{\n\t\t\tid: arrowShapeVersions.ExtractBindings,\n\t\t\tscope: 'storage',\n\t\t\tup: (storage) => {\n\t\t\t\ttype OldArrowTerminal =\n\t\t\t\t\t| {\n\t\t\t\t\t\t\ttype: 'point'\n\t\t\t\t\t\t\tx: number\n\t\t\t\t\t\t\ty: number\n\t\t\t\t\t }\n\t\t\t\t\t| {\n\t\t\t\t\t\t\ttype: 'binding'\n\t\t\t\t\t\t\tboundShapeId: TLShapeId\n\t\t\t\t\t\t\tnormalizedAnchor: VecModel\n\t\t\t\t\t\t\tisExact: boolean\n\t\t\t\t\t\t\tisPrecise: boolean\n\t\t\t\t\t }\n\t\t\t\t\t// new type:\n\t\t\t\t\t| { type?: undefined; x: number; y: number }\n\n\t\t\t\ttype OldArrow = TLBaseShape<'arrow', { start: OldArrowTerminal; end: OldArrowTerminal }>\n\n\t\t\t\t// Collect all updates during iteration, then apply them after.\n\t\t\t\t// This avoids issues with live iterators (e.g., SQLite) where updating\n\t\t\t\t// records during iteration can cause them to be visited multiple times.\n\t\t\t\tconst updates: [string, unknown][] = []\n\n\t\t\t\tfor (const record of storage.values()) {\n\t\t\t\t\tif (record.typeName !== 'shape' || (record as TLShape).type !== 'arrow') continue\n\t\t\t\t\tconst arrow = record as OldArrow\n\t\t\t\t\tconst newArrow = structuredClone(arrow)\n\t\t\t\t\tconst { start, end } = arrow.props\n\t\t\t\t\tif (start.type === 'binding') {\n\t\t\t\t\t\tconst id = createBindingId()\n\t\t\t\t\t\tconst binding = {\n\t\t\t\t\t\t\ttypeName: 'binding',\n\t\t\t\t\t\t\tid,\n\t\t\t\t\t\t\ttype: 'arrow',\n\t\t\t\t\t\t\tfromId: arrow.id,\n\t\t\t\t\t\t\ttoId: start.boundShapeId,\n\t\t\t\t\t\t\tmeta: {},\n\t\t\t\t\t\t\tprops: {\n\t\t\t\t\t\t\t\tterminal: 'start',\n\t\t\t\t\t\t\t\tnormalizedAnchor: start.normalizedAnchor,\n\t\t\t\t\t\t\t\tisExact: start.isExact,\n\t\t\t\t\t\t\t\tisPrecise: start.isPrecise,\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tupdates.push([id, binding])\n\t\t\t\t\t\tnewArrow.props.start = { x: 0, y: 0 }\n\t\t\t\t\t} else {\n\t\t\t\t\t\tdelete newArrow.props.start.type\n\t\t\t\t\t}\n\t\t\t\t\tif (end.type === 'binding') {\n\t\t\t\t\t\tconst id = createBindingId()\n\t\t\t\t\t\tconst binding = {\n\t\t\t\t\t\t\ttypeName: 'binding',\n\t\t\t\t\t\t\tid,\n\t\t\t\t\t\t\ttype: 'arrow',\n\t\t\t\t\t\t\tfromId: arrow.id,\n\t\t\t\t\t\t\ttoId: end.boundShapeId,\n\t\t\t\t\t\t\tmeta: {},\n\t\t\t\t\t\t\tprops: {\n\t\t\t\t\t\t\t\tterminal: 'end',\n\t\t\t\t\t\t\t\tnormalizedAnchor: end.normalizedAnchor,\n\t\t\t\t\t\t\t\tisExact: end.isExact,\n\t\t\t\t\t\t\t\tisPrecise: end.isPrecise,\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tupdates.push([id, binding])\n\t\t\t\t\t\tnewArrow.props.end = { x: 0, y: 0 }\n\t\t\t\t\t} else {\n\t\t\t\t\t\tdelete newArrow.props.end.type\n\t\t\t\t\t}\n\t\t\t\t\tupdates.push([arrow.id, newArrow])\n\t\t\t\t}\n\n\t\t\t\tfor (const [id, record] of updates) {\n\t\t\t\t\tstorage.set(id, record as any)\n\t\t\t\t}\n\t\t\t},\n\t\t},\n\t\tpropsMigration({\n\t\t\tid: arrowShapeVersions.AddScale,\n\t\t\tup: (props) => {\n\t\t\t\tprops.scale = 1\n\t\t\t},\n\t\t\tdown: (props) => {\n\t\t\t\tdelete props.scale\n\t\t\t},\n\t\t}),\n\t\tpropsMigration({\n\t\t\tid: arrowShapeVersions.AddElbow,\n\t\t\tup: (props) => {\n\t\t\t\tprops.kind = 'arc'\n\t\t\t\tprops.elbowMidPoint = 0.5\n\t\t\t},\n\t\t\tdown: (props) => {\n\t\t\t\tdelete props.kind\n\t\t\t\tdelete props.elbowMidPoint\n\t\t\t},\n\t\t}),\n\t\tpropsMigration({\n\t\t\tid: arrowShapeVersions.AddRichText,\n\t\t\tup: (props) => {\n\t\t\t\tprops.richText = toRichText(props.text)\n\t\t\t\tdelete props.text\n\t\t\t},\n\t\t\t// N.B. Explicitly no down state so that we force clients to update.\n\t\t\t// down: (props) => {\n\t\t\t// \tdelete props.richText\n\t\t\t// },\n\t\t}),\n\t\tpropsMigration({\n\t\t\tid: arrowShapeVersions.AddRichTextAttrs,\n\t\t\tup: (_props) => {\n\t\t\t\t// noop - attrs is optional so old records are valid\n\t\t\t},\n\t\t\tdown: (props) => {\n\t\t\t\t// Remove attrs from richText when migrating down\n\t\t\t\tif (props.richText && 'attrs' in props.richText) {\n\t\t\t\t\tdelete props.richText.attrs\n\t\t\t\t}\n\t\t\t},\n\t\t}),\n\t],\n})\n"],
5
+ "mappings": "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",
6
6
  "names": []
7
7
  }
@@ -19,13 +19,14 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
19
19
  var TLDrawShape_exports = {};
20
20
  __export(TLDrawShape_exports, {
21
21
  DrawShapeSegment: () => DrawShapeSegment,
22
+ compressLegacySegments: () => compressLegacySegments,
22
23
  drawShapeMigrations: () => drawShapeMigrations,
23
24
  drawShapeProps: () => drawShapeProps,
24
25
  drawShapeVersions: () => Versions
25
26
  });
26
27
  module.exports = __toCommonJS(TLDrawShape_exports);
27
28
  var import_validate = require("@tldraw/validate");
28
- var import_geometry_types = require("../misc/geometry-types");
29
+ var import_b64Vecs = require("../misc/b64Vecs");
29
30
  var import_TLShape = require("../records/TLShape");
30
31
  var import_TLColorStyle = require("../styles/TLColorStyle");
31
32
  var import_TLDashStyle = require("../styles/TLDashStyle");
@@ -33,7 +34,7 @@ var import_TLFillStyle = require("../styles/TLFillStyle");
33
34
  var import_TLSizeStyle = require("../styles/TLSizeStyle");
34
35
  const DrawShapeSegment = import_validate.T.object({
35
36
  type: import_validate.T.literalEnum("free", "straight"),
36
- points: import_validate.T.arrayOf(import_geometry_types.vecModelValidator)
37
+ points: import_validate.T.string
37
38
  });
38
39
  const drawShapeProps = {
39
40
  color: import_TLColorStyle.DefaultColorStyle,
@@ -44,11 +45,14 @@ const drawShapeProps = {
44
45
  isComplete: import_validate.T.boolean,
45
46
  isClosed: import_validate.T.boolean,
46
47
  isPen: import_validate.T.boolean,
47
- scale: import_validate.T.nonZeroNumber
48
+ scale: import_validate.T.nonZeroNumber,
49
+ scaleX: import_validate.T.nonZeroFiniteNumber,
50
+ scaleY: import_validate.T.nonZeroFiniteNumber
48
51
  };
49
52
  const Versions = (0, import_TLShape.createShapePropsMigrationIds)("draw", {
50
53
  AddInPen: 1,
51
- AddScale: 2
54
+ AddScale: 2,
55
+ Base64: 3
52
56
  });
53
57
  const drawShapeMigrations = (0, import_TLShape.createShapePropsMigrationSequence)({
54
58
  sequence: [
@@ -76,7 +80,36 @@ const drawShapeMigrations = (0, import_TLShape.createShapePropsMigrationSequence
76
80
  down: (props) => {
77
81
  delete props.scale;
78
82
  }
83
+ },
84
+ {
85
+ id: Versions.Base64,
86
+ up: (props) => {
87
+ props.segments = props.segments.map((segment) => {
88
+ return {
89
+ ...segment,
90
+ // Only encode if points is an array (not already base64 string)
91
+ points: typeof segment.points === "string" ? segment.points : import_b64Vecs.b64Vecs.encodePoints(segment.points)
92
+ };
93
+ });
94
+ props.scaleX = props.scaleX ?? 1;
95
+ props.scaleY = props.scaleY ?? 1;
96
+ },
97
+ down: (props) => {
98
+ props.segments = props.segments.map((segment) => ({
99
+ ...segment,
100
+ // Only decode if points is a string (not already VecModel[])
101
+ points: Array.isArray(segment.points) ? segment.points : import_b64Vecs.b64Vecs.decodePoints(segment.points)
102
+ }));
103
+ delete props.scaleX;
104
+ delete props.scaleY;
105
+ }
79
106
  }
80
107
  ]
81
108
  });
109
+ function compressLegacySegments(segments) {
110
+ return segments.map((segment) => ({
111
+ ...segment,
112
+ points: import_b64Vecs.b64Vecs.encodePoints(segment.points)
113
+ }));
114
+ }
82
115
  //# sourceMappingURL=TLDrawShape.js.map
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../src/shapes/TLDrawShape.ts"],
4
- "sourcesContent": ["import { T } from '@tldraw/validate'\nimport { VecModel, vecModelValidator } from '../misc/geometry-types'\nimport { createShapePropsMigrationIds, createShapePropsMigrationSequence } from '../records/TLShape'\nimport { RecordProps } from '../recordsWithProps'\nimport { DefaultColorStyle, TLDefaultColorStyle } from '../styles/TLColorStyle'\nimport { DefaultDashStyle, TLDefaultDashStyle } from '../styles/TLDashStyle'\nimport { DefaultFillStyle, TLDefaultFillStyle } from '../styles/TLFillStyle'\nimport { DefaultSizeStyle, TLDefaultSizeStyle } from '../styles/TLSizeStyle'\nimport { TLBaseShape } from './TLBaseShape'\n\n/**\n * A segment of a draw shape representing either freehand drawing or straight line segments.\n *\n * @public\n */\nexport interface TLDrawShapeSegment {\n\t/** Type of drawing segment - 'free' for freehand curves, 'straight' for line segments */\n\ttype: 'free' | 'straight'\n\t/** Array of points defining the segment path with x, y coordinates and pressure (z) */\n\tpoints: VecModel[]\n}\n\n/**\n * Validator for draw shape segments ensuring proper structure and data types.\n *\n * @public\n * @example\n * ```ts\n * const segment: TLDrawShapeSegment = {\n * type: 'free',\n * points: [{ x: 0, y: 0, z: 0.5 }, { x: 10, y: 10, z: 0.7 }]\n * }\n * const isValid = DrawShapeSegment.isValid(segment)\n * ```\n */\nexport const DrawShapeSegment: T.ObjectValidator<TLDrawShapeSegment> = T.object({\n\ttype: T.literalEnum('free', 'straight'),\n\tpoints: T.arrayOf(vecModelValidator),\n})\n\n/**\n * Properties for the draw shape, which represents freehand drawing and sketching.\n *\n * @public\n */\nexport interface TLDrawShapeProps {\n\t/** Color style for the drawing stroke */\n\tcolor: TLDefaultColorStyle\n\t/** Fill style for closed drawing shapes */\n\tfill: TLDefaultFillStyle\n\t/** Dash pattern style for the stroke */\n\tdash: TLDefaultDashStyle\n\t/** Size/thickness of the drawing stroke */\n\tsize: TLDefaultSizeStyle\n\t/** Array of segments that make up the complete drawing path */\n\tsegments: TLDrawShapeSegment[]\n\t/** Whether the drawing is complete (user finished drawing) */\n\tisComplete: boolean\n\t/** Whether the drawing path forms a closed shape */\n\tisClosed: boolean\n\t/** Whether this drawing was created with a pen/stylus device */\n\tisPen: boolean\n\t/** Scale factor applied to the drawing */\n\tscale: number\n}\n\n/**\n * A draw shape represents freehand drawing, sketching, and pen input on the canvas.\n * Draw shapes are composed of segments that can be either smooth curves or straight lines.\n *\n * @public\n * @example\n * ```ts\n * const drawShape: TLDrawShape = {\n * id: createShapeId(),\n * typeName: 'shape',\n * type: 'draw',\n * x: 50,\n * y: 50,\n * rotation: 0,\n * index: 'a1',\n * parentId: 'page:page1',\n * isLocked: false,\n * opacity: 1,\n * props: {\n * color: 'black',\n * fill: 'none',\n * dash: 'solid',\n * size: 'm',\n * segments: [{\n * type: 'free',\n * points: [{ x: 0, y: 0, z: 0.5 }, { x: 20, y: 15, z: 0.6 }]\n * }],\n * isComplete: true,\n * isClosed: false,\n * isPen: false,\n * scale: 1\n * },\n * meta: {}\n * }\n * ```\n */\nexport type TLDrawShape = TLBaseShape<'draw', TLDrawShapeProps>\n\n/**\n * Validation schema for draw shape properties.\n *\n * @public\n * @example\n * ```ts\n * // Validate draw shape properties\n * const props = {\n * color: 'red',\n * fill: 'solid',\n * segments: [{ type: 'free', points: [] }],\n * isComplete: true\n * }\n * const isValid = drawShapeProps.color.isValid(props.color)\n * ```\n */\nexport const drawShapeProps: RecordProps<TLDrawShape> = {\n\tcolor: DefaultColorStyle,\n\tfill: DefaultFillStyle,\n\tdash: DefaultDashStyle,\n\tsize: DefaultSizeStyle,\n\tsegments: T.arrayOf(DrawShapeSegment),\n\tisComplete: T.boolean,\n\tisClosed: T.boolean,\n\tisPen: T.boolean,\n\tscale: T.nonZeroNumber,\n}\n\nconst Versions = createShapePropsMigrationIds('draw', {\n\tAddInPen: 1,\n\tAddScale: 2,\n})\n\n/**\n * Version identifiers for draw shape migrations.\n *\n * @public\n */\nexport { Versions as drawShapeVersions }\n\n/**\n * Migration sequence for draw shape properties across different schema versions.\n * Handles adding pen detection and scale properties to existing draw shapes.\n *\n * @public\n */\nexport const drawShapeMigrations = createShapePropsMigrationSequence({\n\tsequence: [\n\t\t{\n\t\t\tid: Versions.AddInPen,\n\t\t\tup: (props) => {\n\t\t\t\t// Rather than checking to see whether the shape is a pen at runtime,\n\t\t\t\t// from now on we're going to use the type of device reported to us\n\t\t\t\t// as well as the pressure data received; but for existing shapes we\n\t\t\t\t// need to check the pressure data to see if it's a pen or not.\n\n\t\t\t\tconst { points } = props.segments[0]\n\n\t\t\t\tif (points.length === 0) {\n\t\t\t\t\tprops.isPen = false\n\t\t\t\t\treturn\n\t\t\t\t}\n\n\t\t\t\tlet isPen = !(points[0].z === 0 || points[0].z === 0.5)\n\n\t\t\t\tif (points[1]) {\n\t\t\t\t\t// Double check if we have a second point (we probably should)\n\t\t\t\t\tisPen = isPen && !(points[1].z === 0 || points[1].z === 0.5)\n\t\t\t\t}\n\t\t\t\tprops.isPen = isPen\n\t\t\t},\n\t\t\tdown: 'retired',\n\t\t},\n\t\t{\n\t\t\tid: Versions.AddScale,\n\t\t\tup: (props) => {\n\t\t\t\tprops.scale = 1\n\t\t\t},\n\t\t\tdown: (props) => {\n\t\t\t\tdelete props.scale\n\t\t\t},\n\t\t},\n\t],\n})\n"],
5
- "mappings": ";;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,sBAAkB;AAClB,4BAA4C;AAC5C,qBAAgF;AAEhF,0BAAuD;AACvD,yBAAqD;AACrD,yBAAqD;AACrD,yBAAqD;AA4B9C,MAAM,mBAA0D,kBAAE,OAAO;AAAA,EAC/E,MAAM,kBAAE,YAAY,QAAQ,UAAU;AAAA,EACtC,QAAQ,kBAAE,QAAQ,uCAAiB;AACpC,CAAC;AAkFM,MAAM,iBAA2C;AAAA,EACvD,OAAO;AAAA,EACP,MAAM;AAAA,EACN,MAAM;AAAA,EACN,MAAM;AAAA,EACN,UAAU,kBAAE,QAAQ,gBAAgB;AAAA,EACpC,YAAY,kBAAE;AAAA,EACd,UAAU,kBAAE;AAAA,EACZ,OAAO,kBAAE;AAAA,EACT,OAAO,kBAAE;AACV;AAEA,MAAM,eAAW,6CAA6B,QAAQ;AAAA,EACrD,UAAU;AAAA,EACV,UAAU;AACX,CAAC;AAeM,MAAM,0BAAsB,kDAAkC;AAAA,EACpE,UAAU;AAAA,IACT;AAAA,MACC,IAAI,SAAS;AAAA,MACb,IAAI,CAAC,UAAU;AAMd,cAAM,EAAE,OAAO,IAAI,MAAM,SAAS,CAAC;AAEnC,YAAI,OAAO,WAAW,GAAG;AACxB,gBAAM,QAAQ;AACd;AAAA,QACD;AAEA,YAAI,QAAQ,EAAE,OAAO,CAAC,EAAE,MAAM,KAAK,OAAO,CAAC,EAAE,MAAM;AAEnD,YAAI,OAAO,CAAC,GAAG;AAEd,kBAAQ,SAAS,EAAE,OAAO,CAAC,EAAE,MAAM,KAAK,OAAO,CAAC,EAAE,MAAM;AAAA,QACzD;AACA,cAAM,QAAQ;AAAA,MACf;AAAA,MACA,MAAM;AAAA,IACP;AAAA,IACA;AAAA,MACC,IAAI,SAAS;AAAA,MACb,IAAI,CAAC,UAAU;AACd,cAAM,QAAQ;AAAA,MACf;AAAA,MACA,MAAM,CAAC,UAAU;AAChB,eAAO,MAAM;AAAA,MACd;AAAA,IACD;AAAA,EACD;AACD,CAAC;",
4
+ "sourcesContent": ["import { T } from '@tldraw/validate'\nimport { b64Vecs } from '../misc/b64Vecs'\nimport { VecModel } from '../misc/geometry-types'\nimport { createShapePropsMigrationIds, createShapePropsMigrationSequence } from '../records/TLShape'\nimport { RecordProps } from '../recordsWithProps'\nimport { DefaultColorStyle, TLDefaultColorStyle } from '../styles/TLColorStyle'\nimport { DefaultDashStyle, TLDefaultDashStyle } from '../styles/TLDashStyle'\nimport { DefaultFillStyle, TLDefaultFillStyle } from '../styles/TLFillStyle'\nimport { DefaultSizeStyle, TLDefaultSizeStyle } from '../styles/TLSizeStyle'\nimport { TLBaseShape } from './TLBaseShape'\n\n/**\n * A segment of a draw shape representing either freehand drawing or straight line segments.\n *\n * @public\n */\nexport interface TLDrawShapeSegment {\n\t/** Type of drawing segment - 'free' for freehand curves, 'straight' for line segments */\n\ttype: 'free' | 'straight'\n\t/** Base64-encoded points (x, y, z triplets stored as Float16) */\n\tpoints: string\n}\n\n/**\n * Validator for draw shape segments ensuring proper structure and data types.\n *\n * @public\n */\nexport const DrawShapeSegment: T.ObjectValidator<TLDrawShapeSegment> = T.object({\n\ttype: T.literalEnum('free', 'straight'),\n\tpoints: T.string,\n})\n\n/**\n * Properties for the draw shape, which represents freehand drawing and sketching.\n *\n * @public\n */\nexport interface TLDrawShapeProps {\n\t/** Color style for the drawing stroke */\n\tcolor: TLDefaultColorStyle\n\t/** Fill style for closed drawing shapes */\n\tfill: TLDefaultFillStyle\n\t/** Dash pattern style for the stroke */\n\tdash: TLDefaultDashStyle\n\t/** Size/thickness of the drawing stroke */\n\tsize: TLDefaultSizeStyle\n\t/** Array of segments that make up the complete drawing path */\n\tsegments: TLDrawShapeSegment[]\n\t/** Whether the drawing is complete (user finished drawing) */\n\tisComplete: boolean\n\t/** Whether the drawing path forms a closed shape */\n\tisClosed: boolean\n\t/** Whether this drawing was created with a pen/stylus device */\n\tisPen: boolean\n\t/** Scale factor applied to the drawing */\n\tscale: number\n\t/** Horizontal scale factor for lazy resize */\n\tscaleX: number\n\t/** Vertical scale factor for lazy resize */\n\tscaleY: number\n}\n\n/**\n * A draw shape represents freehand drawing, sketching, and pen input on the canvas.\n * Draw shapes are composed of segments that can be either smooth curves or straight lines.\n *\n * @public\n * @example\n * ```ts\n * const drawShape: TLDrawShape = {\n * id: createShapeId(),\n * typeName: 'shape',\n * type: 'draw',\n * x: 50,\n * y: 50,\n * rotation: 0,\n * index: 'a1',\n * parentId: 'page:page1',\n * isLocked: false,\n * opacity: 1,\n * props: {\n * color: 'black',\n * fill: 'none',\n * dash: 'solid',\n * size: 'm',\n * segments: [{\n * type: 'free',\n * points: [{ x: 0, y: 0, z: 0.5 }, { x: 20, y: 15, z: 0.6 }]\n * }],\n * isComplete: true,\n * isClosed: false,\n * isPen: false,\n * scale: 1\n * },\n * meta: {}\n * }\n * ```\n */\nexport type TLDrawShape = TLBaseShape<'draw', TLDrawShapeProps>\n\n/**\n * Validation schema for draw shape properties.\n *\n * @public\n * @example\n * ```ts\n * // Validate draw shape properties\n * const props = {\n * color: 'red',\n * fill: 'solid',\n * segments: [{ type: 'free', points: [] }],\n * isComplete: true\n * }\n * const isValid = drawShapeProps.color.isValid(props.color)\n * ```\n */\n/** @public */\nexport const drawShapeProps: RecordProps<TLDrawShape> = {\n\tcolor: DefaultColorStyle,\n\tfill: DefaultFillStyle,\n\tdash: DefaultDashStyle,\n\tsize: DefaultSizeStyle,\n\tsegments: T.arrayOf(DrawShapeSegment),\n\tisComplete: T.boolean,\n\tisClosed: T.boolean,\n\tisPen: T.boolean,\n\tscale: T.nonZeroNumber,\n\tscaleX: T.nonZeroFiniteNumber,\n\tscaleY: T.nonZeroFiniteNumber,\n}\n\nconst Versions = createShapePropsMigrationIds('draw', {\n\tAddInPen: 1,\n\tAddScale: 2,\n\tBase64: 3,\n})\n\n/**\n * Version identifiers for draw shape migrations.\n *\n * @public\n */\nexport { Versions as drawShapeVersions }\n\n/**\n * Migration sequence for draw shape properties across different schema versions.\n * Handles adding pen detection and scale properties to existing draw shapes.\n *\n * @public\n */\nexport const drawShapeMigrations = createShapePropsMigrationSequence({\n\tsequence: [\n\t\t{\n\t\t\tid: Versions.AddInPen,\n\t\t\tup: (props) => {\n\t\t\t\t// Rather than checking to see whether the shape is a pen at runtime,\n\t\t\t\t// from now on we're going to use the type of device reported to us\n\t\t\t\t// as well as the pressure data received; but for existing shapes we\n\t\t\t\t// need to check the pressure data to see if it's a pen or not.\n\n\t\t\t\tconst { points } = props.segments[0]\n\n\t\t\t\tif (points.length === 0) {\n\t\t\t\t\tprops.isPen = false\n\t\t\t\t\treturn\n\t\t\t\t}\n\n\t\t\t\tlet isPen = !(points[0].z === 0 || points[0].z === 0.5)\n\n\t\t\t\tif (points[1]) {\n\t\t\t\t\t// Double check if we have a second point (we probably should)\n\t\t\t\t\tisPen = isPen && !(points[1].z === 0 || points[1].z === 0.5)\n\t\t\t\t}\n\t\t\t\tprops.isPen = isPen\n\t\t\t},\n\t\t\tdown: 'retired',\n\t\t},\n\t\t{\n\t\t\tid: Versions.AddScale,\n\t\t\tup: (props) => {\n\t\t\t\tprops.scale = 1\n\t\t\t},\n\t\t\tdown: (props) => {\n\t\t\t\tdelete props.scale\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tid: Versions.Base64,\n\t\t\tup: (props) => {\n\t\t\t\tprops.segments = props.segments.map((segment: any) => {\n\t\t\t\t\treturn {\n\t\t\t\t\t\t...segment,\n\t\t\t\t\t\t// Only encode if points is an array (not already base64 string)\n\t\t\t\t\t\tpoints:\n\t\t\t\t\t\t\ttypeof segment.points === 'string'\n\t\t\t\t\t\t\t\t? segment.points\n\t\t\t\t\t\t\t\t: b64Vecs.encodePoints(segment.points),\n\t\t\t\t\t}\n\t\t\t\t})\n\t\t\t\tprops.scaleX = props.scaleX ?? 1\n\t\t\t\tprops.scaleY = props.scaleY ?? 1\n\t\t\t},\n\t\t\tdown: (props) => {\n\t\t\t\tprops.segments = props.segments.map((segment: any) => ({\n\t\t\t\t\t...segment,\n\t\t\t\t\t// Only decode if points is a string (not already VecModel[])\n\t\t\t\t\tpoints: Array.isArray(segment.points)\n\t\t\t\t\t\t? segment.points\n\t\t\t\t\t\t: b64Vecs.decodePoints(segment.points),\n\t\t\t\t}))\n\t\t\t\tdelete props.scaleX\n\t\t\t\tdelete props.scaleY\n\t\t\t},\n\t\t},\n\t],\n})\n\n/**\n * Compress legacy draw shape segments by converting VecModel[] points to base64 format.\n * This function is useful for converting old draw shape data to the new compressed format.\n *\n * @public\n */\nexport function compressLegacySegments(\n\tsegments: {\n\t\ttype: 'free' | 'straight'\n\t\tpoints: VecModel[]\n\t}[]\n): TLDrawShapeSegment[] {\n\treturn segments.map((segment) => ({\n\t\t...segment,\n\t\tpoints: b64Vecs.encodePoints(segment.points),\n\t}))\n}\n"],
5
+ "mappings": ";;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,sBAAkB;AAClB,qBAAwB;AAExB,qBAAgF;AAEhF,0BAAuD;AACvD,yBAAqD;AACrD,yBAAqD;AACrD,yBAAqD;AAoB9C,MAAM,mBAA0D,kBAAE,OAAO;AAAA,EAC/E,MAAM,kBAAE,YAAY,QAAQ,UAAU;AAAA,EACtC,QAAQ,kBAAE;AACX,CAAC;AAuFM,MAAM,iBAA2C;AAAA,EACvD,OAAO;AAAA,EACP,MAAM;AAAA,EACN,MAAM;AAAA,EACN,MAAM;AAAA,EACN,UAAU,kBAAE,QAAQ,gBAAgB;AAAA,EACpC,YAAY,kBAAE;AAAA,EACd,UAAU,kBAAE;AAAA,EACZ,OAAO,kBAAE;AAAA,EACT,OAAO,kBAAE;AAAA,EACT,QAAQ,kBAAE;AAAA,EACV,QAAQ,kBAAE;AACX;AAEA,MAAM,eAAW,6CAA6B,QAAQ;AAAA,EACrD,UAAU;AAAA,EACV,UAAU;AAAA,EACV,QAAQ;AACT,CAAC;AAeM,MAAM,0BAAsB,kDAAkC;AAAA,EACpE,UAAU;AAAA,IACT;AAAA,MACC,IAAI,SAAS;AAAA,MACb,IAAI,CAAC,UAAU;AAMd,cAAM,EAAE,OAAO,IAAI,MAAM,SAAS,CAAC;AAEnC,YAAI,OAAO,WAAW,GAAG;AACxB,gBAAM,QAAQ;AACd;AAAA,QACD;AAEA,YAAI,QAAQ,EAAE,OAAO,CAAC,EAAE,MAAM,KAAK,OAAO,CAAC,EAAE,MAAM;AAEnD,YAAI,OAAO,CAAC,GAAG;AAEd,kBAAQ,SAAS,EAAE,OAAO,CAAC,EAAE,MAAM,KAAK,OAAO,CAAC,EAAE,MAAM;AAAA,QACzD;AACA,cAAM,QAAQ;AAAA,MACf;AAAA,MACA,MAAM;AAAA,IACP;AAAA,IACA;AAAA,MACC,IAAI,SAAS;AAAA,MACb,IAAI,CAAC,UAAU;AACd,cAAM,QAAQ;AAAA,MACf;AAAA,MACA,MAAM,CAAC,UAAU;AAChB,eAAO,MAAM;AAAA,MACd;AAAA,IACD;AAAA,IACA;AAAA,MACC,IAAI,SAAS;AAAA,MACb,IAAI,CAAC,UAAU;AACd,cAAM,WAAW,MAAM,SAAS,IAAI,CAAC,YAAiB;AACrD,iBAAO;AAAA,YACN,GAAG;AAAA;AAAA,YAEH,QACC,OAAO,QAAQ,WAAW,WACvB,QAAQ,SACR,uBAAQ,aAAa,QAAQ,MAAM;AAAA,UACxC;AAAA,QACD,CAAC;AACD,cAAM,SAAS,MAAM,UAAU;AAC/B,cAAM,SAAS,MAAM,UAAU;AAAA,MAChC;AAAA,MACA,MAAM,CAAC,UAAU;AAChB,cAAM,WAAW,MAAM,SAAS,IAAI,CAAC,aAAkB;AAAA,UACtD,GAAG;AAAA;AAAA,UAEH,QAAQ,MAAM,QAAQ,QAAQ,MAAM,IACjC,QAAQ,SACR,uBAAQ,aAAa,QAAQ,MAAM;AAAA,QACvC,EAAE;AACF,eAAO,MAAM;AACb,eAAO,MAAM;AAAA,MACd;AAAA,IACD;AAAA,EACD;AACD,CAAC;AAQM,SAAS,uBACf,UAIuB;AACvB,SAAO,SAAS,IAAI,CAAC,aAAa;AAAA,IACjC,GAAG;AAAA,IACH,QAAQ,uBAAQ,aAAa,QAAQ,MAAM;AAAA,EAC5C,EAAE;AACH;",
6
6
  "names": []
7
7
  }
@@ -30,6 +30,7 @@ const TLDRAW_APP_RE = /(^\/r\/[^/]+\/?$)/;
30
30
  const EMBED_DEFINITIONS = [
31
31
  {
32
32
  hostnames: ["beta.tldraw.com", "tldraw.com", "localhost:3000"],
33
+ canEditWhileLocked: true,
33
34
  fromEmbedUrl: (url) => {
34
35
  const urlObj = (0, import_utils.safeParseUrl)(url);
35
36
  if (urlObj && urlObj.pathname.match(TLDRAW_APP_RE)) {
@@ -40,6 +41,7 @@ const EMBED_DEFINITIONS = [
40
41
  },
41
42
  {
42
43
  hostnames: ["figma.com"],
44
+ canEditWhileLocked: true,
43
45
  fromEmbedUrl: (url) => {
44
46
  const urlObj = (0, import_utils.safeParseUrl)(url);
45
47
  if (urlObj && urlObj.pathname.match(/^\/embed\/?$/)) {
@@ -53,6 +55,7 @@ const EMBED_DEFINITIONS = [
53
55
  },
54
56
  {
55
57
  hostnames: ["google.*"],
58
+ canEditWhileLocked: true,
56
59
  fromEmbedUrl: (url) => {
57
60
  const urlObj = (0, import_utils.safeParseUrl)(url);
58
61
  if (!urlObj) return;
@@ -67,6 +70,7 @@ const EMBED_DEFINITIONS = [
67
70
  },
68
71
  {
69
72
  hostnames: ["val.town"],
73
+ canEditWhileLocked: true,
70
74
  fromEmbedUrl: (url) => {
71
75
  const urlObj = (0, import_utils.safeParseUrl)(url);
72
76
  const matches = urlObj && urlObj.pathname.match(/\/embed\/(.+)\/?/);
@@ -78,6 +82,7 @@ const EMBED_DEFINITIONS = [
78
82
  },
79
83
  {
80
84
  hostnames: ["codesandbox.io"],
85
+ canEditWhileLocked: true,
81
86
  fromEmbedUrl: (url) => {
82
87
  const urlObj = (0, import_utils.safeParseUrl)(url);
83
88
  const matches = urlObj && urlObj.pathname.match(/\/embed\/([^/]+)\/?/);
@@ -89,6 +94,7 @@ const EMBED_DEFINITIONS = [
89
94
  },
90
95
  {
91
96
  hostnames: ["codepen.io"],
97
+ canEditWhileLocked: true,
92
98
  fromEmbedUrl: (url) => {
93
99
  const CODEPEN_EMBED_REGEXP = /https:\/\/codepen.io\/([^/]+)\/embed\/([^/]+)/;
94
100
  const matches = url.match(CODEPEN_EMBED_REGEXP);
@@ -101,6 +107,7 @@ const EMBED_DEFINITIONS = [
101
107
  },
102
108
  {
103
109
  hostnames: ["scratch.mit.edu"],
110
+ canEditWhileLocked: true,
104
111
  fromEmbedUrl: (url) => {
105
112
  const SCRATCH_EMBED_REGEXP = /https:\/\/scratch.mit.edu\/projects\/embed\/([^/]+)/;
106
113
  const matches = url.match(SCRATCH_EMBED_REGEXP);
@@ -113,6 +120,7 @@ const EMBED_DEFINITIONS = [
113
120
  },
114
121
  {
115
122
  hostnames: ["*.youtube.com", "youtube.com", "youtu.be"],
123
+ canEditWhileLocked: true,
116
124
  fromEmbedUrl: (url) => {
117
125
  const urlObj = (0, import_utils.safeParseUrl)(url);
118
126
  if (!urlObj) return;
@@ -128,6 +136,7 @@ const EMBED_DEFINITIONS = [
128
136
  },
129
137
  {
130
138
  hostnames: ["calendar.google.*"],
139
+ canEditWhileLocked: true,
131
140
  fromEmbedUrl: (url) => {
132
141
  const urlObj = (0, import_utils.safeParseUrl)(url);
133
142
  const srcQs = urlObj?.searchParams.get("src");
@@ -145,6 +154,7 @@ const EMBED_DEFINITIONS = [
145
154
  },
146
155
  {
147
156
  hostnames: ["docs.google.*"],
157
+ canEditWhileLocked: true,
148
158
  fromEmbedUrl: (url) => {
149
159
  const urlObj = (0, import_utils.safeParseUrl)(url);
150
160
  if (urlObj?.pathname.match(/^\/presentation/) && urlObj?.pathname.match(/\/embed\/?$/)) {
@@ -160,6 +170,7 @@ const EMBED_DEFINITIONS = [
160
170
  },
161
171
  {
162
172
  hostnames: ["gist.github.com"],
173
+ canEditWhileLocked: true,
163
174
  fromEmbedUrl: (url) => {
164
175
  const urlObj = (0, import_utils.safeParseUrl)(url);
165
176
  if (urlObj && urlObj.pathname.match(/\/([^/]+)\/([^/]+)/)) {
@@ -171,6 +182,7 @@ const EMBED_DEFINITIONS = [
171
182
  },
172
183
  {
173
184
  hostnames: ["replit.com"],
185
+ canEditWhileLocked: true,
174
186
  fromEmbedUrl: (url) => {
175
187
  const urlObj = (0, import_utils.safeParseUrl)(url);
176
188
  if (urlObj && urlObj.pathname.match(/\/@([^/]+)\/([^/]+)/) && urlObj.searchParams.has("embed")) {
@@ -182,6 +194,7 @@ const EMBED_DEFINITIONS = [
182
194
  },
183
195
  {
184
196
  hostnames: ["felt.com"],
197
+ canEditWhileLocked: true,
185
198
  fromEmbedUrl: (url) => {
186
199
  const urlObj = (0, import_utils.safeParseUrl)(url);
187
200
  if (urlObj && urlObj.pathname.match(/^\/embed\/map\//)) {
@@ -193,6 +206,7 @@ const EMBED_DEFINITIONS = [
193
206
  },
194
207
  {
195
208
  hostnames: ["open.spotify.com"],
209
+ canEditWhileLocked: true,
196
210
  fromEmbedUrl: (url) => {
197
211
  const urlObj = (0, import_utils.safeParseUrl)(url);
198
212
  if (urlObj && urlObj.pathname.match(/^\/embed\/(artist|album)\//)) {
@@ -203,6 +217,7 @@ const EMBED_DEFINITIONS = [
203
217
  },
204
218
  {
205
219
  hostnames: ["vimeo.com", "player.vimeo.com"],
220
+ canEditWhileLocked: true,
206
221
  fromEmbedUrl: (url) => {
207
222
  const urlObj = (0, import_utils.safeParseUrl)(url);
208
223
  if (urlObj && urlObj.hostname === "player.vimeo.com") {
@@ -216,6 +231,7 @@ const EMBED_DEFINITIONS = [
216
231
  },
217
232
  {
218
233
  hostnames: ["observablehq.com"],
234
+ canEditWhileLocked: true,
219
235
  fromEmbedUrl: (url) => {
220
236
  const urlObj = (0, import_utils.safeParseUrl)(url);
221
237
  if (urlObj && urlObj.pathname.match(/^\/embed\/@([^/]+)\/([^/]+)\/?$/)) {
@@ -229,6 +245,7 @@ const EMBED_DEFINITIONS = [
229
245
  },
230
246
  {
231
247
  hostnames: ["desmos.com"],
248
+ canEditWhileLocked: true,
232
249
  fromEmbedUrl: (url) => {
233
250
  const urlObj = (0, import_utils.safeParseUrl)(url);
234
251
  if (urlObj && urlObj.hostname === "www.desmos.com" && urlObj.pathname.match(/^\/calculator\/([^/]+)\/?$/) && urlObj.search === "?embed" && urlObj.hash === "") {
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../src/shapes/TLEmbedShape.ts"],
4
- "sourcesContent": ["import { safeParseUrl } from '@tldraw/utils'\nimport { T } from '@tldraw/validate'\nimport { createShapePropsMigrationIds, createShapePropsMigrationSequence } from '../records/TLShape'\nimport { RecordProps } from '../recordsWithProps'\nimport { TLBaseShape } from './TLBaseShape'\n\n// Only allow multiplayer embeds. If we add additional routes later for example '/help' this won't match\nconst TLDRAW_APP_RE = /(^\\/r\\/[^/]+\\/?$)/\n\nconst EMBED_DEFINITIONS = [\n\t{\n\t\thostnames: ['beta.tldraw.com', 'tldraw.com', 'localhost:3000'],\n\t\tfromEmbedUrl: (url: string) => {\n\t\t\tconst urlObj = safeParseUrl(url)\n\t\t\tif (urlObj && urlObj.pathname.match(TLDRAW_APP_RE)) {\n\t\t\t\treturn url\n\t\t\t}\n\t\t\treturn\n\t\t},\n\t},\n\t{\n\t\thostnames: ['figma.com'],\n\t\tfromEmbedUrl: (url: string) => {\n\t\t\tconst urlObj = safeParseUrl(url)\n\t\t\tif (urlObj && urlObj.pathname.match(/^\\/embed\\/?$/)) {\n\t\t\t\tconst outUrl = urlObj.searchParams.get('url')\n\t\t\t\tif (outUrl) {\n\t\t\t\t\treturn outUrl\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn\n\t\t},\n\t},\n\t{\n\t\thostnames: ['google.*'],\n\t\tfromEmbedUrl: (url: string) => {\n\t\t\tconst urlObj = safeParseUrl(url)\n\t\t\tif (!urlObj) return\n\n\t\t\tconst matches = urlObj.pathname.match(/^\\/maps\\/embed\\/v1\\/view\\/?$/)\n\t\t\tif (matches && urlObj.searchParams.has('center') && urlObj.searchParams.get('zoom')) {\n\t\t\t\tconst zoom = urlObj.searchParams.get('zoom')\n\t\t\t\tconst [lat, lon] = urlObj.searchParams.get('center')!.split(',')\n\t\t\t\treturn `https://www.google.com/maps/@${lat},${lon},${zoom}z`\n\t\t\t}\n\t\t\treturn\n\t\t},\n\t},\n\t{\n\t\thostnames: ['val.town'],\n\t\tfromEmbedUrl: (url: string) => {\n\t\t\tconst urlObj = safeParseUrl(url)\n\t\t\t// e.g. extract \"steveruizok/mathFact\" from https://www.val.town/v/steveruizok/mathFact\n\t\t\tconst matches = urlObj && urlObj.pathname.match(/\\/embed\\/(.+)\\/?/)\n\t\t\tif (matches) {\n\t\t\t\treturn `https://www.val.town/v/${matches[1]}`\n\t\t\t}\n\t\t\treturn\n\t\t},\n\t},\n\t{\n\t\thostnames: ['codesandbox.io'],\n\t\tfromEmbedUrl: (url: string) => {\n\t\t\tconst urlObj = safeParseUrl(url)\n\t\t\tconst matches = urlObj && urlObj.pathname.match(/\\/embed\\/([^/]+)\\/?/)\n\t\t\tif (matches) {\n\t\t\t\treturn `https://codesandbox.io/s/${matches[1]}`\n\t\t\t}\n\t\t\treturn\n\t\t},\n\t},\n\t{\n\t\thostnames: ['codepen.io'],\n\t\tfromEmbedUrl: (url: string) => {\n\t\t\tconst CODEPEN_EMBED_REGEXP = /https:\\/\\/codepen.io\\/([^/]+)\\/embed\\/([^/]+)/\n\t\t\tconst matches = url.match(CODEPEN_EMBED_REGEXP)\n\t\t\tif (matches) {\n\t\t\t\tconst [_, user, id] = matches\n\t\t\t\treturn `https://codepen.io/${user}/pen/${id}`\n\t\t\t}\n\t\t\treturn\n\t\t},\n\t},\n\t{\n\t\thostnames: ['scratch.mit.edu'],\n\t\tfromEmbedUrl: (url: string) => {\n\t\t\tconst SCRATCH_EMBED_REGEXP = /https:\\/\\/scratch.mit.edu\\/projects\\/embed\\/([^/]+)/\n\t\t\tconst matches = url.match(SCRATCH_EMBED_REGEXP)\n\t\t\tif (matches) {\n\t\t\t\tconst [_, id] = matches\n\t\t\t\treturn `https://scratch.mit.edu/projects/${id}`\n\t\t\t}\n\t\t\treturn\n\t\t},\n\t},\n\t{\n\t\thostnames: ['*.youtube.com', 'youtube.com', 'youtu.be'],\n\t\tfromEmbedUrl: (url: string) => {\n\t\t\tconst urlObj = safeParseUrl(url)\n\t\t\tif (!urlObj) return\n\n\t\t\tconst hostname = urlObj.hostname.replace(/^www./, '')\n\t\t\tif (hostname === 'youtube.com') {\n\t\t\t\tconst matches = urlObj.pathname.match(/^\\/embed\\/([^/]+)\\/?/)\n\t\t\t\tif (matches) {\n\t\t\t\t\treturn `https://www.youtube.com/watch?v=${matches[1]}`\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn\n\t\t},\n\t},\n\t{\n\t\thostnames: ['calendar.google.*'],\n\t\tfromEmbedUrl: (url: string) => {\n\t\t\tconst urlObj = safeParseUrl(url)\n\t\t\tconst srcQs = urlObj?.searchParams.get('src')\n\n\t\t\tif (urlObj?.pathname.match(/\\/calendar\\/embed/) && srcQs) {\n\t\t\t\turlObj.pathname = '/calendar/u/0'\n\t\t\t\tconst keys = Array.from(urlObj.searchParams.keys())\n\t\t\t\tfor (const key of keys) {\n\t\t\t\t\turlObj.searchParams.delete(key)\n\t\t\t\t}\n\t\t\t\turlObj.searchParams.set('cid', srcQs)\n\t\t\t\treturn urlObj.href\n\t\t\t}\n\t\t\treturn\n\t\t},\n\t},\n\t{\n\t\thostnames: ['docs.google.*'],\n\t\tfromEmbedUrl: (url: string) => {\n\t\t\tconst urlObj = safeParseUrl(url)\n\n\t\t\tif (urlObj?.pathname.match(/^\\/presentation/) && urlObj?.pathname.match(/\\/embed\\/?$/)) {\n\t\t\t\turlObj.pathname = urlObj.pathname.replace(/\\/embed$/, '/pub')\n\t\t\t\tconst keys = Array.from(urlObj.searchParams.keys())\n\t\t\t\tfor (const key of keys) {\n\t\t\t\t\turlObj.searchParams.delete(key)\n\t\t\t\t}\n\t\t\t\treturn urlObj.href\n\t\t\t}\n\t\t\treturn\n\t\t},\n\t},\n\t{\n\t\thostnames: ['gist.github.com'],\n\t\tfromEmbedUrl: (url: string) => {\n\t\t\tconst urlObj = safeParseUrl(url)\n\t\t\tif (urlObj && urlObj.pathname.match(/\\/([^/]+)\\/([^/]+)/)) {\n\t\t\t\tif (!url.split('/').pop()) return\n\t\t\t\treturn url\n\t\t\t}\n\t\t\treturn\n\t\t},\n\t},\n\t{\n\t\thostnames: ['replit.com'],\n\t\tfromEmbedUrl: (url: string) => {\n\t\t\tconst urlObj = safeParseUrl(url)\n\t\t\tif (\n\t\t\t\turlObj &&\n\t\t\t\turlObj.pathname.match(/\\/@([^/]+)\\/([^/]+)/) &&\n\t\t\t\turlObj.searchParams.has('embed')\n\t\t\t) {\n\t\t\t\turlObj.searchParams.delete('embed')\n\t\t\t\treturn urlObj.href\n\t\t\t}\n\t\t\treturn\n\t\t},\n\t},\n\t{\n\t\thostnames: ['felt.com'],\n\t\tfromEmbedUrl: (url: string) => {\n\t\t\tconst urlObj = safeParseUrl(url)\n\t\t\tif (urlObj && urlObj.pathname.match(/^\\/embed\\/map\\//)) {\n\t\t\t\turlObj.pathname = urlObj.pathname.replace(/^\\/embed/, '')\n\t\t\t\treturn urlObj.href\n\t\t\t}\n\t\t\treturn\n\t\t},\n\t},\n\t{\n\t\thostnames: ['open.spotify.com'],\n\t\tfromEmbedUrl: (url: string) => {\n\t\t\tconst urlObj = safeParseUrl(url)\n\t\t\tif (urlObj && urlObj.pathname.match(/^\\/embed\\/(artist|album)\\//)) {\n\t\t\t\treturn urlObj.origin + urlObj.pathname.replace(/^\\/embed/, '')\n\t\t\t}\n\t\t\treturn\n\t\t},\n\t},\n\t{\n\t\thostnames: ['vimeo.com', 'player.vimeo.com'],\n\t\tfromEmbedUrl: (url: string) => {\n\t\t\tconst urlObj = safeParseUrl(url)\n\t\t\tif (urlObj && urlObj.hostname === 'player.vimeo.com') {\n\t\t\t\tconst matches = urlObj.pathname.match(/^\\/video\\/([^/]+)\\/?$/)\n\t\t\t\tif (matches) {\n\t\t\t\t\treturn 'https://vimeo.com/' + matches[1]\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn\n\t\t},\n\t},\n\t{\n\t\thostnames: ['observablehq.com'],\n\t\tfromEmbedUrl: (url: string) => {\n\t\t\tconst urlObj = safeParseUrl(url)\n\t\t\tif (urlObj && urlObj.pathname.match(/^\\/embed\\/@([^/]+)\\/([^/]+)\\/?$/)) {\n\t\t\t\treturn `${urlObj.origin}${urlObj.pathname.replace('/embed', '')}#cell-*`\n\t\t\t}\n\t\t\tif (urlObj && urlObj.pathname.match(/^\\/embed\\/([^/]+)\\/?$/)) {\n\t\t\t\treturn `${urlObj.origin}${urlObj.pathname.replace('/embed', '/d')}#cell-*`\n\t\t\t}\n\n\t\t\treturn\n\t\t},\n\t},\n\t{\n\t\thostnames: ['desmos.com'],\n\t\tfromEmbedUrl: (url: string) => {\n\t\t\tconst urlObj = safeParseUrl(url)\n\t\t\tif (\n\t\t\t\turlObj &&\n\t\t\t\turlObj.hostname === 'www.desmos.com' &&\n\t\t\t\turlObj.pathname.match(/^\\/calculator\\/([^/]+)\\/?$/) &&\n\t\t\t\turlObj.search === '?embed' &&\n\t\t\t\turlObj.hash === ''\n\t\t\t) {\n\t\t\t\treturn url.replace('?embed', '')\n\t\t\t}\n\t\t\treturn\n\t\t},\n\t},\n]\n\n/**\n * Properties for the embed shape, which displays embedded content from external services.\n *\n * @public\n */\nexport interface TLEmbedShapeProps {\n\t/** Width of the embed shape in pixels */\n\tw: number\n\t/** Height of the embed shape in pixels */\n\th: number\n\t/** URL of the content to embed (supports YouTube, Figma, CodePen, etc.) */\n\turl: string\n}\n\n/**\n * An embed shape displays external content like YouTube videos, Figma designs, CodePen demos,\n * and other embeddable content within the tldraw canvas.\n *\n * @public\n * @example\n * ```ts\n * const embedShape: TLEmbedShape = {\n * id: createShapeId(),\n * typeName: 'shape',\n * type: 'embed',\n * x: 200,\n * y: 200,\n * rotation: 0,\n * index: 'a1',\n * parentId: 'page:page1',\n * isLocked: false,\n * opacity: 1,\n * props: {\n * w: 560,\n * h: 315,\n * url: 'https://www.youtube.com/watch?v=dQw4w9WgXcQ'\n * },\n * meta: {}\n * }\n * ```\n */\nexport type TLEmbedShape = TLBaseShape<'embed', TLEmbedShapeProps>\n\n/**\n * Validation schema for embed shape properties.\n *\n * @public\n * @example\n * ```ts\n * // Validate embed shape properties\n * const isValidUrl = embedShapeProps.url.isValid('https://youtube.com/watch?v=abc123')\n * const isValidSize = embedShapeProps.w.isValid(560)\n * ```\n */\nexport const embedShapeProps: RecordProps<TLEmbedShape> = {\n\tw: T.nonZeroNumber,\n\th: T.nonZeroNumber,\n\turl: T.string,\n}\n\nconst Versions = createShapePropsMigrationIds('embed', {\n\tGenOriginalUrlInEmbed: 1,\n\tRemoveDoesResize: 2,\n\tRemoveTmpOldUrl: 3,\n\tRemovePermissionOverrides: 4,\n})\n\n/**\n * Version identifiers for embed shape migrations.\n *\n * @public\n */\nexport { Versions as embedShapeVersions }\n\n/**\n * Migration sequence for embed shape properties across different schema versions.\n * Handles URL transformations and removal of deprecated properties.\n *\n * @public\n */\nexport const embedShapeMigrations = createShapePropsMigrationSequence({\n\tsequence: [\n\t\t{\n\t\t\tid: Versions.GenOriginalUrlInEmbed,\n\t\t\t// add tmpOldUrl property\n\t\t\tup: (props) => {\n\t\t\t\ttry {\n\t\t\t\t\tconst url = props.url\n\t\t\t\t\tconst host = new URL(url).host.replace('www.', '')\n\t\t\t\t\tlet originalUrl\n\t\t\t\t\tfor (const localEmbedDef of EMBED_DEFINITIONS) {\n\t\t\t\t\t\tif (localEmbedDef.hostnames.includes(host)) {\n\t\t\t\t\t\t\ttry {\n\t\t\t\t\t\t\t\toriginalUrl = localEmbedDef.fromEmbedUrl(url)\n\t\t\t\t\t\t\t} catch (err) {\n\t\t\t\t\t\t\t\tconsole.warn(err)\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\n\t\t\t\t\tprops.tmpOldUrl = props.url\n\t\t\t\t\tprops.url = originalUrl ?? ''\n\t\t\t\t} catch {\n\t\t\t\t\tprops.url = ''\n\t\t\t\t\tprops.tmpOldUrl = props.url\n\t\t\t\t}\n\t\t\t},\n\t\t\tdown: 'retired',\n\t\t},\n\t\t{\n\t\t\tid: Versions.RemoveDoesResize,\n\t\t\tup: (props) => {\n\t\t\t\tdelete props.doesResize\n\t\t\t},\n\t\t\tdown: 'retired',\n\t\t},\n\t\t{\n\t\t\tid: Versions.RemoveTmpOldUrl,\n\t\t\tup: (props) => {\n\t\t\t\tdelete props.tmpOldUrl\n\t\t\t},\n\t\t\tdown: 'retired',\n\t\t},\n\t\t{\n\t\t\tid: Versions.RemovePermissionOverrides,\n\t\t\tup: (props) => {\n\t\t\t\tdelete props.overridePermissions\n\t\t\t},\n\t\t\tdown: 'retired',\n\t\t},\n\t],\n})\n"],
5
- "mappings": "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",
4
+ "sourcesContent": ["import { safeParseUrl } from '@tldraw/utils'\nimport { T } from '@tldraw/validate'\nimport { createShapePropsMigrationIds, createShapePropsMigrationSequence } from '../records/TLShape'\nimport { RecordProps } from '../recordsWithProps'\nimport { TLBaseShape } from './TLBaseShape'\n\n// Only allow multiplayer embeds. If we add additional routes later for example '/help' this won't match\nconst TLDRAW_APP_RE = /(^\\/r\\/[^/]+\\/?$)/\n\nconst EMBED_DEFINITIONS = [\n\t{\n\t\thostnames: ['beta.tldraw.com', 'tldraw.com', 'localhost:3000'],\n\t\tcanEditWhileLocked: true,\n\t\tfromEmbedUrl: (url: string) => {\n\t\t\tconst urlObj = safeParseUrl(url)\n\t\t\tif (urlObj && urlObj.pathname.match(TLDRAW_APP_RE)) {\n\t\t\t\treturn url\n\t\t\t}\n\t\t\treturn\n\t\t},\n\t},\n\t{\n\t\thostnames: ['figma.com'],\n\t\tcanEditWhileLocked: true,\n\t\tfromEmbedUrl: (url: string) => {\n\t\t\tconst urlObj = safeParseUrl(url)\n\t\t\tif (urlObj && urlObj.pathname.match(/^\\/embed\\/?$/)) {\n\t\t\t\tconst outUrl = urlObj.searchParams.get('url')\n\t\t\t\tif (outUrl) {\n\t\t\t\t\treturn outUrl\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn\n\t\t},\n\t},\n\t{\n\t\thostnames: ['google.*'],\n\t\tcanEditWhileLocked: true,\n\t\tfromEmbedUrl: (url: string) => {\n\t\t\tconst urlObj = safeParseUrl(url)\n\t\t\tif (!urlObj) return\n\n\t\t\tconst matches = urlObj.pathname.match(/^\\/maps\\/embed\\/v1\\/view\\/?$/)\n\t\t\tif (matches && urlObj.searchParams.has('center') && urlObj.searchParams.get('zoom')) {\n\t\t\t\tconst zoom = urlObj.searchParams.get('zoom')\n\t\t\t\tconst [lat, lon] = urlObj.searchParams.get('center')!.split(',')\n\t\t\t\treturn `https://www.google.com/maps/@${lat},${lon},${zoom}z`\n\t\t\t}\n\t\t\treturn\n\t\t},\n\t},\n\t{\n\t\thostnames: ['val.town'],\n\t\tcanEditWhileLocked: true,\n\t\tfromEmbedUrl: (url: string) => {\n\t\t\tconst urlObj = safeParseUrl(url)\n\t\t\t// e.g. extract \"steveruizok/mathFact\" from https://www.val.town/v/steveruizok/mathFact\n\t\t\tconst matches = urlObj && urlObj.pathname.match(/\\/embed\\/(.+)\\/?/)\n\t\t\tif (matches) {\n\t\t\t\treturn `https://www.val.town/v/${matches[1]}`\n\t\t\t}\n\t\t\treturn\n\t\t},\n\t},\n\t{\n\t\thostnames: ['codesandbox.io'],\n\t\tcanEditWhileLocked: true,\n\t\tfromEmbedUrl: (url: string) => {\n\t\t\tconst urlObj = safeParseUrl(url)\n\t\t\tconst matches = urlObj && urlObj.pathname.match(/\\/embed\\/([^/]+)\\/?/)\n\t\t\tif (matches) {\n\t\t\t\treturn `https://codesandbox.io/s/${matches[1]}`\n\t\t\t}\n\t\t\treturn\n\t\t},\n\t},\n\t{\n\t\thostnames: ['codepen.io'],\n\t\tcanEditWhileLocked: true,\n\t\tfromEmbedUrl: (url: string) => {\n\t\t\tconst CODEPEN_EMBED_REGEXP = /https:\\/\\/codepen.io\\/([^/]+)\\/embed\\/([^/]+)/\n\t\t\tconst matches = url.match(CODEPEN_EMBED_REGEXP)\n\t\t\tif (matches) {\n\t\t\t\tconst [_, user, id] = matches\n\t\t\t\treturn `https://codepen.io/${user}/pen/${id}`\n\t\t\t}\n\t\t\treturn\n\t\t},\n\t},\n\t{\n\t\thostnames: ['scratch.mit.edu'],\n\t\tcanEditWhileLocked: true,\n\t\tfromEmbedUrl: (url: string) => {\n\t\t\tconst SCRATCH_EMBED_REGEXP = /https:\\/\\/scratch.mit.edu\\/projects\\/embed\\/([^/]+)/\n\t\t\tconst matches = url.match(SCRATCH_EMBED_REGEXP)\n\t\t\tif (matches) {\n\t\t\t\tconst [_, id] = matches\n\t\t\t\treturn `https://scratch.mit.edu/projects/${id}`\n\t\t\t}\n\t\t\treturn\n\t\t},\n\t},\n\t{\n\t\thostnames: ['*.youtube.com', 'youtube.com', 'youtu.be'],\n\t\tcanEditWhileLocked: true,\n\t\tfromEmbedUrl: (url: string) => {\n\t\t\tconst urlObj = safeParseUrl(url)\n\t\t\tif (!urlObj) return\n\n\t\t\tconst hostname = urlObj.hostname.replace(/^www./, '')\n\t\t\tif (hostname === 'youtube.com') {\n\t\t\t\tconst matches = urlObj.pathname.match(/^\\/embed\\/([^/]+)\\/?/)\n\t\t\t\tif (matches) {\n\t\t\t\t\treturn `https://www.youtube.com/watch?v=${matches[1]}`\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn\n\t\t},\n\t},\n\t{\n\t\thostnames: ['calendar.google.*'],\n\t\tcanEditWhileLocked: true,\n\t\tfromEmbedUrl: (url: string) => {\n\t\t\tconst urlObj = safeParseUrl(url)\n\t\t\tconst srcQs = urlObj?.searchParams.get('src')\n\n\t\t\tif (urlObj?.pathname.match(/\\/calendar\\/embed/) && srcQs) {\n\t\t\t\turlObj.pathname = '/calendar/u/0'\n\t\t\t\tconst keys = Array.from(urlObj.searchParams.keys())\n\t\t\t\tfor (const key of keys) {\n\t\t\t\t\turlObj.searchParams.delete(key)\n\t\t\t\t}\n\t\t\t\turlObj.searchParams.set('cid', srcQs)\n\t\t\t\treturn urlObj.href\n\t\t\t}\n\t\t\treturn\n\t\t},\n\t},\n\t{\n\t\thostnames: ['docs.google.*'],\n\t\tcanEditWhileLocked: true,\n\t\tfromEmbedUrl: (url: string) => {\n\t\t\tconst urlObj = safeParseUrl(url)\n\n\t\t\tif (urlObj?.pathname.match(/^\\/presentation/) && urlObj?.pathname.match(/\\/embed\\/?$/)) {\n\t\t\t\turlObj.pathname = urlObj.pathname.replace(/\\/embed$/, '/pub')\n\t\t\t\tconst keys = Array.from(urlObj.searchParams.keys())\n\t\t\t\tfor (const key of keys) {\n\t\t\t\t\turlObj.searchParams.delete(key)\n\t\t\t\t}\n\t\t\t\treturn urlObj.href\n\t\t\t}\n\t\t\treturn\n\t\t},\n\t},\n\t{\n\t\thostnames: ['gist.github.com'],\n\t\tcanEditWhileLocked: true,\n\t\tfromEmbedUrl: (url: string) => {\n\t\t\tconst urlObj = safeParseUrl(url)\n\t\t\tif (urlObj && urlObj.pathname.match(/\\/([^/]+)\\/([^/]+)/)) {\n\t\t\t\tif (!url.split('/').pop()) return\n\t\t\t\treturn url\n\t\t\t}\n\t\t\treturn\n\t\t},\n\t},\n\t{\n\t\thostnames: ['replit.com'],\n\t\tcanEditWhileLocked: true,\n\t\tfromEmbedUrl: (url: string) => {\n\t\t\tconst urlObj = safeParseUrl(url)\n\t\t\tif (\n\t\t\t\turlObj &&\n\t\t\t\turlObj.pathname.match(/\\/@([^/]+)\\/([^/]+)/) &&\n\t\t\t\turlObj.searchParams.has('embed')\n\t\t\t) {\n\t\t\t\turlObj.searchParams.delete('embed')\n\t\t\t\treturn urlObj.href\n\t\t\t}\n\t\t\treturn\n\t\t},\n\t},\n\t{\n\t\thostnames: ['felt.com'],\n\t\tcanEditWhileLocked: true,\n\t\tfromEmbedUrl: (url: string) => {\n\t\t\tconst urlObj = safeParseUrl(url)\n\t\t\tif (urlObj && urlObj.pathname.match(/^\\/embed\\/map\\//)) {\n\t\t\t\turlObj.pathname = urlObj.pathname.replace(/^\\/embed/, '')\n\t\t\t\treturn urlObj.href\n\t\t\t}\n\t\t\treturn\n\t\t},\n\t},\n\t{\n\t\thostnames: ['open.spotify.com'],\n\t\tcanEditWhileLocked: true,\n\t\tfromEmbedUrl: (url: string) => {\n\t\t\tconst urlObj = safeParseUrl(url)\n\t\t\tif (urlObj && urlObj.pathname.match(/^\\/embed\\/(artist|album)\\//)) {\n\t\t\t\treturn urlObj.origin + urlObj.pathname.replace(/^\\/embed/, '')\n\t\t\t}\n\t\t\treturn\n\t\t},\n\t},\n\t{\n\t\thostnames: ['vimeo.com', 'player.vimeo.com'],\n\t\tcanEditWhileLocked: true,\n\t\tfromEmbedUrl: (url: string) => {\n\t\t\tconst urlObj = safeParseUrl(url)\n\t\t\tif (urlObj && urlObj.hostname === 'player.vimeo.com') {\n\t\t\t\tconst matches = urlObj.pathname.match(/^\\/video\\/([^/]+)\\/?$/)\n\t\t\t\tif (matches) {\n\t\t\t\t\treturn 'https://vimeo.com/' + matches[1]\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn\n\t\t},\n\t},\n\t{\n\t\thostnames: ['observablehq.com'],\n\t\tcanEditWhileLocked: true,\n\t\tfromEmbedUrl: (url: string) => {\n\t\t\tconst urlObj = safeParseUrl(url)\n\t\t\tif (urlObj && urlObj.pathname.match(/^\\/embed\\/@([^/]+)\\/([^/]+)\\/?$/)) {\n\t\t\t\treturn `${urlObj.origin}${urlObj.pathname.replace('/embed', '')}#cell-*`\n\t\t\t}\n\t\t\tif (urlObj && urlObj.pathname.match(/^\\/embed\\/([^/]+)\\/?$/)) {\n\t\t\t\treturn `${urlObj.origin}${urlObj.pathname.replace('/embed', '/d')}#cell-*`\n\t\t\t}\n\n\t\t\treturn\n\t\t},\n\t},\n\t{\n\t\thostnames: ['desmos.com'],\n\t\tcanEditWhileLocked: true,\n\t\tfromEmbedUrl: (url: string) => {\n\t\t\tconst urlObj = safeParseUrl(url)\n\t\t\tif (\n\t\t\t\turlObj &&\n\t\t\t\turlObj.hostname === 'www.desmos.com' &&\n\t\t\t\turlObj.pathname.match(/^\\/calculator\\/([^/]+)\\/?$/) &&\n\t\t\t\turlObj.search === '?embed' &&\n\t\t\t\turlObj.hash === ''\n\t\t\t) {\n\t\t\t\treturn url.replace('?embed', '')\n\t\t\t}\n\t\t\treturn\n\t\t},\n\t},\n]\n\n/**\n * Properties for the embed shape, which displays embedded content from external services.\n *\n * @public\n */\nexport interface TLEmbedShapeProps {\n\t/** Width of the embed shape in pixels */\n\tw: number\n\t/** Height of the embed shape in pixels */\n\th: number\n\t/** URL of the content to embed (supports YouTube, Figma, CodePen, etc.) */\n\turl: string\n}\n\n/**\n * An embed shape displays external content like YouTube videos, Figma designs, CodePen demos,\n * and other embeddable content within the tldraw canvas.\n *\n * @public\n * @example\n * ```ts\n * const embedShape: TLEmbedShape = {\n * id: createShapeId(),\n * typeName: 'shape',\n * type: 'embed',\n * x: 200,\n * y: 200,\n * rotation: 0,\n * index: 'a1',\n * parentId: 'page:page1',\n * isLocked: false,\n * opacity: 1,\n * props: {\n * w: 560,\n * h: 315,\n * url: 'https://www.youtube.com/watch?v=dQw4w9WgXcQ'\n * },\n * meta: {}\n * }\n * ```\n */\nexport type TLEmbedShape = TLBaseShape<'embed', TLEmbedShapeProps>\n\n/**\n * Validation schema for embed shape properties.\n *\n * @public\n * @example\n * ```ts\n * // Validate embed shape properties\n * const isValidUrl = embedShapeProps.url.isValid('https://youtube.com/watch?v=abc123')\n * const isValidSize = embedShapeProps.w.isValid(560)\n * ```\n */\nexport const embedShapeProps: RecordProps<TLEmbedShape> = {\n\tw: T.nonZeroNumber,\n\th: T.nonZeroNumber,\n\turl: T.string,\n}\n\nconst Versions = createShapePropsMigrationIds('embed', {\n\tGenOriginalUrlInEmbed: 1,\n\tRemoveDoesResize: 2,\n\tRemoveTmpOldUrl: 3,\n\tRemovePermissionOverrides: 4,\n})\n\n/**\n * Version identifiers for embed shape migrations.\n *\n * @public\n */\nexport { Versions as embedShapeVersions }\n\n/**\n * Migration sequence for embed shape properties across different schema versions.\n * Handles URL transformations and removal of deprecated properties.\n *\n * @public\n */\nexport const embedShapeMigrations = createShapePropsMigrationSequence({\n\tsequence: [\n\t\t{\n\t\t\tid: Versions.GenOriginalUrlInEmbed,\n\t\t\t// add tmpOldUrl property\n\t\t\tup: (props) => {\n\t\t\t\ttry {\n\t\t\t\t\tconst url = props.url\n\t\t\t\t\tconst host = new URL(url).host.replace('www.', '')\n\t\t\t\t\tlet originalUrl\n\t\t\t\t\tfor (const localEmbedDef of EMBED_DEFINITIONS) {\n\t\t\t\t\t\tif (localEmbedDef.hostnames.includes(host)) {\n\t\t\t\t\t\t\ttry {\n\t\t\t\t\t\t\t\toriginalUrl = localEmbedDef.fromEmbedUrl(url)\n\t\t\t\t\t\t\t} catch (err) {\n\t\t\t\t\t\t\t\tconsole.warn(err)\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\n\t\t\t\t\tprops.tmpOldUrl = props.url\n\t\t\t\t\tprops.url = originalUrl ?? ''\n\t\t\t\t} catch {\n\t\t\t\t\tprops.url = ''\n\t\t\t\t\tprops.tmpOldUrl = props.url\n\t\t\t\t}\n\t\t\t},\n\t\t\tdown: 'retired',\n\t\t},\n\t\t{\n\t\t\tid: Versions.RemoveDoesResize,\n\t\t\tup: (props) => {\n\t\t\t\tdelete props.doesResize\n\t\t\t},\n\t\t\tdown: 'retired',\n\t\t},\n\t\t{\n\t\t\tid: Versions.RemoveTmpOldUrl,\n\t\t\tup: (props) => {\n\t\t\t\tdelete props.tmpOldUrl\n\t\t\t},\n\t\t\tdown: 'retired',\n\t\t},\n\t\t{\n\t\t\tid: Versions.RemovePermissionOverrides,\n\t\t\tup: (props) => {\n\t\t\t\tdelete props.overridePermissions\n\t\t\t},\n\t\t\tdown: 'retired',\n\t\t},\n\t],\n})\n"],
5
+ "mappings": "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",
6
6
  "names": []
7
7
  }
@@ -88,7 +88,8 @@ const geoShapeVersions = (0, import_TLShape.createShapePropsMigrationIds)("geo",
88
88
  AddCloud: 7,
89
89
  MakeUrlsValid: 8,
90
90
  AddScale: 9,
91
- AddRichText: 10
91
+ AddRichText: 10,
92
+ AddRichTextAttrs: 11
92
93
  });
93
94
  const geoShapeMigrations = (0, import_TLShape.createShapePropsMigrationSequence)({
94
95
  sequence: [
@@ -182,6 +183,16 @@ const geoShapeMigrations = (0, import_TLShape.createShapePropsMigrationSequence)
182
183
  // down: (props) => {
183
184
  // delete props.richText
184
185
  // },
186
+ },
187
+ {
188
+ id: geoShapeVersions.AddRichTextAttrs,
189
+ up: (_props) => {
190
+ },
191
+ down: (props) => {
192
+ if (props.richText && "attrs" in props.richText) {
193
+ delete props.richText.attrs;
194
+ }
195
+ }
185
196
  }
186
197
  ]
187
198
  });
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../src/shapes/TLGeoShape.ts"],
4
- "sourcesContent": ["import { T } from '@tldraw/validate'\nimport { TLRichText, richTextValidator, toRichText } from '../misc/TLRichText'\nimport { createShapePropsMigrationIds, createShapePropsMigrationSequence } from '../records/TLShape'\nimport { RecordProps } from '../recordsWithProps'\nimport { StyleProp } from '../styles/StyleProp'\nimport {\n\tDefaultColorStyle,\n\tDefaultLabelColorStyle,\n\tTLDefaultColorStyle,\n} from '../styles/TLColorStyle'\nimport { DefaultDashStyle, TLDefaultDashStyle } from '../styles/TLDashStyle'\nimport { DefaultFillStyle, TLDefaultFillStyle } from '../styles/TLFillStyle'\nimport { DefaultFontStyle, TLDefaultFontStyle } from '../styles/TLFontStyle'\nimport {\n\tDefaultHorizontalAlignStyle,\n\tTLDefaultHorizontalAlignStyle,\n} from '../styles/TLHorizontalAlignStyle'\nimport { DefaultSizeStyle, TLDefaultSizeStyle } from '../styles/TLSizeStyle'\nimport {\n\tDefaultVerticalAlignStyle,\n\tTLDefaultVerticalAlignStyle,\n} from '../styles/TLVerticalAlignStyle'\nimport { TLBaseShape } from './TLBaseShape'\n\n/**\n * Style property defining the geometric shape type for geo shapes.\n * Provides a variety of built-in geometric forms including basic shapes,\n * polygons, arrows, and special shapes.\n *\n * @public\n * @example\n * ```ts\n * // Use in shape props\n * const props = {\n * geo: 'rectangle', // or 'ellipse', 'triangle', etc.\n * // other properties...\n * }\n * ```\n */\nexport const GeoShapeGeoStyle = StyleProp.defineEnum('tldraw:geo', {\n\tdefaultValue: 'rectangle',\n\tvalues: [\n\t\t'cloud',\n\t\t'rectangle',\n\t\t'ellipse',\n\t\t'triangle',\n\t\t'diamond',\n\t\t'pentagon',\n\t\t'hexagon',\n\t\t'octagon',\n\t\t'star',\n\t\t'rhombus',\n\t\t'rhombus-2',\n\t\t'oval',\n\t\t'trapezoid',\n\t\t'arrow-right',\n\t\t'arrow-left',\n\t\t'arrow-up',\n\t\t'arrow-down',\n\t\t'x-box',\n\t\t'check-box',\n\t\t'heart',\n\t],\n})\n\n/**\n * Type representing valid geometric shape styles for geo shapes.\n *\n * @public\n */\nexport type TLGeoShapeGeoStyle = T.TypeOf<typeof GeoShapeGeoStyle>\n\n/**\n * Properties for the geo shape, which renders various geometric forms with styling and text.\n *\n * @public\n */\nexport interface TLGeoShapeProps {\n\t/** Geometric shape type (rectangle, ellipse, triangle, etc.) */\n\tgeo: TLGeoShapeGeoStyle\n\t/** Dash pattern style for the shape outline */\n\tdash: TLDefaultDashStyle\n\t/** URL link associated with the shape */\n\turl: string\n\t/** Width of the shape in pixels */\n\tw: number\n\t/** Height of the shape in pixels */\n\th: number\n\t/** Additional vertical growth for text content */\n\tgrowY: number\n\t/** Scale factor applied to the shape */\n\tscale: number\n\n\t/** Color style for text label */\n\tlabelColor: TLDefaultColorStyle\n\t/** Color style for the shape outline */\n\tcolor: TLDefaultColorStyle\n\t/** Fill style for the shape interior */\n\tfill: TLDefaultFillStyle\n\t/** Size/thickness style for outline and text */\n\tsize: TLDefaultSizeStyle\n\t/** Font style for text content */\n\tfont: TLDefaultFontStyle\n\t/** Horizontal alignment for text content */\n\talign: TLDefaultHorizontalAlignStyle\n\t/** Vertical alignment for text content */\n\tverticalAlign: TLDefaultVerticalAlignStyle\n\t/** Rich text content displayed within the shape */\n\trichText: TLRichText\n}\n\n/**\n * A geo shape represents geometric forms like rectangles, ellipses, triangles, and other\n * predefined shapes. Geo shapes support styling, text content, and can act as containers.\n *\n * @public\n * @example\n * ```ts\n * const geoShape: TLGeoShape = {\n * id: createShapeId(),\n * typeName: 'shape',\n * type: 'geo',\n * x: 100,\n * y: 100,\n * rotation: 0,\n * index: 'a1',\n * parentId: 'page:page1',\n * isLocked: false,\n * opacity: 1,\n * props: {\n * geo: 'rectangle',\n * w: 200,\n * h: 100,\n * color: 'black',\n * fill: 'solid',\n * dash: 'solid',\n * size: 'm',\n * font: 'draw',\n * align: 'middle',\n * verticalAlign: 'middle',\n * richText: toRichText('Hello World'),\n * labelColor: 'black',\n * url: '',\n * growY: 0,\n * scale: 1\n * },\n * meta: {}\n * }\n * ```\n */\nexport type TLGeoShape = TLBaseShape<'geo', TLGeoShapeProps>\n\n/**\n * Validation schema for geo shape properties.\n *\n * @public\n * @example\n * ```ts\n * // Validate geo shape properties\n * const isValidGeo = geoShapeProps.geo.isValid('rectangle')\n * const isValidSize = geoShapeProps.w.isValid(100)\n * const isValidText = geoShapeProps.richText.isValid(toRichText('Hello'))\n * ```\n */\nexport const geoShapeProps: RecordProps<TLGeoShape> = {\n\tgeo: GeoShapeGeoStyle,\n\tdash: DefaultDashStyle,\n\turl: T.linkUrl,\n\tw: T.nonZeroNumber,\n\th: T.nonZeroNumber,\n\tgrowY: T.positiveNumber,\n\tscale: T.nonZeroNumber,\n\n\t// Text properties\n\tlabelColor: DefaultLabelColorStyle,\n\tcolor: DefaultColorStyle,\n\tfill: DefaultFillStyle,\n\tsize: DefaultSizeStyle,\n\tfont: DefaultFontStyle,\n\talign: DefaultHorizontalAlignStyle,\n\tverticalAlign: DefaultVerticalAlignStyle,\n\trichText: richTextValidator,\n}\n\nconst geoShapeVersions = createShapePropsMigrationIds('geo', {\n\tAddUrlProp: 1,\n\tAddLabelColor: 2,\n\tRemoveJustify: 3,\n\tAddCheckBox: 4,\n\tAddVerticalAlign: 5,\n\tMigrateLegacyAlign: 6,\n\tAddCloud: 7,\n\tMakeUrlsValid: 8,\n\tAddScale: 9,\n\tAddRichText: 10,\n})\n\n/**\n * Version identifiers for geo shape migrations.\n *\n * @public\n */\nexport { geoShapeVersions as geoShapeVersions }\n\n/**\n * Migration sequence for geo shape properties across different schema versions.\n * Handles evolution of geo shapes including URL support, label colors, alignment changes,\n * and the transition from plain text to rich text.\n *\n * @public\n */\nexport const geoShapeMigrations = createShapePropsMigrationSequence({\n\tsequence: [\n\t\t{\n\t\t\tid: geoShapeVersions.AddUrlProp,\n\t\t\tup: (props) => {\n\t\t\t\tprops.url = ''\n\t\t\t},\n\t\t\tdown: 'retired',\n\t\t},\n\t\t{\n\t\t\tid: geoShapeVersions.AddLabelColor,\n\t\t\tup: (props) => {\n\t\t\t\tprops.labelColor = 'black'\n\t\t\t},\n\t\t\tdown: 'retired',\n\t\t},\n\t\t{\n\t\t\tid: geoShapeVersions.RemoveJustify,\n\t\t\tup: (props) => {\n\t\t\t\tif (props.align === 'justify') {\n\t\t\t\t\tprops.align = 'start'\n\t\t\t\t}\n\t\t\t},\n\t\t\tdown: 'retired',\n\t\t},\n\t\t{\n\t\t\tid: geoShapeVersions.AddCheckBox,\n\t\t\tup: (_props) => {\n\t\t\t\t// noop\n\t\t\t},\n\t\t\tdown: 'retired',\n\t\t},\n\t\t{\n\t\t\tid: geoShapeVersions.AddVerticalAlign,\n\t\t\tup: (props) => {\n\t\t\t\tprops.verticalAlign = 'middle'\n\t\t\t},\n\t\t\tdown: 'retired',\n\t\t},\n\t\t{\n\t\t\tid: geoShapeVersions.MigrateLegacyAlign,\n\t\t\tup: (props) => {\n\t\t\t\tlet newAlign: TLDefaultHorizontalAlignStyle\n\t\t\t\tswitch (props.align) {\n\t\t\t\t\tcase 'start':\n\t\t\t\t\t\tnewAlign = 'start-legacy'\n\t\t\t\t\t\tbreak\n\t\t\t\t\tcase 'end':\n\t\t\t\t\t\tnewAlign = 'end-legacy'\n\t\t\t\t\t\tbreak\n\t\t\t\t\tdefault:\n\t\t\t\t\t\tnewAlign = 'middle-legacy'\n\t\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t\tprops.align = newAlign\n\t\t\t},\n\t\t\tdown: 'retired',\n\t\t},\n\t\t{\n\t\t\tid: geoShapeVersions.AddCloud,\n\t\t\tup: (_props) => {\n\t\t\t\t// noop\n\t\t\t},\n\t\t\tdown: 'retired',\n\t\t},\n\t\t{\n\t\t\tid: geoShapeVersions.MakeUrlsValid,\n\t\t\tup: (props) => {\n\t\t\t\tif (!T.linkUrl.isValid(props.url)) {\n\t\t\t\t\tprops.url = ''\n\t\t\t\t}\n\t\t\t},\n\t\t\tdown: (_props) => {\n\t\t\t\t// noop\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tid: geoShapeVersions.AddScale,\n\t\t\tup: (props) => {\n\t\t\t\tprops.scale = 1\n\t\t\t},\n\t\t\tdown: (props) => {\n\t\t\t\tdelete props.scale\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tid: geoShapeVersions.AddRichText,\n\t\t\tup: (props) => {\n\t\t\t\tprops.richText = toRichText(props.text)\n\t\t\t\tdelete props.text\n\t\t\t},\n\t\t\t// N.B. Explicitly no down state so that we force clients to update.\n\t\t\t// down: (props) => {\n\t\t\t// \tdelete props.richText\n\t\t\t// },\n\t\t},\n\t],\n})\n"],
5
- "mappings": "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",
4
+ "sourcesContent": ["import { T } from '@tldraw/validate'\nimport { TLRichText, richTextValidator, toRichText } from '../misc/TLRichText'\nimport { createShapePropsMigrationIds, createShapePropsMigrationSequence } from '../records/TLShape'\nimport { RecordProps } from '../recordsWithProps'\nimport { StyleProp } from '../styles/StyleProp'\nimport {\n\tDefaultColorStyle,\n\tDefaultLabelColorStyle,\n\tTLDefaultColorStyle,\n} from '../styles/TLColorStyle'\nimport { DefaultDashStyle, TLDefaultDashStyle } from '../styles/TLDashStyle'\nimport { DefaultFillStyle, TLDefaultFillStyle } from '../styles/TLFillStyle'\nimport { DefaultFontStyle, TLDefaultFontStyle } from '../styles/TLFontStyle'\nimport {\n\tDefaultHorizontalAlignStyle,\n\tTLDefaultHorizontalAlignStyle,\n} from '../styles/TLHorizontalAlignStyle'\nimport { DefaultSizeStyle, TLDefaultSizeStyle } from '../styles/TLSizeStyle'\nimport {\n\tDefaultVerticalAlignStyle,\n\tTLDefaultVerticalAlignStyle,\n} from '../styles/TLVerticalAlignStyle'\nimport { TLBaseShape } from './TLBaseShape'\n\n/**\n * Style property defining the geometric shape type for geo shapes.\n * Provides a variety of built-in geometric forms including basic shapes,\n * polygons, arrows, and special shapes.\n *\n * @public\n * @example\n * ```ts\n * // Use in shape props\n * const props = {\n * geo: 'rectangle', // or 'ellipse', 'triangle', etc.\n * // other properties...\n * }\n * ```\n */\nexport const GeoShapeGeoStyle = StyleProp.defineEnum('tldraw:geo', {\n\tdefaultValue: 'rectangle',\n\tvalues: [\n\t\t'cloud',\n\t\t'rectangle',\n\t\t'ellipse',\n\t\t'triangle',\n\t\t'diamond',\n\t\t'pentagon',\n\t\t'hexagon',\n\t\t'octagon',\n\t\t'star',\n\t\t'rhombus',\n\t\t'rhombus-2',\n\t\t'oval',\n\t\t'trapezoid',\n\t\t'arrow-right',\n\t\t'arrow-left',\n\t\t'arrow-up',\n\t\t'arrow-down',\n\t\t'x-box',\n\t\t'check-box',\n\t\t'heart',\n\t],\n})\n\n/**\n * Type representing valid geometric shape styles for geo shapes.\n *\n * @public\n */\nexport type TLGeoShapeGeoStyle = T.TypeOf<typeof GeoShapeGeoStyle>\n\n/**\n * Properties for the geo shape, which renders various geometric forms with styling and text.\n *\n * @public\n */\nexport interface TLGeoShapeProps {\n\t/** Geometric shape type (rectangle, ellipse, triangle, etc.) */\n\tgeo: TLGeoShapeGeoStyle\n\t/** Dash pattern style for the shape outline */\n\tdash: TLDefaultDashStyle\n\t/** URL link associated with the shape */\n\turl: string\n\t/** Width of the shape in pixels */\n\tw: number\n\t/** Height of the shape in pixels */\n\th: number\n\t/** Additional vertical growth for text content */\n\tgrowY: number\n\t/** Scale factor applied to the shape */\n\tscale: number\n\n\t/** Color style for text label */\n\tlabelColor: TLDefaultColorStyle\n\t/** Color style for the shape outline */\n\tcolor: TLDefaultColorStyle\n\t/** Fill style for the shape interior */\n\tfill: TLDefaultFillStyle\n\t/** Size/thickness style for outline and text */\n\tsize: TLDefaultSizeStyle\n\t/** Font style for text content */\n\tfont: TLDefaultFontStyle\n\t/** Horizontal alignment for text content */\n\talign: TLDefaultHorizontalAlignStyle\n\t/** Vertical alignment for text content */\n\tverticalAlign: TLDefaultVerticalAlignStyle\n\t/** Rich text content displayed within the shape */\n\trichText: TLRichText\n}\n\n/**\n * A geo shape represents geometric forms like rectangles, ellipses, triangles, and other\n * predefined shapes. Geo shapes support styling, text content, and can act as containers.\n *\n * @public\n * @example\n * ```ts\n * const geoShape: TLGeoShape = {\n * id: createShapeId(),\n * typeName: 'shape',\n * type: 'geo',\n * x: 100,\n * y: 100,\n * rotation: 0,\n * index: 'a1',\n * parentId: 'page:page1',\n * isLocked: false,\n * opacity: 1,\n * props: {\n * geo: 'rectangle',\n * w: 200,\n * h: 100,\n * color: 'black',\n * fill: 'solid',\n * dash: 'solid',\n * size: 'm',\n * font: 'draw',\n * align: 'middle',\n * verticalAlign: 'middle',\n * richText: toRichText('Hello World'),\n * labelColor: 'black',\n * url: '',\n * growY: 0,\n * scale: 1\n * },\n * meta: {}\n * }\n * ```\n */\nexport type TLGeoShape = TLBaseShape<'geo', TLGeoShapeProps>\n\n/**\n * Validation schema for geo shape properties.\n *\n * @public\n * @example\n * ```ts\n * // Validate geo shape properties\n * const isValidGeo = geoShapeProps.geo.isValid('rectangle')\n * const isValidSize = geoShapeProps.w.isValid(100)\n * const isValidText = geoShapeProps.richText.isValid(toRichText('Hello'))\n * ```\n */\nexport const geoShapeProps: RecordProps<TLGeoShape> = {\n\tgeo: GeoShapeGeoStyle,\n\tdash: DefaultDashStyle,\n\turl: T.linkUrl,\n\tw: T.nonZeroNumber,\n\th: T.nonZeroNumber,\n\tgrowY: T.positiveNumber,\n\tscale: T.nonZeroNumber,\n\n\t// Text properties\n\tlabelColor: DefaultLabelColorStyle,\n\tcolor: DefaultColorStyle,\n\tfill: DefaultFillStyle,\n\tsize: DefaultSizeStyle,\n\tfont: DefaultFontStyle,\n\talign: DefaultHorizontalAlignStyle,\n\tverticalAlign: DefaultVerticalAlignStyle,\n\trichText: richTextValidator,\n}\n\nconst geoShapeVersions = createShapePropsMigrationIds('geo', {\n\tAddUrlProp: 1,\n\tAddLabelColor: 2,\n\tRemoveJustify: 3,\n\tAddCheckBox: 4,\n\tAddVerticalAlign: 5,\n\tMigrateLegacyAlign: 6,\n\tAddCloud: 7,\n\tMakeUrlsValid: 8,\n\tAddScale: 9,\n\tAddRichText: 10,\n\tAddRichTextAttrs: 11,\n})\n\n/**\n * Version identifiers for geo shape migrations.\n *\n * @public\n */\nexport { geoShapeVersions as geoShapeVersions }\n\n/**\n * Migration sequence for geo shape properties across different schema versions.\n * Handles evolution of geo shapes including URL support, label colors, alignment changes,\n * the transition from plain text to rich text, and support for attrs property on richText.\n *\n * @public\n */\nexport const geoShapeMigrations = createShapePropsMigrationSequence({\n\tsequence: [\n\t\t{\n\t\t\tid: geoShapeVersions.AddUrlProp,\n\t\t\tup: (props) => {\n\t\t\t\tprops.url = ''\n\t\t\t},\n\t\t\tdown: 'retired',\n\t\t},\n\t\t{\n\t\t\tid: geoShapeVersions.AddLabelColor,\n\t\t\tup: (props) => {\n\t\t\t\tprops.labelColor = 'black'\n\t\t\t},\n\t\t\tdown: 'retired',\n\t\t},\n\t\t{\n\t\t\tid: geoShapeVersions.RemoveJustify,\n\t\t\tup: (props) => {\n\t\t\t\tif (props.align === 'justify') {\n\t\t\t\t\tprops.align = 'start'\n\t\t\t\t}\n\t\t\t},\n\t\t\tdown: 'retired',\n\t\t},\n\t\t{\n\t\t\tid: geoShapeVersions.AddCheckBox,\n\t\t\tup: (_props) => {\n\t\t\t\t// noop\n\t\t\t},\n\t\t\tdown: 'retired',\n\t\t},\n\t\t{\n\t\t\tid: geoShapeVersions.AddVerticalAlign,\n\t\t\tup: (props) => {\n\t\t\t\tprops.verticalAlign = 'middle'\n\t\t\t},\n\t\t\tdown: 'retired',\n\t\t},\n\t\t{\n\t\t\tid: geoShapeVersions.MigrateLegacyAlign,\n\t\t\tup: (props) => {\n\t\t\t\tlet newAlign: TLDefaultHorizontalAlignStyle\n\t\t\t\tswitch (props.align) {\n\t\t\t\t\tcase 'start':\n\t\t\t\t\t\tnewAlign = 'start-legacy'\n\t\t\t\t\t\tbreak\n\t\t\t\t\tcase 'end':\n\t\t\t\t\t\tnewAlign = 'end-legacy'\n\t\t\t\t\t\tbreak\n\t\t\t\t\tdefault:\n\t\t\t\t\t\tnewAlign = 'middle-legacy'\n\t\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t\tprops.align = newAlign\n\t\t\t},\n\t\t\tdown: 'retired',\n\t\t},\n\t\t{\n\t\t\tid: geoShapeVersions.AddCloud,\n\t\t\tup: (_props) => {\n\t\t\t\t// noop\n\t\t\t},\n\t\t\tdown: 'retired',\n\t\t},\n\t\t{\n\t\t\tid: geoShapeVersions.MakeUrlsValid,\n\t\t\tup: (props) => {\n\t\t\t\tif (!T.linkUrl.isValid(props.url)) {\n\t\t\t\t\tprops.url = ''\n\t\t\t\t}\n\t\t\t},\n\t\t\tdown: (_props) => {\n\t\t\t\t// noop\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tid: geoShapeVersions.AddScale,\n\t\t\tup: (props) => {\n\t\t\t\tprops.scale = 1\n\t\t\t},\n\t\t\tdown: (props) => {\n\t\t\t\tdelete props.scale\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tid: geoShapeVersions.AddRichText,\n\t\t\tup: (props) => {\n\t\t\t\tprops.richText = toRichText(props.text)\n\t\t\t\tdelete props.text\n\t\t\t},\n\t\t\t// N.B. Explicitly no down state so that we force clients to update.\n\t\t\t// down: (props) => {\n\t\t\t// \tdelete props.richText\n\t\t\t// },\n\t\t},\n\t\t{\n\t\t\tid: geoShapeVersions.AddRichTextAttrs,\n\t\t\tup: (_props) => {\n\t\t\t\t// noop - attrs is optional so old records are valid\n\t\t\t},\n\t\t\tdown: (props) => {\n\t\t\t\t// Remove attrs from richText when migrating down\n\t\t\t\tif (props.richText && 'attrs' in props.richText) {\n\t\t\t\t\tdelete props.richText.attrs\n\t\t\t\t}\n\t\t\t},\n\t\t},\n\t],\n})\n"],
5
+ "mappings": "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",
6
6
  "names": []
7
7
  }