fix(workspace): auto-scroll slash command popup when navigating with arrow keys
MindSift CI & Docker Release / Build, Test in Container & Push (push) Successful in 55s

This commit is contained in:
sandrodach committed 2026-10-25 10:28:24 +01:00
1 parent 290848a93e
commit ec79a2493e
1 file changed
+30 -1
@@ -128,6 +128,7 @@ export const WorkspaceView: React.FC<WorkspaceViewProps> = ({
const [slashBlockId, setSlashBlockId] = useState<string | null>(null); const [slashBlockId, setSlashBlockId] = useState<string | null>(null);
const [slashSearch, setSlashSearch] = useState(''); const [slashSearch, setSlashSearch] = useState('');
const [slashSelectedIndex, setSlashSelectedIndex] = useState(0); const [slashSelectedIndex, setSlashSelectedIndex] = useState(0);
const slashMenuRef = useRef<HTMLDivElement | null>(null);
// Drag and Drop reordering state for blocks // Drag and Drop reordering state for blocks
const [draggingBlockId, setDraggingBlockId] = useState<string | null>(null); const [draggingBlockId, setDraggingBlockId] = useState<string | null>(null);
@@ -933,6 +934,12 @@ export const WorkspaceView: React.FC<WorkspaceViewProps> = ({
ensureLock(); ensureLock();
if (slashBlockId === block.id) { if (slashBlockId === block.id) {
if (filteredSlashCommands.length === 0) {
if (e.key === 'Escape') {
setSlashBlockId(null);
}
return;
}
if (e.key === 'ArrowDown') { if (e.key === 'ArrowDown') {
e.preventDefault(); e.preventDefault();
setSlashSelectedIndex((prev) => (prev + 1) % filteredSlashCommands.length); setSlashSelectedIndex((prev) => (prev + 1) % filteredSlashCommands.length);
@@ -1010,6 +1017,27 @@ export const WorkspaceView: React.FC<WorkspaceViewProps> = ({
); );
}, [slashSearch]); }, [slashSearch]);
useEffect(() => {
if (slashBlockId && slashMenuRef.current) {
const container = slashMenuRef.current;
const activeBtn = container.querySelector<HTMLElement>(
`[data-slash-index="${slashSelectedIndex}"]`
);
if (activeBtn) {
const itemTop = activeBtn.offsetTop;
const itemBottom = itemTop + activeBtn.offsetHeight;
const containerTop = container.scrollTop;
const containerBottom = containerTop + container.clientHeight;
if (itemTop < containerTop) {
container.scrollTop = itemTop;
} else if (itemBottom > containerBottom) {
container.scrollTop = itemBottom - container.clientHeight;
}
}
}
}, [slashSelectedIndex, slashBlockId]);
const applySlashCommand = (blockId: string, type: BlockType) => { const applySlashCommand = (blockId: string, type: BlockType) => {
if (isReadOnly || !selectedDoc) return; if (isReadOnly || !selectedDoc) return;
const block = selectedDoc.blocks.find((b) => b.id === blockId); const block = selectedDoc.blocks.find((b) => b.id === blockId);
@@ -2431,11 +2459,12 @@ export const WorkspaceView: React.FC<WorkspaceViewProps> = ({
<div className="px-2 py-1 text-[10px] text-faint font-semibold uppercase tracking-wider border-b border-border"> <div className="px-2 py-1 text-[10px] text-faint font-semibold uppercase tracking-wider border-b border-border">
Block-Typ wählen: Block-Typ wählen:
</div> </div>
<div className="max-h-48 overflow-y-auto space-y-0.5"> <div ref={slashMenuRef} className="relative max-h-48 overflow-y-auto space-y-0.5">
{filteredSlashCommands.map((cmd, idx) => ( {filteredSlashCommands.map((cmd, idx) => (
<button <button
key={cmd.type} key={cmd.type}
type="button" type="button"
data-slash-index={idx}
onMouseDown={(e) => e.preventDefault()} onMouseDown={(e) => e.preventDefault()}
onClick={() => applySlashCommand(block.id, cmd.type)} onClick={() => applySlashCommand(block.id, cmd.type)}
className={`w-full text-left px-2 py-1.5 rounded-btn text-xs flex items-center justify-between transition-colors ${ className={`w-full text-left px-2 py-1.5 rounded-btn text-xs flex items-center justify-between transition-colors ${