├── .babelrc
├── .editorconfig
├── .eslintrc.js
├── .github
└── workflows
│ ├── build.yml
│ └── publish.yml
├── .gitignore
├── .prettierrc.js
├── LICENSE
├── README.md
├── api-extractor.json
├── example
└── vue3-clipboard-example
│ ├── .gitignore
│ ├── index.html
│ ├── package.json
│ ├── public
│ └── favicon.ico
│ └── src
│ ├── App.vue
│ ├── assets
│ └── logo.png
│ ├── components
│ └── HelloWorld.vue
│ ├── index.css
│ └── main.js
├── package-lock.json
├── package.json
├── rollup.config.js
├── src
├── @types
│ └── index.ts
├── VueClipboard.ts
└── index.ts
├── tsconfig.json
└── vite.config.js
/.babelrc:
--------------------------------------------------------------------------------
1 | {
2 | "presets": ["es2015"],
3 | "env": {
4 | "production": {
5 | "presets": ["minify"]
6 | }
7 | }
8 | }
9 |
--------------------------------------------------------------------------------
/.editorconfig:
--------------------------------------------------------------------------------
1 | root = true
2 |
3 | [*]
4 | charset = utf-8
5 | indent_style = space
6 | indent_size = 2
7 | end_of_line = lf
8 | insert_final_newline = true
9 | trim_trailing_whitespace = true
10 |
--------------------------------------------------------------------------------
/.eslintrc.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | parser: '@typescript-eslint/parser',
3 | parserOptions: {
4 | ecmaVersion: 2020,
5 | sourceType: 'module',
6 | },
7 | extends: [
8 | 'plugin:@typescript-eslint/recommended',
9 | 'prettier/@typescript-eslint',
10 | 'plugin:prettier/recommended',
11 | ],
12 | rules: {},
13 | }
14 |
--------------------------------------------------------------------------------
/.github/workflows/build.yml:
--------------------------------------------------------------------------------
1 | name: Build
2 |
3 | on: [push, pull_request]
4 |
5 | jobs:
6 | build:
7 | runs-on: ubuntu-latest
8 | steps:
9 | - uses: actions/checkout@v2
10 | - uses: actions/setup-node@v1
11 | with:
12 | node-version: 12
13 | registry-url: https://registry.npmjs.org/
14 | - run: npm install
15 | - run: npm run-script build
16 |
--------------------------------------------------------------------------------
/.github/workflows/publish.yml:
--------------------------------------------------------------------------------
1 | name: Publish
2 |
3 | on:
4 | release:
5 | types: [published]
6 |
7 | jobs:
8 | build:
9 | runs-on: ubuntu-latest
10 | steps:
11 | - uses: actions/checkout@v2
12 | - uses: actions/setup-node@v1
13 | with:
14 | node-version: 12
15 | registry-url: https://registry.npmjs.org/
16 | - run: npm install
17 | - run: npm run build
18 | - run: npm run build:dts
19 | - run: npm publish --access public
20 | env:
21 | NODE_AUTH_TOKEN: ${{secrets.NPM_TOKEN}}
22 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | .vscode
2 | node_modules
3 | coverage
4 | npm-debug.log
5 | .nyc_output
6 | dist
7 | package-lock.json
8 | .DS_Store
9 | demo_dist
10 |
--------------------------------------------------------------------------------
/.prettierrc.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | singleQuote: true,
3 | trailingComma: 'all',
4 | tabWidth: 2,
5 | semi: false,
6 | }
7 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2020 Soren Martius
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # vue3-clipboard
2 |
3 | **Note:** I don't maintain this repository anymore. Instead I recommend using [vueuse](https://vueuse.org/core/useClipboard/#useclipboard).
4 |
5 |
6 | 
7 |
8 | [Clipboard.js](https://clipboardjs.com/) bindings for Vue 3.
9 |
10 | This repository is a port of Inndy's
11 | [vue-clipboard2](https://github.com/Inndy/vue-clipboard2) plugin for Vue3.
12 |
13 | ## Install
14 |
15 | `npm install --save @soerenmartius/vue3-clipboard`
16 |
17 | ## Usage
18 |
19 | ### Import the `v-clipboard` directive globally
20 |
21 | **`src/main.ts`**
22 |
23 | ```typescript
24 | import { createApp } from 'vue'
25 | import App from './App.vue'
26 | import { VueClipboard } from '@soerenmartius/vue3-clipboard'
27 |
28 | createApp(App).use(VueClipboard).mount('#app')
29 |
30 | ```
31 |
32 | ### Import the `v-clipboard` directive for a specific component
33 |
34 | ## Examples
35 |
36 | ### Apply the v-clipboard directive to an element
37 |
38 | ```typescript
39 |
40 |
41 |
42 |
43 |
44 |
55 | ```
56 |
57 | ### Copy value of an input, and handle events separately.
58 |
59 | ```typescript
60 |
61 |
62 |
69 |
70 |
71 |
90 | ```
91 |
92 | ### Standalone usage of the toClipboard function
93 |
94 | ```typescript
95 |
96 |
97 |
98 |
99 |
100 |
113 | ```
114 |
115 | ## Contributing
116 |
117 | Contributions are always encouraged and welcome!
118 | For the process of accepting changes, we use
119 | [Pull Requests](https://github.com/soerenmartius/vue3-clipboard/pulls).
120 | For feature requests please fill an
121 | [issue](https://github.com/soerenmartius/vue3-clipboard/issues/new).
122 |
123 | ## License
124 |
125 | [](https://opensource.org/licenses/MIT)
126 |
--------------------------------------------------------------------------------
/api-extractor.json:
--------------------------------------------------------------------------------
1 | {
2 | "$schema": "https://developer.microsoft.com/json-schemas/api-extractor/v7/api-extractor.schema.json",
3 | "mainEntryPointFilePath": "./dist/src/index.d.ts",
4 | "apiReport": {
5 | "enabled": true,
6 | "reportFolder": "/temp/"
7 | },
8 | "docModel": {
9 | "enabled": true
10 | },
11 | "dtsRollup": {
12 | "enabled": true,
13 | "untrimmedFilePath": "./dist/.d.ts"
14 | },
15 | "tsdocMetadata": {
16 | "enabled": false
17 | },
18 | "messages": {
19 | "compilerMessageReporting": {
20 | "default": {
21 | "logLevel": "warning"
22 | }
23 | },
24 | "extractorMessageReporting": {
25 | "default": {
26 | "logLevel": "warning",
27 | "addToApiReportFile": true
28 | },
29 | "ae-missing-release-tag": {
30 | "logLevel": "none"
31 | }
32 | },
33 | "tsdocMessageReporting": {
34 | "default": {
35 | "logLevel": "warning"
36 | }
37 | }
38 | }
39 | }
40 |
--------------------------------------------------------------------------------
/example/vue3-clipboard-example/.gitignore:
--------------------------------------------------------------------------------
1 | node_modules
2 | .DS_Store
3 | dist
4 | dist-ssr
5 | *.local
--------------------------------------------------------------------------------
/example/vue3-clipboard-example/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 | Vite App
8 |
9 |
10 |
11 |
12 |
13 |
14 |
--------------------------------------------------------------------------------
/example/vue3-clipboard-example/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "vue3-clipboard-example",
3 | "version": "0.0.0",
4 | "scripts": {
5 | "dev": "vite",
6 | "build": "vite build"
7 | },
8 | "dependencies": {
9 | "vue": "^3.0.4",
10 | "vue3-clipboard": "^1.0.0"
11 | },
12 | "devDependencies": {
13 | "@vue/compiler-sfc": "^3.0.4",
14 | "vite": "^1.0.0-rc.13"
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/example/vue3-clipboard-example/public/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/soerenmartius/vue3-clipboard/157b4ed54529c10eb21351afaa535894a3123934/example/vue3-clipboard-example/public/favicon.ico
--------------------------------------------------------------------------------
/example/vue3-clipboard-example/src/App.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
16 |
--------------------------------------------------------------------------------
/example/vue3-clipboard-example/src/assets/logo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/soerenmartius/vue3-clipboard/157b4ed54529c10eb21351afaa535894a3123934/example/vue3-clipboard-example/src/assets/logo.png
--------------------------------------------------------------------------------
/example/vue3-clipboard-example/src/components/HelloWorld.vue:
--------------------------------------------------------------------------------
1 |
2 | {{ msg }}
3 |
4 |
5 |
6 |
15 |
--------------------------------------------------------------------------------
/example/vue3-clipboard-example/src/index.css:
--------------------------------------------------------------------------------
1 | #app {
2 | font-family: Avenir, Helvetica, Arial, sans-serif;
3 | -webkit-font-smoothing: antialiased;
4 | -moz-osx-font-smoothing: grayscale;
5 | text-align: center;
6 | color: #2c3e50;
7 | margin-top: 60px;
8 | }
9 |
--------------------------------------------------------------------------------
/example/vue3-clipboard-example/src/main.js:
--------------------------------------------------------------------------------
1 | import { createApp } from 'vue'
2 | import App from './App.vue'
3 | import VueClipboard from '@soerenmartius/vue3-clipboard'
4 | import './index.css'
5 |
6 | createApp(App).use(VueClipboard).mount('#app')
7 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "@soerenmartius/vue3-clipboard",
3 | "version": "0.1.2",
4 | "description": "A Vue 3 binding for clipboard.js",
5 | "main": "dist/vue3-clipboard.cjs.js",
6 | "browser": "dist/vue3-clipboard.esm.js",
7 | "unpkg": "dist/vue3-clipboard.global.js",
8 | "jsdelivr": "dist/vue3-clipboard.global.js",
9 | "module": "dist/vue3-clipboard.esm-bundler.js",
10 | "types": "dist/vue3-clipboard.d.ts",
11 | "sideEffects": false,
12 | "files": [
13 | "dist/*.js",
14 | "dist/vue3-clipboard.d.ts",
15 | "LICENSE",
16 | "README.md"
17 | ],
18 | "scripts": {
19 | "build": "rollup -c rollup.config.js",
20 | "dev": "vite serve",
21 | "start": "vite serve --mode production",
22 | "demo:build": "vite build",
23 | "release": "bash scripts/release.sh",
24 | "build:dts": "api-extractor run --local --verbose",
25 | "lint": "eslint './{src,tests,examples}/**/*.{js,ts,tsx,vue,md}'",
26 | "lint:fix": "yarn run lint --fix",
27 | "test:types": "tsc --build tsconfig.json"
28 | },
29 | "repository": {
30 | "type": "git",
31 | "url": "git+https://github.com/soerenmartius/vue3-clipboard.git"
32 | },
33 | "keywords": [
34 | "vue",
35 | "vue3",
36 | "clipboard",
37 | "clipboard.js"
38 | ],
39 | "author": {
40 | "name": "Soeren Martius",
41 | "email": "soeren.martius@gmail.com"
42 | },
43 | "license": "MIT",
44 | "bugs": {
45 | "url": "https://github.com/soerenmartius/vue3-clipboard/issues"
46 | },
47 | "homepage": "https://github.com/soerenmartius/vue3-clipboard#readme",
48 | "husky": {
49 | "hooks": {
50 | "pre-commit": "lint-staged"
51 | }
52 | },
53 | "lint-staged": {
54 | "*.js": [
55 | "prettier --write"
56 | ],
57 | "*.ts?(x)": [
58 | "prettier --parser=typescript --write"
59 | ]
60 | },
61 | "peerDependecies": {
62 | "vue": "^3.0.0"
63 | },
64 | "dependencies": {
65 | "clipboard": "^2.0.0"
66 | },
67 | "devDependencies": {
68 | "@microsoft/api-extractor": "^7.12.0",
69 | "@rollup/plugin-alias": "^3.1.1",
70 | "@rollup/plugin-commonjs": "^16.0.0",
71 | "@rollup/plugin-node-resolve": "^10.0.0",
72 | "@rollup/plugin-replace": "^2.3.3",
73 | "@size-limit/preset-small-lib": "^4.9.0",
74 | "@types/clipboard": "^2.0.1",
75 | "@types/jest": "^26.0.19",
76 | "@typescript-eslint/eslint-plugin": "^4.11.0",
77 | "@typescript-eslint/parser": "^4.11.0",
78 | "chalk": "^4.1.0",
79 | "eslint": "^7.16.0",
80 | "eslint-config-prettier": "^7.1.0",
81 | "eslint-config-standard": "^16.0.2",
82 | "eslint-plugin-import": ">=2.22.0",
83 | "eslint-plugin-node": ">=11.1.0",
84 | "eslint-plugin-prettier": "^3.3.0",
85 | "eslint-plugin-promise": ">=4.2.0",
86 | "eslint-plugin-standard": "^4.0.2",
87 | "husky": "^4.3.6",
88 | "lint-staged": "^10.5.3",
89 | "prettier": "^2.2.1",
90 | "rollup": "^2.35.1",
91 | "rollup-plugin-terser": "^7.0.2",
92 | "rollup-plugin-typescript2": "^0.29.0",
93 | "typescript": "^4.1.2",
94 | "vite": "^1.0.0-rc.13",
95 | "vue": "^3.0.3",
96 | "vue-jest": "^3.0.7"
97 | }
98 | }
99 |
--------------------------------------------------------------------------------
/rollup.config.js:
--------------------------------------------------------------------------------
1 | import path from 'path'
2 | import ts from 'rollup-plugin-typescript2'
3 | import replace from '@rollup/plugin-replace'
4 | import resolve from '@rollup/plugin-node-resolve'
5 | import commonjs from '@rollup/plugin-commonjs'
6 | import pascalcase from 'pascalcase'
7 |
8 | const pkg = require('./package.json')
9 | const name = pkg.name
10 |
11 | function getAuthors(pkg) {
12 | const { contributors, author } = pkg
13 |
14 | const authors = new Set()
15 | if (contributors && contributors)
16 | contributors.forEach((contributor) => {
17 | authors.add(contributor.name)
18 | })
19 | if (author) authors.add(author.name)
20 |
21 | return Array.from(authors).join(', ')
22 | }
23 |
24 | const banner = `/*!
25 | * ${pkg.name} v${pkg.version}
26 | * (c) ${new Date().getFullYear()} ${getAuthors(pkg)}
27 | * @license MIT
28 | */`
29 |
30 | // ensure TS checks only once for each build
31 | let hasTSChecked = false
32 |
33 | const outputConfigs = {
34 | // each file name has the format: `dist/${name}.${format}.js`
35 | // format being a key of this object
36 | 'esm-bundler': {
37 | file: pkg.module,
38 | format: `es`,
39 | },
40 | cjs: {
41 | file: pkg.main,
42 | format: `cjs`,
43 | },
44 | global: {
45 | file: pkg.unpkg,
46 | format: `iife`,
47 | },
48 | esm: {
49 | file: pkg.browser,
50 | format: `es`,
51 | },
52 | }
53 |
54 | const allFormats = Object.keys(outputConfigs)
55 | const packageFormats = allFormats
56 | const packageConfigs = packageFormats.map((format) =>
57 | createConfig(format, outputConfigs[format]),
58 | )
59 |
60 | // only add the production ready if we are bundling the options
61 | packageFormats.forEach((format) => {
62 | if (format === 'cjs') {
63 | packageConfigs.push(createProductionConfig(format))
64 | } else if (format === 'global') {
65 | packageConfigs.push(createMinifiedConfig(format))
66 | }
67 | })
68 |
69 | export default packageConfigs
70 |
71 | function createConfig(format, output, plugins = []) {
72 | if (!output) {
73 | console.log(require('chalk').yellow(`invalid format: "${format}"`))
74 | process.exit(1)
75 | }
76 |
77 | output.sourcemap = !!process.env.SOURCE_MAP
78 | output.banner = banner
79 | output.externalLiveBindings = false
80 | output.globals = { vue: 'Vue' }
81 |
82 | const isProductionBuild = /\.prod\.js$/.test(output.file)
83 | const isGlobalBuild = format === 'global'
84 | const isRawESMBuild = format === 'esm'
85 | const isNodeBuild = format === 'cjs'
86 | const isBundlerESMBuild = /esm-bundler/.test(format)
87 |
88 | if (isGlobalBuild) output.name = pascalcase(pkg.name)
89 |
90 | const shouldEmitDeclarations = !hasTSChecked
91 |
92 | const tsPlugin = ts({
93 | check: !hasTSChecked,
94 | tsconfig: path.resolve(__dirname, 'tsconfig.json'),
95 | cacheRoot: path.resolve(__dirname, 'node_modules/.rts2_cache'),
96 | tsconfigOverride: {
97 | compilerOptions: {
98 | sourceMap: output.sourcemap,
99 | declaration: shouldEmitDeclarations,
100 | declarationMap: shouldEmitDeclarations,
101 | },
102 | exclude: ['__tests__', 'test-dts'],
103 | },
104 | })
105 | // we only need to check TS and generate declarations once for each build.
106 | // it also seems to run into weird issues when checking multiple times
107 | // during a single build.
108 | hasTSChecked = true
109 |
110 | const external = ['vue']
111 |
112 | const nodePlugins = [resolve(), commonjs()]
113 |
114 | return {
115 | input: `src/index.ts`,
116 | // Global and Browser ESM builds inlines everything so that they can be
117 | // used alone.
118 | external,
119 | plugins: [
120 | tsPlugin,
121 | createReplacePlugin(
122 | isProductionBuild,
123 | isBundlerESMBuild,
124 | // isBrowserBuild?
125 | isGlobalBuild || isRawESMBuild || isBundlerESMBuild,
126 | isGlobalBuild,
127 | isNodeBuild,
128 | ),
129 | ...nodePlugins,
130 | ...plugins,
131 | ],
132 | output,
133 | // onwarn: (msg, warn) => {
134 | // if (!/Circular/.test(msg)) {
135 | // warn(msg)
136 | // }
137 | // },
138 | }
139 | }
140 |
141 | function createReplacePlugin(
142 | isProduction,
143 | isBundlerESMBuild,
144 | isBrowserBuild,
145 | isGlobalBuild,
146 | isNodeBuild,
147 | ) {
148 | const replacements = {
149 | __COMMIT__: `"${process.env.COMMIT}"`,
150 | __VERSION__: `"${pkg.version}"`,
151 | __DEV__: isBundlerESMBuild
152 | ? // preserve to be handled by bundlers
153 | `(process.env.NODE_ENV !== 'production')`
154 | : // hard coded dev/prod builds
155 | !isProduction,
156 | // this is only used during tests
157 | __TEST__: isBundlerESMBuild ? `(process.env.NODE_ENV === 'test')` : false,
158 | // If the build is expected to run directly in the browser (global / esm builds)
159 | __BROWSER__: isBrowserBuild,
160 | // is targeting bundlers?
161 | __BUNDLER__: isBundlerESMBuild,
162 | __GLOBAL__: isGlobalBuild,
163 | // is targeting Node (SSR)?
164 | __NODE_JS__: isNodeBuild,
165 | }
166 | // allow inline overrides like
167 | //__RUNTIME_COMPILE__=true yarn build
168 | Object.keys(replacements).forEach((key) => {
169 | if (key in process.env) {
170 | replacements[key] = process.env[key]
171 | }
172 | })
173 | return replace(replacements)
174 | }
175 |
176 | function createProductionConfig(format) {
177 | return createConfig(format, {
178 | file: `dist/${name}.${format}.prod.js`,
179 | format: outputConfigs[format].format,
180 | })
181 | }
182 |
183 | function createMinifiedConfig(format) {
184 | const { terser } = require('rollup-plugin-terser')
185 | return createConfig(
186 | format,
187 | {
188 | file: `dist/${name}.${format}.prod.js`,
189 | format: outputConfigs[format].format,
190 | },
191 | [
192 | terser({
193 | module: /^esm/.test(format),
194 | compress: {
195 | ecma: 2015,
196 | pure_getters: true,
197 | },
198 | }),
199 | ],
200 | )
201 | }
202 |
--------------------------------------------------------------------------------
/src/@types/index.ts:
--------------------------------------------------------------------------------
1 | export type Actions = 'copy' | 'cut'
2 |
3 | export interface ClipboardConfig {
4 | autoSetContainer: boolean
5 | appendToBody: boolean
6 | }
7 |
--------------------------------------------------------------------------------
/src/VueClipboard.ts:
--------------------------------------------------------------------------------
1 | import { App } from 'vue'
2 |
3 | import { Actions, ClipboardConfig } from './@types'
4 | import ClipboardJS from 'clipboard'
5 |
6 | export interface IVueClipboard {
7 | /**
8 | * Set global config
9 | */
10 | config(config: ClipboardConfig): void
11 |
12 | /**
13 | * Copy string to clipboard
14 | */
15 | toClipboard(text: string, action: Actions): Promise
16 |
17 | install(app: App): void
18 | }
19 |
20 | const defaultConfig = {
21 | autoSetContainer: false,
22 | appendToBody: true,
23 | }
24 |
25 | export const VueClipboard: IVueClipboard = {
26 | config: (options: ClipboardConfig) => {
27 | const { autoSetContainer, appendToBody } = options
28 |
29 | defaultConfig.autoSetContainer = autoSetContainer ? autoSetContainer : false
30 | defaultConfig.appendToBody = appendToBody ? appendToBody : true
31 | },
32 | install: (app: App) => {
33 | app.config.globalProperties.$vclipboard = toClipboard
34 |
35 | app.directive('clipboard', {
36 | beforeMount(el, binding) {
37 | if (binding.arg === 'success') {
38 | el._vClipboard_success = binding.value
39 | } else if (binding.arg === 'error') {
40 | el._vClipboard_error = binding.value
41 | } else {
42 | const clipboard = new ClipboardJS(el, {
43 | text: () => binding.value,
44 | action: () => {
45 | return binding.arg === 'cut' ? 'cut' : 'copy'
46 | },
47 | container: defaultConfig.autoSetContainer ? el : undefined,
48 | })
49 | clipboard.on('success', (e) => {
50 | const callback = el._vClipboard_success
51 | callback && callback(e)
52 | })
53 | clipboard.on('error', (e) => {
54 | const callback = el._vClipboard_error
55 | callback && callback(e)
56 | })
57 | el._vClipboard = clipboard
58 | }
59 | },
60 | updated(el, binding) {
61 | if (binding.arg === 'success') {
62 | el._vClipboard_success = binding.value
63 | } else if (binding.arg === 'error') {
64 | el._vClipboard_error = binding.value
65 | } else {
66 | el._vClipboard.text = () => {
67 | return binding.value
68 | }
69 | el._vClipboard.action = () => {
70 | return binding.arg === 'cut' ? 'cut' : 'copy'
71 | }
72 | }
73 | },
74 | unmounted(el, binding) {
75 | if (binding.arg === 'success') {
76 | delete el._vClipboard_success
77 | } else if (binding.arg === 'error') {
78 | delete el._vClipboard_error
79 | } else {
80 | el._vClipboard.destroy()
81 | delete el._vClipboard
82 | }
83 | },
84 | })
85 | },
86 | toClipboard: (text: string, action: Actions) => toClipboard(text, action),
87 | }
88 |
89 | export const toClipboard = (
90 | text: string,
91 | action: Actions = 'copy',
92 | ): Promise => {
93 | return new Promise((resolve, reject) => {
94 | const fakeElement = document.createElement('button')
95 | const clipboard = new ClipboardJS(fakeElement, {
96 | text: () => text,
97 | action: () => action,
98 | })
99 |
100 | clipboard.on('success', (e) => {
101 | clipboard.destroy()
102 | resolve(e)
103 | })
104 |
105 | clipboard.on('error', (e) => {
106 | clipboard.destroy()
107 | reject(e)
108 | })
109 |
110 | if (defaultConfig.appendToBody) {
111 | document.body.appendChild(fakeElement)
112 | }
113 |
114 | fakeElement.click()
115 | if (defaultConfig.appendToBody) {
116 | document.body.removeChild(fakeElement)
117 | }
118 | })
119 | }
120 |
--------------------------------------------------------------------------------
/src/index.ts:
--------------------------------------------------------------------------------
1 | import type { IVueClipboard } from './VueClipboard'
2 | declare module '@vue/runtime-core' {
3 | interface ComponentCustomProperties {
4 | $vclipboard: IVueClipboard
5 | }
6 | }
7 |
8 | export { VueClipboard, toClipboard } from './VueClipboard'
9 |
--------------------------------------------------------------------------------
/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "include": ["src/**/*.ts", "__tests__/**/*.ts"],
3 | "compilerOptions": {
4 | "baseUrl": ".",
5 | "rootDir": ".",
6 | "outDir": "dist",
7 | "sourceMap": false,
8 | "noEmit": true,
9 |
10 | "target": "esnext",
11 | "module": "esnext",
12 | "moduleResolution": "node",
13 | "allowJs": false,
14 |
15 | "noUnusedLocals": true,
16 | "strictNullChecks": true,
17 | "noImplicitAny": true,
18 | "noImplicitThis": true,
19 | "noImplicitReturns": true,
20 | "strict": true,
21 | "isolatedModules": false,
22 | "allowSyntheticDefaultImports": true,
23 | "experimentalDecorators": true,
24 | "resolveJsonModule": true,
25 | "esModuleInterop": true,
26 | "removeComments": false,
27 | "jsx": "preserve",
28 | "lib": ["esnext", "dom"],
29 | "types": ["jest", "clipboard", "node"]
30 | }
31 | }
32 |
--------------------------------------------------------------------------------
/vite.config.js:
--------------------------------------------------------------------------------
1 | const path = require('path')
2 |
3 | module.exports = {
4 | root: 'demo',
5 | outDir: 'demo_dist',
6 | alias: {
7 | '/@/': path.resolve(__dirname, 'src'),
8 | },
9 | optimizeDeps: {
10 | // include: [''],
11 | },
12 | }
13 |
--------------------------------------------------------------------------------