radio-group-card.tsx91 lines · main
1'use client'
2
3import { Circle } from 'lucide-react'
4import { RadioGroup as RadioGroupPrimitive } from 'radix-ui'
5import * as React from 'react'
6
7import { cn } from '../lib/utils/cn'
8
9const RadioGroupCard = React.forwardRef<
10 React.ElementRef<typeof RadioGroupPrimitive.Root>,
11 React.ComponentPropsWithoutRef<typeof RadioGroupPrimitive.Root>
12>(({ className, ...props }, ref) => {
13 return <RadioGroupPrimitive.Root className={cn('grid gap-2', className)} {...props} ref={ref} />
14})
15RadioGroupCard.displayName = RadioGroupPrimitive.Root.displayName
16
17interface RadioGroupCardItemProps {
18 image?: React.ReactNode
19 label: React.ReactNode
20 showIndicator?: boolean
21}
22
23const RadioGroupCardItem = React.forwardRef<
24 React.ElementRef<typeof RadioGroupPrimitive.Item>,
25 RadioGroupCardItemProps & React.ComponentPropsWithoutRef<typeof RadioGroupPrimitive.Item>
26>(({ image, label, showIndicator = true, ...props }, ref) => {
27 return (
28 <RadioGroupPrimitive.Item
29 ref={ref}
30 {...props}
31 className={cn(
32 'flex flex-col gap-2',
33 'w-48',
34 'bg-overlay',
35 'rounded-md',
36 'border',
37 'p-2',
38 // 'hover:bg-selection',
39 'hover:border-foreground-muted',
40 'hover:z-1 focus-visible:z-1',
41 'data-[state=checked]:z-1',
42 'data-[state=checked]:ring-2 data-[state=checked]:ring-border',
43 'data-[state=checked]:bg-surface-300 dark:data-[state=checked]:bg-surface-300',
44 'data-[state=checked]:border-foreground/50',
45 'transition-colors',
46 'group',
47 props.className
48 )}
49 >
50 {props.children}
51 <label className="flex gap-2 w-full" id={props.id} htmlFor={props.value}>
52 {showIndicator && (
53 <div
54 className="
55 aspect-square h-4 w-4
56 rounded-full border group-data-[state=checked]:border-foreground-muted
57 group-focus:border-foreground-muted
58 group-hover:border-foreground-muted
59 ring-offset-background
60 group-focus:outline-hidden
61 group-focus-visible:ring-2 group-focus-visible:ring-ring group-focus-visible:ring-offset-2
62 group-disabled:cursor-not-allowed group-disabled:opacity-50
63 flex items-center justify-center
64 transition
65 "
66 >
67 <RadioGroupPrimitive.Indicator className="flex items-center justify-center">
68 <Circle className="h-2.5 w-2.5 fill-current text-current" />
69 </RadioGroupPrimitive.Indicator>
70 </div>
71 )}
72
73 <div
74 className={cn(
75 'w-full',
76 'text-xs transition-colors text-left',
77 'text-light',
78 'group-hover:text-foreground group-data-[state=checked]:text-foreground',
79 props.disabled ? 'cursor-not-allowed' : 'cursor-pointer'
80 )}
81 >
82 {label}
83 </div>
84 </label>
85 </RadioGroupPrimitive.Item>
86 )
87})
88
89RadioGroupCardItem.displayName = RadioGroupPrimitive.Item.displayName
90
91export { RadioGroupCard, RadioGroupCardItem }