This repository has no description
1<script lang="ts">
2 import type { Snippet } from "svelte";
3 import type { HTMLInputAttributes } from "svelte/elements";
4 import Check from "$icon/check";
5 import Minus from "$icon/minus";
6
7 interface Props extends Omit<HTMLInputAttributes, "type" | "class" | "checked" | "children"> {
8 checked?: boolean;
9 indeterminate?: boolean;
10 disabled?: boolean;
11 class?: string;
12 children?: Snippet;
13 }
14
15 let {
16 checked = $bindable(false),
17 indeterminate = $bindable(false),
18 disabled = false,
19 class: className,
20 children,
21 ...rest
22 }: Props = $props();
23
24 const labelClasses = $derived(
25 `inline-flex items-center gap-2 ${disabled ? "text-foreground-disabled hover:pointer-events-none" : "cursor-pointer"} ${className ?? ""}`
26 );
27
28 const inputClasses = [
29 "peer size-4 shrink-0 appearance-none rounded border border-border-default bg-background-default",
30 "transition-colors duration-150 checked:transition-none indeterminate:transition-none",
31 "hover:cursor-pointer hover:bg-background-inset",
32 "checked:border-foreground-default checked:bg-foreground-default checked:hover:bg-foreground-default",
33 "indeterminate:border-foreground-default indeterminate:bg-foreground-default indeterminate:hover:bg-foreground-default",
34 "focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-foreground-default",
35 "disabled:hover:pointer-events-none disabled:hover:bg-background-default"
36 ].join(" ");
37
38 const checkClasses = [
39 "pointer-events-none absolute inset-0 m-auto hidden size-3.5 text-background-default",
40 "peer-checked:block peer-indeterminate:hidden",
41 "peer-disabled:text-foreground-disabled peer-disabled:hover:cursor-default"
42 ].join(" ");
43
44 const minusClasses = [
45 "pointer-events-none absolute inset-0 m-auto hidden size-3.5 text-background-default",
46 "peer-indeterminate:block",
47 "peer-disabled:text-foreground-disabled peer-disabled:hover:cursor-default"
48 ].join(" ");
49</script>
50
51<label class={labelClasses}>
52 <span class="relative inline-flex size-4 shrink-0">
53 <input
54 type="checkbox"
55 bind:checked
56 bind:indeterminate
57 {disabled}
58 class={inputClasses}
59 {...rest}
60 />
61 <Check class={checkClasses} aria-hidden="true" />
62 <Minus class={minusClasses} aria-hidden="true" />
63 </span>
64 {#if children}
65 <span>{@render children()}</span>
66 {/if}
67</label>