metis-desk/packages/rdx-ui/src/components/option-picker-list.tsx

80 lines
2.1 KiB
TypeScript
Raw Normal View History

import { RadioGroup, RadioGroupItem } from "@repo/shadcn-ui/components/radio-group";
import { EntityTable } from "./entity-list";
import type { PickerOption } from "./option-picker-dialog";
/** Listado de selección única con búsqueda; el diálogo conserva la confirmación provisional. */
export function OptionPickerList({
title,
options,
value,
onChange,
labels,
locale,
loading = false,
}: {
title: string;
options: readonly PickerOption[];
value: string;
onChange: (id: string) => void;
labels: { selection: string; name: string; description: string; search: string };
locale: string;
loading?: boolean;
}) {
const choose = (id: string) => {
if (!loading && options.some((option) => option.id === id && !option.disabled)) {
onChange(id);
}
};
return (
<RadioGroup
aria-label={title}
className="flex min-h-96 flex-1 flex-col"
onValueChange={(id) => {
if (typeof id === "string") {
choose(id);
}
}}
value={value}
>
<EntityTable
columns={[
{
id: "selection",
label: labels.selection,
hideable: false,
render: (option) => (
<RadioGroupItem
aria-label={option.label}
disabled={loading || option.disabled}
value={option.id}
/>
),
},
{
id: "name",
label: labels.name,
value: (option) => option.label,
render: (option) => <span className="font-medium">{option.label}</span>,
},
{
id: "description",
label: labels.description,
value: (option) => option.description,
render: (option) => option.description || "—",
},
]}
items={options}
layout="fill"
loading={loading}
locale={locale}
onRowClick={(option) => choose(option.id)}
rowClassName={(option) => (option.disabled ? "cursor-not-allowed!" : "")}
searchPlaceholder={labels.search}
title={title}
/>
</RadioGroup>
);
}