diff --git a/web/src/components/message-history-window-size-item.tsx b/web/src/components/message-history-window-size-item.tsx index 69df072b1..cd44f0d0a 100644 --- a/web/src/components/message-history-window-size-item.tsx +++ b/web/src/components/message-history-window-size-item.tsx @@ -1,5 +1,6 @@ import { useFormContext } from 'react-hook-form'; import { useTranslation } from 'react-i18next'; +import NumberInput from './originui/number-input'; import { FormControl, FormField, @@ -7,9 +8,13 @@ import { FormLabel, FormMessage, } from './ui/form'; -import { NumberInput } from './ui/input'; -export function MessageHistoryWindowSizeFormField() { +type MessageHistoryWindowSizeFormFieldProps = { + min?: number; +}; +export function MessageHistoryWindowSizeFormField({ + min, +}: MessageHistoryWindowSizeFormFieldProps) { const form = useFormContext(); const { t } = useTranslation(); @@ -23,7 +28,7 @@ export function MessageHistoryWindowSizeFormField() { {t('flow.messageHistoryWindowSize')} - + diff --git a/web/src/components/originui/number-input.tsx b/web/src/components/originui/number-input.tsx index 535c1e8b3..27497ba0d 100644 --- a/web/src/components/originui/number-input.tsx +++ b/web/src/components/originui/number-input.tsx @@ -1,5 +1,13 @@ +import { isNumber, trim } from 'lodash'; import { MinusIcon, PlusIcon } from 'lucide-react'; -import React, { useEffect, useMemo, useState } from 'react'; +import React, { + FocusEventHandler, + useCallback, + useEffect, + useMemo, + useRef, + useState, +} from 'react'; interface NumberInputProps { className?: string; @@ -18,10 +26,12 @@ const NumberInput: React.FC = ({ min = 0, max = Infinity, }) => { - const [value, setValue] = useState(() => { + const [value, setValue] = useState(() => { return initialValue ?? 0; }); + const valueRef = useRef(); + useEffect(() => { if (initialValue !== undefined) { setValue(initialValue); @@ -29,13 +39,16 @@ const NumberInput: React.FC = ({ }, [initialValue]); const handleDecrement = () => { - if (value > 0) { + if (isNumber(value) && value > min) { setValue(value - 1); onChange?.(value - 1); } }; const handleIncrement = () => { + if (!isNumber(value)) { + return; + } if (value > max - 1) { return; } @@ -44,9 +57,19 @@ const NumberInput: React.FC = ({ }; const handleChange = (e: React.ChangeEvent) => { - const newValue = Number(e.target.value); + const currentValue = e.target.value; + const newValue = Number(currentValue); + + if (trim(currentValue) === '') { + if (isNumber(value)) { + valueRef.current = value; + } + setValue(''); + return; + } + if (!isNaN(newValue)) { - if (newValue > max) { + if (newValue > max || newValue < min) { return; } setValue(newValue); @@ -54,12 +77,16 @@ const NumberInput: React.FC = ({ } }; - const handleInput = (e: React.ChangeEvent) => { - // If the input value is not a number, the input is not allowed - if (!/^\d*$/.test(e.target.value)) { - e.preventDefault(); + const handleBlur: FocusEventHandler = useCallback(() => { + if (isNumber(value)) { + onChange?.(value); + } else { + const previousValue = valueRef.current ?? min; + setValue(previousValue); + onChange?.(previousValue); } - }; + }, [min, onChange, value]); + const style = useMemo( () => ({ height: height ? `${height.toString().replace('px', '')}px` : 'auto', @@ -82,8 +109,8 @@ const NumberInput: React.FC = ({ - +