Launch Week Day 5: Introducing Reachability for PHP.Learn More
Socket
Book a DemoSign in
Socket

@react-hook/copy

Package Overview
Dependencies
Maintainers
1
Versions
4
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

@react-hook/copy - npm Package Compare versions

Comparing version
1.0.1
to
2.0.0
+2
dist/esm/index.mjs
function e(e){return e}import{useState as r,useRef as t,useEffect as n,useCallback as o}from"react";export default function(c){function a(){return u(1)}function i(){return u(e)}var[d,u]=r(0),m=t(()=>u(0));return n(()=>m.current,[c]),{copied:d,copy:o(()=>function(e){if(navigator.clipboard)return navigator.clipboard.writeText(e);var r=document.createElement("span");r.textContent=e,r.style.whiteSpace="pre",document.body.appendChild(r);var t=window.getSelection();if(!t)return Promise.reject();var n=window.document.createRange();t.removeAllRanges(),n.selectNode(r),t.addRange(n);try{window.document.execCommand("copy")}catch(e){return Promise.reject()}return t.removeAllRanges(),window.document.body.removeChild(r),Promise.resolve()}(c).then(a).catch(i),[c]),reset:m.current}}
//# sourceMappingURL=index.mjs.map
{"version":3,"file":"index.mjs","sources":["../../src/index.tsx"],"sourcesContent":["import * as React from 'react'\n\nfunction useCopy(text: string) {\n const [copied, setCopied] = React.useState(false)\n const reset = React.useRef(() => setCopied(false))\n // Resets 'copied' if text changes\n React.useEffect(() => reset.current, [text])\n return {\n copied,\n copy: React.useCallback(\n () =>\n copyToClipboard(text)\n .then(() => setCopied(true))\n .catch(() => setCopied((copied) => copied)),\n [text]\n ),\n reset: reset.current,\n } as const\n}\n/* istanbul ignore next */\nfunction copyToClipboard(text: string) {\n // uses the Async Clipboard API when available. Requires a secure browing\n // context (i.e. HTTPS)\n if (navigator.clipboard) return navigator.clipboard.writeText(text)\n // puts the text to copy into a <span>\n const span = document.createElement('span')\n span.textContent = text\n // preserves consecutive spaces and newlines\n span.style.whiteSpace = 'pre'\n // adds the <span> to the page\n document.body.appendChild(span)\n // makes a selection object representing the range of text selected by the user\n const selection = window.getSelection()\n if (!selection) return Promise.reject()\n const range = window.document.createRange()\n selection.removeAllRanges()\n range.selectNode(span)\n selection.addRange(range)\n // copies text to the clipboard\n try {\n window.document.execCommand('copy')\n } catch (err) {\n return Promise.reject()\n }\n // cleans up the dom element and selection\n selection.removeAllRanges()\n window.document.body.removeChild(span)\n // the Async Clipboard API returns a promise that may reject with `undefined`\n // so we match that here for consistency\n return Promise.resolve()\n}\n\nexport default useCopy\n"],"names":["copied","text","setCopied","React","reset","current","copy","navigator","clipboard","writeText","span","document","createElement","textContent","style","whiteSpace","body","appendChild","selection","window","getSelection","Promise","reject","range","createRange","removeAllRanges","selectNode","addRange","execCommand","err","removeChild","resolve","copyToClipboard","then","catch"],"mappings":"AAaiC,WAACA,UAAWA,8FAX7C,SAAiBC,uBAUKC,EAAU,uBACTA,SAVdF,EAAQE,GAAaC,EAAe,GACrCC,EAAQD,EAAa,IAAMD,EAAU,WAE3CC,EAAgB,IAAMC,EAAMC,QAAS,CAACJ,IAC/B,CACLD,OAAAA,EACAM,KAAMH,EACJ,IAUN,SAAyBF,MAGnBM,UAAUC,UAAW,OAAOD,UAAUC,UAAUC,UAAUR,OAExDS,EAAOC,SAASC,cAAc,QACpCF,EAAKG,YAAcZ,EAEnBS,EAAKI,MAAMC,WAAa,MAExBJ,SAASK,KAAKC,YAAYP,OAEpBQ,EAAYC,OAAOC,mBACpBF,EAAW,OAAOG,QAAQC,aACzBC,EAAQJ,OAAOR,SAASa,cAC9BN,EAAUO,kBACVF,EAAMG,WAAWhB,GACjBQ,EAAUS,SAASJ,OAGjBJ,OAAOR,SAASiB,YAAY,QAC5B,MAAOC,UACAR,QAAQC,gBAGjBJ,EAAUO,kBACVN,OAAOR,SAASK,KAAKc,YAAYpB,GAG1BW,QAAQU,UAtCTC,CAAgB/B,GACbgC,QACAC,SACL,CAACjC,IAEHG,MAAOA,EAAMC"}
"use strict";
exports.__esModule = true;
exports.default = void 0;
var React = /*#__PURE__*/_interopRequireWildcard( /*#__PURE__*/require("react"));
function _getRequireWildcardCache() { if (typeof WeakMap !== "function") return null; var cache = new WeakMap(); _getRequireWildcardCache = function () { return cache; }; return cache; }
function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } if (obj === null || typeof obj !== "object" && typeof obj !== "function") { return { default: obj }; } var cache = _getRequireWildcardCache(); if (cache && cache.has(obj)) { return cache.get(obj); } var newObj = {}; var hasPropertyDescriptor = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) { var desc = hasPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : null; if (desc && (desc.get || desc.set)) { Object.defineProperty(newObj, key, desc); } else { newObj[key] = obj[key]; } } } newObj.default = obj; if (cache) { cache.set(obj, newObj); } return newObj; }
function _ref2(copied) {
return copied;
}
function useCopy(text) {
const [copied, setCopied] = React.useState(false);
const reset = React.useRef(() => setCopied(false)); // Resets 'copied' if text changes
React.useEffect(() => reset.current, [text]);
function _ref() {
return setCopied(true);
}
function _ref3() {
return setCopied(_ref2);
}
return {
copied,
copy: React.useCallback(() => copyToClipboard(text).then(_ref).catch(_ref3), [text]),
reset: reset.current
};
}
/* istanbul ignore next */
function copyToClipboard(text) {
// uses the Async Clipboard API when available. Requires a secure browing
// context (i.e. HTTPS)
if (navigator.clipboard) return navigator.clipboard.writeText(text); // puts the text to copy into a <span>
const span = document.createElement('span');
span.textContent = text; // preserves consecutive spaces and newlines
span.style.whiteSpace = 'pre'; // adds the <span> to the page
document.body.appendChild(span); // makes a selection object representing the range of text selected by the user
const selection = window.getSelection();
if (!selection) return Promise.reject();
const range = window.document.createRange();
selection.removeAllRanges();
range.selectNode(span);
selection.addRange(range); // copies text to the clipboard
try {
window.document.execCommand('copy');
} catch (err) {
return Promise.reject();
} // cleans up the dom element and selection
selection.removeAllRanges();
window.document.body.removeChild(span); // the Async Clipboard API returns a promise that may reject with `undefined`
// so we match that here for consistency
return Promise.resolve();
}
var _default = useCopy;
exports.default = _default;
import * as React from 'react';
function _ref2(copied) {
return copied;
}
function useCopy(text) {
const [copied, setCopied] = React.useState(false);
const reset = React.useRef(() => setCopied(false)); // Resets 'copied' if text changes
React.useEffect(() => reset.current, [text]);
function _ref() {
return setCopied(true);
}
function _ref3() {
return setCopied(_ref2);
}
return {
copied,
copy: React.useCallback(() => copyToClipboard(text).then(_ref).catch(_ref3), [text]),
reset: reset.current
};
}
/* istanbul ignore next */
function copyToClipboard(text) {
// uses the Async Clipboard API when available. Requires a secure browing
// context (i.e. HTTPS)
if (navigator.clipboard) return navigator.clipboard.writeText(text); // puts the text to copy into a <span>
const span = document.createElement('span');
span.textContent = text; // preserves consecutive spaces and newlines
span.style.whiteSpace = 'pre'; // adds the <span> to the page
document.body.appendChild(span); // makes a selection object representing the range of text selected by the user
const selection = window.getSelection();
if (!selection) return Promise.reject();
const range = window.document.createRange();
selection.removeAllRanges();
range.selectNode(span);
selection.addRange(range); // copies text to the clipboard
try {
window.document.execCommand('copy');
} catch (err) {
return Promise.reject();
} // cleans up the dom element and selection
selection.removeAllRanges();
window.document.body.removeChild(span); // the Async Clipboard API returns a promise that may reject with `undefined`
// so we match that here for consistency
return Promise.resolve();
}
export default useCopy;
!function(e,t){"object"==typeof exports&&"undefined"!=typeof module?module.exports=t(require("react")):"function"==typeof define&&define.amd?define(["react"],t):(e=e||self).useCopy=t(e.React)}(this,(function(e){"use strict";function t(e){return e}return function(n){function r(){return i(1)}function o(){return i(t)}var c=e.useState(0),u=c[0],i=c[1],a=e.useRef((function(){return i(0)}));return e.useEffect((function(){return a.current}),[n]),{copied:u,copy:e.useCallback((function(){return function(e){if(navigator.clipboard)return navigator.clipboard.writeText(e);var t=document.createElement("span");t.textContent=e,t.style.whiteSpace="pre",document.body.appendChild(t);var n=window.getSelection();if(!n)return Promise.reject();var r=window.document.createRange();n.removeAllRanges(),r.selectNode(t),n.addRange(r);try{window.document.execCommand("copy")}catch(e){return Promise.reject()}return n.removeAllRanges(),window.document.body.removeChild(t),Promise.resolve()}(n).then(r).catch(o)}),[n]),reset:a.current}}}));
//# sourceMappingURL=use-copy.js.map
{"version":3,"file":"use-copy.js","sources":["../../src/index.tsx"],"sourcesContent":["import * as React from 'react'\n\nfunction useCopy(text: string) {\n const [copied, setCopied] = React.useState(false)\n const reset = React.useRef(() => setCopied(false))\n // Resets 'copied' if text changes\n React.useEffect(() => reset.current, [text])\n return {\n copied,\n copy: React.useCallback(\n () =>\n copyToClipboard(text)\n .then(() => setCopied(true))\n .catch(() => setCopied((copied) => copied)),\n [text]\n ),\n reset: reset.current,\n } as const\n}\n/* istanbul ignore next */\nfunction copyToClipboard(text: string) {\n // uses the Async Clipboard API when available. Requires a secure browing\n // context (i.e. HTTPS)\n if (navigator.clipboard) return navigator.clipboard.writeText(text)\n // puts the text to copy into a <span>\n const span = document.createElement('span')\n span.textContent = text\n // preserves consecutive spaces and newlines\n span.style.whiteSpace = 'pre'\n // adds the <span> to the page\n document.body.appendChild(span)\n // makes a selection object representing the range of text selected by the user\n const selection = window.getSelection()\n if (!selection) return Promise.reject()\n const range = window.document.createRange()\n selection.removeAllRanges()\n range.selectNode(span)\n selection.addRange(range)\n // copies text to the clipboard\n try {\n window.document.execCommand('copy')\n } catch (err) {\n return Promise.reject()\n }\n // cleans up the dom element and selection\n selection.removeAllRanges()\n window.document.body.removeChild(span)\n // the Async Clipboard API returns a promise that may reject with `undefined`\n // so we match that here for consistency\n return Promise.resolve()\n}\n\nexport default useCopy\n"],"names":["copied","text","setCopied","React","reset","current","copy","navigator","clipboard","writeText","span","document","createElement","textContent","style","whiteSpace","body","appendChild","selection","window","getSelection","Promise","reject","range","createRange","removeAllRanges","selectNode","addRange","execCommand","err","removeChild","resolve","copyToClipboard","then","catch"],"mappings":"gOAaiC,WAACA,UAAWA,SAX7C,SAAiBC,uBAUKC,EAAU,uBACTA,WAVOC,WAAe,GAApCH,OAAQE,OACTE,EAAQD,UAAa,kBAAMD,EAAU,aAE3CC,aAAgB,kBAAMC,EAAMC,UAAS,CAACJ,IAC/B,CACLD,OAAAA,EACAM,KAAMH,eACJ,kBAUN,SAAyBF,MAGnBM,UAAUC,UAAW,OAAOD,UAAUC,UAAUC,UAAUR,OAExDS,EAAOC,SAASC,cAAc,QACpCF,EAAKG,YAAcZ,EAEnBS,EAAKI,MAAMC,WAAa,MAExBJ,SAASK,KAAKC,YAAYP,OAEpBQ,EAAYC,OAAOC,mBACpBF,EAAW,OAAOG,QAAQC,aACzBC,EAAQJ,OAAOR,SAASa,cAC9BN,EAAUO,kBACVF,EAAMG,WAAWhB,GACjBQ,EAAUS,SAASJ,OAGjBJ,OAAOR,SAASiB,YAAY,QAC5B,MAAOC,UACAR,QAAQC,gBAGjBJ,EAAUO,kBACVN,OAAOR,SAASK,KAAKc,YAAYpB,GAG1BW,QAAQU,UAtCTC,CAAgB/B,GACbgC,QACAC,WACL,CAACjC,IAEHG,MAAOA,EAAMC"}
import {renderHook, act} from '@testing-library/react-hooks'
import useCopy from './index'
describe('useCopy()', () => {
const writeText = jest.fn(async (text) => text)
// @ts-ignore
window.navigator.clipboard = {
writeText,
}
it('should work', async () => {
const {result} = renderHook(() => useCopy('copy me'))
expect(result.current.copied).toBe(false)
await act(() => result.current.copy())
expect(writeText).toBeCalled()
expect(result.current.copied).toBe(true)
act(() => result.current.reset())
expect(result.current.copied).toBe(false)
})
})
import * as React from 'react'
function useCopy(text: string) {
const [copied, setCopied] = React.useState(false)
const reset = React.useRef(() => setCopied(false))
// Resets 'copied' if text changes
React.useEffect(() => reset.current, [text])
return {
copied,
copy: React.useCallback(
() =>
copyToClipboard(text)
.then(() => setCopied(true))
.catch(() => setCopied((copied) => copied)),
[text]
),
reset: reset.current,
} as const
}
/* istanbul ignore next */
function copyToClipboard(text: string) {
// uses the Async Clipboard API when available. Requires a secure browing
// context (i.e. HTTPS)
if (navigator.clipboard) return navigator.clipboard.writeText(text)
// puts the text to copy into a <span>
const span = document.createElement('span')
span.textContent = text
// preserves consecutive spaces and newlines
span.style.whiteSpace = 'pre'
// adds the <span> to the page
document.body.appendChild(span)
// makes a selection object representing the range of text selected by the user
const selection = window.getSelection()
if (!selection) return Promise.reject()
const range = window.document.createRange()
selection.removeAllRanges()
range.selectNode(span)
selection.addRange(range)
// copies text to the clipboard
try {
window.document.execCommand('copy')
} catch (err) {
return Promise.reject()
}
// cleans up the dom element and selection
selection.removeAllRanges()
window.document.body.removeChild(span)
// the Async Clipboard API returns a promise that may reject with `undefined`
// so we match that here for consistency
return Promise.resolve()
}
export default useCopy
declare function useCopy(
text: string
): {
readonly copied: boolean
readonly copy: () => Promise<void>
readonly reset: () => void
}
export default useCopy
+2
-2

@@ -1,4 +0,4 @@

The MIT License (MIT)
MIT License
Copyright (c) 2019 Jared Lunde
Copyright (c) 2020 Jared Lunde

@@ -5,0 +5,0 @@ Permission is hereby granted, free of charge, to any person obtaining a copy

{
"name": "@react-hook/copy",
"version": "1.0.1",
"main": "dist/cjs/index.js",
"module": "dist/es/index.js",
"author": "Jared Lunde <jared@BeStellar.co> (https://BeStellar.co)",
"version": "2.0.0",
"homepage": "https://github.com/jaredLunde/react-hook#readme",
"repository": "github:jaredLunde/react-hook",
"bugs": "https://github.com/jaredLunde/react-hook/issues",
"author": "Jared Lunde <jared.lunde@gmail.com> (https://jaredLunde.com)",
"license": "MIT",
"sideEffects": false,
"repository": "https://github.com/jaredLunde/react-hook/tree/master/packages/copy",
"scripts": {
"build": "yarn run build:es && yarn run build:cjs",
"build:es": "rimraf dist/es && cross-env NODE_ENV=production BABEL_ENV=es babel src --out-dir dist/es && npm run prettier:es",
"build:cjs": "rimraf dist/cjs && cross-env NODE_ENV=production BABEL_ENV=cjs babel src --out-dir dist/cjs && npm run prettier:cjs",
"watch:es": "rimraf dist/es && cross-env NODE_ENV=production BABEL_ENV=es babel src -w --out-dir dist/es",
"prettier": "prettier --single-quote --no-semi --no-bracket-spacing --trailing-comma es5 --write",
"prettier:es": "yarn prettier \"dist/es/**/*.js\"",
"prettier:cjs": "yarn prettier \"dist/cjs/**/*.js\"",
"prepublishOnly": "yarn build"
},
"description": "A React hook for copying text to the clipboard",
"keywords": [

@@ -29,11 +19,114 @@ "react",

],
"main": "dist/main/index.js",
"module": "dist/module/index.js",
"unpkg": "dist/umd/use-copy.js",
"source": "src/index.tsx",
"types": "types/index.d.ts",
"files": [
"/dist",
"/src",
"/types"
],
"exports": {
".": {
"browser": "./dist/module/index.js",
"import": "./dist/esm/index.mjs",
"require": "./dist/main/index.js",
"umd": "./dist/umd/use-copy.js",
"source": "./src/index.tsx",
"types": "./types/index.d.ts",
"default": "./dist/main/index.js"
},
"./package.json": "./package.json",
"./": "./"
},
"sideEffects": false,
"scripts": {
"build": "lundle build --umd-case camel",
"check-types": "lundle check-types",
"dev": "lundle build -f module,cjs -w",
"format": "prettier --write \"{,!(node_modules|dist|coverage)/**/}*.{ts,tsx,js,jsx,md,yml,json}\"",
"lint": "eslint . --ext .ts,.tsx",
"prepublishOnly": "npm run lint && npm run test && npm run build && npm run format",
"test": "jest",
"validate": "lundle check-types && npm run lint && jest --coverage"
},
"husky": {
"hooks": {
"pre-commit": "lint-staged"
}
},
"lint-staged": {
"**/*.{ts,tsx,js,jsx}": [
"lundle build -f types",
"eslint",
"prettier --write"
],
"**/*.{md,yml,json}": [
"prettier --write"
]
},
"eslintConfig": {
"extends": [
"lunde"
]
},
"eslintIgnore": [
"node_modules",
"coverage",
"dist",
"test",
"*.config.js"
],
"jest": {
"moduleDirectories": [
"node_modules",
"src",
"test"
],
"testMatch": [
"<rootDir>/src/**/?(*.)test.{ts,tsx}"
],
"collectCoverageFrom": [
"**/src/**/*.{ts,tsx}"
],
"setupFilesAfterEnv": [
"./test/setup.js"
],
"snapshotResolver": "./test/resolve-snapshot.js",
"globals": {
"__DEV__": true
}
},
"prettier": {
"semi": false,
"singleQuote": true,
"jsxSingleQuote": true,
"bracketSpacing": false
},
"devDependencies": {
"@stellar-apps/babel-preset-es": "^1.0.4",
"@stellar-apps/babel-preset-react": "^1.0.1",
"prettier": "^1.16.4",
"rimraf": "^2.6.3"
"@testing-library/jest-dom": "latest",
"@testing-library/react": "latest",
"@testing-library/react-hooks": "latest",
"@testing-library/user-event": "latest",
"@types/jest": "latest",
"@types/react": "latest",
"@types/react-dom": "latest",
"babel-jest": "latest",
"eslint": "latest",
"eslint-config-lunde": "latest",
"husky": "latest",
"jest": "latest",
"lint-staged": "latest",
"lundle": "latest",
"prettier": "latest",
"react": "latest",
"react-dom": "latest",
"react-test-renderer": "latest",
"typescript": "latest"
},
"dependencies": {},
"peerDependencies": {
"react": "^16.8.0"
"react": ">=16.8"
}
}
+54
-11

@@ -1,19 +0,62 @@

# @react-hook/copy
<hr>
<div align="center">
<h1 align="center">
useCopy()
</h1>
</div>
<p align="center">
<a href="https://bundlephobia.com/result?p=@react-hook/copy">
<img alt="Bundlephobia" src="https://img.shields.io/bundlephobia/minzip/@react-hook/copy?style=for-the-badge&labelColor=24292e">
</a>
<a aria-label="Types" href="https://www.npmjs.com/package/@react-hook/copy">
<img alt="Types" src="https://img.shields.io/npm/types/@react-hook/copy?style=for-the-badge&labelColor=24292e">
</a>
<!--
<a aria-label="Code coverage report" href="https://codecov.io/gh/jaredLunde/react-hook">
<img alt="Code coverage" src="https://img.shields.io/codecov/c/gh/jaredLunde/react-hook?style=for-the-badge&labelColor=24292e">
</a>
<a aria-label="Build status" href="https://travis-ci.com/jaredLunde/react-hook">
<img alt="Build status" src="https://img.shields.io/travis/com/jaredLunde/react-hook?style=for-the-badge&labelColor=24292e">
</a>
-->
<a aria-label="NPM version" href="https://www.npmjs.com/package/@react-hook/copy">
<img alt="NPM Version" src="https://img.shields.io/npm/v/@react-hook/copy?style=for-the-badge&labelColor=24292e">
</a>
<a aria-label="License" href="https://jaredlunde.mit-license.org/">
<img alt="MIT License" src="https://img.shields.io/npm/l/@react-hook/copy?style=for-the-badge&labelColor=24292e">
</a>
</p>
<pre align="center">npm i @react-hook/copy</pre>
<hr>
A React hook for copying text to the clipboard
## Installation
`yarn add @react-hook/copy`
## Quick Start
## Usage
```jsx harmony
import useCopy from '@react-hook/copy'
const F = props => {
const [copied, copy] = useCopy('This text will be copied to the clipboard')
return (
<a onClick={copy}>
{copied === false ? 'Copy' : 'Copied'}
</a>
const Component = (props) => {
const {copied, copy, reset} = useCopy(
'This text will be copied to the clipboard'
)
return <a onClick={copy}>{copied === false ? 'Copy' : 'Copied'}</a>
}
```
```
## API
### useCopy(text: string)
| Argument | Type | Required? | Description |
| -------- | -------- | --------- | ----------------------------------------------------------------- |
| text | `string` | Yes | The text you want to copy to the clipboard when `copy` is clicked |
### Returns `{copied: boolean, copy: () => void, reset: () => void}`
## LICENSE
MIT
'use strict'
exports.__esModule = true
exports.default = exports.copyToClipboard = void 0
var _react = require('react')
const copyToClipboard = text => {
// uses the Async Clipboard API when available. Requires a secure browing
// context (i.e. HTTPS)
if (navigator.clipboard) {
return navigator.clipboard.writeText(text)
} // puts the text to copy into a <span>
const span = document.createElement('span')
span.textContent = text // preserves consecutive spaces and newlines
span.style.whiteSpace = 'pre' // adds the <span> to the page
document.body.appendChild(span) // makes a selection object representing the range of text selected by the user
const selection = window.getSelection()
const range = window.document.createRange()
selection.removeAllRanges()
range.selectNode(span)
selection.addRange(range) // copies text to the clipboard
let success = false
try {
success = window.document.execCommand('copy')
} catch (err) {
console.log('error', err)
} // cleans up the dom element and selection
selection.removeAllRanges()
window.document.body.removeChild(span) // the Async Clipboard API returns a promise that may reject with `undefined`
// so we match that here for consistency
return success ? Promise.resolve() : Promise.reject()
}
exports.copyToClipboard = copyToClipboard
var _default = text => {
const [copied, setCopied] = (0, _react.useState)(false)
function _ref() {
return setCopied(true)
}
const copy = (0, _react.useCallback)(() => {
const promise = copyToClipboard(text)
if (copied === false) {
promise.then(_ref)
}
}, [text]) // reset 'copied' if text changes
function _ref2() {
return setCopied(false)
}
;(0, _react.useEffect)(() => _ref2, [text])
return [copied, copy]
}
exports.default = _default
import {useState, useCallback, useEffect} from 'react'
export const copyToClipboard = text => {
// uses the Async Clipboard API when available. Requires a secure browing
// context (i.e. HTTPS)
if (navigator.clipboard) {
return navigator.clipboard.writeText(text)
} // puts the text to copy into a <span>
const span = document.createElement('span')
span.textContent = text // preserves consecutive spaces and newlines
span.style.whiteSpace = 'pre' // adds the <span> to the page
document.body.appendChild(span) // makes a selection object representing the range of text selected by the user
const selection = window.getSelection()
const range = window.document.createRange()
selection.removeAllRanges()
range.selectNode(span)
selection.addRange(range) // copies text to the clipboard
let success = false
try {
success = window.document.execCommand('copy')
} catch (err) {
console.log('error', err)
} // cleans up the dom element and selection
selection.removeAllRanges()
window.document.body.removeChild(span) // the Async Clipboard API returns a promise that may reject with `undefined`
// so we match that here for consistency
return success ? Promise.resolve() : Promise.reject()
}
export default text => {
const [copied, setCopied] = useState(false)
function _ref() {
return setCopied(true)
}
const copy = useCallback(() => {
const promise = copyToClipboard(text)
if (copied === false) {
promise.then(_ref)
}
}, [text]) // reset 'copied' if text changes
function _ref2() {
return setCopied(false)
}
useEffect(() => _ref2, [text])
return [copied, copy]
}
import {useState, useCallback, useEffect} from 'react'
export const copyToClipboard = text => {
// uses the Async Clipboard API when available. Requires a secure browing
// context (i.e. HTTPS)
if (navigator.clipboard) {
return navigator.clipboard.writeText(text)
}
// puts the text to copy into a <span>
const span = document.createElement('span')
span.textContent = text
// preserves consecutive spaces and newlines
span.style.whiteSpace = 'pre'
// adds the <span> to the page
document.body.appendChild(span)
// makes a selection object representing the range of text selected by the user
const selection = window.getSelection()
const range = window.document.createRange()
selection.removeAllRanges()
range.selectNode(span)
selection.addRange(range)
// copies text to the clipboard
let success = false
try {
success = window.document.execCommand('copy')
} catch (err) {
console.log('error', err)
}
// cleans up the dom element and selection
selection.removeAllRanges()
window.document.body.removeChild(span)
// the Async Clipboard API returns a promise that may reject with `undefined`
// so we match that here for consistency
return success ? Promise.resolve() : Promise.reject()
}
export default text => {
const [copied, setCopied] = useState(false)
const copy = useCallback(
() => {
const promise = copyToClipboard(text)
if (copied === false) {
promise.then(() => setCopied(true))
}
},
[text]
)
// reset 'copied' if text changes
useEffect(() => () => setCopied(false), [text])
return [copied, copy]
}