File size: 1,844 Bytes
ace9a3e
98051f8
ace9a3e
7bf1507
ace9a3e
a1a6daf
 
7bf1507
a1a6daf
 
 
7bf1507
cb5990d
a1a6daf
ace9a3e
7bf1507
 
 
 
 
 
 
cb5990d
7bf1507
a1a6daf
 
59de250
ace9a3e
6bb0e6c
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
ace9a3e
cb5990d
 
ace9a3e
6bb0e6c
ace9a3e
 
 
 
 
 
 
725337f
ace9a3e
 
 
 
 
 
 
 
 
 
 
 
 
8918d96
cb5990d
ace9a3e
cb5990d
a1a6daf
cb5990d
 
 
 
a1a6daf
ace9a3e
725337f
a1a6daf
7bf1507
a1a6daf
f311ca9
ace9a3e
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
<script lang="ts">
	import { onDestroy } from "svelte";

	import CarbonCopy from "~icons/carbon/copy";

	interface Props {
		classNames?: string;
		iconClassNames?: string;
		value: string;
		children?: import("svelte").Snippet;
		onClick?: () => void;
		showTooltip?: boolean;
		disabled?: boolean;
	}

	let {
		classNames = "",
		iconClassNames = "",
		value,
		children,
		onClick,
		showTooltip = true,
		disabled = false,
	}: Props = $props();

	let isSuccess = $state(false);
	let timeout: ReturnType<typeof setTimeout>;

	const unsecuredCopy = (text: string) => {
		//Old or insecure browsers

		const textArea = document.createElement("textarea");
		textArea.value = text;
		document.body.appendChild(textArea);
		textArea.focus();
		textArea.select();
		document.execCommand("copy");
		document.body.removeChild(textArea);

		return Promise.resolve();
	};

	const copy = async (text: string) => {
		if (window.isSecureContext && navigator.clipboard) {
			return navigator.clipboard.writeText(text);
		}
		return unsecuredCopy(text);
	};

	const handleClick = async () => {
		if (disabled) return;
		
		try {
			await copy(value);

			isSuccess = true;
			if (timeout) {
				clearTimeout(timeout);
			}
			timeout = setTimeout(() => {
				isSuccess = false;
			}, 500);
		} catch (err) {
			console.error(err);
		}
	};

	onDestroy(() => {
		if (timeout) {
			clearTimeout(timeout);
		}
	});
</script>

<button
	class={classNames}
	title={disabled ? "Please wait for current response to complete" : "Copy to clipboard"}
	type="button"
	{disabled}
	onclick={() => {
		if (!disabled) {
			onClick?.();
			handleClick();
		}
	}}
>
	<div class="relative transition-transform duration-200 {isSuccess ? 'scale-125' : 'scale-100'}">
		{#if children}{@render children()}{:else}
			<CarbonCopy class={iconClassNames} />
		{/if}
	</div>
</button>