@1771technologies/lytenyte-pro
Version:
Blazingly fast headless React data grid with 100s of features.
79 lines (78 loc) • 2.68 kB
JavaScript
import { useState, useCallback, useRef } from "react";
import { filterCompletionsByPrefix } from "./filter-completions-by-prefix.js";
export function useCompletions(completionProvider) {
const [state, setState] = useState({
items: [],
filteredItems: [],
selectedIndex: 0,
isOpen: false,
isLoading: false,
});
const requestIdRef = useRef(0);
const fetchCompletions = useCallback(async (tokens, cursorPosition, word) => {
if (!completionProvider)
return;
const requestId = ++requestIdRef.current;
setState((prev) => ({ ...prev, isLoading: true, isOpen: true }));
try {
const result = await Promise.resolve(completionProvider(tokens, cursorPosition));
if (requestId !== requestIdRef.current)
return;
const filtered = filterCompletionsByPrefix(result, word.word);
setState({
items: result,
filteredItems: filtered,
selectedIndex: 0,
isOpen: filtered.length > 0,
isLoading: false,
});
}
catch {
if (requestId !== requestIdRef.current)
return;
setState((prev) => ({
...prev,
isOpen: false,
isLoading: false,
}));
}
}, [completionProvider]);
const updateFilter = useCallback((prefix) => {
setState((prev) => {
const filtered = filterCompletionsByPrefix(prev.items, prefix);
return {
...prev,
filteredItems: filtered,
selectedIndex: 0,
isOpen: filtered.length > 0,
};
});
}, []);
const navigate = useCallback((direction) => {
setState((prev) => {
if (prev.filteredItems.length === 0)
return prev;
const delta = direction === "down" ? 1 : -1;
const count = prev.filteredItems.length;
const nextIndex = (prev.selectedIndex + delta + count) % count;
return { ...prev, selectedIndex: nextIndex };
});
}, []);
const dismiss = useCallback(() => {
setState((prev) => ({
...prev,
isOpen: false,
isLoading: false,
selectedIndex: 0,
}));
}, []);
const selectedItem = state.isOpen && state.filteredItems.length > 0 ? state.filteredItems[state.selectedIndex] : null;
return {
...state,
selectedItem,
fetchCompletions,
updateFilter,
navigate,
dismiss,
};
}