Simple popup filter improvements

This commit is contained in:
Adina Țeudan 2024-06-17 15:29:26 +03:00
parent aec5da15df
commit 4c0437d7fc
5 changed files with 69 additions and 37 deletions

View File

@ -0,0 +1,3 @@
<svg width="18" height="12" viewBox="0 0 18 12" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M7 12V10H11V12H7ZM3 7V5H15V7H3ZM0 2V0H18V2H0Z" fill="currentColor" />
</svg>

After

Width:  |  Height:  |  Size: 186 B

View File

@ -0,0 +1,4 @@
export interface SimpleFilterOption<T> {
value: T;
label: string;
}

View File

@ -1,25 +1,33 @@
<ng-container *ngIf="icon"> <iqser-icon-button
<iqser-icon-button *ngIf="type() === 'text' && icon()"
[attr.aria-expanded]="expanded()" [attr.aria-expanded]="expanded()"
[class.disabled]="disabled()" [class.disabled]="disabled()"
[disabled]="disabled()" [disabled]="disabled()"
[icon]="icon()" [icon]="icon()"
[label]="label()" [label]="label()"
[matMenuTriggerFor]="filterMenu" [matMenuTriggerFor]="filterMenu"
[showDot]="hasActiveFilters()" [showDot]="hasActiveFilters()"
></iqser-icon-button> ></iqser-icon-button>
</ng-container>
<ng-container *ngIf="!icon"> <iqser-chevron-button
<iqser-chevron-button [attr.aria-expanded]="expanded()"
[attr.aria-expanded]="expanded()" [class.disabled]="disabled()"
[class.disabled]="disabled" [disabled]="disabled()"
[disabled]="disabled()" [label]="label()"
[label]="label()" [matMenuTriggerFor]="filterMenu"
[matMenuTriggerFor]="filterMenu" [showDot]="hasActiveFilters()"
[showDot]="hasActiveFilters()" *ngIf="type() === 'text' && !icon()"
></iqser-chevron-button> ></iqser-chevron-button>
</ng-container>
<iqser-circle-button
[attr.aria-expanded]="expanded()"
[class.disabled]="disabled()"
[disabled]="disabled()"
[matMenuTriggerFor]="filterMenu"
[showDot]="hasActiveFilters()"
[icon]="icon() || 'iqser:filter-list'"
*ngIf="type() === 'icon'"
></iqser-circle-button>
<mat-menu #filterMenu="matMenu" (closed)="expanded.set(false)" xPosition="before"> <mat-menu #filterMenu="matMenu" (closed)="expanded.set(false)" xPosition="before">
<div iqserStopPropagation> <div iqserStopPropagation>

View File

@ -1,12 +1,12 @@
import { Component, computed, input, output, signal, untracked } from '@angular/core'; import { Component, computed, effect, input, output, signal, untracked } from '@angular/core';
import { MatMenuModule } from '@angular/material/menu'; import { MatMenuModule } from '@angular/material/menu';
import { CommonModule } from '@angular/common'; import { CommonModule } from '@angular/common';
import { TranslateModule } from '@ngx-translate/core'; import { TranslateModule } from '@ngx-translate/core';
import { MatCheckbox } from '@angular/material/checkbox'; import { MatCheckbox } from '@angular/material/checkbox';
import { takeUntilDestroyed, toObservable } from '@angular/core/rxjs-interop'; import { ChevronButtonComponent, CircleButtonComponent, IconButtonComponent } from '../../buttons';
import { ChevronButtonComponent, IconButtonComponent } from '../../buttons';
import { StopPropagationDirective } from '../../directives'; import { StopPropagationDirective } from '../../directives';
import { InputWithActionComponent } from '../../inputs'; import { InputWithActionComponent } from '../../inputs';
import { SimpleFilterOption } from '../models/simple-filter-option';
@Component({ @Component({
selector: 'iqser-simple-popup-filter', selector: 'iqser-simple-popup-filter',
@ -24,18 +24,20 @@ import { InputWithActionComponent } from '../../inputs';
MatCheckbox, MatCheckbox,
IconButtonComponent, IconButtonComponent,
ChevronButtonComponent, ChevronButtonComponent,
CircleButtonComponent,
], ],
}) })
export class SimplePopupFilterComponent<T extends { label: string }> { export class SimplePopupFilterComponent<T> {
options = input.required<T[]>(); readonly options = input.required<SimpleFilterOption<T>[]>();
icon = input<string>(); readonly icon = input<string>();
label = input<string>(); readonly label = input<string>();
filterPlaceholder = input.required<string>(); readonly filterPlaceholder = input.required<string>();
disabled = input<boolean>(false); readonly disabled = input<boolean>(false);
selectionChanged = output<T[]>(); readonly type = input<'text' | 'icon'>('text');
readonly selectionChanged = output<SimpleFilterOption<T>[]>();
readonly expanded = signal(false); readonly expanded = signal(false);
readonly selectedOptions = signal<T[]>([]); readonly selectedOptions = signal<SimpleFilterOption<T>[]>([]);
readonly hasActiveFilters = computed(() => this.selectedOptions().length > 0); readonly hasActiveFilters = computed(() => this.selectedOptions().length > 0);
readonly searchValue = signal(''); readonly searchValue = signal('');
readonly displayedOptions = computed(() => readonly displayedOptions = computed(() =>
@ -43,10 +45,24 @@ export class SimplePopupFilterComponent<T extends { label: string }> {
); );
constructor() { constructor() {
toObservable(this.selectedOptions) effect(() => {
.pipe(takeUntilDestroyed()) this.selectionChanged.emit(this.selectedOptions());
// eslint-disable-next-line rxjs/no-ignored-subscription });
.subscribe(() => this.selectionChanged.emit(this.selectedOptions()));
/** If the options change and the selected options are not in the new options, remove them. */
effect(
() => {
const allOptions = this.options();
const selectedOptions = untracked(this.selectedOptions);
if (selectedOptions.some(selectedOption => !allOptions.find(o => o.value === selectedOption))) {
this.selectedOptions.set(
selectedOptions.filter(selectedOption => allOptions.find(o => o.value === selectedOption.value)),
);
}
},
{ allowSignalWrites: true },
);
} }
protected _selectAll(): void { protected _selectAll(): void {
@ -57,7 +73,7 @@ export class SimplePopupFilterComponent<T extends { label: string }> {
this.selectedOptions.set([]); this.selectedOptions.set([]);
} }
protected _filterCheckboxClicked(option: T): void { protected _filterCheckboxClicked(option: SimpleFilterOption<T>): void {
if (this.selectedOptions().includes(option)) { if (this.selectedOptions().includes(option)) {
this.selectedOptions.set(this.selectedOptions().filter(selectedOption => selectedOption !== option)); this.selectedOptions.set(this.selectedOptions().filter(selectedOption => selectedOption !== option));
} else { } else {

View File

@ -15,6 +15,7 @@ export const ICONS = new Set([
'edit', 'edit',
'expand', 'expand',
'failure', 'failure',
'filter-list',
'help-outline', 'help-outline',
'lanes', 'lanes',
'list', 'list',