feat: Keyboard navigation spreadsheet layout for issues (#3564)
* enable keyboard navigation for spreadsheet layout * move the logic to table level instead of cell level * fix perf issue that made it unusable * fix scroll issue with navigation * fix build errors
This commit is contained in:
parent
a43dfc097d
commit
fb3dd77b66
31 changed files with 368 additions and 126 deletions
|
|
@ -1,23 +1,31 @@
|
|||
import { useCallback } from "react";
|
||||
|
||||
type TUseDropdownKeyDown = {
|
||||
(onEnterKeyDown: () => void, onEscKeyDown: () => void): (event: React.KeyboardEvent<HTMLElement>) => void;
|
||||
(onEnterKeyDown: () => void, onEscKeyDown: () => void, stopPropagation?: boolean): (
|
||||
event: React.KeyboardEvent<HTMLElement>
|
||||
) => void;
|
||||
};
|
||||
|
||||
export const useDropdownKeyDown: TUseDropdownKeyDown = (onEnterKeyDown, onEscKeyDown) => {
|
||||
export const useDropdownKeyDown: TUseDropdownKeyDown = (onEnterKeyDown, onEscKeyDown, stopPropagation = true) => {
|
||||
const stopEventPropagation = (event: React.KeyboardEvent<HTMLElement>) => {
|
||||
if (stopPropagation) {
|
||||
event.stopPropagation();
|
||||
event.preventDefault();
|
||||
}
|
||||
};
|
||||
|
||||
const handleKeyDown = useCallback(
|
||||
(event: React.KeyboardEvent<HTMLElement>) => {
|
||||
if (event.key === "Enter") {
|
||||
event.stopPropagation();
|
||||
event.preventDefault();
|
||||
stopEventPropagation(event);
|
||||
|
||||
onEnterKeyDown();
|
||||
} else if (event.key === "Escape") {
|
||||
event.stopPropagation();
|
||||
event.preventDefault();
|
||||
stopEventPropagation(event);
|
||||
onEscKeyDown();
|
||||
}
|
||||
},
|
||||
[onEnterKeyDown, onEscKeyDown]
|
||||
[onEnterKeyDown, onEscKeyDown, stopEventPropagation]
|
||||
);
|
||||
|
||||
return handleKeyDown;
|
||||
|
|
|
|||
56
web/hooks/use-table-keyboard-navigation.tsx
Normal file
56
web/hooks/use-table-keyboard-navigation.tsx
Normal file
|
|
@ -0,0 +1,56 @@
|
|||
export const useTableKeyboardNavigation = () => {
|
||||
const getPreviousRow = (element: HTMLElement) => {
|
||||
const previousRow = element.closest("tr")?.previousSibling;
|
||||
|
||||
if (previousRow) return previousRow;
|
||||
//if previous row does not exist in the parent check the row with the header of the table
|
||||
return element.closest("tbody")?.previousSibling?.childNodes?.[0];
|
||||
};
|
||||
|
||||
const getNextRow = (element: HTMLElement) => {
|
||||
const nextRow = element.closest("tr")?.nextSibling;
|
||||
|
||||
if (nextRow) return nextRow;
|
||||
//if next row does not exist in the parent check the row with the body of the table
|
||||
return element.closest("thead")?.nextSibling?.childNodes?.[0];
|
||||
};
|
||||
|
||||
const handleKeyBoardNavigation = function (e: React.KeyboardEvent<HTMLTableElement>) {
|
||||
const element = e.target as HTMLElement;
|
||||
|
||||
if (!(element?.tagName === "TD" || element?.tagName === "TH")) return;
|
||||
|
||||
let c: HTMLElement | null = null;
|
||||
if (e.key == "ArrowRight") {
|
||||
// Right Arrow
|
||||
c = element.nextSibling as HTMLElement;
|
||||
} else if (e.key == "ArrowLeft") {
|
||||
// Left Arrow
|
||||
c = element.previousSibling as HTMLElement;
|
||||
} else if (e.key == "ArrowUp") {
|
||||
// Up Arrow
|
||||
const index = Array.prototype.indexOf.call(element?.parentNode?.childNodes || [], element);
|
||||
const prevRow = getPreviousRow(element);
|
||||
|
||||
c = prevRow?.childNodes?.[index] as HTMLElement;
|
||||
} else if (e.key == "ArrowDown") {
|
||||
// Down Arrow
|
||||
const index = Array.prototype.indexOf.call(element?.parentNode?.childNodes || [], element);
|
||||
const nextRow = getNextRow(element);
|
||||
|
||||
c = nextRow?.childNodes[index] as HTMLElement;
|
||||
} else if (e.key == "Enter" || e.key == "Space") {
|
||||
e.preventDefault();
|
||||
(element?.querySelector(".clickable") as HTMLElement)?.click();
|
||||
return;
|
||||
}
|
||||
|
||||
if (!c) return;
|
||||
|
||||
e.preventDefault();
|
||||
c?.focus();
|
||||
c?.scrollIntoView({ behavior: "smooth", block: "center", inline: "end" });
|
||||
};
|
||||
|
||||
return handleKeyBoardNavigation;
|
||||
};
|
||||
Loading…
Add table
Add a link
Reference in a new issue