import FreeSearchAction from "./FreeSearchAction"; import List from "./List"; import ListItem from "./ListItem"; import Page from "./Page"; import React, { Fragment, ReactNode, useEffect, useRef, useState } from "react"; import Search from "./Search"; import { OpenContext, PageContext, RenderLinkContext, SearchContext, SelectContext, } from "../lib/context"; import { RenderLink } from "../types"; import { Transition, Dialog } from "@headlessui/react"; interface CommandPaletteProps { onChangeSelected?: (value: number) => void; onChangeSearch: (search: string) => void; onChangeOpen: (isOpen: boolean) => void; renderLink?: RenderLink; placeholder?: string; children: ReactNode; footer?: ReactNode; selected?: number; isOpen: boolean; search: string; page?: string; searchIcon?: any; cancelIcon?: any; } function CommandPalette({ selected: selectedParent, placeholder = "Search", onChangeSelected, onChangeSearch, onChangeOpen, renderLink, children, isOpen, footer, search, page, searchIcon, cancelIcon, }: CommandPaletteProps) { const inputRef = useRef(null); const [selected, setSelected] = typeof selectedParent === "number" && onChangeSelected ? [selectedParent, onChangeSelected] : useState(0); const [searchPrefix, setSearchPrefix] = useState(); function handleChangeSelected(direction?: "up" | "down") { const items = document.querySelectorAll(".command-palette-list-item"); let index = 0; let newIndex = 0; let newItem: Element; if (direction === "down") { items.forEach((_, i) => { if (i === selected) { index = i; } }); newIndex = index === items.length - 1 ? 0 : index + 1; } else if (direction === "up") { items.forEach((_, i) => { if (i === selected) { index = i; } }); newIndex = !index ? items.length - 1 : index - 1; } else { setSelected(0); } newItem = items[newIndex]; if (newItem && typeof newIndex === "number") { setSelected(newIndex); newItem.scrollIntoView({ behavior: "smooth", block: newIndex ? "center" : "end", }); } } function handleSelect() { const items = document.querySelectorAll( ".command-palette-list-item" ) as NodeListOf; let index = 0; let item: HTMLAnchorElement | HTMLButtonElement; items.forEach((_, i) => { if (i === selected) { index = i; } }); item = items[index]; if (item) { item.click(); if ( item.attributes.getNamedItem("data-close-on-select")?.value === "true" ) { onChangeOpen(false); } } } useEffect(() => { handleChangeSelected(); }, [search]); useEffect(() => { setSelected(0); }, [page]); return (
{ if ( e.key === "ArrowDown" || (e.ctrlKey && e.key === "n") || (e.ctrlKey && e.key === "j") ) { e.preventDefault(); e.stopPropagation(); handleChangeSelected("down"); } else if ( e.key === "ArrowUp" || (e.ctrlKey && e.key === "p") || (e.ctrlKey && e.key === "k") ) { e.preventDefault(); e.stopPropagation(); handleChangeSelected("up"); } else if (e.key === "Enter") { e.preventDefault(); e.stopPropagation(); handleSelect(); } }} > { onChangeOpen(false); }} >
{children}
{footer}
); } CommandPalette.Page = Page; CommandPalette.List = List; CommandPalette.ListItem = ListItem; CommandPalette.FreeSearchAction = FreeSearchAction; export default CommandPalette;