Browse Source

fix(dashboard-v6): 查词框回车查输入的词,不再被鼠标悬停的候选项覆盖

鼠标悬停也会让 AutoComplete 的候选项高亮,回车时先按输入的词查、
紧接着 onSelect 又查悬停项,后者覆盖前者(输入 visuddha 却查了 visuddhatta)。
现在只有用 ↑↓ 选过候选项时回车才选它;鼠标点击不受影响。

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
visuddhinanda 1 day ago
parent
commit
77e35e9b91
1 changed files with 27 additions and 0 deletions
  1. 27 0
      dashboard-v6/src/components/dict/SearchVocabulary.tsx

+ 27 - 0
dashboard-v6/src/components/dict/SearchVocabulary.tsx

@@ -33,6 +33,12 @@ const SearchVocabulary = ({
   const [factors, setFactors] = useState<string[]>([]);
   const [factors, setFactors] = useState<string[]>([]);
   // 请求序号:用于竞态防护,只保留最新一次请求的结果
   // 请求序号:用于竞态防护,只保留最新一次请求的结果
   const seqRef = useRef(0);
   const seqRef = useRef(0);
+  // 回车只认键盘选中的候选项:鼠标悬停也会让某项高亮,此时回车 AutoComplete
+  // 会选中悬停项(先触发 Input.Search 的 onSearch 查输入的词,紧接着 onSelect
+  // 查悬停的词,后者覆盖前者)。用户要的是查自己输入的词。
+  const arrowNavRef = useRef(false); // 本次输入后是否按过 ↑↓
+  const enterRef = useRef(false); // 这次 onSelect 是否由回车触发
+  const typedRef = useRef<string | undefined>(undefined); // 回车那一刻输入框里的词
 
 
   // 外部 value(点击单词触发的查词)变化时,同步输入框显示。
   // 外部 value(点击单词触发的查词)变化时,同步输入框显示。
   // 仅在 value 真正变化时同步,用户手动输入时 value 不会变,因此不会打断输入。
   // 仅在 value 真正变化时同步,用户手动输入时 value 不会变,因此不会打断输入。
@@ -129,6 +135,8 @@ const SearchVocabulary = ({
         }}
         }}
         showSearch={{
         showSearch={{
           onSearch: (val: string) => {
           onSearch: (val: string) => {
+            // 只有打字会走这里(选中候选项不会),借此重置键盘选择
+            arrowNavRef.current = false;
             if (val === "") {
             if (val === "") {
               // 空输入:立即取消挂起请求,并使在途请求失效,清空建议
               // 空输入:立即取消挂起请求,并使在途请求失效,清空建议
               seqRef.current++;
               seqRef.current++;
@@ -142,6 +150,12 @@ const SearchVocabulary = ({
           },
           },
         }}
         }}
         onSelect={(val: string) => {
         onSelect={(val: string) => {
+          if (enterRef.current && !arrowNavRef.current) {
+            // 回车但没用 ↑↓ 选过:高亮来自鼠标悬停,忽略。Input.Search 的
+            // onSearch 已经查过输入的词,这里把被改掉的输入框改回来
+            setInput(typedRef.current);
+            return;
+          }
           onSearch?.(val);
           onSearch?.(val);
         }}
         }}
       >
       >
@@ -150,7 +164,20 @@ const SearchVocabulary = ({
           size={compact ? undefined : "large"}
           size={compact ? undefined : "large"}
           placeholder="search here"
           placeholder="search here"
           loading={fetching}
           loading={fetching}
+          onKeyDown={(e) => {
+            if (e.key === "ArrowUp" || e.key === "ArrowDown") {
+              arrowNavRef.current = true;
+            } else if (e.key === "Enter") {
+              // onSelect 与本次 keydown 同步触发;之后清掉,免得影响鼠标点击选择
+              enterRef.current = true;
+              setTimeout(() => {
+                enterRef.current = false;
+              }, 0);
+            }
+          }}
           onSearch={(val: string) => {
           onSearch={(val: string) => {
+            // 回车时它先于 onSelect 触发,val 就是用户输入的词
+            typedRef.current = val;
             onSearch?.(val);
             onSearch?.(val);
           }}
           }}
         />
         />