tldraw 4.1.0-canary.e4499a57ef5b → 4.1.0-canary.f414ee471d7f

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 (113) hide show
  1. package/dist-cjs/index.d.ts +21 -0
  2. package/dist-cjs/index.js +1 -1
  3. package/dist-cjs/lib/canvas/TldrawCropHandles.js +1 -1
  4. package/dist-cjs/lib/canvas/TldrawScribble.js +1 -1
  5. package/dist-cjs/lib/canvas/TldrawSelectionForeground.js +1 -1
  6. package/dist-cjs/lib/defaultEmbedDefinitions.js +24 -6
  7. package/dist-cjs/lib/defaultEmbedDefinitions.js.map +2 -2
  8. package/dist-cjs/lib/defaultExternalContentHandlers.js +2 -2
  9. package/dist-cjs/lib/defaultExternalContentHandlers.js.map +2 -2
  10. package/dist-cjs/lib/shapes/arrow/ArrowShapeUtil.js +3 -0
  11. package/dist-cjs/lib/shapes/arrow/ArrowShapeUtil.js.map +2 -2
  12. package/dist-cjs/lib/shapes/arrow/curved-arrow.js +8 -2
  13. package/dist-cjs/lib/shapes/arrow/curved-arrow.js.map +2 -2
  14. package/dist-cjs/lib/shapes/arrow/straight-arrow.js +4 -1
  15. package/dist-cjs/lib/shapes/arrow/straight-arrow.js.map +2 -2
  16. package/dist-cjs/lib/shapes/bookmark/BookmarkShapeUtil.js +14 -2
  17. package/dist-cjs/lib/shapes/bookmark/BookmarkShapeUtil.js.map +2 -2
  18. package/dist-cjs/lib/shapes/frame/FrameShapeUtil.js +1 -1
  19. package/dist-cjs/lib/shapes/image/ImageShapeUtil.js +1 -1
  20. package/dist-cjs/lib/shapes/line/LineShapeUtil.js +3 -0
  21. package/dist-cjs/lib/shapes/line/LineShapeUtil.js.map +2 -2
  22. package/dist-cjs/lib/shapes/shared/HyperlinkButton.js +1 -1
  23. package/dist-cjs/lib/shapes/shared/PlainTextLabel.js +1 -1
  24. package/dist-cjs/lib/shapes/shared/RichTextLabel.js +2 -2
  25. package/dist-cjs/lib/shapes/shared/RichTextLabel.js.map +2 -2
  26. package/dist-cjs/lib/shapes/shared/ShapeFill.js +1 -1
  27. package/dist-cjs/lib/shapes/text/PlainTextArea.js +1 -1
  28. package/dist-cjs/lib/shapes/text/RichTextArea.js +1 -1
  29. package/dist-cjs/lib/shapes/video/VideoShapeUtil.js +1 -1
  30. package/dist-cjs/lib/tools/SelectTool/childStates/Crop/children/Idle.js +1 -1
  31. package/dist-cjs/lib/tools/SelectTool/childStates/Crop/children/Idle.js.map +2 -2
  32. package/dist-cjs/lib/tools/SelectTool/childStates/Idle.js +1 -1
  33. package/dist-cjs/lib/tools/SelectTool/childStates/Idle.js.map +2 -2
  34. package/dist-cjs/lib/ui/TldrawUi.js +2 -2
  35. package/dist-cjs/lib/ui/components/DebugMenu/DefaultDebugMenuContent.js +1 -1
  36. package/dist-cjs/lib/ui/components/KeyboardShortcutsDialog/DefaultKeyboardShortcutsDialog.js +1 -1
  37. package/dist-cjs/lib/ui/components/Minimap/DefaultMinimap.js +1 -1
  38. package/dist-cjs/lib/ui/components/Minimap/MinimapManager.js +5 -0
  39. package/dist-cjs/lib/ui/components/Minimap/MinimapManager.js.map +2 -2
  40. package/dist-cjs/lib/ui/components/OfflineIndicator/OfflineIndicator.js +1 -1
  41. package/dist-cjs/lib/ui/components/SharePanel/UserPresenceColorPicker.js +1 -1
  42. package/dist-cjs/lib/ui/components/StylePanel/DefaultStylePanel.js +1 -1
  43. package/dist-cjs/lib/ui/components/StylePanel/DefaultStylePanelContent.js +1 -1
  44. package/dist-cjs/lib/ui/components/StylePanel/StylePanelDoubleDropdownPicker.js +1 -1
  45. package/dist-cjs/lib/ui/components/StylePanel/StylePanelDropdownPicker.js +1 -1
  46. package/dist-cjs/lib/ui/components/Toolbar/DefaultToolbar.js +1 -1
  47. package/dist-cjs/lib/ui/components/Toolbar/OverflowingToolbar.js +1 -1
  48. package/dist-cjs/lib/ui/components/Toolbar/ToggleToolLockedButton.js +1 -1
  49. package/dist-cjs/lib/ui/components/primitives/Button/TldrawUiButton.js +2 -2
  50. package/dist-cjs/lib/ui/components/primitives/TldrawUiContextualToolbar.js +1 -1
  51. package/dist-cjs/lib/ui/components/primitives/TldrawUiDialog.js +1 -1
  52. package/dist-cjs/lib/ui/components/primitives/TldrawUiDropdownMenu.js +1 -1
  53. package/dist-cjs/lib/ui/components/primitives/TldrawUiIcon.js +1 -1
  54. package/dist-cjs/lib/ui/components/primitives/TldrawUiInput.js +2 -2
  55. package/dist-cjs/lib/ui/components/primitives/TldrawUiPopover.js +2 -2
  56. package/dist-cjs/lib/ui/components/primitives/TldrawUiSlider.js +1 -1
  57. package/dist-cjs/lib/ui/components/primitives/TldrawUiToolbar.js +2 -2
  58. package/dist-cjs/lib/ui/components/primitives/TldrawUiTooltip.js +1 -1
  59. package/dist-cjs/lib/ui/components/primitives/layout.js +1 -1
  60. package/dist-cjs/lib/ui/components/primitives/menus/TldrawUiMenuGroup.js +1 -1
  61. package/dist-cjs/lib/ui/context/actions.js +1 -1
  62. package/dist-cjs/lib/ui/context/breakpoints.js +1 -1
  63. package/dist-cjs/lib/ui/context/events.js +1 -1
  64. package/dist-cjs/lib/ui/hooks/useClipboardEvents.js +1 -1
  65. package/dist-cjs/lib/ui/hooks/useKeyboardShortcuts.js +1 -1
  66. package/dist-cjs/lib/ui/hooks/useLocalStorageState.js +1 -1
  67. package/dist-cjs/lib/ui/hooks/useTools.js +1 -1
  68. package/dist-cjs/lib/ui/hooks/useTranslation/useTranslation.js +1 -1
  69. package/dist-cjs/lib/ui/version.js +3 -3
  70. package/dist-cjs/lib/ui/version.js.map +1 -1
  71. package/dist-cjs/lib/utils/text/richText.js +4 -4
  72. package/dist-esm/index.d.mts +21 -0
  73. package/dist-esm/index.mjs +1 -1
  74. package/dist-esm/lib/defaultEmbedDefinitions.mjs +24 -6
  75. package/dist-esm/lib/defaultEmbedDefinitions.mjs.map +2 -2
  76. package/dist-esm/lib/defaultExternalContentHandlers.mjs +2 -2
  77. package/dist-esm/lib/defaultExternalContentHandlers.mjs.map +2 -2
  78. package/dist-esm/lib/shapes/arrow/ArrowShapeUtil.mjs +3 -0
  79. package/dist-esm/lib/shapes/arrow/ArrowShapeUtil.mjs.map +2 -2
  80. package/dist-esm/lib/shapes/arrow/curved-arrow.mjs +8 -2
  81. package/dist-esm/lib/shapes/arrow/curved-arrow.mjs.map +2 -2
  82. package/dist-esm/lib/shapes/arrow/straight-arrow.mjs +4 -1
  83. package/dist-esm/lib/shapes/arrow/straight-arrow.mjs.map +2 -2
  84. package/dist-esm/lib/shapes/bookmark/BookmarkShapeUtil.mjs +13 -1
  85. package/dist-esm/lib/shapes/bookmark/BookmarkShapeUtil.mjs.map +2 -2
  86. package/dist-esm/lib/shapes/line/LineShapeUtil.mjs +3 -0
  87. package/dist-esm/lib/shapes/line/LineShapeUtil.mjs.map +2 -2
  88. package/dist-esm/lib/shapes/shared/RichTextLabel.mjs +1 -1
  89. package/dist-esm/lib/shapes/shared/RichTextLabel.mjs.map +2 -2
  90. package/dist-esm/lib/tools/SelectTool/childStates/Crop/children/Idle.mjs +1 -1
  91. package/dist-esm/lib/tools/SelectTool/childStates/Crop/children/Idle.mjs.map +2 -2
  92. package/dist-esm/lib/tools/SelectTool/childStates/Idle.mjs +1 -1
  93. package/dist-esm/lib/tools/SelectTool/childStates/Idle.mjs.map +2 -2
  94. package/dist-esm/lib/ui/components/Minimap/MinimapManager.mjs +5 -0
  95. package/dist-esm/lib/ui/components/Minimap/MinimapManager.mjs.map +2 -2
  96. package/dist-esm/lib/ui/version.mjs +3 -3
  97. package/dist-esm/lib/ui/version.mjs.map +1 -1
  98. package/package.json +11 -11
  99. package/src/lib/defaultEmbedDefinitions.ts +19 -0
  100. package/src/lib/defaultExternalContentHandlers.ts +2 -2
  101. package/src/lib/shapes/arrow/ArrowShapeUtil.test.ts +211 -1
  102. package/src/lib/shapes/arrow/ArrowShapeUtil.tsx +3 -0
  103. package/src/lib/shapes/arrow/curved-arrow.ts +8 -2
  104. package/src/lib/shapes/arrow/straight-arrow.ts +5 -1
  105. package/src/lib/shapes/bookmark/BookmarkShapeUtil.tsx +13 -3
  106. package/src/lib/shapes/line/LineShapeUtil.tsx +3 -0
  107. package/src/lib/shapes/shared/RichTextLabel.tsx +1 -1
  108. package/src/lib/shapes/text/TextShapeTool.test.ts +74 -0
  109. package/src/lib/tools/SelectTool/childStates/Crop/children/Idle.ts +1 -1
  110. package/src/lib/tools/SelectTool/childStates/Idle.ts +1 -1
  111. package/src/lib/ui/components/Minimap/MinimapManager.ts +6 -0
  112. package/src/lib/ui/version.ts +3 -3
  113. package/tldraw.css +7 -2
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../../../../src/lib/ui/components/Minimap/MinimapManager.ts"],
4
- "sourcesContent": ["import {\n\tBox,\n\tComputedCache,\n\tEditor,\n\tTLShape,\n\tVec,\n\tatom,\n\tbind,\n\tclamp,\n\tcomputed,\n\treact,\n\ttlenv,\n\tuniqueId,\n} from '@tldraw/editor'\nimport { getRgba } from './getRgba'\nimport { BufferStuff, appendVertices, setupWebGl } from './minimap-webgl-setup'\nimport { pie, rectangle, roundedRectangle } from './minimap-webgl-shapes'\n\nexport class MinimapManager {\n\tdisposables = [] as (() => void)[]\n\n\t@bind\n\tclose() {\n\t\treturn this.disposables.forEach((d) => d())\n\t}\n\tgl: ReturnType<typeof setupWebGl>\n\tshapeGeometryCache: ComputedCache<Float32Array | null, TLShape>\n\tconstructor(\n\t\tpublic editor: Editor,\n\t\tpublic readonly elem: HTMLCanvasElement,\n\t\tpublic readonly container: HTMLElement\n\t) {\n\t\tthis.gl = setupWebGl(elem)\n\t\tthis.shapeGeometryCache = editor.store.createComputedCache('webgl-geometry', (r: TLShape) => {\n\t\t\tconst bounds = editor.getShapeMaskedPageBounds(r.id)\n\t\t\tif (!bounds) return null\n\t\t\tconst arr = new Float32Array(12)\n\t\t\trectangle(arr, 0, bounds.x, bounds.y, bounds.w, bounds.h)\n\t\t\treturn arr\n\t\t})\n\t\tthis.colors = this._getColors()\n\t\tthis.disposables.push(this._listenForCanvasResize(), react('minimap render', this.render))\n\t}\n\n\tprivate _getColors() {\n\t\tconst style = getComputedStyle(this.editor.getContainer())\n\n\t\treturn {\n\t\t\tshapeFill: getRgba(style.getPropertyValue('--tl-color-text-3').trim()),\n\t\t\tselectFill: getRgba(style.getPropertyValue('--tl-color-selected').trim()),\n\t\t\tviewportFill: getRgba(style.getPropertyValue('--tl-color-muted-1').trim()),\n\t\t\tbackground: getRgba(style.getPropertyValue('--tl-color-low').trim()),\n\t\t}\n\t}\n\n\tprivate colors: ReturnType<MinimapManager['_getColors']>\n\t// this should be called after dark/light mode changes have propagated to the dom\n\tupdateColors() {\n\t\tthis.colors = this._getColors()\n\t}\n\n\treadonly id = uniqueId()\n\t@computed\n\tgetDpr() {\n\t\treturn this.editor.getInstanceState().devicePixelRatio\n\t}\n\n\t@computed\n\tgetContentPageBounds() {\n\t\tconst viewportPageBounds = this.editor.getViewportPageBounds()\n\t\tconst commonShapeBounds = this.editor.getCurrentPageBounds()\n\t\treturn commonShapeBounds\n\t\t\t? Box.Expand(commonShapeBounds, viewportPageBounds)\n\t\t\t: viewportPageBounds\n\t}\n\n\t@computed\n\tgetContentScreenBounds() {\n\t\tconst contentPageBounds = this.getContentPageBounds()\n\t\tconst topLeft = this.editor.pageToScreen(contentPageBounds.point)\n\t\tconst bottomRight = this.editor.pageToScreen(\n\t\t\tnew Vec(contentPageBounds.maxX, contentPageBounds.maxY)\n\t\t)\n\t\treturn new Box(topLeft.x, topLeft.y, bottomRight.x - topLeft.x, bottomRight.y - topLeft.y)\n\t}\n\n\tprivate _getCanvasBoundingRect() {\n\t\tconst { x, y, width, height } = this.elem.getBoundingClientRect()\n\t\treturn new Box(x, y, width, height)\n\t}\n\n\tprivate readonly canvasBoundingClientRect = atom('canvasBoundingClientRect', new Box())\n\n\tgetCanvasScreenBounds() {\n\t\treturn this.canvasBoundingClientRect.get()\n\t}\n\n\tprivate _listenForCanvasResize() {\n\t\tconst observer = new ResizeObserver(() => {\n\t\t\tconst rect = this._getCanvasBoundingRect()\n\t\t\tthis.canvasBoundingClientRect.set(rect)\n\t\t})\n\t\tobserver.observe(this.elem)\n\t\tobserver.observe(this.container)\n\t\treturn () => observer.disconnect()\n\t}\n\n\t@computed\n\tgetCanvasSize() {\n\t\tconst rect = this.canvasBoundingClientRect.get()\n\t\tconst dpr = this.getDpr()\n\t\treturn new Vec(rect.width * dpr, rect.height * dpr)\n\t}\n\n\t@computed\n\tgetCanvasClientPosition() {\n\t\treturn this.canvasBoundingClientRect.get().point\n\t}\n\n\toriginPagePoint = new Vec()\n\toriginPageCenter = new Vec()\n\n\tisInViewport = false\n\n\t/** Get the canvas's true bounds converted to page bounds. */\n\t@computed getCanvasPageBounds() {\n\t\tconst canvasScreenBounds = this.getCanvasScreenBounds()\n\t\tconst contentPageBounds = this.getContentPageBounds()\n\n\t\tconst aspectRatio = canvasScreenBounds.width / canvasScreenBounds.height\n\n\t\tlet targetWidth = contentPageBounds.width\n\t\tlet targetHeight = targetWidth / aspectRatio\n\t\tif (targetHeight < contentPageBounds.height) {\n\t\t\ttargetHeight = contentPageBounds.height\n\t\t\ttargetWidth = targetHeight * aspectRatio\n\t\t}\n\n\t\tconst box = new Box(0, 0, targetWidth, targetHeight)\n\t\tbox.center = contentPageBounds.center\n\t\treturn box\n\t}\n\n\t@computed getZoom() {\n\t\treturn this.getCanvasPageBounds().width / this.getCanvasScreenBounds().width\n\t}\n\n\t@computed getCanvasPageBoundsArray() {\n\t\tconst { x, y, w, h } = this.getCanvasPageBounds()\n\t\treturn new Float32Array([x, y, w, h])\n\t}\n\n\tgetMinimapPagePoint(clientX: number, clientY: number) {\n\t\tconst canvasPageBounds = this.getCanvasPageBounds()\n\t\tconst canvasScreenBounds = this.getCanvasScreenBounds()\n\n\t\t// first offset the canvas position\n\t\tlet x = clientX - canvasScreenBounds.x\n\t\tlet y = clientY - canvasScreenBounds.y\n\n\t\t// then multiply by the ratio between the page and screen bounds\n\t\tx *= canvasPageBounds.width / canvasScreenBounds.width\n\t\ty *= canvasPageBounds.height / canvasScreenBounds.height\n\n\t\t// then add the canvas page bounds' offset\n\t\tx += canvasPageBounds.minX\n\t\ty += canvasPageBounds.minY\n\n\t\treturn new Vec(x, y, 1)\n\t}\n\n\tminimapScreenPointToPagePoint(x: number, y: number, shiftKey = false, clampToBounds = false) {\n\t\tconst { editor } = this\n\t\tconst vpPageBounds = editor.getViewportPageBounds()\n\n\t\tlet { x: px, y: py } = this.getMinimapPagePoint(x, y)\n\n\t\tif (clampToBounds) {\n\t\t\tconst shapesPageBounds = this.editor.getCurrentPageBounds() ?? new Box()\n\n\t\t\tconst minX = shapesPageBounds.minX - vpPageBounds.width / 2\n\t\t\tconst maxX = shapesPageBounds.maxX + vpPageBounds.width / 2\n\t\t\tconst minY = shapesPageBounds.minY - vpPageBounds.height / 2\n\t\t\tconst maxY = shapesPageBounds.maxY + vpPageBounds.height / 2\n\n\t\t\tconst lx = Math.max(0, minX + vpPageBounds.width - px)\n\t\t\tconst rx = Math.max(0, -(maxX - vpPageBounds.width - px))\n\t\t\tconst ly = Math.max(0, minY + vpPageBounds.height - py)\n\t\t\tconst ry = Math.max(0, -(maxY - vpPageBounds.height - py))\n\n\t\t\tpx += (lx - rx) / 2\n\t\t\tpy += (ly - ry) / 2\n\n\t\t\tpx = clamp(px, minX, maxX)\n\t\t\tpy = clamp(py, minY, maxY)\n\t\t}\n\n\t\tif (shiftKey) {\n\t\t\tconst { originPagePoint } = this\n\t\t\tconst dx = Math.abs(px - originPagePoint.x)\n\t\t\tconst dy = Math.abs(py - originPagePoint.y)\n\t\t\tif (dx > dy) {\n\t\t\t\tpy = originPagePoint.y\n\t\t\t} else {\n\t\t\t\tpx = originPagePoint.x\n\t\t\t}\n\t\t}\n\n\t\treturn new Vec(px, py)\n\t}\n\n\t@bind\n\trender() {\n\t\t// make sure we update when dark mode switches\n\t\tconst context = this.gl.context\n\t\tconst canvasSize = this.getCanvasSize()\n\n\t\tthis.gl.setCanvasPageBounds(this.getCanvasPageBoundsArray())\n\n\t\tthis.elem.width = canvasSize.x\n\t\tthis.elem.height = canvasSize.y\n\t\tcontext.viewport(0, 0, canvasSize.x, canvasSize.y)\n\n\t\t// this affects which color transparent shapes are blended with\n\t\t// during rendering. If we were to invert this any shapes narrower\n\t\t// than 1 px in screen space would have much lower contrast. e.g.\n\t\t// draw shapes on a large canvas.\n\t\tcontext.clearColor(\n\t\t\tthis.colors.background[0],\n\t\t\tthis.colors.background[1],\n\t\t\tthis.colors.background[2],\n\t\t\t1\n\t\t)\n\n\t\tcontext.clear(context.COLOR_BUFFER_BIT)\n\n\t\tconst selectedShapes = new Set(this.editor.getSelectedShapeIds())\n\n\t\tconst colors = this.colors\n\t\tlet selectedShapeOffset = 0\n\t\tlet unselectedShapeOffset = 0\n\n\t\tconst ids = this.editor.getCurrentPageShapeIdsSorted()\n\n\t\tfor (let i = 0, len = ids.length; i < len; i++) {\n\t\t\tconst shapeId = ids[i]\n\t\t\tconst geometry = this.shapeGeometryCache.get(shapeId)\n\t\t\tif (!geometry) continue\n\n\t\t\tconst len = geometry.length\n\n\t\t\tif (selectedShapes.has(shapeId)) {\n\t\t\t\tappendVertices(this.gl.selectedShapes, selectedShapeOffset, geometry)\n\t\t\t\tselectedShapeOffset += len\n\t\t\t} else {\n\t\t\t\tappendVertices(this.gl.unselectedShapes, unselectedShapeOffset, geometry)\n\t\t\t\tunselectedShapeOffset += len\n\t\t\t}\n\t\t}\n\n\t\tthis.drawShapes(this.gl.unselectedShapes, unselectedShapeOffset, colors.shapeFill)\n\t\tthis.drawShapes(this.gl.selectedShapes, selectedShapeOffset, colors.selectFill)\n\n\t\tthis.drawViewport()\n\t\tthis.drawCollaborators()\n\t}\n\n\tprivate drawShapes(stuff: BufferStuff, len: number, color: Float32Array) {\n\t\tthis.gl.prepareTriangles(stuff, len)\n\t\tthis.gl.setFillColor(color)\n\t\tthis.gl.drawTriangles(len)\n\t}\n\n\tprivate drawViewport() {\n\t\tconst viewport = this.editor.getViewportPageBounds()\n\t\tconst len = roundedRectangle(this.gl.viewport.vertices, viewport, 4 * this.getZoom())\n\n\t\tthis.gl.prepareTriangles(this.gl.viewport, len)\n\t\tthis.gl.setFillColor(this.colors.viewportFill)\n\t\tthis.gl.drawTrianglesTransparently(len)\n\t\tif (tlenv.isSafari) {\n\t\t\tthis.gl.drawTrianglesTransparently(len)\n\t\t\tthis.gl.drawTrianglesTransparently(len)\n\t\t\tthis.gl.drawTrianglesTransparently(len)\n\t\t}\n\t}\n\n\tdrawCollaborators() {\n\t\tconst collaborators = this.editor.getCollaboratorsOnCurrentPage()\n\t\tif (!collaborators.length) return\n\n\t\t// just draw a little circle for each collaborator\n\t\tconst numSegmentsPerCircle = 20\n\t\tconst dataSizePerCircle = numSegmentsPerCircle * 6\n\t\tconst totalSize = dataSizePerCircle * collaborators.length\n\n\t\t// expand vertex array if needed\n\t\tif (this.gl.collaborators.vertices.length < totalSize) {\n\t\t\tthis.gl.collaborators.vertices = new Float32Array(totalSize)\n\t\t}\n\n\t\tconst vertices = this.gl.collaborators.vertices\n\t\tlet offset = 0\n\t\tconst zoom = this.getZoom()\n\t\tfor (const { cursor } of collaborators) {\n\t\t\tif (!cursor) continue\n\t\t\tpie(vertices, {\n\t\t\t\tcenter: Vec.From(cursor),\n\t\t\t\tradius: 3 * zoom,\n\t\t\t\toffset,\n\t\t\t\tnumArcSegments: numSegmentsPerCircle,\n\t\t\t})\n\t\t\toffset += dataSizePerCircle\n\t\t}\n\n\t\tthis.gl.prepareTriangles(this.gl.collaborators, totalSize)\n\n\t\toffset = 0\n\t\tfor (const { color } of collaborators) {\n\t\t\tthis.gl.setFillColor(getRgba(color))\n\t\t\tthis.gl.context.drawArrays(this.gl.context.TRIANGLES, offset / 2, dataSizePerCircle / 2)\n\t\t\toffset += dataSizePerCircle\n\t\t}\n\t}\n}\n"],
5
- "mappings": ";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA,EACC;AAAA,EAIA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,OACM;AACP,SAAS,eAAe;AACxB,SAAsB,gBAAgB,kBAAkB;AACxD,SAAS,KAAK,WAAW,wBAAwB;AAKhD,cAAC,OAyCD,eAAC,WAKD,6BAAC,WASD,+BAAC,WA+BD,sBAAC,WAOD,gCAAC,WAWD,4BAAC,WAkBD,gBAAC,WAID,iCAAC,WAgED,eAAC;AAjMK,MAAM,eAAe;AAAA,EAS3B,YACQ,QACS,MACA,WACf;AAHM;AACS;AACA;AAZX;AACN,uCAAc,CAAC;AAMf;AACA;AA6BA,wBAAQ;AAMR,wBAAS,MAAK,SAAS;AA8BvB,wBAAiB,4BAA2B,KAAK,4BAA4B,IAAI,IAAI,CAAC;AA4BtF,2CAAkB,IAAI,IAAI;AAC1B,4CAAmB,IAAI,IAAI;AAE3B,wCAAe;AA1Fd,SAAK,KAAK,WAAW,IAAI;AACzB,SAAK,qBAAqB,OAAO,MAAM,oBAAoB,kBAAkB,CAAC,MAAe;AAC5F,YAAM,SAAS,OAAO,yBAAyB,EAAE,EAAE;AACnD,UAAI,CAAC,OAAQ,QAAO;AACpB,YAAM,MAAM,IAAI,aAAa,EAAE;AAC/B,gBAAU,KAAK,GAAG,OAAO,GAAG,OAAO,GAAG,OAAO,GAAG,OAAO,CAAC;AACxD,aAAO;AAAA,IACR,CAAC;AACD,SAAK,SAAS,KAAK,WAAW;AAC9B,SAAK,YAAY,KAAK,KAAK,uBAAuB,GAAG,MAAM,kBAAkB,KAAK,MAAM,CAAC;AAAA,EAC1F;AAAA,EApBA,QAAQ;AACP,WAAO,KAAK,YAAY,QAAQ,CAAC,MAAM,EAAE,CAAC;AAAA,EAC3C;AAAA,EAoBQ,aAAa;AACpB,UAAM,QAAQ,iBAAiB,KAAK,OAAO,aAAa,CAAC;AAEzD,WAAO;AAAA,MACN,WAAW,QAAQ,MAAM,iBAAiB,mBAAmB,EAAE,KAAK,CAAC;AAAA,MACrE,YAAY,QAAQ,MAAM,iBAAiB,qBAAqB,EAAE,KAAK,CAAC;AAAA,MACxE,cAAc,QAAQ,MAAM,iBAAiB,oBAAoB,EAAE,KAAK,CAAC;AAAA,MACzE,YAAY,QAAQ,MAAM,iBAAiB,gBAAgB,EAAE,KAAK,CAAC;AAAA,IACpE;AAAA,EACD;AAAA;AAAA,EAIA,eAAe;AACd,SAAK,SAAS,KAAK,WAAW;AAAA,EAC/B;AAAA,EAIA,SAAS;AACR,WAAO,KAAK,OAAO,iBAAiB,EAAE;AAAA,EACvC;AAAA,EAGA,uBAAuB;AACtB,UAAM,qBAAqB,KAAK,OAAO,sBAAsB;AAC7D,UAAM,oBAAoB,KAAK,OAAO,qBAAqB;AAC3D,WAAO,oBACJ,IAAI,OAAO,mBAAmB,kBAAkB,IAChD;AAAA,EACJ;AAAA,EAGA,yBAAyB;AACxB,UAAM,oBAAoB,KAAK,qBAAqB;AACpD,UAAM,UAAU,KAAK,OAAO,aAAa,kBAAkB,KAAK;AAChE,UAAM,cAAc,KAAK,OAAO;AAAA,MAC/B,IAAI,IAAI,kBAAkB,MAAM,kBAAkB,IAAI;AAAA,IACvD;AACA,WAAO,IAAI,IAAI,QAAQ,GAAG,QAAQ,GAAG,YAAY,IAAI,QAAQ,GAAG,YAAY,IAAI,QAAQ,CAAC;AAAA,EAC1F;AAAA,EAEQ,yBAAyB;AAChC,UAAM,EAAE,GAAG,GAAG,OAAO,OAAO,IAAI,KAAK,KAAK,sBAAsB;AAChE,WAAO,IAAI,IAAI,GAAG,GAAG,OAAO,MAAM;AAAA,EACnC;AAAA,EAIA,wBAAwB;AACvB,WAAO,KAAK,yBAAyB,IAAI;AAAA,EAC1C;AAAA,EAEQ,yBAAyB;AAChC,UAAM,WAAW,IAAI,eAAe,MAAM;AACzC,YAAM,OAAO,KAAK,uBAAuB;AACzC,WAAK,yBAAyB,IAAI,IAAI;AAAA,IACvC,CAAC;AACD,aAAS,QAAQ,KAAK,IAAI;AAC1B,aAAS,QAAQ,KAAK,SAAS;AAC/B,WAAO,MAAM,SAAS,WAAW;AAAA,EAClC;AAAA,EAGA,gBAAgB;AACf,UAAM,OAAO,KAAK,yBAAyB,IAAI;AAC/C,UAAM,MAAM,KAAK,OAAO;AACxB,WAAO,IAAI,IAAI,KAAK,QAAQ,KAAK,KAAK,SAAS,GAAG;AAAA,EACnD;AAAA,EAGA,0BAA0B;AACzB,WAAO,KAAK,yBAAyB,IAAI,EAAE;AAAA,EAC5C;AAAA,EAQU,sBAAsB;AAC/B,UAAM,qBAAqB,KAAK,sBAAsB;AACtD,UAAM,oBAAoB,KAAK,qBAAqB;AAEpD,UAAM,cAAc,mBAAmB,QAAQ,mBAAmB;AAElE,QAAI,cAAc,kBAAkB;AACpC,QAAI,eAAe,cAAc;AACjC,QAAI,eAAe,kBAAkB,QAAQ;AAC5C,qBAAe,kBAAkB;AACjC,oBAAc,eAAe;AAAA,IAC9B;AAEA,UAAM,MAAM,IAAI,IAAI,GAAG,GAAG,aAAa,YAAY;AACnD,QAAI,SAAS,kBAAkB;AAC/B,WAAO;AAAA,EACR;AAAA,EAEU,UAAU;AACnB,WAAO,KAAK,oBAAoB,EAAE,QAAQ,KAAK,sBAAsB,EAAE;AAAA,EACxE;AAAA,EAEU,2BAA2B;AACpC,UAAM,EAAE,GAAG,GAAG,GAAG,EAAE,IAAI,KAAK,oBAAoB;AAChD,WAAO,IAAI,aAAa,CAAC,GAAG,GAAG,GAAG,CAAC,CAAC;AAAA,EACrC;AAAA,EAEA,oBAAoB,SAAiB,SAAiB;AACrD,UAAM,mBAAmB,KAAK,oBAAoB;AAClD,UAAM,qBAAqB,KAAK,sBAAsB;AAGtD,QAAI,IAAI,UAAU,mBAAmB;AACrC,QAAI,IAAI,UAAU,mBAAmB;AAGrC,SAAK,iBAAiB,QAAQ,mBAAmB;AACjD,SAAK,iBAAiB,SAAS,mBAAmB;AAGlD,SAAK,iBAAiB;AACtB,SAAK,iBAAiB;AAEtB,WAAO,IAAI,IAAI,GAAG,GAAG,CAAC;AAAA,EACvB;AAAA,EAEA,8BAA8B,GAAW,GAAW,WAAW,OAAO,gBAAgB,OAAO;AAC5F,UAAM,EAAE,OAAO,IAAI;AACnB,UAAM,eAAe,OAAO,sBAAsB;AAElD,QAAI,EAAE,GAAG,IAAI,GAAG,GAAG,IAAI,KAAK,oBAAoB,GAAG,CAAC;AAEpD,QAAI,eAAe;AAClB,YAAM,mBAAmB,KAAK,OAAO,qBAAqB,KAAK,IAAI,IAAI;AAEvE,YAAM,OAAO,iBAAiB,OAAO,aAAa,QAAQ;AAC1D,YAAM,OAAO,iBAAiB,OAAO,aAAa,QAAQ;AAC1D,YAAM,OAAO,iBAAiB,OAAO,aAAa,SAAS;AAC3D,YAAM,OAAO,iBAAiB,OAAO,aAAa,SAAS;AAE3D,YAAM,KAAK,KAAK,IAAI,GAAG,OAAO,aAAa,QAAQ,EAAE;AACrD,YAAM,KAAK,KAAK,IAAI,GAAG,EAAE,OAAO,aAAa,QAAQ,GAAG;AACxD,YAAM,KAAK,KAAK,IAAI,GAAG,OAAO,aAAa,SAAS,EAAE;AACtD,YAAM,KAAK,KAAK,IAAI,GAAG,EAAE,OAAO,aAAa,SAAS,GAAG;AAEzD,aAAO,KAAK,MAAM;AAClB,aAAO,KAAK,MAAM;AAElB,WAAK,MAAM,IAAI,MAAM,IAAI;AACzB,WAAK,MAAM,IAAI,MAAM,IAAI;AAAA,IAC1B;AAEA,QAAI,UAAU;AACb,YAAM,EAAE,gBAAgB,IAAI;AAC5B,YAAM,KAAK,KAAK,IAAI,KAAK,gBAAgB,CAAC;AAC1C,YAAM,KAAK,KAAK,IAAI,KAAK,gBAAgB,CAAC;AAC1C,UAAI,KAAK,IAAI;AACZ,aAAK,gBAAgB;AAAA,MACtB,OAAO;AACN,aAAK,gBAAgB;AAAA,MACtB;AAAA,IACD;AAEA,WAAO,IAAI,IAAI,IAAI,EAAE;AAAA,EACtB;AAAA,EAGA,SAAS;AAER,UAAM,UAAU,KAAK,GAAG;AACxB,UAAM,aAAa,KAAK,cAAc;AAEtC,SAAK,GAAG,oBAAoB,KAAK,yBAAyB,CAAC;AAE3D,SAAK,KAAK,QAAQ,WAAW;AAC7B,SAAK,KAAK,SAAS,WAAW;AAC9B,YAAQ,SAAS,GAAG,GAAG,WAAW,GAAG,WAAW,CAAC;AAMjD,YAAQ;AAAA,MACP,KAAK,OAAO,WAAW,CAAC;AAAA,MACxB,KAAK,OAAO,WAAW,CAAC;AAAA,MACxB,KAAK,OAAO,WAAW,CAAC;AAAA,MACxB;AAAA,IACD;AAEA,YAAQ,MAAM,QAAQ,gBAAgB;AAEtC,UAAM,iBAAiB,IAAI,IAAI,KAAK,OAAO,oBAAoB,CAAC;AAEhE,UAAM,SAAS,KAAK;AACpB,QAAI,sBAAsB;AAC1B,QAAI,wBAAwB;AAE5B,UAAM,MAAM,KAAK,OAAO,6BAA6B;AAErD,aAAS,IAAI,GAAG,MAAM,IAAI,QAAQ,IAAI,KAAK,KAAK;AAC/C,YAAM,UAAU,IAAI,CAAC;AACrB,YAAM,WAAW,KAAK,mBAAmB,IAAI,OAAO;AACpD,UAAI,CAAC,SAAU;AAEf,YAAMA,OAAM,SAAS;AAErB,UAAI,eAAe,IAAI,OAAO,GAAG;AAChC,uBAAe,KAAK,GAAG,gBAAgB,qBAAqB,QAAQ;AACpE,+BAAuBA;AAAA,MACxB,OAAO;AACN,uBAAe,KAAK,GAAG,kBAAkB,uBAAuB,QAAQ;AACxE,iCAAyBA;AAAA,MAC1B;AAAA,IACD;AAEA,SAAK,WAAW,KAAK,GAAG,kBAAkB,uBAAuB,OAAO,SAAS;AACjF,SAAK,WAAW,KAAK,GAAG,gBAAgB,qBAAqB,OAAO,UAAU;AAE9E,SAAK,aAAa;AAClB,SAAK,kBAAkB;AAAA,EACxB;AAAA,EAEQ,WAAW,OAAoB,KAAa,OAAqB;AACxE,SAAK,GAAG,iBAAiB,OAAO,GAAG;AACnC,SAAK,GAAG,aAAa,KAAK;AAC1B,SAAK,GAAG,cAAc,GAAG;AAAA,EAC1B;AAAA,EAEQ,eAAe;AACtB,UAAM,WAAW,KAAK,OAAO,sBAAsB;AACnD,UAAM,MAAM,iBAAiB,KAAK,GAAG,SAAS,UAAU,UAAU,IAAI,KAAK,QAAQ,CAAC;AAEpF,SAAK,GAAG,iBAAiB,KAAK,GAAG,UAAU,GAAG;AAC9C,SAAK,GAAG,aAAa,KAAK,OAAO,YAAY;AAC7C,SAAK,GAAG,2BAA2B,GAAG;AACtC,QAAI,MAAM,UAAU;AACnB,WAAK,GAAG,2BAA2B,GAAG;AACtC,WAAK,GAAG,2BAA2B,GAAG;AACtC,WAAK,GAAG,2BAA2B,GAAG;AAAA,IACvC;AAAA,EACD;AAAA,EAEA,oBAAoB;AACnB,UAAM,gBAAgB,KAAK,OAAO,8BAA8B;AAChE,QAAI,CAAC,cAAc,OAAQ;AAG3B,UAAM,uBAAuB;AAC7B,UAAM,oBAAoB,uBAAuB;AACjD,UAAM,YAAY,oBAAoB,cAAc;AAGpD,QAAI,KAAK,GAAG,cAAc,SAAS,SAAS,WAAW;AACtD,WAAK,GAAG,cAAc,WAAW,IAAI,aAAa,SAAS;AAAA,IAC5D;AAEA,UAAM,WAAW,KAAK,GAAG,cAAc;AACvC,QAAI,SAAS;AACb,UAAM,OAAO,KAAK,QAAQ;AAC1B,eAAW,EAAE,OAAO,KAAK,eAAe;AACvC,UAAI,CAAC,OAAQ;AACb,UAAI,UAAU;AAAA,QACb,QAAQ,IAAI,KAAK,MAAM;AAAA,QACvB,QAAQ,IAAI;AAAA,QACZ;AAAA,QACA,gBAAgB;AAAA,MACjB,CAAC;AACD,gBAAU;AAAA,IACX;AAEA,SAAK,GAAG,iBAAiB,KAAK,GAAG,eAAe,SAAS;AAEzD,aAAS;AACT,eAAW,EAAE,MAAM,KAAK,eAAe;AACtC,WAAK,GAAG,aAAa,QAAQ,KAAK,CAAC;AACnC,WAAK,GAAG,QAAQ,WAAW,KAAK,GAAG,QAAQ,WAAW,SAAS,GAAG,oBAAoB,CAAC;AACvF,gBAAU;AAAA,IACX;AAAA,EACD;AACD;AAlTO;AAIN,qCADA,YAHY;AA6CZ,sCADA,aA5CY;AAkDZ,oDADA,2BAjDY;AA2DZ,sDADA,6BA1DY;AA0FZ,6CADA,oBAzFY;AAiGZ,uDADA,8BAhGY;AA2GF,mDAAV,0BA3GY;AA6HF,uCAAV,cA7HY;AAiIF,wDAAV,+BAjIY;AAkMZ,sCADA,aAjMY;AAAN,2BAAM;",
4
+ "sourcesContent": ["import {\n\tBox,\n\tComputedCache,\n\tEditor,\n\tTLShape,\n\tVec,\n\tatom,\n\tbind,\n\tclamp,\n\tcomputed,\n\treact,\n\ttlenv,\n\tuniqueId,\n} from '@tldraw/editor'\nimport { getRgba } from './getRgba'\nimport { BufferStuff, appendVertices, setupWebGl } from './minimap-webgl-setup'\nimport { pie, rectangle, roundedRectangle } from './minimap-webgl-shapes'\n\nexport class MinimapManager {\n\tdisposables = [] as (() => void)[]\n\n\t@bind\n\tclose() {\n\t\treturn this.disposables.forEach((d) => d())\n\t}\n\tgl: ReturnType<typeof setupWebGl>\n\tshapeGeometryCache: ComputedCache<Float32Array | null, TLShape>\n\tconstructor(\n\t\tpublic editor: Editor,\n\t\tpublic readonly elem: HTMLCanvasElement,\n\t\tpublic readonly container: HTMLElement\n\t) {\n\t\tthis.gl = setupWebGl(elem)\n\t\tthis.shapeGeometryCache = editor.store.createComputedCache('webgl-geometry', (r: TLShape) => {\n\t\t\tconst bounds = editor.getShapeMaskedPageBounds(r.id)\n\t\t\tif (!bounds) return null\n\t\t\tconst arr = new Float32Array(12)\n\t\t\trectangle(arr, 0, bounds.x, bounds.y, bounds.w, bounds.h)\n\t\t\treturn arr\n\t\t})\n\t\tthis.colors = this._getColors()\n\t\tthis.disposables.push(this._listenForCanvasResize(), react('minimap render', this.render))\n\t}\n\n\tprivate _getColors() {\n\t\tconst style = getComputedStyle(this.editor.getContainer())\n\n\t\treturn {\n\t\t\tshapeFill: getRgba(style.getPropertyValue('--tl-color-text-3').trim()),\n\t\t\tselectFill: getRgba(style.getPropertyValue('--tl-color-selected').trim()),\n\t\t\tviewportFill: getRgba(style.getPropertyValue('--tl-color-muted-1').trim()),\n\t\t\tbackground: getRgba(style.getPropertyValue('--tl-color-low').trim()),\n\t\t}\n\t}\n\n\tprivate colors: ReturnType<MinimapManager['_getColors']>\n\t// this should be called after dark/light mode changes have propagated to the dom\n\tupdateColors() {\n\t\tthis.colors = this._getColors()\n\t}\n\n\treadonly id = uniqueId()\n\t@computed\n\tgetDpr() {\n\t\treturn this.editor.getInstanceState().devicePixelRatio\n\t}\n\n\t@computed\n\tgetContentPageBounds() {\n\t\tconst viewportPageBounds = this.editor.getViewportPageBounds()\n\t\tconst commonShapeBounds = this.editor.getCurrentPageBounds()\n\t\treturn commonShapeBounds\n\t\t\t? Box.Expand(commonShapeBounds, viewportPageBounds)\n\t\t\t: viewportPageBounds\n\t}\n\n\t@computed\n\tgetContentScreenBounds() {\n\t\tconst contentPageBounds = this.getContentPageBounds()\n\t\tconst topLeft = this.editor.pageToScreen(contentPageBounds.point)\n\t\tconst bottomRight = this.editor.pageToScreen(\n\t\t\tnew Vec(contentPageBounds.maxX, contentPageBounds.maxY)\n\t\t)\n\t\treturn new Box(topLeft.x, topLeft.y, bottomRight.x - topLeft.x, bottomRight.y - topLeft.y)\n\t}\n\n\tprivate _getCanvasBoundingRect() {\n\t\tconst { x, y, width, height } = this.elem.getBoundingClientRect()\n\t\treturn new Box(x, y, width, height)\n\t}\n\n\tprivate readonly canvasBoundingClientRect = atom('canvasBoundingClientRect', new Box())\n\n\tgetCanvasScreenBounds() {\n\t\treturn this.canvasBoundingClientRect.get()\n\t}\n\n\tprivate _listenForCanvasResize() {\n\t\tconst observer = new ResizeObserver(() => {\n\t\t\tconst rect = this._getCanvasBoundingRect()\n\t\t\tthis.canvasBoundingClientRect.set(rect)\n\t\t})\n\t\tobserver.observe(this.elem)\n\t\tobserver.observe(this.container)\n\t\treturn () => observer.disconnect()\n\t}\n\n\t@computed\n\tgetCanvasSize() {\n\t\tconst rect = this.canvasBoundingClientRect.get()\n\t\tconst dpr = this.getDpr()\n\t\treturn new Vec(rect.width * dpr, rect.height * dpr)\n\t}\n\n\t@computed\n\tgetCanvasClientPosition() {\n\t\treturn this.canvasBoundingClientRect.get().point\n\t}\n\n\toriginPagePoint = new Vec()\n\toriginPageCenter = new Vec()\n\n\tisInViewport = false\n\n\t/** Get the canvas's true bounds converted to page bounds. */\n\t@computed getCanvasPageBounds() {\n\t\tconst canvasScreenBounds = this.getCanvasScreenBounds()\n\t\tconst contentPageBounds = this.getContentPageBounds()\n\n\t\tconst aspectRatio = canvasScreenBounds.width / canvasScreenBounds.height\n\n\t\tlet targetWidth = contentPageBounds.width\n\t\tlet targetHeight = targetWidth / aspectRatio\n\t\tif (targetHeight < contentPageBounds.height) {\n\t\t\ttargetHeight = contentPageBounds.height\n\t\t\ttargetWidth = targetHeight * aspectRatio\n\t\t}\n\n\t\tconst box = new Box(0, 0, targetWidth, targetHeight)\n\t\tbox.center = contentPageBounds.center\n\t\treturn box\n\t}\n\n\t@computed getZoom() {\n\t\treturn this.getCanvasPageBounds().width / this.getCanvasScreenBounds().width\n\t}\n\n\t@computed getCanvasPageBoundsArray() {\n\t\tconst { x, y, w, h } = this.getCanvasPageBounds()\n\t\treturn new Float32Array([x, y, w, h])\n\t}\n\n\tgetMinimapPagePoint(clientX: number, clientY: number) {\n\t\tconst canvasPageBounds = this.getCanvasPageBounds()\n\t\tconst canvasScreenBounds = this.getCanvasScreenBounds()\n\n\t\t// first offset the canvas position\n\t\tlet x = clientX - canvasScreenBounds.x\n\t\tlet y = clientY - canvasScreenBounds.y\n\n\t\t// then multiply by the ratio between the page and screen bounds\n\t\tx *= canvasPageBounds.width / canvasScreenBounds.width\n\t\ty *= canvasPageBounds.height / canvasScreenBounds.height\n\n\t\t// then add the canvas page bounds' offset\n\t\tx += canvasPageBounds.minX\n\t\ty += canvasPageBounds.minY\n\n\t\treturn new Vec(x, y, 1)\n\t}\n\n\tminimapScreenPointToPagePoint(x: number, y: number, shiftKey = false, clampToBounds = false) {\n\t\tconst { editor } = this\n\t\tconst vpPageBounds = editor.getViewportPageBounds()\n\n\t\tlet { x: px, y: py } = this.getMinimapPagePoint(x, y)\n\n\t\tif (clampToBounds) {\n\t\t\tconst shapesPageBounds = this.editor.getCurrentPageBounds() ?? new Box()\n\n\t\t\tconst minX = shapesPageBounds.minX - vpPageBounds.width / 2\n\t\t\tconst maxX = shapesPageBounds.maxX + vpPageBounds.width / 2\n\t\t\tconst minY = shapesPageBounds.minY - vpPageBounds.height / 2\n\t\t\tconst maxY = shapesPageBounds.maxY + vpPageBounds.height / 2\n\n\t\t\tconst lx = Math.max(0, minX + vpPageBounds.width - px)\n\t\t\tconst rx = Math.max(0, -(maxX - vpPageBounds.width - px))\n\t\t\tconst ly = Math.max(0, minY + vpPageBounds.height - py)\n\t\t\tconst ry = Math.max(0, -(maxY - vpPageBounds.height - py))\n\n\t\t\tpx += (lx - rx) / 2\n\t\t\tpy += (ly - ry) / 2\n\n\t\t\tpx = clamp(px, minX, maxX)\n\t\t\tpy = clamp(py, minY, maxY)\n\t\t}\n\n\t\tif (shiftKey) {\n\t\t\tconst { originPagePoint } = this\n\t\t\tconst dx = Math.abs(px - originPagePoint.x)\n\t\t\tconst dy = Math.abs(py - originPagePoint.y)\n\t\t\tif (dx > dy) {\n\t\t\t\tpy = originPagePoint.y\n\t\t\t} else {\n\t\t\t\tpx = originPagePoint.x\n\t\t\t}\n\t\t}\n\n\t\treturn new Vec(px, py)\n\t}\n\n\t@bind\n\trender() {\n\t\t// make sure we update when dark mode switches\n\t\tconst context = this.gl.context\n\t\tconst canvasSize = this.getCanvasSize()\n\n\t\tthis.gl.setCanvasPageBounds(this.getCanvasPageBoundsArray())\n\n\t\tthis.elem.width = canvasSize.x\n\t\tthis.elem.height = canvasSize.y\n\t\tcontext.viewport(0, 0, canvasSize.x, canvasSize.y)\n\n\t\t// this affects which color transparent shapes are blended with\n\t\t// during rendering. If we were to invert this any shapes narrower\n\t\t// than 1 px in screen space would have much lower contrast. e.g.\n\t\t// draw shapes on a large canvas.\n\t\tcontext.clearColor(\n\t\t\tthis.colors.background[0],\n\t\t\tthis.colors.background[1],\n\t\t\tthis.colors.background[2],\n\t\t\t1\n\t\t)\n\n\t\tcontext.clear(context.COLOR_BUFFER_BIT)\n\n\t\tconst selectedShapes = new Set(this.editor.getSelectedShapeIds())\n\n\t\tconst colors = this.colors\n\t\tlet selectedShapeOffset = 0\n\t\tlet unselectedShapeOffset = 0\n\n\t\tconst ids = this.editor.getCurrentPageShapeIdsSorted()\n\n\t\tfor (let i = 0, len = ids.length; i < len; i++) {\n\t\t\tconst shapeId = ids[i]\n\t\t\tconst geometry = this.shapeGeometryCache.get(shapeId)\n\t\t\tif (!geometry) continue\n\n\t\t\tconst len = geometry.length\n\n\t\t\tconst shape = this.editor.getShape(shapeId)\n\t\t\tif (shape) {\n\t\t\t\tconst shapeUtil = this.editor.getShapeUtil(shape.type)\n\t\t\t\tif (shapeUtil.hideInMinimap?.(shape)) continue\n\t\t\t}\n\n\t\t\tif (selectedShapes.has(shapeId)) {\n\t\t\t\tappendVertices(this.gl.selectedShapes, selectedShapeOffset, geometry)\n\t\t\t\tselectedShapeOffset += len\n\t\t\t} else {\n\t\t\t\tappendVertices(this.gl.unselectedShapes, unselectedShapeOffset, geometry)\n\t\t\t\tunselectedShapeOffset += len\n\t\t\t}\n\t\t}\n\n\t\tthis.drawShapes(this.gl.unselectedShapes, unselectedShapeOffset, colors.shapeFill)\n\t\tthis.drawShapes(this.gl.selectedShapes, selectedShapeOffset, colors.selectFill)\n\n\t\tthis.drawViewport()\n\t\tthis.drawCollaborators()\n\t}\n\n\tprivate drawShapes(stuff: BufferStuff, len: number, color: Float32Array) {\n\t\tthis.gl.prepareTriangles(stuff, len)\n\t\tthis.gl.setFillColor(color)\n\t\tthis.gl.drawTriangles(len)\n\t}\n\n\tprivate drawViewport() {\n\t\tconst viewport = this.editor.getViewportPageBounds()\n\t\tconst len = roundedRectangle(this.gl.viewport.vertices, viewport, 4 * this.getZoom())\n\n\t\tthis.gl.prepareTriangles(this.gl.viewport, len)\n\t\tthis.gl.setFillColor(this.colors.viewportFill)\n\t\tthis.gl.drawTrianglesTransparently(len)\n\t\tif (tlenv.isSafari) {\n\t\t\tthis.gl.drawTrianglesTransparently(len)\n\t\t\tthis.gl.drawTrianglesTransparently(len)\n\t\t\tthis.gl.drawTrianglesTransparently(len)\n\t\t}\n\t}\n\n\tdrawCollaborators() {\n\t\tconst collaborators = this.editor.getCollaboratorsOnCurrentPage()\n\t\tif (!collaborators.length) return\n\n\t\t// just draw a little circle for each collaborator\n\t\tconst numSegmentsPerCircle = 20\n\t\tconst dataSizePerCircle = numSegmentsPerCircle * 6\n\t\tconst totalSize = dataSizePerCircle * collaborators.length\n\n\t\t// expand vertex array if needed\n\t\tif (this.gl.collaborators.vertices.length < totalSize) {\n\t\t\tthis.gl.collaborators.vertices = new Float32Array(totalSize)\n\t\t}\n\n\t\tconst vertices = this.gl.collaborators.vertices\n\t\tlet offset = 0\n\t\tconst zoom = this.getZoom()\n\t\tfor (const { cursor } of collaborators) {\n\t\t\tif (!cursor) continue\n\t\t\tpie(vertices, {\n\t\t\t\tcenter: Vec.From(cursor),\n\t\t\t\tradius: 3 * zoom,\n\t\t\t\toffset,\n\t\t\t\tnumArcSegments: numSegmentsPerCircle,\n\t\t\t})\n\t\t\toffset += dataSizePerCircle\n\t\t}\n\n\t\tthis.gl.prepareTriangles(this.gl.collaborators, totalSize)\n\n\t\toffset = 0\n\t\tfor (const { color } of collaborators) {\n\t\t\tthis.gl.setFillColor(getRgba(color))\n\t\t\tthis.gl.context.drawArrays(this.gl.context.TRIANGLES, offset / 2, dataSizePerCircle / 2)\n\t\t\toffset += dataSizePerCircle\n\t\t}\n\t}\n}\n"],
5
+ "mappings": "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",
6
6
  "names": ["len"]
7
7
  }
@@ -1,8 +1,8 @@
1
- const version = "4.1.0-canary.e4499a57ef5b";
1
+ const version = "4.1.0-canary.f414ee471d7f";
2
2
  const publishDates = {
3
3
  major: "2025-09-18T14:39:22.803Z",
4
- minor: "2025-09-19T11:41:15.460Z",
5
- patch: "2025-09-19T11:41:15.460Z"
4
+ minor: "2025-10-03T22:03:43.737Z",
5
+ patch: "2025-10-03T22:03:43.737Z"
6
6
  };
7
7
  export {
8
8
  publishDates,
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../../src/lib/ui/version.ts"],
4
- "sourcesContent": ["// This file is automatically generated by internal/scripts/refresh-assets.ts.\n// Do not edit manually. Or do, I'm a comment, not a cop.\n\nexport const version = '4.1.0-canary.e4499a57ef5b'\nexport const publishDates = {\n\tmajor: '2025-09-18T14:39:22.803Z',\n\tminor: '2025-09-19T11:41:15.460Z',\n\tpatch: '2025-09-19T11:41:15.460Z',\n}\n"],
4
+ "sourcesContent": ["// This file is automatically generated by internal/scripts/refresh-assets.ts.\n// Do not edit manually. Or do, I'm a comment, not a cop.\n\nexport const version = '4.1.0-canary.f414ee471d7f'\nexport const publishDates = {\n\tmajor: '2025-09-18T14:39:22.803Z',\n\tminor: '2025-10-03T22:03:43.737Z',\n\tpatch: '2025-10-03T22:03:43.737Z',\n}\n"],
5
5
  "mappings": "AAGO,MAAM,UAAU;AAChB,MAAM,eAAe;AAAA,EAC3B,OAAO;AAAA,EACP,OAAO;AAAA,EACP,OAAO;AACR;",
6
6
  "names": []
7
7
  }
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "tldraw",
3
3
  "description": "A tiny little drawing editor.",
4
- "version": "4.1.0-canary.e4499a57ef5b",
4
+ "version": "4.1.0-canary.f414ee471d7f",
5
5
  "author": {
6
6
  "name": "tldraw Inc.",
7
7
  "email": "hello@tldraw.com"
@@ -26,6 +26,13 @@
26
26
  "infinite"
27
27
  ],
28
28
  "main": "dist-cjs/index.js",
29
+ "exports": {
30
+ ".": {
31
+ "import": "./dist-esm/index.mjs",
32
+ "require": "./dist-cjs/index.js"
33
+ },
34
+ "./tldraw.css": "./tldraw.css"
35
+ },
29
36
  "scripts": {
30
37
  "test-ci": "yarn run -T vitest run --passWithNoTests",
31
38
  "test": "yarn run -T vitest --passWithNoTests",
@@ -55,8 +62,8 @@
55
62
  "@tiptap/pm": "^2.9.1",
56
63
  "@tiptap/react": "^2.9.1",
57
64
  "@tiptap/starter-kit": "^2.9.1",
58
- "@tldraw/editor": "4.1.0-canary.e4499a57ef5b",
59
- "@tldraw/store": "4.1.0-canary.e4499a57ef5b",
65
+ "@tldraw/editor": "4.1.0-canary.f414ee471d7f",
66
+ "@tldraw/store": "4.1.0-canary.f414ee471d7f",
60
67
  "classnames": "^2.5.1",
61
68
  "hotkeys-js": "^3.13.9",
62
69
  "idb": "^7.1.1",
@@ -81,12 +88,5 @@
81
88
  "vitest": "^3.2.4"
82
89
  },
83
90
  "module": "dist-esm/index.mjs",
84
- "source": "src/index.ts",
85
- "exports": {
86
- ".": {
87
- "import": "./dist-esm/index.mjs",
88
- "require": "./dist-cjs/index.js"
89
- },
90
- "./tldraw.css": "./tldraw.css"
91
- }
91
+ "source": "src/index.ts"
92
92
  }
@@ -35,6 +35,7 @@ export const DEFAULT_EMBED_DEFINITIONS = [
35
35
  }
36
36
  return
37
37
  },
38
+ embedOnPaste: false,
38
39
  },
39
40
  {
40
41
  type: 'figma',
@@ -65,6 +66,7 @@ export const DEFAULT_EMBED_DEFINITIONS = [
65
66
  }
66
67
  return
67
68
  },
69
+ embedOnPaste: true,
68
70
  },
69
71
  {
70
72
  type: 'google_maps',
@@ -116,6 +118,7 @@ export const DEFAULT_EMBED_DEFINITIONS = [
116
118
  }
117
119
  return
118
120
  },
121
+ embedOnPaste: true,
119
122
  },
120
123
  {
121
124
  type: 'val_town',
@@ -144,6 +147,7 @@ export const DEFAULT_EMBED_DEFINITIONS = [
144
147
  }
145
148
  return
146
149
  },
150
+ embedOnPaste: true,
147
151
  },
148
152
  {
149
153
  type: 'codesandbox',
@@ -170,6 +174,7 @@ export const DEFAULT_EMBED_DEFINITIONS = [
170
174
  }
171
175
  return
172
176
  },
177
+ embedOnPaste: true,
173
178
  },
174
179
  {
175
180
  type: 'codepen',
@@ -198,6 +203,7 @@ export const DEFAULT_EMBED_DEFINITIONS = [
198
203
  }
199
204
  return
200
205
  },
206
+ embedOnPaste: true,
201
207
  },
202
208
  {
203
209
  type: 'scratch',
@@ -206,6 +212,7 @@ export const DEFAULT_EMBED_DEFINITIONS = [
206
212
  width: 520,
207
213
  height: 400,
208
214
  doesResize: false,
215
+ embedOnPaste: true,
209
216
  toEmbedUrl: (url) => {
210
217
  const SCRATCH_URL_REGEXP = /https?:\/\/scratch.mit.edu\/projects\/([^/]+)/
211
218
  const matches = url.match(SCRATCH_URL_REGEXP)
@@ -237,6 +244,7 @@ export const DEFAULT_EMBED_DEFINITIONS = [
237
244
  'allow-popups-to-escape-sandbox': true,
238
245
  },
239
246
  isAspectRatioLocked: true,
247
+ embedOnPaste: true,
240
248
  toEmbedUrl: (url) => {
241
249
  const urlObj = safeParseUrl(url)
242
250
  if (!urlObj) return
@@ -303,6 +311,7 @@ export const DEFAULT_EMBED_DEFINITIONS = [
303
311
  overridePermissions: {
304
312
  'allow-popups-to-escape-sandbox': true,
305
313
  },
314
+ embedOnPaste: true,
306
315
  toEmbedUrl: (url) => {
307
316
  const urlObj = safeParseUrl(url)
308
317
  const cidQs = urlObj?.searchParams.get('cid')
@@ -347,6 +356,7 @@ export const DEFAULT_EMBED_DEFINITIONS = [
347
356
  overridePermissions: {
348
357
  'allow-popups-to-escape-sandbox': true,
349
358
  },
359
+ embedOnPaste: true,
350
360
  toEmbedUrl: (url) => {
351
361
  const urlObj = safeParseUrl(url)
352
362
 
@@ -381,6 +391,7 @@ export const DEFAULT_EMBED_DEFINITIONS = [
381
391
  width: 720,
382
392
  height: 500,
383
393
  doesResize: true,
394
+ embedOnPaste: true,
384
395
  // Security warning:
385
396
  // Gists allow adding .json extensions to the URL which return JSONP.
386
397
  // Furthermore, the JSONP can include callbacks that execute arbitrary JavaScript.
@@ -413,6 +424,7 @@ export const DEFAULT_EMBED_DEFINITIONS = [
413
424
  width: 720,
414
425
  height: 500,
415
426
  doesResize: true,
427
+ embedOnPaste: true,
416
428
  toEmbedUrl: (url) => {
417
429
  const urlObj = safeParseUrl(url)
418
430
  if (urlObj && urlObj.pathname.match(/\/@([^/]+)\/([^/]+)/)) {
@@ -440,6 +452,7 @@ export const DEFAULT_EMBED_DEFINITIONS = [
440
452
  width: 720,
441
453
  height: 500,
442
454
  doesResize: true,
455
+ embedOnPaste: true,
443
456
  toEmbedUrl: (url) => {
444
457
  const urlObj = safeParseUrl(url)
445
458
  if (urlObj && urlObj.pathname.match(/^\/map\//)) {
@@ -465,6 +478,7 @@ export const DEFAULT_EMBED_DEFINITIONS = [
465
478
  minHeight: 500,
466
479
  overrideOutlineRadius: 12,
467
480
  doesResize: true,
481
+ embedOnPaste: true,
468
482
  toEmbedUrl: (url) => {
469
483
  const urlObj = safeParseUrl(url)
470
484
  if (urlObj && urlObj.pathname.match(/^\/(artist|album)\//)) {
@@ -488,6 +502,7 @@ export const DEFAULT_EMBED_DEFINITIONS = [
488
502
  height: 360,
489
503
  doesResize: true,
490
504
  isAspectRatioLocked: true,
505
+ embedOnPaste: true,
491
506
  toEmbedUrl: (url) => {
492
507
  const urlObj = safeParseUrl(url)
493
508
  if (urlObj && urlObj.hostname === 'vimeo.com') {
@@ -518,6 +533,7 @@ export const DEFAULT_EMBED_DEFINITIONS = [
518
533
  height: 500,
519
534
  doesResize: true,
520
535
  isAspectRatioLocked: true,
536
+ embedOnPaste: true,
521
537
  toEmbedUrl: (url) => {
522
538
  const urlObj = safeParseUrl(url)
523
539
  if (urlObj && urlObj.hash.match(/#room=/)) {
@@ -542,6 +558,7 @@ export const DEFAULT_EMBED_DEFINITIONS = [
542
558
  doesResize: true,
543
559
  isAspectRatioLocked: false,
544
560
  backgroundColor: '#fff',
561
+ embedOnPaste: true,
545
562
  toEmbedUrl: (url) => {
546
563
  const urlObj = safeParseUrl(url)
547
564
  if (urlObj && urlObj.pathname.match(/^\/@([^/]+)\/([^/]+)\/?$/)) {
@@ -573,6 +590,7 @@ export const DEFAULT_EMBED_DEFINITIONS = [
573
590
  width: 700,
574
591
  height: 450,
575
592
  doesResize: true,
593
+ embedOnPaste: true,
576
594
  toEmbedUrl: (url) => {
577
595
  const urlObj = safeParseUrl(url)
578
596
  if (
@@ -673,6 +691,7 @@ export interface EmbedDefinition {
673
691
  readonly overridePermissions?: TLEmbedShapePermissions
674
692
  readonly instructionLink?: string
675
693
  readonly backgroundColor?: string
694
+ readonly embedOnPaste?: boolean
676
695
  // TODO: FIXME this is ugly be required because some embeds have their own border radius for example spotify embeds
677
696
  readonly overrideOutlineRadius?: number
678
697
  // eslint-disable-next-line @typescript-eslint/method-signature-style
@@ -382,7 +382,7 @@ export async function defaultHandleExternalFileContent(
382
382
  ) {
383
383
  const { acceptedImageMimeTypes = DEFAULT_SUPPORTED_IMAGE_TYPES, toasts, msg } = options
384
384
  if (files.length > editor.options.maxFilesAtOnce) {
385
- toasts.addToast({ title: msg('assets.files.amount-too-big'), severity: 'error' })
385
+ toasts.addToast({ title: msg('assets.files.amount-too-many'), severity: 'error' })
386
386
  return
387
387
  }
388
388
 
@@ -557,7 +557,7 @@ export async function defaultHandleExternalUrlContent(
557
557
  const embedUtil = editor.getShapeUtil('embed') as EmbedShapeUtil | undefined
558
558
  const embedInfo = embedUtil?.getEmbedDefinition(url)
559
559
 
560
- if (embedInfo) {
560
+ if (embedInfo && embedInfo.definition.embedOnPaste) {
561
561
  return editor.putExternalContent({
562
562
  type: 'embed',
563
563
  url: embedInfo.url,
@@ -1,7 +1,7 @@
1
1
  import { HALF_PI, TLArrowShape, TLShapeId, createShapeId, toRichText } from '@tldraw/editor'
2
2
  import { vi } from 'vitest'
3
3
  import { TestEditor } from '../../../test/TestEditor'
4
- import { createOrUpdateArrowBinding, getArrowBindings } from './shared'
4
+ import { createOrUpdateArrowBinding, getArrowBindings, getArrowInfo } from './shared'
5
5
 
6
6
  let editor: TestEditor
7
7
 
@@ -620,3 +620,213 @@ describe('Arrow export bounds', () => {
620
620
  expect(arrow.props.richText).not.toBeNull()
621
621
  })
622
622
  })
623
+
624
+ describe('Arrow terminal positioning bug fix', () => {
625
+ const data = {
626
+ document: {
627
+ store: {
628
+ 'shape:1Hm61DGAsY0uqEO-kt75l': {
629
+ x: 637.2890625,
630
+ y: 383.9296875,
631
+ rotation: 0,
632
+ isLocked: false,
633
+ opacity: 1,
634
+ meta: {},
635
+ id: 'shape:1Hm61DGAsY0uqEO-kt75l',
636
+ type: 'geo',
637
+ props: {
638
+ w: 230.66796875,
639
+ h: 114.796875,
640
+ geo: 'rectangle',
641
+ dash: 'draw',
642
+ growY: 0,
643
+ url: '',
644
+ scale: 1,
645
+ color: 'black',
646
+ labelColor: 'black',
647
+ fill: 'none',
648
+ size: 'm',
649
+ font: 'draw',
650
+ align: 'middle',
651
+ verticalAlign: 'middle',
652
+ richText: {
653
+ type: 'doc',
654
+ content: [
655
+ {
656
+ type: 'paragraph',
657
+ },
658
+ ],
659
+ },
660
+ },
661
+ parentId: 'page:page',
662
+ index: 'a1',
663
+ typeName: 'shape',
664
+ },
665
+ 'binding:nekxhMCGaoEJO98DEqWgo': {
666
+ meta: {},
667
+ id: 'binding:nekxhMCGaoEJO98DEqWgo',
668
+ type: 'arrow',
669
+ fromId: 'shape:j0HKQihjBXqMqgVhfRhDS',
670
+ toId: 'shape:1Hm61DGAsY0uqEO-kt75l',
671
+ props: {
672
+ isPrecise: true,
673
+ isExact: false,
674
+ normalizedAnchor: {
675
+ x: 0.13182672605036325,
676
+ y: 0.8036953858717844,
677
+ },
678
+ snap: 'none',
679
+ terminal: 'start',
680
+ },
681
+ typeName: 'binding',
682
+ },
683
+ 'binding:kWamalL_QSq_kFPZDgp7Z': {
684
+ meta: {},
685
+ id: 'binding:kWamalL_QSq_kFPZDgp7Z',
686
+ type: 'arrow',
687
+ fromId: 'shape:j0HKQihjBXqMqgVhfRhDS',
688
+ toId: 'shape:1Hm61DGAsY0uqEO-kt75l',
689
+ props: {
690
+ isPrecise: true,
691
+ isExact: false,
692
+ normalizedAnchor: {
693
+ x: 0.7138744475114731,
694
+ y: 0.45797604464407243,
695
+ },
696
+ snap: 'none',
697
+ terminal: 'end',
698
+ },
699
+ typeName: 'binding',
700
+ },
701
+ 'shape:j0HKQihjBXqMqgVhfRhDS': {
702
+ x: 665.296875,
703
+ y: 477.59765625,
704
+ rotation: 0,
705
+ isLocked: false,
706
+ opacity: 1,
707
+ meta: {},
708
+ id: 'shape:j0HKQihjBXqMqgVhfRhDS',
709
+ type: 'arrow',
710
+ props: {
711
+ kind: 'arc',
712
+ elbowMidPoint: 0.5,
713
+ dash: 'draw',
714
+ size: 'm',
715
+ fill: 'none',
716
+ color: 'black',
717
+ labelColor: 'black',
718
+ bend: 0,
719
+ start: {
720
+ x: 0,
721
+ y: 0,
722
+ },
723
+ end: {
724
+ x: 2,
725
+ y: 0,
726
+ },
727
+ arrowheadStart: 'none',
728
+ arrowheadEnd: 'arrow',
729
+ richText: {
730
+ type: 'doc',
731
+ content: [
732
+ {
733
+ type: 'paragraph',
734
+ },
735
+ ],
736
+ },
737
+ labelPosition: 0.5,
738
+ font: 'draw',
739
+ scale: 1,
740
+ },
741
+ parentId: 'page:page',
742
+ index: 'a2lbpzZG',
743
+ typeName: 'shape',
744
+ },
745
+ 'page:page': {
746
+ meta: {},
747
+ id: 'page:page',
748
+ name: 'Page 1',
749
+ index: 'a1',
750
+ typeName: 'page',
751
+ },
752
+ 'document:document': {
753
+ gridSize: 10,
754
+ name: '',
755
+ meta: {},
756
+ id: 'document:document',
757
+ typeName: 'document',
758
+ },
759
+ },
760
+ schema: {
761
+ schemaVersion: 2,
762
+ sequences: {
763
+ 'com.tldraw.store': 5,
764
+ 'com.tldraw.asset': 1,
765
+ 'com.tldraw.camera': 1,
766
+ 'com.tldraw.document': 2,
767
+ 'com.tldraw.instance': 25,
768
+ 'com.tldraw.instance_page_state': 5,
769
+ 'com.tldraw.page': 1,
770
+ 'com.tldraw.instance_presence': 6,
771
+ 'com.tldraw.pointer': 1,
772
+ 'com.tldraw.shape': 4,
773
+ 'com.tldraw.asset.bookmark': 2,
774
+ 'com.tldraw.asset.image': 5,
775
+ 'com.tldraw.asset.video': 5,
776
+ 'com.tldraw.shape.group': 0,
777
+ 'com.tldraw.shape.text': 3,
778
+ 'com.tldraw.shape.bookmark': 2,
779
+ 'com.tldraw.shape.draw': 2,
780
+ 'com.tldraw.shape.geo': 10,
781
+ 'com.tldraw.shape.note': 9,
782
+ 'com.tldraw.shape.line': 5,
783
+ 'com.tldraw.shape.frame': 1,
784
+ 'com.tldraw.shape.arrow': 7,
785
+ 'com.tldraw.shape.highlight': 1,
786
+ 'com.tldraw.shape.embed': 4,
787
+ 'com.tldraw.shape.image': 5,
788
+ 'com.tldraw.shape.video': 4,
789
+ 'com.tldraw.binding.arrow': 1,
790
+ },
791
+ },
792
+ },
793
+ session: {
794
+ version: 0,
795
+ currentPageId: 'page:page',
796
+ exportBackground: true,
797
+ isFocusMode: false,
798
+ isDebugMode: false,
799
+ isToolLocked: false,
800
+ isGridMode: false,
801
+ pageStates: [
802
+ {
803
+ pageId: 'page:page',
804
+ camera: {
805
+ x: 0,
806
+ y: 0,
807
+ z: 1,
808
+ },
809
+ selectedShapeIds: ['shape:j0HKQihjBXqMqgVhfRhDS'],
810
+ focusedGroupId: null,
811
+ },
812
+ ],
813
+ },
814
+ }
815
+
816
+ it('should position straight arrow terminals on shape boundary, not text label boundary', () => {
817
+ // Create a geo shape with text label
818
+ editor.loadSnapshot(data as any)
819
+
820
+ const arrow = editor.getShape('shape:j0HKQihjBXqMqgVhfRhDS' as TLShapeId) as TLArrowShape
821
+ expect(arrow).toBeDefined()
822
+
823
+ expect(getArrowBindings(editor, arrow)).toMatchObject({
824
+ end: { props: { isPrecise: true } },
825
+ start: { props: { isPrecise: true } },
826
+ })
827
+
828
+ const info = getArrowInfo(editor, arrow)
829
+ expect(info?.start.handle).toEqual(info?.start.point)
830
+ expect(info?.end.handle).toEqual(info?.end.point)
831
+ })
832
+ })
@@ -144,6 +144,9 @@ export class ArrowShapeUtil extends ShapeUtil<TLArrowShape> {
144
144
  override hideSelectionBoundsFg() {
145
145
  return true
146
146
  }
147
+ override hideInMinimap() {
148
+ return true
149
+ }
147
150
 
148
151
  override canBeLaidOut(shape: TLArrowShape, info: TLShapeUtilCanBeLaidOutOpts) {
149
152
  if (info.type === 'flip') {
@@ -154,7 +154,10 @@ export function getCurvedArrowInfo(
154
154
  }
155
155
  if (!point) {
156
156
  if (isClosed) {
157
- const nearestPoint = startShapeInfo.geometry.nearestPoint(startInStartShapeLocalSpace)
157
+ const nearestPoint = startShapeInfo.geometry.nearestPoint(startInStartShapeLocalSpace, {
158
+ includeInternal: false,
159
+ includeLabels: false,
160
+ })
158
161
  if (Vec.DistMin(nearestPoint, startInStartShapeLocalSpace, 1)) {
159
162
  point = nearestPoint
160
163
  }
@@ -233,7 +236,10 @@ export function getCurvedArrowInfo(
233
236
  }
234
237
  if (!point) {
235
238
  if (isClosed) {
236
- const nearestPoint = endShapeInfo.geometry.nearestPoint(endInEndShapeLocalSpace)
239
+ const nearestPoint = endShapeInfo.geometry.nearestPoint(endInEndShapeLocalSpace, {
240
+ includeInternal: false,
241
+ includeLabels: false,
242
+ })
237
243
  if (Vec.DistMin(nearestPoint, endInEndShapeLocalSpace, 1)) {
238
244
  point = nearestPoint
239
245
  }
@@ -248,7 +248,11 @@ function updateArrowheadPointWithBoundShape(
248
248
  if (targetInt === undefined) {
249
249
  // No intersection? The arrowhead point will be at the arrow terminal.
250
250
  // if we _almost_ hit the target, just put the arrowhead at the target.
251
- targetInt = targetShapeInfo.geometry.nearestPoint(targetTo)
251
+ targetInt = targetShapeInfo.geometry.nearestPoint(targetTo, {
252
+ includeLabels: false,
253
+ includeInternal: false,
254
+ })
255
+
252
256
  if (!Vec.DistMin(targetInt, targetTo, 1)) {
253
257
  return
254
258
  }
@@ -168,9 +168,19 @@ function BookmarkShapeComponent({ shape }: { shape: TLBookmarkShape }) {
168
168
  )}
169
169
  <div className="tl-bookmark__copy_container">
170
170
  {asset?.props.title ? (
171
- <h2 className="tl-bookmark__heading">
172
- {convertCommonTitleHTMLEntities(asset.props.title)}
173
- </h2>
171
+ <a
172
+ className="tl-bookmark__link"
173
+ href={shape.props.url || ''}
174
+ target="_blank"
175
+ rel="noopener noreferrer"
176
+ draggable={false}
177
+ onPointerDown={markAsHandledOnShiftKey}
178
+ onPointerUp={markAsHandledOnShiftKey}
179
+ >
180
+ <h2 className="tl-bookmark__heading">
181
+ {convertCommonTitleHTMLEntities(asset.props.title)}
182
+ </h2>
183
+ </a>
174
184
  ) : null}
175
185
  {asset?.props.description && asset?.props.image ? (
176
186
  <p className="tl-bookmark__description">{asset.props.description}</p>
@@ -48,6 +48,9 @@ export class LineShapeUtil extends ShapeUtil<TLLineShape> {
48
48
  override hideSelectionBoundsBg() {
49
49
  return true
50
50
  }
51
+ override hideInMinimap() {
52
+ return true
53
+ }
51
54
 
52
55
  override getDefaultProps(): TLLineShape['props'] {
53
56
  const [start, end] = getIndices(2)
@@ -109,7 +109,7 @@ export const RichTextLabel = React.memo(function RichTextLabel({
109
109
  // We don't get the mouseup event later because we preventDefault
110
110
  // so we have to do it manually.
111
111
  const handlePointerUp = (e: TLEventInfo) => {
112
- if (e.name !== 'pointer_up') return
112
+ if (e.name !== 'pointer_up' || !link) return
113
113
 
114
114
  if (!isDragging.current) {
115
115
  window.open(link, '_blank', 'noopener, noreferrer')