Skip to content

Commit

Permalink
Add support for moving focus with the Enter key in the input table
Browse files Browse the repository at this point in the history
  • Loading branch information
TomasEng committed Oct 16, 2024
1 parent 1b47df6 commit 7d07a6c
Show file tree
Hide file tree
Showing 8 changed files with 37 additions and 10 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -41,13 +41,35 @@ export abstract class BaseInputCell<
};

private handleKeyDown(event: KeyboardEvent<Element>): void {
switch (event.key) {
case 'ArrowUp':
case 'ArrowDown':
case 'ArrowLeft':
case 'ArrowRight':
this.handleArrowKeyDown(event);
break;
case 'Enter':
this.handleEnterKeyDown(event);
break;
}
}

private handleArrowKeyDown(event: KeyboardEvent<Element>): void {
if (this.shouldMoveFocusOnArrowKey(event)) {
this.moveFocus(event);
}
}

private handleEnterKeyDown(event: KeyboardEvent<Element>): void {
if (this.shouldMoveFocusOnEnterKey(event)) {
this.moveFocus(event);
}
}

protected abstract shouldMoveFocusOnArrowKey(event: KeyboardEvent<Element>): boolean;

protected abstract shouldMoveFocusOnEnterKey(event: KeyboardEvent<Element>): boolean;

private moveFocus(event: KeyboardEvent<Element>) {
const nextElement = this.getNextElement(event);
if (nextElement) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,4 +23,6 @@ export class CellButton extends BaseInputCell<HTMLButtonElement, CellButtonProps
}

shouldMoveFocusOnArrowKey = () => true;

shouldMoveFocusOnEnterKey = () => false;
}
Original file line number Diff line number Diff line change
Expand Up @@ -20,4 +20,6 @@ export class CellCheckbox extends BaseInputCell<HTMLInputElement, CellCheckboxPr
}

shouldMoveFocusOnArrowKey = () => true;

shouldMoveFocusOnEnterKey = () => true;
}
Original file line number Diff line number Diff line change
Expand Up @@ -40,8 +40,8 @@ export class CellTextarea extends BaseInputCell<HTMLTextAreaElement, CellTextare
return isCaretAtStart(currentTarget);
case 'ArrowRight':
return isCaretAtEnd(currentTarget);
default:
return false;
}
}

shouldMoveFocusOnEnterKey = () => false;
}
Original file line number Diff line number Diff line change
Expand Up @@ -40,8 +40,8 @@ export class CellTextfield extends BaseInputCell<HTMLInputElement, CellTextfield
return isCaretAtStart(currentTarget);
case 'ArrowRight':
return isCaretAtEnd(currentTarget);
default:
return false;
}
}

shouldMoveFocusOnEnterKey = () => true;
}
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,7 @@ describe('StudioInputTable', () => {
expect(document.body).toHaveFocus();
});

it('Lets the user focus on the input elements using the arrow keys', async () => {
it('Lets the user focus on the input elements using the arrow and enter keys', async () => {
const user = userEvent.setup();
render(<TestTable />);
const headerCheckbox = getCheckbox(headerCheckboxLabel);
Expand All @@ -86,7 +86,7 @@ describe('StudioInputTable', () => {
expect(getCheckboxInRow(1)).toHaveFocus();
await user.keyboard('{ArrowRight}'); // Move right to textfield 1
expect(getTextfieldInRow(1)).toHaveFocus();
await user.keyboard('{ArrowDown}'); // Move down to textfield 2
await user.keyboard('{Enter}'); // Move down to textfield 2
expect(getTextfieldInRow(2)).toHaveFocus();
await user.keyboard('{ArrowRight}'); // Move right to textarea 2
expect(getTextareaInRow(2)).toHaveFocus();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ type TestCase = {
};

describe('getNextInputElement', () => {
describe('With ArrowDown key', () => {
describe.each(['ArrowDown', 'Enter'])('With %s key', (key) => {
it('Returns the input element directly below the given element', () => {
render(<TableWithTextfieldsOnly />);
const testCases: TestCase[] = [
Expand All @@ -23,23 +23,23 @@ describe('getNextInputElement', () => {
];
testCases.forEach(({ queryCoords, expectedResult }) => {
const input = getInputByCoords(queryCoords);
const result = getNextInputElement(input, 'ArrowDown');
const result = getNextInputElement(input, key);
expect(result).toBe(getInputByCoords(expectedResult));
});
});

it('Returns null when there is no input element below the given element', () => {
render(<TableWithTextfieldsOnly />);
const input = getInputByCoords({ row: 2, column: 0 });
const result = getNextInputElement(input, 'ArrowDown');
const result = getNextInputElement(input, key);
expect(result).toBeNull();
});

it('Returns the input element below the given element when there are empty cells in between', () => {
render(<DiverseTable />);
const input = getInputByCoords({ row: 1, column: 1 });
const expectedResult = getInputByCoords({ row: 4, column: 1 });
const result = getNextInputElement(input, 'ArrowDown');
const result = getNextInputElement(input, key);
expect(result).toBe(expectedResult);
});
});
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ export function getNextInputElement(
case 'ArrowUp':
return getInputElementAboveCoords(table, currentCoords);
case 'ArrowDown':
case 'Enter':
return getInputElementBelowCoords(table, currentCoords);
case 'ArrowLeft':
return getInputElementLeftToCoords(table, currentCoords);
Expand Down

0 comments on commit 7d07a6c

Please sign in to comment.