{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "toggle",
  "title": "Toggle",
  "description": "Soft-rect two-state button with pressed fill morph on Base UI.",
  "dependencies": [
    "@base-ui/react",
    "class-variance-authority",
    "motion"
  ],
  "registryDependencies": [
    "@atroui/utils",
    "@atroui/motion"
  ],
  "files": [
    {
      "path": "registry/default/ui/toggle.tsx",
      "content": "\"use client\"\n\nimport * as React from \"react\"\nimport { Toggle as TogglePrimitive } from \"@base-ui/react/toggle\"\nimport { cva, type VariantProps } from \"class-variance-authority\"\nimport { motion, useReducedMotion } from \"motion/react\"\n\nimport {\n  controlGestures,\n  easeOutExpo,\n  layoutTween,\n} from \"@/lib/motion\"\nimport { cn } from \"@/lib/utils\"\n\n/** Pressed fill settle — ~160ms easeOutExpo, no spring. */\nconst pressedMorph = {\n  duration: 0.16,\n  ease: easeOutExpo,\n} as const\n\nconst PRESSED_FILL =\n  \"absolute z-0 inset-0 bg-muted shadow-sm ring-1 ring-border-subtle/60\"\n\n/** Soft-rect via style — layoutId scale-corrects borderRadius during morph. */\nconst PRESSED_FILL_STYLE = {\n  borderRadius: \"calc(var(--atro-control-radius, var(--radius)) - 2px)\",\n} as const\n\nexport type ToggleGroupMotionValue = {\n  layoutId: string\n  multiple: boolean\n}\n\n/** Set by ToggleGroup so peer toggles share one layoutId highlight. */\nexport const ToggleGroupMotionContext =\n  React.createContext<ToggleGroupMotionValue | null>(null)\n\nfunction withoutDomAnimationHandlers<T extends Record<string, unknown>>(\n  props: T\n) {\n  const {\n    onAnimationStart: _onAnimationStart,\n    onDrag: _onDrag,\n    onDragStart: _onDragStart,\n    onDragEnd: _onDragEnd,\n    ...rest\n  } = props\n  return rest\n}\n\nconst toggleVariants = cva(\n  [\n    \"group/toggle relative inline-flex shrink-0 items-center justify-center gap-1.5 border border-transparent\",\n    \"bg-clip-padding text-[0.8125rem] font-medium tracking-[-0.01em] whitespace-nowrap outline-none select-none\",\n    \"text-muted-foreground transition-[color,background-color,border-color,box-shadow] duration-150\",\n    \"ease-[cubic-bezier(0.16,1,0.3,1)]\",\n    \"hover:text-foreground\",\n    \"focus-visible:border-ring focus-visible:ring-2 focus-visible:ring-ring/20\",\n    \"data-disabled:pointer-events-none data-disabled:opacity-50\",\n    \"data-pressed:text-foreground\",\n    \"[&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4\",\n    \"motion-reduce:transition-none\",\n  ].join(\" \"),\n  {\n    variants: {\n      variant: {\n        default: \"hover:bg-muted/60\",\n        outline:\n          \"border-border-subtle bg-background hover:bg-muted/40 data-pressed:border-border-subtle\",\n      },\n      size: {\n        default:\n          \"h-[var(--atro-control-height,2.25rem)] min-w-[var(--atro-control-height,2.25rem)] rounded-[var(--atro-control-radius,var(--radius))] px-3\",\n        sm: \"h-7 min-w-7 rounded-[calc(var(--atro-control-radius,var(--radius))-1px)] px-2.5 text-[0.8rem] [&_svg:not([class*='size-'])]:size-3.5\",\n        lg: \"h-10 min-w-10 rounded-[var(--atro-control-radius,var(--radius))] px-4\",\n      },\n    },\n    defaultVariants: {\n      variant: \"default\",\n      size: \"default\",\n    },\n  }\n)\n\n/**\n * Soft-rect toggle — pressed fill morphs in (standalone) or travels via\n * layoutId when inside ToggleGroup (single-select). No spring bounce.\n */\nfunction Toggle({\n  className,\n  variant = \"default\",\n  size = \"default\",\n  children,\n  ...props\n}: TogglePrimitive.Props & VariantProps<typeof toggleVariants>) {\n  const reduce = useReducedMotion()\n  const group = React.useContext(ToggleGroupMotionContext)\n  const useSharedHighlight = Boolean(group && !group.multiple)\n  const gestures = controlGestures(reduce)\n\n  return (\n    <TogglePrimitive\n      data-slot=\"toggle\"\n      {...props}\n      className={cn(toggleVariants({ variant, size }), className)}\n      render={(htmlProps, state) => {\n        const showFill = state.pressed\n        const shared = useSharedHighlight && showFill\n\n        return (\n          <motion.button\n            {...withoutDomAnimationHandlers(\n              htmlProps as Record<string, unknown>\n            )}\n            whileHover={gestures.whileHover}\n            whileFocus={gestures.whileFocus}\n            whileTap={gestures.whileTap}\n          >\n            {shared ? (\n              reduce ? (\n                <span\n                  className={PRESSED_FILL}\n                  style={PRESSED_FILL_STYLE}\n                  aria-hidden\n                />\n              ) : (\n                <motion.span\n                  layoutId={group!.layoutId}\n                  className={PRESSED_FILL}\n                  style={PRESSED_FILL_STYLE}\n                  transition={layoutTween}\n                  aria-hidden\n                />\n              )\n            ) : showFill ? (\n              reduce ? (\n                <span\n                  className={PRESSED_FILL}\n                  style={PRESSED_FILL_STYLE}\n                  aria-hidden\n                />\n              ) : (\n                <motion.span\n                  className={PRESSED_FILL}\n                  style={PRESSED_FILL_STYLE}\n                  initial={{ opacity: 0, scale: 0.92 }}\n                  animate={{ opacity: 1, scale: 1 }}\n                  transition={pressedMorph}\n                  aria-hidden\n                />\n              )\n            ) : null}\n            <span className=\"relative z-[1] inline-flex items-center justify-center gap-1.5\">\n              {children}\n            </span>\n          </motion.button>\n        )\n      }}\n    />\n  )\n}\n\nexport { Toggle, toggleVariants }\n",
      "type": "registry:ui",
      "target": "components/ui/toggle.tsx"
    }
  ],
  "type": "registry:ui"
}