File size: 1,543 Bytes
336b102
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
<script lang="ts" module>
	import type { MouseEventHandler } from 'svelte/elements';

	export type ButtonProps = ButtonPrimitiveProps & {
		loading?: boolean;
		onClickPromise?: (
			e:
				| Parameters<MouseEventHandler<HTMLButtonElement>>[0]
				| Parameters<MouseEventHandler<HTMLAnchorElement>>[0]
		) => Promise<void>;
	};

	export type Size = 'default' | 'xs' | 'sm' | 'lg';

	/**
	 * Map sizes to their icon/normal size variant
	 */
	export const sizeMap = {
		default: {
			icon: 'icon',
			normal: 'default'
		},
		xs: {
			icon: 'icon-xs',
			normal: 'xs'
		},
		sm: {
			icon: 'icon-sm',
			normal: 'sm'
		},
		lg: {
			icon: 'icon-lg',
			normal: 'lg'
		}
	} as const;

	export { type ButtonSize, type ButtonVariant } from '$lib/components/ui/button';
</script>

<script lang="ts">
	import { Button, type ButtonProps as ButtonPrimitiveProps } from '$lib/components/ui/button';
	import { Spinner } from '$lib/components/ui/spinner';

	let {
		ref = $bindable(null),
		loading: loadingProp = false,
		onClickPromise,
		onclick,
		disabled,
		children,
		...restProps
	}: ButtonProps = $props();

	let pending = $state(false);

	const loading = $derived(loadingProp || pending);
</script>

<Button
	bind:ref
	disabled={loading || disabled}
	onclick={async (e) => {
		onclick?.(e as never);

		if (onClickPromise) {
			pending = true;
			try {
				await onClickPromise(e);
			} finally {
				pending = false;
			}
		}
	}}
	{...restProps}
>
	{#if loading}
		<Spinner data-icon="inline-start" />
	{/if}
	{@render children?.()}
</Button>