You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
68 lines
1.6 KiB
68 lines
1.6 KiB
import { ref, watch } from 'vue' |
|
|
|
import { isDef } from '@/utils/is' |
|
interface Options { |
|
target?: HTMLElement |
|
} |
|
export function useCopyToClipboard(initial?: string) { |
|
const clipboardRef = ref(initial || '') |
|
const isSuccessRef = ref(false) |
|
const copiedRef = ref(false) |
|
|
|
watch( |
|
clipboardRef, |
|
(str?: string) => { |
|
if (isDef(str)) { |
|
copiedRef.value = true |
|
isSuccessRef.value = copyTextToClipboard(str) |
|
} |
|
}, |
|
{ immediate: !!initial, flush: 'sync' } |
|
) |
|
|
|
return { clipboardRef, isSuccessRef, copiedRef } |
|
} |
|
|
|
export function copyTextToClipboard(input: string, { target = document.body }: Options = {}) { |
|
const element = document.createElement('textarea') |
|
const previouslyFocusedElement = document.activeElement |
|
|
|
element.value = input |
|
|
|
element.setAttribute('readonly', '') |
|
;(element.style as any).contain = 'strict' |
|
element.style.position = 'absolute' |
|
element.style.left = '-9999px' |
|
element.style.fontSize = '12pt' |
|
|
|
const selection = document.getSelection() |
|
let originalRange |
|
if (selection && selection.rangeCount > 0) { |
|
originalRange = selection.getRangeAt(0) |
|
} |
|
|
|
target.append(element) |
|
element.select() |
|
|
|
element.selectionStart = 0 |
|
element.selectionEnd = input.length |
|
|
|
let isSuccess = false |
|
try { |
|
isSuccess = document.execCommand('copy') |
|
} catch (e: any) { |
|
throw new Error(e) |
|
} |
|
|
|
element.remove() |
|
|
|
if (originalRange && selection) { |
|
selection.removeAllRanges() |
|
selection.addRange(originalRange) |
|
} |
|
|
|
if (previouslyFocusedElement) { |
|
;(previouslyFocusedElement as HTMLElement).focus() |
|
} |
|
return isSuccess |
|
}
|
|
|