@tldraw/tlschema 4.1.0-canary.5d5610599458 → 4.1.0-canary.65769c249e0d
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.d.ts +5 -1
- package/dist-cjs/index.js +1 -1
- package/dist-cjs/misc/TLHandle.js.map +1 -1
- package/dist-cjs/shapes/TLEmbedShape.js +0 -10
- package/dist-cjs/shapes/TLEmbedShape.js.map +2 -2
- package/dist-esm/index.d.mts +5 -1
- package/dist-esm/index.mjs +1 -1
- package/dist-esm/misc/TLHandle.mjs.map +1 -1
- package/dist-esm/shapes/TLEmbedShape.mjs +0 -10
- package/dist-esm/shapes/TLEmbedShape.mjs.map +2 -2
- package/package.json +5 -5
- package/src/misc/TLHandle.ts +5 -1
- package/src/shapes/TLEmbedShape.ts +0 -10
package/dist-cjs/index.d.ts
CHANGED
|
@@ -4318,8 +4318,12 @@ export declare interface TLHandle {
|
|
|
4318
4318
|
label?: string;
|
|
4319
4319
|
/** The type of handle, determining its behavior and interaction mode */
|
|
4320
4320
|
type: TLHandleType;
|
|
4321
|
-
/**
|
|
4321
|
+
/**
|
|
4322
|
+
* @deprecated Use `snapType` instead. Whether this handle should snap to other geometry during interactions.
|
|
4323
|
+
*/
|
|
4322
4324
|
canSnap?: boolean;
|
|
4325
|
+
/** The type of snap to use for this handle */
|
|
4326
|
+
snapType?: 'align' | 'point';
|
|
4323
4327
|
/** The fractional index used for ordering handles */
|
|
4324
4328
|
index: IndexKey;
|
|
4325
4329
|
/** The x-coordinate of the handle in the shape's local coordinate system */
|
package/dist-cjs/index.js
CHANGED
|
@@ -177,7 +177,7 @@ var import_TLVerticalAlignStyle = require("./styles/TLVerticalAlignStyle");
|
|
|
177
177
|
var import_translations = require("./translations/translations");
|
|
178
178
|
(0, import_utils.registerTldrawLibraryVersion)(
|
|
179
179
|
"@tldraw/tlschema",
|
|
180
|
-
"4.1.0-canary.
|
|
180
|
+
"4.1.0-canary.65769c249e0d",
|
|
181
181
|
"cjs"
|
|
182
182
|
);
|
|
183
183
|
//# sourceMappingURL=index.js.map
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../src/misc/TLHandle.ts"],
|
|
4
|
-
"sourcesContent": ["import { IndexKey } from '@tldraw/utils'\nimport { SetValue } from '../util-types'\n\n/**\n * All available handle types used by shapes in the tldraw editor.\n *\n * Handles are interactive control points on shapes that allow users to\n * modify the shape's geometry. Different handle types serve different purposes:\n *\n * - `vertex`: A control point that defines a vertex of the shape\n * - `virtual`: A handle that exists between vertices for adding new points\n * - `create`: A handle for creating new geometry (like extending a line)\n * - `clone`: A handle for duplicating or cloning shape elements\n *\n * @example\n * ```ts\n * // Check if a handle type is valid\n * if (TL_HANDLE_TYPES.has('vertex')) {\n * console.log('Valid handle type')\n * }\n *\n * // Get all available handle types\n * const allHandleTypes = Array.from(TL_HANDLE_TYPES)\n * ```\n *\n * @public\n */\nexport const TL_HANDLE_TYPES = new Set(['vertex', 'virtual', 'create', 'clone'] as const)\n\n/**\n * A union type representing all available handle types.\n *\n * Handle types determine how a handle behaves when interacted with and\n * what kind of shape modification it enables.\n *\n * @example\n * ```ts\n * const vertexHandle: TLHandleType = 'vertex'\n * const virtualHandle: TLHandleType = 'virtual'\n * const createHandle: TLHandleType = 'create'\n * const cloneHandle: TLHandleType = 'clone'\n * ```\n *\n * @public\n */\nexport type TLHandleType = SetValue<typeof TL_HANDLE_TYPES>\n\n/**\n * A handle object representing an interactive control point on a shape.\n *\n * Handles allow users to manipulate shape geometry by dragging control points.\n * Each handle has a position, type, and various properties that control its\n * behavior during interactions.\n *\n * @example\n * ```ts\n * // A vertex handle for a line endpoint\n * const lineEndHandle: TLHandle = {\n * id: 'end',\n * label: 'End point',\n * type: 'vertex',\n * canSnap: true,\n * index: 'a1',\n * x: 100,\n * y: 50\n * }\n *\n * // A virtual handle for adding new points\n * const virtualHandle: TLHandle = {\n * id: 'virtual-1',\n * type: 'virtual',\n * canSnap: false,\n * index: 'a1V',\n * x: 75,\n * y: 25\n * }\n *\n * // A create handle for extending geometry\n * const createHandle: TLHandle = {\n * id: 'create',\n * type: 'create',\n * canSnap: true,\n * index: 'a2',\n * x: 200,\n * y: 100\n * }\n * ```\n *\n * @public\n */\nexport interface TLHandle {\n\t/** A unique identifier for the handle within the shape */\n\tid: string\n\t/** Optional human-readable label for the handle */\n\t// TODO(mime): this needs to be required.\n\tlabel?: string\n\t/** The type of handle, determining its behavior and interaction mode */\n\ttype: TLHandleType\n\t
|
|
4
|
+
"sourcesContent": ["import { IndexKey } from '@tldraw/utils'\nimport { SetValue } from '../util-types'\n\n/**\n * All available handle types used by shapes in the tldraw editor.\n *\n * Handles are interactive control points on shapes that allow users to\n * modify the shape's geometry. Different handle types serve different purposes:\n *\n * - `vertex`: A control point that defines a vertex of the shape\n * - `virtual`: A handle that exists between vertices for adding new points\n * - `create`: A handle for creating new geometry (like extending a line)\n * - `clone`: A handle for duplicating or cloning shape elements\n *\n * @example\n * ```ts\n * // Check if a handle type is valid\n * if (TL_HANDLE_TYPES.has('vertex')) {\n * console.log('Valid handle type')\n * }\n *\n * // Get all available handle types\n * const allHandleTypes = Array.from(TL_HANDLE_TYPES)\n * ```\n *\n * @public\n */\nexport const TL_HANDLE_TYPES = new Set(['vertex', 'virtual', 'create', 'clone'] as const)\n\n/**\n * A union type representing all available handle types.\n *\n * Handle types determine how a handle behaves when interacted with and\n * what kind of shape modification it enables.\n *\n * @example\n * ```ts\n * const vertexHandle: TLHandleType = 'vertex'\n * const virtualHandle: TLHandleType = 'virtual'\n * const createHandle: TLHandleType = 'create'\n * const cloneHandle: TLHandleType = 'clone'\n * ```\n *\n * @public\n */\nexport type TLHandleType = SetValue<typeof TL_HANDLE_TYPES>\n\n/**\n * A handle object representing an interactive control point on a shape.\n *\n * Handles allow users to manipulate shape geometry by dragging control points.\n * Each handle has a position, type, and various properties that control its\n * behavior during interactions.\n *\n * @example\n * ```ts\n * // A vertex handle for a line endpoint\n * const lineEndHandle: TLHandle = {\n * id: 'end',\n * label: 'End point',\n * type: 'vertex',\n * canSnap: true,\n * index: 'a1',\n * x: 100,\n * y: 50\n * }\n *\n * // A virtual handle for adding new points\n * const virtualHandle: TLHandle = {\n * id: 'virtual-1',\n * type: 'virtual',\n * canSnap: false,\n * index: 'a1V',\n * x: 75,\n * y: 25\n * }\n *\n * // A create handle for extending geometry\n * const createHandle: TLHandle = {\n * id: 'create',\n * type: 'create',\n * canSnap: true,\n * index: 'a2',\n * x: 200,\n * y: 100\n * }\n * ```\n *\n * @public\n */\nexport interface TLHandle {\n\t/** A unique identifier for the handle within the shape */\n\tid: string\n\t/** Optional human-readable label for the handle */\n\t// TODO(mime): this needs to be required.\n\tlabel?: string\n\t/** The type of handle, determining its behavior and interaction mode */\n\ttype: TLHandleType\n\t/**\n\t * @deprecated Use `snapType` instead. Whether this handle should snap to other geometry during interactions.\n\t */\n\tcanSnap?: boolean\n\t/** The type of snap to use for this handle */\n\tsnapType?: 'point' | 'align'\n\t/** The fractional index used for ordering handles */\n\tindex: IndexKey\n\t/** The x-coordinate of the handle in the shape's local coordinate system */\n\tx: number\n\t/** The y-coordinate of the handle in the shape's local coordinate system */\n\ty: number\n}\n"],
|
|
5
5
|
"mappings": ";;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AA2BO,MAAM,kBAAkB,oBAAI,IAAI,CAAC,UAAU,WAAW,UAAU,OAAO,CAAU;",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
|
@@ -214,16 +214,6 @@ const EMBED_DEFINITIONS = [
|
|
|
214
214
|
return;
|
|
215
215
|
}
|
|
216
216
|
},
|
|
217
|
-
{
|
|
218
|
-
hostnames: ["excalidraw.com"],
|
|
219
|
-
fromEmbedUrl: (url) => {
|
|
220
|
-
const urlObj = (0, import_utils.safeParseUrl)(url);
|
|
221
|
-
if (urlObj && urlObj.hash.match(/#room=/)) {
|
|
222
|
-
return url;
|
|
223
|
-
}
|
|
224
|
-
return;
|
|
225
|
-
}
|
|
226
|
-
},
|
|
227
217
|
{
|
|
228
218
|
hostnames: ["observablehq.com"],
|
|
229
219
|
fromEmbedUrl: (url) => {
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../src/shapes/TLEmbedShape.ts"],
|
|
4
|
-
"sourcesContent": ["import { safeParseUrl } from '@tldraw/utils'\nimport { T } from '@tldraw/validate'\nimport { createShapePropsMigrationIds, createShapePropsMigrationSequence } from '../records/TLShape'\nimport { RecordProps } from '../recordsWithProps'\nimport { TLBaseShape } from './TLBaseShape'\n\n// Only allow multiplayer embeds. If we add additional routes later for example '/help' this won't match\nconst TLDRAW_APP_RE = /(^\\/r\\/[^/]+\\/?$)/\n\nconst EMBED_DEFINITIONS = [\n\t{\n\t\thostnames: ['beta.tldraw.com', 'tldraw.com', 'localhost:3000'],\n\t\tfromEmbedUrl: (url: string) => {\n\t\t\tconst urlObj = safeParseUrl(url)\n\t\t\tif (urlObj && urlObj.pathname.match(TLDRAW_APP_RE)) {\n\t\t\t\treturn url\n\t\t\t}\n\t\t\treturn\n\t\t},\n\t},\n\t{\n\t\thostnames: ['figma.com'],\n\t\tfromEmbedUrl: (url: string) => {\n\t\t\tconst urlObj = safeParseUrl(url)\n\t\t\tif (urlObj && urlObj.pathname.match(/^\\/embed\\/?$/)) {\n\t\t\t\tconst outUrl = urlObj.searchParams.get('url')\n\t\t\t\tif (outUrl) {\n\t\t\t\t\treturn outUrl\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn\n\t\t},\n\t},\n\t{\n\t\thostnames: ['google.*'],\n\t\tfromEmbedUrl: (url: string) => {\n\t\t\tconst urlObj = safeParseUrl(url)\n\t\t\tif (!urlObj) return\n\n\t\t\tconst matches = urlObj.pathname.match(/^\\/maps\\/embed\\/v1\\/view\\/?$/)\n\t\t\tif (matches && urlObj.searchParams.has('center') && urlObj.searchParams.get('zoom')) {\n\t\t\t\tconst zoom = urlObj.searchParams.get('zoom')\n\t\t\t\tconst [lat, lon] = urlObj.searchParams.get('center')!.split(',')\n\t\t\t\treturn `https://www.google.com/maps/@${lat},${lon},${zoom}z`\n\t\t\t}\n\t\t\treturn\n\t\t},\n\t},\n\t{\n\t\thostnames: ['val.town'],\n\t\tfromEmbedUrl: (url: string) => {\n\t\t\tconst urlObj = safeParseUrl(url)\n\t\t\t// e.g. extract \"steveruizok/mathFact\" from https://www.val.town/v/steveruizok/mathFact\n\t\t\tconst matches = urlObj && urlObj.pathname.match(/\\/embed\\/(.+)\\/?/)\n\t\t\tif (matches) {\n\t\t\t\treturn `https://www.val.town/v/${matches[1]}`\n\t\t\t}\n\t\t\treturn\n\t\t},\n\t},\n\t{\n\t\thostnames: ['codesandbox.io'],\n\t\tfromEmbedUrl: (url: string) => {\n\t\t\tconst urlObj = safeParseUrl(url)\n\t\t\tconst matches = urlObj && urlObj.pathname.match(/\\/embed\\/([^/]+)\\/?/)\n\t\t\tif (matches) {\n\t\t\t\treturn `https://codesandbox.io/s/${matches[1]}`\n\t\t\t}\n\t\t\treturn\n\t\t},\n\t},\n\t{\n\t\thostnames: ['codepen.io'],\n\t\tfromEmbedUrl: (url: string) => {\n\t\t\tconst CODEPEN_EMBED_REGEXP = /https:\\/\\/codepen.io\\/([^/]+)\\/embed\\/([^/]+)/\n\t\t\tconst matches = url.match(CODEPEN_EMBED_REGEXP)\n\t\t\tif (matches) {\n\t\t\t\tconst [_, user, id] = matches\n\t\t\t\treturn `https://codepen.io/${user}/pen/${id}`\n\t\t\t}\n\t\t\treturn\n\t\t},\n\t},\n\t{\n\t\thostnames: ['scratch.mit.edu'],\n\t\tfromEmbedUrl: (url: string) => {\n\t\t\tconst SCRATCH_EMBED_REGEXP = /https:\\/\\/scratch.mit.edu\\/projects\\/embed\\/([^/]+)/\n\t\t\tconst matches = url.match(SCRATCH_EMBED_REGEXP)\n\t\t\tif (matches) {\n\t\t\t\tconst [_, id] = matches\n\t\t\t\treturn `https://scratch.mit.edu/projects/${id}`\n\t\t\t}\n\t\t\treturn\n\t\t},\n\t},\n\t{\n\t\thostnames: ['*.youtube.com', 'youtube.com', 'youtu.be'],\n\t\tfromEmbedUrl: (url: string) => {\n\t\t\tconst urlObj = safeParseUrl(url)\n\t\t\tif (!urlObj) return\n\n\t\t\tconst hostname = urlObj.hostname.replace(/^www./, '')\n\t\t\tif (hostname === 'youtube.com') {\n\t\t\t\tconst matches = urlObj.pathname.match(/^\\/embed\\/([^/]+)\\/?/)\n\t\t\t\tif (matches) {\n\t\t\t\t\treturn `https://www.youtube.com/watch?v=${matches[1]}`\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn\n\t\t},\n\t},\n\t{\n\t\thostnames: ['calendar.google.*'],\n\t\tfromEmbedUrl: (url: string) => {\n\t\t\tconst urlObj = safeParseUrl(url)\n\t\t\tconst srcQs = urlObj?.searchParams.get('src')\n\n\t\t\tif (urlObj?.pathname.match(/\\/calendar\\/embed/) && srcQs) {\n\t\t\t\turlObj.pathname = '/calendar/u/0'\n\t\t\t\tconst keys = Array.from(urlObj.searchParams.keys())\n\t\t\t\tfor (const key of keys) {\n\t\t\t\t\turlObj.searchParams.delete(key)\n\t\t\t\t}\n\t\t\t\turlObj.searchParams.set('cid', srcQs)\n\t\t\t\treturn urlObj.href\n\t\t\t}\n\t\t\treturn\n\t\t},\n\t},\n\t{\n\t\thostnames: ['docs.google.*'],\n\t\tfromEmbedUrl: (url: string) => {\n\t\t\tconst urlObj = safeParseUrl(url)\n\n\t\t\tif (urlObj?.pathname.match(/^\\/presentation/) && urlObj?.pathname.match(/\\/embed\\/?$/)) {\n\t\t\t\turlObj.pathname = urlObj.pathname.replace(/\\/embed$/, '/pub')\n\t\t\t\tconst keys = Array.from(urlObj.searchParams.keys())\n\t\t\t\tfor (const key of keys) {\n\t\t\t\t\turlObj.searchParams.delete(key)\n\t\t\t\t}\n\t\t\t\treturn urlObj.href\n\t\t\t}\n\t\t\treturn\n\t\t},\n\t},\n\t{\n\t\thostnames: ['gist.github.com'],\n\t\tfromEmbedUrl: (url: string) => {\n\t\t\tconst urlObj = safeParseUrl(url)\n\t\t\tif (urlObj && urlObj.pathname.match(/\\/([^/]+)\\/([^/]+)/)) {\n\t\t\t\tif (!url.split('/').pop()) return\n\t\t\t\treturn url\n\t\t\t}\n\t\t\treturn\n\t\t},\n\t},\n\t{\n\t\thostnames: ['replit.com'],\n\t\tfromEmbedUrl: (url: string) => {\n\t\t\tconst urlObj = safeParseUrl(url)\n\t\t\tif (\n\t\t\t\turlObj &&\n\t\t\t\turlObj.pathname.match(/\\/@([^/]+)\\/([^/]+)/) &&\n\t\t\t\turlObj.searchParams.has('embed')\n\t\t\t) {\n\t\t\t\turlObj.searchParams.delete('embed')\n\t\t\t\treturn urlObj.href\n\t\t\t}\n\t\t\treturn\n\t\t},\n\t},\n\t{\n\t\thostnames: ['felt.com'],\n\t\tfromEmbedUrl: (url: string) => {\n\t\t\tconst urlObj = safeParseUrl(url)\n\t\t\tif (urlObj && urlObj.pathname.match(/^\\/embed\\/map\\//)) {\n\t\t\t\turlObj.pathname = urlObj.pathname.replace(/^\\/embed/, '')\n\t\t\t\treturn urlObj.href\n\t\t\t}\n\t\t\treturn\n\t\t},\n\t},\n\t{\n\t\thostnames: ['open.spotify.com'],\n\t\tfromEmbedUrl: (url: string) => {\n\t\t\tconst urlObj = safeParseUrl(url)\n\t\t\tif (urlObj && urlObj.pathname.match(/^\\/embed\\/(artist|album)\\//)) {\n\t\t\t\treturn urlObj.origin + urlObj.pathname.replace(/^\\/embed/, '')\n\t\t\t}\n\t\t\treturn\n\t\t},\n\t},\n\t{\n\t\thostnames: ['vimeo.com', 'player.vimeo.com'],\n\t\tfromEmbedUrl: (url: string) => {\n\t\t\tconst urlObj = safeParseUrl(url)\n\t\t\tif (urlObj && urlObj.hostname === 'player.vimeo.com') {\n\t\t\t\tconst matches = urlObj.pathname.match(/^\\/video\\/([^/]+)\\/?$/)\n\t\t\t\tif (matches) {\n\t\t\t\t\treturn 'https://vimeo.com/' + matches[1]\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn\n\t\t},\n\t},\n\t{\n\t\thostnames: ['excalidraw.com'],\n\t\tfromEmbedUrl: (url: string) => {\n\t\t\tconst urlObj = safeParseUrl(url)\n\t\t\tif (urlObj && urlObj.hash.match(/#room=/)) {\n\t\t\t\treturn url\n\t\t\t}\n\t\t\treturn\n\t\t},\n\t},\n\t{\n\t\thostnames: ['observablehq.com'],\n\t\tfromEmbedUrl: (url: string) => {\n\t\t\tconst urlObj = safeParseUrl(url)\n\t\t\tif (urlObj && urlObj.pathname.match(/^\\/embed\\/@([^/]+)\\/([^/]+)\\/?$/)) {\n\t\t\t\treturn `${urlObj.origin}${urlObj.pathname.replace('/embed', '')}#cell-*`\n\t\t\t}\n\t\t\tif (urlObj && urlObj.pathname.match(/^\\/embed\\/([^/]+)\\/?$/)) {\n\t\t\t\treturn `${urlObj.origin}${urlObj.pathname.replace('/embed', '/d')}#cell-*`\n\t\t\t}\n\n\t\t\treturn\n\t\t},\n\t},\n\t{\n\t\thostnames: ['desmos.com'],\n\t\tfromEmbedUrl: (url: string) => {\n\t\t\tconst urlObj = safeParseUrl(url)\n\t\t\tif (\n\t\t\t\turlObj &&\n\t\t\t\turlObj.hostname === 'www.desmos.com' &&\n\t\t\t\turlObj.pathname.match(/^\\/calculator\\/([^/]+)\\/?$/) &&\n\t\t\t\turlObj.search === '?embed' &&\n\t\t\t\turlObj.hash === ''\n\t\t\t) {\n\t\t\t\treturn url.replace('?embed', '')\n\t\t\t}\n\t\t\treturn\n\t\t},\n\t},\n]\n\n/**\n * Properties for the embed shape, which displays embedded content from external services.\n *\n * @public\n */\nexport interface TLEmbedShapeProps {\n\t/** Width of the embed shape in pixels */\n\tw: number\n\t/** Height of the embed shape in pixels */\n\th: number\n\t/** URL of the content to embed (supports YouTube, Figma, CodePen, etc.) */\n\turl: string\n}\n\n/**\n * An embed shape displays external content like YouTube videos, Figma designs, CodePen demos,\n * and other embeddable content within the tldraw canvas.\n *\n * @public\n * @example\n * ```ts\n * const embedShape: TLEmbedShape = {\n * id: createShapeId(),\n * typeName: 'shape',\n * type: 'embed',\n * x: 200,\n * y: 200,\n * rotation: 0,\n * index: 'a1',\n * parentId: 'page:page1',\n * isLocked: false,\n * opacity: 1,\n * props: {\n * w: 560,\n * h: 315,\n * url: 'https://www.youtube.com/watch?v=dQw4w9WgXcQ'\n * },\n * meta: {}\n * }\n * ```\n */\nexport type TLEmbedShape = TLBaseShape<'embed', TLEmbedShapeProps>\n\n/**\n * Validation schema for embed shape properties.\n *\n * @public\n * @example\n * ```ts\n * // Validate embed shape properties\n * const isValidUrl = embedShapeProps.url.isValid('https://youtube.com/watch?v=abc123')\n * const isValidSize = embedShapeProps.w.isValid(560)\n * ```\n */\nexport const embedShapeProps: RecordProps<TLEmbedShape> = {\n\tw: T.nonZeroNumber,\n\th: T.nonZeroNumber,\n\turl: T.string,\n}\n\nconst Versions = createShapePropsMigrationIds('embed', {\n\tGenOriginalUrlInEmbed: 1,\n\tRemoveDoesResize: 2,\n\tRemoveTmpOldUrl: 3,\n\tRemovePermissionOverrides: 4,\n})\n\n/**\n * Version identifiers for embed shape migrations.\n *\n * @public\n */\nexport { Versions as embedShapeVersions }\n\n/**\n * Migration sequence for embed shape properties across different schema versions.\n * Handles URL transformations and removal of deprecated properties.\n *\n * @public\n */\nexport const embedShapeMigrations = createShapePropsMigrationSequence({\n\tsequence: [\n\t\t{\n\t\t\tid: Versions.GenOriginalUrlInEmbed,\n\t\t\t// add tmpOldUrl property\n\t\t\tup: (props) => {\n\t\t\t\ttry {\n\t\t\t\t\tconst url = props.url\n\t\t\t\t\tconst host = new URL(url).host.replace('www.', '')\n\t\t\t\t\tlet originalUrl\n\t\t\t\t\tfor (const localEmbedDef of EMBED_DEFINITIONS) {\n\t\t\t\t\t\tif (localEmbedDef.hostnames.includes(host)) {\n\t\t\t\t\t\t\ttry {\n\t\t\t\t\t\t\t\toriginalUrl = localEmbedDef.fromEmbedUrl(url)\n\t\t\t\t\t\t\t} catch (err) {\n\t\t\t\t\t\t\t\tconsole.warn(err)\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\n\t\t\t\t\tprops.tmpOldUrl = props.url\n\t\t\t\t\tprops.url = originalUrl ?? ''\n\t\t\t\t} catch {\n\t\t\t\t\tprops.url = ''\n\t\t\t\t\tprops.tmpOldUrl = props.url\n\t\t\t\t}\n\t\t\t},\n\t\t\tdown: 'retired',\n\t\t},\n\t\t{\n\t\t\tid: Versions.RemoveDoesResize,\n\t\t\tup: (props) => {\n\t\t\t\tdelete props.doesResize\n\t\t\t},\n\t\t\tdown: 'retired',\n\t\t},\n\t\t{\n\t\t\tid: Versions.RemoveTmpOldUrl,\n\t\t\tup: (props) => {\n\t\t\t\tdelete props.tmpOldUrl\n\t\t\t},\n\t\t\tdown: 'retired',\n\t\t},\n\t\t{\n\t\t\tid: Versions.RemovePermissionOverrides,\n\t\t\tup: (props) => {\n\t\t\t\tdelete props.overridePermissions\n\t\t\t},\n\t\t\tdown: 'retired',\n\t\t},\n\t],\n})\n"],
|
|
5
|
-
"mappings": "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
|
|
4
|
+
"sourcesContent": ["import { safeParseUrl } from '@tldraw/utils'\nimport { T } from '@tldraw/validate'\nimport { createShapePropsMigrationIds, createShapePropsMigrationSequence } from '../records/TLShape'\nimport { RecordProps } from '../recordsWithProps'\nimport { TLBaseShape } from './TLBaseShape'\n\n// Only allow multiplayer embeds. If we add additional routes later for example '/help' this won't match\nconst TLDRAW_APP_RE = /(^\\/r\\/[^/]+\\/?$)/\n\nconst EMBED_DEFINITIONS = [\n\t{\n\t\thostnames: ['beta.tldraw.com', 'tldraw.com', 'localhost:3000'],\n\t\tfromEmbedUrl: (url: string) => {\n\t\t\tconst urlObj = safeParseUrl(url)\n\t\t\tif (urlObj && urlObj.pathname.match(TLDRAW_APP_RE)) {\n\t\t\t\treturn url\n\t\t\t}\n\t\t\treturn\n\t\t},\n\t},\n\t{\n\t\thostnames: ['figma.com'],\n\t\tfromEmbedUrl: (url: string) => {\n\t\t\tconst urlObj = safeParseUrl(url)\n\t\t\tif (urlObj && urlObj.pathname.match(/^\\/embed\\/?$/)) {\n\t\t\t\tconst outUrl = urlObj.searchParams.get('url')\n\t\t\t\tif (outUrl) {\n\t\t\t\t\treturn outUrl\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn\n\t\t},\n\t},\n\t{\n\t\thostnames: ['google.*'],\n\t\tfromEmbedUrl: (url: string) => {\n\t\t\tconst urlObj = safeParseUrl(url)\n\t\t\tif (!urlObj) return\n\n\t\t\tconst matches = urlObj.pathname.match(/^\\/maps\\/embed\\/v1\\/view\\/?$/)\n\t\t\tif (matches && urlObj.searchParams.has('center') && urlObj.searchParams.get('zoom')) {\n\t\t\t\tconst zoom = urlObj.searchParams.get('zoom')\n\t\t\t\tconst [lat, lon] = urlObj.searchParams.get('center')!.split(',')\n\t\t\t\treturn `https://www.google.com/maps/@${lat},${lon},${zoom}z`\n\t\t\t}\n\t\t\treturn\n\t\t},\n\t},\n\t{\n\t\thostnames: ['val.town'],\n\t\tfromEmbedUrl: (url: string) => {\n\t\t\tconst urlObj = safeParseUrl(url)\n\t\t\t// e.g. extract \"steveruizok/mathFact\" from https://www.val.town/v/steveruizok/mathFact\n\t\t\tconst matches = urlObj && urlObj.pathname.match(/\\/embed\\/(.+)\\/?/)\n\t\t\tif (matches) {\n\t\t\t\treturn `https://www.val.town/v/${matches[1]}`\n\t\t\t}\n\t\t\treturn\n\t\t},\n\t},\n\t{\n\t\thostnames: ['codesandbox.io'],\n\t\tfromEmbedUrl: (url: string) => {\n\t\t\tconst urlObj = safeParseUrl(url)\n\t\t\tconst matches = urlObj && urlObj.pathname.match(/\\/embed\\/([^/]+)\\/?/)\n\t\t\tif (matches) {\n\t\t\t\treturn `https://codesandbox.io/s/${matches[1]}`\n\t\t\t}\n\t\t\treturn\n\t\t},\n\t},\n\t{\n\t\thostnames: ['codepen.io'],\n\t\tfromEmbedUrl: (url: string) => {\n\t\t\tconst CODEPEN_EMBED_REGEXP = /https:\\/\\/codepen.io\\/([^/]+)\\/embed\\/([^/]+)/\n\t\t\tconst matches = url.match(CODEPEN_EMBED_REGEXP)\n\t\t\tif (matches) {\n\t\t\t\tconst [_, user, id] = matches\n\t\t\t\treturn `https://codepen.io/${user}/pen/${id}`\n\t\t\t}\n\t\t\treturn\n\t\t},\n\t},\n\t{\n\t\thostnames: ['scratch.mit.edu'],\n\t\tfromEmbedUrl: (url: string) => {\n\t\t\tconst SCRATCH_EMBED_REGEXP = /https:\\/\\/scratch.mit.edu\\/projects\\/embed\\/([^/]+)/\n\t\t\tconst matches = url.match(SCRATCH_EMBED_REGEXP)\n\t\t\tif (matches) {\n\t\t\t\tconst [_, id] = matches\n\t\t\t\treturn `https://scratch.mit.edu/projects/${id}`\n\t\t\t}\n\t\t\treturn\n\t\t},\n\t},\n\t{\n\t\thostnames: ['*.youtube.com', 'youtube.com', 'youtu.be'],\n\t\tfromEmbedUrl: (url: string) => {\n\t\t\tconst urlObj = safeParseUrl(url)\n\t\t\tif (!urlObj) return\n\n\t\t\tconst hostname = urlObj.hostname.replace(/^www./, '')\n\t\t\tif (hostname === 'youtube.com') {\n\t\t\t\tconst matches = urlObj.pathname.match(/^\\/embed\\/([^/]+)\\/?/)\n\t\t\t\tif (matches) {\n\t\t\t\t\treturn `https://www.youtube.com/watch?v=${matches[1]}`\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn\n\t\t},\n\t},\n\t{\n\t\thostnames: ['calendar.google.*'],\n\t\tfromEmbedUrl: (url: string) => {\n\t\t\tconst urlObj = safeParseUrl(url)\n\t\t\tconst srcQs = urlObj?.searchParams.get('src')\n\n\t\t\tif (urlObj?.pathname.match(/\\/calendar\\/embed/) && srcQs) {\n\t\t\t\turlObj.pathname = '/calendar/u/0'\n\t\t\t\tconst keys = Array.from(urlObj.searchParams.keys())\n\t\t\t\tfor (const key of keys) {\n\t\t\t\t\turlObj.searchParams.delete(key)\n\t\t\t\t}\n\t\t\t\turlObj.searchParams.set('cid', srcQs)\n\t\t\t\treturn urlObj.href\n\t\t\t}\n\t\t\treturn\n\t\t},\n\t},\n\t{\n\t\thostnames: ['docs.google.*'],\n\t\tfromEmbedUrl: (url: string) => {\n\t\t\tconst urlObj = safeParseUrl(url)\n\n\t\t\tif (urlObj?.pathname.match(/^\\/presentation/) && urlObj?.pathname.match(/\\/embed\\/?$/)) {\n\t\t\t\turlObj.pathname = urlObj.pathname.replace(/\\/embed$/, '/pub')\n\t\t\t\tconst keys = Array.from(urlObj.searchParams.keys())\n\t\t\t\tfor (const key of keys) {\n\t\t\t\t\turlObj.searchParams.delete(key)\n\t\t\t\t}\n\t\t\t\treturn urlObj.href\n\t\t\t}\n\t\t\treturn\n\t\t},\n\t},\n\t{\n\t\thostnames: ['gist.github.com'],\n\t\tfromEmbedUrl: (url: string) => {\n\t\t\tconst urlObj = safeParseUrl(url)\n\t\t\tif (urlObj && urlObj.pathname.match(/\\/([^/]+)\\/([^/]+)/)) {\n\t\t\t\tif (!url.split('/').pop()) return\n\t\t\t\treturn url\n\t\t\t}\n\t\t\treturn\n\t\t},\n\t},\n\t{\n\t\thostnames: ['replit.com'],\n\t\tfromEmbedUrl: (url: string) => {\n\t\t\tconst urlObj = safeParseUrl(url)\n\t\t\tif (\n\t\t\t\turlObj &&\n\t\t\t\turlObj.pathname.match(/\\/@([^/]+)\\/([^/]+)/) &&\n\t\t\t\turlObj.searchParams.has('embed')\n\t\t\t) {\n\t\t\t\turlObj.searchParams.delete('embed')\n\t\t\t\treturn urlObj.href\n\t\t\t}\n\t\t\treturn\n\t\t},\n\t},\n\t{\n\t\thostnames: ['felt.com'],\n\t\tfromEmbedUrl: (url: string) => {\n\t\t\tconst urlObj = safeParseUrl(url)\n\t\t\tif (urlObj && urlObj.pathname.match(/^\\/embed\\/map\\//)) {\n\t\t\t\turlObj.pathname = urlObj.pathname.replace(/^\\/embed/, '')\n\t\t\t\treturn urlObj.href\n\t\t\t}\n\t\t\treturn\n\t\t},\n\t},\n\t{\n\t\thostnames: ['open.spotify.com'],\n\t\tfromEmbedUrl: (url: string) => {\n\t\t\tconst urlObj = safeParseUrl(url)\n\t\t\tif (urlObj && urlObj.pathname.match(/^\\/embed\\/(artist|album)\\//)) {\n\t\t\t\treturn urlObj.origin + urlObj.pathname.replace(/^\\/embed/, '')\n\t\t\t}\n\t\t\treturn\n\t\t},\n\t},\n\t{\n\t\thostnames: ['vimeo.com', 'player.vimeo.com'],\n\t\tfromEmbedUrl: (url: string) => {\n\t\t\tconst urlObj = safeParseUrl(url)\n\t\t\tif (urlObj && urlObj.hostname === 'player.vimeo.com') {\n\t\t\t\tconst matches = urlObj.pathname.match(/^\\/video\\/([^/]+)\\/?$/)\n\t\t\t\tif (matches) {\n\t\t\t\t\treturn 'https://vimeo.com/' + matches[1]\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn\n\t\t},\n\t},\n\t{\n\t\thostnames: ['observablehq.com'],\n\t\tfromEmbedUrl: (url: string) => {\n\t\t\tconst urlObj = safeParseUrl(url)\n\t\t\tif (urlObj && urlObj.pathname.match(/^\\/embed\\/@([^/]+)\\/([^/]+)\\/?$/)) {\n\t\t\t\treturn `${urlObj.origin}${urlObj.pathname.replace('/embed', '')}#cell-*`\n\t\t\t}\n\t\t\tif (urlObj && urlObj.pathname.match(/^\\/embed\\/([^/]+)\\/?$/)) {\n\t\t\t\treturn `${urlObj.origin}${urlObj.pathname.replace('/embed', '/d')}#cell-*`\n\t\t\t}\n\n\t\t\treturn\n\t\t},\n\t},\n\t{\n\t\thostnames: ['desmos.com'],\n\t\tfromEmbedUrl: (url: string) => {\n\t\t\tconst urlObj = safeParseUrl(url)\n\t\t\tif (\n\t\t\t\turlObj &&\n\t\t\t\turlObj.hostname === 'www.desmos.com' &&\n\t\t\t\turlObj.pathname.match(/^\\/calculator\\/([^/]+)\\/?$/) &&\n\t\t\t\turlObj.search === '?embed' &&\n\t\t\t\turlObj.hash === ''\n\t\t\t) {\n\t\t\t\treturn url.replace('?embed', '')\n\t\t\t}\n\t\t\treturn\n\t\t},\n\t},\n]\n\n/**\n * Properties for the embed shape, which displays embedded content from external services.\n *\n * @public\n */\nexport interface TLEmbedShapeProps {\n\t/** Width of the embed shape in pixels */\n\tw: number\n\t/** Height of the embed shape in pixels */\n\th: number\n\t/** URL of the content to embed (supports YouTube, Figma, CodePen, etc.) */\n\turl: string\n}\n\n/**\n * An embed shape displays external content like YouTube videos, Figma designs, CodePen demos,\n * and other embeddable content within the tldraw canvas.\n *\n * @public\n * @example\n * ```ts\n * const embedShape: TLEmbedShape = {\n * id: createShapeId(),\n * typeName: 'shape',\n * type: 'embed',\n * x: 200,\n * y: 200,\n * rotation: 0,\n * index: 'a1',\n * parentId: 'page:page1',\n * isLocked: false,\n * opacity: 1,\n * props: {\n * w: 560,\n * h: 315,\n * url: 'https://www.youtube.com/watch?v=dQw4w9WgXcQ'\n * },\n * meta: {}\n * }\n * ```\n */\nexport type TLEmbedShape = TLBaseShape<'embed', TLEmbedShapeProps>\n\n/**\n * Validation schema for embed shape properties.\n *\n * @public\n * @example\n * ```ts\n * // Validate embed shape properties\n * const isValidUrl = embedShapeProps.url.isValid('https://youtube.com/watch?v=abc123')\n * const isValidSize = embedShapeProps.w.isValid(560)\n * ```\n */\nexport const embedShapeProps: RecordProps<TLEmbedShape> = {\n\tw: T.nonZeroNumber,\n\th: T.nonZeroNumber,\n\turl: T.string,\n}\n\nconst Versions = createShapePropsMigrationIds('embed', {\n\tGenOriginalUrlInEmbed: 1,\n\tRemoveDoesResize: 2,\n\tRemoveTmpOldUrl: 3,\n\tRemovePermissionOverrides: 4,\n})\n\n/**\n * Version identifiers for embed shape migrations.\n *\n * @public\n */\nexport { Versions as embedShapeVersions }\n\n/**\n * Migration sequence for embed shape properties across different schema versions.\n * Handles URL transformations and removal of deprecated properties.\n *\n * @public\n */\nexport const embedShapeMigrations = createShapePropsMigrationSequence({\n\tsequence: [\n\t\t{\n\t\t\tid: Versions.GenOriginalUrlInEmbed,\n\t\t\t// add tmpOldUrl property\n\t\t\tup: (props) => {\n\t\t\t\ttry {\n\t\t\t\t\tconst url = props.url\n\t\t\t\t\tconst host = new URL(url).host.replace('www.', '')\n\t\t\t\t\tlet originalUrl\n\t\t\t\t\tfor (const localEmbedDef of EMBED_DEFINITIONS) {\n\t\t\t\t\t\tif (localEmbedDef.hostnames.includes(host)) {\n\t\t\t\t\t\t\ttry {\n\t\t\t\t\t\t\t\toriginalUrl = localEmbedDef.fromEmbedUrl(url)\n\t\t\t\t\t\t\t} catch (err) {\n\t\t\t\t\t\t\t\tconsole.warn(err)\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\n\t\t\t\t\tprops.tmpOldUrl = props.url\n\t\t\t\t\tprops.url = originalUrl ?? ''\n\t\t\t\t} catch {\n\t\t\t\t\tprops.url = ''\n\t\t\t\t\tprops.tmpOldUrl = props.url\n\t\t\t\t}\n\t\t\t},\n\t\t\tdown: 'retired',\n\t\t},\n\t\t{\n\t\t\tid: Versions.RemoveDoesResize,\n\t\t\tup: (props) => {\n\t\t\t\tdelete props.doesResize\n\t\t\t},\n\t\t\tdown: 'retired',\n\t\t},\n\t\t{\n\t\t\tid: Versions.RemoveTmpOldUrl,\n\t\t\tup: (props) => {\n\t\t\t\tdelete props.tmpOldUrl\n\t\t\t},\n\t\t\tdown: 'retired',\n\t\t},\n\t\t{\n\t\t\tid: Versions.RemovePermissionOverrides,\n\t\t\tup: (props) => {\n\t\t\t\tdelete props.overridePermissions\n\t\t\t},\n\t\t\tdown: 'retired',\n\t\t},\n\t],\n})\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
package/dist-esm/index.d.mts
CHANGED
|
@@ -4318,8 +4318,12 @@ export declare interface TLHandle {
|
|
|
4318
4318
|
label?: string;
|
|
4319
4319
|
/** The type of handle, determining its behavior and interaction mode */
|
|
4320
4320
|
type: TLHandleType;
|
|
4321
|
-
/**
|
|
4321
|
+
/**
|
|
4322
|
+
* @deprecated Use `snapType` instead. Whether this handle should snap to other geometry during interactions.
|
|
4323
|
+
*/
|
|
4322
4324
|
canSnap?: boolean;
|
|
4325
|
+
/** The type of snap to use for this handle */
|
|
4326
|
+
snapType?: 'align' | 'point';
|
|
4323
4327
|
/** The fractional index used for ordering handles */
|
|
4324
4328
|
index: IndexKey;
|
|
4325
4329
|
/** The x-coordinate of the handle in the shape's local coordinate system */
|
package/dist-esm/index.mjs
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../src/misc/TLHandle.ts"],
|
|
4
|
-
"sourcesContent": ["import { IndexKey } from '@tldraw/utils'\nimport { SetValue } from '../util-types'\n\n/**\n * All available handle types used by shapes in the tldraw editor.\n *\n * Handles are interactive control points on shapes that allow users to\n * modify the shape's geometry. Different handle types serve different purposes:\n *\n * - `vertex`: A control point that defines a vertex of the shape\n * - `virtual`: A handle that exists between vertices for adding new points\n * - `create`: A handle for creating new geometry (like extending a line)\n * - `clone`: A handle for duplicating or cloning shape elements\n *\n * @example\n * ```ts\n * // Check if a handle type is valid\n * if (TL_HANDLE_TYPES.has('vertex')) {\n * console.log('Valid handle type')\n * }\n *\n * // Get all available handle types\n * const allHandleTypes = Array.from(TL_HANDLE_TYPES)\n * ```\n *\n * @public\n */\nexport const TL_HANDLE_TYPES = new Set(['vertex', 'virtual', 'create', 'clone'] as const)\n\n/**\n * A union type representing all available handle types.\n *\n * Handle types determine how a handle behaves when interacted with and\n * what kind of shape modification it enables.\n *\n * @example\n * ```ts\n * const vertexHandle: TLHandleType = 'vertex'\n * const virtualHandle: TLHandleType = 'virtual'\n * const createHandle: TLHandleType = 'create'\n * const cloneHandle: TLHandleType = 'clone'\n * ```\n *\n * @public\n */\nexport type TLHandleType = SetValue<typeof TL_HANDLE_TYPES>\n\n/**\n * A handle object representing an interactive control point on a shape.\n *\n * Handles allow users to manipulate shape geometry by dragging control points.\n * Each handle has a position, type, and various properties that control its\n * behavior during interactions.\n *\n * @example\n * ```ts\n * // A vertex handle for a line endpoint\n * const lineEndHandle: TLHandle = {\n * id: 'end',\n * label: 'End point',\n * type: 'vertex',\n * canSnap: true,\n * index: 'a1',\n * x: 100,\n * y: 50\n * }\n *\n * // A virtual handle for adding new points\n * const virtualHandle: TLHandle = {\n * id: 'virtual-1',\n * type: 'virtual',\n * canSnap: false,\n * index: 'a1V',\n * x: 75,\n * y: 25\n * }\n *\n * // A create handle for extending geometry\n * const createHandle: TLHandle = {\n * id: 'create',\n * type: 'create',\n * canSnap: true,\n * index: 'a2',\n * x: 200,\n * y: 100\n * }\n * ```\n *\n * @public\n */\nexport interface TLHandle {\n\t/** A unique identifier for the handle within the shape */\n\tid: string\n\t/** Optional human-readable label for the handle */\n\t// TODO(mime): this needs to be required.\n\tlabel?: string\n\t/** The type of handle, determining its behavior and interaction mode */\n\ttype: TLHandleType\n\t
|
|
4
|
+
"sourcesContent": ["import { IndexKey } from '@tldraw/utils'\nimport { SetValue } from '../util-types'\n\n/**\n * All available handle types used by shapes in the tldraw editor.\n *\n * Handles are interactive control points on shapes that allow users to\n * modify the shape's geometry. Different handle types serve different purposes:\n *\n * - `vertex`: A control point that defines a vertex of the shape\n * - `virtual`: A handle that exists between vertices for adding new points\n * - `create`: A handle for creating new geometry (like extending a line)\n * - `clone`: A handle for duplicating or cloning shape elements\n *\n * @example\n * ```ts\n * // Check if a handle type is valid\n * if (TL_HANDLE_TYPES.has('vertex')) {\n * console.log('Valid handle type')\n * }\n *\n * // Get all available handle types\n * const allHandleTypes = Array.from(TL_HANDLE_TYPES)\n * ```\n *\n * @public\n */\nexport const TL_HANDLE_TYPES = new Set(['vertex', 'virtual', 'create', 'clone'] as const)\n\n/**\n * A union type representing all available handle types.\n *\n * Handle types determine how a handle behaves when interacted with and\n * what kind of shape modification it enables.\n *\n * @example\n * ```ts\n * const vertexHandle: TLHandleType = 'vertex'\n * const virtualHandle: TLHandleType = 'virtual'\n * const createHandle: TLHandleType = 'create'\n * const cloneHandle: TLHandleType = 'clone'\n * ```\n *\n * @public\n */\nexport type TLHandleType = SetValue<typeof TL_HANDLE_TYPES>\n\n/**\n * A handle object representing an interactive control point on a shape.\n *\n * Handles allow users to manipulate shape geometry by dragging control points.\n * Each handle has a position, type, and various properties that control its\n * behavior during interactions.\n *\n * @example\n * ```ts\n * // A vertex handle for a line endpoint\n * const lineEndHandle: TLHandle = {\n * id: 'end',\n * label: 'End point',\n * type: 'vertex',\n * canSnap: true,\n * index: 'a1',\n * x: 100,\n * y: 50\n * }\n *\n * // A virtual handle for adding new points\n * const virtualHandle: TLHandle = {\n * id: 'virtual-1',\n * type: 'virtual',\n * canSnap: false,\n * index: 'a1V',\n * x: 75,\n * y: 25\n * }\n *\n * // A create handle for extending geometry\n * const createHandle: TLHandle = {\n * id: 'create',\n * type: 'create',\n * canSnap: true,\n * index: 'a2',\n * x: 200,\n * y: 100\n * }\n * ```\n *\n * @public\n */\nexport interface TLHandle {\n\t/** A unique identifier for the handle within the shape */\n\tid: string\n\t/** Optional human-readable label for the handle */\n\t// TODO(mime): this needs to be required.\n\tlabel?: string\n\t/** The type of handle, determining its behavior and interaction mode */\n\ttype: TLHandleType\n\t/**\n\t * @deprecated Use `snapType` instead. Whether this handle should snap to other geometry during interactions.\n\t */\n\tcanSnap?: boolean\n\t/** The type of snap to use for this handle */\n\tsnapType?: 'point' | 'align'\n\t/** The fractional index used for ordering handles */\n\tindex: IndexKey\n\t/** The x-coordinate of the handle in the shape's local coordinate system */\n\tx: number\n\t/** The y-coordinate of the handle in the shape's local coordinate system */\n\ty: number\n}\n"],
|
|
5
5
|
"mappings": "AA2BO,MAAM,kBAAkB,oBAAI,IAAI,CAAC,UAAU,WAAW,UAAU,OAAO,CAAU;",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
|
@@ -189,16 +189,6 @@ const EMBED_DEFINITIONS = [
|
|
|
189
189
|
return;
|
|
190
190
|
}
|
|
191
191
|
},
|
|
192
|
-
{
|
|
193
|
-
hostnames: ["excalidraw.com"],
|
|
194
|
-
fromEmbedUrl: (url) => {
|
|
195
|
-
const urlObj = safeParseUrl(url);
|
|
196
|
-
if (urlObj && urlObj.hash.match(/#room=/)) {
|
|
197
|
-
return url;
|
|
198
|
-
}
|
|
199
|
-
return;
|
|
200
|
-
}
|
|
201
|
-
},
|
|
202
192
|
{
|
|
203
193
|
hostnames: ["observablehq.com"],
|
|
204
194
|
fromEmbedUrl: (url) => {
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../src/shapes/TLEmbedShape.ts"],
|
|
4
|
-
"sourcesContent": ["import { safeParseUrl } from '@tldraw/utils'\nimport { T } from '@tldraw/validate'\nimport { createShapePropsMigrationIds, createShapePropsMigrationSequence } from '../records/TLShape'\nimport { RecordProps } from '../recordsWithProps'\nimport { TLBaseShape } from './TLBaseShape'\n\n// Only allow multiplayer embeds. If we add additional routes later for example '/help' this won't match\nconst TLDRAW_APP_RE = /(^\\/r\\/[^/]+\\/?$)/\n\nconst EMBED_DEFINITIONS = [\n\t{\n\t\thostnames: ['beta.tldraw.com', 'tldraw.com', 'localhost:3000'],\n\t\tfromEmbedUrl: (url: string) => {\n\t\t\tconst urlObj = safeParseUrl(url)\n\t\t\tif (urlObj && urlObj.pathname.match(TLDRAW_APP_RE)) {\n\t\t\t\treturn url\n\t\t\t}\n\t\t\treturn\n\t\t},\n\t},\n\t{\n\t\thostnames: ['figma.com'],\n\t\tfromEmbedUrl: (url: string) => {\n\t\t\tconst urlObj = safeParseUrl(url)\n\t\t\tif (urlObj && urlObj.pathname.match(/^\\/embed\\/?$/)) {\n\t\t\t\tconst outUrl = urlObj.searchParams.get('url')\n\t\t\t\tif (outUrl) {\n\t\t\t\t\treturn outUrl\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn\n\t\t},\n\t},\n\t{\n\t\thostnames: ['google.*'],\n\t\tfromEmbedUrl: (url: string) => {\n\t\t\tconst urlObj = safeParseUrl(url)\n\t\t\tif (!urlObj) return\n\n\t\t\tconst matches = urlObj.pathname.match(/^\\/maps\\/embed\\/v1\\/view\\/?$/)\n\t\t\tif (matches && urlObj.searchParams.has('center') && urlObj.searchParams.get('zoom')) {\n\t\t\t\tconst zoom = urlObj.searchParams.get('zoom')\n\t\t\t\tconst [lat, lon] = urlObj.searchParams.get('center')!.split(',')\n\t\t\t\treturn `https://www.google.com/maps/@${lat},${lon},${zoom}z`\n\t\t\t}\n\t\t\treturn\n\t\t},\n\t},\n\t{\n\t\thostnames: ['val.town'],\n\t\tfromEmbedUrl: (url: string) => {\n\t\t\tconst urlObj = safeParseUrl(url)\n\t\t\t// e.g. extract \"steveruizok/mathFact\" from https://www.val.town/v/steveruizok/mathFact\n\t\t\tconst matches = urlObj && urlObj.pathname.match(/\\/embed\\/(.+)\\/?/)\n\t\t\tif (matches) {\n\t\t\t\treturn `https://www.val.town/v/${matches[1]}`\n\t\t\t}\n\t\t\treturn\n\t\t},\n\t},\n\t{\n\t\thostnames: ['codesandbox.io'],\n\t\tfromEmbedUrl: (url: string) => {\n\t\t\tconst urlObj = safeParseUrl(url)\n\t\t\tconst matches = urlObj && urlObj.pathname.match(/\\/embed\\/([^/]+)\\/?/)\n\t\t\tif (matches) {\n\t\t\t\treturn `https://codesandbox.io/s/${matches[1]}`\n\t\t\t}\n\t\t\treturn\n\t\t},\n\t},\n\t{\n\t\thostnames: ['codepen.io'],\n\t\tfromEmbedUrl: (url: string) => {\n\t\t\tconst CODEPEN_EMBED_REGEXP = /https:\\/\\/codepen.io\\/([^/]+)\\/embed\\/([^/]+)/\n\t\t\tconst matches = url.match(CODEPEN_EMBED_REGEXP)\n\t\t\tif (matches) {\n\t\t\t\tconst [_, user, id] = matches\n\t\t\t\treturn `https://codepen.io/${user}/pen/${id}`\n\t\t\t}\n\t\t\treturn\n\t\t},\n\t},\n\t{\n\t\thostnames: ['scratch.mit.edu'],\n\t\tfromEmbedUrl: (url: string) => {\n\t\t\tconst SCRATCH_EMBED_REGEXP = /https:\\/\\/scratch.mit.edu\\/projects\\/embed\\/([^/]+)/\n\t\t\tconst matches = url.match(SCRATCH_EMBED_REGEXP)\n\t\t\tif (matches) {\n\t\t\t\tconst [_, id] = matches\n\t\t\t\treturn `https://scratch.mit.edu/projects/${id}`\n\t\t\t}\n\t\t\treturn\n\t\t},\n\t},\n\t{\n\t\thostnames: ['*.youtube.com', 'youtube.com', 'youtu.be'],\n\t\tfromEmbedUrl: (url: string) => {\n\t\t\tconst urlObj = safeParseUrl(url)\n\t\t\tif (!urlObj) return\n\n\t\t\tconst hostname = urlObj.hostname.replace(/^www./, '')\n\t\t\tif (hostname === 'youtube.com') {\n\t\t\t\tconst matches = urlObj.pathname.match(/^\\/embed\\/([^/]+)\\/?/)\n\t\t\t\tif (matches) {\n\t\t\t\t\treturn `https://www.youtube.com/watch?v=${matches[1]}`\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn\n\t\t},\n\t},\n\t{\n\t\thostnames: ['calendar.google.*'],\n\t\tfromEmbedUrl: (url: string) => {\n\t\t\tconst urlObj = safeParseUrl(url)\n\t\t\tconst srcQs = urlObj?.searchParams.get('src')\n\n\t\t\tif (urlObj?.pathname.match(/\\/calendar\\/embed/) && srcQs) {\n\t\t\t\turlObj.pathname = '/calendar/u/0'\n\t\t\t\tconst keys = Array.from(urlObj.searchParams.keys())\n\t\t\t\tfor (const key of keys) {\n\t\t\t\t\turlObj.searchParams.delete(key)\n\t\t\t\t}\n\t\t\t\turlObj.searchParams.set('cid', srcQs)\n\t\t\t\treturn urlObj.href\n\t\t\t}\n\t\t\treturn\n\t\t},\n\t},\n\t{\n\t\thostnames: ['docs.google.*'],\n\t\tfromEmbedUrl: (url: string) => {\n\t\t\tconst urlObj = safeParseUrl(url)\n\n\t\t\tif (urlObj?.pathname.match(/^\\/presentation/) && urlObj?.pathname.match(/\\/embed\\/?$/)) {\n\t\t\t\turlObj.pathname = urlObj.pathname.replace(/\\/embed$/, '/pub')\n\t\t\t\tconst keys = Array.from(urlObj.searchParams.keys())\n\t\t\t\tfor (const key of keys) {\n\t\t\t\t\turlObj.searchParams.delete(key)\n\t\t\t\t}\n\t\t\t\treturn urlObj.href\n\t\t\t}\n\t\t\treturn\n\t\t},\n\t},\n\t{\n\t\thostnames: ['gist.github.com'],\n\t\tfromEmbedUrl: (url: string) => {\n\t\t\tconst urlObj = safeParseUrl(url)\n\t\t\tif (urlObj && urlObj.pathname.match(/\\/([^/]+)\\/([^/]+)/)) {\n\t\t\t\tif (!url.split('/').pop()) return\n\t\t\t\treturn url\n\t\t\t}\n\t\t\treturn\n\t\t},\n\t},\n\t{\n\t\thostnames: ['replit.com'],\n\t\tfromEmbedUrl: (url: string) => {\n\t\t\tconst urlObj = safeParseUrl(url)\n\t\t\tif (\n\t\t\t\turlObj &&\n\t\t\t\turlObj.pathname.match(/\\/@([^/]+)\\/([^/]+)/) &&\n\t\t\t\turlObj.searchParams.has('embed')\n\t\t\t) {\n\t\t\t\turlObj.searchParams.delete('embed')\n\t\t\t\treturn urlObj.href\n\t\t\t}\n\t\t\treturn\n\t\t},\n\t},\n\t{\n\t\thostnames: ['felt.com'],\n\t\tfromEmbedUrl: (url: string) => {\n\t\t\tconst urlObj = safeParseUrl(url)\n\t\t\tif (urlObj && urlObj.pathname.match(/^\\/embed\\/map\\//)) {\n\t\t\t\turlObj.pathname = urlObj.pathname.replace(/^\\/embed/, '')\n\t\t\t\treturn urlObj.href\n\t\t\t}\n\t\t\treturn\n\t\t},\n\t},\n\t{\n\t\thostnames: ['open.spotify.com'],\n\t\tfromEmbedUrl: (url: string) => {\n\t\t\tconst urlObj = safeParseUrl(url)\n\t\t\tif (urlObj && urlObj.pathname.match(/^\\/embed\\/(artist|album)\\//)) {\n\t\t\t\treturn urlObj.origin + urlObj.pathname.replace(/^\\/embed/, '')\n\t\t\t}\n\t\t\treturn\n\t\t},\n\t},\n\t{\n\t\thostnames: ['vimeo.com', 'player.vimeo.com'],\n\t\tfromEmbedUrl: (url: string) => {\n\t\t\tconst urlObj = safeParseUrl(url)\n\t\t\tif (urlObj && urlObj.hostname === 'player.vimeo.com') {\n\t\t\t\tconst matches = urlObj.pathname.match(/^\\/video\\/([^/]+)\\/?$/)\n\t\t\t\tif (matches) {\n\t\t\t\t\treturn 'https://vimeo.com/' + matches[1]\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn\n\t\t},\n\t},\n\t{\n\t\thostnames: ['excalidraw.com'],\n\t\tfromEmbedUrl: (url: string) => {\n\t\t\tconst urlObj = safeParseUrl(url)\n\t\t\tif (urlObj && urlObj.hash.match(/#room=/)) {\n\t\t\t\treturn url\n\t\t\t}\n\t\t\treturn\n\t\t},\n\t},\n\t{\n\t\thostnames: ['observablehq.com'],\n\t\tfromEmbedUrl: (url: string) => {\n\t\t\tconst urlObj = safeParseUrl(url)\n\t\t\tif (urlObj && urlObj.pathname.match(/^\\/embed\\/@([^/]+)\\/([^/]+)\\/?$/)) {\n\t\t\t\treturn `${urlObj.origin}${urlObj.pathname.replace('/embed', '')}#cell-*`\n\t\t\t}\n\t\t\tif (urlObj && urlObj.pathname.match(/^\\/embed\\/([^/]+)\\/?$/)) {\n\t\t\t\treturn `${urlObj.origin}${urlObj.pathname.replace('/embed', '/d')}#cell-*`\n\t\t\t}\n\n\t\t\treturn\n\t\t},\n\t},\n\t{\n\t\thostnames: ['desmos.com'],\n\t\tfromEmbedUrl: (url: string) => {\n\t\t\tconst urlObj = safeParseUrl(url)\n\t\t\tif (\n\t\t\t\turlObj &&\n\t\t\t\turlObj.hostname === 'www.desmos.com' &&\n\t\t\t\turlObj.pathname.match(/^\\/calculator\\/([^/]+)\\/?$/) &&\n\t\t\t\turlObj.search === '?embed' &&\n\t\t\t\turlObj.hash === ''\n\t\t\t) {\n\t\t\t\treturn url.replace('?embed', '')\n\t\t\t}\n\t\t\treturn\n\t\t},\n\t},\n]\n\n/**\n * Properties for the embed shape, which displays embedded content from external services.\n *\n * @public\n */\nexport interface TLEmbedShapeProps {\n\t/** Width of the embed shape in pixels */\n\tw: number\n\t/** Height of the embed shape in pixels */\n\th: number\n\t/** URL of the content to embed (supports YouTube, Figma, CodePen, etc.) */\n\turl: string\n}\n\n/**\n * An embed shape displays external content like YouTube videos, Figma designs, CodePen demos,\n * and other embeddable content within the tldraw canvas.\n *\n * @public\n * @example\n * ```ts\n * const embedShape: TLEmbedShape = {\n * id: createShapeId(),\n * typeName: 'shape',\n * type: 'embed',\n * x: 200,\n * y: 200,\n * rotation: 0,\n * index: 'a1',\n * parentId: 'page:page1',\n * isLocked: false,\n * opacity: 1,\n * props: {\n * w: 560,\n * h: 315,\n * url: 'https://www.youtube.com/watch?v=dQw4w9WgXcQ'\n * },\n * meta: {}\n * }\n * ```\n */\nexport type TLEmbedShape = TLBaseShape<'embed', TLEmbedShapeProps>\n\n/**\n * Validation schema for embed shape properties.\n *\n * @public\n * @example\n * ```ts\n * // Validate embed shape properties\n * const isValidUrl = embedShapeProps.url.isValid('https://youtube.com/watch?v=abc123')\n * const isValidSize = embedShapeProps.w.isValid(560)\n * ```\n */\nexport const embedShapeProps: RecordProps<TLEmbedShape> = {\n\tw: T.nonZeroNumber,\n\th: T.nonZeroNumber,\n\turl: T.string,\n}\n\nconst Versions = createShapePropsMigrationIds('embed', {\n\tGenOriginalUrlInEmbed: 1,\n\tRemoveDoesResize: 2,\n\tRemoveTmpOldUrl: 3,\n\tRemovePermissionOverrides: 4,\n})\n\n/**\n * Version identifiers for embed shape migrations.\n *\n * @public\n */\nexport { Versions as embedShapeVersions }\n\n/**\n * Migration sequence for embed shape properties across different schema versions.\n * Handles URL transformations and removal of deprecated properties.\n *\n * @public\n */\nexport const embedShapeMigrations = createShapePropsMigrationSequence({\n\tsequence: [\n\t\t{\n\t\t\tid: Versions.GenOriginalUrlInEmbed,\n\t\t\t// add tmpOldUrl property\n\t\t\tup: (props) => {\n\t\t\t\ttry {\n\t\t\t\t\tconst url = props.url\n\t\t\t\t\tconst host = new URL(url).host.replace('www.', '')\n\t\t\t\t\tlet originalUrl\n\t\t\t\t\tfor (const localEmbedDef of EMBED_DEFINITIONS) {\n\t\t\t\t\t\tif (localEmbedDef.hostnames.includes(host)) {\n\t\t\t\t\t\t\ttry {\n\t\t\t\t\t\t\t\toriginalUrl = localEmbedDef.fromEmbedUrl(url)\n\t\t\t\t\t\t\t} catch (err) {\n\t\t\t\t\t\t\t\tconsole.warn(err)\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\n\t\t\t\t\tprops.tmpOldUrl = props.url\n\t\t\t\t\tprops.url = originalUrl ?? ''\n\t\t\t\t} catch {\n\t\t\t\t\tprops.url = ''\n\t\t\t\t\tprops.tmpOldUrl = props.url\n\t\t\t\t}\n\t\t\t},\n\t\t\tdown: 'retired',\n\t\t},\n\t\t{\n\t\t\tid: Versions.RemoveDoesResize,\n\t\t\tup: (props) => {\n\t\t\t\tdelete props.doesResize\n\t\t\t},\n\t\t\tdown: 'retired',\n\t\t},\n\t\t{\n\t\t\tid: Versions.RemoveTmpOldUrl,\n\t\t\tup: (props) => {\n\t\t\t\tdelete props.tmpOldUrl\n\t\t\t},\n\t\t\tdown: 'retired',\n\t\t},\n\t\t{\n\t\t\tid: Versions.RemovePermissionOverrides,\n\t\t\tup: (props) => {\n\t\t\t\tdelete props.overridePermissions\n\t\t\t},\n\t\t\tdown: 'retired',\n\t\t},\n\t],\n})\n"],
|
|
5
|
-
"mappings": "AAAA,SAAS,oBAAoB;AAC7B,SAAS,SAAS;AAClB,SAAS,8BAA8B,yCAAyC;AAKhF,MAAM,gBAAgB;AAEtB,MAAM,oBAAoB;AAAA,EACzB;AAAA,IACC,WAAW,CAAC,mBAAmB,cAAc,gBAAgB;AAAA,IAC7D,cAAc,CAAC,QAAgB;AAC9B,YAAM,SAAS,aAAa,GAAG;AAC/B,UAAI,UAAU,OAAO,SAAS,MAAM,aAAa,GAAG;AACnD,eAAO;AAAA,MACR;AACA;AAAA,IACD;AAAA,EACD;AAAA,EACA;AAAA,IACC,WAAW,CAAC,WAAW;AAAA,IACvB,cAAc,CAAC,QAAgB;AAC9B,YAAM,SAAS,aAAa,GAAG;AAC/B,UAAI,UAAU,OAAO,SAAS,MAAM,cAAc,GAAG;AACpD,cAAM,SAAS,OAAO,aAAa,IAAI,KAAK;AAC5C,YAAI,QAAQ;AACX,iBAAO;AAAA,QACR;AAAA,MACD;AACA;AAAA,IACD;AAAA,EACD;AAAA,EACA;AAAA,IACC,WAAW,CAAC,UAAU;AAAA,IACtB,cAAc,CAAC,QAAgB;AAC9B,YAAM,SAAS,aAAa,GAAG;AAC/B,UAAI,CAAC,OAAQ;AAEb,YAAM,UAAU,OAAO,SAAS,MAAM,8BAA8B;AACpE,UAAI,WAAW,OAAO,aAAa,IAAI,QAAQ,KAAK,OAAO,aAAa,IAAI,MAAM,GAAG;AACpF,cAAM,OAAO,OAAO,aAAa,IAAI,MAAM;AAC3C,cAAM,CAAC,KAAK,GAAG,IAAI,OAAO,aAAa,IAAI,QAAQ,EAAG,MAAM,GAAG;AAC/D,eAAO,gCAAgC,GAAG,IAAI,GAAG,IAAI,IAAI;AAAA,MAC1D;AACA;AAAA,IACD;AAAA,EACD;AAAA,EACA;AAAA,IACC,WAAW,CAAC,UAAU;AAAA,IACtB,cAAc,CAAC,QAAgB;AAC9B,YAAM,SAAS,aAAa,GAAG;AAE/B,YAAM,UAAU,UAAU,OAAO,SAAS,MAAM,kBAAkB;AAClE,UAAI,SAAS;AACZ,eAAO,0BAA0B,QAAQ,CAAC,CAAC;AAAA,MAC5C;AACA;AAAA,IACD;AAAA,EACD;AAAA,EACA;AAAA,IACC,WAAW,CAAC,gBAAgB;AAAA,IAC5B,cAAc,CAAC,QAAgB;AAC9B,YAAM,SAAS,aAAa,GAAG;AAC/B,YAAM,UAAU,UAAU,OAAO,SAAS,MAAM,qBAAqB;AACrE,UAAI,SAAS;AACZ,eAAO,4BAA4B,QAAQ,CAAC,CAAC;AAAA,MAC9C;AACA;AAAA,IACD;AAAA,EACD;AAAA,EACA;AAAA,IACC,WAAW,CAAC,YAAY;AAAA,IACxB,cAAc,CAAC,QAAgB;AAC9B,YAAM,uBAAuB;AAC7B,YAAM,UAAU,IAAI,MAAM,oBAAoB;AAC9C,UAAI,SAAS;AACZ,cAAM,CAAC,GAAG,MAAM,EAAE,IAAI;AACtB,eAAO,sBAAsB,IAAI,QAAQ,EAAE;AAAA,MAC5C;AACA;AAAA,IACD;AAAA,EACD;AAAA,EACA;AAAA,IACC,WAAW,CAAC,iBAAiB;AAAA,IAC7B,cAAc,CAAC,QAAgB;AAC9B,YAAM,uBAAuB;AAC7B,YAAM,UAAU,IAAI,MAAM,oBAAoB;AAC9C,UAAI,SAAS;AACZ,cAAM,CAAC,GAAG,EAAE,IAAI;AAChB,eAAO,oCAAoC,EAAE;AAAA,MAC9C;AACA;AAAA,IACD;AAAA,EACD;AAAA,EACA;AAAA,IACC,WAAW,CAAC,iBAAiB,eAAe,UAAU;AAAA,IACtD,cAAc,CAAC,QAAgB;AAC9B,YAAM,SAAS,aAAa,GAAG;AAC/B,UAAI,CAAC,OAAQ;AAEb,YAAM,WAAW,OAAO,SAAS,QAAQ,SAAS,EAAE;AACpD,UAAI,aAAa,eAAe;AAC/B,cAAM,UAAU,OAAO,SAAS,MAAM,sBAAsB;AAC5D,YAAI,SAAS;AACZ,iBAAO,mCAAmC,QAAQ,CAAC,CAAC;AAAA,QACrD;AAAA,MACD;AACA;AAAA,IACD;AAAA,EACD;AAAA,EACA;AAAA,IACC,WAAW,CAAC,mBAAmB;AAAA,IAC/B,cAAc,CAAC,QAAgB;AAC9B,YAAM,SAAS,aAAa,GAAG;AAC/B,YAAM,QAAQ,QAAQ,aAAa,IAAI,KAAK;AAE5C,UAAI,QAAQ,SAAS,MAAM,mBAAmB,KAAK,OAAO;AACzD,eAAO,WAAW;AAClB,cAAM,OAAO,MAAM,KAAK,OAAO,aAAa,KAAK,CAAC;AAClD,mBAAW,OAAO,MAAM;AACvB,iBAAO,aAAa,OAAO,GAAG;AAAA,QAC/B;AACA,eAAO,aAAa,IAAI,OAAO,KAAK;AACpC,eAAO,OAAO;AAAA,MACf;AACA;AAAA,IACD;AAAA,EACD;AAAA,EACA;AAAA,IACC,WAAW,CAAC,eAAe;AAAA,IAC3B,cAAc,CAAC,QAAgB;AAC9B,YAAM,SAAS,aAAa,GAAG;AAE/B,UAAI,QAAQ,SAAS,MAAM,iBAAiB,KAAK,QAAQ,SAAS,MAAM,aAAa,GAAG;AACvF,eAAO,WAAW,OAAO,SAAS,QAAQ,YAAY,MAAM;AAC5D,cAAM,OAAO,MAAM,KAAK,OAAO,aAAa,KAAK,CAAC;AAClD,mBAAW,OAAO,MAAM;AACvB,iBAAO,aAAa,OAAO,GAAG;AAAA,QAC/B;AACA,eAAO,OAAO;AAAA,MACf;AACA;AAAA,IACD;AAAA,EACD;AAAA,EACA;AAAA,IACC,WAAW,CAAC,iBAAiB;AAAA,IAC7B,cAAc,CAAC,QAAgB;AAC9B,YAAM,SAAS,aAAa,GAAG;AAC/B,UAAI,UAAU,OAAO,SAAS,MAAM,oBAAoB,GAAG;AAC1D,YAAI,CAAC,IAAI,MAAM,GAAG,EAAE,IAAI,EAAG;AAC3B,eAAO;AAAA,MACR;AACA;AAAA,IACD;AAAA,EACD;AAAA,EACA;AAAA,IACC,WAAW,CAAC,YAAY;AAAA,IACxB,cAAc,CAAC,QAAgB;AAC9B,YAAM,SAAS,aAAa,GAAG;AAC/B,UACC,UACA,OAAO,SAAS,MAAM,qBAAqB,KAC3C,OAAO,aAAa,IAAI,OAAO,GAC9B;AACD,eAAO,aAAa,OAAO,OAAO;AAClC,eAAO,OAAO;AAAA,MACf;AACA;AAAA,IACD;AAAA,EACD;AAAA,EACA;AAAA,IACC,WAAW,CAAC,UAAU;AAAA,IACtB,cAAc,CAAC,QAAgB;AAC9B,YAAM,SAAS,aAAa,GAAG;AAC/B,UAAI,UAAU,OAAO,SAAS,MAAM,iBAAiB,GAAG;AACvD,eAAO,WAAW,OAAO,SAAS,QAAQ,YAAY,EAAE;AACxD,eAAO,OAAO;AAAA,MACf;AACA;AAAA,IACD;AAAA,EACD;AAAA,EACA;AAAA,IACC,WAAW,CAAC,kBAAkB;AAAA,IAC9B,cAAc,CAAC,QAAgB;AAC9B,YAAM,SAAS,aAAa,GAAG;AAC/B,UAAI,UAAU,OAAO,SAAS,MAAM,4BAA4B,GAAG;AAClE,eAAO,OAAO,SAAS,OAAO,SAAS,QAAQ,YAAY,EAAE;AAAA,MAC9D;AACA;AAAA,IACD;AAAA,EACD;AAAA,EACA;AAAA,IACC,WAAW,CAAC,aAAa,kBAAkB;AAAA,IAC3C,cAAc,CAAC,QAAgB;AAC9B,YAAM,SAAS,aAAa,GAAG;AAC/B,UAAI,UAAU,OAAO,aAAa,oBAAoB;AACrD,cAAM,UAAU,OAAO,SAAS,MAAM,uBAAuB;AAC7D,YAAI,SAAS;AACZ,iBAAO,uBAAuB,QAAQ,CAAC;AAAA,QACxC;AAAA,MACD;AACA;AAAA,IACD;AAAA,EACD;AAAA,EACA;AAAA,IACC,WAAW,CAAC,
|
|
4
|
+
"sourcesContent": ["import { safeParseUrl } from '@tldraw/utils'\nimport { T } from '@tldraw/validate'\nimport { createShapePropsMigrationIds, createShapePropsMigrationSequence } from '../records/TLShape'\nimport { RecordProps } from '../recordsWithProps'\nimport { TLBaseShape } from './TLBaseShape'\n\n// Only allow multiplayer embeds. If we add additional routes later for example '/help' this won't match\nconst TLDRAW_APP_RE = /(^\\/r\\/[^/]+\\/?$)/\n\nconst EMBED_DEFINITIONS = [\n\t{\n\t\thostnames: ['beta.tldraw.com', 'tldraw.com', 'localhost:3000'],\n\t\tfromEmbedUrl: (url: string) => {\n\t\t\tconst urlObj = safeParseUrl(url)\n\t\t\tif (urlObj && urlObj.pathname.match(TLDRAW_APP_RE)) {\n\t\t\t\treturn url\n\t\t\t}\n\t\t\treturn\n\t\t},\n\t},\n\t{\n\t\thostnames: ['figma.com'],\n\t\tfromEmbedUrl: (url: string) => {\n\t\t\tconst urlObj = safeParseUrl(url)\n\t\t\tif (urlObj && urlObj.pathname.match(/^\\/embed\\/?$/)) {\n\t\t\t\tconst outUrl = urlObj.searchParams.get('url')\n\t\t\t\tif (outUrl) {\n\t\t\t\t\treturn outUrl\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn\n\t\t},\n\t},\n\t{\n\t\thostnames: ['google.*'],\n\t\tfromEmbedUrl: (url: string) => {\n\t\t\tconst urlObj = safeParseUrl(url)\n\t\t\tif (!urlObj) return\n\n\t\t\tconst matches = urlObj.pathname.match(/^\\/maps\\/embed\\/v1\\/view\\/?$/)\n\t\t\tif (matches && urlObj.searchParams.has('center') && urlObj.searchParams.get('zoom')) {\n\t\t\t\tconst zoom = urlObj.searchParams.get('zoom')\n\t\t\t\tconst [lat, lon] = urlObj.searchParams.get('center')!.split(',')\n\t\t\t\treturn `https://www.google.com/maps/@${lat},${lon},${zoom}z`\n\t\t\t}\n\t\t\treturn\n\t\t},\n\t},\n\t{\n\t\thostnames: ['val.town'],\n\t\tfromEmbedUrl: (url: string) => {\n\t\t\tconst urlObj = safeParseUrl(url)\n\t\t\t// e.g. extract \"steveruizok/mathFact\" from https://www.val.town/v/steveruizok/mathFact\n\t\t\tconst matches = urlObj && urlObj.pathname.match(/\\/embed\\/(.+)\\/?/)\n\t\t\tif (matches) {\n\t\t\t\treturn `https://www.val.town/v/${matches[1]}`\n\t\t\t}\n\t\t\treturn\n\t\t},\n\t},\n\t{\n\t\thostnames: ['codesandbox.io'],\n\t\tfromEmbedUrl: (url: string) => {\n\t\t\tconst urlObj = safeParseUrl(url)\n\t\t\tconst matches = urlObj && urlObj.pathname.match(/\\/embed\\/([^/]+)\\/?/)\n\t\t\tif (matches) {\n\t\t\t\treturn `https://codesandbox.io/s/${matches[1]}`\n\t\t\t}\n\t\t\treturn\n\t\t},\n\t},\n\t{\n\t\thostnames: ['codepen.io'],\n\t\tfromEmbedUrl: (url: string) => {\n\t\t\tconst CODEPEN_EMBED_REGEXP = /https:\\/\\/codepen.io\\/([^/]+)\\/embed\\/([^/]+)/\n\t\t\tconst matches = url.match(CODEPEN_EMBED_REGEXP)\n\t\t\tif (matches) {\n\t\t\t\tconst [_, user, id] = matches\n\t\t\t\treturn `https://codepen.io/${user}/pen/${id}`\n\t\t\t}\n\t\t\treturn\n\t\t},\n\t},\n\t{\n\t\thostnames: ['scratch.mit.edu'],\n\t\tfromEmbedUrl: (url: string) => {\n\t\t\tconst SCRATCH_EMBED_REGEXP = /https:\\/\\/scratch.mit.edu\\/projects\\/embed\\/([^/]+)/\n\t\t\tconst matches = url.match(SCRATCH_EMBED_REGEXP)\n\t\t\tif (matches) {\n\t\t\t\tconst [_, id] = matches\n\t\t\t\treturn `https://scratch.mit.edu/projects/${id}`\n\t\t\t}\n\t\t\treturn\n\t\t},\n\t},\n\t{\n\t\thostnames: ['*.youtube.com', 'youtube.com', 'youtu.be'],\n\t\tfromEmbedUrl: (url: string) => {\n\t\t\tconst urlObj = safeParseUrl(url)\n\t\t\tif (!urlObj) return\n\n\t\t\tconst hostname = urlObj.hostname.replace(/^www./, '')\n\t\t\tif (hostname === 'youtube.com') {\n\t\t\t\tconst matches = urlObj.pathname.match(/^\\/embed\\/([^/]+)\\/?/)\n\t\t\t\tif (matches) {\n\t\t\t\t\treturn `https://www.youtube.com/watch?v=${matches[1]}`\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn\n\t\t},\n\t},\n\t{\n\t\thostnames: ['calendar.google.*'],\n\t\tfromEmbedUrl: (url: string) => {\n\t\t\tconst urlObj = safeParseUrl(url)\n\t\t\tconst srcQs = urlObj?.searchParams.get('src')\n\n\t\t\tif (urlObj?.pathname.match(/\\/calendar\\/embed/) && srcQs) {\n\t\t\t\turlObj.pathname = '/calendar/u/0'\n\t\t\t\tconst keys = Array.from(urlObj.searchParams.keys())\n\t\t\t\tfor (const key of keys) {\n\t\t\t\t\turlObj.searchParams.delete(key)\n\t\t\t\t}\n\t\t\t\turlObj.searchParams.set('cid', srcQs)\n\t\t\t\treturn urlObj.href\n\t\t\t}\n\t\t\treturn\n\t\t},\n\t},\n\t{\n\t\thostnames: ['docs.google.*'],\n\t\tfromEmbedUrl: (url: string) => {\n\t\t\tconst urlObj = safeParseUrl(url)\n\n\t\t\tif (urlObj?.pathname.match(/^\\/presentation/) && urlObj?.pathname.match(/\\/embed\\/?$/)) {\n\t\t\t\turlObj.pathname = urlObj.pathname.replace(/\\/embed$/, '/pub')\n\t\t\t\tconst keys = Array.from(urlObj.searchParams.keys())\n\t\t\t\tfor (const key of keys) {\n\t\t\t\t\turlObj.searchParams.delete(key)\n\t\t\t\t}\n\t\t\t\treturn urlObj.href\n\t\t\t}\n\t\t\treturn\n\t\t},\n\t},\n\t{\n\t\thostnames: ['gist.github.com'],\n\t\tfromEmbedUrl: (url: string) => {\n\t\t\tconst urlObj = safeParseUrl(url)\n\t\t\tif (urlObj && urlObj.pathname.match(/\\/([^/]+)\\/([^/]+)/)) {\n\t\t\t\tif (!url.split('/').pop()) return\n\t\t\t\treturn url\n\t\t\t}\n\t\t\treturn\n\t\t},\n\t},\n\t{\n\t\thostnames: ['replit.com'],\n\t\tfromEmbedUrl: (url: string) => {\n\t\t\tconst urlObj = safeParseUrl(url)\n\t\t\tif (\n\t\t\t\turlObj &&\n\t\t\t\turlObj.pathname.match(/\\/@([^/]+)\\/([^/]+)/) &&\n\t\t\t\turlObj.searchParams.has('embed')\n\t\t\t) {\n\t\t\t\turlObj.searchParams.delete('embed')\n\t\t\t\treturn urlObj.href\n\t\t\t}\n\t\t\treturn\n\t\t},\n\t},\n\t{\n\t\thostnames: ['felt.com'],\n\t\tfromEmbedUrl: (url: string) => {\n\t\t\tconst urlObj = safeParseUrl(url)\n\t\t\tif (urlObj && urlObj.pathname.match(/^\\/embed\\/map\\//)) {\n\t\t\t\turlObj.pathname = urlObj.pathname.replace(/^\\/embed/, '')\n\t\t\t\treturn urlObj.href\n\t\t\t}\n\t\t\treturn\n\t\t},\n\t},\n\t{\n\t\thostnames: ['open.spotify.com'],\n\t\tfromEmbedUrl: (url: string) => {\n\t\t\tconst urlObj = safeParseUrl(url)\n\t\t\tif (urlObj && urlObj.pathname.match(/^\\/embed\\/(artist|album)\\//)) {\n\t\t\t\treturn urlObj.origin + urlObj.pathname.replace(/^\\/embed/, '')\n\t\t\t}\n\t\t\treturn\n\t\t},\n\t},\n\t{\n\t\thostnames: ['vimeo.com', 'player.vimeo.com'],\n\t\tfromEmbedUrl: (url: string) => {\n\t\t\tconst urlObj = safeParseUrl(url)\n\t\t\tif (urlObj && urlObj.hostname === 'player.vimeo.com') {\n\t\t\t\tconst matches = urlObj.pathname.match(/^\\/video\\/([^/]+)\\/?$/)\n\t\t\t\tif (matches) {\n\t\t\t\t\treturn 'https://vimeo.com/' + matches[1]\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn\n\t\t},\n\t},\n\t{\n\t\thostnames: ['observablehq.com'],\n\t\tfromEmbedUrl: (url: string) => {\n\t\t\tconst urlObj = safeParseUrl(url)\n\t\t\tif (urlObj && urlObj.pathname.match(/^\\/embed\\/@([^/]+)\\/([^/]+)\\/?$/)) {\n\t\t\t\treturn `${urlObj.origin}${urlObj.pathname.replace('/embed', '')}#cell-*`\n\t\t\t}\n\t\t\tif (urlObj && urlObj.pathname.match(/^\\/embed\\/([^/]+)\\/?$/)) {\n\t\t\t\treturn `${urlObj.origin}${urlObj.pathname.replace('/embed', '/d')}#cell-*`\n\t\t\t}\n\n\t\t\treturn\n\t\t},\n\t},\n\t{\n\t\thostnames: ['desmos.com'],\n\t\tfromEmbedUrl: (url: string) => {\n\t\t\tconst urlObj = safeParseUrl(url)\n\t\t\tif (\n\t\t\t\turlObj &&\n\t\t\t\turlObj.hostname === 'www.desmos.com' &&\n\t\t\t\turlObj.pathname.match(/^\\/calculator\\/([^/]+)\\/?$/) &&\n\t\t\t\turlObj.search === '?embed' &&\n\t\t\t\turlObj.hash === ''\n\t\t\t) {\n\t\t\t\treturn url.replace('?embed', '')\n\t\t\t}\n\t\t\treturn\n\t\t},\n\t},\n]\n\n/**\n * Properties for the embed shape, which displays embedded content from external services.\n *\n * @public\n */\nexport interface TLEmbedShapeProps {\n\t/** Width of the embed shape in pixels */\n\tw: number\n\t/** Height of the embed shape in pixels */\n\th: number\n\t/** URL of the content to embed (supports YouTube, Figma, CodePen, etc.) */\n\turl: string\n}\n\n/**\n * An embed shape displays external content like YouTube videos, Figma designs, CodePen demos,\n * and other embeddable content within the tldraw canvas.\n *\n * @public\n * @example\n * ```ts\n * const embedShape: TLEmbedShape = {\n * id: createShapeId(),\n * typeName: 'shape',\n * type: 'embed',\n * x: 200,\n * y: 200,\n * rotation: 0,\n * index: 'a1',\n * parentId: 'page:page1',\n * isLocked: false,\n * opacity: 1,\n * props: {\n * w: 560,\n * h: 315,\n * url: 'https://www.youtube.com/watch?v=dQw4w9WgXcQ'\n * },\n * meta: {}\n * }\n * ```\n */\nexport type TLEmbedShape = TLBaseShape<'embed', TLEmbedShapeProps>\n\n/**\n * Validation schema for embed shape properties.\n *\n * @public\n * @example\n * ```ts\n * // Validate embed shape properties\n * const isValidUrl = embedShapeProps.url.isValid('https://youtube.com/watch?v=abc123')\n * const isValidSize = embedShapeProps.w.isValid(560)\n * ```\n */\nexport const embedShapeProps: RecordProps<TLEmbedShape> = {\n\tw: T.nonZeroNumber,\n\th: T.nonZeroNumber,\n\turl: T.string,\n}\n\nconst Versions = createShapePropsMigrationIds('embed', {\n\tGenOriginalUrlInEmbed: 1,\n\tRemoveDoesResize: 2,\n\tRemoveTmpOldUrl: 3,\n\tRemovePermissionOverrides: 4,\n})\n\n/**\n * Version identifiers for embed shape migrations.\n *\n * @public\n */\nexport { Versions as embedShapeVersions }\n\n/**\n * Migration sequence for embed shape properties across different schema versions.\n * Handles URL transformations and removal of deprecated properties.\n *\n * @public\n */\nexport const embedShapeMigrations = createShapePropsMigrationSequence({\n\tsequence: [\n\t\t{\n\t\t\tid: Versions.GenOriginalUrlInEmbed,\n\t\t\t// add tmpOldUrl property\n\t\t\tup: (props) => {\n\t\t\t\ttry {\n\t\t\t\t\tconst url = props.url\n\t\t\t\t\tconst host = new URL(url).host.replace('www.', '')\n\t\t\t\t\tlet originalUrl\n\t\t\t\t\tfor (const localEmbedDef of EMBED_DEFINITIONS) {\n\t\t\t\t\t\tif (localEmbedDef.hostnames.includes(host)) {\n\t\t\t\t\t\t\ttry {\n\t\t\t\t\t\t\t\toriginalUrl = localEmbedDef.fromEmbedUrl(url)\n\t\t\t\t\t\t\t} catch (err) {\n\t\t\t\t\t\t\t\tconsole.warn(err)\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\n\t\t\t\t\tprops.tmpOldUrl = props.url\n\t\t\t\t\tprops.url = originalUrl ?? ''\n\t\t\t\t} catch {\n\t\t\t\t\tprops.url = ''\n\t\t\t\t\tprops.tmpOldUrl = props.url\n\t\t\t\t}\n\t\t\t},\n\t\t\tdown: 'retired',\n\t\t},\n\t\t{\n\t\t\tid: Versions.RemoveDoesResize,\n\t\t\tup: (props) => {\n\t\t\t\tdelete props.doesResize\n\t\t\t},\n\t\t\tdown: 'retired',\n\t\t},\n\t\t{\n\t\t\tid: Versions.RemoveTmpOldUrl,\n\t\t\tup: (props) => {\n\t\t\t\tdelete props.tmpOldUrl\n\t\t\t},\n\t\t\tdown: 'retired',\n\t\t},\n\t\t{\n\t\t\tid: Versions.RemovePermissionOverrides,\n\t\t\tup: (props) => {\n\t\t\t\tdelete props.overridePermissions\n\t\t\t},\n\t\t\tdown: 'retired',\n\t\t},\n\t],\n})\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@tldraw/tlschema",
|
|
3
3
|
"description": "tldraw infinite canvas SDK (schema).",
|
|
4
|
-
"version": "4.1.0-canary.
|
|
4
|
+
"version": "4.1.0-canary.65769c249e0d",
|
|
5
5
|
"author": {
|
|
6
6
|
"name": "tldraw Inc.",
|
|
7
7
|
"email": "hello@tldraw.com"
|
|
@@ -51,10 +51,10 @@
|
|
|
51
51
|
"vitest": "^3.2.4"
|
|
52
52
|
},
|
|
53
53
|
"dependencies": {
|
|
54
|
-
"@tldraw/state": "4.1.0-canary.
|
|
55
|
-
"@tldraw/store": "4.1.0-canary.
|
|
56
|
-
"@tldraw/utils": "4.1.0-canary.
|
|
57
|
-
"@tldraw/validate": "4.1.0-canary.
|
|
54
|
+
"@tldraw/state": "4.1.0-canary.65769c249e0d",
|
|
55
|
+
"@tldraw/store": "4.1.0-canary.65769c249e0d",
|
|
56
|
+
"@tldraw/utils": "4.1.0-canary.65769c249e0d",
|
|
57
|
+
"@tldraw/validate": "4.1.0-canary.65769c249e0d"
|
|
58
58
|
},
|
|
59
59
|
"peerDependencies": {
|
|
60
60
|
"react": "^18.2.0 || ^19.0.0",
|
package/src/misc/TLHandle.ts
CHANGED
|
@@ -96,8 +96,12 @@ export interface TLHandle {
|
|
|
96
96
|
label?: string
|
|
97
97
|
/** The type of handle, determining its behavior and interaction mode */
|
|
98
98
|
type: TLHandleType
|
|
99
|
-
/**
|
|
99
|
+
/**
|
|
100
|
+
* @deprecated Use `snapType` instead. Whether this handle should snap to other geometry during interactions.
|
|
101
|
+
*/
|
|
100
102
|
canSnap?: boolean
|
|
103
|
+
/** The type of snap to use for this handle */
|
|
104
|
+
snapType?: 'point' | 'align'
|
|
101
105
|
/** The fractional index used for ordering handles */
|
|
102
106
|
index: IndexKey
|
|
103
107
|
/** The x-coordinate of the handle in the shape's local coordinate system */
|
|
@@ -203,16 +203,6 @@ const EMBED_DEFINITIONS = [
|
|
|
203
203
|
return
|
|
204
204
|
},
|
|
205
205
|
},
|
|
206
|
-
{
|
|
207
|
-
hostnames: ['excalidraw.com'],
|
|
208
|
-
fromEmbedUrl: (url: string) => {
|
|
209
|
-
const urlObj = safeParseUrl(url)
|
|
210
|
-
if (urlObj && urlObj.hash.match(/#room=/)) {
|
|
211
|
-
return url
|
|
212
|
-
}
|
|
213
|
-
return
|
|
214
|
-
},
|
|
215
|
-
},
|
|
216
206
|
{
|
|
217
207
|
hostnames: ['observablehq.com'],
|
|
218
208
|
fromEmbedUrl: (url: string) => {
|