Feat: Modify the style of the classification operator and fix some console errors. (#13314)

### What problem does this PR solve?

Feat: Modify the style of the classification operator and fix some
console errors.

### Type of change


- [x] New Feature (non-breaking change which adds functionality)
This commit is contained in:
balibabu
2026-03-02 16:53:24 +08:00
committed by GitHub
parent 5fc3bd38b0
commit 7d6f20585f
9 changed files with 216 additions and 190 deletions

View File

@@ -16,7 +16,7 @@ interface EditTagsProps {
}
const EditTag = React.forwardRef<HTMLDivElement, EditTagsProps>(
({ value = [], onChange, disabled }: EditTagsProps) => {
function EditTag({ value = [], onChange, disabled }, ref) {
const [inputVisible, setInputVisible] = useState(false);
const [inputValue, setInputValue] = useState('');
const inputRef = useRef<HTMLInputElement>(null);
@@ -82,7 +82,7 @@ const EditTag = React.forwardRef<HTMLDivElement, EditTagsProps>(
const tagChild = value?.map(forMap);
return (
<div>
<div ref={ref}>
{inputVisible && (
<Input
ref={inputRef}

View File

@@ -2,12 +2,14 @@ import { isNumber, trim } from 'lodash';
import { MinusIcon, PlusIcon } from 'lucide-react';
import React, {
FocusEventHandler,
forwardRef,
useCallback,
useEffect,
useMemo,
useRef,
useState,
} from 'react';
import { InputProps } from '../ui/input';
interface NumberInputProps {
className?: string;
@@ -18,113 +20,119 @@ interface NumberInputProps {
max?: number;
}
const NumberInput: React.FC<NumberInputProps> = ({
className,
value: initialValue,
onChange,
height,
min = 0,
max = Infinity,
}) => {
const [value, setValue] = useState<number | ''>(() => {
return initialValue ?? 0;
});
const NumberInput = forwardRef<HTMLInputElement, InputProps & NumberInputProps>(
function NumberInput(
{
className,
value: initialValue,
onChange,
height,
min = 0,
max = Infinity,
},
ref,
) {
const [value, setValue] = useState<number | ''>(() => {
return initialValue ?? 0;
});
const valueRef = useRef<number>();
const valueRef = useRef<number>();
useEffect(() => {
if (initialValue !== undefined) {
setValue(initialValue);
}
}, [initialValue]);
const handleDecrement = () => {
if (isNumber(value) && value > min) {
setValue(value - 1);
onChange?.(value - 1);
}
};
const handleIncrement = () => {
if (!isNumber(value)) {
return;
}
if (value > max - 1) {
return;
}
setValue(value + 1);
onChange?.(value + 1);
};
const handleChange = (e: React.ChangeEvent<HTMLInputElement>) => {
const currentValue = e.target.value;
const newValue = Number(currentValue);
if (trim(currentValue) === '') {
if (isNumber(value)) {
valueRef.current = value;
useEffect(() => {
if (initialValue !== undefined) {
setValue(initialValue);
}
setValue('');
return;
}
}, [initialValue]);
if (!isNaN(newValue)) {
if (newValue > max || newValue < min) {
const handleDecrement = () => {
if (isNumber(value) && value > min) {
setValue(value - 1);
onChange?.(value - 1);
}
};
const handleIncrement = () => {
if (!isNumber(value)) {
return;
}
setValue(newValue);
onChange?.(newValue);
}
};
if (value > max - 1) {
return;
}
setValue(value + 1);
onChange?.(value + 1);
};
const handleBlur: FocusEventHandler<HTMLInputElement> = useCallback(() => {
if (isNumber(value)) {
onChange?.(value);
} else {
const previousValue = valueRef.current ?? min;
setValue(previousValue);
onChange?.(previousValue);
}
}, [min, onChange, value]);
const handleChange = (e: React.ChangeEvent<HTMLInputElement>) => {
const currentValue = e.target.value;
const newValue = Number(currentValue);
const style = useMemo(
() => ({
height: height ? `${height.toString().replace('px', '')}px` : 'auto',
}),
[height],
);
return (
<div
className={`flex h-10 items-center space-x-2 border-[1px] rounded-lg w-[150px] ${className || ''}`}
style={style}
>
<button
type="button"
className="w-10 p-2 focus:outline-none border-r-[1px]"
onClick={handleDecrement}
if (trim(currentValue) === '') {
if (isNumber(value)) {
valueRef.current = value;
}
setValue('');
return;
}
if (!isNaN(newValue)) {
if (newValue > max || newValue < min) {
return;
}
setValue(newValue);
onChange?.(newValue);
}
};
const handleBlur: FocusEventHandler<HTMLInputElement> = 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',
}),
[height],
);
return (
<div
className={`flex h-10 items-center space-x-2 border-[1px] rounded-lg w-[150px] ${className || ''}`}
style={style}
ref={ref}
>
<MinusIcon size={16} aria-hidden="true" />
</button>
<input
type="text"
value={value}
onChange={handleChange}
onBlur={handleBlur}
className="w-full flex-1 text-center bg-transparent focus:outline-none"
style={style}
min={min}
/>
<button
type="button"
className="w-10 p-2 focus:outline-none border-l-[1px]"
onClick={handleIncrement}
style={style}
>
<PlusIcon size={16} aria-hidden="true" />
</button>
</div>
);
};
<button
type="button"
className="w-10 p-2 focus:outline-none border-r-[1px]"
onClick={handleDecrement}
style={style}
>
<MinusIcon size={16} aria-hidden="true" />
</button>
<input
type="text"
value={value}
onChange={handleChange}
onBlur={handleBlur}
className="w-full flex-1 text-center bg-transparent focus:outline-none"
style={style}
min={min}
/>
<button
type="button"
className="w-10 p-2 focus:outline-none border-l-[1px]"
onClick={handleIncrement}
style={style}
>
<PlusIcon size={16} aria-hidden="true" />
</button>
</div>
);
},
);
export default NumberInput;