Spaces:
Running
Running
<script lang="ts" module> | |
import { cn, type WithElementRef } from "$lib/utils.js"; | |
import type { HTMLAnchorAttributes, HTMLButtonAttributes } from "svelte/elements"; | |
import { type VariantProps, tv } from "tailwind-variants"; | |
export const buttonVariants = tv({ | |
base: "focus-visible:border-ring focus-visible:ring-ring/50 aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive inline-flex shrink-0 items-center justify-center gap-2 whitespace-nowrap rounded-md text-sm font-medium outline-none transition-all focus-visible:ring-[3px] disabled:pointer-events-none disabled:opacity-50 aria-disabled:pointer-events-none aria-disabled:opacity-50 [&_svg:not([class*='size-'])]:size-4 [&_svg]:pointer-events-none [&_svg]:shrink-0", | |
variants: { | |
variant: { | |
default: "bg-primary text-primary-foreground shadow-xs hover:bg-primary/90", | |
destructive: | |
"bg-destructive shadow-xs hover:bg-destructive/90 focus-visible:ring-destructive/20 dark:focus-visible:ring-destructive/40 dark:bg-destructive/60 text-white", | |
outline: | |
"bg-background shadow-xs hover:bg-accent hover:text-accent-foreground dark:bg-input/30 dark:border-input dark:hover:bg-input/50 border", | |
secondary: "bg-secondary text-secondary-foreground shadow-xs hover:bg-secondary/80", | |
ghost: "hover:bg-accent hover:text-accent-foreground dark:hover:bg-accent/50", | |
link: "text-primary underline-offset-4 hover:underline" | |
}, | |
size: { | |
default: "h-9 px-4 py-2 has-[>svg]:px-3", | |
sm: "h-8 gap-1.5 rounded-md px-3 has-[>svg]:px-2.5", | |
lg: "h-10 rounded-md px-6 has-[>svg]:px-4", | |
icon: "size-9" | |
} | |
}, | |
defaultVariants: { | |
variant: "default", | |
size: "default" | |
} | |
}); | |
export type ButtonVariant = VariantProps<typeof buttonVariants>["variant"]; | |
export type ButtonSize = VariantProps<typeof buttonVariants>["size"]; | |
export type ButtonProps = WithElementRef<HTMLButtonAttributes> & | |
WithElementRef<HTMLAnchorAttributes> & { | |
variant?: ButtonVariant; | |
size?: ButtonSize; | |
}; | |
</script> | |
<script lang="ts"> | |
let { | |
class: className, | |
variant = "default", | |
size = "default", | |
ref = $bindable(null), | |
href = undefined, | |
type = "button", | |
disabled, | |
children, | |
...restProps | |
}: ButtonProps = $props(); | |
</script> | |
{#if href} | |
<a | |
bind:this={ref} | |
data-slot="button" | |
class={cn(buttonVariants({ variant, size }), className)} | |
href={disabled ? undefined : href} | |
aria-disabled={disabled} | |
role={disabled ? "link" : undefined} | |
tabindex={disabled ? -1 : undefined} | |
{...restProps} | |
> | |
{@render children?.()} | |
</a> | |
{:else} | |
<button | |
bind:this={ref} | |
data-slot="button" | |
class={cn(buttonVariants({ variant, size }), className)} | |
{type} | |
{disabled} | |
{...restProps} | |
> | |
{@render children?.()} | |
</button> | |
{/if} | |