@deepkit/desktop-ui
Version:
Library for desktop UI widgets in Angular 10+
213 lines (183 loc) • 5.96 kB
text/typescript
/*
* Deepkit Framework
* Copyright (C) 2021 Deepkit UG, Marc J. Schmidt
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the MIT License.
*
* You should have received a copy of the MIT License along with this program.
*/
import { booleanAttribute, Component, EventEmitter, HostBinding, HostListener, inject, input, OnDestroy, Output } from '@angular/core';
import { Router, RouterLink, RouterLinkActive } from '@angular/router';
import { ngValueAccessor, ValueAccessorBase } from '../../core/form';
import { arrayRemoveItem } from '@deepkit/core';
import { injectElementRef } from '../app/utils';
/**
* Non-interactive title item for a list.
*
* ```html
* <dui-list>
* <dui-list-title>Title</dui-list-title>
* <dui-list-item value="1">Item 1</dui-list-item>
* </list>
* ```
*/
export class ListTitleComponent {
constructor() {
}
}
export class ListComponent extends ValueAccessorBase<any> {
static ids: number = 0;
id = ++ListComponent.ids;
white = input(false, { transform: booleanAttribute });
focusable = input<boolean>(true);
delimiterLine = input(false, { transform: booleanAttribute });
protected tabIndex: number = 1;
protected items: ListItemComponent[] = [];
protected itemMap = new Map<string, ListItemComponent>();
protected element = injectElementRef();
/**
* @hidden
*/
deregister(item: ListItemComponent) {
arrayRemoveItem(this.items, item);
this.itemMap.delete(item.id + '');
}
/**
* @hidden
*/
register(item: ListItemComponent) {
this.items.push(item);
this.itemMap.set(item.id + '', item);
}
protected getSortedList(): ListItemComponent[] {
const list = Array.from(this.element.nativeElement.querySelectorAll(`dui-list-item[list-id="${this.id}"]`));
return list.map(v => this.itemMap.get(v.getAttribute('list-item-id')!)!);
}
protected async onKeyDown(event: KeyboardEvent) {
if (event.key === 'ArrowDown') {
event.preventDefault();
const selectedItem = this.getSelectedItem();
if (selectedItem) {
const items = this.getSortedList();
const position = items.indexOf(selectedItem);
if (items[position + 1]) {
await items[position + 1].select();
}
}
}
if (event.key === 'ArrowUp') {
event.preventDefault();
const selectedItem = this.getSelectedItem();
if (selectedItem) {
const items = this.getSortedList();
const position = items.indexOf(selectedItem);
if (items[position - 1]) {
await items[position - 1].select();
}
}
}
}
public getSelectedItem(): ListItemComponent | undefined {
for (const item of this.items) {
if (item.isSelected()) {
return item;
}
}
return;
}
}
/**
* Interactive item for a list.
* Supports router links, selection and more.
*
* ```html
* <dui-list>
* <dui-list-item value="1">Item 1</dui-list-item>
* </list>
* ```
*/
export class ListItemComponent implements OnDestroy {
protected static ids: number = 0;
id = ++ListItemComponent.ids;
protected activeClass = 'selected';
value = input<any>();
active = input<boolean>();
/**
* When position is dynamic, it might be handy to define the position
* explicitly to make arrow-up/arrow-down navigation possible.
*/
position = input<number>(0);
onSelect = new EventEmitter<any>();
protected element = injectElementRef();
protected list = inject(ListComponent);
protected router = inject(Router, { optional: true });
protected routerLink = inject(RouterLink, { optional: true });
protected routerLinkActive = inject(RouterLinkActive);
constructor() {
this.element.nativeElement.removeAttribute('tabindex');
this.list.register(this);
}
ngOnDestroy(): void {
this.list.deregister(this);
}
public async select() {
const routerLink = this.routerLink;
if (routerLink && this.router) {
routerLink.onClick(1, false, false, false, false);
} else {
this.list.setValue(this.value());
}
this.onSelect.emit(this.value());
}
public isSelected(): boolean {
const active = this.active();
if (active !== undefined) return active;
const value = this.value();
if (value !== undefined) {
return this.list.value() === value;
}
return this.routerLinkActive.isActive;
}
protected onClick() {
this.list.setValue(this.value());
this.onSelect.emit(this.value());
}
}