primeng
Version:
PrimeNG is a premium UI library for Angular featuring a rich set of 90+ components, a theme designer, various theme alternatives such as Material, Bootstrap, Tailwind, premium templates and professional support. In addition, it integrates with PrimeBlock,
114 lines (110 loc) • 5.98 kB
JavaScript
import { isPlatformBrowser } from '@angular/common';
import * as i0 from '@angular/core';
import { input, booleanAttribute, effect, Directive, NgModule } from '@angular/core';
import { createElement, getFirstFocusableElement, focus, getLastFocusableElement } from '@primeuix/utils';
import { BaseComponent } from 'primeng/basecomponent';
/**
* Focus Trap keeps focus within a certain DOM element while tabbing.
* @group Components
*/
class FocusTrap extends BaseComponent {
/**
* When set as true, focus wouldn't be managed.
* @group Props
*/
pFocusTrapDisabled = input(false, { ...(ngDevMode ? { debugName: "pFocusTrapDisabled" } : /* istanbul ignore next */ {}), transform: booleanAttribute });
firstHiddenFocusableElement;
lastHiddenFocusableElement;
constructor() {
super();
effect(() => {
const disabled = this.pFocusTrapDisabled();
if (isPlatformBrowser(this.platformId)) {
if (disabled) {
this.removeHiddenFocusableElements();
}
else if (!this.firstHiddenFocusableElement && !this.lastHiddenFocusableElement) {
this.createHiddenFocusableElements();
}
}
});
}
onInit() {
if (isPlatformBrowser(this.platformId) && !this.pFocusTrapDisabled()) {
!this.firstHiddenFocusableElement && !this.lastHiddenFocusableElement && this.createHiddenFocusableElements();
}
}
removeHiddenFocusableElements() {
if (this.firstHiddenFocusableElement && this.firstHiddenFocusableElement.parentNode) {
this.firstHiddenFocusableElement.parentNode.removeChild(this.firstHiddenFocusableElement);
}
if (this.lastHiddenFocusableElement && this.lastHiddenFocusableElement.parentNode) {
this.lastHiddenFocusableElement.parentNode.removeChild(this.lastHiddenFocusableElement);
}
this.firstHiddenFocusableElement = null;
this.lastHiddenFocusableElement = null;
}
getComputedSelector(selector) {
return `:not(.p-hidden-focusable):not([data-p-hidden-focusable="true"])${selector ?? ''}`;
}
createHiddenFocusableElements() {
const tabindex = '0';
const createFocusableElement = (onFocus) => {
return createElement('span', {
class: 'p-hidden-accessible p-hidden-focusable',
tabindex,
role: 'presentation',
'aria-hidden': true,
'data-p-hidden-accessible': true,
'data-p-hidden-focusable': true,
onFocus: onFocus?.bind(this)
});
};
this.firstHiddenFocusableElement = createFocusableElement(this.onFirstHiddenElementFocus);
this.lastHiddenFocusableElement = createFocusableElement(this.onLastHiddenElementFocus);
this.firstHiddenFocusableElement.setAttribute('data-pc-section', 'firstfocusableelement');
this.lastHiddenFocusableElement.setAttribute('data-pc-section', 'lastfocusableelement');
this.el.nativeElement.prepend(this.firstHiddenFocusableElement);
this.el.nativeElement.append(this.lastHiddenFocusableElement);
}
onFirstHiddenElementFocus(event) {
const { currentTarget, relatedTarget } = event;
const focusableElement = relatedTarget === this.lastHiddenFocusableElement || !this.el.nativeElement?.contains(relatedTarget)
? getFirstFocusableElement(currentTarget.parentElement, ':not(.p-hidden-focusable)')
: this.lastHiddenFocusableElement;
focus(focusableElement);
}
onLastHiddenElementFocus(event) {
const { currentTarget, relatedTarget } = event;
const focusableElement = relatedTarget === this.firstHiddenFocusableElement || !this.el.nativeElement?.contains(relatedTarget)
? getLastFocusableElement(currentTarget.parentElement, ':not(.p-hidden-focusable)')
: this.firstHiddenFocusableElement;
focus(focusableElement);
}
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.6", ngImport: i0, type: FocusTrap, deps: [], target: i0.ɵɵFactoryTarget.Directive });
static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "17.1.0", version: "22.0.6", type: FocusTrap, isStandalone: true, selector: "[pFocusTrap]", inputs: { pFocusTrapDisabled: { classPropertyName: "pFocusTrapDisabled", publicName: "pFocusTrapDisabled", isSignal: true, isRequired: false, transformFunction: null } }, usesInheritance: true, ngImport: i0 });
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.6", ngImport: i0, type: FocusTrap, decorators: [{
type: Directive,
args: [{
selector: '[pFocusTrap]',
standalone: true
}]
}], ctorParameters: () => [], propDecorators: { pFocusTrapDisabled: [{ type: i0.Input, args: [{ isSignal: true, alias: "pFocusTrapDisabled", required: false }] }] } });
class FocusTrapModule {
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.6", ngImport: i0, type: FocusTrapModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule });
static ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "14.0.0", version: "22.0.6", ngImport: i0, type: FocusTrapModule, imports: [FocusTrap], exports: [FocusTrap] });
static ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "22.0.6", ngImport: i0, type: FocusTrapModule });
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.6", ngImport: i0, type: FocusTrapModule, decorators: [{
type: NgModule,
args: [{
imports: [FocusTrap],
exports: [FocusTrap]
}]
}] });
/**
* Generated bundle index. Do not edit.
*/
export { FocusTrap, FocusTrapModule };
//# sourceMappingURL=primeng-focustrap.mjs.map