Skip to content

Commit 5dcbc04

Browse files
authored
Merge pull request #28 from user-interviews/feature/UIDS-27-copy-to-clipboard-component
UIDS-27 Add CopyToClipboard and TrackedButton components
2 parents 02cbdfd + 5c7371d commit 5dcbc04

File tree

15 files changed

+396
-145
lines changed

15 files changed

+396
-145
lines changed

package.json

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,13 +2,20 @@
22
"name": "ui-design-system",
33
"version": "1.0.3",
44
"dependencies": {
5+
"@fortawesome/fontawesome-svg-core": "^1.2.27",
6+
"@fortawesome/free-regular-svg-icons": "^5.12.1",
7+
"@fortawesome/free-solid-svg-icons": "^5.12.1",
8+
"@fortawesome/react-fontawesome": "^0.1.9",
59
"bootstrap": "^4.3.1",
610
"classnames": "^2.2.6",
711
"node-sass": "^4.13.1",
812
"polished": "^3.4.2",
913
"prop-types": "^15.7.2",
1014
"react-bootstrap": "^1.0.0-beta.16",
1115
"react-transition-group": "^4.3.0",
16+
"react-copy-to-clipboard": "^5.0.2",
17+
"react-popper": "^1.3.7",
18+
"react-tracking": "^7.3.0",
1219
"uuid": "^7.0.2"
1320
},
1421
"scripts": {

scss/borders.scss

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
$ux-border-radius: 0.25rem;

scss/buttons.scss

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
@import './palette';
2+
3+
.btn-link--neutral {
4+
color: $ux-gray-500;
5+
6+
&:hover {
7+
color: $ux-gray-700;
8+
}
9+
}

scss/theme.scss

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
@import './box_shadow';
2+
@import './buttons';
23
@import './lists';
34
@import './navbar';
45
@import './palette';

spec/__snapshots__/Storyshots.test.js.snap

Lines changed: 88 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -65,7 +65,7 @@ exports[`Storyshots Design System/Card all cards 1`] = `
6565
</div>
6666
`;
6767

68-
exports[`Storyshots Design System/Flash Flash Message 1`] = `
68+
exports[`Storyshots Design System/Copy To Clipboard Default 1`] = `
6969
<div
7070
style={
7171
Object {
@@ -74,24 +74,49 @@ exports[`Storyshots Design System/Flash Flash Message 1`] = `
7474
}
7575
>
7676
<div
77-
className="container Flash"
78-
/>
79-
<div>
80-
<p>
81-
Click the button to see a flash message. Use the knobs to try different types!
82-
</p>
77+
className="CopyToClipboard"
78+
>
79+
<span
80+
className="CopyToClipboard__copy-text"
81+
>
82+
Copy me!
83+
</span>
8384
<button
84-
className="btn btn-primary"
85+
className="btn btn-link btn-link--neutral"
8586
onClick={[Function]}
87+
tracking={
88+
Object {
89+
"getTrackingData": [Function],
90+
"trackEvent": [Function],
91+
}
92+
}
8693
type="button"
8794
>
88-
Submit
95+
<div>
96+
<svg
97+
aria-hidden="true"
98+
className="svg-inline--fa fa-copy fa-w-14 "
99+
data-icon="copy"
100+
data-prefix="far"
101+
focusable="false"
102+
role="img"
103+
style={Object {}}
104+
viewBox="0 0 448 512"
105+
xmlns="http://www.w3.org/2000/svg"
106+
>
107+
<path
108+
d="M433.941 65.941l-51.882-51.882A48 48 0 0 0 348.118 0H176c-26.51 0-48 21.49-48 48v48H48c-26.51 0-48 21.49-48 48v320c0 26.51 21.49 48 48 48h224c26.51 0 48-21.49 48-48v-48h80c26.51 0 48-21.49 48-48V99.882a48 48 0 0 0-14.059-33.941zM266 464H54a6 6 0 0 1-6-6V150a6 6 0 0 1 6-6h74v224c0 26.51 21.49 48 48 48h96v42a6 6 0 0 1-6 6zm128-96H182a6 6 0 0 1-6-6V54a6 6 0 0 1 6-6h106v88c0 13.255 10.745 24 24 24h88v202a6 6 0 0 1-6 6zm6-256h-64V48h9.632c1.591 0 3.117.632 4.243 1.757l48.368 48.368a6 6 0 0 1 1.757 4.243V112z"
109+
fill="currentColor"
110+
style={Object {}}
111+
/>
112+
</svg>
113+
</div>
89114
</button>
90115
</div>
91116
</div>
92117
`;
93118

94-
exports[`Storyshots Design System/Flash flash message 1`] = `
119+
exports[`Storyshots Design System/Flash Flash Message 1`] = `
95120
<div
96121
style={
97122
Object {
@@ -100,7 +125,7 @@ exports[`Storyshots Design System/Flash flash message 1`] = `
100125
}
101126
>
102127
<div
103-
className="container flash"
128+
className="container Flash"
104129
/>
105130
<div>
106131
<p>
@@ -615,3 +640,55 @@ exports[`Storyshots Design System/Pill Small 1`] = `
615640
</div>
616641
</div>
617642
`;
643+
644+
exports[`Storyshots Design System/Popper Dark 1`] = `
645+
<div
646+
style={
647+
Object {
648+
"padding": "1rem",
649+
}
650+
}
651+
>
652+
<div />
653+
<div
654+
className="Popper Popper--dark"
655+
style={
656+
Object {
657+
"left": 0,
658+
"opacity": 0,
659+
"pointerEvents": "none",
660+
"position": "absolute",
661+
"top": 0,
662+
}
663+
}
664+
>
665+
Dark Popper
666+
</div>
667+
</div>
668+
`;
669+
670+
exports[`Storyshots Design System/Popper Default 1`] = `
671+
<div
672+
style={
673+
Object {
674+
"padding": "1rem",
675+
}
676+
}
677+
>
678+
<div />
679+
<div
680+
className="Popper"
681+
style={
682+
Object {
683+
"left": 0,
684+
"opacity": 0,
685+
"pointerEvents": "none",
686+
"position": "absolute",
687+
"top": 0,
688+
}
689+
}
690+
>
691+
Default Popper
692+
</div>
693+
</div>
694+
`;
Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
import React, { useState } from 'react';
2+
import PropTypes from 'prop-types';
3+
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
4+
import { faCopy } from '@fortawesome/free-regular-svg-icons';
5+
import { CopyToClipboard as ReactCopyToClipboard } from 'react-copy-to-clipboard';
6+
7+
import Popper from '../Popper/Popper';
8+
import TrackedButton from '../TrackedButton/TrackedButton';
9+
10+
import './CopyToClipboard.scss';
11+
12+
function CopyToClipboard(props) {
13+
const [copied, setCopied] = useState(false);
14+
15+
const handleClickCopy = () => {
16+
setCopied(true);
17+
setTimeout(() => setCopied(false), 1000);
18+
};
19+
20+
return (
21+
<div className="CopyToClipboard">
22+
<span className="CopyToClipboard__copy-text">{props.copyText}</span>
23+
<ReactCopyToClipboard text={props.copyText} onCopy={handleClickCopy}>
24+
<TrackedButton
25+
className="btn btn-link btn-link--neutral"
26+
event={props.trackingEvent}
27+
type="button"
28+
>
29+
<Popper
30+
dark
31+
text="Copied!"
32+
visible={copied}
33+
>
34+
<FontAwesomeIcon icon={faCopy} />
35+
</Popper>
36+
</TrackedButton>
37+
</ReactCopyToClipboard>
38+
</div>
39+
);
40+
}
41+
42+
CopyToClipboard.propTypes = {
43+
copyText: PropTypes.string,
44+
trackingEvent: PropTypes.string.isRequired,
45+
};
46+
47+
CopyToClipboard.defaultProps = {
48+
copyText: '',
49+
};
50+
51+
export default CopyToClipboard;
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
@import '../../scss/theme';
2+
3+
.CopyToClipboard {
4+
align-items: center;
5+
border: 1px solid $ux-gray-400;
6+
border-radius: .25rem;
7+
color: $ux-gray-800;
8+
display: flex;
9+
font-weight: $font-weight-bold;
10+
justify-content: space-between;
11+
min-height: 2rem;
12+
padding: 0 0 0 .375rem;
13+
14+
&__copy-text {
15+
overflow: hidden;
16+
text-overflow: ellipsis;
17+
white-space: nowrap;
18+
}
19+
}

src/Popper/Popper.jsx

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
import React from 'react';
2+
import PropTypes from 'prop-types';
3+
import classNames from 'classnames';
4+
import { Manager, Popper as ReactPopper, Reference } from 'react-popper';
5+
6+
import './Popper.scss';
7+
8+
function Popper(props) {
9+
return (
10+
<Manager>
11+
<Reference>
12+
{({ ref }) => <div ref={ref}>{props.children}</div>}
13+
</Reference>
14+
{
15+
props.visible && (
16+
<ReactPopper placement={props.placement}>
17+
{
18+
({ placement, ref, style }) => (
19+
<div
20+
className={classNames('Popper', { 'Popper--dark': props.dark })}
21+
data-placement={placement}
22+
ref={ref}
23+
style={style}
24+
>
25+
{props.text}
26+
</div>
27+
)
28+
}
29+
</ReactPopper>
30+
)
31+
}
32+
</Manager>
33+
);
34+
}
35+
36+
Popper.propTypes = {
37+
dark: PropTypes.bool,
38+
placement: PropTypes.string,
39+
text: PropTypes.string.isRequired,
40+
visible: PropTypes.bool,
41+
};
42+
43+
Popper.defaultProps = {
44+
dark: false,
45+
placement: 'top',
46+
visible: false,
47+
};
48+
49+
export default Popper;

src/Popper/Popper.scss

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
@import '../../scss/borders';
2+
@import '../../scss/box_shadow';
3+
@import '../../scss/palette';
4+
@import '../../scss/typography';
5+
6+
.Popper {
7+
background-color: $ux-white;
8+
border-radius: $ux-border-radius;
9+
border: 1px solid $ux-gray-300;
10+
box-shadow: $ux-box-shadow-card;
11+
max-width: 15rem;
12+
padding: .25rem .5rem;
13+
14+
&--dark {
15+
background-color: $ux-gray-800;
16+
color: $ux-gray-100;
17+
font-weight: $font-weight-bold;
18+
}
19+
}
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
import withTrackedClick from '../hoc/withTrackedClick';
2+
3+
export default withTrackedClick('button');

0 commit comments

Comments
 (0)