{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "button-group",
  "title": "Button Group",
  "description": "Related actions joined under one border, across or down, including a main action with a menu of its alternatives.",
  "dependencies": [
    "lucide-react"
  ],
  "registryDependencies": [
    "utils",
    "https://miseui.junsu4621.workers.dev/r/dropdown-menu.json"
  ],
  "files": [
    {
      "path": "registry/miseui/ui/button-group.tsx",
      "content": "import type * as React from \"react\"\nimport { createContext, useContext, useMemo } from \"react\"\nimport { ChevronDown } from \"lucide-react\"\nimport {\n  DropdownMenu,\n  DropdownMenuContent,\n  DropdownMenuTrigger,\n  type DropdownMenuContentProps,\n  type DropdownMenuEffect,\n} from \"@/registry/miseui/ui/dropdown-menu\"\nimport { cn } from \"@/registry/miseui/lib/utils\"\n\ntype ButtonGroupVariant = \"plain\" | \"outline\" | \"split\" | \"pill\"\ntype ButtonGroupOrientation = \"horizontal\" | \"vertical\"\ntype ButtonGroupEffect = \"press\"\n\n/** Each surface is drawn once on the root, which is what makes one shared border possible. */\nconst ROOT_CLASS: Record<ButtonGroupVariant, string> = {\n  plain: \"rounded-md bg-foreground/[0.06] divide-foreground/10\",\n  outline: \"rounded-md border bg-background shadow-xs\",\n  split: \"rounded-md bg-mise text-mise-foreground shadow-xs divide-mise-foreground/25\",\n  pill: \"gap-1 rounded-3xl border bg-background p-1 shadow-xs\",\n}\n\nconst ORIENTATION_CLASS: Record<ButtonGroupOrientation, string> = {\n  horizontal: \"max-w-full\",\n  vertical: \"flex-col\",\n}\n\nconst DIVIDE_CLASS: Record<ButtonGroupOrientation, string> = {\n  horizontal: \"divide-x\",\n  vertical: \"divide-y\",\n}\n\nconst ITEM_CLASS: Record<ButtonGroupVariant, string> = {\n  plain: \"h-9 px-3 hover:bg-foreground/[0.06] active:bg-foreground/10 pointer-coarse:h-10\",\n  outline: \"h-9 px-3 hover:bg-accent active:bg-accent/70 data-[state=open]:bg-accent pointer-coarse:h-10\",\n  split:\n    \"h-9 px-4 hover:bg-mise-foreground/10 active:bg-mise-foreground/[0.15] data-[state=open]:bg-mise-foreground/[0.15] pointer-coarse:h-10\",\n  pill: \"h-8 rounded-full px-3 text-[13px] hover:bg-accent active:bg-accent/70 data-[state=open]:bg-accent pointer-coarse:h-10\",\n}\n\n/** The shell of a joined group must not move, so the press dips the label and leaves every border where it is. */\nconst PRESS_LABEL_CLASS =\n  \"transition-[scale] duration-(--duration-base) ease-(--ease-mise-out) group-active/item:scale-[0.94] group-active/item:duration-0 motion-reduce:group-active/item:scale-100\"\n\nfunction joinedCorners(variant: ButtonGroupVariant, orientation: ButtonGroupOrientation) {\n  if (variant === \"pill\") return orientation === \"vertical\" ? \"w-full justify-start\" : undefined\n  return orientation === \"vertical\"\n    ? \"w-full justify-start first:rounded-t-[inherit] last:rounded-b-[inherit]\"\n    : \"first:rounded-l-[inherit] last:rounded-r-[inherit]\"\n}\n\nfunction itemClass(variant: ButtonGroupVariant, orientation: ButtonGroupOrientation) {\n  return cn(\n    \"group/item relative inline-flex min-w-0 items-center justify-center overflow-hidden text-sm font-medium whitespace-nowrap outline-none select-none\",\n    \"transition-[color,background-color] duration-(--duration-fast) ease-(--ease-mise) active:duration-0\",\n    \"focus-visible:z-10 focus-visible:ring-[3px] focus-visible:ring-ring/50\",\n    \"disabled:pointer-events-none disabled:opacity-50\",\n    \"[&_svg]:pointer-events-none [&_svg]:size-4 [&_svg]:shrink-0\",\n    ITEM_CLASS[variant],\n    joinedCorners(variant, orientation),\n  )\n}\n\ninterface ButtonGroupContextValue {\n  variant: ButtonGroupVariant\n  orientation: ButtonGroupOrientation\n  press: boolean\n}\n\nconst ButtonGroupContext = createContext<ButtonGroupContextValue>({\n  variant: \"outline\",\n  orientation: \"horizontal\",\n  press: false,\n})\n\ntype ButtonGroupProps = React.ComponentProps<\"div\"> & {\n  /** `plain` one quiet fill, `outline` one shared hairline, `split` a main action in the accent with its menu, `pill` separate rounded actions in one tray. */\n  variant?: ButtonGroupVariant\n  orientation?: ButtonGroupOrientation\n  /** `press` dips the pressed label while the shared border stays still. */\n  effect?: ButtonGroupEffect\n}\n\nfunction ButtonGroup({ variant = \"outline\", orientation = \"horizontal\", effect, className, ...props }: ButtonGroupProps) {\n  const press = effect === \"press\"\n  const context = useMemo(() => ({ variant, orientation, press }), [variant, orientation, press])\n  return (\n    <ButtonGroupContext.Provider value={context}>\n      <div\n        role=\"group\"\n        data-slot=\"button-group\"\n        data-variant={variant}\n        data-orientation={orientation}\n        data-effect={effect}\n        className={cn(\n          \"isolate inline-flex min-w-0\",\n          ORIENTATION_CLASS[orientation],\n          variant !== \"pill\" && DIVIDE_CLASS[orientation],\n          ROOT_CLASS[variant],\n          className,\n        )}\n        {...props}\n      />\n    </ButtonGroupContext.Provider>\n  )\n}\n\nfunction ButtonGroupItem({ className, children, type = \"button\", ...props }: React.ComponentProps<\"button\">) {\n  const { variant, orientation, press } = useContext(ButtonGroupContext)\n  return (\n    <button type={type} data-slot=\"button-group-item\" className={cn(itemClass(variant, orientation), className)} {...props}>\n      <span data-slot=\"button-group-label\" className={cn(\"inline-flex min-w-0 items-center gap-2\", press && PRESS_LABEL_CLASS)}>\n        {children}\n      </span>\n    </button>\n  )\n}\n\ntype ButtonGroupMenuProps = {\n  /** The name of the arrow button, such as \"More publish options\". It has no text of its own. */\n  label: string\n  /** DropdownMenuItem rows. */\n  children: React.ReactNode\n  /** Passed to the menu: `materialize` or `spring`. */\n  effect?: DropdownMenuEffect\n  align?: DropdownMenuContentProps[\"align\"]\n  disabled?: boolean\n  className?: string\n  contentClassName?: string\n}\n\nfunction ButtonGroupMenu({ label, children, effect, align = \"end\", disabled, className, contentClassName }: ButtonGroupMenuProps) {\n  const { variant, orientation } = useContext(ButtonGroupContext)\n  return (\n    <DropdownMenu>\n      <DropdownMenuTrigger\n        aria-label={label}\n        disabled={disabled}\n        data-slot=\"button-group-menu\"\n        className={cn(itemClass(variant, orientation), \"px-0\", orientation === \"vertical\" ? \"justify-center\" : \"w-9 shrink-0 pointer-coarse:w-10\", className)}\n      >\n        <ChevronDown className=\"transition-transform duration-(--duration-fast) ease-(--ease-mise) group-data-[state=open]/item:rotate-180 motion-reduce:transition-none\" />\n      </DropdownMenuTrigger>\n      <DropdownMenuContent align={align} effect={effect} className={contentClassName}>\n        {children}\n      </DropdownMenuContent>\n    </DropdownMenu>\n  )\n}\n\nexport {\n  ButtonGroup,\n  ButtonGroupItem,\n  ButtonGroupMenu,\n  type ButtonGroupProps,\n  type ButtonGroupMenuProps,\n  type ButtonGroupVariant,\n  type ButtonGroupOrientation,\n  type ButtonGroupEffect,\n}\n",
      "type": "registry:ui"
    }
  ],
  "categories": [
    "forms"
  ],
  "type": "registry:ui"
}