Skip to content

Commit

Permalink
elements respond to enter or spacebar (#590)
Browse files Browse the repository at this point in the history
* elements respond to enter or spacebar

* New launcher botton respond to enter or spacebar

* check if the class name is on the list of classes

* Refactored to remove synthetic events

* formatting and api changes fix

* formatting and api changes fix 2

* Revert "formatting and api changes fix"

This reverts commit ef10564.

* Simplify code.
Don't handle keydown dynamically.

* Add tests
Undo removal of listeners as they are use at capturing phase

---------

Co-authored-by: Frédéric Collonval <fcollonval@gmail.com>
  • Loading branch information
g547315 and fcollonval authored Jul 19, 2023
1 parent adb6838 commit af2ae00
Show file tree
Hide file tree
Showing 2 changed files with 121 additions and 3 deletions.
54 changes: 51 additions & 3 deletions packages/widgets/src/tabbar.ts
Original file line number Diff line number Diff line change
Expand Up @@ -601,7 +601,9 @@ export class TabBar<T> extends Widget {
this._evtDblClick(event as MouseEvent);
break;
case 'keydown':
this._evtKeyDown(event as KeyboardEvent);
event.eventPhase === Event.CAPTURING_PHASE
? this._evtKeyDownCapturing(event as KeyboardEvent)
: this._evtKeyDown(event as KeyboardEvent);
break;
case 'contextmenu':
event.preventDefault();
Expand All @@ -616,6 +618,7 @@ export class TabBar<T> extends Widget {
protected onBeforeAttach(msg: Message): void {
this.node.addEventListener('pointerdown', this);
this.node.addEventListener('dblclick', this);
this.node.addEventListener('keydown', this);
}

/**
Expand All @@ -624,6 +627,7 @@ export class TabBar<T> extends Widget {
protected onAfterDetach(msg: Message): void {
this.node.removeEventListener('pointerdown', this);
this.node.removeEventListener('dblclick', this);
this.node.removeEventListener('keydown', this);
this._releaseMouse();
}

Expand Down Expand Up @@ -708,9 +712,13 @@ export class TabBar<T> extends Widget {
}

/**
* Handle the `'keydown'` event for the tab bar.
* Handle the `'keydown'` event for the tab bar at capturing phase.
*/
private _evtKeyDown(event: KeyboardEvent): void {
private _evtKeyDownCapturing(event: KeyboardEvent): void {
if (event.eventPhase !== Event.CAPTURING_PHASE) {
return;
}

// Stop all input events during drag.
event.preventDefault();
event.stopPropagation();
Expand All @@ -721,6 +729,45 @@ export class TabBar<T> extends Widget {
}
}

/**
* Handle the `'keydown'` event for the tab bar at target phase.
*/
private _evtKeyDown(event: KeyboardEvent): void {
// Allow for navigation using tab key
if (event.key === 'Tab' || event.eventPhase === Event.CAPTURING_PHASE) {
return;
}

// Check if Enter or Spacebar key has been pressed and open that tab
if (
event.key === 'Enter' ||
event.key === 'Spacebar' ||
event.key === ' '
) {
// Get focus element that is in focus by the tab key
const focusedElement = document.activeElement;

// Test first if the focus is on the add button node
if (
this.addButtonEnabled &&
this.addButtonNode.contains(focusedElement)
) {
event.preventDefault();
event.stopPropagation();
this._addRequested.emit();
} else {
const index = ArrayExt.findFirstIndex(this.contentNode.children, tab =>
tab.contains(focusedElement)
);
if (index >= 0) {
event.preventDefault();
event.stopPropagation();
this.currentIndex = index;
}
}
}
}

/**
* Handle the `'pointerdown'` event for the tab bar.
*/
Expand Down Expand Up @@ -1863,6 +1910,7 @@ namespace Private {

let add = document.createElement('div');
add.className = 'lm-TabBar-addButton lm-mod-hidden';
add.setAttribute('tabindex', '0');
node.appendChild(add);
return node;
}
Expand Down
70 changes: 70 additions & 0 deletions packages/widgets/tests/src/tabbar.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1522,6 +1522,76 @@ describe('@lumino/widgets', () => {
simulateOnNode(tab, 'pointerdown');
expect(bar.events.indexOf('pointermove')).to.equal(-1);
});

it('should activate the focused title on Enter', () => {
// Focus 3rd tab
(bar.contentNode.children[2] as HTMLElement).focus();

bar.node.dispatchEvent(
new KeyboardEvent('keydown', {
key: 'Enter',
cancelable: true,
bubbles: true
})
);

expect(bar.currentIndex).to.equal(2);
});

it('should activate the focused title on Space', () => {
// Focus 2nd tab
(bar.contentNode.children[1] as HTMLElement).focus();

bar.node.dispatchEvent(
new KeyboardEvent('keydown', {
key: ' ',
cancelable: true,
bubbles: true
})
);

expect(bar.currentIndex).to.equal(1);
});

it('should add a tab when Enter is pressed with focus on add button', () => {
let addRequested = false;
bar.addButtonEnabled = true;
bar.addButtonNode.focus();

bar.addRequested.connect(() => {
addRequested = true;
});

bar.node.dispatchEvent(
new KeyboardEvent('keydown', {
key: 'Enter',
cancelable: true,
bubbles: true
})
);

expect(addRequested).to.be.true;
});

it('should add a tab when Space is pressed with focus on add button', () => {
let addRequested = false;
bar.addButtonEnabled = true;
bar.addButtonNode.focus();

bar.addRequested.connect(() => {
addRequested = true;
});

bar.node.dispatchEvent(
new KeyboardEvent('keydown', {
key: ' ',
cancelable: true,
bubbles: true
})
);

expect(addRequested).to.be.true;
});
});

context('contextmenu', () => {
Expand Down

0 comments on commit af2ae00

Please sign in to comment.