|
1 | 1 | import { useMemo } from 'react'; |
2 | 2 |
|
3 | | -export default function useNavigation(terminalWidth: number, totalItems: number) { |
4 | | - const cardWidth = 35 + 2; // Card width + gap |
5 | | - const cardsPerRow = Math.max(1, Math.floor(terminalWidth / cardWidth)); |
| 3 | +export default function useNavigation(navigationRows: number[][]) { |
| 4 | + const indexToPosition = useMemo(() => { |
| 5 | + const map = new Map<number, { row: number; col: number }>(); |
| 6 | + navigationRows.forEach((rowItems, row) => { |
| 7 | + rowItems.forEach((itemIndex, col) => { |
| 8 | + map.set(itemIndex, { row, col }); |
| 9 | + }); |
| 10 | + }); |
| 11 | + return map; |
| 12 | + }, [navigationRows]); |
6 | 13 |
|
7 | 14 | const getCardGridPosition = useMemo(() => { |
8 | 15 | return (index: number): { row: number; col: number } => { |
9 | | - const row = Math.floor(index / cardsPerRow); |
10 | | - const col = index % cardsPerRow; |
11 | | - return { row, col }; |
| 16 | + return indexToPosition.get(index) || { row: 0, col: 0 }; |
12 | 17 | }; |
13 | | - }, [cardsPerRow]); |
| 18 | + }, [indexToPosition]); |
14 | 19 |
|
15 | 20 | const findCardInDirection = useMemo(() => { |
16 | 21 | return (currentIndex: number, direction: 'up' | 'down' | 'left' | 'right'): number | null => { |
17 | | - const currentPos = getCardGridPosition(currentIndex); |
18 | | - let targetIndex: number | null = null; |
| 22 | + const currentPos = indexToPosition.get(currentIndex); |
| 23 | + if (!currentPos) return null; |
19 | 24 |
|
20 | 25 | switch (direction) { |
21 | 26 | case 'up': |
22 | | - if (currentPos.row > 0) { |
23 | | - targetIndex = (currentPos.row - 1) * cardsPerRow + currentPos.col; |
24 | | - if (targetIndex >= totalItems) { |
25 | | - targetIndex = Math.min((currentPos.row - 1) * cardsPerRow + cardsPerRow - 1, totalItems - 1); |
26 | | - } |
| 27 | + if (currentPos.row > 0 && navigationRows[currentPos.row - 1]) { |
| 28 | + const targetRow = navigationRows[currentPos.row - 1]; |
| 29 | + const targetCol = Math.min(currentPos.col, targetRow.length - 1); |
| 30 | + return targetRow[targetCol] ?? null; |
27 | 31 | } |
28 | 32 | break; |
29 | 33 | case 'down': |
30 | | - targetIndex = (currentPos.row + 1) * cardsPerRow + currentPos.col; |
31 | | - if (targetIndex >= totalItems) { |
32 | | - if (currentIndex < totalItems - 1) targetIndex = totalItems - 1; else targetIndex = null; |
| 34 | + if (currentPos.row < navigationRows.length - 1 && navigationRows[currentPos.row + 1]) { |
| 35 | + const targetRow = navigationRows[currentPos.row + 1]; |
| 36 | + const targetCol = Math.min(currentPos.col, targetRow.length - 1); |
| 37 | + return targetRow[targetCol] ?? null; |
33 | 38 | } |
34 | 39 | break; |
35 | 40 | case 'left': |
36 | 41 | if (currentPos.col > 0) { |
37 | | - targetIndex = currentIndex - 1; |
38 | | - } else if (currentPos.row > 0) { |
39 | | - targetIndex = currentPos.row * cardsPerRow - 1; |
40 | | - if (targetIndex >= totalItems) targetIndex = totalItems - 1; |
| 42 | + const row = navigationRows[currentPos.row]; |
| 43 | + return row?.[currentPos.col - 1] ?? null; |
41 | 44 | } |
42 | 45 | break; |
43 | 46 | case 'right': |
44 | | - if (currentPos.col < cardsPerRow - 1 && currentIndex < totalItems - 1) { |
45 | | - targetIndex = currentIndex + 1; |
46 | | - } else if ((currentPos.row + 1) * cardsPerRow < totalItems) { |
47 | | - targetIndex = (currentPos.row + 1) * cardsPerRow; |
| 47 | + if (navigationRows[currentPos.row] && currentPos.col < navigationRows[currentPos.row].length - 1) { |
| 48 | + const row = navigationRows[currentPos.row]; |
| 49 | + return row?.[currentPos.col + 1] ?? null; |
48 | 50 | } |
49 | 51 | break; |
50 | 52 | } |
51 | 53 |
|
52 | | - if (targetIndex !== null && targetIndex >= 0 && targetIndex < totalItems) { |
53 | | - return targetIndex; |
54 | | - } |
55 | 54 | return null; |
56 | 55 | }; |
57 | | - }, [cardsPerRow, totalItems, getCardGridPosition]); |
| 56 | + }, [indexToPosition, navigationRows]); |
58 | 57 |
|
59 | 58 | return { getCardGridPosition, findCardInDirection }; |
60 | 59 | } |
0 commit comments