UNPKG

ngx-bootstrap

Version:
832 lines (821 loc) 39.3 kB
(function (global, factory) { typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports, require('@angular/core'), require('@angular/common'), require('rxjs/operators')) : typeof define === 'function' && define.amd ? define('ngx-bootstrap/focus-trap', ['exports', '@angular/core', '@angular/common', 'rxjs/operators'], factory) : (global = typeof globalThis !== 'undefined' ? globalThis : global || self, factory((global['ngx-bootstrap'] = global['ngx-bootstrap'] || {}, global['ngx-bootstrap']['focus-trap'] = {}), global.ng.core, global.ng.common, global.rxjs.operators)); }(this, (function (exports, i0, i2, operators) { 'use strict'; /** * @license * Copyright Google LLC All Rights Reserved. * * Use of this source code is governed by an MIT-style license that can be * found in the LICENSE file at https://angular.io/license */ /** Injectable that ensures only the most recently enabled FocusTrap is active. */ var FocusTrapManager = /** @class */ (function () { function FocusTrapManager() { // A stack of the FocusTraps on the page. Only the FocusTrap at the // top of the stack is active. this._focusTrapStack = []; } /** * Disables the FocusTrap at the top of the stack, and then pushes * the new FocusTrap onto the stack. */ FocusTrapManager.prototype.register = function (focusTrap) { // Dedupe focusTraps that register multiple times. this._focusTrapStack = this._focusTrapStack.filter(function (ft) { return ft !== focusTrap; }); var stack = this._focusTrapStack; if (stack.length) { stack[stack.length - 1]._disable(); } stack.push(focusTrap); focusTrap._enable(); }; /** * Removes the FocusTrap from the stack, and activates the * FocusTrap that is the new top of the stack. */ FocusTrapManager.prototype.deregister = function (focusTrap) { focusTrap._disable(); var stack = this._focusTrapStack; var i = stack.indexOf(focusTrap); if (i !== -1) { stack.splice(i, 1); if (stack.length) { stack[stack.length - 1]._enable(); } } }; return FocusTrapManager; }()); FocusTrapManager.ɵprov = i0.ɵɵdefineInjectable({ factory: function FocusTrapManager_Factory() { return new FocusTrapManager(); }, token: FocusTrapManager, providedIn: "root" }); FocusTrapManager.decorators = [ { type: i0.Injectable, args: [{ providedIn: 'root' },] } ]; /** * @license * Copyright Google LLC All Rights Reserved. * * Use of this source code is governed by an MIT-style license that can be * found in the LICENSE file at https://angular.io/license */ // Whether the current platform supports the V8 Break Iterator. The V8 check // is necessary to detect all Blink based browsers. var hasV8BreakIterator; // We need a try/catch around the reference to `Intl`, because accessing it in some cases can // cause IE to throw. These cases are tied to particular versions of Windows and can happen if // the consumer is providing a polyfilled `Map`. See: // https://github.com/Microsoft/ChakraCore/issues/3189 // https://github.com/angular/components/issues/15687 try { hasV8BreakIterator = (typeof Intl !== 'undefined' && Intl.v8BreakIterator); } catch (_a) { hasV8BreakIterator = false; } /** * Service to detect the current platform by comparing the userAgent strings and * checking browser-specific global properties. */ var Platform = /** @class */ (function () { function Platform(_platformId) { this._platformId = _platformId; // We want to use the Angular platform check because if the Document is shimmed // without the navigator, the following checks will fail. This is preferred because // sometimes the Document may be shimmed without the user's knowledge or intention /** Whether the Angular application is being rendered in the browser. */ this.isBrowser = this._platformId ? i2.isPlatformBrowser(this._platformId) : typeof document === 'object' && !!document; /** Whether the current browser is Microsoft Edge. */ this.EDGE = this.isBrowser && /(edge)/i.test(navigator.userAgent); /** Whether the current rendering engine is Microsoft Trident. */ this.TRIDENT = this.isBrowser && /(msie|trident)/i.test(navigator.userAgent); // EdgeHTML and Trident mock Blink specific things and need to be excluded from this check. /** Whether the current rendering engine is Blink. */ this.BLINK = this.isBrowser && (!!(window.chrome || hasV8BreakIterator) && typeof CSS !== 'undefined' && !this.EDGE && !this.TRIDENT); // Webkit is part of the userAgent in EdgeHTML, Blink and Trident. Therefore we need to // ensure that Webkit runs standalone and is not used as another engine's base. /** Whether the current rendering engine is WebKit. */ this.WEBKIT = this.isBrowser && /AppleWebKit/i.test(navigator.userAgent) && !this.BLINK && !this.EDGE && !this.TRIDENT; /** Whether the current platform is Apple iOS. */ this.IOS = this.isBrowser && /iPad|iPhone|iPod/.test(navigator.userAgent) && !('MSStream' in window); // It's difficult to detect the plain Gecko engine, because most of the browsers identify // them self as Gecko-like browsers and modify the userAgent's according to that. // Since we only cover one explicit Firefox case, we can simply check for Firefox // instead of having an unstable check for Gecko. /** Whether the current browser is Firefox. */ this.FIREFOX = this.isBrowser && /(firefox|minefield)/i.test(navigator.userAgent); /** Whether the current platform is Android. */ // Trident on mobile adds the android platform to the userAgent to trick detections. this.ANDROID = this.isBrowser && /android/i.test(navigator.userAgent) && !this.TRIDENT; // Safari browsers will include the Safari keyword in their userAgent. Some browsers may fake // this and just place the Safari keyword in the userAgent. To be more safe about Safari every // Safari browser should also use Webkit as its layout engine. /** Whether the current browser is Safari. */ this.SAFARI = this.isBrowser && /safari/i.test(navigator.userAgent) && this.WEBKIT; } return Platform; }()); Platform.ɵprov = i0.ɵɵdefineInjectable({ factory: function Platform_Factory() { return new Platform(i0.ɵɵinject(i0.PLATFORM_ID)); }, token: Platform, providedIn: "root" }); Platform.decorators = [ { type: i0.Injectable, args: [{ providedIn: 'root' },] } ]; Platform.ctorParameters = function () { return [ { type: Object, decorators: [{ type: i0.Inject, args: [i0.PLATFORM_ID,] }] } ]; }; /** * @license * Copyright Google LLC All Rights Reserved. * * Use of this source code is governed by an MIT-style license that can be * found in the LICENSE file at https://angular.io/license */ /** * Configuration for the isFocusable method. */ var IsFocusableConfig = /** @class */ (function () { function IsFocusableConfig() { /** * Whether to count an element as focusable even if it is not currently visible. */ this.ignoreVisibility = false; } return IsFocusableConfig; }()); // The InteractivityChecker leans heavily on the ally.js accessibility utilities. // Methods like `isTabbable` are only covering specific edge-cases for the browsers which are // supported. /** * Utility for checking the interactivity of an element, such as whether is is focusable or * tabbable. */ var InteractivityChecker = /** @class */ (function () { function InteractivityChecker(_platform) { this._platform = _platform; } /** * Gets whether an element is disabled. * * @param element Element to be checked. * @returns Whether the element is disabled. */ InteractivityChecker.prototype.isDisabled = function (element) { // This does not capture some cases, such as a non-form control with a disabled attribute or // a form control inside of a disabled form, but should capture the most common cases. return element.hasAttribute('disabled'); }; /** * Gets whether an element is visible for the purposes of interactivity. * * This will capture states like `display: none` and `visibility: hidden`, but not things like * being clipped by an `overflow: hidden` parent or being outside the viewport. * * @returns Whether the element is visible. */ InteractivityChecker.prototype.isVisible = function (element) { return hasGeometry(element) && getComputedStyle(element).visibility === 'visible'; }; /** * Gets whether an element can be reached via Tab key. * Assumes that the element has already been checked with isFocusable. * * @param element Element to be checked. * @returns Whether the element is tabbable. */ InteractivityChecker.prototype.isTabbable = function (element) { // Nothing is tabbable on the server 😎 if (!this._platform.isBrowser) { return false; } var frameElement = getFrameElement(getWindow(element)); if (frameElement) { // Frame elements inherit their tabindex onto all child elements. if (getTabIndexValue(frameElement) === -1) { return false; } // Browsers disable tabbing to an element inside of an invisible frame. if (!this.isVisible(frameElement)) { return false; } } var nodeName = element.nodeName.toLowerCase(); var tabIndexValue = getTabIndexValue(element); if (element.hasAttribute('contenteditable')) { return tabIndexValue !== -1; } if (nodeName === 'iframe' || nodeName === 'object') { // The frame or object's content may be tabbable depending on the content, but it's // not possibly to reliably detect the content of the frames. We always consider such // elements as non-tabbable. return false; } // In iOS, the browser only considers some specific elements as tabbable. if (this._platform.WEBKIT && this._platform.IOS && !isPotentiallyTabbableIOS(element)) { return false; } if (nodeName === 'audio') { // Audio elements without controls enabled are never tabbable, regardless // of the tabindex attribute explicitly being set. if (!element.hasAttribute('controls')) { return false; } // Audio elements with controls are by default tabbable unless the // tabindex attribute is set to `-1` explicitly. return tabIndexValue !== -1; } if (nodeName === 'video') { // For all video elements, if the tabindex attribute is set to `-1`, the video // is not tabbable. Note: We cannot rely on the default `HTMLElement.tabIndex` // property as that one is set to `-1` in Chrome, Edge and Safari v13.1. The // tabindex attribute is the source of truth here. if (tabIndexValue === -1) { return false; } // If the tabindex is explicitly set, and not `-1` (as per check before), the // video element is always tabbable (regardless of whether it has controls or not). if (tabIndexValue !== null) { return true; } // Otherwise (when no explicit tabindex is set), a video is only tabbable if it // has controls enabled. Firefox is special as videos are always tabbable regardless // of whether there are controls or not. return this._platform.FIREFOX || element.hasAttribute('controls'); } return element.tabIndex >= 0; }; /** * Gets whether an element can be focused by the user. * * @param element Element to be checked. * @param config The config object with options to customize this method's behavior * @returns Whether the element is focusable. */ InteractivityChecker.prototype.isFocusable = function (element, config) { // Perform checks in order of left to most expensive. // Again, naive approach that does not capture many edge cases and browser quirks. return isPotentiallyFocusable(element) && !this.isDisabled(element) && ((config === null || config === void 0 ? void 0 : config.ignoreVisibility) || this.isVisible(element)); }; return InteractivityChecker; }()); InteractivityChecker.ɵprov = i0.ɵɵdefineInjectable({ factory: function InteractivityChecker_Factory() { return new InteractivityChecker(i0.ɵɵinject(Platform)); }, token: InteractivityChecker, providedIn: "root" }); InteractivityChecker.decorators = [ { type: i0.Injectable, args: [{ providedIn: 'root' },] } ]; InteractivityChecker.ctorParameters = function () { return [ { type: Platform } ]; }; /** * Returns the frame element from a window object. Since browsers like MS Edge throw errors if * the frameElement property is being accessed from a different host address, this property * should be accessed carefully. */ function getFrameElement(window) { try { return window.frameElement; } catch (_a) { return null; } } /** Checks whether the specified element has any geometry / rectangles. */ function hasGeometry(element) { // Use logic from jQuery to check for an invisible element. // See https://github.com/jquery/jquery/blob/master/src/css/hiddenVisibleSelectors.js#L12 return !!(element.offsetWidth || element.offsetHeight || (typeof element.getClientRects === 'function' && element.getClientRects().length)); } /** Gets whether an element's */ function isNativeFormElement(element) { var nodeName = element.nodeName.toLowerCase(); return nodeName === 'input' || nodeName === 'select' || nodeName === 'button' || nodeName === 'textarea'; } /** Gets whether an element is an `<input type="hidden">`. */ function isHiddenInput(element) { return isInputElement(element) && element.type == 'hidden'; } /** Gets whether an element is an anchor that has an href attribute. */ function isAnchorWithHref(element) { return isAnchorElement(element) && element.hasAttribute('href'); } /** Gets whether an element is an input element. */ function isInputElement(element) { return element.nodeName.toLowerCase() == 'input'; } /** Gets whether an element is an anchor element. */ function isAnchorElement(element) { return element.nodeName.toLowerCase() == 'a'; } /** Gets whether an element has a valid tabindex. */ function hasValidTabIndex(element) { if (!element.hasAttribute('tabindex') || element.tabIndex === undefined) { return false; } var tabIndex = element.getAttribute('tabindex'); // IE11 parses tabindex="" as the value "-32768" if (tabIndex == '-32768') { return false; } return !!(tabIndex && !isNaN(parseInt(tabIndex, 10))); } /** * Returns the parsed tabindex from the element attributes instead of returning the * evaluated tabindex from the browsers defaults. */ function getTabIndexValue(element) { if (!hasValidTabIndex(element)) { return null; } // See browser issue in Gecko https://bugzilla.mozilla.org/show_bug.cgi?id=1128054 var tabIndex = parseInt(element.getAttribute('tabindex') || '', 10); return isNaN(tabIndex) ? -1 : tabIndex; } /** Checks whether the specified element is potentially tabbable on iOS */ function isPotentiallyTabbableIOS(element) { var nodeName = element.nodeName.toLowerCase(); var inputType = nodeName === 'input' && element.type; return inputType === 'text' || inputType === 'password' || nodeName === 'select' || nodeName === 'textarea'; } /** * Gets whether an element is potentially focusable without taking current visible/disabled state * into account. */ function isPotentiallyFocusable(element) { // Inputs are potentially focusable *unless* they're type="hidden". if (isHiddenInput(element)) { return false; } return isNativeFormElement(element) || isAnchorWithHref(element) || element.hasAttribute('contenteditable') || hasValidTabIndex(element); } /** Gets the parent window of a DOM node with regards of being inside of an iframe. */ function getWindow(node) { // ownerDocument is null if `node` itself *is* a document. return node.ownerDocument && node.ownerDocument.defaultView || window; } /** * @license * Copyright Google LLC All Rights Reserved. * * Use of this source code is governed by an MIT-style license that can be * found in the LICENSE file at https://angular.io/license */ /** Coerces a data-bound value (typically a string) to a boolean. */ function coerceBooleanProperty(value) { return value != null && "" + value !== 'false'; } /** * @license * Copyright Google LLC All Rights Reserved. * * Use of this source code is governed by an MIT-style license that can be * found in the LICENSE file at https://angular.io/license */ /** * Class that allows for trapping focus within a DOM element. * * This class currently uses a relatively simple approach to focus trapping. * It assumes that the tab order is the same as DOM order, which is not necessarily true. * Things like `tabIndex > 0`, flex `order`, and shadow roots can cause the two to misalign. * * @deprecated Use `ConfigurableFocusTrap` instead. * @breaking-change for 11.0.0 Remove this class. */ var FocusTrap = /** @class */ (function () { function FocusTrap(_element, _checker, _ngZone, _document, deferAnchors) { var _this = this; if (deferAnchors === void 0) { deferAnchors = false; } this._element = _element; this._checker = _checker; this._ngZone = _ngZone; this._document = _document; this._hasAttached = false; // Event listeners for the anchors. Need to be regular functions so that we can unbind them later. this.startAnchorListener = function () { return _this.focusLastTabbableElement(); }; this.endAnchorListener = function () { return _this.focusFirstTabbableElement(); }; this._enabled = true; if (!deferAnchors) { this.attachAnchors(); } } Object.defineProperty(FocusTrap.prototype, "enabled", { /** Whether the focus trap is active. */ get: function () { return this._enabled; }, set: function (value) { this._enabled = value; if (this._startAnchor && this._endAnchor) { this._toggleAnchorTabIndex(value, this._startAnchor); this._toggleAnchorTabIndex(value, this._endAnchor); } }, enumerable: false, configurable: true }); /** Destroys the focus trap by cleaning up the anchors. */ FocusTrap.prototype.destroy = function () { var startAnchor = this._startAnchor; var endAnchor = this._endAnchor; if (startAnchor) { startAnchor.removeEventListener('focus', this.startAnchorListener); if (startAnchor.parentNode) { startAnchor.parentNode.removeChild(startAnchor); } } if (endAnchor) { endAnchor.removeEventListener('focus', this.endAnchorListener); if (endAnchor.parentNode) { endAnchor.parentNode.removeChild(endAnchor); } } this._startAnchor = this._endAnchor = null; this._hasAttached = false; }; /** * Inserts the anchors into the DOM. This is usually done automatically * in the constructor, but can be deferred for cases like directives with `*ngIf`. * @returns Whether the focus trap managed to attach successfuly. This may not be the case * if the target element isn't currently in the DOM. */ FocusTrap.prototype.attachAnchors = function () { var _this = this; // If we're not on the browser, there can be no focus to trap. if (this._hasAttached) { return true; } this._ngZone.runOutsideAngular(function () { if (!_this._startAnchor) { _this._startAnchor = _this._createAnchor(); _this._startAnchor.addEventListener('focus', _this.startAnchorListener); } if (!_this._endAnchor) { _this._endAnchor = _this._createAnchor(); _this._endAnchor.addEventListener('focus', _this.endAnchorListener); } }); if (this._element.parentNode) { this._element.parentNode.insertBefore(this._startAnchor, this._element); this._element.parentNode.insertBefore(this._endAnchor, this._element.nextSibling); this._hasAttached = true; } return this._hasAttached; }; /** * Waits for the zone to stabilize, then either focuses the first element that the * user specified, or the first tabbable element. * @returns Returns a promise that resolves with a boolean, depending * on whether focus was moved successfully. */ FocusTrap.prototype.focusInitialElementWhenReady = function () { var _this = this; return new Promise(function (resolve) { _this._executeOnStable(function () { return resolve(_this.focusInitialElement()); }); }); }; /** * Waits for the zone to stabilize, then focuses * the first tabbable element within the focus trap region. * @returns Returns a promise that resolves with a boolean, depending * on whether focus was moved successfully. */ FocusTrap.prototype.focusFirstTabbableElementWhenReady = function () { var _this = this; return new Promise(function (resolve) { _this._executeOnStable(function () { return resolve(_this.focusFirstTabbableElement()); }); }); }; /** * Waits for the zone to stabilize, then focuses * the last tabbable element within the focus trap region. * @returns Returns a promise that resolves with a boolean, depending * on whether focus was moved successfully. */ FocusTrap.prototype.focusLastTabbableElementWhenReady = function () { var _this = this; return new Promise(function (resolve) { _this._executeOnStable(function () { return resolve(_this.focusLastTabbableElement()); }); }); }; /** * Get the specified boundary element of the trapped region. * @param bound The boundary to get (start or end of trapped region). * @returns The boundary element. */ FocusTrap.prototype._getRegionBoundary = function (bound) { // Contains the deprecated version of selector, for temporary backwards comparability. var markers = this._element.querySelectorAll("[cdk-focus-region-" + bound + "], " + ("[cdkFocusRegion" + bound + "], ") + ("[cdk-focus-" + bound + "]")); for (var i = 0; i < markers.length; i++) { // @breaking-change 8.0.0 if (markers[i].hasAttribute("cdk-focus-" + bound)) { console.warn("Found use of deprecated attribute 'cdk-focus-" + bound + "', " + ("use 'cdkFocusRegion" + bound + "' instead. The deprecated ") + "attribute will be removed in 8.0.0.", markers[i]); } else if (markers[i].hasAttribute("cdk-focus-region-" + bound)) { console.warn("Found use of deprecated attribute 'cdk-focus-region-" + bound + "', " + ("use 'cdkFocusRegion" + bound + "' instead. The deprecated attribute ") + "will be removed in 8.0.0.", markers[i]); } } if (bound == 'start') { return markers.length ? markers[0] : this._getFirstTabbableElement(this._element); } return markers.length ? markers[markers.length - 1] : this._getLastTabbableElement(this._element); }; /** * Focuses the element that should be focused when the focus trap is initialized. * @returns Whether focus was moved successfully. */ FocusTrap.prototype.focusInitialElement = function () { // Contains the deprecated version of selector, for temporary backwards comparability. var redirectToElement = this._element.querySelector("[cdk-focus-initial], " + "[cdkFocusInitial]"); if (redirectToElement) { // @breaking-change 8.0.0 if (redirectToElement.hasAttribute("cdk-focus-initial")) { console.warn("Found use of deprecated attribute 'cdk-focus-initial', " + "use 'cdkFocusInitial' instead. The deprecated attribute " + "will be removed in 8.0.0", redirectToElement); } // Warn the consumer if the element they've pointed to // isn't focusable, when not in production mode. if (!this._checker.isFocusable(redirectToElement)) { var focusableChild = this._getFirstTabbableElement(redirectToElement); focusableChild === null || focusableChild === void 0 ? void 0 : focusableChild.focus(); return !!focusableChild; } redirectToElement.focus(); return true; } return this.focusFirstTabbableElement(); }; /** * Focuses the first tabbable element within the focus trap region. * @returns Whether focus was moved successfully. */ FocusTrap.prototype.focusFirstTabbableElement = function () { var redirectToElement = this._getRegionBoundary('start'); if (redirectToElement) { redirectToElement.focus(); } return !!redirectToElement; }; /** * Focuses the last tabbable element within the focus trap region. * @returns Whether focus was moved successfully. */ FocusTrap.prototype.focusLastTabbableElement = function () { var redirectToElement = this._getRegionBoundary('end'); if (redirectToElement) { redirectToElement.focus(); } return !!redirectToElement; }; /** * Checks whether the focus trap has successfully been attached. */ FocusTrap.prototype.hasAttached = function () { return this._hasAttached; }; /** Get the first tabbable element from a DOM subtree (inclusive). */ FocusTrap.prototype._getFirstTabbableElement = function (root) { if (this._checker.isFocusable(root) && this._checker.isTabbable(root)) { return root; } // Iterate in DOM order. Note that IE doesn't have `children` for SVG so we fall // back to `childNodes` which includes text nodes, comments etc. var children = root.children || root.childNodes; for (var i = 0; i < children.length; i++) { var tabbableChild = children[i].nodeType === this._document.ELEMENT_NODE ? this._getFirstTabbableElement(children[i]) : null; if (tabbableChild) { return tabbableChild; } } return null; }; /** Get the last tabbable element from a DOM subtree (inclusive). */ FocusTrap.prototype._getLastTabbableElement = function (root) { if (this._checker.isFocusable(root) && this._checker.isTabbable(root)) { return root; } // Iterate in reverse DOM order. var children = root.children || root.childNodes; for (var i = children.length - 1; i >= 0; i--) { var tabbableChild = children[i].nodeType === this._document.ELEMENT_NODE ? this._getLastTabbableElement(children[i]) : null; if (tabbableChild) { return tabbableChild; } } return null; }; /** Creates an anchor element. */ FocusTrap.prototype._createAnchor = function () { var anchor = this._document.createElement('div'); this._toggleAnchorTabIndex(this._enabled, anchor); anchor.classList.add('cdk-visually-hidden'); anchor.classList.add('cdk-focus-trap-anchor'); anchor.setAttribute('aria-hidden', 'true'); return anchor; }; /** * Toggles the `tabindex` of an anchor, based on the enabled state of the focus trap. * @param isEnabled Whether the focus trap is enabled. * @param anchor Anchor on which to toggle the tabindex. */ FocusTrap.prototype._toggleAnchorTabIndex = function (isEnabled, anchor) { // Remove the tabindex completely, rather than setting it to -1, because if the // element has a tabindex, the user might still hit it when navigating with the arrow keys. isEnabled ? anchor.setAttribute('tabindex', '0') : anchor.removeAttribute('tabindex'); }; /** * Toggles the`tabindex` of both anchors to either trap Tab focus or allow it to escape. * @param enabled: Whether the anchors should trap Tab. */ FocusTrap.prototype.toggleAnchors = function (enabled) { if (this._startAnchor && this._endAnchor) { this._toggleAnchorTabIndex(enabled, this._startAnchor); this._toggleAnchorTabIndex(enabled, this._endAnchor); } }; /** Executes a function when the zone is stable. */ FocusTrap.prototype._executeOnStable = function (fn) { if (this._ngZone.isStable) { fn(); } else { this._ngZone.onStable.pipe(operators.take(1)).subscribe(fn); } }; return FocusTrap; }()); /** * Factory that allows easy instantiation of focus traps. * @deprecated Use `ConfigurableFocusTrapFactory` instead. * @breaking-change for 11.0.0 Remove this class. */ var FocusTrapFactory = /** @class */ (function () { function FocusTrapFactory(_checker, _ngZone, _document) { this._checker = _checker; this._ngZone = _ngZone; this._document = _document; } /** * Creates a focus-trapped region around the given element. * @param element The element around which focus will be trapped. * @param deferCaptureElements Defers the creation of focus-capturing elements to be done * manually by the user. * @returns The created focus trap instance. */ FocusTrapFactory.prototype.create = function (element, deferCaptureElements) { if (deferCaptureElements === void 0) { deferCaptureElements = false; } return new FocusTrap(element, this._checker, this._ngZone, this._document, deferCaptureElements); }; return FocusTrapFactory; }()); FocusTrapFactory.ɵprov = i0.ɵɵdefineInjectable({ factory: function FocusTrapFactory_Factory() { return new FocusTrapFactory(i0.ɵɵinject(InteractivityChecker), i0.ɵɵinject(i0.NgZone), i0.ɵɵinject(i2.DOCUMENT)); }, token: FocusTrapFactory, providedIn: "root" }); FocusTrapFactory.decorators = [ { type: i0.Injectable, args: [{ providedIn: 'root' },] } ]; FocusTrapFactory.ctorParameters = function () { return [ { type: InteractivityChecker }, { type: i0.NgZone }, { type: undefined, decorators: [{ type: i0.Inject, args: [i2.DOCUMENT,] }] } ]; }; /** Directive for trapping focus within a region. */ var FocusTrapDirective = /** @class */ (function () { function FocusTrapDirective(_elementRef, _focusTrapFactory, _document) { this._elementRef = _elementRef; this._focusTrapFactory = _focusTrapFactory; /** Previously focused element to restore focus to upon destroy when using autoCapture. */ this._previouslyFocusedElement = null; this._autoCapture = false; this._document = _document; this.focusTrap = this._focusTrapFactory.create(this._elementRef.nativeElement, true); } Object.defineProperty(FocusTrapDirective.prototype, "enabled", { /** Whether the focus trap is active. */ get: function () { return this.focusTrap.enabled; }, set: function (value) { this.focusTrap.enabled = coerceBooleanProperty(value); }, enumerable: false, configurable: true }); Object.defineProperty(FocusTrapDirective.prototype, "autoCapture", { /** * Whether the directive should automatically move focus into the trapped region upon * initialization and return focus to the previous activeElement upon destruction. */ get: function () { return this._autoCapture; }, set: function (value) { this._autoCapture = coerceBooleanProperty(value); }, enumerable: false, configurable: true }); FocusTrapDirective.prototype.ngOnDestroy = function () { this.focusTrap.destroy(); // If we stored a previously focused element when using autoCapture, return focus to that // element now that the trapped region is being destroyed. if (this._previouslyFocusedElement) { this._previouslyFocusedElement.focus(); this._previouslyFocusedElement = null; } }; FocusTrapDirective.prototype.ngAfterContentInit = function () { this.focusTrap.attachAnchors(); if (this.autoCapture) { this._captureFocus(); } }; FocusTrapDirective.prototype.ngDoCheck = function () { if (!this.focusTrap.hasAttached()) { this.focusTrap.attachAnchors(); } }; FocusTrapDirective.prototype.ngOnChanges = function (changes) { var autoCaptureChange = changes['autoCapture']; if (autoCaptureChange && !autoCaptureChange.firstChange && this.autoCapture && this.focusTrap.hasAttached()) { this._captureFocus(); } }; FocusTrapDirective.prototype._captureFocus = function () { this._previouslyFocusedElement = this._document.activeElement; this.focusTrap.focusInitialElementWhenReady(); }; return FocusTrapDirective; }()); FocusTrapDirective.decorators = [ { type: i0.Directive, args: [{ selector: '[focusTrap]', exportAs: 'focusTrap' },] } ]; FocusTrapDirective.ctorParameters = function () { return [ { type: i0.ElementRef }, { type: FocusTrapFactory }, { type: undefined, decorators: [{ type: i0.Inject, args: [i2.DOCUMENT,] }] } ]; }; FocusTrapDirective.propDecorators = { enabled: [{ type: i0.Input, args: ['cdkTrapFocus',] }], autoCapture: [{ type: i0.Input, args: ['cdkTrapFocusAutoCapture',] }] }; var FocusTrapModule = /** @class */ (function () { function FocusTrapModule() { } FocusTrapModule.forRoot = function () { return { ngModule: FocusTrapModule, providers: [ FocusTrapManager, Platform, InteractivityChecker ] }; }; return FocusTrapModule; }()); FocusTrapModule.decorators = [ { type: i0.NgModule, args: [{ imports: [i2.CommonModule], declarations: [FocusTrapDirective], exports: [FocusTrapDirective] },] } ]; /** * Generated bundle index. Do not edit. */ exports.FocusTrap = FocusTrap; exports.FocusTrapDirective = FocusTrapDirective; exports.FocusTrapModule = FocusTrapModule; exports.ɵa = FocusTrapFactory; exports.ɵb = InteractivityChecker; exports.ɵc = Platform; exports.ɵd = FocusTrapManager; Object.defineProperty(exports, '__esModule', { value: true }); }))); //# sourceMappingURL=ngx-bootstrap-focus-trap.umd.js.map