♻️ refactor: 重构ArgsInput组件 (#8765)

* ♻️ refactor(utils): extract args parsing logic from ArgsInput component
- Extract parseArgs and argsToString functions to src/utils/args.ts
- Add comprehensive test suite with 19 test cases covering edge cases
- Fix escaped quote handling in parseArgs function
- Replace String.replace() with String.replaceAll() for better readability
- Improve code reusability and maintainability following project best practices

* 📝 docs(utils): improve JSDoc comments and clean up redundant comments
- Add comprehensive JSDoc with @param and @returns for args functions
- Translate inline comments to English for consistency
- Remove redundant comments in ArgsInput component
- Keep only essential comments and improve code clarity
- Improve code documentation quality and IDE support

* ♻️ refactor(ArgsInput): completely redesign as array editor
- Replace single input with individual argument inputs
- Add visual array structure with add/remove buttons
- Support keyboard shortcuts (Enter to add, Backspace to delete)
- Improve UX with proper array operations and indexing
- Remove dependency on args parsing utils for better performance

* 🌐 i18n: add ArgsInput internationalization support
- Add ArgsInput translations for en-US and zh-CN
- Add TypeScript type definitions for new translation keys
- Support dynamic placeholder with argument index
- Fix TypeScript error for missing translation keys
This commit is contained in:
Coooolfan
2025-08-16 18:34:14 +08:00
committed by GitHub
parent 86a28d9615
commit 09055595e4
4 changed files with 107 additions and 10 deletions
+5
View File
@@ -1,4 +1,9 @@
{
"ArgsInput": {
"addArgument": "Add Argument",
"argumentPlaceholder": "Argument {{index}}",
"enterFirstArgument": "Enter first argument..."
},
"DragUpload": {
"dragDesc": "Drag and drop files here to upload multiple images.",
"dragFileDesc": "Drag and drop images and files here to upload multiple images and files.",
+5
View File
@@ -1,4 +1,9 @@
{
"ArgsInput": {
"addArgument": "添加参数",
"argumentPlaceholder": "参数 {{index}}",
"enterFirstArgument": "输入第一个参数..."
},
"DragUpload": {
"dragDesc": "拖拽文件到这里,支持上传多个图片。",
"dragFileDesc": "拖拽图片和文件到这里,支持上传多个图片和文件。",
@@ -1,20 +1,102 @@
import { Input, type InputProps } from '@lobehub/ui';
import { memo } from 'react';
import { ActionIcon, Button, Input, type InputProps } from '@lobehub/ui';
import { Plus, X } from 'lucide-react';
import React, { memo, useCallback } from 'react';
import { useTranslation } from 'react-i18next';
import { Flexbox } from 'react-layout-kit';
interface ArgsInputProps extends Omit<InputProps, 'value' | 'onChange'> {
onChange?: (value: string[]) => void;
value?: string[];
}
const ArgsInput = memo<ArgsInputProps>(({ value, onChange, ...res }) => {
const ArgsInput = memo<ArgsInputProps>(({ value = [], onChange, ...res }) => {
const { t } = useTranslation('components');
const handleAddArg = useCallback(() => {
onChange?.([...value, '']);
}, [value, onChange]);
const handleRemoveArg = useCallback(
(index: number) => {
const newValue = value.filter((_, i) => i !== index);
onChange?.(newValue);
},
[value, onChange],
);
const handleArgChange = useCallback(
(index: number, newArg: string) => {
const newValue = [...value];
newValue[index] = newArg;
onChange?.(newValue);
},
[value, onChange],
);
const handleKeyDown = useCallback(
(e: React.KeyboardEvent<HTMLInputElement>, index: number) => {
if (e.key === 'Enter') {
e.preventDefault();
if (index === value.length - 1) {
handleAddArg();
}
} else if (e.key === 'Backspace' && e.currentTarget.value === '' && value.length > 1) {
e.preventDefault();
handleRemoveArg(index);
}
},
[value.length, handleAddArg, handleRemoveArg],
);
return (
<Input
onChange={(e) => {
onChange?.([e.target.value]);
}}
value={value?.join(' ')}
{...res}
/>
<Flexbox gap={8} style={{ width: '100%' }}>
{value.length === 0 ? (
<Flexbox align="center" gap={8} horizontal>
<Input
{...res}
onBlur={(e) => {
if (e.target.value.trim()) {
onChange?.([e.target.value.trim()]);
}
res.onBlur?.(e);
}}
placeholder={t('ArgsInput.enterFirstArgument')}
style={{ flex: 1 }}
/>
<Button icon={Plus} onClick={handleAddArg} size="small" type="primary" />
</Flexbox>
) : (
<>
{value.map((arg, index) => (
<Flexbox align="center" gap={8} horizontal key={index}>
<Input
onChange={(e) => handleArgChange(index, e.target.value)}
onKeyDown={(e) => handleKeyDown(e, index)}
placeholder={t('ArgsInput.argumentPlaceholder', { index: index + 1 })}
style={{ flex: 1 }}
value={arg}
/>
<ActionIcon
icon={X}
onClick={() => handleRemoveArg(index)}
size="small"
style={{ flexShrink: 0 }}
/>
</Flexbox>
))}
<Button
icon={Plus}
onClick={handleAddArg}
size="small"
style={{ alignSelf: 'flex-start' }}
type="dashed"
>
{t('ArgsInput.addArgument')}
</Button>
</>
)}
</Flexbox>
);
});
export default ArgsInput;
+5
View File
@@ -1,4 +1,9 @@
export default {
ArgsInput: {
addArgument: '添加参数',
argumentPlaceholder: '参数 {{index}}',
enterFirstArgument: '输入第一个参数...',
},
DragUpload: {
dragDesc: '拖拽文件到这里,支持上传多个图片。',
dragFileDesc: '拖拽图片和文件到这里,支持上传多个图片和文件。',