@obliczeniowo/elementary
Version:
Library made in Angular version 20
434 lines (425 loc) • 24.8 kB
JavaScript
import { NG_VALUE_ACCESSOR, FormsModule, ReactiveFormsModule } from '@angular/forms';
import * as i0 from '@angular/core';
import { EventEmitter, Output, Input, Component, ContentChild, NgModule } from '@angular/core';
import * as i1 from '@angular/common';
import { CommonModule } from '@angular/common';
import * as i3$1 from '@angular/cdk/overlay';
import { OverlayModule } from '@angular/cdk/overlay';
import * as i4 from '@obliczeniowo/elementary/loading';
import { LoadingModule } from '@obliczeniowo/elementary/loading';
import * as i3 from '@obliczeniowo/elementary/buttons';
import { ButtonsModule } from '@obliczeniowo/elementary/buttons';
import * as i2 from '@obliczeniowo/elementary/icons';
import { IconsModule } from '@obliczeniowo/elementary/icons';
import { of, BehaviorSubject, finalize, map } from 'rxjs';
class AbstractValueSetModel {
set = [];
max = 12;
columns = 3;
loading = false;
nextDisabled() {
return of(undefined);
}
previousDisabled() {
return of(undefined);
}
decreaseDisabled(current) {
return current === this.set[0];
}
increaseDisabled(current) {
return current === (this.set && this.set[this.set.length - 1]);
}
selected(item, current) {
return current === item;
}
}
class ValueSetStaticModel extends AbstractValueSetModel {
offset = 0;
init(current) {
this.offset = current && Math.floor((this.set.indexOf(current) || 0) / this.max) || 0;
return of();
}
displayNextPrevious() {
return of(this.set.length > this.max);
}
getNextSet() {
const offset = this.offset + 1;
if (offset * this.max < this.set.length - 1) {
this.offset = offset;
return of(true);
}
return of(false);
}
getPreviousSet() {
if (this.offset) {
this.offset = this.offset - 1;
return of(true);
}
return of(false);
}
getCurrentSet() {
return of(this.set.slice(this.offset * this.max, (this.offset + 1) * this.max));
}
next(current) {
if (!this.set) {
return of();
}
if (current) {
const index = this.set.findIndex(item => item === current);
return of(this.set[Math.min(index + 1, this.set.length - 1)]);
}
else if (!current) {
return of(this.set && this.set[this.set.length - 1]);
}
return of();
}
previous(current) {
if (!this.set) {
return of();
}
if (current) {
const index = this.set.findIndex(item => item === current);
return of(this.set[Math.max(index - 1, 0)]);
}
else if (!current) {
return of(this.set?.[0]);
}
return of();
}
nextDisabled() {
return of(this.max * this.offset + this.max >= (this.set.length || 0));
}
previousDisabled() {
return of(!this.offset || undefined);
}
}
class ValuesSetComponent {
/**
* Input item that can have external optional data, must be the same reference object as one exist on items table
*/
current;
model = new ValueSetStaticModel();
itemRef;
selected = new EventEmitter();
next = new EventEmitter();
previous = new EventEmitter();
ngOnInit() {
this.model.init(this.current);
}
setOffset(type) {
(type === 'next' && this.model.getNextSet() || this.model.getPreviousSet()).subscribe(resp => {
if (resp) {
this[type].emit();
}
});
}
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.0.4", ngImport: i0, type: ValuesSetComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.0.4", type: ValuesSetComponent, isStandalone: false, selector: "obl-values-set", inputs: { current: "current", model: "model", itemRef: "itemRef" }, outputs: { selected: "selected", next: "next", previous: "previous" }, ngImport: i0, template: "@if (!model.loading) {\n @if (model.displayNextPrevious() | async) {\n <div class=\"navigation\">\n <button\n oblButton\n (click)=\"setOffset('previous')\"\n [disabled]=\"model.previousDisabled() | async\"\n >\n <obl-icon [name]=\"'left'\"></obl-icon>\n </button>\n <button\n oblButton\n (click)=\"setOffset('next')\"\n [disabled]=\"model.nextDisabled() | async\"\n >\n <obl-icon [name]=\"'right'\"></obl-icon>\n </button>\n </div>\n }\n <div class=\"items\">\n <ng-container>\n @for (item of model.getCurrentSet() | async; track item) {\n <button\n oblButton\n [selected]=\"model.selected(item, current)\"\n [style.width]=\"'calc(100% / ' + model.columns + ')'\"\n (click)=\"selected.emit(item)\"\n >\n <ng-container\n *ngTemplateOutlet=\"\n itemRef || defaultRef;\n context: { $implicit: item }\n \"\n ></ng-container>\n </button>\n }\n </ng-container>\n </div>\n} @else {\n <div class=\"loading\">\n <obl-spinner></obl-spinner>\n </div>\n}\n\n<ng-template let-item #defaultRef>\n {{ item?.value.toString() }}\n</ng-template>\n\n", styles: [":host{display:flex;flex-wrap:wrap;max-width:100%;width:300px;border-radius:5px;overflow:hidden;background-color:var(--obl-button-background-color, #d4d4d4);box-shadow:0 0 4px gray}:host .navigation{display:flex;flex-direction:row;width:100%;justify-content:right}:host .navigation button{--obl-default-button-padding: 5px}.items{display:flex;flex-wrap:wrap;max-width:100%;justify-items:stretch;width:300px}.items button{font-size:var(--obl-font-size, 16px);--obl-default-button-padding: 10px;border-radius:5px}.items button div{padding:var(--obl-default-button-padding)}.loading{display:flex;justify-content:center;width:100%}.loading obl-spinner{--obl-spinner-width: 80px;--obl-spinner-color: gray;display:block;margin:20px auto}\n"], dependencies: [{ kind: "directive", type: i1.NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "component", type: i2.IconComponent, selector: "obl-icon", inputs: ["name", "width"] }, { kind: "directive", type: i3.ButtonDirective, selector: "oblButton, [oblButton]", inputs: ["oblButton", "icon", "blockWhenLoading", "loading", "toggle", "selected", "link", "target"], exportAs: ["oblButton"] }, { kind: "component", type: i4.SpinnerComponent, selector: "obl-spinner" }, { kind: "pipe", type: i1.AsyncPipe, name: "async" }] });
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.0.4", ngImport: i0, type: ValuesSetComponent, decorators: [{
type: Component,
args: [{ selector: 'obl-values-set', standalone: false, template: "@if (!model.loading) {\n @if (model.displayNextPrevious() | async) {\n <div class=\"navigation\">\n <button\n oblButton\n (click)=\"setOffset('previous')\"\n [disabled]=\"model.previousDisabled() | async\"\n >\n <obl-icon [name]=\"'left'\"></obl-icon>\n </button>\n <button\n oblButton\n (click)=\"setOffset('next')\"\n [disabled]=\"model.nextDisabled() | async\"\n >\n <obl-icon [name]=\"'right'\"></obl-icon>\n </button>\n </div>\n }\n <div class=\"items\">\n <ng-container>\n @for (item of model.getCurrentSet() | async; track item) {\n <button\n oblButton\n [selected]=\"model.selected(item, current)\"\n [style.width]=\"'calc(100% / ' + model.columns + ')'\"\n (click)=\"selected.emit(item)\"\n >\n <ng-container\n *ngTemplateOutlet=\"\n itemRef || defaultRef;\n context: { $implicit: item }\n \"\n ></ng-container>\n </button>\n }\n </ng-container>\n </div>\n} @else {\n <div class=\"loading\">\n <obl-spinner></obl-spinner>\n </div>\n}\n\n<ng-template let-item #defaultRef>\n {{ item?.value.toString() }}\n</ng-template>\n\n", styles: [":host{display:flex;flex-wrap:wrap;max-width:100%;width:300px;border-radius:5px;overflow:hidden;background-color:var(--obl-button-background-color, #d4d4d4);box-shadow:0 0 4px gray}:host .navigation{display:flex;flex-direction:row;width:100%;justify-content:right}:host .navigation button{--obl-default-button-padding: 5px}.items{display:flex;flex-wrap:wrap;max-width:100%;justify-items:stretch;width:300px}.items button{font-size:var(--obl-font-size, 16px);--obl-default-button-padding: 10px;border-radius:5px}.items button div{padding:var(--obl-default-button-padding)}.loading{display:flex;justify-content:center;width:100%}.loading obl-spinner{--obl-spinner-width: 80px;--obl-spinner-color: gray;display:block;margin:20px auto}\n"] }]
}], propDecorators: { current: [{
type: Input
}], model: [{
type: Input
}], itemRef: [{
type: Input
}], selected: [{
type: Output
}], next: [{
type: Output
}], previous: [{
type: Output
}] } });
class ValuePickerComponent {
_current;
/**
* Input item that can have external optional data, must be the same reference object as one exist on items table
*/
set current(value) {
this._current = value;
}
get current() {
return this._current;
}
/**
* items to pickup
*/
set items(value) {
if (!this.model) {
this.model = new ValueSetStaticModel();
}
this.model.set = value;
}
get items() {
return this._model.set;
}
/**
* disable the whole things
*/
disabled = false;
/** */
placeholder;
_model = new ValueSetStaticModel();
/**
* Set model class that need to extends AbstractValueSetModel
*/
set model(value) {
value.set = value.set.length && value.set || this._model?.set;
this._model = value;
}
get model() {
return this._model;
}
/**
* Options to control displaying different parts, right now only next/previous buttons
*/
display = { nextPrevious: true };
/**
* Picker settings
*/
picker = {};
/**
* Emit when picker value changed
*/
changed = new EventEmitter();
/** define if list is opened */
isOpen = false;
touched = false;
valueRef;
itemRef;
onChange = (value) => { };
onTouched = () => { };
registerOnValidatorChange(fn) { this.onChange = fn; }
writeValue(set) {
this.current = set;
}
registerOnChange(onChange) {
this.onChange = onChange;
}
registerOnTouched(onTouched) {
this.onTouched = onTouched;
}
setDisabledState(disabled) {
this.disabled = disabled;
}
markAsTouched() {
if (this.disabled) {
return;
}
if (!this.touched) {
this.onTouched();
this.touched = true;
}
}
previous() {
this.setValue(this.model.previous(this.current));
}
next() {
this.setValue(this.model.next(this.current));
}
open() {
if (!this.isOpen) {
this.isOpen = true;
}
}
toggle() {
this.isOpen = !this.isOpen;
}
selected(item) {
this.isOpen = false;
this.setValue(of(item));
}
setValue(value) {
value.subscribe(value => {
this.writeValue(value);
this.onChange(value);
this.changed.emit(value);
});
}
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.0.4", ngImport: i0, type: ValuePickerComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.0.4", type: ValuePickerComponent, isStandalone: false, selector: "obl-value-picker", inputs: { current: "current", items: "items", disabled: "disabled", placeholder: "placeholder", model: "model", display: "display", picker: "picker" }, outputs: { changed: "changed" }, providers: [
{
provide: NG_VALUE_ACCESSOR,
multi: true,
useExisting: ValuePickerComponent
},
], queries: [{ propertyName: "valueRef", first: true, predicate: ["valueRef"], descendants: true }, { propertyName: "itemRef", first: true, predicate: ["itemRef"], descendants: true }], ngImport: i0, template: "@if (display.nextPrevious) {\n <button\n oblButton\n (click)=\"previous()\"\n [icon]=\"'left'\"\n [disabled]=\"disabled || model.loading || model.decreaseDisabled(current)\"\n ></button>\n}\n<button\n [disabled]=\"disabled\"\n oblButton\n class=\"current\"\n (click)=\"open()\"\n cdkOverlayOrigin\n #dropDown=\"cdkOverlayOrigin\"\n>\n @if (model.loading) {\n <obl-spinner></obl-spinner>\n }\n <ng-container\n *ngTemplateOutlet=\"\n (current && (valueRef || defaultRef)) || placeholderRef;\n context: { $implicit: current }\n \"\n ></ng-container>\n</button>\n\n@if (display.nextPrevious) {\n <button\n oblButton\n (click)=\"next()\"\n [icon]=\"'right'\"\n [disabled]=\"disabled || model.loading || model.increaseDisabled(current)\"\n >\n </button>\n}\n\n<ng-template\n cdkConnectedOverlay\n [cdkConnectedOverlayOrigin]=\"dropDown\"\n [cdkConnectedOverlayOpen]=\"isOpen\"\n [cdkConnectedOverlayOffsetX]=\"2\"\n (overlayOutsideClick)=\"toggle()\"\n>\n <obl-values-set\n [class]=\"picker.className\"\n [current]=\"current\"\n [model]=\"model\"\n [itemRef]=\"itemRef\"\n (selected)=\"selected($event)\"\n >\n </obl-values-set>\n</ng-template>\n\n<ng-template #defaultRef>\n {{ current?.value.toString() }}\n</ng-template>\n\n<ng-content></ng-content>\n\n<ng-template #placeholderRef>\n {{ placeholder }}\n</ng-template>\n", styles: [":host{display:flex;flex-wrap:nowrap;border-radius:5px;overflow:hidden;min-height:30px}.current{min-width:100px;width:100%}button{--obl-default-button-padding: 5px;font-size:var(--obl-font-size, 16px)}obl-spinner{--obl-spinner-width: 14px;--obl-spinner-color: gray;display:block;margin:0 5px}\n"], dependencies: [{ kind: "directive", type: i1.NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "directive", type: i3.ButtonDirective, selector: "oblButton, [oblButton]", inputs: ["oblButton", "icon", "blockWhenLoading", "loading", "toggle", "selected", "link", "target"], exportAs: ["oblButton"] }, { kind: "directive", type: i3$1.CdkConnectedOverlay, selector: "[cdk-connected-overlay], [connected-overlay], [cdkConnectedOverlay]", inputs: ["cdkConnectedOverlayOrigin", "cdkConnectedOverlayPositions", "cdkConnectedOverlayPositionStrategy", "cdkConnectedOverlayOffsetX", "cdkConnectedOverlayOffsetY", "cdkConnectedOverlayWidth", "cdkConnectedOverlayHeight", "cdkConnectedOverlayMinWidth", "cdkConnectedOverlayMinHeight", "cdkConnectedOverlayBackdropClass", "cdkConnectedOverlayPanelClass", "cdkConnectedOverlayViewportMargin", "cdkConnectedOverlayScrollStrategy", "cdkConnectedOverlayOpen", "cdkConnectedOverlayDisableClose", "cdkConnectedOverlayTransformOriginOn", "cdkConnectedOverlayHasBackdrop", "cdkConnectedOverlayLockPosition", "cdkConnectedOverlayFlexibleDimensions", "cdkConnectedOverlayGrowAfterOpen", "cdkConnectedOverlayPush", "cdkConnectedOverlayDisposeOnNavigation"], outputs: ["backdropClick", "positionChange", "attach", "detach", "overlayKeydown", "overlayOutsideClick"], exportAs: ["cdkConnectedOverlay"] }, { kind: "directive", type: i3$1.CdkOverlayOrigin, selector: "[cdk-overlay-origin], [overlay-origin], [cdkOverlayOrigin]", exportAs: ["cdkOverlayOrigin"] }, { kind: "component", type: i4.SpinnerComponent, selector: "obl-spinner" }, { kind: "component", type: ValuesSetComponent, selector: "obl-values-set", inputs: ["current", "model", "itemRef"], outputs: ["selected", "next", "previous"] }] });
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.0.4", ngImport: i0, type: ValuePickerComponent, decorators: [{
type: Component,
args: [{ selector: 'obl-value-picker', providers: [
{
provide: NG_VALUE_ACCESSOR,
multi: true,
useExisting: ValuePickerComponent
},
], standalone: false, template: "@if (display.nextPrevious) {\n <button\n oblButton\n (click)=\"previous()\"\n [icon]=\"'left'\"\n [disabled]=\"disabled || model.loading || model.decreaseDisabled(current)\"\n ></button>\n}\n<button\n [disabled]=\"disabled\"\n oblButton\n class=\"current\"\n (click)=\"open()\"\n cdkOverlayOrigin\n #dropDown=\"cdkOverlayOrigin\"\n>\n @if (model.loading) {\n <obl-spinner></obl-spinner>\n }\n <ng-container\n *ngTemplateOutlet=\"\n (current && (valueRef || defaultRef)) || placeholderRef;\n context: { $implicit: current }\n \"\n ></ng-container>\n</button>\n\n@if (display.nextPrevious) {\n <button\n oblButton\n (click)=\"next()\"\n [icon]=\"'right'\"\n [disabled]=\"disabled || model.loading || model.increaseDisabled(current)\"\n >\n </button>\n}\n\n<ng-template\n cdkConnectedOverlay\n [cdkConnectedOverlayOrigin]=\"dropDown\"\n [cdkConnectedOverlayOpen]=\"isOpen\"\n [cdkConnectedOverlayOffsetX]=\"2\"\n (overlayOutsideClick)=\"toggle()\"\n>\n <obl-values-set\n [class]=\"picker.className\"\n [current]=\"current\"\n [model]=\"model\"\n [itemRef]=\"itemRef\"\n (selected)=\"selected($event)\"\n >\n </obl-values-set>\n</ng-template>\n\n<ng-template #defaultRef>\n {{ current?.value.toString() }}\n</ng-template>\n\n<ng-content></ng-content>\n\n<ng-template #placeholderRef>\n {{ placeholder }}\n</ng-template>\n", styles: [":host{display:flex;flex-wrap:nowrap;border-radius:5px;overflow:hidden;min-height:30px}.current{min-width:100px;width:100%}button{--obl-default-button-padding: 5px;font-size:var(--obl-font-size, 16px)}obl-spinner{--obl-spinner-width: 14px;--obl-spinner-color: gray;display:block;margin:0 5px}\n"] }]
}], propDecorators: { current: [{
type: Input
}], items: [{
type: Input
}], disabled: [{
type: Input
}], placeholder: [{
type: Input
}], model: [{
type: Input
}], display: [{
type: Input
}], picker: [{
type: Input
}], changed: [{
type: Output
}], valueRef: [{
type: ContentChild,
args: ['valueRef']
}], itemRef: [{
type: ContentChild,
args: ['itemRef']
}] } });
class ValuePickerModule {
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.0.4", ngImport: i0, type: ValuePickerModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule });
static ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "14.0.0", version: "20.0.4", ngImport: i0, type: ValuePickerModule, declarations: [ValuePickerComponent,
ValuesSetComponent], imports: [CommonModule,
IconsModule,
ButtonsModule,
OverlayModule,
FormsModule,
ReactiveFormsModule,
LoadingModule], exports: [ValuePickerComponent,
ValuesSetComponent] });
static ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "20.0.4", ngImport: i0, type: ValuePickerModule, imports: [CommonModule,
IconsModule,
ButtonsModule,
OverlayModule,
FormsModule,
ReactiveFormsModule,
LoadingModule] });
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.0.4", ngImport: i0, type: ValuePickerModule, decorators: [{
type: NgModule,
args: [{
declarations: [
ValuePickerComponent,
ValuesSetComponent
],
imports: [
CommonModule,
IconsModule,
ButtonsModule,
OverlayModule,
FormsModule,
ReactiveFormsModule,
LoadingModule,
],
exports: [
ValuePickerComponent,
ValuesSetComponent
]
}]
}] });
class ValueSetDynamicModel extends AbstractValueSetModel {
values = new BehaviorSubject(undefined);
observer = this.values.asObservable();
getSet;
get(type, current) {
if (this.getSet) {
setTimeout(() => this.loading = true);
return this.getSet(this, type, current).pipe(finalize(() => this.loading = false));
}
return of();
}
init(current) {
const values = this.values.value;
if (values && current) {
if (values.items.findIndex(item => item.value.id === current?.value.id) !== -1) {
return of();
}
}
this.get(current && 'current' || 'default', current).subscribe(resp => this.values.next(resp));
return of();
}
getNextSet() {
return this.getPreviousNextSet('next');
}
getPreviousSet() {
return this.getPreviousNextSet('previous');
}
getPreviousNextSet(type, current) {
const res = this.values.value;
if (this.getSet) {
if (res) {
if (res.next) {
this.loading = true;
this.get(type).subscribe(resp => this.values.next(resp));
}
return of(res.next);
}
this.loading = true;
this.get(current && 'current' || 'default', current).subscribe(resp => this.values.next(resp));
}
return of(false);
}
getCurrentSet() {
return this.observer.pipe(map(resp => resp?.items || []));
}
displayNextPrevious() {
const value = this.values.value;
return of(value && (value.next && value.previous) || false);
}
next(current) {
return this.getPreviousNext('next', current);
}
previous(current) {
return this.getPreviousNext('previous', current);
}
getPreviousNext(type, current) {
if (this.loading) {
return of(current);
}
const value = this.values.value;
const get = () => {
if (this.getSet) {
setTimeout(() => this.loading = true);
return this.getSet(this, type).pipe(map(resp => (this.values.next(resp), resp.items[type === 'next' ? 0 : resp.items.length - 1])), finalize(() => this.loading = false));
}
return of();
};
if (value) {
const { items, next, previous } = value;
const index = items.findIndex(item => item.value.id === current?.value.id);
if (type === 'next' && next) {
return items[index + 1] && of(items[index + 1]) || get();
}
else if (type === 'previous' && previous) {
return items[index - 1] && of(items[index - 1]) || get();
}
return of();
}
return get();
}
nextDisabled() {
return of(this.values.value?.next !== true || false);
}
previousDisabled() {
return of(this.values.value?.previous !== true || false);
}
decreaseDisabled(current) {
const values = this.values.value;
return current?.value.id === values?.items[0].value.id && values?.previous !== true || false;
}
increaseDisabled(current) {
const values = this.values.value;
return current?.value.id === values?.items[(values?.items.length || 0) - 1]?.value.id && values?.next !== true || false;
}
selected(item, current) {
return current?.value.id === item?.value.id;
}
}
/**
* Generated bundle index. Do not edit.
*/
export { AbstractValueSetModel, ValuePickerComponent, ValuePickerModule, ValueSetDynamicModel, ValueSetStaticModel, ValuesSetComponent };
//# sourceMappingURL=obliczeniowo-elementary-value-picker.mjs.map