{ "version": 3, "sources": ["../../../../src/lib/ui/hooks/useCopyAs.ts"], "sourcesContent": ["import { Editor, TLShapeId, useEditor } from '@tldraw/editor'\nimport { useCallback } from 'react'\nimport { TLCopyType, getSvgAsImage, getSvgAsString } from '../../utils/export'\nimport { useToasts } from './useToastsProvider'\nimport { useTranslation } from './useTranslation/useTranslation'\n\n/** @public */\nexport function useCopyAs() {\n\tconst editor = useEditor()\n\tconst { addToast } = useToasts()\n\tconst msg = useTranslation()\n\n\treturn useCallback(\n\t\t// it's important that this function itself isn't async - we need to\n\t\t// create the relevant `ClipboardItem`s synchronously to make sure\n\t\t// safari knows that the user _wants_ to copy:\n\t\t// https://bugs.webkit.org/show_bug.cgi?id=222262\n\t\t//\n\t\t// this is fine for navigator.clipboard.write, but for fallbacks it's a\n\t\t// little awkward.\n\t\tfunction copyAs(ids: TLShapeId[] = editor.selectedShapeIds, format: TLCopyType = 'svg') {\n\t\t\tif (ids.length === 0) {\n\t\t\t\tids = [...editor.currentPageShapeIds]\n\t\t\t}\n\n\t\t\tif (ids.length === 0) {\n\t\t\t\treturn\n\t\t\t}\n\n\t\t\tswitch (format) {\n\t\t\t\tcase 'svg': {\n\t\t\t\t\tif (window.navigator.clipboard) {\n\t\t\t\t\t\tif (window.navigator.clipboard.write) {\n\t\t\t\t\t\t\twindow.navigator.clipboard.write([\n\t\t\t\t\t\t\t\tnew ClipboardItem({\n\t\t\t\t\t\t\t\t\t'text/plain': getExportedSvgBlob(editor, ids),\n\t\t\t\t\t\t\t\t}),\n\t\t\t\t\t\t\t])\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\tfallbackWriteTextAsync(async () =>\n\t\t\t\t\t\t\t\tgetSvgAsString(await getExportSvgElement(editor, ids))\n\t\t\t\t\t\t\t)\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\tbreak\n\t\t\t\t}\n\n\t\t\t\tcase 'jpeg':\n\t\t\t\tcase 'png': {\n\t\t\t\t\tconst mimeType = format === 'jpeg' ? 'image/jpeg' : 'image/png'\n\t\t\t\t\tconst blobPromise = getExportedImageBlob(editor, ids, format).then((blob) => {\n\t\t\t\t\t\tif (blob) {\n\t\t\t\t\t\t\tif (window.navigator.clipboard) {\n\t\t\t\t\t\t\t\treturn blob\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tthrow new Error('Copy not supported')\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\taddToast({\n\t\t\t\t\t\t\t\tid: 'copy-fail',\n\t\t\t\t\t\t\t\ticon: 'warning-triangle',\n\t\t\t\t\t\t\t\ttitle: msg('toast.error.copy-fail.title'),\n\t\t\t\t\t\t\t\tdescription: msg('toast.error.copy-fail.desc'),\n\t\t\t\t\t\t\t})\n\t\t\t\t\t\t\tthrow new Error('Copy not possible')\n\t\t\t\t\t\t}\n\t\t\t\t\t})\n\n\t\t\t\t\twindow.navigator.clipboard\n\t\t\t\t\t\t.write([\n\t\t\t\t\t\t\tnew ClipboardItem({\n\t\t\t\t\t\t\t\t// Note: This needs to use the promise based approach for safari/ios to not bail on a permissions error.\n\t\t\t\t\t\t\t\t[mimeType]: blobPromise,\n\t\t\t\t\t\t\t}),\n\t\t\t\t\t\t])\n\t\t\t\t\t\t.catch((err: any) => {\n\t\t\t\t\t\t\t// Firefox will fail with the above if `dom.events.asyncClipboard.clipboardItem` is enabled.\n\t\t\t\t\t\t\t// See \n\t\t\t\t\t\t\tif (!err.toString().match(/^TypeError: DOMString not supported/)) {\n\t\t\t\t\t\t\t\tconsole.error(err)\n\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\tblobPromise.then((blob) => {\n\t\t\t\t\t\t\t\twindow.navigator.clipboard.write([\n\t\t\t\t\t\t\t\t\tnew ClipboardItem({\n\t\t\t\t\t\t\t\t\t\t// Note: This needs to use the promise based approach for safari/ios to not bail on a permissions error.\n\t\t\t\t\t\t\t\t\t\t[mimeType]: blob,\n\t\t\t\t\t\t\t\t\t}),\n\t\t\t\t\t\t\t\t])\n\t\t\t\t\t\t\t})\n\t\t\t\t\t\t})\n\n\t\t\t\t\tbreak\n\t\t\t\t}\n\n\t\t\t\tcase 'json': {\n\t\t\t\t\tconst data = editor.getContentFromCurrentPage(ids)\n\n\t\t\t\t\tif (window.navigator.clipboard) {\n\t\t\t\t\t\tconst jsonStr = JSON.stringify(data)\n\n\t\t\t\t\t\tif (window.navigator.clipboard.write) {\n\t\t\t\t\t\t\twindow.navigator.clipboard.write([\n\t\t\t\t\t\t\t\tnew ClipboardItem({\n\t\t\t\t\t\t\t\t\t'text/plain': new Blob([jsonStr], { type: 'text/plain' }),\n\t\t\t\t\t\t\t\t}),\n\t\t\t\t\t\t\t])\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\tfallbackWriteTextAsync(async () => jsonStr)\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\tbreak\n\t\t\t\t}\n\n\t\t\t\tdefault:\n\t\t\t\t\tthrow new Error(`Copy type ${format} not supported.`)\n\t\t\t}\n\t\t},\n\t\t[editor, addToast, msg]\n\t)\n}\n\nasync function getExportSvgElement(editor: Editor, ids: TLShapeId[]) {\n\tconst svg = await editor.getSvg(ids, {\n\t\tscale: 1,\n\t\tbackground: editor.instanceState.exportBackground,\n\t})\n\n\tif (!svg) throw new Error('Could not construct SVG.')\n\n\treturn svg\n}\n\nasync function getExportedSvgBlob(editor: Editor, ids: TLShapeId[]) {\n\treturn new Blob([getSvgAsString(await getExportSvgElement(editor, ids))], {\n\t\ttype: 'text/plain',\n\t})\n}\n\nasync function getExportedImageBlob(editor: Editor, ids: TLShapeId[], format: 'png' | 'jpeg') {\n\treturn await getSvgAsImage(await getExportSvgElement(editor, ids), {\n\t\ttype: format,\n\t\tquality: 1,\n\t\tscale: 2,\n\t})\n}\n\nasync function fallbackWriteTextAsync(getText: () => Promise) {\n\tif (!(navigator && navigator.clipboard)) return\n\tnavigator.clipboard.writeText(await getText())\n}\n"], "mappings": "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", "names": [] }