This repository has no description
1<script module lang="ts">
2 import { tv, type VariantProps } from "tailwind-variants";
3
4 export const link = tv({
5 base: "inline-flex cursor-pointer items-center gap-1 no-underline transition-colors duration-150 ease-in-out select-none hover:underline focus-visible:outline-2 focus-visible:outline-offset-2",
6 variants: {
7 variant: {
8 default:
9 "text-foreground-link-default hover:text-foreground-link-hover focus-visible:outline-border-focus",
10 success:
11 "text-foreground-link-success hover:text-foreground-link-success-hover focus-visible:outline-foreground-link-success",
12 warning:
13 "text-foreground-link-warning hover:text-foreground-link-warning-hover focus-visible:outline-foreground-link-warning",
14 danger:
15 "text-foreground-link-danger hover:text-foreground-link-danger-hover focus-visible:outline-foreground-link-danger"
16 },
17 size: {
18 regular: "",
19 small: "text-xs"
20 },
21 disabled: {
22 true: "pointer-events-none opacity-50",
23 false: ""
24 }
25 },
26 defaultVariants: {
27 variant: "default",
28 size: "regular",
29 disabled: false
30 }
31 });
32
33 export type LinkVariants = VariantProps<typeof link>;
34</script>
35
36<script lang="ts">
37 import type { ResolvedPathname } from "$app/types";
38 import type { Component, Snippet } from "svelte";
39 import type {
40 HTMLAnchorAttributes,
41 HTMLButtonAttributes,
42 SvelteHTMLElements
43 } from "svelte/elements";
44
45 interface Props extends Omit<HTMLAnchorAttributes & HTMLButtonAttributes, "class" | "children"> {
46 variant?: LinkVariants["variant"];
47 size?: LinkVariants["size"];
48 href?: ResolvedPathname;
49 type?: "button" | "submit" | "reset";
50 disabled?: boolean;
51 iconLeft?: Component<SvelteHTMLElements["svg"]>;
52 iconRight?: Component<SvelteHTMLElements["svg"]>;
53 class?: string;
54 children?: Snippet;
55 }
56
57 let {
58 variant = "default",
59 size = "regular",
60 href,
61 type = "button",
62 disabled = false,
63 iconLeft,
64 iconRight,
65 class: className,
66 children,
67 ...rest
68 }: Props = $props();
69
70 const classes = $derived(link({ variant, size, disabled, class: className }));
71 const iconSize = $derived(size === "small" ? "size-3" : "size-4");
72</script>
73
74{#if href}
75 <a
76 {href}
77 class={classes}
78 aria-disabled={disabled ? "true" : undefined}
79 tabindex={disabled ? -1 : undefined}
80 {...rest}
81 >
82 {#if iconLeft}
83 {@const IconLeft = iconLeft}
84 <IconLeft class={iconSize} aria-hidden="true" />
85 {/if}
86 {#if children}
87 {@render children()}
88 {/if}
89 {#if iconRight}
90 {@const IconRight = iconRight}
91 <IconRight class={iconSize} aria-hidden="true" />
92 {/if}
93 </a>
94{:else}
95 <button {type} {disabled} class={classes} {...rest}>
96 {#if iconLeft}
97 {@const IconLeft = iconLeft}
98 <IconLeft class={iconSize} aria-hidden="true" />
99 {/if}
100 {#if children}
101 {@render children()}
102 {/if}
103 {#if iconRight}
104 {@const IconRight = iconRight}
105 <IconRight class={iconSize} aria-hidden="true" />
106 {/if}
107 </button>
108{/if}