"use client" import { type ReactNode, useContext } from "react" import { type SelectProps, Select } from "@heroui/react" import type { Key } from "@react-types/shared" import { clsx, isNonNullable } from "deepsea-tools" import type { FieldComponentProps } from "soda-tanstack-form" import type { StrictOmit } from "soda-type" import { type EmptyValue, FormContext, getEmptyValue } from "./FormProvider" import { getFieldProps } from "../utils/getFieldProps" export type SelectionMode = "single" | "multiple" export type SelectLabelPlacement = "inside" | "outside" | "outside-left" | "outside-top" export interface FormSelectProps< Mode extends SelectionMode = "single", Value extends (Mode extends "multiple" ? Key[] : Key) | null | undefined = (Mode extends "multiple" ? Key[] : Key) | null | undefined, RenderItem extends object = object, > extends StrictOmit, Value>, "selectionMode" | "labelPlacement"> { labelPlacement?: SelectLabelPlacement selectionMode?: Mode emptyValue?: EmptyValue component?: (props: SelectProps) => ReactNode } export function FormSelect< Mode extends SelectionMode = "single", Value extends (Mode extends "multiple" ? Key[] : Key) | null | undefined = (Mode extends "multiple" ? Key[] : Key) | null | undefined, RenderItem extends object = object, >({ field, emptyValue, component: Select2 = Select, selectionMode, labelPlacement, classNames: { base, label, ...restClassNames } = {}, ...rest }: FormSelectProps): ReactNode { const context = useContext(FormContext) emptyValue ??= context.emptyValue return ( classNames={{ base: clsx(labelPlacement === "outside-top" && "flex flex-col", base), label: clsx(labelPlacement === "outside-top" && "pb-2", label), ...restClassNames, }} selectedKeys={isNonNullable(field.state.value) ? (selectionMode === "multiple" ? (field.state.value as Key[]) : [field.state.value as Key]) : []} onSelectionChange={keys => { const value = Array.from(keys) field.handleChange((selectionMode === "multiple" ? value : (value.at(0) ?? getEmptyValue(emptyValue))) as Value) }} selectionMode={selectionMode} labelPlacement={labelPlacement === "outside-top" ? "outside-left" : labelPlacement} {...getFieldProps(field)} {...rest} /> ) }