2024-08-14 00:58:26 +00:00
|
|
|
<script lang="ts">
|
2026-06-24 20:56:53 +00:00
|
|
|
import type {Snippet} from "svelte"
|
|
|
|
|
import cx from "classnames"
|
2024-08-14 00:58:26 +00:00
|
|
|
|
2026-06-24 20:56:53 +00:00
|
|
|
const {
|
|
|
|
|
children,
|
|
|
|
|
size = "md",
|
|
|
|
|
loading = true,
|
2026-09-21 20:25:01 +00:00
|
|
|
reserveSpace = false,
|
2026-06-24 20:56:53 +00:00
|
|
|
...restProps
|
|
|
|
|
}: {
|
|
|
|
|
children?: Snippet
|
|
|
|
|
size?: "md" | "sm" | "xs"
|
2025-02-04 00:37:14 +00:00
|
|
|
loading?: boolean
|
2026-09-21 20:25:01 +00:00
|
|
|
// Reserves the spinner's slot even while idle, so toggling `loading` doesn't resize
|
|
|
|
|
// (and reflow) the button. Off by default since it costs unused width otherwise.
|
|
|
|
|
reserveSpace?: boolean
|
2026-06-24 20:10:06 +00:00
|
|
|
class?: string
|
2026-06-24 20:56:53 +00:00
|
|
|
} = $props()
|
2025-02-04 00:37:14 +00:00
|
|
|
|
2026-06-24 20:56:53 +00:00
|
|
|
const spinnerClass = $derived(
|
|
|
|
|
cx("spinner", {
|
|
|
|
|
"spinner-sm": size === "sm",
|
|
|
|
|
"spinner-xs": size === "xs",
|
|
|
|
|
}),
|
|
|
|
|
)
|
2024-08-14 00:58:26 +00:00
|
|
|
</script>
|
|
|
|
|
|
2026-06-24 20:56:53 +00:00
|
|
|
<div class={cx("flex items-center gap-2", restProps.class)}>
|
2024-08-14 00:58:26 +00:00
|
|
|
{#if loading}
|
2026-06-24 20:56:53 +00:00
|
|
|
<span class={spinnerClass}></span>
|
2026-09-21 20:25:01 +00:00
|
|
|
{:else if reserveSpace}
|
|
|
|
|
<span class={cx(spinnerClass, "invisible")}></span>
|
2024-08-14 00:58:26 +00:00
|
|
|
{/if}
|
2025-02-04 00:37:14 +00:00
|
|
|
{@render children?.()}
|
2026-06-24 20:56:53 +00:00
|
|
|
</div>
|