@deepkit/desktop-ui
Version:
Library for desktop UI widgets in Angular 10+
240 lines (206 loc) • 6.85 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 {
AfterViewInit,
ChangeDetectorRef,
Component,
ContentChild,
ContentChildren,
Directive,
ElementRef,
HostBinding,
HostListener,
Injector,
Input,
OnChanges,
OnDestroy,
QueryList,
SimpleChanges,
SkipSelf,
TemplateRef,
ViewChild,
} from '@angular/core';
import { Subscription } from 'rxjs';
import { ngValueAccessor, ValueAccessorBase } from '../../core/form';
import { Overlay } from '@angular/cdk/overlay';
import { DropdownComponent } from '../button/dropdown.component';
import { ButtonComponent } from '../button/button.component';
/**
* Necessary directive to get a dynamic rendered option.
*
* ```html
* <dui-option>
* <ng-container *dynamicOption>
* {{item.fieldName | date}}
* </ng-container>
* </dui-option>
* ```
*/
export class DynamicOptionDirective {
constructor(
public template: TemplateRef<any>
) {
}
}
export class OptionDirective {
value: any;
disabled: boolean = false;
dynamic?: DynamicOptionDirective;
constructor(public readonly element: ElementRef) {
}
}
export class OptionSeparatorDirective {
constructor() {
}
}
class NotSelected {
}
export class SelectboxComponent<T> extends ValueAccessorBase<T | NotSelected> implements AfterViewInit, OnDestroy, OnChanges {
placeholder: string = '';
/**
* Different textured styled.
*/
textured: boolean | '' = false;
/**
* Smaller text and height.
*/
small: boolean | '' = false;
button?: ButtonComponent;
options?: QueryList<OptionDirective>;
dropdown!: DropdownComponent;
public label: string = '';
public optionsValueMap = new Map<T | NotSelected, OptionDirective>();
protected changeSubscription?: Subscription;
constructor(
protected overlay: Overlay,
protected injector: Injector,
public element: ElementRef,
public readonly cd: ChangeDetectorRef,
public readonly cdParent: ChangeDetectorRef,
) {
super(injector, cd, cdParent);
this.innerValue = new NotSelected;
}
isSeparator(item: any): boolean {
return item instanceof OptionSeparatorDirective;
}
ngAfterViewInit(): void {
if (this.options) {
this.changeSubscription = this.options.changes.subscribe(() => this.updateMap());
setTimeout(() => {
this.updateMap();
});
}
}
public select(value: T) {
this.innerValue = value;
this.touch();
this.dropdown.close();
}
public onClick() {
if (this.disabled) return;
if (this.button) return;
this.dropdown.toggle();
}
ngOnChanges(changes: SimpleChanges) {
}
open() {
if (this.dropdown) this.dropdown.open();
}
writeValue(value?: T | NotSelected): void {
super.writeValue(value);
}
get isSelected(): boolean {
return !(this.innerValue instanceof NotSelected);
}
protected updateMap() {
this.optionsValueMap.clear();
if (!this.options) return;
for (const option of this.options.toArray()) {
this.optionsValueMap.set(option.value, option);
}
this.cd.detectChanges();
}
ngOnDestroy(): void {
if (this.changeSubscription) {
this.changeSubscription.unsubscribe();
}
}
}