import { Typography } from '@mui/material'; import type { AutocompleteRenderInputParams } from '@mui/material/Autocomplete'; import { equals, F, findIndex, inc, isEmpty, isNil, last, length, not, pipe, pluck, propEq, remove } from 'ramda'; import { type ChangeEvent, type HTMLAttributes, useEffect, useState } from 'react'; import TextField from '../../../Text'; import type { Props as SingleAutocompletefieldProps } from '..'; import type { ConnectedAutoCompleteFieldProps } from '../Connected'; import SortableList, { type DraggableSelectEntry } from './SortableList'; export interface ItemActionProps { anchorElement?: HTMLElement | null; index: number; item: DraggableSelectEntry; } interface Props { error?: string; initialValues?: Array; itemClick?: (item: ItemActionProps) => void; itemHover?: (item: ItemActionProps | null) => void; label: string; onSelectedValuesChange?: ( values: Array, valueAddedOrDeleted?: DraggableSelectEntry ) => Array; required?: boolean; } // biome-ignore lint/suspicious/noExplicitAny: HOC accepts varied multi-autocomplete shapes type MultiAutocompleteLike = (props: any) => JSX.Element; const DraggableAutocomplete = ( MultiAutocomplete: MultiAutocompleteLike ): (( props: Props & (ConnectedAutoCompleteFieldProps | SingleAutocompletefieldProps) ) => JSX.Element) => { const InnerDraggableAutocompleteField = ({ onSelectedValuesChange, initialValues, itemClick, itemHover, label, required, error, ...props }: Props & ( | ConnectedAutoCompleteFieldProps | SingleAutocompletefieldProps )): JSX.Element => { const [selectedValues, setSelectedValues] = useState< Array >(initialValues || []); const [totalValues, setTotalValues] = useState( length(initialValues || []) ); const [inputText, setInputText] = useState(null); const onChangeSelectedValuesOrder = ( newSelectedValues: Array ): void => { setSelectedValues(newSelectedValues); onSelectedValuesChange?.(newSelectedValues); }; const deleteValue = (id: string | number): void => { itemHover?.(null); setSelectedValues((values: Array) => { const index = findIndex(propEq(id, 'id'), values); const newSelectedValues = remove(index, 1, values); onSelectedValuesChange?.(newSelectedValues); return newSelectedValues; }); }; const onChange = ( _: React.SyntheticEvent, newValue: Array ): void => { if (isEmpty(newValue)) { setInputText(null); onSelectedValuesChange?.([]); return; } const lastValue = last(newValue); if (typeof lastValue === 'string') { const lastDraggableItem: DraggableSelectEntry = { createOption: lastValue, id: `${lastValue}_${totalValues}`, name: lastValue }; setSelectedValues((values) => { const newSelectedValues = [...values, lastDraggableItem]; onSelectedValuesChange?.(newSelectedValues, lastDraggableItem); return newSelectedValues; }); setTotalValues(inc(totalValues)); setInputText(null); return; } const lastItem = last( newValue as Array ) as DraggableSelectEntry; const lastDraggableItem: DraggableSelectEntry = { id: `${lastItem.name}_${totalValues}`, name: lastItem.name }; setSelectedValues((values) => { const newSelectedValues = [...values, lastDraggableItem]; onSelectedValuesChange?.(newSelectedValues, lastDraggableItem); return newSelectedValues; }); setTotalValues(inc(totalValues)); setInputText(null); }; const renderTags = (): JSX.Element => { return ( ); }; const changeInput = (e: ChangeEvent): void => { if (pipe(isNil, not)(e)) { setInputText(e.target.value); } }; const blurInput = (): void => { if (inputText) { const lastItem = { createOption: inputText, id: `${inputText}_${totalValues}`, name: inputText }; setSelectedValues((values) => { const newSelectedValues = [...values, lastItem]; onSelectedValuesChange?.(newSelectedValues, lastItem); return newSelectedValues; }); setTotalValues(inc(totalValues)); } setInputText(null); }; const renderOption = ( renderProps: HTMLAttributes, option: DraggableSelectEntry ): JSX.Element => (
  • {option.name}
  • ); const renderInput = ( renderProps: AutocompleteRenderInputParams & { inputLabel?: Record; } ): JSX.Element => ( ); useEffect(() => { if (isNil(initialValues)) { return; } const areValuesEqual = equals( pluck('name', initialValues), pluck('name', selectedValues as Array) ); if (areValuesEqual) { return; } setSelectedValues(initialValues); }, [initialValues, selectedValues]); return ( ); }; return InnerDraggableAutocompleteField; }; export default DraggableAutocomplete;