{
  "$schema": "https://shadcn-vue.com/schema/registry-item.json",
  "name": "switch",
  "title": "Switch",
  "type": "registry:ui",
  "files": [
    {
      "path": "packages/registry-vue/components/switch/Switch.vue",
      "content": "<script setup lang=\"ts\">\nimport type { SwitchRootEmits, SwitchRootProps } from 'reka-ui'\nimport type { HTMLAttributes } from 'vue'\nimport { computed, getCurrentInstance, useSlots } from 'vue'\nimport { reactiveOmit } from '@vueuse/core'\nimport { SwitchRoot, SwitchThumb, useForwardPropsEmits } from 'reka-ui'\nimport { Loader2 } from 'lucide-vue-next'\nimport { cn } from '@/lib/utils'\n\nconst props = defineProps<\n  SwitchRootProps & {\n    class?: HTMLAttributes['class']\n    size?: 'sm' | 'default' | 'lg'\n    checkedChildren?: string\n    unCheckedChildren?: string\n    loading?: boolean\n    color?: 'primary' | 'secondary' | 'success' | 'warning' | 'error' | 'info' | string\n  }\n>()\n\nconst emits = defineEmits<SwitchRootEmits>()\nconst slots = useSlots()\n\nconst delegatedProps = reactiveOmit(\n  props,\n  'class',\n  'size',\n  'modelValue',\n  'checkedChildren',\n  'unCheckedChildren',\n  'loading',\n  'color',\n)\n\nconst forwarded = useForwardPropsEmits(delegatedProps, emits)\n\n// Detect controlled-vs-uncontrolled (Vue auto-defaults Boolean props to `false`,\n// so the prop value alone can't distinguish).\nconst instance = getCurrentInstance()\nconst isControlled = computed(() => Boolean(instance?.vnode?.props?.['onUpdate:modelValue']))\nconst userPassedModelValue = computed(() => {\n  const raw = instance?.vnode?.props\n  return Boolean(raw && ('modelValue' in raw || 'model-value' in raw))\n})\n\nconst switchStateBindings = computed(() => {\n  if (isControlled.value) return { 'model-value': props.modelValue }\n  if (userPassedModelValue.value) return { 'default-value': Boolean(props.modelValue) }\n  return { 'default-value': false }\n})\n\nconst hasChildren = computed(() =>\n  Boolean(props.checkedChildren || props.unCheckedChildren || slots['checked-children'] || slots['unchecked-children']),\n)\n\nconst sizeClasses = computed(() => {\n  const height = {\n    sm: 'h-4',\n    default: 'h-[1.15rem]',\n    lg: 'h-6',\n  }[props.size ?? 'default']\n\n  if (hasChildren.value) {\n    const width = {\n      sm: 'min-w-8 w-fit',\n      default: 'min-w-10 w-fit',\n      lg: 'min-w-[3.25rem] w-fit',\n    }[props.size ?? 'default']\n    return `${height} ${width}`\n  }\n\n  const width = {\n    sm: 'w-6',\n    default: 'w-8',\n    lg: 'w-11',\n  }[props.size ?? 'default']\n  return `${height} ${width}`\n})\n\nconst thumbSizes = {\n  sm: 'size-3',\n  default: 'size-4',\n  lg: 'size-5',\n}\n\nconst 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}\n\nconst textSizes = {\n  sm: 'text-[7px]',\n  default: 'text-xs',\n  lg: 'text-xs',\n}\n\nconst thumbIconSizes = {\n  sm: 'size-2',\n  default: 'size-2.5',\n  lg: 'size-3',\n}\n\nconst 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\nconst trackStyle = computed(() => ({\n  '--switch-checked-bg': props.color ? colorMap[props.color] || props.color : 'var(--primary)',\n}))\n</script>\n\n<template>\n  <SwitchRoot\n    v-slot=\"{ checked }\"\n    v-bind=\"{ 'data-slot': 'switch', ...forwarded, ...switchStateBindings }\"\n    :disabled=\"props.disabled || props.loading\"\n    :class=\"\n      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 transition-[background-color,border-color,box-shadow] duration-150 outline-none focus-visible:ring-[3px] disabled:cursor-not-allowed disabled:opacity-50 data-[state=checked]:bg-[var(--switch-checked-bg)]',\n        sizeClasses,\n        props.class,\n      )\n    \"\n    :style=\"trackStyle\"\n  >\n    <!-- Checked children (left side, visible when checked) -->\n    <div\n      v-if=\"hasChildren\"\n      class=\"pointer-events-none absolute inset-y-0 left-0 flex items-center pl-1 transition-opacity duration-150\"\n      :class=\"[checked ? 'opacity-100' : 'opacity-0', textSizes[size ?? 'default']]\"\n    >\n      <span class=\"text-primary-foreground truncate font-medium\">\n        <slot name=\"checked-children\">{{ checkedChildren }}</slot>\n      </span>\n    </div>\n\n    <!-- Unchecked children (right side, visible when unchecked) -->\n    <div\n      v-if=\"hasChildren\"\n      class=\"pointer-events-none absolute inset-y-0 right-0 flex items-center pr-1 transition-opacity duration-150\"\n      :class=\"[!checked ? 'opacity-100' : 'opacity-0', textSizes[size ?? 'default']]\"\n    >\n      <span class=\"text-muted-foreground truncate font-medium\">\n        <slot name=\"unchecked-children\">{{ unCheckedChildren }}</slot>\n      </span>\n    </div>\n\n    <SwitchThumb\n      data-uipkge\n      data-slot=\"switch-thumb\"\n      :class=\"\n        cn(\n          'bg-background dark:data-[state=unchecked]:bg-foreground dark:data-[state=checked]:bg-primary-foreground pointer-events-none z-10 block rounded-full ring-0 transition-transform duration-200 ease-[cubic-bezier(0.34,1.56,0.64,1)] data-[state=unchecked]:translate-x-0',\n          thumbSizes[size ?? 'default'],\n          thumbTranslate[size ?? 'default'],\n        )\n      \"\n    >\n      <Loader2 v-if=\"loading\" :class=\"[thumbIconSizes[size ?? 'default'], 'text-muted-foreground animate-spin']\" />\n      <slot v-else name=\"thumb\" v-bind=\"{ checked }\" />\n    </SwitchThumb>\n  </SwitchRoot>\n</template>\n",
      "type": "registry:ui",
      "target": "~/app/components/ui/switch/Switch.vue"
    },
    {
      "path": "packages/registry-vue/components/switch/index.ts",
      "content": "export { default as Switch } from './Switch.vue'\n",
      "type": "registry:ui",
      "target": "~/app/components/ui/switch/index.ts"
    }
  ],
  "dependencies": [
    "@vueuse/core",
    "lucide-vue-next",
    "reka-ui"
  ],
  "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"
  ]
}