navigation.ts 2.2 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273
  1. import { useRouter } from 'next/navigation'
  2. import type { NextRouter } from 'next/router'
  3. import { BASE_PATH } from './constants'
  4. type Router = NextRouter | ReturnType<typeof useRouter>
  5. const MIDDLE_MOUSE_BUTTON = 1
  6. /**
  7. * Creates a navigation handler that supports keyboard, modifier clicks, and middle mouse button.
  8. *
  9. * This is a curried function that takes a URL and router, and returns an event handler that:
  10. * - Handles keyboard navigation (Enter/Space keys)
  11. * - Opens in new tab on Cmd/Ctrl + click
  12. * - Opens in new tab on middle mouse button click
  13. * - Performs normal navigation on regular click
  14. *
  15. * @param url - The relative URL to navigate to (e.g., "/project/123/functions/my-function")
  16. * @param router - Next.js router instance (supports both Pages Router and App Router)
  17. * @returns Event handler function for onClick, onAuxClick, and onKeyDown
  18. *
  19. * @example
  20. * ```tsx
  21. * const router = useRouter()
  22. * const handleNavigation = createNavigationHandler(`/project/${ref}/functions/${slug}`, router)
  23. *
  24. * <TableRow
  25. * onClick={handleNavigation}
  26. * onAuxClick={handleNavigation}
  27. * onKeyDown={handleNavigation}
  28. * tabIndex={0}
  29. * />
  30. * ```
  31. */
  32. export const createNavigationHandler = (url: string, router: Router) => {
  33. return (event: React.MouseEvent | React.KeyboardEvent) => {
  34. // Handle keyboard events
  35. if ('key' in event) {
  36. if (event.key === 'Enter' || event.key === ' ') {
  37. event.preventDefault()
  38. const isModifierKey = event.metaKey || event.ctrlKey
  39. if (isModifierKey) {
  40. window.open(`${BASE_PATH}${url}`, '_blank')
  41. } else {
  42. router.push(url)
  43. }
  44. }
  45. return
  46. }
  47. // Handle Cmd/Ctrl + left click (modifier click)
  48. const isModifierClick =
  49. 'button' in event && event.button === 0 && (event.metaKey || event.ctrlKey)
  50. if (isModifierClick) {
  51. event.preventDefault()
  52. window.open(`${BASE_PATH}${url}`, '_blank')
  53. return
  54. }
  55. // Handle middle mouse button click
  56. const isMiddleClick = 'button' in event && event.button === MIDDLE_MOUSE_BUTTON
  57. if (isMiddleClick) {
  58. event.preventDefault()
  59. window.open(`${BASE_PATH}${url}`, '_blank')
  60. return
  61. }
  62. // Handle regular left click
  63. router.push(url)
  64. }
  65. }