import { cva } from 'class-variance-authority' import { cn } from '../../utils/cn' export const BUTTON_SET_SIZE_OPTIONS = ['default', 'sm', 'xs'] as const export type ButtonSetSize = (typeof BUTTON_SET_SIZE_OPTIONS)[number] export const BUTTON_SET_ORIENTATION_OPTIONS = [ 'responsive', 'horizontal', 'vertical', ] as const export type ButtonSetOrientation = (typeof BUTTON_SET_ORIENTATION_OPTIONS)[number] export type ButtonSetProps = React.PropsWithChildren<{ /** Controls the height, padding, and typography density of all child buttons. */ size?: ButtonSetSize /** * Layout direction of the button group. * - `responsive` (default): stacks vertically on mobile, flows horizontally on desktop. * - `horizontal`: always flows in a row, each button sharing equal width. * - `vertical`: always stacks in a column, each button full width. */ orientation?: ButtonSetOrientation className?: string }> // Explicitely set button sizing to avoid having to use React.cloneChildren, // which is not preferable for a component as low-level as Button // This is verbose, but it's better for performance const buttonSetVariants = cva( 'gap-2 [&_[data-slot="button"]]:whitespace-normal [&_[data-slot="button"]]:break-words', { variants: { orientation: { responsive: 'flex flex-col md:flex-row [&_button]:w-full md:[&_button]:flex-1 md:[&_button]:basis-0', horizontal: 'flex flex-row [&_button]:flex-1 [&_button]:basis-0 [&_button]:whitespace-normal', vertical: 'flex flex-col [&_button]:w-full', }, size: { default: '[&_[data-slot="button"]]:max-h-12 [&_[data-slot="button"]]:min-h-12 [&_[data-slot="button"]]:px-6 [&_[data-slot="button"]]:py-3.5 [&_[data-slot="button"]_svg]:!size-4', sm: '[&_[data-slot="button"]]:max-h-10 [&_[data-slot="button"]]:min-h-10 [&_[data-slot="button"]]:px-6 [&_[data-slot="button"]]:py-3 [&_[data-slot="button"]_svg]:!size-3', xs: '[&_[data-slot="button"]]:max-h-8 [&_[data-slot="button"]]:min-h-8 [&_[data-slot="button"]]:px-4 [&_[data-slot="button"]]:py-2 [&_[data-slot="button"]_svg]:!size-3', }, }, compoundVariants: [ { orientation: 'horizontal', size: 'default', className: '[&_[data-slot="button"]]:min-w-[120px] [&_[data-slot="button"]]:max-w-[200px]', }, { orientation: 'horizontal', size: 'sm', className: '[&_[data-slot="button"]]:min-w-[96px] [&_[data-slot="button"]]:max-w-[200px]', }, { orientation: 'horizontal', size: 'xs', className: '[&_[data-slot="button"]]:min-w-[72px] [&_[data-slot="button"]]:max-w-[120px]', }, { orientation: 'responsive', size: 'default', className: 'md:[&_[data-slot="button"]]:min-w-[120px] md:[&_[data-slot="button"]]:max-w-[200px]', }, { orientation: 'responsive', size: 'sm', className: 'md:[&_[data-slot="button"]]:min-w-[96px] md:[&_[data-slot="button"]]:max-w-[200px]', }, { orientation: 'responsive', size: 'xs', className: 'md:[&_[data-slot="button"]]:min-w-[72px] md:[&_[data-slot="button"]]:max-w-[120px]', }, ], }, ) /** * Groups related buttons with consistent sizing and layout. Enforces uniform * size across all child buttons without needing to set it on each one. */ export function ButtonSet({ children, size = 'default', orientation = 'responsive', className, }: ButtonSetProps) { return (
{children}
) } ButtonSet.displayName = 'ButtonSet' export default ButtonSet