@firestitch/filter 18.2.38 → 18.2.40

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,5 +1,5 @@
1
1
  import * as i0 from '@angular/core';
2
- import { inject, Injectable, Component, ChangeDetectionStrategy, Input, DestroyRef, Injector, EventEmitter, Output, InjectionToken, Directive, Optional, Self, ChangeDetectorRef, ViewChild, NgZone, ElementRef, ContentChild, HostBinding, HostListener, NgModule } from '@angular/core';
2
+ import { inject, Injectable, Component, ChangeDetectionStrategy, Input, DestroyRef, Injector, EventEmitter, Output, InjectionToken, Directive, Optional, Self, ChangeDetectorRef, ViewChild, NgZone, TemplateRef, ElementRef, ContentChild, HostBinding, HostListener, NgModule } from '@angular/core';
3
3
  import { FsPrompt } from '@firestitch/prompt';
4
4
  import { BehaviorSubject, Subject, of, forkJoin, Observable, tap as tap$1, map as map$1, switchMap as switchMap$1, distinctUntilChanged as distinctUntilChanged$1, merge, filter, combineLatest, fromEvent, interval, takeUntil as takeUntil$1, debounceTime as debounceTime$1 } from 'rxjs';
5
5
  import { distinctUntilChanged, tap, switchMap, map, debounceTime, finalize, takeUntil, filter as filter$1, delay, skip } from 'rxjs/operators';
@@ -1548,6 +1548,83 @@ class DateTimeItem extends BaseDateItem {
1548
1548
  }
1549
1549
  }
1550
1550
 
1551
+ class TextItem extends BaseItem {
1552
+ _additionalConfig;
1553
+ _filter;
1554
+ constructor(itemConfig, _additionalConfig, _filter) {
1555
+ super(itemConfig, _additionalConfig, _filter);
1556
+ this._additionalConfig = _additionalConfig;
1557
+ this._filter = _filter;
1558
+ this.prefix = itemConfig.prefix;
1559
+ this.suffix = itemConfig.suffix;
1560
+ }
1561
+ static create(config, filter) {
1562
+ return new TextItem(config, null, filter);
1563
+ }
1564
+ get hasValue() {
1565
+ return typeof this.value === 'string' && this.value.length > 0;
1566
+ }
1567
+ get query() {
1568
+ if (!this.hasValue) {
1569
+ return {};
1570
+ }
1571
+ const value = this.value;
1572
+ const name = this.name;
1573
+ const params = {};
1574
+ params[name] = value;
1575
+ return params;
1576
+ }
1577
+ get chips() {
1578
+ if (!this.hasValue || this.isTypeKeyword) {
1579
+ return [];
1580
+ }
1581
+ return [
1582
+ {
1583
+ value: this.value,
1584
+ label: this.label,
1585
+ },
1586
+ ];
1587
+ }
1588
+ }
1589
+
1590
+ class KeywordItem extends TextItem {
1591
+ _additionalConfig;
1592
+ _filter;
1593
+ constructor(itemConfig, _additionalConfig, _filter) {
1594
+ super(itemConfig, _additionalConfig, _filter);
1595
+ this._additionalConfig = _additionalConfig;
1596
+ this._filter = _filter;
1597
+ this.fullWidth = itemConfig.fullWidth;
1598
+ }
1599
+ static create(config, filter) {
1600
+ return new KeywordItem(config, null, filter);
1601
+ }
1602
+ get hasValue() {
1603
+ return typeof this.value === 'string' && this.value.length > 0;
1604
+ }
1605
+ get query() {
1606
+ if (!this.hasValue) {
1607
+ return {};
1608
+ }
1609
+ const value = this.value;
1610
+ const name = this.name;
1611
+ const params = {};
1612
+ params[name] = value;
1613
+ return params;
1614
+ }
1615
+ get chips() {
1616
+ if (!this.hasValue || this.isTypeKeyword) {
1617
+ return [];
1618
+ }
1619
+ return [
1620
+ {
1621
+ value: this.value,
1622
+ label: this.label,
1623
+ },
1624
+ ];
1625
+ }
1626
+ }
1627
+
1551
1628
  class SelectItem extends BaseItem {
1552
1629
  _additionalConfig;
1553
1630
  _filter;
@@ -1653,45 +1730,6 @@ class SelectItem extends BaseItem {
1653
1730
  }
1654
1731
  }
1655
1732
 
1656
- class TextItem extends BaseItem {
1657
- _additionalConfig;
1658
- _filter;
1659
- constructor(itemConfig, _additionalConfig, _filter) {
1660
- super(itemConfig, _additionalConfig, _filter);
1661
- this._additionalConfig = _additionalConfig;
1662
- this._filter = _filter;
1663
- this.prefix = itemConfig.prefix;
1664
- this.suffix = itemConfig.suffix;
1665
- }
1666
- static create(config, filter) {
1667
- return new TextItem(config, null, filter);
1668
- }
1669
- get hasValue() {
1670
- return typeof this.value === 'string' && this.value.length > 0;
1671
- }
1672
- get query() {
1673
- if (!this.hasValue) {
1674
- return {};
1675
- }
1676
- const value = this.value;
1677
- const name = this.name;
1678
- const params = {};
1679
- params[name] = value;
1680
- return params;
1681
- }
1682
- get chips() {
1683
- if (!this.hasValue || this.isTypeKeyword) {
1684
- return [];
1685
- }
1686
- return [
1687
- {
1688
- value: this.value,
1689
- label: this.label,
1690
- },
1691
- ];
1692
- }
1693
- }
1694
-
1695
1733
  function createFilterItem(item, config, filter) {
1696
1734
  switch (item.type) {
1697
1735
  case ItemType.Select: {
@@ -1727,7 +1765,9 @@ function createFilterItem(item, config, filter) {
1727
1765
  case ItemType.Checkbox: {
1728
1766
  return new CheckboxItem(item, null, filter);
1729
1767
  }
1730
- case ItemType.Keyword:
1768
+ case ItemType.Keyword: {
1769
+ return KeywordItem.create(item, filter);
1770
+ }
1731
1771
  case ItemType.Text: {
1732
1772
  return TextItem.create(item, filter);
1733
1773
  }
@@ -1737,19 +1777,25 @@ function createFilterItem(item, config, filter) {
1737
1777
  class KeywordController {
1738
1778
  _keywordItem$ = new BehaviorSubject(null);
1739
1779
  _keywordVisible$ = new BehaviorSubject(null);
1780
+ _keywordFullWidth$ = new BehaviorSubject(null);
1740
1781
  _destroyRef = inject(DestroyRef);
1741
- _filterController;
1742
- init(filterController) {
1743
- this._filterController = filterController;
1782
+ init() {
1744
1783
  this._keywordItem$
1745
1784
  .pipe(
1746
1785
  // when item changes, unsubscribe from the previous visible$
1747
1786
  switchMap$1((item) => item ? item.visible$ : of(false)),
1748
1787
  // avoid redundant writes
1749
- distinctUntilChanged$1(),
1788
+ distinctUntilChanged$1(), tap$1((visible) => this._keywordVisible$.next(visible)),
1789
+ // clean up on destroy,
1790
+ takeUntilDestroyed(this._destroyRef))
1791
+ .subscribe();
1792
+ this._keywordItem$
1793
+ .pipe(map$1((item) => !!item.fullWidth),
1794
+ // avoid redundant writes
1795
+ distinctUntilChanged$1(), tap$1((fullWidth) => this._keywordFullWidth$.next(fullWidth)),
1750
1796
  // clean up on destroy,
1751
1797
  takeUntilDestroyed(this._destroyRef))
1752
- .subscribe((visible) => this._keywordVisible$.next(visible));
1798
+ .subscribe();
1753
1799
  }
1754
1800
  get keywordItem$() {
1755
1801
  return this._keywordItem$.asObservable();
@@ -1772,6 +1818,9 @@ class KeywordController {
1772
1818
  get keywordVisible$() {
1773
1819
  return this._keywordVisible$.asObservable();
1774
1820
  }
1821
+ get keywordFullWidth$() {
1822
+ return this._keywordFullWidth$.asObservable();
1823
+ }
1775
1824
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: KeywordController, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
1776
1825
  static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: KeywordController });
1777
1826
  }
@@ -2025,7 +2074,7 @@ class FilterController {
2025
2074
  init(config) {
2026
2075
  this._config = config;
2027
2076
  of(null)
2028
- .pipe(tap(() => this._addItems(this._config.items || [])), tap(() => this._keywordController.init(this)), tap(() => this._sortController.init(this)), switchMap(() => forkJoin({
2077
+ .pipe(tap(() => this._addItems(this._config.items || [])), tap(() => this._keywordController.init()), tap(() => this._sortController.init(this)), switchMap(() => forkJoin({
2029
2078
  savedFilters: this._savedFilterController.init(this),
2030
2079
  persistance: this._persistanceController.init(this),
2031
2080
  queryParams: this._queryParamController.init(this),
@@ -2142,7 +2191,7 @@ class FilterController {
2142
2191
  })
2143
2192
  .map((item) => {
2144
2193
  const filterItem = createFilterItem(item, {}, this.filter);
2145
- if (filterItem.type === ItemType.Keyword) {
2194
+ if (filterItem instanceof KeywordItem) {
2146
2195
  this._keywordController.keywordItem = filterItem;
2147
2196
  }
2148
2197
  this._items.set(item.name, filterItem);
@@ -2213,14 +2262,14 @@ class FsFilterChipsComponent {
2213
2262
  item.clear(chip.name);
2214
2263
  }
2215
2264
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: FsFilterChipsComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
2216
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "18.2.13", type: FsFilterChipsComponent, isStandalone: true, selector: "fs-filter-chips", ngImport: i0, template: "@for (item of items; track item.name) {\n @for (chip of item.chips$ | async; track chip.label) {\n <fs-chip\n [removable]=\"item.clearable\"\n size=\"small\"\n (click)=\"click(item, chip)\"\n (removed)=\"remove(item, chip)\">\n {{ chip.value ? chip.label + ': ' + chip.value : chip.label }}\n </fs-chip>\n }\n}", styles: [":host{display:flex;flex-wrap:wrap;column-gap:4px}fs-chip{margin-top:4px}\n"], dependencies: [{ kind: "pipe", type: AsyncPipe, name: "async" }, { kind: "ngmodule", type: FsChipModule }, { kind: "component", type: i1$2.FsChipComponent, selector: "fs-chip", inputs: ["selectable", "removable", "value", "maxWidth", "width", "backgroundColor", "borderColor", "color", "shape", "outlined", "icon", "image", "selected", "padding", "contrastColor", "size"], outputs: ["selectedToggled", "removed"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
2265
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "18.2.13", type: FsFilterChipsComponent, isStandalone: true, selector: "fs-filter-chips", ngImport: i0, template: "@for (item of items; track item.name) {\n @for (chip of item.chips$ | async; track chip.label) {\n <fs-chip\n [removable]=\"item.clearable\"\n size=\"small\"\n (click)=\"click(item, chip)\"\n (removed)=\"remove(item, chip)\">\n {{ chip.value ? chip.label + ': ' + chip.value : chip.label }}\n </fs-chip>\n }\n}", styles: [":host{display:flex;flex-wrap:wrap;column-gap:4px;max-width:100%}fs-chip{margin-top:4px}\n"], dependencies: [{ kind: "pipe", type: AsyncPipe, name: "async" }, { kind: "ngmodule", type: FsChipModule }, { kind: "component", type: i1$2.FsChipComponent, selector: "fs-chip", inputs: ["selectable", "removable", "value", "maxWidth", "width", "backgroundColor", "borderColor", "color", "shape", "outlined", "icon", "image", "selected", "padding", "contrastColor", "size"], outputs: ["selectedToggled", "removed"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
2217
2266
  }
2218
2267
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: FsFilterChipsComponent, decorators: [{
2219
2268
  type: Component,
2220
2269
  args: [{ selector: 'fs-filter-chips', changeDetection: ChangeDetectionStrategy.OnPush, standalone: true, imports: [
2221
2270
  AsyncPipe,
2222
2271
  FsChipModule,
2223
- ], template: "@for (item of items; track item.name) {\n @for (chip of item.chips$ | async; track chip.label) {\n <fs-chip\n [removable]=\"item.clearable\"\n size=\"small\"\n (click)=\"click(item, chip)\"\n (removed)=\"remove(item, chip)\">\n {{ chip.value ? chip.label + ': ' + chip.value : chip.label }}\n </fs-chip>\n }\n}", styles: [":host{display:flex;flex-wrap:wrap;column-gap:4px}fs-chip{margin-top:4px}\n"] }]
2272
+ ], template: "@for (item of items; track item.name) {\n @for (chip of item.chips$ | async; track chip.label) {\n <fs-chip\n [removable]=\"item.clearable\"\n size=\"small\"\n (click)=\"click(item, chip)\"\n (removed)=\"remove(item, chip)\">\n {{ chip.value ? chip.label + ': ' + chip.value : chip.label }}\n </fs-chip>\n }\n}", styles: [":host{display:flex;flex-wrap:wrap;column-gap:4px;max-width:100%}fs-chip{margin-top:4px}\n"] }]
2224
2273
  }] });
2225
2274
 
2226
2275
  class FsFilterDrawerActionsComponent {
@@ -2845,7 +2894,6 @@ class KeywordInputComponent {
2845
2894
  _destroyRef = inject(DestroyRef);
2846
2895
  _destroy$ = new Subject();
2847
2896
  _keywordController = inject(KeywordController);
2848
- _filterController = inject(FilterController);
2849
2897
  _cdRef = inject(ChangeDetectorRef);
2850
2898
  get keywordVisible$() {
2851
2899
  return this._keywordController.keywordVisible$;
@@ -3124,7 +3172,7 @@ class FilterComponent {
3124
3172
  opened = new EventEmitter();
3125
3173
  ready = new EventEmitter();
3126
3174
  statusBar;
3127
- heading;
3175
+ headingTemplate;
3128
3176
  reloadEl;
3129
3177
  showFilterMenu = false;
3130
3178
  windowDesktop = false;
@@ -3222,6 +3270,9 @@ class FilterComponent {
3222
3270
  change() {
3223
3271
  this._filterController.change();
3224
3272
  }
3273
+ get hasHeading() {
3274
+ return !!this.headingTemplate || !!this.config.heading;
3275
+ }
3225
3276
  get hasFilterChips$() {
3226
3277
  return this._hasFilterChips$.asObservable();
3227
3278
  }
@@ -3238,6 +3289,9 @@ class FilterComponent {
3238
3289
  get keywordVisible$() {
3239
3290
  return this._keywordController.keywordVisible$;
3240
3291
  }
3292
+ get keywordFullWidth$() {
3293
+ return this._keywordController.keywordFullWidth$;
3294
+ }
3241
3295
  get filterInputVisible$() {
3242
3296
  return combineLatest({
3243
3297
  keywordVisible: this.keywordVisible$,
@@ -3490,7 +3544,7 @@ class FilterComponent {
3490
3544
  ActionsController,
3491
3545
  KeywordController,
3492
3546
  SortController,
3493
- ], queries: [{ propertyName: "statusBar", first: true, predicate: FilterStatusBarDirective, descendants: true }, { propertyName: "heading", first: true, predicate: FilterHeadingDirective, descendants: true }], viewQueries: [{ propertyName: "keywordInput", first: true, predicate: KeywordInputComponent, descendants: true }, { propertyName: "reloadEl", first: true, predicate: ["reloadEl"], descendants: true, read: ElementRef }], ngImport: i0, template: "<div class=\"filter-container\">\n @if (filterInputVisible$ | async) {\n <ng-container *ngTemplateOutlet=\"header\"></ng-container>\n }\n <div class=\"filter-inner-container\">\n <div class=\"filter-left-container\">\n @if (filterInputVisible$ | async) {\n <div class=\"filter-inner-inputs\">\n @if (keywordVisible$ | async) {\n <fs-keyword-input [autofocus]=\"config.autofocus\"></fs-keyword-input>\n }\n @if (savedFilterController.enabled) {\n <fs-saved-filter-autocomplete-chips [savedFiltersController]=\"savedFilterController\"></fs-saved-filter-autocomplete-chips>\n }\n </div>\n } @else {\n <ng-container *ngTemplateOutlet=\"header\"></ng-container>\n <ng-container *ngTemplateOutlet=\"filterStatusBarChips\"></ng-container>\n }\n </div>\n <ng-container [ngTemplateOutlet]=\"filterToolbar\"></ng-container>\n <ng-container [ngTemplateOutlet]=\"filterActions\"></ng-container>\n </div>\n @if ((filterInputVisible$ | async)) {\n <ng-container *ngTemplateOutlet=\"filterStatusBarChips\"></ng-container>\n }\n</div>\n<ng-template #filterStatusBarChips>\n @if (statusBar) {\n <div\n class=\"filter-status-container\"\n [ngClass]=\"{ 'has-status': !!filterStatus.textContent }\">\n <div\n class=\"filter-status\"\n #filterStatus>\n <ng-container *ngTemplateOutlet=\"statusBar.templateRef\"></ng-container>\n </div>\n </div>\n }\n @if (config.chips) {\n <fs-filter-chips class=\"filter-chips\"></fs-filter-chips>\n }\n</ng-template>\n<ng-template #filterActions>\n @if ((actionsVisible$ | async)) {\n <div class=\"filter-actions\">\n <fs-filter-actions\n [actions]=\"actions$ | async\"\n [kebabActions]=\"menuActions$ | async\">\n </fs-filter-actions>\n </div>\n }\n</ng-template>\n<ng-template #filterToolbar>\n @if (config.reload || config.autoReload || (filtersVisible$ | async)) {\n <div class=\"filter-toolbar\">\n @if ((filtersVisible$ | async)) {\n <a\n mat-icon-button\n class=\"button-filters\"\n (click)=\"filterButtonClick($event)\"\n [color]=\"config.button.color\">\n @if (config.button.icon) {\n <mat-icon [svgIcon]=\"'filterOutline'\"></mat-icon>\n }\n </a>\n }\n @if (config.reload) {\n <a\n mat-icon-button\n (click)=\"reload($event)\"\n class=\"button-reload\">\n <mat-icon #reloadEl>\n refresh\n </mat-icon>\n </a>\n }\n @if (config.autoReload) {\n <div class=\"filter-reload\">\n <mat-slide-toggle\n name=\"autoReload\"\n class=\"auto-reload\"\n [ngModel]=\"config.autoReload.enabled\"\n (ngModelChange)=\"config.autoReload.enabled = $event\">\n <span>\n Auto refresh\n </span>\n </mat-slide-toggle>\n </div>\n }\n </div>\n }\n</ng-template>\n<ng-template #header>\n @if (heading) {\n <ng-container *ngTemplateOutlet=\"heading.templateRef\"></ng-container>\n } @else if (config.heading) {\n <div class=\"heading\">\n <h2>\n {{ config.heading }}\n </h2>\n <div class=\"subheading\">\n {{ config.subheading }}\n </div>\n </div>\n }\n</ng-template>", styles: [":host{margin-bottom:20px;display:block}.filter-status-container{flex-grow:1;display:flex;justify-content:center;flex-direction:column;align-self:flex-end;margin-top:4px}.filter-status-container .filter-status{overflow:hidden;text-overflow:ellipsis;line-height:18px}.filter-container{width:100%}.filter-inner-container{flex-direction:row;box-sizing:border-box;display:flex;position:relative;align-items:center}.filter-inner-container .filter-left-container{min-width:0}.filter-inner-container .filter-inner-inputs{flex-direction:row;box-sizing:border-box;display:flex;align-items:center;min-width:0;gap:5px}.filter-actions{display:flex;align-items:center;flex:1;justify-content:flex-end}.filter-toolbar{white-space:nowrap;display:flex;align-items:center}.filter-toolbar .button-filters,.filter-toolbar .button-reload{display:flex;--mdc-icon-button-state-layer-size: 40px;padding:8px}.filter-toolbar .button-filters ::ng-deep svg,.filter-toolbar .button-reload ::ng-deep svg{display:flex}.filter-toolbar .filter-reload{margin-left:10px;display:flex;align-items:center}.filter-toolbar .filter-reload .auto-reload{margin-right:5px}.filter-toolbar .filter-reload .auto-reload span{font-size:80%}.heading{margin-right:10px}.heading h2{margin:0}.heading h2+.subheading{margin:0}.results{min-height:90px;position:relative;overflow-x:auto;overflow-y:hidden}@media screen and (min-width: 1200px){html.fs-filter-open body{margin-right:350px}}html.fs-filter-open{scrollbar-width:none}:host ::ng-deep .auto-reload.mat-checked .mat-slide-toggle-thumb-container{transform:translate3d(12px,0,0)}:host ::ng-deep .auto-reload:not(.mat-checked) .mat-slide-toggle-content{color:#ccc}:host ::ng-deep .auto-reload .mat-slide-toggle-thumb,:host ::ng-deep .auto-reload .mat-slide-toggle-thumb-container{height:15px;width:15px}:host ::ng-deep .auto-reload .mat-slide-toggle-content{font-size:90%}:host ::ng-deep .auto-reload .mat-slide-toggle-bar{width:26px;height:10px;border-radius:10px}\n"], dependencies: [{ kind: "directive", type: NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "component", type: FsSavedFilterAutocompleteChipsComponent, selector: "fs-saved-filter-autocomplete-chips", inputs: ["savedFiltersController"] }, { kind: "directive", type: NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "component", type: MatIcon, selector: "mat-icon", inputs: ["color", "inline", "svgIcon", "fontSet", "fontIcon"], exportAs: ["matIcon"] }, { kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i1$1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1$1.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "ngmodule", type: FsFormModule }, { kind: "directive", type: i3.FsFormNoFsValidatorsDirective, selector: "[ngModel]:not([required]):not([fsFormRequired]):not([fsFormCompare]):not([fsFormDateRange]):not([fsFormEmail]):not([fsFormEmails]):not([fsFormFunction]):not([fsFormGreater]):not([fsFormGreaterEqual]):not([fsFormInteger]):not([fsFormLesser]):not([fsFormMax]):not([fsFormMaxLength]):not([fsFormMin]):not([fsFormMinLength]):not([fsFormNumeric]):not([fsFormPattern]):not([fsFormPhone]):not([fsFormUrl]):not([validate])" }, { kind: "ngmodule", type: FsClearModule }, { kind: "component", type: FsFilterChipsComponent, selector: "fs-filter-chips" }, { kind: "component", type: FsFilterActionsComponent, selector: "fs-filter-actions", inputs: ["kebabActions", "actions"] }, { kind: "component", type: MatIconAnchor, selector: "a[mat-icon-button]", exportAs: ["matButton", "matAnchor"] }, { kind: "component", type: MatSlideToggle, selector: "mat-slide-toggle", inputs: ["name", "id", "labelPosition", "aria-label", "aria-labelledby", "aria-describedby", "required", "color", "disabled", "disableRipple", "tabIndex", "checked", "hideIcon", "disabledInteractive"], outputs: ["change", "toggleChange"], exportAs: ["matSlideToggle"] }, { kind: "pipe", type: AsyncPipe, name: "async" }, { kind: "component", type: KeywordInputComponent, selector: "fs-keyword-input", inputs: ["autofocus"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
3547
+ ], queries: [{ propertyName: "statusBar", first: true, predicate: FilterStatusBarDirective, descendants: true }, { propertyName: "headingTemplate", first: true, predicate: FilterHeadingDirective, descendants: true, read: TemplateRef }], viewQueries: [{ propertyName: "keywordInput", first: true, predicate: KeywordInputComponent, descendants: true }, { propertyName: "reloadEl", first: true, predicate: ["reloadEl"], descendants: true, read: ElementRef }], ngImport: i0, template: "<div\n class=\"filter-container\"\n [ngClass]=\"{ 'has-input': filterInputVisible$ | async }\"\n [ngClass]=\"{ 'keyword-full-width': keywordFullWidth$ | async }\">\n @if (filterInputVisible$ | async) {\n <ng-container *ngTemplateOutlet=\"heading\"></ng-container>\n }\n <div class=\"filter-bar-container\">\n @if (filterInputVisible$ | async) {\n <div class=\"filter-input-container\">\n @if (keywordVisible$ | async) {\n <fs-keyword-input [autofocus]=\"config.autofocus\"></fs-keyword-input>\n }\n @if (savedFilterController.enabled) {\n <fs-saved-filter-autocomplete-chips [savedFiltersController]=\"savedFilterController\"></fs-saved-filter-autocomplete-chips>\n }\n <ng-container [ngTemplateOutlet]=\"filterToolbar\"></ng-container>\n </div>\n } @else {\n @if (hasHeading) {\n <div class=\"filter-heading-container\">\n <ng-container *ngTemplateOutlet=\"heading\"></ng-container>\n <ng-container [ngTemplateOutlet]=\"filterToolbar\"></ng-container>\n </div>\n }\n }\n <ng-container [ngTemplateOutlet]=\"filterActions\"></ng-container>\n </div>\n <ng-container *ngTemplateOutlet=\"filterStatusBarChips\"></ng-container>\n</div>\n<ng-template #filterStatusBarChips>\n @if (statusBar) {\n <div\n class=\"filter-status-container\"\n [ngClass]=\"{ 'has-status': !!filterStatus.textContent }\">\n <div\n class=\"filter-status\"\n #filterStatus>\n <ng-container *ngTemplateOutlet=\"statusBar.templateRef\"></ng-container>\n </div>\n </div>\n }\n @if (config.chips) {\n <fs-filter-chips class=\"filter-chips\"></fs-filter-chips>\n }\n</ng-template>\n<ng-template #filterActions>\n @if ((actionsVisible$ | async)) {\n <div class=\"filter-actions\">\n <fs-filter-actions\n [actions]=\"actions$ | async\"\n [kebabActions]=\"menuActions$ | async\">\n </fs-filter-actions>\n </div>\n }\n</ng-template>\n<ng-template #filterToolbar>\n @if (config.reload || config.autoReload || (filtersVisible$ | async)) {\n <div class=\"filter-toolbar\">\n @if ((filtersVisible$ | async)) {\n <a\n mat-icon-button\n class=\"button-filters\"\n (click)=\"filterButtonClick($event)\"\n [color]=\"config.button.color\">\n @if (config.button.icon) {\n <mat-icon [svgIcon]=\"'filterOutline'\"></mat-icon>\n }\n </a>\n }\n @if (config.reload) {\n <a\n mat-icon-button\n (click)=\"reload($event)\"\n class=\"button-reload\">\n <mat-icon #reloadEl>\n refresh\n </mat-icon>\n </a>\n }\n @if (config.autoReload) {\n <div class=\"filter-reload\">\n <mat-slide-toggle\n name=\"autoReload\"\n class=\"auto-reload\"\n [ngModel]=\"config.autoReload.enabled\"\n (ngModelChange)=\"config.autoReload.enabled = $event\">\n <span>\n Auto refresh\n </span>\n </mat-slide-toggle>\n </div>\n }\n </div>\n }\n</ng-template>\n<ng-template #heading>\n @if (headingTemplate) {\n <ng-container *ngTemplateOutlet=\"headingTemplate\"></ng-container>\n } @else if (config.heading) {\n <div class=\"heading\">\n <h2>\n {{ config.heading }}\n </h2>\n <div class=\"subheading\">\n {{ config.subheading }}\n </div>\n </div>\n }\n</ng-template>", styles: [":host{margin-bottom:20px;display:block}.filter-status-container{flex-grow:1;display:flex;justify-content:center;flex-direction:column;align-self:flex-end}.filter-status-container .filter-status{overflow:hidden;text-overflow:ellipsis}.filter-container{width:100%}.filter-container.has-input .heading{margin-bottom:10px}.filter-container.has-input .filter-bar-container{margin-bottom:4px}.filter-container.keyword-full-width .filter-input-container{flex:1}.filter-container.keyword-full-width .filter-input-container fs-keyword-input{flex:1}.filter-container.keyword-full-width .filter-input-container fs-keyword-input ::ng-deep mat-form-field{width:100%}.filter-container .filter-bar-container{flex-direction:row;box-sizing:border-box;display:flex;position:relative;align-items:center}.filter-container .filter-bar-container .filter-input-container{flex-direction:row;box-sizing:border-box;display:flex;align-items:center;min-width:0;gap:5px}.filter-container .filter-bar-container .filter-heading-container{flex-direction:row;box-sizing:border-box;display:flex;align-items:center;min-width:0}.filter-container .filter-bar-container .filter-heading-container fs-keyword-input+fs-saved-filter-autocomplete-chips{margin-left:5px}.filter-actions{display:flex;align-items:center;flex:1;justify-content:flex-end}.filter-toolbar{white-space:nowrap;display:flex;align-items:center}.filter-toolbar .button-filters,.filter-toolbar .button-reload{display:flex;--mdc-icon-button-state-layer-size: 40px;padding:8px}.filter-toolbar .button-filters ::ng-deep svg,.filter-toolbar .button-reload ::ng-deep svg{display:flex}.filter-toolbar .button-reload{display:flex;align-items:center}.filter-toolbar .button-reload .auto-reload{margin-right:5px}.filter-toolbar .button-reload .auto-reload span{font-size:80%}.heading{margin-right:8px}.heading h2{margin:0}.heading h2+.subheading{margin:0}@media screen and (min-width: 1200px){html.fs-filter-open body{margin-right:350px}}html.fs-filter-open{scrollbar-width:none}:host ::ng-deep .auto-reload.mat-checked .mat-slide-toggle-thumb-container{transform:translate3d(12px,0,0)}:host ::ng-deep .auto-reload:not(.mat-checked) .mat-slide-toggle-content{color:#ccc}:host ::ng-deep .auto-reload .mat-slide-toggle-thumb,:host ::ng-deep .auto-reload .mat-slide-toggle-thumb-container{height:15px;width:15px}:host ::ng-deep .auto-reload .mat-slide-toggle-content{font-size:90%}:host ::ng-deep .auto-reload .mat-slide-toggle-bar{width:26px;height:10px;border-radius:10px}\n"], dependencies: [{ kind: "directive", type: NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "component", type: FsSavedFilterAutocompleteChipsComponent, selector: "fs-saved-filter-autocomplete-chips", inputs: ["savedFiltersController"] }, { kind: "directive", type: NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "component", type: MatIcon, selector: "mat-icon", inputs: ["color", "inline", "svgIcon", "fontSet", "fontIcon"], exportAs: ["matIcon"] }, { kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i1$1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1$1.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "ngmodule", type: FsFormModule }, { kind: "directive", type: i3.FsFormNoFsValidatorsDirective, selector: "[ngModel]:not([required]):not([fsFormRequired]):not([fsFormCompare]):not([fsFormDateRange]):not([fsFormEmail]):not([fsFormEmails]):not([fsFormFunction]):not([fsFormGreater]):not([fsFormGreaterEqual]):not([fsFormInteger]):not([fsFormLesser]):not([fsFormMax]):not([fsFormMaxLength]):not([fsFormMin]):not([fsFormMinLength]):not([fsFormNumeric]):not([fsFormPattern]):not([fsFormPhone]):not([fsFormUrl]):not([validate])" }, { kind: "ngmodule", type: FsClearModule }, { kind: "component", type: FsFilterChipsComponent, selector: "fs-filter-chips" }, { kind: "component", type: FsFilterActionsComponent, selector: "fs-filter-actions", inputs: ["kebabActions", "actions"] }, { kind: "component", type: MatIconAnchor, selector: "a[mat-icon-button]", exportAs: ["matButton", "matAnchor"] }, { kind: "component", type: MatSlideToggle, selector: "mat-slide-toggle", inputs: ["name", "id", "labelPosition", "aria-label", "aria-labelledby", "aria-describedby", "required", "color", "disabled", "disableRipple", "tabIndex", "checked", "hideIcon", "disabledInteractive"], outputs: ["change", "toggleChange"], exportAs: ["matSlideToggle"] }, { kind: "pipe", type: AsyncPipe, name: "async" }, { kind: "component", type: KeywordInputComponent, selector: "fs-keyword-input", inputs: ["autofocus"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
3494
3548
  }
3495
3549
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: FilterComponent, decorators: [{
3496
3550
  type: Component,
@@ -3518,7 +3572,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.13", ngImpo
3518
3572
  MatSlideToggle,
3519
3573
  AsyncPipe,
3520
3574
  KeywordInputComponent,
3521
- ], template: "<div class=\"filter-container\">\n @if (filterInputVisible$ | async) {\n <ng-container *ngTemplateOutlet=\"header\"></ng-container>\n }\n <div class=\"filter-inner-container\">\n <div class=\"filter-left-container\">\n @if (filterInputVisible$ | async) {\n <div class=\"filter-inner-inputs\">\n @if (keywordVisible$ | async) {\n <fs-keyword-input [autofocus]=\"config.autofocus\"></fs-keyword-input>\n }\n @if (savedFilterController.enabled) {\n <fs-saved-filter-autocomplete-chips [savedFiltersController]=\"savedFilterController\"></fs-saved-filter-autocomplete-chips>\n }\n </div>\n } @else {\n <ng-container *ngTemplateOutlet=\"header\"></ng-container>\n <ng-container *ngTemplateOutlet=\"filterStatusBarChips\"></ng-container>\n }\n </div>\n <ng-container [ngTemplateOutlet]=\"filterToolbar\"></ng-container>\n <ng-container [ngTemplateOutlet]=\"filterActions\"></ng-container>\n </div>\n @if ((filterInputVisible$ | async)) {\n <ng-container *ngTemplateOutlet=\"filterStatusBarChips\"></ng-container>\n }\n</div>\n<ng-template #filterStatusBarChips>\n @if (statusBar) {\n <div\n class=\"filter-status-container\"\n [ngClass]=\"{ 'has-status': !!filterStatus.textContent }\">\n <div\n class=\"filter-status\"\n #filterStatus>\n <ng-container *ngTemplateOutlet=\"statusBar.templateRef\"></ng-container>\n </div>\n </div>\n }\n @if (config.chips) {\n <fs-filter-chips class=\"filter-chips\"></fs-filter-chips>\n }\n</ng-template>\n<ng-template #filterActions>\n @if ((actionsVisible$ | async)) {\n <div class=\"filter-actions\">\n <fs-filter-actions\n [actions]=\"actions$ | async\"\n [kebabActions]=\"menuActions$ | async\">\n </fs-filter-actions>\n </div>\n }\n</ng-template>\n<ng-template #filterToolbar>\n @if (config.reload || config.autoReload || (filtersVisible$ | async)) {\n <div class=\"filter-toolbar\">\n @if ((filtersVisible$ | async)) {\n <a\n mat-icon-button\n class=\"button-filters\"\n (click)=\"filterButtonClick($event)\"\n [color]=\"config.button.color\">\n @if (config.button.icon) {\n <mat-icon [svgIcon]=\"'filterOutline'\"></mat-icon>\n }\n </a>\n }\n @if (config.reload) {\n <a\n mat-icon-button\n (click)=\"reload($event)\"\n class=\"button-reload\">\n <mat-icon #reloadEl>\n refresh\n </mat-icon>\n </a>\n }\n @if (config.autoReload) {\n <div class=\"filter-reload\">\n <mat-slide-toggle\n name=\"autoReload\"\n class=\"auto-reload\"\n [ngModel]=\"config.autoReload.enabled\"\n (ngModelChange)=\"config.autoReload.enabled = $event\">\n <span>\n Auto refresh\n </span>\n </mat-slide-toggle>\n </div>\n }\n </div>\n }\n</ng-template>\n<ng-template #header>\n @if (heading) {\n <ng-container *ngTemplateOutlet=\"heading.templateRef\"></ng-container>\n } @else if (config.heading) {\n <div class=\"heading\">\n <h2>\n {{ config.heading }}\n </h2>\n <div class=\"subheading\">\n {{ config.subheading }}\n </div>\n </div>\n }\n</ng-template>", styles: [":host{margin-bottom:20px;display:block}.filter-status-container{flex-grow:1;display:flex;justify-content:center;flex-direction:column;align-self:flex-end;margin-top:4px}.filter-status-container .filter-status{overflow:hidden;text-overflow:ellipsis;line-height:18px}.filter-container{width:100%}.filter-inner-container{flex-direction:row;box-sizing:border-box;display:flex;position:relative;align-items:center}.filter-inner-container .filter-left-container{min-width:0}.filter-inner-container .filter-inner-inputs{flex-direction:row;box-sizing:border-box;display:flex;align-items:center;min-width:0;gap:5px}.filter-actions{display:flex;align-items:center;flex:1;justify-content:flex-end}.filter-toolbar{white-space:nowrap;display:flex;align-items:center}.filter-toolbar .button-filters,.filter-toolbar .button-reload{display:flex;--mdc-icon-button-state-layer-size: 40px;padding:8px}.filter-toolbar .button-filters ::ng-deep svg,.filter-toolbar .button-reload ::ng-deep svg{display:flex}.filter-toolbar .filter-reload{margin-left:10px;display:flex;align-items:center}.filter-toolbar .filter-reload .auto-reload{margin-right:5px}.filter-toolbar .filter-reload .auto-reload span{font-size:80%}.heading{margin-right:10px}.heading h2{margin:0}.heading h2+.subheading{margin:0}.results{min-height:90px;position:relative;overflow-x:auto;overflow-y:hidden}@media screen and (min-width: 1200px){html.fs-filter-open body{margin-right:350px}}html.fs-filter-open{scrollbar-width:none}:host ::ng-deep .auto-reload.mat-checked .mat-slide-toggle-thumb-container{transform:translate3d(12px,0,0)}:host ::ng-deep .auto-reload:not(.mat-checked) .mat-slide-toggle-content{color:#ccc}:host ::ng-deep .auto-reload .mat-slide-toggle-thumb,:host ::ng-deep .auto-reload .mat-slide-toggle-thumb-container{height:15px;width:15px}:host ::ng-deep .auto-reload .mat-slide-toggle-content{font-size:90%}:host ::ng-deep .auto-reload .mat-slide-toggle-bar{width:26px;height:10px;border-radius:10px}\n"] }]
3575
+ ], template: "<div\n class=\"filter-container\"\n [ngClass]=\"{ 'has-input': filterInputVisible$ | async }\"\n [ngClass]=\"{ 'keyword-full-width': keywordFullWidth$ | async }\">\n @if (filterInputVisible$ | async) {\n <ng-container *ngTemplateOutlet=\"heading\"></ng-container>\n }\n <div class=\"filter-bar-container\">\n @if (filterInputVisible$ | async) {\n <div class=\"filter-input-container\">\n @if (keywordVisible$ | async) {\n <fs-keyword-input [autofocus]=\"config.autofocus\"></fs-keyword-input>\n }\n @if (savedFilterController.enabled) {\n <fs-saved-filter-autocomplete-chips [savedFiltersController]=\"savedFilterController\"></fs-saved-filter-autocomplete-chips>\n }\n <ng-container [ngTemplateOutlet]=\"filterToolbar\"></ng-container>\n </div>\n } @else {\n @if (hasHeading) {\n <div class=\"filter-heading-container\">\n <ng-container *ngTemplateOutlet=\"heading\"></ng-container>\n <ng-container [ngTemplateOutlet]=\"filterToolbar\"></ng-container>\n </div>\n }\n }\n <ng-container [ngTemplateOutlet]=\"filterActions\"></ng-container>\n </div>\n <ng-container *ngTemplateOutlet=\"filterStatusBarChips\"></ng-container>\n</div>\n<ng-template #filterStatusBarChips>\n @if (statusBar) {\n <div\n class=\"filter-status-container\"\n [ngClass]=\"{ 'has-status': !!filterStatus.textContent }\">\n <div\n class=\"filter-status\"\n #filterStatus>\n <ng-container *ngTemplateOutlet=\"statusBar.templateRef\"></ng-container>\n </div>\n </div>\n }\n @if (config.chips) {\n <fs-filter-chips class=\"filter-chips\"></fs-filter-chips>\n }\n</ng-template>\n<ng-template #filterActions>\n @if ((actionsVisible$ | async)) {\n <div class=\"filter-actions\">\n <fs-filter-actions\n [actions]=\"actions$ | async\"\n [kebabActions]=\"menuActions$ | async\">\n </fs-filter-actions>\n </div>\n }\n</ng-template>\n<ng-template #filterToolbar>\n @if (config.reload || config.autoReload || (filtersVisible$ | async)) {\n <div class=\"filter-toolbar\">\n @if ((filtersVisible$ | async)) {\n <a\n mat-icon-button\n class=\"button-filters\"\n (click)=\"filterButtonClick($event)\"\n [color]=\"config.button.color\">\n @if (config.button.icon) {\n <mat-icon [svgIcon]=\"'filterOutline'\"></mat-icon>\n }\n </a>\n }\n @if (config.reload) {\n <a\n mat-icon-button\n (click)=\"reload($event)\"\n class=\"button-reload\">\n <mat-icon #reloadEl>\n refresh\n </mat-icon>\n </a>\n }\n @if (config.autoReload) {\n <div class=\"filter-reload\">\n <mat-slide-toggle\n name=\"autoReload\"\n class=\"auto-reload\"\n [ngModel]=\"config.autoReload.enabled\"\n (ngModelChange)=\"config.autoReload.enabled = $event\">\n <span>\n Auto refresh\n </span>\n </mat-slide-toggle>\n </div>\n }\n </div>\n }\n</ng-template>\n<ng-template #heading>\n @if (headingTemplate) {\n <ng-container *ngTemplateOutlet=\"headingTemplate\"></ng-container>\n } @else if (config.heading) {\n <div class=\"heading\">\n <h2>\n {{ config.heading }}\n </h2>\n <div class=\"subheading\">\n {{ config.subheading }}\n </div>\n </div>\n }\n</ng-template>", styles: [":host{margin-bottom:20px;display:block}.filter-status-container{flex-grow:1;display:flex;justify-content:center;flex-direction:column;align-self:flex-end}.filter-status-container .filter-status{overflow:hidden;text-overflow:ellipsis}.filter-container{width:100%}.filter-container.has-input .heading{margin-bottom:10px}.filter-container.has-input .filter-bar-container{margin-bottom:4px}.filter-container.keyword-full-width .filter-input-container{flex:1}.filter-container.keyword-full-width .filter-input-container fs-keyword-input{flex:1}.filter-container.keyword-full-width .filter-input-container fs-keyword-input ::ng-deep mat-form-field{width:100%}.filter-container .filter-bar-container{flex-direction:row;box-sizing:border-box;display:flex;position:relative;align-items:center}.filter-container .filter-bar-container .filter-input-container{flex-direction:row;box-sizing:border-box;display:flex;align-items:center;min-width:0;gap:5px}.filter-container .filter-bar-container .filter-heading-container{flex-direction:row;box-sizing:border-box;display:flex;align-items:center;min-width:0}.filter-container .filter-bar-container .filter-heading-container fs-keyword-input+fs-saved-filter-autocomplete-chips{margin-left:5px}.filter-actions{display:flex;align-items:center;flex:1;justify-content:flex-end}.filter-toolbar{white-space:nowrap;display:flex;align-items:center}.filter-toolbar .button-filters,.filter-toolbar .button-reload{display:flex;--mdc-icon-button-state-layer-size: 40px;padding:8px}.filter-toolbar .button-filters ::ng-deep svg,.filter-toolbar .button-reload ::ng-deep svg{display:flex}.filter-toolbar .button-reload{display:flex;align-items:center}.filter-toolbar .button-reload .auto-reload{margin-right:5px}.filter-toolbar .button-reload .auto-reload span{font-size:80%}.heading{margin-right:8px}.heading h2{margin:0}.heading h2+.subheading{margin:0}@media screen and (min-width: 1200px){html.fs-filter-open body{margin-right:350px}}html.fs-filter-open{scrollbar-width:none}:host ::ng-deep .auto-reload.mat-checked .mat-slide-toggle-thumb-container{transform:translate3d(12px,0,0)}:host ::ng-deep .auto-reload:not(.mat-checked) .mat-slide-toggle-content{color:#ccc}:host ::ng-deep .auto-reload .mat-slide-toggle-thumb,:host ::ng-deep .auto-reload .mat-slide-toggle-thumb-container{height:15px;width:15px}:host ::ng-deep .auto-reload .mat-slide-toggle-content{font-size:90%}:host ::ng-deep .auto-reload .mat-slide-toggle-bar{width:26px;height:10px;border-radius:10px}\n"] }]
3522
3576
  }], ctorParameters: () => [], propDecorators: { keywordInput: [{
3523
3577
  type: ViewChild,
3524
3578
  args: [KeywordInputComponent]
@@ -3537,9 +3591,9 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.13", ngImpo
3537
3591
  }], statusBar: [{
3538
3592
  type: ContentChild,
3539
3593
  args: [FilterStatusBarDirective]
3540
- }], heading: [{
3594
+ }], headingTemplate: [{
3541
3595
  type: ContentChild,
3542
- args: [FilterHeadingDirective]
3596
+ args: [FilterHeadingDirective, { read: TemplateRef }]
3543
3597
  }], reloadEl: [{
3544
3598
  type: ViewChild,
3545
3599
  args: ['reloadEl', { read: ElementRef }]