bitmovin-player-ui
Version:
Bitmovin Player UI Framework
77 lines (63 loc) • 2.24 kB
text/typescript
import { DOM } from '../DOM';
const FocusVisibleCssClassName = '{{PREFIX}}-focus-visible';
export class FocusVisibilityTracker {
private readonly eventHandlerMap: { [eventName: string]: EventListenerOrEventListenerObject };
private lastInteractionWasKeyboard: boolean = true;
private uiWrapperElement: DOM;
constructor(
private bitmovinUiPrefix: string,
uiWrapperElement: DOM,
) {
this.uiWrapperElement = uiWrapperElement;
this.eventHandlerMap = {
mousedown: this.onMouseOrPointerOrTouch,
pointerdown: this.onMouseOrPointerOrTouch,
touchstart: this.onMouseOrPointerOrTouch,
keydown: this.onKeyDown,
focus: this.onFocus,
blur: this.onBlur,
};
this.registerEventListeners();
}
private onKeyDown = (e: KeyboardEvent) => {
if (e.metaKey || e.altKey || e.ctrlKey) {
return;
}
this.lastInteractionWasKeyboard = true;
};
private onMouseOrPointerOrTouch = () => (this.lastInteractionWasKeyboard = false);
private onFocus = ({ target: element }: FocusEvent) => {
if (
this.lastInteractionWasKeyboard &&
isHtmlElement(element) &&
isBitmovinUi(element, this.bitmovinUiPrefix) &&
!element.classList.contains(FocusVisibleCssClassName)
) {
element.classList.add(FocusVisibleCssClassName);
}
};
private onBlur = ({ target: element }: FocusEvent) => {
if (isHtmlElement(element)) {
element.classList.remove(FocusVisibleCssClassName);
}
};
private registerEventListeners(): void {
for (const event in this.eventHandlerMap) {
this.uiWrapperElement.on(event, this.eventHandlerMap[event], true);
}
}
private unregisterEventListeners(): void {
for (const event in this.eventHandlerMap) {
this.uiWrapperElement.off(event, this.eventHandlerMap[event], true);
}
}
public release(): void {
this.unregisterEventListeners();
}
}
function isBitmovinUi(element: Element, bitmovinUiPrefix: string): boolean {
return element.id.indexOf(bitmovinUiPrefix) === 0;
}
function isHtmlElement(element: unknown): element is HTMLElement & { classList: DOMTokenList } {
return element instanceof HTMLElement && element.classList instanceof DOMTokenList;
}