UNPKG

@angular/cdk

Version:

Angular Material Component Development Kit

1,005 lines (971 loc) 124 kB
(function (global, factory) { typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports, require('@angular/common'), require('@angular/core'), require('rxjs'), require('@angular/cdk/keycodes'), require('rxjs/operators'), require('@angular/cdk/coercion'), require('@angular/cdk/platform'), require('@angular/cdk/observers')) : typeof define === 'function' && define.amd ? define('@angular/cdk/a11y', ['exports', '@angular/common', '@angular/core', 'rxjs', '@angular/cdk/keycodes', 'rxjs/operators', '@angular/cdk/coercion', '@angular/cdk/platform', '@angular/cdk/observers'], factory) : (global = global || self, factory((global.ng = global.ng || {}, global.ng.cdk = global.ng.cdk || {}, global.ng.cdk.a11y = {}), global.ng.common, global.ng.core, global.rxjs, global.ng.cdk.keycodes, global.rxjs.operators, global.ng.cdk.coercion, global.ng.cdk.platform, global.ng.cdk.observers)); }(this, (function (exports, i2, i0, rxjs, keycodes, operators, coercion, i1, observers) { '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 */ /** IDs are delimited by an empty space, as per the spec. */ var ID_DELIMITER = ' '; /** * Adds the given ID to the specified ARIA attribute on an element. * Used for attributes such as aria-labelledby, aria-owns, etc. */ function addAriaReferencedId(el, attr, id) { var ids = getAriaReferenceIds(el, attr); if (ids.some(function (existingId) { return existingId.trim() == id.trim(); })) { return; } ids.push(id.trim()); el.setAttribute(attr, ids.join(ID_DELIMITER)); } /** * Removes the given ID from the specified ARIA attribute on an element. * Used for attributes such as aria-labelledby, aria-owns, etc. */ function removeAriaReferencedId(el, attr, id) { var ids = getAriaReferenceIds(el, attr); var filteredIds = ids.filter(function (val) { return val != id.trim(); }); if (filteredIds.length) { el.setAttribute(attr, filteredIds.join(ID_DELIMITER)); } else { el.removeAttribute(attr); } } /** * Gets the list of IDs referenced by the given ARIA attribute on an element. * Used for attributes such as aria-labelledby, aria-owns, etc. */ function getAriaReferenceIds(el, attr) { // Get string array of all individual ids (whitespace delimited) in the attribute value return (el.getAttribute(attr) || '').match(/\S+/g) || []; } /** * @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 */ /** ID used for the body container where all messages are appended. */ var MESSAGES_CONTAINER_ID = 'cdk-describedby-message-container'; /** ID prefix used for each created message element. */ var CDK_DESCRIBEDBY_ID_PREFIX = 'cdk-describedby-message'; /** Attribute given to each host element that is described by a message element. */ var CDK_DESCRIBEDBY_HOST_ATTRIBUTE = 'cdk-describedby-host'; /** Global incremental identifier for each registered message element. */ var nextId = 0; /** Global map of all registered message elements that have been placed into the document. */ var messageRegistry = new Map(); /** Container for all registered messages. */ var messagesContainer = null; /** * Utility that creates visually hidden elements with a message content. Useful for elements that * want to use aria-describedby to further describe themselves without adding additional visual * content. */ var AriaDescriber = /** @class */ (function () { function AriaDescriber(_document) { this._document = _document; } /** * Adds to the host element an aria-describedby reference to a hidden element that contains * the message. If the same message has already been registered, then it will reuse the created * message element. */ AriaDescriber.prototype.describe = function (hostElement, message) { if (!this._canBeDescribed(hostElement, message)) { return; } if (typeof message !== 'string') { // We need to ensure that the element has an ID. this._setMessageId(message); messageRegistry.set(message, { messageElement: message, referenceCount: 0 }); } else if (!messageRegistry.has(message)) { this._createMessageElement(message); } if (!this._isElementDescribedByMessage(hostElement, message)) { this._addMessageReference(hostElement, message); } }; /** Removes the host element's aria-describedby reference to the message element. */ AriaDescriber.prototype.removeDescription = function (hostElement, message) { if (!this._isElementNode(hostElement)) { return; } if (this._isElementDescribedByMessage(hostElement, message)) { this._removeMessageReference(hostElement, message); } // If the message is a string, it means that it's one that we created for the // consumer so we can remove it safely, otherwise we should leave it in place. if (typeof message === 'string') { var registeredMessage = messageRegistry.get(message); if (registeredMessage && registeredMessage.referenceCount === 0) { this._deleteMessageElement(message); } } if (messagesContainer && messagesContainer.childNodes.length === 0) { this._deleteMessagesContainer(); } }; /** Unregisters all created message elements and removes the message container. */ AriaDescriber.prototype.ngOnDestroy = function () { var describedElements = this._document.querySelectorAll("[" + CDK_DESCRIBEDBY_HOST_ATTRIBUTE + "]"); for (var i = 0; i < describedElements.length; i++) { this._removeCdkDescribedByReferenceIds(describedElements[i]); describedElements[i].removeAttribute(CDK_DESCRIBEDBY_HOST_ATTRIBUTE); } if (messagesContainer) { this._deleteMessagesContainer(); } messageRegistry.clear(); }; /** * Creates a new element in the visually hidden message container element with the message * as its content and adds it to the message registry. */ AriaDescriber.prototype._createMessageElement = function (message) { var messageElement = this._document.createElement('div'); this._setMessageId(messageElement); messageElement.textContent = message; this._createMessagesContainer(); messagesContainer.appendChild(messageElement); messageRegistry.set(message, { messageElement: messageElement, referenceCount: 0 }); }; /** Assigns a unique ID to an element, if it doesn't have one already. */ AriaDescriber.prototype._setMessageId = function (element) { if (!element.id) { element.id = CDK_DESCRIBEDBY_ID_PREFIX + "-" + nextId++; } }; /** Deletes the message element from the global messages container. */ AriaDescriber.prototype._deleteMessageElement = function (message) { var registeredMessage = messageRegistry.get(message); var messageElement = registeredMessage && registeredMessage.messageElement; if (messagesContainer && messageElement) { messagesContainer.removeChild(messageElement); } messageRegistry.delete(message); }; /** Creates the global container for all aria-describedby messages. */ AriaDescriber.prototype._createMessagesContainer = function () { if (!messagesContainer) { var preExistingContainer = this._document.getElementById(MESSAGES_CONTAINER_ID); // When going from the server to the client, we may end up in a situation where there's // already a container on the page, but we don't have a reference to it. Clear the // old container so we don't get duplicates. Doing this, instead of emptying the previous // container, should be slightly faster. if (preExistingContainer) { preExistingContainer.parentNode.removeChild(preExistingContainer); } messagesContainer = this._document.createElement('div'); messagesContainer.id = MESSAGES_CONTAINER_ID; messagesContainer.setAttribute('aria-hidden', 'true'); messagesContainer.style.display = 'none'; this._document.body.appendChild(messagesContainer); } }; /** Deletes the global messages container. */ AriaDescriber.prototype._deleteMessagesContainer = function () { if (messagesContainer && messagesContainer.parentNode) { messagesContainer.parentNode.removeChild(messagesContainer); messagesContainer = null; } }; /** Removes all cdk-describedby messages that are hosted through the element. */ AriaDescriber.prototype._removeCdkDescribedByReferenceIds = function (element) { // Remove all aria-describedby reference IDs that are prefixed by CDK_DESCRIBEDBY_ID_PREFIX var originalReferenceIds = getAriaReferenceIds(element, 'aria-describedby') .filter(function (id) { return id.indexOf(CDK_DESCRIBEDBY_ID_PREFIX) != 0; }); element.setAttribute('aria-describedby', originalReferenceIds.join(' ')); }; /** * Adds a message reference to the element using aria-describedby and increments the registered * message's reference count. */ AriaDescriber.prototype._addMessageReference = function (element, message) { var registeredMessage = messageRegistry.get(message); // Add the aria-describedby reference and set the // describedby_host attribute to mark the element. addAriaReferencedId(element, 'aria-describedby', registeredMessage.messageElement.id); element.setAttribute(CDK_DESCRIBEDBY_HOST_ATTRIBUTE, ''); registeredMessage.referenceCount++; }; /** * Removes a message reference from the element using aria-describedby * and decrements the registered message's reference count. */ AriaDescriber.prototype._removeMessageReference = function (element, message) { var registeredMessage = messageRegistry.get(message); registeredMessage.referenceCount--; removeAriaReferencedId(element, 'aria-describedby', registeredMessage.messageElement.id); element.removeAttribute(CDK_DESCRIBEDBY_HOST_ATTRIBUTE); }; /** Returns true if the element has been described by the provided message ID. */ AriaDescriber.prototype._isElementDescribedByMessage = function (element, message) { var referenceIds = getAriaReferenceIds(element, 'aria-describedby'); var registeredMessage = messageRegistry.get(message); var messageId = registeredMessage && registeredMessage.messageElement.id; return !!messageId && referenceIds.indexOf(messageId) != -1; }; /** Determines whether a message can be described on a particular element. */ AriaDescriber.prototype._canBeDescribed = function (element, message) { if (!this._isElementNode(element)) { return false; } if (message && typeof message === 'object') { // We'd have to make some assumptions about the description element's text, if the consumer // passed in an element. Assume that if an element is passed in, the consumer has verified // that it can be used as a description. return true; } var trimmedMessage = message == null ? '' : ("" + message).trim(); var ariaLabel = element.getAttribute('aria-label'); // We shouldn't set descriptions if they're exactly the same as the `aria-label` of the // element, because screen readers will end up reading out the same text twice in a row. return trimmedMessage ? (!ariaLabel || ariaLabel.trim() !== trimmedMessage) : false; }; /** Checks whether a node is an Element node. */ AriaDescriber.prototype._isElementNode = function (element) { return element.nodeType === this._document.ELEMENT_NODE; }; AriaDescriber.ɵprov = i0.ɵɵdefineInjectable({ factory: function AriaDescriber_Factory() { return new AriaDescriber(i0.ɵɵinject(i2.DOCUMENT)); }, token: AriaDescriber, providedIn: "root" }); AriaDescriber.decorators = [ { type: i0.Injectable, args: [{ providedIn: 'root' },] } ]; AriaDescriber.ctorParameters = function () { return [ { type: undefined, decorators: [{ type: i0.Inject, args: [i2.DOCUMENT,] }] } ]; }; return AriaDescriber; }()); /*! ***************************************************************************** Copyright (c) Microsoft Corporation. Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted. THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. ***************************************************************************** */ /* global Reflect, Promise */ var extendStatics = function(d, b) { extendStatics = Object.setPrototypeOf || ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) || function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; }; return extendStatics(d, b); }; function __extends(d, b) { extendStatics(d, b); function __() { this.constructor = d; } d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __()); } var __assign = function() { __assign = Object.assign || function __assign(t) { for (var s, i = 1, n = arguments.length; i < n; i++) { s = arguments[i]; for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p)) t[p] = s[p]; } return t; }; return __assign.apply(this, arguments); }; function __rest(s, e) { var t = {}; for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0) t[p] = s[p]; if (s != null && typeof Object.getOwnPropertySymbols === "function") for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) { if (e.indexOf(p[i]) < 0 && Object.prototype.propertyIsEnumerable.call(s, p[i])) t[p[i]] = s[p[i]]; } return t; } function __decorate(decorators, target, key, desc) { var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d; if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc); else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r; return c > 3 && r && Object.defineProperty(target, key, r), r; } function __param(paramIndex, decorator) { return function (target, key) { decorator(target, key, paramIndex); } } function __metadata(metadataKey, metadataValue) { if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(metadataKey, metadataValue); } function __awaiter(thisArg, _arguments, P, generator) { function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } return new (P || (P = Promise))(function (resolve, reject) { function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } step((generator = generator.apply(thisArg, _arguments || [])).next()); }); } function __generator(thisArg, body) { var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g; return g = { next: verb(0), "throw": verb(1), "return": verb(2) }, typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g; function verb(n) { return function (v) { return step([n, v]); }; } function step(op) { if (f) throw new TypeError("Generator is already executing."); while (_) try { if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t; if (y = 0, t) op = [op[0] & 2, t.value]; switch (op[0]) { case 0: case 1: t = op; break; case 4: _.label++; return { value: op[1], done: false }; case 5: _.label++; y = op[1]; op = [0]; continue; case 7: op = _.ops.pop(); _.trys.pop(); continue; default: if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; } if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; } if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; } if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; } if (t[2]) _.ops.pop(); _.trys.pop(); continue; } op = body.call(thisArg, _); } catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; } if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true }; } } var __createBinding = Object.create ? (function(o, m, k, k2) { if (k2 === undefined) k2 = k; Object.defineProperty(o, k2, { enumerable: true, get: function() { return m[k]; } }); }) : (function(o, m, k, k2) { if (k2 === undefined) k2 = k; o[k2] = m[k]; }); function __exportStar(m, exports) { for (var p in m) if (p !== "default" && !exports.hasOwnProperty(p)) __createBinding(exports, m, p); } function __values(o) { var s = typeof Symbol === "function" && Symbol.iterator, m = s && o[s], i = 0; if (m) return m.call(o); if (o && typeof o.length === "number") return { next: function () { if (o && i >= o.length) o = void 0; return { value: o && o[i++], done: !o }; } }; throw new TypeError(s ? "Object is not iterable." : "Symbol.iterator is not defined."); } function __read(o, n) { var m = typeof Symbol === "function" && o[Symbol.iterator]; if (!m) return o; var i = m.call(o), r, ar = [], e; try { while ((n === void 0 || n-- > 0) && !(r = i.next()).done) ar.push(r.value); } catch (error) { e = { error: error }; } finally { try { if (r && !r.done && (m = i["return"])) m.call(i); } finally { if (e) throw e.error; } } return ar; } function __spread() { for (var ar = [], i = 0; i < arguments.length; i++) ar = ar.concat(__read(arguments[i])); return ar; } function __spreadArrays() { for (var s = 0, i = 0, il = arguments.length; i < il; i++) s += arguments[i].length; for (var r = Array(s), k = 0, i = 0; i < il; i++) for (var a = arguments[i], j = 0, jl = a.length; j < jl; j++, k++) r[k] = a[j]; return r; }; function __await(v) { return this instanceof __await ? (this.v = v, this) : new __await(v); } function __asyncGenerator(thisArg, _arguments, generator) { if (!Symbol.asyncIterator) throw new TypeError("Symbol.asyncIterator is not defined."); var g = generator.apply(thisArg, _arguments || []), i, q = []; return i = {}, verb("next"), verb("throw"), verb("return"), i[Symbol.asyncIterator] = function () { return this; }, i; function verb(n) { if (g[n]) i[n] = function (v) { return new Promise(function (a, b) { q.push([n, v, a, b]) > 1 || resume(n, v); }); }; } function resume(n, v) { try { step(g[n](v)); } catch (e) { settle(q[0][3], e); } } function step(r) { r.value instanceof __await ? Promise.resolve(r.value.v).then(fulfill, reject) : settle(q[0][2], r); } function fulfill(value) { resume("next", value); } function reject(value) { resume("throw", value); } function settle(f, v) { if (f(v), q.shift(), q.length) resume(q[0][0], q[0][1]); } } function __asyncDelegator(o) { var i, p; return i = {}, verb("next"), verb("throw", function (e) { throw e; }), verb("return"), i[Symbol.iterator] = function () { return this; }, i; function verb(n, f) { i[n] = o[n] ? function (v) { return (p = !p) ? { value: __await(o[n](v)), done: n === "return" } : f ? f(v) : v; } : f; } } function __asyncValues(o) { if (!Symbol.asyncIterator) throw new TypeError("Symbol.asyncIterator is not defined."); var m = o[Symbol.asyncIterator], i; return m ? m.call(o) : (o = typeof __values === "function" ? __values(o) : o[Symbol.iterator](), i = {}, verb("next"), verb("throw"), verb("return"), i[Symbol.asyncIterator] = function () { return this; }, i); function verb(n) { i[n] = o[n] && function (v) { return new Promise(function (resolve, reject) { v = o[n](v), settle(resolve, reject, v.done, v.value); }); }; } function settle(resolve, reject, d, v) { Promise.resolve(v).then(function(v) { resolve({ value: v, done: d }); }, reject); } } function __makeTemplateObject(cooked, raw) { if (Object.defineProperty) { Object.defineProperty(cooked, "raw", { value: raw }); } else { cooked.raw = raw; } return cooked; }; var __setModuleDefault = Object.create ? (function(o, v) { Object.defineProperty(o, "default", { enumerable: true, value: v }); }) : function(o, v) { o["default"] = v; }; function __importStar(mod) { if (mod && mod.__esModule) return mod; var result = {}; if (mod != null) for (var k in mod) if (Object.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k); __setModuleDefault(result, mod); return result; } function __importDefault(mod) { return (mod && mod.__esModule) ? mod : { default: mod }; } function __classPrivateFieldGet(receiver, privateMap) { if (!privateMap.has(receiver)) { throw new TypeError("attempted to get private field on non-instance"); } return privateMap.get(receiver); } function __classPrivateFieldSet(receiver, privateMap, value) { if (!privateMap.has(receiver)) { throw new TypeError("attempted to set private field on non-instance"); } privateMap.set(receiver, value); return value; } /** * @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 */ /** * This class manages keyboard events for selectable lists. If you pass it a query list * of items, it will set the active item correctly when arrow events occur. */ var ListKeyManager = /** @class */ (function () { function ListKeyManager(_items) { var _this = this; this._items = _items; this._activeItemIndex = -1; this._activeItem = null; this._wrap = false; this._letterKeyStream = new rxjs.Subject(); this._typeaheadSubscription = rxjs.Subscription.EMPTY; this._vertical = true; this._allowedModifierKeys = []; /** * Predicate function that can be used to check whether an item should be skipped * by the key manager. By default, disabled items are skipped. */ this._skipPredicateFn = function (item) { return item.disabled; }; // Buffer for the letters that the user has pressed when the typeahead option is turned on. this._pressedLetters = []; /** * Stream that emits any time the TAB key is pressed, so components can react * when focus is shifted off of the list. */ this.tabOut = new rxjs.Subject(); /** Stream that emits whenever the active item of the list manager changes. */ this.change = new rxjs.Subject(); // We allow for the items to be an array because, in some cases, the consumer may // not have access to a QueryList of the items they want to manage (e.g. when the // items aren't being collected via `ViewChildren` or `ContentChildren`). if (_items instanceof i0.QueryList) { _items.changes.subscribe(function (newItems) { if (_this._activeItem) { var itemArray = newItems.toArray(); var newIndex = itemArray.indexOf(_this._activeItem); if (newIndex > -1 && newIndex !== _this._activeItemIndex) { _this._activeItemIndex = newIndex; } } }); } } /** * Sets the predicate function that determines which items should be skipped by the * list key manager. * @param predicate Function that determines whether the given item should be skipped. */ ListKeyManager.prototype.skipPredicate = function (predicate) { this._skipPredicateFn = predicate; return this; }; /** * Configures wrapping mode, which determines whether the active item will wrap to * the other end of list when there are no more items in the given direction. * @param shouldWrap Whether the list should wrap when reaching the end. */ ListKeyManager.prototype.withWrap = function (shouldWrap) { if (shouldWrap === void 0) { shouldWrap = true; } this._wrap = shouldWrap; return this; }; /** * Configures whether the key manager should be able to move the selection vertically. * @param enabled Whether vertical selection should be enabled. */ ListKeyManager.prototype.withVerticalOrientation = function (enabled) { if (enabled === void 0) { enabled = true; } this._vertical = enabled; return this; }; /** * Configures the key manager to move the selection horizontally. * Passing in `null` will disable horizontal movement. * @param direction Direction in which the selection can be moved. */ ListKeyManager.prototype.withHorizontalOrientation = function (direction) { this._horizontal = direction; return this; }; /** * Modifier keys which are allowed to be held down and whose default actions will be prevented * as the user is pressing the arrow keys. Defaults to not allowing any modifier keys. */ ListKeyManager.prototype.withAllowedModifierKeys = function (keys) { this._allowedModifierKeys = keys; return this; }; /** * Turns on typeahead mode which allows users to set the active item by typing. * @param debounceInterval Time to wait after the last keystroke before setting the active item. */ ListKeyManager.prototype.withTypeAhead = function (debounceInterval) { var _this = this; if (debounceInterval === void 0) { debounceInterval = 200; } if (this._items.length && this._items.some(function (item) { return typeof item.getLabel !== 'function'; })) { throw Error('ListKeyManager items in typeahead mode must implement the `getLabel` method.'); } this._typeaheadSubscription.unsubscribe(); // Debounce the presses of non-navigational keys, collect the ones that correspond to letters // and convert those letters back into a string. Afterwards find the first item that starts // with that string and select it. this._typeaheadSubscription = this._letterKeyStream.pipe(operators.tap(function (letter) { return _this._pressedLetters.push(letter); }), operators.debounceTime(debounceInterval), operators.filter(function () { return _this._pressedLetters.length > 0; }), operators.map(function () { return _this._pressedLetters.join(''); })).subscribe(function (inputString) { var items = _this._getItemsArray(); // Start at 1 because we want to start searching at the item immediately // following the current active item. for (var i = 1; i < items.length + 1; i++) { var index = (_this._activeItemIndex + i) % items.length; var item = items[index]; if (!_this._skipPredicateFn(item) && item.getLabel().toUpperCase().trim().indexOf(inputString) === 0) { _this.setActiveItem(index); break; } } _this._pressedLetters = []; }); return this; }; ListKeyManager.prototype.setActiveItem = function (item) { var previousActiveItem = this._activeItem; this.updateActiveItem(item); if (this._activeItem !== previousActiveItem) { this.change.next(this._activeItemIndex); } }; /** * Sets the active item depending on the key event passed in. * @param event Keyboard event to be used for determining which element should be active. */ ListKeyManager.prototype.onKeydown = function (event) { var _this = this; var keyCode = event.keyCode; var modifiers = ['altKey', 'ctrlKey', 'metaKey', 'shiftKey']; var isModifierAllowed = modifiers.every(function (modifier) { return !event[modifier] || _this._allowedModifierKeys.indexOf(modifier) > -1; }); switch (keyCode) { case keycodes.TAB: this.tabOut.next(); return; case keycodes.DOWN_ARROW: if (this._vertical && isModifierAllowed) { this.setNextItemActive(); break; } else { return; } case keycodes.UP_ARROW: if (this._vertical && isModifierAllowed) { this.setPreviousItemActive(); break; } else { return; } case keycodes.RIGHT_ARROW: if (this._horizontal && isModifierAllowed) { this._horizontal === 'rtl' ? this.setPreviousItemActive() : this.setNextItemActive(); break; } else { return; } case keycodes.LEFT_ARROW: if (this._horizontal && isModifierAllowed) { this._horizontal === 'rtl' ? this.setNextItemActive() : this.setPreviousItemActive(); break; } else { return; } default: if (isModifierAllowed || keycodes.hasModifierKey(event, 'shiftKey')) { // Attempt to use the `event.key` which also maps it to the user's keyboard language, // otherwise fall back to resolving alphanumeric characters via the keyCode. if (event.key && event.key.length === 1) { this._letterKeyStream.next(event.key.toLocaleUpperCase()); } else if ((keyCode >= keycodes.A && keyCode <= keycodes.Z) || (keyCode >= keycodes.ZERO && keyCode <= keycodes.NINE)) { this._letterKeyStream.next(String.fromCharCode(keyCode)); } } // Note that we return here, in order to avoid preventing // the default action of non-navigational keys. return; } this._pressedLetters = []; event.preventDefault(); }; Object.defineProperty(ListKeyManager.prototype, "activeItemIndex", { /** Index of the currently active item. */ get: function () { return this._activeItemIndex; }, enumerable: false, configurable: true }); Object.defineProperty(ListKeyManager.prototype, "activeItem", { /** The active item. */ get: function () { return this._activeItem; }, enumerable: false, configurable: true }); /** Gets whether the user is currently typing into the manager using the typeahead feature. */ ListKeyManager.prototype.isTyping = function () { return this._pressedLetters.length > 0; }; /** Sets the active item to the first enabled item in the list. */ ListKeyManager.prototype.setFirstItemActive = function () { this._setActiveItemByIndex(0, 1); }; /** Sets the active item to the last enabled item in the list. */ ListKeyManager.prototype.setLastItemActive = function () { this._setActiveItemByIndex(this._items.length - 1, -1); }; /** Sets the active item to the next enabled item in the list. */ ListKeyManager.prototype.setNextItemActive = function () { this._activeItemIndex < 0 ? this.setFirstItemActive() : this._setActiveItemByDelta(1); }; /** Sets the active item to a previous enabled item in the list. */ ListKeyManager.prototype.setPreviousItemActive = function () { this._activeItemIndex < 0 && this._wrap ? this.setLastItemActive() : this._setActiveItemByDelta(-1); }; ListKeyManager.prototype.updateActiveItem = function (item) { var itemArray = this._getItemsArray(); var index = typeof item === 'number' ? item : itemArray.indexOf(item); var activeItem = itemArray[index]; // Explicitly check for `null` and `undefined` because other falsy values are valid. this._activeItem = activeItem == null ? null : activeItem; this._activeItemIndex = index; }; /** * This method sets the active item, given a list of items and the delta between the * currently active item and the new active item. It will calculate differently * depending on whether wrap mode is turned on. */ ListKeyManager.prototype._setActiveItemByDelta = function (delta) { this._wrap ? this._setActiveInWrapMode(delta) : this._setActiveInDefaultMode(delta); }; /** * Sets the active item properly given "wrap" mode. In other words, it will continue to move * down the list until it finds an item that is not disabled, and it will wrap if it * encounters either end of the list. */ ListKeyManager.prototype._setActiveInWrapMode = function (delta) { var items = this._getItemsArray(); for (var i = 1; i <= items.length; i++) { var index = (this._activeItemIndex + (delta * i) + items.length) % items.length; var item = items[index]; if (!this._skipPredicateFn(item)) { this.setActiveItem(index); return; } } }; /** * Sets the active item properly given the default mode. In other words, it will * continue to move down the list until it finds an item that is not disabled. If * it encounters either end of the list, it will stop and not wrap. */ ListKeyManager.prototype._setActiveInDefaultMode = function (delta) { this._setActiveItemByIndex(this._activeItemIndex + delta, delta); }; /** * Sets the active item to the first enabled item starting at the index specified. If the * item is disabled, it will move in the fallbackDelta direction until it either * finds an enabled item or encounters the end of the list. */ ListKeyManager.prototype._setActiveItemByIndex = function (index, fallbackDelta) { var items = this._getItemsArray(); if (!items[index]) { return; } while (this._skipPredicateFn(items[index])) { index += fallbackDelta; if (!items[index]) { return; } } this.setActiveItem(index); }; /** Returns the items as an array. */ ListKeyManager.prototype._getItemsArray = function () { return this._items instanceof i0.QueryList ? this._items.toArray() : this._items; }; return ListKeyManager; }()); /** * @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 */ var ActiveDescendantKeyManager = /** @class */ (function (_super) { __extends(ActiveDescendantKeyManager, _super); function ActiveDescendantKeyManager() { return _super !== null && _super.apply(this, arguments) || this; } ActiveDescendantKeyManager.prototype.setActiveItem = function (index) { if (this.activeItem) { this.activeItem.setInactiveStyles(); } _super.prototype.setActiveItem.call(this, index); if (this.activeItem) { this.activeItem.setActiveStyles(); } }; return ActiveDescendantKeyManager; }(ListKeyManager)); /** * @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 */ var FocusKeyManager = /** @class */ (function (_super) { __extends(FocusKeyManager, _super); function FocusKeyManager() { var _this = _super !== null && _super.apply(this, arguments) || this; _this._origin = 'program'; return _this; } /** * Sets the focus origin that will be passed in to the items for any subsequent `focus` calls. * @param origin Focus origin to be used when focusing items. */ FocusKeyManager.prototype.setFocusOrigin = function (origin) { this._origin = origin; return this; }; FocusKeyManager.prototype.setActiveItem = function (item) { _super.prototype.setActiveItem.call(this, item); if (this.activeItem) { this.activeItem.focus(this._origin); } }; return FocusKeyManager; }(ListKeyManager)); /** * @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 */ // 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) { var frameType = frameElement && frameElement.nodeName.toLowerCase(); // Frame elements inherit their tabindex onto all child elements. if (getTabIndexValue(frameElement) === -1) { return false; } // Webkit and Blink consider anything inside of an <object> element as non-tabbable. if ((this._platform.BLINK || this._platform.WEBKIT) && frameType === 'object') { return false; } // Webkit and Blink disable tabbing to an element inside of an invisible frame. if ((this._platform.BLINK || this._platform.WEBKIT) && !this.isVisible(frameElement)) { return false; } } var nodeName = element.nodeName.toLowerCase(); var tabIndexValue = getTabIndexValue(element); if (element.hasAttribute('contenteditable')) { return tabIndexValue !== -1; } if (nodeName === 'iframe') { // The frames may be tabbable depending on content, but it's not possibly to reliably // investigate the content of the frames. return false; } if (nodeName === 'audio') { if (!element.hasAttribute('controls')) { // By default an <audio> element without the controls enabled is not tabbable. return false; } else if (this._platform.BLINK) { // In Blink <audio controls> elements are always tabbable. return true; } } if (nodeName === 'video') { if (!element.hasAttribute('controls') && this._platform.TRIDENT) { // In Trident a <video> element without the controls enabled is not tabbable. return false; } else if (this._platform.BLINK || this._platform.FIREFOX) { // In Chrome and Firefox <video controls> elements are always tabbable. return true; } } if (nodeName === 'object' && (this._platform.BLINK || this._platform.WEBKIT)) { // In all Blink and WebKit based browsers <object> elements are never 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; } return element.tabIndex >= 0; }; /** * Gets whether an element can be focused by the user. * * @param element Element to be checked. * @returns Whether the element is focusable. */ InteractivityChecker.prototype.isFocusable = function (element) { // 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) && this.isVisible(element); }; InteractivityChecker.ɵprov = i0.ɵɵdefineInjectable({ factory: function InteractivityChecker_Factory() { return new InteractivityChecker(i0.ɵɵinject(i1.Platform)); }, token: InteractivityChecker, providedIn: "root" }); InteractivityChecker.decorators = [ { type: i0.Injectable, args: [{ providedIn: 'root' },] } ]; InteractivityChecker.ctorParameters = function () { return [ { type: i1.Platform } ]; }; return InteractivityChecker; }()); /** * 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