@jigisha_ruparel/taf-client-filter-bar-angular 0.1.0 → 0.3.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.
|
@@ -1,8 +1,18 @@
|
|
|
1
1
|
import * as i1 from '@angular/common';
|
|
2
2
|
import { CommonModule } from '@angular/common';
|
|
3
3
|
import * as i0 from '@angular/core';
|
|
4
|
-
import { Directive, EventEmitter,
|
|
4
|
+
import { Directive, EventEmitter, Output, Input, ChangeDetectionStrategy, Component } from '@angular/core';
|
|
5
5
|
|
|
6
|
+
/** Marks host content to place at the START of the bar, before the filters (a date navigator, a
|
|
7
|
+
* tab strip, a counts block) — the controls a row leads with rather than trails. */
|
|
8
|
+
class TafFilterBarStartDirective {
|
|
9
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.5", ngImport: i0, type: TafFilterBarStartDirective, deps: [], target: i0.ɵɵFactoryTarget.Directive });
|
|
10
|
+
static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "22.1.5", type: TafFilterBarStartDirective, isStandalone: true, selector: "[tafFilterBarStart]", ngImport: i0 });
|
|
11
|
+
}
|
|
12
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.5", ngImport: i0, type: TafFilterBarStartDirective, decorators: [{
|
|
13
|
+
type: Directive,
|
|
14
|
+
args: [{ selector: '[tafFilterBarStart]', standalone: true }]
|
|
15
|
+
}] });
|
|
6
16
|
/** Marks host content to place at the end of the bar (an export button, a view switch). */
|
|
7
17
|
class TafFilterBarEndDirective {
|
|
8
18
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.5", ngImport: i0, type: TafFilterBarEndDirective, deps: [], target: i0.ɵɵFactoryTarget.Directive });
|
|
@@ -20,8 +30,9 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.5", ngImpor
|
|
|
20
30
|
* key that moved plus `(valueChange)` with the whole record, so a host can keep either one signal per
|
|
21
31
|
* filter or a single object — whichever it already has.
|
|
22
32
|
*
|
|
23
|
-
* Values by kind: `search`/`select`/`date` → string; `chips` → string[]; `date-range` →
|
|
24
|
-
* `{ from: string; to: string }`; `toggle` → boolean.
|
|
33
|
+
* Values by kind: `search`/`select`/`date`/`segmented` → string; `chips` → string[]; `date-range` →
|
|
34
|
+
* `{ from: string; to: string }`; `toggle` → boolean. `segmented` is the single-select sibling of
|
|
35
|
+
* `chips`, for a status rail where exactly one choice is active.
|
|
25
36
|
*
|
|
26
37
|
* Ships NO theme — `taf-filter-bar__*` class hooks plus `data-kind` / `data-active`, and
|
|
27
38
|
* `ViewEncapsulation.None` is deliberately NOT used here: the controls are plain elements the host
|
|
@@ -30,8 +41,12 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.5", ngImpor
|
|
|
30
41
|
class TafFilterBarComponent {
|
|
31
42
|
filters = [];
|
|
32
43
|
value = {};
|
|
33
|
-
/**
|
|
34
|
-
|
|
44
|
+
/**
|
|
45
|
+
* Whether the Clear button renders. Left unset it appears once any filter is set; set it
|
|
46
|
+
* explicitly to decide yourself — a host whose Clear also resets state the bar cannot see (tiles,
|
|
47
|
+
* a tree selection) needs that, or Clear would hide while those filters are still on.
|
|
48
|
+
*/
|
|
49
|
+
showClear = null;
|
|
35
50
|
clearLabel = 'Clear';
|
|
36
51
|
/** Default debounce for `search` filters that do not set their own, in ms. */
|
|
37
52
|
searchDebounce = 200;
|
|
@@ -46,7 +61,11 @@ class TafFilterBarComponent {
|
|
|
46
61
|
if (this.timer)
|
|
47
62
|
clearTimeout(this.timer);
|
|
48
63
|
}
|
|
49
|
-
/**
|
|
64
|
+
/** Clear renders when the host says so, or by default once anything is set. */
|
|
65
|
+
get clearVisible() {
|
|
66
|
+
return this.showClear ?? this.isDirty;
|
|
67
|
+
}
|
|
68
|
+
/** True when anything is set. */
|
|
50
69
|
get isDirty() {
|
|
51
70
|
return this.filters.some((f) => {
|
|
52
71
|
const v = this.value[f.key];
|
|
@@ -67,6 +86,8 @@ class TafFilterBarComponent {
|
|
|
67
86
|
return raw.map((o) => ({
|
|
68
87
|
value: String(o[vk ?? 'value'] ?? ''),
|
|
69
88
|
label: String(o[lk ?? 'label'] ?? o[vk ?? 'value'] ?? ''),
|
|
89
|
+
count: typeof o['count'] === 'number' ? o['count'] : undefined,
|
|
90
|
+
dot: typeof o['dot'] === 'string' ? o['dot'] : undefined,
|
|
70
91
|
}));
|
|
71
92
|
}
|
|
72
93
|
asText(key) {
|
|
@@ -119,9 +140,18 @@ class TafFilterBarComponent {
|
|
|
119
140
|
this.valueChange.emit(this.value);
|
|
120
141
|
}
|
|
121
142
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.5", ngImport: i0, type: TafFilterBarComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
122
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "
|
|
143
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "22.1.5", type: TafFilterBarComponent, isStandalone: true, selector: "taf-filter-bar", inputs: { filters: "filters", value: "value", showClear: "showClear", clearLabel: "clearLabel", searchDebounce: "searchDebounce" }, outputs: { changed: "changed", valueChange: "valueChange", cleared: "cleared" }, ngImport: i0, template: `
|
|
123
144
|
<div class="taf-filter-bar" role="search">
|
|
145
|
+
<ng-content select="[tafFilterBarStart]"></ng-content>
|
|
124
146
|
<ng-container *ngFor="let f of filters; trackBy: trackKey">
|
|
147
|
+
<div
|
|
148
|
+
class="taf-filter-bar__group"
|
|
149
|
+
[attr.data-key]="f.key"
|
|
150
|
+
[attr.data-kind]="f.kind"
|
|
151
|
+
[attr.data-captioned]="f.caption ? '' : null"
|
|
152
|
+
[attr.data-grow]="f.grow ? '' : null"
|
|
153
|
+
>
|
|
154
|
+
<span class="taf-filter-bar__caption" *ngIf="f.caption">{{ f.caption }}</span>
|
|
125
155
|
<ng-container [ngSwitch]="f.kind">
|
|
126
156
|
<input
|
|
127
157
|
*ngSwitchCase="'search'"
|
|
@@ -149,7 +179,7 @@ class TafFilterBarComponent {
|
|
|
149
179
|
[value]="asText(f.key)"
|
|
150
180
|
(change)="set(f.key, $any($event.target).value)"
|
|
151
181
|
>
|
|
152
|
-
<option value="" [selected]="!asText(f.key)">{{ f.label || 'All' }}</option>
|
|
182
|
+
<option *ngIf="f.allowEmpty !== false" value="" [selected]="!asText(f.key)">{{ f.label || 'All' }}</option>
|
|
153
183
|
<option
|
|
154
184
|
*ngFor="let o of options(f)"
|
|
155
185
|
[value]="o.value"
|
|
@@ -166,7 +196,35 @@ class TafFilterBarComponent {
|
|
|
166
196
|
[attr.aria-pressed]="isPicked(f.key, o.value)"
|
|
167
197
|
[disabled]="!!f.disabled"
|
|
168
198
|
(click)="toggleChip(f.key, o.value)"
|
|
169
|
-
>
|
|
199
|
+
>
|
|
200
|
+
<span class="taf-filter-bar__dot" *ngIf="o.dot" [style.background]="o.dot" aria-hidden="true"></span>
|
|
201
|
+
{{ o.label }}
|
|
202
|
+
<span class="taf-filter-bar__count" *ngIf="o.count !== undefined">{{ o.count }}</span>
|
|
203
|
+
</button>
|
|
204
|
+
</div>
|
|
205
|
+
|
|
206
|
+
<div
|
|
207
|
+
*ngSwitchCase="'segmented'"
|
|
208
|
+
class="taf-filter-bar__chips taf-filter-bar__chips--single"
|
|
209
|
+
data-kind="segmented"
|
|
210
|
+
role="radiogroup"
|
|
211
|
+
[attr.data-key]="f.key"
|
|
212
|
+
>
|
|
213
|
+
<button
|
|
214
|
+
*ngFor="let o of options(f)"
|
|
215
|
+
type="button"
|
|
216
|
+
role="radio"
|
|
217
|
+
class="taf-filter-bar__chip"
|
|
218
|
+
[attr.data-active]="asText(f.key) === o.value ? '' : null"
|
|
219
|
+
[attr.data-option]="o.value"
|
|
220
|
+
[attr.aria-checked]="asText(f.key) === o.value"
|
|
221
|
+
[disabled]="!!f.disabled"
|
|
222
|
+
(click)="set(f.key, o.value)"
|
|
223
|
+
>
|
|
224
|
+
<span class="taf-filter-bar__dot" *ngIf="o.dot" [style.background]="o.dot" aria-hidden="true"></span>
|
|
225
|
+
{{ o.label }}
|
|
226
|
+
<span class="taf-filter-bar__count" *ngIf="o.count !== undefined">{{ o.count }}</span>
|
|
227
|
+
</button>
|
|
170
228
|
</div>
|
|
171
229
|
|
|
172
230
|
<input
|
|
@@ -214,12 +272,13 @@ class TafFilterBarComponent {
|
|
|
214
272
|
{{ f.label }}
|
|
215
273
|
</label>
|
|
216
274
|
</ng-container>
|
|
275
|
+
</div>
|
|
217
276
|
</ng-container>
|
|
218
277
|
|
|
219
278
|
<span class="taf-filter-bar__spacer"></span>
|
|
220
279
|
<ng-content select="[tafFilterBarEnd]"></ng-content>
|
|
221
280
|
<button
|
|
222
|
-
*ngIf="
|
|
281
|
+
*ngIf="clearVisible"
|
|
223
282
|
type="button"
|
|
224
283
|
class="taf-filter-bar__clear"
|
|
225
284
|
(click)="clear()"
|
|
@@ -231,7 +290,16 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.5", ngImpor
|
|
|
231
290
|
type: Component,
|
|
232
291
|
args: [{ selector: 'taf-filter-bar', standalone: true, imports: [CommonModule], changeDetection: ChangeDetectionStrategy.OnPush, template: `
|
|
233
292
|
<div class="taf-filter-bar" role="search">
|
|
293
|
+
<ng-content select="[tafFilterBarStart]"></ng-content>
|
|
234
294
|
<ng-container *ngFor="let f of filters; trackBy: trackKey">
|
|
295
|
+
<div
|
|
296
|
+
class="taf-filter-bar__group"
|
|
297
|
+
[attr.data-key]="f.key"
|
|
298
|
+
[attr.data-kind]="f.kind"
|
|
299
|
+
[attr.data-captioned]="f.caption ? '' : null"
|
|
300
|
+
[attr.data-grow]="f.grow ? '' : null"
|
|
301
|
+
>
|
|
302
|
+
<span class="taf-filter-bar__caption" *ngIf="f.caption">{{ f.caption }}</span>
|
|
235
303
|
<ng-container [ngSwitch]="f.kind">
|
|
236
304
|
<input
|
|
237
305
|
*ngSwitchCase="'search'"
|
|
@@ -259,7 +327,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.5", ngImpor
|
|
|
259
327
|
[value]="asText(f.key)"
|
|
260
328
|
(change)="set(f.key, $any($event.target).value)"
|
|
261
329
|
>
|
|
262
|
-
<option value="" [selected]="!asText(f.key)">{{ f.label || 'All' }}</option>
|
|
330
|
+
<option *ngIf="f.allowEmpty !== false" value="" [selected]="!asText(f.key)">{{ f.label || 'All' }}</option>
|
|
263
331
|
<option
|
|
264
332
|
*ngFor="let o of options(f)"
|
|
265
333
|
[value]="o.value"
|
|
@@ -276,7 +344,35 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.5", ngImpor
|
|
|
276
344
|
[attr.aria-pressed]="isPicked(f.key, o.value)"
|
|
277
345
|
[disabled]="!!f.disabled"
|
|
278
346
|
(click)="toggleChip(f.key, o.value)"
|
|
279
|
-
>
|
|
347
|
+
>
|
|
348
|
+
<span class="taf-filter-bar__dot" *ngIf="o.dot" [style.background]="o.dot" aria-hidden="true"></span>
|
|
349
|
+
{{ o.label }}
|
|
350
|
+
<span class="taf-filter-bar__count" *ngIf="o.count !== undefined">{{ o.count }}</span>
|
|
351
|
+
</button>
|
|
352
|
+
</div>
|
|
353
|
+
|
|
354
|
+
<div
|
|
355
|
+
*ngSwitchCase="'segmented'"
|
|
356
|
+
class="taf-filter-bar__chips taf-filter-bar__chips--single"
|
|
357
|
+
data-kind="segmented"
|
|
358
|
+
role="radiogroup"
|
|
359
|
+
[attr.data-key]="f.key"
|
|
360
|
+
>
|
|
361
|
+
<button
|
|
362
|
+
*ngFor="let o of options(f)"
|
|
363
|
+
type="button"
|
|
364
|
+
role="radio"
|
|
365
|
+
class="taf-filter-bar__chip"
|
|
366
|
+
[attr.data-active]="asText(f.key) === o.value ? '' : null"
|
|
367
|
+
[attr.data-option]="o.value"
|
|
368
|
+
[attr.aria-checked]="asText(f.key) === o.value"
|
|
369
|
+
[disabled]="!!f.disabled"
|
|
370
|
+
(click)="set(f.key, o.value)"
|
|
371
|
+
>
|
|
372
|
+
<span class="taf-filter-bar__dot" *ngIf="o.dot" [style.background]="o.dot" aria-hidden="true"></span>
|
|
373
|
+
{{ o.label }}
|
|
374
|
+
<span class="taf-filter-bar__count" *ngIf="o.count !== undefined">{{ o.count }}</span>
|
|
375
|
+
</button>
|
|
280
376
|
</div>
|
|
281
377
|
|
|
282
378
|
<input
|
|
@@ -324,12 +420,13 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.5", ngImpor
|
|
|
324
420
|
{{ f.label }}
|
|
325
421
|
</label>
|
|
326
422
|
</ng-container>
|
|
423
|
+
</div>
|
|
327
424
|
</ng-container>
|
|
328
425
|
|
|
329
426
|
<span class="taf-filter-bar__spacer"></span>
|
|
330
427
|
<ng-content select="[tafFilterBarEnd]"></ng-content>
|
|
331
428
|
<button
|
|
332
|
-
*ngIf="
|
|
429
|
+
*ngIf="clearVisible"
|
|
333
430
|
type="button"
|
|
334
431
|
class="taf-filter-bar__clear"
|
|
335
432
|
(click)="clear()"
|
|
@@ -341,8 +438,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.5", ngImpor
|
|
|
341
438
|
}], value: [{
|
|
342
439
|
type: Input
|
|
343
440
|
}], showClear: [{
|
|
344
|
-
type: Input
|
|
345
|
-
args: [{ transform: booleanAttribute }]
|
|
441
|
+
type: Input
|
|
346
442
|
}], clearLabel: [{
|
|
347
443
|
type: Input
|
|
348
444
|
}], searchDebounce: [{
|
|
@@ -354,10 +450,20 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.5", ngImpor
|
|
|
354
450
|
}], cleared: [{
|
|
355
451
|
type: Output
|
|
356
452
|
}] } });
|
|
453
|
+
/**
|
|
454
|
+
* Everything `<taf-filter-bar>` needs, in one import: `imports: [...TAF_FILTER_BAR]`.
|
|
455
|
+
* Importing the component alone leaves `[tafFilterBarStart]` / `[tafFilterBarEnd]` content
|
|
456
|
+
* unprojected — it simply does not render, with no error.
|
|
457
|
+
*/
|
|
458
|
+
const TAF_FILTER_BAR = [
|
|
459
|
+
TafFilterBarComponent,
|
|
460
|
+
TafFilterBarStartDirective,
|
|
461
|
+
TafFilterBarEndDirective,
|
|
462
|
+
];
|
|
357
463
|
|
|
358
464
|
/**
|
|
359
465
|
* Generated bundle index. Do not edit.
|
|
360
466
|
*/
|
|
361
467
|
|
|
362
|
-
export { TafFilterBarComponent, TafFilterBarEndDirective };
|
|
468
|
+
export { TAF_FILTER_BAR, TafFilterBarComponent, TafFilterBarEndDirective, TafFilterBarStartDirective };
|
|
363
469
|
//# sourceMappingURL=jigisha_ruparel-taf-client-filter-bar-angular.mjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"jigisha_ruparel-taf-client-filter-bar-angular.mjs","sources":["../../src/taf-filter-bar.component.ts","../../src/jigisha_ruparel-taf-client-filter-bar-angular.ts"],"sourcesContent":["import { CommonModule } from '@angular/common';\nimport {\n ChangeDetectionStrategy,\n Component,\n Directive,\n EventEmitter,\n Input,\n OnDestroy,\n Output,\n booleanAttribute,\n} from '@angular/core';\n\n/** What a filter looks like on screen. */\nexport type TafFilterKind = 'search' | 'select' | 'chips' | 'date' | 'date-range' | 'toggle';\n\n/** One entry in a select or chip group. */\nexport interface TafFilterOption {\n value: string;\n label: string;\n}\n\n/** One filter in the bar. `key` is what the value is stored and emitted under. */\nexport interface TafFilterSpec {\n key: string;\n kind: TafFilterKind;\n /** Placeholder for a search box, the \"nothing selected\" entry for a select, the caption for a toggle. */\n label?: string;\n /** Options for `select` and `chips`. Raw rows work too — name the fields with optionValue/optionLabel. */\n options?: readonly TafFilterOption[] | readonly object[];\n optionValue?: string;\n optionLabel?: string;\n /** Width in px; the bar's own layout applies when unset. */\n width?: number;\n /** Search only: ms to wait after typing before emitting (0 emits on every keystroke). */\n debounce?: number;\n /** Shown instead of `label` inside the control, when both make sense (e.g. a select's own title). */\n title?: string;\n disabled?: boolean;\n}\n\n/** The bar's current state: one entry per filter key. */\nexport type TafFilterValue = Record<string, unknown>;\n\n/** Marks host content to place at the end of the bar (an export button, a view switch). */\n@Directive({ selector: '[tafFilterBarEnd]', standalone: true })\nexport class TafFilterBarEndDirective {}\n\n/**\n * `<taf-filter-bar>` — the row of controls that sits above a list: a search box, some selects, a\n * chip group, a date range, and a Clear that appears once anything is set.\n *\n * The bar owns no state. It renders `[value]`, and every interaction emits `(changed)` with the one\n * key that moved plus `(valueChange)` with the whole record, so a host can keep either one signal per\n * filter or a single object — whichever it already has.\n *\n * Values by kind: `search`/`select`/`date` → string; `chips` → string[]; `date-range` →\n * `{ from: string; to: string }`; `toggle` → boolean.\n *\n * Ships NO theme — `taf-filter-bar__*` class hooks plus `data-kind` / `data-active`, and\n * `ViewEncapsulation.None` is deliberately NOT used here: the controls are plain elements the host\n * app styles through those classes.\n */\n@Component({\n selector: 'taf-filter-bar',\n standalone: true,\n imports: [CommonModule],\n changeDetection: ChangeDetectionStrategy.OnPush,\n template: `\n <div class=\"taf-filter-bar\" role=\"search\">\n <ng-container *ngFor=\"let f of filters; trackBy: trackKey\">\n <ng-container [ngSwitch]=\"f.kind\">\n <input\n *ngSwitchCase=\"'search'\"\n class=\"taf-filter-bar__field taf-filter-bar__search\"\n type=\"search\"\n data-kind=\"search\"\n [attr.data-key]=\"f.key\"\n [attr.aria-label]=\"f.label || 'Search'\"\n [placeholder]=\"f.label || ''\"\n [disabled]=\"!!f.disabled\"\n [style.width.px]=\"f.width || null\"\n [value]=\"asText(f.key)\"\n (input)=\"onSearch(f, $any($event.target).value)\"\n />\n\n <select\n *ngSwitchCase=\"'select'\"\n class=\"taf-filter-bar__field taf-filter-bar__select\"\n data-kind=\"select\"\n [attr.data-key]=\"f.key\"\n [attr.data-active]=\"asText(f.key) ? '' : null\"\n [attr.aria-label]=\"f.title || f.label || f.key\"\n [disabled]=\"!!f.disabled\"\n [style.width.px]=\"f.width || null\"\n [value]=\"asText(f.key)\"\n (change)=\"set(f.key, $any($event.target).value)\"\n >\n <option value=\"\" [selected]=\"!asText(f.key)\">{{ f.label || 'All' }}</option>\n <option\n *ngFor=\"let o of options(f)\"\n [value]=\"o.value\"\n [selected]=\"asText(f.key) === o.value\"\n >{{ o.label }}</option>\n </select>\n\n <div *ngSwitchCase=\"'chips'\" class=\"taf-filter-bar__chips\" data-kind=\"chips\" [attr.data-key]=\"f.key\">\n <button\n *ngFor=\"let o of options(f)\"\n type=\"button\"\n class=\"taf-filter-bar__chip\"\n [attr.data-active]=\"isPicked(f.key, o.value) ? '' : null\"\n [attr.aria-pressed]=\"isPicked(f.key, o.value)\"\n [disabled]=\"!!f.disabled\"\n (click)=\"toggleChip(f.key, o.value)\"\n >{{ o.label }}</button>\n </div>\n\n <input\n *ngSwitchCase=\"'date'\"\n class=\"taf-filter-bar__field taf-filter-bar__date\"\n type=\"date\"\n data-kind=\"date\"\n [attr.data-key]=\"f.key\"\n [attr.aria-label]=\"f.label || f.key\"\n [attr.title]=\"f.title || f.label || null\"\n [disabled]=\"!!f.disabled\"\n [value]=\"asText(f.key)\"\n (input)=\"set(f.key, $any($event.target).value)\"\n />\n\n <div *ngSwitchCase=\"'date-range'\" class=\"taf-filter-bar__range\" data-kind=\"date-range\" [attr.data-key]=\"f.key\">\n <input\n type=\"date\"\n class=\"taf-filter-bar__field taf-filter-bar__date\"\n [attr.aria-label]=\"(f.label || f.key) + ' from'\"\n title=\"From\"\n [disabled]=\"!!f.disabled\"\n [value]=\"range(f.key).from\"\n (input)=\"setRange(f.key, 'from', $any($event.target).value)\"\n />\n <span class=\"taf-filter-bar__range-sep\" aria-hidden=\"true\">–</span>\n <input\n type=\"date\"\n class=\"taf-filter-bar__field taf-filter-bar__date\"\n [attr.aria-label]=\"(f.label || f.key) + ' to'\"\n title=\"To\"\n [disabled]=\"!!f.disabled\"\n [value]=\"range(f.key).to\"\n (input)=\"setRange(f.key, 'to', $any($event.target).value)\"\n />\n </div>\n\n <label *ngSwitchCase=\"'toggle'\" class=\"taf-filter-bar__toggle\" data-kind=\"toggle\" [attr.data-key]=\"f.key\">\n <input\n type=\"checkbox\"\n [disabled]=\"!!f.disabled\"\n [checked]=\"!!value[f.key]\"\n (change)=\"set(f.key, $any($event.target).checked)\"\n />\n {{ f.label }}\n </label>\n </ng-container>\n </ng-container>\n\n <span class=\"taf-filter-bar__spacer\"></span>\n <ng-content select=\"[tafFilterBarEnd]\"></ng-content>\n <button\n *ngIf=\"showClear && isDirty\"\n type=\"button\"\n class=\"taf-filter-bar__clear\"\n (click)=\"clear()\"\n >{{ clearLabel }}</button>\n </div>\n `,\n styles: [\n `\n taf-filter-bar { display: contents; }\n `,\n ],\n})\nexport class TafFilterBarComponent implements OnDestroy {\n @Input() filters: readonly TafFilterSpec[] = [];\n @Input() value: TafFilterValue = {};\n /** Show a Clear button once any filter is set. */\n @Input({ transform: booleanAttribute }) showClear = true;\n @Input() clearLabel = 'Clear';\n /** Default debounce for `search` filters that do not set their own, in ms. */\n @Input() searchDebounce = 200;\n\n /** The one filter that moved. */\n @Output() readonly changed = new EventEmitter<{ key: string; value: unknown }>();\n /** The whole record after that change. */\n @Output() readonly valueChange = new EventEmitter<TafFilterValue>();\n /** Clear pressed — the host decides what \"empty\" means for its own state. */\n @Output() readonly cleared = new EventEmitter<void>();\n\n private timer?: ReturnType<typeof setTimeout>;\n\n ngOnDestroy(): void {\n if (this.timer) clearTimeout(this.timer);\n }\n\n /** True when anything is set — what makes Clear appear. */\n get isDirty(): boolean {\n return this.filters.some((f) => {\n const v = this.value[f.key];\n if (Array.isArray(v)) return v.length > 0;\n if (v && typeof v === 'object') return Object.values(v as object).some(Boolean);\n return v !== undefined && v !== null && v !== '' && v !== false;\n });\n }\n\n protected trackKey = (_: number, f: TafFilterSpec) => f.key;\n\n protected options(f: TafFilterSpec): TafFilterOption[] {\n const raw = f.options ?? [];\n const vk = f.optionValue;\n const lk = f.optionLabel;\n if (!vk && !lk) return raw as TafFilterOption[];\n return (raw as readonly Record<string, unknown>[]).map((o) => ({\n value: String(o[vk ?? 'value'] ?? ''),\n label: String(o[lk ?? 'label'] ?? o[vk ?? 'value'] ?? ''),\n }));\n }\n\n protected asText(key: string): string {\n const v = this.value[key];\n return v === undefined || v === null ? '' : String(v);\n }\n\n protected range(key: string): { from: string; to: string } {\n const v = (this.value[key] ?? {}) as { from?: string; to?: string };\n return { from: v.from ?? '', to: v.to ?? '' };\n }\n\n protected isPicked(key: string, option: string): boolean {\n const v = this.value[key];\n return Array.isArray(v) ? v.includes(option) : false;\n }\n\n protected onSearch(f: TafFilterSpec, text: string): void {\n const wait = f.debounce ?? this.searchDebounce;\n if (this.timer) clearTimeout(this.timer);\n if (!wait) {\n this.set(f.key, text);\n return;\n }\n this.timer = setTimeout(() => this.set(f.key, text), wait);\n }\n\n protected toggleChip(key: string, option: string): void {\n const current = Array.isArray(this.value[key]) ? ([...(this.value[key] as string[])]) : [];\n const at = current.indexOf(option);\n if (at >= 0) current.splice(at, 1);\n else current.push(option);\n this.set(key, current);\n }\n\n protected setRange(key: string, edge: 'from' | 'to', text: string): void {\n this.set(key, { ...this.range(key), [edge]: text });\n }\n\n protected set(key: string, next: unknown): void {\n this.value = { ...this.value, [key]: next };\n this.changed.emit({ key, value: next });\n this.valueChange.emit(this.value);\n }\n\n protected clear(): void {\n const empty: TafFilterValue = {};\n for (const f of this.filters) {\n empty[f.key] =\n f.kind === 'chips' ? [] : f.kind === 'date-range' ? { from: '', to: '' } : f.kind === 'toggle' ? false : '';\n }\n this.value = empty;\n this.cleared.emit();\n this.valueChange.emit(this.value);\n }\n}\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './index';\n"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"jigisha_ruparel-taf-client-filter-bar-angular.mjs","sources":["../../src/taf-filter-bar.component.ts","../../src/jigisha_ruparel-taf-client-filter-bar-angular.ts"],"sourcesContent":["import { CommonModule } from '@angular/common';\nimport {\n ChangeDetectionStrategy,\n Component,\n Directive,\n EventEmitter,\n Input,\n OnDestroy,\n Output,\n booleanAttribute,\n} from '@angular/core';\n\n/** What a filter looks like on screen. */\nexport type TafFilterKind = 'search' | 'select' | 'chips' | 'segmented' | 'date' | 'date-range' | 'toggle';\n\n/** One entry in a select or chip group. */\nexport interface TafFilterOption {\n value: string;\n label: string;\n /** A live count beside the label — how many rows this choice would show. */\n count?: number;\n /** A colour for the chip's leading dot; the host theme decides what it means. */\n dot?: string;\n}\n\n/** One filter in the bar. `key` is what the value is stored and emitted under. */\nexport interface TafFilterSpec {\n key: string;\n kind: TafFilterKind;\n /** Placeholder for a search box, the \"nothing selected\" entry for a select, the caption for a toggle. */\n label?: string;\n /** Options for `select` and `chips`. Raw rows work too — name the fields with optionValue/optionLabel. */\n options?: readonly TafFilterOption[] | readonly object[];\n optionValue?: string;\n optionLabel?: string;\n /** Width in px; the bar's own layout applies when unset. */\n width?: number;\n /** Search only: ms to wait after typing before emitting (0 emits on every keystroke). */\n debounce?: number;\n /** Shown instead of `label` inside the control, when both make sense (e.g. a select's own title). */\n title?: string;\n disabled?: boolean;\n /** A caption above the control, for a bar whose groups are labelled (DATE RANGE, STATUS, …). */\n caption?: string;\n /**\n * `select` only. False drops the injected \"nothing selected\" entry, for a preset picker whose\n * every option is a real value and which therefore always has one chosen.\n */\n allowEmpty?: boolean;\n /**\n * Let this control take the row's leftover width — a chip group that used to be the flexible\n * element of a toolbar, so what follows it stays on the same line instead of wrapping.\n */\n grow?: boolean;\n}\n\n/** The bar's current state: one entry per filter key. */\nexport type TafFilterValue = Record<string, unknown>;\n\n/** Marks host content to place at the START of the bar, before the filters (a date navigator, a\n * tab strip, a counts block) — the controls a row leads with rather than trails. */\n@Directive({ selector: '[tafFilterBarStart]', standalone: true })\nexport class TafFilterBarStartDirective {}\n\n/** Marks host content to place at the end of the bar (an export button, a view switch). */\n@Directive({ selector: '[tafFilterBarEnd]', standalone: true })\nexport class TafFilterBarEndDirective {}\n\n/**\n * `<taf-filter-bar>` — the row of controls that sits above a list: a search box, some selects, a\n * chip group, a date range, and a Clear that appears once anything is set.\n *\n * The bar owns no state. It renders `[value]`, and every interaction emits `(changed)` with the one\n * key that moved plus `(valueChange)` with the whole record, so a host can keep either one signal per\n * filter or a single object — whichever it already has.\n *\n * Values by kind: `search`/`select`/`date`/`segmented` → string; `chips` → string[]; `date-range` →\n * `{ from: string; to: string }`; `toggle` → boolean. `segmented` is the single-select sibling of\n * `chips`, for a status rail where exactly one choice is active.\n *\n * Ships NO theme — `taf-filter-bar__*` class hooks plus `data-kind` / `data-active`, and\n * `ViewEncapsulation.None` is deliberately NOT used here: the controls are plain elements the host\n * app styles through those classes.\n */\n@Component({\n selector: 'taf-filter-bar',\n standalone: true,\n imports: [CommonModule],\n changeDetection: ChangeDetectionStrategy.OnPush,\n template: `\n <div class=\"taf-filter-bar\" role=\"search\">\n <ng-content select=\"[tafFilterBarStart]\"></ng-content>\n <ng-container *ngFor=\"let f of filters; trackBy: trackKey\">\n <div\n class=\"taf-filter-bar__group\"\n [attr.data-key]=\"f.key\"\n [attr.data-kind]=\"f.kind\"\n [attr.data-captioned]=\"f.caption ? '' : null\"\n [attr.data-grow]=\"f.grow ? '' : null\"\n >\n <span class=\"taf-filter-bar__caption\" *ngIf=\"f.caption\">{{ f.caption }}</span>\n <ng-container [ngSwitch]=\"f.kind\">\n <input\n *ngSwitchCase=\"'search'\"\n class=\"taf-filter-bar__field taf-filter-bar__search\"\n type=\"search\"\n data-kind=\"search\"\n [attr.data-key]=\"f.key\"\n [attr.aria-label]=\"f.label || 'Search'\"\n [placeholder]=\"f.label || ''\"\n [disabled]=\"!!f.disabled\"\n [style.width.px]=\"f.width || null\"\n [value]=\"asText(f.key)\"\n (input)=\"onSearch(f, $any($event.target).value)\"\n />\n\n <select\n *ngSwitchCase=\"'select'\"\n class=\"taf-filter-bar__field taf-filter-bar__select\"\n data-kind=\"select\"\n [attr.data-key]=\"f.key\"\n [attr.data-active]=\"asText(f.key) ? '' : null\"\n [attr.aria-label]=\"f.title || f.label || f.key\"\n [disabled]=\"!!f.disabled\"\n [style.width.px]=\"f.width || null\"\n [value]=\"asText(f.key)\"\n (change)=\"set(f.key, $any($event.target).value)\"\n >\n <option *ngIf=\"f.allowEmpty !== false\" value=\"\" [selected]=\"!asText(f.key)\">{{ f.label || 'All' }}</option>\n <option\n *ngFor=\"let o of options(f)\"\n [value]=\"o.value\"\n [selected]=\"asText(f.key) === o.value\"\n >{{ o.label }}</option>\n </select>\n\n <div *ngSwitchCase=\"'chips'\" class=\"taf-filter-bar__chips\" data-kind=\"chips\" [attr.data-key]=\"f.key\">\n <button\n *ngFor=\"let o of options(f)\"\n type=\"button\"\n class=\"taf-filter-bar__chip\"\n [attr.data-active]=\"isPicked(f.key, o.value) ? '' : null\"\n [attr.aria-pressed]=\"isPicked(f.key, o.value)\"\n [disabled]=\"!!f.disabled\"\n (click)=\"toggleChip(f.key, o.value)\"\n >\n <span class=\"taf-filter-bar__dot\" *ngIf=\"o.dot\" [style.background]=\"o.dot\" aria-hidden=\"true\"></span>\n {{ o.label }}\n <span class=\"taf-filter-bar__count\" *ngIf=\"o.count !== undefined\">{{ o.count }}</span>\n </button>\n </div>\n\n <div\n *ngSwitchCase=\"'segmented'\"\n class=\"taf-filter-bar__chips taf-filter-bar__chips--single\"\n data-kind=\"segmented\"\n role=\"radiogroup\"\n [attr.data-key]=\"f.key\"\n >\n <button\n *ngFor=\"let o of options(f)\"\n type=\"button\"\n role=\"radio\"\n class=\"taf-filter-bar__chip\"\n [attr.data-active]=\"asText(f.key) === o.value ? '' : null\"\n [attr.data-option]=\"o.value\"\n [attr.aria-checked]=\"asText(f.key) === o.value\"\n [disabled]=\"!!f.disabled\"\n (click)=\"set(f.key, o.value)\"\n >\n <span class=\"taf-filter-bar__dot\" *ngIf=\"o.dot\" [style.background]=\"o.dot\" aria-hidden=\"true\"></span>\n {{ o.label }}\n <span class=\"taf-filter-bar__count\" *ngIf=\"o.count !== undefined\">{{ o.count }}</span>\n </button>\n </div>\n\n <input\n *ngSwitchCase=\"'date'\"\n class=\"taf-filter-bar__field taf-filter-bar__date\"\n type=\"date\"\n data-kind=\"date\"\n [attr.data-key]=\"f.key\"\n [attr.aria-label]=\"f.label || f.key\"\n [attr.title]=\"f.title || f.label || null\"\n [disabled]=\"!!f.disabled\"\n [value]=\"asText(f.key)\"\n (input)=\"set(f.key, $any($event.target).value)\"\n />\n\n <div *ngSwitchCase=\"'date-range'\" class=\"taf-filter-bar__range\" data-kind=\"date-range\" [attr.data-key]=\"f.key\">\n <input\n type=\"date\"\n class=\"taf-filter-bar__field taf-filter-bar__date\"\n [attr.aria-label]=\"(f.label || f.key) + ' from'\"\n title=\"From\"\n [disabled]=\"!!f.disabled\"\n [value]=\"range(f.key).from\"\n (input)=\"setRange(f.key, 'from', $any($event.target).value)\"\n />\n <span class=\"taf-filter-bar__range-sep\" aria-hidden=\"true\">–</span>\n <input\n type=\"date\"\n class=\"taf-filter-bar__field taf-filter-bar__date\"\n [attr.aria-label]=\"(f.label || f.key) + ' to'\"\n title=\"To\"\n [disabled]=\"!!f.disabled\"\n [value]=\"range(f.key).to\"\n (input)=\"setRange(f.key, 'to', $any($event.target).value)\"\n />\n </div>\n\n <label *ngSwitchCase=\"'toggle'\" class=\"taf-filter-bar__toggle\" data-kind=\"toggle\" [attr.data-key]=\"f.key\">\n <input\n type=\"checkbox\"\n [disabled]=\"!!f.disabled\"\n [checked]=\"!!value[f.key]\"\n (change)=\"set(f.key, $any($event.target).checked)\"\n />\n {{ f.label }}\n </label>\n </ng-container>\n </div>\n </ng-container>\n\n <span class=\"taf-filter-bar__spacer\"></span>\n <ng-content select=\"[tafFilterBarEnd]\"></ng-content>\n <button\n *ngIf=\"clearVisible\"\n type=\"button\"\n class=\"taf-filter-bar__clear\"\n (click)=\"clear()\"\n >{{ clearLabel }}</button>\n </div>\n `,\n styles: [\n `\n taf-filter-bar { display: contents; }\n `,\n ],\n})\nexport class TafFilterBarComponent implements OnDestroy {\n @Input() filters: readonly TafFilterSpec[] = [];\n @Input() value: TafFilterValue = {};\n /**\n * Whether the Clear button renders. Left unset it appears once any filter is set; set it\n * explicitly to decide yourself — a host whose Clear also resets state the bar cannot see (tiles,\n * a tree selection) needs that, or Clear would hide while those filters are still on.\n */\n @Input() showClear: boolean | null = null;\n @Input() clearLabel = 'Clear';\n /** Default debounce for `search` filters that do not set their own, in ms. */\n @Input() searchDebounce = 200;\n\n /** The one filter that moved. */\n @Output() readonly changed = new EventEmitter<{ key: string; value: unknown }>();\n /** The whole record after that change. */\n @Output() readonly valueChange = new EventEmitter<TafFilterValue>();\n /** Clear pressed — the host decides what \"empty\" means for its own state. */\n @Output() readonly cleared = new EventEmitter<void>();\n\n private timer?: ReturnType<typeof setTimeout>;\n\n ngOnDestroy(): void {\n if (this.timer) clearTimeout(this.timer);\n }\n\n /** Clear renders when the host says so, or by default once anything is set. */\n get clearVisible(): boolean {\n return this.showClear ?? this.isDirty;\n }\n\n /** True when anything is set. */\n get isDirty(): boolean {\n return this.filters.some((f) => {\n const v = this.value[f.key];\n if (Array.isArray(v)) return v.length > 0;\n if (v && typeof v === 'object') return Object.values(v as object).some(Boolean);\n return v !== undefined && v !== null && v !== '' && v !== false;\n });\n }\n\n protected trackKey = (_: number, f: TafFilterSpec) => f.key;\n\n protected options(f: TafFilterSpec): TafFilterOption[] {\n const raw = f.options ?? [];\n const vk = f.optionValue;\n const lk = f.optionLabel;\n if (!vk && !lk) return raw as TafFilterOption[];\n return (raw as readonly Record<string, unknown>[]).map((o) => ({\n value: String(o[vk ?? 'value'] ?? ''),\n label: String(o[lk ?? 'label'] ?? o[vk ?? 'value'] ?? ''),\n count: typeof o['count'] === 'number' ? (o['count'] as number) : undefined,\n dot: typeof o['dot'] === 'string' ? (o['dot'] as string) : undefined,\n }));\n }\n\n protected asText(key: string): string {\n const v = this.value[key];\n return v === undefined || v === null ? '' : String(v);\n }\n\n protected range(key: string): { from: string; to: string } {\n const v = (this.value[key] ?? {}) as { from?: string; to?: string };\n return { from: v.from ?? '', to: v.to ?? '' };\n }\n\n protected isPicked(key: string, option: string): boolean {\n const v = this.value[key];\n return Array.isArray(v) ? v.includes(option) : false;\n }\n\n protected onSearch(f: TafFilterSpec, text: string): void {\n const wait = f.debounce ?? this.searchDebounce;\n if (this.timer) clearTimeout(this.timer);\n if (!wait) {\n this.set(f.key, text);\n return;\n }\n this.timer = setTimeout(() => this.set(f.key, text), wait);\n }\n\n protected toggleChip(key: string, option: string): void {\n const current = Array.isArray(this.value[key]) ? ([...(this.value[key] as string[])]) : [];\n const at = current.indexOf(option);\n if (at >= 0) current.splice(at, 1);\n else current.push(option);\n this.set(key, current);\n }\n\n protected setRange(key: string, edge: 'from' | 'to', text: string): void {\n this.set(key, { ...this.range(key), [edge]: text });\n }\n\n protected set(key: string, next: unknown): void {\n this.value = { ...this.value, [key]: next };\n this.changed.emit({ key, value: next });\n this.valueChange.emit(this.value);\n }\n\n protected clear(): void {\n const empty: TafFilterValue = {};\n for (const f of this.filters) {\n empty[f.key] =\n f.kind === 'chips' ? [] : f.kind === 'date-range' ? { from: '', to: '' } : f.kind === 'toggle' ? false : '';\n }\n this.value = empty;\n this.cleared.emit();\n this.valueChange.emit(this.value);\n }\n}\n\n/**\n * Everything `<taf-filter-bar>` needs, in one import: `imports: [...TAF_FILTER_BAR]`.\n * Importing the component alone leaves `[tafFilterBarStart]` / `[tafFilterBarEnd]` content\n * unprojected — it simply does not render, with no error.\n */\nexport const TAF_FILTER_BAR = [\n TafFilterBarComponent,\n TafFilterBarStartDirective,\n TafFilterBarEndDirective,\n] as const;\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './index';\n"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@jigisha_ruparel/taf-client-filter-bar-angular",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.3.0",
|
|
4
4
|
"description": "<taf-filter-bar> — the themeless row of list filters: search, selects, chip groups, date ranges and Clear.",
|
|
5
5
|
"publishConfig": {
|
|
6
6
|
"access": "public",
|
|
@@ -2,11 +2,15 @@ import * as i0 from '@angular/core';
|
|
|
2
2
|
import { OnDestroy, EventEmitter } from '@angular/core';
|
|
3
3
|
|
|
4
4
|
/** What a filter looks like on screen. */
|
|
5
|
-
type TafFilterKind = 'search' | 'select' | 'chips' | 'date' | 'date-range' | 'toggle';
|
|
5
|
+
type TafFilterKind = 'search' | 'select' | 'chips' | 'segmented' | 'date' | 'date-range' | 'toggle';
|
|
6
6
|
/** One entry in a select or chip group. */
|
|
7
7
|
interface TafFilterOption {
|
|
8
8
|
value: string;
|
|
9
9
|
label: string;
|
|
10
|
+
/** A live count beside the label — how many rows this choice would show. */
|
|
11
|
+
count?: number;
|
|
12
|
+
/** A colour for the chip's leading dot; the host theme decides what it means. */
|
|
13
|
+
dot?: string;
|
|
10
14
|
}
|
|
11
15
|
/** One filter in the bar. `key` is what the value is stored and emitted under. */
|
|
12
16
|
interface TafFilterSpec {
|
|
@@ -25,9 +29,27 @@ interface TafFilterSpec {
|
|
|
25
29
|
/** Shown instead of `label` inside the control, when both make sense (e.g. a select's own title). */
|
|
26
30
|
title?: string;
|
|
27
31
|
disabled?: boolean;
|
|
32
|
+
/** A caption above the control, for a bar whose groups are labelled (DATE RANGE, STATUS, …). */
|
|
33
|
+
caption?: string;
|
|
34
|
+
/**
|
|
35
|
+
* `select` only. False drops the injected "nothing selected" entry, for a preset picker whose
|
|
36
|
+
* every option is a real value and which therefore always has one chosen.
|
|
37
|
+
*/
|
|
38
|
+
allowEmpty?: boolean;
|
|
39
|
+
/**
|
|
40
|
+
* Let this control take the row's leftover width — a chip group that used to be the flexible
|
|
41
|
+
* element of a toolbar, so what follows it stays on the same line instead of wrapping.
|
|
42
|
+
*/
|
|
43
|
+
grow?: boolean;
|
|
28
44
|
}
|
|
29
45
|
/** The bar's current state: one entry per filter key. */
|
|
30
46
|
type TafFilterValue = Record<string, unknown>;
|
|
47
|
+
/** Marks host content to place at the START of the bar, before the filters (a date navigator, a
|
|
48
|
+
* tab strip, a counts block) — the controls a row leads with rather than trails. */
|
|
49
|
+
declare class TafFilterBarStartDirective {
|
|
50
|
+
static ɵfac: i0.ɵɵFactoryDeclaration<TafFilterBarStartDirective, never>;
|
|
51
|
+
static ɵdir: i0.ɵɵDirectiveDeclaration<TafFilterBarStartDirective, "[tafFilterBarStart]", never, {}, {}, never, never, true, never>;
|
|
52
|
+
}
|
|
31
53
|
/** Marks host content to place at the end of the bar (an export button, a view switch). */
|
|
32
54
|
declare class TafFilterBarEndDirective {
|
|
33
55
|
static ɵfac: i0.ɵɵFactoryDeclaration<TafFilterBarEndDirective, never>;
|
|
@@ -41,8 +63,9 @@ declare class TafFilterBarEndDirective {
|
|
|
41
63
|
* key that moved plus `(valueChange)` with the whole record, so a host can keep either one signal per
|
|
42
64
|
* filter or a single object — whichever it already has.
|
|
43
65
|
*
|
|
44
|
-
* Values by kind: `search`/`select`/`date` → string; `chips` → string[]; `date-range` →
|
|
45
|
-
* `{ from: string; to: string }`; `toggle` → boolean.
|
|
66
|
+
* Values by kind: `search`/`select`/`date`/`segmented` → string; `chips` → string[]; `date-range` →
|
|
67
|
+
* `{ from: string; to: string }`; `toggle` → boolean. `segmented` is the single-select sibling of
|
|
68
|
+
* `chips`, for a status rail where exactly one choice is active.
|
|
46
69
|
*
|
|
47
70
|
* Ships NO theme — `taf-filter-bar__*` class hooks plus `data-kind` / `data-active`, and
|
|
48
71
|
* `ViewEncapsulation.None` is deliberately NOT used here: the controls are plain elements the host
|
|
@@ -51,8 +74,12 @@ declare class TafFilterBarEndDirective {
|
|
|
51
74
|
declare class TafFilterBarComponent implements OnDestroy {
|
|
52
75
|
filters: readonly TafFilterSpec[];
|
|
53
76
|
value: TafFilterValue;
|
|
54
|
-
/**
|
|
55
|
-
|
|
77
|
+
/**
|
|
78
|
+
* Whether the Clear button renders. Left unset it appears once any filter is set; set it
|
|
79
|
+
* explicitly to decide yourself — a host whose Clear also resets state the bar cannot see (tiles,
|
|
80
|
+
* a tree selection) needs that, or Clear would hide while those filters are still on.
|
|
81
|
+
*/
|
|
82
|
+
showClear: boolean | null;
|
|
56
83
|
clearLabel: string;
|
|
57
84
|
/** Default debounce for `search` filters that do not set their own, in ms. */
|
|
58
85
|
searchDebounce: number;
|
|
@@ -67,7 +94,9 @@ declare class TafFilterBarComponent implements OnDestroy {
|
|
|
67
94
|
readonly cleared: EventEmitter<void>;
|
|
68
95
|
private timer?;
|
|
69
96
|
ngOnDestroy(): void;
|
|
70
|
-
/**
|
|
97
|
+
/** Clear renders when the host says so, or by default once anything is set. */
|
|
98
|
+
get clearVisible(): boolean;
|
|
99
|
+
/** True when anything is set. */
|
|
71
100
|
get isDirty(): boolean;
|
|
72
101
|
protected trackKey: (_: number, f: TafFilterSpec) => string;
|
|
73
102
|
protected options(f: TafFilterSpec): TafFilterOption[];
|
|
@@ -83,9 +112,14 @@ declare class TafFilterBarComponent implements OnDestroy {
|
|
|
83
112
|
protected set(key: string, next: unknown): void;
|
|
84
113
|
protected clear(): void;
|
|
85
114
|
static ɵfac: i0.ɵɵFactoryDeclaration<TafFilterBarComponent, never>;
|
|
86
|
-
static ɵcmp: i0.ɵɵComponentDeclaration<TafFilterBarComponent, "taf-filter-bar", never, { "filters": { "alias": "filters"; "required": false; }; "value": { "alias": "value"; "required": false; }; "showClear": { "alias": "showClear"; "required": false; }; "clearLabel": { "alias": "clearLabel"; "required": false; }; "searchDebounce": { "alias": "searchDebounce"; "required": false; }; }, { "changed": "changed"; "valueChange": "valueChange"; "cleared": "cleared"; }, never, ["[tafFilterBarEnd]"], true, never>;
|
|
87
|
-
static ngAcceptInputType_showClear: unknown;
|
|
115
|
+
static ɵcmp: i0.ɵɵComponentDeclaration<TafFilterBarComponent, "taf-filter-bar", never, { "filters": { "alias": "filters"; "required": false; }; "value": { "alias": "value"; "required": false; }; "showClear": { "alias": "showClear"; "required": false; }; "clearLabel": { "alias": "clearLabel"; "required": false; }; "searchDebounce": { "alias": "searchDebounce"; "required": false; }; }, { "changed": "changed"; "valueChange": "valueChange"; "cleared": "cleared"; }, never, ["[tafFilterBarStart]", "[tafFilterBarEnd]"], true, never>;
|
|
88
116
|
}
|
|
117
|
+
/**
|
|
118
|
+
* Everything `<taf-filter-bar>` needs, in one import: `imports: [...TAF_FILTER_BAR]`.
|
|
119
|
+
* Importing the component alone leaves `[tafFilterBarStart]` / `[tafFilterBarEnd]` content
|
|
120
|
+
* unprojected — it simply does not render, with no error.
|
|
121
|
+
*/
|
|
122
|
+
declare const TAF_FILTER_BAR: readonly [typeof TafFilterBarComponent, typeof TafFilterBarStartDirective, typeof TafFilterBarEndDirective];
|
|
89
123
|
|
|
90
|
-
export { TafFilterBarComponent, TafFilterBarEndDirective };
|
|
124
|
+
export { TAF_FILTER_BAR, TafFilterBarComponent, TafFilterBarEndDirective, TafFilterBarStartDirective };
|
|
91
125
|
export type { TafFilterKind, TafFilterOption, TafFilterSpec, TafFilterValue };
|