Refactored the `CommandMenu` component to make it more readable and easier to refactor. The file was way too big so I introduced a few hooks and eliminated code duplication. Introduced: - `useMatchCommands` hook to match commands with the search - `useCommandMenuCommands` which returns all command menu commands - `useMatchingCommandMenuCommands` to return the commands matched with the search - `CommandMenuContainer` to simplify the `DefaultLayout` - Unmounted the `CommandMenu` when it wasn't opened to improve performances I also introduced a new behavior: Automatically select the first item when opening the command menu: https://github.com/user-attachments/assets/4b683d49-570e-47c9-8939-99f42ed8691c
38 lines
1.0 KiB
TypeScript
38 lines
1.0 KiB
TypeScript
import { Command } from '@/command-menu/types/Command';
|
|
import { isNonEmptyString } from '@sniptt/guards';
|
|
import { useDebounce } from 'use-debounce';
|
|
|
|
export const useMatchCommands = ({
|
|
commandMenuSearch,
|
|
}: {
|
|
commandMenuSearch: string;
|
|
}) => {
|
|
const [deferredCommandMenuSearch] = useDebounce(commandMenuSearch, 300); // 200ms - 500ms
|
|
|
|
const checkInShortcuts = (cmd: Command, search: string) => {
|
|
return (cmd.firstHotKey + (cmd.secondHotKey ?? ''))
|
|
.toLowerCase()
|
|
.includes(search.toLowerCase());
|
|
};
|
|
|
|
const checkInLabels = (cmd: Command, search: string) => {
|
|
if (isNonEmptyString(cmd.label)) {
|
|
return cmd.label.toLowerCase().includes(search.toLowerCase());
|
|
}
|
|
return false;
|
|
};
|
|
|
|
const matchCommands = (commands: Command[]) => {
|
|
return commands.filter((cmd) =>
|
|
deferredCommandMenuSearch.length > 0
|
|
? checkInShortcuts(cmd, deferredCommandMenuSearch) ||
|
|
checkInLabels(cmd, deferredCommandMenuSearch)
|
|
: true,
|
|
);
|
|
};
|
|
|
|
return {
|
|
matchCommands,
|
|
};
|
|
};
|