diff --git a/docs/.vitepress/items/util.ts b/docs/.vitepress/items/util.ts index 2dda5e4..03e69cb 100644 --- a/docs/.vitepress/items/util.ts +++ b/docs/.vitepress/items/util.ts @@ -16,4 +16,5 @@ export const utilItems = [ { text: 'getAllParentScroller', link: '/util/get-all-parent-scroller' }, { text: 'prettyJSONObject', link: '/util/pretty-JSON-object' }, { text: 'tryParseJSON', link: '/util/try-parse-JSON' }, + { text: 'copyText', link: '/util/copy-text' }, ] diff --git a/docs/util/copy-text.md b/docs/util/copy-text.md new file mode 100644 index 0000000..3e666b3 --- /dev/null +++ b/docs/util/copy-text.md @@ -0,0 +1,23 @@ +# copyText + +Copies text to the clipboard. + +### Usage + +```js +import { copyText } from 'rattail' + +copyText('Hello, clipboard!') // The string will be written to the clipboard +``` + +### Arguments + +| Arg | Type | Defaults | +| ------ | -------- | -------- | +| `text` | `string` | | + +### Return + +| Type | +| ------ | +| `-` | diff --git a/docs/zh/util/copy-text.md b/docs/zh/util/copy-text.md new file mode 100644 index 0000000..71bc38d --- /dev/null +++ b/docs/zh/util/copy-text.md @@ -0,0 +1,23 @@ +# copyText + +复制文本到剪贴板 + +### 用法 + +```js +import { copyText } from 'rattail' + +copyText('Hello, clipboard!') // 字符串会被写入剪切板 +``` + +### 参数 + +| 参数 | 类型 | 默认值 | +| ------ | -------- | ------ | +| `text` | `string` | | + +### 返回值 + +| 类型 | +| ------ | +| `-` | diff --git a/src/util.ts b/src/util.ts index 57b1093..eaca545 100644 --- a/src/util.ts +++ b/src/util.ts @@ -225,3 +225,15 @@ export function createStorage(storage: globalThis.Storage): Storage { export const sessionStorage = createStorage(globalThis.sessionStorage) export const localStorage = createStorage(globalThis.localStorage) + +export function copyText(value: string) { + if (!value) return + const textArea = document.createElement('textarea') + textArea.value = value + textArea.style.position = 'fixed' + textArea.style.opacity = '0' + document.body.appendChild(textArea) + textArea.select() + document.execCommand('copy') + document.body.removeChild(textArea) +} diff --git a/tests/util.spec.ts b/tests/util.spec.ts index 59679ab..bdeff63 100644 --- a/tests/util.spec.ts +++ b/tests/util.spec.ts @@ -17,6 +17,7 @@ import { createStorage, tryParseJSON, prettyJSONObject, + copyText, } from '../src' it('requestAnimationFrame', () => { @@ -244,3 +245,21 @@ describe('JSON utility functions', () => { expect(prettyString).toBe('{\n "key": "value",\n "number": 42\n}') }) }) + +describe('copyText', () => { + it('should copy text successfully', () => { + const execCommandMock = vi.fn().mockImplementation(() => true) + document.execCommand = execCommandMock + copyText('Hello, world!') + expect(execCommandMock).toHaveBeenCalledWith('copy') + execCommandMock.mockRestore() + }) + + it('should not execute copy when no text is provided', () => { + const execCommandMock = vi.fn() + document.execCommand = execCommandMock + copyText('') + expect(execCommandMock).not.toHaveBeenCalled() + execCommandMock.mockRestore() + }) +})