@ngneers/controls 0.0.1-pre1 → 0.0.1-pre2
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.
- package/LICENSE +21 -0
- package/fesm2022/ngneers-controls-accordion.mjs +194 -0
- package/fesm2022/ngneers-controls-accordion.mjs.map +1 -0
- package/fesm2022/ngneers-controls-api-ng.mjs +668 -0
- package/fesm2022/ngneers-controls-api-ng.mjs.map +1 -0
- package/fesm2022/ngneers-controls-api.mjs +256 -227
- package/fesm2022/ngneers-controls-api.mjs.map +1 -1
- package/fesm2022/ngneers-controls-avatar.mjs +70 -0
- package/fesm2022/ngneers-controls-avatar.mjs.map +1 -0
- package/fesm2022/ngneers-controls-base.mjs +397 -0
- package/fesm2022/ngneers-controls-base.mjs.map +1 -0
- package/fesm2022/ngneers-controls-breadcrumb.mjs +74 -0
- package/fesm2022/ngneers-controls-breadcrumb.mjs.map +1 -0
- package/fesm2022/ngneers-controls-button-group.mjs +51 -0
- package/fesm2022/ngneers-controls-button-group.mjs.map +1 -0
- package/fesm2022/ngneers-controls-button.mjs +62 -0
- package/fesm2022/ngneers-controls-button.mjs.map +1 -0
- package/fesm2022/ngneers-controls-calendar-time-C7UnIFzU.mjs +63 -0
- package/fesm2022/ngneers-controls-calendar-time-C7UnIFzU.mjs.map +1 -0
- package/fesm2022/ngneers-controls-calendar.mjs +468 -0
- package/fesm2022/ngneers-controls-calendar.mjs.map +1 -0
- package/fesm2022/ngneers-controls-checkbox.mjs +58 -0
- package/fesm2022/ngneers-controls-checkbox.mjs.map +1 -0
- package/fesm2022/ngneers-controls-chip.mjs +52 -0
- package/fesm2022/ngneers-controls-chip.mjs.map +1 -0
- package/fesm2022/ngneers-controls-defer.mjs +43 -0
- package/fesm2022/ngneers-controls-defer.mjs.map +1 -0
- package/fesm2022/ngneers-controls-dialog.mjs +329 -33
- package/fesm2022/ngneers-controls-dialog.mjs.map +1 -1
- package/fesm2022/ngneers-controls-directives.mjs +443 -0
- package/fesm2022/ngneers-controls-directives.mjs.map +1 -0
- package/fesm2022/ngneers-controls-drawer.mjs +232 -0
- package/fesm2022/ngneers-controls-drawer.mjs.map +1 -0
- package/fesm2022/ngneers-controls-edit-inplace.mjs +120 -0
- package/fesm2022/ngneers-controls-edit-inplace.mjs.map +1 -0
- package/fesm2022/ngneers-controls-filter.mjs +516 -0
- package/fesm2022/ngneers-controls-filter.mjs.map +1 -0
- package/fesm2022/ngneers-controls-i18n-de-CdTPeBiR.mjs +87 -0
- package/fesm2022/ngneers-controls-i18n-de-CdTPeBiR.mjs.map +1 -0
- package/fesm2022/ngneers-controls-i18n-en-Cfp2pOLY.mjs +87 -0
- package/fesm2022/ngneers-controls-i18n-en-Cfp2pOLY.mjs.map +1 -0
- package/fesm2022/ngneers-controls-i18n.mjs +57 -0
- package/fesm2022/ngneers-controls-i18n.mjs.map +1 -0
- package/fesm2022/ngneers-controls-icon-calendar-z5xA9wTT.mjs +4 -0
- package/fesm2022/ngneers-controls-icon-calendar-z5xA9wTT.mjs.map +1 -0
- package/fesm2022/ngneers-controls-icon-check-DdAQ9k-T.mjs +4 -0
- package/fesm2022/ngneers-controls-icon-check-DdAQ9k-T.mjs.map +1 -0
- package/fesm2022/ngneers-controls-icon-chevron_down-HO-z-xOr.mjs +4 -0
- package/fesm2022/ngneers-controls-icon-chevron_down-HO-z-xOr.mjs.map +1 -0
- package/fesm2022/ngneers-controls-icon-chevron_left-CC5psi16.mjs +4 -0
- package/fesm2022/ngneers-controls-icon-chevron_left-CC5psi16.mjs.map +1 -0
- package/fesm2022/ngneers-controls-icon-chevron_right-BRxlzx4G.mjs +4 -0
- package/fesm2022/ngneers-controls-icon-chevron_right-BRxlzx4G.mjs.map +1 -0
- package/fesm2022/ngneers-controls-icon-chevron_up-cqhPO7g2.mjs +4 -0
- package/fesm2022/ngneers-controls-icon-chevron_up-cqhPO7g2.mjs.map +1 -0
- package/fesm2022/ngneers-controls-icon-ellipsis-DXIGA1sk.mjs +4 -0
- package/fesm2022/ngneers-controls-icon-ellipsis-DXIGA1sk.mjs.map +1 -0
- package/fesm2022/ngneers-controls-icon-filter-oU7E6Xgr.mjs +4 -0
- package/fesm2022/ngneers-controls-icon-filter-oU7E6Xgr.mjs.map +1 -0
- package/fesm2022/ngneers-controls-icon-filter_solid-CqIKuR4N.mjs +4 -0
- package/fesm2022/ngneers-controls-icon-filter_solid-CqIKuR4N.mjs.map +1 -0
- package/fesm2022/ngneers-controls-icon-magnifying_glass-T4Hzbkig.mjs +4 -0
- package/fesm2022/ngneers-controls-icon-magnifying_glass-T4Hzbkig.mjs.map +1 -0
- package/fesm2022/ngneers-controls-icon-minus-oGDEFO4E.mjs +4 -0
- package/fesm2022/ngneers-controls-icon-minus-oGDEFO4E.mjs.map +1 -0
- package/fesm2022/ngneers-controls-icon-sort-CRD4tafz.mjs +4 -0
- package/fesm2022/ngneers-controls-icon-sort-CRD4tafz.mjs.map +1 -0
- package/fesm2022/ngneers-controls-icon-sort_down-DiFB1P6R.mjs +4 -0
- package/fesm2022/ngneers-controls-icon-sort_down-DiFB1P6R.mjs.map +1 -0
- package/fesm2022/ngneers-controls-icon-sort_up-Bq_q3hIi.mjs +4 -0
- package/fesm2022/ngneers-controls-icon-sort_up-Bq_q3hIi.mjs.map +1 -0
- package/fesm2022/ngneers-controls-icon-xmark-BZKZORiu.mjs +4 -0
- package/fesm2022/ngneers-controls-icon-xmark-BZKZORiu.mjs.map +1 -0
- package/fesm2022/ngneers-controls-icon.mjs +60 -18
- package/fesm2022/ngneers-controls-icon.mjs.map +1 -1
- package/fesm2022/ngneers-controls-inplace.mjs +107 -0
- package/fesm2022/ngneers-controls-inplace.mjs.map +1 -0
- package/fesm2022/ngneers-controls-input-field.mjs +141 -0
- package/fesm2022/ngneers-controls-input-field.mjs.map +1 -0
- package/fesm2022/ngneers-controls-input-mask.mjs +282 -0
- package/fesm2022/ngneers-controls-input-mask.mjs.map +1 -0
- package/fesm2022/ngneers-controls-input.mjs +69 -0
- package/fesm2022/ngneers-controls-input.mjs.map +1 -0
- package/fesm2022/ngneers-controls-item-view.mjs +441 -0
- package/fesm2022/ngneers-controls-item-view.mjs.map +1 -0
- package/fesm2022/ngneers-controls-list-box.mjs +157 -53
- package/fesm2022/ngneers-controls-list-box.mjs.map +1 -1
- package/fesm2022/ngneers-controls-menu.mjs +332 -0
- package/fesm2022/ngneers-controls-menu.mjs.map +1 -0
- package/fesm2022/ngneers-controls-message.mjs +29 -0
- package/fesm2022/ngneers-controls-message.mjs.map +1 -0
- package/fesm2022/ngneers-controls-paginator.mjs +111 -0
- package/fesm2022/ngneers-controls-paginator.mjs.map +1 -0
- package/fesm2022/ngneers-controls-popover.mjs +129 -40
- package/fesm2022/ngneers-controls-popover.mjs.map +1 -1
- package/fesm2022/ngneers-controls-progress.mjs +82 -0
- package/fesm2022/ngneers-controls-progress.mjs.map +1 -0
- package/fesm2022/ngneers-controls-scroller.mjs +155 -78
- package/fesm2022/ngneers-controls-scroller.mjs.map +1 -1
- package/fesm2022/ngneers-controls-select-button.mjs +55 -0
- package/fesm2022/ngneers-controls-select-button.mjs.map +1 -0
- package/fesm2022/ngneers-controls-select.mjs +313 -103
- package/fesm2022/ngneers-controls-select.mjs.map +1 -1
- package/fesm2022/ngneers-controls-slider.mjs +155 -0
- package/fesm2022/ngneers-controls-slider.mjs.map +1 -0
- package/fesm2022/ngneers-controls-spinner.mjs +169 -0
- package/fesm2022/ngneers-controls-spinner.mjs.map +1 -0
- package/fesm2022/ngneers-controls-splitter.mjs +717 -0
- package/fesm2022/ngneers-controls-splitter.mjs.map +1 -0
- package/fesm2022/ngneers-controls-switch.mjs +39 -0
- package/fesm2022/ngneers-controls-switch.mjs.map +1 -0
- package/fesm2022/ngneers-controls-table.mjs +379 -0
- package/fesm2022/ngneers-controls-table.mjs.map +1 -0
- package/fesm2022/ngneers-controls-tabs.mjs +287 -0
- package/fesm2022/ngneers-controls-tabs.mjs.map +1 -0
- package/fesm2022/ngneers-controls-tag.mjs +29 -0
- package/fesm2022/ngneers-controls-tag.mjs.map +1 -0
- package/fesm2022/ngneers-controls-toast.mjs +184 -0
- package/fesm2022/ngneers-controls-toast.mjs.map +1 -0
- package/fesm2022/ngneers-controls-toggle-button.mjs +65 -0
- package/fesm2022/ngneers-controls-toggle-button.mjs.map +1 -0
- package/fesm2022/ngneers-controls-tooltip.mjs +454 -0
- package/fesm2022/ngneers-controls-tooltip.mjs.map +1 -0
- package/fesm2022/ngneers-controls-utils-ng.mjs +227 -0
- package/fesm2022/ngneers-controls-utils-ng.mjs.map +1 -0
- package/fesm2022/ngneers-controls-utils.mjs +217 -60
- package/fesm2022/ngneers-controls-utils.mjs.map +1 -1
- package/fesm2022/ngneers-controls.mjs.map +1 -1
- package/package.json +167 -32
- package/types/ngneers-controls-accordion.d.ts +114 -0
- package/types/ngneers-controls-api-ng.d.ts +291 -0
- package/types/ngneers-controls-api.d.ts +99 -0
- package/types/ngneers-controls-avatar.d.ts +50 -0
- package/types/ngneers-controls-base.d.ts +166 -0
- package/types/ngneers-controls-breadcrumb.d.ts +86 -0
- package/types/ngneers-controls-button-group.d.ts +30 -0
- package/types/ngneers-controls-button.d.ts +34 -0
- package/types/ngneers-controls-calendar.d.ts +275 -0
- package/types/ngneers-controls-checkbox.d.ts +38 -0
- package/types/ngneers-controls-chip.d.ts +37 -0
- package/types/ngneers-controls-defer.d.ts +22 -0
- package/types/ngneers-controls-dialog.d.ts +218 -0
- package/types/ngneers-controls-directives.d.ts +146 -0
- package/types/ngneers-controls-drawer.d.ts +220 -0
- package/types/ngneers-controls-edit-inplace.d.ts +182 -0
- package/types/ngneers-controls-filter.d.ts +304 -0
- package/types/ngneers-controls-i18n.d.ts +108 -0
- package/types/ngneers-controls-icon.d.ts +74 -0
- package/types/ngneers-controls-inplace.d.ts +95 -0
- package/types/ngneers-controls-input-field.d.ts +159 -0
- package/types/ngneers-controls-input-mask.d.ts +83 -0
- package/types/ngneers-controls-input.d.ts +27 -0
- package/types/ngneers-controls-item-view.d.ts +211 -0
- package/types/ngneers-controls-list-box.d.ts +216 -0
- package/types/ngneers-controls-menu.d.ts +178 -0
- package/types/ngneers-controls-message.d.ts +19 -0
- package/types/ngneers-controls-paginator.d.ts +162 -0
- package/types/ngneers-controls-popover.d.ts +101 -0
- package/types/ngneers-controls-progress.d.ts +44 -0
- package/types/ngneers-controls-scroller.d.ts +137 -0
- package/types/ngneers-controls-select-button.d.ts +37 -0
- package/types/ngneers-controls-select.d.ts +314 -0
- package/types/ngneers-controls-slider.d.ts +53 -0
- package/types/ngneers-controls-spinner.d.ts +105 -0
- package/types/ngneers-controls-splitter.d.ts +391 -0
- package/types/ngneers-controls-switch.d.ts +18 -0
- package/types/ngneers-controls-table.d.ts +157 -0
- package/types/ngneers-controls-tabs.d.ts +106 -0
- package/types/ngneers-controls-tag.d.ts +19 -0
- package/types/ngneers-controls-toast.d.ts +70 -0
- package/types/ngneers-controls-toggle-button.d.ts +46 -0
- package/types/ngneers-controls-tooltip.d.ts +188 -0
- package/types/ngneers-controls-utils-ng.d.ts +57 -0
- package/types/ngneers-controls-utils.d.ts +130 -0
- package/api/index.d.ts +0 -134
- package/custom-types/index.d.ts +0 -7
- package/dialog/index.d.ts +0 -43
- package/fesm2022/ngneers-controls-custom-types.mjs +0 -4
- package/fesm2022/ngneers-controls-custom-types.mjs.map +0 -1
- package/fesm2022/ngneers-controls-form-field.mjs +0 -33
- package/fesm2022/ngneers-controls-form-field.mjs.map +0 -1
- package/fesm2022/ngneers-controls-lazy-cacher.mjs +0 -30
- package/fesm2022/ngneers-controls-lazy-cacher.mjs.map +0 -1
- package/fesm2022/ngneers-controls-text-field.mjs +0 -23
- package/fesm2022/ngneers-controls-text-field.mjs.map +0 -1
- package/form-field/index.d.ts +0 -19
- package/icon/index.d.ts +0 -30
- package/lazy-cacher/index.d.ts +0 -14
- package/list-box/index.d.ts +0 -58
- package/popover/index.d.ts +0 -41
- package/scroller/index.d.ts +0 -95
- package/select/index.d.ts +0 -86
- package/text-field/index.d.ts +0 -10
- package/utils/index.d.ts +0 -36
- /package/{index.d.ts → types/ngneers-controls.d.ts} +0 -0
|
@@ -0,0 +1,516 @@
|
|
|
1
|
+
import { NgTemplateOutlet } from '@angular/common';
|
|
2
|
+
import * as i0 from '@angular/core';
|
|
3
|
+
import { inject, input, booleanAttribute, computed, output, viewChild, effect, ChangeDetectionStrategy, Component } from '@angular/core';
|
|
4
|
+
import { getActiveFilterConditions, executeFilter } from '@ngneers/controls/api';
|
|
5
|
+
import { ValueControlBase, NgnPt, provideSelf } from '@ngneers/controls/base';
|
|
6
|
+
import { NgnButton } from '@ngneers/controls/button';
|
|
7
|
+
import { I18n } from '@ngneers/controls/i18n';
|
|
8
|
+
import { NgnIcon } from '@ngneers/controls/icon';
|
|
9
|
+
import { NgnInput } from '@ngneers/controls/input';
|
|
10
|
+
import { NgnInputField } from '@ngneers/controls/input-field';
|
|
11
|
+
import { NgnPopover } from '@ngneers/controls/popover';
|
|
12
|
+
import { NgnSelect } from '@ngneers/controls/select';
|
|
13
|
+
import { deepMerge, NgnError } from '@ngneers/controls/utils';
|
|
14
|
+
import { filterControlTemplate } from '@ngneers/controls-themes/templates/filter';
|
|
15
|
+
|
|
16
|
+
function defaultOperatorsForType(dataType) {
|
|
17
|
+
switch (dataType) {
|
|
18
|
+
case 'string':
|
|
19
|
+
return [
|
|
20
|
+
{ id: 'isEqual', labelKey: 'filter_operators_isEqual', requiresValue: true },
|
|
21
|
+
{ id: 'isNotEqual', labelKey: 'filter_operators_isNotEqual', requiresValue: true },
|
|
22
|
+
{ id: 'contains', labelKey: 'filter_operators_contains', requiresValue: true },
|
|
23
|
+
{ id: 'startsWith', labelKey: 'filter_operators_startsWith', requiresValue: true },
|
|
24
|
+
{ id: 'endsWith', labelKey: 'filter_operators_endsWith', requiresValue: true },
|
|
25
|
+
{ id: 'isEmpty', labelKey: 'filter_operators_isEmpty', requiresValue: false },
|
|
26
|
+
{ id: 'isNotEmpty', labelKey: 'filter_operators_isNotEmpty', requiresValue: false },
|
|
27
|
+
];
|
|
28
|
+
case 'number':
|
|
29
|
+
return [
|
|
30
|
+
{ id: 'isEqual', labelKey: 'filter_operators_isEqual', requiresValue: true },
|
|
31
|
+
{ id: 'isNotEqual', labelKey: 'filter_operators_isNotEqual', requiresValue: true },
|
|
32
|
+
{ id: 'greaterThan', labelKey: 'filter_operators_greaterThan', requiresValue: true },
|
|
33
|
+
{
|
|
34
|
+
id: 'greaterThanOrEqual',
|
|
35
|
+
labelKey: 'filter_operators_greaterThanOrEqual',
|
|
36
|
+
requiresValue: true,
|
|
37
|
+
},
|
|
38
|
+
{ id: 'lessThan', labelKey: 'filter_operators_lessThan', requiresValue: true },
|
|
39
|
+
{
|
|
40
|
+
id: 'lessThanOrEqual',
|
|
41
|
+
labelKey: 'filter_operators_lessThanOrEqual',
|
|
42
|
+
requiresValue: true,
|
|
43
|
+
},
|
|
44
|
+
];
|
|
45
|
+
case 'date':
|
|
46
|
+
case 'dateTime':
|
|
47
|
+
return [
|
|
48
|
+
{ id: 'isEqual', labelKey: 'filter_operators_isEqual', requiresValue: true },
|
|
49
|
+
{ id: 'isNotEqual', labelKey: 'filter_operators_isNotEqual', requiresValue: true },
|
|
50
|
+
{ id: 'greaterThan', labelKey: 'filter_operators_after', requiresValue: true },
|
|
51
|
+
{ id: 'greaterThanOrEqual', labelKey: 'filter_operators_onOrAfter', requiresValue: true },
|
|
52
|
+
{ id: 'lessThan', labelKey: 'filter_operators_before', requiresValue: true },
|
|
53
|
+
{ id: 'lessThanOrEqual', labelKey: 'filter_operators_onOrBefore', requiresValue: true },
|
|
54
|
+
];
|
|
55
|
+
case 'boolean':
|
|
56
|
+
return [
|
|
57
|
+
{ id: 'isTrue', labelKey: 'filter_operators_isTrue', requiresValue: false },
|
|
58
|
+
{ id: 'isFalse', labelKey: 'filter_operators_isFalse', requiresValue: false },
|
|
59
|
+
];
|
|
60
|
+
case 'custom':
|
|
61
|
+
return [
|
|
62
|
+
{ id: 'custom', labelKey: 'filter_operators_custom', requiresValue: true },
|
|
63
|
+
];
|
|
64
|
+
case 'list':
|
|
65
|
+
return [
|
|
66
|
+
{ id: 'in', labelKey: 'filter_operators_in', requiresValue: true },
|
|
67
|
+
];
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
/**
|
|
71
|
+
* @category control
|
|
72
|
+
*/
|
|
73
|
+
class NgnFilter extends ValueControlBase {
|
|
74
|
+
theme = this.injectThemeTemplate(filterControlTemplate, 'root');
|
|
75
|
+
i18n = inject(I18n).translations;
|
|
76
|
+
unsafeI18n = inject(I18n).unsafe;
|
|
77
|
+
/** Data to filter. */
|
|
78
|
+
data = input([], ...(ngDevMode ? [{ debugName: "data" }] : []));
|
|
79
|
+
/** Datatype of the values in {@link data}. */
|
|
80
|
+
dataType = input('string', ...(ngDevMode ? [{ debugName: "dataType" }] : []));
|
|
81
|
+
/** Allows multiple conditions and a match mode (any/all). */
|
|
82
|
+
allowMultiple = input(false, { ...(ngDevMode ? { debugName: "allowMultiple" } : {}), transform: booleanAttribute });
|
|
83
|
+
/**
|
|
84
|
+
* Options for `dataType="list"`.
|
|
85
|
+
* When provided, they are used as-is. When `null` or `undefined`, options are derived from {@link data}.
|
|
86
|
+
*/
|
|
87
|
+
listOptions = input(...(ngDevMode ? [undefined, { debugName: "listOptions" }] : []));
|
|
88
|
+
/**
|
|
89
|
+
* Controls how the filter is rendered.
|
|
90
|
+
* - `inline`: renders the filter rows directly
|
|
91
|
+
* - `input`: renders an input-like trigger that opens a popover (default)
|
|
92
|
+
* - `headless`: renders only the popover and can be opened programmatically via {@link show}
|
|
93
|
+
*/
|
|
94
|
+
mode = input('input', ...(ngDevMode ? [{ debugName: "mode" }] : []));
|
|
95
|
+
/**
|
|
96
|
+
* Popover anchor used only in `headless` mode.
|
|
97
|
+
* In `input` mode the anchor is the internal input-field.
|
|
98
|
+
*/
|
|
99
|
+
anchor = input(null, ...(ngDevMode ? [{ debugName: "anchor" }] : []));
|
|
100
|
+
/**
|
|
101
|
+
* When true, the component will filter {@link data} locally and emit the filtered result.
|
|
102
|
+
* When false, only the filter configuration is emitted (useful for server-side filtering).
|
|
103
|
+
*/
|
|
104
|
+
filterLocally = input(true, { ...(ngDevMode ? { debugName: "filterLocally" } : {}), transform: booleanAttribute });
|
|
105
|
+
/** Options for the popover (when {@link mode} is not `inline`). */
|
|
106
|
+
popoverOptions = input({}, ...(ngDevMode ? [{ debugName: "popoverOptions" }] : []));
|
|
107
|
+
appliedPopoverOptions = computed(() => deepMerge({
|
|
108
|
+
sizeConstraints: {
|
|
109
|
+
width: '250px',
|
|
110
|
+
minHeight: '200px',
|
|
111
|
+
maxHeight: '500px',
|
|
112
|
+
},
|
|
113
|
+
placement: 'bottom-start',
|
|
114
|
+
}, this.popoverOptions()), ...(ngDevMode ? [{ debugName: "appliedPopoverOptions" }] : []));
|
|
115
|
+
/** Emits whenever the filter configuration changes. */
|
|
116
|
+
filterChange = output();
|
|
117
|
+
/** Emits the filtered data whenever local filtering is enabled. */
|
|
118
|
+
filterResultChange = output();
|
|
119
|
+
_popover = viewChild(NgnPopover, ...(ngDevMode ? [{ debugName: "_popover" }] : []));
|
|
120
|
+
// Note: `value()` is the single source of truth.
|
|
121
|
+
// It can be `null` (cleared). For rendering, use `templateConfig()` which falls back to defaults.
|
|
122
|
+
createCondition(operator) {
|
|
123
|
+
return { operator, rawValue: null };
|
|
124
|
+
}
|
|
125
|
+
defaultConfig() {
|
|
126
|
+
if (this.dataType() === 'list') {
|
|
127
|
+
return {
|
|
128
|
+
dataType: 'list',
|
|
129
|
+
matchMode: 'all',
|
|
130
|
+
conditions: [{ operator: 'in', rawValue: null }],
|
|
131
|
+
};
|
|
132
|
+
}
|
|
133
|
+
const firstOp = this.operatorDefs()[0]?.id ?? 'isEqual';
|
|
134
|
+
return {
|
|
135
|
+
dataType: this.dataType(),
|
|
136
|
+
matchMode: this.allowMultiple() ? 'all' : 'all',
|
|
137
|
+
conditions: [
|
|
138
|
+
{
|
|
139
|
+
operator: firstOp,
|
|
140
|
+
rawValue: null,
|
|
141
|
+
},
|
|
142
|
+
],
|
|
143
|
+
};
|
|
144
|
+
}
|
|
145
|
+
/**
|
|
146
|
+
* Config used for UI rendering.
|
|
147
|
+
* Falls back to a default config when the actual {@link value} is null.
|
|
148
|
+
*/
|
|
149
|
+
templateConfig = computed(() => (this.value() ?? this.defaultConfig()), ...(ngDevMode ? [{ debugName: "templateConfig" }] : []));
|
|
150
|
+
templateListSelection = computed(() => {
|
|
151
|
+
const cfg = this.templateConfig();
|
|
152
|
+
if (cfg.dataType !== 'list') {
|
|
153
|
+
return [];
|
|
154
|
+
}
|
|
155
|
+
const raw = cfg.conditions[0]?.rawValue;
|
|
156
|
+
if (!raw) {
|
|
157
|
+
return [];
|
|
158
|
+
}
|
|
159
|
+
try {
|
|
160
|
+
const parsed = JSON.parse(raw);
|
|
161
|
+
return Array.isArray(parsed) ? parsed.map(v => String(v)) : [];
|
|
162
|
+
}
|
|
163
|
+
catch {
|
|
164
|
+
return [];
|
|
165
|
+
}
|
|
166
|
+
}, ...(ngDevMode ? [{ debugName: "templateListSelection" }] : []));
|
|
167
|
+
operatorDefs = computed(() => {
|
|
168
|
+
const dt = this.dataType();
|
|
169
|
+
const defs = defaultOperatorsForType(dt);
|
|
170
|
+
if (dt === 'custom' && defs.length === 1 && defs[0]?.id === 'custom') {
|
|
171
|
+
return defs;
|
|
172
|
+
}
|
|
173
|
+
return defs;
|
|
174
|
+
}, ...(ngDevMode ? [{ debugName: "operatorDefs" }] : []));
|
|
175
|
+
operatorOptions = computed(() => {
|
|
176
|
+
const options = this.operatorDefs().map(op => ({
|
|
177
|
+
label: this.i18n[op.labelKey],
|
|
178
|
+
value: op.id,
|
|
179
|
+
testId: `filter-operator-${op.id}`,
|
|
180
|
+
}));
|
|
181
|
+
return options;
|
|
182
|
+
}, ...(ngDevMode ? [{ debugName: "operatorOptions" }] : []));
|
|
183
|
+
autoListOptions = computed(() => {
|
|
184
|
+
const seen = new Set();
|
|
185
|
+
const items = [];
|
|
186
|
+
for (const raw of this.data()) {
|
|
187
|
+
const s = String(raw);
|
|
188
|
+
if (seen.has(s)) {
|
|
189
|
+
continue;
|
|
190
|
+
}
|
|
191
|
+
seen.add(s);
|
|
192
|
+
items.push({ label: s, value: s, testId: `filter-list-${s}` });
|
|
193
|
+
}
|
|
194
|
+
return items.sort((a, b) => {
|
|
195
|
+
if (typeof a.label === 'string' && typeof b.label === 'string') {
|
|
196
|
+
return a.label.localeCompare(b.label);
|
|
197
|
+
}
|
|
198
|
+
if (typeof a.label === 'function' && typeof b.label === 'function') {
|
|
199
|
+
return a.label().localeCompare(b.label());
|
|
200
|
+
}
|
|
201
|
+
return 0;
|
|
202
|
+
});
|
|
203
|
+
}, ...(ngDevMode ? [{ debugName: "autoListOptions" }] : []));
|
|
204
|
+
resolvedListOptions = computed(() => {
|
|
205
|
+
const listOptions = this.listOptions();
|
|
206
|
+
return listOptions
|
|
207
|
+
? listOptions.map((opt) => ({
|
|
208
|
+
label: opt,
|
|
209
|
+
value: opt,
|
|
210
|
+
testId: `filter-list-${opt}`,
|
|
211
|
+
}))
|
|
212
|
+
: this.autoListOptions();
|
|
213
|
+
}, ...(ngDevMode ? [{ debugName: "resolvedListOptions" }] : []));
|
|
214
|
+
matchModeOptions = [
|
|
215
|
+
{ label: this.i18n['filter_match_all'], value: 'all', testId: 'filter-match-all' },
|
|
216
|
+
{ label: this.i18n['filter_match_any'], value: 'any', testId: 'filter-match-any' },
|
|
217
|
+
];
|
|
218
|
+
inputType = computed(() => {
|
|
219
|
+
switch (this.dataType()) {
|
|
220
|
+
case 'number':
|
|
221
|
+
return 'number';
|
|
222
|
+
case 'date':
|
|
223
|
+
return 'date';
|
|
224
|
+
case 'dateTime':
|
|
225
|
+
return 'datetime-local';
|
|
226
|
+
default:
|
|
227
|
+
return 'text';
|
|
228
|
+
}
|
|
229
|
+
}, ...(ngDevMode ? [{ debugName: "inputType" }] : []));
|
|
230
|
+
summaryText = computed(() => {
|
|
231
|
+
const currentValue = this.value();
|
|
232
|
+
if (!currentValue) {
|
|
233
|
+
return this.i18n['filter_noFilter']();
|
|
234
|
+
}
|
|
235
|
+
if (currentValue.dataType === 'list') {
|
|
236
|
+
const selected = this.templateListSelection();
|
|
237
|
+
if (selected.length === 0) {
|
|
238
|
+
return this.i18n['filter_noFilter']();
|
|
239
|
+
}
|
|
240
|
+
if (selected.length === 1) {
|
|
241
|
+
return selected[0] ?? this.i18n['filter_noFilter']();
|
|
242
|
+
}
|
|
243
|
+
return `${selected.length} ${this.i18n['filter_selected']()}`;
|
|
244
|
+
}
|
|
245
|
+
const active = this.activeConditionConfigs();
|
|
246
|
+
if (active.length === 0) {
|
|
247
|
+
return this.i18n['filter_noFilter']();
|
|
248
|
+
}
|
|
249
|
+
if (active.length === 1) {
|
|
250
|
+
const c = active[0];
|
|
251
|
+
const def = this.operatorDefs().find(d => d.id === c?.operator);
|
|
252
|
+
const operatorLabel = def ? this.i18n._unsafe[def.labelKey]?.() : c?.operator;
|
|
253
|
+
return c?.rawValue == null || c?.rawValue === ''
|
|
254
|
+
? operatorLabel
|
|
255
|
+
: `${operatorLabel} ${c.rawValue}`;
|
|
256
|
+
}
|
|
257
|
+
const matchLabel = currentValue.matchMode === 'all'
|
|
258
|
+
? this.i18n['filter_match_all']()
|
|
259
|
+
: this.i18n['filter_match_any']();
|
|
260
|
+
return `${active.length} ${this.i18n['filter_conditions']()} (${matchLabel})`;
|
|
261
|
+
}, ...(ngDevMode ? [{ debugName: "summaryText" }] : []));
|
|
262
|
+
activeConditionConfigs = computed(() => {
|
|
263
|
+
const cfg = this.value();
|
|
264
|
+
if (!cfg || cfg.dataType === 'list') {
|
|
265
|
+
return [];
|
|
266
|
+
}
|
|
267
|
+
const defs = this.operatorDefs();
|
|
268
|
+
const defById = new Map(defs.map(d => [d.id, d]));
|
|
269
|
+
return cfg.conditions.filter(c => {
|
|
270
|
+
const def = defById.get(c.operator);
|
|
271
|
+
const requiresValue = def?.requiresValue ?? true;
|
|
272
|
+
return !requiresValue || (c.rawValue != null && c.rawValue !== '');
|
|
273
|
+
});
|
|
274
|
+
}, ...(ngDevMode ? [{ debugName: "activeConditionConfigs" }] : []));
|
|
275
|
+
activeConditions = computed(() => {
|
|
276
|
+
const cfg = this.value();
|
|
277
|
+
return cfg ? getActiveFilterConditions(cfg) : [];
|
|
278
|
+
}, ...(ngDevMode ? [{ debugName: "activeConditions" }] : []));
|
|
279
|
+
filteredData = computed(() => {
|
|
280
|
+
if (!this.filterLocally()) {
|
|
281
|
+
return this.data();
|
|
282
|
+
}
|
|
283
|
+
const cfg = this.value();
|
|
284
|
+
if (!cfg) {
|
|
285
|
+
return this.data();
|
|
286
|
+
}
|
|
287
|
+
return executeFilter(this.data(), cfg);
|
|
288
|
+
}, ...(ngDevMode ? [{ debugName: "filteredData" }] : []));
|
|
289
|
+
constructor() {
|
|
290
|
+
super();
|
|
291
|
+
effect(() => {
|
|
292
|
+
this.filterChange.emit(this.value() ?? null);
|
|
293
|
+
});
|
|
294
|
+
effect(() => {
|
|
295
|
+
// When local filtering is disabled, do not emit or compute any result.
|
|
296
|
+
if (!this.filterLocally()) {
|
|
297
|
+
return;
|
|
298
|
+
}
|
|
299
|
+
this.filterResultChange.emit(this.filteredData());
|
|
300
|
+
});
|
|
301
|
+
effect(() => {
|
|
302
|
+
if (!this.allowMultiple()) {
|
|
303
|
+
const cfg = this.value();
|
|
304
|
+
if (!cfg || cfg.dataType === 'list') {
|
|
305
|
+
return;
|
|
306
|
+
}
|
|
307
|
+
if (cfg.conditions.length <= 1 && cfg.matchMode === 'all') {
|
|
308
|
+
return;
|
|
309
|
+
}
|
|
310
|
+
this.value.set({
|
|
311
|
+
...cfg,
|
|
312
|
+
matchMode: 'all',
|
|
313
|
+
conditions: cfg.conditions.slice(0, 1),
|
|
314
|
+
});
|
|
315
|
+
}
|
|
316
|
+
});
|
|
317
|
+
effect(() => {
|
|
318
|
+
const defs = this.operatorDefs();
|
|
319
|
+
const first = defs[0];
|
|
320
|
+
if (!first) {
|
|
321
|
+
throw new NgnError('filter', 'No operators available.');
|
|
322
|
+
}
|
|
323
|
+
// Ensure all conditions use a valid operator
|
|
324
|
+
const defIds = new Set(defs.map(d => d.id));
|
|
325
|
+
const normalizeConditions = (conditions) => {
|
|
326
|
+
let changed = false;
|
|
327
|
+
const next = conditions.map(c => {
|
|
328
|
+
if (defIds.has(c.operator)) {
|
|
329
|
+
return c;
|
|
330
|
+
}
|
|
331
|
+
changed = true;
|
|
332
|
+
return { ...c, operator: first.id, rawValue: null };
|
|
333
|
+
});
|
|
334
|
+
return changed ? next : conditions;
|
|
335
|
+
};
|
|
336
|
+
const cfg = this.value();
|
|
337
|
+
if (!cfg || cfg.dataType === 'list') {
|
|
338
|
+
return;
|
|
339
|
+
}
|
|
340
|
+
const current = cfg.conditions;
|
|
341
|
+
const next = normalizeConditions(current);
|
|
342
|
+
if (next !== current) {
|
|
343
|
+
this.value.set({ ...cfg, conditions: next });
|
|
344
|
+
}
|
|
345
|
+
});
|
|
346
|
+
}
|
|
347
|
+
setMatchMode(value) {
|
|
348
|
+
if (value === 'all' || value === 'any') {
|
|
349
|
+
const cfg = this.templateConfig();
|
|
350
|
+
if (cfg.dataType === 'list') {
|
|
351
|
+
return;
|
|
352
|
+
}
|
|
353
|
+
this.value.set({
|
|
354
|
+
...cfg,
|
|
355
|
+
matchMode: this.allowMultiple() ? value : 'all',
|
|
356
|
+
});
|
|
357
|
+
}
|
|
358
|
+
}
|
|
359
|
+
operatorRequiresValue(operator) {
|
|
360
|
+
const def = this.operatorDefs().find(d => d.id === operator);
|
|
361
|
+
return def?.requiresValue ?? true;
|
|
362
|
+
}
|
|
363
|
+
setOperator(index, operator) {
|
|
364
|
+
if (!operator) {
|
|
365
|
+
return;
|
|
366
|
+
}
|
|
367
|
+
const cfg = this.templateConfig();
|
|
368
|
+
if (cfg.dataType === 'list') {
|
|
369
|
+
return;
|
|
370
|
+
}
|
|
371
|
+
const next = cfg.conditions.slice();
|
|
372
|
+
const existing = next[index];
|
|
373
|
+
if (!existing) {
|
|
374
|
+
return;
|
|
375
|
+
}
|
|
376
|
+
next[index] = {
|
|
377
|
+
...existing,
|
|
378
|
+
operator,
|
|
379
|
+
rawValue: this.operatorRequiresValue(operator) ? existing.rawValue : null,
|
|
380
|
+
};
|
|
381
|
+
this.value.set({
|
|
382
|
+
...cfg,
|
|
383
|
+
matchMode: this.allowMultiple() ? cfg.matchMode : 'all',
|
|
384
|
+
conditions: next,
|
|
385
|
+
});
|
|
386
|
+
}
|
|
387
|
+
setRawValue(index, rawValue) {
|
|
388
|
+
const cfg = this.templateConfig();
|
|
389
|
+
if (cfg.dataType === 'list') {
|
|
390
|
+
return;
|
|
391
|
+
}
|
|
392
|
+
const next = cfg.conditions.slice();
|
|
393
|
+
const existing = next[index];
|
|
394
|
+
if (!existing) {
|
|
395
|
+
return;
|
|
396
|
+
}
|
|
397
|
+
next[index] = { ...existing, rawValue };
|
|
398
|
+
this.value.set({
|
|
399
|
+
...cfg,
|
|
400
|
+
matchMode: this.allowMultiple() ? cfg.matchMode : 'all',
|
|
401
|
+
conditions: next,
|
|
402
|
+
});
|
|
403
|
+
}
|
|
404
|
+
addCondition() {
|
|
405
|
+
if (!this.allowMultiple()) {
|
|
406
|
+
return;
|
|
407
|
+
}
|
|
408
|
+
const cfg = this.templateConfig();
|
|
409
|
+
if (cfg.dataType === 'list') {
|
|
410
|
+
return;
|
|
411
|
+
}
|
|
412
|
+
const firstOp = this.operatorDefs()[0]?.id ?? 'isEqual';
|
|
413
|
+
this.value.set({
|
|
414
|
+
...cfg,
|
|
415
|
+
matchMode: 'all',
|
|
416
|
+
conditions: [...cfg.conditions, this.createCondition(firstOp)],
|
|
417
|
+
});
|
|
418
|
+
}
|
|
419
|
+
removeCondition(index) {
|
|
420
|
+
if (!this.allowMultiple()) {
|
|
421
|
+
return;
|
|
422
|
+
}
|
|
423
|
+
const cfg = this.templateConfig();
|
|
424
|
+
if (cfg.dataType === 'list') {
|
|
425
|
+
return;
|
|
426
|
+
}
|
|
427
|
+
const current = cfg.conditions;
|
|
428
|
+
if (current.length <= 1) {
|
|
429
|
+
return;
|
|
430
|
+
}
|
|
431
|
+
const next = current.slice();
|
|
432
|
+
next.splice(index, 1);
|
|
433
|
+
this.value.set({
|
|
434
|
+
...cfg,
|
|
435
|
+
matchMode: cfg.matchMode,
|
|
436
|
+
conditions: next,
|
|
437
|
+
});
|
|
438
|
+
}
|
|
439
|
+
setListSelection(value) {
|
|
440
|
+
const arr = Array.isArray(value)
|
|
441
|
+
? value.map(v => String(v))
|
|
442
|
+
: value == null
|
|
443
|
+
? []
|
|
444
|
+
: [String(value)];
|
|
445
|
+
this.value.set({
|
|
446
|
+
dataType: 'list',
|
|
447
|
+
matchMode: 'all',
|
|
448
|
+
conditions: [
|
|
449
|
+
{
|
|
450
|
+
operator: 'in',
|
|
451
|
+
rawValue: arr.length > 0 ? JSON.stringify(arr) : null,
|
|
452
|
+
},
|
|
453
|
+
],
|
|
454
|
+
});
|
|
455
|
+
}
|
|
456
|
+
clear() {
|
|
457
|
+
this.value.set(null);
|
|
458
|
+
if (this.mode() !== 'inline') {
|
|
459
|
+
this.hide();
|
|
460
|
+
}
|
|
461
|
+
}
|
|
462
|
+
/** Shows the filter popup. Only works when {@link mode} is not `inline`. */
|
|
463
|
+
show() {
|
|
464
|
+
if (this.mode() === 'inline') {
|
|
465
|
+
throw new NgnError('filter', 'Cannot open an inline filter.');
|
|
466
|
+
}
|
|
467
|
+
if (this.mode() === 'headless' && !this.anchor()) {
|
|
468
|
+
throw new NgnError('filter', 'Headless mode requires an [anchor] input.');
|
|
469
|
+
}
|
|
470
|
+
const popover = this._popover();
|
|
471
|
+
if (!popover) {
|
|
472
|
+
throw new NgnError('filter', 'Popover is not available.');
|
|
473
|
+
}
|
|
474
|
+
popover.show();
|
|
475
|
+
}
|
|
476
|
+
/** Hides the filter popup. Only works when {@link mode} is not `inline`. */
|
|
477
|
+
hide() {
|
|
478
|
+
if (this.mode() === 'inline') {
|
|
479
|
+
throw new NgnError('filter', 'Cannot close an inline filter.');
|
|
480
|
+
}
|
|
481
|
+
this._popover()?.hide();
|
|
482
|
+
}
|
|
483
|
+
onKeyDown(event) {
|
|
484
|
+
if (event.key === 'Enter') {
|
|
485
|
+
if (this.mode() !== 'inline') {
|
|
486
|
+
this._popover()?.toggle();
|
|
487
|
+
event.stopPropagation();
|
|
488
|
+
event.preventDefault();
|
|
489
|
+
}
|
|
490
|
+
}
|
|
491
|
+
}
|
|
492
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.0", ngImport: i0, type: NgnFilter, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
493
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.1.0", type: NgnFilter, isStandalone: true, selector: "ngn-filter", inputs: { data: { classPropertyName: "data", publicName: "data", isSignal: true, isRequired: false, transformFunction: null }, dataType: { classPropertyName: "dataType", publicName: "dataType", isSignal: true, isRequired: false, transformFunction: null }, allowMultiple: { classPropertyName: "allowMultiple", publicName: "allowMultiple", isSignal: true, isRequired: false, transformFunction: null }, listOptions: { classPropertyName: "listOptions", publicName: "listOptions", isSignal: true, isRequired: false, transformFunction: null }, mode: { classPropertyName: "mode", publicName: "mode", isSignal: true, isRequired: false, transformFunction: null }, anchor: { classPropertyName: "anchor", publicName: "anchor", isSignal: true, isRequired: false, transformFunction: null }, filterLocally: { classPropertyName: "filterLocally", publicName: "filterLocally", isSignal: true, isRequired: false, transformFunction: null }, popoverOptions: { classPropertyName: "popoverOptions", publicName: "popoverOptions", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { filterChange: "filterChange", filterResultChange: "filterResultChange" }, host: { styleAttribute: "display: block;" }, providers: [provideSelf(NgnFilter)], viewQueries: [{ propertyName: "_popover", first: true, predicate: NgnPopover, descendants: true, isSignal: true }], usesInheritance: true, ngImport: i0, template: "<ng-template #rowsTemplate>\r\n <div [ptInt]=\"this\" [ptClass]=\"'rows'\">\r\n @if (dataType() === 'list') {\r\n <div [ptInt]=\"this\" [ptClass]=\"'row'\" data-testid=\"filter-row-list\">\r\n <ngn-select\r\n [ptInt]=\"this\"\r\n [ptClass]=\"'value'\"\r\n [multiple]=\"true\"\r\n [options]=\"resolvedListOptions()\"\r\n [value]=\"$any(templateListSelection())\"\r\n (valueChange)=\"setListSelection($event)\"\r\n />\r\n </div>\r\n } @else {\r\n @for (c of templateConfig().conditions; track $index; let i = $index) {\r\n <div [ptInt]=\"this\" [ptClass]=\"'row'\" [attr.data-testid]=\"'filter-row-' + i\">\r\n <ngn-select\r\n [ptInt]=\"this\"\r\n [ptClass]=\"'operator'\"\r\n [options]=\"operatorOptions()\"\r\n [value]=\"c.operator\"\r\n (valueChange)=\"setOperator(i, $event)\"\r\n />\r\n @if (operatorRequiresValue(c.operator)) {\r\n <ngn-input-field [ptInt]=\"this\" [ptClass]=\"'value'\">\r\n <input\r\n ngnInput\r\n [type]=\"inputType()\"\r\n [value]=\"c.rawValue || ''\"\r\n (valueChange)=\"setRawValue(i, $event)\"\r\n />\r\n </ngn-input-field>\r\n }\r\n\r\n @if (allowMultiple() && templateConfig().conditions.length > 1) {\r\n <div [ptInt]=\"this\" [ptClass]=\"'row-actions'\">\r\n <button\r\n type=\"button\"\r\n ngnButton\r\n [kind]=\"'text'\"\r\n [color]=\"'error'\"\r\n (click)=\"removeCondition(i)\"\r\n >\r\n {{ i18n['filter_removeCondition']() + ' ' + (i + 1) }}\r\n </button>\r\n </div>\r\n }\r\n </div>\r\n }\r\n }\r\n </div>\r\n</ng-template>\r\n\r\n<ng-template #matchModeTemplate>\r\n @if (dataType() !== 'list' && allowMultiple()) {\r\n <ngn-select\r\n [ptInt]=\"this\"\r\n [ptClass]=\"'match'\"\r\n [options]=\"matchModeOptions\"\r\n [value]=\"templateConfig().matchMode\"\r\n (valueChange)=\"setMatchMode($event)\"\r\n data-testid=\"filter-match-mode\"\r\n />\r\n }\r\n</ng-template>\r\n\r\n<ng-template #footerTemplate>\r\n <div [ptInt]=\"this\" [ptClass]=\"'footer'\">\r\n @if (dataType() !== 'list' && allowMultiple()) {\r\n <button\r\n type=\"button\"\r\n ngnButton\r\n kind=\"secondary\"\r\n (click)=\"addCondition()\"\r\n data-testid=\"filter-add-rule\"\r\n >\r\n <span aria-hidden=\"true\">+</span>\r\n {{ i18n['filter_addCondition']() }}\r\n </button>\r\n }\r\n <button type=\"button\" ngnButton kind=\"secondary\" (click)=\"clear()\" data-testid=\"filter-clear\">\r\n {{ i18n['filter_clear']() }}\r\n </button>\r\n </div>\r\n</ng-template>\r\n\r\n<ng-template #popoverTemplate let-anchor=\"anchor\">\r\n <ngn-popover\r\n #popover\r\n [options]=\"appliedPopoverOptions()\"\r\n [anchor]=\"anchor\"\r\n [hasShrinkableContent]=\"true\"\r\n (keydown)=\"onKeyDown($event)\"\r\n [id]=\"inputId() + '_popover'\"\r\n >\r\n <ng-template #lazy>\r\n <div [ptInt]=\"this\" [ptClass]=\"'popover-content'\">\r\n <ng-container [ngTemplateOutlet]=\"matchModeTemplate\" />\r\n <ng-container [ngTemplateOutlet]=\"rowsTemplate\" />\r\n <ng-container [ngTemplateOutlet]=\"footerTemplate\" />\r\n </div>\r\n </ng-template>\r\n </ngn-popover>\r\n</ng-template>\r\n\r\n@if (mode() === 'inline') {\r\n <div [ptInt]=\"this\" [ptClass]=\"'inline'\">\r\n <ng-container [ngTemplateOutlet]=\"matchModeTemplate\" />\r\n <ng-container [ngTemplateOutlet]=\"rowsTemplate\" />\r\n <ng-container [ngTemplateOutlet]=\"footerTemplate\" />\r\n </div>\r\n} @else if (mode() === 'input') {\r\n <ngn-input-field\r\n [ptInt]=\"this\"\r\n [ptClass]=\"'input-field'\"\r\n (click)=\"show()\"\r\n (keydown)=\"onKeyDown($event)\"\r\n #field\r\n [label]=\"label()\"\r\n [inputId]=\"inputId()\"\r\n [invalid]=\"invalid()\"\r\n >\r\n <div role=\"button\" [ptInt]=\"this\" [ptClass]=\"'summary'\">{{ summaryText() }}</div>\r\n <ngn-icon [ptInt]=\"this\" [ptClass]=\"'icon'\" defaultIcon=\"magnifying_glass\" />\r\n </ngn-input-field>\r\n\r\n <ng-container\r\n [ngTemplateOutlet]=\"popoverTemplate\"\r\n [ngTemplateOutletContext]=\"{ anchor: field.element.nativeElement }\"\r\n />\r\n} @else {\r\n @if (anchor()) {\r\n <ng-container\r\n [ngTemplateOutlet]=\"popoverTemplate\"\r\n [ngTemplateOutletContext]=\"{ anchor: anchor() }\"\r\n />\r\n }\r\n}\r\n", dependencies: [{ kind: "directive", type: NgnPt, selector: "[ptInt]", inputs: ["ptInt", "ptClass"] }, { kind: "directive", type: NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "component", type: NgnInputField, selector: "ngn-input-field", inputs: ["label", "labelledBy", "labelKind", "inputId", "showClearButton", "iconClearButton", "tabindex", "invalid", "readonly", "disabled"] }, { kind: "directive", type: NgnInput, selector: "input[ngnInput], textarea[ngnInput]", inputs: ["invalid", "value"], outputs: ["valueChange"] }, { kind: "component", type: NgnSelect, selector: "ngn-select", inputs: ["popoverOptions", "options", "filter", "filterText", "filterIcon", "dropdownIcon", "virtual", "itemHeight", "editable", "editableAutoFilter", "multiple", "scrollToSelectedItemOnOpen", "tabindex", "checkbox"] }, { kind: "component", type: NgnPopover, selector: "ngn-popover", inputs: ["open", "anchor", "options", "hasShrinkableContent", "closeBy"], outputs: ["closed", "closing", "openChange"] }, { kind: "component", type: NgnIcon, selector: "ngn-icon", inputs: ["defaultIcon", "icon"] }, { kind: "directive", type: NgnButton, selector: "button[ngnButton], a[ngnButton]", inputs: ["inline"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
494
|
+
}
|
|
495
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.0", ngImport: i0, type: NgnFilter, decorators: [{
|
|
496
|
+
type: Component,
|
|
497
|
+
args: [{ changeDetection: ChangeDetectionStrategy.OnPush, selector: 'ngn-filter', imports: [
|
|
498
|
+
NgnPt,
|
|
499
|
+
NgTemplateOutlet,
|
|
500
|
+
NgnInputField,
|
|
501
|
+
NgnInput,
|
|
502
|
+
NgnSelect,
|
|
503
|
+
NgnPopover,
|
|
504
|
+
NgnIcon,
|
|
505
|
+
NgnButton,
|
|
506
|
+
], providers: [provideSelf(NgnFilter)], host: {
|
|
507
|
+
style: 'display: block;',
|
|
508
|
+
}, template: "<ng-template #rowsTemplate>\r\n <div [ptInt]=\"this\" [ptClass]=\"'rows'\">\r\n @if (dataType() === 'list') {\r\n <div [ptInt]=\"this\" [ptClass]=\"'row'\" data-testid=\"filter-row-list\">\r\n <ngn-select\r\n [ptInt]=\"this\"\r\n [ptClass]=\"'value'\"\r\n [multiple]=\"true\"\r\n [options]=\"resolvedListOptions()\"\r\n [value]=\"$any(templateListSelection())\"\r\n (valueChange)=\"setListSelection($event)\"\r\n />\r\n </div>\r\n } @else {\r\n @for (c of templateConfig().conditions; track $index; let i = $index) {\r\n <div [ptInt]=\"this\" [ptClass]=\"'row'\" [attr.data-testid]=\"'filter-row-' + i\">\r\n <ngn-select\r\n [ptInt]=\"this\"\r\n [ptClass]=\"'operator'\"\r\n [options]=\"operatorOptions()\"\r\n [value]=\"c.operator\"\r\n (valueChange)=\"setOperator(i, $event)\"\r\n />\r\n @if (operatorRequiresValue(c.operator)) {\r\n <ngn-input-field [ptInt]=\"this\" [ptClass]=\"'value'\">\r\n <input\r\n ngnInput\r\n [type]=\"inputType()\"\r\n [value]=\"c.rawValue || ''\"\r\n (valueChange)=\"setRawValue(i, $event)\"\r\n />\r\n </ngn-input-field>\r\n }\r\n\r\n @if (allowMultiple() && templateConfig().conditions.length > 1) {\r\n <div [ptInt]=\"this\" [ptClass]=\"'row-actions'\">\r\n <button\r\n type=\"button\"\r\n ngnButton\r\n [kind]=\"'text'\"\r\n [color]=\"'error'\"\r\n (click)=\"removeCondition(i)\"\r\n >\r\n {{ i18n['filter_removeCondition']() + ' ' + (i + 1) }}\r\n </button>\r\n </div>\r\n }\r\n </div>\r\n }\r\n }\r\n </div>\r\n</ng-template>\r\n\r\n<ng-template #matchModeTemplate>\r\n @if (dataType() !== 'list' && allowMultiple()) {\r\n <ngn-select\r\n [ptInt]=\"this\"\r\n [ptClass]=\"'match'\"\r\n [options]=\"matchModeOptions\"\r\n [value]=\"templateConfig().matchMode\"\r\n (valueChange)=\"setMatchMode($event)\"\r\n data-testid=\"filter-match-mode\"\r\n />\r\n }\r\n</ng-template>\r\n\r\n<ng-template #footerTemplate>\r\n <div [ptInt]=\"this\" [ptClass]=\"'footer'\">\r\n @if (dataType() !== 'list' && allowMultiple()) {\r\n <button\r\n type=\"button\"\r\n ngnButton\r\n kind=\"secondary\"\r\n (click)=\"addCondition()\"\r\n data-testid=\"filter-add-rule\"\r\n >\r\n <span aria-hidden=\"true\">+</span>\r\n {{ i18n['filter_addCondition']() }}\r\n </button>\r\n }\r\n <button type=\"button\" ngnButton kind=\"secondary\" (click)=\"clear()\" data-testid=\"filter-clear\">\r\n {{ i18n['filter_clear']() }}\r\n </button>\r\n </div>\r\n</ng-template>\r\n\r\n<ng-template #popoverTemplate let-anchor=\"anchor\">\r\n <ngn-popover\r\n #popover\r\n [options]=\"appliedPopoverOptions()\"\r\n [anchor]=\"anchor\"\r\n [hasShrinkableContent]=\"true\"\r\n (keydown)=\"onKeyDown($event)\"\r\n [id]=\"inputId() + '_popover'\"\r\n >\r\n <ng-template #lazy>\r\n <div [ptInt]=\"this\" [ptClass]=\"'popover-content'\">\r\n <ng-container [ngTemplateOutlet]=\"matchModeTemplate\" />\r\n <ng-container [ngTemplateOutlet]=\"rowsTemplate\" />\r\n <ng-container [ngTemplateOutlet]=\"footerTemplate\" />\r\n </div>\r\n </ng-template>\r\n </ngn-popover>\r\n</ng-template>\r\n\r\n@if (mode() === 'inline') {\r\n <div [ptInt]=\"this\" [ptClass]=\"'inline'\">\r\n <ng-container [ngTemplateOutlet]=\"matchModeTemplate\" />\r\n <ng-container [ngTemplateOutlet]=\"rowsTemplate\" />\r\n <ng-container [ngTemplateOutlet]=\"footerTemplate\" />\r\n </div>\r\n} @else if (mode() === 'input') {\r\n <ngn-input-field\r\n [ptInt]=\"this\"\r\n [ptClass]=\"'input-field'\"\r\n (click)=\"show()\"\r\n (keydown)=\"onKeyDown($event)\"\r\n #field\r\n [label]=\"label()\"\r\n [inputId]=\"inputId()\"\r\n [invalid]=\"invalid()\"\r\n >\r\n <div role=\"button\" [ptInt]=\"this\" [ptClass]=\"'summary'\">{{ summaryText() }}</div>\r\n <ngn-icon [ptInt]=\"this\" [ptClass]=\"'icon'\" defaultIcon=\"magnifying_glass\" />\r\n </ngn-input-field>\r\n\r\n <ng-container\r\n [ngTemplateOutlet]=\"popoverTemplate\"\r\n [ngTemplateOutletContext]=\"{ anchor: field.element.nativeElement }\"\r\n />\r\n} @else {\r\n @if (anchor()) {\r\n <ng-container\r\n [ngTemplateOutlet]=\"popoverTemplate\"\r\n [ngTemplateOutletContext]=\"{ anchor: anchor() }\"\r\n />\r\n }\r\n}\r\n" }]
|
|
509
|
+
}], ctorParameters: () => [], propDecorators: { data: [{ type: i0.Input, args: [{ isSignal: true, alias: "data", required: false }] }], dataType: [{ type: i0.Input, args: [{ isSignal: true, alias: "dataType", required: false }] }], allowMultiple: [{ type: i0.Input, args: [{ isSignal: true, alias: "allowMultiple", required: false }] }], listOptions: [{ type: i0.Input, args: [{ isSignal: true, alias: "listOptions", required: false }] }], mode: [{ type: i0.Input, args: [{ isSignal: true, alias: "mode", required: false }] }], anchor: [{ type: i0.Input, args: [{ isSignal: true, alias: "anchor", required: false }] }], filterLocally: [{ type: i0.Input, args: [{ isSignal: true, alias: "filterLocally", required: false }] }], popoverOptions: [{ type: i0.Input, args: [{ isSignal: true, alias: "popoverOptions", required: false }] }], filterChange: [{ type: i0.Output, args: ["filterChange"] }], filterResultChange: [{ type: i0.Output, args: ["filterResultChange"] }], _popover: [{ type: i0.ViewChild, args: [i0.forwardRef(() => NgnPopover), { isSignal: true }] }] } });
|
|
510
|
+
|
|
511
|
+
/**
|
|
512
|
+
* Generated bundle index. Do not edit.
|
|
513
|
+
*/
|
|
514
|
+
|
|
515
|
+
export { NgnFilter };
|
|
516
|
+
//# sourceMappingURL=ngneers-controls-filter.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ngneers-controls-filter.mjs","sources":["../../src/filter/filter.ts","../../src/filter/filter.html","../../src/filter/ngneers-controls-filter.ts"],"sourcesContent":["import { NgTemplateOutlet } from '@angular/common';\r\nimport {\r\n booleanAttribute,\r\n ChangeDetectionStrategy,\r\n Component,\r\n computed,\r\n effect,\r\n inject,\r\n input,\r\n output,\r\n viewChild,\r\n} from '@angular/core';\r\nimport { executeFilter, getActiveFilterConditions, type NgnItem } from '@ngneers/controls/api';\r\nimport { NgnPt, provideSelf, ValueControlBase } from '@ngneers/controls/base';\r\nimport { NgnButton } from '@ngneers/controls/button';\r\nimport { I18n } from '@ngneers/controls/i18n';\r\nimport { NgnIcon } from '@ngneers/controls/icon';\r\nimport { NgnInput } from '@ngneers/controls/input';\r\nimport { NgnInputField } from '@ngneers/controls/input-field';\r\nimport { NgnPopover, type PopoverOptions } from '@ngneers/controls/popover';\r\nimport { NgnSelect } from '@ngneers/controls/select';\r\nimport { deepMerge, NgnError } from '@ngneers/controls/utils';\r\nimport { filterControlTemplate } from '@ngneers/controls-themes/templates/filter';\r\n\r\nimport type {\r\n NgnFilterCondition,\r\n NgnFilterConditionConfig,\r\n NgnFilterConfig,\r\n NgnFilterDataType,\r\n NgnFilterMode,\r\n NgnFilterOperatorId,\r\n} from './types';\r\nimport type { Anchor } from '@ngneers/controls/api/ng';\r\n\r\ntype ConditionInternal = {\r\n operator: NgnFilterOperatorId;\r\n rawValue: string | null;\r\n};\r\n\r\ntype OperatorDef = {\r\n id: NgnFilterOperatorId;\r\n labelKey: string;\r\n requiresValue: boolean;\r\n};\r\n\r\nfunction defaultOperatorsForType(dataType: NgnFilterDataType) {\r\n switch (dataType) {\r\n case 'string':\r\n return [\r\n { id: 'isEqual', labelKey: 'filter_operators_isEqual', requiresValue: true },\r\n { id: 'isNotEqual', labelKey: 'filter_operators_isNotEqual', requiresValue: true },\r\n { id: 'contains', labelKey: 'filter_operators_contains', requiresValue: true },\r\n { id: 'startsWith', labelKey: 'filter_operators_startsWith', requiresValue: true },\r\n { id: 'endsWith', labelKey: 'filter_operators_endsWith', requiresValue: true },\r\n { id: 'isEmpty', labelKey: 'filter_operators_isEmpty', requiresValue: false },\r\n { id: 'isNotEmpty', labelKey: 'filter_operators_isNotEmpty', requiresValue: false },\r\n ] as const satisfies OperatorDef[];\r\n case 'number':\r\n return [\r\n { id: 'isEqual', labelKey: 'filter_operators_isEqual', requiresValue: true },\r\n { id: 'isNotEqual', labelKey: 'filter_operators_isNotEqual', requiresValue: true },\r\n { id: 'greaterThan', labelKey: 'filter_operators_greaterThan', requiresValue: true },\r\n {\r\n id: 'greaterThanOrEqual',\r\n labelKey: 'filter_operators_greaterThanOrEqual',\r\n requiresValue: true,\r\n },\r\n { id: 'lessThan', labelKey: 'filter_operators_lessThan', requiresValue: true },\r\n {\r\n id: 'lessThanOrEqual',\r\n labelKey: 'filter_operators_lessThanOrEqual',\r\n requiresValue: true,\r\n },\r\n ] as const satisfies OperatorDef[];\r\n case 'date':\r\n case 'dateTime':\r\n return [\r\n { id: 'isEqual', labelKey: 'filter_operators_isEqual', requiresValue: true },\r\n { id: 'isNotEqual', labelKey: 'filter_operators_isNotEqual', requiresValue: true },\r\n { id: 'greaterThan', labelKey: 'filter_operators_after', requiresValue: true },\r\n { id: 'greaterThanOrEqual', labelKey: 'filter_operators_onOrAfter', requiresValue: true },\r\n { id: 'lessThan', labelKey: 'filter_operators_before', requiresValue: true },\r\n { id: 'lessThanOrEqual', labelKey: 'filter_operators_onOrBefore', requiresValue: true },\r\n ] as const satisfies OperatorDef[];\r\n case 'boolean':\r\n return [\r\n { id: 'isTrue', labelKey: 'filter_operators_isTrue', requiresValue: false },\r\n { id: 'isFalse', labelKey: 'filter_operators_isFalse', requiresValue: false },\r\n ] as const satisfies OperatorDef[];\r\n case 'custom':\r\n return [\r\n { id: 'custom', labelKey: 'filter_operators_custom', requiresValue: true },\r\n ] as const satisfies OperatorDef[];\r\n case 'list':\r\n return [\r\n { id: 'in', labelKey: 'filter_operators_in', requiresValue: true },\r\n ] as const satisfies OperatorDef[];\r\n }\r\n}\r\n\r\n/**\r\n * @category control\r\n */\r\n@Component({\r\n changeDetection: ChangeDetectionStrategy.OnPush,\r\n selector: 'ngn-filter',\r\n templateUrl: './filter.html',\r\n imports: [\r\n NgnPt,\r\n NgTemplateOutlet,\r\n NgnInputField,\r\n NgnInput,\r\n NgnSelect,\r\n NgnPopover,\r\n NgnIcon,\r\n NgnButton,\r\n ],\r\n providers: [provideSelf(NgnFilter)],\r\n host: {\r\n style: 'display: block;',\r\n },\r\n})\r\nexport class NgnFilter<T = unknown> extends ValueControlBase<'filter', NgnFilterConfig | null> {\r\n protected readonly theme = this.injectThemeTemplate(filterControlTemplate, 'root');\r\n protected readonly i18n = inject(I18n).translations;\r\n protected readonly unsafeI18n = inject(I18n).unsafe;\r\n\r\n /** Data to filter. */\r\n public readonly data = input<readonly T[]>([]);\r\n /** Datatype of the values in {@link data}. */\r\n public readonly dataType = input<NgnFilterDataType>('string');\r\n /** Allows multiple conditions and a match mode (any/all). */\r\n public readonly allowMultiple = input(false, { transform: booleanAttribute });\r\n\r\n /**\r\n * Options for `dataType=\"list\"`.\r\n * When provided, they are used as-is. When `null` or `undefined`, options are derived from {@link data}.\r\n */\r\n public readonly listOptions = input<readonly string[] | null | undefined>();\r\n\r\n /**\r\n * Controls how the filter is rendered.\r\n * - `inline`: renders the filter rows directly\r\n * - `input`: renders an input-like trigger that opens a popover (default)\r\n * - `headless`: renders only the popover and can be opened programmatically via {@link show}\r\n */\r\n public readonly mode = input<NgnFilterMode>('input');\r\n\r\n /**\r\n * Popover anchor used only in `headless` mode.\r\n * In `input` mode the anchor is the internal input-field.\r\n */\r\n public readonly anchor = input<Anchor | null>(null);\r\n\r\n /**\r\n * When true, the component will filter {@link data} locally and emit the filtered result.\r\n * When false, only the filter configuration is emitted (useful for server-side filtering).\r\n */\r\n public readonly filterLocally = input(true, { transform: booleanAttribute });\r\n\r\n /** Options for the popover (when {@link mode} is not `inline`). */\r\n public readonly popoverOptions = input<PopoverOptions>({});\r\n protected readonly appliedPopoverOptions = computed(() =>\r\n deepMerge(\r\n <PopoverOptions>{\r\n sizeConstraints: {\r\n width: '250px',\r\n minHeight: '200px',\r\n maxHeight: '500px',\r\n },\r\n placement: 'bottom-start',\r\n },\r\n this.popoverOptions()\r\n )\r\n );\r\n\r\n /** Emits whenever the filter configuration changes. */\r\n public readonly filterChange = output<NgnFilterConfig | null>();\r\n /** Emits the filtered data whenever local filtering is enabled. */\r\n public readonly filterResultChange = output<readonly T[]>();\r\n\r\n private readonly _popover = viewChild(NgnPopover);\r\n\r\n // Note: `value()` is the single source of truth.\r\n // It can be `null` (cleared). For rendering, use `templateConfig()` which falls back to defaults.\r\n\r\n private createCondition(operator: NgnFilterOperatorId): ConditionInternal {\r\n return { operator, rawValue: null };\r\n }\r\n\r\n private defaultConfig(): NgnFilterConfig {\r\n if (this.dataType() === 'list') {\r\n return {\r\n dataType: 'list',\r\n matchMode: 'all',\r\n conditions: <readonly NgnFilterConditionConfig[]>[{ operator: 'in', rawValue: null }],\r\n };\r\n }\r\n\r\n const firstOp = this.operatorDefs()[0]?.id ?? 'isEqual';\r\n return {\r\n dataType: this.dataType(),\r\n matchMode: this.allowMultiple() ? 'all' : 'all',\r\n conditions: <readonly NgnFilterConditionConfig[]>[\r\n {\r\n operator: firstOp,\r\n rawValue: null,\r\n },\r\n ],\r\n };\r\n }\r\n\r\n /**\r\n * Config used for UI rendering.\r\n * Falls back to a default config when the actual {@link value} is null.\r\n */\r\n protected readonly templateConfig = computed<NgnFilterConfig>(\r\n () => (this.value() ?? this.defaultConfig()) as NgnFilterConfig\r\n );\r\n\r\n protected readonly templateListSelection = computed<readonly string[]>(() => {\r\n const cfg = this.templateConfig();\r\n if (cfg.dataType !== 'list') {\r\n return [];\r\n }\r\n const raw = cfg.conditions[0]?.rawValue;\r\n if (!raw) {\r\n return [];\r\n }\r\n try {\r\n const parsed: unknown = JSON.parse(raw);\r\n return Array.isArray(parsed) ? parsed.map(v => String(v)) : [];\r\n } catch {\r\n return [];\r\n }\r\n });\r\n\r\n protected readonly operatorDefs = computed(() => {\r\n const dt = this.dataType();\r\n const defs = defaultOperatorsForType(dt);\r\n if (dt === 'custom' && defs.length === 1 && defs[0]?.id === 'custom') {\r\n return defs;\r\n }\r\n return defs;\r\n });\r\n\r\n protected readonly operatorOptions = computed(() => {\r\n const options = this.operatorDefs().map(\r\n op =>\r\n <NgnItem>{\r\n label: this.i18n[op.labelKey],\r\n value: op.id,\r\n testId: `filter-operator-${op.id}`,\r\n }\r\n );\r\n return options;\r\n });\r\n\r\n protected readonly autoListOptions = computed<readonly NgnItem[]>(() => {\r\n const seen = new Set<string>();\r\n const items: Array<NgnItem> = [];\r\n\r\n for (const raw of this.data()) {\r\n const s = String(raw);\r\n if (seen.has(s)) {\r\n continue;\r\n }\r\n seen.add(s);\r\n items.push({ label: s, value: s, testId: `filter-list-${s}` });\r\n }\r\n\r\n return items.sort((a, b) => {\r\n if (typeof a.label === 'string' && typeof b.label === 'string') {\r\n return a.label.localeCompare(b.label);\r\n }\r\n if (typeof a.label === 'function' && typeof b.label === 'function') {\r\n return a.label().localeCompare(b.label());\r\n }\r\n return 0;\r\n });\r\n });\r\n\r\n protected readonly resolvedListOptions = computed<readonly NgnItem[]>(() => {\r\n const listOptions = this.listOptions();\r\n return listOptions\r\n ? listOptions.map(\r\n (opt): NgnItem => ({\r\n label: opt,\r\n value: opt,\r\n testId: `filter-list-${opt}`,\r\n })\r\n )\r\n : this.autoListOptions();\r\n });\r\n\r\n protected readonly matchModeOptions: readonly NgnItem[] = [\r\n { label: this.i18n['filter_match_all'], value: 'all', testId: 'filter-match-all' },\r\n { label: this.i18n['filter_match_any'], value: 'any', testId: 'filter-match-any' },\r\n ];\r\n\r\n protected readonly inputType = computed(() => {\r\n switch (this.dataType()) {\r\n case 'number':\r\n return 'number';\r\n case 'date':\r\n return 'date';\r\n case 'dateTime':\r\n return 'datetime-local';\r\n default:\r\n return 'text';\r\n }\r\n });\r\n\r\n protected readonly summaryText = computed(() => {\r\n const currentValue = this.value();\r\n if (!currentValue) {\r\n return this.i18n['filter_noFilter']();\r\n }\r\n\r\n if (currentValue.dataType === 'list') {\r\n const selected = this.templateListSelection();\r\n if (selected.length === 0) {\r\n return this.i18n['filter_noFilter']();\r\n }\r\n if (selected.length === 1) {\r\n return selected[0] ?? this.i18n['filter_noFilter']();\r\n }\r\n return `${selected.length} ${this.i18n['filter_selected']()}`;\r\n }\r\n\r\n const active = this.activeConditionConfigs();\r\n if (active.length === 0) {\r\n return this.i18n['filter_noFilter']();\r\n }\r\n if (active.length === 1) {\r\n const c = active[0];\r\n\r\n const def = this.operatorDefs().find(d => d.id === c?.operator);\r\n const operatorLabel = def ? this.i18n._unsafe[def.labelKey]?.() : c?.operator;\r\n return c?.rawValue == null || c?.rawValue === ''\r\n ? operatorLabel\r\n : `${operatorLabel} ${c.rawValue}`;\r\n }\r\n\r\n const matchLabel =\r\n currentValue.matchMode === 'all'\r\n ? this.i18n['filter_match_all']()\r\n : this.i18n['filter_match_any']();\r\n return `${active.length} ${this.i18n['filter_conditions']()} (${matchLabel})`;\r\n });\r\n\r\n protected readonly activeConditionConfigs = computed<readonly NgnFilterConditionConfig[]>(() => {\r\n const cfg = this.value();\r\n if (!cfg || cfg.dataType === 'list') {\r\n return [];\r\n }\r\n const defs = this.operatorDefs();\r\n const defById = new Map(defs.map(d => [d.id, d] as const));\r\n\r\n return cfg.conditions.filter(c => {\r\n const def = defById.get(c.operator);\r\n const requiresValue = def?.requiresValue ?? true;\r\n return !requiresValue || (c.rawValue != null && c.rawValue !== '');\r\n });\r\n });\r\n\r\n protected readonly activeConditions = computed<readonly NgnFilterCondition[]>(() => {\r\n const cfg = this.value();\r\n return cfg ? getActiveFilterConditions(cfg) : [];\r\n });\r\n\r\n protected readonly filteredData = computed<readonly T[]>(() => {\r\n if (!this.filterLocally()) {\r\n return this.data();\r\n }\r\n const cfg = this.value();\r\n if (!cfg) {\r\n return this.data();\r\n }\r\n return executeFilter(this.data(), cfg);\r\n });\r\n\r\n constructor() {\r\n super();\r\n\r\n effect(() => {\r\n this.filterChange.emit(this.value() ?? null);\r\n });\r\n\r\n effect(() => {\r\n // When local filtering is disabled, do not emit or compute any result.\r\n if (!this.filterLocally()) {\r\n return;\r\n }\r\n this.filterResultChange.emit(this.filteredData());\r\n });\r\n\r\n effect(() => {\r\n if (!this.allowMultiple()) {\r\n const cfg = this.value();\r\n if (!cfg || cfg.dataType === 'list') {\r\n return;\r\n }\r\n if (cfg.conditions.length <= 1 && cfg.matchMode === 'all') {\r\n return;\r\n }\r\n this.value.set({\r\n ...cfg,\r\n matchMode: 'all',\r\n conditions: cfg.conditions.slice(0, 1),\r\n });\r\n }\r\n });\r\n\r\n effect(() => {\r\n const defs = this.operatorDefs();\r\n const first = defs[0];\r\n if (!first) {\r\n throw new NgnError('filter', 'No operators available.');\r\n }\r\n // Ensure all conditions use a valid operator\r\n const defIds = new Set(defs.map(d => d.id));\r\n\r\n const normalizeConditions = (\r\n conditions: readonly ConditionInternal[]\r\n ): readonly ConditionInternal[] => {\r\n let changed = false;\r\n const next = conditions.map(c => {\r\n if (defIds.has(c.operator)) {\r\n return c;\r\n }\r\n changed = true;\r\n return { ...c, operator: first.id, rawValue: null };\r\n });\r\n return changed ? next : conditions;\r\n };\r\n\r\n const cfg = this.value();\r\n if (!cfg || cfg.dataType === 'list') {\r\n return;\r\n }\r\n\r\n const current = cfg.conditions;\r\n const next = normalizeConditions(current);\r\n if (next !== current) {\r\n this.value.set({ ...cfg, conditions: next });\r\n }\r\n });\r\n }\r\n\r\n protected setMatchMode(value: unknown): void {\r\n if (value === 'all' || value === 'any') {\r\n const cfg = this.templateConfig();\r\n if (cfg.dataType === 'list') {\r\n return;\r\n }\r\n this.value.set({\r\n ...cfg,\r\n matchMode: this.allowMultiple() ? value : 'all',\r\n });\r\n }\r\n }\r\n\r\n protected operatorRequiresValue(operator: NgnFilterOperatorId): boolean {\r\n const def = this.operatorDefs().find(d => d.id === operator);\r\n return def?.requiresValue ?? true;\r\n }\r\n\r\n protected setOperator(index: number, operator: NgnFilterOperatorId | null): void {\r\n if (!operator) {\r\n return;\r\n }\r\n const cfg = this.templateConfig();\r\n if (cfg.dataType === 'list') {\r\n return;\r\n }\r\n const next = cfg.conditions.slice();\r\n const existing = next[index];\r\n if (!existing) {\r\n return;\r\n }\r\n next[index] = {\r\n ...existing,\r\n operator,\r\n rawValue: this.operatorRequiresValue(operator) ? existing.rawValue : null,\r\n };\r\n this.value.set({\r\n ...cfg,\r\n matchMode: this.allowMultiple() ? cfg.matchMode : 'all',\r\n conditions: next,\r\n });\r\n }\r\n\r\n protected setRawValue(index: number, rawValue: string | null): void {\r\n const cfg = this.templateConfig();\r\n if (cfg.dataType === 'list') {\r\n return;\r\n }\r\n const next = cfg.conditions.slice();\r\n const existing = next[index];\r\n if (!existing) {\r\n return;\r\n }\r\n next[index] = { ...existing, rawValue };\r\n this.value.set({\r\n ...cfg,\r\n matchMode: this.allowMultiple() ? cfg.matchMode : 'all',\r\n conditions: next,\r\n });\r\n }\r\n\r\n protected addCondition(): void {\r\n if (!this.allowMultiple()) {\r\n return;\r\n }\r\n const cfg = this.templateConfig();\r\n if (cfg.dataType === 'list') {\r\n return;\r\n }\r\n const firstOp = this.operatorDefs()[0]?.id ?? 'isEqual';\r\n this.value.set({\r\n ...cfg,\r\n matchMode: 'all',\r\n conditions: [...cfg.conditions, this.createCondition(firstOp)],\r\n });\r\n }\r\n\r\n protected removeCondition(index: number): void {\r\n if (!this.allowMultiple()) {\r\n return;\r\n }\r\n const cfg = this.templateConfig();\r\n if (cfg.dataType === 'list') {\r\n return;\r\n }\r\n const current = cfg.conditions;\r\n if (current.length <= 1) {\r\n return;\r\n }\r\n const next = current.slice();\r\n next.splice(index, 1);\r\n this.value.set({\r\n ...cfg,\r\n matchMode: cfg.matchMode,\r\n conditions: next,\r\n });\r\n }\r\n\r\n protected setListSelection(value: unknown): void {\r\n const arr = Array.isArray(value)\r\n ? value.map(v => String(v))\r\n : value == null\r\n ? []\r\n : [String(value)];\r\n\r\n this.value.set({\r\n dataType: 'list',\r\n matchMode: 'all',\r\n conditions: <readonly NgnFilterConditionConfig[]>[\r\n {\r\n operator: 'in',\r\n rawValue: arr.length > 0 ? JSON.stringify(arr) : null,\r\n },\r\n ],\r\n });\r\n }\r\n\r\n protected clear(): void {\r\n this.value.set(null);\r\n if (this.mode() !== 'inline') {\r\n this.hide();\r\n }\r\n }\r\n\r\n /** Shows the filter popup. Only works when {@link mode} is not `inline`. */\r\n public show(): void {\r\n if (this.mode() === 'inline') {\r\n throw new NgnError('filter', 'Cannot open an inline filter.');\r\n }\r\n if (this.mode() === 'headless' && !this.anchor()) {\r\n throw new NgnError('filter', 'Headless mode requires an [anchor] input.');\r\n }\r\n const popover = this._popover();\r\n if (!popover) {\r\n throw new NgnError('filter', 'Popover is not available.');\r\n }\r\n popover.show();\r\n }\r\n\r\n /** Hides the filter popup. Only works when {@link mode} is not `inline`. */\r\n public hide(): void {\r\n if (this.mode() === 'inline') {\r\n throw new NgnError('filter', 'Cannot close an inline filter.');\r\n }\r\n this._popover()?.hide();\r\n }\r\n\r\n protected onKeyDown(event: KeyboardEvent): void {\r\n if (event.key === 'Enter') {\r\n if (this.mode() !== 'inline') {\r\n this._popover()?.toggle();\r\n event.stopPropagation();\r\n event.preventDefault();\r\n }\r\n }\r\n }\r\n}\r\n","<ng-template #rowsTemplate>\r\n <div [ptInt]=\"this\" [ptClass]=\"'rows'\">\r\n @if (dataType() === 'list') {\r\n <div [ptInt]=\"this\" [ptClass]=\"'row'\" data-testid=\"filter-row-list\">\r\n <ngn-select\r\n [ptInt]=\"this\"\r\n [ptClass]=\"'value'\"\r\n [multiple]=\"true\"\r\n [options]=\"resolvedListOptions()\"\r\n [value]=\"$any(templateListSelection())\"\r\n (valueChange)=\"setListSelection($event)\"\r\n />\r\n </div>\r\n } @else {\r\n @for (c of templateConfig().conditions; track $index; let i = $index) {\r\n <div [ptInt]=\"this\" [ptClass]=\"'row'\" [attr.data-testid]=\"'filter-row-' + i\">\r\n <ngn-select\r\n [ptInt]=\"this\"\r\n [ptClass]=\"'operator'\"\r\n [options]=\"operatorOptions()\"\r\n [value]=\"c.operator\"\r\n (valueChange)=\"setOperator(i, $event)\"\r\n />\r\n @if (operatorRequiresValue(c.operator)) {\r\n <ngn-input-field [ptInt]=\"this\" [ptClass]=\"'value'\">\r\n <input\r\n ngnInput\r\n [type]=\"inputType()\"\r\n [value]=\"c.rawValue || ''\"\r\n (valueChange)=\"setRawValue(i, $event)\"\r\n />\r\n </ngn-input-field>\r\n }\r\n\r\n @if (allowMultiple() && templateConfig().conditions.length > 1) {\r\n <div [ptInt]=\"this\" [ptClass]=\"'row-actions'\">\r\n <button\r\n type=\"button\"\r\n ngnButton\r\n [kind]=\"'text'\"\r\n [color]=\"'error'\"\r\n (click)=\"removeCondition(i)\"\r\n >\r\n {{ i18n['filter_removeCondition']() + ' ' + (i + 1) }}\r\n </button>\r\n </div>\r\n }\r\n </div>\r\n }\r\n }\r\n </div>\r\n</ng-template>\r\n\r\n<ng-template #matchModeTemplate>\r\n @if (dataType() !== 'list' && allowMultiple()) {\r\n <ngn-select\r\n [ptInt]=\"this\"\r\n [ptClass]=\"'match'\"\r\n [options]=\"matchModeOptions\"\r\n [value]=\"templateConfig().matchMode\"\r\n (valueChange)=\"setMatchMode($event)\"\r\n data-testid=\"filter-match-mode\"\r\n />\r\n }\r\n</ng-template>\r\n\r\n<ng-template #footerTemplate>\r\n <div [ptInt]=\"this\" [ptClass]=\"'footer'\">\r\n @if (dataType() !== 'list' && allowMultiple()) {\r\n <button\r\n type=\"button\"\r\n ngnButton\r\n kind=\"secondary\"\r\n (click)=\"addCondition()\"\r\n data-testid=\"filter-add-rule\"\r\n >\r\n <span aria-hidden=\"true\">+</span>\r\n {{ i18n['filter_addCondition']() }}\r\n </button>\r\n }\r\n <button type=\"button\" ngnButton kind=\"secondary\" (click)=\"clear()\" data-testid=\"filter-clear\">\r\n {{ i18n['filter_clear']() }}\r\n </button>\r\n </div>\r\n</ng-template>\r\n\r\n<ng-template #popoverTemplate let-anchor=\"anchor\">\r\n <ngn-popover\r\n #popover\r\n [options]=\"appliedPopoverOptions()\"\r\n [anchor]=\"anchor\"\r\n [hasShrinkableContent]=\"true\"\r\n (keydown)=\"onKeyDown($event)\"\r\n [id]=\"inputId() + '_popover'\"\r\n >\r\n <ng-template #lazy>\r\n <div [ptInt]=\"this\" [ptClass]=\"'popover-content'\">\r\n <ng-container [ngTemplateOutlet]=\"matchModeTemplate\" />\r\n <ng-container [ngTemplateOutlet]=\"rowsTemplate\" />\r\n <ng-container [ngTemplateOutlet]=\"footerTemplate\" />\r\n </div>\r\n </ng-template>\r\n </ngn-popover>\r\n</ng-template>\r\n\r\n@if (mode() === 'inline') {\r\n <div [ptInt]=\"this\" [ptClass]=\"'inline'\">\r\n <ng-container [ngTemplateOutlet]=\"matchModeTemplate\" />\r\n <ng-container [ngTemplateOutlet]=\"rowsTemplate\" />\r\n <ng-container [ngTemplateOutlet]=\"footerTemplate\" />\r\n </div>\r\n} @else if (mode() === 'input') {\r\n <ngn-input-field\r\n [ptInt]=\"this\"\r\n [ptClass]=\"'input-field'\"\r\n (click)=\"show()\"\r\n (keydown)=\"onKeyDown($event)\"\r\n #field\r\n [label]=\"label()\"\r\n [inputId]=\"inputId()\"\r\n [invalid]=\"invalid()\"\r\n >\r\n <div role=\"button\" [ptInt]=\"this\" [ptClass]=\"'summary'\">{{ summaryText() }}</div>\r\n <ngn-icon [ptInt]=\"this\" [ptClass]=\"'icon'\" defaultIcon=\"magnifying_glass\" />\r\n </ngn-input-field>\r\n\r\n <ng-container\r\n [ngTemplateOutlet]=\"popoverTemplate\"\r\n [ngTemplateOutletContext]=\"{ anchor: field.element.nativeElement }\"\r\n />\r\n} @else {\r\n @if (anchor()) {\r\n <ng-container\r\n [ngTemplateOutlet]=\"popoverTemplate\"\r\n [ngTemplateOutletContext]=\"{ anchor: anchor() }\"\r\n />\r\n }\r\n}\r\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './index';\n"],"names":[],"mappings":"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"}
|