tldraw 4.2.1 → 4.2.3

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.
package/dist-cjs/index.js CHANGED
@@ -584,7 +584,7 @@ var import_buildFromV1Document = require("./lib/utils/tldr/buildFromV1Document")
584
584
  var import_file = require("./lib/utils/tldr/file");
585
585
  (0, import_editor.registerTldrawLibraryVersion)(
586
586
  "tldraw",
587
- "4.2.1",
587
+ "4.2.3",
588
588
  "cjs"
589
589
  );
590
590
  //# sourceMappingURL=index.js.map
@@ -596,7 +596,7 @@ const embedShapePermissionDefaults = {
596
596
  // [REASON] We want to allow embeds to link back to their original sites (e.g. YouTube).
597
597
  "allow-popups": true,
598
598
  // [MDN] Lets the sandboxed document open new windows without those windows inheriting the sandboxing. For example, this can safely sandbox an advertisement without forcing the same restrictions upon the page the ad links to.
599
- // [REASON] We shouldn't allow popups as a embed could pretend to be us by opening a mocked version of tldraw. This is very unobvious when it is performed as an action within our app.
599
+ // [REASON] We shouldn't allow popups as an embed could pretend to be us by opening a mocked version of tldraw. This is very unobvious when it is performed as an action within our app.
600
600
  "allow-popups-to-escape-sandbox": false,
601
601
  // [MDN] Lets the resource start a presentation session.
602
602
  // [REASON] Prevents embed from navigating away from tldraw and pretending to be us.
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../src/lib/defaultEmbedDefinitions.ts"],
4
- "sourcesContent": ["import { safeParseUrl } from '@tldraw/editor'\n\n// Only allow multiplayer embeds. If we add additional routes later for example '/help' this won't match\nconst TLDRAW_APP_RE = /(^\\/[f|p|r|ro|s|v]\\/[^/]+\\/?$)/\n\n/** @public */\nexport const DEFAULT_EMBED_DEFINITIONS = [\n\t{\n\t\ttype: 'tldraw',\n\t\ttitle: 'tldraw',\n\t\thostnames: ['beta.tldraw.com', 'tldraw.com', 'localhost:3000'],\n\t\tminWidth: 300,\n\t\tminHeight: 300,\n\t\twidth: 720,\n\t\theight: 500,\n\t\tdoesResize: true,\n\t\toverridePermissions: {\n\t\t\t'allow-top-navigation': true,\n\t\t},\n\t\ttoEmbedUrl: (url) => {\n\t\t\tconst urlObj = safeParseUrl(url)\n\t\t\tif (urlObj && urlObj.pathname.match(TLDRAW_APP_RE)) {\n\t\t\t\t// Add the \"clean=true\" search param to the URL to hide the sidebar\n\t\t\t\turlObj.searchParams.append('embed', 'true')\n\t\t\t\treturn url\n\t\t\t}\n\t\t\treturn\n\t\t},\n\t\tfromEmbedUrl: (url) => {\n\t\t\tconst urlObj = safeParseUrl(url)\n\t\t\tif (urlObj && urlObj.pathname.match(TLDRAW_APP_RE)) {\n\t\t\t\t// Add the \"clean=true\" search param to the URL to hide the sidebar\n\t\t\t\turlObj.searchParams.delete('embed')\n\t\t\t\treturn url\n\t\t\t}\n\t\t\treturn\n\t\t},\n\t\tembedOnPaste: false,\n\t},\n\t{\n\t\ttype: 'figma',\n\t\ttitle: 'Figma',\n\t\thostnames: ['figma.com'],\n\t\twidth: 720,\n\t\theight: 500,\n\t\tdoesResize: true,\n\t\ttoEmbedUrl: (url) => {\n\t\t\tif (\n\t\t\t\t!!url.match(\n\t\t\t\t\t// eslint-disable-next-line no-useless-escape\n\t\t\t\t\t/https:\\/\\/([\\w\\.-]+\\.)?figma.com\\/(file|proto|design)\\/([0-9a-zA-Z]{22,128})(?:\\/.*)?$/\n\t\t\t\t) &&\n\t\t\t\t!url.includes('figma.com/embed')\n\t\t\t) {\n\t\t\t\treturn `https://www.figma.com/embed?embed_host=share&url=${url}`\n\t\t\t}\n\t\t\treturn\n\t\t},\n\t\tfromEmbedUrl: (url) => {\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\tembedOnPaste: true,\n\t},\n\t{\n\t\ttype: 'google_maps',\n\t\ttitle: 'Google Maps',\n\t\thostnames: ['google.*'],\n\t\twidth: 720,\n\t\theight: 500,\n\t\tdoesResize: true,\n\t\toverridePermissions: {\n\t\t\t'allow-presentation': true,\n\t\t},\n\t\ttoEmbedUrl: (url) => {\n\t\t\tif (url.includes('/maps/embed?')) {\n\t\t\t\treturn url\n\t\t\t} else if (url.includes('/maps/')) {\n\t\t\t\tconst match = url.match(/@(.*?),(.*?),(.*?)(z|m)/)\n\t\t\t\tlet result: string\n\t\t\t\tif (match) {\n\t\t\t\t\tconst [, lat, lng, zoomOrMeters, mapTypeSymbol] = match\n\t\t\t\t\tconst mapType = mapTypeSymbol === 'z' ? 'roadmap' : 'satellite'\n\t\t\t\t\t// Note: This meters to zoom equation is a rough approximation and not canonical.\n\t\t\t\t\tconst z =\n\t\t\t\t\t\tmapType === 'roadmap'\n\t\t\t\t\t\t\t? zoomOrMeters\n\t\t\t\t\t\t\t: -Math.log2(parseInt(zoomOrMeters) / 14772321) / 0.8\n\t\t\t\t\tconst host = new URL(url).host.replace('www.', '')\n\t\t\t\t\tresult = `https://${host}/maps/embed/v1/view?key=${process.env.NEXT_PUBLIC_GC_API_KEY}&center=${lat},${lng}&zoom=${z}&maptype=${mapType}`\n\t\t\t\t} else {\n\t\t\t\t\tresult = ''\n\t\t\t\t}\n\n\t\t\t\treturn result\n\t\t\t}\n\t\t\treturn\n\t\t},\n\t\tfromEmbedUrl: (url) => {\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') ?? '12'\n\t\t\t\tconst mapType = urlObj.searchParams.get('maptype') ?? 'roadmap'\n\t\t\t\t// Note: This zoom to meters equation is a rough approximation and not canonical.\n\t\t\t\tconst zoomOrMeters =\n\t\t\t\t\tmapType === 'roadmap' ? zoom : 14772321 * Math.pow(2, parseInt(zoom) * -0.8)\n\t\t\t\tconst [lat, lon] = urlObj.searchParams.get('center')!.split(',')\n\t\t\t\treturn `https://www.google.com/maps/@${lat},${lon},${zoomOrMeters}${mapType === 'roadmap' ? 'z' : 'm'}`\n\t\t\t}\n\t\t\treturn\n\t\t},\n\t\tembedOnPaste: true,\n\t},\n\t{\n\t\ttype: 'val_town',\n\t\ttitle: 'Val Town',\n\t\thostnames: ['val.town'],\n\t\tminWidth: 260,\n\t\tminHeight: 100,\n\t\twidth: 720,\n\t\theight: 500,\n\t\tdoesResize: true,\n\t\ttoEmbedUrl: (url) => {\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(/\\/v\\/(.+)\\/?/)\n\t\t\tif (matches) {\n\t\t\t\treturn `https://www.val.town/embed/${matches[1]}`\n\t\t\t}\n\t\t\treturn\n\t\t},\n\t\tfromEmbedUrl: (url) => {\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\tembedOnPaste: true,\n\t},\n\t{\n\t\ttype: 'codesandbox',\n\t\ttitle: 'CodeSandbox',\n\t\thostnames: ['codesandbox.io'],\n\t\tminWidth: 300,\n\t\tminHeight: 300,\n\t\twidth: 720,\n\t\theight: 500,\n\t\tdoesResize: true,\n\t\ttoEmbedUrl: (url) => {\n\t\t\tconst urlObj = safeParseUrl(url)\n\t\t\tconst matches = urlObj && urlObj.pathname.match(/\\/s\\/([^/]+)\\/?/)\n\t\t\tif (matches) {\n\t\t\t\treturn `https://codesandbox.io/embed/${matches[1]}`\n\t\t\t}\n\t\t\treturn\n\t\t},\n\t\tfromEmbedUrl: (url) => {\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\tembedOnPaste: true,\n\t},\n\t{\n\t\ttype: 'codepen',\n\t\ttitle: 'Codepen',\n\t\thostnames: ['codepen.io'],\n\t\tminWidth: 300,\n\t\tminHeight: 300,\n\t\twidth: 520,\n\t\theight: 400,\n\t\tdoesResize: true,\n\t\ttoEmbedUrl: (url) => {\n\t\t\tconst CODEPEN_URL_REGEXP = /https:\\/\\/codepen.io\\/([^/]+)\\/pen\\/([^/]+)/\n\t\t\tconst matches = url.match(CODEPEN_URL_REGEXP)\n\t\t\tif (matches) {\n\t\t\t\tconst [_, user, id] = matches\n\t\t\t\treturn `https://codepen.io/${user}/embed/${id}`\n\t\t\t}\n\t\t\treturn\n\t\t},\n\t\tfromEmbedUrl: (url) => {\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\tembedOnPaste: true,\n\t},\n\t{\n\t\ttype: 'scratch',\n\t\ttitle: 'Scratch',\n\t\thostnames: ['scratch.mit.edu'],\n\t\twidth: 520,\n\t\theight: 400,\n\t\tdoesResize: false,\n\t\tembedOnPaste: true,\n\t\ttoEmbedUrl: (url) => {\n\t\t\tconst SCRATCH_URL_REGEXP = /https?:\\/\\/scratch.mit.edu\\/projects\\/([^/]+)/\n\t\t\tconst matches = url.match(SCRATCH_URL_REGEXP)\n\t\t\tif (matches) {\n\t\t\t\tconst [_, id] = matches\n\t\t\t\treturn `https://scratch.mit.edu/projects/embed/${id}`\n\t\t\t}\n\t\t\treturn\n\t\t},\n\t\tfromEmbedUrl: (url) => {\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\ttype: 'youtube',\n\t\ttitle: 'YouTube',\n\t\thostnames: ['*.youtube.com', 'youtube.com', 'youtu.be'],\n\t\twidth: 800,\n\t\theight: 450,\n\t\tdoesResize: true,\n\t\toverridePermissions: {\n\t\t\t'allow-presentation': true,\n\t\t\t'allow-popups-to-escape-sandbox': true,\n\t\t},\n\t\tisAspectRatioLocked: true,\n\t\tembedOnPaste: true,\n\t\ttoEmbedUrl: (url) => {\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 === 'youtu.be') {\n\t\t\t\tconst videoId = urlObj.pathname.split('/').filter(Boolean)[0]\n\t\t\t\tconst searchParams = new URLSearchParams(urlObj.search)\n\t\t\t\tconst timeStart = searchParams.get('t')\n\t\t\t\tif (timeStart) {\n\t\t\t\t\tsearchParams.set('start', timeStart)\n\t\t\t\t\tsearchParams.delete('t')\n\t\t\t\t}\n\t\t\t\tconst search = searchParams.toString() ? '?' + searchParams.toString() : ''\n\t\t\t\treturn `https://www.youtube.com/embed/${videoId}${search}`\n\t\t\t} else if (\n\t\t\t\t(hostname === 'youtube.com' || hostname === 'm.youtube.com') &&\n\t\t\t\turlObj.pathname.match(/^\\/watch/)\n\t\t\t) {\n\t\t\t\tconst videoId = urlObj.searchParams.get('v')\n\t\t\t\tconst searchParams = new URLSearchParams(urlObj.search)\n\t\t\t\tsearchParams.delete('v')\n\t\t\t\tconst timeStart = searchParams.get('t')\n\t\t\t\tif (timeStart) {\n\t\t\t\t\tsearchParams.set('start', timeStart)\n\t\t\t\t\tsearchParams.delete('t')\n\t\t\t\t}\n\t\t\t\tconst search = searchParams.toString() ? '?' + searchParams.toString() : ''\n\t\t\t\treturn `https://www.youtube.com/embed/${videoId}${search}`\n\t\t\t}\n\t\t\treturn\n\t\t},\n\t\tfromEmbedUrl: (url) => {\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\tconst params = new URLSearchParams(urlObj.search)\n\t\t\t\t\tparams.set('v', matches?.[1] ?? '')\n\t\t\t\t\tconst timeStart = params.get('start')\n\t\t\t\t\tif (timeStart) {\n\t\t\t\t\t\tparams.set('t', timeStart)\n\t\t\t\t\t\tparams.delete('start')\n\t\t\t\t\t}\n\t\t\t\t\treturn `https://www.youtube.com/watch?${params.toString()}`\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn\n\t\t},\n\t},\n\t{\n\t\ttype: 'google_calendar',\n\t\ttitle: 'Google Calendar',\n\t\thostnames: ['calendar.google.*'],\n\t\twidth: 720,\n\t\theight: 500,\n\t\tminWidth: 460,\n\t\tminHeight: 360,\n\t\tdoesResize: true,\n\t\tinstructionLink: 'https://support.google.com/calendar/answer/41207?hl=en',\n\t\toverridePermissions: {\n\t\t\t'allow-popups-to-escape-sandbox': true,\n\t\t},\n\t\tembedOnPaste: true,\n\t\ttoEmbedUrl: (url) => {\n\t\t\tconst urlObj = safeParseUrl(url)\n\t\t\tconst cidQs = urlObj?.searchParams.get('cid')\n\n\t\t\tif (urlObj?.pathname.match(/\\/calendar\\/u\\/0/) && cidQs) {\n\t\t\t\turlObj.pathname = '/calendar/embed'\n\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('src', cidQs)\n\t\t\t\treturn urlObj.href\n\t\t\t}\n\t\t\treturn\n\t\t},\n\t\tfromEmbedUrl: (url) => {\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\ttype: 'google_slides',\n\t\ttitle: 'Google Slides',\n\t\thostnames: ['docs.google.*'],\n\t\twidth: 720,\n\t\theight: 500,\n\t\tminWidth: 460,\n\t\tminHeight: 360,\n\t\tdoesResize: true,\n\t\toverridePermissions: {\n\t\t\t'allow-popups-to-escape-sandbox': true,\n\t\t},\n\t\tembedOnPaste: true,\n\t\ttoEmbedUrl: (url) => {\n\t\t\tconst urlObj = safeParseUrl(url)\n\n\t\t\tif (urlObj?.pathname.match(/^\\/presentation/) && urlObj?.pathname.match(/\\/pub\\/?$/)) {\n\t\t\t\turlObj.pathname = urlObj.pathname.replace(/\\/pub$/, '/embed')\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\tfromEmbedUrl: (url) => {\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\ttype: 'github_gist',\n\t\ttitle: 'GitHub Gist',\n\t\thostnames: ['gist.github.com'],\n\t\twidth: 720,\n\t\theight: 500,\n\t\tdoesResize: true,\n\t\tembedOnPaste: true,\n\t\t// Security warning:\n\t\t// Gists allow adding .json extensions to the URL which return JSONP.\n\t\t// Furthermore, the JSONP can include callbacks that execute arbitrary JavaScript.\n\t\t// It _is_ sandboxed by the iframe but we still want to disable it nonetheless.\n\t\t// We restrict the id to only allow hexdecimal characters to prevent this.\n\t\t// Read more:\n\t\t// https://github.com/bhaveshk90/Content-Security-Policy-CSP-Bypass-Techniques\n\t\t// https://github.com/renniepak/CSPBypass\n\t\ttoEmbedUrl: (url) => {\n\t\t\tconst urlObj = safeParseUrl(url)\n\t\t\tif (urlObj && urlObj.pathname.match(/\\/([^/]+)\\/([0-9a-f]+)$/)) {\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\tfromEmbedUrl: (url) => {\n\t\t\tconst urlObj = safeParseUrl(url)\n\t\t\tif (urlObj && urlObj.pathname.match(/\\/([^/]+)\\/([0-9a-f]+)$/)) {\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\ttype: 'replit',\n\t\ttitle: 'Replit',\n\t\thostnames: ['replit.com'],\n\t\twidth: 720,\n\t\theight: 500,\n\t\tdoesResize: true,\n\t\tembedOnPaste: true,\n\t\ttoEmbedUrl: (url) => {\n\t\t\tconst urlObj = safeParseUrl(url)\n\t\t\tif (urlObj && urlObj.pathname.match(/\\/@([^/]+)\\/([^/]+)/)) {\n\t\t\t\turlObj.searchParams.append('embed', 'true')\n\t\t\t\treturn urlObj.href\n\t\t\t}\n\t\t\treturn\n\t\t},\n\t\tfromEmbedUrl: (url) => {\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\ttype: 'felt',\n\t\ttitle: 'Felt',\n\t\thostnames: ['felt.com'],\n\t\twidth: 720,\n\t\theight: 500,\n\t\tdoesResize: true,\n\t\tembedOnPaste: true,\n\t\ttoEmbedUrl: (url) => {\n\t\t\tconst urlObj = safeParseUrl(url)\n\t\t\tif (urlObj && urlObj.pathname.match(/^\\/map\\//)) {\n\t\t\t\treturn urlObj.origin + '/embed' + urlObj.pathname\n\t\t\t}\n\t\t\treturn\n\t\t},\n\t\tfromEmbedUrl: (url) => {\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\ttype: 'spotify',\n\t\ttitle: 'Spotify',\n\t\thostnames: ['open.spotify.com'],\n\t\twidth: 720,\n\t\theight: 500,\n\t\tminHeight: 500,\n\t\toverrideOutlineRadius: 12,\n\t\tdoesResize: true,\n\t\tembedOnPaste: true,\n\t\ttoEmbedUrl: (url) => {\n\t\t\tconst urlObj = safeParseUrl(url)\n\t\t\tif (urlObj && urlObj.pathname.match(/^\\/(artist|album)\\//)) {\n\t\t\t\treturn urlObj.origin + '/embed' + urlObj.pathname\n\t\t\t}\n\t\t\treturn\n\t\t},\n\t\tfromEmbedUrl: (url) => {\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\ttype: 'vimeo',\n\t\ttitle: 'Vimeo',\n\t\thostnames: ['vimeo.com', 'player.vimeo.com'],\n\t\twidth: 640,\n\t\theight: 360,\n\t\tdoesResize: true,\n\t\tisAspectRatioLocked: true,\n\t\tembedOnPaste: true,\n\t\ttoEmbedUrl: (url) => {\n\t\t\tconst urlObj = safeParseUrl(url)\n\t\t\tif (urlObj && urlObj.hostname === 'vimeo.com') {\n\t\t\t\tif (urlObj.pathname.match(/^\\/[0-9]+/)) {\n\t\t\t\t\treturn (\n\t\t\t\t\t\t'https://player.vimeo.com/video/' + urlObj.pathname.split('/')[1] + '?title=0&byline=0'\n\t\t\t\t\t)\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn\n\t\t},\n\t\tfromEmbedUrl: (url) => {\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\ttype: 'observable',\n\t\ttitle: 'Observable',\n\t\thostnames: ['observablehq.com'],\n\t\twidth: 720,\n\t\theight: 500,\n\t\tdoesResize: true,\n\t\tisAspectRatioLocked: false,\n\t\tbackgroundColor: '#fff',\n\t\tembedOnPaste: true,\n\t\ttoEmbedUrl: (url) => {\n\t\t\tconst urlObj = safeParseUrl(url)\n\t\t\tif (urlObj && urlObj.pathname.match(/^\\/@([^/]+)\\/([^/]+)\\/?$/)) {\n\t\t\t\treturn `${urlObj.origin}/embed${urlObj.pathname}?cell=*`\n\t\t\t}\n\t\t\tif (urlObj && urlObj.pathname.match(/^\\/d\\/([^/]+)\\/?$/)) {\n\t\t\t\tconst pathName = urlObj.pathname.replace(/^\\/d/, '')\n\t\t\t\treturn `${urlObj.origin}/embed${pathName}?cell=*`\n\t\t\t}\n\n\t\t\treturn\n\t\t},\n\t\tfromEmbedUrl: (url) => {\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\ttype: 'desmos',\n\t\ttitle: 'Desmos',\n\t\thostnames: ['desmos.com'],\n\t\twidth: 700,\n\t\theight: 450,\n\t\tdoesResize: true,\n\t\tembedOnPaste: true,\n\t\ttoEmbedUrl: (url) => {\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 === '' &&\n\t\t\t\turlObj.hash === ''\n\t\t\t) {\n\t\t\t\treturn `${url}?embed`\n\t\t\t}\n\t\t\treturn\n\t\t},\n\t\tfromEmbedUrl: (url) => {\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] as const satisfies readonly EmbedDefinition[]\n\n/**\n * Permissions with note inline from\n * https://developer.mozilla.org/en-US/docs/Web/HTML/Element/iframe#attr-sandbox\n *\n * @public\n */\nexport const embedShapePermissionDefaults = {\n\t// ========================================================================================\n\t// Disabled permissions\n\t// ========================================================================================\n\t// [MDN] Experimental: Allows for downloads to occur without a gesture from the user.\n\t// [REASON] Disabled because otherwise the <iframe/> can trick the user on behalf of us to perform an action.\n\t'allow-downloads-without-user-activation': false,\n\t// [MDN] Allows for downloads to occur with a gesture from the user.\n\t// [REASON] Disabled because otherwise the <iframe/> can trick the user on behalf of us to perform an action.\n\t'allow-downloads': false,\n\t// [MDN] Lets the resource open modal windows.\n\t// [REASON] The <iframe/> could 'window.prompt(\"Enter your tldraw password\")'.\n\t'allow-modals': false,\n\t// [MDN] Lets the resource lock the screen orientation.\n\t// [REASON] Would interfere with the tldraw interface.\n\t'allow-orientation-lock': false,\n\t// [MDN] Lets the resource use the Pointer Lock API.\n\t// [REASON] Maybe we should allow this for games embeds (scratch/codepen/codesandbox).\n\t'allow-pointer-lock': false,\n\t// [MDN] Allows popups (such as window.open(), target=\"_blank\", or showModalDialog()). If this keyword is not used, the popup will silently fail to open.\n\t// [REASON] We want to allow embeds to link back to their original sites (e.g. YouTube).\n\t'allow-popups': true,\n\t// [MDN] Lets the sandboxed document open new windows without those windows inheriting the sandboxing. For example, this can safely sandbox an advertisement without forcing the same restrictions upon the page the ad links to.\n\t// [REASON] We shouldn't allow popups as a embed could pretend to be us by opening a mocked version of tldraw. This is very unobvious when it is performed as an action within our app.\n\t'allow-popups-to-escape-sandbox': false,\n\t// [MDN] Lets the resource start a presentation session.\n\t// [REASON] Prevents embed from navigating away from tldraw and pretending to be us.\n\t'allow-presentation': false,\n\t// [MDN] Experimental: Lets the resource request access to the parent's storage capabilities with the Storage Access API.\n\t// [REASON] We don't want anyone else to access our storage.\n\t'allow-storage-access-by-user-activation': false,\n\t// [MDN] Lets the resource navigate the top-level browsing context (the one named _top).\n\t// [REASON] Prevents embed from navigating away from tldraw and pretending to be us.\n\t'allow-top-navigation': false,\n\t// [MDN] Lets the resource navigate the top-level browsing context, but only if initiated by a user gesture.\n\t// [REASON] Prevents embed from navigating away from tldraw and pretending to be us.\n\t'allow-top-navigation-by-user-activation': false,\n\t// ========================================================================================\n\t// Enabled permissions\n\t// ========================================================================================\n\t// [MDN] Lets the resource run scripts (but not create popup windows).\n\t'allow-scripts': true,\n\t// [MDN] If this token is not used, the resource is treated as being from a special origin that always fails the same-origin policy (potentially preventing access to data storage/cookies and some JavaScript APIs).\n\t'allow-same-origin': true,\n\t// [MDN] Allows the resource to submit forms. If this keyword is not used, form submission is blocked.\n\t'allow-forms': true,\n} as const\n\n/** @public */\nexport type TLEmbedShapePermissions = { [K in keyof typeof embedShapePermissionDefaults]?: boolean }\n\n/** @public */\nexport interface EmbedDefinition {\n\treadonly type: string\n\treadonly title: string\n\treadonly hostnames: readonly string[]\n\treadonly minWidth?: number\n\treadonly minHeight?: number\n\treadonly width: number\n\treadonly height: number\n\treadonly doesResize: boolean\n\treadonly isAspectRatioLocked?: boolean\n\treadonly overridePermissions?: TLEmbedShapePermissions\n\treadonly instructionLink?: string\n\treadonly backgroundColor?: string\n\treadonly embedOnPaste?: boolean\n\t// TODO: FIXME this is ugly be required because some embeds have their own border radius for example spotify embeds\n\treadonly overrideOutlineRadius?: number\n\t// eslint-disable-next-line @typescript-eslint/method-signature-style\n\treadonly toEmbedUrl: (url: string) => string | undefined\n\t// eslint-disable-next-line @typescript-eslint/method-signature-style\n\treadonly fromEmbedUrl: (url: string) => string | undefined\n}\n\n/** @public */\nexport interface CustomEmbedDefinition extends EmbedDefinition {\n\treadonly icon: string\n}\n\n/** @public */\nexport type TLEmbedDefinition = EmbedDefinition | CustomEmbedDefinition\n\n/** @public */\nexport type DefaultEmbedDefinitionType = (typeof DEFAULT_EMBED_DEFINITIONS)[number]['type']\n\nconst DEFAULT_EMBED_DEFINITION_TYPES = DEFAULT_EMBED_DEFINITIONS.map(\n\t(def) => def.type\n) as DefaultEmbedDefinitionType[]\n\n/** @public */\nexport function isDefaultEmbedDefinitionType(type: string): type is DefaultEmbedDefinitionType {\n\treturn DEFAULT_EMBED_DEFINITION_TYPES.includes(type as DefaultEmbedDefinitionType)\n}\n\n/** @public */\nexport function isCustomEmbedDefinition(\n\tdef: EmbedDefinition | CustomEmbedDefinition\n): def is CustomEmbedDefinition {\n\treturn 'icon' in def\n}\n"],
4
+ "sourcesContent": ["import { safeParseUrl } from '@tldraw/editor'\n\n// Only allow multiplayer embeds. If we add additional routes later for example '/help' this won't match\nconst TLDRAW_APP_RE = /(^\\/[f|p|r|ro|s|v]\\/[^/]+\\/?$)/\n\n/** @public */\nexport const DEFAULT_EMBED_DEFINITIONS = [\n\t{\n\t\ttype: 'tldraw',\n\t\ttitle: 'tldraw',\n\t\thostnames: ['beta.tldraw.com', 'tldraw.com', 'localhost:3000'],\n\t\tminWidth: 300,\n\t\tminHeight: 300,\n\t\twidth: 720,\n\t\theight: 500,\n\t\tdoesResize: true,\n\t\toverridePermissions: {\n\t\t\t'allow-top-navigation': true,\n\t\t},\n\t\ttoEmbedUrl: (url) => {\n\t\t\tconst urlObj = safeParseUrl(url)\n\t\t\tif (urlObj && urlObj.pathname.match(TLDRAW_APP_RE)) {\n\t\t\t\t// Add the \"clean=true\" search param to the URL to hide the sidebar\n\t\t\t\turlObj.searchParams.append('embed', 'true')\n\t\t\t\treturn url\n\t\t\t}\n\t\t\treturn\n\t\t},\n\t\tfromEmbedUrl: (url) => {\n\t\t\tconst urlObj = safeParseUrl(url)\n\t\t\tif (urlObj && urlObj.pathname.match(TLDRAW_APP_RE)) {\n\t\t\t\t// Add the \"clean=true\" search param to the URL to hide the sidebar\n\t\t\t\turlObj.searchParams.delete('embed')\n\t\t\t\treturn url\n\t\t\t}\n\t\t\treturn\n\t\t},\n\t\tembedOnPaste: false,\n\t},\n\t{\n\t\ttype: 'figma',\n\t\ttitle: 'Figma',\n\t\thostnames: ['figma.com'],\n\t\twidth: 720,\n\t\theight: 500,\n\t\tdoesResize: true,\n\t\ttoEmbedUrl: (url) => {\n\t\t\tif (\n\t\t\t\t!!url.match(\n\t\t\t\t\t// eslint-disable-next-line no-useless-escape\n\t\t\t\t\t/https:\\/\\/([\\w\\.-]+\\.)?figma.com\\/(file|proto|design)\\/([0-9a-zA-Z]{22,128})(?:\\/.*)?$/\n\t\t\t\t) &&\n\t\t\t\t!url.includes('figma.com/embed')\n\t\t\t) {\n\t\t\t\treturn `https://www.figma.com/embed?embed_host=share&url=${url}`\n\t\t\t}\n\t\t\treturn\n\t\t},\n\t\tfromEmbedUrl: (url) => {\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\tembedOnPaste: true,\n\t},\n\t{\n\t\ttype: 'google_maps',\n\t\ttitle: 'Google Maps',\n\t\thostnames: ['google.*'],\n\t\twidth: 720,\n\t\theight: 500,\n\t\tdoesResize: true,\n\t\toverridePermissions: {\n\t\t\t'allow-presentation': true,\n\t\t},\n\t\ttoEmbedUrl: (url) => {\n\t\t\tif (url.includes('/maps/embed?')) {\n\t\t\t\treturn url\n\t\t\t} else if (url.includes('/maps/')) {\n\t\t\t\tconst match = url.match(/@(.*?),(.*?),(.*?)(z|m)/)\n\t\t\t\tlet result: string\n\t\t\t\tif (match) {\n\t\t\t\t\tconst [, lat, lng, zoomOrMeters, mapTypeSymbol] = match\n\t\t\t\t\tconst mapType = mapTypeSymbol === 'z' ? 'roadmap' : 'satellite'\n\t\t\t\t\t// Note: This meters to zoom equation is a rough approximation and not canonical.\n\t\t\t\t\tconst z =\n\t\t\t\t\t\tmapType === 'roadmap'\n\t\t\t\t\t\t\t? zoomOrMeters\n\t\t\t\t\t\t\t: -Math.log2(parseInt(zoomOrMeters) / 14772321) / 0.8\n\t\t\t\t\tconst host = new URL(url).host.replace('www.', '')\n\t\t\t\t\tresult = `https://${host}/maps/embed/v1/view?key=${process.env.NEXT_PUBLIC_GC_API_KEY}&center=${lat},${lng}&zoom=${z}&maptype=${mapType}`\n\t\t\t\t} else {\n\t\t\t\t\tresult = ''\n\t\t\t\t}\n\n\t\t\t\treturn result\n\t\t\t}\n\t\t\treturn\n\t\t},\n\t\tfromEmbedUrl: (url) => {\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') ?? '12'\n\t\t\t\tconst mapType = urlObj.searchParams.get('maptype') ?? 'roadmap'\n\t\t\t\t// Note: This zoom to meters equation is a rough approximation and not canonical.\n\t\t\t\tconst zoomOrMeters =\n\t\t\t\t\tmapType === 'roadmap' ? zoom : 14772321 * Math.pow(2, parseInt(zoom) * -0.8)\n\t\t\t\tconst [lat, lon] = urlObj.searchParams.get('center')!.split(',')\n\t\t\t\treturn `https://www.google.com/maps/@${lat},${lon},${zoomOrMeters}${mapType === 'roadmap' ? 'z' : 'm'}`\n\t\t\t}\n\t\t\treturn\n\t\t},\n\t\tembedOnPaste: true,\n\t},\n\t{\n\t\ttype: 'val_town',\n\t\ttitle: 'Val Town',\n\t\thostnames: ['val.town'],\n\t\tminWidth: 260,\n\t\tminHeight: 100,\n\t\twidth: 720,\n\t\theight: 500,\n\t\tdoesResize: true,\n\t\ttoEmbedUrl: (url) => {\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(/\\/v\\/(.+)\\/?/)\n\t\t\tif (matches) {\n\t\t\t\treturn `https://www.val.town/embed/${matches[1]}`\n\t\t\t}\n\t\t\treturn\n\t\t},\n\t\tfromEmbedUrl: (url) => {\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\tembedOnPaste: true,\n\t},\n\t{\n\t\ttype: 'codesandbox',\n\t\ttitle: 'CodeSandbox',\n\t\thostnames: ['codesandbox.io'],\n\t\tminWidth: 300,\n\t\tminHeight: 300,\n\t\twidth: 720,\n\t\theight: 500,\n\t\tdoesResize: true,\n\t\ttoEmbedUrl: (url) => {\n\t\t\tconst urlObj = safeParseUrl(url)\n\t\t\tconst matches = urlObj && urlObj.pathname.match(/\\/s\\/([^/]+)\\/?/)\n\t\t\tif (matches) {\n\t\t\t\treturn `https://codesandbox.io/embed/${matches[1]}`\n\t\t\t}\n\t\t\treturn\n\t\t},\n\t\tfromEmbedUrl: (url) => {\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\tembedOnPaste: true,\n\t},\n\t{\n\t\ttype: 'codepen',\n\t\ttitle: 'Codepen',\n\t\thostnames: ['codepen.io'],\n\t\tminWidth: 300,\n\t\tminHeight: 300,\n\t\twidth: 520,\n\t\theight: 400,\n\t\tdoesResize: true,\n\t\ttoEmbedUrl: (url) => {\n\t\t\tconst CODEPEN_URL_REGEXP = /https:\\/\\/codepen.io\\/([^/]+)\\/pen\\/([^/]+)/\n\t\t\tconst matches = url.match(CODEPEN_URL_REGEXP)\n\t\t\tif (matches) {\n\t\t\t\tconst [_, user, id] = matches\n\t\t\t\treturn `https://codepen.io/${user}/embed/${id}`\n\t\t\t}\n\t\t\treturn\n\t\t},\n\t\tfromEmbedUrl: (url) => {\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\tembedOnPaste: true,\n\t},\n\t{\n\t\ttype: 'scratch',\n\t\ttitle: 'Scratch',\n\t\thostnames: ['scratch.mit.edu'],\n\t\twidth: 520,\n\t\theight: 400,\n\t\tdoesResize: false,\n\t\tembedOnPaste: true,\n\t\ttoEmbedUrl: (url) => {\n\t\t\tconst SCRATCH_URL_REGEXP = /https?:\\/\\/scratch.mit.edu\\/projects\\/([^/]+)/\n\t\t\tconst matches = url.match(SCRATCH_URL_REGEXP)\n\t\t\tif (matches) {\n\t\t\t\tconst [_, id] = matches\n\t\t\t\treturn `https://scratch.mit.edu/projects/embed/${id}`\n\t\t\t}\n\t\t\treturn\n\t\t},\n\t\tfromEmbedUrl: (url) => {\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\ttype: 'youtube',\n\t\ttitle: 'YouTube',\n\t\thostnames: ['*.youtube.com', 'youtube.com', 'youtu.be'],\n\t\twidth: 800,\n\t\theight: 450,\n\t\tdoesResize: true,\n\t\toverridePermissions: {\n\t\t\t'allow-presentation': true,\n\t\t\t'allow-popups-to-escape-sandbox': true,\n\t\t},\n\t\tisAspectRatioLocked: true,\n\t\tembedOnPaste: true,\n\t\ttoEmbedUrl: (url) => {\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 === 'youtu.be') {\n\t\t\t\tconst videoId = urlObj.pathname.split('/').filter(Boolean)[0]\n\t\t\t\tconst searchParams = new URLSearchParams(urlObj.search)\n\t\t\t\tconst timeStart = searchParams.get('t')\n\t\t\t\tif (timeStart) {\n\t\t\t\t\tsearchParams.set('start', timeStart)\n\t\t\t\t\tsearchParams.delete('t')\n\t\t\t\t}\n\t\t\t\tconst search = searchParams.toString() ? '?' + searchParams.toString() : ''\n\t\t\t\treturn `https://www.youtube.com/embed/${videoId}${search}`\n\t\t\t} else if (\n\t\t\t\t(hostname === 'youtube.com' || hostname === 'm.youtube.com') &&\n\t\t\t\turlObj.pathname.match(/^\\/watch/)\n\t\t\t) {\n\t\t\t\tconst videoId = urlObj.searchParams.get('v')\n\t\t\t\tconst searchParams = new URLSearchParams(urlObj.search)\n\t\t\t\tsearchParams.delete('v')\n\t\t\t\tconst timeStart = searchParams.get('t')\n\t\t\t\tif (timeStart) {\n\t\t\t\t\tsearchParams.set('start', timeStart)\n\t\t\t\t\tsearchParams.delete('t')\n\t\t\t\t}\n\t\t\t\tconst search = searchParams.toString() ? '?' + searchParams.toString() : ''\n\t\t\t\treturn `https://www.youtube.com/embed/${videoId}${search}`\n\t\t\t}\n\t\t\treturn\n\t\t},\n\t\tfromEmbedUrl: (url) => {\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\tconst params = new URLSearchParams(urlObj.search)\n\t\t\t\t\tparams.set('v', matches?.[1] ?? '')\n\t\t\t\t\tconst timeStart = params.get('start')\n\t\t\t\t\tif (timeStart) {\n\t\t\t\t\t\tparams.set('t', timeStart)\n\t\t\t\t\t\tparams.delete('start')\n\t\t\t\t\t}\n\t\t\t\t\treturn `https://www.youtube.com/watch?${params.toString()}`\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn\n\t\t},\n\t},\n\t{\n\t\ttype: 'google_calendar',\n\t\ttitle: 'Google Calendar',\n\t\thostnames: ['calendar.google.*'],\n\t\twidth: 720,\n\t\theight: 500,\n\t\tminWidth: 460,\n\t\tminHeight: 360,\n\t\tdoesResize: true,\n\t\tinstructionLink: 'https://support.google.com/calendar/answer/41207?hl=en',\n\t\toverridePermissions: {\n\t\t\t'allow-popups-to-escape-sandbox': true,\n\t\t},\n\t\tembedOnPaste: true,\n\t\ttoEmbedUrl: (url) => {\n\t\t\tconst urlObj = safeParseUrl(url)\n\t\t\tconst cidQs = urlObj?.searchParams.get('cid')\n\n\t\t\tif (urlObj?.pathname.match(/\\/calendar\\/u\\/0/) && cidQs) {\n\t\t\t\turlObj.pathname = '/calendar/embed'\n\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('src', cidQs)\n\t\t\t\treturn urlObj.href\n\t\t\t}\n\t\t\treturn\n\t\t},\n\t\tfromEmbedUrl: (url) => {\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\ttype: 'google_slides',\n\t\ttitle: 'Google Slides',\n\t\thostnames: ['docs.google.*'],\n\t\twidth: 720,\n\t\theight: 500,\n\t\tminWidth: 460,\n\t\tminHeight: 360,\n\t\tdoesResize: true,\n\t\toverridePermissions: {\n\t\t\t'allow-popups-to-escape-sandbox': true,\n\t\t},\n\t\tembedOnPaste: true,\n\t\ttoEmbedUrl: (url) => {\n\t\t\tconst urlObj = safeParseUrl(url)\n\n\t\t\tif (urlObj?.pathname.match(/^\\/presentation/) && urlObj?.pathname.match(/\\/pub\\/?$/)) {\n\t\t\t\turlObj.pathname = urlObj.pathname.replace(/\\/pub$/, '/embed')\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\tfromEmbedUrl: (url) => {\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\ttype: 'github_gist',\n\t\ttitle: 'GitHub Gist',\n\t\thostnames: ['gist.github.com'],\n\t\twidth: 720,\n\t\theight: 500,\n\t\tdoesResize: true,\n\t\tembedOnPaste: true,\n\t\t// Security warning:\n\t\t// Gists allow adding .json extensions to the URL which return JSONP.\n\t\t// Furthermore, the JSONP can include callbacks that execute arbitrary JavaScript.\n\t\t// It _is_ sandboxed by the iframe but we still want to disable it nonetheless.\n\t\t// We restrict the id to only allow hexdecimal characters to prevent this.\n\t\t// Read more:\n\t\t// https://github.com/bhaveshk90/Content-Security-Policy-CSP-Bypass-Techniques\n\t\t// https://github.com/renniepak/CSPBypass\n\t\ttoEmbedUrl: (url) => {\n\t\t\tconst urlObj = safeParseUrl(url)\n\t\t\tif (urlObj && urlObj.pathname.match(/\\/([^/]+)\\/([0-9a-f]+)$/)) {\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\tfromEmbedUrl: (url) => {\n\t\t\tconst urlObj = safeParseUrl(url)\n\t\t\tif (urlObj && urlObj.pathname.match(/\\/([^/]+)\\/([0-9a-f]+)$/)) {\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\ttype: 'replit',\n\t\ttitle: 'Replit',\n\t\thostnames: ['replit.com'],\n\t\twidth: 720,\n\t\theight: 500,\n\t\tdoesResize: true,\n\t\tembedOnPaste: true,\n\t\ttoEmbedUrl: (url) => {\n\t\t\tconst urlObj = safeParseUrl(url)\n\t\t\tif (urlObj && urlObj.pathname.match(/\\/@([^/]+)\\/([^/]+)/)) {\n\t\t\t\turlObj.searchParams.append('embed', 'true')\n\t\t\t\treturn urlObj.href\n\t\t\t}\n\t\t\treturn\n\t\t},\n\t\tfromEmbedUrl: (url) => {\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\ttype: 'felt',\n\t\ttitle: 'Felt',\n\t\thostnames: ['felt.com'],\n\t\twidth: 720,\n\t\theight: 500,\n\t\tdoesResize: true,\n\t\tembedOnPaste: true,\n\t\ttoEmbedUrl: (url) => {\n\t\t\tconst urlObj = safeParseUrl(url)\n\t\t\tif (urlObj && urlObj.pathname.match(/^\\/map\\//)) {\n\t\t\t\treturn urlObj.origin + '/embed' + urlObj.pathname\n\t\t\t}\n\t\t\treturn\n\t\t},\n\t\tfromEmbedUrl: (url) => {\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\ttype: 'spotify',\n\t\ttitle: 'Spotify',\n\t\thostnames: ['open.spotify.com'],\n\t\twidth: 720,\n\t\theight: 500,\n\t\tminHeight: 500,\n\t\toverrideOutlineRadius: 12,\n\t\tdoesResize: true,\n\t\tembedOnPaste: true,\n\t\ttoEmbedUrl: (url) => {\n\t\t\tconst urlObj = safeParseUrl(url)\n\t\t\tif (urlObj && urlObj.pathname.match(/^\\/(artist|album)\\//)) {\n\t\t\t\treturn urlObj.origin + '/embed' + urlObj.pathname\n\t\t\t}\n\t\t\treturn\n\t\t},\n\t\tfromEmbedUrl: (url) => {\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\ttype: 'vimeo',\n\t\ttitle: 'Vimeo',\n\t\thostnames: ['vimeo.com', 'player.vimeo.com'],\n\t\twidth: 640,\n\t\theight: 360,\n\t\tdoesResize: true,\n\t\tisAspectRatioLocked: true,\n\t\tembedOnPaste: true,\n\t\ttoEmbedUrl: (url) => {\n\t\t\tconst urlObj = safeParseUrl(url)\n\t\t\tif (urlObj && urlObj.hostname === 'vimeo.com') {\n\t\t\t\tif (urlObj.pathname.match(/^\\/[0-9]+/)) {\n\t\t\t\t\treturn (\n\t\t\t\t\t\t'https://player.vimeo.com/video/' + urlObj.pathname.split('/')[1] + '?title=0&byline=0'\n\t\t\t\t\t)\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn\n\t\t},\n\t\tfromEmbedUrl: (url) => {\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\ttype: 'observable',\n\t\ttitle: 'Observable',\n\t\thostnames: ['observablehq.com'],\n\t\twidth: 720,\n\t\theight: 500,\n\t\tdoesResize: true,\n\t\tisAspectRatioLocked: false,\n\t\tbackgroundColor: '#fff',\n\t\tembedOnPaste: true,\n\t\ttoEmbedUrl: (url) => {\n\t\t\tconst urlObj = safeParseUrl(url)\n\t\t\tif (urlObj && urlObj.pathname.match(/^\\/@([^/]+)\\/([^/]+)\\/?$/)) {\n\t\t\t\treturn `${urlObj.origin}/embed${urlObj.pathname}?cell=*`\n\t\t\t}\n\t\t\tif (urlObj && urlObj.pathname.match(/^\\/d\\/([^/]+)\\/?$/)) {\n\t\t\t\tconst pathName = urlObj.pathname.replace(/^\\/d/, '')\n\t\t\t\treturn `${urlObj.origin}/embed${pathName}?cell=*`\n\t\t\t}\n\n\t\t\treturn\n\t\t},\n\t\tfromEmbedUrl: (url) => {\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\ttype: 'desmos',\n\t\ttitle: 'Desmos',\n\t\thostnames: ['desmos.com'],\n\t\twidth: 700,\n\t\theight: 450,\n\t\tdoesResize: true,\n\t\tembedOnPaste: true,\n\t\ttoEmbedUrl: (url) => {\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 === '' &&\n\t\t\t\turlObj.hash === ''\n\t\t\t) {\n\t\t\t\treturn `${url}?embed`\n\t\t\t}\n\t\t\treturn\n\t\t},\n\t\tfromEmbedUrl: (url) => {\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] as const satisfies readonly EmbedDefinition[]\n\n/**\n * Permissions with note inline from\n * https://developer.mozilla.org/en-US/docs/Web/HTML/Element/iframe#attr-sandbox\n *\n * @public\n */\nexport const embedShapePermissionDefaults = {\n\t// ========================================================================================\n\t// Disabled permissions\n\t// ========================================================================================\n\t// [MDN] Experimental: Allows for downloads to occur without a gesture from the user.\n\t// [REASON] Disabled because otherwise the <iframe/> can trick the user on behalf of us to perform an action.\n\t'allow-downloads-without-user-activation': false,\n\t// [MDN] Allows for downloads to occur with a gesture from the user.\n\t// [REASON] Disabled because otherwise the <iframe/> can trick the user on behalf of us to perform an action.\n\t'allow-downloads': false,\n\t// [MDN] Lets the resource open modal windows.\n\t// [REASON] The <iframe/> could 'window.prompt(\"Enter your tldraw password\")'.\n\t'allow-modals': false,\n\t// [MDN] Lets the resource lock the screen orientation.\n\t// [REASON] Would interfere with the tldraw interface.\n\t'allow-orientation-lock': false,\n\t// [MDN] Lets the resource use the Pointer Lock API.\n\t// [REASON] Maybe we should allow this for games embeds (scratch/codepen/codesandbox).\n\t'allow-pointer-lock': false,\n\t// [MDN] Allows popups (such as window.open(), target=\"_blank\", or showModalDialog()). If this keyword is not used, the popup will silently fail to open.\n\t// [REASON] We want to allow embeds to link back to their original sites (e.g. YouTube).\n\t'allow-popups': true,\n\t// [MDN] Lets the sandboxed document open new windows without those windows inheriting the sandboxing. For example, this can safely sandbox an advertisement without forcing the same restrictions upon the page the ad links to.\n\t// [REASON] We shouldn't allow popups as an embed could pretend to be us by opening a mocked version of tldraw. This is very unobvious when it is performed as an action within our app.\n\t'allow-popups-to-escape-sandbox': false,\n\t// [MDN] Lets the resource start a presentation session.\n\t// [REASON] Prevents embed from navigating away from tldraw and pretending to be us.\n\t'allow-presentation': false,\n\t// [MDN] Experimental: Lets the resource request access to the parent's storage capabilities with the Storage Access API.\n\t// [REASON] We don't want anyone else to access our storage.\n\t'allow-storage-access-by-user-activation': false,\n\t// [MDN] Lets the resource navigate the top-level browsing context (the one named _top).\n\t// [REASON] Prevents embed from navigating away from tldraw and pretending to be us.\n\t'allow-top-navigation': false,\n\t// [MDN] Lets the resource navigate the top-level browsing context, but only if initiated by a user gesture.\n\t// [REASON] Prevents embed from navigating away from tldraw and pretending to be us.\n\t'allow-top-navigation-by-user-activation': false,\n\t// ========================================================================================\n\t// Enabled permissions\n\t// ========================================================================================\n\t// [MDN] Lets the resource run scripts (but not create popup windows).\n\t'allow-scripts': true,\n\t// [MDN] If this token is not used, the resource is treated as being from a special origin that always fails the same-origin policy (potentially preventing access to data storage/cookies and some JavaScript APIs).\n\t'allow-same-origin': true,\n\t// [MDN] Allows the resource to submit forms. If this keyword is not used, form submission is blocked.\n\t'allow-forms': true,\n} as const\n\n/** @public */\nexport type TLEmbedShapePermissions = { [K in keyof typeof embedShapePermissionDefaults]?: boolean }\n\n/** @public */\nexport interface EmbedDefinition {\n\treadonly type: string\n\treadonly title: string\n\treadonly hostnames: readonly string[]\n\treadonly minWidth?: number\n\treadonly minHeight?: number\n\treadonly width: number\n\treadonly height: number\n\treadonly doesResize: boolean\n\treadonly isAspectRatioLocked?: boolean\n\treadonly overridePermissions?: TLEmbedShapePermissions\n\treadonly instructionLink?: string\n\treadonly backgroundColor?: string\n\treadonly embedOnPaste?: boolean\n\t// TODO: FIXME this is ugly be required because some embeds have their own border radius for example spotify embeds\n\treadonly overrideOutlineRadius?: number\n\t// eslint-disable-next-line @typescript-eslint/method-signature-style\n\treadonly toEmbedUrl: (url: string) => string | undefined\n\t// eslint-disable-next-line @typescript-eslint/method-signature-style\n\treadonly fromEmbedUrl: (url: string) => string | undefined\n}\n\n/** @public */\nexport interface CustomEmbedDefinition extends EmbedDefinition {\n\treadonly icon: string\n}\n\n/** @public */\nexport type TLEmbedDefinition = EmbedDefinition | CustomEmbedDefinition\n\n/** @public */\nexport type DefaultEmbedDefinitionType = (typeof DEFAULT_EMBED_DEFINITIONS)[number]['type']\n\nconst DEFAULT_EMBED_DEFINITION_TYPES = DEFAULT_EMBED_DEFINITIONS.map(\n\t(def) => def.type\n) as DefaultEmbedDefinitionType[]\n\n/** @public */\nexport function isDefaultEmbedDefinitionType(type: string): type is DefaultEmbedDefinitionType {\n\treturn DEFAULT_EMBED_DEFINITION_TYPES.includes(type as DefaultEmbedDefinitionType)\n}\n\n/** @public */\nexport function isCustomEmbedDefinition(\n\tdef: EmbedDefinition | CustomEmbedDefinition\n): def is CustomEmbedDefinition {\n\treturn 'icon' in def\n}\n"],
5
5
  "mappings": "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",
6
6
  "names": []
7
7
  }
@@ -231,7 +231,7 @@ function getEdgeFromNormalizedAnchor(normalizedAnchor) {
231
231
  }
232
232
  function getElbowArrowTerminalInfo(editor, arrow, binding, point) {
233
233
  const arrowStrokeSize = import_shared.STROKE_SIZES[arrow.props.size] * arrow.props.scale / 2;
234
- const minEndSegmentLength = arrowStrokeSize * arrow.props.scale * 3;
234
+ const minEndSegmentLength = arrowStrokeSize * 3;
235
235
  if (binding) {
236
236
  const target = editor.getShape(binding.toId);
237
237
  const geometry = getBindingGeometryInArrowSpace(editor, arrow, binding.toId, binding.props);
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../../../../src/lib/shapes/arrow/elbow/getElbowArrowInfo.tsx"],
4
- "sourcesContent": ["import {\n\tapproximately,\n\tassert,\n\tBox,\n\tEditor,\n\texhaustiveSwitchError,\n\tGeometry2dFilters,\n\tlerp,\n\tMat,\n\tTLArrowBinding,\n\tTLArrowBindingProps,\n\tTLArrowShape,\n\tTLShapeId,\n\tVec,\n\tVecLike,\n\tVecModel,\n} from '@tldraw/editor'\nimport { ArrowShapeUtil } from '../ArrowShapeUtil'\nimport { BOUND_ARROW_OFFSET, STROKE_SIZES, TLArrowBindings } from '../shared'\nimport {\n\tElbowArrowAxes,\n\tElbowArrowBox,\n\tElbowArrowBoxEdges,\n\tElbowArrowEdge,\n\tElbowArrowInfo,\n\tElbowArrowInfoWithoutRoute,\n\tElbowArrowOptions,\n\tElbowArrowRoute,\n\tElbowArrowSide,\n\tElbowArrowSideWithAxis,\n\tElbowArrowTargetBox,\n\tElbowArrowTerminal,\n} from './definitions'\nimport { createRange, expandRange, isWithinRange, rangeSize, subtractRange } from './range'\nimport { ElbowArrowWorkingInfo } from './routes/ElbowArrowWorkingInfo'\nimport {\n\trouteArrowWithAutoEdgePicking,\n\trouteArrowWithManualEdgePicking,\n\trouteArrowWithPartialEdgePicking,\n} from './routes/routeArrowWithAutoEdgePicking'\n\nexport function getElbowArrowInfo(\n\teditor: Editor,\n\tarrow: TLArrowShape,\n\tbindings: TLArrowBindings\n): ElbowArrowInfo {\n\tconst shapeOptions = editor.getShapeUtil<ArrowShapeUtil>(arrow.type).options\n\tconst options: ElbowArrowOptions = {\n\t\telbowMidpoint: arrow.props.elbowMidPoint,\n\t\texpandElbowLegLength: shapeOptions.expandElbowLegLength[arrow.props.size] * arrow.props.scale,\n\t\tminElbowLegLength: shapeOptions.minElbowLegLength[arrow.props.size] * arrow.props.scale,\n\t}\n\n\t// Before we can do anything else, we need to find the start and end terminals of the arrow.\n\t// These contain the binding info, geometry, bounds, etc.\n\tlet startTerminal = getElbowArrowTerminalInfo(editor, arrow, bindings.start, arrow.props.start)\n\tlet endTerminal = getElbowArrowTerminalInfo(editor, arrow, bindings.end, arrow.props.end)\n\t// unclosed paths are weird - we handle them outside of the initial terminal info.\n\tstartTerminal = adjustTerminalForUnclosedPathIfNeeded(startTerminal, endTerminal, options)\n\tendTerminal = adjustTerminalForUnclosedPathIfNeeded(endTerminal, startTerminal, options)\n\n\t// Ther terminal might include a \"side\" if the user has explicitly indicated what side the arrow\n\t// should come from. There are two terminals, and two cases for each terminal (explicit side or\n\t// not), for a total for 4 cases to handle. In order to keep things a bit simpler though, we\n\t// only handle 3 cases: if start no side and end has a side, we flip them around. From here on\n\t// out, we use A and B to refer to the terminals as they may be swapped.\n\tconst swapOrder = !!(!startTerminal.side && endTerminal.side)\n\n\tlet { aTerminal, bTerminal } = swapOrder\n\t\t? { aTerminal: endTerminal, bTerminal: startTerminal }\n\t\t: { aTerminal: startTerminal, bTerminal: endTerminal }\n\n\t// We model each edge that an arrow might enter/exit from separately. If an edge is blocked,\n\t// `getUsableEdge` might return null.\n\tlet edgesA = {\n\t\ttop: getUsableEdge(aTerminal, bTerminal, 'top', options),\n\t\tright: getUsableEdge(aTerminal, bTerminal, 'right', options),\n\t\tbottom: getUsableEdge(aTerminal, bTerminal, 'bottom', options),\n\t\tleft: getUsableEdge(aTerminal, bTerminal, 'left', options),\n\t}\n\n\tlet edgesB = {\n\t\ttop: getUsableEdge(bTerminal, aTerminal, 'top', options),\n\t\tright: getUsableEdge(bTerminal, aTerminal, 'right', options),\n\t\tbottom: getUsableEdge(bTerminal, aTerminal, 'bottom', options),\n\t\tleft: getUsableEdge(bTerminal, aTerminal, 'left', options),\n\t}\n\n\t// We we don't have a usable edge because it's blocked, we can convert some of the terminals to\n\t// points. Point terminals have less strict edge routing rules, but don't look as good\n\t// generally. For example, the arrow might go through the shape instead of around.\n\tconst aIsUsable = hasUsableEdge(edgesA, aTerminal.side)\n\tconst bIsUsable = hasUsableEdge(edgesB, bTerminal.side)\n\tlet needsNewEdges = false\n\tif (!aIsUsable || !bIsUsable) {\n\t\tneedsNewEdges = true\n\t\tif (!aIsUsable) {\n\t\t\tbTerminal = convertTerminalToPoint(bTerminal)\n\t\t}\n\n\t\tif (!bIsUsable) {\n\t\t\taTerminal = convertTerminalToPoint(aTerminal)\n\t\t}\n\n\t\tif (bTerminal.bounds.containsPoint(aTerminal.target, options.expandElbowLegLength)) {\n\t\t\tbTerminal = convertTerminalToPoint(bTerminal)\n\t\t}\n\n\t\tif (aTerminal.bounds.containsPoint(bTerminal.target, options.expandElbowLegLength)) {\n\t\t\taTerminal = convertTerminalToPoint(aTerminal)\n\t\t}\n\t}\n\n\tif (needsNewEdges) {\n\t\tedgesA = {\n\t\t\ttop: getUsableEdge(aTerminal, bTerminal, 'top', options),\n\t\t\tright: getUsableEdge(aTerminal, bTerminal, 'right', options),\n\t\t\tbottom: getUsableEdge(aTerminal, bTerminal, 'bottom', options),\n\t\t\tleft: getUsableEdge(aTerminal, bTerminal, 'left', options),\n\t\t}\n\n\t\tedgesB = {\n\t\t\ttop: getUsableEdge(bTerminal, aTerminal, 'top', options),\n\t\t\tright: getUsableEdge(bTerminal, aTerminal, 'right', options),\n\t\t\tbottom: getUsableEdge(bTerminal, aTerminal, 'bottom', options),\n\t\t\tleft: getUsableEdge(bTerminal, aTerminal, 'left', options),\n\t\t}\n\t}\n\n\t// We expand the bounds of the terminals so we can route arrows around them without the arrows\n\t// being too close to the shapes.\n\tconst expandedA = aTerminal.isPoint\n\t\t? aTerminal.bounds\n\t\t: aTerminal.bounds.clone().expandBy(options.expandElbowLegLength)\n\tconst expandedB = bTerminal.isPoint\n\t\t? bTerminal.bounds\n\t\t: bTerminal.bounds.clone().expandBy(options.expandElbowLegLength)\n\n\tconst common: ElbowArrowBox = {\n\t\toriginal: Box.Common([aTerminal.bounds, bTerminal.bounds]),\n\t\texpanded: Box.Common([expandedA, expandedB]),\n\t}\n\n\t// Calculate the gaps between the two terminals. If gap is positive, B is to the right of A. If\n\t// it's negative, the opposite is true. If it's 0, there's no gap between the shapes in that\n\t// dimension.\n\tlet gapX = bTerminal.bounds.minX - aTerminal.bounds.maxX\n\tif (gapX < 0) {\n\t\tgapX = aTerminal.bounds.minX - bTerminal.bounds.maxX\n\t\tif (gapX < 0) {\n\t\t\tgapX = 0\n\t\t}\n\t\tgapX = -gapX\n\t}\n\tlet gapY = bTerminal.bounds.minY - aTerminal.bounds.maxY\n\tif (gapY < 0) {\n\t\tgapY = aTerminal.bounds.minY - bTerminal.bounds.maxY\n\t\tif (gapY < 0) {\n\t\t\tgapY = 0\n\t\t}\n\t\tgapY = -gapY\n\t}\n\n\t// The midpoint of the gap is a useful point to route arrows through, but the user can also drag\n\t// it to choose a new midpoint. First, we calculate some constraints we'll need to keep in mind\n\t// when figuring out the midpoint...\n\tconst aMinLength = aTerminal.minEndSegmentLength * 3\n\tconst bMinLength = bTerminal.minEndSegmentLength * 3\n\tconst minLegDistanceNeeded =\n\t\t(aTerminal.isPoint ? aMinLength : options.minElbowLegLength) +\n\t\t(bTerminal.isPoint ? bMinLength : options.minElbowLegLength)\n\n\t// ...then, the possible range of the midpoint. This is also used when dragging the midpoint.\n\tlet mxRange: null | { a: number; b: number } = null\n\tif (gapX > minLegDistanceNeeded) {\n\t\tmxRange = {\n\t\t\ta: aTerminal.isPoint ? aTerminal.bounds.maxX + aMinLength : expandedA.maxX,\n\t\t\tb: bTerminal.isPoint ? bTerminal.bounds.minX - bMinLength : expandedB.minX,\n\t\t}\n\t} else if (gapX < -minLegDistanceNeeded) {\n\t\tmxRange = {\n\t\t\ta: aTerminal.isPoint ? aTerminal.bounds.minX - aMinLength : expandedA.minX,\n\t\t\tb: bTerminal.isPoint ? bTerminal.bounds.maxX + bMinLength : expandedB.maxX,\n\t\t}\n\t}\n\n\tlet myRange: null | { a: number; b: number } = null\n\tif (gapY > minLegDistanceNeeded) {\n\t\tmyRange = {\n\t\t\ta: aTerminal.isPoint ? aTerminal.bounds.maxY + aMinLength : expandedA.maxY,\n\t\t\tb: bTerminal.isPoint ? bTerminal.bounds.minY - bMinLength : expandedB.minY,\n\t\t}\n\t} else if (gapY < -minLegDistanceNeeded) {\n\t\tmyRange = {\n\t\t\ta: aTerminal.isPoint ? aTerminal.bounds.minY - aMinLength : expandedA.minY,\n\t\t\tb: bTerminal.isPoint ? bTerminal.bounds.maxY + bMinLength : expandedB.maxY,\n\t\t}\n\t}\n\n\t// and finally we take the range and the midpoint prop and calculate the actual position of the\n\t// midpoint. Note that the midpoint and midpoint range can be null if the gap is too small for a\n\t// midpoint line.\n\tconst midpoint = swapOrder ? 1 - options.elbowMidpoint : options.elbowMidpoint\n\tconst mx = mxRange ? lerp(mxRange.a, mxRange.b, midpoint) : null\n\tconst my = myRange ? lerp(myRange.a, myRange.b, midpoint) : null\n\n\t// The info without route is given to the route-finding functions to route between the two\n\t// terminals.\n\tconst info: ElbowArrowInfoWithoutRoute = {\n\t\toptions,\n\t\tswapOrder,\n\t\tA: {\n\t\t\tisPoint: aTerminal.isPoint,\n\t\t\ttarget: aTerminal.target,\n\t\t\tisExact: aTerminal.isExact,\n\t\t\tarrowheadOffset: aTerminal.arrowheadOffset,\n\t\t\tminEndSegmentLength: aTerminal.minEndSegmentLength,\n\t\t\toriginal: aTerminal.bounds,\n\t\t\texpanded: expandedA,\n\t\t\tedges: edgesA,\n\t\t\tgeometry: aTerminal.geometry,\n\t\t},\n\t\tB: {\n\t\t\tisPoint: bTerminal.isPoint,\n\t\t\ttarget: bTerminal.target,\n\t\t\tisExact: bTerminal.isExact,\n\t\t\tarrowheadOffset: bTerminal.arrowheadOffset,\n\t\t\tminEndSegmentLength: bTerminal.minEndSegmentLength,\n\t\t\toriginal: bTerminal.bounds,\n\t\t\texpanded: expandedB,\n\t\t\tedges: edgesB,\n\t\t\tgeometry: bTerminal.geometry,\n\t\t},\n\t\tcommon,\n\t\tgapX,\n\t\tgapY,\n\t\tmidX: mx,\n\t\tmidY: my,\n\t}\n\n\t// We wrap the info in a working info object that lets us mutate and reset it as needed.\n\tconst workingInfo = new ElbowArrowWorkingInfo(info)\n\n\t// Figure out the final sides to use for each terminal.\n\tconst aSide = getSideToUse(aTerminal, bTerminal, info.A.edges)\n\tconst bSide = getSideToUse(bTerminal, aTerminal, info.B.edges)\n\n\t// try to find a route with the specification we have:\n\tlet route\n\tif (aSide && bSide) {\n\t\troute = routeArrowWithManualEdgePicking(workingInfo, aSide, bSide)\n\t} else if (aSide && !bSide) {\n\t\troute = routeArrowWithPartialEdgePicking(workingInfo, aSide)\n\t}\n\tif (!route) {\n\t\troute = routeArrowWithAutoEdgePicking(workingInfo, aSide || bSide ? 'fallback' : 'auto')\n\t}\n\n\tif (route) {\n\t\t// If we found a route, we need to fix it up. The route will only go to the bounding box of\n\t\t// the shape, so we need to cast the final segments into the actual geometry of the shape.\n\t\tcastPathSegmentIntoGeometry('first', info.A, info.B, route)\n\t\tcastPathSegmentIntoGeometry('last', info.B, info.A, route)\n\t\t// If we have tiny L-shaped arrows, the arrowheads look super janky. We fix those up by just\n\t\t// drawing a straight line instead.\n\t\tfixTinyEndNubs(route, aTerminal, bTerminal)\n\n\t\t// If we swapped the order way back of the start of things, we need to reverse the route so\n\t\t// it flows start -> end instead of A -> B.\n\t\tif (swapOrder) route.points.reverse()\n\t}\n\n\treturn {\n\t\t...info,\n\t\troute,\n\t\tmidXRange: mxRange\n\t\t\t? swapOrder\n\t\t\t\t? { lo: mxRange.b, hi: mxRange.a }\n\t\t\t\t: { lo: mxRange.a, hi: mxRange.b }\n\t\t\t: null,\n\t\tmidYRange: myRange\n\t\t\t? swapOrder\n\t\t\t\t? { lo: myRange.b, hi: myRange.a }\n\t\t\t\t: { lo: myRange.a, hi: myRange.b }\n\t\t\t: null,\n\t}\n}\n\n/**\n * Take the route from `getElbowArrowInfo` (which represents the visible body of the arrow) and\n * convert it into a path we can use to show that paths to the handles, which may extend further\n * into the target shape geometries.\n * @returns\n */\nexport function getRouteHandlePath(info: ElbowArrowInfo, route: ElbowArrowRoute): ElbowArrowRoute {\n\tconst startTarget = info.swapOrder ? info.B.target : info.A.target\n\tconst endTarget = info.swapOrder ? info.A.target : info.B.target\n\n\tconst firstSegmentLength = Vec.ManhattanDist(route.points[0], route.points[1])\n\tconst lastSegmentLength = Vec.ManhattanDist(\n\t\troute.points[route.points.length - 2],\n\t\troute.points[route.points.length - 1]\n\t)\n\n\tconst newFirstSegmentLength = Vec.ManhattanDist(startTarget, route.points[1])\n\tconst newLastSegmentLength = Vec.ManhattanDist(route.points[route.points.length - 2], endTarget)\n\n\tconst firstSegmentLengthChange = firstSegmentLength - newFirstSegmentLength\n\tconst lastSegmentLengthChange = lastSegmentLength - newLastSegmentLength\n\n\tconst newPoints = [startTarget, ...route.points, endTarget]\n\n\treturn {\n\t\tname: route.name,\n\t\tdistance: route.distance + firstSegmentLengthChange + lastSegmentLengthChange,\n\t\tpoints: newPoints.filter((p) => !route.skipPointsWhenDrawing.has(p)),\n\t\taEdgePicking: route.aEdgePicking,\n\t\tbEdgePicking: route.bEdgePicking,\n\t\tskipPointsWhenDrawing: route.skipPointsWhenDrawing,\n\t\tmidpointHandle: route.midpointHandle,\n\t}\n}\n\n/**\n * Take a normalizes anchor and return the side we think it's closest to.\n */\nexport function getEdgeFromNormalizedAnchor(normalizedAnchor: VecLike) {\n\tif (approximately(normalizedAnchor.x, 0.5) && approximately(normalizedAnchor.y, 0.5)) {\n\t\treturn null\n\t}\n\n\tif (\n\t\tMath.abs(normalizedAnchor.x - 0.5) >\n\t\t// slightly bias towards x arrows to prevent flickering when the anchor is right on the line\n\t\t// between the two directions\n\t\tMath.abs(normalizedAnchor.y - 0.5) - 0.0001\n\t) {\n\t\treturn normalizedAnchor.x < 0.5 ? 'left' : 'right'\n\t}\n\n\treturn normalizedAnchor.y < 0.5 ? 'top' : 'bottom'\n}\n\nfunction getElbowArrowTerminalInfo(\n\teditor: Editor,\n\tarrow: TLArrowShape,\n\tbinding: TLArrowBinding | undefined,\n\tpoint: VecModel\n): ElbowArrowTerminal {\n\tconst arrowStrokeSize = (STROKE_SIZES[arrow.props.size] * arrow.props.scale) / 2\n\tconst minEndSegmentLength = arrowStrokeSize * arrow.props.scale * 3\n\n\tif (binding) {\n\t\tconst target = editor.getShape(binding.toId)\n\t\tconst geometry = getBindingGeometryInArrowSpace(editor, arrow, binding.toId, binding.props)\n\t\tif (geometry && target) {\n\t\t\tlet arrowheadOffset = 0\n\t\t\tconst arrowheadProp = binding.props.terminal === 'start' ? 'arrowheadStart' : 'arrowheadEnd'\n\t\t\tif (arrow.props[arrowheadProp] !== 'none') {\n\t\t\t\tconst targetScale = 'scale' in target.props ? target.props.scale : 1\n\t\t\t\tconst targetStrokeSize =\n\t\t\t\t\t'size' in target.props ? ((STROKE_SIZES[target.props.size] ?? 0) * targetScale) / 2 : 0\n\n\t\t\t\tarrowheadOffset =\n\t\t\t\t\tarrowStrokeSize + targetStrokeSize + BOUND_ARROW_OFFSET * arrow.props.scale\n\t\t\t}\n\n\t\t\tlet side: ElbowArrowSideWithAxis | null = null\n\t\t\tconst targetPoint = geometry.target\n\t\t\tif (binding.props.isPrecise) {\n\t\t\t\tside = getEdgeFromNormalizedAnchor(\n\t\t\t\t\tVec.RotWith(\n\t\t\t\t\t\tbinding.props.normalizedAnchor,\n\t\t\t\t\t\t{ x: 0.5, y: 0.5 },\n\t\t\t\t\t\tgeometry.shapeToArrowTransform.rotation()\n\t\t\t\t\t)\n\t\t\t\t)\n\t\t\t}\n\n\t\t\treturn {\n\t\t\t\ttargetShapeId: binding.toId,\n\t\t\t\tisPoint: false,\n\t\t\t\tisExact: binding.props.isExact,\n\t\t\t\tbounds: geometry.bounds,\n\t\t\t\tgeometry: geometry.geometry,\n\t\t\t\ttarget: targetPoint,\n\t\t\t\tarrowheadOffset,\n\t\t\t\tminEndSegmentLength,\n\t\t\t\tside,\n\t\t\t\tsnap: binding.props.snap,\n\t\t\t}\n\t\t}\n\t}\n\n\treturn {\n\t\ttargetShapeId: null,\n\t\tbounds: Box.FromCenter(point, { x: 0, y: 0 }),\n\t\tgeometry: null,\n\t\tisExact: false,\n\t\tisPoint: true,\n\t\ttarget: Vec.From(point),\n\t\tarrowheadOffset: 0,\n\t\tminEndSegmentLength,\n\t\tside: null,\n\t\tsnap: 'none',\n\t}\n}\n\nfunction getBindingGeometryInArrowSpace(\n\teditor: Editor,\n\tarrow: TLArrowShape,\n\ttargetId: TLShapeId,\n\tbindingProps: TLArrowBindingProps\n) {\n\tconst hasArrowhead =\n\t\tbindingProps.terminal === 'start'\n\t\t\t? arrow.props.arrowheadStart !== 'none'\n\t\t\t: arrow.props.arrowheadEnd !== 'none'\n\n\tconst targetGeometryInTargetSpace = editor.getShapeGeometry(\n\t\ttargetId,\n\t\thasArrowhead ? undefined : { context: '@tldraw/arrow-without-arrowhead' }\n\t)\n\n\tif (!targetGeometryInTargetSpace) {\n\t\treturn null\n\t}\n\n\tconst arrowTransform = editor.getShapePageTransform(arrow.id)\n\tconst shapeTransform = editor.getShapePageTransform(targetId)\n\tconst shapeToArrowTransform = arrowTransform.clone().invert().multiply(shapeTransform)\n\n\tconst targetGeometryInArrowSpace = targetGeometryInTargetSpace.transform(shapeToArrowTransform)\n\n\tconst center = { x: 0.5, y: 0.5 }\n\tconst normalizedAnchor = bindingProps.isPrecise ? bindingProps.normalizedAnchor : center\n\n\tconst targetInShapeSpace = {\n\t\tx: lerp(\n\t\t\ttargetGeometryInTargetSpace.bounds.minX,\n\t\t\ttargetGeometryInTargetSpace.bounds.maxX,\n\t\t\tnormalizedAnchor.x\n\t\t),\n\t\ty: lerp(\n\t\t\ttargetGeometryInTargetSpace.bounds.minY,\n\t\t\ttargetGeometryInTargetSpace.bounds.maxY,\n\t\t\tnormalizedAnchor.y\n\t\t),\n\t}\n\tconst centerInShapeSpace = {\n\t\tx: lerp(\n\t\t\ttargetGeometryInTargetSpace.bounds.minX,\n\t\t\ttargetGeometryInTargetSpace.bounds.maxX,\n\t\t\tcenter.x\n\t\t),\n\t\ty: lerp(\n\t\t\ttargetGeometryInTargetSpace.bounds.minY,\n\t\t\ttargetGeometryInTargetSpace.bounds.maxY,\n\t\t\tcenter.y\n\t\t),\n\t}\n\n\tconst targetInArrowSpace = Mat.applyToPoint(shapeToArrowTransform, targetInShapeSpace)\n\tconst centerInArrowSpace = Mat.applyToPoint(shapeToArrowTransform, centerInShapeSpace)\n\n\treturn {\n\t\tbounds: targetGeometryInArrowSpace.bounds,\n\t\tgeometry: targetGeometryInArrowSpace,\n\t\ttarget: targetInArrowSpace,\n\t\tcenter: centerInArrowSpace,\n\t\tshapeToArrowTransform,\n\t}\n}\n\nconst sideProps = {\n\ttop: {\n\t\texpand: -1,\n\t\tmain: 'minY',\n\t\topposite: 'maxY',\n\t\tcrossMid: 'midX',\n\t\tcrossMin: 'minX',\n\t\tcrossMax: 'maxX',\n\t\tbRangeExpand: 'max',\n\t\tcrossAxis: 'x',\n\t},\n\tbottom: {\n\t\texpand: 1,\n\t\tmain: 'maxY',\n\t\topposite: 'minY',\n\t\tcrossMid: 'midX',\n\t\tcrossMin: 'minX',\n\t\tcrossMax: 'maxX',\n\t\tbRangeExpand: 'min',\n\t\tcrossAxis: 'x',\n\t},\n\tleft: {\n\t\texpand: -1,\n\t\tmain: 'minX',\n\t\topposite: 'maxX',\n\t\tcrossMid: 'midY',\n\t\tcrossMin: 'minY',\n\t\tcrossMax: 'maxY',\n\t\tbRangeExpand: 'max',\n\t\tcrossAxis: 'y',\n\t},\n\tright: {\n\t\texpand: 1,\n\t\tmain: 'maxX',\n\t\topposite: 'minX',\n\t\tcrossMid: 'midY',\n\t\tcrossMin: 'minY',\n\t\tcrossMax: 'maxY',\n\t\tbRangeExpand: 'min',\n\t\tcrossAxis: 'y',\n\t},\n} as const\n\nexport function getUsableEdge(\n\ta: ElbowArrowTerminal,\n\tb: ElbowArrowTerminal,\n\tside: 'top' | 'right' | 'bottom' | 'left',\n\toptions: ElbowArrowOptions\n): ElbowArrowEdge | null {\n\tconst props = sideProps[side]\n\n\t// if a shape is bound to itself, by default we'd end up routing the arrow _within_ the shape -\n\t// as if it were a point-to-point arrow. if one of the bindings is specifically to the edge\n\t// though, we route it externally instead.\n\tconst isSelfBoundAndShouldRouteExternal =\n\t\ta.targetShapeId === b.targetShapeId &&\n\t\ta.targetShapeId !== null &&\n\t\t(a.snap === 'edge' || a.snap === 'edge-point') &&\n\t\t(b.snap === 'edge' || b.snap === 'edge-point')\n\n\tconst aValue = a.bounds[props.main]\n\tconst aExpanded = a.isPoint ? null : aValue + props.expand * options.expandElbowLegLength\n\n\tconst originalACrossRange = createRange(a.bounds[props.crossMin], a.bounds[props.crossMax])\n\tlet aCrossRange = originalACrossRange\n\n\t// this edge is too small to be useful:\n\tif (!aCrossRange) {\n\t\treturn null\n\t}\n\n\tassert(originalACrossRange)\n\tconst bRange = createRange(b.bounds[props.main], b.bounds[props.opposite])\n\tif (!b.isPoint) {\n\t\tbRange[props.bRangeExpand] -= options.minElbowLegLength * 2 * props.expand\n\t}\n\n\tconst bCrossRange = expandRange(\n\t\tcreateRange(b.bounds[props.crossMin], b.bounds[props.crossMax]),\n\t\toptions.expandElbowLegLength\n\t)\n\tassert(bRange && bCrossRange)\n\n\tlet isPartial = false\n\tif (\n\t\tisWithinRange(aValue, bRange) &&\n\t\t!a.isPoint &&\n\t\t!b.isPoint &&\n\t\t!isSelfBoundAndShouldRouteExternal\n\t) {\n\t\tconst subtracted = subtractRange(aCrossRange, bCrossRange)\n\t\tswitch (subtracted.length) {\n\t\t\tcase 0:\n\t\t\t\treturn null\n\t\t\tcase 1:\n\t\t\t\tisPartial = subtracted[0] !== aCrossRange\n\t\t\t\taCrossRange = subtracted[0]\n\t\t\t\tbreak\n\t\t\tcase 2:\n\t\t\t\tisPartial = true\n\t\t\t\taCrossRange =\n\t\t\t\t\trangeSize(subtracted[0]) > rangeSize(subtracted[1]) ? subtracted[0] : subtracted[1]\n\t\t\t\tbreak\n\t\t\tdefault:\n\t\t\t\texhaustiveSwitchError(subtracted)\n\t\t}\n\t}\n\n\tif (!isWithinRange(a.target[props.crossAxis], aCrossRange)) {\n\t\treturn null\n\t}\n\tconst crossTarget = a.target[props.crossAxis]\n\n\treturn {\n\t\tvalue: aValue,\n\t\texpanded: aExpanded,\n\t\tcross: aCrossRange,\n\t\tcrossTarget,\n\t\tisPartial,\n\t}\n}\n\nfunction hasUsableEdge(edges: ElbowArrowBoxEdges, side: ElbowArrowSideWithAxis | null) {\n\tif (side === null) {\n\t\treturn !!(edges.bottom || edges.left || edges.right || edges.top)\n\t}\n\n\tif (side === 'x') {\n\t\treturn !!edges.left || !!edges.right\n\t}\n\n\tif (side === 'y') {\n\t\treturn !!edges.top || !!edges.bottom\n\t}\n\n\treturn !!edges[side]\n}\n\nfunction getSideToUse(\n\tbinding: ElbowArrowTerminal,\n\tother: ElbowArrowTerminal,\n\tedges: ElbowArrowBoxEdges | null\n): ElbowArrowSide | null {\n\tswitch (binding.side) {\n\t\tcase null:\n\t\t\treturn null\n\t\tcase 'x':\n\t\t\tif (binding.bounds.center.x > other.bounds.center.x && edges?.left) {\n\t\t\t\treturn 'left'\n\t\t\t} else if (edges?.right) {\n\t\t\t\treturn 'right'\n\t\t\t}\n\t\t\treturn null\n\t\tcase 'y':\n\t\t\tif (binding.bounds.center.y > other.bounds.center.y && edges?.top) {\n\t\t\t\treturn 'top'\n\t\t\t} else if (edges?.bottom) {\n\t\t\t\treturn 'bottom'\n\t\t\t}\n\t\t\treturn null\n\t\tdefault:\n\t\t\treturn binding.side\n\t}\n}\n\nfunction convertTerminalToPoint(terminal: ElbowArrowTerminal): ElbowArrowTerminal {\n\tif (terminal.isPoint) return terminal\n\n\tlet side: ElbowArrowSideWithAxis | null = null\n\tlet arrowheadOffset = 0\n\tif (terminal.snap === 'edge' || terminal.snap === 'edge-point') {\n\t\tarrowheadOffset = terminal.arrowheadOffset\n\t\tif (terminal.side === 'x' || terminal.side === 'left' || terminal.side === 'right') {\n\t\t\tside = 'x'\n\t\t}\n\t\tif (terminal.side === 'y' || terminal.side === 'top' || terminal.side === 'bottom') {\n\t\t\tside = 'y'\n\t\t}\n\t}\n\n\treturn {\n\t\ttargetShapeId: terminal.targetShapeId,\n\t\tside,\n\t\tbounds: new Box(terminal.target.x, terminal.target.y, 0, 0),\n\t\tgeometry: terminal.geometry,\n\t\ttarget: terminal.target,\n\t\tarrowheadOffset,\n\t\tminEndSegmentLength: terminal.minEndSegmentLength,\n\t\tisExact: terminal.isExact,\n\t\tisPoint: true,\n\t\tsnap: terminal.snap,\n\t}\n}\n\n/**\n * Make sure the first path segments goes fully into the target, and doesn't just point to its\n * bounding box. This modifies the route in-place.\n */\nfunction castPathSegmentIntoGeometry(\n\tsegment: 'first' | 'last',\n\ttarget: ElbowArrowTargetBox,\n\tother: ElbowArrowTargetBox,\n\troute: ElbowArrowRoute\n) {\n\tif (!target.geometry) return\n\n\tconst point1 = segment === 'first' ? route.points[0] : route.points[route.points.length - 1]\n\tconst point2 = segment === 'first' ? route.points[1] : route.points[route.points.length - 2]\n\n\tconst pointToFindClosestIntersectionTo = target.geometry.isClosed ? point2 : target.target\n\n\tconst initialDistance = Vec.ManhattanDist(point1, pointToFindClosestIntersectionTo)\n\n\tlet nearestIntersectionToPoint2: VecLike | null = null\n\tlet nearestDistanceToPoint2 = Infinity\n\n\tif (target.isExact) {\n\t\tnearestIntersectionToPoint2 = target.target\n\t} else if (target.geometry) {\n\t\tconst intersections = target.geometry.intersectLineSegment(point2, target.target, {\n\t\t\tincludeLabels: false,\n\t\t\tincludeInternal: false,\n\t\t})\n\t\tif (\n\t\t\ttarget.geometry.hitTestPoint(\n\t\t\t\ttarget.target,\n\t\t\t\tMath.max(1, target.arrowheadOffset),\n\t\t\t\ttrue,\n\t\t\t\tGeometry2dFilters.EXCLUDE_NON_STANDARD\n\t\t\t)\n\t\t) {\n\t\t\tintersections.push(target.target)\n\t\t}\n\t\tfor (const intersection of intersections) {\n\t\t\tconst point2Distance = Vec.ManhattanDist(pointToFindClosestIntersectionTo, intersection)\n\t\t\tif (point2Distance < nearestDistanceToPoint2) {\n\t\t\t\tnearestDistanceToPoint2 = point2Distance\n\t\t\t\tnearestIntersectionToPoint2 = intersection\n\t\t\t}\n\t\t}\n\t}\n\n\tif (nearestIntersectionToPoint2) {\n\t\tlet offset = target.arrowheadOffset\n\n\t\tconst currentFinalSegmentLength = Vec.ManhattanDist(point2, nearestIntersectionToPoint2)\n\t\tconst minLength = target.arrowheadOffset * 2\n\t\tif (currentFinalSegmentLength < minLength) {\n\t\t\tconst targetLength = minLength - target.arrowheadOffset\n\t\t\toffset = currentFinalSegmentLength - targetLength\n\t\t}\n\t\tif (offset < target.minEndSegmentLength) {\n\t\t\tif (target.geometry.bounds.containsPoint(other.target)) {\n\t\t\t\toffset = Math.max(0, offset)\n\t\t\t} else {\n\t\t\t\toffset = -target.arrowheadOffset\n\t\t\t}\n\t\t}\n\n\t\tlet nudgedPoint = nearestIntersectionToPoint2\n\t\tlet shouldAddExtraPointForNudge = false\n\t\tif (!target.isExact && offset !== 0) {\n\t\t\tconst nudged = Vec.Nudge(nearestIntersectionToPoint2, point2, offset)\n\t\t\tnudgedPoint = nudged\n\t\t\tif (\n\t\t\t\toffset < 0 &&\n\t\t\t\t!target.geometry.hitTestPoint(nudged, 0, true, Geometry2dFilters.EXCLUDE_NON_STANDARD)\n\t\t\t) {\n\t\t\t\t// point has been nudged _out_ of the shape so lets not actually apply the nudge\n\t\t\t\tnudgedPoint = nearestIntersectionToPoint2\n\t\t\t} else {\n\t\t\t\tif (offset < 0) {\n\t\t\t\t\tshouldAddExtraPointForNudge = true\n\t\t\t\t}\n\t\t\t\tnudgedPoint = nudged\n\t\t\t}\n\t\t}\n\n\t\tconst newDistance = Vec.ManhattanDist(point2, nudgedPoint)\n\t\troute.distance += newDistance - initialDistance\n\t\tpoint1.x = nudgedPoint.x\n\t\tpoint1.y = nudgedPoint.y\n\n\t\tif (shouldAddExtraPointForNudge) {\n\t\t\tconst midPoint = Vec.Lrp(point2, point1, 0.5)\n\t\t\troute.skipPointsWhenDrawing.add(midPoint)\n\t\t\troute.points.splice(segment === 'first' ? 1 : route.points.length - 1, 0, midPoint)\n\t\t}\n\t}\n}\n\nfunction fixTinyEndNubs(\n\troute: ElbowArrowRoute,\n\taTerminal: ElbowArrowTerminal,\n\tbTerminal: ElbowArrowTerminal\n) {\n\tif (!route) return\n\n\tif (route.points.length >= 3) {\n\t\tconst a = route.points[0]\n\t\tconst b = route.points[1]\n\t\tconst firstSegmentLength = Vec.ManhattanDist(a, b)\n\t\tif (firstSegmentLength < aTerminal.minEndSegmentLength) {\n\t\t\troute.points.splice(1, 1)\n\t\t\tif (route.points.length >= 3) {\n\t\t\t\tconst matchAxis = approximately(a.x, b.x) ? 'y' : 'x'\n\t\t\t\troute.points[1][matchAxis] = a[matchAxis]\n\t\t\t}\n\t\t}\n\t}\n\n\tif (route.points.length >= 3) {\n\t\tconst a = route.points[route.points.length - 1]\n\t\tconst b = route.points[route.points.length - 2]\n\t\tconst lastSegmentLength = Vec.ManhattanDist(a, b)\n\t\tif (lastSegmentLength < bTerminal.minEndSegmentLength) {\n\t\t\troute.points.splice(route.points.length - 2, 1)\n\t\t\tif (route.points.length >= 3) {\n\t\t\t\tconst matchAxis = approximately(a.x, b.x) ? 'y' : 'x'\n\t\t\t\troute.points[route.points.length - 2][matchAxis] = a[matchAxis]\n\t\t\t}\n\t\t}\n\t}\n}\n\nfunction adjustTerminalForUnclosedPathIfNeeded(\n\tterminal: ElbowArrowTerminal,\n\totherTerminal: ElbowArrowTerminal,\n\toptions: ElbowArrowOptions\n): ElbowArrowTerminal {\n\tif (!terminal.geometry || terminal.geometry.isClosed) return terminal\n\tconst normalizedPointAlongPath = terminal.geometry.uninterpolateAlongEdge(\n\t\tterminal.target,\n\t\tGeometry2dFilters.EXCLUDE_NON_STANDARD\n\t)\n\n\tconst prev = terminal.geometry.interpolateAlongEdge(\n\t\tnormalizedPointAlongPath - 0.01 / terminal.geometry.length\n\t)\n\tconst next = terminal.geometry.interpolateAlongEdge(\n\t\tnormalizedPointAlongPath + 0.01 / terminal.geometry.length\n\t)\n\n\tconst normal = next.sub(prev).per().uni()\n\tconst axis = Math.abs(normal.x) > Math.abs(normal.y) ? ElbowArrowAxes.x : ElbowArrowAxes.y\n\n\tif (terminal.geometry.bounds.containsPoint(otherTerminal.target, options.expandElbowLegLength)) {\n\t\tterminal.side = axis.self\n\t\treturn convertTerminalToPoint(terminal)\n\t}\n\n\tconst min = axis.v(\n\t\tterminal.target[axis.self] - terminal.bounds[axis.size] * 2,\n\t\tterminal.target[axis.cross]\n\t)\n\tconst max = axis.v(\n\t\tterminal.target[axis.self] + terminal.bounds[axis.size] * 2,\n\t\tterminal.target[axis.cross]\n\t)\n\n\tlet furthestIntersectionTowardsMin: VecLike | null = null\n\tlet furthestIntersectionTowardsMinDistance = 0\n\tlet furthestIntersectionTowardsMax: VecLike | null = null\n\tlet furthestIntersectionTowardsMaxDistance = 0\n\tlet side: ElbowArrowSideWithAxis = axis.self\n\n\tfor (const intersection of terminal.geometry.intersectLineSegment(\n\t\tmin,\n\t\tmax,\n\t\tGeometry2dFilters.EXCLUDE_NON_STANDARD\n\t)) {\n\t\tif (Math.abs(intersection[axis.self] - terminal.target[axis.self]) < 1) {\n\t\t\tcontinue\n\t\t}\n\t\tif (intersection[axis.self] < terminal.target[axis.self]) {\n\t\t\tif (\n\t\t\t\tVec.ManhattanDist(intersection, terminal.target) > furthestIntersectionTowardsMinDistance\n\t\t\t) {\n\t\t\t\tfurthestIntersectionTowardsMinDistance = Vec.ManhattanDist(intersection, terminal.target)\n\t\t\t\tfurthestIntersectionTowardsMin = intersection\n\t\t\t}\n\t\t} else {\n\t\t\tif (\n\t\t\t\tVec.ManhattanDist(intersection, terminal.target) > furthestIntersectionTowardsMaxDistance\n\t\t\t) {\n\t\t\t\tfurthestIntersectionTowardsMaxDistance = Vec.ManhattanDist(intersection, terminal.target)\n\t\t\t\tfurthestIntersectionTowardsMax = intersection\n\t\t\t}\n\t\t}\n\t}\n\n\tif (furthestIntersectionTowardsMin && furthestIntersectionTowardsMax) {\n\t\tif (furthestIntersectionTowardsMinDistance > furthestIntersectionTowardsMaxDistance) {\n\t\t\tside = axis.hiEdge\n\t\t} else {\n\t\t\tside = axis.loEdge\n\t\t}\n\t} else if (furthestIntersectionTowardsMin && !furthestIntersectionTowardsMax) {\n\t\tside = axis.hiEdge\n\t} else if (!furthestIntersectionTowardsMin && furthestIntersectionTowardsMax) {\n\t\tside = axis.loEdge\n\t}\n\n\tterminal.side = side\n\treturn terminal\n}\n"],
5
- "mappings": "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",
4
+ "sourcesContent": ["import {\n\tapproximately,\n\tassert,\n\tBox,\n\tEditor,\n\texhaustiveSwitchError,\n\tGeometry2dFilters,\n\tlerp,\n\tMat,\n\tTLArrowBinding,\n\tTLArrowBindingProps,\n\tTLArrowShape,\n\tTLShapeId,\n\tVec,\n\tVecLike,\n\tVecModel,\n} from '@tldraw/editor'\nimport { ArrowShapeUtil } from '../ArrowShapeUtil'\nimport { BOUND_ARROW_OFFSET, STROKE_SIZES, TLArrowBindings } from '../shared'\nimport {\n\tElbowArrowAxes,\n\tElbowArrowBox,\n\tElbowArrowBoxEdges,\n\tElbowArrowEdge,\n\tElbowArrowInfo,\n\tElbowArrowInfoWithoutRoute,\n\tElbowArrowOptions,\n\tElbowArrowRoute,\n\tElbowArrowSide,\n\tElbowArrowSideWithAxis,\n\tElbowArrowTargetBox,\n\tElbowArrowTerminal,\n} from './definitions'\nimport { createRange, expandRange, isWithinRange, rangeSize, subtractRange } from './range'\nimport { ElbowArrowWorkingInfo } from './routes/ElbowArrowWorkingInfo'\nimport {\n\trouteArrowWithAutoEdgePicking,\n\trouteArrowWithManualEdgePicking,\n\trouteArrowWithPartialEdgePicking,\n} from './routes/routeArrowWithAutoEdgePicking'\n\nexport function getElbowArrowInfo(\n\teditor: Editor,\n\tarrow: TLArrowShape,\n\tbindings: TLArrowBindings\n): ElbowArrowInfo {\n\tconst shapeOptions = editor.getShapeUtil<ArrowShapeUtil>(arrow.type).options\n\tconst options: ElbowArrowOptions = {\n\t\telbowMidpoint: arrow.props.elbowMidPoint,\n\t\texpandElbowLegLength: shapeOptions.expandElbowLegLength[arrow.props.size] * arrow.props.scale,\n\t\tminElbowLegLength: shapeOptions.minElbowLegLength[arrow.props.size] * arrow.props.scale,\n\t}\n\n\t// Before we can do anything else, we need to find the start and end terminals of the arrow.\n\t// These contain the binding info, geometry, bounds, etc.\n\tlet startTerminal = getElbowArrowTerminalInfo(editor, arrow, bindings.start, arrow.props.start)\n\tlet endTerminal = getElbowArrowTerminalInfo(editor, arrow, bindings.end, arrow.props.end)\n\t// unclosed paths are weird - we handle them outside of the initial terminal info.\n\tstartTerminal = adjustTerminalForUnclosedPathIfNeeded(startTerminal, endTerminal, options)\n\tendTerminal = adjustTerminalForUnclosedPathIfNeeded(endTerminal, startTerminal, options)\n\n\t// Ther terminal might include a \"side\" if the user has explicitly indicated what side the arrow\n\t// should come from. There are two terminals, and two cases for each terminal (explicit side or\n\t// not), for a total for 4 cases to handle. In order to keep things a bit simpler though, we\n\t// only handle 3 cases: if start no side and end has a side, we flip them around. From here on\n\t// out, we use A and B to refer to the terminals as they may be swapped.\n\tconst swapOrder = !!(!startTerminal.side && endTerminal.side)\n\n\tlet { aTerminal, bTerminal } = swapOrder\n\t\t? { aTerminal: endTerminal, bTerminal: startTerminal }\n\t\t: { aTerminal: startTerminal, bTerminal: endTerminal }\n\n\t// We model each edge that an arrow might enter/exit from separately. If an edge is blocked,\n\t// `getUsableEdge` might return null.\n\tlet edgesA = {\n\t\ttop: getUsableEdge(aTerminal, bTerminal, 'top', options),\n\t\tright: getUsableEdge(aTerminal, bTerminal, 'right', options),\n\t\tbottom: getUsableEdge(aTerminal, bTerminal, 'bottom', options),\n\t\tleft: getUsableEdge(aTerminal, bTerminal, 'left', options),\n\t}\n\n\tlet edgesB = {\n\t\ttop: getUsableEdge(bTerminal, aTerminal, 'top', options),\n\t\tright: getUsableEdge(bTerminal, aTerminal, 'right', options),\n\t\tbottom: getUsableEdge(bTerminal, aTerminal, 'bottom', options),\n\t\tleft: getUsableEdge(bTerminal, aTerminal, 'left', options),\n\t}\n\n\t// We we don't have a usable edge because it's blocked, we can convert some of the terminals to\n\t// points. Point terminals have less strict edge routing rules, but don't look as good\n\t// generally. For example, the arrow might go through the shape instead of around.\n\tconst aIsUsable = hasUsableEdge(edgesA, aTerminal.side)\n\tconst bIsUsable = hasUsableEdge(edgesB, bTerminal.side)\n\tlet needsNewEdges = false\n\tif (!aIsUsable || !bIsUsable) {\n\t\tneedsNewEdges = true\n\t\tif (!aIsUsable) {\n\t\t\tbTerminal = convertTerminalToPoint(bTerminal)\n\t\t}\n\n\t\tif (!bIsUsable) {\n\t\t\taTerminal = convertTerminalToPoint(aTerminal)\n\t\t}\n\n\t\tif (bTerminal.bounds.containsPoint(aTerminal.target, options.expandElbowLegLength)) {\n\t\t\tbTerminal = convertTerminalToPoint(bTerminal)\n\t\t}\n\n\t\tif (aTerminal.bounds.containsPoint(bTerminal.target, options.expandElbowLegLength)) {\n\t\t\taTerminal = convertTerminalToPoint(aTerminal)\n\t\t}\n\t}\n\n\tif (needsNewEdges) {\n\t\tedgesA = {\n\t\t\ttop: getUsableEdge(aTerminal, bTerminal, 'top', options),\n\t\t\tright: getUsableEdge(aTerminal, bTerminal, 'right', options),\n\t\t\tbottom: getUsableEdge(aTerminal, bTerminal, 'bottom', options),\n\t\t\tleft: getUsableEdge(aTerminal, bTerminal, 'left', options),\n\t\t}\n\n\t\tedgesB = {\n\t\t\ttop: getUsableEdge(bTerminal, aTerminal, 'top', options),\n\t\t\tright: getUsableEdge(bTerminal, aTerminal, 'right', options),\n\t\t\tbottom: getUsableEdge(bTerminal, aTerminal, 'bottom', options),\n\t\t\tleft: getUsableEdge(bTerminal, aTerminal, 'left', options),\n\t\t}\n\t}\n\n\t// We expand the bounds of the terminals so we can route arrows around them without the arrows\n\t// being too close to the shapes.\n\tconst expandedA = aTerminal.isPoint\n\t\t? aTerminal.bounds\n\t\t: aTerminal.bounds.clone().expandBy(options.expandElbowLegLength)\n\tconst expandedB = bTerminal.isPoint\n\t\t? bTerminal.bounds\n\t\t: bTerminal.bounds.clone().expandBy(options.expandElbowLegLength)\n\n\tconst common: ElbowArrowBox = {\n\t\toriginal: Box.Common([aTerminal.bounds, bTerminal.bounds]),\n\t\texpanded: Box.Common([expandedA, expandedB]),\n\t}\n\n\t// Calculate the gaps between the two terminals. If gap is positive, B is to the right of A. If\n\t// it's negative, the opposite is true. If it's 0, there's no gap between the shapes in that\n\t// dimension.\n\tlet gapX = bTerminal.bounds.minX - aTerminal.bounds.maxX\n\tif (gapX < 0) {\n\t\tgapX = aTerminal.bounds.minX - bTerminal.bounds.maxX\n\t\tif (gapX < 0) {\n\t\t\tgapX = 0\n\t\t}\n\t\tgapX = -gapX\n\t}\n\tlet gapY = bTerminal.bounds.minY - aTerminal.bounds.maxY\n\tif (gapY < 0) {\n\t\tgapY = aTerminal.bounds.minY - bTerminal.bounds.maxY\n\t\tif (gapY < 0) {\n\t\t\tgapY = 0\n\t\t}\n\t\tgapY = -gapY\n\t}\n\n\t// The midpoint of the gap is a useful point to route arrows through, but the user can also drag\n\t// it to choose a new midpoint. First, we calculate some constraints we'll need to keep in mind\n\t// when figuring out the midpoint...\n\tconst aMinLength = aTerminal.minEndSegmentLength * 3\n\tconst bMinLength = bTerminal.minEndSegmentLength * 3\n\tconst minLegDistanceNeeded =\n\t\t(aTerminal.isPoint ? aMinLength : options.minElbowLegLength) +\n\t\t(bTerminal.isPoint ? bMinLength : options.minElbowLegLength)\n\n\t// ...then, the possible range of the midpoint. This is also used when dragging the midpoint.\n\tlet mxRange: null | { a: number; b: number } = null\n\tif (gapX > minLegDistanceNeeded) {\n\t\tmxRange = {\n\t\t\ta: aTerminal.isPoint ? aTerminal.bounds.maxX + aMinLength : expandedA.maxX,\n\t\t\tb: bTerminal.isPoint ? bTerminal.bounds.minX - bMinLength : expandedB.minX,\n\t\t}\n\t} else if (gapX < -minLegDistanceNeeded) {\n\t\tmxRange = {\n\t\t\ta: aTerminal.isPoint ? aTerminal.bounds.minX - aMinLength : expandedA.minX,\n\t\t\tb: bTerminal.isPoint ? bTerminal.bounds.maxX + bMinLength : expandedB.maxX,\n\t\t}\n\t}\n\n\tlet myRange: null | { a: number; b: number } = null\n\tif (gapY > minLegDistanceNeeded) {\n\t\tmyRange = {\n\t\t\ta: aTerminal.isPoint ? aTerminal.bounds.maxY + aMinLength : expandedA.maxY,\n\t\t\tb: bTerminal.isPoint ? bTerminal.bounds.minY - bMinLength : expandedB.minY,\n\t\t}\n\t} else if (gapY < -minLegDistanceNeeded) {\n\t\tmyRange = {\n\t\t\ta: aTerminal.isPoint ? aTerminal.bounds.minY - aMinLength : expandedA.minY,\n\t\t\tb: bTerminal.isPoint ? bTerminal.bounds.maxY + bMinLength : expandedB.maxY,\n\t\t}\n\t}\n\n\t// and finally we take the range and the midpoint prop and calculate the actual position of the\n\t// midpoint. Note that the midpoint and midpoint range can be null if the gap is too small for a\n\t// midpoint line.\n\tconst midpoint = swapOrder ? 1 - options.elbowMidpoint : options.elbowMidpoint\n\tconst mx = mxRange ? lerp(mxRange.a, mxRange.b, midpoint) : null\n\tconst my = myRange ? lerp(myRange.a, myRange.b, midpoint) : null\n\n\t// The info without route is given to the route-finding functions to route between the two\n\t// terminals.\n\tconst info: ElbowArrowInfoWithoutRoute = {\n\t\toptions,\n\t\tswapOrder,\n\t\tA: {\n\t\t\tisPoint: aTerminal.isPoint,\n\t\t\ttarget: aTerminal.target,\n\t\t\tisExact: aTerminal.isExact,\n\t\t\tarrowheadOffset: aTerminal.arrowheadOffset,\n\t\t\tminEndSegmentLength: aTerminal.minEndSegmentLength,\n\t\t\toriginal: aTerminal.bounds,\n\t\t\texpanded: expandedA,\n\t\t\tedges: edgesA,\n\t\t\tgeometry: aTerminal.geometry,\n\t\t},\n\t\tB: {\n\t\t\tisPoint: bTerminal.isPoint,\n\t\t\ttarget: bTerminal.target,\n\t\t\tisExact: bTerminal.isExact,\n\t\t\tarrowheadOffset: bTerminal.arrowheadOffset,\n\t\t\tminEndSegmentLength: bTerminal.minEndSegmentLength,\n\t\t\toriginal: bTerminal.bounds,\n\t\t\texpanded: expandedB,\n\t\t\tedges: edgesB,\n\t\t\tgeometry: bTerminal.geometry,\n\t\t},\n\t\tcommon,\n\t\tgapX,\n\t\tgapY,\n\t\tmidX: mx,\n\t\tmidY: my,\n\t}\n\n\t// We wrap the info in a working info object that lets us mutate and reset it as needed.\n\tconst workingInfo = new ElbowArrowWorkingInfo(info)\n\n\t// Figure out the final sides to use for each terminal.\n\tconst aSide = getSideToUse(aTerminal, bTerminal, info.A.edges)\n\tconst bSide = getSideToUse(bTerminal, aTerminal, info.B.edges)\n\n\t// try to find a route with the specification we have:\n\tlet route\n\tif (aSide && bSide) {\n\t\troute = routeArrowWithManualEdgePicking(workingInfo, aSide, bSide)\n\t} else if (aSide && !bSide) {\n\t\troute = routeArrowWithPartialEdgePicking(workingInfo, aSide)\n\t}\n\tif (!route) {\n\t\troute = routeArrowWithAutoEdgePicking(workingInfo, aSide || bSide ? 'fallback' : 'auto')\n\t}\n\n\tif (route) {\n\t\t// If we found a route, we need to fix it up. The route will only go to the bounding box of\n\t\t// the shape, so we need to cast the final segments into the actual geometry of the shape.\n\t\tcastPathSegmentIntoGeometry('first', info.A, info.B, route)\n\t\tcastPathSegmentIntoGeometry('last', info.B, info.A, route)\n\t\t// If we have tiny L-shaped arrows, the arrowheads look super janky. We fix those up by just\n\t\t// drawing a straight line instead.\n\t\tfixTinyEndNubs(route, aTerminal, bTerminal)\n\n\t\t// If we swapped the order way back of the start of things, we need to reverse the route so\n\t\t// it flows start -> end instead of A -> B.\n\t\tif (swapOrder) route.points.reverse()\n\t}\n\n\treturn {\n\t\t...info,\n\t\troute,\n\t\tmidXRange: mxRange\n\t\t\t? swapOrder\n\t\t\t\t? { lo: mxRange.b, hi: mxRange.a }\n\t\t\t\t: { lo: mxRange.a, hi: mxRange.b }\n\t\t\t: null,\n\t\tmidYRange: myRange\n\t\t\t? swapOrder\n\t\t\t\t? { lo: myRange.b, hi: myRange.a }\n\t\t\t\t: { lo: myRange.a, hi: myRange.b }\n\t\t\t: null,\n\t}\n}\n\n/**\n * Take the route from `getElbowArrowInfo` (which represents the visible body of the arrow) and\n * convert it into a path we can use to show that paths to the handles, which may extend further\n * into the target shape geometries.\n * @returns\n */\nexport function getRouteHandlePath(info: ElbowArrowInfo, route: ElbowArrowRoute): ElbowArrowRoute {\n\tconst startTarget = info.swapOrder ? info.B.target : info.A.target\n\tconst endTarget = info.swapOrder ? info.A.target : info.B.target\n\n\tconst firstSegmentLength = Vec.ManhattanDist(route.points[0], route.points[1])\n\tconst lastSegmentLength = Vec.ManhattanDist(\n\t\troute.points[route.points.length - 2],\n\t\troute.points[route.points.length - 1]\n\t)\n\n\tconst newFirstSegmentLength = Vec.ManhattanDist(startTarget, route.points[1])\n\tconst newLastSegmentLength = Vec.ManhattanDist(route.points[route.points.length - 2], endTarget)\n\n\tconst firstSegmentLengthChange = firstSegmentLength - newFirstSegmentLength\n\tconst lastSegmentLengthChange = lastSegmentLength - newLastSegmentLength\n\n\tconst newPoints = [startTarget, ...route.points, endTarget]\n\n\treturn {\n\t\tname: route.name,\n\t\tdistance: route.distance + firstSegmentLengthChange + lastSegmentLengthChange,\n\t\tpoints: newPoints.filter((p) => !route.skipPointsWhenDrawing.has(p)),\n\t\taEdgePicking: route.aEdgePicking,\n\t\tbEdgePicking: route.bEdgePicking,\n\t\tskipPointsWhenDrawing: route.skipPointsWhenDrawing,\n\t\tmidpointHandle: route.midpointHandle,\n\t}\n}\n\n/**\n * Take a normalizes anchor and return the side we think it's closest to.\n */\nexport function getEdgeFromNormalizedAnchor(normalizedAnchor: VecLike) {\n\tif (approximately(normalizedAnchor.x, 0.5) && approximately(normalizedAnchor.y, 0.5)) {\n\t\treturn null\n\t}\n\n\tif (\n\t\tMath.abs(normalizedAnchor.x - 0.5) >\n\t\t// slightly bias towards x arrows to prevent flickering when the anchor is right on the line\n\t\t// between the two directions\n\t\tMath.abs(normalizedAnchor.y - 0.5) - 0.0001\n\t) {\n\t\treturn normalizedAnchor.x < 0.5 ? 'left' : 'right'\n\t}\n\n\treturn normalizedAnchor.y < 0.5 ? 'top' : 'bottom'\n}\n\nfunction getElbowArrowTerminalInfo(\n\teditor: Editor,\n\tarrow: TLArrowShape,\n\tbinding: TLArrowBinding | undefined,\n\tpoint: VecModel\n): ElbowArrowTerminal {\n\tconst arrowStrokeSize = (STROKE_SIZES[arrow.props.size] * arrow.props.scale) / 2\n\tconst minEndSegmentLength = arrowStrokeSize * 3\n\n\tif (binding) {\n\t\tconst target = editor.getShape(binding.toId)\n\t\tconst geometry = getBindingGeometryInArrowSpace(editor, arrow, binding.toId, binding.props)\n\t\tif (geometry && target) {\n\t\t\tlet arrowheadOffset = 0\n\t\t\tconst arrowheadProp = binding.props.terminal === 'start' ? 'arrowheadStart' : 'arrowheadEnd'\n\t\t\tif (arrow.props[arrowheadProp] !== 'none') {\n\t\t\t\tconst targetScale = 'scale' in target.props ? target.props.scale : 1\n\t\t\t\tconst targetStrokeSize =\n\t\t\t\t\t'size' in target.props ? ((STROKE_SIZES[target.props.size] ?? 0) * targetScale) / 2 : 0\n\n\t\t\t\tarrowheadOffset =\n\t\t\t\t\tarrowStrokeSize + targetStrokeSize + BOUND_ARROW_OFFSET * arrow.props.scale\n\t\t\t}\n\n\t\t\tlet side: ElbowArrowSideWithAxis | null = null\n\t\t\tconst targetPoint = geometry.target\n\t\t\tif (binding.props.isPrecise) {\n\t\t\t\tside = getEdgeFromNormalizedAnchor(\n\t\t\t\t\tVec.RotWith(\n\t\t\t\t\t\tbinding.props.normalizedAnchor,\n\t\t\t\t\t\t{ x: 0.5, y: 0.5 },\n\t\t\t\t\t\tgeometry.shapeToArrowTransform.rotation()\n\t\t\t\t\t)\n\t\t\t\t)\n\t\t\t}\n\n\t\t\treturn {\n\t\t\t\ttargetShapeId: binding.toId,\n\t\t\t\tisPoint: false,\n\t\t\t\tisExact: binding.props.isExact,\n\t\t\t\tbounds: geometry.bounds,\n\t\t\t\tgeometry: geometry.geometry,\n\t\t\t\ttarget: targetPoint,\n\t\t\t\tarrowheadOffset,\n\t\t\t\tminEndSegmentLength,\n\t\t\t\tside,\n\t\t\t\tsnap: binding.props.snap,\n\t\t\t}\n\t\t}\n\t}\n\n\treturn {\n\t\ttargetShapeId: null,\n\t\tbounds: Box.FromCenter(point, { x: 0, y: 0 }),\n\t\tgeometry: null,\n\t\tisExact: false,\n\t\tisPoint: true,\n\t\ttarget: Vec.From(point),\n\t\tarrowheadOffset: 0,\n\t\tminEndSegmentLength,\n\t\tside: null,\n\t\tsnap: 'none',\n\t}\n}\n\nfunction getBindingGeometryInArrowSpace(\n\teditor: Editor,\n\tarrow: TLArrowShape,\n\ttargetId: TLShapeId,\n\tbindingProps: TLArrowBindingProps\n) {\n\tconst hasArrowhead =\n\t\tbindingProps.terminal === 'start'\n\t\t\t? arrow.props.arrowheadStart !== 'none'\n\t\t\t: arrow.props.arrowheadEnd !== 'none'\n\n\tconst targetGeometryInTargetSpace = editor.getShapeGeometry(\n\t\ttargetId,\n\t\thasArrowhead ? undefined : { context: '@tldraw/arrow-without-arrowhead' }\n\t)\n\n\tif (!targetGeometryInTargetSpace) {\n\t\treturn null\n\t}\n\n\tconst arrowTransform = editor.getShapePageTransform(arrow.id)\n\tconst shapeTransform = editor.getShapePageTransform(targetId)\n\tconst shapeToArrowTransform = arrowTransform.clone().invert().multiply(shapeTransform)\n\n\tconst targetGeometryInArrowSpace = targetGeometryInTargetSpace.transform(shapeToArrowTransform)\n\n\tconst center = { x: 0.5, y: 0.5 }\n\tconst normalizedAnchor = bindingProps.isPrecise ? bindingProps.normalizedAnchor : center\n\n\tconst targetInShapeSpace = {\n\t\tx: lerp(\n\t\t\ttargetGeometryInTargetSpace.bounds.minX,\n\t\t\ttargetGeometryInTargetSpace.bounds.maxX,\n\t\t\tnormalizedAnchor.x\n\t\t),\n\t\ty: lerp(\n\t\t\ttargetGeometryInTargetSpace.bounds.minY,\n\t\t\ttargetGeometryInTargetSpace.bounds.maxY,\n\t\t\tnormalizedAnchor.y\n\t\t),\n\t}\n\tconst centerInShapeSpace = {\n\t\tx: lerp(\n\t\t\ttargetGeometryInTargetSpace.bounds.minX,\n\t\t\ttargetGeometryInTargetSpace.bounds.maxX,\n\t\t\tcenter.x\n\t\t),\n\t\ty: lerp(\n\t\t\ttargetGeometryInTargetSpace.bounds.minY,\n\t\t\ttargetGeometryInTargetSpace.bounds.maxY,\n\t\t\tcenter.y\n\t\t),\n\t}\n\n\tconst targetInArrowSpace = Mat.applyToPoint(shapeToArrowTransform, targetInShapeSpace)\n\tconst centerInArrowSpace = Mat.applyToPoint(shapeToArrowTransform, centerInShapeSpace)\n\n\treturn {\n\t\tbounds: targetGeometryInArrowSpace.bounds,\n\t\tgeometry: targetGeometryInArrowSpace,\n\t\ttarget: targetInArrowSpace,\n\t\tcenter: centerInArrowSpace,\n\t\tshapeToArrowTransform,\n\t}\n}\n\nconst sideProps = {\n\ttop: {\n\t\texpand: -1,\n\t\tmain: 'minY',\n\t\topposite: 'maxY',\n\t\tcrossMid: 'midX',\n\t\tcrossMin: 'minX',\n\t\tcrossMax: 'maxX',\n\t\tbRangeExpand: 'max',\n\t\tcrossAxis: 'x',\n\t},\n\tbottom: {\n\t\texpand: 1,\n\t\tmain: 'maxY',\n\t\topposite: 'minY',\n\t\tcrossMid: 'midX',\n\t\tcrossMin: 'minX',\n\t\tcrossMax: 'maxX',\n\t\tbRangeExpand: 'min',\n\t\tcrossAxis: 'x',\n\t},\n\tleft: {\n\t\texpand: -1,\n\t\tmain: 'minX',\n\t\topposite: 'maxX',\n\t\tcrossMid: 'midY',\n\t\tcrossMin: 'minY',\n\t\tcrossMax: 'maxY',\n\t\tbRangeExpand: 'max',\n\t\tcrossAxis: 'y',\n\t},\n\tright: {\n\t\texpand: 1,\n\t\tmain: 'maxX',\n\t\topposite: 'minX',\n\t\tcrossMid: 'midY',\n\t\tcrossMin: 'minY',\n\t\tcrossMax: 'maxY',\n\t\tbRangeExpand: 'min',\n\t\tcrossAxis: 'y',\n\t},\n} as const\n\nexport function getUsableEdge(\n\ta: ElbowArrowTerminal,\n\tb: ElbowArrowTerminal,\n\tside: 'top' | 'right' | 'bottom' | 'left',\n\toptions: ElbowArrowOptions\n): ElbowArrowEdge | null {\n\tconst props = sideProps[side]\n\n\t// if a shape is bound to itself, by default we'd end up routing the arrow _within_ the shape -\n\t// as if it were a point-to-point arrow. if one of the bindings is specifically to the edge\n\t// though, we route it externally instead.\n\tconst isSelfBoundAndShouldRouteExternal =\n\t\ta.targetShapeId === b.targetShapeId &&\n\t\ta.targetShapeId !== null &&\n\t\t(a.snap === 'edge' || a.snap === 'edge-point') &&\n\t\t(b.snap === 'edge' || b.snap === 'edge-point')\n\n\tconst aValue = a.bounds[props.main]\n\tconst aExpanded = a.isPoint ? null : aValue + props.expand * options.expandElbowLegLength\n\n\tconst originalACrossRange = createRange(a.bounds[props.crossMin], a.bounds[props.crossMax])\n\tlet aCrossRange = originalACrossRange\n\n\t// this edge is too small to be useful:\n\tif (!aCrossRange) {\n\t\treturn null\n\t}\n\n\tassert(originalACrossRange)\n\tconst bRange = createRange(b.bounds[props.main], b.bounds[props.opposite])\n\tif (!b.isPoint) {\n\t\tbRange[props.bRangeExpand] -= options.minElbowLegLength * 2 * props.expand\n\t}\n\n\tconst bCrossRange = expandRange(\n\t\tcreateRange(b.bounds[props.crossMin], b.bounds[props.crossMax]),\n\t\toptions.expandElbowLegLength\n\t)\n\tassert(bRange && bCrossRange)\n\n\tlet isPartial = false\n\tif (\n\t\tisWithinRange(aValue, bRange) &&\n\t\t!a.isPoint &&\n\t\t!b.isPoint &&\n\t\t!isSelfBoundAndShouldRouteExternal\n\t) {\n\t\tconst subtracted = subtractRange(aCrossRange, bCrossRange)\n\t\tswitch (subtracted.length) {\n\t\t\tcase 0:\n\t\t\t\treturn null\n\t\t\tcase 1:\n\t\t\t\tisPartial = subtracted[0] !== aCrossRange\n\t\t\t\taCrossRange = subtracted[0]\n\t\t\t\tbreak\n\t\t\tcase 2:\n\t\t\t\tisPartial = true\n\t\t\t\taCrossRange =\n\t\t\t\t\trangeSize(subtracted[0]) > rangeSize(subtracted[1]) ? subtracted[0] : subtracted[1]\n\t\t\t\tbreak\n\t\t\tdefault:\n\t\t\t\texhaustiveSwitchError(subtracted)\n\t\t}\n\t}\n\n\tif (!isWithinRange(a.target[props.crossAxis], aCrossRange)) {\n\t\treturn null\n\t}\n\tconst crossTarget = a.target[props.crossAxis]\n\n\treturn {\n\t\tvalue: aValue,\n\t\texpanded: aExpanded,\n\t\tcross: aCrossRange,\n\t\tcrossTarget,\n\t\tisPartial,\n\t}\n}\n\nfunction hasUsableEdge(edges: ElbowArrowBoxEdges, side: ElbowArrowSideWithAxis | null) {\n\tif (side === null) {\n\t\treturn !!(edges.bottom || edges.left || edges.right || edges.top)\n\t}\n\n\tif (side === 'x') {\n\t\treturn !!edges.left || !!edges.right\n\t}\n\n\tif (side === 'y') {\n\t\treturn !!edges.top || !!edges.bottom\n\t}\n\n\treturn !!edges[side]\n}\n\nfunction getSideToUse(\n\tbinding: ElbowArrowTerminal,\n\tother: ElbowArrowTerminal,\n\tedges: ElbowArrowBoxEdges | null\n): ElbowArrowSide | null {\n\tswitch (binding.side) {\n\t\tcase null:\n\t\t\treturn null\n\t\tcase 'x':\n\t\t\tif (binding.bounds.center.x > other.bounds.center.x && edges?.left) {\n\t\t\t\treturn 'left'\n\t\t\t} else if (edges?.right) {\n\t\t\t\treturn 'right'\n\t\t\t}\n\t\t\treturn null\n\t\tcase 'y':\n\t\t\tif (binding.bounds.center.y > other.bounds.center.y && edges?.top) {\n\t\t\t\treturn 'top'\n\t\t\t} else if (edges?.bottom) {\n\t\t\t\treturn 'bottom'\n\t\t\t}\n\t\t\treturn null\n\t\tdefault:\n\t\t\treturn binding.side\n\t}\n}\n\nfunction convertTerminalToPoint(terminal: ElbowArrowTerminal): ElbowArrowTerminal {\n\tif (terminal.isPoint) return terminal\n\n\tlet side: ElbowArrowSideWithAxis | null = null\n\tlet arrowheadOffset = 0\n\tif (terminal.snap === 'edge' || terminal.snap === 'edge-point') {\n\t\tarrowheadOffset = terminal.arrowheadOffset\n\t\tif (terminal.side === 'x' || terminal.side === 'left' || terminal.side === 'right') {\n\t\t\tside = 'x'\n\t\t}\n\t\tif (terminal.side === 'y' || terminal.side === 'top' || terminal.side === 'bottom') {\n\t\t\tside = 'y'\n\t\t}\n\t}\n\n\treturn {\n\t\ttargetShapeId: terminal.targetShapeId,\n\t\tside,\n\t\tbounds: new Box(terminal.target.x, terminal.target.y, 0, 0),\n\t\tgeometry: terminal.geometry,\n\t\ttarget: terminal.target,\n\t\tarrowheadOffset,\n\t\tminEndSegmentLength: terminal.minEndSegmentLength,\n\t\tisExact: terminal.isExact,\n\t\tisPoint: true,\n\t\tsnap: terminal.snap,\n\t}\n}\n\n/**\n * Make sure the first path segments goes fully into the target, and doesn't just point to its\n * bounding box. This modifies the route in-place.\n */\nfunction castPathSegmentIntoGeometry(\n\tsegment: 'first' | 'last',\n\ttarget: ElbowArrowTargetBox,\n\tother: ElbowArrowTargetBox,\n\troute: ElbowArrowRoute\n) {\n\tif (!target.geometry) return\n\n\tconst point1 = segment === 'first' ? route.points[0] : route.points[route.points.length - 1]\n\tconst point2 = segment === 'first' ? route.points[1] : route.points[route.points.length - 2]\n\n\tconst pointToFindClosestIntersectionTo = target.geometry.isClosed ? point2 : target.target\n\n\tconst initialDistance = Vec.ManhattanDist(point1, pointToFindClosestIntersectionTo)\n\n\tlet nearestIntersectionToPoint2: VecLike | null = null\n\tlet nearestDistanceToPoint2 = Infinity\n\n\tif (target.isExact) {\n\t\tnearestIntersectionToPoint2 = target.target\n\t} else if (target.geometry) {\n\t\tconst intersections = target.geometry.intersectLineSegment(point2, target.target, {\n\t\t\tincludeLabels: false,\n\t\t\tincludeInternal: false,\n\t\t})\n\t\tif (\n\t\t\ttarget.geometry.hitTestPoint(\n\t\t\t\ttarget.target,\n\t\t\t\tMath.max(1, target.arrowheadOffset),\n\t\t\t\ttrue,\n\t\t\t\tGeometry2dFilters.EXCLUDE_NON_STANDARD\n\t\t\t)\n\t\t) {\n\t\t\tintersections.push(target.target)\n\t\t}\n\t\tfor (const intersection of intersections) {\n\t\t\tconst point2Distance = Vec.ManhattanDist(pointToFindClosestIntersectionTo, intersection)\n\t\t\tif (point2Distance < nearestDistanceToPoint2) {\n\t\t\t\tnearestDistanceToPoint2 = point2Distance\n\t\t\t\tnearestIntersectionToPoint2 = intersection\n\t\t\t}\n\t\t}\n\t}\n\n\tif (nearestIntersectionToPoint2) {\n\t\tlet offset = target.arrowheadOffset\n\n\t\tconst currentFinalSegmentLength = Vec.ManhattanDist(point2, nearestIntersectionToPoint2)\n\t\tconst minLength = target.arrowheadOffset * 2\n\t\tif (currentFinalSegmentLength < minLength) {\n\t\t\tconst targetLength = minLength - target.arrowheadOffset\n\t\t\toffset = currentFinalSegmentLength - targetLength\n\t\t}\n\t\tif (offset < target.minEndSegmentLength) {\n\t\t\tif (target.geometry.bounds.containsPoint(other.target)) {\n\t\t\t\toffset = Math.max(0, offset)\n\t\t\t} else {\n\t\t\t\toffset = -target.arrowheadOffset\n\t\t\t}\n\t\t}\n\n\t\tlet nudgedPoint = nearestIntersectionToPoint2\n\t\tlet shouldAddExtraPointForNudge = false\n\t\tif (!target.isExact && offset !== 0) {\n\t\t\tconst nudged = Vec.Nudge(nearestIntersectionToPoint2, point2, offset)\n\t\t\tnudgedPoint = nudged\n\t\t\tif (\n\t\t\t\toffset < 0 &&\n\t\t\t\t!target.geometry.hitTestPoint(nudged, 0, true, Geometry2dFilters.EXCLUDE_NON_STANDARD)\n\t\t\t) {\n\t\t\t\t// point has been nudged _out_ of the shape so lets not actually apply the nudge\n\t\t\t\tnudgedPoint = nearestIntersectionToPoint2\n\t\t\t} else {\n\t\t\t\tif (offset < 0) {\n\t\t\t\t\tshouldAddExtraPointForNudge = true\n\t\t\t\t}\n\t\t\t\tnudgedPoint = nudged\n\t\t\t}\n\t\t}\n\n\t\tconst newDistance = Vec.ManhattanDist(point2, nudgedPoint)\n\t\troute.distance += newDistance - initialDistance\n\t\tpoint1.x = nudgedPoint.x\n\t\tpoint1.y = nudgedPoint.y\n\n\t\tif (shouldAddExtraPointForNudge) {\n\t\t\tconst midPoint = Vec.Lrp(point2, point1, 0.5)\n\t\t\troute.skipPointsWhenDrawing.add(midPoint)\n\t\t\troute.points.splice(segment === 'first' ? 1 : route.points.length - 1, 0, midPoint)\n\t\t}\n\t}\n}\n\nfunction fixTinyEndNubs(\n\troute: ElbowArrowRoute,\n\taTerminal: ElbowArrowTerminal,\n\tbTerminal: ElbowArrowTerminal\n) {\n\tif (!route) return\n\n\tif (route.points.length >= 3) {\n\t\tconst a = route.points[0]\n\t\tconst b = route.points[1]\n\t\tconst firstSegmentLength = Vec.ManhattanDist(a, b)\n\t\tif (firstSegmentLength < aTerminal.minEndSegmentLength) {\n\t\t\troute.points.splice(1, 1)\n\t\t\tif (route.points.length >= 3) {\n\t\t\t\tconst matchAxis = approximately(a.x, b.x) ? 'y' : 'x'\n\t\t\t\troute.points[1][matchAxis] = a[matchAxis]\n\t\t\t}\n\t\t}\n\t}\n\n\tif (route.points.length >= 3) {\n\t\tconst a = route.points[route.points.length - 1]\n\t\tconst b = route.points[route.points.length - 2]\n\t\tconst lastSegmentLength = Vec.ManhattanDist(a, b)\n\t\tif (lastSegmentLength < bTerminal.minEndSegmentLength) {\n\t\t\troute.points.splice(route.points.length - 2, 1)\n\t\t\tif (route.points.length >= 3) {\n\t\t\t\tconst matchAxis = approximately(a.x, b.x) ? 'y' : 'x'\n\t\t\t\troute.points[route.points.length - 2][matchAxis] = a[matchAxis]\n\t\t\t}\n\t\t}\n\t}\n}\n\nfunction adjustTerminalForUnclosedPathIfNeeded(\n\tterminal: ElbowArrowTerminal,\n\totherTerminal: ElbowArrowTerminal,\n\toptions: ElbowArrowOptions\n): ElbowArrowTerminal {\n\tif (!terminal.geometry || terminal.geometry.isClosed) return terminal\n\tconst normalizedPointAlongPath = terminal.geometry.uninterpolateAlongEdge(\n\t\tterminal.target,\n\t\tGeometry2dFilters.EXCLUDE_NON_STANDARD\n\t)\n\n\tconst prev = terminal.geometry.interpolateAlongEdge(\n\t\tnormalizedPointAlongPath - 0.01 / terminal.geometry.length\n\t)\n\tconst next = terminal.geometry.interpolateAlongEdge(\n\t\tnormalizedPointAlongPath + 0.01 / terminal.geometry.length\n\t)\n\n\tconst normal = next.sub(prev).per().uni()\n\tconst axis = Math.abs(normal.x) > Math.abs(normal.y) ? ElbowArrowAxes.x : ElbowArrowAxes.y\n\n\tif (terminal.geometry.bounds.containsPoint(otherTerminal.target, options.expandElbowLegLength)) {\n\t\tterminal.side = axis.self\n\t\treturn convertTerminalToPoint(terminal)\n\t}\n\n\tconst min = axis.v(\n\t\tterminal.target[axis.self] - terminal.bounds[axis.size] * 2,\n\t\tterminal.target[axis.cross]\n\t)\n\tconst max = axis.v(\n\t\tterminal.target[axis.self] + terminal.bounds[axis.size] * 2,\n\t\tterminal.target[axis.cross]\n\t)\n\n\tlet furthestIntersectionTowardsMin: VecLike | null = null\n\tlet furthestIntersectionTowardsMinDistance = 0\n\tlet furthestIntersectionTowardsMax: VecLike | null = null\n\tlet furthestIntersectionTowardsMaxDistance = 0\n\tlet side: ElbowArrowSideWithAxis = axis.self\n\n\tfor (const intersection of terminal.geometry.intersectLineSegment(\n\t\tmin,\n\t\tmax,\n\t\tGeometry2dFilters.EXCLUDE_NON_STANDARD\n\t)) {\n\t\tif (Math.abs(intersection[axis.self] - terminal.target[axis.self]) < 1) {\n\t\t\tcontinue\n\t\t}\n\t\tif (intersection[axis.self] < terminal.target[axis.self]) {\n\t\t\tif (\n\t\t\t\tVec.ManhattanDist(intersection, terminal.target) > furthestIntersectionTowardsMinDistance\n\t\t\t) {\n\t\t\t\tfurthestIntersectionTowardsMinDistance = Vec.ManhattanDist(intersection, terminal.target)\n\t\t\t\tfurthestIntersectionTowardsMin = intersection\n\t\t\t}\n\t\t} else {\n\t\t\tif (\n\t\t\t\tVec.ManhattanDist(intersection, terminal.target) > furthestIntersectionTowardsMaxDistance\n\t\t\t) {\n\t\t\t\tfurthestIntersectionTowardsMaxDistance = Vec.ManhattanDist(intersection, terminal.target)\n\t\t\t\tfurthestIntersectionTowardsMax = intersection\n\t\t\t}\n\t\t}\n\t}\n\n\tif (furthestIntersectionTowardsMin && furthestIntersectionTowardsMax) {\n\t\tif (furthestIntersectionTowardsMinDistance > furthestIntersectionTowardsMaxDistance) {\n\t\t\tside = axis.hiEdge\n\t\t} else {\n\t\t\tside = axis.loEdge\n\t\t}\n\t} else if (furthestIntersectionTowardsMin && !furthestIntersectionTowardsMax) {\n\t\tside = axis.hiEdge\n\t} else if (!furthestIntersectionTowardsMin && furthestIntersectionTowardsMax) {\n\t\tside = axis.loEdge\n\t}\n\n\tterminal.side = side\n\treturn terminal\n}\n"],
5
+ "mappings": "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",
6
6
  "names": []
7
7
  }
@@ -22,10 +22,10 @@ __export(version_exports, {
22
22
  version: () => version
23
23
  });
24
24
  module.exports = __toCommonJS(version_exports);
25
- const version = "4.2.1";
25
+ const version = "4.2.3";
26
26
  const publishDates = {
27
27
  major: "2025-09-18T14:39:22.803Z",
28
28
  minor: "2025-11-19T11:47:45.748Z",
29
- patch: "2025-12-05T12:30:07.819Z"
29
+ patch: "2026-01-08T10:11:20.530Z"
30
30
  };
31
31
  //# sourceMappingURL=version.js.map
@@ -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.2.1'\nexport const publishDates = {\n\tmajor: '2025-09-18T14:39:22.803Z',\n\tminor: '2025-11-19T11:47:45.748Z',\n\tpatch: '2025-12-05T12:30:07.819Z',\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.2.3'\nexport const publishDates = {\n\tmajor: '2025-09-18T14:39:22.803Z',\n\tminor: '2025-11-19T11:47:45.748Z',\n\tpatch: '2026-01-08T10:11:20.530Z',\n}\n"],
5
5
  "mappings": ";;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAGO,MAAM,UAAU;AAChB,MAAM,eAAe;AAAA,EAC3B,OAAO;AAAA,EACP,OAAO;AAAA,EACP,OAAO;AACR;",
6
6
  "names": []
7
7
  }
@@ -533,7 +533,7 @@ import {
533
533
  } from "./lib/utils/tldr/file.mjs";
534
534
  registerTldrawLibraryVersion(
535
535
  "tldraw",
536
- "4.2.1",
536
+ "4.2.3",
537
537
  "esm"
538
538
  );
539
539
  export {
@@ -570,7 +570,7 @@ const embedShapePermissionDefaults = {
570
570
  // [REASON] We want to allow embeds to link back to their original sites (e.g. YouTube).
571
571
  "allow-popups": true,
572
572
  // [MDN] Lets the sandboxed document open new windows without those windows inheriting the sandboxing. For example, this can safely sandbox an advertisement without forcing the same restrictions upon the page the ad links to.
573
- // [REASON] We shouldn't allow popups as a embed could pretend to be us by opening a mocked version of tldraw. This is very unobvious when it is performed as an action within our app.
573
+ // [REASON] We shouldn't allow popups as an embed could pretend to be us by opening a mocked version of tldraw. This is very unobvious when it is performed as an action within our app.
574
574
  "allow-popups-to-escape-sandbox": false,
575
575
  // [MDN] Lets the resource start a presentation session.
576
576
  // [REASON] Prevents embed from navigating away from tldraw and pretending to be us.
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../src/lib/defaultEmbedDefinitions.ts"],
4
- "sourcesContent": ["import { safeParseUrl } from '@tldraw/editor'\n\n// Only allow multiplayer embeds. If we add additional routes later for example '/help' this won't match\nconst TLDRAW_APP_RE = /(^\\/[f|p|r|ro|s|v]\\/[^/]+\\/?$)/\n\n/** @public */\nexport const DEFAULT_EMBED_DEFINITIONS = [\n\t{\n\t\ttype: 'tldraw',\n\t\ttitle: 'tldraw',\n\t\thostnames: ['beta.tldraw.com', 'tldraw.com', 'localhost:3000'],\n\t\tminWidth: 300,\n\t\tminHeight: 300,\n\t\twidth: 720,\n\t\theight: 500,\n\t\tdoesResize: true,\n\t\toverridePermissions: {\n\t\t\t'allow-top-navigation': true,\n\t\t},\n\t\ttoEmbedUrl: (url) => {\n\t\t\tconst urlObj = safeParseUrl(url)\n\t\t\tif (urlObj && urlObj.pathname.match(TLDRAW_APP_RE)) {\n\t\t\t\t// Add the \"clean=true\" search param to the URL to hide the sidebar\n\t\t\t\turlObj.searchParams.append('embed', 'true')\n\t\t\t\treturn url\n\t\t\t}\n\t\t\treturn\n\t\t},\n\t\tfromEmbedUrl: (url) => {\n\t\t\tconst urlObj = safeParseUrl(url)\n\t\t\tif (urlObj && urlObj.pathname.match(TLDRAW_APP_RE)) {\n\t\t\t\t// Add the \"clean=true\" search param to the URL to hide the sidebar\n\t\t\t\turlObj.searchParams.delete('embed')\n\t\t\t\treturn url\n\t\t\t}\n\t\t\treturn\n\t\t},\n\t\tembedOnPaste: false,\n\t},\n\t{\n\t\ttype: 'figma',\n\t\ttitle: 'Figma',\n\t\thostnames: ['figma.com'],\n\t\twidth: 720,\n\t\theight: 500,\n\t\tdoesResize: true,\n\t\ttoEmbedUrl: (url) => {\n\t\t\tif (\n\t\t\t\t!!url.match(\n\t\t\t\t\t// eslint-disable-next-line no-useless-escape\n\t\t\t\t\t/https:\\/\\/([\\w\\.-]+\\.)?figma.com\\/(file|proto|design)\\/([0-9a-zA-Z]{22,128})(?:\\/.*)?$/\n\t\t\t\t) &&\n\t\t\t\t!url.includes('figma.com/embed')\n\t\t\t) {\n\t\t\t\treturn `https://www.figma.com/embed?embed_host=share&url=${url}`\n\t\t\t}\n\t\t\treturn\n\t\t},\n\t\tfromEmbedUrl: (url) => {\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\tembedOnPaste: true,\n\t},\n\t{\n\t\ttype: 'google_maps',\n\t\ttitle: 'Google Maps',\n\t\thostnames: ['google.*'],\n\t\twidth: 720,\n\t\theight: 500,\n\t\tdoesResize: true,\n\t\toverridePermissions: {\n\t\t\t'allow-presentation': true,\n\t\t},\n\t\ttoEmbedUrl: (url) => {\n\t\t\tif (url.includes('/maps/embed?')) {\n\t\t\t\treturn url\n\t\t\t} else if (url.includes('/maps/')) {\n\t\t\t\tconst match = url.match(/@(.*?),(.*?),(.*?)(z|m)/)\n\t\t\t\tlet result: string\n\t\t\t\tif (match) {\n\t\t\t\t\tconst [, lat, lng, zoomOrMeters, mapTypeSymbol] = match\n\t\t\t\t\tconst mapType = mapTypeSymbol === 'z' ? 'roadmap' : 'satellite'\n\t\t\t\t\t// Note: This meters to zoom equation is a rough approximation and not canonical.\n\t\t\t\t\tconst z =\n\t\t\t\t\t\tmapType === 'roadmap'\n\t\t\t\t\t\t\t? zoomOrMeters\n\t\t\t\t\t\t\t: -Math.log2(parseInt(zoomOrMeters) / 14772321) / 0.8\n\t\t\t\t\tconst host = new URL(url).host.replace('www.', '')\n\t\t\t\t\tresult = `https://${host}/maps/embed/v1/view?key=${process.env.NEXT_PUBLIC_GC_API_KEY}&center=${lat},${lng}&zoom=${z}&maptype=${mapType}`\n\t\t\t\t} else {\n\t\t\t\t\tresult = ''\n\t\t\t\t}\n\n\t\t\t\treturn result\n\t\t\t}\n\t\t\treturn\n\t\t},\n\t\tfromEmbedUrl: (url) => {\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') ?? '12'\n\t\t\t\tconst mapType = urlObj.searchParams.get('maptype') ?? 'roadmap'\n\t\t\t\t// Note: This zoom to meters equation is a rough approximation and not canonical.\n\t\t\t\tconst zoomOrMeters =\n\t\t\t\t\tmapType === 'roadmap' ? zoom : 14772321 * Math.pow(2, parseInt(zoom) * -0.8)\n\t\t\t\tconst [lat, lon] = urlObj.searchParams.get('center')!.split(',')\n\t\t\t\treturn `https://www.google.com/maps/@${lat},${lon},${zoomOrMeters}${mapType === 'roadmap' ? 'z' : 'm'}`\n\t\t\t}\n\t\t\treturn\n\t\t},\n\t\tembedOnPaste: true,\n\t},\n\t{\n\t\ttype: 'val_town',\n\t\ttitle: 'Val Town',\n\t\thostnames: ['val.town'],\n\t\tminWidth: 260,\n\t\tminHeight: 100,\n\t\twidth: 720,\n\t\theight: 500,\n\t\tdoesResize: true,\n\t\ttoEmbedUrl: (url) => {\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(/\\/v\\/(.+)\\/?/)\n\t\t\tif (matches) {\n\t\t\t\treturn `https://www.val.town/embed/${matches[1]}`\n\t\t\t}\n\t\t\treturn\n\t\t},\n\t\tfromEmbedUrl: (url) => {\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\tembedOnPaste: true,\n\t},\n\t{\n\t\ttype: 'codesandbox',\n\t\ttitle: 'CodeSandbox',\n\t\thostnames: ['codesandbox.io'],\n\t\tminWidth: 300,\n\t\tminHeight: 300,\n\t\twidth: 720,\n\t\theight: 500,\n\t\tdoesResize: true,\n\t\ttoEmbedUrl: (url) => {\n\t\t\tconst urlObj = safeParseUrl(url)\n\t\t\tconst matches = urlObj && urlObj.pathname.match(/\\/s\\/([^/]+)\\/?/)\n\t\t\tif (matches) {\n\t\t\t\treturn `https://codesandbox.io/embed/${matches[1]}`\n\t\t\t}\n\t\t\treturn\n\t\t},\n\t\tfromEmbedUrl: (url) => {\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\tembedOnPaste: true,\n\t},\n\t{\n\t\ttype: 'codepen',\n\t\ttitle: 'Codepen',\n\t\thostnames: ['codepen.io'],\n\t\tminWidth: 300,\n\t\tminHeight: 300,\n\t\twidth: 520,\n\t\theight: 400,\n\t\tdoesResize: true,\n\t\ttoEmbedUrl: (url) => {\n\t\t\tconst CODEPEN_URL_REGEXP = /https:\\/\\/codepen.io\\/([^/]+)\\/pen\\/([^/]+)/\n\t\t\tconst matches = url.match(CODEPEN_URL_REGEXP)\n\t\t\tif (matches) {\n\t\t\t\tconst [_, user, id] = matches\n\t\t\t\treturn `https://codepen.io/${user}/embed/${id}`\n\t\t\t}\n\t\t\treturn\n\t\t},\n\t\tfromEmbedUrl: (url) => {\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\tembedOnPaste: true,\n\t},\n\t{\n\t\ttype: 'scratch',\n\t\ttitle: 'Scratch',\n\t\thostnames: ['scratch.mit.edu'],\n\t\twidth: 520,\n\t\theight: 400,\n\t\tdoesResize: false,\n\t\tembedOnPaste: true,\n\t\ttoEmbedUrl: (url) => {\n\t\t\tconst SCRATCH_URL_REGEXP = /https?:\\/\\/scratch.mit.edu\\/projects\\/([^/]+)/\n\t\t\tconst matches = url.match(SCRATCH_URL_REGEXP)\n\t\t\tif (matches) {\n\t\t\t\tconst [_, id] = matches\n\t\t\t\treturn `https://scratch.mit.edu/projects/embed/${id}`\n\t\t\t}\n\t\t\treturn\n\t\t},\n\t\tfromEmbedUrl: (url) => {\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\ttype: 'youtube',\n\t\ttitle: 'YouTube',\n\t\thostnames: ['*.youtube.com', 'youtube.com', 'youtu.be'],\n\t\twidth: 800,\n\t\theight: 450,\n\t\tdoesResize: true,\n\t\toverridePermissions: {\n\t\t\t'allow-presentation': true,\n\t\t\t'allow-popups-to-escape-sandbox': true,\n\t\t},\n\t\tisAspectRatioLocked: true,\n\t\tembedOnPaste: true,\n\t\ttoEmbedUrl: (url) => {\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 === 'youtu.be') {\n\t\t\t\tconst videoId = urlObj.pathname.split('/').filter(Boolean)[0]\n\t\t\t\tconst searchParams = new URLSearchParams(urlObj.search)\n\t\t\t\tconst timeStart = searchParams.get('t')\n\t\t\t\tif (timeStart) {\n\t\t\t\t\tsearchParams.set('start', timeStart)\n\t\t\t\t\tsearchParams.delete('t')\n\t\t\t\t}\n\t\t\t\tconst search = searchParams.toString() ? '?' + searchParams.toString() : ''\n\t\t\t\treturn `https://www.youtube.com/embed/${videoId}${search}`\n\t\t\t} else if (\n\t\t\t\t(hostname === 'youtube.com' || hostname === 'm.youtube.com') &&\n\t\t\t\turlObj.pathname.match(/^\\/watch/)\n\t\t\t) {\n\t\t\t\tconst videoId = urlObj.searchParams.get('v')\n\t\t\t\tconst searchParams = new URLSearchParams(urlObj.search)\n\t\t\t\tsearchParams.delete('v')\n\t\t\t\tconst timeStart = searchParams.get('t')\n\t\t\t\tif (timeStart) {\n\t\t\t\t\tsearchParams.set('start', timeStart)\n\t\t\t\t\tsearchParams.delete('t')\n\t\t\t\t}\n\t\t\t\tconst search = searchParams.toString() ? '?' + searchParams.toString() : ''\n\t\t\t\treturn `https://www.youtube.com/embed/${videoId}${search}`\n\t\t\t}\n\t\t\treturn\n\t\t},\n\t\tfromEmbedUrl: (url) => {\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\tconst params = new URLSearchParams(urlObj.search)\n\t\t\t\t\tparams.set('v', matches?.[1] ?? '')\n\t\t\t\t\tconst timeStart = params.get('start')\n\t\t\t\t\tif (timeStart) {\n\t\t\t\t\t\tparams.set('t', timeStart)\n\t\t\t\t\t\tparams.delete('start')\n\t\t\t\t\t}\n\t\t\t\t\treturn `https://www.youtube.com/watch?${params.toString()}`\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn\n\t\t},\n\t},\n\t{\n\t\ttype: 'google_calendar',\n\t\ttitle: 'Google Calendar',\n\t\thostnames: ['calendar.google.*'],\n\t\twidth: 720,\n\t\theight: 500,\n\t\tminWidth: 460,\n\t\tminHeight: 360,\n\t\tdoesResize: true,\n\t\tinstructionLink: 'https://support.google.com/calendar/answer/41207?hl=en',\n\t\toverridePermissions: {\n\t\t\t'allow-popups-to-escape-sandbox': true,\n\t\t},\n\t\tembedOnPaste: true,\n\t\ttoEmbedUrl: (url) => {\n\t\t\tconst urlObj = safeParseUrl(url)\n\t\t\tconst cidQs = urlObj?.searchParams.get('cid')\n\n\t\t\tif (urlObj?.pathname.match(/\\/calendar\\/u\\/0/) && cidQs) {\n\t\t\t\turlObj.pathname = '/calendar/embed'\n\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('src', cidQs)\n\t\t\t\treturn urlObj.href\n\t\t\t}\n\t\t\treturn\n\t\t},\n\t\tfromEmbedUrl: (url) => {\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\ttype: 'google_slides',\n\t\ttitle: 'Google Slides',\n\t\thostnames: ['docs.google.*'],\n\t\twidth: 720,\n\t\theight: 500,\n\t\tminWidth: 460,\n\t\tminHeight: 360,\n\t\tdoesResize: true,\n\t\toverridePermissions: {\n\t\t\t'allow-popups-to-escape-sandbox': true,\n\t\t},\n\t\tembedOnPaste: true,\n\t\ttoEmbedUrl: (url) => {\n\t\t\tconst urlObj = safeParseUrl(url)\n\n\t\t\tif (urlObj?.pathname.match(/^\\/presentation/) && urlObj?.pathname.match(/\\/pub\\/?$/)) {\n\t\t\t\turlObj.pathname = urlObj.pathname.replace(/\\/pub$/, '/embed')\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\tfromEmbedUrl: (url) => {\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\ttype: 'github_gist',\n\t\ttitle: 'GitHub Gist',\n\t\thostnames: ['gist.github.com'],\n\t\twidth: 720,\n\t\theight: 500,\n\t\tdoesResize: true,\n\t\tembedOnPaste: true,\n\t\t// Security warning:\n\t\t// Gists allow adding .json extensions to the URL which return JSONP.\n\t\t// Furthermore, the JSONP can include callbacks that execute arbitrary JavaScript.\n\t\t// It _is_ sandboxed by the iframe but we still want to disable it nonetheless.\n\t\t// We restrict the id to only allow hexdecimal characters to prevent this.\n\t\t// Read more:\n\t\t// https://github.com/bhaveshk90/Content-Security-Policy-CSP-Bypass-Techniques\n\t\t// https://github.com/renniepak/CSPBypass\n\t\ttoEmbedUrl: (url) => {\n\t\t\tconst urlObj = safeParseUrl(url)\n\t\t\tif (urlObj && urlObj.pathname.match(/\\/([^/]+)\\/([0-9a-f]+)$/)) {\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\tfromEmbedUrl: (url) => {\n\t\t\tconst urlObj = safeParseUrl(url)\n\t\t\tif (urlObj && urlObj.pathname.match(/\\/([^/]+)\\/([0-9a-f]+)$/)) {\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\ttype: 'replit',\n\t\ttitle: 'Replit',\n\t\thostnames: ['replit.com'],\n\t\twidth: 720,\n\t\theight: 500,\n\t\tdoesResize: true,\n\t\tembedOnPaste: true,\n\t\ttoEmbedUrl: (url) => {\n\t\t\tconst urlObj = safeParseUrl(url)\n\t\t\tif (urlObj && urlObj.pathname.match(/\\/@([^/]+)\\/([^/]+)/)) {\n\t\t\t\turlObj.searchParams.append('embed', 'true')\n\t\t\t\treturn urlObj.href\n\t\t\t}\n\t\t\treturn\n\t\t},\n\t\tfromEmbedUrl: (url) => {\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\ttype: 'felt',\n\t\ttitle: 'Felt',\n\t\thostnames: ['felt.com'],\n\t\twidth: 720,\n\t\theight: 500,\n\t\tdoesResize: true,\n\t\tembedOnPaste: true,\n\t\ttoEmbedUrl: (url) => {\n\t\t\tconst urlObj = safeParseUrl(url)\n\t\t\tif (urlObj && urlObj.pathname.match(/^\\/map\\//)) {\n\t\t\t\treturn urlObj.origin + '/embed' + urlObj.pathname\n\t\t\t}\n\t\t\treturn\n\t\t},\n\t\tfromEmbedUrl: (url) => {\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\ttype: 'spotify',\n\t\ttitle: 'Spotify',\n\t\thostnames: ['open.spotify.com'],\n\t\twidth: 720,\n\t\theight: 500,\n\t\tminHeight: 500,\n\t\toverrideOutlineRadius: 12,\n\t\tdoesResize: true,\n\t\tembedOnPaste: true,\n\t\ttoEmbedUrl: (url) => {\n\t\t\tconst urlObj = safeParseUrl(url)\n\t\t\tif (urlObj && urlObj.pathname.match(/^\\/(artist|album)\\//)) {\n\t\t\t\treturn urlObj.origin + '/embed' + urlObj.pathname\n\t\t\t}\n\t\t\treturn\n\t\t},\n\t\tfromEmbedUrl: (url) => {\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\ttype: 'vimeo',\n\t\ttitle: 'Vimeo',\n\t\thostnames: ['vimeo.com', 'player.vimeo.com'],\n\t\twidth: 640,\n\t\theight: 360,\n\t\tdoesResize: true,\n\t\tisAspectRatioLocked: true,\n\t\tembedOnPaste: true,\n\t\ttoEmbedUrl: (url) => {\n\t\t\tconst urlObj = safeParseUrl(url)\n\t\t\tif (urlObj && urlObj.hostname === 'vimeo.com') {\n\t\t\t\tif (urlObj.pathname.match(/^\\/[0-9]+/)) {\n\t\t\t\t\treturn (\n\t\t\t\t\t\t'https://player.vimeo.com/video/' + urlObj.pathname.split('/')[1] + '?title=0&byline=0'\n\t\t\t\t\t)\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn\n\t\t},\n\t\tfromEmbedUrl: (url) => {\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\ttype: 'observable',\n\t\ttitle: 'Observable',\n\t\thostnames: ['observablehq.com'],\n\t\twidth: 720,\n\t\theight: 500,\n\t\tdoesResize: true,\n\t\tisAspectRatioLocked: false,\n\t\tbackgroundColor: '#fff',\n\t\tembedOnPaste: true,\n\t\ttoEmbedUrl: (url) => {\n\t\t\tconst urlObj = safeParseUrl(url)\n\t\t\tif (urlObj && urlObj.pathname.match(/^\\/@([^/]+)\\/([^/]+)\\/?$/)) {\n\t\t\t\treturn `${urlObj.origin}/embed${urlObj.pathname}?cell=*`\n\t\t\t}\n\t\t\tif (urlObj && urlObj.pathname.match(/^\\/d\\/([^/]+)\\/?$/)) {\n\t\t\t\tconst pathName = urlObj.pathname.replace(/^\\/d/, '')\n\t\t\t\treturn `${urlObj.origin}/embed${pathName}?cell=*`\n\t\t\t}\n\n\t\t\treturn\n\t\t},\n\t\tfromEmbedUrl: (url) => {\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\ttype: 'desmos',\n\t\ttitle: 'Desmos',\n\t\thostnames: ['desmos.com'],\n\t\twidth: 700,\n\t\theight: 450,\n\t\tdoesResize: true,\n\t\tembedOnPaste: true,\n\t\ttoEmbedUrl: (url) => {\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 === '' &&\n\t\t\t\turlObj.hash === ''\n\t\t\t) {\n\t\t\t\treturn `${url}?embed`\n\t\t\t}\n\t\t\treturn\n\t\t},\n\t\tfromEmbedUrl: (url) => {\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] as const satisfies readonly EmbedDefinition[]\n\n/**\n * Permissions with note inline from\n * https://developer.mozilla.org/en-US/docs/Web/HTML/Element/iframe#attr-sandbox\n *\n * @public\n */\nexport const embedShapePermissionDefaults = {\n\t// ========================================================================================\n\t// Disabled permissions\n\t// ========================================================================================\n\t// [MDN] Experimental: Allows for downloads to occur without a gesture from the user.\n\t// [REASON] Disabled because otherwise the <iframe/> can trick the user on behalf of us to perform an action.\n\t'allow-downloads-without-user-activation': false,\n\t// [MDN] Allows for downloads to occur with a gesture from the user.\n\t// [REASON] Disabled because otherwise the <iframe/> can trick the user on behalf of us to perform an action.\n\t'allow-downloads': false,\n\t// [MDN] Lets the resource open modal windows.\n\t// [REASON] The <iframe/> could 'window.prompt(\"Enter your tldraw password\")'.\n\t'allow-modals': false,\n\t// [MDN] Lets the resource lock the screen orientation.\n\t// [REASON] Would interfere with the tldraw interface.\n\t'allow-orientation-lock': false,\n\t// [MDN] Lets the resource use the Pointer Lock API.\n\t// [REASON] Maybe we should allow this for games embeds (scratch/codepen/codesandbox).\n\t'allow-pointer-lock': false,\n\t// [MDN] Allows popups (such as window.open(), target=\"_blank\", or showModalDialog()). If this keyword is not used, the popup will silently fail to open.\n\t// [REASON] We want to allow embeds to link back to their original sites (e.g. YouTube).\n\t'allow-popups': true,\n\t// [MDN] Lets the sandboxed document open new windows without those windows inheriting the sandboxing. For example, this can safely sandbox an advertisement without forcing the same restrictions upon the page the ad links to.\n\t// [REASON] We shouldn't allow popups as a embed could pretend to be us by opening a mocked version of tldraw. This is very unobvious when it is performed as an action within our app.\n\t'allow-popups-to-escape-sandbox': false,\n\t// [MDN] Lets the resource start a presentation session.\n\t// [REASON] Prevents embed from navigating away from tldraw and pretending to be us.\n\t'allow-presentation': false,\n\t// [MDN] Experimental: Lets the resource request access to the parent's storage capabilities with the Storage Access API.\n\t// [REASON] We don't want anyone else to access our storage.\n\t'allow-storage-access-by-user-activation': false,\n\t// [MDN] Lets the resource navigate the top-level browsing context (the one named _top).\n\t// [REASON] Prevents embed from navigating away from tldraw and pretending to be us.\n\t'allow-top-navigation': false,\n\t// [MDN] Lets the resource navigate the top-level browsing context, but only if initiated by a user gesture.\n\t// [REASON] Prevents embed from navigating away from tldraw and pretending to be us.\n\t'allow-top-navigation-by-user-activation': false,\n\t// ========================================================================================\n\t// Enabled permissions\n\t// ========================================================================================\n\t// [MDN] Lets the resource run scripts (but not create popup windows).\n\t'allow-scripts': true,\n\t// [MDN] If this token is not used, the resource is treated as being from a special origin that always fails the same-origin policy (potentially preventing access to data storage/cookies and some JavaScript APIs).\n\t'allow-same-origin': true,\n\t// [MDN] Allows the resource to submit forms. If this keyword is not used, form submission is blocked.\n\t'allow-forms': true,\n} as const\n\n/** @public */\nexport type TLEmbedShapePermissions = { [K in keyof typeof embedShapePermissionDefaults]?: boolean }\n\n/** @public */\nexport interface EmbedDefinition {\n\treadonly type: string\n\treadonly title: string\n\treadonly hostnames: readonly string[]\n\treadonly minWidth?: number\n\treadonly minHeight?: number\n\treadonly width: number\n\treadonly height: number\n\treadonly doesResize: boolean\n\treadonly isAspectRatioLocked?: boolean\n\treadonly overridePermissions?: TLEmbedShapePermissions\n\treadonly instructionLink?: string\n\treadonly backgroundColor?: string\n\treadonly embedOnPaste?: boolean\n\t// TODO: FIXME this is ugly be required because some embeds have their own border radius for example spotify embeds\n\treadonly overrideOutlineRadius?: number\n\t// eslint-disable-next-line @typescript-eslint/method-signature-style\n\treadonly toEmbedUrl: (url: string) => string | undefined\n\t// eslint-disable-next-line @typescript-eslint/method-signature-style\n\treadonly fromEmbedUrl: (url: string) => string | undefined\n}\n\n/** @public */\nexport interface CustomEmbedDefinition extends EmbedDefinition {\n\treadonly icon: string\n}\n\n/** @public */\nexport type TLEmbedDefinition = EmbedDefinition | CustomEmbedDefinition\n\n/** @public */\nexport type DefaultEmbedDefinitionType = (typeof DEFAULT_EMBED_DEFINITIONS)[number]['type']\n\nconst DEFAULT_EMBED_DEFINITION_TYPES = DEFAULT_EMBED_DEFINITIONS.map(\n\t(def) => def.type\n) as DefaultEmbedDefinitionType[]\n\n/** @public */\nexport function isDefaultEmbedDefinitionType(type: string): type is DefaultEmbedDefinitionType {\n\treturn DEFAULT_EMBED_DEFINITION_TYPES.includes(type as DefaultEmbedDefinitionType)\n}\n\n/** @public */\nexport function isCustomEmbedDefinition(\n\tdef: EmbedDefinition | CustomEmbedDefinition\n): def is CustomEmbedDefinition {\n\treturn 'icon' in def\n}\n"],
4
+ "sourcesContent": ["import { safeParseUrl } from '@tldraw/editor'\n\n// Only allow multiplayer embeds. If we add additional routes later for example '/help' this won't match\nconst TLDRAW_APP_RE = /(^\\/[f|p|r|ro|s|v]\\/[^/]+\\/?$)/\n\n/** @public */\nexport const DEFAULT_EMBED_DEFINITIONS = [\n\t{\n\t\ttype: 'tldraw',\n\t\ttitle: 'tldraw',\n\t\thostnames: ['beta.tldraw.com', 'tldraw.com', 'localhost:3000'],\n\t\tminWidth: 300,\n\t\tminHeight: 300,\n\t\twidth: 720,\n\t\theight: 500,\n\t\tdoesResize: true,\n\t\toverridePermissions: {\n\t\t\t'allow-top-navigation': true,\n\t\t},\n\t\ttoEmbedUrl: (url) => {\n\t\t\tconst urlObj = safeParseUrl(url)\n\t\t\tif (urlObj && urlObj.pathname.match(TLDRAW_APP_RE)) {\n\t\t\t\t// Add the \"clean=true\" search param to the URL to hide the sidebar\n\t\t\t\turlObj.searchParams.append('embed', 'true')\n\t\t\t\treturn url\n\t\t\t}\n\t\t\treturn\n\t\t},\n\t\tfromEmbedUrl: (url) => {\n\t\t\tconst urlObj = safeParseUrl(url)\n\t\t\tif (urlObj && urlObj.pathname.match(TLDRAW_APP_RE)) {\n\t\t\t\t// Add the \"clean=true\" search param to the URL to hide the sidebar\n\t\t\t\turlObj.searchParams.delete('embed')\n\t\t\t\treturn url\n\t\t\t}\n\t\t\treturn\n\t\t},\n\t\tembedOnPaste: false,\n\t},\n\t{\n\t\ttype: 'figma',\n\t\ttitle: 'Figma',\n\t\thostnames: ['figma.com'],\n\t\twidth: 720,\n\t\theight: 500,\n\t\tdoesResize: true,\n\t\ttoEmbedUrl: (url) => {\n\t\t\tif (\n\t\t\t\t!!url.match(\n\t\t\t\t\t// eslint-disable-next-line no-useless-escape\n\t\t\t\t\t/https:\\/\\/([\\w\\.-]+\\.)?figma.com\\/(file|proto|design)\\/([0-9a-zA-Z]{22,128})(?:\\/.*)?$/\n\t\t\t\t) &&\n\t\t\t\t!url.includes('figma.com/embed')\n\t\t\t) {\n\t\t\t\treturn `https://www.figma.com/embed?embed_host=share&url=${url}`\n\t\t\t}\n\t\t\treturn\n\t\t},\n\t\tfromEmbedUrl: (url) => {\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\tembedOnPaste: true,\n\t},\n\t{\n\t\ttype: 'google_maps',\n\t\ttitle: 'Google Maps',\n\t\thostnames: ['google.*'],\n\t\twidth: 720,\n\t\theight: 500,\n\t\tdoesResize: true,\n\t\toverridePermissions: {\n\t\t\t'allow-presentation': true,\n\t\t},\n\t\ttoEmbedUrl: (url) => {\n\t\t\tif (url.includes('/maps/embed?')) {\n\t\t\t\treturn url\n\t\t\t} else if (url.includes('/maps/')) {\n\t\t\t\tconst match = url.match(/@(.*?),(.*?),(.*?)(z|m)/)\n\t\t\t\tlet result: string\n\t\t\t\tif (match) {\n\t\t\t\t\tconst [, lat, lng, zoomOrMeters, mapTypeSymbol] = match\n\t\t\t\t\tconst mapType = mapTypeSymbol === 'z' ? 'roadmap' : 'satellite'\n\t\t\t\t\t// Note: This meters to zoom equation is a rough approximation and not canonical.\n\t\t\t\t\tconst z =\n\t\t\t\t\t\tmapType === 'roadmap'\n\t\t\t\t\t\t\t? zoomOrMeters\n\t\t\t\t\t\t\t: -Math.log2(parseInt(zoomOrMeters) / 14772321) / 0.8\n\t\t\t\t\tconst host = new URL(url).host.replace('www.', '')\n\t\t\t\t\tresult = `https://${host}/maps/embed/v1/view?key=${process.env.NEXT_PUBLIC_GC_API_KEY}&center=${lat},${lng}&zoom=${z}&maptype=${mapType}`\n\t\t\t\t} else {\n\t\t\t\t\tresult = ''\n\t\t\t\t}\n\n\t\t\t\treturn result\n\t\t\t}\n\t\t\treturn\n\t\t},\n\t\tfromEmbedUrl: (url) => {\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') ?? '12'\n\t\t\t\tconst mapType = urlObj.searchParams.get('maptype') ?? 'roadmap'\n\t\t\t\t// Note: This zoom to meters equation is a rough approximation and not canonical.\n\t\t\t\tconst zoomOrMeters =\n\t\t\t\t\tmapType === 'roadmap' ? zoom : 14772321 * Math.pow(2, parseInt(zoom) * -0.8)\n\t\t\t\tconst [lat, lon] = urlObj.searchParams.get('center')!.split(',')\n\t\t\t\treturn `https://www.google.com/maps/@${lat},${lon},${zoomOrMeters}${mapType === 'roadmap' ? 'z' : 'm'}`\n\t\t\t}\n\t\t\treturn\n\t\t},\n\t\tembedOnPaste: true,\n\t},\n\t{\n\t\ttype: 'val_town',\n\t\ttitle: 'Val Town',\n\t\thostnames: ['val.town'],\n\t\tminWidth: 260,\n\t\tminHeight: 100,\n\t\twidth: 720,\n\t\theight: 500,\n\t\tdoesResize: true,\n\t\ttoEmbedUrl: (url) => {\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(/\\/v\\/(.+)\\/?/)\n\t\t\tif (matches) {\n\t\t\t\treturn `https://www.val.town/embed/${matches[1]}`\n\t\t\t}\n\t\t\treturn\n\t\t},\n\t\tfromEmbedUrl: (url) => {\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\tembedOnPaste: true,\n\t},\n\t{\n\t\ttype: 'codesandbox',\n\t\ttitle: 'CodeSandbox',\n\t\thostnames: ['codesandbox.io'],\n\t\tminWidth: 300,\n\t\tminHeight: 300,\n\t\twidth: 720,\n\t\theight: 500,\n\t\tdoesResize: true,\n\t\ttoEmbedUrl: (url) => {\n\t\t\tconst urlObj = safeParseUrl(url)\n\t\t\tconst matches = urlObj && urlObj.pathname.match(/\\/s\\/([^/]+)\\/?/)\n\t\t\tif (matches) {\n\t\t\t\treturn `https://codesandbox.io/embed/${matches[1]}`\n\t\t\t}\n\t\t\treturn\n\t\t},\n\t\tfromEmbedUrl: (url) => {\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\tembedOnPaste: true,\n\t},\n\t{\n\t\ttype: 'codepen',\n\t\ttitle: 'Codepen',\n\t\thostnames: ['codepen.io'],\n\t\tminWidth: 300,\n\t\tminHeight: 300,\n\t\twidth: 520,\n\t\theight: 400,\n\t\tdoesResize: true,\n\t\ttoEmbedUrl: (url) => {\n\t\t\tconst CODEPEN_URL_REGEXP = /https:\\/\\/codepen.io\\/([^/]+)\\/pen\\/([^/]+)/\n\t\t\tconst matches = url.match(CODEPEN_URL_REGEXP)\n\t\t\tif (matches) {\n\t\t\t\tconst [_, user, id] = matches\n\t\t\t\treturn `https://codepen.io/${user}/embed/${id}`\n\t\t\t}\n\t\t\treturn\n\t\t},\n\t\tfromEmbedUrl: (url) => {\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\tembedOnPaste: true,\n\t},\n\t{\n\t\ttype: 'scratch',\n\t\ttitle: 'Scratch',\n\t\thostnames: ['scratch.mit.edu'],\n\t\twidth: 520,\n\t\theight: 400,\n\t\tdoesResize: false,\n\t\tembedOnPaste: true,\n\t\ttoEmbedUrl: (url) => {\n\t\t\tconst SCRATCH_URL_REGEXP = /https?:\\/\\/scratch.mit.edu\\/projects\\/([^/]+)/\n\t\t\tconst matches = url.match(SCRATCH_URL_REGEXP)\n\t\t\tif (matches) {\n\t\t\t\tconst [_, id] = matches\n\t\t\t\treturn `https://scratch.mit.edu/projects/embed/${id}`\n\t\t\t}\n\t\t\treturn\n\t\t},\n\t\tfromEmbedUrl: (url) => {\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\ttype: 'youtube',\n\t\ttitle: 'YouTube',\n\t\thostnames: ['*.youtube.com', 'youtube.com', 'youtu.be'],\n\t\twidth: 800,\n\t\theight: 450,\n\t\tdoesResize: true,\n\t\toverridePermissions: {\n\t\t\t'allow-presentation': true,\n\t\t\t'allow-popups-to-escape-sandbox': true,\n\t\t},\n\t\tisAspectRatioLocked: true,\n\t\tembedOnPaste: true,\n\t\ttoEmbedUrl: (url) => {\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 === 'youtu.be') {\n\t\t\t\tconst videoId = urlObj.pathname.split('/').filter(Boolean)[0]\n\t\t\t\tconst searchParams = new URLSearchParams(urlObj.search)\n\t\t\t\tconst timeStart = searchParams.get('t')\n\t\t\t\tif (timeStart) {\n\t\t\t\t\tsearchParams.set('start', timeStart)\n\t\t\t\t\tsearchParams.delete('t')\n\t\t\t\t}\n\t\t\t\tconst search = searchParams.toString() ? '?' + searchParams.toString() : ''\n\t\t\t\treturn `https://www.youtube.com/embed/${videoId}${search}`\n\t\t\t} else if (\n\t\t\t\t(hostname === 'youtube.com' || hostname === 'm.youtube.com') &&\n\t\t\t\turlObj.pathname.match(/^\\/watch/)\n\t\t\t) {\n\t\t\t\tconst videoId = urlObj.searchParams.get('v')\n\t\t\t\tconst searchParams = new URLSearchParams(urlObj.search)\n\t\t\t\tsearchParams.delete('v')\n\t\t\t\tconst timeStart = searchParams.get('t')\n\t\t\t\tif (timeStart) {\n\t\t\t\t\tsearchParams.set('start', timeStart)\n\t\t\t\t\tsearchParams.delete('t')\n\t\t\t\t}\n\t\t\t\tconst search = searchParams.toString() ? '?' + searchParams.toString() : ''\n\t\t\t\treturn `https://www.youtube.com/embed/${videoId}${search}`\n\t\t\t}\n\t\t\treturn\n\t\t},\n\t\tfromEmbedUrl: (url) => {\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\tconst params = new URLSearchParams(urlObj.search)\n\t\t\t\t\tparams.set('v', matches?.[1] ?? '')\n\t\t\t\t\tconst timeStart = params.get('start')\n\t\t\t\t\tif (timeStart) {\n\t\t\t\t\t\tparams.set('t', timeStart)\n\t\t\t\t\t\tparams.delete('start')\n\t\t\t\t\t}\n\t\t\t\t\treturn `https://www.youtube.com/watch?${params.toString()}`\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn\n\t\t},\n\t},\n\t{\n\t\ttype: 'google_calendar',\n\t\ttitle: 'Google Calendar',\n\t\thostnames: ['calendar.google.*'],\n\t\twidth: 720,\n\t\theight: 500,\n\t\tminWidth: 460,\n\t\tminHeight: 360,\n\t\tdoesResize: true,\n\t\tinstructionLink: 'https://support.google.com/calendar/answer/41207?hl=en',\n\t\toverridePermissions: {\n\t\t\t'allow-popups-to-escape-sandbox': true,\n\t\t},\n\t\tembedOnPaste: true,\n\t\ttoEmbedUrl: (url) => {\n\t\t\tconst urlObj = safeParseUrl(url)\n\t\t\tconst cidQs = urlObj?.searchParams.get('cid')\n\n\t\t\tif (urlObj?.pathname.match(/\\/calendar\\/u\\/0/) && cidQs) {\n\t\t\t\turlObj.pathname = '/calendar/embed'\n\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('src', cidQs)\n\t\t\t\treturn urlObj.href\n\t\t\t}\n\t\t\treturn\n\t\t},\n\t\tfromEmbedUrl: (url) => {\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\ttype: 'google_slides',\n\t\ttitle: 'Google Slides',\n\t\thostnames: ['docs.google.*'],\n\t\twidth: 720,\n\t\theight: 500,\n\t\tminWidth: 460,\n\t\tminHeight: 360,\n\t\tdoesResize: true,\n\t\toverridePermissions: {\n\t\t\t'allow-popups-to-escape-sandbox': true,\n\t\t},\n\t\tembedOnPaste: true,\n\t\ttoEmbedUrl: (url) => {\n\t\t\tconst urlObj = safeParseUrl(url)\n\n\t\t\tif (urlObj?.pathname.match(/^\\/presentation/) && urlObj?.pathname.match(/\\/pub\\/?$/)) {\n\t\t\t\turlObj.pathname = urlObj.pathname.replace(/\\/pub$/, '/embed')\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\tfromEmbedUrl: (url) => {\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\ttype: 'github_gist',\n\t\ttitle: 'GitHub Gist',\n\t\thostnames: ['gist.github.com'],\n\t\twidth: 720,\n\t\theight: 500,\n\t\tdoesResize: true,\n\t\tembedOnPaste: true,\n\t\t// Security warning:\n\t\t// Gists allow adding .json extensions to the URL which return JSONP.\n\t\t// Furthermore, the JSONP can include callbacks that execute arbitrary JavaScript.\n\t\t// It _is_ sandboxed by the iframe but we still want to disable it nonetheless.\n\t\t// We restrict the id to only allow hexdecimal characters to prevent this.\n\t\t// Read more:\n\t\t// https://github.com/bhaveshk90/Content-Security-Policy-CSP-Bypass-Techniques\n\t\t// https://github.com/renniepak/CSPBypass\n\t\ttoEmbedUrl: (url) => {\n\t\t\tconst urlObj = safeParseUrl(url)\n\t\t\tif (urlObj && urlObj.pathname.match(/\\/([^/]+)\\/([0-9a-f]+)$/)) {\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\tfromEmbedUrl: (url) => {\n\t\t\tconst urlObj = safeParseUrl(url)\n\t\t\tif (urlObj && urlObj.pathname.match(/\\/([^/]+)\\/([0-9a-f]+)$/)) {\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\ttype: 'replit',\n\t\ttitle: 'Replit',\n\t\thostnames: ['replit.com'],\n\t\twidth: 720,\n\t\theight: 500,\n\t\tdoesResize: true,\n\t\tembedOnPaste: true,\n\t\ttoEmbedUrl: (url) => {\n\t\t\tconst urlObj = safeParseUrl(url)\n\t\t\tif (urlObj && urlObj.pathname.match(/\\/@([^/]+)\\/([^/]+)/)) {\n\t\t\t\turlObj.searchParams.append('embed', 'true')\n\t\t\t\treturn urlObj.href\n\t\t\t}\n\t\t\treturn\n\t\t},\n\t\tfromEmbedUrl: (url) => {\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\ttype: 'felt',\n\t\ttitle: 'Felt',\n\t\thostnames: ['felt.com'],\n\t\twidth: 720,\n\t\theight: 500,\n\t\tdoesResize: true,\n\t\tembedOnPaste: true,\n\t\ttoEmbedUrl: (url) => {\n\t\t\tconst urlObj = safeParseUrl(url)\n\t\t\tif (urlObj && urlObj.pathname.match(/^\\/map\\//)) {\n\t\t\t\treturn urlObj.origin + '/embed' + urlObj.pathname\n\t\t\t}\n\t\t\treturn\n\t\t},\n\t\tfromEmbedUrl: (url) => {\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\ttype: 'spotify',\n\t\ttitle: 'Spotify',\n\t\thostnames: ['open.spotify.com'],\n\t\twidth: 720,\n\t\theight: 500,\n\t\tminHeight: 500,\n\t\toverrideOutlineRadius: 12,\n\t\tdoesResize: true,\n\t\tembedOnPaste: true,\n\t\ttoEmbedUrl: (url) => {\n\t\t\tconst urlObj = safeParseUrl(url)\n\t\t\tif (urlObj && urlObj.pathname.match(/^\\/(artist|album)\\//)) {\n\t\t\t\treturn urlObj.origin + '/embed' + urlObj.pathname\n\t\t\t}\n\t\t\treturn\n\t\t},\n\t\tfromEmbedUrl: (url) => {\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\ttype: 'vimeo',\n\t\ttitle: 'Vimeo',\n\t\thostnames: ['vimeo.com', 'player.vimeo.com'],\n\t\twidth: 640,\n\t\theight: 360,\n\t\tdoesResize: true,\n\t\tisAspectRatioLocked: true,\n\t\tembedOnPaste: true,\n\t\ttoEmbedUrl: (url) => {\n\t\t\tconst urlObj = safeParseUrl(url)\n\t\t\tif (urlObj && urlObj.hostname === 'vimeo.com') {\n\t\t\t\tif (urlObj.pathname.match(/^\\/[0-9]+/)) {\n\t\t\t\t\treturn (\n\t\t\t\t\t\t'https://player.vimeo.com/video/' + urlObj.pathname.split('/')[1] + '?title=0&byline=0'\n\t\t\t\t\t)\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn\n\t\t},\n\t\tfromEmbedUrl: (url) => {\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\ttype: 'observable',\n\t\ttitle: 'Observable',\n\t\thostnames: ['observablehq.com'],\n\t\twidth: 720,\n\t\theight: 500,\n\t\tdoesResize: true,\n\t\tisAspectRatioLocked: false,\n\t\tbackgroundColor: '#fff',\n\t\tembedOnPaste: true,\n\t\ttoEmbedUrl: (url) => {\n\t\t\tconst urlObj = safeParseUrl(url)\n\t\t\tif (urlObj && urlObj.pathname.match(/^\\/@([^/]+)\\/([^/]+)\\/?$/)) {\n\t\t\t\treturn `${urlObj.origin}/embed${urlObj.pathname}?cell=*`\n\t\t\t}\n\t\t\tif (urlObj && urlObj.pathname.match(/^\\/d\\/([^/]+)\\/?$/)) {\n\t\t\t\tconst pathName = urlObj.pathname.replace(/^\\/d/, '')\n\t\t\t\treturn `${urlObj.origin}/embed${pathName}?cell=*`\n\t\t\t}\n\n\t\t\treturn\n\t\t},\n\t\tfromEmbedUrl: (url) => {\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\ttype: 'desmos',\n\t\ttitle: 'Desmos',\n\t\thostnames: ['desmos.com'],\n\t\twidth: 700,\n\t\theight: 450,\n\t\tdoesResize: true,\n\t\tembedOnPaste: true,\n\t\ttoEmbedUrl: (url) => {\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 === '' &&\n\t\t\t\turlObj.hash === ''\n\t\t\t) {\n\t\t\t\treturn `${url}?embed`\n\t\t\t}\n\t\t\treturn\n\t\t},\n\t\tfromEmbedUrl: (url) => {\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] as const satisfies readonly EmbedDefinition[]\n\n/**\n * Permissions with note inline from\n * https://developer.mozilla.org/en-US/docs/Web/HTML/Element/iframe#attr-sandbox\n *\n * @public\n */\nexport const embedShapePermissionDefaults = {\n\t// ========================================================================================\n\t// Disabled permissions\n\t// ========================================================================================\n\t// [MDN] Experimental: Allows for downloads to occur without a gesture from the user.\n\t// [REASON] Disabled because otherwise the <iframe/> can trick the user on behalf of us to perform an action.\n\t'allow-downloads-without-user-activation': false,\n\t// [MDN] Allows for downloads to occur with a gesture from the user.\n\t// [REASON] Disabled because otherwise the <iframe/> can trick the user on behalf of us to perform an action.\n\t'allow-downloads': false,\n\t// [MDN] Lets the resource open modal windows.\n\t// [REASON] The <iframe/> could 'window.prompt(\"Enter your tldraw password\")'.\n\t'allow-modals': false,\n\t// [MDN] Lets the resource lock the screen orientation.\n\t// [REASON] Would interfere with the tldraw interface.\n\t'allow-orientation-lock': false,\n\t// [MDN] Lets the resource use the Pointer Lock API.\n\t// [REASON] Maybe we should allow this for games embeds (scratch/codepen/codesandbox).\n\t'allow-pointer-lock': false,\n\t// [MDN] Allows popups (such as window.open(), target=\"_blank\", or showModalDialog()). If this keyword is not used, the popup will silently fail to open.\n\t// [REASON] We want to allow embeds to link back to their original sites (e.g. YouTube).\n\t'allow-popups': true,\n\t// [MDN] Lets the sandboxed document open new windows without those windows inheriting the sandboxing. For example, this can safely sandbox an advertisement without forcing the same restrictions upon the page the ad links to.\n\t// [REASON] We shouldn't allow popups as an embed could pretend to be us by opening a mocked version of tldraw. This is very unobvious when it is performed as an action within our app.\n\t'allow-popups-to-escape-sandbox': false,\n\t// [MDN] Lets the resource start a presentation session.\n\t// [REASON] Prevents embed from navigating away from tldraw and pretending to be us.\n\t'allow-presentation': false,\n\t// [MDN] Experimental: Lets the resource request access to the parent's storage capabilities with the Storage Access API.\n\t// [REASON] We don't want anyone else to access our storage.\n\t'allow-storage-access-by-user-activation': false,\n\t// [MDN] Lets the resource navigate the top-level browsing context (the one named _top).\n\t// [REASON] Prevents embed from navigating away from tldraw and pretending to be us.\n\t'allow-top-navigation': false,\n\t// [MDN] Lets the resource navigate the top-level browsing context, but only if initiated by a user gesture.\n\t// [REASON] Prevents embed from navigating away from tldraw and pretending to be us.\n\t'allow-top-navigation-by-user-activation': false,\n\t// ========================================================================================\n\t// Enabled permissions\n\t// ========================================================================================\n\t// [MDN] Lets the resource run scripts (but not create popup windows).\n\t'allow-scripts': true,\n\t// [MDN] If this token is not used, the resource is treated as being from a special origin that always fails the same-origin policy (potentially preventing access to data storage/cookies and some JavaScript APIs).\n\t'allow-same-origin': true,\n\t// [MDN] Allows the resource to submit forms. If this keyword is not used, form submission is blocked.\n\t'allow-forms': true,\n} as const\n\n/** @public */\nexport type TLEmbedShapePermissions = { [K in keyof typeof embedShapePermissionDefaults]?: boolean }\n\n/** @public */\nexport interface EmbedDefinition {\n\treadonly type: string\n\treadonly title: string\n\treadonly hostnames: readonly string[]\n\treadonly minWidth?: number\n\treadonly minHeight?: number\n\treadonly width: number\n\treadonly height: number\n\treadonly doesResize: boolean\n\treadonly isAspectRatioLocked?: boolean\n\treadonly overridePermissions?: TLEmbedShapePermissions\n\treadonly instructionLink?: string\n\treadonly backgroundColor?: string\n\treadonly embedOnPaste?: boolean\n\t// TODO: FIXME this is ugly be required because some embeds have their own border radius for example spotify embeds\n\treadonly overrideOutlineRadius?: number\n\t// eslint-disable-next-line @typescript-eslint/method-signature-style\n\treadonly toEmbedUrl: (url: string) => string | undefined\n\t// eslint-disable-next-line @typescript-eslint/method-signature-style\n\treadonly fromEmbedUrl: (url: string) => string | undefined\n}\n\n/** @public */\nexport interface CustomEmbedDefinition extends EmbedDefinition {\n\treadonly icon: string\n}\n\n/** @public */\nexport type TLEmbedDefinition = EmbedDefinition | CustomEmbedDefinition\n\n/** @public */\nexport type DefaultEmbedDefinitionType = (typeof DEFAULT_EMBED_DEFINITIONS)[number]['type']\n\nconst DEFAULT_EMBED_DEFINITION_TYPES = DEFAULT_EMBED_DEFINITIONS.map(\n\t(def) => def.type\n) as DefaultEmbedDefinitionType[]\n\n/** @public */\nexport function isDefaultEmbedDefinitionType(type: string): type is DefaultEmbedDefinitionType {\n\treturn DEFAULT_EMBED_DEFINITION_TYPES.includes(type as DefaultEmbedDefinitionType)\n}\n\n/** @public */\nexport function isCustomEmbedDefinition(\n\tdef: EmbedDefinition | CustomEmbedDefinition\n): def is CustomEmbedDefinition {\n\treturn 'icon' in def\n}\n"],
5
5
  "mappings": "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",
6
6
  "names": []
7
7
  }
@@ -220,7 +220,7 @@ function getEdgeFromNormalizedAnchor(normalizedAnchor) {
220
220
  }
221
221
  function getElbowArrowTerminalInfo(editor, arrow, binding, point) {
222
222
  const arrowStrokeSize = STROKE_SIZES[arrow.props.size] * arrow.props.scale / 2;
223
- const minEndSegmentLength = arrowStrokeSize * arrow.props.scale * 3;
223
+ const minEndSegmentLength = arrowStrokeSize * 3;
224
224
  if (binding) {
225
225
  const target = editor.getShape(binding.toId);
226
226
  const geometry = getBindingGeometryInArrowSpace(editor, arrow, binding.toId, binding.props);
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../../../../src/lib/shapes/arrow/elbow/getElbowArrowInfo.tsx"],
4
- "sourcesContent": ["import {\n\tapproximately,\n\tassert,\n\tBox,\n\tEditor,\n\texhaustiveSwitchError,\n\tGeometry2dFilters,\n\tlerp,\n\tMat,\n\tTLArrowBinding,\n\tTLArrowBindingProps,\n\tTLArrowShape,\n\tTLShapeId,\n\tVec,\n\tVecLike,\n\tVecModel,\n} from '@tldraw/editor'\nimport { ArrowShapeUtil } from '../ArrowShapeUtil'\nimport { BOUND_ARROW_OFFSET, STROKE_SIZES, TLArrowBindings } from '../shared'\nimport {\n\tElbowArrowAxes,\n\tElbowArrowBox,\n\tElbowArrowBoxEdges,\n\tElbowArrowEdge,\n\tElbowArrowInfo,\n\tElbowArrowInfoWithoutRoute,\n\tElbowArrowOptions,\n\tElbowArrowRoute,\n\tElbowArrowSide,\n\tElbowArrowSideWithAxis,\n\tElbowArrowTargetBox,\n\tElbowArrowTerminal,\n} from './definitions'\nimport { createRange, expandRange, isWithinRange, rangeSize, subtractRange } from './range'\nimport { ElbowArrowWorkingInfo } from './routes/ElbowArrowWorkingInfo'\nimport {\n\trouteArrowWithAutoEdgePicking,\n\trouteArrowWithManualEdgePicking,\n\trouteArrowWithPartialEdgePicking,\n} from './routes/routeArrowWithAutoEdgePicking'\n\nexport function getElbowArrowInfo(\n\teditor: Editor,\n\tarrow: TLArrowShape,\n\tbindings: TLArrowBindings\n): ElbowArrowInfo {\n\tconst shapeOptions = editor.getShapeUtil<ArrowShapeUtil>(arrow.type).options\n\tconst options: ElbowArrowOptions = {\n\t\telbowMidpoint: arrow.props.elbowMidPoint,\n\t\texpandElbowLegLength: shapeOptions.expandElbowLegLength[arrow.props.size] * arrow.props.scale,\n\t\tminElbowLegLength: shapeOptions.minElbowLegLength[arrow.props.size] * arrow.props.scale,\n\t}\n\n\t// Before we can do anything else, we need to find the start and end terminals of the arrow.\n\t// These contain the binding info, geometry, bounds, etc.\n\tlet startTerminal = getElbowArrowTerminalInfo(editor, arrow, bindings.start, arrow.props.start)\n\tlet endTerminal = getElbowArrowTerminalInfo(editor, arrow, bindings.end, arrow.props.end)\n\t// unclosed paths are weird - we handle them outside of the initial terminal info.\n\tstartTerminal = adjustTerminalForUnclosedPathIfNeeded(startTerminal, endTerminal, options)\n\tendTerminal = adjustTerminalForUnclosedPathIfNeeded(endTerminal, startTerminal, options)\n\n\t// Ther terminal might include a \"side\" if the user has explicitly indicated what side the arrow\n\t// should come from. There are two terminals, and two cases for each terminal (explicit side or\n\t// not), for a total for 4 cases to handle. In order to keep things a bit simpler though, we\n\t// only handle 3 cases: if start no side and end has a side, we flip them around. From here on\n\t// out, we use A and B to refer to the terminals as they may be swapped.\n\tconst swapOrder = !!(!startTerminal.side && endTerminal.side)\n\n\tlet { aTerminal, bTerminal } = swapOrder\n\t\t? { aTerminal: endTerminal, bTerminal: startTerminal }\n\t\t: { aTerminal: startTerminal, bTerminal: endTerminal }\n\n\t// We model each edge that an arrow might enter/exit from separately. If an edge is blocked,\n\t// `getUsableEdge` might return null.\n\tlet edgesA = {\n\t\ttop: getUsableEdge(aTerminal, bTerminal, 'top', options),\n\t\tright: getUsableEdge(aTerminal, bTerminal, 'right', options),\n\t\tbottom: getUsableEdge(aTerminal, bTerminal, 'bottom', options),\n\t\tleft: getUsableEdge(aTerminal, bTerminal, 'left', options),\n\t}\n\n\tlet edgesB = {\n\t\ttop: getUsableEdge(bTerminal, aTerminal, 'top', options),\n\t\tright: getUsableEdge(bTerminal, aTerminal, 'right', options),\n\t\tbottom: getUsableEdge(bTerminal, aTerminal, 'bottom', options),\n\t\tleft: getUsableEdge(bTerminal, aTerminal, 'left', options),\n\t}\n\n\t// We we don't have a usable edge because it's blocked, we can convert some of the terminals to\n\t// points. Point terminals have less strict edge routing rules, but don't look as good\n\t// generally. For example, the arrow might go through the shape instead of around.\n\tconst aIsUsable = hasUsableEdge(edgesA, aTerminal.side)\n\tconst bIsUsable = hasUsableEdge(edgesB, bTerminal.side)\n\tlet needsNewEdges = false\n\tif (!aIsUsable || !bIsUsable) {\n\t\tneedsNewEdges = true\n\t\tif (!aIsUsable) {\n\t\t\tbTerminal = convertTerminalToPoint(bTerminal)\n\t\t}\n\n\t\tif (!bIsUsable) {\n\t\t\taTerminal = convertTerminalToPoint(aTerminal)\n\t\t}\n\n\t\tif (bTerminal.bounds.containsPoint(aTerminal.target, options.expandElbowLegLength)) {\n\t\t\tbTerminal = convertTerminalToPoint(bTerminal)\n\t\t}\n\n\t\tif (aTerminal.bounds.containsPoint(bTerminal.target, options.expandElbowLegLength)) {\n\t\t\taTerminal = convertTerminalToPoint(aTerminal)\n\t\t}\n\t}\n\n\tif (needsNewEdges) {\n\t\tedgesA = {\n\t\t\ttop: getUsableEdge(aTerminal, bTerminal, 'top', options),\n\t\t\tright: getUsableEdge(aTerminal, bTerminal, 'right', options),\n\t\t\tbottom: getUsableEdge(aTerminal, bTerminal, 'bottom', options),\n\t\t\tleft: getUsableEdge(aTerminal, bTerminal, 'left', options),\n\t\t}\n\n\t\tedgesB = {\n\t\t\ttop: getUsableEdge(bTerminal, aTerminal, 'top', options),\n\t\t\tright: getUsableEdge(bTerminal, aTerminal, 'right', options),\n\t\t\tbottom: getUsableEdge(bTerminal, aTerminal, 'bottom', options),\n\t\t\tleft: getUsableEdge(bTerminal, aTerminal, 'left', options),\n\t\t}\n\t}\n\n\t// We expand the bounds of the terminals so we can route arrows around them without the arrows\n\t// being too close to the shapes.\n\tconst expandedA = aTerminal.isPoint\n\t\t? aTerminal.bounds\n\t\t: aTerminal.bounds.clone().expandBy(options.expandElbowLegLength)\n\tconst expandedB = bTerminal.isPoint\n\t\t? bTerminal.bounds\n\t\t: bTerminal.bounds.clone().expandBy(options.expandElbowLegLength)\n\n\tconst common: ElbowArrowBox = {\n\t\toriginal: Box.Common([aTerminal.bounds, bTerminal.bounds]),\n\t\texpanded: Box.Common([expandedA, expandedB]),\n\t}\n\n\t// Calculate the gaps between the two terminals. If gap is positive, B is to the right of A. If\n\t// it's negative, the opposite is true. If it's 0, there's no gap between the shapes in that\n\t// dimension.\n\tlet gapX = bTerminal.bounds.minX - aTerminal.bounds.maxX\n\tif (gapX < 0) {\n\t\tgapX = aTerminal.bounds.minX - bTerminal.bounds.maxX\n\t\tif (gapX < 0) {\n\t\t\tgapX = 0\n\t\t}\n\t\tgapX = -gapX\n\t}\n\tlet gapY = bTerminal.bounds.minY - aTerminal.bounds.maxY\n\tif (gapY < 0) {\n\t\tgapY = aTerminal.bounds.minY - bTerminal.bounds.maxY\n\t\tif (gapY < 0) {\n\t\t\tgapY = 0\n\t\t}\n\t\tgapY = -gapY\n\t}\n\n\t// The midpoint of the gap is a useful point to route arrows through, but the user can also drag\n\t// it to choose a new midpoint. First, we calculate some constraints we'll need to keep in mind\n\t// when figuring out the midpoint...\n\tconst aMinLength = aTerminal.minEndSegmentLength * 3\n\tconst bMinLength = bTerminal.minEndSegmentLength * 3\n\tconst minLegDistanceNeeded =\n\t\t(aTerminal.isPoint ? aMinLength : options.minElbowLegLength) +\n\t\t(bTerminal.isPoint ? bMinLength : options.minElbowLegLength)\n\n\t// ...then, the possible range of the midpoint. This is also used when dragging the midpoint.\n\tlet mxRange: null | { a: number; b: number } = null\n\tif (gapX > minLegDistanceNeeded) {\n\t\tmxRange = {\n\t\t\ta: aTerminal.isPoint ? aTerminal.bounds.maxX + aMinLength : expandedA.maxX,\n\t\t\tb: bTerminal.isPoint ? bTerminal.bounds.minX - bMinLength : expandedB.minX,\n\t\t}\n\t} else if (gapX < -minLegDistanceNeeded) {\n\t\tmxRange = {\n\t\t\ta: aTerminal.isPoint ? aTerminal.bounds.minX - aMinLength : expandedA.minX,\n\t\t\tb: bTerminal.isPoint ? bTerminal.bounds.maxX + bMinLength : expandedB.maxX,\n\t\t}\n\t}\n\n\tlet myRange: null | { a: number; b: number } = null\n\tif (gapY > minLegDistanceNeeded) {\n\t\tmyRange = {\n\t\t\ta: aTerminal.isPoint ? aTerminal.bounds.maxY + aMinLength : expandedA.maxY,\n\t\t\tb: bTerminal.isPoint ? bTerminal.bounds.minY - bMinLength : expandedB.minY,\n\t\t}\n\t} else if (gapY < -minLegDistanceNeeded) {\n\t\tmyRange = {\n\t\t\ta: aTerminal.isPoint ? aTerminal.bounds.minY - aMinLength : expandedA.minY,\n\t\t\tb: bTerminal.isPoint ? bTerminal.bounds.maxY + bMinLength : expandedB.maxY,\n\t\t}\n\t}\n\n\t// and finally we take the range and the midpoint prop and calculate the actual position of the\n\t// midpoint. Note that the midpoint and midpoint range can be null if the gap is too small for a\n\t// midpoint line.\n\tconst midpoint = swapOrder ? 1 - options.elbowMidpoint : options.elbowMidpoint\n\tconst mx = mxRange ? lerp(mxRange.a, mxRange.b, midpoint) : null\n\tconst my = myRange ? lerp(myRange.a, myRange.b, midpoint) : null\n\n\t// The info without route is given to the route-finding functions to route between the two\n\t// terminals.\n\tconst info: ElbowArrowInfoWithoutRoute = {\n\t\toptions,\n\t\tswapOrder,\n\t\tA: {\n\t\t\tisPoint: aTerminal.isPoint,\n\t\t\ttarget: aTerminal.target,\n\t\t\tisExact: aTerminal.isExact,\n\t\t\tarrowheadOffset: aTerminal.arrowheadOffset,\n\t\t\tminEndSegmentLength: aTerminal.minEndSegmentLength,\n\t\t\toriginal: aTerminal.bounds,\n\t\t\texpanded: expandedA,\n\t\t\tedges: edgesA,\n\t\t\tgeometry: aTerminal.geometry,\n\t\t},\n\t\tB: {\n\t\t\tisPoint: bTerminal.isPoint,\n\t\t\ttarget: bTerminal.target,\n\t\t\tisExact: bTerminal.isExact,\n\t\t\tarrowheadOffset: bTerminal.arrowheadOffset,\n\t\t\tminEndSegmentLength: bTerminal.minEndSegmentLength,\n\t\t\toriginal: bTerminal.bounds,\n\t\t\texpanded: expandedB,\n\t\t\tedges: edgesB,\n\t\t\tgeometry: bTerminal.geometry,\n\t\t},\n\t\tcommon,\n\t\tgapX,\n\t\tgapY,\n\t\tmidX: mx,\n\t\tmidY: my,\n\t}\n\n\t// We wrap the info in a working info object that lets us mutate and reset it as needed.\n\tconst workingInfo = new ElbowArrowWorkingInfo(info)\n\n\t// Figure out the final sides to use for each terminal.\n\tconst aSide = getSideToUse(aTerminal, bTerminal, info.A.edges)\n\tconst bSide = getSideToUse(bTerminal, aTerminal, info.B.edges)\n\n\t// try to find a route with the specification we have:\n\tlet route\n\tif (aSide && bSide) {\n\t\troute = routeArrowWithManualEdgePicking(workingInfo, aSide, bSide)\n\t} else if (aSide && !bSide) {\n\t\troute = routeArrowWithPartialEdgePicking(workingInfo, aSide)\n\t}\n\tif (!route) {\n\t\troute = routeArrowWithAutoEdgePicking(workingInfo, aSide || bSide ? 'fallback' : 'auto')\n\t}\n\n\tif (route) {\n\t\t// If we found a route, we need to fix it up. The route will only go to the bounding box of\n\t\t// the shape, so we need to cast the final segments into the actual geometry of the shape.\n\t\tcastPathSegmentIntoGeometry('first', info.A, info.B, route)\n\t\tcastPathSegmentIntoGeometry('last', info.B, info.A, route)\n\t\t// If we have tiny L-shaped arrows, the arrowheads look super janky. We fix those up by just\n\t\t// drawing a straight line instead.\n\t\tfixTinyEndNubs(route, aTerminal, bTerminal)\n\n\t\t// If we swapped the order way back of the start of things, we need to reverse the route so\n\t\t// it flows start -> end instead of A -> B.\n\t\tif (swapOrder) route.points.reverse()\n\t}\n\n\treturn {\n\t\t...info,\n\t\troute,\n\t\tmidXRange: mxRange\n\t\t\t? swapOrder\n\t\t\t\t? { lo: mxRange.b, hi: mxRange.a }\n\t\t\t\t: { lo: mxRange.a, hi: mxRange.b }\n\t\t\t: null,\n\t\tmidYRange: myRange\n\t\t\t? swapOrder\n\t\t\t\t? { lo: myRange.b, hi: myRange.a }\n\t\t\t\t: { lo: myRange.a, hi: myRange.b }\n\t\t\t: null,\n\t}\n}\n\n/**\n * Take the route from `getElbowArrowInfo` (which represents the visible body of the arrow) and\n * convert it into a path we can use to show that paths to the handles, which may extend further\n * into the target shape geometries.\n * @returns\n */\nexport function getRouteHandlePath(info: ElbowArrowInfo, route: ElbowArrowRoute): ElbowArrowRoute {\n\tconst startTarget = info.swapOrder ? info.B.target : info.A.target\n\tconst endTarget = info.swapOrder ? info.A.target : info.B.target\n\n\tconst firstSegmentLength = Vec.ManhattanDist(route.points[0], route.points[1])\n\tconst lastSegmentLength = Vec.ManhattanDist(\n\t\troute.points[route.points.length - 2],\n\t\troute.points[route.points.length - 1]\n\t)\n\n\tconst newFirstSegmentLength = Vec.ManhattanDist(startTarget, route.points[1])\n\tconst newLastSegmentLength = Vec.ManhattanDist(route.points[route.points.length - 2], endTarget)\n\n\tconst firstSegmentLengthChange = firstSegmentLength - newFirstSegmentLength\n\tconst lastSegmentLengthChange = lastSegmentLength - newLastSegmentLength\n\n\tconst newPoints = [startTarget, ...route.points, endTarget]\n\n\treturn {\n\t\tname: route.name,\n\t\tdistance: route.distance + firstSegmentLengthChange + lastSegmentLengthChange,\n\t\tpoints: newPoints.filter((p) => !route.skipPointsWhenDrawing.has(p)),\n\t\taEdgePicking: route.aEdgePicking,\n\t\tbEdgePicking: route.bEdgePicking,\n\t\tskipPointsWhenDrawing: route.skipPointsWhenDrawing,\n\t\tmidpointHandle: route.midpointHandle,\n\t}\n}\n\n/**\n * Take a normalizes anchor and return the side we think it's closest to.\n */\nexport function getEdgeFromNormalizedAnchor(normalizedAnchor: VecLike) {\n\tif (approximately(normalizedAnchor.x, 0.5) && approximately(normalizedAnchor.y, 0.5)) {\n\t\treturn null\n\t}\n\n\tif (\n\t\tMath.abs(normalizedAnchor.x - 0.5) >\n\t\t// slightly bias towards x arrows to prevent flickering when the anchor is right on the line\n\t\t// between the two directions\n\t\tMath.abs(normalizedAnchor.y - 0.5) - 0.0001\n\t) {\n\t\treturn normalizedAnchor.x < 0.5 ? 'left' : 'right'\n\t}\n\n\treturn normalizedAnchor.y < 0.5 ? 'top' : 'bottom'\n}\n\nfunction getElbowArrowTerminalInfo(\n\teditor: Editor,\n\tarrow: TLArrowShape,\n\tbinding: TLArrowBinding | undefined,\n\tpoint: VecModel\n): ElbowArrowTerminal {\n\tconst arrowStrokeSize = (STROKE_SIZES[arrow.props.size] * arrow.props.scale) / 2\n\tconst minEndSegmentLength = arrowStrokeSize * arrow.props.scale * 3\n\n\tif (binding) {\n\t\tconst target = editor.getShape(binding.toId)\n\t\tconst geometry = getBindingGeometryInArrowSpace(editor, arrow, binding.toId, binding.props)\n\t\tif (geometry && target) {\n\t\t\tlet arrowheadOffset = 0\n\t\t\tconst arrowheadProp = binding.props.terminal === 'start' ? 'arrowheadStart' : 'arrowheadEnd'\n\t\t\tif (arrow.props[arrowheadProp] !== 'none') {\n\t\t\t\tconst targetScale = 'scale' in target.props ? target.props.scale : 1\n\t\t\t\tconst targetStrokeSize =\n\t\t\t\t\t'size' in target.props ? ((STROKE_SIZES[target.props.size] ?? 0) * targetScale) / 2 : 0\n\n\t\t\t\tarrowheadOffset =\n\t\t\t\t\tarrowStrokeSize + targetStrokeSize + BOUND_ARROW_OFFSET * arrow.props.scale\n\t\t\t}\n\n\t\t\tlet side: ElbowArrowSideWithAxis | null = null\n\t\t\tconst targetPoint = geometry.target\n\t\t\tif (binding.props.isPrecise) {\n\t\t\t\tside = getEdgeFromNormalizedAnchor(\n\t\t\t\t\tVec.RotWith(\n\t\t\t\t\t\tbinding.props.normalizedAnchor,\n\t\t\t\t\t\t{ x: 0.5, y: 0.5 },\n\t\t\t\t\t\tgeometry.shapeToArrowTransform.rotation()\n\t\t\t\t\t)\n\t\t\t\t)\n\t\t\t}\n\n\t\t\treturn {\n\t\t\t\ttargetShapeId: binding.toId,\n\t\t\t\tisPoint: false,\n\t\t\t\tisExact: binding.props.isExact,\n\t\t\t\tbounds: geometry.bounds,\n\t\t\t\tgeometry: geometry.geometry,\n\t\t\t\ttarget: targetPoint,\n\t\t\t\tarrowheadOffset,\n\t\t\t\tminEndSegmentLength,\n\t\t\t\tside,\n\t\t\t\tsnap: binding.props.snap,\n\t\t\t}\n\t\t}\n\t}\n\n\treturn {\n\t\ttargetShapeId: null,\n\t\tbounds: Box.FromCenter(point, { x: 0, y: 0 }),\n\t\tgeometry: null,\n\t\tisExact: false,\n\t\tisPoint: true,\n\t\ttarget: Vec.From(point),\n\t\tarrowheadOffset: 0,\n\t\tminEndSegmentLength,\n\t\tside: null,\n\t\tsnap: 'none',\n\t}\n}\n\nfunction getBindingGeometryInArrowSpace(\n\teditor: Editor,\n\tarrow: TLArrowShape,\n\ttargetId: TLShapeId,\n\tbindingProps: TLArrowBindingProps\n) {\n\tconst hasArrowhead =\n\t\tbindingProps.terminal === 'start'\n\t\t\t? arrow.props.arrowheadStart !== 'none'\n\t\t\t: arrow.props.arrowheadEnd !== 'none'\n\n\tconst targetGeometryInTargetSpace = editor.getShapeGeometry(\n\t\ttargetId,\n\t\thasArrowhead ? undefined : { context: '@tldraw/arrow-without-arrowhead' }\n\t)\n\n\tif (!targetGeometryInTargetSpace) {\n\t\treturn null\n\t}\n\n\tconst arrowTransform = editor.getShapePageTransform(arrow.id)\n\tconst shapeTransform = editor.getShapePageTransform(targetId)\n\tconst shapeToArrowTransform = arrowTransform.clone().invert().multiply(shapeTransform)\n\n\tconst targetGeometryInArrowSpace = targetGeometryInTargetSpace.transform(shapeToArrowTransform)\n\n\tconst center = { x: 0.5, y: 0.5 }\n\tconst normalizedAnchor = bindingProps.isPrecise ? bindingProps.normalizedAnchor : center\n\n\tconst targetInShapeSpace = {\n\t\tx: lerp(\n\t\t\ttargetGeometryInTargetSpace.bounds.minX,\n\t\t\ttargetGeometryInTargetSpace.bounds.maxX,\n\t\t\tnormalizedAnchor.x\n\t\t),\n\t\ty: lerp(\n\t\t\ttargetGeometryInTargetSpace.bounds.minY,\n\t\t\ttargetGeometryInTargetSpace.bounds.maxY,\n\t\t\tnormalizedAnchor.y\n\t\t),\n\t}\n\tconst centerInShapeSpace = {\n\t\tx: lerp(\n\t\t\ttargetGeometryInTargetSpace.bounds.minX,\n\t\t\ttargetGeometryInTargetSpace.bounds.maxX,\n\t\t\tcenter.x\n\t\t),\n\t\ty: lerp(\n\t\t\ttargetGeometryInTargetSpace.bounds.minY,\n\t\t\ttargetGeometryInTargetSpace.bounds.maxY,\n\t\t\tcenter.y\n\t\t),\n\t}\n\n\tconst targetInArrowSpace = Mat.applyToPoint(shapeToArrowTransform, targetInShapeSpace)\n\tconst centerInArrowSpace = Mat.applyToPoint(shapeToArrowTransform, centerInShapeSpace)\n\n\treturn {\n\t\tbounds: targetGeometryInArrowSpace.bounds,\n\t\tgeometry: targetGeometryInArrowSpace,\n\t\ttarget: targetInArrowSpace,\n\t\tcenter: centerInArrowSpace,\n\t\tshapeToArrowTransform,\n\t}\n}\n\nconst sideProps = {\n\ttop: {\n\t\texpand: -1,\n\t\tmain: 'minY',\n\t\topposite: 'maxY',\n\t\tcrossMid: 'midX',\n\t\tcrossMin: 'minX',\n\t\tcrossMax: 'maxX',\n\t\tbRangeExpand: 'max',\n\t\tcrossAxis: 'x',\n\t},\n\tbottom: {\n\t\texpand: 1,\n\t\tmain: 'maxY',\n\t\topposite: 'minY',\n\t\tcrossMid: 'midX',\n\t\tcrossMin: 'minX',\n\t\tcrossMax: 'maxX',\n\t\tbRangeExpand: 'min',\n\t\tcrossAxis: 'x',\n\t},\n\tleft: {\n\t\texpand: -1,\n\t\tmain: 'minX',\n\t\topposite: 'maxX',\n\t\tcrossMid: 'midY',\n\t\tcrossMin: 'minY',\n\t\tcrossMax: 'maxY',\n\t\tbRangeExpand: 'max',\n\t\tcrossAxis: 'y',\n\t},\n\tright: {\n\t\texpand: 1,\n\t\tmain: 'maxX',\n\t\topposite: 'minX',\n\t\tcrossMid: 'midY',\n\t\tcrossMin: 'minY',\n\t\tcrossMax: 'maxY',\n\t\tbRangeExpand: 'min',\n\t\tcrossAxis: 'y',\n\t},\n} as const\n\nexport function getUsableEdge(\n\ta: ElbowArrowTerminal,\n\tb: ElbowArrowTerminal,\n\tside: 'top' | 'right' | 'bottom' | 'left',\n\toptions: ElbowArrowOptions\n): ElbowArrowEdge | null {\n\tconst props = sideProps[side]\n\n\t// if a shape is bound to itself, by default we'd end up routing the arrow _within_ the shape -\n\t// as if it were a point-to-point arrow. if one of the bindings is specifically to the edge\n\t// though, we route it externally instead.\n\tconst isSelfBoundAndShouldRouteExternal =\n\t\ta.targetShapeId === b.targetShapeId &&\n\t\ta.targetShapeId !== null &&\n\t\t(a.snap === 'edge' || a.snap === 'edge-point') &&\n\t\t(b.snap === 'edge' || b.snap === 'edge-point')\n\n\tconst aValue = a.bounds[props.main]\n\tconst aExpanded = a.isPoint ? null : aValue + props.expand * options.expandElbowLegLength\n\n\tconst originalACrossRange = createRange(a.bounds[props.crossMin], a.bounds[props.crossMax])\n\tlet aCrossRange = originalACrossRange\n\n\t// this edge is too small to be useful:\n\tif (!aCrossRange) {\n\t\treturn null\n\t}\n\n\tassert(originalACrossRange)\n\tconst bRange = createRange(b.bounds[props.main], b.bounds[props.opposite])\n\tif (!b.isPoint) {\n\t\tbRange[props.bRangeExpand] -= options.minElbowLegLength * 2 * props.expand\n\t}\n\n\tconst bCrossRange = expandRange(\n\t\tcreateRange(b.bounds[props.crossMin], b.bounds[props.crossMax]),\n\t\toptions.expandElbowLegLength\n\t)\n\tassert(bRange && bCrossRange)\n\n\tlet isPartial = false\n\tif (\n\t\tisWithinRange(aValue, bRange) &&\n\t\t!a.isPoint &&\n\t\t!b.isPoint &&\n\t\t!isSelfBoundAndShouldRouteExternal\n\t) {\n\t\tconst subtracted = subtractRange(aCrossRange, bCrossRange)\n\t\tswitch (subtracted.length) {\n\t\t\tcase 0:\n\t\t\t\treturn null\n\t\t\tcase 1:\n\t\t\t\tisPartial = subtracted[0] !== aCrossRange\n\t\t\t\taCrossRange = subtracted[0]\n\t\t\t\tbreak\n\t\t\tcase 2:\n\t\t\t\tisPartial = true\n\t\t\t\taCrossRange =\n\t\t\t\t\trangeSize(subtracted[0]) > rangeSize(subtracted[1]) ? subtracted[0] : subtracted[1]\n\t\t\t\tbreak\n\t\t\tdefault:\n\t\t\t\texhaustiveSwitchError(subtracted)\n\t\t}\n\t}\n\n\tif (!isWithinRange(a.target[props.crossAxis], aCrossRange)) {\n\t\treturn null\n\t}\n\tconst crossTarget = a.target[props.crossAxis]\n\n\treturn {\n\t\tvalue: aValue,\n\t\texpanded: aExpanded,\n\t\tcross: aCrossRange,\n\t\tcrossTarget,\n\t\tisPartial,\n\t}\n}\n\nfunction hasUsableEdge(edges: ElbowArrowBoxEdges, side: ElbowArrowSideWithAxis | null) {\n\tif (side === null) {\n\t\treturn !!(edges.bottom || edges.left || edges.right || edges.top)\n\t}\n\n\tif (side === 'x') {\n\t\treturn !!edges.left || !!edges.right\n\t}\n\n\tif (side === 'y') {\n\t\treturn !!edges.top || !!edges.bottom\n\t}\n\n\treturn !!edges[side]\n}\n\nfunction getSideToUse(\n\tbinding: ElbowArrowTerminal,\n\tother: ElbowArrowTerminal,\n\tedges: ElbowArrowBoxEdges | null\n): ElbowArrowSide | null {\n\tswitch (binding.side) {\n\t\tcase null:\n\t\t\treturn null\n\t\tcase 'x':\n\t\t\tif (binding.bounds.center.x > other.bounds.center.x && edges?.left) {\n\t\t\t\treturn 'left'\n\t\t\t} else if (edges?.right) {\n\t\t\t\treturn 'right'\n\t\t\t}\n\t\t\treturn null\n\t\tcase 'y':\n\t\t\tif (binding.bounds.center.y > other.bounds.center.y && edges?.top) {\n\t\t\t\treturn 'top'\n\t\t\t} else if (edges?.bottom) {\n\t\t\t\treturn 'bottom'\n\t\t\t}\n\t\t\treturn null\n\t\tdefault:\n\t\t\treturn binding.side\n\t}\n}\n\nfunction convertTerminalToPoint(terminal: ElbowArrowTerminal): ElbowArrowTerminal {\n\tif (terminal.isPoint) return terminal\n\n\tlet side: ElbowArrowSideWithAxis | null = null\n\tlet arrowheadOffset = 0\n\tif (terminal.snap === 'edge' || terminal.snap === 'edge-point') {\n\t\tarrowheadOffset = terminal.arrowheadOffset\n\t\tif (terminal.side === 'x' || terminal.side === 'left' || terminal.side === 'right') {\n\t\t\tside = 'x'\n\t\t}\n\t\tif (terminal.side === 'y' || terminal.side === 'top' || terminal.side === 'bottom') {\n\t\t\tside = 'y'\n\t\t}\n\t}\n\n\treturn {\n\t\ttargetShapeId: terminal.targetShapeId,\n\t\tside,\n\t\tbounds: new Box(terminal.target.x, terminal.target.y, 0, 0),\n\t\tgeometry: terminal.geometry,\n\t\ttarget: terminal.target,\n\t\tarrowheadOffset,\n\t\tminEndSegmentLength: terminal.minEndSegmentLength,\n\t\tisExact: terminal.isExact,\n\t\tisPoint: true,\n\t\tsnap: terminal.snap,\n\t}\n}\n\n/**\n * Make sure the first path segments goes fully into the target, and doesn't just point to its\n * bounding box. This modifies the route in-place.\n */\nfunction castPathSegmentIntoGeometry(\n\tsegment: 'first' | 'last',\n\ttarget: ElbowArrowTargetBox,\n\tother: ElbowArrowTargetBox,\n\troute: ElbowArrowRoute\n) {\n\tif (!target.geometry) return\n\n\tconst point1 = segment === 'first' ? route.points[0] : route.points[route.points.length - 1]\n\tconst point2 = segment === 'first' ? route.points[1] : route.points[route.points.length - 2]\n\n\tconst pointToFindClosestIntersectionTo = target.geometry.isClosed ? point2 : target.target\n\n\tconst initialDistance = Vec.ManhattanDist(point1, pointToFindClosestIntersectionTo)\n\n\tlet nearestIntersectionToPoint2: VecLike | null = null\n\tlet nearestDistanceToPoint2 = Infinity\n\n\tif (target.isExact) {\n\t\tnearestIntersectionToPoint2 = target.target\n\t} else if (target.geometry) {\n\t\tconst intersections = target.geometry.intersectLineSegment(point2, target.target, {\n\t\t\tincludeLabels: false,\n\t\t\tincludeInternal: false,\n\t\t})\n\t\tif (\n\t\t\ttarget.geometry.hitTestPoint(\n\t\t\t\ttarget.target,\n\t\t\t\tMath.max(1, target.arrowheadOffset),\n\t\t\t\ttrue,\n\t\t\t\tGeometry2dFilters.EXCLUDE_NON_STANDARD\n\t\t\t)\n\t\t) {\n\t\t\tintersections.push(target.target)\n\t\t}\n\t\tfor (const intersection of intersections) {\n\t\t\tconst point2Distance = Vec.ManhattanDist(pointToFindClosestIntersectionTo, intersection)\n\t\t\tif (point2Distance < nearestDistanceToPoint2) {\n\t\t\t\tnearestDistanceToPoint2 = point2Distance\n\t\t\t\tnearestIntersectionToPoint2 = intersection\n\t\t\t}\n\t\t}\n\t}\n\n\tif (nearestIntersectionToPoint2) {\n\t\tlet offset = target.arrowheadOffset\n\n\t\tconst currentFinalSegmentLength = Vec.ManhattanDist(point2, nearestIntersectionToPoint2)\n\t\tconst minLength = target.arrowheadOffset * 2\n\t\tif (currentFinalSegmentLength < minLength) {\n\t\t\tconst targetLength = minLength - target.arrowheadOffset\n\t\t\toffset = currentFinalSegmentLength - targetLength\n\t\t}\n\t\tif (offset < target.minEndSegmentLength) {\n\t\t\tif (target.geometry.bounds.containsPoint(other.target)) {\n\t\t\t\toffset = Math.max(0, offset)\n\t\t\t} else {\n\t\t\t\toffset = -target.arrowheadOffset\n\t\t\t}\n\t\t}\n\n\t\tlet nudgedPoint = nearestIntersectionToPoint2\n\t\tlet shouldAddExtraPointForNudge = false\n\t\tif (!target.isExact && offset !== 0) {\n\t\t\tconst nudged = Vec.Nudge(nearestIntersectionToPoint2, point2, offset)\n\t\t\tnudgedPoint = nudged\n\t\t\tif (\n\t\t\t\toffset < 0 &&\n\t\t\t\t!target.geometry.hitTestPoint(nudged, 0, true, Geometry2dFilters.EXCLUDE_NON_STANDARD)\n\t\t\t) {\n\t\t\t\t// point has been nudged _out_ of the shape so lets not actually apply the nudge\n\t\t\t\tnudgedPoint = nearestIntersectionToPoint2\n\t\t\t} else {\n\t\t\t\tif (offset < 0) {\n\t\t\t\t\tshouldAddExtraPointForNudge = true\n\t\t\t\t}\n\t\t\t\tnudgedPoint = nudged\n\t\t\t}\n\t\t}\n\n\t\tconst newDistance = Vec.ManhattanDist(point2, nudgedPoint)\n\t\troute.distance += newDistance - initialDistance\n\t\tpoint1.x = nudgedPoint.x\n\t\tpoint1.y = nudgedPoint.y\n\n\t\tif (shouldAddExtraPointForNudge) {\n\t\t\tconst midPoint = Vec.Lrp(point2, point1, 0.5)\n\t\t\troute.skipPointsWhenDrawing.add(midPoint)\n\t\t\troute.points.splice(segment === 'first' ? 1 : route.points.length - 1, 0, midPoint)\n\t\t}\n\t}\n}\n\nfunction fixTinyEndNubs(\n\troute: ElbowArrowRoute,\n\taTerminal: ElbowArrowTerminal,\n\tbTerminal: ElbowArrowTerminal\n) {\n\tif (!route) return\n\n\tif (route.points.length >= 3) {\n\t\tconst a = route.points[0]\n\t\tconst b = route.points[1]\n\t\tconst firstSegmentLength = Vec.ManhattanDist(a, b)\n\t\tif (firstSegmentLength < aTerminal.minEndSegmentLength) {\n\t\t\troute.points.splice(1, 1)\n\t\t\tif (route.points.length >= 3) {\n\t\t\t\tconst matchAxis = approximately(a.x, b.x) ? 'y' : 'x'\n\t\t\t\troute.points[1][matchAxis] = a[matchAxis]\n\t\t\t}\n\t\t}\n\t}\n\n\tif (route.points.length >= 3) {\n\t\tconst a = route.points[route.points.length - 1]\n\t\tconst b = route.points[route.points.length - 2]\n\t\tconst lastSegmentLength = Vec.ManhattanDist(a, b)\n\t\tif (lastSegmentLength < bTerminal.minEndSegmentLength) {\n\t\t\troute.points.splice(route.points.length - 2, 1)\n\t\t\tif (route.points.length >= 3) {\n\t\t\t\tconst matchAxis = approximately(a.x, b.x) ? 'y' : 'x'\n\t\t\t\troute.points[route.points.length - 2][matchAxis] = a[matchAxis]\n\t\t\t}\n\t\t}\n\t}\n}\n\nfunction adjustTerminalForUnclosedPathIfNeeded(\n\tterminal: ElbowArrowTerminal,\n\totherTerminal: ElbowArrowTerminal,\n\toptions: ElbowArrowOptions\n): ElbowArrowTerminal {\n\tif (!terminal.geometry || terminal.geometry.isClosed) return terminal\n\tconst normalizedPointAlongPath = terminal.geometry.uninterpolateAlongEdge(\n\t\tterminal.target,\n\t\tGeometry2dFilters.EXCLUDE_NON_STANDARD\n\t)\n\n\tconst prev = terminal.geometry.interpolateAlongEdge(\n\t\tnormalizedPointAlongPath - 0.01 / terminal.geometry.length\n\t)\n\tconst next = terminal.geometry.interpolateAlongEdge(\n\t\tnormalizedPointAlongPath + 0.01 / terminal.geometry.length\n\t)\n\n\tconst normal = next.sub(prev).per().uni()\n\tconst axis = Math.abs(normal.x) > Math.abs(normal.y) ? ElbowArrowAxes.x : ElbowArrowAxes.y\n\n\tif (terminal.geometry.bounds.containsPoint(otherTerminal.target, options.expandElbowLegLength)) {\n\t\tterminal.side = axis.self\n\t\treturn convertTerminalToPoint(terminal)\n\t}\n\n\tconst min = axis.v(\n\t\tterminal.target[axis.self] - terminal.bounds[axis.size] * 2,\n\t\tterminal.target[axis.cross]\n\t)\n\tconst max = axis.v(\n\t\tterminal.target[axis.self] + terminal.bounds[axis.size] * 2,\n\t\tterminal.target[axis.cross]\n\t)\n\n\tlet furthestIntersectionTowardsMin: VecLike | null = null\n\tlet furthestIntersectionTowardsMinDistance = 0\n\tlet furthestIntersectionTowardsMax: VecLike | null = null\n\tlet furthestIntersectionTowardsMaxDistance = 0\n\tlet side: ElbowArrowSideWithAxis = axis.self\n\n\tfor (const intersection of terminal.geometry.intersectLineSegment(\n\t\tmin,\n\t\tmax,\n\t\tGeometry2dFilters.EXCLUDE_NON_STANDARD\n\t)) {\n\t\tif (Math.abs(intersection[axis.self] - terminal.target[axis.self]) < 1) {\n\t\t\tcontinue\n\t\t}\n\t\tif (intersection[axis.self] < terminal.target[axis.self]) {\n\t\t\tif (\n\t\t\t\tVec.ManhattanDist(intersection, terminal.target) > furthestIntersectionTowardsMinDistance\n\t\t\t) {\n\t\t\t\tfurthestIntersectionTowardsMinDistance = Vec.ManhattanDist(intersection, terminal.target)\n\t\t\t\tfurthestIntersectionTowardsMin = intersection\n\t\t\t}\n\t\t} else {\n\t\t\tif (\n\t\t\t\tVec.ManhattanDist(intersection, terminal.target) > furthestIntersectionTowardsMaxDistance\n\t\t\t) {\n\t\t\t\tfurthestIntersectionTowardsMaxDistance = Vec.ManhattanDist(intersection, terminal.target)\n\t\t\t\tfurthestIntersectionTowardsMax = intersection\n\t\t\t}\n\t\t}\n\t}\n\n\tif (furthestIntersectionTowardsMin && furthestIntersectionTowardsMax) {\n\t\tif (furthestIntersectionTowardsMinDistance > furthestIntersectionTowardsMaxDistance) {\n\t\t\tside = axis.hiEdge\n\t\t} else {\n\t\t\tside = axis.loEdge\n\t\t}\n\t} else if (furthestIntersectionTowardsMin && !furthestIntersectionTowardsMax) {\n\t\tside = axis.hiEdge\n\t} else if (!furthestIntersectionTowardsMin && furthestIntersectionTowardsMax) {\n\t\tside = axis.loEdge\n\t}\n\n\tterminal.side = side\n\treturn terminal\n}\n"],
5
- "mappings": "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",
4
+ "sourcesContent": ["import {\n\tapproximately,\n\tassert,\n\tBox,\n\tEditor,\n\texhaustiveSwitchError,\n\tGeometry2dFilters,\n\tlerp,\n\tMat,\n\tTLArrowBinding,\n\tTLArrowBindingProps,\n\tTLArrowShape,\n\tTLShapeId,\n\tVec,\n\tVecLike,\n\tVecModel,\n} from '@tldraw/editor'\nimport { ArrowShapeUtil } from '../ArrowShapeUtil'\nimport { BOUND_ARROW_OFFSET, STROKE_SIZES, TLArrowBindings } from '../shared'\nimport {\n\tElbowArrowAxes,\n\tElbowArrowBox,\n\tElbowArrowBoxEdges,\n\tElbowArrowEdge,\n\tElbowArrowInfo,\n\tElbowArrowInfoWithoutRoute,\n\tElbowArrowOptions,\n\tElbowArrowRoute,\n\tElbowArrowSide,\n\tElbowArrowSideWithAxis,\n\tElbowArrowTargetBox,\n\tElbowArrowTerminal,\n} from './definitions'\nimport { createRange, expandRange, isWithinRange, rangeSize, subtractRange } from './range'\nimport { ElbowArrowWorkingInfo } from './routes/ElbowArrowWorkingInfo'\nimport {\n\trouteArrowWithAutoEdgePicking,\n\trouteArrowWithManualEdgePicking,\n\trouteArrowWithPartialEdgePicking,\n} from './routes/routeArrowWithAutoEdgePicking'\n\nexport function getElbowArrowInfo(\n\teditor: Editor,\n\tarrow: TLArrowShape,\n\tbindings: TLArrowBindings\n): ElbowArrowInfo {\n\tconst shapeOptions = editor.getShapeUtil<ArrowShapeUtil>(arrow.type).options\n\tconst options: ElbowArrowOptions = {\n\t\telbowMidpoint: arrow.props.elbowMidPoint,\n\t\texpandElbowLegLength: shapeOptions.expandElbowLegLength[arrow.props.size] * arrow.props.scale,\n\t\tminElbowLegLength: shapeOptions.minElbowLegLength[arrow.props.size] * arrow.props.scale,\n\t}\n\n\t// Before we can do anything else, we need to find the start and end terminals of the arrow.\n\t// These contain the binding info, geometry, bounds, etc.\n\tlet startTerminal = getElbowArrowTerminalInfo(editor, arrow, bindings.start, arrow.props.start)\n\tlet endTerminal = getElbowArrowTerminalInfo(editor, arrow, bindings.end, arrow.props.end)\n\t// unclosed paths are weird - we handle them outside of the initial terminal info.\n\tstartTerminal = adjustTerminalForUnclosedPathIfNeeded(startTerminal, endTerminal, options)\n\tendTerminal = adjustTerminalForUnclosedPathIfNeeded(endTerminal, startTerminal, options)\n\n\t// Ther terminal might include a \"side\" if the user has explicitly indicated what side the arrow\n\t// should come from. There are two terminals, and two cases for each terminal (explicit side or\n\t// not), for a total for 4 cases to handle. In order to keep things a bit simpler though, we\n\t// only handle 3 cases: if start no side and end has a side, we flip them around. From here on\n\t// out, we use A and B to refer to the terminals as they may be swapped.\n\tconst swapOrder = !!(!startTerminal.side && endTerminal.side)\n\n\tlet { aTerminal, bTerminal } = swapOrder\n\t\t? { aTerminal: endTerminal, bTerminal: startTerminal }\n\t\t: { aTerminal: startTerminal, bTerminal: endTerminal }\n\n\t// We model each edge that an arrow might enter/exit from separately. If an edge is blocked,\n\t// `getUsableEdge` might return null.\n\tlet edgesA = {\n\t\ttop: getUsableEdge(aTerminal, bTerminal, 'top', options),\n\t\tright: getUsableEdge(aTerminal, bTerminal, 'right', options),\n\t\tbottom: getUsableEdge(aTerminal, bTerminal, 'bottom', options),\n\t\tleft: getUsableEdge(aTerminal, bTerminal, 'left', options),\n\t}\n\n\tlet edgesB = {\n\t\ttop: getUsableEdge(bTerminal, aTerminal, 'top', options),\n\t\tright: getUsableEdge(bTerminal, aTerminal, 'right', options),\n\t\tbottom: getUsableEdge(bTerminal, aTerminal, 'bottom', options),\n\t\tleft: getUsableEdge(bTerminal, aTerminal, 'left', options),\n\t}\n\n\t// We we don't have a usable edge because it's blocked, we can convert some of the terminals to\n\t// points. Point terminals have less strict edge routing rules, but don't look as good\n\t// generally. For example, the arrow might go through the shape instead of around.\n\tconst aIsUsable = hasUsableEdge(edgesA, aTerminal.side)\n\tconst bIsUsable = hasUsableEdge(edgesB, bTerminal.side)\n\tlet needsNewEdges = false\n\tif (!aIsUsable || !bIsUsable) {\n\t\tneedsNewEdges = true\n\t\tif (!aIsUsable) {\n\t\t\tbTerminal = convertTerminalToPoint(bTerminal)\n\t\t}\n\n\t\tif (!bIsUsable) {\n\t\t\taTerminal = convertTerminalToPoint(aTerminal)\n\t\t}\n\n\t\tif (bTerminal.bounds.containsPoint(aTerminal.target, options.expandElbowLegLength)) {\n\t\t\tbTerminal = convertTerminalToPoint(bTerminal)\n\t\t}\n\n\t\tif (aTerminal.bounds.containsPoint(bTerminal.target, options.expandElbowLegLength)) {\n\t\t\taTerminal = convertTerminalToPoint(aTerminal)\n\t\t}\n\t}\n\n\tif (needsNewEdges) {\n\t\tedgesA = {\n\t\t\ttop: getUsableEdge(aTerminal, bTerminal, 'top', options),\n\t\t\tright: getUsableEdge(aTerminal, bTerminal, 'right', options),\n\t\t\tbottom: getUsableEdge(aTerminal, bTerminal, 'bottom', options),\n\t\t\tleft: getUsableEdge(aTerminal, bTerminal, 'left', options),\n\t\t}\n\n\t\tedgesB = {\n\t\t\ttop: getUsableEdge(bTerminal, aTerminal, 'top', options),\n\t\t\tright: getUsableEdge(bTerminal, aTerminal, 'right', options),\n\t\t\tbottom: getUsableEdge(bTerminal, aTerminal, 'bottom', options),\n\t\t\tleft: getUsableEdge(bTerminal, aTerminal, 'left', options),\n\t\t}\n\t}\n\n\t// We expand the bounds of the terminals so we can route arrows around them without the arrows\n\t// being too close to the shapes.\n\tconst expandedA = aTerminal.isPoint\n\t\t? aTerminal.bounds\n\t\t: aTerminal.bounds.clone().expandBy(options.expandElbowLegLength)\n\tconst expandedB = bTerminal.isPoint\n\t\t? bTerminal.bounds\n\t\t: bTerminal.bounds.clone().expandBy(options.expandElbowLegLength)\n\n\tconst common: ElbowArrowBox = {\n\t\toriginal: Box.Common([aTerminal.bounds, bTerminal.bounds]),\n\t\texpanded: Box.Common([expandedA, expandedB]),\n\t}\n\n\t// Calculate the gaps between the two terminals. If gap is positive, B is to the right of A. If\n\t// it's negative, the opposite is true. If it's 0, there's no gap between the shapes in that\n\t// dimension.\n\tlet gapX = bTerminal.bounds.minX - aTerminal.bounds.maxX\n\tif (gapX < 0) {\n\t\tgapX = aTerminal.bounds.minX - bTerminal.bounds.maxX\n\t\tif (gapX < 0) {\n\t\t\tgapX = 0\n\t\t}\n\t\tgapX = -gapX\n\t}\n\tlet gapY = bTerminal.bounds.minY - aTerminal.bounds.maxY\n\tif (gapY < 0) {\n\t\tgapY = aTerminal.bounds.minY - bTerminal.bounds.maxY\n\t\tif (gapY < 0) {\n\t\t\tgapY = 0\n\t\t}\n\t\tgapY = -gapY\n\t}\n\n\t// The midpoint of the gap is a useful point to route arrows through, but the user can also drag\n\t// it to choose a new midpoint. First, we calculate some constraints we'll need to keep in mind\n\t// when figuring out the midpoint...\n\tconst aMinLength = aTerminal.minEndSegmentLength * 3\n\tconst bMinLength = bTerminal.minEndSegmentLength * 3\n\tconst minLegDistanceNeeded =\n\t\t(aTerminal.isPoint ? aMinLength : options.minElbowLegLength) +\n\t\t(bTerminal.isPoint ? bMinLength : options.minElbowLegLength)\n\n\t// ...then, the possible range of the midpoint. This is also used when dragging the midpoint.\n\tlet mxRange: null | { a: number; b: number } = null\n\tif (gapX > minLegDistanceNeeded) {\n\t\tmxRange = {\n\t\t\ta: aTerminal.isPoint ? aTerminal.bounds.maxX + aMinLength : expandedA.maxX,\n\t\t\tb: bTerminal.isPoint ? bTerminal.bounds.minX - bMinLength : expandedB.minX,\n\t\t}\n\t} else if (gapX < -minLegDistanceNeeded) {\n\t\tmxRange = {\n\t\t\ta: aTerminal.isPoint ? aTerminal.bounds.minX - aMinLength : expandedA.minX,\n\t\t\tb: bTerminal.isPoint ? bTerminal.bounds.maxX + bMinLength : expandedB.maxX,\n\t\t}\n\t}\n\n\tlet myRange: null | { a: number; b: number } = null\n\tif (gapY > minLegDistanceNeeded) {\n\t\tmyRange = {\n\t\t\ta: aTerminal.isPoint ? aTerminal.bounds.maxY + aMinLength : expandedA.maxY,\n\t\t\tb: bTerminal.isPoint ? bTerminal.bounds.minY - bMinLength : expandedB.minY,\n\t\t}\n\t} else if (gapY < -minLegDistanceNeeded) {\n\t\tmyRange = {\n\t\t\ta: aTerminal.isPoint ? aTerminal.bounds.minY - aMinLength : expandedA.minY,\n\t\t\tb: bTerminal.isPoint ? bTerminal.bounds.maxY + bMinLength : expandedB.maxY,\n\t\t}\n\t}\n\n\t// and finally we take the range and the midpoint prop and calculate the actual position of the\n\t// midpoint. Note that the midpoint and midpoint range can be null if the gap is too small for a\n\t// midpoint line.\n\tconst midpoint = swapOrder ? 1 - options.elbowMidpoint : options.elbowMidpoint\n\tconst mx = mxRange ? lerp(mxRange.a, mxRange.b, midpoint) : null\n\tconst my = myRange ? lerp(myRange.a, myRange.b, midpoint) : null\n\n\t// The info without route is given to the route-finding functions to route between the two\n\t// terminals.\n\tconst info: ElbowArrowInfoWithoutRoute = {\n\t\toptions,\n\t\tswapOrder,\n\t\tA: {\n\t\t\tisPoint: aTerminal.isPoint,\n\t\t\ttarget: aTerminal.target,\n\t\t\tisExact: aTerminal.isExact,\n\t\t\tarrowheadOffset: aTerminal.arrowheadOffset,\n\t\t\tminEndSegmentLength: aTerminal.minEndSegmentLength,\n\t\t\toriginal: aTerminal.bounds,\n\t\t\texpanded: expandedA,\n\t\t\tedges: edgesA,\n\t\t\tgeometry: aTerminal.geometry,\n\t\t},\n\t\tB: {\n\t\t\tisPoint: bTerminal.isPoint,\n\t\t\ttarget: bTerminal.target,\n\t\t\tisExact: bTerminal.isExact,\n\t\t\tarrowheadOffset: bTerminal.arrowheadOffset,\n\t\t\tminEndSegmentLength: bTerminal.minEndSegmentLength,\n\t\t\toriginal: bTerminal.bounds,\n\t\t\texpanded: expandedB,\n\t\t\tedges: edgesB,\n\t\t\tgeometry: bTerminal.geometry,\n\t\t},\n\t\tcommon,\n\t\tgapX,\n\t\tgapY,\n\t\tmidX: mx,\n\t\tmidY: my,\n\t}\n\n\t// We wrap the info in a working info object that lets us mutate and reset it as needed.\n\tconst workingInfo = new ElbowArrowWorkingInfo(info)\n\n\t// Figure out the final sides to use for each terminal.\n\tconst aSide = getSideToUse(aTerminal, bTerminal, info.A.edges)\n\tconst bSide = getSideToUse(bTerminal, aTerminal, info.B.edges)\n\n\t// try to find a route with the specification we have:\n\tlet route\n\tif (aSide && bSide) {\n\t\troute = routeArrowWithManualEdgePicking(workingInfo, aSide, bSide)\n\t} else if (aSide && !bSide) {\n\t\troute = routeArrowWithPartialEdgePicking(workingInfo, aSide)\n\t}\n\tif (!route) {\n\t\troute = routeArrowWithAutoEdgePicking(workingInfo, aSide || bSide ? 'fallback' : 'auto')\n\t}\n\n\tif (route) {\n\t\t// If we found a route, we need to fix it up. The route will only go to the bounding box of\n\t\t// the shape, so we need to cast the final segments into the actual geometry of the shape.\n\t\tcastPathSegmentIntoGeometry('first', info.A, info.B, route)\n\t\tcastPathSegmentIntoGeometry('last', info.B, info.A, route)\n\t\t// If we have tiny L-shaped arrows, the arrowheads look super janky. We fix those up by just\n\t\t// drawing a straight line instead.\n\t\tfixTinyEndNubs(route, aTerminal, bTerminal)\n\n\t\t// If we swapped the order way back of the start of things, we need to reverse the route so\n\t\t// it flows start -> end instead of A -> B.\n\t\tif (swapOrder) route.points.reverse()\n\t}\n\n\treturn {\n\t\t...info,\n\t\troute,\n\t\tmidXRange: mxRange\n\t\t\t? swapOrder\n\t\t\t\t? { lo: mxRange.b, hi: mxRange.a }\n\t\t\t\t: { lo: mxRange.a, hi: mxRange.b }\n\t\t\t: null,\n\t\tmidYRange: myRange\n\t\t\t? swapOrder\n\t\t\t\t? { lo: myRange.b, hi: myRange.a }\n\t\t\t\t: { lo: myRange.a, hi: myRange.b }\n\t\t\t: null,\n\t}\n}\n\n/**\n * Take the route from `getElbowArrowInfo` (which represents the visible body of the arrow) and\n * convert it into a path we can use to show that paths to the handles, which may extend further\n * into the target shape geometries.\n * @returns\n */\nexport function getRouteHandlePath(info: ElbowArrowInfo, route: ElbowArrowRoute): ElbowArrowRoute {\n\tconst startTarget = info.swapOrder ? info.B.target : info.A.target\n\tconst endTarget = info.swapOrder ? info.A.target : info.B.target\n\n\tconst firstSegmentLength = Vec.ManhattanDist(route.points[0], route.points[1])\n\tconst lastSegmentLength = Vec.ManhattanDist(\n\t\troute.points[route.points.length - 2],\n\t\troute.points[route.points.length - 1]\n\t)\n\n\tconst newFirstSegmentLength = Vec.ManhattanDist(startTarget, route.points[1])\n\tconst newLastSegmentLength = Vec.ManhattanDist(route.points[route.points.length - 2], endTarget)\n\n\tconst firstSegmentLengthChange = firstSegmentLength - newFirstSegmentLength\n\tconst lastSegmentLengthChange = lastSegmentLength - newLastSegmentLength\n\n\tconst newPoints = [startTarget, ...route.points, endTarget]\n\n\treturn {\n\t\tname: route.name,\n\t\tdistance: route.distance + firstSegmentLengthChange + lastSegmentLengthChange,\n\t\tpoints: newPoints.filter((p) => !route.skipPointsWhenDrawing.has(p)),\n\t\taEdgePicking: route.aEdgePicking,\n\t\tbEdgePicking: route.bEdgePicking,\n\t\tskipPointsWhenDrawing: route.skipPointsWhenDrawing,\n\t\tmidpointHandle: route.midpointHandle,\n\t}\n}\n\n/**\n * Take a normalizes anchor and return the side we think it's closest to.\n */\nexport function getEdgeFromNormalizedAnchor(normalizedAnchor: VecLike) {\n\tif (approximately(normalizedAnchor.x, 0.5) && approximately(normalizedAnchor.y, 0.5)) {\n\t\treturn null\n\t}\n\n\tif (\n\t\tMath.abs(normalizedAnchor.x - 0.5) >\n\t\t// slightly bias towards x arrows to prevent flickering when the anchor is right on the line\n\t\t// between the two directions\n\t\tMath.abs(normalizedAnchor.y - 0.5) - 0.0001\n\t) {\n\t\treturn normalizedAnchor.x < 0.5 ? 'left' : 'right'\n\t}\n\n\treturn normalizedAnchor.y < 0.5 ? 'top' : 'bottom'\n}\n\nfunction getElbowArrowTerminalInfo(\n\teditor: Editor,\n\tarrow: TLArrowShape,\n\tbinding: TLArrowBinding | undefined,\n\tpoint: VecModel\n): ElbowArrowTerminal {\n\tconst arrowStrokeSize = (STROKE_SIZES[arrow.props.size] * arrow.props.scale) / 2\n\tconst minEndSegmentLength = arrowStrokeSize * 3\n\n\tif (binding) {\n\t\tconst target = editor.getShape(binding.toId)\n\t\tconst geometry = getBindingGeometryInArrowSpace(editor, arrow, binding.toId, binding.props)\n\t\tif (geometry && target) {\n\t\t\tlet arrowheadOffset = 0\n\t\t\tconst arrowheadProp = binding.props.terminal === 'start' ? 'arrowheadStart' : 'arrowheadEnd'\n\t\t\tif (arrow.props[arrowheadProp] !== 'none') {\n\t\t\t\tconst targetScale = 'scale' in target.props ? target.props.scale : 1\n\t\t\t\tconst targetStrokeSize =\n\t\t\t\t\t'size' in target.props ? ((STROKE_SIZES[target.props.size] ?? 0) * targetScale) / 2 : 0\n\n\t\t\t\tarrowheadOffset =\n\t\t\t\t\tarrowStrokeSize + targetStrokeSize + BOUND_ARROW_OFFSET * arrow.props.scale\n\t\t\t}\n\n\t\t\tlet side: ElbowArrowSideWithAxis | null = null\n\t\t\tconst targetPoint = geometry.target\n\t\t\tif (binding.props.isPrecise) {\n\t\t\t\tside = getEdgeFromNormalizedAnchor(\n\t\t\t\t\tVec.RotWith(\n\t\t\t\t\t\tbinding.props.normalizedAnchor,\n\t\t\t\t\t\t{ x: 0.5, y: 0.5 },\n\t\t\t\t\t\tgeometry.shapeToArrowTransform.rotation()\n\t\t\t\t\t)\n\t\t\t\t)\n\t\t\t}\n\n\t\t\treturn {\n\t\t\t\ttargetShapeId: binding.toId,\n\t\t\t\tisPoint: false,\n\t\t\t\tisExact: binding.props.isExact,\n\t\t\t\tbounds: geometry.bounds,\n\t\t\t\tgeometry: geometry.geometry,\n\t\t\t\ttarget: targetPoint,\n\t\t\t\tarrowheadOffset,\n\t\t\t\tminEndSegmentLength,\n\t\t\t\tside,\n\t\t\t\tsnap: binding.props.snap,\n\t\t\t}\n\t\t}\n\t}\n\n\treturn {\n\t\ttargetShapeId: null,\n\t\tbounds: Box.FromCenter(point, { x: 0, y: 0 }),\n\t\tgeometry: null,\n\t\tisExact: false,\n\t\tisPoint: true,\n\t\ttarget: Vec.From(point),\n\t\tarrowheadOffset: 0,\n\t\tminEndSegmentLength,\n\t\tside: null,\n\t\tsnap: 'none',\n\t}\n}\n\nfunction getBindingGeometryInArrowSpace(\n\teditor: Editor,\n\tarrow: TLArrowShape,\n\ttargetId: TLShapeId,\n\tbindingProps: TLArrowBindingProps\n) {\n\tconst hasArrowhead =\n\t\tbindingProps.terminal === 'start'\n\t\t\t? arrow.props.arrowheadStart !== 'none'\n\t\t\t: arrow.props.arrowheadEnd !== 'none'\n\n\tconst targetGeometryInTargetSpace = editor.getShapeGeometry(\n\t\ttargetId,\n\t\thasArrowhead ? undefined : { context: '@tldraw/arrow-without-arrowhead' }\n\t)\n\n\tif (!targetGeometryInTargetSpace) {\n\t\treturn null\n\t}\n\n\tconst arrowTransform = editor.getShapePageTransform(arrow.id)\n\tconst shapeTransform = editor.getShapePageTransform(targetId)\n\tconst shapeToArrowTransform = arrowTransform.clone().invert().multiply(shapeTransform)\n\n\tconst targetGeometryInArrowSpace = targetGeometryInTargetSpace.transform(shapeToArrowTransform)\n\n\tconst center = { x: 0.5, y: 0.5 }\n\tconst normalizedAnchor = bindingProps.isPrecise ? bindingProps.normalizedAnchor : center\n\n\tconst targetInShapeSpace = {\n\t\tx: lerp(\n\t\t\ttargetGeometryInTargetSpace.bounds.minX,\n\t\t\ttargetGeometryInTargetSpace.bounds.maxX,\n\t\t\tnormalizedAnchor.x\n\t\t),\n\t\ty: lerp(\n\t\t\ttargetGeometryInTargetSpace.bounds.minY,\n\t\t\ttargetGeometryInTargetSpace.bounds.maxY,\n\t\t\tnormalizedAnchor.y\n\t\t),\n\t}\n\tconst centerInShapeSpace = {\n\t\tx: lerp(\n\t\t\ttargetGeometryInTargetSpace.bounds.minX,\n\t\t\ttargetGeometryInTargetSpace.bounds.maxX,\n\t\t\tcenter.x\n\t\t),\n\t\ty: lerp(\n\t\t\ttargetGeometryInTargetSpace.bounds.minY,\n\t\t\ttargetGeometryInTargetSpace.bounds.maxY,\n\t\t\tcenter.y\n\t\t),\n\t}\n\n\tconst targetInArrowSpace = Mat.applyToPoint(shapeToArrowTransform, targetInShapeSpace)\n\tconst centerInArrowSpace = Mat.applyToPoint(shapeToArrowTransform, centerInShapeSpace)\n\n\treturn {\n\t\tbounds: targetGeometryInArrowSpace.bounds,\n\t\tgeometry: targetGeometryInArrowSpace,\n\t\ttarget: targetInArrowSpace,\n\t\tcenter: centerInArrowSpace,\n\t\tshapeToArrowTransform,\n\t}\n}\n\nconst sideProps = {\n\ttop: {\n\t\texpand: -1,\n\t\tmain: 'minY',\n\t\topposite: 'maxY',\n\t\tcrossMid: 'midX',\n\t\tcrossMin: 'minX',\n\t\tcrossMax: 'maxX',\n\t\tbRangeExpand: 'max',\n\t\tcrossAxis: 'x',\n\t},\n\tbottom: {\n\t\texpand: 1,\n\t\tmain: 'maxY',\n\t\topposite: 'minY',\n\t\tcrossMid: 'midX',\n\t\tcrossMin: 'minX',\n\t\tcrossMax: 'maxX',\n\t\tbRangeExpand: 'min',\n\t\tcrossAxis: 'x',\n\t},\n\tleft: {\n\t\texpand: -1,\n\t\tmain: 'minX',\n\t\topposite: 'maxX',\n\t\tcrossMid: 'midY',\n\t\tcrossMin: 'minY',\n\t\tcrossMax: 'maxY',\n\t\tbRangeExpand: 'max',\n\t\tcrossAxis: 'y',\n\t},\n\tright: {\n\t\texpand: 1,\n\t\tmain: 'maxX',\n\t\topposite: 'minX',\n\t\tcrossMid: 'midY',\n\t\tcrossMin: 'minY',\n\t\tcrossMax: 'maxY',\n\t\tbRangeExpand: 'min',\n\t\tcrossAxis: 'y',\n\t},\n} as const\n\nexport function getUsableEdge(\n\ta: ElbowArrowTerminal,\n\tb: ElbowArrowTerminal,\n\tside: 'top' | 'right' | 'bottom' | 'left',\n\toptions: ElbowArrowOptions\n): ElbowArrowEdge | null {\n\tconst props = sideProps[side]\n\n\t// if a shape is bound to itself, by default we'd end up routing the arrow _within_ the shape -\n\t// as if it were a point-to-point arrow. if one of the bindings is specifically to the edge\n\t// though, we route it externally instead.\n\tconst isSelfBoundAndShouldRouteExternal =\n\t\ta.targetShapeId === b.targetShapeId &&\n\t\ta.targetShapeId !== null &&\n\t\t(a.snap === 'edge' || a.snap === 'edge-point') &&\n\t\t(b.snap === 'edge' || b.snap === 'edge-point')\n\n\tconst aValue = a.bounds[props.main]\n\tconst aExpanded = a.isPoint ? null : aValue + props.expand * options.expandElbowLegLength\n\n\tconst originalACrossRange = createRange(a.bounds[props.crossMin], a.bounds[props.crossMax])\n\tlet aCrossRange = originalACrossRange\n\n\t// this edge is too small to be useful:\n\tif (!aCrossRange) {\n\t\treturn null\n\t}\n\n\tassert(originalACrossRange)\n\tconst bRange = createRange(b.bounds[props.main], b.bounds[props.opposite])\n\tif (!b.isPoint) {\n\t\tbRange[props.bRangeExpand] -= options.minElbowLegLength * 2 * props.expand\n\t}\n\n\tconst bCrossRange = expandRange(\n\t\tcreateRange(b.bounds[props.crossMin], b.bounds[props.crossMax]),\n\t\toptions.expandElbowLegLength\n\t)\n\tassert(bRange && bCrossRange)\n\n\tlet isPartial = false\n\tif (\n\t\tisWithinRange(aValue, bRange) &&\n\t\t!a.isPoint &&\n\t\t!b.isPoint &&\n\t\t!isSelfBoundAndShouldRouteExternal\n\t) {\n\t\tconst subtracted = subtractRange(aCrossRange, bCrossRange)\n\t\tswitch (subtracted.length) {\n\t\t\tcase 0:\n\t\t\t\treturn null\n\t\t\tcase 1:\n\t\t\t\tisPartial = subtracted[0] !== aCrossRange\n\t\t\t\taCrossRange = subtracted[0]\n\t\t\t\tbreak\n\t\t\tcase 2:\n\t\t\t\tisPartial = true\n\t\t\t\taCrossRange =\n\t\t\t\t\trangeSize(subtracted[0]) > rangeSize(subtracted[1]) ? subtracted[0] : subtracted[1]\n\t\t\t\tbreak\n\t\t\tdefault:\n\t\t\t\texhaustiveSwitchError(subtracted)\n\t\t}\n\t}\n\n\tif (!isWithinRange(a.target[props.crossAxis], aCrossRange)) {\n\t\treturn null\n\t}\n\tconst crossTarget = a.target[props.crossAxis]\n\n\treturn {\n\t\tvalue: aValue,\n\t\texpanded: aExpanded,\n\t\tcross: aCrossRange,\n\t\tcrossTarget,\n\t\tisPartial,\n\t}\n}\n\nfunction hasUsableEdge(edges: ElbowArrowBoxEdges, side: ElbowArrowSideWithAxis | null) {\n\tif (side === null) {\n\t\treturn !!(edges.bottom || edges.left || edges.right || edges.top)\n\t}\n\n\tif (side === 'x') {\n\t\treturn !!edges.left || !!edges.right\n\t}\n\n\tif (side === 'y') {\n\t\treturn !!edges.top || !!edges.bottom\n\t}\n\n\treturn !!edges[side]\n}\n\nfunction getSideToUse(\n\tbinding: ElbowArrowTerminal,\n\tother: ElbowArrowTerminal,\n\tedges: ElbowArrowBoxEdges | null\n): ElbowArrowSide | null {\n\tswitch (binding.side) {\n\t\tcase null:\n\t\t\treturn null\n\t\tcase 'x':\n\t\t\tif (binding.bounds.center.x > other.bounds.center.x && edges?.left) {\n\t\t\t\treturn 'left'\n\t\t\t} else if (edges?.right) {\n\t\t\t\treturn 'right'\n\t\t\t}\n\t\t\treturn null\n\t\tcase 'y':\n\t\t\tif (binding.bounds.center.y > other.bounds.center.y && edges?.top) {\n\t\t\t\treturn 'top'\n\t\t\t} else if (edges?.bottom) {\n\t\t\t\treturn 'bottom'\n\t\t\t}\n\t\t\treturn null\n\t\tdefault:\n\t\t\treturn binding.side\n\t}\n}\n\nfunction convertTerminalToPoint(terminal: ElbowArrowTerminal): ElbowArrowTerminal {\n\tif (terminal.isPoint) return terminal\n\n\tlet side: ElbowArrowSideWithAxis | null = null\n\tlet arrowheadOffset = 0\n\tif (terminal.snap === 'edge' || terminal.snap === 'edge-point') {\n\t\tarrowheadOffset = terminal.arrowheadOffset\n\t\tif (terminal.side === 'x' || terminal.side === 'left' || terminal.side === 'right') {\n\t\t\tside = 'x'\n\t\t}\n\t\tif (terminal.side === 'y' || terminal.side === 'top' || terminal.side === 'bottom') {\n\t\t\tside = 'y'\n\t\t}\n\t}\n\n\treturn {\n\t\ttargetShapeId: terminal.targetShapeId,\n\t\tside,\n\t\tbounds: new Box(terminal.target.x, terminal.target.y, 0, 0),\n\t\tgeometry: terminal.geometry,\n\t\ttarget: terminal.target,\n\t\tarrowheadOffset,\n\t\tminEndSegmentLength: terminal.minEndSegmentLength,\n\t\tisExact: terminal.isExact,\n\t\tisPoint: true,\n\t\tsnap: terminal.snap,\n\t}\n}\n\n/**\n * Make sure the first path segments goes fully into the target, and doesn't just point to its\n * bounding box. This modifies the route in-place.\n */\nfunction castPathSegmentIntoGeometry(\n\tsegment: 'first' | 'last',\n\ttarget: ElbowArrowTargetBox,\n\tother: ElbowArrowTargetBox,\n\troute: ElbowArrowRoute\n) {\n\tif (!target.geometry) return\n\n\tconst point1 = segment === 'first' ? route.points[0] : route.points[route.points.length - 1]\n\tconst point2 = segment === 'first' ? route.points[1] : route.points[route.points.length - 2]\n\n\tconst pointToFindClosestIntersectionTo = target.geometry.isClosed ? point2 : target.target\n\n\tconst initialDistance = Vec.ManhattanDist(point1, pointToFindClosestIntersectionTo)\n\n\tlet nearestIntersectionToPoint2: VecLike | null = null\n\tlet nearestDistanceToPoint2 = Infinity\n\n\tif (target.isExact) {\n\t\tnearestIntersectionToPoint2 = target.target\n\t} else if (target.geometry) {\n\t\tconst intersections = target.geometry.intersectLineSegment(point2, target.target, {\n\t\t\tincludeLabels: false,\n\t\t\tincludeInternal: false,\n\t\t})\n\t\tif (\n\t\t\ttarget.geometry.hitTestPoint(\n\t\t\t\ttarget.target,\n\t\t\t\tMath.max(1, target.arrowheadOffset),\n\t\t\t\ttrue,\n\t\t\t\tGeometry2dFilters.EXCLUDE_NON_STANDARD\n\t\t\t)\n\t\t) {\n\t\t\tintersections.push(target.target)\n\t\t}\n\t\tfor (const intersection of intersections) {\n\t\t\tconst point2Distance = Vec.ManhattanDist(pointToFindClosestIntersectionTo, intersection)\n\t\t\tif (point2Distance < nearestDistanceToPoint2) {\n\t\t\t\tnearestDistanceToPoint2 = point2Distance\n\t\t\t\tnearestIntersectionToPoint2 = intersection\n\t\t\t}\n\t\t}\n\t}\n\n\tif (nearestIntersectionToPoint2) {\n\t\tlet offset = target.arrowheadOffset\n\n\t\tconst currentFinalSegmentLength = Vec.ManhattanDist(point2, nearestIntersectionToPoint2)\n\t\tconst minLength = target.arrowheadOffset * 2\n\t\tif (currentFinalSegmentLength < minLength) {\n\t\t\tconst targetLength = minLength - target.arrowheadOffset\n\t\t\toffset = currentFinalSegmentLength - targetLength\n\t\t}\n\t\tif (offset < target.minEndSegmentLength) {\n\t\t\tif (target.geometry.bounds.containsPoint(other.target)) {\n\t\t\t\toffset = Math.max(0, offset)\n\t\t\t} else {\n\t\t\t\toffset = -target.arrowheadOffset\n\t\t\t}\n\t\t}\n\n\t\tlet nudgedPoint = nearestIntersectionToPoint2\n\t\tlet shouldAddExtraPointForNudge = false\n\t\tif (!target.isExact && offset !== 0) {\n\t\t\tconst nudged = Vec.Nudge(nearestIntersectionToPoint2, point2, offset)\n\t\t\tnudgedPoint = nudged\n\t\t\tif (\n\t\t\t\toffset < 0 &&\n\t\t\t\t!target.geometry.hitTestPoint(nudged, 0, true, Geometry2dFilters.EXCLUDE_NON_STANDARD)\n\t\t\t) {\n\t\t\t\t// point has been nudged _out_ of the shape so lets not actually apply the nudge\n\t\t\t\tnudgedPoint = nearestIntersectionToPoint2\n\t\t\t} else {\n\t\t\t\tif (offset < 0) {\n\t\t\t\t\tshouldAddExtraPointForNudge = true\n\t\t\t\t}\n\t\t\t\tnudgedPoint = nudged\n\t\t\t}\n\t\t}\n\n\t\tconst newDistance = Vec.ManhattanDist(point2, nudgedPoint)\n\t\troute.distance += newDistance - initialDistance\n\t\tpoint1.x = nudgedPoint.x\n\t\tpoint1.y = nudgedPoint.y\n\n\t\tif (shouldAddExtraPointForNudge) {\n\t\t\tconst midPoint = Vec.Lrp(point2, point1, 0.5)\n\t\t\troute.skipPointsWhenDrawing.add(midPoint)\n\t\t\troute.points.splice(segment === 'first' ? 1 : route.points.length - 1, 0, midPoint)\n\t\t}\n\t}\n}\n\nfunction fixTinyEndNubs(\n\troute: ElbowArrowRoute,\n\taTerminal: ElbowArrowTerminal,\n\tbTerminal: ElbowArrowTerminal\n) {\n\tif (!route) return\n\n\tif (route.points.length >= 3) {\n\t\tconst a = route.points[0]\n\t\tconst b = route.points[1]\n\t\tconst firstSegmentLength = Vec.ManhattanDist(a, b)\n\t\tif (firstSegmentLength < aTerminal.minEndSegmentLength) {\n\t\t\troute.points.splice(1, 1)\n\t\t\tif (route.points.length >= 3) {\n\t\t\t\tconst matchAxis = approximately(a.x, b.x) ? 'y' : 'x'\n\t\t\t\troute.points[1][matchAxis] = a[matchAxis]\n\t\t\t}\n\t\t}\n\t}\n\n\tif (route.points.length >= 3) {\n\t\tconst a = route.points[route.points.length - 1]\n\t\tconst b = route.points[route.points.length - 2]\n\t\tconst lastSegmentLength = Vec.ManhattanDist(a, b)\n\t\tif (lastSegmentLength < bTerminal.minEndSegmentLength) {\n\t\t\troute.points.splice(route.points.length - 2, 1)\n\t\t\tif (route.points.length >= 3) {\n\t\t\t\tconst matchAxis = approximately(a.x, b.x) ? 'y' : 'x'\n\t\t\t\troute.points[route.points.length - 2][matchAxis] = a[matchAxis]\n\t\t\t}\n\t\t}\n\t}\n}\n\nfunction adjustTerminalForUnclosedPathIfNeeded(\n\tterminal: ElbowArrowTerminal,\n\totherTerminal: ElbowArrowTerminal,\n\toptions: ElbowArrowOptions\n): ElbowArrowTerminal {\n\tif (!terminal.geometry || terminal.geometry.isClosed) return terminal\n\tconst normalizedPointAlongPath = terminal.geometry.uninterpolateAlongEdge(\n\t\tterminal.target,\n\t\tGeometry2dFilters.EXCLUDE_NON_STANDARD\n\t)\n\n\tconst prev = terminal.geometry.interpolateAlongEdge(\n\t\tnormalizedPointAlongPath - 0.01 / terminal.geometry.length\n\t)\n\tconst next = terminal.geometry.interpolateAlongEdge(\n\t\tnormalizedPointAlongPath + 0.01 / terminal.geometry.length\n\t)\n\n\tconst normal = next.sub(prev).per().uni()\n\tconst axis = Math.abs(normal.x) > Math.abs(normal.y) ? ElbowArrowAxes.x : ElbowArrowAxes.y\n\n\tif (terminal.geometry.bounds.containsPoint(otherTerminal.target, options.expandElbowLegLength)) {\n\t\tterminal.side = axis.self\n\t\treturn convertTerminalToPoint(terminal)\n\t}\n\n\tconst min = axis.v(\n\t\tterminal.target[axis.self] - terminal.bounds[axis.size] * 2,\n\t\tterminal.target[axis.cross]\n\t)\n\tconst max = axis.v(\n\t\tterminal.target[axis.self] + terminal.bounds[axis.size] * 2,\n\t\tterminal.target[axis.cross]\n\t)\n\n\tlet furthestIntersectionTowardsMin: VecLike | null = null\n\tlet furthestIntersectionTowardsMinDistance = 0\n\tlet furthestIntersectionTowardsMax: VecLike | null = null\n\tlet furthestIntersectionTowardsMaxDistance = 0\n\tlet side: ElbowArrowSideWithAxis = axis.self\n\n\tfor (const intersection of terminal.geometry.intersectLineSegment(\n\t\tmin,\n\t\tmax,\n\t\tGeometry2dFilters.EXCLUDE_NON_STANDARD\n\t)) {\n\t\tif (Math.abs(intersection[axis.self] - terminal.target[axis.self]) < 1) {\n\t\t\tcontinue\n\t\t}\n\t\tif (intersection[axis.self] < terminal.target[axis.self]) {\n\t\t\tif (\n\t\t\t\tVec.ManhattanDist(intersection, terminal.target) > furthestIntersectionTowardsMinDistance\n\t\t\t) {\n\t\t\t\tfurthestIntersectionTowardsMinDistance = Vec.ManhattanDist(intersection, terminal.target)\n\t\t\t\tfurthestIntersectionTowardsMin = intersection\n\t\t\t}\n\t\t} else {\n\t\t\tif (\n\t\t\t\tVec.ManhattanDist(intersection, terminal.target) > furthestIntersectionTowardsMaxDistance\n\t\t\t) {\n\t\t\t\tfurthestIntersectionTowardsMaxDistance = Vec.ManhattanDist(intersection, terminal.target)\n\t\t\t\tfurthestIntersectionTowardsMax = intersection\n\t\t\t}\n\t\t}\n\t}\n\n\tif (furthestIntersectionTowardsMin && furthestIntersectionTowardsMax) {\n\t\tif (furthestIntersectionTowardsMinDistance > furthestIntersectionTowardsMaxDistance) {\n\t\t\tside = axis.hiEdge\n\t\t} else {\n\t\t\tside = axis.loEdge\n\t\t}\n\t} else if (furthestIntersectionTowardsMin && !furthestIntersectionTowardsMax) {\n\t\tside = axis.hiEdge\n\t} else if (!furthestIntersectionTowardsMin && furthestIntersectionTowardsMax) {\n\t\tside = axis.loEdge\n\t}\n\n\tterminal.side = side\n\treturn terminal\n}\n"],
5
+ "mappings": "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",
6
6
  "names": []
7
7
  }
@@ -1,8 +1,8 @@
1
- const version = "4.2.1";
1
+ const version = "4.2.3";
2
2
  const publishDates = {
3
3
  major: "2025-09-18T14:39:22.803Z",
4
4
  minor: "2025-11-19T11:47:45.748Z",
5
- patch: "2025-12-05T12:30:07.819Z"
5
+ patch: "2026-01-08T10:11:20.530Z"
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.2.1'\nexport const publishDates = {\n\tmajor: '2025-09-18T14:39:22.803Z',\n\tminor: '2025-11-19T11:47:45.748Z',\n\tpatch: '2025-12-05T12:30:07.819Z',\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.2.3'\nexport const publishDates = {\n\tmajor: '2025-09-18T14:39:22.803Z',\n\tminor: '2025-11-19T11:47:45.748Z',\n\tpatch: '2026-01-08T10:11:20.530Z',\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.2.1",
4
+ "version": "4.2.3",
5
5
  "author": {
6
6
  "name": "tldraw Inc.",
7
7
  "email": "hello@tldraw.com"
@@ -62,8 +62,8 @@
62
62
  "@tiptap/pm": "3.6.2",
63
63
  "@tiptap/react": "3.6.2",
64
64
  "@tiptap/starter-kit": "3.6.2",
65
- "@tldraw/editor": "4.2.1",
66
- "@tldraw/store": "4.2.1",
65
+ "@tldraw/editor": "4.2.3",
66
+ "@tldraw/store": "4.2.3",
67
67
  "classnames": "^2.5.1",
68
68
  "hotkeys-js": "^3.13.9",
69
69
  "idb": "^7.1.1",
@@ -626,7 +626,7 @@ export const embedShapePermissionDefaults = {
626
626
  // [REASON] We want to allow embeds to link back to their original sites (e.g. YouTube).
627
627
  'allow-popups': true,
628
628
  // [MDN] Lets the sandboxed document open new windows without those windows inheriting the sandboxing. For example, this can safely sandbox an advertisement without forcing the same restrictions upon the page the ad links to.
629
- // [REASON] We shouldn't allow popups as a embed could pretend to be us by opening a mocked version of tldraw. This is very unobvious when it is performed as an action within our app.
629
+ // [REASON] We shouldn't allow popups as an embed could pretend to be us by opening a mocked version of tldraw. This is very unobvious when it is performed as an action within our app.
630
630
  'allow-popups-to-escape-sandbox': false,
631
631
  // [MDN] Lets the resource start a presentation session.
632
632
  // [REASON] Prevents embed from navigating away from tldraw and pretending to be us.
@@ -0,0 +1,80 @@
1
+ import { createShapeId, TLArrowShape } from '@tldraw/editor'
2
+ import { TestEditor } from '../../../../test/TestEditor'
3
+ import { createOrUpdateArrowBinding, getArrowBindings } from '../shared'
4
+ import { getElbowArrowInfo } from './getElbowArrowInfo'
5
+
6
+ let editor: TestEditor
7
+
8
+ const ids = {
9
+ box1: createShapeId('box1'),
10
+ box2: createShapeId('box2'),
11
+ arrow1: createShapeId('arrow1'),
12
+ }
13
+
14
+ beforeEach(() => {
15
+ editor = new TestEditor()
16
+ })
17
+
18
+ describe('Elbow arrow with scale', () => {
19
+ it.each([1, 5, 10, 20])('creates valid orthogonal routes with scale=%i', (scale) => {
20
+ editor.createShapes([
21
+ { id: ids.box1, type: 'geo', x: 0, y: 0, props: { w: 100, h: 100 } },
22
+ { id: ids.box2, type: 'geo', x: 250, y: 100, props: { w: 100, h: 100 } },
23
+ {
24
+ id: ids.arrow1,
25
+ type: 'arrow',
26
+ x: 0,
27
+ y: 0,
28
+ props: {
29
+ start: { x: 0, y: 0 },
30
+ end: { x: 0, y: 0 },
31
+ kind: 'elbow',
32
+ scale,
33
+ size: 's',
34
+ },
35
+ },
36
+ ])
37
+
38
+ createOrUpdateArrowBinding(editor, ids.arrow1, ids.box1, {
39
+ terminal: 'start',
40
+ isExact: false,
41
+ isPrecise: false,
42
+ normalizedAnchor: { x: 0.5, y: 0.5 },
43
+ snap: 'none',
44
+ })
45
+
46
+ createOrUpdateArrowBinding(editor, ids.arrow1, ids.box2, {
47
+ terminal: 'end',
48
+ isExact: false,
49
+ isPrecise: false,
50
+ normalizedAnchor: { x: 0.5, y: 0.5 },
51
+ snap: 'none',
52
+ })
53
+
54
+ const arrow = editor.getShape(ids.arrow1)! as TLArrowShape
55
+ const bindings = getArrowBindings(editor, arrow)
56
+ const info = getElbowArrowInfo(editor, arrow, bindings)
57
+
58
+ expect(info).toBeDefined()
59
+ expect(arrow.props.kind).toBe('elbow')
60
+ expect(info.route).toBeDefined()
61
+ expect(info.route!.points.length).toBeGreaterThanOrEqual(3)
62
+
63
+ // No duplicate consecutive points
64
+ for (let i = 0; i < info.route!.points.length - 1; i++) {
65
+ const p1 = info.route!.points[i]
66
+ const p2 = info.route!.points[i + 1]
67
+ const isDuplicate = Math.abs(p1.x - p2.x) < 0.01 && Math.abs(p1.y - p2.y) < 0.01
68
+ expect(isDuplicate).toBe(false)
69
+ }
70
+
71
+ // All segments orthogonal
72
+ for (let i = 0; i < info.route!.points.length - 1; i++) {
73
+ const p1 = info.route!.points[i]
74
+ const p2 = info.route!.points[i + 1]
75
+ const isHorizontal = Math.abs(p1.y - p2.y) < 0.01
76
+ const isVertical = Math.abs(p1.x - p2.x) < 0.01
77
+ expect(isHorizontal || isVertical).toBe(true)
78
+ }
79
+ })
80
+ })
@@ -348,7 +348,7 @@ function getElbowArrowTerminalInfo(
348
348
  point: VecModel
349
349
  ): ElbowArrowTerminal {
350
350
  const arrowStrokeSize = (STROKE_SIZES[arrow.props.size] * arrow.props.scale) / 2
351
- const minEndSegmentLength = arrowStrokeSize * arrow.props.scale * 3
351
+ const minEndSegmentLength = arrowStrokeSize * 3
352
352
 
353
353
  if (binding) {
354
354
  const target = editor.getShape(binding.toId)
@@ -1,9 +1,9 @@
1
1
  // This file is automatically generated by internal/scripts/refresh-assets.ts.
2
2
  // Do not edit manually. Or do, I'm a comment, not a cop.
3
3
 
4
- export const version = '4.2.1'
4
+ export const version = '4.2.3'
5
5
  export const publishDates = {
6
6
  major: '2025-09-18T14:39:22.803Z',
7
7
  minor: '2025-11-19T11:47:45.748Z',
8
- patch: '2025-12-05T12:30:07.819Z',
8
+ patch: '2026-01-08T10:11:20.530Z',
9
9
  }