@ngneers/controls 0.0.1-next.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.
- package/fesm2022/ngneers-controls-accordion.mjs +234 -0
- package/fesm2022/ngneers-controls-accordion.mjs.map +1 -0
- package/fesm2022/ngneers-controls-api-ng.mjs +959 -0
- package/fesm2022/ngneers-controls-api-ng.mjs.map +1 -0
- package/fesm2022/ngneers-controls-api-resize.mjs +712 -0
- package/fesm2022/ngneers-controls-api-resize.mjs.map +1 -0
- package/fesm2022/ngneers-controls-api.mjs +347 -0
- package/fesm2022/ngneers-controls-api.mjs.map +1 -0
- package/fesm2022/ngneers-controls-avatar.mjs +77 -0
- package/fesm2022/ngneers-controls-avatar.mjs.map +1 -0
- package/fesm2022/ngneers-controls-base.mjs +620 -0
- package/fesm2022/ngneers-controls-base.mjs.map +1 -0
- package/fesm2022/ngneers-controls-breadcrumb.mjs +100 -0
- package/fesm2022/ngneers-controls-breadcrumb.mjs.map +1 -0
- package/fesm2022/ngneers-controls-button-group.mjs +110 -0
- package/fesm2022/ngneers-controls-button-group.mjs.map +1 -0
- package/fesm2022/ngneers-controls-button.mjs +83 -0
- package/fesm2022/ngneers-controls-button.mjs.map +1 -0
- package/fesm2022/ngneers-controls-calendar-time-CJT5AFlA.mjs +74 -0
- package/fesm2022/ngneers-controls-calendar-time-CJT5AFlA.mjs.map +1 -0
- package/fesm2022/ngneers-controls-calendar.mjs +801 -0
- package/fesm2022/ngneers-controls-calendar.mjs.map +1 -0
- package/fesm2022/ngneers-controls-checkbox.mjs +63 -0
- package/fesm2022/ngneers-controls-checkbox.mjs.map +1 -0
- package/fesm2022/ngneers-controls-chip.mjs +55 -0
- package/fesm2022/ngneers-controls-chip.mjs.map +1 -0
- package/fesm2022/ngneers-controls-default-icons.mjs +82 -0
- package/fesm2022/ngneers-controls-default-icons.mjs.map +1 -0
- package/fesm2022/ngneers-controls-defer.mjs +72 -0
- package/fesm2022/ngneers-controls-defer.mjs.map +1 -0
- package/fesm2022/ngneers-controls-dialog.mjs +407 -0
- package/fesm2022/ngneers-controls-dialog.mjs.map +1 -0
- package/fesm2022/ngneers-controls-directives.mjs +498 -0
- package/fesm2022/ngneers-controls-directives.mjs.map +1 -0
- package/fesm2022/ngneers-controls-drawer.mjs +271 -0
- package/fesm2022/ngneers-controls-drawer.mjs.map +1 -0
- package/fesm2022/ngneers-controls-edit-inplace.mjs +127 -0
- package/fesm2022/ngneers-controls-edit-inplace.mjs.map +1 -0
- package/fesm2022/ngneers-controls-errors.mjs +329 -0
- package/fesm2022/ngneers-controls-errors.mjs.map +1 -0
- package/fesm2022/ngneers-controls-filter.mjs +708 -0
- package/fesm2022/ngneers-controls-filter.mjs.map +1 -0
- package/fesm2022/ngneers-controls-hint.mjs +153 -0
- package/fesm2022/ngneers-controls-hint.mjs.map +1 -0
- package/fesm2022/ngneers-controls-i18n-translations-de.mjs +170 -0
- package/fesm2022/ngneers-controls-i18n-translations-de.mjs.map +1 -0
- package/fesm2022/ngneers-controls-i18n-translations-en.mjs +170 -0
- package/fesm2022/ngneers-controls-i18n-translations-en.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.mjs +195 -0
- package/fesm2022/ngneers-controls-icon.mjs.map +1 -0
- package/fesm2022/ngneers-controls-inplace.mjs +150 -0
- package/fesm2022/ngneers-controls-inplace.mjs.map +1 -0
- package/fesm2022/ngneers-controls-input-field.mjs +165 -0
- package/fesm2022/ngneers-controls-input-field.mjs.map +1 -0
- package/fesm2022/ngneers-controls-input.mjs +72 -0
- package/fesm2022/ngneers-controls-input.mjs.map +1 -0
- package/fesm2022/ngneers-controls-item-view.mjs +473 -0
- package/fesm2022/ngneers-controls-item-view.mjs.map +1 -0
- package/fesm2022/ngneers-controls-list-box.mjs +281 -0
- package/fesm2022/ngneers-controls-list-box.mjs.map +1 -0
- package/fesm2022/ngneers-controls-mask-input.mjs +888 -0
- package/fesm2022/ngneers-controls-mask-input.mjs.map +1 -0
- package/fesm2022/ngneers-controls-menu.mjs +371 -0
- package/fesm2022/ngneers-controls-menu.mjs.map +1 -0
- package/fesm2022/ngneers-controls-message.mjs +30 -0
- package/fesm2022/ngneers-controls-message.mjs.map +1 -0
- package/fesm2022/ngneers-controls-number-input.mjs +366 -0
- package/fesm2022/ngneers-controls-number-input.mjs.map +1 -0
- package/fesm2022/ngneers-controls-paginator.mjs +129 -0
- package/fesm2022/ngneers-controls-paginator.mjs.map +1 -0
- package/fesm2022/ngneers-controls-popover.mjs +215 -0
- package/fesm2022/ngneers-controls-popover.mjs.map +1 -0
- package/fesm2022/ngneers-controls-progress.mjs +98 -0
- package/fesm2022/ngneers-controls-progress.mjs.map +1 -0
- package/fesm2022/ngneers-controls-radio.mjs +152 -0
- package/fesm2022/ngneers-controls-radio.mjs.map +1 -0
- package/fesm2022/ngneers-controls-roving-focus.mjs +323 -0
- package/fesm2022/ngneers-controls-roving-focus.mjs.map +1 -0
- package/fesm2022/ngneers-controls-scroll-shadow.mjs +65 -0
- package/fesm2022/ngneers-controls-scroll-shadow.mjs.map +1 -0
- package/fesm2022/ngneers-controls-scroller.mjs +308 -0
- package/fesm2022/ngneers-controls-scroller.mjs.map +1 -0
- package/fesm2022/ngneers-controls-select-button.mjs +58 -0
- package/fesm2022/ngneers-controls-select-button.mjs.map +1 -0
- package/fesm2022/ngneers-controls-select.mjs +417 -0
- package/fesm2022/ngneers-controls-select.mjs.map +1 -0
- package/fesm2022/ngneers-controls-slider.mjs +167 -0
- package/fesm2022/ngneers-controls-slider.mjs.map +1 -0
- package/fesm2022/ngneers-controls-snackbar.mjs +414 -0
- package/fesm2022/ngneers-controls-snackbar.mjs.map +1 -0
- package/fesm2022/ngneers-controls-spin-buttons.mjs +126 -0
- package/fesm2022/ngneers-controls-spin-buttons.mjs.map +1 -0
- package/fesm2022/ngneers-controls-spinner.mjs +184 -0
- package/fesm2022/ngneers-controls-spinner.mjs.map +1 -0
- package/fesm2022/ngneers-controls-splitter.mjs +604 -0
- package/fesm2022/ngneers-controls-splitter.mjs.map +1 -0
- package/fesm2022/ngneers-controls-state.mjs +185 -0
- package/fesm2022/ngneers-controls-state.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 +2634 -0
- package/fesm2022/ngneers-controls-table.mjs.map +1 -0
- package/fesm2022/ngneers-controls-tabs.mjs +336 -0
- package/fesm2022/ngneers-controls-tabs.mjs.map +1 -0
- package/fesm2022/ngneers-controls-tag.mjs +30 -0
- package/fesm2022/ngneers-controls-tag.mjs.map +1 -0
- package/fesm2022/ngneers-controls-toast.mjs +350 -0
- package/fesm2022/ngneers-controls-toast.mjs.map +1 -0
- package/fesm2022/ngneers-controls-toggle-button.mjs +70 -0
- package/fesm2022/ngneers-controls-toggle-button.mjs.map +1 -0
- package/fesm2022/ngneers-controls-tooltip.mjs +506 -0
- package/fesm2022/ngneers-controls-tooltip.mjs.map +1 -0
- package/fesm2022/ngneers-controls-tree.mjs +599 -0
- package/fesm2022/ngneers-controls-tree.mjs.map +1 -0
- package/fesm2022/ngneers-controls-upload.mjs +377 -0
- package/fesm2022/ngneers-controls-upload.mjs.map +1 -0
- package/fesm2022/ngneers-controls-utils-ng.mjs +411 -0
- package/fesm2022/ngneers-controls-utils-ng.mjs.map +1 -0
- package/fesm2022/ngneers-controls-utils.mjs +261 -0
- package/fesm2022/ngneers-controls-utils.mjs.map +1 -0
- package/fesm2022/ngneers-controls.mjs +6 -0
- package/fesm2022/ngneers-controls.mjs.map +1 -0
- package/package.json +302 -0
- package/types/ngneers-controls-accordion.d.ts +139 -0
- package/types/ngneers-controls-api-ng.d.ts +364 -0
- package/types/ngneers-controls-api-resize.d.ts +318 -0
- package/types/ngneers-controls-api.d.ts +145 -0
- package/types/ngneers-controls-avatar.d.ts +54 -0
- package/types/ngneers-controls-base.d.ts +277 -0
- package/types/ngneers-controls-breadcrumb.d.ts +272 -0
- package/types/ngneers-controls-button-group.d.ts +46 -0
- package/types/ngneers-controls-button.d.ts +48 -0
- package/types/ngneers-controls-calendar.d.ts +466 -0
- package/types/ngneers-controls-checkbox.d.ts +40 -0
- package/types/ngneers-controls-chip.d.ts +202 -0
- package/types/ngneers-controls-default-icons.d.ts +5 -0
- package/types/ngneers-controls-defer.d.ts +48 -0
- package/types/ngneers-controls-dialog.d.ts +399 -0
- package/types/ngneers-controls-directives.d.ts +171 -0
- package/types/ngneers-controls-drawer.d.ts +308 -0
- package/types/ngneers-controls-edit-inplace.d.ts +263 -0
- package/types/ngneers-controls-errors.d.ts +155 -0
- package/types/ngneers-controls-filter.d.ts +609 -0
- package/types/ngneers-controls-hint.d.ts +88 -0
- package/types/ngneers-controls-i18n-translations-de.d.ts +164 -0
- package/types/ngneers-controls-i18n-translations-en.d.ts +164 -0
- package/types/ngneers-controls-i18n.d.ts +186 -0
- package/types/ngneers-controls-icon.d.ts +68 -0
- package/types/ngneers-controls-inplace.d.ts +98 -0
- package/types/ngneers-controls-input-field.d.ts +248 -0
- package/types/ngneers-controls-input.d.ts +30 -0
- package/types/ngneers-controls-item-view.d.ts +215 -0
- package/types/ngneers-controls-list-box.d.ts +334 -0
- package/types/ngneers-controls-mask-input.d.ts +434 -0
- package/types/ngneers-controls-menu.d.ts +192 -0
- package/types/ngneers-controls-message.d.ts +21 -0
- package/types/ngneers-controls-number-input.d.ts +146 -0
- package/types/ngneers-controls-paginator.d.ts +255 -0
- package/types/ngneers-controls-popover.d.ts +116 -0
- package/types/ngneers-controls-progress.d.ts +49 -0
- package/types/ngneers-controls-radio.d.ts +91 -0
- package/types/ngneers-controls-roving-focus.d.ts +107 -0
- package/types/ngneers-controls-scroll-shadow.d.ts +25 -0
- package/types/ngneers-controls-scroller.d.ts +151 -0
- package/types/ngneers-controls-select-button.d.ts +51 -0
- package/types/ngneers-controls-select.d.ts +409 -0
- package/types/ngneers-controls-slider.d.ts +57 -0
- package/types/ngneers-controls-snackbar.d.ts +330 -0
- package/types/ngneers-controls-spin-buttons.d.ts +69 -0
- package/types/ngneers-controls-spinner.d.ts +117 -0
- package/types/ngneers-controls-splitter.d.ts +465 -0
- package/types/ngneers-controls-state.d.ts +102 -0
- package/types/ngneers-controls-switch.d.ts +18 -0
- package/types/ngneers-controls-table.d.ts +3127 -0
- package/types/ngneers-controls-tabs.d.ts +118 -0
- package/types/ngneers-controls-tag.d.ts +21 -0
- package/types/ngneers-controls-toast.d.ts +298 -0
- package/types/ngneers-controls-toggle-button.d.ts +48 -0
- package/types/ngneers-controls-tooltip.d.ts +189 -0
- package/types/ngneers-controls-tree.d.ts +409 -0
- package/types/ngneers-controls-upload.d.ts +347 -0
- package/types/ngneers-controls-utils-ng.d.ts +129 -0
- package/types/ngneers-controls-utils.d.ts +130 -0
- package/types/ngneers-controls.d.ts +2 -0
|
@@ -0,0 +1,708 @@
|
|
|
1
|
+
import { NgTemplateOutlet } from '@angular/common';
|
|
2
|
+
import * as i0 from '@angular/core';
|
|
3
|
+
import { inject, DestroyRef, input, booleanAttribute, numberAttribute, computed, output, viewChild, signal, effect, 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 { NgnCalendar } from '@ngneers/controls/calendar';
|
|
8
|
+
import { I18n } from '@ngneers/controls/i18n';
|
|
9
|
+
import { NgnIcon } from '@ngneers/controls/icon';
|
|
10
|
+
import { NgnInput } from '@ngneers/controls/input';
|
|
11
|
+
import { NgnInputField } from '@ngneers/controls/input-field';
|
|
12
|
+
import { NgnPopover } from '@ngneers/controls/popover';
|
|
13
|
+
import { NgnSelect } from '@ngneers/controls/select';
|
|
14
|
+
import { deepMerge, NgnError } from '@ngneers/controls/utils';
|
|
15
|
+
import { filterControlTemplate } from '@ngneers/controls-themes/templates/filter';
|
|
16
|
+
|
|
17
|
+
function defaultOperatorsForType(dataType) {
|
|
18
|
+
switch (dataType) {
|
|
19
|
+
case 'string':
|
|
20
|
+
return [
|
|
21
|
+
{ id: 'isEqual', labelKey: 'filter_operators_isEqual', requiresValue: true },
|
|
22
|
+
{ id: 'isNotEqual', labelKey: 'filter_operators_isNotEqual', requiresValue: true },
|
|
23
|
+
{ id: 'contains', labelKey: 'filter_operators_contains', requiresValue: true },
|
|
24
|
+
{ id: 'startsWith', labelKey: 'filter_operators_startsWith', requiresValue: true },
|
|
25
|
+
{ id: 'endsWith', labelKey: 'filter_operators_endsWith', requiresValue: true },
|
|
26
|
+
{ id: 'isEmpty', labelKey: 'filter_operators_isEmpty', requiresValue: false },
|
|
27
|
+
{ id: 'isNotEmpty', labelKey: 'filter_operators_isNotEmpty', requiresValue: false },
|
|
28
|
+
];
|
|
29
|
+
case 'number':
|
|
30
|
+
return [
|
|
31
|
+
{ id: 'isEqual', labelKey: 'filter_operators_isEqual', requiresValue: true },
|
|
32
|
+
{ id: 'isNotEqual', labelKey: 'filter_operators_isNotEqual', requiresValue: true },
|
|
33
|
+
{ id: 'greaterThan', labelKey: 'filter_operators_greaterThan', requiresValue: true },
|
|
34
|
+
{
|
|
35
|
+
id: 'greaterThanOrEqual',
|
|
36
|
+
labelKey: 'filter_operators_greaterThanOrEqual',
|
|
37
|
+
requiresValue: true,
|
|
38
|
+
},
|
|
39
|
+
{ id: 'lessThan', labelKey: 'filter_operators_lessThan', requiresValue: true },
|
|
40
|
+
{
|
|
41
|
+
id: 'lessThanOrEqual',
|
|
42
|
+
labelKey: 'filter_operators_lessThanOrEqual',
|
|
43
|
+
requiresValue: true,
|
|
44
|
+
},
|
|
45
|
+
];
|
|
46
|
+
case 'date':
|
|
47
|
+
case 'dateTime':
|
|
48
|
+
return [
|
|
49
|
+
{ id: 'isEqual', labelKey: 'filter_operators_isEqual', requiresValue: true },
|
|
50
|
+
{ id: 'isNotEqual', labelKey: 'filter_operators_isNotEqual', requiresValue: true },
|
|
51
|
+
{ id: 'greaterThan', labelKey: 'filter_operators_after', requiresValue: true },
|
|
52
|
+
{ id: 'greaterThanOrEqual', labelKey: 'filter_operators_onOrAfter', requiresValue: true },
|
|
53
|
+
{ id: 'lessThan', labelKey: 'filter_operators_before', requiresValue: true },
|
|
54
|
+
{ id: 'lessThanOrEqual', labelKey: 'filter_operators_onOrBefore', requiresValue: true },
|
|
55
|
+
];
|
|
56
|
+
case 'boolean':
|
|
57
|
+
return [
|
|
58
|
+
{ id: 'isTrue', labelKey: 'filter_operators_isTrue', requiresValue: false },
|
|
59
|
+
{ id: 'isFalse', labelKey: 'filter_operators_isFalse', requiresValue: false },
|
|
60
|
+
];
|
|
61
|
+
case 'custom':
|
|
62
|
+
return [
|
|
63
|
+
{ id: 'custom', labelKey: 'filter_operators_custom', requiresValue: true },
|
|
64
|
+
];
|
|
65
|
+
case 'list':
|
|
66
|
+
return [
|
|
67
|
+
{ id: 'in', labelKey: 'filter_operators_in', requiresValue: true },
|
|
68
|
+
];
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
/**
|
|
72
|
+
* @category control
|
|
73
|
+
*/
|
|
74
|
+
class NgnFilter extends ValueControlBase {
|
|
75
|
+
theme = this.injectThemeTemplate(filterControlTemplate, 'root');
|
|
76
|
+
_i18n = inject(I18n);
|
|
77
|
+
i18n = this._i18n.translations;
|
|
78
|
+
unsafeI18n = this._i18n.unsafe.bind(this._i18n);
|
|
79
|
+
_destroyRef = inject(DestroyRef);
|
|
80
|
+
/**
|
|
81
|
+
* Data to filter.
|
|
82
|
+
* @default []
|
|
83
|
+
*/
|
|
84
|
+
data = input([], /* @ts-ignore */
|
|
85
|
+
...(ngDevMode ? [{ debugName: "data" }] : /* istanbul ignore next */ []));
|
|
86
|
+
/**
|
|
87
|
+
* Datatype of the values in {@link data}. Determines the available operators and editor UI.
|
|
88
|
+
* @default 'string'
|
|
89
|
+
*/
|
|
90
|
+
dataType = input('string', /* @ts-ignore */
|
|
91
|
+
...(ngDevMode ? [{ debugName: "dataType" }] : /* istanbul ignore next */ []));
|
|
92
|
+
/**
|
|
93
|
+
* Allows multiple conditions and a match mode (any/all).
|
|
94
|
+
* @default false
|
|
95
|
+
*/
|
|
96
|
+
allowMultiple = input(false, { ...(ngDevMode ? { debugName: "allowMultiple" } : /* istanbul ignore next */ {}), transform: booleanAttribute });
|
|
97
|
+
/**
|
|
98
|
+
* Options for `dataType="list"`.
|
|
99
|
+
* When provided, they are used as-is. When `null` or `undefined`, options are derived from {@link data}.
|
|
100
|
+
* @default undefined
|
|
101
|
+
*/
|
|
102
|
+
listOptions = input(/* @ts-ignore */
|
|
103
|
+
...(ngDevMode ? [undefined, { debugName: "listOptions" }] : /* istanbul ignore next */ []));
|
|
104
|
+
/**
|
|
105
|
+
* Controls how the filter is rendered.
|
|
106
|
+
* - `inline`: renders the filter rows directly
|
|
107
|
+
* - `input`: renders an input-like trigger that opens a popover (default)
|
|
108
|
+
* - `headless`: renders only the popover and can be opened programmatically via {@link show}
|
|
109
|
+
* @default 'input'
|
|
110
|
+
*/
|
|
111
|
+
mode = input('input', /* @ts-ignore */
|
|
112
|
+
...(ngDevMode ? [{ debugName: "mode" }] : /* istanbul ignore next */ []));
|
|
113
|
+
/**
|
|
114
|
+
* Popover anchor used only in `headless` mode.
|
|
115
|
+
* In `input` mode the anchor is the internal input-field.
|
|
116
|
+
* @default null
|
|
117
|
+
*/
|
|
118
|
+
anchor = input(null, /* @ts-ignore */
|
|
119
|
+
...(ngDevMode ? [{ debugName: "anchor" }] : /* istanbul ignore next */ []));
|
|
120
|
+
/**
|
|
121
|
+
* When true, the component will filter {@link data} locally and emit the filtered result
|
|
122
|
+
* via {@link filterResultChange}. When false, only the filter configuration is emitted
|
|
123
|
+
* (useful for server-side filtering).
|
|
124
|
+
* @default true
|
|
125
|
+
*/
|
|
126
|
+
filterLocally = input(true, { ...(ngDevMode ? { debugName: "filterLocally" } : /* istanbul ignore next */ {}), transform: booleanAttribute });
|
|
127
|
+
/**
|
|
128
|
+
* When true, filters apply automatically as the user types/selects.
|
|
129
|
+
* When false, the user must click "Apply" to commit the filter.
|
|
130
|
+
* @default true
|
|
131
|
+
*/
|
|
132
|
+
autoApply = input(true, { ...(ngDevMode ? { debugName: "autoApply" } : /* istanbul ignore next */ {}), transform: booleanAttribute });
|
|
133
|
+
/**
|
|
134
|
+
* Debounce time in milliseconds for auto-apply mode.
|
|
135
|
+
* Only relevant when {@link autoApply} is `true`.
|
|
136
|
+
* @default 300
|
|
137
|
+
*/
|
|
138
|
+
autoApplyDebounce = input(300, { ...(ngDevMode ? { debugName: "autoApplyDebounce" } : /* istanbul ignore next */ {}), transform: numberAttribute });
|
|
139
|
+
/**
|
|
140
|
+
* Options for the popover (when {@link mode} is not `inline`).
|
|
141
|
+
* @default {}
|
|
142
|
+
*/
|
|
143
|
+
popoverOptions = input({}, /* @ts-ignore */
|
|
144
|
+
...(ngDevMode ? [{ debugName: "popoverOptions" }] : /* istanbul ignore next */ []));
|
|
145
|
+
appliedPopoverOptions = computed(() => deepMerge({
|
|
146
|
+
sizeConstraints: {
|
|
147
|
+
width: '360px',
|
|
148
|
+
minHeight: '120px',
|
|
149
|
+
maxHeight: '500px',
|
|
150
|
+
},
|
|
151
|
+
placement: 'bottom-start',
|
|
152
|
+
}, this.popoverOptions()), /* @ts-ignore */
|
|
153
|
+
...(ngDevMode ? [{ debugName: "appliedPopoverOptions" }] : /* istanbul ignore next */ []));
|
|
154
|
+
/** Emits whenever the filter configuration changes. */
|
|
155
|
+
filterChange = output();
|
|
156
|
+
/** Emits the filtered data whenever local filtering is enabled. */
|
|
157
|
+
filterResultChange = output();
|
|
158
|
+
_popover = viewChild(NgnPopover, /* @ts-ignore */
|
|
159
|
+
...(ngDevMode ? [{ debugName: "_popover" }] : /* istanbul ignore next */ []));
|
|
160
|
+
/**
|
|
161
|
+
* Internal working config that the template binds to.
|
|
162
|
+
* In auto-apply mode, this syncs to value() via debounce.
|
|
163
|
+
* In manual mode, only apply() commits this to value().
|
|
164
|
+
*/
|
|
165
|
+
workingConfig = signal(null, /* @ts-ignore */
|
|
166
|
+
...(ngDevMode ? [{ debugName: "workingConfig" }] : /* istanbul ignore next */ []));
|
|
167
|
+
/** Snapshot of value() taken when popover opens in manual mode, for cancel to restore. */
|
|
168
|
+
_snapshotConfig = null;
|
|
169
|
+
/** Debounce timer handle for auto-apply. */
|
|
170
|
+
_debounceTimer = null;
|
|
171
|
+
/** Whether there is an active filter applied. */
|
|
172
|
+
hasActiveFilter = computed(() => {
|
|
173
|
+
const cfg = this.value();
|
|
174
|
+
if (!cfg)
|
|
175
|
+
return false;
|
|
176
|
+
if (cfg.dataType === 'list') {
|
|
177
|
+
const raw = cfg.conditions[0]?.rawValue;
|
|
178
|
+
if (!raw)
|
|
179
|
+
return false;
|
|
180
|
+
try {
|
|
181
|
+
const parsed = JSON.parse(raw);
|
|
182
|
+
return Array.isArray(parsed) && parsed.length > 0;
|
|
183
|
+
}
|
|
184
|
+
catch {
|
|
185
|
+
return false;
|
|
186
|
+
}
|
|
187
|
+
}
|
|
188
|
+
return this.activeConditionConfigs().length > 0;
|
|
189
|
+
}, /* @ts-ignore */
|
|
190
|
+
...(ngDevMode ? [{ debugName: "hasActiveFilter" }] : /* istanbul ignore next */ []));
|
|
191
|
+
createCondition(operator) {
|
|
192
|
+
return { operator, rawValue: null };
|
|
193
|
+
}
|
|
194
|
+
defaultConfig() {
|
|
195
|
+
if (this.dataType() === 'list') {
|
|
196
|
+
return {
|
|
197
|
+
dataType: 'list',
|
|
198
|
+
matchMode: 'all',
|
|
199
|
+
conditions: [{ operator: 'in', rawValue: null }],
|
|
200
|
+
};
|
|
201
|
+
}
|
|
202
|
+
const firstOp = this.operatorDefs()[0]?.id ?? 'isEqual';
|
|
203
|
+
return {
|
|
204
|
+
dataType: this.dataType(),
|
|
205
|
+
matchMode: 'all',
|
|
206
|
+
conditions: [
|
|
207
|
+
{
|
|
208
|
+
operator: firstOp,
|
|
209
|
+
rawValue: null,
|
|
210
|
+
},
|
|
211
|
+
],
|
|
212
|
+
};
|
|
213
|
+
}
|
|
214
|
+
/**
|
|
215
|
+
* Config used for UI rendering.
|
|
216
|
+
* Always reads from workingConfig (the live editing state).
|
|
217
|
+
* Falls back to a default config when null.
|
|
218
|
+
*/
|
|
219
|
+
templateConfig = computed(() => (this.workingConfig() ?? this.defaultConfig()), /* @ts-ignore */
|
|
220
|
+
...(ngDevMode ? [{ debugName: "templateConfig" }] : /* istanbul ignore next */ []));
|
|
221
|
+
templateListSelection = computed(() => {
|
|
222
|
+
const cfg = this.templateConfig();
|
|
223
|
+
if (cfg.dataType !== 'list') {
|
|
224
|
+
return [];
|
|
225
|
+
}
|
|
226
|
+
const raw = cfg.conditions[0]?.rawValue;
|
|
227
|
+
if (!raw) {
|
|
228
|
+
return [];
|
|
229
|
+
}
|
|
230
|
+
try {
|
|
231
|
+
const parsed = JSON.parse(raw);
|
|
232
|
+
return Array.isArray(parsed) ? parsed.map(v => String(v)) : [];
|
|
233
|
+
}
|
|
234
|
+
catch {
|
|
235
|
+
return [];
|
|
236
|
+
}
|
|
237
|
+
}, /* @ts-ignore */
|
|
238
|
+
...(ngDevMode ? [{ debugName: "templateListSelection" }] : /* istanbul ignore next */ []));
|
|
239
|
+
operatorDefs = computed(() => {
|
|
240
|
+
const dt = this.dataType();
|
|
241
|
+
const defs = defaultOperatorsForType(dt);
|
|
242
|
+
if (dt === 'custom' && defs.length === 1 && defs[0]?.id === 'custom') {
|
|
243
|
+
return defs;
|
|
244
|
+
}
|
|
245
|
+
return defs;
|
|
246
|
+
}, /* @ts-ignore */
|
|
247
|
+
...(ngDevMode ? [{ debugName: "operatorDefs" }] : /* istanbul ignore next */ []));
|
|
248
|
+
operatorOptions = computed(() => {
|
|
249
|
+
const options = this.operatorDefs().map(op => ({
|
|
250
|
+
label: this.i18n[op.labelKey],
|
|
251
|
+
value: op.id,
|
|
252
|
+
testId: `filter-operator-${op.id}`,
|
|
253
|
+
}));
|
|
254
|
+
return options;
|
|
255
|
+
}, /* @ts-ignore */
|
|
256
|
+
...(ngDevMode ? [{ debugName: "operatorOptions" }] : /* istanbul ignore next */ []));
|
|
257
|
+
autoListOptions = computed(() => {
|
|
258
|
+
const seen = new Set();
|
|
259
|
+
const items = [];
|
|
260
|
+
for (const raw of this.data()) {
|
|
261
|
+
const s = String(raw);
|
|
262
|
+
if (seen.has(s)) {
|
|
263
|
+
continue;
|
|
264
|
+
}
|
|
265
|
+
seen.add(s);
|
|
266
|
+
items.push({ label: s, value: s, testId: `filter-list-${s}` });
|
|
267
|
+
}
|
|
268
|
+
return items.sort((a, b) => {
|
|
269
|
+
if (typeof a.label === 'string' && typeof b.label === 'string') {
|
|
270
|
+
return a.label.localeCompare(b.label);
|
|
271
|
+
}
|
|
272
|
+
if (typeof a.label === 'function' && typeof b.label === 'function') {
|
|
273
|
+
return a.label().localeCompare(b.label());
|
|
274
|
+
}
|
|
275
|
+
return 0;
|
|
276
|
+
});
|
|
277
|
+
}, /* @ts-ignore */
|
|
278
|
+
...(ngDevMode ? [{ debugName: "autoListOptions" }] : /* istanbul ignore next */ []));
|
|
279
|
+
resolvedListOptions = computed(() => {
|
|
280
|
+
const listOptions = this.listOptions();
|
|
281
|
+
return listOptions
|
|
282
|
+
? listOptions.map((opt) => ({
|
|
283
|
+
label: opt,
|
|
284
|
+
value: opt,
|
|
285
|
+
testId: `filter-list-${opt}`,
|
|
286
|
+
}))
|
|
287
|
+
: this.autoListOptions();
|
|
288
|
+
}, /* @ts-ignore */
|
|
289
|
+
...(ngDevMode ? [{ debugName: "resolvedListOptions" }] : /* istanbul ignore next */ []));
|
|
290
|
+
matchModeOptions = [
|
|
291
|
+
{ label: this.i18n['filter_match_all'], value: 'all', testId: 'filter-match-all' },
|
|
292
|
+
{ label: this.i18n['filter_match_any'], value: 'any', testId: 'filter-match-any' },
|
|
293
|
+
];
|
|
294
|
+
inputType = computed(() => {
|
|
295
|
+
switch (this.dataType()) {
|
|
296
|
+
case 'number':
|
|
297
|
+
return 'number';
|
|
298
|
+
case 'date':
|
|
299
|
+
return 'date';
|
|
300
|
+
case 'dateTime':
|
|
301
|
+
return 'datetime-local';
|
|
302
|
+
default:
|
|
303
|
+
return 'text';
|
|
304
|
+
}
|
|
305
|
+
}, /* @ts-ignore */
|
|
306
|
+
...(ngDevMode ? [{ debugName: "inputType" }] : /* istanbul ignore next */ []));
|
|
307
|
+
isDateType = computed(() => this.dataType() === 'date' || this.dataType() === 'dateTime', /* @ts-ignore */
|
|
308
|
+
...(ngDevMode ? [{ debugName: "isDateType" }] : /* istanbul ignore next */ []));
|
|
309
|
+
isShowTime = computed(() => this.dataType() === 'dateTime', /* @ts-ignore */
|
|
310
|
+
...(ngDevMode ? [{ debugName: "isShowTime" }] : /* istanbul ignore next */ []));
|
|
311
|
+
/** Parse a rawValue string to a Date for the calendar component. */
|
|
312
|
+
parseRawDate(rawValue) {
|
|
313
|
+
if (!rawValue)
|
|
314
|
+
return null;
|
|
315
|
+
const d = new Date(rawValue);
|
|
316
|
+
return Number.isNaN(d.getTime()) ? null : d;
|
|
317
|
+
}
|
|
318
|
+
/** Convert a Date from the calendar to a rawValue string. */
|
|
319
|
+
dateToRaw(date) {
|
|
320
|
+
if (!date || Number.isNaN(date.getTime()))
|
|
321
|
+
return null;
|
|
322
|
+
if (this.dataType() === 'dateTime') {
|
|
323
|
+
// Format as YYYY-MM-DDTHH:mm for datetime-local compatibility
|
|
324
|
+
const pad = (n) => String(n).padStart(2, '0');
|
|
325
|
+
return `${date.getFullYear()}-${pad(date.getMonth() + 1)}-${pad(date.getDate())}T${pad(date.getHours())}:${pad(date.getMinutes())}`;
|
|
326
|
+
}
|
|
327
|
+
// Format as YYYY-MM-DD for date
|
|
328
|
+
const pad = (n) => String(n).padStart(2, '0');
|
|
329
|
+
return `${date.getFullYear()}-${pad(date.getMonth() + 1)}-${pad(date.getDate())}`;
|
|
330
|
+
}
|
|
331
|
+
summaryText = computed(() => {
|
|
332
|
+
const currentValue = this.value();
|
|
333
|
+
if (!currentValue) {
|
|
334
|
+
return this.i18n['filter_noFilter']();
|
|
335
|
+
}
|
|
336
|
+
if (currentValue.dataType === 'list') {
|
|
337
|
+
const selected = this.templateListSelection();
|
|
338
|
+
if (selected.length === 0) {
|
|
339
|
+
return this.i18n['filter_noFilter']();
|
|
340
|
+
}
|
|
341
|
+
if (selected.length === 1) {
|
|
342
|
+
return selected[0] ?? this.i18n['filter_noFilter']();
|
|
343
|
+
}
|
|
344
|
+
return `${selected.length} ${this.i18n['filter_selected']()}`;
|
|
345
|
+
}
|
|
346
|
+
const active = this.activeConditionConfigs();
|
|
347
|
+
if (active.length === 0) {
|
|
348
|
+
return this.i18n['filter_noFilter']();
|
|
349
|
+
}
|
|
350
|
+
if (active.length === 1) {
|
|
351
|
+
const c = active[0];
|
|
352
|
+
const def = this.operatorDefs().find(d => d.id === c?.operator);
|
|
353
|
+
const operatorLabel = def ? this.i18n._unsafe[def.labelKey]?.() : c?.operator;
|
|
354
|
+
return c?.rawValue == null || c?.rawValue === ''
|
|
355
|
+
? operatorLabel
|
|
356
|
+
: `${operatorLabel} "${c.rawValue}"`;
|
|
357
|
+
}
|
|
358
|
+
const matchLabel = currentValue.matchMode === 'all'
|
|
359
|
+
? this.i18n['filter_match_all']()
|
|
360
|
+
: this.i18n['filter_match_any']();
|
|
361
|
+
return `${active.length} ${this.i18n['filter_conditions']()} (${matchLabel})`;
|
|
362
|
+
}, /* @ts-ignore */
|
|
363
|
+
...(ngDevMode ? [{ debugName: "summaryText" }] : /* istanbul ignore next */ []));
|
|
364
|
+
activeConditionConfigs = computed(() => {
|
|
365
|
+
const cfg = this.value();
|
|
366
|
+
if (!cfg || cfg.dataType === 'list') {
|
|
367
|
+
return [];
|
|
368
|
+
}
|
|
369
|
+
const defs = this.operatorDefs();
|
|
370
|
+
const defById = new Map(defs.map(d => [d.id, d]));
|
|
371
|
+
return cfg.conditions.filter(c => {
|
|
372
|
+
const def = defById.get(c.operator);
|
|
373
|
+
const requiresValue = def?.requiresValue ?? true;
|
|
374
|
+
return !requiresValue || (c.rawValue != null && c.rawValue !== '');
|
|
375
|
+
});
|
|
376
|
+
}, /* @ts-ignore */
|
|
377
|
+
...(ngDevMode ? [{ debugName: "activeConditionConfigs" }] : /* istanbul ignore next */ []));
|
|
378
|
+
activeConditions = computed(() => {
|
|
379
|
+
const cfg = this.value();
|
|
380
|
+
return cfg ? getActiveFilterConditions(cfg) : [];
|
|
381
|
+
}, /* @ts-ignore */
|
|
382
|
+
...(ngDevMode ? [{ debugName: "activeConditions" }] : /* istanbul ignore next */ []));
|
|
383
|
+
filteredData = computed(() => {
|
|
384
|
+
if (!this.filterLocally()) {
|
|
385
|
+
return this.data();
|
|
386
|
+
}
|
|
387
|
+
const cfg = this.value();
|
|
388
|
+
if (!cfg) {
|
|
389
|
+
return this.data();
|
|
390
|
+
}
|
|
391
|
+
return executeFilter(this.data(), cfg);
|
|
392
|
+
}, /* @ts-ignore */
|
|
393
|
+
...(ngDevMode ? [{ debugName: "filteredData" }] : /* istanbul ignore next */ []));
|
|
394
|
+
/** The current match mode label for the condition divider */
|
|
395
|
+
matchModeLabel = computed(() => {
|
|
396
|
+
const cfg = this.templateConfig();
|
|
397
|
+
return cfg.matchMode === 'all'
|
|
398
|
+
? this.i18n['filter_match_and']()
|
|
399
|
+
: this.i18n['filter_match_or']();
|
|
400
|
+
}, /* @ts-ignore */
|
|
401
|
+
...(ngDevMode ? [{ debugName: "matchModeLabel" }] : /* istanbul ignore next */ []));
|
|
402
|
+
constructor() {
|
|
403
|
+
super();
|
|
404
|
+
// Initialize workingConfig from initial value.
|
|
405
|
+
this.workingConfig.set(this.value());
|
|
406
|
+
effect(() => {
|
|
407
|
+
this.filterChange.emit(this.value() ?? null);
|
|
408
|
+
});
|
|
409
|
+
effect(() => {
|
|
410
|
+
if (!this.filterLocally()) {
|
|
411
|
+
return;
|
|
412
|
+
}
|
|
413
|
+
this.filterResultChange.emit(this.filteredData());
|
|
414
|
+
});
|
|
415
|
+
effect(() => {
|
|
416
|
+
if (!this.allowMultiple()) {
|
|
417
|
+
const cfg = this.value();
|
|
418
|
+
if (!cfg || cfg.dataType === 'list') {
|
|
419
|
+
return;
|
|
420
|
+
}
|
|
421
|
+
if (cfg.conditions.length <= 1 && cfg.matchMode === 'all') {
|
|
422
|
+
return;
|
|
423
|
+
}
|
|
424
|
+
this.value.set({
|
|
425
|
+
...cfg,
|
|
426
|
+
matchMode: 'all',
|
|
427
|
+
conditions: cfg.conditions.slice(0, 1),
|
|
428
|
+
});
|
|
429
|
+
}
|
|
430
|
+
});
|
|
431
|
+
effect(() => {
|
|
432
|
+
const defs = this.operatorDefs();
|
|
433
|
+
const first = defs[0];
|
|
434
|
+
if (!first) {
|
|
435
|
+
throw new NgnError('filter', 'No operators available.');
|
|
436
|
+
}
|
|
437
|
+
const defIds = new Set(defs.map(d => d.id));
|
|
438
|
+
const normalizeConditions = (conditions) => {
|
|
439
|
+
let changed = false;
|
|
440
|
+
const next = conditions.map(c => {
|
|
441
|
+
if (defIds.has(c.operator)) {
|
|
442
|
+
return c;
|
|
443
|
+
}
|
|
444
|
+
changed = true;
|
|
445
|
+
return { ...c, operator: first.id, rawValue: null };
|
|
446
|
+
});
|
|
447
|
+
return changed ? next : conditions;
|
|
448
|
+
};
|
|
449
|
+
const cfg = this.value();
|
|
450
|
+
if (!cfg || cfg.dataType === 'list') {
|
|
451
|
+
return;
|
|
452
|
+
}
|
|
453
|
+
const current = cfg.conditions;
|
|
454
|
+
const next = normalizeConditions(current);
|
|
455
|
+
if (next !== current) {
|
|
456
|
+
this.value.set({ ...cfg, conditions: next });
|
|
457
|
+
}
|
|
458
|
+
});
|
|
459
|
+
this._destroyRef.onDestroy(() => {
|
|
460
|
+
if (this._debounceTimer != null) {
|
|
461
|
+
clearTimeout(this._debounceTimer);
|
|
462
|
+
}
|
|
463
|
+
});
|
|
464
|
+
}
|
|
465
|
+
/**
|
|
466
|
+
* Commits the working config to the actual value, with optional debounce.
|
|
467
|
+
* Called after every working config change.
|
|
468
|
+
*/
|
|
469
|
+
commitWorkingConfig() {
|
|
470
|
+
if (this.autoApply()) {
|
|
471
|
+
if (this._debounceTimer != null) {
|
|
472
|
+
clearTimeout(this._debounceTimer);
|
|
473
|
+
}
|
|
474
|
+
const debounceMs = this.autoApplyDebounce();
|
|
475
|
+
if (debounceMs > 0) {
|
|
476
|
+
this._debounceTimer = setTimeout(() => {
|
|
477
|
+
this._debounceTimer = null;
|
|
478
|
+
this.value.set(this.workingConfig());
|
|
479
|
+
}, debounceMs);
|
|
480
|
+
}
|
|
481
|
+
else {
|
|
482
|
+
this.value.set(this.workingConfig());
|
|
483
|
+
}
|
|
484
|
+
}
|
|
485
|
+
// In manual mode, do nothing — wait for apply()
|
|
486
|
+
}
|
|
487
|
+
/** Updates the working config and optionally auto-applies. */
|
|
488
|
+
updateWorkingConfig(config) {
|
|
489
|
+
this.workingConfig.set(config);
|
|
490
|
+
this.commitWorkingConfig();
|
|
491
|
+
}
|
|
492
|
+
toggleMatchMode() {
|
|
493
|
+
const cfg = this.templateConfig();
|
|
494
|
+
if (cfg.dataType === 'list' || !this.allowMultiple()) {
|
|
495
|
+
return;
|
|
496
|
+
}
|
|
497
|
+
const newMode = cfg.matchMode === 'all' ? 'any' : 'all';
|
|
498
|
+
this.updateWorkingConfig({
|
|
499
|
+
...cfg,
|
|
500
|
+
matchMode: newMode,
|
|
501
|
+
});
|
|
502
|
+
}
|
|
503
|
+
setMatchMode(value) {
|
|
504
|
+
if (value === 'all' || value === 'any') {
|
|
505
|
+
const cfg = this.templateConfig();
|
|
506
|
+
if (cfg.dataType === 'list') {
|
|
507
|
+
return;
|
|
508
|
+
}
|
|
509
|
+
this.updateWorkingConfig({
|
|
510
|
+
...cfg,
|
|
511
|
+
matchMode: this.allowMultiple() ? value : 'all',
|
|
512
|
+
});
|
|
513
|
+
}
|
|
514
|
+
}
|
|
515
|
+
operatorRequiresValue(operator) {
|
|
516
|
+
const def = this.operatorDefs().find(d => d.id === operator);
|
|
517
|
+
return def?.requiresValue ?? true;
|
|
518
|
+
}
|
|
519
|
+
setOperator(index, operator) {
|
|
520
|
+
if (!operator) {
|
|
521
|
+
return;
|
|
522
|
+
}
|
|
523
|
+
const cfg = this.templateConfig();
|
|
524
|
+
if (cfg.dataType === 'list') {
|
|
525
|
+
return;
|
|
526
|
+
}
|
|
527
|
+
const next = cfg.conditions.slice();
|
|
528
|
+
const existing = next[index];
|
|
529
|
+
if (!existing) {
|
|
530
|
+
return;
|
|
531
|
+
}
|
|
532
|
+
next[index] = {
|
|
533
|
+
...existing,
|
|
534
|
+
operator,
|
|
535
|
+
rawValue: this.operatorRequiresValue(operator) ? existing.rawValue : null,
|
|
536
|
+
};
|
|
537
|
+
this.updateWorkingConfig({
|
|
538
|
+
...cfg,
|
|
539
|
+
matchMode: this.allowMultiple() ? cfg.matchMode : 'all',
|
|
540
|
+
conditions: next,
|
|
541
|
+
});
|
|
542
|
+
}
|
|
543
|
+
setRawValue(index, rawValue) {
|
|
544
|
+
const cfg = this.templateConfig();
|
|
545
|
+
if (cfg.dataType === 'list') {
|
|
546
|
+
return;
|
|
547
|
+
}
|
|
548
|
+
const next = cfg.conditions.slice();
|
|
549
|
+
const existing = next[index];
|
|
550
|
+
if (!existing) {
|
|
551
|
+
return;
|
|
552
|
+
}
|
|
553
|
+
next[index] = { ...existing, rawValue };
|
|
554
|
+
this.updateWorkingConfig({
|
|
555
|
+
...cfg,
|
|
556
|
+
matchMode: this.allowMultiple() ? cfg.matchMode : 'all',
|
|
557
|
+
conditions: next,
|
|
558
|
+
});
|
|
559
|
+
}
|
|
560
|
+
setDateValue(index, date) {
|
|
561
|
+
this.setRawValue(index, this.dateToRaw(date));
|
|
562
|
+
}
|
|
563
|
+
addCondition() {
|
|
564
|
+
if (!this.allowMultiple()) {
|
|
565
|
+
return;
|
|
566
|
+
}
|
|
567
|
+
const cfg = this.templateConfig();
|
|
568
|
+
if (cfg.dataType === 'list') {
|
|
569
|
+
return;
|
|
570
|
+
}
|
|
571
|
+
const firstOp = this.operatorDefs()[0]?.id ?? 'isEqual';
|
|
572
|
+
this.updateWorkingConfig({
|
|
573
|
+
...cfg,
|
|
574
|
+
matchMode: cfg.matchMode,
|
|
575
|
+
conditions: [...cfg.conditions, this.createCondition(firstOp)],
|
|
576
|
+
});
|
|
577
|
+
}
|
|
578
|
+
removeCondition(index) {
|
|
579
|
+
if (!this.allowMultiple()) {
|
|
580
|
+
return;
|
|
581
|
+
}
|
|
582
|
+
const cfg = this.templateConfig();
|
|
583
|
+
if (cfg.dataType === 'list') {
|
|
584
|
+
return;
|
|
585
|
+
}
|
|
586
|
+
const current = cfg.conditions;
|
|
587
|
+
if (current.length <= 1) {
|
|
588
|
+
return;
|
|
589
|
+
}
|
|
590
|
+
const next = current.slice();
|
|
591
|
+
next.splice(index, 1);
|
|
592
|
+
this.updateWorkingConfig({
|
|
593
|
+
...cfg,
|
|
594
|
+
matchMode: cfg.matchMode,
|
|
595
|
+
conditions: next,
|
|
596
|
+
});
|
|
597
|
+
}
|
|
598
|
+
setListSelection(value) {
|
|
599
|
+
const arr = Array.isArray(value)
|
|
600
|
+
? value.map(v => String(v))
|
|
601
|
+
: value == null
|
|
602
|
+
? []
|
|
603
|
+
: [String(value)];
|
|
604
|
+
this.updateWorkingConfig({
|
|
605
|
+
dataType: 'list',
|
|
606
|
+
matchMode: 'all',
|
|
607
|
+
conditions: [
|
|
608
|
+
{
|
|
609
|
+
operator: 'in',
|
|
610
|
+
rawValue: arr.length > 0 ? JSON.stringify(arr) : null,
|
|
611
|
+
},
|
|
612
|
+
],
|
|
613
|
+
});
|
|
614
|
+
}
|
|
615
|
+
/** Applies the working config (manual mode). */
|
|
616
|
+
apply() {
|
|
617
|
+
const cfg = this.workingConfig();
|
|
618
|
+
this.value.set(cfg);
|
|
619
|
+
// Update snapshot so next cancel restores to this applied state
|
|
620
|
+
this._snapshotConfig = cfg ? JSON.parse(JSON.stringify(cfg)) : null;
|
|
621
|
+
if (this.mode() !== 'inline') {
|
|
622
|
+
this.hide();
|
|
623
|
+
}
|
|
624
|
+
}
|
|
625
|
+
/** Cancels changes and restores the snapshot (manual mode). */
|
|
626
|
+
cancelChanges() {
|
|
627
|
+
// Clear any pending debounce
|
|
628
|
+
if (this._debounceTimer != null) {
|
|
629
|
+
clearTimeout(this._debounceTimer);
|
|
630
|
+
this._debounceTimer = null;
|
|
631
|
+
}
|
|
632
|
+
this.workingConfig.set(this._snapshotConfig ? JSON.parse(JSON.stringify(this._snapshotConfig)) : null);
|
|
633
|
+
if (this.mode() !== 'inline') {
|
|
634
|
+
this.hide();
|
|
635
|
+
}
|
|
636
|
+
}
|
|
637
|
+
clear() {
|
|
638
|
+
this.updateWorkingConfig(null);
|
|
639
|
+
if (!this.autoApply()) {
|
|
640
|
+
// In manual mode, also commit clear immediately
|
|
641
|
+
this.value.set(null);
|
|
642
|
+
this._snapshotConfig = null;
|
|
643
|
+
}
|
|
644
|
+
if (this.mode() !== 'inline') {
|
|
645
|
+
this.hide();
|
|
646
|
+
}
|
|
647
|
+
}
|
|
648
|
+
/** Shows the filter popup. Only works when {@link mode} is not `inline`. */
|
|
649
|
+
show() {
|
|
650
|
+
if (this.mode() === 'inline') {
|
|
651
|
+
throw new NgnError('filter', 'Cannot open an inline filter.');
|
|
652
|
+
}
|
|
653
|
+
if (this.mode() === 'headless' && !this.anchor()) {
|
|
654
|
+
throw new NgnError('filter', 'Headless mode requires an [anchor] input.');
|
|
655
|
+
}
|
|
656
|
+
const popover = this._popover();
|
|
657
|
+
if (!popover) {
|
|
658
|
+
throw new NgnError('filter', 'Popover is not available.');
|
|
659
|
+
}
|
|
660
|
+
// Snapshot current value for cancel
|
|
661
|
+
const val = this.value();
|
|
662
|
+
this._snapshotConfig = val ? JSON.parse(JSON.stringify(val)) : null;
|
|
663
|
+
// Reset working config to current value
|
|
664
|
+
this.workingConfig.set(val);
|
|
665
|
+
popover.show();
|
|
666
|
+
}
|
|
667
|
+
/** Hides the filter popup. Only works when {@link mode} is not `inline`. */
|
|
668
|
+
hide() {
|
|
669
|
+
if (this.mode() === 'inline') {
|
|
670
|
+
throw new NgnError('filter', 'Cannot close an inline filter.');
|
|
671
|
+
}
|
|
672
|
+
this._popover()?.hide();
|
|
673
|
+
}
|
|
674
|
+
onKeyDown(event) {
|
|
675
|
+
if (event.key === 'Enter') {
|
|
676
|
+
if (this.mode() !== 'inline') {
|
|
677
|
+
this._popover()?.toggle();
|
|
678
|
+
event.stopPropagation();
|
|
679
|
+
event.preventDefault();
|
|
680
|
+
}
|
|
681
|
+
}
|
|
682
|
+
}
|
|
683
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.5", ngImport: i0, type: NgnFilter, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
684
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.0.5", 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 }, autoApply: { classPropertyName: "autoApply", publicName: "autoApply", isSignal: true, isRequired: false, transformFunction: null }, autoApplyDebounce: { classPropertyName: "autoApplyDebounce", publicName: "autoApplyDebounce", 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>\n <div [ptInt]=\"this\" [ptClass]=\"'rows'\">\n @if (dataType() === 'list') {\n <div [ptInt]=\"this\" [ptClass]=\"'row'\" data-testid=\"filter-row-list\">\n <ngn-input-field\n [ptInt]=\"this\"\n [ptDep]=\"'value'\"\n [disabled]=\"disabled()\"\n [readonly]=\"readonly()\"\n >\n <ngn-select\n [ptInt]=\"this\"\n [ptDep]=\"'list-select'\"\n [multiple]=\"true\"\n [options]=\"resolvedListOptions()\"\n [value]=\"$any(templateListSelection())\"\n [disabled]=\"disabled()\"\n [readonly]=\"readonly()\"\n (valueChange)=\"setListSelection($event)\"\n />\n </ngn-input-field>\n </div>\n } @else {\n @for (c of templateConfig().conditions; track $index; let i = $index; let last = $last) {\n <div [ptInt]=\"this\" [ptClass]=\"'row'\" [attr.data-testid]=\"'filter-row-' + i\">\n <ngn-input-field\n [ptInt]=\"this\"\n [ptDep]=\"operatorRequiresValue(c.operator) ? 'operator' : 'value'\"\n [disabled]=\"disabled()\"\n [readonly]=\"readonly()\"\n >\n <ngn-select\n [ptInt]=\"this\"\n [ptDep]=\"'operator-select'\"\n [options]=\"operatorOptions()\"\n [label]=\"i18n['filter_operator']()\"\n [value]=\"c.operator\"\n [disabled]=\"disabled()\"\n [readonly]=\"readonly()\"\n (valueChange)=\"setOperator(i, $event)\"\n />\n </ngn-input-field>\n @if (operatorRequiresValue(c.operator)) {\n @if (isDateType()) {\n <ngn-input-field\n [ptInt]=\"this\"\n [ptDep]=\"'value'\"\n [disabled]=\"disabled()\"\n [readonly]=\"readonly()\"\n >\n <ngn-calendar\n [ptInt]=\"this\"\n [ptDep]=\"'calendar'\"\n [showTime]=\"isShowTime()\"\n [value]=\"parseRawDate(c.rawValue)\"\n [disabled]=\"disabled()\"\n [readonly]=\"readonly()\"\n (valueChange)=\"setDateValue(i, $event)\"\n />\n </ngn-input-field>\n } @else {\n <ngn-input-field\n [ptInt]=\"this\"\n [ptDep]=\"'value'\"\n [disabled]=\"disabled()\"\n [readonly]=\"readonly()\"\n >\n <input\n ngnInput\n [ptInt]=\"this\"\n [ptDep]=\"'input'\"\n [attr.aria-label]=\"i18n['filter_value']()\"\n [type]=\"inputType()\"\n [value]=\"c.rawValue || ''\"\n [disabled]=\"disabled()\"\n [readOnly]=\"readonly()\"\n (valueChange)=\"setRawValue(i, $event)\"\n />\n </ngn-input-field>\n }\n }\n\n @if (allowMultiple() && templateConfig().conditions.length > 1) {\n <button\n type=\"button\"\n ngnButton\n kind=\"icon\"\n [ptInt]=\"this\"\n [ptDep]=\"'remove-btn'\"\n [disabled]=\"disabled() || readonly()\"\n (click)=\"removeCondition(i)\"\n [attr.aria-label]=\"i18n['filter_removeCondition']() + ' ' + (i + 1)\"\n data-testid=\"filter-remove-condition\"\n >\n <ngn-icon defaultIcon=\"filter-remove\" />\n </button>\n }\n </div>\n\n @if (allowMultiple() && !last && templateConfig().conditions.length > 1) {\n <div\n [ptInt]=\"this\"\n [ptClass]=\"'condition-divider'\"\n role=\"button\"\n tabindex=\"0\"\n (click)=\"!disabled() && !readonly() && toggleMatchMode()\"\n (keydown.enter)=\"!disabled() && !readonly() && toggleMatchMode()\"\n (keydown.space)=\"\n !disabled() && !readonly() && toggleMatchMode(); $event.preventDefault()\n \"\n [attr.aria-disabled]=\"disabled() || readonly()\"\n data-testid=\"filter-match-mode\"\n >\n {{ matchModeLabel() }}\n </div>\n }\n }\n }\n </div>\n</ng-template>\n\n<ng-template #footerTemplate>\n @if (!disabled() && !readonly()) {\n <div [ptInt]=\"this\" [ptClass]=\"'footer'\">\n @if (dataType() !== 'list' && allowMultiple()) {\n <button\n type=\"button\"\n ngnButton\n kind=\"secondary\"\n [ptInt]=\"this\"\n [ptDep]=\"'add-button'\"\n (click)=\"addCondition()\"\n data-testid=\"filter-add-rule\"\n >\n <span aria-hidden=\"true\">+</span>\n {{ i18n['filter_addCondition']() }}\n </button>\n }\n <div [ptInt]=\"this\" [ptClass]=\"'footer-actions'\">\n @if (!autoApply()) {\n <button\n type=\"button\"\n ngnButton\n kind=\"secondary\"\n [ptInt]=\"this\"\n [ptDep]=\"'cancel-button'\"\n (click)=\"cancelChanges()\"\n data-testid=\"filter-cancel\"\n >\n {{ i18n['filter_cancel']() }}\n </button>\n <button\n type=\"button\"\n ngnButton\n kind=\"primary\"\n [ptInt]=\"this\"\n [ptDep]=\"'apply-button'\"\n (click)=\"apply()\"\n data-testid=\"filter-apply\"\n >\n {{ i18n['filter_apply']() }}\n </button>\n } @else {\n <button\n type=\"button\"\n ngnButton\n kind=\"secondary\"\n [ptInt]=\"this\"\n [ptDep]=\"'clear-button'\"\n (click)=\"clear()\"\n data-testid=\"filter-clear\"\n >\n {{ i18n['filter_clear']() }}\n </button>\n }\n </div>\n </div>\n }\n</ng-template>\n\n<ng-template #popoverTemplate let-anchor=\"anchor\">\n <ngn-popover\n #popover\n [ptInt]=\"this\"\n [ptDep]=\"'popover'\"\n [options]=\"appliedPopoverOptions()\"\n [anchor]=\"anchor\"\n [hasShrinkableContent]=\"true\"\n (keydown)=\"onKeyDown($event)\"\n [id]=\"inputId() + '_popover'\"\n >\n <ng-template #lazy>\n <div [ptInt]=\"this\" [ptClass]=\"'popover-content'\">\n <ng-container [ngTemplateOutlet]=\"rowsTemplate\" />\n <ng-container [ngTemplateOutlet]=\"footerTemplate\" />\n </div>\n </ng-template>\n </ngn-popover>\n</ng-template>\n\n@if (mode() === 'inline') {\n <div [ptInt]=\"this\" [ptClass]=\"'inline'\">\n <ng-container [ngTemplateOutlet]=\"rowsTemplate\" />\n <ng-container [ngTemplateOutlet]=\"footerTemplate\" />\n </div>\n} @else if (mode() === 'input') {\n <ngn-input-field\n [ptInt]=\"this\"\n [ptDep]=\"'input-field'\"\n (click)=\"!disabled() && !readonly() && show()\"\n (keydown)=\"onKeyDown($event)\"\n #field\n [label]=\"label()\"\n [inputId]=\"inputId()\"\n [invalid]=\"invalid()\"\n [disabled]=\"disabled()\"\n [readonly]=\"readonly()\"\n >\n <div role=\"button\" [ptInt]=\"this\" [ptClass]=\"'summary'\">{{ summaryText() }}</div>\n <ngn-icon [ptInt]=\"this\" [ptClass]=\"'icon'\" defaultIcon=\"search\" />\n </ngn-input-field>\n\n <ng-container\n [ngTemplateOutlet]=\"popoverTemplate\"\n [ngTemplateOutletContext]=\"{ anchor: field.element.nativeElement }\"\n />\n} @else {\n @if (anchor()) {\n <ng-container\n [ngTemplateOutlet]=\"popoverTemplate\"\n [ngTemplateOutletContext]=\"{ anchor: anchor() }\"\n />\n }\n}\n", dependencies: [{ kind: "directive", type: NgnPt, selector: "[ptInt]", inputs: ["ptInt", "ptClass", "ptDep"] }, { kind: "directive", type: NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "component", type: NgnCalendar, selector: "ngn-calendar", inputs: ["firstDayOfWeek", "showTime", "showSeconds", "inline", "format"] }, { 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"], exportAs: ["ngnInput"] }, { kind: "component", type: NgnSelect, selector: "ngn-select", inputs: ["popoverOptions", "options", "filter", "filterText", "iconFilter", "iconDropdown", "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: ["ngnButtonInline"], exportAs: ["ngnButton"] }] });
|
|
685
|
+
}
|
|
686
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.5", ngImport: i0, type: NgnFilter, decorators: [{
|
|
687
|
+
type: Component,
|
|
688
|
+
args: [{ selector: 'ngn-filter', imports: [
|
|
689
|
+
NgnPt,
|
|
690
|
+
NgTemplateOutlet,
|
|
691
|
+
NgnCalendar,
|
|
692
|
+
NgnInputField,
|
|
693
|
+
NgnInput,
|
|
694
|
+
NgnSelect,
|
|
695
|
+
NgnPopover,
|
|
696
|
+
NgnIcon,
|
|
697
|
+
NgnButton,
|
|
698
|
+
], providers: [provideSelf(NgnFilter)], host: {
|
|
699
|
+
style: 'display: block;',
|
|
700
|
+
}, template: "<ng-template #rowsTemplate>\n <div [ptInt]=\"this\" [ptClass]=\"'rows'\">\n @if (dataType() === 'list') {\n <div [ptInt]=\"this\" [ptClass]=\"'row'\" data-testid=\"filter-row-list\">\n <ngn-input-field\n [ptInt]=\"this\"\n [ptDep]=\"'value'\"\n [disabled]=\"disabled()\"\n [readonly]=\"readonly()\"\n >\n <ngn-select\n [ptInt]=\"this\"\n [ptDep]=\"'list-select'\"\n [multiple]=\"true\"\n [options]=\"resolvedListOptions()\"\n [value]=\"$any(templateListSelection())\"\n [disabled]=\"disabled()\"\n [readonly]=\"readonly()\"\n (valueChange)=\"setListSelection($event)\"\n />\n </ngn-input-field>\n </div>\n } @else {\n @for (c of templateConfig().conditions; track $index; let i = $index; let last = $last) {\n <div [ptInt]=\"this\" [ptClass]=\"'row'\" [attr.data-testid]=\"'filter-row-' + i\">\n <ngn-input-field\n [ptInt]=\"this\"\n [ptDep]=\"operatorRequiresValue(c.operator) ? 'operator' : 'value'\"\n [disabled]=\"disabled()\"\n [readonly]=\"readonly()\"\n >\n <ngn-select\n [ptInt]=\"this\"\n [ptDep]=\"'operator-select'\"\n [options]=\"operatorOptions()\"\n [label]=\"i18n['filter_operator']()\"\n [value]=\"c.operator\"\n [disabled]=\"disabled()\"\n [readonly]=\"readonly()\"\n (valueChange)=\"setOperator(i, $event)\"\n />\n </ngn-input-field>\n @if (operatorRequiresValue(c.operator)) {\n @if (isDateType()) {\n <ngn-input-field\n [ptInt]=\"this\"\n [ptDep]=\"'value'\"\n [disabled]=\"disabled()\"\n [readonly]=\"readonly()\"\n >\n <ngn-calendar\n [ptInt]=\"this\"\n [ptDep]=\"'calendar'\"\n [showTime]=\"isShowTime()\"\n [value]=\"parseRawDate(c.rawValue)\"\n [disabled]=\"disabled()\"\n [readonly]=\"readonly()\"\n (valueChange)=\"setDateValue(i, $event)\"\n />\n </ngn-input-field>\n } @else {\n <ngn-input-field\n [ptInt]=\"this\"\n [ptDep]=\"'value'\"\n [disabled]=\"disabled()\"\n [readonly]=\"readonly()\"\n >\n <input\n ngnInput\n [ptInt]=\"this\"\n [ptDep]=\"'input'\"\n [attr.aria-label]=\"i18n['filter_value']()\"\n [type]=\"inputType()\"\n [value]=\"c.rawValue || ''\"\n [disabled]=\"disabled()\"\n [readOnly]=\"readonly()\"\n (valueChange)=\"setRawValue(i, $event)\"\n />\n </ngn-input-field>\n }\n }\n\n @if (allowMultiple() && templateConfig().conditions.length > 1) {\n <button\n type=\"button\"\n ngnButton\n kind=\"icon\"\n [ptInt]=\"this\"\n [ptDep]=\"'remove-btn'\"\n [disabled]=\"disabled() || readonly()\"\n (click)=\"removeCondition(i)\"\n [attr.aria-label]=\"i18n['filter_removeCondition']() + ' ' + (i + 1)\"\n data-testid=\"filter-remove-condition\"\n >\n <ngn-icon defaultIcon=\"filter-remove\" />\n </button>\n }\n </div>\n\n @if (allowMultiple() && !last && templateConfig().conditions.length > 1) {\n <div\n [ptInt]=\"this\"\n [ptClass]=\"'condition-divider'\"\n role=\"button\"\n tabindex=\"0\"\n (click)=\"!disabled() && !readonly() && toggleMatchMode()\"\n (keydown.enter)=\"!disabled() && !readonly() && toggleMatchMode()\"\n (keydown.space)=\"\n !disabled() && !readonly() && toggleMatchMode(); $event.preventDefault()\n \"\n [attr.aria-disabled]=\"disabled() || readonly()\"\n data-testid=\"filter-match-mode\"\n >\n {{ matchModeLabel() }}\n </div>\n }\n }\n }\n </div>\n</ng-template>\n\n<ng-template #footerTemplate>\n @if (!disabled() && !readonly()) {\n <div [ptInt]=\"this\" [ptClass]=\"'footer'\">\n @if (dataType() !== 'list' && allowMultiple()) {\n <button\n type=\"button\"\n ngnButton\n kind=\"secondary\"\n [ptInt]=\"this\"\n [ptDep]=\"'add-button'\"\n (click)=\"addCondition()\"\n data-testid=\"filter-add-rule\"\n >\n <span aria-hidden=\"true\">+</span>\n {{ i18n['filter_addCondition']() }}\n </button>\n }\n <div [ptInt]=\"this\" [ptClass]=\"'footer-actions'\">\n @if (!autoApply()) {\n <button\n type=\"button\"\n ngnButton\n kind=\"secondary\"\n [ptInt]=\"this\"\n [ptDep]=\"'cancel-button'\"\n (click)=\"cancelChanges()\"\n data-testid=\"filter-cancel\"\n >\n {{ i18n['filter_cancel']() }}\n </button>\n <button\n type=\"button\"\n ngnButton\n kind=\"primary\"\n [ptInt]=\"this\"\n [ptDep]=\"'apply-button'\"\n (click)=\"apply()\"\n data-testid=\"filter-apply\"\n >\n {{ i18n['filter_apply']() }}\n </button>\n } @else {\n <button\n type=\"button\"\n ngnButton\n kind=\"secondary\"\n [ptInt]=\"this\"\n [ptDep]=\"'clear-button'\"\n (click)=\"clear()\"\n data-testid=\"filter-clear\"\n >\n {{ i18n['filter_clear']() }}\n </button>\n }\n </div>\n </div>\n }\n</ng-template>\n\n<ng-template #popoverTemplate let-anchor=\"anchor\">\n <ngn-popover\n #popover\n [ptInt]=\"this\"\n [ptDep]=\"'popover'\"\n [options]=\"appliedPopoverOptions()\"\n [anchor]=\"anchor\"\n [hasShrinkableContent]=\"true\"\n (keydown)=\"onKeyDown($event)\"\n [id]=\"inputId() + '_popover'\"\n >\n <ng-template #lazy>\n <div [ptInt]=\"this\" [ptClass]=\"'popover-content'\">\n <ng-container [ngTemplateOutlet]=\"rowsTemplate\" />\n <ng-container [ngTemplateOutlet]=\"footerTemplate\" />\n </div>\n </ng-template>\n </ngn-popover>\n</ng-template>\n\n@if (mode() === 'inline') {\n <div [ptInt]=\"this\" [ptClass]=\"'inline'\">\n <ng-container [ngTemplateOutlet]=\"rowsTemplate\" />\n <ng-container [ngTemplateOutlet]=\"footerTemplate\" />\n </div>\n} @else if (mode() === 'input') {\n <ngn-input-field\n [ptInt]=\"this\"\n [ptDep]=\"'input-field'\"\n (click)=\"!disabled() && !readonly() && show()\"\n (keydown)=\"onKeyDown($event)\"\n #field\n [label]=\"label()\"\n [inputId]=\"inputId()\"\n [invalid]=\"invalid()\"\n [disabled]=\"disabled()\"\n [readonly]=\"readonly()\"\n >\n <div role=\"button\" [ptInt]=\"this\" [ptClass]=\"'summary'\">{{ summaryText() }}</div>\n <ngn-icon [ptInt]=\"this\" [ptClass]=\"'icon'\" defaultIcon=\"search\" />\n </ngn-input-field>\n\n <ng-container\n [ngTemplateOutlet]=\"popoverTemplate\"\n [ngTemplateOutletContext]=\"{ anchor: field.element.nativeElement }\"\n />\n} @else {\n @if (anchor()) {\n <ng-container\n [ngTemplateOutlet]=\"popoverTemplate\"\n [ngTemplateOutletContext]=\"{ anchor: anchor() }\"\n />\n }\n}\n" }]
|
|
701
|
+
}], 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 }] }], autoApply: [{ type: i0.Input, args: [{ isSignal: true, alias: "autoApply", required: false }] }], autoApplyDebounce: [{ type: i0.Input, args: [{ isSignal: true, alias: "autoApplyDebounce", 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 }] }] } });
|
|
702
|
+
|
|
703
|
+
/**
|
|
704
|
+
* Generated bundle index. Do not edit.
|
|
705
|
+
*/
|
|
706
|
+
|
|
707
|
+
export { NgnFilter };
|
|
708
|
+
//# sourceMappingURL=ngneers-controls-filter.mjs.map
|