import { type ChangeEvent, forwardRef, useImperativeHandle, useMemo, useRef } from "react"; import { useTranslation } from "react-i18next"; import { ArrowDownOutlined as ArrowDownOutlinedIcon, ArrowUpOutlined as ArrowUpOutlinedIcon, MinusOutlined as MinusOutlinedIcon, PlusOutlined as PlusOutlinedIcon, } from "@ant-design/icons"; import { useControllableValue } from "ahooks"; import { Button, Input, type InputProps, type InputRef, Space } from "antd"; import { produce } from "immer"; export type MultipleInputProps = Omit & { allowClear?: boolean; defaultValue?: string[]; maxCount?: number; minCount?: number; showSortButton?: boolean; value?: string[]; onChange?: (value: string[]) => void; onValueChange?: (index: number, element: string) => void; onValueCreate?: (index: number) => void; onValueRemove?: (index: number) => void; onValueSort?: (oldIndex: number, newIndex: number) => void; }; const MultipleInput = ({ allowClear = false, disabled, maxCount, minCount, showSortButton = true, onValueChange, onValueCreate, onValueSort, onValueRemove, ...props }: MultipleInputProps) => { const { t } = useTranslation(); const itemRefs = useRef([]); const [value, setValue] = useControllableValue(props, { valuePropName: "value", defaultValue: [], defaultValuePropName: "defaultValue", trigger: "onChange", }); const handleCreate = () => { const newValue = produce(value, (draft) => { draft.push(""); }); setValue(newValue); setTimeout(() => itemRefs.current[newValue.length - 1]?.focus(), 0); onValueCreate?.(newValue.length - 1); }; const handleChange = (index: number, element: string) => { const newValue = produce(value, (draft) => { draft[index] = element; }); setValue(newValue); onValueChange?.(index, element); }; const handleInputBlur = (index: number) => { if (!allowClear && !value[index]) { const newValue = produce(value, (draft) => { draft.splice(index, 1); }); setValue(newValue); } }; const handleClickUp = (index: number) => { if (index === 0) { return; } const newValue = produce(value, (draft) => { const temp = draft[index - 1]; draft[index - 1] = draft[index]; draft[index] = temp; }); setValue(newValue); onValueSort?.(index, index - 1); }; const handleClickDown = (index: number) => { if (index === value.length - 1) { return; } const newValue = produce(value, (draft) => { const temp = draft[index + 1]; draft[index + 1] = draft[index]; draft[index] = temp; }); setValue(newValue); onValueSort?.(index, index + 1); }; const handleClickAdd = (index: number) => { const newValue = produce(value, (draft) => { draft.splice(index + 1, 0, ""); }); setValue(newValue); setTimeout(() => itemRefs.current[index + 1]?.focus(), 0); onValueCreate?.(index + 1); }; const handleClickRemove = (index: number) => { const newValue = produce(value, (draft) => { draft.splice(index, 1); }); setValue(newValue); onValueRemove?.(index); }; return value == null || value.length === 0 ? ( ) : ( {Array.from(value).map((element, index) => { const allowUp = index > 0; const allowDown = index < value.length - 1; const allowRemove = minCount == null || value.length > minCount; const allowAdd = maxCount == null || value.length < maxCount; return ( (itemRefs.current[index] = ref!)} allowAdd={allowAdd} allowClear={allowClear} allowDown={allowDown} allowRemove={allowRemove} allowUp={allowUp} disabled={disabled} defaultValue={undefined} showSortButton={showSortButton} value={element} onBlur={() => handleInputBlur(index)} onChange={(val) => handleChange(index, val)} onClickAdd={() => handleClickAdd(index)} onClickDown={() => handleClickDown(index)} onClickUp={() => handleClickUp(index)} onClickRemove={() => handleClickRemove(index)} /> ); })} ); }; type MultipleInputItemProps = Omit< MultipleInputProps, "defaultValue" | "maxCount" | "minCount" | "preset" | "value" | "onChange" | "onValueCreate" | "onValueRemove" | "onValueSort" | "onValueChange" > & { allowAdd: boolean; allowRemove: boolean; allowUp: boolean; allowDown: boolean; defaultValue?: string; value?: string; onChange?: (value: string) => void; onClickAdd?: () => void; onClickDown?: () => void; onClickUp?: () => void; onClickRemove?: () => void; }; type MultipleInputItemInstance = { focus: InputRef["focus"]; blur: InputRef["blur"]; select: InputRef["select"]; }; const MultipleInputItem = forwardRef( ( { allowAdd, allowClear, allowDown, allowRemove, allowUp, disabled, showSortButton, size, onClickAdd, onClickDown, onClickUp, onClickRemove, ...props }: MultipleInputItemProps, ref ) => { const inputRef = useRef(null); const [value, setValue] = useControllableValue(props, { valuePropName: "value", defaultValue: "", defaultValuePropName: "defaultValue", trigger: "onChange", }); const upBtn = useMemo(() => { if (!showSortButton) return null; return