67 lines
2.6 KiB
TypeScript
67 lines
2.6 KiB
TypeScript
import { RadioCardGroup } from "~/ui/components/RadioCardGroup";
|
|
import { Label } from "../label";
|
|
import { cn } from "~/lib/utils";
|
|
|
|
interface Props {
|
|
name?: string;
|
|
title?: string;
|
|
value?: string;
|
|
defaultValue?: string;
|
|
onChange?: (value: string) => void;
|
|
options: { name: string | React.ReactNode; value: string; description?: string }[];
|
|
required?: boolean;
|
|
columns?: 1 | 2 | 3 | 4;
|
|
disabled?: boolean;
|
|
style?: React.CSSProperties;
|
|
}
|
|
|
|
// Subframe migration (strangler shim):
|
|
// Single-choice picker rendered with the Subframe design-system `RadioCardGroup` behind the
|
|
// original `InputChoicebox` API. Public props are unchanged; call sites are not touched.
|
|
// - `value`/`defaultValue`/`onChange` keep controlled + uncontrolled behaviour (Radix RadioGroup).
|
|
// - Form submission still goes through the hidden <input name=...> (RadioGroup buttons are not
|
|
// submitted natively), preserving the prior contract exactly.
|
|
// - `columns` maps to a CSS grid on the group; default (no columns) keeps the legacy 2-up grid
|
|
// when there are exactly two options, otherwise a single column.
|
|
export default function InputChoicebox({ name, title, value, defaultValue, onChange, options, required, columns, disabled, style }: Props) {
|
|
return (
|
|
<div>
|
|
{name && <input type="hidden" name={name} value={value} readOnly hidden />}
|
|
{title && (
|
|
<Label className="mb-1 block text-xs">
|
|
{title} {required && <span className="text-red-600">*</span>}
|
|
</Label>
|
|
)}
|
|
<RadioCardGroup
|
|
defaultValue={defaultValue}
|
|
value={value}
|
|
onValueChange={onChange ? (value) => onChange(value) : undefined}
|
|
disabled={disabled}
|
|
className={cn(
|
|
"grid w-full",
|
|
columns === 1
|
|
? "grid-cols-1"
|
|
: columns === 2
|
|
? "grid-cols-2"
|
|
: columns === 3
|
|
? "sm:grid-cols-3"
|
|
: columns === 4
|
|
? "sm:grid-cols-4"
|
|
: options.length === 2
|
|
? "grid-cols-2"
|
|
: "grid-cols-1"
|
|
)}
|
|
>
|
|
{options.map((option) => (
|
|
<RadioCardGroup.RadioCard value={option.value} key={option.value} disabled={disabled} style={style} className="max-w-none">
|
|
<div className="flex flex-col items-start gap-1">
|
|
<span className="text-sm font-medium">{option.name}</span>
|
|
{option.description && <span className="text-muted-foreground text-xs">{option.description}</span>}
|
|
</div>
|
|
</RadioCardGroup.RadioCard>
|
|
))}
|
|
</RadioCardGroup>
|
|
</div>
|
|
);
|
|
}
|