@taiga-ui/cdk
Version:
Base library for creating Angular components and applications using Taiga UI principles regarding of actual visual appearance
67 lines • 8.68 kB
JavaScript
import { DOCUMENT } from '@angular/common';
import { Directive, inject } from '@angular/core';
import { tuiContainsOrAfter, tuiInjectElement, tuiIsHTMLElement, } from '@taiga-ui/cdk/utils/dom';
import { tuiBlurNativeFocused, tuiGetClosestFocusable, tuiGetNativeFocused, } from '@taiga-ui/cdk/utils/focus';
import * as i0 from "@angular/core";
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 }); }
}
export { TuiFocusTrap };
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 []; } });
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiZm9jdXMtdHJhcC5kaXJlY3RpdmUuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi8uLi8uLi9wcm9qZWN0cy9jZGsvZGlyZWN0aXZlcy9mb2N1cy10cmFwL2ZvY3VzLXRyYXAuZGlyZWN0aXZlLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBLE9BQU8sRUFBQyxRQUFRLEVBQUMsTUFBTSxpQkFBaUIsQ0FBQztBQUV6QyxPQUFPLEVBQUMsU0FBUyxFQUFFLE1BQU0sRUFBQyxNQUFNLGVBQWUsQ0FBQztBQUNoRCxPQUFPLEVBQ0gsa0JBQWtCLEVBQ2xCLGdCQUFnQixFQUNoQixnQkFBZ0IsR0FDbkIsTUFBTSx5QkFBeUIsQ0FBQztBQUNqQyxPQUFPLEVBQ0gsb0JBQW9CLEVBQ3BCLHNCQUFzQixFQUN0QixtQkFBbUIsR0FDdEIsTUFBTSwyQkFBMkIsQ0FBQzs7QUFFbkMsTUFRYSxZQUFZO0lBTXJCO1FBTGlCLFFBQUcsR0FBRyxNQUFNLENBQUMsUUFBUSxDQUFDLENBQUM7UUFDdkIsT0FBRSxHQUFHLGdCQUFnQixFQUFFLENBQUM7UUFDakMsa0JBQWEsR0FBbUIsSUFBSSxDQUFDO1FBQ25DLGdCQUFXLEdBQUcsS0FBSyxDQUFDO1FBRzFCOzs7O1dBSUc7UUFDSCxPQUFPLENBQUMsT0FBTyxFQUFFLENBQUMsSUFBSSxDQUFDLEdBQUcsRUFBRTtZQUN4Qjs7Ozs7ZUFLRztZQUNILElBQUksQ0FBQyxXQUFXLEdBQUcsSUFBSSxDQUFDO1lBQ3hCLElBQUksQ0FBQyxhQUFhLEdBQUcsbUJBQW1CLENBQUMsSUFBSSxDQUFDLEdBQUcsQ0FBQyxDQUFDO1lBQ25ELElBQUksQ0FBQyxFQUFFLENBQUMsS0FBSyxFQUFFLENBQUM7UUFDcEIsQ0FBQyxDQUFDLENBQUM7SUFDUCxDQUFDO0lBRU0sV0FBVztRQUNkLG9CQUFvQixDQUFDLElBQUksQ0FBQyxHQUFHLENBQUMsQ0FBQztRQUUvQjs7Ozs7V0FLRztRQUNILE9BQU8sQ0FBQyxPQUFPLEVBQUUsQ0FBQyxJQUFJLENBQUMsR0FBRyxFQUFFO1lBQ3hCLElBQUksZ0JBQWdCLENBQUMsSUFBSSxDQUFDLGFBQWEsQ0FBQyxFQUFFO2dCQUN0QyxJQUFJLENBQUMsYUFBYSxDQUFDLEtBQUssRUFBRSxDQUFDO2FBQzlCO1FBQ0wsQ0FBQyxDQUFDLENBQUM7SUFDUCxDQUFDO0lBRVMsU0FBUyxDQUFDLElBQVU7UUFDMUIsTUFBTSxFQUFDLGlCQUFpQixFQUFDLEdBQUcsSUFBSSxDQUFDLEVBQUUsQ0FBQztRQUVwQyxJQUFJLENBQUMsa0JBQWtCLENBQUMsSUFBSSxDQUFDLEVBQUUsRUFBRSxJQUFJLENBQUMsSUFBSSxpQkFBaUIsRUFBRTtZQUN6RCxzQkFBc0IsQ0FBQztnQkFDbkIsT0FBTyxFQUFFLGlCQUFpQjtnQkFDMUIsSUFBSSxFQUFFLElBQUksQ0FBQyxFQUFFO2FBQ2hCLENBQUMsRUFBRSxLQUFLLEVBQUUsQ0FBQztTQUNmO0lBQ0wsQ0FBQzsrR0FsRFEsWUFBWTttR0FBWixZQUFZOztTQUFaLFlBQVk7NEZBQVosWUFBWTtrQkFSeEIsU0FBUzttQkFBQztvQkFDUCxVQUFVLEVBQUUsSUFBSTtvQkFDaEIsUUFBUSxFQUFFLGdCQUFnQjtvQkFDMUIsSUFBSSxFQUFFO3dCQUNGLFFBQVEsRUFBRSxHQUFHO3dCQUNiLDJCQUEyQixFQUFFLHlDQUF5QztxQkFDekU7aUJBQ0oiLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQge0RPQ1VNRU5UfSBmcm9tICdAYW5ndWxhci9jb21tb24nO1xuaW1wb3J0IHR5cGUge09uRGVzdHJveX0gZnJvbSAnQGFuZ3VsYXIvY29yZSc7XG5pbXBvcnQge0RpcmVjdGl2ZSwgaW5qZWN0fSBmcm9tICdAYW5ndWxhci9jb3JlJztcbmltcG9ydCB7XG4gICAgdHVpQ29udGFpbnNPckFmdGVyLFxuICAgIHR1aUluamVjdEVsZW1lbnQsXG4gICAgdHVpSXNIVE1MRWxlbWVudCxcbn0gZnJvbSAnQHRhaWdhLXVpL2Nkay91dGlscy9kb20nO1xuaW1wb3J0IHtcbiAgICB0dWlCbHVyTmF0aXZlRm9jdXNlZCxcbiAgICB0dWlHZXRDbG9zZXN0Rm9jdXNhYmxlLFxuICAgIHR1aUdldE5hdGl2ZUZvY3VzZWQsXG59IGZyb20gJ0B0YWlnYS11aS9jZGsvdXRpbHMvZm9jdXMnO1xuXG5ARGlyZWN0aXZlKHtcbiAgICBzdGFuZGFsb25lOiB0cnVlLFxuICAgIHNlbGVjdG9yOiAnW3R1aUZvY3VzVHJhcF0nLFxuICAgIGhvc3Q6IHtcbiAgICAgICAgdGFiSW5kZXg6ICcwJyxcbiAgICAgICAgJyh3aW5kb3c6Zm9jdXNpbi56b25lbGVzcyknOiAnaW5pdGlhbGl6ZWQgJiYgb25Gb2N1c0luKCRldmVudC50YXJnZXQpJyxcbiAgICB9LFxufSlcbmV4cG9ydCBjbGFzcyBUdWlGb2N1c1RyYXAgaW1wbGVtZW50cyBPbkRlc3Ryb3kge1xuICAgIHByaXZhdGUgcmVhZG9ubHkgZG9jID0gaW5qZWN0KERPQ1VNRU5UKTtcbiAgICBwcml2YXRlIHJlYWRvbmx5IGVsID0gdHVpSW5qZWN0RWxlbWVudCgpO1xuICAgIHByaXZhdGUgYWN0aXZlRWxlbWVudDogRWxlbWVudCB8IG51bGwgPSBudWxsO1xuICAgIHByb3RlY3RlZCBpbml0aWFsaXplZCA9IGZhbHNlO1xuXG4gICAgY29uc3RydWN0b3IoKSB7XG4gICAgICAgIC8qKlxuICAgICAgICAgKiBUaGlzIHdvdWxkIGNhdXNlIGN1cnJlbnRseSBmb2N1c2VkIGVsZW1lbnQgdG8gbG9zZSBmb2N1cyxcbiAgICAgICAgICogYnV0IGl0IG1pZ2h0IGNhdXNlIEV4cHJlc3Npb25DaGFuZ2VkIGVycm9yIGR1ZSB0byBwb3RlbnRpYWwgSG9zdEJpbmRpbmcuXG4gICAgICAgICAqIE1pY3JvdGFzayBrZWVwcyBpdCBpbiB0aGUgc2FtZSBmcmFtZSBidXQgYWxsb3dzIGNoYW5nZSBkZXRlY3Rpb24gdG8gcnVuXG4gICAgICAgICAqL1xuICAgICAgICBQcm9taXNlLnJlc29sdmUoKS50aGVuKCgpID0+IHtcbiAgICAgICAgICAgIC8qKlxuICAgICAgICAgICAgICogVGhlIHNhbWUgZXZlbnQgY2FuIHN5bmNocm9ub3VzbHkgY2xvc2UgYWxyZWFkeSBvcGVuZWQgZm9jdXMgdHJhcCBhbmQgb3BlbiBhbm90aGVyIG9uZS5cbiAgICAgICAgICAgICAqIEFsbCBmb2N1cyB0cmFwcyBoYXZlIG1pY3JvdGFzayBpbnNpZGUgaXRzIGBuZ09uRGVzdHJveWAg4oCTXG4gICAgICAgICAgICAgKiB0aGV5IHNob3VsZCBiZSByZXNvbHZlZCBiZWZvcmUgZW5hYmxpbmcgb2YgbmV3IGZvY3VzIHRyYXAuXG4gICAgICAgICAgICAgKiBEb24ndCBlbmFibGUgYW55IG5ldyBldmVudCBsaXN0ZW5lcnMgYmVmb3JlIGBpbml0aWFsaXplZGAgZXF1YWxzIHRvIGB0cnVlYCFcbiAgICAgICAgICAgICAqL1xuICAgICAgICAgICAgdGhpcy5pbml0aWFsaXplZCA9IHRydWU7XG4gICAgICAgICAgICB0aGlzLmFjdGl2ZUVsZW1lbnQgPSB0dWlHZXROYXRpdmVGb2N1c2VkKHRoaXMuZG9jKTtcbiAgICAgICAgICAgIHRoaXMuZWwuZm9jdXMoKTtcbiAgICAgICAgfSk7XG4gICAgfVxuXG4gICAgcHVibGljIG5nT25EZXN0cm95KCk6IHZvaWQge1xuICAgICAgICB0dWlCbHVyTmF0aXZlRm9jdXNlZCh0aGlzLmRvYyk7XG5cbiAgICAgICAgLyoqXG4gICAgICAgICAqIEhvc3RMaXN0ZW5lcnMgYXJlIHRyaWdnZXJlZCBldmVuIGFmdGVyIG5nT25EZXN0cm95XG4gICAgICAgICAqIHtAbGluayBodHRwczovL2dpdGh1Yi5jb20vYW5ndWxhci9hbmd1bGFyL2lzc3Vlcy8zODEwMH1cbiAgICAgICAgICogc28gd2UgbmVlZCB0byBkZWxheSBpdCBidXQgc3RheSBpbiB0aGUgc2FtZSBzeW5jIGN5Y2xlLFxuICAgICAgICAgKiB0aGVyZWZvcmUgdXNpbmcgUHJvbWlzZSBpbnN0ZWFkIG9mIHNldFRpbWVvdXRcbiAgICAgICAgICovXG4gICAgICAgIFByb21pc2UucmVzb2x2ZSgpLnRoZW4oKCkgPT4ge1xuICAgICAgICAgICAgaWYgKHR1aUlzSFRNTEVsZW1lbnQodGhpcy5hY3RpdmVFbGVtZW50KSkge1xuICAgICAgICAgICAgICAgIHRoaXMuYWN0aXZlRWxlbWVudC5mb2N1cygpO1xuICAgICAgICAgICAgfVxuICAgICAgICB9KTtcbiAgICB9XG5cbiAgICBwcm90ZWN0ZWQgb25Gb2N1c0luKG5vZGU6IE5vZGUpOiB2b2lkIHtcbiAgICAgICAgY29uc3Qge2ZpcnN0RWxlbWVudENoaWxkfSA9IHRoaXMuZWw7XG5cbiAgICAgICAgaWYgKCF0dWlDb250YWluc09yQWZ0ZXIodGhpcy5lbCwgbm9kZSkgJiYgZmlyc3RFbGVtZW50Q2hpbGQpIHtcbiAgICAgICAgICAgIHR1aUdldENsb3Nlc3RGb2N1c2FibGUoe1xuICAgICAgICAgICAgICAgIGluaXRpYWw6IGZpcnN0RWxlbWVudENoaWxkLFxuICAgICAgICAgICAgICAgIHJvb3Q6IHRoaXMuZWwsXG4gICAgICAgICAgICB9KT8uZm9jdXMoKTtcbiAgICAgICAgfVxuICAgIH1cbn1cbiJdfQ==