返回 AiToEarn
radio.tsx
根目录 / project / aitoearn-web / src / components / ui / radio.tsx
1 /**
2 * Radio - 单选组件
3 * 用于单选选择
4 */
5
6 'use client'
7
8 import * as React from 'react'
9 import { cn } from '@/utils/className'
10
11 interface RadioProps extends React.InputHTMLAttributes<HTMLInputElement> {
12 /** 值 */
13 value?: string | number
14 /** 是否选中 */
15 checked?: boolean
16 /** 是否禁用 */
17 disabled?: boolean
18 /** 子元素 */
19 children?: React.ReactNode
20 }
21
22 const RadioComponent = React.forwardRef<HTMLInputElement, RadioProps>(
23 ({ className, value, checked, disabled, children, ...props }, ref) => {
24 return (
25 <label
26 className={cn(
27 'flex items-center gap-2 cursor-pointer',
28 disabled && 'opacity-50 cursor-not-allowed',
29 className,
30 )}
31 >
32 <input
33 type="radio"
34 ref={ref}
35 value={value}
36 checked={checked}
37 disabled={disabled}
38 className="w-4 h-4 text-primary border-border focus:ring-primary"
39 {...props}
40 />
41 {children && <span>{children}</span>}
42 </label>
43 )
44 },
45 )
46 RadioComponent.displayName = 'Radio'
47
48 interface RadioGroupProps {
49 /** 选中的值 */
50 value?: string | number
51 /** 值改变回调 */
52 onChange?: (e: { target: { value: string | number } }) => void
53 /** 子元素 */
54 children?: React.ReactNode
55 /** 自定义类名 */
56 className?: string
57 }
58
59 function RadioGroup({ value, onChange, children, className }: RadioGroupProps) {
60 const handleChange = (newValue: string | number) => {
61 onChange?.({ target: { value: newValue } })
62 }
63
64 return (
65 <div className={cn('flex items-center gap-4', className)}>
66 {React.Children.map(children, (child) => {
67 if (React.isValidElement<RadioProps>(child) && child.type === RadioComponent) {
68 return React.cloneElement(child, {
69 checked: child.props.value === value,
70 onChange: () => handleChange(child.props.value as string | number),
71 })
72 }
73 return child
74 })}
75 </div>
76 )
77 }
78
79 // 创建带 Group 的 Radio 组件
80 const Radio = Object.assign(RadioComponent, {
81 Group: RadioGroup,
82 })
83
84 export { Radio, RadioGroup }
85
85 lines Plain Text