src/lib/CopyButton/CopyButton.svelte (76 lines of code) (raw):

<script lang="ts"> import type { SvelteComponent } from 'svelte'; import { onDestroy } from 'svelte'; import IconCopy from '../Icons/IconCopy.svelte'; import { tooltip } from '../utils/tooltip'; export const hydrate = true; export let classNames = ''; export let label = ''; export let noIcon = false; export let icon: typeof SvelteComponent | undefined = undefined; export let style: 'blank' | 'button' | 'button-clear' | 'text' = 'text'; export let title = ''; export let value: string; export let successType: 'tooltip' | 'text' = 'tooltip'; export let successText: string = 'Copied'; let isSuccess = false; let timeout: any; onDestroy(() => { if (timeout) { clearTimeout(timeout); } }); function handleClick() { copyToClipboard(value); isSuccess = true; if (timeout) { clearTimeout(timeout); } timeout = setTimeout(() => { isSuccess = false; }, 1000); } function copyToClipboard(value: string): void { const textArea = document.createElement('textarea'); document.body.appendChild(textArea); textArea.value = value; textArea.select(); document.execCommand('copy'); document.body.removeChild(textArea); } </script> {#key isSuccess} <button class="border-gray-500 {classNames} {style !== 'blank' ? 'inline-flex cursor-pointer items-center text-sm focus:outline-hidden' : ''} {['button', 'button-clear'].includes(style) ? 'bg-white dark:bg-gray-900' : ''} {style === 'text' ? 'mx-0.5' : ''} {style === 'button' ? 'btn' : ''} {style === 'button-clear' ? 'rounded-md border p-1 shadow-xs' : ''} {!isSuccess && ['button-clear', 'text'].includes(style) ? 'text-gray-600' : ''} {isSuccess && style !== 'blank' ? 'text-green-500' : ''} " on:click|preventDefault|stopPropagation={handleClick} title={title || label || 'Copy to clipboard'} type="button" use:tooltip={{ content: successText, disabled: successType !== 'tooltip' || !isSuccess, showOn: 'always', opts: { placement: 'bottom' } }} > {#if !noIcon} <svelte:component this={icon ?? IconCopy} /> {/if} {#if label} {#if isSuccess && successType === 'text'} <span class="ml-1.5">{successText}</span> {:else} <span class="ml-1.5 {style === 'text' ? 'underline' : ''}"> {label} </span> {/if} {/if} </button> {/key}