-
Notifications
You must be signed in to change notification settings - Fork 90
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat(CopyToClipboard): Add CopyToClipboard and CopyToClipboardButton
components [finishes #104647528] Signed-off-by: Weyman Fung <wfung@pivotal.io>
- Loading branch information
1 parent
50149a5
commit 175855a
Showing
12 changed files
with
306 additions
and
0 deletions.
There are no files selected for viewing
51 changes: 51 additions & 0 deletions
51
library/spec/pivotal-ui-react/copy-to-clipboard/clipboard-helper_spec.js
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,51 @@ | ||
require('../spec_helper'); | ||
|
||
describe('ClipboardHelper', () => { | ||
let subject; | ||
|
||
beforeEach(() => { | ||
subject = require('../../../src/pivotal-ui-react/copy-to-clipboard/clipboard-helper'); | ||
}); | ||
|
||
describe('copy', () => { | ||
const element = 'mock element'; | ||
let window, document, range, selection; | ||
beforeEach(() => { | ||
range = jasmine.createSpyObj('range', ['selectNode']); | ||
selection = jasmine.createSpyObj('selection', ['removeAllRanges', 'addRange']); | ||
window = jasmine.createSpyObj('window', ['getSelection']); | ||
window.getSelection.and.returnValue(selection); | ||
document = jasmine.createSpyObj('document', ['createRange', 'execCommand']); | ||
document.createRange.and.returnValue(range); | ||
}); | ||
|
||
it('does some useful things', () => { | ||
subject.copy(window, document, element); | ||
expect(selection.removeAllRanges).toHaveBeenCalled(); | ||
expect(selection.addRange).toHaveBeenCalledWith(range); | ||
expect(range.selectNode).toHaveBeenCalledWith(element); | ||
expect(document.execCommand).toHaveBeenCalledWith('copy'); | ||
expect(selection.removeAllRanges.calls.count()).toBe(2); | ||
}); | ||
}); | ||
|
||
describe('select', () => { | ||
const element = 'mock element'; | ||
let window, document, range, selection; | ||
beforeEach(() => { | ||
range = jasmine.createSpyObj('range', ['selectNode']); | ||
selection = jasmine.createSpyObj('selection', ['removeAllRanges', 'addRange']); | ||
window = jasmine.createSpyObj('window', ['getSelection']); | ||
window.getSelection.and.returnValue(selection); | ||
document = jasmine.createSpyObj('document', ['createRange']); | ||
document.createRange.and.returnValue(range); | ||
}); | ||
|
||
it('does some useful things', () => { | ||
subject.select(window, document, element); | ||
expect(selection.removeAllRanges).toHaveBeenCalled(); | ||
expect(selection.addRange).toHaveBeenCalledWith(range); | ||
expect(range.selectNode).toHaveBeenCalledWith(element); | ||
}); | ||
}); | ||
}); |
78 changes: 78 additions & 0 deletions
78
library/spec/pivotal-ui-react/copy-to-clipboard/copy-to-clipboard_spec.js
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,78 @@ | ||
require('../spec_helper'); | ||
|
||
const {itPropagatesAttributes} = require('../support/shared_examples'); | ||
|
||
describe('CopyToClipboard', () => { | ||
const text = 'some copy text'; | ||
let onClick, CopyToClipboard, CopyToClipboardButton; | ||
|
||
beforeEach(() => { | ||
CopyToClipboard = require('../../../src/pivotal-ui-react/copy-to-clipboard/copy-to-clipboard').CopyToClipboard; | ||
CopyToClipboardButton = require('../../../src/pivotal-ui-react/copy-to-clipboard/copy-to-clipboard').CopyToClipboardButton; | ||
onClick = jasmine.createSpy('onClick'); | ||
spyOn(document, 'execCommand'); | ||
}); | ||
|
||
describe('CopyToClipboard (basic)', () => { | ||
beforeEach(() => { | ||
ReactDOM.render(<CopyToClipboard {...{text, onClick, className: 'test-class', id: 'test-id', style: {opacity: '0.5'}}}/>, root); | ||
}); | ||
|
||
it('renders the text', () => { | ||
expect('.sr-only').toHaveText(text); | ||
}); | ||
|
||
itPropagatesAttributes('.copy-to-clipboard', {className: 'test-class', id: 'test-id', style: {opacity: '0.5'}}); | ||
|
||
describe('when clicking on copy to clipboard', () => { | ||
beforeEach(() => { | ||
$('.copy-to-clipboard').simulate('click'); | ||
}); | ||
|
||
it('copies the text to the clipboard', () => { | ||
expect(document.execCommand).toHaveBeenCalledWith('copy'); | ||
}); | ||
|
||
it('calls the provided callback', () => { | ||
expect(onClick).toHaveBeenCalled(); | ||
}); | ||
}); | ||
}); | ||
|
||
describe('CopyToClipboardButton', () => { | ||
let Tooltip; | ||
|
||
beforeEach(() => { | ||
ReactDOM.render(<CopyToClipboardButton {...{text, onClick, className: 'test-class', id: 'test-id', style: {opacity: '0.5'}}}/>, root); | ||
}); | ||
|
||
itPropagatesAttributes('.copy-to-clipboard-button', {className: 'test-class', id: 'test-id', style: {opacity: '0.5'}}); | ||
|
||
|
||
describe('clicking on the button', () => { | ||
beforeEach(() => { | ||
Tooltip = require('pui-react-tooltip').Tooltip; | ||
spyOn(Tooltip.prototype, 'render').and.callThrough(); | ||
$('.copy-to-clipboard-image').simulate('click'); | ||
}); | ||
|
||
it('renders a tooltip that says "Copied"', () => { | ||
expect('.pui-tooltip').toContainText('Copied'); | ||
}); | ||
|
||
it('hides tooltip after 3 seconds', () => { | ||
expect('.pui-tooltip:visible').toExist(); | ||
jasmine.clock().tick(3500); | ||
expect('.pui-tooltip:visible').not.toExist(); | ||
}); | ||
|
||
it('copies the text to the clipboard', () => { | ||
expect(document.execCommand).toHaveBeenCalledWith('copy'); | ||
}); | ||
|
||
it('calls the provided callback', () => { | ||
expect(onClick).toHaveBeenCalled(); | ||
}); | ||
}); | ||
}); | ||
}); |
20 changes: 20 additions & 0 deletions
20
library/src/pivotal-ui-react/copy-to-clipboard/clipboard-helper.js
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,20 @@ | ||
const ClipboardHelper = { | ||
select(window, document, element) { | ||
window.getSelection().removeAllRanges(); | ||
const range = document.createRange(); | ||
range.selectNode(element); | ||
window.getSelection().addRange(range); | ||
}, | ||
|
||
copy(window, document, element) { | ||
ClipboardHelper.select(window, document, element); | ||
try { | ||
document.execCommand('copy'); | ||
} catch (e) { | ||
} finally { | ||
window.getSelection().removeAllRanges(); | ||
} | ||
} | ||
}; | ||
|
||
module.exports = ClipboardHelper; |
85 changes: 85 additions & 0 deletions
85
library/src/pivotal-ui-react/copy-to-clipboard/copy-to-clipboard.js
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,85 @@ | ||
const {copy} = require('./clipboard-helper'); | ||
const {mergeProps} = require('pui-react-helpers'); | ||
const {OverlayTrigger} = require('pui-react-overlay-trigger'); | ||
const React = require('react'); | ||
const {Tooltip} = require('pui-react-tooltip'); | ||
require('pui-css-copy-to-clipboard'); | ||
|
||
const types = React.PropTypes; | ||
|
||
function click({props, text}, e) { | ||
copy(window, document, text); | ||
const {onClick} = props; | ||
if (onClick) onClick(e); | ||
} | ||
|
||
function CopyToClipboard(props) { | ||
const {children, text, onClick, ...others} = props; | ||
const obj = {props, text: null}; | ||
|
||
const anchorProps = mergeProps(others, { | ||
className: 'copy-to-clipboard', | ||
onClick: click.bind(undefined, obj), | ||
role: 'button' | ||
}); | ||
|
||
return ( | ||
<a {...anchorProps}> | ||
<span className="sr-only" ref={ref => obj.text = ref}>{text}</span> | ||
{children} | ||
</a> | ||
); | ||
} | ||
|
||
CopyToClipboard.propTypes = { | ||
text: types.string.isRequired, | ||
onClick: types.func | ||
}; | ||
|
||
class CopyToClipboardButton extends React.Component { | ||
static propTypes = { | ||
text: types.string, | ||
onClick: types.func | ||
}; | ||
|
||
static defaultProps = { | ||
onClick() { | ||
} | ||
}; | ||
|
||
constructor(props, context) { | ||
super(props, context); | ||
this.state = {display: false}; | ||
} | ||
|
||
click = (e) => { | ||
if (!this.state.display) this.setState({display: true}, () => { | ||
this.setState({display: false}); | ||
}); | ||
this.props.onClick(e) | ||
}; | ||
|
||
render() { | ||
const {onClick, ...props} = this.props; | ||
const {display} = this.state; | ||
|
||
const copyProps = mergeProps(props, { | ||
className: 'copy-to-clipboard-button', | ||
onClick: this.click | ||
}); | ||
|
||
return ( | ||
<CopyToClipboard {...copyProps}> | ||
<OverlayTrigger trigger="manual" delayHide={3000} placement="top" overlay={<Tooltip id="copy-to-clipboard">Copied</Tooltip>} {...{display}}> | ||
<div className="clipboard-button"> | ||
<svg className="copy-to-clipboard-image" width="20" height="20" viewBox="0 0 1792 1792" xmlns="http://www.w3.org/2000/svg"> | ||
<path d="M768 1664h896v-640h-416q-40 0-68-28t-28-68v-416h-384v1152zm256-1440v-64q0-13-9.5-22.5t-22.5-9.5h-704q-13 0-22.5 9.5t-9.5 22.5v64q0 13 9.5 22.5t22.5 9.5h704q13 0 22.5-9.5t9.5-22.5zm256 672h299l-299-299v299zm512 128v672q0 40-28 68t-68 28h-960q-40 0-68-28t-28-68v-160h-544q-40 0-68-28t-28-68v-1344q0-40 28-68t68-28h1088q40 0 68 28t28 68v328q21 13 36 28l408 408q28 28 48 76t20 88z"/> | ||
</svg> | ||
</div> | ||
</OverlayTrigger> | ||
</CopyToClipboard> | ||
); | ||
} | ||
} | ||
|
||
module.exports = {CopyToClipboard, CopyToClipboardButton}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,9 @@ | ||
{ | ||
"version": "5.3.0", | ||
"description": "React copy component", | ||
"homepage": "http://styleguide.pivotal.io/", | ||
"dependencies": { | ||
"pui-react-overlay-trigger": "^5.3.0", | ||
"pui-react-tooltip": "^5.3.0" | ||
} | ||
} |
Empty file.
16 changes: 16 additions & 0 deletions
16
library/src/pivotal-ui/components/copy-to-clipboard/copy-to-clipboard.scss
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,16 @@ | ||
@import "../pui-variables"; | ||
|
||
.copy-to-clipboard-image { | ||
path { | ||
fill: $gray-3; | ||
} | ||
} | ||
|
||
.clipboard-button { | ||
display: flex; | ||
align-items: center; | ||
justify-content: center; | ||
border: 1px solid $gray-2; | ||
height: $input-height-base; | ||
width: $input-height-base; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,4 @@ | ||
try { | ||
require('./copy-to-clipboard.css'); | ||
} catch(e) { | ||
} |
5 changes: 5 additions & 0 deletions
5
library/src/pivotal-ui/components/copy-to-clipboard/package.json
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
{ | ||
"homepage": "http://styleguide.pivotal.io/", | ||
"dependencies": {}, | ||
"version": "5.3.0" | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,35 @@ | ||
/*doc | ||
--- | ||
title: Copy To Clipboard | ||
name: copy_to_clipboard_react | ||
categories: | ||
- react_components_copy-to-clipboard | ||
- react_all | ||
--- | ||
<code class="pam"> | ||
<i class="fa fa-download" alt="Install the Component"></i> | ||
npm install pui-react-copy-to-clipboard --save | ||
</code> | ||
Require the subcomponents: | ||
``` | ||
var CopyToClipboard = require('pui-react-copy-to-clipboard').CopyToClipboard; | ||
var CopyToClipboardButton = require('pui-react-copy-to-clipboard').CopyToClipboardButton; | ||
``` | ||
```react_example_table | ||
<CopyToClipboard text="I got copied by a button"><button>Click Me To Copy</button></CopyToClipboard> | ||
<CopyToClipboardButton text="I got copied by a good looking button"/> | ||
``` | ||
The CopyToClipboard Components require the following property: | ||
Property | Type | Description | ||
------------- | --------------| -------------------------------------------------------------------------- | ||
`text` | String | Text that is copied when the user clicks | ||
*/ |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters