UNPKG

igniteui-webcomponents

Version:

Ignite UI for Web Components is a complete library of UI components, giving you the ability to build modern web applications using encapsulation and the concept of reusable components in a dependency-free approach.

256 lines 8.1 kB
import { isLTR } from '../common/util.js'; export const NAVIGATION_KEYS = new Set([ 'down', 'up', 'left', 'right', 'arrowdown', 'arrowup', 'arrowleft', 'arrowright', 'home', 'end', 'space', 'spacebar', ' ', ]); export class IgcTreeNavigationService { constructor(tree, selectionService) { this._focusedItem = null; this._lastFocusedItem = null; this._activeItem = null; this._visibleChildren = []; this._invisibleChildren = new Set(); this._disabledChildren = new Set(); this.tree = tree; this.selectionService = selectionService; } updateVisChild() { this._visibleChildren = this.tree?.items ? this.tree.items.filter((i) => !(this._invisibleChildren.has(i) || this._disabledChildren.has(i))) : []; } get focusedItem() { return this._focusedItem; } focusItem(value, shouldFocus = true) { if (this._focusedItem === value) { return; } this._lastFocusedItem = this._focusedItem; if (this._lastFocusedItem) { this._lastFocusedItem.removeAttribute('tabindex'); } this._focusedItem = value; if (this._focusedItem !== null && shouldFocus) { this._focusedItem.tabIndex = 0; this._focusedItem.focus({ preventScroll: true, }); this._focusedItem.wrapper?.scrollIntoView({ behavior: 'smooth', block: 'nearest', inline: 'nearest', }); } } get activeItem() { return this._activeItem; } setActiveItem(value, shouldEmit = true) { if (this._activeItem === value) { return; } if (this._activeItem && value) { this._activeItem.active = false; } this._activeItem = value; if (this._activeItem) { this._activeItem.active = true; } if (shouldEmit && this._activeItem) { this.tree.emitEvent('igcActiveItem', { detail: this._activeItem }); } } get visibleChildren() { return this._visibleChildren; } update_disabled_cache(item) { if (item.disabled) { this._disabledChildren.add(item); } else { this._disabledChildren.delete(item); } this.updateVisChild(); } delete_item(item) { if (this.activeItem === item) { this.setActiveItem(null); } if (this.focusedItem === item) { this.focusItem(null, false); const firstNotDisableItem = this.tree.items.find((i) => !i.disabled); if (firstNotDisableItem) { firstNotDisableItem.tabIndex = 0; this.focusItem(firstNotDisableItem, false); } } } update_visible_cache(item, expanded, shouldUpdateNestedChildren = true, shouldUpdate = true) { if (expanded && !this._invisibleChildren.has(item)) { item.getChildren()?.forEach((child) => { this._invisibleChildren.delete(child); if (shouldUpdateNestedChildren) { this.update_visible_cache(child, child.expanded, true, false); } }); } else { item .getChildren({ flatten: true }) ?.forEach((c) => this._invisibleChildren.add(c)); } if (shouldUpdate) { this.updateVisChild(); } } setFocusedAndActiveItem(item, isActive = true, shouldFocus = true) { if (isActive) { this.setActiveItem(item); } this.focusItem(item, shouldFocus); } handleKeydown(event) { const key = event.key.toLowerCase(); if (!this.focusedItem) { return; } if (!(NAVIGATION_KEYS.has(key) || key === '*')) { if (key === 'enter') { this.setActiveItem(this.focusedItem); } return; } event.preventDefault(); this.handleNavigation(event); } handleNavigation(event) { switch (event.key.toLowerCase()) { case 'home': this.setFocusedAndActiveItem(this.visibleChildren[0]); break; case 'end': this.setFocusedAndActiveItem(this.visibleChildren[this.visibleChildren.length - 1]); break; case 'arrowleft': case 'left': if (!isLTR(this.tree)) { this.handleArrowRight(); } else { this.handleArrowLeft(); } break; case 'arrowright': case 'right': if (!isLTR(this.tree)) { this.handleArrowLeft(); } else { this.handleArrowRight(); } break; case 'arrowup': case 'up': this.handleUpDownArrow(true, event); break; case 'arrowdown': case 'down': this.handleUpDownArrow(false, event); break; case '*': this.handleAsterisk(); break; case ' ': case 'spacebar': case 'space': this.handleSpace(event.shiftKey); break; default: return; } } handleArrowLeft() { if (this.focusedItem?.expanded && this.focusedItem.getChildren()?.length) { this.setActiveItem(this.focusedItem); this.focusedItem.collapseWithEvent(); } else { const parentItem = this.focusedItem?.parent; if (parentItem && !parentItem.disabled) { this.setFocusedAndActiveItem(parentItem); } } } handleArrowRight() { if (this.focusedItem.getChildren()?.length > 0) { if (!this.focusedItem?.expanded) { this.setActiveItem(this.focusedItem); this.focusedItem.expandWithEvent(); } else { const firstChild = this.focusedItem .getChildren() .find((item) => !item.disabled); if (firstChild) { this.setFocusedAndActiveItem(firstChild); } } } } handleUpDownArrow(isUp, event) { const next = this.getVisibleItem(this.focusedItem, isUp ? -1 : 1); if (next === this.focusedItem) { return; } if (event.ctrlKey) { this.setFocusedAndActiveItem(next, false); } else { this.setFocusedAndActiveItem(next); } } handleAsterisk() { const items = this.focusedItem?.parent ? this.focusedItem.parent?.getChildren() : this.tree.items?.filter((item) => item.level === 0); items?.forEach((item) => { if (!item.disabled && !item.expanded && item.hasChildren) { item.expandWithEvent(); } }); } handleSpace(shiftKey = false) { if (this.tree.selection === 'none') { this.setActiveItem(this.focusedItem); return; } this.setActiveItem(this.focusedItem); if (shiftKey) { this.selectionService.selectMultipleItems(this.focusedItem); return; } if (this.focusedItem.selected) { this.selectionService.deselectItem(this.focusedItem); } else { this.selectionService.selectItem(this.focusedItem); } } getVisibleItem(item, dir = 1) { const itemIndex = this.visibleChildren.indexOf(item); return this.visibleChildren[itemIndex + dir] || item; } } //# sourceMappingURL=tree.navigation.js.map