<script lang="ts">
	import type { Snippet } from "svelte";
	import type { HTMLInputAttributes } from "svelte/elements";
	import Check from "$icon/check";
	import Minus from "$icon/minus";

	interface Props extends Omit<HTMLInputAttributes, "type" | "class" | "checked" | "children"> {
		checked?: boolean;
		indeterminate?: boolean;
		disabled?: boolean;
		class?: string;
		children?: Snippet;
	}

	let {
		checked = $bindable(false),
		indeterminate = $bindable(false),
		disabled = false,
		class: className,
		children,
		...rest
	}: Props = $props();

	const labelClasses = $derived(
		`inline-flex items-center gap-2 ${disabled ? "text-foreground-disabled hover:pointer-events-none" : "cursor-pointer"} ${className ?? ""}`
	);

	const inputClasses = [
		"peer size-4 shrink-0 appearance-none rounded border border-border-default bg-background-default",
		"transition-colors duration-150 checked:transition-none indeterminate:transition-none",
		"hover:cursor-pointer hover:bg-background-inset",
		"checked:border-foreground-default checked:bg-foreground-default checked:hover:bg-foreground-default",
		"indeterminate:border-foreground-default indeterminate:bg-foreground-default indeterminate:hover:bg-foreground-default",
		"focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-foreground-default",
		"disabled:hover:pointer-events-none disabled:hover:bg-background-default"
	].join(" ");

	const checkClasses = [
		"pointer-events-none absolute inset-0 m-auto hidden size-3.5 text-background-default",
		"peer-checked:block peer-indeterminate:hidden",
		"peer-disabled:text-foreground-disabled peer-disabled:hover:cursor-default"
	].join(" ");

	const minusClasses = [
		"pointer-events-none absolute inset-0 m-auto hidden size-3.5 text-background-default",
		"peer-indeterminate:block",
		"peer-disabled:text-foreground-disabled peer-disabled:hover:cursor-default"
	].join(" ");
</script>

<label class={labelClasses}>
	<span class="relative inline-flex size-4 shrink-0">
		<input
			type="checkbox"
			bind:checked
			bind:indeterminate
			{disabled}
			class={inputClasses}
			{...rest}
		/>
		<Check class={checkClasses} aria-hidden="true" />
		<Minus class={minusClasses} aria-hidden="true" />
	</span>
	{#if children}
		<span>{@render children()}</span>
	{/if}
</label>
