Compare commits
1 Commits
bc4c1f9c70
...
01ade3fb3c
| Author | SHA1 | Date | |
|---|---|---|---|
| 01ade3fb3c |
@@ -56,15 +56,6 @@ export function LinkAutocomplete({
|
|||||||
const mirrorRef = useRef<HTMLDivElement | null>(null);
|
const mirrorRef = useRef<HTMLDivElement | null>(null);
|
||||||
const cursorSpanRef = useRef<HTMLSpanElement | null>(null);
|
const cursorSpanRef = useRef<HTMLSpanElement | null>(null);
|
||||||
|
|
||||||
// Refs for event handler to avoid stale closures when effects re-attach listeners
|
|
||||||
const stateRef = useRef(state);
|
|
||||||
const resultsRef = useRef(results);
|
|
||||||
const selectedIndexRef = useRef(selectedIndex);
|
|
||||||
const insertLinkRef = useRef<((result: SearchResult) => void) | null>(null);
|
|
||||||
stateRef.current = state;
|
|
||||||
resultsRef.current = results;
|
|
||||||
selectedIndexRef.current = selectedIndex;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Search for knowledge entries matching the query.
|
* Search for knowledge entries matching the query.
|
||||||
* Accepts an AbortSignal to allow cancellation of in-flight requests,
|
* Accepts an AbortSignal to allow cancellation of in-flight requests,
|
||||||
@@ -263,32 +254,29 @@ export function LinkAutocomplete({
|
|||||||
}, [textareaRef, state.isOpen, calculateDropdownPosition, debouncedSearch]);
|
}, [textareaRef, state.isOpen, calculateDropdownPosition, debouncedSearch]);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Handle keyboard navigation in the dropdown.
|
* Handle keyboard navigation in the dropdown
|
||||||
* Reads from refs to avoid stale closures when the effect
|
|
||||||
* that attaches this listener hasn't re-run yet.
|
|
||||||
*/
|
*/
|
||||||
const handleKeyDown = useCallback((e: KeyboardEvent): void => {
|
const handleKeyDown = useCallback(
|
||||||
if (!stateRef.current.isOpen) return;
|
(e: KeyboardEvent): void => {
|
||||||
|
if (!state.isOpen) return;
|
||||||
const currentResults = resultsRef.current;
|
|
||||||
|
|
||||||
switch (e.key) {
|
switch (e.key) {
|
||||||
case "ArrowDown":
|
case "ArrowDown":
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
setSelectedIndex((prev) => (prev + 1) % currentResults.length);
|
setSelectedIndex((prev) => (prev + 1) % results.length);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case "ArrowUp":
|
case "ArrowUp":
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
setSelectedIndex((prev) => (prev - 1 + currentResults.length) % currentResults.length);
|
setSelectedIndex((prev) => (prev - 1 + results.length) % results.length);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case "Enter":
|
case "Enter":
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
if (currentResults.length > 0 && selectedIndexRef.current >= 0) {
|
if (results.length > 0 && selectedIndex >= 0) {
|
||||||
const selected = currentResults[selectedIndexRef.current];
|
const selected = results[selectedIndex];
|
||||||
if (selected) {
|
if (selected) {
|
||||||
insertLinkRef.current?.(selected);
|
insertLink(selected);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
@@ -304,7 +292,9 @@ export function LinkAutocomplete({
|
|||||||
setResults([]);
|
setResults([]);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}, []);
|
},
|
||||||
|
[state.isOpen, results, selectedIndex]
|
||||||
|
);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Insert the selected link into the textarea
|
* Insert the selected link into the textarea
|
||||||
@@ -340,7 +330,6 @@ export function LinkAutocomplete({
|
|||||||
},
|
},
|
||||||
[textareaRef, state.triggerIndex, onInsert]
|
[textareaRef, state.triggerIndex, onInsert]
|
||||||
);
|
);
|
||||||
insertLinkRef.current = insertLink;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Handle click on a result
|
* Handle click on a result
|
||||||
|
|||||||
Reference in New Issue
Block a user