diff --git a/src/components/input/SelectInput.tsx b/src/components/input/SelectInput.tsx index 930b5ed5..43a3f622 100644 --- a/src/components/input/SelectInput.tsx +++ b/src/components/input/SelectInput.tsx @@ -1,28 +1,38 @@ 'use client'; -import { ComponentType, ReactNode, useEffect, useMemo, useState } from 'react'; -import Select, { OptionProps, GroupBase, InputActionMeta } from 'react-select'; +import { + ComponentType, + ReactNode, + useEffect, + useMemo, + useState, +} from 'react'; +import Select, { + OptionProps, + GroupBase, + InputActionMeta, + MultiValue, + SingleValue, +} from 'react-select'; +import CreatableSelect from 'react-select/creatable'; import makeAnimated from 'react-select/animated'; import { useDebounce } from 'use-debounce'; - import { cn } from '@/lib/helper'; export interface OptionType { value: string | number; label: string; - className?: string; // for multi select - labelClassName?: string; // for multi select + className?: string; + labelClassName?: string; } export type OptionComponent = ComponentType< OptionProps> >; -interface SelectInputProps { +interface SelectInputBaseProps { label?: ReactNode; bottomLabel?: ReactNode; - value?: T | T[]; - onChange?: (val: T | T[] | null) => void; options: T[]; optionComponent?: OptionComponent; isDisabled?: boolean; @@ -46,52 +56,78 @@ interface SelectInputProps { onInputChange?: (search: string) => void; } +interface SelectInputProps extends SelectInputBaseProps { + createables?: boolean; + value?: T | T[] | null; + onChange?: (val: T | T[] | null) => void; +} + const animatedComponents = makeAnimated(); -const SelectInput = ({ - label, - bottomLabel, - value, - onChange, - options, - optionComponent, - isDisabled, - isLoading, - isClearable, - isRtl, - isSearchable = true, - isMulti, - placeholder, - required, - className, - isError, - errorMessage, - isAnimated = true, - openMenu, - delay = 300, - onInputChange, -}: SelectInputProps) => { - const [internalInputValue, setInternalInputValue] = useState(''); +const SelectInput = (props: SelectInputProps) => { + const { + label, + bottomLabel, + value, + onChange, + options, + optionComponent, + isDisabled, + isLoading, + isClearable, + isRtl, + isSearchable = true, + isMulti, + placeholder, + required, + className, + isError, + errorMessage, + isAnimated = true, + openMenu, + delay = 300, + createables = false, + onInputChange, + } = props; - const [debouncedInputValue] = useDebounce(internalInputValue, delay ?? 300); + const [internalInputValue, setInternalInputValue] = useState(''); + const [debouncedInputValue] = useDebounce(internalInputValue, delay); const components = useMemo(() => { const base = isAnimated ? animatedComponents : {}; - - return { - ...base, - IndicatorSeparator: () => null, - }; + return { ...base, IndicatorSeparator: () => null }; }, [isAnimated]); - const internalInputChangeHandler = (value: string, meta: InputActionMeta) => { - if (meta.action === 'input-change') setInternalInputValue(value); + const internalInputChangeHandler = ( + val: string, + meta: InputActionMeta + ) => { + if (meta.action === 'input-change') setInternalInputValue(val); if (meta.action === 'menu-close') setInternalInputValue(''); }; useEffect(() => { onInputChange?.(debouncedInputValue); - }, [debouncedInputValue]); + }, [onInputChange, debouncedInputValue]); + + const SelectComponent = createables ? CreatableSelect : Select; + + /** 🎯 handleChange tanpa any */ + const handleChange = ( + val: MultiValue | SingleValue + ): void => { + if (!val) { + onChange?.(null); + return; + } + + if (isMulti) { + onChange?.(val as T[]); + } else { + onChange?.(val as T); + } + }; + return (
({ {label} {required && ( - <> - {' '} - - * - - + + * + )} )} -