feat: replace ObjectSelect with LocalSelect and introduce custom FieldSelect wrappers for object-based RHF state management
This commit is contained in:
@@ -7,7 +7,7 @@ import {
|
||||
} from 'react-hook-form';
|
||||
import type { SelectProps, MultiSelectProps } from '@mantine/core';
|
||||
import { AsyncSelect } from '../custom/selects/AsyncSelect';
|
||||
import type { ObjectSelectBaseProps } from '../custom/selects/types';
|
||||
import type { AsyncSelectBaseProps, LoadOptionsFn } from '../custom/selects/types';
|
||||
import { useTranslatedError } from '../useTranslatedError';
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
@@ -16,19 +16,29 @@ import { useTranslatedError } from '../useTranslatedError';
|
||||
//
|
||||
// Thin RHF wrapper around the standalone AsyncSelect engine.
|
||||
// Adds useController binding + i18n error translation.
|
||||
//
|
||||
// Data Mapping Contract:
|
||||
// Single: RHF stores T | null → maps to Mantine string | null
|
||||
// Multi: RHF stores T[] → maps to Mantine string[]
|
||||
//
|
||||
// Inversion of Control: accepts `loadOptions` callback instead of
|
||||
// hardcoded API endpoint. The component is transport-agnostic.
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
/** 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';
|
||||
|
||||
/** Async-specific props */
|
||||
/** Async-specific props (IoC pattern) */
|
||||
interface AsyncExtraProps<T> {
|
||||
apiEndpoint: string;
|
||||
transformResponse?: (res: any) => { data: T[]; hasMore?: boolean } | T[];
|
||||
pageSize?: number;
|
||||
/** Async callback to load options — (search, page, prevOptions) => Promise */
|
||||
loadOptions: LoadOptionsFn<T>;
|
||||
|
||||
/** Pre-loaded objects for edit forms (injected into dropdown regardless of fetch state) */
|
||||
defaultOptions?: T[];
|
||||
|
||||
/** Search debounce delay in ms (default: 300) */
|
||||
debounceMs?: number;
|
||||
fetchFn?: (url: string) => Promise<any>;
|
||||
}
|
||||
|
||||
/** Single-select async RHF props */
|
||||
@@ -36,7 +46,7 @@ export type FieldAsyncSelectSingleProps<
|
||||
T extends Record<string, any>,
|
||||
TFieldValues extends FieldValues = FieldValues,
|
||||
TName extends FieldPath<TFieldValues> = FieldPath<TFieldValues>,
|
||||
> = Omit<ObjectSelectBaseProps<T>, 'data'> &
|
||||
> = AsyncSelectBaseProps<T> &
|
||||
AsyncExtraProps<T> &
|
||||
UseControllerProps<TFieldValues, TName> &
|
||||
Omit<SelectProps, ManagedSelectProps> & {
|
||||
@@ -48,7 +58,7 @@ export type FieldAsyncSelectMultiProps<
|
||||
T extends Record<string, any>,
|
||||
TFieldValues extends FieldValues = FieldValues,
|
||||
TName extends FieldPath<TFieldValues> = FieldPath<TFieldValues>,
|
||||
> = Omit<ObjectSelectBaseProps<T>, 'data'> &
|
||||
> = AsyncSelectBaseProps<T> &
|
||||
AsyncExtraProps<T> &
|
||||
UseControllerProps<TFieldValues, TName> &
|
||||
Omit<MultiSelectProps, ManagedMultiSelectProps> & {
|
||||
@@ -86,12 +96,10 @@ function FieldAsyncSelectInner<
|
||||
renderLabel,
|
||||
multiple,
|
||||
filterOption,
|
||||
onSelect: onObjectSelect,
|
||||
apiEndpoint,
|
||||
transformResponse,
|
||||
pageSize,
|
||||
onSelect: onSelectCallback,
|
||||
loadOptions,
|
||||
defaultOptions,
|
||||
debounceMs,
|
||||
fetchFn,
|
||||
// Remaining Mantine props
|
||||
...mantineProps
|
||||
} = props;
|
||||
@@ -112,7 +120,7 @@ function FieldAsyncSelectInner<
|
||||
|
||||
const handleChange = (value: any) => {
|
||||
field.onChange(value);
|
||||
onObjectSelect?.(value);
|
||||
onSelectCallback?.(value);
|
||||
};
|
||||
|
||||
const engineProps = {
|
||||
@@ -120,11 +128,9 @@ function FieldAsyncSelectInner<
|
||||
labelKey,
|
||||
renderLabel,
|
||||
filterOption,
|
||||
apiEndpoint,
|
||||
transformResponse,
|
||||
pageSize,
|
||||
loadOptions,
|
||||
defaultOptions,
|
||||
debounceMs,
|
||||
fetchFn,
|
||||
onBlur: field.onBlur,
|
||||
error: translatedError,
|
||||
disabled: field.disabled,
|
||||
|
||||
Reference in New Issue
Block a user