{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "toggle",
  "title": "Toggle",
  "description": "A button that stays pressed: quiet fill, darkening border, filter chip with a check, or a square icon in the accent.",
  "dependencies": [
    "radix-ui",
    "lucide-react",
    "motion"
  ],
  "registryDependencies": [
    "utils",
    "https://miseui.junsu4621.workers.dev/r/motion.json"
  ],
  "files": [
    {
      "path": "registry/miseui/ui/toggle.tsx",
      "content": "import type * as React from \"react\"\r\nimport { useState } from \"react\"\r\nimport { Toggle as TogglePrimitive } from \"radix-ui\"\r\nimport { Check } from \"lucide-react\"\r\nimport { motion, useReducedMotion } from \"motion/react\"\r\nimport { SPRING_DEFAULT } from \"@/registry/miseui/lib/motion\"\r\nimport { cn } from \"@/registry/miseui/lib/utils\"\r\n\r\ntype ToggleVariant = \"plain\" | \"outline\" | \"pill\" | \"icon\"\r\ntype ToggleEffect = \"pop\"\r\n\r\nconst POP_FROM_SCALE = 0.8\r\n\r\nconst ROOT_CLASS = [\r\n  \"group/toggle inline-flex shrink-0 items-center justify-center whitespace-nowrap font-medium select-none\",\r\n  \"transition-[color,background-color,border-color,box-shadow,scale] duration-(--duration-fast) ease-(--ease-mise)\",\r\n  \"outline-none focus-visible:ring-[3px] focus-visible:ring-ring/50\",\r\n  \"active:scale-[0.97] active:duration-100 motion-reduce:active:scale-100\",\r\n  \"disabled:pointer-events-none disabled:opacity-50\",\r\n  \"[&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4\",\r\n]\r\n\r\nconst VARIANT_CLASS: Record<ToggleVariant, string> = {\r\n  plain: cn(\r\n    \"h-9 gap-2 rounded-md px-3 text-sm text-muted-foreground pointer-coarse:h-10\",\r\n    \"hover:bg-accent hover:text-foreground data-[state=on]:bg-accent data-[state=on]:text-foreground\",\r\n  ),\r\n  outline: cn(\r\n    \"h-9 gap-2 rounded-md border border-input px-3 text-sm text-muted-foreground shadow-xs pointer-coarse:h-10\",\r\n    \"hover:text-foreground data-[state=on]:border-foreground data-[state=on]:text-foreground\",\r\n  ),\r\n  pill: cn(\r\n    \"h-8 rounded-full border border-input px-3 text-[13px] text-muted-foreground pointer-coarse:h-10\",\r\n    \"hover:text-foreground data-[state=on]:border-transparent data-[state=on]:bg-primary data-[state=on]:text-primary-foreground data-[state=on]:hover:text-primary-foreground\",\r\n  ),\r\n  icon: cn(\r\n    \"size-9 rounded-md text-muted-foreground pointer-coarse:size-10\",\r\n    \"hover:bg-accent hover:text-foreground data-[state=on]:bg-mise data-[state=on]:text-mise-foreground data-[state=on]:hover:bg-mise/90 data-[state=on]:hover:text-mise-foreground\",\r\n  ),\r\n}\r\n\r\n/** Grows from zero width through the grid track, so a chip widens smoothly instead of pushing its neighbours in one jump. */\r\nfunction PillCheck() {\r\n  return (\r\n    <span\r\n      aria-hidden=\"true\"\r\n      data-slot=\"toggle-check\"\r\n      className=\"grid grid-cols-[0fr] transition-[grid-template-columns] duration-(--duration-fast) ease-(--ease-mise) group-data-[state=on]/toggle:grid-cols-[1fr] motion-reduce:transition-none\"\r\n    >\r\n      <span className=\"overflow-hidden\">\r\n        <Check className=\"mr-1 size-3.5\" />\r\n      </span>\r\n    </span>\r\n  )\r\n}\r\n\r\ninterface ToggleContentProps {\r\n  pressed: boolean\r\n  pop: boolean\r\n  children: React.ReactNode\r\n}\r\n\r\nfunction ToggleContent({ pressed, pop, children }: ToggleContentProps) {\r\n  const reduceMotion = useReducedMotion() ?? false\r\n  const className = \"inline-flex items-center gap-2\"\r\n  if (!pop || reduceMotion) return <span className={className}>{children}</span>\r\n  return (\r\n    <motion.span\r\n      data-slot=\"toggle-pop\"\r\n      className={className}\r\n      initial={false}\r\n      // Only switching on earns the movement: it confirms a choice, and switching off should simply stop.\r\n      animate={pressed ? { scale: [POP_FROM_SCALE, 1] } : { scale: 1 }}\r\n      transition={SPRING_DEFAULT}\r\n    >\r\n      {children}\r\n    </motion.span>\r\n  )\r\n}\r\n\r\ntype ToggleProps = React.ComponentProps<typeof TogglePrimitive.Root> & {\r\n  /** `plain` quiet fill, `outline` border darkens, `pill` chip with a check, `icon` square in the accent. `icon` needs an aria-label. */\r\n  variant?: ToggleVariant\r\n  /** `pop` springs the content up when it switches on. */\r\n  effect?: ToggleEffect\r\n}\r\n\r\nfunction Toggle({\r\n  variant = \"plain\",\r\n  effect,\r\n  className,\r\n  children,\r\n  pressed,\r\n  defaultPressed = false,\r\n  onPressedChange,\r\n  ...props\r\n}: ToggleProps) {\r\n  const [uncontrolled, setUncontrolled] = useState(defaultPressed)\r\n  const current = pressed ?? uncontrolled\r\n  return (\r\n    <TogglePrimitive.Root\r\n      data-slot=\"toggle\"\r\n      data-variant={variant}\r\n      data-effect={effect}\r\n      className={cn(ROOT_CLASS, VARIANT_CLASS[variant], className)}\r\n      pressed={current}\r\n      onPressedChange={(next) => {\r\n        setUncontrolled(next)\r\n        onPressedChange?.(next)\r\n      }}\r\n      {...props}\r\n    >\r\n      {variant === \"pill\" ? <PillCheck /> : null}\r\n      <ToggleContent pressed={current} pop={effect === \"pop\"}>\r\n        {children}\r\n      </ToggleContent>\r\n    </TogglePrimitive.Root>\r\n  )\r\n}\r\n\r\nexport { Toggle, type ToggleProps, type ToggleVariant, type ToggleEffect }\r\n",
      "type": "registry:ui"
    }
  ],
  "categories": [
    "forms"
  ],
  "type": "registry:ui"
}