├── .github ├── FUNDING.yml └── workflows │ └── ci.yml ├── index.d.ts ├── .gitignore ├── dist ├── copy-to-clipboard.umd.min.js ├── copy-to-clipboard.esm.js ├── copy-to-clipboard.cjs.js ├── copy-to-clipboard.umd.min.js.map ├── copy-to-clipboard.umd.js └── copy-to-clipboard.umd.js.map ├── LICENSE ├── package.json ├── rollup.config.mjs ├── src └── main.js ├── test └── main.test.js └── README.md /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | ko_fi: jaywcjlove 2 | buy_me_a_coffee: jaywcjlove 3 | custom: ["https://www.paypal.me/kennyiseeyou", "https://jaywcjlove.github.io/#/sponsor"] 4 | -------------------------------------------------------------------------------- /index.d.ts: -------------------------------------------------------------------------------- 1 | 2 | interface CopyTextToClipboard { 3 | (text: string, method?: (isCopy: boolean) => void): void 4 | } 5 | 6 | declare var copyTextToClipboard: CopyTextToClipboard 7 | export default copyTextToClipboard; -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | build 2 | dist 3 | lib 4 | cjs 5 | esm 6 | node_modules 7 | coverage 8 | npm-debug.log* 9 | package-lock.json 10 | 11 | .eslintcache 12 | .DS_Store 13 | .cache 14 | .rdoc-dist 15 | 16 | *.log 17 | *.bak 18 | *.tem 19 | *.temp 20 | #.swp 21 | *.*~ 22 | ~*.* 23 | -------------------------------------------------------------------------------- /dist/copy-to-clipboard.umd.min.js: -------------------------------------------------------------------------------- 1 | /*! @uiw/copy-to-clipboard v1.0.15 | MIT © 2023 Kenny Wang https://uiwjs.github.io/copy-to-clipboard */ 2 | !function(e,t){"object"==typeof exports&&"undefined"!=typeof module?module.exports=t():"function"==typeof define&&define.amd?define(t):(e="undefined"!=typeof globalThis?globalThis:e||self).copyTextToClipboard=t()}(this,(function(){"use strict";return function(e,t){if("undefined"==typeof document)return;const o=document.createElement("textarea");o.value=e,o.setAttribute("readonly",""),o.style={position:"absolute",left:"-9999px"},document.body.appendChild(o);const n=document.getSelection().rangeCount>0&&document.getSelection().getRangeAt(0);o.select();let d=!1;try{d=!!document.execCommand("copy")}catch(e){d=!1}document.body.removeChild(o),n&&document.getSelection&&(document.getSelection().removeAllRanges(),document.getSelection().addRange(n)),t&&t(d)}})); 3 | //# sourceMappingURL=copy-to-clipboard.umd.min.js.map 4 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2023 uiw 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 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@uiw/copy-to-clipboard", 3 | "version": "1.0.19", 4 | "description": "Copy to clipboard.", 5 | "main": "dist/copy-to-clipboard.cjs.js", 6 | "module": "dist/copy-to-clipboard.esm.js", 7 | "browser": "dist/copy-to-clipboard.umd.js", 8 | "homepage": "https://uiwjs.github.io/copy-to-clipboard", 9 | "funding": "https://jaywcjlove.github.io/#/sponsor", 10 | "types": "index.d.ts", 11 | "scripts": { 12 | "test": "tsbb test", 13 | "coverage": "tsbb test --coverage --bail", 14 | "build": "rollup -c rollup.config.mjs", 15 | "dev": "rollup -c rollup.config.mjs -w" 16 | }, 17 | "files": [ 18 | "index.d.ts", 19 | "dist", 20 | "README.md" 21 | ], 22 | "keywords": [ 23 | "copy", 24 | "text", 25 | "clipboard", 26 | "browser", 27 | "clipboard-copy", 28 | "clipboard.js" 29 | ], 30 | "author": { 31 | "name": "Kenny Wang", 32 | "email": "wowohoo@qq.com", 33 | "url": "https://wangchujiang.com" 34 | }, 35 | "repository": { 36 | "type": "git", 37 | "url": "https://github.com/uiwjs/copy-to-clipboard.git" 38 | }, 39 | "license": "MIT", 40 | "devDependencies": { 41 | "@rollup/plugin-commonjs": "^24.1.0", 42 | "@rollup/plugin-node-resolve": "^15.0.2", 43 | "@rollup/plugin-terser": "^0.4.1", 44 | "bannerjs": "^3.0.1", 45 | "rollup": "^3.20.2", 46 | "tsbb": "^4.2.3" 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /rollup.config.mjs: -------------------------------------------------------------------------------- 1 | import { createRequire } from 'module'; 2 | import commonjs from '@rollup/plugin-commonjs'; 3 | import { nodeResolve } from '@rollup/plugin-node-resolve'; 4 | import terser from '@rollup/plugin-terser'; 5 | import * as banner from 'bannerjs'; 6 | 7 | const require = createRequire(import.meta.url); 8 | const pkg = require('./package.json'); 9 | 10 | export default [ 11 | // browser-friendly UMD build 12 | { 13 | input: 'src/main.js', 14 | output: { 15 | name: 'copyTextToClipboard', 16 | file: pkg.browser, 17 | format: 'umd', 18 | banner: banner.multibanner(), 19 | sourcemap: true, 20 | }, 21 | plugins: [ 22 | nodeResolve(), // so Rollup can find `ms` 23 | commonjs() // so Rollup can convert `ms` to an ES module 24 | ] 25 | }, 26 | { 27 | input: 'src/main.js', 28 | output: { 29 | file: 'dist/copy-to-clipboard.umd.min.js', 30 | format: 'umd', 31 | name: 'copyTextToClipboard', 32 | banner: banner.onebanner(), 33 | sourcemap: true 34 | }, 35 | plugins: [ 36 | nodeResolve(), // so Rollup can find `ms` 37 | commonjs(), // so Rollup can convert `ms` to an ES module 38 | terser(), 39 | ] 40 | }, 41 | // CommonJS (for Node) and ES module (for bundlers) build. 42 | // (We could have three entries in the configuration array 43 | // instead of two, but it's quicker to generate multiple 44 | // builds from a single configuration where possible, using 45 | // an array for the `output` option, where we can specify 46 | // `file` and `format` for each target) 47 | { 48 | input: 'src/main.js', 49 | external: ['ms'], 50 | output: [ 51 | // { file: pkg.main, format: 'umd', banner: banner.multibanner() }, 52 | { file: pkg.main, format: 'cjs', banner: banner.multibanner(), exports: 'auto' }, 53 | { file: pkg.module, format: 'es', banner: banner.multibanner(), exports: 'auto' } 54 | ] 55 | } 56 | ]; -------------------------------------------------------------------------------- /src/main.js: -------------------------------------------------------------------------------- 1 | /** 2 | * *** This styling is an extra step which is likely not required. *** 3 | * https://github.com/w3c/clipboard-apis/blob/master/explainer.adoc#writing-to-the-clipboard 4 | * 5 | * Why is it here? To ensure: 6 | * 7 | * 1. the element is able to have focus and selection. 8 | * 2. if element was to flash render it has minimal visual impact. 9 | * 3. less flakyness with selection and copying which **might** occur if 10 | * the textarea element is not visible. 11 | * 12 | * The likelihood is the element won't even render, not even a flash, 13 | * so some of these are just precautions. However in IE the element 14 | * is visible whilst the popup box asking the user for permission for 15 | * the web page to copy to the clipboard. 16 | * 17 | * Place in top-left corner of screen regardless of scroll position. 18 | * 19 | * @typedef CopyTextToClipboard 20 | * @property {(text: string, method?: (isCopy: boolean) => void) => void} void 21 | * @returns {void} 22 | * 23 | * @param {string} text 24 | * @param {CopyTextToClipboard} cb 25 | */ 26 | export default function copyTextToClipboard(text, cb) { 27 | if (typeof document === "undefined") return; 28 | const el = document.createElement('textarea'); 29 | el.value = text; 30 | el.setAttribute('readonly', ''); 31 | el.style = { 32 | position: 'absolute', 33 | left: '-9999px', 34 | } 35 | document.body.appendChild(el); 36 | const selected = document.getSelection().rangeCount > 0 ? document.getSelection().getRangeAt(0) : false; 37 | el.select(); 38 | let isCopy = false; 39 | try { 40 | const successful = document.execCommand('copy'); 41 | isCopy = !!successful; 42 | } catch (err) { 43 | isCopy = false; 44 | } 45 | document.body.removeChild(el); 46 | if (selected && document.getSelection) { 47 | document.getSelection().removeAllRanges(); 48 | document.getSelection().addRange(selected); 49 | } 50 | cb && cb(isCopy); 51 | }; 52 | -------------------------------------------------------------------------------- /dist/copy-to-clipboard.esm.js: -------------------------------------------------------------------------------- 1 | /**! 2 | * @uiw/copy-to-clipboard v1.0.15 3 | * Copy to clipboard. 4 | * 5 | * Copyright (c) 2023 Kenny Wang 6 | * https://github.com/uiwjs/copy-to-clipboard.git 7 | * 8 | * @website: https://uiwjs.github.io/copy-to-clipboard 9 | 10 | * Licensed under the MIT license 11 | */ 12 | 13 | /** 14 | * *** This styling is an extra step which is likely not required. *** 15 | * https://github.com/w3c/clipboard-apis/blob/master/explainer.adoc#writing-to-the-clipboard 16 | * 17 | * Why is it here? To ensure: 18 | * 19 | * 1. the element is able to have focus and selection. 20 | * 2. if element was to flash render it has minimal visual impact. 21 | * 3. less flakyness with selection and copying which **might** occur if 22 | * the textarea element is not visible. 23 | * 24 | * The likelihood is the element won't even render, not even a flash, 25 | * so some of these are just precautions. However in IE the element 26 | * is visible whilst the popup box asking the user for permission for 27 | * the web page to copy to the clipboard. 28 | * 29 | * Place in top-left corner of screen regardless of scroll position. 30 | * 31 | * @typedef CopyTextToClipboard 32 | * @property {(text: string, method?: (isCopy: boolean) => void) => void} void 33 | * @returns {void} 34 | * 35 | * @param {string} text 36 | * @param {CopyTextToClipboard} cb 37 | */ 38 | function copyTextToClipboard(text, cb) { 39 | if (typeof document === "undefined") return; 40 | const el = document.createElement('textarea'); 41 | el.value = text; 42 | el.setAttribute('readonly', ''); 43 | el.style = { 44 | position: 'absolute', 45 | left: '-9999px', 46 | }; 47 | document.body.appendChild(el); 48 | const selected = document.getSelection().rangeCount > 0 ? document.getSelection().getRangeAt(0) : false; 49 | el.select(); 50 | let isCopy = false; 51 | try { 52 | const successful = document.execCommand('copy'); 53 | isCopy = !!successful; 54 | } catch (err) { 55 | isCopy = false; 56 | } 57 | document.body.removeChild(el); 58 | if (selected && document.getSelection) { 59 | document.getSelection().removeAllRanges(); 60 | document.getSelection().addRange(selected); 61 | } 62 | cb && cb(isCopy); 63 | } 64 | 65 | export { copyTextToClipboard as default }; 66 | -------------------------------------------------------------------------------- /dist/copy-to-clipboard.cjs.js: -------------------------------------------------------------------------------- 1 | /**! 2 | * @uiw/copy-to-clipboard v1.0.15 3 | * Copy to clipboard. 4 | * 5 | * Copyright (c) 2023 Kenny Wang 6 | * https://github.com/uiwjs/copy-to-clipboard.git 7 | * 8 | * @website: https://uiwjs.github.io/copy-to-clipboard 9 | 10 | * Licensed under the MIT license 11 | */ 12 | 13 | 'use strict'; 14 | 15 | /** 16 | * *** This styling is an extra step which is likely not required. *** 17 | * https://github.com/w3c/clipboard-apis/blob/master/explainer.adoc#writing-to-the-clipboard 18 | * 19 | * Why is it here? To ensure: 20 | * 21 | * 1. the element is able to have focus and selection. 22 | * 2. if element was to flash render it has minimal visual impact. 23 | * 3. less flakyness with selection and copying which **might** occur if 24 | * the textarea element is not visible. 25 | * 26 | * The likelihood is the element won't even render, not even a flash, 27 | * so some of these are just precautions. However in IE the element 28 | * is visible whilst the popup box asking the user for permission for 29 | * the web page to copy to the clipboard. 30 | * 31 | * Place in top-left corner of screen regardless of scroll position. 32 | * 33 | * @typedef CopyTextToClipboard 34 | * @property {(text: string, method?: (isCopy: boolean) => void) => void} void 35 | * @returns {void} 36 | * 37 | * @param {string} text 38 | * @param {CopyTextToClipboard} cb 39 | */ 40 | function copyTextToClipboard(text, cb) { 41 | if (typeof document === "undefined") return; 42 | const el = document.createElement('textarea'); 43 | el.value = text; 44 | el.setAttribute('readonly', ''); 45 | el.style = { 46 | position: 'absolute', 47 | left: '-9999px', 48 | }; 49 | document.body.appendChild(el); 50 | const selected = document.getSelection().rangeCount > 0 ? document.getSelection().getRangeAt(0) : false; 51 | el.select(); 52 | let isCopy = false; 53 | try { 54 | const successful = document.execCommand('copy'); 55 | isCopy = !!successful; 56 | } catch (err) { 57 | isCopy = false; 58 | } 59 | document.body.removeChild(el); 60 | if (selected && document.getSelection) { 61 | document.getSelection().removeAllRanges(); 62 | document.getSelection().addRange(selected); 63 | } 64 | cb && cb(isCopy); 65 | } 66 | 67 | module.exports = copyTextToClipboard; 68 | -------------------------------------------------------------------------------- /dist/copy-to-clipboard.umd.min.js.map: -------------------------------------------------------------------------------- 1 | {"version":3,"file":"copy-to-clipboard.umd.min.js","sources":["../src/main.js"],"sourcesContent":["/**\n * *** This styling is an extra step which is likely not required. ***\n * https://github.com/w3c/clipboard-apis/blob/master/explainer.adoc#writing-to-the-clipboard\n * \n * Why is it here? To ensure:\n * \n * 1. the element is able to have focus and selection.\n * 2. if element was to flash render it has minimal visual impact.\n * 3. less flakyness with selection and copying which **might** occur if\n * the textarea element is not visible.\n *\n * The likelihood is the element won't even render, not even a flash,\n * so some of these are just precautions. However in IE the element\n * is visible whilst the popup box asking the user for permission for\n * the web page to copy to the clipboard.\n * \n * Place in top-left corner of screen regardless of scroll position.\n *\n * @typedef CopyTextToClipboard\n * @property {(text: string, method?: (isCopy: boolean) => void) => void} void\n * @returns {void}\n * \n * @param {string} text \n * @param {CopyTextToClipboard} cb \n */\nexport default function copyTextToClipboard(text, cb) {\n if (typeof document === \"undefined\") return;\n const el = document.createElement('textarea');\n el.value = text;\n el.setAttribute('readonly', '');\n el.style = {\n position: 'absolute',\n left: '-9999px',\n }\n document.body.appendChild(el);\n const selected = document.getSelection().rangeCount > 0 ? document.getSelection().getRangeAt(0) : false;\n el.select();\n let isCopy = false;\n try {\n const successful = document.execCommand('copy');\n isCopy = !!successful;\n } catch (err) {\n isCopy = false;\n }\n document.body.removeChild(el);\n if (selected && document.getSelection) {\n document.getSelection().removeAllRanges();\n document.getSelection().addRange(selected);\n }\n cb && cb(isCopy);\n};\n"],"names":["text","cb","document","el","createElement","value","setAttribute","style","position","left","body","appendChild","selected","getSelection","rangeCount","getRangeAt","select","isCopy","execCommand","err","removeChild","removeAllRanges","addRange"],"mappings":";2PAyBe,SAA6BA,EAAMC,GAChD,GAAwB,oBAAbC,SAA0B,OACrC,MAAMC,EAAKD,SAASE,cAAc,YAClCD,EAAGE,MAAQL,EACXG,EAAGG,aAAa,WAAY,IAC5BH,EAAGI,MAAQ,CACTC,SAAU,WACVC,KAAM,WAERP,SAASQ,KAAKC,YAAYR,GAC1B,MAAMS,EAAWV,SAASW,eAAeC,WAAa,GAAIZ,SAASW,eAAeE,WAAW,GAC7FZ,EAAGa,SACH,IAAIC,GAAS,EACb,IAEEA,IADmBf,SAASgB,YAAY,OAEzC,CAAC,MAAOC,GACPF,GAAS,CACV,CACDf,SAASQ,KAAKU,YAAYjB,GACtBS,GAAYV,SAASW,eACvBX,SAASW,eAAeQ,kBACxBnB,SAASW,eAAeS,SAASV,IAEnCX,GAAMA,EAAGgB,EACX"} -------------------------------------------------------------------------------- /test/main.test.js: -------------------------------------------------------------------------------- 1 | import copyTextToClipboard from '../src/main'; 2 | 3 | it('should handle document not available', () => { 4 | const text = 'Hello, world!'; 5 | const mockCb = jest.fn(); 6 | // Create a spy to replace the document object 7 | const documentSpy = jest.spyOn(global, 'document', 'get'); 8 | documentSpy.mockImplementation(() => undefined); 9 | copyTextToClipboard(text, mockCb); 10 | expect(mockCb).not.toHaveBeenCalled(); 11 | // Restore the original document object 12 | documentSpy.mockRestore(); 13 | }); 14 | 15 | test('copyTextToClipboard should copy the text to the clipboard and return true', () => { 16 | const text = 'Hello, world!'; 17 | const copied = jest.fn(); 18 | document.execCommand = jest.fn(() => true); 19 | const cb = isCopy => { 20 | copied(isCopy); 21 | expect(isCopy).toBe(true); 22 | }; 23 | 24 | copyTextToClipboard(text, cb); 25 | 26 | expect(copied).toHaveBeenCalledWith(true); 27 | }); 28 | 29 | test('copyTextToClipboard should not copy the text to the clipboard and return false', () => { 30 | const text = 'Hello, world!'; 31 | const copied = jest.fn(); 32 | const cb = isCopy => { 33 | copied(isCopy); 34 | expect(isCopy).toBe(false); 35 | }; 36 | 37 | // Simulating an error during `document.execCommand('copy')` 38 | document.execCommand = jest.fn(() => { 39 | throw new Error('Copy failed'); 40 | }); 41 | 42 | copyTextToClipboard(text, cb); 43 | 44 | expect(copied).toHaveBeenCalledWith(false); 45 | }); 46 | 47 | 48 | it('should copy text to clipboard', () => { 49 | let mockCb = jest.fn(); 50 | const text = 'Hello, world!'; 51 | const mockRange = { 52 | commonAncestorContainer: 'mockContainer', 53 | startContainer: 'mockContainer', 54 | endContainer: 'mockContainer', 55 | startOffset: 0, 56 | endOffset: 0, 57 | }; 58 | 59 | document.execCommand = jest.fn(() => true); 60 | document.getSelection = jest.fn(() => ({ 61 | rangeCount: 1, 62 | getRangeAt: jest.fn(() => mockRange), 63 | removeAllRanges: jest.fn(), 64 | addRange: jest.fn(), 65 | })); 66 | document.createElement = jest.fn(() => ({ 67 | value: '', 68 | setAttribute: jest.fn(), 69 | select: jest.fn(), 70 | })); 71 | document.body.appendChild = jest.fn(); 72 | document.body.removeChild = jest.fn(); 73 | 74 | copyTextToClipboard(text, mockCb); 75 | 76 | expect(document.createElement).toHaveBeenCalledWith('textarea'); 77 | expect(document.body.appendChild).toHaveBeenCalled(); 78 | expect(document.execCommand).toHaveBeenCalledWith('copy'); 79 | expect(document.body.removeChild).toHaveBeenCalled(); 80 | expect(mockCb).toHaveBeenCalledWith(true); 81 | }); 82 | -------------------------------------------------------------------------------- /dist/copy-to-clipboard.umd.js: -------------------------------------------------------------------------------- 1 | /**! 2 | * @uiw/copy-to-clipboard v1.0.15 3 | * Copy to clipboard. 4 | * 5 | * Copyright (c) 2023 Kenny Wang 6 | * https://github.com/uiwjs/copy-to-clipboard.git 7 | * 8 | * @website: https://uiwjs.github.io/copy-to-clipboard 9 | 10 | * Licensed under the MIT license 11 | */ 12 | 13 | (function (global, factory) { 14 | typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory() : 15 | typeof define === 'function' && define.amd ? define(factory) : 16 | (global = typeof globalThis !== 'undefined' ? globalThis : global || self, global.copyTextToClipboard = factory()); 17 | })(this, (function () { 'use strict'; 18 | 19 | /** 20 | * *** This styling is an extra step which is likely not required. *** 21 | * https://github.com/w3c/clipboard-apis/blob/master/explainer.adoc#writing-to-the-clipboard 22 | * 23 | * Why is it here? To ensure: 24 | * 25 | * 1. the element is able to have focus and selection. 26 | * 2. if element was to flash render it has minimal visual impact. 27 | * 3. less flakyness with selection and copying which **might** occur if 28 | * the textarea element is not visible. 29 | * 30 | * The likelihood is the element won't even render, not even a flash, 31 | * so some of these are just precautions. However in IE the element 32 | * is visible whilst the popup box asking the user for permission for 33 | * the web page to copy to the clipboard. 34 | * 35 | * Place in top-left corner of screen regardless of scroll position. 36 | * 37 | * @typedef CopyTextToClipboard 38 | * @property {(text: string, method?: (isCopy: boolean) => void) => void} void 39 | * @returns {void} 40 | * 41 | * @param {string} text 42 | * @param {CopyTextToClipboard} cb 43 | */ 44 | function copyTextToClipboard(text, cb) { 45 | if (typeof document === "undefined") return; 46 | const el = document.createElement('textarea'); 47 | el.value = text; 48 | el.setAttribute('readonly', ''); 49 | el.style = { 50 | position: 'absolute', 51 | left: '-9999px', 52 | }; 53 | document.body.appendChild(el); 54 | const selected = document.getSelection().rangeCount > 0 ? document.getSelection().getRangeAt(0) : false; 55 | el.select(); 56 | let isCopy = false; 57 | try { 58 | const successful = document.execCommand('copy'); 59 | isCopy = !!successful; 60 | } catch (err) { 61 | isCopy = false; 62 | } 63 | document.body.removeChild(el); 64 | if (selected && document.getSelection) { 65 | document.getSelection().removeAllRanges(); 66 | document.getSelection().addRange(selected); 67 | } 68 | cb && cb(isCopy); 69 | } 70 | 71 | return copyTextToClipboard; 72 | 73 | })); 74 | //# sourceMappingURL=copy-to-clipboard.umd.js.map 75 | -------------------------------------------------------------------------------- /dist/copy-to-clipboard.umd.js.map: -------------------------------------------------------------------------------- 1 | {"version":3,"file":"copy-to-clipboard.umd.js","sources":["../src/main.js"],"sourcesContent":["/**\n * *** This styling is an extra step which is likely not required. ***\n * https://github.com/w3c/clipboard-apis/blob/master/explainer.adoc#writing-to-the-clipboard\n * \n * Why is it here? To ensure:\n * \n * 1. the element is able to have focus and selection.\n * 2. if element was to flash render it has minimal visual impact.\n * 3. less flakyness with selection and copying which **might** occur if\n * the textarea element is not visible.\n *\n * The likelihood is the element won't even render, not even a flash,\n * so some of these are just precautions. However in IE the element\n * is visible whilst the popup box asking the user for permission for\n * the web page to copy to the clipboard.\n * \n * Place in top-left corner of screen regardless of scroll position.\n *\n * @typedef CopyTextToClipboard\n * @property {(text: string, method?: (isCopy: boolean) => void) => void} void\n * @returns {void}\n * \n * @param {string} text \n * @param {CopyTextToClipboard} cb \n */\nexport default function copyTextToClipboard(text, cb) {\n if (typeof document === \"undefined\") return;\n const el = document.createElement('textarea');\n el.value = text;\n el.setAttribute('readonly', '');\n el.style = {\n position: 'absolute',\n left: '-9999px',\n }\n document.body.appendChild(el);\n const selected = document.getSelection().rangeCount > 0 ? document.getSelection().getRangeAt(0) : false;\n el.select();\n let isCopy = false;\n try {\n const successful = document.execCommand('copy');\n isCopy = !!successful;\n } catch (err) {\n isCopy = false;\n }\n document.body.removeChild(el);\n if (selected && document.getSelection) {\n document.getSelection().removeAllRanges();\n document.getSelection().addRange(selected);\n }\n cb && cb(isCopy);\n};\n"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;EAAA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACe,SAAS,mBAAmB,CAAC,IAAI,EAAE,EAAE,EAAE;EACtD,EAAE,IAAI,OAAO,QAAQ,KAAK,WAAW,EAAE,OAAO;EAC9C,EAAE,MAAM,EAAE,GAAG,QAAQ,CAAC,aAAa,CAAC,UAAU,CAAC,CAAC;EAChD,EAAE,EAAE,CAAC,KAAK,GAAG,IAAI,CAAC;EAClB,EAAE,EAAE,CAAC,YAAY,CAAC,UAAU,EAAE,EAAE,CAAC,CAAC;EAClC,EAAE,EAAE,CAAC,KAAK,GAAG;EACb,IAAI,QAAQ,EAAE,UAAU;EACxB,IAAI,IAAI,EAAE,SAAS;EACnB,IAAG;EACH,EAAE,QAAQ,CAAC,IAAI,CAAC,WAAW,CAAC,EAAE,CAAC,CAAC;EAChC,EAAE,MAAM,QAAQ,GAAG,QAAQ,CAAC,YAAY,EAAE,CAAC,UAAU,GAAG,CAAC,GAAG,QAAQ,CAAC,YAAY,EAAE,CAAC,UAAU,CAAC,CAAC,CAAC,GAAG,KAAK,CAAC;EAC1G,EAAE,EAAE,CAAC,MAAM,EAAE,CAAC;EACd,EAAE,IAAI,MAAM,GAAG,KAAK,CAAC;EACrB,EAAE,IAAI;EACN,IAAI,MAAM,UAAU,GAAG,QAAQ,CAAC,WAAW,CAAC,MAAM,CAAC,CAAC;EACpD,IAAI,MAAM,GAAG,CAAC,CAAC,UAAU,CAAC;EAC1B,GAAG,CAAC,OAAO,GAAG,EAAE;EAChB,IAAI,MAAM,GAAG,KAAK,CAAC;EACnB,GAAG;EACH,EAAE,QAAQ,CAAC,IAAI,CAAC,WAAW,CAAC,EAAE,CAAC,CAAC;EAChC,EAAE,IAAI,QAAQ,IAAI,QAAQ,CAAC,YAAY,EAAE;EACzC,IAAI,QAAQ,CAAC,YAAY,EAAE,CAAC,eAAe,EAAE,CAAC;EAC9C,IAAI,QAAQ,CAAC,YAAY,EAAE,CAAC,QAAQ,CAAC,QAAQ,CAAC,CAAC;EAC/C,GAAG;EACH,EAAE,EAAE,IAAI,EAAE,CAAC,MAAM,CAAC,CAAC;EACnB;;;;;;;;"} -------------------------------------------------------------------------------- /.github/workflows/ci.yml: -------------------------------------------------------------------------------- 1 | name: Build 2 | on: 3 | push: 4 | branches: 5 | - master 6 | jobs: 7 | build-deploy: 8 | runs-on: ubuntu-latest 9 | permissions: 10 | contents: write 11 | id-token: write 12 | steps: 13 | - uses: actions/checkout@v6 14 | - uses: actions/setup-node@v6 15 | with: 16 | node-version: 24 17 | registry-url: 'https://registry.npmjs.org' 18 | 19 | - run: npm install 20 | - run: npm run build 21 | - run: npm run coverage 22 | 23 | - name: Create idoc config. 24 | run: | 25 | cat > idoc.yml << EOF 26 | site: "Copy Text to Clipboard {{version}}" 27 | description: Copy Text to Clipboard 28 | openSource: https://github.com/jaywcjlove/copy-to-clipboard 29 | homepage: https://wangchujiang.com/copy-to-clipboard/ 30 | tocs: false 31 | element: 32 | wrapper: style=max-width:720px; 33 | meta: 34 | - 35 | - 36 | - 37 | - 38 | - 39 | - 40 | - 41 | - 42 | - 43 | - 44 | menus: 45 | Home: index.html 46 | Apps: 47 | url: https://wangchujiang.com/#/app 48 | target: __blank 49 | Sponsor: 50 | url: https://jaywcjlove.github.io/#/sponsor 51 | target: __blank 52 | footer: | 53 | App • 54 | Projects • 55 | Sponsor • 56 | More Apps

57 | Generated by idoc v{{idocVersion}} 58 | EOF 59 | 60 | - run: npm install idoc@1 -g 61 | - run: idoc 62 | 63 | - name: Create Coverage Badges 64 | uses: jaywcjlove/coverage-badges-cli@main 65 | with: 66 | output: dist/badges.svg 67 | 68 | - name: Generate Contributors Images 69 | uses: jaywcjlove/github-action-contributors@main 70 | with: 71 | filter-author: (renovate\[bot\]|renovate-bot|dependabot\[bot\]) 72 | output: dist/CONTRIBUTORS.svg 73 | avatarSize: 42 74 | 75 | - run: cp -rp coverage/lcov-report dist 76 | 77 | - name: Deploy 78 | uses: peaceiris/actions-gh-pages@v4 79 | with: 80 | github_token: ${{ secrets.GITHUB_TOKEN }} 81 | publish_dir: ./dist 82 | 83 | - name: Create Tag 84 | id: create_tag 85 | uses: jaywcjlove/create-tag-action@main 86 | with: 87 | token: ${{ secrets.GITHUB_TOKEN }} 88 | package-path: ./package.json 89 | 90 | - name: Generate Changelog 91 | id: changelog 92 | uses: jaywcjlove/changelog-generator@main 93 | with: 94 | token: ${{ secrets.GITHUB_TOKEN }} 95 | head-ref: ${{steps.create_tag.outputs.version}} 96 | filter-author: (jaywcjlove|小弟调调™|dependabot\[bot\]|Renovate Bot) 97 | filter: '[R|r]elease[d]\s+[v|V]\d(\.\d+){0,2}' 98 | 99 | - name: Create Release 100 | uses: ncipollo/release-action@v1 101 | if: steps.create_tag.outputs.successful 102 | with: 103 | allowUpdates: true 104 | token: ${{ secrets.GITHUB_TOKEN }} 105 | name: ${{ steps.create_tag.outputs.version }} 106 | tag: ${{ steps.create_tag.outputs.version }} 107 | body: | 108 | [![](https://img.shields.io/badge/Open%20in-unpkg-blue)](https://uiwjs.github.io/npm-unpkg/#/pkg/@uiw/copy-to-clipboard@${{steps.create_tag.outputs.versionNumber}}/file/README.md) 109 | 110 | ```bash 111 | npm i @uiw/copy-to-clipboard@${{steps.create_tag.outputs.versionNumber}} 112 | ``` 113 | 114 | ${{ steps.changelog.outputs.compareurl }} 115 | 116 | ${{ steps.changelog.outputs.changelog }} 117 | 118 | # - run: npm install @jsdevtools/npm-publish -g 119 | # - run: npm-publish --token="${{ secrets.NPM_TOKEN }}" ./package.json 120 | - name: package.json info 121 | uses: jaywcjlove/github-action-package@main 122 | with: 123 | unset: scripts,devDependencies 124 | 125 | # npm@v11.5.0+ is required for OIDC support 126 | - name: Upgrade npm for OIDC support 127 | run: npm install -g npm@latest 128 | # node@v22.0.0+ 129 | # https://gist.github.com/jaywcjlove/a178278521a6f72c74525d3f1d9c4bf9 130 | - run: NODE_AUTH_TOKEN="" npm publish --access public --provenance 131 | name: 📦 @uiw/copy-to-clipboard publish to NPM 132 | continue-on-error: true 133 | 134 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 |
2 | Using my app is also a way to support me: 3 |
4 | Deskmark 5 | Keyzer 6 | Vidwall Hub 7 | VidCrop 8 | Vidwall 9 | Mousio Hint 10 | Mousio 11 | Musicer 12 | Audioer 13 | FileSentinel 14 | FocusCursor 15 | Videoer 16 | KeyClicker 17 | DayBar 18 | Iconed 19 | Mousio 20 | Quick RSS 21 | Quick RSS 22 | Web Serve 23 | Copybook Generator 24 | DevTutor for SwiftUI 25 | RegexMate 26 | Time Passage 27 | Iconize Folder 28 | Textsound Saver 29 | Create Custom Symbols 30 | DevHub 31 | Resume Revise 32 | Palette Genius 33 | Symbol Scribe 34 |
35 |
36 | 37 | Copy Text to Clipboard 38 | === 39 | 40 | [![Buy me a coffee](https://img.shields.io/badge/Buy%20me%20a%20coffee-048754?logo=buymeacoffee)](https://jaywcjlove.github.io/#/sponsor) 41 | ![No Dependencies](http://jaywcjlove.github.io/sb/status/no-dependencies.svg) 42 | [![NPM Downloads](https://img.shields.io/npm/dm/@uiw/copy-to-clipboard.svg?style=flat)](https://www.npmjs.com/package/@uiw/copy-to-clipboard) 43 | [![Build & Deploy](https://github.com/uiwjs/copy-to-clipboard/workflows/Build/badge.svg)](https://github.com/uiwjs/react-codemirror/actions) 44 | [![Open in unpkg](https://img.shields.io/badge/Open%20in-unpkg-blue)](https://uiwjs.github.io/npm-unpkg/#/pkg/@uiw/copy-to-clipboard/file/README.md) 45 | [![npm version](https://img.shields.io/npm/v/@uiw/copy-to-clipboard.svg)](https://www.npmjs.com/package/@uiw/copy-to-clipboard) 46 | [![Repo Dependents](https://badgen.net/github/dependents-repo/uiwjs/copy-to-clipboard)](https://github.com/uiwjs/copy-to-clipboard/network/dependents) 47 | [![Coverage Status](https://uiwjs.github.io/copy-to-clipboard/badges.svg)](https://uiwjs.github.io/copy-to-clipboard/lcov-report/) 48 | 49 | **This styling is an extra step which is likely not required.** 50 | 51 | Why is it here? To ensure: 52 | 53 | 1. the element is able to have focus and selection. 54 | 2. if element was to `flash` render it has minimal visual impact. 55 | 3. less flakyness with selection and copying which **might** occur if the textarea element is not visible. 56 | 57 | The likelihood is the element won't even render, not even a flash, so some of these are just precautions. However in IE the element is visible whilst the popup box asking the user for permission for the web page to copy to the clipboard. Place in top-left corner of screen regardless of scroll position. 58 | 59 | ## Usage 60 | 61 | You will need Node.js installed on your system. 62 | 63 | ```bash 64 | $ npm i @uiw/copy-to-clipboard 65 | ``` 66 | 67 | ```js 68 | import copyTextToClipboard from '@uiw/copy-to-clipboard'; 69 | 70 | copyTextToClipboard('test', (isCopy) => { 71 | console.log('isCopy:', isCopy); 72 | }); 73 | ``` 74 | 75 | Or manually download and link [copy-to-clipboard](https://unpkg.com/@uiw/copy-to-clipboard/dist/) in your HTML, It can also be downloaded via [UNPKG](https://unpkg.com/@uiw/copy-to-clipboard/dist/): 76 | 77 | ```html 78 | 79 | 84 | ``` 85 | 86 | ## Contributors 87 | 88 | As always, thanks to our amazing contributors! 89 | 90 | 91 | 92 | 93 | 94 | Made with [contributors](https://github.com/jaywcjlove/github-action-contributors). 95 | 96 | ### License 97 | 98 | Licensed under the MIT License. 99 | --------------------------------------------------------------------------------