<script lang="ts">
	import type { Snippet } from "svelte";
	import type { HTMLInputAttributes } from "svelte/elements";

	interface Props extends Omit<HTMLInputAttributes, "type" | "class" | "checked" | "children"> {
		checked?: boolean;
		disabled?: boolean;
		/** `inline` hugs the label, `block` stretches it to fill the row. */
		layout?: "inline" | "block";
		class?: string;
		children?: Snippet;
	}

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

	const labelClasses = $derived(
		[
			"items-center gap-2",
			layout === "block" ? "flex w-full" : "inline-flex",
			disabled ? "cursor-not-allowed text-foreground-disabled" : "cursor-pointer",
			className ?? ""
		].join(" ")
	);

	const inputClasses = [
		"peer absolute inset-0 size-full appearance-none rounded-full bg-background-muted",
		"transition-colors duration-150",
		"checked:bg-foreground-default",
		"enabled:hover:bg-background-strong checked:enabled:hover:bg-foreground-muted",
		"focus-visible:ring-2 focus-visible:ring-border-strong focus-visible:outline-none",
		"disabled:cursor-not-allowed disabled:bg-background-inset checked:disabled:bg-foreground-disabled"
	].join(" ");

	const thumbClasses = [
		"pointer-events-none absolute top-px left-px size-4 rounded-full bg-background-default",
		"transition-transform duration-150 peer-checked:translate-x-[15px]"
	].join(" ");

	const textClasses = $derived(layout === "block" ? "min-w-0 flex-1" : "whitespace-nowrap");
</script>

<label class={labelClasses}>
	<span class="relative inline-flex h-4.5 w-8.25 shrink-0">
		<input type="checkbox" role="switch" bind:checked {disabled} class={inputClasses} {...rest} />
		<span class={thumbClasses} aria-hidden="true"></span>
	</span>
	{#if children}
		<span class={textClasses}>{@render children()}</span>
	{/if}
</label>
