Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 1aa50f8

Browse files
Doctor-wuantfu
andauthored
feat(useClipboardItems): new function (#3477)
Co-authored-by: Anthony Fu <[email protected]>
1 parent 3f3f153 commit 1aa50f8

File tree

4 files changed

+182
-0
lines changed

4 files changed

+182
-0
lines changed

packages/core/index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ export * from './useBroadcastChannel'
2121
export * from './useBrowserLocation'
2222
export * from './useCached'
2323
export * from './useClipboard'
24+
export * from './useClipboardItems'
2425
export * from './useCloned'
2526
export * from './useColorMode'
2627
export * from './useConfirmDialog'
Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
<script setup lang="ts">
2+
import { effect, ref } from 'vue'
3+
import { useClipboardItems, usePermission } from '@vueuse/core'
4+
5+
const input = ref('')
6+
7+
const { content, isSupported, copy } = useClipboardItems()
8+
const computedText = ref('')
9+
effect(() => {
10+
Promise.all(content.value.map(item => item.getType('text/html')))
11+
.then((blobs) => {
12+
return Promise.all(blobs.map(blob => blob.text()))
13+
})
14+
.then((texts) => {
15+
computedText.value = texts.join('')
16+
})
17+
})
18+
const permissionRead = usePermission('clipboard-read')
19+
const permissionWrite = usePermission('clipboard-write')
20+
21+
function createClipboardItems(text: string) {
22+
const mime = 'text/html'
23+
const blob = new Blob([text], { type: mime })
24+
return new ClipboardItem({
25+
[mime]: blob,
26+
})
27+
}
28+
</script>
29+
30+
<template>
31+
<div v-if="isSupported">
32+
<note>
33+
Clipboard Permission: read <b>{{ permissionRead }}</b> | write
34+
<b>{{ permissionWrite }}</b>
35+
</note>
36+
<p>
37+
Current copied: <code>{{ (computedText && `${computedText} (mime: text/html)`) || "none" }}</code>
38+
</p>
39+
<input v-model="input" type="text">
40+
<button
41+
@click="
42+
copy([createClipboardItems(input)])
43+
"
44+
>
45+
Copy
46+
</button>
47+
</div>
48+
<p v-else>
49+
Your browser does not support Clipboard API
50+
</p>
51+
</template>
Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
---
2+
category: Browser
3+
related:
4+
- useClipboard
5+
---
6+
7+
# useClipboardItems
8+
9+
Reactive [Clipboard API](https://developer.mozilla.org/en-US/docs/Web/API/Clipboard_API). Provides the ability to respond to clipboard commands (cut, copy, and paste) as well as to asynchronously read from and write to the system clipboard. Access to the contents of the clipboard is gated behind the [Permissions API](https://developer.mozilla.org/en-US/docs/Web/API/Permissions_API). Without user permission, reading or altering the clipboard contents is not permitted.
10+
11+
## Difference from `useClipboard`
12+
13+
`useClipboard` is a "text-only" function, while `useClipboardItems` is a [ClipboardItem](https://developer.mozilla.org/en-US/docs/Web/API/ClipboardItem) based function. You can use `useClipboardItems` to copy any content supported by [ClipboardItem](https://developer.mozilla.org/en-US/docs/Web/API/ClipboardItem).
14+
15+
## Usage
16+
17+
```js
18+
import { useClipboardItems } from '@vueuse/core'
19+
20+
const mime = 'text/html'
21+
const source = ref([
22+
new ClipboardItem({
23+
[mime]: new Blob(['\'<b>HTML content</b>\'', { type: mime }]),
24+
})
25+
])
26+
27+
const { content, copy, copied, isSupported } = useClipboardItems({ source })
28+
```
29+
30+
```html
31+
<div v-if="isSupported">
32+
<button @click='copy(source)'>
33+
<!-- by default, `copied` will be reset in 1.5s -->
34+
<span v-if='!copied'>Copy</span>
35+
<span v-else>Copied!</span>
36+
</button>
37+
<p>
38+
Current copied: <code>{{ text || 'none' }}</code>
39+
</p>
40+
</div>
41+
<p v-else>
42+
Your browser does not support Clipboard API
43+
</p>
44+
```
Lines changed: 86 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,86 @@
1+
import type { MaybeRefOrGetter } from '@vueuse/shared'
2+
import { toValue, useTimeoutFn } from '@vueuse/shared'
3+
import type { ComputedRef, Ref } from 'vue-demi'
4+
import { ref } from 'vue-demi'
5+
import { useEventListener } from '../useEventListener'
6+
import { useSupported } from '../useSupported'
7+
import type { ConfigurableNavigator } from '../_configurable'
8+
import { defaultNavigator } from '../_configurable'
9+
10+
export interface UseClipboardItemsOptions<Source> extends ConfigurableNavigator {
11+
/**
12+
* Enabled reading for clipboard
13+
*
14+
* @default false
15+
*/
16+
read?: boolean
17+
18+
/**
19+
* Copy source
20+
*/
21+
source?: Source
22+
23+
/**
24+
* Milliseconds to reset state of `copied` ref
25+
*
26+
* @default 1500
27+
*/
28+
copiedDuring?: number
29+
}
30+
31+
export interface UseClipboardItemsReturn<Optional> {
32+
isSupported: Ref<boolean>
33+
content: ComputedRef<ClipboardItems>
34+
copied: ComputedRef<boolean>
35+
copy: Optional extends true ? (content?: ClipboardItems) => Promise<void> : (text: ClipboardItems) => Promise<void>
36+
}
37+
38+
/**
39+
* Reactive Clipboard API.
40+
*
41+
* @see https://vueuse.org/useClipboardItems
42+
* @param options
43+
*/
44+
export function useClipboardItems(options?: UseClipboardItemsOptions<undefined>): UseClipboardItemsReturn<false>
45+
export function useClipboardItems(options: UseClipboardItemsOptions<MaybeRefOrGetter<ClipboardItems>>): UseClipboardItemsReturn<true>
46+
export function useClipboardItems(options: UseClipboardItemsOptions<MaybeRefOrGetter<ClipboardItems> | undefined> = {}): UseClipboardItemsReturn<boolean> {
47+
const {
48+
navigator = defaultNavigator,
49+
read = false,
50+
source,
51+
copiedDuring = 1500,
52+
} = options
53+
54+
const isSupported = useSupported(() => (navigator && 'clipboard' in navigator))
55+
const content = ref<ClipboardItems>([])
56+
const copied = ref(false)
57+
const timeout = useTimeoutFn(() => copied.value = false, copiedDuring)
58+
59+
function updateContent() {
60+
if (isSupported.value) {
61+
navigator!.clipboard.read().then((items) => {
62+
content.value = items
63+
})
64+
}
65+
}
66+
67+
if (isSupported.value && read)
68+
useEventListener(['copy', 'cut'], updateContent)
69+
70+
async function copy(value = toValue(source)) {
71+
if (isSupported.value && value != null) {
72+
await navigator!.clipboard.write(value)
73+
74+
content.value = value
75+
copied.value = true
76+
timeout.start()
77+
}
78+
}
79+
80+
return {
81+
isSupported,
82+
content: content as ComputedRef<ClipboardItems>,
83+
copied: copied as ComputedRef<boolean>,
84+
copy,
85+
}
86+
}

0 commit comments

Comments
 (0)