{ "$schema": "https://ui.shadcn.com/schema/registry-item.json", "name": "button-group", "type": "registry:ui", "title": "Button Group", "description": "Attached or segmented group of buttons.", "registryDependencies": [ "https://raw.githubusercontent.com/truongnat/rnui/main/registry/dist/nativewind/utils.json" ], "dependencies": [ "tailwind-variants" ], "files": [ { "path": "registry/shared/ui/button-group.tsx", "type": "registry:ui", "target": "components/ui/button-group.tsx", "content": "import {\n Children,\n cloneElement,\n isValidElement,\n type ReactElement,\n} from 'react';\nimport { View, type ViewProps } from 'react-native';\nimport { tv } from 'tailwind-variants';\nimport type { ButtonSize, ButtonVariant } from '@/components/ui/button';\nimport { cn } from '@/lib/utils';\n\nconst buttonGroupVariants = tv({\n base: 'flex-row items-stretch self-start',\n variants: {\n variant: {\n attached: '',\n segmented: 'gap-1 rounded-lg bg-muted p-1',\n },\n orientation: {\n horizontal: 'flex-row',\n vertical: 'flex-col',\n },\n },\n defaultVariants: { variant: 'attached', orientation: 'horizontal' },\n});\n\nexport type ButtonGroupVariant = 'attached' | 'segmented';\nexport type ButtonGroupOrientation = 'horizontal' | 'vertical';\n\ntype Position = 'only' | 'first' | 'middle' | 'last';\n\n/** Radius on the outer ends only; inner seams collapse to a single edge. */\nconst ATTACHED_POSITION_CLASS: Record<\n ButtonGroupOrientation,\n Record\n> = {\n horizontal: {\n only: '',\n first: 'rounded-r-none',\n middle: '-ml-px rounded-none',\n last: '-ml-px rounded-l-none',\n },\n vertical: {\n only: '',\n first: 'rounded-b-none',\n middle: '-mt-px rounded-none',\n last: '-mt-px rounded-t-none',\n },\n};\n\ntype InjectableProps = {\n variant?: ButtonVariant | 'default' | 'outline';\n size?: ButtonSize | 'default' | 'sm' | 'lg';\n disabled?: boolean;\n className?: string;\n};\n\nexport interface ButtonGroupProps extends ViewProps {\n /**\n * `attached` joins children edge-to-edge (radius on the ends only,\n * shared borders collapse via negative margin). `segmented` wraps\n * children in a muted pill — pair with `Toggle`/ghost children.\n */\n variant?: ButtonGroupVariant;\n orientation?: ButtonGroupOrientation;\n /** Default variant propagated to children that don't set their own. */\n buttonVariant?: ButtonVariant;\n /** Default size propagated to children that don't set their own. */\n size?: ButtonSize;\n /** Disables every child in the group. */\n disabled?: boolean;\n /** Stretch to parent width; horizontal children share space equally. */\n fullWidth?: boolean;\n /** Accessible label for the grouped controls. */\n label?: string;\n className?: string;\n}\n\nexport function ButtonGroup({\n variant = 'attached',\n orientation = 'horizontal',\n buttonVariant,\n size,\n disabled = false,\n fullWidth = false,\n label = 'Button group',\n className,\n children,\n ...props\n}: ButtonGroupProps) {\n const items = Children.toArray(children);\n const horizontal = orientation === 'horizontal';\n const injectedVariant =\n buttonVariant ?? (variant === 'attached' ? 'outline' : 'ghost');\n\n return (\n \n {items.map((child, index) => {\n if (!isValidElement(child)) return child;\n\n const position: Position =\n items.length === 1\n ? 'only'\n : index === 0\n ? 'first'\n : index === items.length - 1\n ? 'last'\n : 'middle';\n const positionClass =\n variant === 'attached'\n ? ATTACHED_POSITION_CLASS[orientation][position]\n : 'rounded-md border-0 bg-transparent';\n\n return cloneElement(child as ReactElement, {\n variant: child.props.variant ?? injectedVariant,\n size: child.props.size ?? size,\n disabled: disabled || child.props.disabled,\n className: cn(\n positionClass,\n fullWidth && horizontal && 'flex-1',\n child.props.className\n ),\n });\n })}\n \n );\n}\n" } ] }