import React from 'react'; import { useController, type FieldPath, type FieldValues, type UseControllerProps, } from 'react-hook-form'; import type { SelectProps, MultiSelectProps } from '@mantine/core'; import { LocalSelect } from '../custom/selects/LocalSelect'; import type { LocalSelectBaseProps } from '../custom/selects/types'; import { useTranslatedError } from '../useTranslatedError'; // --------------------------------------------------------------------------- // FieldLocalSelect — RHF-connected Local Select // --------------------------------------------------------------------------- // // Follows the same architectural pattern as the existing `FieldSelect`: // Mantine Component → withRHF HOC → FieldXxx // // But instead of using the generic withRHF factory (which assumes string values), // we use a manual useController binding with an object interception layer. // The actual rendering is delegated to the standalone LocalSelect engine // in `custom/selects/LocalSelect.tsx`. // // Data Mapping Contract: // Single: RHF stores T | null → maps to Mantine string | null // Multi: RHF stores T[] → maps to Mantine string[] // --------------------------------------------------------------------------- /** Mantine props we manage ourselves */ type ManagedSelectProps = 'data' | 'value' | 'defaultValue' | 'onChange' | 'onBlur' | 'error' | 'filter' | 'name' | 'onSelect'; type ManagedMultiSelectProps = 'data' | 'value' | 'defaultValue' | 'onChange' | 'onBlur' | 'error' | 'filter' | 'name' | 'onSelect'; /** Single-select RHF props — stores T | null */ export type FieldLocalSelectSingleProps< T extends Record, TFieldValues extends FieldValues = FieldValues, TName extends FieldPath = FieldPath, > = LocalSelectBaseProps & UseControllerProps & Omit & { multiple?: false; }; /** Multi-select RHF props — stores T[] */ export type FieldLocalSelectMultiProps< T extends Record, TFieldValues extends FieldValues = FieldValues, TName extends FieldPath = FieldPath, > = LocalSelectBaseProps & UseControllerProps & Omit & { multiple: true; }; /** Discriminated union based on `multiple` */ export type FieldLocalSelectProps< T extends Record, TFieldValues extends FieldValues = FieldValues, TName extends FieldPath = FieldPath, > = | FieldLocalSelectSingleProps | FieldLocalSelectMultiProps; // --------------------------------------------------------------------------- // Component Implementation // --------------------------------------------------------------------------- function FieldLocalSelectInner< T extends Record, TFieldValues extends FieldValues = FieldValues, TName extends FieldPath = FieldPath, >(props: FieldLocalSelectProps) { const { // RHF controller props name, control, rules, shouldUnregister, defaultValue, disabled, // LocalSelect engine props options, valueKey, labelKey, renderLabel, multiple, filterOption, onSelect: onSelectCallback, // Remaining Mantine props ...mantineProps } = props; const { field, fieldState: { error }, } = useController({ name, control, rules, shouldUnregister, defaultValue, disabled, }); // Translate the error message (handles JSON i18n payloads) const translatedError = useTranslatedError(error?.message); // Intercept onChange to pass full objects to RHF const handleChange = (value: any) => { field.onChange(value); onSelectCallback?.(value); }; // Build engine props based on single/multi mode if (multiple) { return ( multiple options={options} valueKey={valueKey} labelKey={labelKey} renderLabel={renderLabel} filterOption={filterOption} value={field.value ?? []} onChange={handleChange} onBlur={field.onBlur} error={translatedError} disabled={field.disabled} {...(mantineProps as any)} /> ); } return ( options={options} valueKey={valueKey} labelKey={labelKey} renderLabel={renderLabel} filterOption={filterOption} value={field.value ?? null} onChange={handleChange} onBlur={field.onBlur} error={translatedError} disabled={field.disabled} {...(mantineProps as any)} /> ); } export const FieldLocalSelect = React.memo(FieldLocalSelectInner) as typeof FieldLocalSelectInner; (FieldLocalSelect as any).displayName = 'FieldLocalSelect';