{"$schema":"https://ui.shadcn.com/schema/registry-item.json","name":"button-group","type":"registry:ui","title":"Button Group","description":"Buttons that belong together, joined into one control.","dependencies":[],"registryDependencies":["https://dashral.com/r/utils.json"],"files":[{"path":"registry/dashral/button-group.tsx","type":"registry:file","target":"components/dashral/button-group.tsx","content":"import * as React from \"react\"\n\nimport { cn } from \"./lib/utils\"\n\ntype ButtonGroupProps = React.ComponentProps<\"div\"> & {\n  /** Side by side (default) or one above the other. */\n  orientation?: \"horizontal\" | \"vertical\"\n  /**\n   * Joined (default): the buttons share their edges, as one control, with a thin line between filled ones. Off, they\n   * stay apart with a small gap, still grouped for screen readers.\n   */\n  attached?: boolean\n  /** Names the group for screen readers, e.g. \"Text alignment\". */\n  \"aria-label\"?: string\n}\n\n// Joined buttons: square inner corners, overlapping borders, and the focused one on top so its ring shows whole. A\n// button without a border of its own (solid, soft, ghost) gets a thin line in its text color at the joint instead.\nconst joined = {\n  horizontal: [\n    \"[&>*]:rounded-none [&>*:first-child]:rounded-s-md [&>*:last-child]:rounded-e-md\",\n    \"[&>[class~=border]:not(:first-child)]:-ms-px\",\n    \"[&>*:not(:first-child):not([class~=border])]:relative [&>*:not(:first-child):not([class~=border])]:before:pointer-events-none [&>*:not(:first-child):not([class~=border])]:before:absolute [&>*:not(:first-child):not([class~=border])]:before:inset-y-0 [&>*:not(:first-child):not([class~=border])]:before:start-0 [&>*:not(:first-child):not([class~=border])]:before:w-px [&>*:not(:first-child):not([class~=border])]:before:bg-current [&>*:not(:first-child):not([class~=border])]:before:opacity-20\",\n  ],\n  vertical: [\n    \"flex-col [&>*]:rounded-none [&>*:first-child]:rounded-t-md [&>*:last-child]:rounded-b-md\",\n    \"[&>[class~=border]:not(:first-child)]:-mt-px\",\n    \"[&>*:not(:first-child):not([class~=border])]:relative [&>*:not(:first-child):not([class~=border])]:before:pointer-events-none [&>*:not(:first-child):not([class~=border])]:before:absolute [&>*:not(:first-child):not([class~=border])]:before:inset-x-0 [&>*:not(:first-child):not([class~=border])]:before:top-0 [&>*:not(:first-child):not([class~=border])]:before:h-px [&>*:not(:first-child):not([class~=border])]:before:bg-current [&>*:not(:first-child):not([class~=border])]:before:opacity-20\",\n  ],\n}\n\n/**\n * Buttons that belong together, joined into one control: `<ButtonGroup aria-label=\"View\"><Button …/><Button …/></ButtonGroup>`.\n * Put any Button in it, a menu's trigger included (a split button), and give each the same variant and size. For one\n * choice among options that stays pressed, use SegmentedControl or ToggleGroup.\n */\nfunction ButtonGroup({ orientation = \"horizontal\", attached = true, className, ...props }: ButtonGroupProps) {\n  return (\n    <div\n      role=\"group\"\n      data-slot=\"button-group\"\n      data-orientation={orientation}\n      className={cn(\n        \"inline-flex w-fit items-stretch [&>*:focus-visible]:z-10\",\n        attached ? joined[orientation] : [orientation === \"vertical\" ? \"flex-col\" : \"flex-wrap\", \"gap-2\"],\n        className\n      )}\n      {...props}\n    />\n  )\n}\n\nexport { ButtonGroup, type ButtonGroupProps }\n"}]}