Skip to content

Commit b15c476

Browse files
wesruvheyMPgithub-actions[bot]zhawkins
authored
feat: Make it so PFE-Clipboard can copy arbitrary content (#1795)
* Added proof of concept for copying arbitrary content Need docs update and tests still * ported pfe-clipboard tests to web-test-runner * removed old slotchange event * removed arrow functions to allow individual tests to override timeouts. * Adding disabled states for when copy target has issues * Writing tests to for disabled state and fixing resulting bugs * Cleaning up code a bit * Removing checks for copying text content of HTML Discussed with Kyle Buchanan, Michael Clayton, and other CPFED folks, guarding against the HTML element that will have it's text copied isn't really worth it. There isn't a good way to know that it _should_ be disabled and then _should_ be enabled later. Better to leave it to the click event, and hopefully things were setup so it'll work when the user clicks on it * Added docs and fixed some bugs * Updated changelog * On element copy, use innerText instead of innerHTML, think it's safer * added correct icon colors * ignore [disabled] on focus,hover states * update docs * Removing unnecessary event listener ... removal. * update docs * Revert "update docs" This reverts commit 8de71ec. * Providing better default UI for buttons not copying a URL * Updating documentation for pfe-clipboard based on updates * Updating default content for icon slot in tests * chore: update docs Co-authored-by: heyMP <[email protected]> Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com> Co-authored-by: Zack Hawkins <[email protected]>
1 parent f33ba4a commit b15c476

15 files changed

+591
-332
lines changed

CHANGELOG-1.x.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
- [HASH](#URL) feat: Update pfe-clipboard so it can copy arbitrary content, and updated tests to new framework
12
- [HASH](#URL) fix: Update primary-detail resize listener so it only runs with width changes
23

34
# 1.11.2 (2021-09-29)

elements/pfe-clipboard/README.md

Lines changed: 54 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,33 @@ A button to copy the current URL to the system clipboard.
99
<pfe-clipboard role="button" tabindex="0"></pfe-clipboard>
1010
```
1111

12+
### Copy text from an element on the page
13+
14+
Add a valid HTML selector to the target attribute, component will use `document.querySelector` to find the first element that the selector fits.
15+
16+
We recommend using ID's.
17+
18+
```html
19+
<pfe-clipboard role="button" tabindex="0" copy-from="#copy-me"></pfe-clipboard>
20+
<div id="copy-me">This text will get copied</div>
21+
22+
<pfe-clipboard role="button" tabindex="0" copy-from="body .copy-me"></pfe-clipboard>
23+
<div class="copy-me">This text will get copied</div>
24+
```
25+
26+
### Copy arbitrary content
27+
Set the attribute `copy-from="property"` and set the property `contentToCopy` on the component with what should be copied.
28+
```html
29+
<!-- Markup on the page -->
30+
<pfe-clipboard role="button" tabindex="0" copy-from="property" id="copyButton"></pfe-clipboard>
31+
```
32+
```js
33+
// In some JS for the page
34+
window.addEventListener('load', function() {
35+
document.getElementById('copyButton').contentToCopy('Wakka wakka!');
36+
});
37+
```
38+
1239
### Optionally hide the icon
1340
```html
1441
<pfe-clipboard no-icon role="button" tabindex="0"></pfe-clipboard>
@@ -66,6 +93,10 @@ mouse clicks as well as enter and space key presses per the recommendation of
6693

6794
## Attributes
6895

96+
- `copy-from`: Defaults to `url`, decides what should be copied. Possible values are:
97+
- `url` Will copy the current page's URL.
98+
- `property` Will copy the text from `contentToCopy` method of the component.
99+
- A DOMString (e.g. `#copyTarget` or `.code-sample pre`) will use `document.querySelector()` with the given text to find the target and will use `innerText` on most elements or `value` on form fields.
69100
- `no-icon`: Optional boolean attribute that, when present, removes the icon from the template.
70101
- `copied-duration`: Specify the amount of time in seconds the copy success text should be visible.
71102

@@ -87,7 +118,9 @@ Available hooks for styling:
87118
| `--pfe-clipboard--Color--hover` | `var(--pfe-broadcasted--link--hover, #004080)` | N/A |
88119

89120
## Events
90-
Describe any events that are accessible external to the web component. There is no need to describe all the internal-only functions.
121+
### pfe-clipboard:connected
122+
123+
Let's you know when the component has run connectedCallback, useful for knowing when you can set the `contentToCopy` method and know that it will work.
91124

92125
### pfe-clipboard:copied
93126

@@ -99,17 +132,17 @@ detail: {
99132
}
100133
```
101134

102-
## API
135+
## Methods
103136

104-
### copyURLToClipboard()
137+
### contentToCopy
138+
139+
A setter to set the content you would like to copy, only works if `copy-from` attribute is set to `property`. Recommend using `pfe-clipboard:connected` event to know when the component's setter is ready.
105140

106-
Copy url to the user's system clipboard
141+
### copyTextToClipboard()
107142

108-
If available, it will use the new Navigator API to access the system clipboard
109-
https://developer.mozilla.org/en-US/docs/Web/API/Navigator/clipboard
143+
Will copy the text the component is set to copy to the system clipboard
110144

111-
If unavailable, it will use the legacy execCommand("copy")
112-
https://developer.mozilla.org/en-US/docs/Web/API/Document/execCommand
145+
If available, it will use the new [Navigator API](https://developer.mozilla.org/en-US/docs/Web/API/Navigator/clipboard) to access the system clipboard. If unavailable, it will use the legacy [execCommand("copy")](https://developer.mozilla.org/en-US/docs/Web/API/Document/execCommand).
113146

114147
#### Returns
115148

@@ -121,6 +154,19 @@ document.querySelector("pfe-clipboard").copyURLToClipboard()
121154
.catch(error => console.error(error));
122155
```
123156

157+
### copyURLToClipboard()
158+
159+
Deprecrated, will copy the current URL to the clipboard using `copyTextToClipboard`.
160+
161+
#### Returns
162+
163+
- `Promise<string>` url
164+
165+
```javascript
166+
document.querySelector("pfe-clipboard").copyURLToClipboard()
167+
.then(url => console.log(`Successfully copied: ${url}`))
168+
.catch(error => console.error(error));
169+
```
124170
## Dependencies
125171

126172
None.

elements/pfe-clipboard/demo/index.html

Lines changed: 56 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,40 @@ <h2>Clipboard: with custom icon</h2>
6363
<pfe-icon slot="icon" icon="web-icon-globe"></pfe-icon>
6464
</pfe-clipboard>
6565

66+
<h2>Clipboard: with custom text & copying text from element</h2>
67+
<pfe-clipboard role="button" tabindex="0" copy-from="#textToCopy">
68+
<span slot="text">This will copy the text in the text field below!</span>
69+
<span slot="text--success">Making some copies!</span>
70+
</pfe-clipboard>
71+
<input type="text" id="textToCopy" value="This text will be copied!!11"></input>
72+
73+
<h2>Clipboard: Copying text from property</h2>
74+
<pfe-clipboard role="button" tabindex="0" copy-from="property" id="propertyCopy">
75+
</pfe-clipboard>
76+
<script>
77+
window.addEventListener('load', function() {
78+
document.getElementById('propertyCopy').contentToCopy = ' <h2>Clipboard: with custom text & copying text from element</h2>\n <pfe-clipboard role="button" tabindex="0" copy-from="#textToCopy">\n <span slot="text">This will copy the text in the text field below!</span>\n <span slot="text--success">Making some copies!</span>\n </pfe-clipboard>\n <input type="text" id="textToCopy" value="This text will be copied!!11"></input>';
79+
})
80+
</script>
81+
82+
<h2>Clipboard: with custom success text duration.</h2>
83+
<pfe-clipboard role="button" tabindex="0" copied-duration="5"></pfe-clipboard>
84+
</pfe-band>
85+
86+
<pfe-band color="darkest">
87+
<p>This element embeds a copy url button on your site.</p>
88+
89+
<h2>Clipboard</h2>
90+
<pfe-clipboard role="button" tabindex="0"></pfe-clipboard>
91+
92+
<h2>Clipboard with no icon</h2>
93+
<pfe-clipboard no-icon role="button" tabindex="0"></pfe-clipboard>
94+
95+
<h2>Clipboard: with custom icon</h2>
96+
<pfe-clipboard role="button" tabindex="0">
97+
<pfe-icon slot="icon" icon="web-icon-globe"></pfe-icon>
98+
</pfe-clipboard>
99+
66100
<h2>Clipboard: with custom text</h2>
67101
<pfe-clipboard role="button" tabindex="0">
68102
<span slot="text">You can totally click to copy url</span>
@@ -73,7 +107,7 @@ <h2>Clipboard: with custom success text duration.</h2>
73107
<pfe-clipboard role="button" tabindex="0" copied-duration="5"></pfe-clipboard>
74108
</pfe-band>
75109

76-
<pfe-band color="darkest">
110+
<pfe-band color="accent">
77111
<p>This element embeds a copy url button on your site.</p>
78112

79113
<h2>Clipboard</h2>
@@ -97,6 +131,27 @@ <h2>Clipboard: with custom success text duration.</h2>
97131
<pfe-clipboard role="button" tabindex="0" copied-duration="5"></pfe-clipboard>
98132
</pfe-band>
99133

134+
<pfe-band color="lightest">
135+
<h2>Error cases</h2>
136+
137+
<h3>Set to copy "property", but Property doesn't exist</h3>
138+
<pfe-clipboard role="button" tabindex="0" copy-from="property">
139+
<span slot="text">Oops, I didn't set the property to be copied</span>
140+
</pfe-clipboard>
141+
142+
<h3>Set to copy a non-existent selector</h3>
143+
<pfe-clipboard role="button" tabindex="0" copy-from="#wakka-wakka">
144+
<span slot="text">Oops, I didn't set a valid selector to be copied</span>
145+
</pfe-clipboard>
146+
147+
</pfe-band>
148+
149+
<pfe-band color="darkest">
150+
<pfe-clipboard role="button" tabindex="0" copy-from="property">
151+
<span slot="text">Oops, I didn't set the property to be copied</span>
152+
</pfe-clipboard>
153+
</pfe-band>
154+
100155
</body>
101156

102157
</html>

elements/pfe-clipboard/docs/index.md

Lines changed: 74 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ tags:
1717

1818
::: section
1919
## Overview
20-
A button to copy the current URL to the system clipboard.
20+
A button to copy the text to the system clipboard. By default it will copy the current URL, but it can also copy the text of an element, or arbitrary content set as a property on the component.
2121

2222
<pfe-clipboard role="button" tabindex="0"></pfe-clipboard>
2323
:::
@@ -55,6 +55,38 @@ npm install @patternfly/pfe-clipboard
5555
</pfe-clipboard>
5656
```
5757

58+
### Copying text from element with custom button text
59+
<pfe-clipboard role="button" tabindex="0" copy-from="#textToCopy">
60+
<span slot="text">This will copy the text in the text field below!</span>
61+
</pfe-clipboard>
62+
<input type="text" id="textToCopy" value="This text will be copied!"></input>
63+
64+
```html
65+
<pfe-clipboard role="button" tabindex="0" copy-from="#textToCopy">
66+
<span slot="text">This will copy the text in the text field below!</span>
67+
</pfe-clipboard>
68+
<input type="text" id="textToCopy" value="This text will be copied!"></input>
69+
```
70+
71+
### Copying text from property
72+
<pfe-clipboard role="button" tabindex="0" copy-from="property" id="propertyCopy">
73+
</pfe-clipboard>
74+
<script>
75+
window.addEventListener('load', function() {
76+
document.getElementById('propertyCopy').contentToCopy = ' <h2>Clipboard: with custom text & copying text from element</h2>\n <pfe-clipboard role="button" tabindex="0" copy-from="#textToCopy">\n <span slot="text">This will copy the text in the text field below!</span>\n <span slot="text--success">Making some copies!</span>\n </pfe-clipboard>\n <input type="text" id="textToCopy" value="This text will be copied!!11"></input>';
77+
})
78+
</script>
79+
80+
```html
81+
<pfe-clipboard role="button" tabindex="0" copy-from="property" id="propertyCopy">
82+
</pfe-clipboard>
83+
<script>
84+
window.addEventListener('load', function() {
85+
document.getElementById('propertyCopy').contentToCopy = ' <h2>Clipboard: with custom text & copying text from element</h2>\n <pfe-clipboard role="button" tabindex="0" copy-from="#textToCopy">\n <span slot="text">This will copy the text in the text field below!</span>\n <span slot="text--success">Making some copies!</span>\n </pfe-clipboard>\n <input type="text" id="textToCopy" value="This text will be copied!!11"></input>';
86+
})
87+
</script>
88+
```
89+
5890
### Override the copied notification text
5991
<pfe-clipboard role="button" tabindex="0">
6092
<span slot="text--success">URL Copied to clipboard</span>
@@ -126,6 +158,13 @@ Optionally override the text of the success state which defaults to `Copied`.
126158
::: section
127159
## Attributes
128160

161+
### copy-from
162+
Defaults to `url`, decides what should be copied. Possible values are:
163+
164+
- `url` Will copy the current page's URL.
165+
- `property` Will copy the text from `contentToCopy` method of the component.
166+
- A DOMString (e.g. `#copyTarget` or `.code-sample pre`) will use `document.querySelector()` with the given text to find first match and will use `innerText` on most elements or `value` on form fields to get text to be copied.
167+
129168
### no-icon
130169
Optional boolean attribute that, when present, removes the icon from the template.
131170

@@ -135,24 +174,48 @@ Specify the amount of time in seconds the copy success text should be visible.
135174

136175
::: section
137176
## Methods
138-
### copyURLToClipboard()
139177

140-
Copy url to the user's system clipboard
178+
### contentToCopy
179+
180+
A setter to set the content you would like to copy, only works if `copy-from` attribute is set to `property`. Recommend using `pfe-clipboard:connected` event to know when the component's setter is ready.
181+
182+
### copyTextToClipboard()
183+
184+
Will copy the text the component is set to copy to the system clipboard
141185

142186
If available, it will use the new [Navigator API](https://developer.mozilla.org/en-US/docs/Web/API/Navigator/clipboard) to access the system clipboard. If unavailable, it will use the legacy [execCommand("copy")](https://developer.mozilla.org/en-US/docs/Web/API/Document/execCommand).
143187

144188
#### Returns
145189

190+
- `Promise<string>` text
191+
192+
```javascript
193+
document.querySelector("pfe-clipboard").copyTextToClipboard(text)
194+
.then(res => console.log(`Successfully copied: ${res}`))
195+
.catch(error => console.error(error));
196+
```
197+
198+
### copyURLToClipboard()
199+
200+
Deprecrated, will copy the current URL to the clipboard using `copyTextToClipboard`.
201+
202+
#### Returns
203+
146204
- `Promise<string>` url
147205

148206
```javascript
149207
document.querySelector("pfe-clipboard").copyURLToClipboard()
150208
.then(url => console.log(`Successfully copied: ${url}`))
151209
.catch(error => console.error(error));
210+
```
152211
:::
153212

154213
::: section
155214
## Events
215+
### pfe-clipboard:connected
216+
217+
Let's you know when the component has run connectedCallback, useful for knowing when you can set the `contentToCopy` method and know that it will work.
218+
156219
### pfe-clipboard:copied
157220

158221
Fires when the current url is successfully copied the user's system clipboard.
@@ -170,13 +233,18 @@ detail: {
170233
| Variable name | Default value | Region |
171234
| --- | --- | --- |
172235
| `--pfe-clipboard--Color` | `var(--pfe-broadcasted--link, #06c)` | N/A |
236+
| `--pfe-clipboard--Color--focus` | `var(--pfe-broadcasted--link--focus, #004080)` | N/A |
237+
| `--pfe-clipboard--Color--hover` | `var(--pfe-broadcasted--link--hover, #004080)` | N/A |
173238
| `--pfe-clipboard--FontWeight` | `var(--pfe-theme--font-weight--light, 300)` | N/A |
174239
| `--pfe-clipboard--FontSize` | `1rem` | N/A |
175240
| `--pfe-clipboard--Padding` | `6px 16px` | N/A |
176241
| `--pfe-clipboard--icon--Width` | `16px` | `icon` |
177242
| `--pfe-clipboard--icon--Height` | `auto` | `icon` |
178243
| `--pfe-clipboard--icon--margin` | `0 0.4825rem 0 0` | `icon` |
179-
| `--pfe-clipboard--icon--Color` | `#6a6e73` | `icon` |
180-
| `--pfe-clipboard--Color--focus` | `var(--pfe-broadcasted--link--focus, #004080)` | N/A |
181-
| `--pfe-clipboard--Color--hover` | `var(--pfe-broadcasted--link--hover, #004080)` | N/A |
244+
| `--pfe-clipboard--icon--Color` | `var(--pfe-theme--color--text--muted, #6a6e73)` | `icon` |
245+
| `--pfe-clipboard--icon--Color--hover` | `var(--pfe-theme--color--ui-base--hover, #151515)` | `icon` |
246+
| `--pfe-clipboard--icon--Color--dark` | `var(--pfe-theme--color--text--muted--on-dark, #d2d2d2)` | `icon` |
247+
| `--pfe-clipboard--icon--Color--dark--hover` | `var(--pfe-theme--color--text--on-dark, #fff)` | `icon` |
248+
| `--pfe-clipboard--icon--Color--saturated` | `var(--pfe-theme--color--text--muted--on-saturated, #d2d2d2)` | `icon` |
249+
| `--pfe-clipboard--icon--Color--saturated--hover` | `var(--pfe-theme--color--text--on-saturated, #fff)` | `icon` |
182250
:::
Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,15 @@
11
<!-- icon slot -->
22
${!this.noIcon ? `
33
<div class="pfe-clipboard__icon">
4-
<slot name="icon" id="icon">
5-
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 15.277 16"><g transform="translate(-2.077 -1.807)"><path class="a" d="M15.34,2.879a3.86,3.86,0,0,0-5.339,0L6.347,6.545a3.769,3.769,0,0,0,0,5.339.81.81,0,0,0,1.132,0,.823.823,0,0,0,0-1.145A2.144,2.144,0,0,1,7.5,7.677l3.641-3.654a2.161,2.161,0,1,1,3.049,3.062l-.8.8a.811.811,0,1,0,1.145,1.132l.8-.8a3.769,3.769,0,0,0,0-5.339Z" transform="translate(0.906 0)"/><path class="a" d="M10.482,6.822a.823.823,0,0,0,0,1.145,2.161,2.161,0,0,1,0,3.049L7.343,14.155a2.161,2.161,0,0,1-3.062,0,2.187,2.187,0,0,1,0-3.062l.193-.116a.823.823,0,0,0,0-1.145.811.811,0,0,0-1.132,0l-.193.193a3.86,3.86,0,0,0,0,5.339,3.86,3.86,0,0,0,5.339,0l3.126-3.139A3.731,3.731,0,0,0,12.72,9.562a3.769,3.769,0,0,0-1.094-2.74A.823.823,0,0,0,10.482,6.822Z" transform="translate(0 1.37)"/></g></svg>
6-
</slot>
4+
<slot name="icon" id="icon">
5+
<svg id="icon--url" xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 15.277 16"><g transform="translate(-2.077 -1.807)"><path class="a" d="M15.34,2.879a3.86,3.86,0,0,0-5.339,0L6.347,6.545a3.769,3.769,0,0,0,0,5.339.81.81,0,0,0,1.132,0,.823.823,0,0,0,0-1.145A2.144,2.144,0,0,1,7.5,7.677l3.641-3.654a2.161,2.161,0,1,1,3.049,3.062l-.8.8a.811.811,0,1,0,1.145,1.132l.8-.8a3.769,3.769,0,0,0,0-5.339Z" transform="translate(0.906 0)"/><path class="a" d="M10.482,6.822a.823.823,0,0,0,0,1.145,2.161,2.161,0,0,1,0,3.049L7.343,14.155a2.161,2.161,0,0,1-3.062,0,2.187,2.187,0,0,1,0-3.062l.193-.116a.823.823,0,0,0,0-1.145.811.811,0,0,0-1.132,0l-.193.193a3.86,3.86,0,0,0,0,5.339,3.86,3.86,0,0,0,5.339,0l3.126-3.139A3.731,3.731,0,0,0,12.72,9.562a3.769,3.769,0,0,0-1.094-2.74A.823.823,0,0,0,10.482,6.822Z" transform="translate(0 1.37)"/></g></svg>
6+
<svg id="icon--copy" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="32" height="32" viewBox="0 0 32 32"><g></g><path d="M30.286 6.857q0.714 0 1.214 0.5t0.5 1.214v21.714q0 0.714-0.5 1.214t-1.214 0.5h-17.143q-0.714 0-1.214-0.5t-0.5-1.214v-5.143h-9.714q-0.714 0-1.214-0.5t-0.5-1.214v-12q0-0.714 0.357-1.571t0.857-1.357l7.286-7.286q0.5-0.5 1.357-0.857t1.571-0.357h7.429q0.714 0 1.214 0.5t0.5 1.214v5.857q1.214-0.714 2.286-0.714h7.429zM20.571 10.661l-5.339 5.339h5.339v-5.339zM9.143 3.804l-5.339 5.339h5.339v-5.339zM12.643 15.357l5.643-5.643v-7.429h-6.857v7.429q0 0.714-0.5 1.214t-1.214 0.5h-7.429v11.429h9.143v-4.571q0-0.714 0.357-1.571t0.857-1.357zM29.714 29.714v-20.571h-6.857v7.429q0 0.714-0.5 1.214t-1.214 0.5h-7.429v11.429h16z"/></svg>
7+
</slot>
78
</div>
89
` : ""}
910
<div class="pfe-clipboard__text">
10-
<slot name="text" id="text">Copy URL</slot>
11+
<slot name="text" id="text">Copy</slot>
1112
</div>
1213
<div class="pfe-clipboard__text--success" role="alert">
1314
<slot name="text--success" id="text--success">Copied</slot>
14-
</div>
15+
</div>

0 commit comments

Comments
 (0)