Simple popup filter improvements
This commit is contained in:
parent
aec5da15df
commit
4c0437d7fc
3
src/assets/icons/filter-list.svg
Normal file
3
src/assets/icons/filter-list.svg
Normal 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 |
4
src/lib/filtering/models/simple-filter-option.ts
Normal file
4
src/lib/filtering/models/simple-filter-option.ts
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
export interface SimpleFilterOption<T> {
|
||||||
|
value: T;
|
||||||
|
label: string;
|
||||||
|
}
|
||||||
@ -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>
|
||||||
|
|||||||
@ -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 {
|
||||||
|
|||||||
@ -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',
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user