metis-desk/packages/rdx-ui/src/components/select-with-action.tsx

93 lines
2.3 KiB
TypeScript

import { Button } from "@repo/shadcn-ui/components/button";
import {
Select,
SelectContent,
SelectItem,
SelectTrigger,
SelectValue,
} from "@repo/shadcn-ui/components/select";
import { PlusIcon } from "lucide-react";
import { ButtonGroup } from "./button-group";
export type SelectOption = { value: string; label: string; disabled?: boolean };
export type SelectAction = { label: string; onClick: () => void; disabled?: boolean };
/** Selección controlada con una acción adyacente; el consumidor gestiona el alta y su contexto. */
export function SelectWithAction({
id,
label,
options,
placeholder,
value,
onValueChange,
disabled = false,
action,
required = false,
invalid = false,
describedBy,
}: {
id: string;
label: string;
options: readonly SelectOption[];
placeholder: string;
value: string;
onValueChange: (value: string) => void;
disabled?: boolean;
action?: SelectAction | undefined;
required?: boolean;
invalid?: boolean;
describedBy?: string | undefined;
}) {
const select = (
<Select
disabled={disabled}
items={[{ value: "", label: placeholder }, ...options]}
onValueChange={(selected) => {
if (typeof selected === "string") {
onValueChange(selected);
}
}}
required={required}
value={value}
>
<SelectTrigger
aria-describedby={describedBy}
aria-invalid={invalid || undefined}
aria-label={label}
className="w-full min-w-0 flex-1"
id={id}
>
<SelectValue />
</SelectTrigger>
<SelectContent>
<SelectItem value="">{placeholder}</SelectItem>
{options.map((option) => (
<SelectItem disabled={option.disabled} key={option.value} value={option.value}>
{option.label}
</SelectItem>
))}
</SelectContent>
</Select>
);
if (!action) {
return select;
}
return (
<ButtonGroup aria-label={label} className="w-full min-w-0">
{select}
<Button
aria-label={action.label}
disabled={disabled || action.disabled}
onClick={action.onClick}
size="icon"
title={action.label}
type="button"
variant="outline"
>
<PlusIcon aria-hidden="true" />
</Button>
</ButtonGroup>
);
}