- Introduced PickerHelp component for contextual help in pickers. - Created PickerBrowserFixture for testing picker components in a browser-like environment. - Implemented a comprehensive regression test suite for picker UI using Playwright. - Added support for localization in picker components and tests.
88 lines
2.2 KiB
TypeScript
88 lines
2.2 KiB
TypeScript
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;
|
|
entity: (count: number) => 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-0 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,
|
|
hideable: false,
|
|
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 || "—",
|
|
},
|
|
]}
|
|
entityLabel={labels.entity}
|
|
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>
|
|
);
|
|
}
|