[fix] iOS safari clipboard / text position (#686)

* use idb for clipboard, too

* Add warnings for firefox

* remove logs

* Update getTextSvgElement.ts
This commit is contained in:
Steve Ruiz 2022-05-14 14:59:47 +01:00 committed by GitHub
parent c3050db968
commit 60e936dfed
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
3 changed files with 53 additions and 31 deletions

View file

@ -0,0 +1,17 @@
import { get, set, del } from 'idb-keyval'
// Used for clipboard
const ID = 'tldraw_clipboard'
export async function getClipboard(): Promise<string | undefined> {
return get(ID)
}
export async function setClipboard(item: string): Promise<void> {
return set(ID, item)
}
export function clearClipboard(): Promise<void> {
return del(ID)
}

View file

@ -80,6 +80,7 @@ import { ArrowTool } from './tools/ArrowTool'
import { StickyTool } from './tools/StickyTool' import { StickyTool } from './tools/StickyTool'
import { StateManager } from './StateManager' import { StateManager } from './StateManager'
import { clearPrevSize } from './shapes/shared/getTextSize' import { clearPrevSize } from './shapes/shared/getTextSize'
import { getClipboard, setClipboard } from './IdbClipboard'
const uuid = Utils.uniqueId() const uuid = Utils.uniqueId()
@ -1778,11 +1779,13 @@ export class TldrawApp extends StateManager<TDSnapshot> {
const tldrawString = `<tldraw>${jsonString}</tldraw>` const tldrawString = `<tldraw>${jsonString}</tldraw>`
setClipboard(tldrawString)
if (e) { if (e) {
e.clipboardData?.setData('text/html', tldrawString) e.clipboardData?.setData('text/html', tldrawString)
} }
if (navigator.clipboard) { if (navigator.clipboard && window.ClipboardItem) {
navigator.clipboard.write([ navigator.clipboard.write([
new ClipboardItem({ new ClipboardItem({
'text/html': new Blob([tldrawString], { type: 'text/html' }), 'text/html': new Blob([tldrawString], { type: 'text/html' }),
@ -1993,6 +1996,12 @@ export class TldrawApp extends StateManager<TDSnapshot> {
} }
} }
getClipboard().then((clipboard) => {
if (clipboard) {
pasteAsHTML(clipboard)
}
})
if (navigator.clipboard) { if (navigator.clipboard) {
const items = await navigator.clipboard.read() const items = await navigator.clipboard.read()
@ -2000,16 +2009,27 @@ export class TldrawApp extends StateManager<TDSnapshot> {
try { try {
for (const item of items) { for (const item of items) {
// First, look for tldraw json in html. // look for png data.
const htmlData = await item.getType('text/html') const pngData = await item.getType('text/png')
if (htmlData) { if (pngData) {
let html = await htmlData.text() const file = new File([pngData], 'image.png')
pasteAsHTML(html) this.addMediaFromFile(file)
return
} }
// Next, look for plain text data. // look for svg data.
const svgData = await item.getType('image/svg+xml')
if (svgData) {
const file = new File([svgData], 'image.svg')
this.addMediaFromFile(file)
return
}
// look for plain text data.
const textData = await item.getType('text/plain') const textData = await item.getType('text/plain')
@ -2026,26 +2046,6 @@ export class TldrawApp extends StateManager<TDSnapshot> {
return return
} }
// Next, look for png data.
const pngData = await item.getType('text/png')
if (pngData) {
const file = new File([pngData], 'image.png')
this.addMediaFromFile(file)
return
}
// Finally, look for svg data.
const svgData = await item.getType('image/svg+xml')
if (svgData) {
const file = new File([svgData], 'image.svg')
this.addMediaFromFile(file)
return
}
} }
} catch (e) { } catch (e) {
// noop // noop
@ -2240,7 +2240,7 @@ export class TldrawApp extends StateManager<TDSnapshot> {
...this.clipboard, ...this.clipboard,
}) })
if (navigator.clipboard) { if (navigator.clipboard && window.ClipboardItem) {
navigator.clipboard.write([ navigator.clipboard.write([
new ClipboardItem({ new ClipboardItem({
'text/html': new Blob([tldrawString], { type: 'text/html' }), 'text/html': new Blob([tldrawString], { type: 'text/html' }),
@ -2356,7 +2356,10 @@ export class TldrawApp extends StateManager<TDSnapshot> {
return return
} }
if (!navigator.clipboard) return if (!(navigator.clipboard && window.ClipboardItem)) {
console.warn('Sorry, your browser does not support copying images.')
return
}
const blob = await this.getImage(format, opts) const blob = await this.getImage(format, opts)

View file

@ -12,10 +12,12 @@ export function getTextSvgElement(text: string, style: ShapeStyles, bounds: TLBo
const textElm = document.createElementNS('http://www.w3.org/2000/svg', 'text') const textElm = document.createElementNS('http://www.w3.org/2000/svg', 'text')
textElm.textContent = line textElm.textContent = line
textElm.setAttribute('y', LINE_HEIGHT * fontSize * (0.5 + i) + '') textElm.setAttribute('y', LINE_HEIGHT * fontSize * (0.5 + i) + '')
textElm.setAttribute('letter-spacing', '-0.03px') textElm.setAttribute('letter-spacing', fontSize * -0.03 + '')
textElm.setAttribute('font-size', fontSize + 'px') textElm.setAttribute('font-size', fontSize + 'px')
textElm.setAttribute('font-family', getFontFace(style.font).slice(1, -1)) textElm.setAttribute('font-family', getFontFace(style.font).slice(1, -1))
textElm.setAttribute('text-align', getTextAlign(style.textAlign)) textElm.setAttribute('text-align', getTextAlign(style.textAlign))
textElm.setAttribute('text-align', getTextAlign(style.textAlign))
textElm.setAttribute('alignment-baseline', 'central')
g.appendChild(textElm) g.appendChild(textElm)
return textElm return textElm
@ -37,8 +39,8 @@ export function getTextSvgElement(text: string, style: ShapeStyles, bounds: TLBo
break break
} }
case AlignStyle.Start: { case AlignStyle.Start: {
g.setAttribute('text-align', 'left')
g.setAttribute('text-anchor', 'start') g.setAttribute('text-anchor', 'start')
g.setAttribute('alignment-baseline', 'central')
} }
} }