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:
rahulramesha 2024-02-08 11:49:00 +05:30 committed by GitHub
parent a43dfc097d
commit fb3dd77b66
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
31 changed files with 368 additions and 126 deletions

View file

@ -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;

View 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;
};