button-group.tsx 2.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778
  1. import { cva, type VariantProps } from 'class-variance-authority';
  2. import { Slot } from 'radix-ui';
  3. import { cn } from '@/lib/utils';
  4. import { Separator } from '@/components/ui/separator';
  5. const buttonGroupVariants = cva(
  6. "has-[>[data-slot=button-group]]:gap-2 has-[select[aria-hidden=true]:last-child]:[&>[data-slot=select-trigger]:last-of-type]:rounded-r-md flex w-fit items-stretch [&>*]:focus-visible:z-10 [&>*]:focus-visible:relative [&>[data-slot=select-trigger]:not([class*='w-'])]:w-fit [&>input]:flex-1",
  7. {
  8. variants: {
  9. orientation: {
  10. horizontal:
  11. '[&>[data-slot]:not(:has(~[data-slot]))]:rounded-r-md! [&>*:not(:first-child)]:rounded-l-none [&>*:not(:first-child)]:border-l-0 [&>*:not(:last-child)]:rounded-r-none',
  12. vertical:
  13. '[&>[data-slot]:not(:has(~[data-slot]))]:rounded-b-md! flex-col [&>*:not(:first-child)]:rounded-t-none [&>*:not(:first-child)]:border-t-0 [&>*:not(:last-child)]:rounded-b-none',
  14. },
  15. },
  16. defaultVariants: {
  17. orientation: 'horizontal',
  18. },
  19. },
  20. );
  21. function ButtonGroup({
  22. className,
  23. orientation,
  24. ...props
  25. }: React.ComponentProps<'div'> & VariantProps<typeof buttonGroupVariants>) {
  26. return (
  27. <div
  28. role="group"
  29. data-slot="button-group"
  30. data-orientation={orientation}
  31. className={cn(buttonGroupVariants({ orientation }), className)}
  32. {...props}
  33. />
  34. );
  35. }
  36. function ButtonGroupText({
  37. className,
  38. asChild = false,
  39. ...props
  40. }: React.ComponentProps<'div'> & {
  41. asChild?: boolean;
  42. }) {
  43. const Comp = asChild ? Slot.Root : 'div';
  44. return (
  45. <Comp
  46. className={cn(
  47. "bg-muted gap-2 rounded-md border px-2.5 text-sm font-medium shadow-xs [&_svg:not([class*='size-'])]:size-4 flex items-center [&_svg]:pointer-events-none",
  48. className,
  49. )}
  50. {...props}
  51. />
  52. );
  53. }
  54. function ButtonGroupSeparator({
  55. className,
  56. orientation = 'vertical',
  57. ...props
  58. }: React.ComponentProps<typeof Separator>) {
  59. return (
  60. <Separator
  61. data-slot="button-group-separator"
  62. orientation={orientation}
  63. className={cn(
  64. 'bg-input relative self-stretch data-[orientation=horizontal]:mx-px data-[orientation=horizontal]:w-auto data-[orientation=vertical]:my-px data-[orientation=vertical]:h-auto',
  65. className,
  66. )}
  67. {...props}
  68. />
  69. );
  70. }
  71. export { ButtonGroup, ButtonGroupSeparator, ButtonGroupText, buttonGroupVariants };