@drsutphin/ngx-mat-facet-toolkit 1.0.0

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.
Files changed (33) hide show
  1. package/README.md +62 -0
  2. package/_facet-toolkit-theme.scss +66 -0
  3. package/fesm2022/drsutphin-ngx-mat-facet-toolkit.mjs +1093 -0
  4. package/fesm2022/drsutphin-ngx-mat-facet-toolkit.mjs.map +1 -0
  5. package/index.d.ts +5 -0
  6. package/lib/directives/focus-on-show.directive.d.ts +12 -0
  7. package/lib/facet-toolkit.config.d.ts +4 -0
  8. package/lib/misc/parent.helper.d.ts +7 -0
  9. package/lib/modals/facet-details-modal/facet-details-modal.component.d.ts +41 -0
  10. package/lib/modals/facet-modal/facet-modal.animations.d.ts +4 -0
  11. package/lib/modals/facet-modal/facet-modal.component.d.ts +23 -0
  12. package/lib/modals/facet-modal.config.d.ts +12 -0
  13. package/lib/modals/facet-modal.data.d.ts +2 -0
  14. package/lib/modals/facet-modal.ref.d.ts +17 -0
  15. package/lib/modals/facet-modal.service.d.ts +14 -0
  16. package/lib/models/facet-data-type.model.d.ts +10 -0
  17. package/lib/models/facet-definition.model.d.ts +24 -0
  18. package/lib/models/facet-editor-state.model.d.ts +9 -0
  19. package/lib/models/facet-filter-type.model.d.ts +12 -0
  20. package/lib/models/facet-result.model.d.ts +10 -0
  21. package/lib/models/facet-selection.model.d.ts +9 -0
  22. package/lib/models/facet-toolkit-config.model.d.ts +14 -0
  23. package/lib/models/facet-value.model.d.ts +11 -0
  24. package/lib/models/index.d.ts +6 -0
  25. package/lib/ngx-mat-facet-toolkit.animations.d.ts +1 -0
  26. package/lib/ngx-mat-facet-toolkit.component.d.ts +80 -0
  27. package/lib/pipes/csv/csv.pipe.d.ts +9 -0
  28. package/lib/pipes/filter/filter.pipe.d.ts +9 -0
  29. package/lib/pipes/index.d.ts +3 -0
  30. package/lib/pipes/keys/keys.pipe.d.ts +7 -0
  31. package/lib/services/facet-storage.service.d.ts +28 -0
  32. package/package.json +45 -0
  33. package/public-api.d.ts +3 -0
@@ -0,0 +1,1093 @@
1
+ import * as i0 from '@angular/core';
2
+ import { InjectionToken, Input, Directive, ViewChildren, Inject, Component, EventEmitter, HostListener, HostBinding, ViewChild, Injector, Injectable, makeEnvironmentProviders, Pipe, input, output, signal, inject, ViewContainerRef, computed, effect } from '@angular/core';
3
+ import * as i2 from '@angular/common';
4
+ import { CommonModule } from '@angular/common';
5
+ import * as i3 from '@angular/forms';
6
+ import { FormsModule, ReactiveFormsModule } from '@angular/forms';
7
+ import * as i9$1 from '@angular/material/autocomplete';
8
+ import { MatAutocompleteModule, MatAutocompleteTrigger } from '@angular/material/autocomplete';
9
+ import * as i6 from '@angular/material/button';
10
+ import { MatButtonModule } from '@angular/material/button';
11
+ import * as i14 from '@angular/material/checkbox';
12
+ import { MatCheckboxModule } from '@angular/material/checkbox';
13
+ import * as i7$1 from '@angular/material/chips';
14
+ import { MatChipsModule } from '@angular/material/chips';
15
+ import { MatNativeDateModule, MatOptionModule } from '@angular/material/core';
16
+ import * as i13 from '@angular/material/datepicker';
17
+ import { MatDatepickerModule } from '@angular/material/datepicker';
18
+ import * as i11 from '@angular/material/form-field';
19
+ import { MatFormFieldModule } from '@angular/material/form-field';
20
+ import * as i5 from '@angular/material/icon';
21
+ import { MatIconModule } from '@angular/material/icon';
22
+ import * as i12 from '@angular/material/input';
23
+ import { MatInputModule } from '@angular/material/input';
24
+ import * as i10 from '@angular/material/list';
25
+ import { MatListModule } from '@angular/material/list';
26
+ import { MatProgressBarModule } from '@angular/material/progress-bar';
27
+ import * as i8 from '@angular/material/progress-spinner';
28
+ import { MatProgressSpinnerModule } from '@angular/material/progress-spinner';
29
+ import * as i15 from '@angular/material/select';
30
+ import { MatSelectModule } from '@angular/material/select';
31
+ import * as i4 from '@angular/material/toolbar';
32
+ import { MatToolbarModule } from '@angular/material/toolbar';
33
+ import * as i7 from '@angular/material/tooltip';
34
+ import { MatTooltipModule } from '@angular/material/tooltip';
35
+ import { A11yModule } from '@angular/cdk/a11y';
36
+ import * as i1$1 from '@angular/cdk/overlay';
37
+ import { OverlayModule } from '@angular/cdk/overlay';
38
+ import * as i1 from '@angular/cdk/portal';
39
+ import { BasePortalOutlet, PortalModule, CdkPortalOutlet, ComponentPortal } from '@angular/cdk/portal';
40
+ import { Subject, BehaviorSubject, of, fromEvent, isObservable } from 'rxjs';
41
+ import { filter, tap, debounceTime, distinctUntilChanged, map } from 'rxjs/operators';
42
+ import * as i9 from '@angular/material/divider';
43
+ import { MatDividerModule } from '@angular/material/divider';
44
+ import { trigger, transition, style, animate, state } from '@angular/animations';
45
+ import { v4 } from 'uuid';
46
+
47
+ var FacetDataType;
48
+ (function (FacetDataType) {
49
+ FacetDataType["Text"] = "Text";
50
+ // eslint-disable-next-line id-blacklist
51
+ FacetDataType["Boolean"] = "Boolean";
52
+ FacetDataType["Category"] = "Category";
53
+ FacetDataType["CategorySingle"] = "CategorySingle";
54
+ FacetDataType["Date"] = "Date";
55
+ FacetDataType["DateRange"] = "DateRange";
56
+ FacetDataType["Typeahead"] = "Typeahead";
57
+ FacetDataType["TypeaheadSingle"] = "TypeaheadSingle";
58
+ })(FacetDataType || (FacetDataType = {}));
59
+
60
+ var FacetFilterType;
61
+ (function (FacetFilterType) {
62
+ FacetFilterType["contains"] = "contains";
63
+ FacetFilterType["startsWith"] = "startsWith";
64
+ FacetFilterType["endsWith"] = "endsWith";
65
+ FacetFilterType["equal"] = "equal";
66
+ FacetFilterType["and"] = "and";
67
+ FacetFilterType["between"] = "between";
68
+ FacetFilterType["greaterThan"] = "greaterThan";
69
+ FacetFilterType["lessThan"] = "lessThan";
70
+ FacetFilterType["greaterThanOrEqual"] = "greaterThanOrEqual";
71
+ FacetFilterType["lessThanOrEqual"] = "lessThanOrEqual";
72
+ })(FacetFilterType || (FacetFilterType = {}));
73
+
74
+ var FacetIdentifierStrategy;
75
+ (function (FacetIdentifierStrategy) {
76
+ FacetIdentifierStrategy["WindowURL"] = "windowURL";
77
+ FacetIdentifierStrategy["ParentID"] = "parentID";
78
+ FacetIdentifierStrategy["Random"] = "random";
79
+ FacetIdentifierStrategy["Manual"] = "manual";
80
+ })(FacetIdentifierStrategy || (FacetIdentifierStrategy = {}));
81
+ const DEFAULT_FACET_TOOLKIT_CONFIG = {
82
+ allowDebugClick: false,
83
+ identifierStrategy: FacetIdentifierStrategy.ParentID,
84
+ loggingCallback: () => { },
85
+ storage: 'session'
86
+ };
87
+
88
+ const FACET_MODAL_DATA = new InjectionToken('facet.data');
89
+
90
+ var FacetResultType;
91
+ (function (FacetResultType) {
92
+ FacetResultType[FacetResultType["REMOVE"] = 0] = "REMOVE";
93
+ FacetResultType[FacetResultType["CANCEL"] = 1] = "CANCEL";
94
+ FacetResultType[FacetResultType["ADD"] = 2] = "ADD";
95
+ })(FacetResultType || (FacetResultType = {}));
96
+
97
+ class FocusOnShowDirective {
98
+ el;
99
+ timeout = '0';
100
+ firstElement = true;
101
+ constructor(el) {
102
+ this.el = el;
103
+ if (!el.nativeElement.focus) {
104
+ throw new Error('Element does not accept focus.');
105
+ }
106
+ }
107
+ ngOnInit() {
108
+ if (this.firstElement) {
109
+ setTimeout(() => {
110
+ this.focusInput();
111
+ }, (Number(this.timeout) || 0));
112
+ }
113
+ }
114
+ focusInput() {
115
+ const input = this.el.nativeElement;
116
+ input.focus();
117
+ if (this.el.nativeElement.hasOwnProperty('select')) {
118
+ input.select();
119
+ }
120
+ }
121
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.17", ngImport: i0, type: FocusOnShowDirective, deps: [{ token: i0.ElementRef }], target: i0.ɵɵFactoryTarget.Directive });
122
+ static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "19.2.17", type: FocusOnShowDirective, isStandalone: true, selector: "[focusOnShow]", inputs: { timeout: ["focusOnShow", "timeout"], firstElement: "firstElement" }, ngImport: i0 });
123
+ }
124
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.17", ngImport: i0, type: FocusOnShowDirective, decorators: [{
125
+ type: Directive,
126
+ args: [{
127
+ selector: '[focusOnShow]',
128
+ standalone: true
129
+ }]
130
+ }], ctorParameters: () => [{ type: i0.ElementRef }], propDecorators: { timeout: [{
131
+ type: Input,
132
+ args: ['focusOnShow']
133
+ }], firstElement: [{
134
+ type: Input
135
+ }] } });
136
+
137
+ class FacetModalRef {
138
+ overlayRef;
139
+ positionStrategy;
140
+ config;
141
+ afterClosedSubject = new Subject();
142
+ beforeClosedSubject = new Subject();
143
+ _result = { type: FacetResultType.CANCEL };
144
+ constructor(overlayRef, positionStrategy, config) {
145
+ this.overlayRef = overlayRef;
146
+ this.positionStrategy = positionStrategy;
147
+ this.config = config;
148
+ if (!config.disableClose) {
149
+ this.overlayRef.backdropClick().subscribe(() => {
150
+ this.close(this._result);
151
+ });
152
+ this.overlayRef.detachments().subscribe(() => {
153
+ this.beforeClosedSubject.next(this._result);
154
+ this.beforeClosedSubject.complete();
155
+ });
156
+ this.overlayRef.keydownEvents().pipe(filter(event => event.key === 'Escape')).subscribe(() => {
157
+ this.close();
158
+ });
159
+ }
160
+ }
161
+ close(dialogResult) {
162
+ if (!!dialogResult) {
163
+ this._result = dialogResult;
164
+ }
165
+ this.beforeClosedSubject.next(this._result);
166
+ this.beforeClosedSubject.complete();
167
+ this.afterClosedSubject.next(this._result);
168
+ this.afterClosedSubject.complete();
169
+ this.overlayRef.dispose();
170
+ }
171
+ afterClosed() {
172
+ return this.afterClosedSubject.asObservable();
173
+ }
174
+ beforeClosed() {
175
+ return this.beforeClosedSubject.asObservable();
176
+ }
177
+ positionChanges() {
178
+ return this.positionStrategy.positionChanges;
179
+ }
180
+ }
181
+
182
+ const MAX_TEXT_LENGTH = 60;
183
+ class FacetDetailsModalComponent {
184
+ data;
185
+ modalRef;
186
+ typeAheadInputs;
187
+ isUpdate;
188
+ typeaheadText;
189
+ clearButtonDisabled = true;
190
+ resolvedOptions$;
191
+ FacetDataType = FacetDataType;
192
+ FacetFilterType = FacetFilterType;
193
+ typeAheadInputChanged = new BehaviorSubject('');
194
+ constructor(data, modalRef) {
195
+ this.data = data;
196
+ this.modalRef = modalRef;
197
+ this.isUpdate = modalRef.config.isUpdate;
198
+ }
199
+ ngOnInit() {
200
+ switch (this.data.type) {
201
+ case FacetDataType.Typeahead:
202
+ case FacetDataType.TypeaheadSingle:
203
+ if (this.data.typeahead?.provider) {
204
+ this.resolvedOptions$ = this.data.typeahead.provider('');
205
+ }
206
+ break;
207
+ case FacetDataType.Date:
208
+ this.data.values = this.data.values?.length ? this.data.values : [{ value: null }];
209
+ break;
210
+ case FacetDataType.DateRange:
211
+ this.data.values = this.data.values?.length ? this.data.values : [{ value: null }, { value: null }];
212
+ break;
213
+ case FacetDataType.Boolean:
214
+ this.data.values = this.data.values?.length ? this.data.values : [{ value: null }];
215
+ break;
216
+ case FacetDataType.Text:
217
+ this.data.values = this.data.values?.length ? this.data.values : [{ value: '' }];
218
+ this.data.filterType = this.data.filterType || this.data.fixedFilterType || FacetFilterType.contains;
219
+ break;
220
+ default:
221
+ this.data.values = this.data.values?.length ? this.data.values : [{ value: null }];
222
+ }
223
+ if (!this.resolvedOptions$ && this.data.options) {
224
+ this.resolvedOptions$ = this.normalizeOptions(this.data.options);
225
+ }
226
+ }
227
+ ngAfterViewInit() {
228
+ if (this.typeAheadInputs.length > 0) {
229
+ this.typeAheadInputChanged.pipe(tap(() => this.resolvedOptions$ = undefined), debounceTime(this.data.typeahead?.debounce || 300)).subscribe(search => {
230
+ if (!!this.data.typeahead?.provider) {
231
+ this.data.typeahead.provider((search || '')).subscribe(options => {
232
+ this.resolvedOptions$ = of(options || []);
233
+ });
234
+ }
235
+ });
236
+ }
237
+ }
238
+ typeaheadValueChanged(event) {
239
+ this.typeAheadInputChanged.next(event || '');
240
+ this.clearButtonDisabled = (!event || event.length === 0);
241
+ }
242
+ truncateText(txt) {
243
+ if (txt && txt.length) {
244
+ return txt.length > MAX_TEXT_LENGTH ?
245
+ `${txt.substring(0, MAX_TEXT_LENGTH).trim()}...` :
246
+ txt;
247
+ }
248
+ else {
249
+ return txt;
250
+ }
251
+ }
252
+ onOk() {
253
+ this.modalRef.close({
254
+ type: FacetResultType.ADD,
255
+ data: this.data
256
+ });
257
+ }
258
+ onRemove() {
259
+ this.modalRef.close({
260
+ type: FacetResultType.REMOVE,
261
+ data: this.data
262
+ });
263
+ }
264
+ onCancel() {
265
+ this.modalRef.close({
266
+ type: FacetResultType.CANCEL,
267
+ });
268
+ }
269
+ onClose() {
270
+ this.modalRef.close();
271
+ }
272
+ validateAndSubmit() {
273
+ if (!this.isUpdateButtonDisabled()) {
274
+ this.onOk();
275
+ }
276
+ }
277
+ isItemSelected = (option) => (this.data.values || []).some(o => o.value === option.value);
278
+ addOptionToSelected = (facet, option) => {
279
+ const isSelected = (facet.values || []).some(f => f.value === option.value);
280
+ if (isSelected && (facet.type === FacetDataType.Category || facet.type === FacetDataType.Typeahead)) {
281
+ facet.values = (facet.values || []).filter(f => f.value !== option.value);
282
+ }
283
+ else {
284
+ option.selected = true;
285
+ switch (facet.type) {
286
+ case FacetDataType.Category:
287
+ case FacetDataType.Typeahead:
288
+ facet.values = (facet.values || []);
289
+ facet.values.push(option);
290
+ break;
291
+ case FacetDataType.CategorySingle:
292
+ case FacetDataType.TypeaheadSingle:
293
+ facet.values = [option];
294
+ break;
295
+ }
296
+ }
297
+ };
298
+ isUpdateButtonDisabled = () => {
299
+ switch (this.data.type) {
300
+ case FacetDataType.Category:
301
+ case FacetDataType.CategorySingle:
302
+ case FacetDataType.Date:
303
+ case FacetDataType.Text:
304
+ case FacetDataType.Typeahead:
305
+ case FacetDataType.TypeaheadSingle:
306
+ return !(this.data.values || []).some(v => !!v?.value);
307
+ case FacetDataType.DateRange:
308
+ return !(this.getRawValue(this.data)) || !(this.getRawValue(this.data, 1));
309
+ case FacetDataType.Boolean:
310
+ return !(this.getRawValue(this.data));
311
+ }
312
+ };
313
+ emptyFunction() { }
314
+ clearInput() {
315
+ this.typeaheadText = null;
316
+ this.typeaheadValueChanged('');
317
+ }
318
+ getRawValue(facet, offset) {
319
+ if (!!facet?.values?.length && facet.values[offset || 0]) {
320
+ return facet.values[offset || 0].value;
321
+ }
322
+ return null;
323
+ }
324
+ setValue(facet, newValue, offset) {
325
+ if (!!facet?.values?.length && facet.values[offset || 0]) {
326
+ facet.values[offset || 0] = {
327
+ ...facet.values[offset || 0],
328
+ value: newValue
329
+ };
330
+ }
331
+ }
332
+ setType(newType) {
333
+ this.data.filterType = newType;
334
+ }
335
+ normalizeOptions(options) {
336
+ return Array.isArray(options) ? of(options) : options;
337
+ }
338
+ selectionChange(selection, facet, options) {
339
+ selection.options
340
+ .map(selectedOption => (options || []).find(option => option.value === selectedOption.value))
341
+ .filter((option) => !!option)
342
+ .filter(facetOption => !(facet.values || []).find(v => v.value === facetOption.value))
343
+ .forEach(selectedOption => this.addOptionToSelected(facet, selectedOption));
344
+ }
345
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.17", ngImport: i0, type: FacetDetailsModalComponent, deps: [{ token: FACET_MODAL_DATA }, { token: FacetModalRef }], target: i0.ɵɵFactoryTarget.Component });
346
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "19.2.17", type: FacetDetailsModalComponent, isStandalone: true, selector: "ngx-mat-facet-details-modal", viewQueries: [{ propertyName: "typeAheadInputs", predicate: ["typeAheadInput"], descendants: true }], ngImport: i0, template: "<div class=\"mat-typography details\">\n\n <mat-toolbar color=\"primary\" class=\"modal-header\">\n <h2 class=\"modal-title\">{{data.label}}</h2>\n <button class=\"modal-close\" mat-icon-button (click)=\"onCancel()\">\n <mat-icon>clear</mat-icon>\n </button>\n </mat-toolbar>\n\n <div class=\"content\">\n\n @if (data.description) {\n <p class=\"description\">{{data.description}}</p>\n }\n\n <ng-template #loading>\n <mat-spinner diameter=\"20\"></mat-spinner>\n </ng-template>\n\n <ng-template #noResults>\n <span class=\"facet-no-results\" @fadeIn>No Results</span>\n </ng-template>\n\n @switch (true) {\n @case (data.type === FacetDataType.Category || data.type === FacetDataType.CategorySingle) {\n <div class=\"category-wrapper\">\n @if (resolvedOptions$ | async; as options) {\n <mat-divider></mat-divider>\n @if (options.length > 0) {\n <mat-selection-list (selectionChange)=\"selectionChange($event, data, options)\">\n @for (item of options; track item.value) {\n <mat-list-option [value]=\"item.value\" [selected]=\"isItemSelected(item)\"\n @fadeIn\n focusOnShow\n [firstElement]=\"$first\">\n <span>\n {{ item.label ? truncateText(item.label) : \"- empty -\" }}\n @if (item.count) {\n <small><i>({{item.count}})</i></small>\n }\n </span>\n </mat-list-option>\n }\n </mat-selection-list>\n } @else {\n <ng-container *ngTemplateOutlet=\"noResults\"></ng-container>\n }\n <mat-divider></mat-divider>\n } @else {\n <ng-container *ngTemplateOutlet=\"loading\"></ng-container>\n }\n </div>\n }\n @case (data.type === FacetDataType.Typeahead || data.type === FacetDataType.TypeaheadSingle) {\n <div class=\"typeahead-wrapper\">\n\n <mat-form-field class=\"typeahead-form-field\" appearance=\"outline\" floatLabel=\"auto\">\n <mat-label>Search...</mat-label>\n <input matInput #typeAheadInput\n autocomplete=\"off\"\n focusOnShow=\"100\"\n [(ngModel)]=\"typeaheadText\"\n placeholder=\"{{(data.typeahead || {placeholder: ''}).placeholder}}\"\n (ngModelChange)=\"typeaheadValueChanged($event)\"/>\n\n @if (!clearButtonDisabled) {\n <button matSuffix mat-icon-button aria-label=\"Clear\" (click)=\"clearInput()\">\n <mat-icon>clear</mat-icon>\n </button>\n }\n </mat-form-field>\n\n @if (resolvedOptions$ | async; as options) {\n <mat-divider></mat-divider>\n @if (options.length > 0) {\n <mat-selection-list (selectionChange)=\"selectionChange($event, data, options)\">\n @for (item of options; track item.value) {\n <mat-list-option [value]=\"item.value\"\n @fadeIn\n focusOnShow\n [firstElement]=\"$first\"\n [selected]=\"isItemSelected(item)\">\n <span>\n {{ item.label ? truncateText(item.label) : \"- empty -\" }}\n @if (item.count) {\n <small><i>({{item.count}})</i></small>\n }\n </span>\n </mat-list-option>\n }\n </mat-selection-list>\n } @else {\n <ng-container *ngTemplateOutlet=\"noResults\"></ng-container>\n }\n <mat-divider></mat-divider>\n } @else {\n <ng-container *ngTemplateOutlet=\"loading\"></ng-container>\n }\n\n </div>\n }\n @case (data.type === FacetDataType.Date) {\n <div class=\"date-wrapper\">\n\n <mat-form-field appearance=\"outline\" floatLabel=\"always\" class=\"date-field\">\n <mat-label>{{data.label}}</mat-label>\n <input matInput autocomplete=\"off\" focusOnShow=\"100\" [matDatepicker]=\"picker\" [ngModel]=\"getRawValue(data)\" (ngModelChange)=\"setValue(data, $event)\"\n placeholder=\"Choose a date\" (focus)=\"isUpdate ? emptyFunction() : picker.open()\"/>\n <mat-datepicker-toggle matSuffix [for]=\"picker\"></mat-datepicker-toggle>\n </mat-form-field>\n <mat-datepicker #picker></mat-datepicker>\n\n </div>\n }\n @case (data.type === FacetDataType.DateRange) {\n <div class=\"date-range-wrapper\">\n\n <mat-form-field appearance=\"outline\" floatLabel=\"always\">\n <mat-label>{{data.label}} - Start</mat-label>\n <input matInput focusOnShow=\"100\" autocomplete=\"off\" [matDatepicker]=\"startDatePicker\"\n [ngModel]=\"getRawValue(data)\" (ngModelChange)=\"setValue(data, $event)\" placeholder=\"Choose a starting date\"\n (focus)=\"isUpdate ? emptyFunction() : startDatePicker.open()\"/>\n <mat-datepicker-toggle matSuffix [for]=\"startDatePicker\"></mat-datepicker-toggle>\n </mat-form-field>\n <mat-datepicker #startDatePicker></mat-datepicker>\n\n <mat-form-field appearance=\"outline\" floatLabel=\"always\">\n <mat-label>{{data.label}} - End</mat-label>\n <input matInput autocomplete=\"off\" [matDatepicker]=\"endDatePicker\"\n [ngModel]=\"getRawValue(data, 1)\" (ngModelChange)=\"setValue(data, $event, 1)\" placeholder=\"Choose an end date\"/>\n <mat-datepicker-toggle matSuffix [for]=\"endDatePicker\"></mat-datepicker-toggle>\n </mat-form-field>\n <mat-datepicker #endDatePicker></mat-datepicker>\n\n </div>\n }\n @case (data.type === FacetDataType.Text) {\n <div class=\"text-wrapper\">\n\n <mat-form-field class=\"criteria-field\" appearance=\"outline\">\n <mat-label>Criteria Type</mat-label>\n <mat-select [value]=\"data.fixedFilterType || data.filterType\"\n (valueChange)=\"setType($event)\" placeholder=\"Criteria Type\">\n <mat-option [value]=\"FacetFilterType.contains\">Contains</mat-option>\n <mat-option [value]=\"FacetFilterType.endsWith\">Ends With</mat-option>\n <mat-option [value]=\"FacetFilterType.equal\">Equals</mat-option>\n <mat-option [value]=\"FacetFilterType.startsWith\">Starts With</mat-option>\n </mat-select>\n </mat-form-field>\n\n <mat-form-field class=\"search-field\" appearance=\"outline\">\n <mat-label>Search Text</mat-label>\n <input matInput focusOnShow (keydown.enter)=\"validateAndSubmit()\" autocomplete=\"off\"\n [ngModel]=\"getRawValue(data)\" (ngModelChange)=\"setValue(data, $event)\"\n placeholder=\"{{data.placeholder || data.label }}\" autofocus/>\n @if (data.values) {\n <button matSuffix mat-icon-button aria-label=\"Clear\" (click)=\"data.values = []\">\n <mat-icon>close</mat-icon>\n </button>\n }\n </mat-form-field>\n\n </div>\n }\n @case (data.type === FacetDataType.Boolean) {\n <div class=\"boolean-wrapper\">\n <mat-checkbox [ngModel]=\"getRawValue(data)\" (ngModelChange)=\"setValue(data, $event)\">{{data.placeholder || data.label}}</mat-checkbox>\n </div>\n }\n }\n\n </div>\n\n <div class=\"actions\">\n\n <button mat-flat-button class=\"add-update-button\" [color]=\"isUpdate ? 'accent' : 'primary'\" (click)=\"onOk()\"\n [disabled]=\"isUpdateButtonDisabled()\">{{isUpdate ? 'Update' : 'Add'}}</button>\n\n @if (isUpdate) {\n <button mat-icon-button class=\"remove-button\" color=\"warn\" (click)=\"onRemove()\" matTooltip=\"Delete Filter\" matTooltipPosition=\"after\">\n <mat-icon>delete</mat-icon>\n </button>\n }\n\n </div>\n</div>\n", styles: ["mat-spinner{margin:1em auto}.details{display:flex;flex-direction:column;align-items:stretch}.content{min-height:120px;padding-top:22px;display:flex;flex-direction:column;align-items:normal}.content mat-selection-list{flex:1;max-height:30vh;overflow-y:auto}.actions{padding:16px;display:flex;justify-content:space-between;flex-direction:row-reverse}span.facet-no-results{text-align:center;color:gray;margin-top:1em;margin-bottom:1em}.mat-selection-list{margin-top:0;padding-top:0}.mat-form-field{margin:0!important;padding-left:15px;padding-right:15px}.mat-dialog-actions{padding:0 15px 15px}.modal-header{display:flex;justify-content:space-between;align-items:center!important;border-top-left-radius:8px;border-top-right-radius:8px}.modal-header .modal-title{height:40px!important;margin:0!important;line-height:45px}p.description{padding-left:15px;padding-right:15px;margin-bottom:0;color:gray;flex:1}.date-range-wrapper{padding-left:15px;padding-right:15px;display:flex;flex-direction:column;align-items:stretch;justify-content:space-between}.date-range-wrapper,.category-wrapper{margin-top:1em}.boolean-wrapper{padding-left:15px;padding-right:15px;flex:4;display:flex;justify-content:flex-start;align-items:center}.text-wrapper{padding-left:15px;padding-right:15px;display:flex;flex-direction:column;flex:2;margin-top:1rem}.date-wrapper{padding-left:15px;padding-right:15px;display:flex;justify-content:center;align-items:center}.date-wrapper .date-field{flex:1}.typeahead-wrapper{padding-left:15px;padding-right:15px;display:flex;flex-direction:column;align-items:stretch;margin-top:1em}.typeahead-wrapper .typeahead-form-field{flex:1}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i2.NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "pipe", type: i2.AsyncPipe, name: "async" }, { kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i3.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { kind: "directive", type: i3.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i3.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "ngmodule", type: MatToolbarModule }, { kind: "component", type: i4.MatToolbar, selector: "mat-toolbar", inputs: ["color"], exportAs: ["matToolbar"] }, { kind: "ngmodule", type: MatIconModule }, { kind: "component", type: i5.MatIcon, selector: "mat-icon", inputs: ["color", "inline", "svgIcon", "fontSet", "fontIcon"], exportAs: ["matIcon"] }, { kind: "ngmodule", type: MatButtonModule }, { kind: "component", type: i6.MatButton, selector: " button[mat-button], button[mat-raised-button], button[mat-flat-button], button[mat-stroked-button] ", exportAs: ["matButton"] }, { kind: "component", type: i6.MatIconButton, selector: "button[mat-icon-button]", exportAs: ["matButton"] }, { kind: "ngmodule", type: MatTooltipModule }, { kind: "directive", type: i7.MatTooltip, selector: "[matTooltip]", inputs: ["matTooltipPosition", "matTooltipPositionAtOrigin", "matTooltipDisabled", "matTooltipShowDelay", "matTooltipHideDelay", "matTooltipTouchGestures", "matTooltip", "matTooltipClass"], exportAs: ["matTooltip"] }, { kind: "ngmodule", type: MatProgressSpinnerModule }, { kind: "component", type: i8.MatProgressSpinner, selector: "mat-progress-spinner, mat-spinner", inputs: ["color", "mode", "value", "diameter", "strokeWidth"], exportAs: ["matProgressSpinner"] }, { kind: "ngmodule", type: MatDividerModule }, { kind: "component", type: i9.MatDivider, selector: "mat-divider", inputs: ["vertical", "inset"] }, { kind: "ngmodule", type: MatListModule }, { kind: "component", type: i10.MatSelectionList, selector: "mat-selection-list", inputs: ["color", "compareWith", "multiple", "hideSingleSelectionIndicator", "disabled"], outputs: ["selectionChange"], exportAs: ["matSelectionList"] }, { kind: "component", type: i10.MatListOption, selector: "mat-list-option", inputs: ["togglePosition", "checkboxPosition", "color", "value", "selected"], outputs: ["selectedChange"], exportAs: ["matListOption"] }, { kind: "ngmodule", type: MatFormFieldModule }, { kind: "component", type: i11.MatFormField, selector: "mat-form-field", inputs: ["hideRequiredMarker", "color", "floatLabel", "appearance", "subscriptSizing", "hintLabel"], exportAs: ["matFormField"] }, { kind: "directive", type: i11.MatLabel, selector: "mat-label" }, { kind: "directive", type: i11.MatSuffix, selector: "[matSuffix], [matIconSuffix], [matTextSuffix]", inputs: ["matTextSuffix"] }, { kind: "ngmodule", type: MatInputModule }, { kind: "directive", type: i12.MatInput, selector: "input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]", inputs: ["disabled", "id", "placeholder", "name", "required", "type", "errorStateMatcher", "aria-describedby", "value", "readonly", "disabledInteractive"], exportAs: ["matInput"] }, { kind: "ngmodule", type: MatDatepickerModule }, { kind: "component", type: i13.MatDatepicker, selector: "mat-datepicker", exportAs: ["matDatepicker"] }, { kind: "directive", type: i13.MatDatepickerInput, selector: "input[matDatepicker]", inputs: ["matDatepicker", "min", "max", "matDatepickerFilter"], exportAs: ["matDatepickerInput"] }, { kind: "component", type: i13.MatDatepickerToggle, selector: "mat-datepicker-toggle", inputs: ["for", "tabIndex", "aria-label", "disabled", "disableRipple"], exportAs: ["matDatepickerToggle"] }, { kind: "ngmodule", type: MatNativeDateModule }, { kind: "ngmodule", type: MatCheckboxModule }, { kind: "component", type: i14.MatCheckbox, selector: "mat-checkbox", inputs: ["aria-label", "aria-labelledby", "aria-describedby", "aria-expanded", "aria-controls", "aria-owns", "id", "required", "labelPosition", "name", "value", "disableRipple", "tabIndex", "color", "disabledInteractive", "checked", "disabled", "indeterminate"], outputs: ["change", "indeterminateChange"], exportAs: ["matCheckbox"] }, { kind: "ngmodule", type: MatSelectModule }, { kind: "component", type: i15.MatSelect, selector: "mat-select", inputs: ["aria-describedby", "panelClass", "disabled", "disableRipple", "tabIndex", "hideSingleSelectionIndicator", "placeholder", "required", "multiple", "disableOptionCentering", "compareWith", "value", "aria-label", "aria-labelledby", "errorStateMatcher", "typeaheadDebounceInterval", "sortComparator", "id", "panelWidth", "canSelectNullableOptions"], outputs: ["openedChange", "opened", "closed", "selectionChange", "valueChange"], exportAs: ["matSelect"] }, { kind: "component", type: i15.MatOption, selector: "mat-option", inputs: ["value", "id", "disabled"], outputs: ["onSelectionChange"], exportAs: ["matOption"] }, { kind: "ngmodule", type: MatOptionModule }, { kind: "directive", type: FocusOnShowDirective, selector: "[focusOnShow]", inputs: ["focusOnShow", "firstElement"] }], animations: [
347
+ trigger('fadeIn', [
348
+ transition(':enter', [
349
+ style({ opacity: '0', height: 0 }),
350
+ animate('.2s ease-out', style({ opacity: '1', height: '*' })),
351
+ ]),
352
+ ]),
353
+ ] });
354
+ }
355
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.17", ngImport: i0, type: FacetDetailsModalComponent, decorators: [{
356
+ type: Component,
357
+ args: [{ selector: 'ngx-mat-facet-details-modal', standalone: true, imports: [
358
+ CommonModule,
359
+ FormsModule,
360
+ MatToolbarModule,
361
+ MatIconModule,
362
+ MatButtonModule,
363
+ MatTooltipModule,
364
+ MatProgressSpinnerModule,
365
+ MatDividerModule,
366
+ MatListModule,
367
+ MatFormFieldModule,
368
+ MatInputModule,
369
+ MatDatepickerModule,
370
+ MatNativeDateModule,
371
+ MatCheckboxModule,
372
+ MatSelectModule,
373
+ MatOptionModule,
374
+ FocusOnShowDirective
375
+ ], animations: [
376
+ trigger('fadeIn', [
377
+ transition(':enter', [
378
+ style({ opacity: '0', height: 0 }),
379
+ animate('.2s ease-out', style({ opacity: '1', height: '*' })),
380
+ ]),
381
+ ]),
382
+ ], template: "<div class=\"mat-typography details\">\n\n <mat-toolbar color=\"primary\" class=\"modal-header\">\n <h2 class=\"modal-title\">{{data.label}}</h2>\n <button class=\"modal-close\" mat-icon-button (click)=\"onCancel()\">\n <mat-icon>clear</mat-icon>\n </button>\n </mat-toolbar>\n\n <div class=\"content\">\n\n @if (data.description) {\n <p class=\"description\">{{data.description}}</p>\n }\n\n <ng-template #loading>\n <mat-spinner diameter=\"20\"></mat-spinner>\n </ng-template>\n\n <ng-template #noResults>\n <span class=\"facet-no-results\" @fadeIn>No Results</span>\n </ng-template>\n\n @switch (true) {\n @case (data.type === FacetDataType.Category || data.type === FacetDataType.CategorySingle) {\n <div class=\"category-wrapper\">\n @if (resolvedOptions$ | async; as options) {\n <mat-divider></mat-divider>\n @if (options.length > 0) {\n <mat-selection-list (selectionChange)=\"selectionChange($event, data, options)\">\n @for (item of options; track item.value) {\n <mat-list-option [value]=\"item.value\" [selected]=\"isItemSelected(item)\"\n @fadeIn\n focusOnShow\n [firstElement]=\"$first\">\n <span>\n {{ item.label ? truncateText(item.label) : \"- empty -\" }}\n @if (item.count) {\n <small><i>({{item.count}})</i></small>\n }\n </span>\n </mat-list-option>\n }\n </mat-selection-list>\n } @else {\n <ng-container *ngTemplateOutlet=\"noResults\"></ng-container>\n }\n <mat-divider></mat-divider>\n } @else {\n <ng-container *ngTemplateOutlet=\"loading\"></ng-container>\n }\n </div>\n }\n @case (data.type === FacetDataType.Typeahead || data.type === FacetDataType.TypeaheadSingle) {\n <div class=\"typeahead-wrapper\">\n\n <mat-form-field class=\"typeahead-form-field\" appearance=\"outline\" floatLabel=\"auto\">\n <mat-label>Search...</mat-label>\n <input matInput #typeAheadInput\n autocomplete=\"off\"\n focusOnShow=\"100\"\n [(ngModel)]=\"typeaheadText\"\n placeholder=\"{{(data.typeahead || {placeholder: ''}).placeholder}}\"\n (ngModelChange)=\"typeaheadValueChanged($event)\"/>\n\n @if (!clearButtonDisabled) {\n <button matSuffix mat-icon-button aria-label=\"Clear\" (click)=\"clearInput()\">\n <mat-icon>clear</mat-icon>\n </button>\n }\n </mat-form-field>\n\n @if (resolvedOptions$ | async; as options) {\n <mat-divider></mat-divider>\n @if (options.length > 0) {\n <mat-selection-list (selectionChange)=\"selectionChange($event, data, options)\">\n @for (item of options; track item.value) {\n <mat-list-option [value]=\"item.value\"\n @fadeIn\n focusOnShow\n [firstElement]=\"$first\"\n [selected]=\"isItemSelected(item)\">\n <span>\n {{ item.label ? truncateText(item.label) : \"- empty -\" }}\n @if (item.count) {\n <small><i>({{item.count}})</i></small>\n }\n </span>\n </mat-list-option>\n }\n </mat-selection-list>\n } @else {\n <ng-container *ngTemplateOutlet=\"noResults\"></ng-container>\n }\n <mat-divider></mat-divider>\n } @else {\n <ng-container *ngTemplateOutlet=\"loading\"></ng-container>\n }\n\n </div>\n }\n @case (data.type === FacetDataType.Date) {\n <div class=\"date-wrapper\">\n\n <mat-form-field appearance=\"outline\" floatLabel=\"always\" class=\"date-field\">\n <mat-label>{{data.label}}</mat-label>\n <input matInput autocomplete=\"off\" focusOnShow=\"100\" [matDatepicker]=\"picker\" [ngModel]=\"getRawValue(data)\" (ngModelChange)=\"setValue(data, $event)\"\n placeholder=\"Choose a date\" (focus)=\"isUpdate ? emptyFunction() : picker.open()\"/>\n <mat-datepicker-toggle matSuffix [for]=\"picker\"></mat-datepicker-toggle>\n </mat-form-field>\n <mat-datepicker #picker></mat-datepicker>\n\n </div>\n }\n @case (data.type === FacetDataType.DateRange) {\n <div class=\"date-range-wrapper\">\n\n <mat-form-field appearance=\"outline\" floatLabel=\"always\">\n <mat-label>{{data.label}} - Start</mat-label>\n <input matInput focusOnShow=\"100\" autocomplete=\"off\" [matDatepicker]=\"startDatePicker\"\n [ngModel]=\"getRawValue(data)\" (ngModelChange)=\"setValue(data, $event)\" placeholder=\"Choose a starting date\"\n (focus)=\"isUpdate ? emptyFunction() : startDatePicker.open()\"/>\n <mat-datepicker-toggle matSuffix [for]=\"startDatePicker\"></mat-datepicker-toggle>\n </mat-form-field>\n <mat-datepicker #startDatePicker></mat-datepicker>\n\n <mat-form-field appearance=\"outline\" floatLabel=\"always\">\n <mat-label>{{data.label}} - End</mat-label>\n <input matInput autocomplete=\"off\" [matDatepicker]=\"endDatePicker\"\n [ngModel]=\"getRawValue(data, 1)\" (ngModelChange)=\"setValue(data, $event, 1)\" placeholder=\"Choose an end date\"/>\n <mat-datepicker-toggle matSuffix [for]=\"endDatePicker\"></mat-datepicker-toggle>\n </mat-form-field>\n <mat-datepicker #endDatePicker></mat-datepicker>\n\n </div>\n }\n @case (data.type === FacetDataType.Text) {\n <div class=\"text-wrapper\">\n\n <mat-form-field class=\"criteria-field\" appearance=\"outline\">\n <mat-label>Criteria Type</mat-label>\n <mat-select [value]=\"data.fixedFilterType || data.filterType\"\n (valueChange)=\"setType($event)\" placeholder=\"Criteria Type\">\n <mat-option [value]=\"FacetFilterType.contains\">Contains</mat-option>\n <mat-option [value]=\"FacetFilterType.endsWith\">Ends With</mat-option>\n <mat-option [value]=\"FacetFilterType.equal\">Equals</mat-option>\n <mat-option [value]=\"FacetFilterType.startsWith\">Starts With</mat-option>\n </mat-select>\n </mat-form-field>\n\n <mat-form-field class=\"search-field\" appearance=\"outline\">\n <mat-label>Search Text</mat-label>\n <input matInput focusOnShow (keydown.enter)=\"validateAndSubmit()\" autocomplete=\"off\"\n [ngModel]=\"getRawValue(data)\" (ngModelChange)=\"setValue(data, $event)\"\n placeholder=\"{{data.placeholder || data.label }}\" autofocus/>\n @if (data.values) {\n <button matSuffix mat-icon-button aria-label=\"Clear\" (click)=\"data.values = []\">\n <mat-icon>close</mat-icon>\n </button>\n }\n </mat-form-field>\n\n </div>\n }\n @case (data.type === FacetDataType.Boolean) {\n <div class=\"boolean-wrapper\">\n <mat-checkbox [ngModel]=\"getRawValue(data)\" (ngModelChange)=\"setValue(data, $event)\">{{data.placeholder || data.label}}</mat-checkbox>\n </div>\n }\n }\n\n </div>\n\n <div class=\"actions\">\n\n <button mat-flat-button class=\"add-update-button\" [color]=\"isUpdate ? 'accent' : 'primary'\" (click)=\"onOk()\"\n [disabled]=\"isUpdateButtonDisabled()\">{{isUpdate ? 'Update' : 'Add'}}</button>\n\n @if (isUpdate) {\n <button mat-icon-button class=\"remove-button\" color=\"warn\" (click)=\"onRemove()\" matTooltip=\"Delete Filter\" matTooltipPosition=\"after\">\n <mat-icon>delete</mat-icon>\n </button>\n }\n\n </div>\n</div>\n", styles: ["mat-spinner{margin:1em auto}.details{display:flex;flex-direction:column;align-items:stretch}.content{min-height:120px;padding-top:22px;display:flex;flex-direction:column;align-items:normal}.content mat-selection-list{flex:1;max-height:30vh;overflow-y:auto}.actions{padding:16px;display:flex;justify-content:space-between;flex-direction:row-reverse}span.facet-no-results{text-align:center;color:gray;margin-top:1em;margin-bottom:1em}.mat-selection-list{margin-top:0;padding-top:0}.mat-form-field{margin:0!important;padding-left:15px;padding-right:15px}.mat-dialog-actions{padding:0 15px 15px}.modal-header{display:flex;justify-content:space-between;align-items:center!important;border-top-left-radius:8px;border-top-right-radius:8px}.modal-header .modal-title{height:40px!important;margin:0!important;line-height:45px}p.description{padding-left:15px;padding-right:15px;margin-bottom:0;color:gray;flex:1}.date-range-wrapper{padding-left:15px;padding-right:15px;display:flex;flex-direction:column;align-items:stretch;justify-content:space-between}.date-range-wrapper,.category-wrapper{margin-top:1em}.boolean-wrapper{padding-left:15px;padding-right:15px;flex:4;display:flex;justify-content:flex-start;align-items:center}.text-wrapper{padding-left:15px;padding-right:15px;display:flex;flex-direction:column;flex:2;margin-top:1rem}.date-wrapper{padding-left:15px;padding-right:15px;display:flex;justify-content:center;align-items:center}.date-wrapper .date-field{flex:1}.typeahead-wrapper{padding-left:15px;padding-right:15px;display:flex;flex-direction:column;align-items:stretch;margin-top:1em}.typeahead-wrapper .typeahead-form-field{flex:1}\n"] }]
383
+ }], ctorParameters: () => [{ type: undefined, decorators: [{
384
+ type: Inject,
385
+ args: [FACET_MODAL_DATA]
386
+ }] }, { type: FacetModalRef }], propDecorators: { typeAheadInputs: [{
387
+ type: ViewChildren,
388
+ args: ['typeAheadInput']
389
+ }] } });
390
+
391
+ const DefaultFacetModalConfig = {
392
+ backdropClass: '',
393
+ disableClose: false,
394
+ hasBackdrop: true,
395
+ panelClass: '',
396
+ isUpdate: false,
397
+ };
398
+
399
+ const facetModalAnimations = {
400
+ modalContainer: trigger('modalContainer', [
401
+ state('void, exit', style({ opacity: 0, transform: 'scale(0.7)' })),
402
+ state('enter', style({ transform: 'none' })),
403
+ transition('* => enter', animate('150ms cubic-bezier(0, 0, 0.2, 1)', style({ transform: 'none', opacity: 1 }))),
404
+ transition('* => void, * => exit', animate('75ms cubic-bezier(0.4, 0.0, 0.2, 1)', style({ opacity: 0 }))),
405
+ ])
406
+ };
407
+
408
+ class FacetModalComponent extends BasePortalOutlet {
409
+ portalOutlet;
410
+ hostClass = 'facet-modal-component';
411
+ state = 'enter';
412
+ animationStateChanged = new EventEmitter();
413
+ get animationState() {
414
+ return this.state;
415
+ }
416
+ _onAnimationDone({ toState, totalTime }) {
417
+ if (toState === 'enter') {
418
+ this.animationStateChanged.next({ state: 'opened', totalTime });
419
+ }
420
+ else if (toState === 'exit') {
421
+ this.animationStateChanged.next({ state: 'closed', totalTime });
422
+ }
423
+ }
424
+ _onAnimationStart({ toState, totalTime }) {
425
+ if (toState === 'enter') {
426
+ this.animationStateChanged.next({ state: 'opening', totalTime });
427
+ }
428
+ else if (toState === 'exit' || toState === 'void') {
429
+ this.animationStateChanged.next({ state: 'closing', totalTime });
430
+ }
431
+ }
432
+ attachComponentPortal(componentPortal) {
433
+ return this.portalOutlet.attachComponentPortal(componentPortal);
434
+ }
435
+ attachTemplatePortal(portal) {
436
+ throw new Error('Method not implemented.');
437
+ }
438
+ _startExitAnimation() {
439
+ this.state = 'exit';
440
+ }
441
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.17", ngImport: i0, type: FacetModalComponent, deps: null, target: i0.ɵɵFactoryTarget.Component });
442
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "19.2.17", type: FacetModalComponent, isStandalone: true, selector: "ngx-facet-modal", host: { listeners: { "@modalContainer.done": "_onAnimationDone($event)", "@modalContainer.start": "_onAnimationStart($event)" }, properties: { "class": "this.hostClass", "@modalContainer": "this.animationState" } }, viewQueries: [{ propertyName: "portalOutlet", first: true, predicate: CdkPortalOutlet, descendants: true, static: true }], usesInheritance: true, ngImport: i0, template: "<ng-template cdkPortalOutlet></ng-template>\n<div class=\"arrow\"></div>\n", styles: [":host{position:relative;background:#fff;border-radius:8px;min-width:300px}.arrow{position:absolute;z-index:-1;width:20px;height:20px;top:-10px;left:24px;border-radius:4px;transform-origin:top left;transform:rotate(45deg)}\n"], dependencies: [{ kind: "ngmodule", type: PortalModule }, { kind: "directive", type: i1.CdkPortalOutlet, selector: "[cdkPortalOutlet]", inputs: ["cdkPortalOutlet"], outputs: ["attached"], exportAs: ["cdkPortalOutlet"] }], animations: [facetModalAnimations.modalContainer] });
443
+ }
444
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.17", ngImport: i0, type: FacetModalComponent, decorators: [{
445
+ type: Component,
446
+ args: [{ selector: 'ngx-facet-modal', standalone: true, imports: [PortalModule], animations: [facetModalAnimations.modalContainer], template: "<ng-template cdkPortalOutlet></ng-template>\n<div class=\"arrow\"></div>\n", styles: [":host{position:relative;background:#fff;border-radius:8px;min-width:300px}.arrow{position:absolute;z-index:-1;width:20px;height:20px;top:-10px;left:24px;border-radius:4px;transform-origin:top left;transform:rotate(45deg)}\n"] }]
447
+ }], propDecorators: { portalOutlet: [{
448
+ type: ViewChild,
449
+ args: [CdkPortalOutlet, { static: true }]
450
+ }], hostClass: [{
451
+ type: HostBinding,
452
+ args: ['class']
453
+ }], animationState: [{
454
+ type: HostBinding,
455
+ args: ['@modalContainer']
456
+ }], _onAnimationDone: [{
457
+ type: HostListener,
458
+ args: ['@modalContainer.done', ['$event']]
459
+ }], _onAnimationStart: [{
460
+ type: HostListener,
461
+ args: ['@modalContainer.start', ['$event']]
462
+ }] } });
463
+
464
+ class FacetModalService {
465
+ overlay;
466
+ injector;
467
+ constructor(overlay, injector) {
468
+ this.overlay = overlay;
469
+ this.injector = injector;
470
+ }
471
+ open(component, target, config = {}) {
472
+ const facetModalConfig = Object.assign({}, DefaultFacetModalConfig, config);
473
+ const offsetY = facetModalConfig.offsetY || 0;
474
+ const offsetX = facetModalConfig.offsetX || 0;
475
+ const positionStrategy = this.overlay
476
+ .position()
477
+ .flexibleConnectedTo(target)
478
+ .withPush(false)
479
+ .withFlexibleDimensions(true)
480
+ .withPositions([
481
+ {
482
+ overlayX: 'start',
483
+ overlayY: 'top',
484
+ originX: 'start',
485
+ originY: 'center',
486
+ offsetX,
487
+ offsetY,
488
+ },
489
+ ]);
490
+ const overlayRef = this.overlay.create({
491
+ hasBackdrop: facetModalConfig.hasBackdrop ?? true,
492
+ backdropClass: facetModalConfig.backdropClass,
493
+ panelClass: facetModalConfig.panelClass,
494
+ positionStrategy,
495
+ scrollStrategy: this.overlay.scrollStrategies.block()
496
+ });
497
+ if (facetModalConfig.width) {
498
+ overlayRef.updateSize({ width: facetModalConfig.width });
499
+ }
500
+ const modalRef = new FacetModalRef(overlayRef, positionStrategy, facetModalConfig);
501
+ const injector = Injector.create({
502
+ providers: [
503
+ {
504
+ provide: FACET_MODAL_DATA,
505
+ useValue: config.data
506
+ },
507
+ {
508
+ provide: FacetModalRef,
509
+ useValue: modalRef
510
+ },
511
+ ],
512
+ parent: this.injector
513
+ });
514
+ const modal = overlayRef.attach(new ComponentPortal(FacetModalComponent, null, injector)).instance;
515
+ modal.attachComponentPortal(new ComponentPortal(component, null, injector));
516
+ return modalRef;
517
+ }
518
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.17", ngImport: i0, type: FacetModalService, deps: [{ token: i1$1.Overlay }, { token: i0.Injector }], target: i0.ɵɵFactoryTarget.Injectable });
519
+ static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "19.2.17", ngImport: i0, type: FacetModalService, providedIn: 'root' });
520
+ }
521
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.17", ngImport: i0, type: FacetModalService, decorators: [{
522
+ type: Injectable,
523
+ args: [{
524
+ providedIn: 'root'
525
+ }]
526
+ }], ctorParameters: () => [{ type: i1$1.Overlay }, { type: i0.Injector }] });
527
+
528
+ class VCRefInjector {
529
+ raw;
530
+ constructor(injector) {
531
+ this.raw = injector;
532
+ }
533
+ get parentIdentifier() {
534
+ const parent = this.parent;
535
+ if (!!parent) {
536
+ return parent.tagName.toLowerCase();
537
+ }
538
+ return null;
539
+ }
540
+ get parent() {
541
+ if (!!this.raw && this.raw._lView && this.raw._lView.length > 0) {
542
+ return this.raw._lView[0];
543
+ }
544
+ return null;
545
+ }
546
+ }
547
+
548
+ const chipAnimation = [
549
+ trigger('chipAnimation', [
550
+ state('in', style({
551
+ transform: 'translateX(0)',
552
+ opacity: 0,
553
+ position: 'absolute'
554
+ })),
555
+ transition('void => *', [
556
+ style({
557
+ transform: 'translateX(-100%)',
558
+ opacity: 1,
559
+ position: '*'
560
+ }),
561
+ animate('200ms ease-out')
562
+ ]),
563
+ transition('* => void', [
564
+ style({
565
+ position: 'absolute'
566
+ }),
567
+ animate('200ms ease-in', style({
568
+ transform: 'translateX(-100%)',
569
+ opacity: 0
570
+ }))
571
+ ])
572
+ ])
573
+ ];
574
+
575
+ class FacetStorageService {
576
+ storageStrategy = 'session';
577
+ /**
578
+ * Update the loggingCallback function
579
+ */
580
+ updateLoggingCallback(loggingCallback) {
581
+ this.loggingCallback = loggingCallback;
582
+ }
583
+ /**
584
+ * Saves the selected facets to localStorage for our current identifier
585
+ */
586
+ updateSavedFacets(identifier, selectedFacets) {
587
+ if (!identifier) {
588
+ this.loggingCallback(`Cannot update ${this.mode}, no ID set`);
589
+ return;
590
+ }
591
+ if (this.storageStrategy === 'none') {
592
+ return;
593
+ }
594
+ this.loggingCallback(`Saving facets in ${this.mode} for component with ID`, identifier);
595
+ this.storageBackend?.setItem(identifier, JSON.stringify(selectedFacets));
596
+ }
597
+ /**
598
+ * Clears previously saved facets for this specific component
599
+ */
600
+ clearStorage(identifier) {
601
+ if (!identifier) {
602
+ return;
603
+ }
604
+ if (this.storageStrategy === 'none') {
605
+ return;
606
+ }
607
+ this.loggingCallback(`Clearing ${this.mode} for ID`, identifier);
608
+ this.storageBackend?.removeItem(identifier);
609
+ }
610
+ /**
611
+ * Loads facets from storage for our current identifier
612
+ */
613
+ loadFacetsFromStorage(identifier) {
614
+ let sessionFacets = [];
615
+ if (this.storageStrategy === 'none') {
616
+ return [];
617
+ }
618
+ if (!!identifier && !this.checkStorage(identifier)) {
619
+ sessionFacets = JSON.parse(this.storageBackend?.getItem(identifier) || '[]');
620
+ sessionFacets = (sessionFacets || []);
621
+ this.loggingCallback('Loaded facets for component with ID', identifier, sessionFacets);
622
+ }
623
+ else if (!identifier) {
624
+ this.loggingCallback('No identifier set on this component');
625
+ }
626
+ else if (this.checkStorage(identifier)) {
627
+ this.loggingCallback(`No ${this.mode} variable set for component with ID`, identifier, localStorage.getItem(identifier));
628
+ }
629
+ return sessionFacets;
630
+ }
631
+ loggingCallback = () => {
632
+ };
633
+ updateStorageStrategy(strategy) {
634
+ this.storageStrategy = strategy;
635
+ }
636
+ get mode() {
637
+ if (this.storageStrategy === 'none') {
638
+ return 'none';
639
+ }
640
+ return (this.storageStrategy === 'local' ? 'localStorage' : 'sessionStorage');
641
+ }
642
+ checkStorage(key) {
643
+ return !this.storageBackend?.getItem(key);
644
+ }
645
+ get storageBackend() {
646
+ if (this.storageStrategy === 'none') {
647
+ return null;
648
+ }
649
+ return this.storageStrategy === 'local' ? localStorage : sessionStorage;
650
+ }
651
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.17", ngImport: i0, type: FacetStorageService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
652
+ static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "19.2.17", ngImport: i0, type: FacetStorageService, providedIn: 'root' });
653
+ }
654
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.17", ngImport: i0, type: FacetStorageService, decorators: [{
655
+ type: Injectable,
656
+ args: [{
657
+ providedIn: 'root'
658
+ }]
659
+ }] });
660
+
661
+ const FACET_TOOLKIT_CONFIG = new InjectionToken('Facet Toolkit Configuration', {
662
+ providedIn: 'root',
663
+ factory: () => DEFAULT_FACET_TOOLKIT_CONFIG
664
+ });
665
+ const provideFacetToolkitConfig = (config) => makeEnvironmentProviders([
666
+ {
667
+ provide: FACET_TOOLKIT_CONFIG,
668
+ useValue: {
669
+ ...DEFAULT_FACET_TOOLKIT_CONFIG,
670
+ ...config
671
+ }
672
+ }
673
+ ]);
674
+
675
+ class CSVPipe {
676
+ transform(value, objectKeyName, separator) {
677
+ return value.map(e => objectKeyName ? e[objectKeyName] : e).join(separator || ',');
678
+ }
679
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.17", ngImport: i0, type: CSVPipe, deps: [], target: i0.ɵɵFactoryTarget.Pipe });
680
+ static ɵpipe = i0.ɵɵngDeclarePipe({ minVersion: "14.0.0", version: "19.2.17", ngImport: i0, type: CSVPipe, isStandalone: true, name: "csv", pure: false });
681
+ }
682
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.17", ngImport: i0, type: CSVPipe, decorators: [{
683
+ type: Pipe,
684
+ args: [{
685
+ name: 'csv',
686
+ standalone: true,
687
+ pure: false
688
+ }]
689
+ }] });
690
+
691
+ class FilterPipe {
692
+ transform(objectArray, fieldName, fieldValue) {
693
+ return objectArray.filter(obj => obj[fieldName] === fieldValue);
694
+ }
695
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.17", ngImport: i0, type: FilterPipe, deps: [], target: i0.ɵɵFactoryTarget.Pipe });
696
+ static ɵpipe = i0.ɵɵngDeclarePipe({ minVersion: "14.0.0", version: "19.2.17", ngImport: i0, type: FilterPipe, isStandalone: true, name: "filter", pure: false });
697
+ }
698
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.17", ngImport: i0, type: FilterPipe, decorators: [{
699
+ type: Pipe,
700
+ args: [{
701
+ name: 'filter',
702
+ standalone: true,
703
+ pure: false
704
+ }]
705
+ }] });
706
+
707
+ class KeysPipe {
708
+ transform(value) {
709
+ return Object.keys(value).map(k => ({ key: k, value: k }));
710
+ }
711
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.17", ngImport: i0, type: KeysPipe, deps: [], target: i0.ɵɵFactoryTarget.Pipe });
712
+ static ɵpipe = i0.ɵɵngDeclarePipe({ minVersion: "14.0.0", version: "19.2.17", ngImport: i0, type: KeysPipe, isStandalone: true, name: "keys", pure: false });
713
+ }
714
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.17", ngImport: i0, type: KeysPipe, decorators: [{
715
+ type: Pipe,
716
+ args: [{
717
+ name: 'keys',
718
+ standalone: true,
719
+ pure: false
720
+ }]
721
+ }] });
722
+
723
+ class NgxMatFacetToolkitComponent {
724
+ facets = input([]);
725
+ config = input({});
726
+ placeholder = input('Filter Table...');
727
+ clearButtonText = input('Clear Filters');
728
+ clearButtonEnabled = input(true);
729
+ dateFormat = input('M/d/yyyy');
730
+ tooltip = input(null);
731
+ displayFilterIcon = input(true);
732
+ facetWidth = input('400px');
733
+ facetHasBackdrop = input(true);
734
+ confirmOnRemove = input(true);
735
+ chipLabelsEnabled = input(true);
736
+ identifier = input(null);
737
+ facetChange = output();
738
+ facetRemoved = output();
739
+ facetReset = output();
740
+ filterInput;
741
+ inputAutoComplete;
742
+ FacetDataType = FacetDataType;
743
+ FacetFilterType = FacetFilterType;
744
+ selectedFacetId = signal(null);
745
+ filterText = signal('');
746
+ injectedConfig = inject(FACET_TOOLKIT_CONFIG);
747
+ storageService = inject(FacetStorageService);
748
+ modal = inject(FacetModalService);
749
+ vcRef = inject(ViewContainerRef);
750
+ identifierStrategy = signal(FacetIdentifierStrategy.ParentID);
751
+ resolvedIdentifier = signal(null);
752
+ allowDebugClick = signal(false);
753
+ loggingCallback = signal(() => { });
754
+ timeoutHandler = null;
755
+ injectorRef = new VCRefInjector(this.vcRef.injector);
756
+ selectedFacets = signal([]);
757
+ facetDefinitions = computed(() => this.facets() || []);
758
+ selectedFacetViews = computed(() => this.selectedFacets()
759
+ .map(selection => this.toEditorState(selection))
760
+ .filter((facet) => !!facet));
761
+ availableFacets = computed(() => {
762
+ const selectedIds = new Set(this.selectedFacets().map(selection => selection.id));
763
+ return this.facetDefinitions().filter(facet => !selectedIds.has(facet.id));
764
+ });
765
+ filteredFacets = computed(() => {
766
+ const filterText = this.filterText().toLowerCase();
767
+ if (!filterText) {
768
+ return this.availableFacets();
769
+ }
770
+ return this.availableFacets().filter(facet => facet.label.toLowerCase().includes(filterText));
771
+ });
772
+ constructor() {
773
+ effect(() => {
774
+ this.identifier();
775
+ const config = {
776
+ ...DEFAULT_FACET_TOOLKIT_CONFIG,
777
+ ...this.injectedConfig,
778
+ ...this.config()
779
+ };
780
+ this.allowDebugClick.set(config.allowDebugClick);
781
+ this.identifierStrategy.set(config.identifierStrategy);
782
+ this.loggingCallback.set(config.loggingCallback);
783
+ this.storageService.updateLoggingCallback(config.loggingCallback);
784
+ this.storageService.updateStorageStrategy(config.storage);
785
+ this.resolveIdentity();
786
+ });
787
+ effect(() => {
788
+ const facets = this.facetDefinitions();
789
+ const identifier = this.resolvedIdentifier();
790
+ this.refreshSelectionsFromFacets(facets, identifier);
791
+ });
792
+ effect(() => {
793
+ const selections = this.selectedFacets();
794
+ this.facetChange.emit(selections);
795
+ });
796
+ }
797
+ static getFixedURL() {
798
+ return window.location.pathname.toString()
799
+ .replace(/\s+/g, '-')
800
+ .replace(/\//g, '-')
801
+ .replace(/^-/g, '')
802
+ .replace(/--/g, '-');
803
+ }
804
+ ngAfterViewInit() {
805
+ fromEvent(this.filterInput.nativeElement, 'keyup')
806
+ .pipe(filter(Boolean), debounceTime(150), distinctUntilChanged(), map(() => this.filterInput.nativeElement.value))
807
+ .subscribe((text) => {
808
+ this.filterText.set(text || '');
809
+ });
810
+ }
811
+ chipSelected(event, facet) {
812
+ if (event.selected && !facet.readonly) {
813
+ const elementRef = event.source._elementRef.nativeElement;
814
+ this.facetSelected(facet, {
815
+ top: (elementRef.clientHeight - 5),
816
+ left: -3,
817
+ }, true, elementRef);
818
+ }
819
+ }
820
+ autoCompleteDisplay(_) {
821
+ return '';
822
+ }
823
+ autoCompleteSelected(event) {
824
+ const selectedFacet = event.option.value;
825
+ const parentElement = this.filterInput.nativeElement;
826
+ if (!!parentElement) {
827
+ const elementRef = parentElement.getBoundingClientRect();
828
+ const top = elementRef.height - 3;
829
+ const left = -38;
830
+ const editorState = this.toEditorState(this.toSelection(selectedFacet, [])) || {
831
+ ...selectedFacet,
832
+ values: [],
833
+ options: this.normalizeOptions(selectedFacet.options)
834
+ };
835
+ this.facetSelected(editorState, { top, left }, false, this.filterInput);
836
+ this.filterInput.nativeElement.value = '';
837
+ this.filterText.set('');
838
+ }
839
+ }
840
+ facetSelected(facet, position, isUpdate, target) {
841
+ this.promptFacet({ ...facet }, position, isUpdate, target);
842
+ }
843
+ promptFacet(facet, position, isUpdate, target) {
844
+ const facetDetailsModal = this.modal.open(FacetDetailsModalComponent, target, {
845
+ data: facet,
846
+ offsetY: position.top,
847
+ offsetX: position.left,
848
+ isUpdate,
849
+ hasBackdrop: this.facetHasBackdrop(),
850
+ width: this.facetWidth()
851
+ });
852
+ facetDetailsModal.beforeClosed().subscribe(() => {
853
+ this.selectedFacetId.set(null);
854
+ });
855
+ facetDetailsModal.afterClosed().subscribe(result => {
856
+ if (result.type === FacetResultType.REMOVE && result.data) {
857
+ this.removeFacet(result.data);
858
+ }
859
+ else if (result.type === FacetResultType.ADD && result.data) {
860
+ this.addOrUpdateFacet(result.data);
861
+ }
862
+ });
863
+ }
864
+ addOrUpdateFacet(facet) {
865
+ const selection = this.toSelection(facet, facet.values, facet.filterType);
866
+ const nextSelections = this.selectedFacets()
867
+ .filter(existing => existing.id !== selection.id)
868
+ .concat(selection);
869
+ this.selectedFacets.set(nextSelections);
870
+ this.storageService.updateSavedFacets(this.resolvedIdentifier(), nextSelections);
871
+ }
872
+ removeFacet(facet) {
873
+ if (!this.confirmOnRemove() || (this.confirmOnRemove() && confirm(`Do you really want to remove "${facet.label}" filter?`))) {
874
+ const updatedSelections = this.selectedFacets().filter(selection => selection.id !== facet.id);
875
+ this.selectedFacets.set(updatedSelections);
876
+ this.storageService.updateSavedFacets(this.resolvedIdentifier(), updatedSelections);
877
+ this.facetRemoved.emit(this.toSelection(facet, facet.values, facet.filterType));
878
+ return true;
879
+ }
880
+ return false;
881
+ }
882
+ reset() {
883
+ const readonlySelections = this.facetDefinitions()
884
+ .filter(facet => facet.readonly && (facet.defaultValues || []).length > 0)
885
+ .map(facet => this.toSelection(facet, facet.defaultValues || []));
886
+ this.selectedFacets.set(readonlySelections);
887
+ this.storageService.clearStorage(this.resolvedIdentifier());
888
+ this.facetReset.emit();
889
+ }
890
+ focus(event) {
891
+ event.stopPropagation();
892
+ this.inputAutoComplete.openPanel();
893
+ }
894
+ getValue(facet, offset) {
895
+ if (!!facet?.values?.length && facet.values[offset || 0]?.value !== undefined) {
896
+ return facet.values[offset || 0];
897
+ }
898
+ return null;
899
+ }
900
+ getRawValue(facet, offset) {
901
+ const value = this.getValue(facet, offset);
902
+ return value ? value.value : null;
903
+ }
904
+ getDateValue(facet, offset) {
905
+ const value = this.getRawValue(facet, offset);
906
+ if (value instanceof Date || typeof value === 'string' || typeof value === 'number') {
907
+ return value;
908
+ }
909
+ return null;
910
+ }
911
+ setValue(facet, newValue, offset) {
912
+ if (!!facet?.values?.length && facet.values[offset || 0]) {
913
+ facet.values[offset || 0] = {
914
+ ...facet.values[offset || 0],
915
+ value: newValue
916
+ };
917
+ }
918
+ }
919
+ identify(identifier) {
920
+ this.loggingCallback()(`Identifying facet with ID: ${identifier}`);
921
+ if (!identifier || identifier.length === 0 || identifier === '-') {
922
+ this.resolvedIdentifier.set('default-facet');
923
+ }
924
+ else {
925
+ this.resolvedIdentifier.set(`${identifier}-facet`);
926
+ }
927
+ }
928
+ getIdentifierStrategy() {
929
+ return this.identifierStrategy();
930
+ }
931
+ printIdentity() {
932
+ console.log(this.resolvedIdentifier());
933
+ }
934
+ clickStarted() {
935
+ if (!this.allowDebugClick()) {
936
+ return;
937
+ }
938
+ this.timeoutHandler = setTimeout(() => {
939
+ this.printIdentity();
940
+ this.timeoutHandler = null;
941
+ }, 1000);
942
+ }
943
+ clickEnded() {
944
+ if (this.timeoutHandler) {
945
+ clearTimeout(this.timeoutHandler);
946
+ this.timeoutHandler = null;
947
+ }
948
+ }
949
+ resolveIdentity(manual) {
950
+ const identifierInput = manual ?? this.identifier();
951
+ let identity;
952
+ this.loggingCallback()('Generating ID with strategy', this.identifierStrategy());
953
+ switch (this.identifierStrategy()) {
954
+ case FacetIdentifierStrategy.WindowURL:
955
+ identity = NgxMatFacetToolkitComponent.getFixedURL();
956
+ break;
957
+ case FacetIdentifierStrategy.ParentID:
958
+ identity = this.injectorRef.parentIdentifier;
959
+ break;
960
+ case FacetIdentifierStrategy.Random:
961
+ identity = v4();
962
+ break;
963
+ default:
964
+ identity = identifierInput;
965
+ break;
966
+ }
967
+ this.identify(identity);
968
+ }
969
+ refreshSelectionsFromFacets(facets, identifier) {
970
+ if (!facets.length) {
971
+ this.selectedFacets.set([]);
972
+ return;
973
+ }
974
+ const storedSelections = this.storageService.loadFacetsFromStorage(identifier);
975
+ const storedById = new Map(storedSelections.map(selection => [selection.id, selection]));
976
+ const nextSelections = facets
977
+ .map(facet => {
978
+ const stored = storedById.get(facet.id);
979
+ if (stored) {
980
+ return stored;
981
+ }
982
+ if (facet.defaultValues && facet.defaultValues.length > 0) {
983
+ return this.toSelection(facet, facet.defaultValues);
984
+ }
985
+ return null;
986
+ })
987
+ .filter((selection) => !!selection);
988
+ this.selectedFacets.set(nextSelections);
989
+ }
990
+ toSelection(facet, values, filterType) {
991
+ return {
992
+ id: facet.id,
993
+ type: facet.type,
994
+ filterType: this.resolveFilterType(facet, filterType),
995
+ values: values || []
996
+ };
997
+ }
998
+ resolveFilterType(facet, filterType) {
999
+ if (filterType) {
1000
+ return filterType;
1001
+ }
1002
+ if (facet.fixedFilterType) {
1003
+ return facet.fixedFilterType;
1004
+ }
1005
+ switch (facet.type) {
1006
+ case FacetDataType.Date:
1007
+ case FacetDataType.Boolean:
1008
+ return FacetFilterType.equal;
1009
+ case FacetDataType.DateRange:
1010
+ return FacetFilterType.between;
1011
+ case FacetDataType.CategorySingle:
1012
+ case FacetDataType.TypeaheadSingle:
1013
+ return FacetFilterType.equal;
1014
+ case FacetDataType.Text:
1015
+ case FacetDataType.Category:
1016
+ case FacetDataType.Typeahead:
1017
+ default:
1018
+ return FacetFilterType.contains;
1019
+ }
1020
+ }
1021
+ toEditorState(selection) {
1022
+ const facet = this.facetDefinitions().find(definition => definition.id === selection.id);
1023
+ if (!facet) {
1024
+ return null;
1025
+ }
1026
+ return {
1027
+ ...facet,
1028
+ values: selection.values,
1029
+ filterType: selection.filterType,
1030
+ options: this.normalizeOptions(facet.options)
1031
+ };
1032
+ }
1033
+ normalizeOptions(options) {
1034
+ if (!options) {
1035
+ return undefined;
1036
+ }
1037
+ return isObservable(options) ? options : of(options);
1038
+ }
1039
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.17", ngImport: i0, type: NgxMatFacetToolkitComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
1040
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "19.2.17", type: NgxMatFacetToolkitComponent, isStandalone: true, selector: "ngx-mat-facet-toolkit", inputs: { facets: { classPropertyName: "facets", publicName: "facets", isSignal: true, isRequired: false, transformFunction: null }, config: { classPropertyName: "config", publicName: "config", isSignal: true, isRequired: false, transformFunction: null }, placeholder: { classPropertyName: "placeholder", publicName: "placeholder", isSignal: true, isRequired: false, transformFunction: null }, clearButtonText: { classPropertyName: "clearButtonText", publicName: "clearButtonText", isSignal: true, isRequired: false, transformFunction: null }, clearButtonEnabled: { classPropertyName: "clearButtonEnabled", publicName: "clearButtonEnabled", isSignal: true, isRequired: false, transformFunction: null }, dateFormat: { classPropertyName: "dateFormat", publicName: "dateFormat", isSignal: true, isRequired: false, transformFunction: null }, tooltip: { classPropertyName: "tooltip", publicName: "tooltip", isSignal: true, isRequired: false, transformFunction: null }, displayFilterIcon: { classPropertyName: "displayFilterIcon", publicName: "displayFilterIcon", isSignal: true, isRequired: false, transformFunction: null }, facetWidth: { classPropertyName: "facetWidth", publicName: "facetWidth", isSignal: true, isRequired: false, transformFunction: null }, facetHasBackdrop: { classPropertyName: "facetHasBackdrop", publicName: "facetHasBackdrop", isSignal: true, isRequired: false, transformFunction: null }, confirmOnRemove: { classPropertyName: "confirmOnRemove", publicName: "confirmOnRemove", isSignal: true, isRequired: false, transformFunction: null }, chipLabelsEnabled: { classPropertyName: "chipLabelsEnabled", publicName: "chipLabelsEnabled", isSignal: true, isRequired: false, transformFunction: null }, identifier: { classPropertyName: "identifier", publicName: "identifier", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { facetChange: "facetChange", facetRemoved: "facetRemoved", facetReset: "facetReset" }, viewQueries: [{ propertyName: "filterInput", first: true, predicate: ["filterInput"], descendants: true }, { propertyName: "inputAutoComplete", first: true, predicate: MatAutocompleteTrigger, descendants: true, read: MatAutocompleteTrigger }], ngImport: i0, template: "<div class=\"main-facet-wrapper\">\n\n @if (displayFilterIcon()) {\n <div class=\"icon-wrapper\">\n @if (tooltip() !== null) {\n <mat-icon class=\"filter-list-icon\" (mousedown)=\"clickStarted()\" (mouseup)=\"clickEnded()\" (mouseleave)=\"clickEnded()\" [matTooltip]=\"tooltip()\">filter_list</mat-icon>\n } @else {\n <mat-icon class=\"filter-list-icon\" (mousedown)=\"clickStarted()\" (mouseup)=\"clickEnded()\" (mouseleave)=\"clickEnded()\">filter_list</mat-icon>\n }\n </div>\n }\n\n <div class=\"content-wrapper\">\n\n <mat-chip-grid #chipList>\n\n @for (facet of selectedFacetViews(); track facet.id) {\n <mat-chip-option @chipAnimation [color]=\"facet.readonly ? 'accent' : undefined\"\n class=\"facet-chip\"\n (selectionChange)=\"chipSelected($event, facet)\" (click)=\"selectedFacetId.set(facet.id)\"\n [selected]=\"facet.id === selectedFacetId()\"\n matTooltip=\"{{facet.label + (facet.description ? ': ' + facet.description : '')}}\"\n matTooltipShowDelay=\"1000\">\n <span class=\"flex-facet\">\n\n @if (facet.icon) {\n <mat-icon class=\"inline-chip-icon\">{{facet.icon}}</mat-icon>\n }\n\n @if (chipLabelsEnabled()) {\n <span>{{ facet.label + ': &nbsp;'}}</span>\n }\n\n @switch (facet.type) {\n @case (FacetDataType.Category) {\n {{facet.values | csv:'label':' / '}}\n }\n @case (FacetDataType.CategorySingle) {\n {{facet.values | csv:'label':' / '}}\n }\n @case (FacetDataType.Typeahead) {\n {{facet.values | csv:'label':' / '}}\n }\n @case (FacetDataType.TypeaheadSingle) {\n {{facet.values | csv:'label':' / '}}\n }\n @case (FacetDataType.Date) {\n \u201C{{getDateValue(facet) | date:dateFormat()}}\u201D\n }\n @case (FacetDataType.DateRange) {\n \u201C{{getDateValue(facet) | date:dateFormat()}}\u201D ~ \u201C{{getDateValue(facet, 1) | date:dateFormat()}}\u201D\n }\n @case (FacetDataType.Boolean) {\n <mat-checkbox [disabled]=\"true\" class=\"inline-chip-checkbox\" [ngModel]=\"getRawValue(facet)\" (ngModelChange)=\"setValue(facet, $event)\">\n {{facet.label}}\n </mat-checkbox>\n }\n @case (FacetDataType.Text) {\n @switch (facet.filterType) {\n @case (FacetFilterType.contains) {\n \u201C..{{getRawValue(facet)}}..\u201D\n }\n @case (FacetFilterType.equal) {\n \u201C{{getRawValue(facet)}}\u201D\n }\n @case (FacetFilterType.startsWith) {\n \u201C{{getRawValue(facet)}}...\u201D\n }\n @case (FacetFilterType.endsWith) {\n \u201C...{{getRawValue(facet)}}\u201D\n }\n }\n }\n }\n\n @if (!facet.readonly) {\n <mat-icon matChipRemove (click)=\"removeFacet(facet)\">cancel</mat-icon>\n }\n\n </span>\n\n </mat-chip-option>\n }\n\n <mat-chip-row class=\"filter-input-container\" disableRipple=\"true\" disabled=\"true\" @chipAnimation>\n\n <span class=\"flex-facet-autocomplete\">\n\n <mat-icon class=\"add-icon\" (click)=\"focus($event)\">add</mat-icon>\n\n <input #filterInput [matChipInputFor]=\"chipList\" class=\"filter-input\" [placeholder]=\"placeholder()\"\n [matChipInputAddOnBlur]=\"false\" [matAutocomplete]=\"auto\">\n\n <mat-autocomplete #auto=\"matAutocomplete\" class=\"mat-facet-autocomplete\" (optionSelected)=\"autoCompleteSelected($event)\"\n [displayWith]=\"autoCompleteDisplay\" panelWidth=\"250px\">\n @for (facet of filteredFacets(); track facet.id) {\n <mat-option [value]=\"facet\">\n @if (facet.icon) {\n <mat-icon>{{facet.icon}}</mat-icon>\n }\n <span>{{ facet.label }}</span>\n </mat-option>\n }\n </mat-autocomplete>\n\n </span>\n\n </mat-chip-row>\n\n </mat-chip-grid>\n\n </div>\n\n\n @if (clearButtonEnabled() && selectedFacets().length > 0) {\n <button mat-flat-button (click)=\"reset()\" color=\"accent\">\n {{clearButtonText()}}\n </button>\n }\n\n</div>\n", styles: ["*{outline:0}.filter-input-container{background-color:transparent!important;opacity:1!important;box-shadow:none!important}.filter-input-container .filter-input{border:none!important;background:none!important;width:85px;font-size:14px!important;font-weight:400;text-align:right;position:relative;top:-7px;margin-left:2px}::placeholder{color:#000000db;opacity:1}.inline-chip-icon{width:18px;height:18px;font-size:18px;margin-right:7px;margin-left:0}:host-context .mat-checkbox-inner-container{transform:scale(.7)}:host-context(.inlineChipCheckbox) label.mat-checkbox-layout div.mat-checkbox-inner-container{transform:scale(.7)}.add-icon{margin-top:8px}.add-icon:hover,.filter-input-container:hover{cursor:pointer}.main-facet-wrapper{min-height:36px;display:flex;align-items:center}.main-facet-wrapper .icon-wrapper{height:100%;display:flex;justify-content:center;align-items:center;margin-right:20px}::ng-deep .mat-autocomplete-panel.mat-autocomplete-visible{left:-40px!important;top:15px!important}::ng-deep .mat-chip-list-wrapper{transition:width .3s ease-in-out}.content-wrapper{flex:1}.flex-facet{display:flex;align-items:center}.flex-facet-autocomplete{justify-content:center}\n"], dependencies: [{ kind: "ngmodule", type: A11yModule }, { kind: "ngmodule", type: CommonModule }, { kind: "pipe", type: i2.DatePipe, name: "date" }, { kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i3.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i3.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "ngmodule", type: ReactiveFormsModule }, { kind: "ngmodule", type: MatIconModule }, { kind: "component", type: i5.MatIcon, selector: "mat-icon", inputs: ["color", "inline", "svgIcon", "fontSet", "fontIcon"], exportAs: ["matIcon"] }, { kind: "ngmodule", type: MatToolbarModule }, { kind: "ngmodule", type: MatProgressBarModule }, { kind: "ngmodule", type: MatListModule }, { kind: "ngmodule", type: MatFormFieldModule }, { kind: "ngmodule", type: MatDatepickerModule }, { kind: "ngmodule", type: MatOptionModule }, { kind: "component", type: i15.MatOption, selector: "mat-option", inputs: ["value", "id", "disabled"], outputs: ["onSelectionChange"], exportAs: ["matOption"] }, { kind: "ngmodule", type: MatSelectModule }, { kind: "ngmodule", type: MatButtonModule }, { kind: "component", type: i6.MatButton, selector: " button[mat-button], button[mat-raised-button], button[mat-flat-button], button[mat-stroked-button] ", exportAs: ["matButton"] }, { kind: "ngmodule", type: MatCheckboxModule }, { kind: "component", type: i14.MatCheckbox, selector: "mat-checkbox", inputs: ["aria-label", "aria-labelledby", "aria-describedby", "aria-expanded", "aria-controls", "aria-owns", "id", "required", "labelPosition", "name", "value", "disableRipple", "tabIndex", "color", "disabledInteractive", "checked", "disabled", "indeterminate"], outputs: ["change", "indeterminateChange"], exportAs: ["matCheckbox"] }, { kind: "ngmodule", type: MatInputModule }, { kind: "ngmodule", type: MatChipsModule }, { kind: "component", type: i7$1.MatChipGrid, selector: "mat-chip-grid", inputs: ["disabled", "placeholder", "required", "value", "errorStateMatcher"], outputs: ["change", "valueChange"] }, { kind: "directive", type: i7$1.MatChipInput, selector: "input[matChipInputFor]", inputs: ["matChipInputFor", "matChipInputAddOnBlur", "matChipInputSeparatorKeyCodes", "placeholder", "id", "disabled"], outputs: ["matChipInputTokenEnd"], exportAs: ["matChipInput", "matChipInputFor"] }, { kind: "component", type: i7$1.MatChipOption, selector: "mat-basic-chip-option, [mat-basic-chip-option], mat-chip-option, [mat-chip-option]", inputs: ["selectable", "selected"], outputs: ["selectionChange"] }, { kind: "directive", type: i7$1.MatChipRemove, selector: "[matChipRemove]" }, { kind: "component", type: i7$1.MatChipRow, selector: "mat-chip-row, [mat-chip-row], mat-basic-chip-row, [mat-basic-chip-row]", inputs: ["editable"], outputs: ["edited"] }, { kind: "ngmodule", type: MatTooltipModule }, { kind: "directive", type: i7.MatTooltip, selector: "[matTooltip]", inputs: ["matTooltipPosition", "matTooltipPositionAtOrigin", "matTooltipDisabled", "matTooltipShowDelay", "matTooltipHideDelay", "matTooltipTouchGestures", "matTooltip", "matTooltipClass"], exportAs: ["matTooltip"] }, { kind: "ngmodule", type: MatAutocompleteModule }, { kind: "component", type: i9$1.MatAutocomplete, selector: "mat-autocomplete", inputs: ["aria-label", "aria-labelledby", "displayWith", "autoActiveFirstOption", "autoSelectActiveOption", "requireSelection", "panelWidth", "disableRipple", "class", "hideSingleSelectionIndicator"], outputs: ["optionSelected", "opened", "closed", "optionActivated"], exportAs: ["matAutocomplete"] }, { kind: "directive", type: i9$1.MatAutocompleteTrigger, selector: "input[matAutocomplete], textarea[matAutocomplete]", inputs: ["matAutocomplete", "matAutocompletePosition", "matAutocompleteConnectedTo", "autocomplete", "matAutocompleteDisabled"], exportAs: ["matAutocompleteTrigger"] }, { kind: "ngmodule", type: MatNativeDateModule }, { kind: "ngmodule", type: MatProgressSpinnerModule }, { kind: "ngmodule", type: OverlayModule }, { kind: "ngmodule", type: PortalModule }, { kind: "pipe", type: CSVPipe, name: "csv" }], animations: [
1041
+ chipAnimation
1042
+ ] });
1043
+ }
1044
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.17", ngImport: i0, type: NgxMatFacetToolkitComponent, decorators: [{
1045
+ type: Component,
1046
+ args: [{ selector: 'ngx-mat-facet-toolkit', standalone: true, imports: [
1047
+ A11yModule,
1048
+ CommonModule,
1049
+ FormsModule,
1050
+ ReactiveFormsModule,
1051
+ MatIconModule,
1052
+ MatToolbarModule,
1053
+ MatProgressBarModule,
1054
+ MatListModule,
1055
+ MatFormFieldModule,
1056
+ MatDatepickerModule,
1057
+ MatOptionModule,
1058
+ MatSelectModule,
1059
+ MatButtonModule,
1060
+ MatCheckboxModule,
1061
+ MatInputModule,
1062
+ MatChipsModule,
1063
+ MatTooltipModule,
1064
+ MatAutocompleteModule,
1065
+ MatNativeDateModule,
1066
+ MatProgressSpinnerModule,
1067
+ OverlayModule,
1068
+ PortalModule,
1069
+ CSVPipe,
1070
+ FilterPipe,
1071
+ KeysPipe,
1072
+ FocusOnShowDirective
1073
+ ], animations: [
1074
+ chipAnimation
1075
+ ], template: "<div class=\"main-facet-wrapper\">\n\n @if (displayFilterIcon()) {\n <div class=\"icon-wrapper\">\n @if (tooltip() !== null) {\n <mat-icon class=\"filter-list-icon\" (mousedown)=\"clickStarted()\" (mouseup)=\"clickEnded()\" (mouseleave)=\"clickEnded()\" [matTooltip]=\"tooltip()\">filter_list</mat-icon>\n } @else {\n <mat-icon class=\"filter-list-icon\" (mousedown)=\"clickStarted()\" (mouseup)=\"clickEnded()\" (mouseleave)=\"clickEnded()\">filter_list</mat-icon>\n }\n </div>\n }\n\n <div class=\"content-wrapper\">\n\n <mat-chip-grid #chipList>\n\n @for (facet of selectedFacetViews(); track facet.id) {\n <mat-chip-option @chipAnimation [color]=\"facet.readonly ? 'accent' : undefined\"\n class=\"facet-chip\"\n (selectionChange)=\"chipSelected($event, facet)\" (click)=\"selectedFacetId.set(facet.id)\"\n [selected]=\"facet.id === selectedFacetId()\"\n matTooltip=\"{{facet.label + (facet.description ? ': ' + facet.description : '')}}\"\n matTooltipShowDelay=\"1000\">\n <span class=\"flex-facet\">\n\n @if (facet.icon) {\n <mat-icon class=\"inline-chip-icon\">{{facet.icon}}</mat-icon>\n }\n\n @if (chipLabelsEnabled()) {\n <span>{{ facet.label + ': &nbsp;'}}</span>\n }\n\n @switch (facet.type) {\n @case (FacetDataType.Category) {\n {{facet.values | csv:'label':' / '}}\n }\n @case (FacetDataType.CategorySingle) {\n {{facet.values | csv:'label':' / '}}\n }\n @case (FacetDataType.Typeahead) {\n {{facet.values | csv:'label':' / '}}\n }\n @case (FacetDataType.TypeaheadSingle) {\n {{facet.values | csv:'label':' / '}}\n }\n @case (FacetDataType.Date) {\n \u201C{{getDateValue(facet) | date:dateFormat()}}\u201D\n }\n @case (FacetDataType.DateRange) {\n \u201C{{getDateValue(facet) | date:dateFormat()}}\u201D ~ \u201C{{getDateValue(facet, 1) | date:dateFormat()}}\u201D\n }\n @case (FacetDataType.Boolean) {\n <mat-checkbox [disabled]=\"true\" class=\"inline-chip-checkbox\" [ngModel]=\"getRawValue(facet)\" (ngModelChange)=\"setValue(facet, $event)\">\n {{facet.label}}\n </mat-checkbox>\n }\n @case (FacetDataType.Text) {\n @switch (facet.filterType) {\n @case (FacetFilterType.contains) {\n \u201C..{{getRawValue(facet)}}..\u201D\n }\n @case (FacetFilterType.equal) {\n \u201C{{getRawValue(facet)}}\u201D\n }\n @case (FacetFilterType.startsWith) {\n \u201C{{getRawValue(facet)}}...\u201D\n }\n @case (FacetFilterType.endsWith) {\n \u201C...{{getRawValue(facet)}}\u201D\n }\n }\n }\n }\n\n @if (!facet.readonly) {\n <mat-icon matChipRemove (click)=\"removeFacet(facet)\">cancel</mat-icon>\n }\n\n </span>\n\n </mat-chip-option>\n }\n\n <mat-chip-row class=\"filter-input-container\" disableRipple=\"true\" disabled=\"true\" @chipAnimation>\n\n <span class=\"flex-facet-autocomplete\">\n\n <mat-icon class=\"add-icon\" (click)=\"focus($event)\">add</mat-icon>\n\n <input #filterInput [matChipInputFor]=\"chipList\" class=\"filter-input\" [placeholder]=\"placeholder()\"\n [matChipInputAddOnBlur]=\"false\" [matAutocomplete]=\"auto\">\n\n <mat-autocomplete #auto=\"matAutocomplete\" class=\"mat-facet-autocomplete\" (optionSelected)=\"autoCompleteSelected($event)\"\n [displayWith]=\"autoCompleteDisplay\" panelWidth=\"250px\">\n @for (facet of filteredFacets(); track facet.id) {\n <mat-option [value]=\"facet\">\n @if (facet.icon) {\n <mat-icon>{{facet.icon}}</mat-icon>\n }\n <span>{{ facet.label }}</span>\n </mat-option>\n }\n </mat-autocomplete>\n\n </span>\n\n </mat-chip-row>\n\n </mat-chip-grid>\n\n </div>\n\n\n @if (clearButtonEnabled() && selectedFacets().length > 0) {\n <button mat-flat-button (click)=\"reset()\" color=\"accent\">\n {{clearButtonText()}}\n </button>\n }\n\n</div>\n", styles: ["*{outline:0}.filter-input-container{background-color:transparent!important;opacity:1!important;box-shadow:none!important}.filter-input-container .filter-input{border:none!important;background:none!important;width:85px;font-size:14px!important;font-weight:400;text-align:right;position:relative;top:-7px;margin-left:2px}::placeholder{color:#000000db;opacity:1}.inline-chip-icon{width:18px;height:18px;font-size:18px;margin-right:7px;margin-left:0}:host-context .mat-checkbox-inner-container{transform:scale(.7)}:host-context(.inlineChipCheckbox) label.mat-checkbox-layout div.mat-checkbox-inner-container{transform:scale(.7)}.add-icon{margin-top:8px}.add-icon:hover,.filter-input-container:hover{cursor:pointer}.main-facet-wrapper{min-height:36px;display:flex;align-items:center}.main-facet-wrapper .icon-wrapper{height:100%;display:flex;justify-content:center;align-items:center;margin-right:20px}::ng-deep .mat-autocomplete-panel.mat-autocomplete-visible{left:-40px!important;top:15px!important}::ng-deep .mat-chip-list-wrapper{transition:width .3s ease-in-out}.content-wrapper{flex:1}.flex-facet{display:flex;align-items:center}.flex-facet-autocomplete{justify-content:center}\n"] }]
1076
+ }], ctorParameters: () => [], propDecorators: { filterInput: [{
1077
+ type: ViewChild,
1078
+ args: ['filterInput']
1079
+ }], inputAutoComplete: [{
1080
+ type: ViewChild,
1081
+ args: [MatAutocompleteTrigger, { read: MatAutocompleteTrigger }]
1082
+ }] } });
1083
+
1084
+ /*
1085
+ * Public API Surface of ngx-mat-facet-toolkit
1086
+ */
1087
+
1088
+ /**
1089
+ * Generated bundle index. Do not edit.
1090
+ */
1091
+
1092
+ export { DEFAULT_FACET_TOOLKIT_CONFIG, FACET_TOOLKIT_CONFIG, FacetDataType, FacetFilterType, FacetIdentifierStrategy, NgxMatFacetToolkitComponent, provideFacetToolkitConfig };
1093
+ //# sourceMappingURL=drsutphin-ngx-mat-facet-toolkit.mjs.map