{
  "$schema": "https://uipkge.dev/schema/registry-item.json",
  "name": "switch",
  "title": "Switch",
  "type": "registry:ui",
  "files": [
    {
      "path": "packages/registry-svelte/components/switch/Switch.svelte",
      "content": "<script lang=\"ts\" module>\n  import type { Snippet } from 'svelte'\n  import type { HTMLButtonAttributes } from 'svelte/elements'\n\n  export interface SwitchProps extends HTMLButtonAttributes {\n    /** Controlled checked state. Bind with `bind:checked`. */\n    checked?: boolean\n    /** Initial state for uncontrolled usage. */\n    defaultChecked?: boolean\n    size?: 'sm' | 'default' | 'lg'\n    checkedChildren?: string\n    unCheckedChildren?: string\n    loading?: boolean\n    color?: 'primary' | 'secondary' | 'success' | 'warning' | 'error' | 'info' | string\n    /** Snippet overrides for the track labels. Presence implies `hasChildren` layout. */\n    checkedSnippet?: Snippet\n    uncheckedSnippet?: Snippet\n    /** Thumb content override. Receives the current checked state. */\n    thumb?: Snippet<[{ checked: boolean }]>\n    ref?: HTMLButtonElement | null\n    onCheckedChange?: (checked: boolean) => void\n  }\n</script>\n\n<script lang=\"ts\">\n  import type { MouseEventHandler } from 'svelte/elements'\n  import { Loader2 } from '@lucide/svelte'\n  import { cn } from '$lib/utils'\n\n  let {\n    class: className,\n    defaultChecked = false,\n    checked = $bindable(defaultChecked),\n    size = 'default',\n    checkedChildren,\n    unCheckedChildren,\n    loading = false,\n    color,\n    checkedSnippet,\n    uncheckedSnippet,\n    thumb,\n    ref = $bindable(null),\n    onCheckedChange,\n    disabled,\n    onclick,\n    ...restProps\n  }: SwitchProps = $props()\n\n  function setChecked(next: boolean, notify = true) {\n    checked = next\n    if (notify) onCheckedChange?.(next)\n  }\n\n  const toggle: MouseEventHandler<HTMLButtonElement> = (event) => {\n    onclick?.(event)\n    if (event.defaultPrevented) return\n    if (disabled || loading) return\n    setChecked(!checked)\n  }\n\n  const hasChildren = $derived(Boolean(checkedChildren || unCheckedChildren || checkedSnippet || uncheckedSnippet))\n\n  const sizeClasses = $derived.by(() => {\n    const height = { sm: 'h-4', default: 'h-5', lg: 'h-6' }[size]\n    if (hasChildren) {\n      const width = { sm: 'min-w-8 w-fit', default: 'min-w-10 w-fit', lg: 'min-w-13 w-fit' }[size]\n      return `${height} ${width}`\n    }\n    const width = { sm: 'w-6', default: 'w-8', lg: 'w-11' }[size]\n    return `${height} ${width}`\n  })\n\n  const thumbSizes = { sm: 'size-3', default: 'size-4', lg: 'size-5' } as const\n  const thumbTranslate = {\n    sm: 'data-[state=checked]:translate-x-[calc(100%-2px)]',\n    default: 'data-[state=checked]:translate-x-[calc(100%-2px)]',\n    lg: 'data-[state=checked]:translate-x-[calc(100%-5px)]',\n  } as const\n  const textSizes = { sm: 'text-[0.5rem]', default: 'text-xs', lg: 'text-xs' } as const\n  const thumbIconSizes = { sm: 'size-2', default: 'size-3', lg: 'size-3' } as const\n\n  const colorMap: Record<string, string> = {\n    primary: 'var(--primary)',\n    secondary: 'var(--secondary)',\n    success: 'var(--success)',\n    warning: 'var(--warning)',\n    error: 'var(--destructive)',\n    info: 'var(--info)',\n  }\n</script>\n\n<button\n  bind:this={ref}\n  type=\"button\"\n  role=\"switch\"\n  aria-checked={checked}\n  data-uipkge=\"\"\n  data-slot=\"switch\"\n  data-state={checked ? 'checked' : 'unchecked'}\n  data-size={size}\n  disabled={disabled || loading}\n  style=\"--switch-checked-bg: {color ? colorMap[color] || color : 'var(--primary)'}\"\n  class={cn(\n    'peer focus-visible:ring-ring/50 focus-visible:border-ring data-[state=unchecked]:bg-input dark:data-[state=unchecked]:bg-input/80 relative inline-flex shrink-0 items-center overflow-hidden rounded-full border border-transparent shadow-xs outline-none focus-visible:ring-[3px] disabled:cursor-not-allowed disabled:opacity-50 data-[state=checked]:bg-[var(--switch-checked-bg)]',\n    'touch-manipulation enabled:active:scale-[0.97] enabled:active:duration-100 motion-safe:transition-[background-color,border-color,box-shadow,transform,scale] motion-safe:duration-200 motion-safe:ease-[cubic-bezier(0.22,1,0.36,1)] motion-reduce:transition-none',\n    sizeClasses,\n    className,\n  )}\n  onclick={toggle}\n  {...restProps}\n>\n  {#if hasChildren}\n    <div\n      class={cn(\n        'pointer-events-none absolute inset-y-0 left-0 flex items-center pl-1 motion-safe:transition-[opacity,transform] motion-safe:duration-200 motion-safe:ease-[cubic-bezier(0.22,1,0.36,1)] motion-reduce:transition-none',\n        checked ? 'translate-x-0 opacity-100' : '-translate-x-0.5 opacity-0',\n        textSizes[size],\n      )}\n    >\n      <span class=\"text-primary-foreground truncate font-medium\">\n        {#if checkedSnippet}{@render checkedSnippet()}{:else}{checkedChildren}{/if}\n      </span>\n    </div>\n    <div\n      class={cn(\n        'pointer-events-none absolute inset-y-0 right-0 flex items-center pr-1 motion-safe:transition-[opacity,transform] motion-safe:duration-200 motion-safe:ease-[cubic-bezier(0.22,1,0.36,1)] motion-reduce:transition-none',\n        !checked ? 'translate-x-0 opacity-100' : 'translate-x-0.5 opacity-0',\n        textSizes[size],\n      )}\n    >\n      <span class=\"text-muted-foreground truncate font-medium\">\n        {#if uncheckedSnippet}{@render uncheckedSnippet()}{:else}{unCheckedChildren}{/if}\n      </span>\n    </div>\n  {/if}\n\n  <span\n    data-uipkge=\"\"\n    data-slot=\"switch-thumb\"\n    data-state={checked ? 'checked' : 'unchecked'}\n    class={cn(\n      'bg-background dark:data-[state=unchecked]:bg-foreground dark:data-[state=checked]:bg-primary-foreground pointer-events-none z-10 flex items-center justify-center rounded-full shadow-sm ring-0 data-[state=unchecked]:translate-x-0 motion-safe:transition-transform motion-safe:duration-200 motion-safe:ease-[cubic-bezier(0.22,1.15,0.36,1)] motion-reduce:transition-none',\n      thumbSizes[size],\n      thumbTranslate[size],\n    )}\n  >\n    {#if loading}\n      <Loader2 class={cn(thumbIconSizes[size], 'text-muted-foreground motion-safe:animate-spin')} />\n    {:else if thumb}\n      {@render thumb({ checked })}\n    {/if}\n  </span>\n</button>\n",
      "type": "registry:ui",
      "target": "~/src/lib/components/ui/switch/Switch.svelte"
    },
    {
      "path": "packages/registry-svelte/components/switch/index.ts",
      "content": "export { default as Switch, type SwitchProps } from './Switch.svelte'\n",
      "type": "registry:ui",
      "target": "~/src/lib/components/ui/switch/index.ts"
    }
  ],
  "dependencies": [
    "@lucide/svelte"
  ],
  "devDependencies": [],
  "registryDependencies": [],
  "description": "On/off toggle — visual analog of a hardware switch. Use for binary settings where the change takes effect immediately, not for form fields that submit later (use Checkbox there).",
  "categories": [
    "form"
  ]
}