Files
Codewalkers/packages/web/src/components/editor/SlashCommandList.tsx
2026-02-07 00:33:12 +01:00

89 lines
2.3 KiB
TypeScript

import {
useState,
useEffect,
useCallback,
forwardRef,
useImperativeHandle,
} from "react";
import type { SlashCommandItem } from "./slash-command-items";
export interface SlashCommandListRef {
onKeyDown: (props: { event: KeyboardEvent }) => boolean;
}
interface SlashCommandListProps {
items: SlashCommandItem[];
command: (item: SlashCommandItem) => void;
}
export const SlashCommandList = forwardRef<
SlashCommandListRef,
SlashCommandListProps
>(({ items, command }, ref) => {
const [selectedIndex, setSelectedIndex] = useState(0);
useEffect(() => {
setSelectedIndex(0);
}, [items]);
const selectItem = useCallback(
(index: number) => {
const item = items[index];
if (item) {
command(item);
}
},
[items, command],
);
useImperativeHandle(ref, () => ({
onKeyDown: ({ event }: { event: KeyboardEvent }) => {
if (event.key === "ArrowUp") {
setSelectedIndex((prev) => (prev + items.length - 1) % items.length);
return true;
}
if (event.key === "ArrowDown") {
setSelectedIndex((prev) => (prev + 1) % items.length);
return true;
}
if (event.key === "Enter") {
selectItem(selectedIndex);
return true;
}
return false;
},
}));
if (items.length === 0) {
return null;
}
return (
<div className="z-50 min-w-[200px] overflow-hidden rounded-md border border-border bg-popover p-1 shadow-md">
{items.map((item, index) => (
<button
key={item.label}
onClick={() => selectItem(index)}
className={`flex w-full items-center gap-2 rounded-sm px-2 py-1.5 text-sm ${
index === selectedIndex
? "bg-accent text-accent-foreground"
: "text-popover-foreground"
}`}
>
<span className="flex h-6 w-6 shrink-0 items-center justify-center rounded border border-border bg-muted text-xs font-mono">
{item.icon}
</span>
<div className="flex flex-col items-start">
<span className="font-medium">{item.label}</span>
<span className="text-xs text-muted-foreground">
{item.description}
</span>
</div>
</button>
))}
</div>
);
});
SlashCommandList.displayName = "SlashCommandList";