-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Added Trim and CopyButton components
- Loading branch information
1 parent
2c36c4c
commit 03e8d06
Showing
30 changed files
with
546 additions
and
54 deletions.
There are no files selected for viewing
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
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,3 @@ | ||
.copy-button { | ||
color: #6c757d; | ||
} |
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 @@ | ||
import { Component, Prop, h, State } from '@stencil/core'; | ||
import { faCheck, faCopy, IconDefinition } from '@fortawesome/free-solid-svg-icons'; | ||
import { copyToClipboard } from 'utils/copyToClipboard'; | ||
|
||
@Component({ | ||
tag: 'copy-button', | ||
styleUrl: 'copy-button.css', | ||
shadow: true, | ||
}) | ||
export class CopyButton { | ||
@Prop() class?: string = 'copy-button'; | ||
@Prop() copyIcon: IconDefinition = faCopy; | ||
@Prop() successIcon: IconDefinition = faCheck; | ||
@Prop() text: string; | ||
|
||
@State() isSuccess: boolean = false; | ||
|
||
private timeoutId: number | undefined; | ||
|
||
private handleClick = async (event: MouseEvent) => { | ||
event.preventDefault(); | ||
event.stopPropagation(); | ||
|
||
const trimmedText = this.text ? this.text.trim() : this.text; | ||
const success = await copyToClipboard(trimmedText); | ||
|
||
this.isSuccess = success; | ||
|
||
if (success) { | ||
this.timeoutId = window.setTimeout(() => { | ||
this.isSuccess = false; | ||
}, 1000); | ||
} | ||
}; | ||
|
||
disconnectedCallback() { | ||
// Clear the timeout if the component is unmounted | ||
if (this.timeoutId) { | ||
clearTimeout(this.timeoutId); | ||
this.timeoutId = undefined; // Reset the timeout ID | ||
} | ||
} | ||
|
||
render() { | ||
return ( | ||
<a href="/#" class={this.class} onClick={this.handleClick}> | ||
<fa-icon icon={this.isSuccess ? this.successIcon : this.copyIcon}></fa-icon> | ||
</a> | ||
); | ||
} | ||
} |
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,109 @@ | ||
import { newSpecPage } from '@stencil/core/testing'; | ||
import { CopyButton } from '../copy-button'; | ||
import * as copyUtils from 'utils/copyToClipboard'; | ||
|
||
describe('CopyButton', () => { | ||
it('renders with default props', async () => { | ||
const page = await newSpecPage({ | ||
components: [CopyButton], | ||
html: '<copy-button text="Copy me"></copy-button>', | ||
}); | ||
|
||
expect(page.root).toEqualHtml(` | ||
<copy-button text="Copy me"> | ||
<mock:shadow-root> | ||
<a href="/#" class="copy-button"> | ||
<fa-icon></fa-icon> | ||
</a> | ||
</mock:shadow-root> | ||
</copy-button> | ||
`); | ||
}); | ||
|
||
it('renders with custom class', async () => { | ||
const page = await newSpecPage({ | ||
components: [CopyButton], | ||
html: '<copy-button class="custom-class" text="Copy me"></copy-button>', | ||
}); | ||
|
||
expect(page.root).toEqualHtml(` | ||
<copy-button class="custom-class" text="Copy me"> | ||
<mock:shadow-root> | ||
<a href="/#" class="custom-class"> | ||
<fa-icon></fa-icon> | ||
</a> | ||
</mock:shadow-root> | ||
</copy-button> | ||
`); | ||
}); | ||
|
||
it('changes to success icon when clicked and copy succeeds', async () => { | ||
jest.spyOn(copyUtils, 'copyToClipboard').mockResolvedValue(true); | ||
|
||
const page = await newSpecPage({ | ||
components: [CopyButton], | ||
html: '<copy-button text="Copy me"></copy-button>', | ||
}); | ||
|
||
const copyButton = page.root; | ||
const anchor = copyButton.shadowRoot.querySelector('a'); | ||
|
||
await anchor.click(); | ||
await page.waitForChanges(); | ||
|
||
expect(copyButton).toEqualHtml(` | ||
<copy-button text="Copy me"> | ||
<mock:shadow-root> | ||
<a href="/#" class="copy-button"> | ||
<fa-icon></fa-icon> | ||
</a> | ||
</mock:shadow-root> | ||
</copy-button> | ||
`); | ||
}); | ||
|
||
it('remains with copy icon when clicked and copy fails', async () => { | ||
jest.spyOn(copyUtils, 'copyToClipboard').mockResolvedValue(false); | ||
|
||
const page = await newSpecPage({ | ||
components: [CopyButton], | ||
html: '<copy-button text="Copy me"></copy-button>', | ||
}); | ||
|
||
const copyButton = page.root; | ||
const anchor = copyButton.shadowRoot.querySelector('a'); | ||
|
||
await anchor.click(); | ||
await page.waitForChanges(); | ||
|
||
expect(copyButton).toEqualHtml(` | ||
<copy-button text="Copy me"> | ||
<mock:shadow-root> | ||
<a href="/#" class="copy-button"> | ||
<fa-icon></fa-icon> | ||
</a> | ||
</mock:shadow-root> | ||
</copy-button> | ||
`); | ||
}); | ||
|
||
it('prevents default behavior and stops propagation on click', async () => { | ||
const page = await newSpecPage({ | ||
components: [CopyButton], | ||
html: '<copy-button text="Copy me"></copy-button>', | ||
}); | ||
|
||
const copyButton = page.root; | ||
const anchor = copyButton.shadowRoot.querySelector('a'); | ||
|
||
const mockEvent = { | ||
preventDefault: jest.fn(), | ||
stopPropagation: jest.fn(), | ||
}; | ||
|
||
anchor.dispatchEvent(new MouseEvent('click', mockEvent as any)); | ||
|
||
expect(mockEvent.preventDefault).toHaveBeenCalledTimes(1); | ||
expect(mockEvent.stopPropagation).toHaveBeenCalledTimes(1); | ||
}); | ||
}); |
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
Oops, something went wrong.