-
-
Notifications
You must be signed in to change notification settings - Fork 2.4k
/
index.ts
122 lines (107 loc) · 3.27 KB
/
index.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
/* this implementation is original ported from https://github.com/logaretm/vue-use-web by Abdelrahman Awad */
import type { MaybeRefOrGetter } from '@vueuse/shared'
import { toValue, useTimeoutFn } from '@vueuse/shared'
import type { ComputedRef, Ref } from 'vue-demi'
import { computed, ref } from 'vue-demi'
import type { WindowEventName } from '../useEventListener'
import { useEventListener } from '../useEventListener'
import { useSupported } from '../useSupported'
import type { ConfigurableNavigator } from '../_configurable'
import { defaultNavigator } from '../_configurable'
export interface UseClipboardOptions<Source> extends ConfigurableNavigator {
/**
* Enabled reading for clipboard
*
* @default false
*/
read?: boolean
/**
* Copy source
*/
source?: Source
/**
* Milliseconds to reset state of `copied` ref
*
* @default 1500
*/
copiedDuring?: number
/**
* Whether fallback to document.execCommand('copy') if clipboard is undefined.
*
* @default false
*/
legacy?: boolean
}
export interface UseClipboardReturn<Optional> {
isSupported: Ref<boolean>
text: ComputedRef<string>
copied: ComputedRef<boolean>
copy: Optional extends true ? (text?: string) => Promise<void> : (text: string) => Promise<void>
}
/**
* Reactive Clipboard API.
*
* @see https://vueuse.org/useClipboard
* @param options
*/
export function useClipboard(options?: UseClipboardOptions<undefined>): UseClipboardReturn<false>
export function useClipboard(options: UseClipboardOptions<MaybeRefOrGetter<string>>): UseClipboardReturn<true>
export function useClipboard(options: UseClipboardOptions<MaybeRefOrGetter<string> | undefined> = {}): UseClipboardReturn<boolean> {
const {
navigator = defaultNavigator,
read = false,
source,
copiedDuring = 1500,
legacy = false,
} = options
const events = ['copy', 'cut']
const isClipboardApiSupported = useSupported(() => (navigator && 'clipboard' in navigator))
const isSupported = computed(() => isClipboardApiSupported.value || legacy)
const text = ref('')
const copied = ref(false)
const timeout = useTimeoutFn(() => copied.value = false, copiedDuring)
function updateText() {
if (isClipboardApiSupported.value) {
navigator!.clipboard.readText().then((value) => {
text.value = value
})
}
else {
text.value = legacyRead()
}
}
if (isSupported.value && read) {
for (const event of events)
useEventListener(event as WindowEventName, updateText)
}
async function copy(value = toValue(source)) {
if (isSupported.value && value != null) {
if (isClipboardApiSupported.value)
await navigator!.clipboard.writeText(value)
else
legacyCopy(value)
text.value = value
copied.value = true
timeout.start()
}
}
function legacyCopy(value: string) {
const ta = document.createElement('textarea')
ta.value = value ?? ''
ta.style.position = 'absolute'
ta.style.opacity = '0'
document.body.appendChild(ta)
ta.select()
document.execCommand('copy')
ta.remove()
}
function legacyRead() {
return document?.getSelection?.()?.toString() ?? ''
}
return {
isSupported,
text: text as ComputedRef<string>,
copied: copied as ComputedRef<boolean>,
copy,
}
}