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
JavaScript
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