metis-desk/packages/rdx-ui/src/components/icon-picker.tsx
David f6c6b8c95c refactor: replace Label component with FormLabel for consistent required indicator display
- Updated TeleworkAuthorizationForm, WorkProfileForm, PasswordForm, CredentialForm, UserForm, and various resource-related forms to use FormLabel instead of Label.
- Introduced FormLabel component to encapsulate required indicator logic.
- Removed optional labels from localization files and adjusted tests accordingly.
- Ensured accessibility and consistency across forms by implementing required indicators visually.
2026-10-15 18:02:32 +02:00

77 lines
2.1 KiB
TypeScript

import {
Select,
SelectContent,
SelectItem,
SelectTrigger,
SelectValue,
} from "@repo/shadcn-ui/components/select";
import type { ReactNode } from "react";
import { useId } from "react";
import { FormLabel } from "./form-label";
/** Selección compacta con vista previa; el consumidor aporta iconos, textos y claves válidas. */
export function IconPicker({
label,
description,
describedBy,
options,
value,
onChange,
disabled = false,
}: {
label: string;
description?: string;
describedBy?: string;
options: readonly { value: string; label: string; icon: ReactNode }[];
value: string;
onChange: (value: string) => void;
disabled?: boolean;
}) {
const id = useId();
const selected = options.find((option) => option.value === value);
const descriptionIds =
[description ? `${id}-description` : undefined, describedBy].filter(Boolean).join(" ") ||
undefined;
return (
<div className="space-y-2">
<FormLabel htmlFor={id}>{label}</FormLabel>
<Select
disabled={disabled}
items={options.map((option) => ({ value: option.value, label: option.label }))}
onValueChange={(next) => {
if (typeof next === "string") {
onChange(next);
}
}}
value={value}
>
<SelectTrigger aria-describedby={descriptionIds} className="w-full sm:max-w-64" id={id}>
<SelectValue>
<span aria-hidden="true" className="shrink-0">
{selected?.icon}
</span>
<span className="truncate">{selected?.label}</span>
</SelectValue>
</SelectTrigger>
<SelectContent>
{options.map((option) => (
<SelectItem key={option.value} value={option.value}>
<span aria-hidden="true" className="shrink-0">
{option.icon}
</span>
{option.label}
</SelectItem>
))}
</SelectContent>
</Select>
{description && (
<p className="text-sm text-muted-foreground" id={`${id}-description`}>
{description}
</p>
)}
</div>
);
}