tldraw
Version:
A tiny little drawing editor.
8 lines (7 loc) • 30.8 kB
Source Map (JSON)
{
"version": 3,
"sources": ["../../src/lib/defaultExternalContentHandlers.ts"],
"sourcesContent": ["import {\n\tAssetRecordType,\n\tEditor,\n\tMediaHelpers,\n\tTLAsset,\n\tTLAssetId,\n\tTLBookmarkShape,\n\tTLEmbedShape,\n\tTLImageAsset,\n\tTLShapeId,\n\tTLShapePartial,\n\tTLTextShape,\n\tTLTextShapeProps,\n\tTLVideoAsset,\n\tVec,\n\tVecLike,\n\tassert,\n\tcreateShapeId,\n\tfetch,\n\tgetHashForBuffer,\n\tgetHashForString,\n} from '@tldraw/editor'\nimport { EmbedDefinition } from './defaultEmbedDefinitions'\nimport { EmbedShapeUtil } from './shapes/embed/EmbedShapeUtil'\nimport { FONT_FAMILIES, FONT_SIZES, TEXT_PROPS } from './shapes/shared/default-shape-constants'\nimport { TLUiToastsContextType } from './ui/context/toasts'\nimport { useTranslation } from './ui/hooks/useTranslation/useTranslation'\nimport { containBoxSize } from './utils/assets/assets'\nimport { cleanupText, isRightToLeftLanguage } from './utils/text/text'\n\n/** @public */\nexport interface TLExternalContentProps {\n\t/**\n\t * The maximum dimension (width or height) of an image. Images larger than this will be rescaled\n\t * to fit. Defaults to infinity.\n\t */\n\tmaxImageDimension?: number\n\t/**\n\t * The maximum size (in bytes) of an asset. Assets larger than this will be rejected. Defaults\n\t * to 10mb (10 * 1024 * 1024).\n\t */\n\tmaxAssetSize?: number\n\t/**\n\t * The mime types of images that are allowed to be handled. Defaults to\n\t * DEFAULT_SUPPORTED_IMAGE_TYPES.\n\t */\n\tacceptedImageMimeTypes?: readonly string[]\n\t/**\n\t * The mime types of videos that are allowed to be handled. Defaults to\n\t * DEFAULT_SUPPORT_VIDEO_TYPES.\n\t */\n\tacceptedVideoMimeTypes?: readonly string[]\n}\n\n/** @public */\nexport function registerDefaultExternalContentHandlers(\n\teditor: Editor,\n\t{\n\t\tmaxImageDimension,\n\t\tmaxAssetSize,\n\t\tacceptedImageMimeTypes,\n\t\tacceptedVideoMimeTypes,\n\t}: Required<TLExternalContentProps>,\n\t{ toasts, msg }: { toasts: TLUiToastsContextType; msg: ReturnType<typeof useTranslation> }\n) {\n\t// files -> asset\n\teditor.registerExternalAssetHandler('file', async ({ file, assetId }) => {\n\t\tconst isImageType = acceptedImageMimeTypes.includes(file.type)\n\t\tconst isVideoType = acceptedVideoMimeTypes.includes(file.type)\n\n\t\tif (!isImageType && !isVideoType) {\n\t\t\ttoasts.addToast({\n\t\t\t\ttitle: msg('assets.files.type-not-allowed'),\n\t\t\t\tseverity: 'error',\n\t\t\t})\n\t\t}\n\t\tassert(isImageType || isVideoType, `File type not allowed: ${file.type}`)\n\n\t\tif (file.size > maxAssetSize) {\n\t\t\ttoasts.addToast({\n\t\t\t\ttitle: msg('assets.files.size-too-big'),\n\t\t\t\tseverity: 'error',\n\t\t\t})\n\t\t}\n\t\tassert(\n\t\t\tfile.size <= maxAssetSize,\n\t\t\t`File size too big: ${(file.size / 1024).toFixed()}kb > ${(maxAssetSize / 1024).toFixed()}kb`\n\t\t)\n\n\t\tconst hash = getHashForBuffer(await file.arrayBuffer())\n\t\tassetId = assetId ?? AssetRecordType.createId(hash)\n\t\tconst assetInfo = await getMediaAssetInfoPartial(file, assetId, isImageType, isVideoType)\n\n\t\tif (isFinite(maxImageDimension)) {\n\t\t\tconst size = { w: assetInfo.props.w, h: assetInfo.props.h }\n\t\t\tconst resizedSize = containBoxSize(size, { w: maxImageDimension, h: maxImageDimension })\n\t\t\tif (size !== resizedSize && MediaHelpers.isStaticImageType(file.type)) {\n\t\t\t\tassetInfo.props.w = resizedSize.w\n\t\t\t\tassetInfo.props.h = resizedSize.h\n\t\t\t}\n\t\t}\n\n\t\tassetInfo.props.src = await editor.uploadAsset(assetInfo, file)\n\n\t\treturn AssetRecordType.create(assetInfo)\n\t})\n\n\t// urls -> bookmark asset\n\teditor.registerExternalAssetHandler('url', async ({ url }) => {\n\t\tlet meta: { image: string; favicon: string; title: string; description: string }\n\n\t\ttry {\n\t\t\tconst resp = await fetch(url, {\n\t\t\t\tmethod: 'GET',\n\t\t\t\tmode: 'no-cors',\n\t\t\t})\n\t\t\tconst html = await resp.text()\n\t\t\tconst doc = new DOMParser().parseFromString(html, 'text/html')\n\t\t\tmeta = {\n\t\t\t\timage: doc.head.querySelector('meta[property=\"og:image\"]')?.getAttribute('content') ?? '',\n\t\t\t\tfavicon:\n\t\t\t\t\tdoc.head.querySelector('link[rel=\"apple-touch-icon\"]')?.getAttribute('href') ??\n\t\t\t\t\tdoc.head.querySelector('link[rel=\"icon\"]')?.getAttribute('href') ??\n\t\t\t\t\t'',\n\t\t\t\ttitle: doc.head.querySelector('meta[property=\"og:title\"]')?.getAttribute('content') ?? url,\n\t\t\t\tdescription:\n\t\t\t\t\tdoc.head.querySelector('meta[property=\"og:description\"]')?.getAttribute('content') ?? '',\n\t\t\t}\n\t\t\tif (!meta.image.startsWith('http')) {\n\t\t\t\tmeta.image = new URL(meta.image, url).href\n\t\t\t}\n\t\t\tif (!meta.favicon.startsWith('http')) {\n\t\t\t\tmeta.favicon = new URL(meta.favicon, url).href\n\t\t\t}\n\t\t} catch (error) {\n\t\t\tconsole.error(error)\n\t\t\ttoasts.addToast({\n\t\t\t\ttitle: msg('assets.url.failed'),\n\t\t\t\tseverity: 'error',\n\t\t\t})\n\t\t\tmeta = { image: '', favicon: '', title: '', description: '' }\n\t\t}\n\n\t\t// Create the bookmark asset from the meta\n\t\treturn {\n\t\t\tid: AssetRecordType.createId(getHashForString(url)),\n\t\t\ttypeName: 'asset',\n\t\t\ttype: 'bookmark',\n\t\t\tprops: {\n\t\t\t\tsrc: url,\n\t\t\t\tdescription: meta.description,\n\t\t\t\timage: meta.image,\n\t\t\t\tfavicon: meta.favicon,\n\t\t\t\ttitle: meta.title,\n\t\t\t},\n\t\t\tmeta: {},\n\t\t}\n\t})\n\n\t// svg text\n\teditor.registerExternalContentHandler('svg-text', async ({ point, text }) => {\n\t\tconst position =\n\t\t\tpoint ??\n\t\t\t(editor.inputs.shiftKey\n\t\t\t\t? editor.inputs.currentPagePoint\n\t\t\t\t: editor.getViewportPageBounds().center)\n\n\t\tconst svg = new DOMParser().parseFromString(text, 'image/svg+xml').querySelector('svg')\n\t\tif (!svg) {\n\t\t\tthrow new Error('No <svg/> element present')\n\t\t}\n\n\t\tlet width = parseFloat(svg.getAttribute('width') || '0')\n\t\tlet height = parseFloat(svg.getAttribute('height') || '0')\n\n\t\tif (!(width && height)) {\n\t\t\tdocument.body.appendChild(svg)\n\t\t\tconst box = svg.getBoundingClientRect()\n\t\t\tdocument.body.removeChild(svg)\n\n\t\t\twidth = box.width\n\t\t\theight = box.height\n\t\t}\n\n\t\tconst asset = await editor.getAssetForExternalContent({\n\t\t\ttype: 'file',\n\t\t\tfile: new File([text], 'asset.svg', { type: 'image/svg+xml' }),\n\t\t})\n\n\t\tif (!asset) throw Error('Could not create an asset')\n\n\t\tcreateShapesForAssets(editor, [asset], position)\n\t})\n\n\t// embeds\n\teditor.registerExternalContentHandler<'embed', EmbedDefinition>(\n\t\t'embed',\n\t\t({ point, url, embed }) => {\n\t\t\tconst position =\n\t\t\t\tpoint ??\n\t\t\t\t(editor.inputs.shiftKey\n\t\t\t\t\t? editor.inputs.currentPagePoint\n\t\t\t\t\t: editor.getViewportPageBounds().center)\n\n\t\t\tconst { width, height } = embed\n\n\t\t\tconst id = createShapeId()\n\n\t\t\tconst shapePartial: TLShapePartial<TLEmbedShape> = {\n\t\t\t\tid,\n\t\t\t\ttype: 'embed',\n\t\t\t\tx: position.x - (width || 450) / 2,\n\t\t\t\ty: position.y - (height || 450) / 2,\n\t\t\t\tprops: {\n\t\t\t\t\tw: width,\n\t\t\t\t\th: height,\n\t\t\t\t\turl,\n\t\t\t\t},\n\t\t\t}\n\n\t\t\teditor.createShapes([shapePartial]).select(id)\n\t\t}\n\t)\n\n\t// files\n\teditor.registerExternalContentHandler('files', async ({ point, files }) => {\n\t\tif (files.length > editor.options.maxFilesAtOnce) {\n\t\t\tthrow Error('Too many files')\n\t\t}\n\n\t\tconst position =\n\t\t\tpoint ??\n\t\t\t(editor.inputs.shiftKey\n\t\t\t\t? editor.inputs.currentPagePoint\n\t\t\t\t: editor.getViewportPageBounds().center)\n\n\t\tconst pagePoint = new Vec(position.x, position.y)\n\t\tconst assetsToUpdate: {\n\t\t\tasset: TLAsset\n\t\t\tfile: File\n\t\t\ttemporaryAssetPreview?: string\n\t\t}[] = []\n\t\tfor (const file of files) {\n\t\t\tif (file.size > maxAssetSize) {\n\t\t\t\ttoasts.addToast({\n\t\t\t\t\ttitle: msg('assets.files.size-too-big'),\n\t\t\t\t\tseverity: 'error',\n\t\t\t\t})\n\n\t\t\t\tconsole.warn(\n\t\t\t\t\t`File size too big: ${(file.size / 1024).toFixed()}kb > ${(\n\t\t\t\t\t\tmaxAssetSize / 1024\n\t\t\t\t\t).toFixed()}kb`\n\t\t\t\t)\n\t\t\t\tcontinue\n\t\t\t}\n\n\t\t\t// Use mime type instead of file ext, this is because\n\t\t\t// window.navigator.clipboard does not preserve file names\n\t\t\t// of copied files.\n\t\t\tif (!file.type) {\n\t\t\t\ttoasts.addToast({\n\t\t\t\t\ttitle: msg('assets.files.upload-failed'),\n\t\t\t\t\tseverity: 'error',\n\t\t\t\t})\n\t\t\t\tconsole.error('No mime type')\n\t\t\t\tcontinue\n\t\t\t}\n\n\t\t\t// We can only accept certain extensions (either images or a videos)\n\t\t\tif (!acceptedImageMimeTypes.concat(acceptedVideoMimeTypes).includes(file.type)) {\n\t\t\t\ttoasts.addToast({\n\t\t\t\t\ttitle: msg('assets.files.type-not-allowed'),\n\t\t\t\t\tseverity: 'error',\n\t\t\t\t})\n\n\t\t\t\tconsole.warn(`${file.name} not loaded - Mime type not allowed ${file.type}.`)\n\t\t\t\tcontinue\n\t\t\t}\n\n\t\t\tconst isImageType = acceptedImageMimeTypes.includes(file.type)\n\t\t\tconst isVideoType = acceptedVideoMimeTypes.includes(file.type)\n\t\t\tconst hash = getHashForBuffer(await file.arrayBuffer())\n\t\t\tconst assetId: TLAssetId = AssetRecordType.createId(hash)\n\t\t\tconst assetInfo = await getMediaAssetInfoPartial(file, assetId, isImageType, isVideoType)\n\t\t\tlet temporaryAssetPreview\n\t\t\tif (isImageType) {\n\t\t\t\ttemporaryAssetPreview = editor.createTemporaryAssetPreview(assetId, file)\n\t\t\t}\n\t\t\tassetsToUpdate.push({ asset: assetInfo, file, temporaryAssetPreview })\n\t\t}\n\n\t\tconst assets: TLAsset[] = []\n\t\tawait Promise.allSettled(\n\t\t\tassetsToUpdate.map(async (assetAndFile) => {\n\t\t\t\ttry {\n\t\t\t\t\tconst newAsset = await editor.getAssetForExternalContent({\n\t\t\t\t\t\ttype: 'file',\n\t\t\t\t\t\tfile: assetAndFile.file,\n\t\t\t\t\t})\n\n\t\t\t\t\tif (!newAsset) {\n\t\t\t\t\t\tthrow Error('Could not create an asset')\n\t\t\t\t\t}\n\n\t\t\t\t\tconst updated = { ...newAsset, id: assetAndFile.asset.id }\n\t\t\t\t\tassets.push(updated)\n\t\t\t\t\t// Save the new asset under the old asset's id\n\t\t\t\t\teditor.updateAssets([updated])\n\t\t\t\t} catch (error) {\n\t\t\t\t\ttoasts.addToast({\n\t\t\t\t\t\ttitle: msg('assets.files.upload-failed'),\n\t\t\t\t\t\tseverity: 'error',\n\t\t\t\t\t})\n\t\t\t\t\tconsole.error(error)\n\t\t\t\t\treturn\n\t\t\t\t}\n\t\t\t})\n\t\t)\n\n\t\tcreateShapesForAssets(editor, assets, pagePoint)\n\t})\n\n\t// text\n\teditor.registerExternalContentHandler('text', async ({ point, text }) => {\n\t\tconst p =\n\t\t\tpoint ??\n\t\t\t(editor.inputs.shiftKey\n\t\t\t\t? editor.inputs.currentPagePoint\n\t\t\t\t: editor.getViewportPageBounds().center)\n\n\t\tconst defaultProps = editor.getShapeUtil<TLTextShape>('text').getDefaultProps()\n\n\t\tconst textToPaste = cleanupText(text)\n\n\t\t// If we're pasting into a text shape, update the text.\n\t\tconst onlySelectedShape = editor.getOnlySelectedShape()\n\t\tif (onlySelectedShape && 'text' in onlySelectedShape.props) {\n\t\t\teditor.updateShapes([\n\t\t\t\t{\n\t\t\t\t\tid: onlySelectedShape.id,\n\t\t\t\t\ttype: onlySelectedShape.type,\n\t\t\t\t\tprops: {\n\t\t\t\t\t\ttext: textToPaste,\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t])\n\n\t\t\treturn\n\t\t}\n\n\t\t// Measure the text with default values\n\t\tlet w: number\n\t\tlet h: number\n\t\tlet autoSize: boolean\n\t\tlet align = 'middle' as TLTextShapeProps['textAlign']\n\n\t\tconst isMultiLine = textToPaste.split('\\n').length > 1\n\n\t\t// check whether the text contains the most common characters in RTL languages\n\t\tconst isRtl = isRightToLeftLanguage(textToPaste)\n\n\t\tif (isMultiLine) {\n\t\t\talign = isMultiLine ? (isRtl ? 'end' : 'start') : 'middle'\n\t\t}\n\n\t\tconst rawSize = editor.textMeasure.measureText(textToPaste, {\n\t\t\t...TEXT_PROPS,\n\t\t\tfontFamily: FONT_FAMILIES[defaultProps.font],\n\t\t\tfontSize: FONT_SIZES[defaultProps.size],\n\t\t\tmaxWidth: null,\n\t\t})\n\n\t\tconst minWidth = Math.min(\n\t\t\tisMultiLine ? editor.getViewportPageBounds().width * 0.9 : 920,\n\t\t\tMath.max(200, editor.getViewportPageBounds().width * 0.9)\n\t\t)\n\n\t\tif (rawSize.w > minWidth) {\n\t\t\tconst shrunkSize = editor.textMeasure.measureText(textToPaste, {\n\t\t\t\t...TEXT_PROPS,\n\t\t\t\tfontFamily: FONT_FAMILIES[defaultProps.font],\n\t\t\t\tfontSize: FONT_SIZES[defaultProps.size],\n\t\t\t\tmaxWidth: minWidth,\n\t\t\t})\n\t\t\tw = shrunkSize.w\n\t\t\th = shrunkSize.h\n\t\t\tautoSize = false\n\t\t\talign = isRtl ? 'end' : 'start'\n\t\t} else {\n\t\t\t// autosize is fine\n\t\t\tw = rawSize.w\n\t\t\th = rawSize.h\n\t\t\tautoSize = true\n\t\t}\n\n\t\tif (p.y - h / 2 < editor.getViewportPageBounds().minY + 40) {\n\t\t\tp.y = editor.getViewportPageBounds().minY + 40 + h / 2\n\t\t}\n\n\t\teditor.createShapes<TLTextShape>([\n\t\t\t{\n\t\t\t\tid: createShapeId(),\n\t\t\t\ttype: 'text',\n\t\t\t\tx: p.x - w / 2,\n\t\t\t\ty: p.y - h / 2,\n\t\t\t\tprops: {\n\t\t\t\t\ttext: textToPaste,\n\t\t\t\t\t// if the text has more than one line, align it to the left\n\t\t\t\t\ttextAlign: align,\n\t\t\t\t\tautoSize,\n\t\t\t\t\tw,\n\t\t\t\t},\n\t\t\t},\n\t\t])\n\t})\n\n\t// url\n\teditor.registerExternalContentHandler('url', async ({ point, url }) => {\n\t\t// try to paste as an embed first\n\t\tconst embedUtil = editor.getShapeUtil('embed') as EmbedShapeUtil | undefined\n\t\tconst embedInfo = embedUtil?.getEmbedDefinition(url)\n\n\t\tif (embedInfo) {\n\t\t\treturn editor.putExternalContent({\n\t\t\t\ttype: 'embed',\n\t\t\t\turl: embedInfo.url,\n\t\t\t\tpoint,\n\t\t\t\tembed: embedInfo.definition,\n\t\t\t})\n\t\t}\n\n\t\tconst position =\n\t\t\tpoint ??\n\t\t\t(editor.inputs.shiftKey\n\t\t\t\t? editor.inputs.currentPagePoint\n\t\t\t\t: editor.getViewportPageBounds().center)\n\n\t\tconst assetId: TLAssetId = AssetRecordType.createId(getHashForString(url))\n\t\tconst shape = createEmptyBookmarkShape(editor, url, position)\n\n\t\t// Use an existing asset if we have one, or else else create a new one\n\t\tlet asset = editor.getAsset(assetId) as TLAsset\n\t\tlet shouldAlsoCreateAsset = false\n\t\tif (!asset) {\n\t\t\tshouldAlsoCreateAsset = true\n\t\t\ttry {\n\t\t\t\tconst bookmarkAsset = await editor.getAssetForExternalContent({ type: 'url', url })\n\t\t\t\tif (!bookmarkAsset) throw Error('Could not create an asset')\n\t\t\t\tasset = bookmarkAsset\n\t\t\t} catch {\n\t\t\t\ttoasts.addToast({\n\t\t\t\t\ttitle: msg('assets.url.failed'),\n\t\t\t\t\tseverity: 'error',\n\t\t\t\t})\n\t\t\t\treturn\n\t\t\t}\n\t\t}\n\n\t\teditor.run(() => {\n\t\t\tif (shouldAlsoCreateAsset) {\n\t\t\t\teditor.createAssets([asset])\n\t\t\t}\n\n\t\t\teditor.updateShapes([\n\t\t\t\t{\n\t\t\t\t\tid: shape.id,\n\t\t\t\t\ttype: shape.type,\n\t\t\t\t\tprops: {\n\t\t\t\t\t\tassetId: asset.id,\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t])\n\t\t})\n\t})\n}\n\n/** @public */\nexport async function getMediaAssetInfoPartial(\n\tfile: File,\n\tassetId: TLAssetId,\n\tisImageType: boolean,\n\tisVideoType: boolean\n) {\n\tlet fileType = file.type\n\n\tif (file.type === 'video/quicktime') {\n\t\t// hack to make .mov videos work\n\t\tfileType = 'video/mp4'\n\t}\n\n\tconst size = isImageType\n\t\t? await MediaHelpers.getImageSize(file)\n\t\t: await MediaHelpers.getVideoSize(file)\n\n\tconst isAnimated = (await MediaHelpers.isAnimated(file)) || isVideoType\n\n\tconst assetInfo = {\n\t\tid: assetId,\n\t\ttype: isImageType ? 'image' : 'video',\n\t\ttypeName: 'asset',\n\t\tprops: {\n\t\t\tname: file.name,\n\t\t\tsrc: '',\n\t\t\tw: size.w,\n\t\t\th: size.h,\n\t\t\tfileSize: file.size,\n\t\t\tmimeType: fileType,\n\t\t\tisAnimated,\n\t\t},\n\t\tmeta: {},\n\t} as TLAsset\n\n\treturn assetInfo as TLImageAsset | TLVideoAsset\n}\n\n/**\n * A helper function for an external content handler. It creates bookmarks,\n * images or video shapes corresponding to the type of assets provided.\n *\n * @param editor - The editor instance\n *\n * @param assets - An array of asset Ids\n *\n * @param position - the position at which to create the shapes\n *\n * @public\n */\nexport async function createShapesForAssets(\n\teditor: Editor,\n\tassets: TLAsset[],\n\tposition: VecLike\n): Promise<TLShapeId[]> {\n\tif (!assets.length) return []\n\n\tconst currentPoint = Vec.From(position)\n\tconst partials: TLShapePartial[] = []\n\n\tfor (let i = 0; i < assets.length; i++) {\n\t\tconst asset = assets[i]\n\t\tswitch (asset.type) {\n\t\t\tcase 'image': {\n\t\t\t\tpartials.push({\n\t\t\t\t\tid: createShapeId(),\n\t\t\t\t\ttype: 'image',\n\t\t\t\t\tx: currentPoint.x,\n\t\t\t\t\ty: currentPoint.y,\n\t\t\t\t\topacity: 1,\n\t\t\t\t\tprops: {\n\t\t\t\t\t\tassetId: asset.id,\n\t\t\t\t\t\tw: asset.props.w,\n\t\t\t\t\t\th: asset.props.h,\n\t\t\t\t\t},\n\t\t\t\t})\n\n\t\t\t\tcurrentPoint.x += asset.props.w\n\t\t\t\tbreak\n\t\t\t}\n\t\t\tcase 'video': {\n\t\t\t\tpartials.push({\n\t\t\t\t\tid: createShapeId(),\n\t\t\t\t\ttype: 'video',\n\t\t\t\t\tx: currentPoint.x,\n\t\t\t\t\ty: currentPoint.y,\n\t\t\t\t\topacity: 1,\n\t\t\t\t\tprops: {\n\t\t\t\t\t\tassetId: asset.id,\n\t\t\t\t\t\tw: asset.props.w,\n\t\t\t\t\t\th: asset.props.h,\n\t\t\t\t\t},\n\t\t\t\t})\n\n\t\t\t\tcurrentPoint.x += asset.props.w\n\t\t\t}\n\t\t}\n\t}\n\n\teditor.run(() => {\n\t\t// Create any assets\n\t\tconst assetsToCreate = assets.filter((asset) => !editor.getAsset(asset.id))\n\t\tif (assetsToCreate.length) {\n\t\t\teditor.createAssets(assetsToCreate)\n\t\t}\n\n\t\t// Create the shapes\n\t\teditor.createShapes(partials).select(...partials.map((p) => p.id))\n\n\t\t// Re-position shapes so that the center of the group is at the provided point\n\t\tcenterSelectionAroundPoint(editor, position)\n\t})\n\n\treturn partials.map((p) => p.id)\n}\n\n/**\n * Repositions selected shapes do that the center of the group is\n * at the provided position\n *\n * @param editor - The editor instance\n *\n * @param position - the point to center the shapes around\n *\n * @public\n */\nexport function centerSelectionAroundPoint(editor: Editor, position: VecLike) {\n\t// Re-position shapes so that the center of the group is at the provided point\n\tconst viewportPageBounds = editor.getViewportPageBounds()\n\tlet selectionPageBounds = editor.getSelectionPageBounds()\n\n\tif (selectionPageBounds) {\n\t\tconst offset = selectionPageBounds!.center.sub(position)\n\n\t\teditor.updateShapes(\n\t\t\teditor.getSelectedShapes().map((shape) => {\n\t\t\t\tconst localRotation = editor.getShapeParentTransform(shape).decompose().rotation\n\t\t\t\tconst localDelta = Vec.Rot(offset, -localRotation)\n\t\t\t\treturn {\n\t\t\t\t\tid: shape.id,\n\t\t\t\t\ttype: shape.type,\n\t\t\t\t\tx: shape.x! - localDelta.x,\n\t\t\t\t\ty: shape.y! - localDelta.y,\n\t\t\t\t}\n\t\t\t})\n\t\t)\n\t}\n\tselectionPageBounds = editor.getSelectionPageBounds()\n\t// align selection with the grid if necessary\n\tif (selectionPageBounds && editor.getInstanceState().isGridMode) {\n\t\tconst gridSize = editor.getDocumentSettings().gridSize\n\t\tconst topLeft = new Vec(selectionPageBounds.minX, selectionPageBounds.minY)\n\t\tconst gridSnappedPoint = topLeft.clone().snapToGrid(gridSize)\n\t\tconst delta = Vec.Sub(topLeft, gridSnappedPoint)\n\t\teditor.updateShapes(\n\t\t\teditor.getSelectedShapes().map((shape) => {\n\t\t\t\tconst newPoint = { x: shape.x! - delta.x, y: shape.y! - delta.y }\n\t\t\t\treturn {\n\t\t\t\t\tid: shape.id,\n\t\t\t\t\ttype: shape.type,\n\t\t\t\t\tx: newPoint.x,\n\t\t\t\t\ty: newPoint.y,\n\t\t\t\t}\n\t\t\t})\n\t\t)\n\t}\n\t// Zoom out to fit the shapes, if necessary\n\tselectionPageBounds = editor.getSelectionPageBounds()\n\tif (selectionPageBounds && !viewportPageBounds.contains(selectionPageBounds)) {\n\t\teditor.zoomToSelection({ animation: { duration: editor.options.animationMediumMs } })\n\t}\n}\n\nexport function createEmptyBookmarkShape(\n\teditor: Editor,\n\turl: string,\n\tposition: VecLike\n): TLBookmarkShape {\n\tconst partial: TLShapePartial = {\n\t\tid: createShapeId(),\n\t\ttype: 'bookmark',\n\t\tx: position.x - 150,\n\t\ty: position.y - 160,\n\t\topacity: 1,\n\t\tprops: {\n\t\t\tassetId: null,\n\t\t\turl,\n\t\t},\n\t}\n\n\teditor.run(() => {\n\t\teditor.createShapes([partial]).select(partial.id)\n\t\tcenterSelectionAroundPoint(editor, position)\n\t})\n\n\treturn editor.getShape(partial.id) as TLBookmarkShape\n}\n"],
"mappings": "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",
"names": []
}