Skip to content

feat: Adds uui-button-copy-text #985

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 43 commits into from
Mar 4, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
43 commits
Select commit Hold shift + click to select a range
380f454
Adds scaffolding files for uui-copy
warrenbuckley Dec 16, 2024
9620a66
Adds first attempt at uui-copy
warrenbuckley Dec 23, 2024
8bffab2
Make eslint happy
warrenbuckley Dec 24, 2024
0901ebe
WIP: To add useful tests
warrenbuckley Jan 2, 2025
75aeaa1
Update packages/uui-copy/lib/uui-copy.element.ts
warrenbuckley Jan 7, 2025
54943f7
Update packages/uui-copy/lib/uui-copy.element.ts
warrenbuckley Jan 7, 2025
474a352
Remove the reflect on the props as PR suggestion
warrenbuckley Jan 7, 2025
3b0bd2c
Merge branch 'feature/uui-copy' of https://github.com/warrenbuckley/U…
warrenbuckley Jan 7, 2025
a291199
Adds in the util func demandCustomElement in ctor as suggested by Jacob
warrenbuckley Jan 7, 2025
e46e459
Fix typo
warrenbuckley Jan 7, 2025
de55e9b
Remove the tests for the clipboard API - agreed with Jacob to keep th…
warrenbuckley Jan 7, 2025
9ca79f3
Waits 2 seconds before setting uuiButton state to success
warrenbuckley Jan 7, 2025
3c1fc10
Fix the problem with the story, as you needed to browse to uui-button…
warrenbuckley Jan 7, 2025
65a4e60
Adds the LabelMixin to add the prop.
warrenbuckley Jan 7, 2025
c72d0b7
Make the sonar code quality thing a bit happier
warrenbuckley Jan 7, 2025
c371aa8
Add a prop & story for the timeout delay for the animation/state of t…
warrenbuckley Jan 7, 2025
dffdef4
An explicit story to help with docs to show how to use a different icon
warrenbuckley Jan 7, 2025
bf86ac4
Fix test failing on CI only - not locally
warrenbuckley Jan 7, 2025
8e2bb32
Rename from uui-copy to more explicit uui-text-copy-button
warrenbuckley Jan 10, 2025
fbe484f
Merge branch 'umbraco:v1/contrib' into feature/uui-copy
warrenbuckley Jan 10, 2025
5e6134f
Renaming files & folders was bein a PITA and things not working 🤬
warrenbuckley Jan 12, 2025
9a4ed42
FIx problem from test
warrenbuckley Jan 13, 2025
2a8db77
Remove console.log
warrenbuckley Jan 15, 2025
ac50a35
Wrap with try/catch & drop the uneeded .then()
warrenbuckley Jan 15, 2025
b8437b0
Merge branch 'v1/contrib' into feature/uui-copy
nielslyngsoe Feb 4, 2025
03e09a3
Merge branch 'v1/contrib' into feature/uui-copy
warrenbuckley Feb 6, 2025
5276fc7
Removes the event from bubbling, not sure there is a valid reason to
warrenbuckley Feb 8, 2025
3999917
Merge branch 'v1/contrib' into feature/uui-copy
warrenbuckley Feb 24, 2025
e4e1ae8
Merge branch 'v1/contrib' into feature/uui-copy
iOvergaard Mar 4, 2025
f9087d8
feat: rename element to `uui-button-copy-text`
iOvergaard Mar 4, 2025
f9631b4
feat: rename to uui-button-copy-text and add dependencies
iOvergaard Mar 4, 2025
2535b1f
feat: rename to uui-button-copy-text and add dependencies
iOvergaard Mar 4, 2025
e7ddf6d
feat: uui-icon package is optional
iOvergaard Mar 4, 2025
69b7b03
feat: uui-icon package is optional
iOvergaard Mar 4, 2025
11479a8
feat: extend from uui-button and rename `value` to `text`
iOvergaard Mar 4, 2025
67d6eef
feat: copy only from other element if there is no 'value' field
iOvergaard Mar 4, 2025
87e2c02
feat: use real class property to hold copied value
iOvergaard Mar 4, 2025
9614380
feat: clear animation timer if element disconnects
iOvergaard Mar 4, 2025
6f4de34
feat: rename base folder
iOvergaard Mar 4, 2025
a09260f
chore: format lint
iOvergaard Mar 4, 2025
fbf5f8b
Merge branch 'v1/contrib' into pr/warrenbuckley/985
iOvergaard Mar 4, 2025
31614d3
docs: update README
iOvergaard Mar 4, 2025
147fed9
chore: cleanup old files
iOvergaard Mar 4, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
23 changes: 23 additions & 0 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

31 changes: 31 additions & 0 deletions packages/uui-button-copy-text/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
# uui-button-copy-text

![npm](https://img.shields.io/npm/v/@umbraco-ui/uui-button-copy-text?logoColor=%231B264F)

Umbraco style text-copy component.

## Installation

### ES imports

```zsh
npm i @umbraco-ui/uui-button-copy-text
```

Import the registration of `<uui-button-copy-text>` via:

```javascript
import '@umbraco-ui/uui-button-copy-text';
```

When looking to leverage the `UUIButtonCopyTextElement` base class as a type and/or for extension purposes, do so via:

```javascript
import { UUIButtonCopyTextElement } from '@umbraco-ui/uui-button-copy-text';
```

## Usage

```html
<uui-button-copy-text></uui-button-copy-text>
```
15 changes: 15 additions & 0 deletions packages/uui-button-copy-text/lib/UUICopyTextEvent.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
import { UUIEvent } from '@umbraco-ui/uui-base/lib/events';
import { UUIButtonCopyTextElement } from './uui-button-copy-text.element';

export class UUICopyTextEvent extends UUIEvent<
{ text: string },
UUIButtonCopyTextElement
> {
public static readonly COPIED: string = 'copied';
public static readonly COPYING: string = 'copying';

/**
* The text content that is about to be copied to the clipboard
*/
public text: string | null = null;
}
2 changes: 2 additions & 0 deletions packages/uui-button-copy-text/lib/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
export * from './uui-button-copy-text.element';
export * from './UUICopyTextEvent';
126 changes: 126 additions & 0 deletions packages/uui-button-copy-text/lib/uui-button-copy-text.element.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,126 @@
import { html } from 'lit';
import { property } from 'lit/decorators.js';
import { defineElement } from '@umbraco-ui/uui-base/lib/registration';
import { demandCustomElement } from '@umbraco-ui/uui-base/lib/utils';
import { UUIButtonElement } from '@umbraco-ui/uui-button/lib';
import { UUICopyTextEvent } from './UUICopyTextEvent.js';

/**
* @summary A button to trigger text content to be copied to the clipboard
* @element uui-button-copy-text
* @dependency uui-button
* @dependency uui-icon
* @fires {UUICopyTextEvent} copying - Fires before the content is about to copied to the clipboard and can be used to transform or modify the data before its added to the clipboard
* @fires {UUICopyTextEvent} copied - Fires when the content is copied to the clipboard
* @slot - Use to replace the default content of the copy icon
*/
@defineElement('uui-button-copy-text')
export class UUIButtonCopyTextElement extends UUIButtonElement {
/**
* Set a string you wish to copy to the clipboard
* @type {string}
* @default ''
*/
@property({ type: String })
text: string = '';

/**
* Copies the text content from another element by specifying the ID of the element
* The ID of the element does not need to start with # like a CSS selector
* If this property is set, the value property is ignored
* @type {string}
* @attr
* @default ''
* @example copy-from="element-id"
*/
@property({ type: String, attribute: 'copy-from' })
copyFrom: string = '';

/**
* The delay in milliseconds before the button returns to its default state after a successful copy
* @type {number}
* @attr
* @default 250
*/
@property({ type: Number, attribute: 'animation-state-delay' })
animationStateDelay: number = 250;

#animationTimer?: any;

constructor() {
super();
demandCustomElement(this, 'uui-icon');

this.addEventListener('click', this.#onClick);
}

disconnectedCallback(): void {
super.disconnectedCallback();
if (this.#animationTimer) {
clearTimeout(this.#animationTimer);
}
}

readonly #onClick = async () => {
this.state = 'waiting';

// By default use the value property
let valueToCopy = this.text;

// If copy-from is set use that instead
if (this.copyFrom) {
// Try & find an element with the ID
const el = document.getElementById(this.copyFrom);
if (el) {
// Override the value to copy, if the element has a value property
// Such as uui-input or uui-textarea or native inout elements
if ('value' in el) {
valueToCopy = (el as any).value;
} else {
valueToCopy = el.textContent ?? el.innerText ?? '';
}
} else {
console.error(`Element ID ${this.copyFrom} not found to copy from`);
this.state = 'failed';
return;
}
}

const beforeCopyEv = new UUICopyTextEvent(UUICopyTextEvent.COPYING);
beforeCopyEv.text = valueToCopy;
this.dispatchEvent(beforeCopyEv);

if (beforeCopyEv.text != null) {
valueToCopy = beforeCopyEv.text;
}

try {
await navigator.clipboard.writeText(valueToCopy);
const copiedEv = new UUICopyTextEvent(UUICopyTextEvent.COPIED);
copiedEv.text = valueToCopy;
this.dispatchEvent(copiedEv);
this.#animationTimer = setTimeout(() => {
this.state = 'success';
}, this.animationStateDelay);
} catch (err) {
this.state = 'failed';
console.error('Error copying to clipboard', err);
}
};

protected override renderLabel() {
return html`
<slot class="label">
<uui-icon name="copy"></uui-icon>
</slot>
`;
}

static override readonly styles = UUIButtonElement.styles;
}

declare global {
interface HTMLElementTagNameMap {
'uui-button-copy-text': UUIButtonCopyTextElement;
}
}
Loading
Loading