@angular/cdk
Version:
Angular Material Component Development Kit
89 lines (86 loc) • 3.77 kB
JavaScript
import { Subject } from 'rxjs';
import { tap, debounceTime, filter, map } from 'rxjs/operators';
import { A, Z, b as ZERO, N as NINE } from './keycodes-CpHkExLC.mjs';
const DEFAULT_TYPEAHEAD_DEBOUNCE_INTERVAL_MS = 200;
/**
* Selects items based on keyboard inputs. Implements the typeahead functionality of
* `role="listbox"` or `role="tree"` and other related roles.
*/
class Typeahead {
_letterKeyStream = new Subject();
_items = [];
_selectedItemIndex = -1;
/** Buffer for the letters that the user has pressed */
_pressedLetters = [];
_skipPredicateFn;
_selectedItem = new Subject();
selectedItem = this._selectedItem;
constructor(initialItems, config) {
const typeAheadInterval = typeof config?.debounceInterval === 'number'
? config.debounceInterval
: DEFAULT_TYPEAHEAD_DEBOUNCE_INTERVAL_MS;
if (config?.skipPredicate) {
this._skipPredicateFn = config.skipPredicate;
}
if ((typeof ngDevMode === 'undefined' || ngDevMode) &&
initialItems.length &&
initialItems.some(item => typeof item.getLabel !== 'function')) {
throw new Error('KeyManager items in typeahead mode must implement the `getLabel` method.');
}
this.setItems(initialItems);
this._setupKeyHandler(typeAheadInterval);
}
destroy() {
this._pressedLetters = [];
this._letterKeyStream.complete();
this._selectedItem.complete();
}
setCurrentSelectedItemIndex(index) {
this._selectedItemIndex = index;
}
setItems(items) {
this._items = items;
}
handleKey(event) {
const keyCode = event.keyCode;
// 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 >= A && keyCode <= Z) || (keyCode >= ZERO && keyCode <= NINE)) {
this._letterKeyStream.next(String.fromCharCode(keyCode));
}
}
/** Gets whether the user is currently typing into the manager using the typeahead feature. */
isTyping() {
return this._pressedLetters.length > 0;
}
/** Resets the currently stored sequence of typed letters. */
reset() {
this._pressedLetters = [];
}
_setupKeyHandler(typeAheadInterval) {
// 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._letterKeyStream
.pipe(tap(letter => this._pressedLetters.push(letter)), debounceTime(typeAheadInterval), filter(() => this._pressedLetters.length > 0), map(() => this._pressedLetters.join('').toLocaleUpperCase()))
.subscribe(inputString => {
// Start at 1 because we want to start searching at the item immediately
// following the current active item.
for (let i = 1; i < this._items.length + 1; i++) {
const index = (this._selectedItemIndex + i) % this._items.length;
const item = this._items[index];
if (!this._skipPredicateFn?.(item) &&
item.getLabel?.().toLocaleUpperCase().trim().indexOf(inputString) === 0) {
this._selectedItem.next(item);
break;
}
}
this._pressedLetters = [];
});
}
}
export { Typeahead as T };
//# sourceMappingURL=typeahead-9ZW4Dtsf.mjs.map