@taiga-ui/cdk
Version:
Base library for creating Angular components and applications using Taiga UI principles regarding of actual visual appearance
74 lines (70 loc) • 3.31 kB
JavaScript
import { DOCUMENT } from '@angular/common';
import * as i0 from '@angular/core';
import { inject, Directive } from '@angular/core';
import { tuiInjectElement, tuiIsHTMLElement, tuiContainsOrAfter } from '@taiga-ui/cdk/utils/dom';
import { tuiGetNativeFocused, tuiBlurNativeFocused, tuiGetClosestFocusable } from '@taiga-ui/cdk/utils/focus';
class TuiFocusTrap {
constructor() {
this.doc = inject(DOCUMENT);
this.el = tuiInjectElement();
this.activeElement = null;
this.initialized = false;
/**
* This would cause currently focused element to lose focus,
* but it might cause ExpressionChanged error due to potential HostBinding.
* Microtask keeps it in the same frame but allows change detection to run
*/
Promise.resolve().then(() => {
/**
* The same event can synchronously close already opened focus trap and open another one.
* All focus traps have microtask inside its `ngOnDestroy` –
* they should be resolved before enabling of new focus trap.
* Don't enable any new event listeners before `initialized` equals to `true`!
*/
this.initialized = true;
this.activeElement = tuiGetNativeFocused(this.doc);
this.el.focus();
});
}
ngOnDestroy() {
tuiBlurNativeFocused(this.doc);
/**
* HostListeners are triggered even after ngOnDestroy
* {@link https://github.com/angular/angular/issues/38100}
* so we need to delay it but stay in the same sync cycle,
* therefore using Promise instead of setTimeout
*/
Promise.resolve().then(() => {
if (tuiIsHTMLElement(this.activeElement)) {
this.activeElement.focus();
}
});
}
onFocusIn(node) {
const { firstElementChild } = this.el;
if (!tuiContainsOrAfter(this.el, node) && firstElementChild) {
tuiGetClosestFocusable({
initial: firstElementChild,
root: this.el,
})?.focus();
}
}
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: TuiFocusTrap, deps: [], target: i0.ɵɵFactoryTarget.Directive }); }
static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "16.2.12", type: TuiFocusTrap, isStandalone: true, selector: "[tuiFocusTrap]", host: { attributes: { "tabIndex": "0" }, listeners: { "window:focusin.zoneless": "initialized && onFocusIn($event.target)" } }, ngImport: i0 }); }
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: TuiFocusTrap, decorators: [{
type: Directive,
args: [{
standalone: true,
selector: '[tuiFocusTrap]',
host: {
tabIndex: '0',
'(window:focusin.zoneless)': 'initialized && onFocusIn($event.target)',
},
}]
}], ctorParameters: function () { return []; } });
/**
* Generated bundle index. Do not edit.
*/
export { TuiFocusTrap };
//# sourceMappingURL=taiga-ui-cdk-directives-focus-trap.mjs.map