Created
June 28, 2025 23:38
-
-
Save milksense/b48e5400c574d061283862a36bd8080c to your computer and use it in GitHub Desktop.
This file contains hidden or 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
type Options = { | |
/** The time before the copied status is reset. */ | |
delay: number; | |
/** Whether to reset the copied status after a delay. */ | |
reset: boolean; | |
}; | |
/** Use this hook to copy text to the clipboard and show a copied state. | |
* | |
* ## Usage | |
* ```svelte | |
* <script lang="ts"> | |
* import { UseClipboard } from "$lib/hooks/use-clipboard.svelte"; | |
* | |
* const clipboard = new UseClipboard(); | |
* </script> | |
* | |
* <button onclick={clipboard.copy('Hello, World!')}> | |
* {#if clipboard.copied === 'success'} | |
* Copied! | |
* {:else if clipboard.copied === 'failure'} | |
* Failed to copy! | |
* {:else} | |
* Copy | |
* {/if} | |
* </button> | |
* ``` | |
* | |
*/ | |
export class UseClipboard { | |
#copiedStatus = $state<"success" | "failure">(); | |
delay: number; | |
reset: boolean; | |
timeout: ReturnType<typeof setTimeout> | undefined = undefined; | |
#lastCopied = $state<string | undefined>(undefined); | |
constructor({ delay = 2000, reset = true }: Partial<Options> = {}) { | |
this.delay = delay; | |
this.reset = reset; | |
} | |
/** Copies the given text to the users clipboard. | |
* | |
* ## Usage | |
* ```ts | |
* clipboard.copy('Hello, World!'); | |
* ``` | |
* | |
* @param text | |
* @returns | |
*/ | |
async copy(_text: string | number): Promise<"success" | "failure"> { | |
const text = typeof _text === "number" ? _text.toString() : _text; | |
if (this.timeout) { | |
this.#copiedStatus = undefined; | |
clearTimeout(this.timeout); | |
} | |
try { | |
await navigator.clipboard.writeText(text); | |
this.#copiedStatus = "success"; | |
this.#lastCopied = text; | |
if (this.reset) { | |
this.timeout = setTimeout(() => { | |
this.#copiedStatus = undefined; | |
}, this.delay); | |
} | |
} catch { | |
// an error can occur when not in the browser or if the user hasn't given clipboard access | |
this.#copiedStatus = "failure"; | |
if (this.reset) { | |
this.timeout = setTimeout(() => { | |
this.#copiedStatus = undefined; | |
}, this.delay); | |
} | |
} | |
return this.#copiedStatus; | |
} | |
/** True when the user has just copied to the clipboard. */ | |
get copied(): boolean { | |
return this.#copiedStatus === "success"; | |
} | |
/** Indicates whether a copy has occurred | |
* and gives a status of either `success` or `failure`. */ | |
get status(): "success" | "failure" | undefined { | |
return this.#copiedStatus; | |
} | |
/** | |
* The last copied text. | |
*/ | |
get lastCopied(): string | undefined { | |
return this.#lastCopied; | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment