Skip to content

Commit 74769b9

Browse files
committed
restore focus origin on window focus
1 parent aae4b65 commit 74769b9

File tree

1 file changed

+27
-3
lines changed

1 file changed

+27
-3
lines changed

src/lib/core/style/focus-classes.ts

Lines changed: 27 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,12 @@ export class FocusOriginMonitor {
1212
/** The focus origin that the next focus event is a result of. */
1313
private _origin: FocusOrigin = null;
1414

15+
/** A WeakMap used to track the last element focused via the FocusOriginMonitor. */
16+
private _lastFocused = new WeakMap<Element, FocusOrigin>();
17+
18+
/** Whether the window has just been focused. */
19+
private _windowFocused = false;
20+
1521
constructor() {
1622
// Listen to keydown and mousedown in the capture phase so we can detect them even if the user
1723
// stops propagation.
@@ -20,6 +26,13 @@ export class FocusOriginMonitor {
2026
'keydown', () => this._setOriginForCurrentEventQueue('keyboard'), true);
2127
document.addEventListener(
2228
'mousedown', () => this._setOriginForCurrentEventQueue('mouse'), true);
29+
30+
// Make a note of when the window regains focus, so we can restore the origin info for the
31+
// focused element.
32+
window.addEventListener('focus', () => {
33+
this._windowFocused = true;
34+
setTimeout(() => this._windowFocused = false, 0);
35+
});
2336
}
2437

2538
/** Register an element to receive focus classes. */
@@ -44,15 +57,26 @@ export class FocusOriginMonitor {
4457

4558
/** Handles focus events on a registered element. */
4659
private _onFocus(element: Element, renderer: Renderer, subject: Subject<FocusOrigin>) {
47-
// If we couldn't detect a cause for the focus event, assume it was due to programmatically
48-
// setting the focus.
49-
this._origin = this._origin || 'program';
60+
// If we couldn't detect a cause for the focus event, it's due to one of two reasons:
61+
// 1) The window has just regained focus, in which case we want to restore the focused state of
62+
// the element from before the window blurred.
63+
// 2) The element was programmatically focused, in which case we should mark the origin as
64+
// 'program'.
65+
if (!this._origin) {
66+
if (this._windowFocused && this._lastFocused.has(element)) {
67+
this._origin = this._lastFocused.get(element);
68+
} else {
69+
this._origin = 'program';
70+
}
71+
}
5072

5173
renderer.setElementClass(element, 'cdk-focused', true);
5274
renderer.setElementClass(element, 'cdk-keyboard-focused', this._origin == 'keyboard');
5375
renderer.setElementClass(element, 'cdk-mouse-focused', this._origin == 'mouse');
5476
renderer.setElementClass(element, 'cdk-program-focused', this._origin == 'program');
77+
5578
subject.next(this._origin);
79+
this._lastFocused = new WeakMap().set(element, this._origin);
5680
this._origin = null;
5781
}
5882

0 commit comments

Comments
 (0)