fix(opencode): prevent model ID input focus loss on keystroke

Use local state + onBlur pattern for ModelIdInput to keep React key
stable during editing. Previously, each keystroke changed the object
key, causing React to unmount/remount the input and lose focus.
This commit is contained in:
Jason
2026-01-18 21:52:44 +08:00
parent 255a7f570a
commit 1a0872c153

View File

@@ -1,3 +1,4 @@
import { useState, useEffect } from "react";
import { useTranslation } from "react-i18next";
import { FormLabel } from "@/components/ui/form";
import { Input } from "@/components/ui/input";
@@ -14,6 +15,43 @@ import { ApiKeySection } from "./shared";
import { opencodeNpmPackages } from "@/config/opencodeProviderPresets";
import type { ProviderCategory, OpenCodeModel } from "@/types";
/**
* Model ID input with local state to prevent focus loss.
* The key prop issue: when Model ID changes, React sees it as a new element
* and unmounts/remounts the input, losing focus. Using local state + onBlur
* keeps the key stable during editing.
*/
function ModelIdInput({
modelId,
onChange,
placeholder,
}: {
modelId: string;
onChange: (newId: string) => void;
placeholder?: string;
}) {
const [localValue, setLocalValue] = useState(modelId);
// Sync when external modelId changes (e.g., undo operation)
useEffect(() => {
setLocalValue(modelId);
}, [modelId]);
return (
<Input
value={localValue}
onChange={(e) => setLocalValue(e.target.value)}
onBlur={() => {
if (localValue !== modelId && localValue.trim()) {
onChange(localValue);
}
}}
placeholder={placeholder}
className="flex-1"
/>
);
}
interface OpenCodeFormFieldsProps {
// NPM Package
npm: string;
@@ -177,13 +215,12 @@ export function OpenCodeFormFields({
<div className="space-y-2">
{Object.entries(models).map(([key, model]) => (
<div key={key} className="flex items-center gap-2">
<Input
value={key}
onChange={(e) => handleModelIdChange(key, e.target.value)}
<ModelIdInput
modelId={key}
onChange={(newId) => handleModelIdChange(key, newId)}
placeholder={t("opencode.modelId", {
defaultValue: "Model ID",
})}
className="flex-1"
/>
<Input
value={model.name}