clean up grid code

This commit is contained in:
William Martin 2024-04-23 21:59:41 -04:00
parent c4da29bcf4
commit 10c9b621c9
No known key found for this signature in database
GPG Key ID: A65ACD91BADF316B
2 changed files with 42 additions and 22 deletions

View File

@ -19,6 +19,5 @@ export class A11yCellDirective implements AfterContentChecked {
console.error("A11yCellDirective must contain content that provides FocusableElement");
return;
}
// this.focusableChild.getFocusTarget().tabIndex = -1;
}
}

View File

@ -4,6 +4,7 @@ import {
Directive,
HostBinding,
HostListener,
Input,
QueryList,
} from "@angular/core";
@ -15,77 +16,95 @@ import { A11yRowDirective } from "./a11y-row.directive";
standalone: true,
})
export class A11yGridDirective implements AfterViewInit {
@ContentChildren(A11yRowDirective)
rows: QueryList<A11yRowDirective>;
@HostBinding("attr.role")
role = "grid";
@ContentChildren(A11yRowDirective)
rows: QueryList<A11yRowDirective>;
/** The number of pages to navigate on `PageUp` and `PageDown` */
@Input() pageSize = 5;
private grid: A11yCellDirective[][];
private activeRow: number = 0;
private activeCol: number = 0;
/** The row that currently has focus */
private activeRow = 0;
/** The cell that currently has focus */
private activeCol = 0;
@HostListener("keydown", ["$event"])
onKeyDown(event: KeyboardEvent) {
switch (event.code) {
case "ArrowUp":
this.updateCellFocusByDelta(0, -1);
break;
case "ArrowRight":
this.updateCellFocusByDelta(1, 0);
break;
case "ArrowDown":
this.updateCellFocusByDelta(0, 1);
break;
case "ArrowLeft":
this.updateCellFocusByDelta(-1, 0);
break;
case "ArrowRight":
this.updateCellFocusByDelta(0, 1);
break;
case "ArrowDown":
this.updateCellFocusByDelta(1, 0);
break;
case "ArrowLeft":
this.updateCellFocusByDelta(0, -1);
break;
case "Home":
this.updateCellFocusByDelta(-this.activeCol, -this.activeRow);
this.updateCellFocusByDelta(-this.activeRow, -this.activeCol);
break;
case "End":
this.updateCellFocusByDelta(this.grid[this.grid.length - 1].length, this.grid.length);
this.updateCellFocusByDelta(this.grid.length, this.grid[this.grid.length - 1].length);
break;
case "PageUp":
this.updateCellFocusByDelta(0, -5);
this.updateCellFocusByDelta(-this.pageSize, 0);
break;
case "PageDown":
this.updateCellFocusByDelta(0, 5);
this.updateCellFocusByDelta(this.pageSize, 0);
break;
default:
return;
}
/** Prevent default scrolling behavior */
event.preventDefault();
}
ngAfterViewInit(): void {
this.initializeGrid();
}
private initializeGrid(): void {
this.grid = this.rows.map((listItem) => [...listItem.cells]);
this.grid.flat().map((cell) => (cell.focusableChild.getFocusTarget().tabIndex = -1));
const firstCell = this.getActiveCellContent();
firstCell.tabIndex = 0;
this.getActiveCellContent().tabIndex = 0;
}
/** Get the focusable content of the active cell */
private getActiveCellContent(): HTMLElement {
return this.grid[this.activeRow][this.activeCol].focusableChild.getFocusTarget();
}
private updateCellFocusByDelta(colDelta: number, rowDelta: number) {
/** Move focus via a delta against the currently active gridcell */
private updateCellFocusByDelta(rowDelta: number, colDelta: number) {
const prevActive = this.getActiveCellContent();
this.activeCol += colDelta;
this.activeRow += rowDelta;
// Row upper bound
if (this.activeRow >= this.grid.length) {
this.activeRow = this.grid.length - 1;
}
// Row lower bound
if (this.activeRow < 0) {
this.activeRow = 0;
}
// Column upper bound
if (this.activeCol >= this.grid[this.activeRow].length) {
if (this.activeRow < this.grid.length - 1) {
// Wrap to next row on right arrow
this.activeCol = 0;
this.activeRow += 1;
} else {
@ -93,8 +112,10 @@ export class A11yGridDirective implements AfterViewInit {
}
}
// Column lower bound
if (this.activeCol < 0) {
if (this.activeRow > 0) {
// Wrap to prev row on left arrow
this.activeRow -= 1;
this.activeCol = this.grid[this.activeRow].length - 1;
} else {