Nested Groups Fixes

This commit is contained in:
2025-11-29 19:05:54 +00:00
parent 757386f611
commit 9c7d9c5406
6 changed files with 73 additions and 39 deletions
+38 -23
View File
@@ -6,6 +6,7 @@
import type { DisplayedLine } from './types';
import { browser } from '$app/environment';
import { goto } from '$app/navigation';
export interface KeyboardHandlerOptions {
getIsTyping: () => boolean;
@@ -31,14 +32,9 @@ export function scrollToSelected(
): void {
if (!bodyElement || selectedIndex < 0) return;
const buttons = bodyElement.querySelectorAll('.tui-button');
const btnIndices = displayedLines
.map((item, idx) => item.parsed.line.type === 'button' ? idx : -1)
.filter(idx => idx !== -1);
const selectedButton = Array.from(buttons).find((_, i) => {
return btnIndices[i] === selectedIndex;
}) as HTMLElement | undefined;
// Get all buttons in DOM order (including nested ones in groups)
const allButtons = bodyElement.querySelectorAll('.tui-button');
const selectedButton = allButtons[selectedIndex] as HTMLElement | undefined;
if (selectedButton && bodyElement) {
const containerRect = bodyElement.getBoundingClientRect();
@@ -67,7 +63,8 @@ export function handleNavigation(line: { action?: () => void; href?: string; ext
if (isExternal) {
window.open(line.href, '_blank', 'noopener,noreferrer');
} else {
window.location.href = line.href;
// Use SvelteKit's goto for client-side navigation (no page reload)
goto(line.href);
}
}
}
@@ -99,30 +96,48 @@ export function createKeyboardHandler(options: KeyboardHandlerOptions) {
if (!getInteractive() || !getIsComplete()) return;
const buttonIndices = getButtonIndices();
if (buttonIndices.length === 0) return;
const bodyElement = getBodyElement();
if (!bodyElement) return;
// Get all buttons from the DOM (including nested ones in groups)
const allButtons = bodyElement.querySelectorAll('.tui-button');
const buttonCount = allButtons.length;
if (buttonCount === 0) return;
const selectedIndex = getSelectedIndex();
const currentButtonIdx = buttonIndices.indexOf(selectedIndex);
const displayedLines = getDisplayedLines();
const bodyElement = getBodyElement();
if (event.key === 'ArrowDown' || event.key === 'j') {
event.preventDefault();
const nextIdx = (currentButtonIdx + 1) % buttonIndices.length;
const newSelectedIndex = buttonIndices[nextIdx];
setSelectedIndex(newSelectedIndex);
scrollToSelected(bodyElement, newSelectedIndex, displayedLines, scrollMargin);
const nextIdx = selectedIndex < 0 ? 0 : (selectedIndex + 1) % buttonCount;
setSelectedIndex(nextIdx);
scrollToSelected(bodyElement, nextIdx, displayedLines, scrollMargin);
// Update visual selection on buttons
allButtons.forEach((btn, i) => btn.classList.toggle('selected', i === nextIdx));
} else if (event.key === 'ArrowUp' || event.key === 'k') {
event.preventDefault();
const prevIdx = (currentButtonIdx - 1 + buttonIndices.length) % buttonIndices.length;
const newSelectedIndex = buttonIndices[prevIdx];
setSelectedIndex(newSelectedIndex);
scrollToSelected(bodyElement, newSelectedIndex, displayedLines, scrollMargin);
const prevIdx = selectedIndex < 0 ? buttonCount - 1 : (selectedIndex - 1 + buttonCount) % buttonCount;
setSelectedIndex(prevIdx);
scrollToSelected(bodyElement, prevIdx, displayedLines, scrollMargin);
// Update visual selection on buttons
allButtons.forEach((btn, i) => btn.classList.toggle('selected', i === prevIdx));
} else if (event.key === 'Enter') {
event.preventDefault();
const selectedLine = displayedLines[selectedIndex]?.parsed.line;
handleNavigation(selectedLine);
if (selectedIndex >= 0 && selectedIndex < buttonCount) {
const selectedButton = allButtons[selectedIndex] as HTMLElement;
if (selectedButton) {
// Read navigation data from button data attributes
const href = selectedButton.dataset.href;
const isExternal = selectedButton.dataset.external === 'true';
if (href) {
handleNavigation({ href, external: isExternal });
} else {
// Fallback to click for buttons with actions (non-navigational)
selectedButton.click();
}
}
}
}
};
}