Skip to content

Commit

Permalink
fix: address issue that prevents dropdown menus from closing in some …
Browse files Browse the repository at this point in the history
…browsers
  • Loading branch information
mikecarenzo authored Sep 13, 2024
1 parent 7d3163f commit 6e15f0b
Showing 1 changed file with 47 additions and 17 deletions.
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import "./RawFocusBox.css";

export class RawFocusBox {

/**
* The focus box's class name.
*/
Expand Down Expand Up @@ -33,6 +33,11 @@ export class RawFocusBox {
*/
private _eventHandlers: FocusEventHandlers;

/**
* Indicates if an exit item has just been clicked or not.
*/
private _lastTarget: HTMLElement | null;


/**
* Creates a new {@link RawFocusBox}.
Expand Down Expand Up @@ -65,6 +70,7 @@ export class RawFocusBox {
emitFocusOut: () => {},
pointerdown: this.onPointerEvent.bind(this)
}
this._lastTarget = null;
}


Expand Down Expand Up @@ -132,17 +138,26 @@ export class RawFocusBox {
/**
* Focus in behavior.
*/
public onFocusIn() {
this._focused = true;
this._eventHandlers.emitFocusIn();
private onFocusIn() {
// If last target was inside an element with an exit flag...
if(this.isTargetInExitElement(this._lastTarget)) {
// ...force container out of focus
this._el!.blur();
}
// If last target was inside container...
else {
// ...emit focus
this._focused = true;
this._eventHandlers.emitFocusIn();
}
}

/**
* Focus out behavior.
* @param event
* The focus event.
*/
public onFocusOut(event: FocusEvent) {
private onFocusOut(event: FocusEvent) {
// If target is not a child of this container, unfocus.
const target = event.relatedTarget as Node | null;
if(this._focused && !this._el!.contains(target)) {
Expand All @@ -156,20 +171,35 @@ export class RawFocusBox {
* @param event
* The pointer event.
*/
public onPointerEvent(event: PointerEvent | MouseEvent) {
// If target is a child of this container...
let target = event.target as HTMLElement;
while(this._el !== target) {
// ...but has the exit flag, emit unfocus.
if(target.hasAttribute("exit-focus-box")) {
this._focused = false;
this._eventHandlers.emitFocusOut();
// Force the container out of focus
this._el!.blur();
return;
private onPointerEvent(event: PointerEvent | MouseEvent) {
this._lastTarget = event.target as HTMLElement;
// If target is inside an element with an exit flag...
if(this.isTargetInExitElement(this._lastTarget)) {
// ...emit unfocus...
this._focused = false;
this._eventHandlers.emitFocusOut();
// ...and force the container out of focus
this._el!.blur();
}
}

/**
* Tests if an element has (or is contained within an element that has) the
* `exit-focus-box` attribute.
* @param el
* The element to test.
* @returns
* True if the element has (or is contained within an element that has)
* the `exit-focus-box` attribute, false otherwise.
*/
private isTargetInExitElement(el: HTMLElement | null) {
while(el && this._el !== el) {
if(el.hasAttribute("exit-focus-box")) {
return true;
}
target = target.parentElement!;
el = el.parentElement!;
}
return false;
}

}
Expand Down

0 comments on commit 6e15f0b

Please sign in to comment.