new-personal-site/components/lib/form/Radios.tsx
2025-10-02 08:16:11 +01:00

80 lines
2.2 KiB
TypeScript

import {
ComponentProps,
DetailedHTMLProps,
InputHTMLAttributes,
LabelHTMLAttributes,
} from "react";
import Row from "../layout/Row";
import twuiSlugify from "../utils/slugify";
import twuiSlugToNormalText from "../utils/slug-to-normal-text";
import { twMerge } from "tailwind-merge";
type Value = {
value: string;
title?: string;
default?: boolean;
};
export type TWUI_FORM_RADIO_PROPS = {
values: Value[];
name: string;
inputProps?: DetailedHTMLProps<
InputHTMLAttributes<HTMLInputElement>,
HTMLInputElement
>;
labelProps?: DetailedHTMLProps<
LabelHTMLAttributes<HTMLLabelElement>,
HTMLLabelElement
>;
wrapperProps?: ComponentProps<typeof Row>;
changeHandler?: (value: string) => void;
};
/**
* # Form Radios Component
* @className twui-textarea
*/
export default function Radios({
values,
name,
inputProps,
labelProps,
wrapperProps,
changeHandler,
}: TWUI_FORM_RADIO_PROPS) {
const finalName = twuiSlugify(name);
const finalTitle = twuiSlugToNormalText(finalName);
return (
<Row
title={finalTitle}
{...wrapperProps}
className={twMerge("gap-4", wrapperProps?.className)}
>
{values.map((v, i) => {
const valueName = twuiSlugify(`${finalName}-${v.value}`);
const valueTitle = v.title || twuiSlugToNormalText(v.value);
return (
<Row key={i} className="gap-1.5">
<input
id={valueName}
type="radio"
defaultChecked={v.default}
name={finalName}
onChange={(e) => {
const targetValue = v.value;
changeHandler?.(targetValue);
}}
{...inputProps}
/>
<label htmlFor={valueName} {...labelProps}>
{valueTitle}
</label>
</Row>
);
})}
</Row>
);
}