86 lines
2.5 KiB
TypeScript
86 lines
2.5 KiB
TypeScript
'use client';
|
|
|
|
import React, { forwardRef, useState } from 'react';
|
|
|
|
export interface RadioButtonProps extends React.InputHTMLAttributes<HTMLInputElement> {
|
|
label?: string;
|
|
className?: string;
|
|
}
|
|
|
|
export const RadioButton = forwardRef<HTMLInputElement, RadioButtonProps>(
|
|
({ label, className = '', onChange, ...props }, ref) => {
|
|
// Keep track of focus state for styling
|
|
const [isFocused, setIsFocused] = useState(false);
|
|
|
|
// Handle click on the custom radio button
|
|
const handleClick = () => {
|
|
if (props.disabled) return;
|
|
|
|
// Only trigger onChange if the radio button is not already checked
|
|
if (!props.checked) {
|
|
// Create a synthetic event to pass to the onChange handler
|
|
const syntheticEvent = {
|
|
target: {
|
|
name: props.name,
|
|
checked: true,
|
|
type: 'radio',
|
|
value: props.value
|
|
}
|
|
} as React.ChangeEvent<HTMLInputElement>;
|
|
|
|
// Call the onChange handler with the synthetic event
|
|
if (onChange) {
|
|
onChange(syntheticEvent);
|
|
}
|
|
}
|
|
};
|
|
|
|
return (
|
|
<div className={`flex items-center ${className}`}>
|
|
<div
|
|
className="relative flex items-center cursor-pointer"
|
|
onClick={handleClick}
|
|
>
|
|
<input
|
|
type="radio"
|
|
ref={ref}
|
|
className="sr-only"
|
|
onFocus={() => setIsFocused(true)}
|
|
onBlur={() => setIsFocused(false)}
|
|
onChange={onChange}
|
|
{...props}
|
|
/>
|
|
|
|
<div
|
|
className={`
|
|
h-5 w-5 rounded-full flex items-center justify-center
|
|
${props.checked
|
|
? 'border-primary'
|
|
: 'border-gray-300'
|
|
}
|
|
${isFocused ? 'ring-2 ring-primary/30' : ''}
|
|
${props.disabled ? 'opacity-50 cursor-not-allowed' : 'cursor-pointer'}
|
|
border-2 bg-white transition-colors
|
|
`}
|
|
>
|
|
{props.checked && (
|
|
<div className="w-3 h-3 rounded-full bg-primary"></div>
|
|
)}
|
|
</div>
|
|
</div>
|
|
|
|
{label && (
|
|
<label
|
|
htmlFor={props.id}
|
|
className={`ml-2 text-sm ${props.disabled ? 'opacity-50 cursor-not-allowed' : 'cursor-pointer'}`}
|
|
onClick={!props.disabled ? handleClick : undefined}
|
|
>
|
|
{label}
|
|
</label>
|
|
)}
|
|
</div>
|
|
);
|
|
}
|
|
);
|
|
|
|
RadioButton.displayName = 'RadioButton';
|