Skip to content

feat(frontend): keyboard navigation for GlobalSearch results#148

Merged
Kevin737866 merged 3 commits into
Kevin737866:mainfrom
Bill-tech1:feat/global-search-keyboard-nav
Jun 1, 2026
Merged

feat(frontend): keyboard navigation for GlobalSearch results#148
Kevin737866 merged 3 commits into
Kevin737866:mainfrom
Bill-tech1:feat/global-search-keyboard-nav

Conversation

@Bill-tech1
Copy link
Copy Markdown
Contributor

@Bill-tech1 Bill-tech1 commented May 30, 2026

Closes #123


Summary

Adds correct Up/Down Arrow keyboard navigation to the GlobalSearch component and sets up the frontend unit test infrastructure.

Problem

The existing handleKeyDown used modulo arithmetic for navigation:

setActiveIndex((i) => (i + 1) % total);   // ArrowDown
setActiveIndex((i) => (i - 1 + total) % total); // ArrowUp

This had two bugs:

  1. Empty results crash – when total === 0, % 0 produces NaN, corrupting activeIndex state.
  2. Wrapping – ArrowDown on the last item jumped back to the first; ArrowUp on the first item jumped to the last. The requirement is to stay within bounds.

Changes

packages/frontend/src/components/GlobalSearch.tsx

Replaced modulo navigation with clamped navigation guarded by an empty-results check:

// Before
setActiveIndex((i) => (i + 1) % total);
setActiveIndex((i) => (i - 1 + total) % total);

// After
if (total > 0) setActiveIndex((i) => Math.min(i + 1, total - 1));
if (total > 0) setActiveIndex((i) => Math.max(i - 1, 0));

All existing behaviour (mouse clicks, Enter to select, Escape to close, Ctrl+K shortcut, search history, accessibility attributes) is preserved unchanged.

Test infrastructure (new)

  • vitest@1 + @testing-library/react + jsdom added as devDependencies
  • vite.config.ts extended with a test block (environment: 'jsdom', globals, setupFiles)
  • test / test:watch scripts added to package.json
  • src/test/setup.ts imports @testing-library/jest-dom matchers

packages/frontend/src/components/__tests__/GlobalSearch.test.tsx (new)

10 tests across two suites:

Suite Tests
GlobalSearch keyboard navigation renders input; ArrowDown on empty results (no throw); ArrowUp on empty results (no throw); Escape closes dropdown; focus opens dropdown
keyboard navigation clamping logic ArrowDown clamps at last index; ArrowUp clamps at first index; ArrowDown from -1 moves to 0; no navigation when total=0; old modulo-on-zero bug demonstrated

packages/frontend/.eslintrc.cjs (new)

The root .eslintrc.js references @typescript-eslint/recommended but the package was not resolvable from the workspace root, making pnpm lint fail with a config error before this PR. A frontend-specific config is added so pnpm lint runs cleanly.

Testing

pnpm --filter @stellar-analytics/frontend lint    # ✅ 0 errors, 0 warnings
pnpm --filter @stellar-analytics/frontend test    # ✅ 10/10 tests pass
pnpm --filter @stellar-analytics/frontend type-check  # pre-existing errors only (14, all in unrelated files, confirmed present on main)

Notes

  • No regressions introduced. All pre-existing type errors were confirmed to exist on main before this branch.
  • No new dependencies beyond the test toolchain.

- Fix ArrowDown/ArrowUp navigation to clamp within bounds instead of
  wrapping with modulo, which caused NaN errors on empty result sets
- Guard navigation with `if (total > 0)` to handle empty results safely
- Add vitest + @testing-library/react test infrastructure to frontend
- Add 10 unit tests covering keyboard nav, edge cases, and the old bug
- Add frontend-specific .eslintrc.cjs (root config was unresolvable)

Fixes: ArrowDown/ArrowUp % 0 producing NaN when results list is empty
@drips-wave
Copy link
Copy Markdown

drips-wave Bot commented May 30, 2026

@Bill-tech1 Great news! 🎉 Based on an automated assessment of this PR, the linked Wave issue(s) no longer count against your application limits.

You can now already apply to more issues while waiting for a review of this PR. Keep up the great work! 🚀

Learn more about application limits

@Kevin737866 Kevin737866 merged commit f509af4 into Kevin737866:main Jun 1, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Add keyboard navigation to GlobalSearch

2 participants