@memberjunction/ng-search 0.0.1 → 5.22.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (38) hide show
  1. package/dist/__tests__/search-types.test.d.ts +2 -0
  2. package/dist/__tests__/search-types.test.d.ts.map +1 -0
  3. package/dist/__tests__/search-types.test.js +107 -0
  4. package/dist/__tests__/search-types.test.js.map +1 -0
  5. package/dist/__tests__/search.service.test.d.ts +2 -0
  6. package/dist/__tests__/search.service.test.d.ts.map +1 -0
  7. package/dist/__tests__/search.service.test.js +183 -0
  8. package/dist/__tests__/search.service.test.js.map +1 -0
  9. package/dist/lib/module.d.ts +13 -0
  10. package/dist/lib/module.d.ts.map +1 -0
  11. package/dist/lib/module.js +43 -0
  12. package/dist/lib/module.js.map +1 -0
  13. package/dist/lib/search-filter.component.d.ts +39 -0
  14. package/dist/lib/search-filter.component.d.ts.map +1 -0
  15. package/dist/lib/search-filter.component.js +200 -0
  16. package/dist/lib/search-filter.component.js.map +1 -0
  17. package/dist/lib/search-overlay.component.d.ts +103 -0
  18. package/dist/lib/search-overlay.component.d.ts.map +1 -0
  19. package/dist/lib/search-overlay.component.js +626 -0
  20. package/dist/lib/search-overlay.component.js.map +1 -0
  21. package/dist/lib/search-results.component.d.ts +64 -0
  22. package/dist/lib/search-results.component.d.ts.map +1 -0
  23. package/dist/lib/search-results.component.js +378 -0
  24. package/dist/lib/search-results.component.js.map +1 -0
  25. package/dist/lib/search-types.d.ts +142 -0
  26. package/dist/lib/search-types.d.ts.map +1 -0
  27. package/dist/lib/search-types.js +8 -0
  28. package/dist/lib/search-types.js.map +1 -0
  29. package/dist/lib/search.service.d.ts +52 -0
  30. package/dist/lib/search.service.d.ts.map +1 -0
  31. package/dist/lib/search.service.js +287 -0
  32. package/dist/lib/search.service.js.map +1 -0
  33. package/dist/public-api.d.ts +7 -0
  34. package/dist/public-api.d.ts.map +1 -0
  35. package/dist/public-api.js +10 -0
  36. package/dist/public-api.js.map +1 -0
  37. package/package.json +38 -7
  38. package/README.md +0 -45
@@ -0,0 +1,200 @@
1
+ /**
2
+ * @fileoverview Search Filter Component
3
+ *
4
+ * Faceted filter sidebar for narrowing search results.
5
+ * Displays filter categories with checkable options and counts.
6
+ */
7
+ import { Component, EventEmitter, Input, Output, ChangeDetectorRef, inject } from '@angular/core';
8
+ import * as i0 from "@angular/core";
9
+ const _forTrack0 = ($index, $item) => $item.Category;
10
+ const _forTrack1 = ($index, $item) => $item.Value;
11
+ function SearchFilterComponent_Conditional_5_Template(rf, ctx) { if (rf & 1) {
12
+ const _r1 = i0.ɵɵgetCurrentView();
13
+ i0.ɵɵelementStart(0, "button", 7);
14
+ i0.ɵɵlistener("click", function SearchFilterComponent_Conditional_5_Template_button_click_0_listener() { i0.ɵɵrestoreView(_r1); const ctx_r1 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r1.ClearAll()); });
15
+ i0.ɵɵtext(1);
16
+ i0.ɵɵelementEnd();
17
+ } if (rf & 2) {
18
+ const ctx_r1 = i0.ɵɵnextContext();
19
+ i0.ɵɵadvance();
20
+ i0.ɵɵtextInterpolate1(" Clear (", ctx_r1.GetActiveFilterCount(), ") ");
21
+ } }
22
+ function SearchFilterComponent_For_7_Conditional_4_Template(rf, ctx) { if (rf & 1) {
23
+ i0.ɵɵelement(0, "i", 12);
24
+ } if (rf & 2) {
25
+ const filter_r4 = i0.ɵɵnextContext().$implicit;
26
+ const ctx_r1 = i0.ɵɵnextContext();
27
+ i0.ɵɵclassProp("fa-chevron-down", ctx_r1.IsCategoryCollapsed(filter_r4.Category))("fa-chevron-up", !ctx_r1.IsCategoryCollapsed(filter_r4.Category));
28
+ } }
29
+ function SearchFilterComponent_For_7_Conditional_5_For_2_Conditional_2_Template(rf, ctx) { if (rf & 1) {
30
+ i0.ɵɵelement(0, "i", 16);
31
+ } }
32
+ function SearchFilterComponent_For_7_Conditional_5_For_2_Conditional_3_Template(rf, ctx) { if (rf & 1) {
33
+ i0.ɵɵelement(0, "i");
34
+ } if (rf & 2) {
35
+ const option_r6 = i0.ɵɵnextContext().$implicit;
36
+ i0.ɵɵclassMap(option_r6.Icon + " filter-option-icon");
37
+ } }
38
+ function SearchFilterComponent_For_7_Conditional_5_For_2_Template(rf, ctx) { if (rf & 1) {
39
+ const _r5 = i0.ɵɵgetCurrentView();
40
+ i0.ɵɵelementStart(0, "label", 14);
41
+ i0.ɵɵlistener("click", function SearchFilterComponent_For_7_Conditional_5_For_2_Template_label_click_0_listener($event) { const option_r6 = i0.ɵɵrestoreView(_r5).$implicit; const filter_r4 = i0.ɵɵnextContext(2).$implicit; const ctx_r1 = i0.ɵɵnextContext(); ctx_r1.ToggleOption(filter_r4.Category, option_r6.Value); return i0.ɵɵresetView($event.preventDefault()); });
42
+ i0.ɵɵelementStart(1, "span", 15);
43
+ i0.ɵɵconditionalCreate(2, SearchFilterComponent_For_7_Conditional_5_For_2_Conditional_2_Template, 1, 0, "i", 16);
44
+ i0.ɵɵelementEnd();
45
+ i0.ɵɵconditionalCreate(3, SearchFilterComponent_For_7_Conditional_5_For_2_Conditional_3_Template, 1, 2, "i", 17);
46
+ i0.ɵɵelementStart(4, "span", 18);
47
+ i0.ɵɵtext(5);
48
+ i0.ɵɵelementEnd();
49
+ i0.ɵɵelementStart(6, "span", 19);
50
+ i0.ɵɵtext(7);
51
+ i0.ɵɵelementEnd()();
52
+ } if (rf & 2) {
53
+ const option_r6 = ctx.$implicit;
54
+ const filter_r4 = i0.ɵɵnextContext(2).$implicit;
55
+ const ctx_r1 = i0.ɵɵnextContext();
56
+ i0.ɵɵadvance();
57
+ i0.ɵɵclassProp("filter-checkbox-checked", ctx_r1.IsOptionSelected(filter_r4.Category, option_r6.Value));
58
+ i0.ɵɵadvance();
59
+ i0.ɵɵconditional(ctx_r1.IsOptionSelected(filter_r4.Category, option_r6.Value) ? 2 : -1);
60
+ i0.ɵɵadvance();
61
+ i0.ɵɵconditional(option_r6.Icon ? 3 : -1);
62
+ i0.ɵɵadvance(2);
63
+ i0.ɵɵtextInterpolate(option_r6.Label);
64
+ i0.ɵɵadvance(2);
65
+ i0.ɵɵtextInterpolate(option_r6.Count);
66
+ } }
67
+ function SearchFilterComponent_For_7_Conditional_5_Template(rf, ctx) { if (rf & 1) {
68
+ i0.ɵɵelementStart(0, "div", 11);
69
+ i0.ɵɵrepeaterCreate(1, SearchFilterComponent_For_7_Conditional_5_For_2_Template, 8, 6, "label", 13, _forTrack1);
70
+ i0.ɵɵelementEnd();
71
+ } if (rf & 2) {
72
+ const filter_r4 = i0.ɵɵnextContext().$implicit;
73
+ i0.ɵɵadvance();
74
+ i0.ɵɵrepeater(filter_r4.Options);
75
+ } }
76
+ function SearchFilterComponent_For_7_Template(rf, ctx) { if (rf & 1) {
77
+ const _r3 = i0.ɵɵgetCurrentView();
78
+ i0.ɵɵelementStart(0, "div", 5)(1, "div", 8);
79
+ i0.ɵɵlistener("click", function SearchFilterComponent_For_7_Template_div_click_1_listener() { const filter_r4 = i0.ɵɵrestoreView(_r3).$implicit; const ctx_r1 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r1.ToggleCategory(filter_r4.Category)); });
80
+ i0.ɵɵelementStart(2, "span", 9);
81
+ i0.ɵɵtext(3);
82
+ i0.ɵɵelementEnd();
83
+ i0.ɵɵconditionalCreate(4, SearchFilterComponent_For_7_Conditional_4_Template, 1, 4, "i", 10);
84
+ i0.ɵɵelementEnd();
85
+ i0.ɵɵconditionalCreate(5, SearchFilterComponent_For_7_Conditional_5_Template, 3, 0, "div", 11);
86
+ i0.ɵɵelementEnd();
87
+ } if (rf & 2) {
88
+ const filter_r4 = ctx.$implicit;
89
+ const ctx_r1 = i0.ɵɵnextContext();
90
+ i0.ɵɵadvance();
91
+ i0.ɵɵclassProp("filter-category-collapsed", ctx_r1.IsCategoryCollapsed(filter_r4.Category));
92
+ i0.ɵɵadvance(2);
93
+ i0.ɵɵtextInterpolate(filter_r4.Category);
94
+ i0.ɵɵadvance();
95
+ i0.ɵɵconditional(ctx_r1.Collapsible ? 4 : -1);
96
+ i0.ɵɵadvance();
97
+ i0.ɵɵconditional(!ctx_r1.IsCategoryCollapsed(filter_r4.Category) ? 5 : -1);
98
+ } }
99
+ function SearchFilterComponent_Conditional_8_Template(rf, ctx) { if (rf & 1) {
100
+ i0.ɵɵelementStart(0, "div", 6)(1, "p");
101
+ i0.ɵɵtext(2, "No filters available");
102
+ i0.ɵɵelementEnd()();
103
+ } }
104
+ export class SearchFilterComponent {
105
+ cdr = inject(ChangeDetectorRef);
106
+ /** Available filters to display */
107
+ Filters = [];
108
+ /** Currently active filter selections */
109
+ ActiveFilters = {};
110
+ /** Whether the filter panel is collapsible */
111
+ Collapsible = true;
112
+ FilterChanged = new EventEmitter();
113
+ FiltersCleared = new EventEmitter();
114
+ /** Collapsed state per category */
115
+ CollapsedCategories = new Set();
116
+ /** Toggle a filter option */
117
+ ToggleOption(category, value) {
118
+ const current = this.ActiveFilters[category] ? [...this.ActiveFilters[category]] : [];
119
+ const index = current.indexOf(value);
120
+ if (index >= 0) {
121
+ current.splice(index, 1);
122
+ }
123
+ else {
124
+ current.push(value);
125
+ }
126
+ // Update local state to reflect change
127
+ this.ActiveFilters = { ...this.ActiveFilters, [category]: current };
128
+ this.FilterChanged.emit({ Category: category, SelectedValues: current });
129
+ this.cdr.detectChanges();
130
+ }
131
+ /** Toggle category collapse */
132
+ ToggleCategory(category) {
133
+ if (!this.Collapsible)
134
+ return;
135
+ if (this.CollapsedCategories.has(category)) {
136
+ this.CollapsedCategories.delete(category);
137
+ }
138
+ else {
139
+ this.CollapsedCategories.add(category);
140
+ }
141
+ this.cdr.detectChanges();
142
+ }
143
+ /** Check if a category is collapsed */
144
+ IsCategoryCollapsed(category) {
145
+ return this.CollapsedCategories.has(category);
146
+ }
147
+ /** Check if an option is selected */
148
+ IsOptionSelected(category, value) {
149
+ return (this.ActiveFilters[category] ?? []).includes(value);
150
+ }
151
+ /** Check if any filters are active */
152
+ HasActiveFilters() {
153
+ return Object.values(this.ActiveFilters).some(v => v.length > 0);
154
+ }
155
+ /** Get total active filter count */
156
+ GetActiveFilterCount() {
157
+ return Object.values(this.ActiveFilters).reduce((sum, v) => sum + v.length, 0);
158
+ }
159
+ /** Clear all filters */
160
+ ClearAll() {
161
+ this.ActiveFilters = {};
162
+ this.FiltersCleared.emit();
163
+ this.cdr.detectChanges();
164
+ }
165
+ static ɵfac = function SearchFilterComponent_Factory(__ngFactoryType__) { return new (__ngFactoryType__ || SearchFilterComponent)(); };
166
+ static ɵcmp = /*@__PURE__*/ i0.ɵɵdefineComponent({ type: SearchFilterComponent, selectors: [["mj-search-filter"]], inputs: { Filters: "Filters", ActiveFilters: "ActiveFilters", Collapsible: "Collapsible" }, outputs: { FilterChanged: "FilterChanged", FiltersCleared: "FiltersCleared" }, standalone: false, decls: 9, vars: 2, consts: [[1, "filter-panel"], [1, "filter-panel-header"], [1, "filter-panel-title"], [1, "fa-solid", "fa-filter"], [1, "filter-clear-all"], [1, "filter-category"], [1, "filter-empty"], [1, "filter-clear-all", 3, "click"], [1, "filter-category-header", 3, "click"], [1, "filter-category-name"], [1, "fa-solid", "filter-category-chevron", 3, "fa-chevron-down", "fa-chevron-up"], [1, "filter-options"], [1, "fa-solid", "filter-category-chevron"], [1, "filter-option"], [1, "filter-option", 3, "click"], [1, "filter-checkbox"], [1, "fa-solid", "fa-check"], [3, "class"], [1, "filter-option-label"], [1, "filter-option-count"]], template: function SearchFilterComponent_Template(rf, ctx) { if (rf & 1) {
167
+ i0.ɵɵelementStart(0, "div", 0)(1, "div", 1)(2, "span", 2);
168
+ i0.ɵɵelement(3, "i", 3);
169
+ i0.ɵɵtext(4, " Filters ");
170
+ i0.ɵɵelementEnd();
171
+ i0.ɵɵconditionalCreate(5, SearchFilterComponent_Conditional_5_Template, 2, 1, "button", 4);
172
+ i0.ɵɵelementEnd();
173
+ i0.ɵɵrepeaterCreate(6, SearchFilterComponent_For_7_Template, 6, 5, "div", 5, _forTrack0);
174
+ i0.ɵɵconditionalCreate(8, SearchFilterComponent_Conditional_8_Template, 3, 0, "div", 6);
175
+ i0.ɵɵelementEnd();
176
+ } if (rf & 2) {
177
+ i0.ɵɵadvance(5);
178
+ i0.ɵɵconditional(ctx.HasActiveFilters() ? 5 : -1);
179
+ i0.ɵɵadvance();
180
+ i0.ɵɵrepeater(ctx.Filters);
181
+ i0.ɵɵadvance(2);
182
+ i0.ɵɵconditional(ctx.Filters.length === 0 ? 8 : -1);
183
+ } }, styles: ["\n\n\n.filter-panel[_ngcontent-%COMP%] {\n border: 1px solid var(--mj-border-default);\n border-radius: 8px;\n background: var(--mj-bg-surface);\n overflow: hidden;\n}\n\n.filter-panel-header[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n justify-content: space-between;\n padding: 0.75rem 1rem;\n border-bottom: 1px solid var(--mj-border-subtle);\n}\n\n.filter-panel-title[_ngcontent-%COMP%] {\n font-weight: 600;\n font-size: 0.85rem;\n color: var(--mj-text-primary);\n display: flex;\n align-items: center;\n gap: 0.5rem;\n}\n\n.filter-clear-all[_ngcontent-%COMP%] {\n border: none;\n background: none;\n color: var(--mj-brand-primary);\n font-size: 0.78rem;\n cursor: pointer;\n padding: 0.15rem 0.4rem;\n border-radius: 4px;\n}\n\n.filter-clear-all[_ngcontent-%COMP%]:hover {\n background: color-mix(in srgb, var(--mj-brand-primary) 10%, var(--mj-bg-surface));\n}\n\n\n\n.filter-category[_ngcontent-%COMP%] {\n border-bottom: 1px solid var(--mj-border-subtle);\n}\n\n.filter-category[_ngcontent-%COMP%]:last-child {\n border-bottom: none;\n}\n\n.filter-category-header[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n justify-content: space-between;\n padding: 0.6rem 1rem;\n cursor: pointer;\n transition: background 0.1s ease;\n}\n\n.filter-category-header[_ngcontent-%COMP%]:hover {\n background: var(--mj-bg-surface-hover);\n}\n\n.filter-category-name[_ngcontent-%COMP%] {\n font-weight: 500;\n font-size: 0.82rem;\n color: var(--mj-text-primary);\n}\n\n.filter-category-chevron[_ngcontent-%COMP%] {\n font-size: 0.65rem;\n color: var(--mj-text-muted);\n}\n\n\n\n.filter-options[_ngcontent-%COMP%] {\n padding: 0.25rem 0;\n}\n\n.filter-option[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: 0.5rem;\n padding: 0.4rem 1rem;\n cursor: pointer;\n transition: background 0.1s ease;\n font-size: 0.82rem;\n}\n\n.filter-option[_ngcontent-%COMP%]:hover {\n background: var(--mj-bg-surface-hover);\n}\n\n.filter-checkbox[_ngcontent-%COMP%] {\n width: 1rem;\n height: 1rem;\n border: 1.5px solid var(--mj-border-strong);\n border-radius: 3px;\n display: flex;\n align-items: center;\n justify-content: center;\n flex-shrink: 0;\n font-size: 0.6rem;\n transition: all 0.15s ease;\n}\n\n.filter-checkbox-checked[_ngcontent-%COMP%] {\n background: var(--mj-brand-primary);\n border-color: var(--mj-brand-primary);\n color: var(--mj-text-inverse);\n}\n\n.filter-option-icon[_ngcontent-%COMP%] {\n color: var(--mj-text-muted);\n font-size: 0.78rem;\n width: 1rem;\n text-align: center;\n}\n\n.filter-option-label[_ngcontent-%COMP%] {\n flex: 1;\n color: var(--mj-text-secondary);\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n}\n\n.filter-option-count[_ngcontent-%COMP%] {\n color: var(--mj-text-muted);\n font-size: 0.72rem;\n flex-shrink: 0;\n}\n\n\n\n.filter-empty[_ngcontent-%COMP%] {\n padding: 1.5rem 1rem;\n text-align: center;\n color: var(--mj-text-muted);\n font-size: 0.82rem;\n}"] });
184
+ }
185
+ (() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassMetadata(SearchFilterComponent, [{
186
+ type: Component,
187
+ args: [{ standalone: false, selector: 'mj-search-filter', template: "<div class=\"filter-panel\">\n <div class=\"filter-panel-header\">\n <span class=\"filter-panel-title\">\n <i class=\"fa-solid fa-filter\"></i> Filters\n </span>\n @if (HasActiveFilters()) {\n <button class=\"filter-clear-all\" (click)=\"ClearAll()\">\n Clear ({{ GetActiveFilterCount() }})\n </button>\n }\n </div>\n\n @for (filter of Filters; track filter.Category) {\n <div class=\"filter-category\">\n <div\n class=\"filter-category-header\"\n (click)=\"ToggleCategory(filter.Category)\"\n [class.filter-category-collapsed]=\"IsCategoryCollapsed(filter.Category)\"\n >\n <span class=\"filter-category-name\">{{ filter.Category }}</span>\n @if (Collapsible) {\n <i class=\"fa-solid filter-category-chevron\"\n [class.fa-chevron-down]=\"IsCategoryCollapsed(filter.Category)\"\n [class.fa-chevron-up]=\"!IsCategoryCollapsed(filter.Category)\"></i>\n }\n </div>\n\n @if (!IsCategoryCollapsed(filter.Category)) {\n <div class=\"filter-options\">\n @for (option of filter.Options; track option.Value) {\n <label class=\"filter-option\" (click)=\"ToggleOption(filter.Category, option.Value); $event.preventDefault()\">\n <span class=\"filter-checkbox\" [class.filter-checkbox-checked]=\"IsOptionSelected(filter.Category, option.Value)\">\n @if (IsOptionSelected(filter.Category, option.Value)) {\n <i class=\"fa-solid fa-check\"></i>\n }\n </span>\n @if (option.Icon) {\n <i [class]=\"option.Icon + ' filter-option-icon'\"></i>\n }\n <span class=\"filter-option-label\">{{ option.Label }}</span>\n <span class=\"filter-option-count\">{{ option.Count }}</span>\n </label>\n }\n </div>\n }\n </div>\n }\n\n @if (Filters.length === 0) {\n <div class=\"filter-empty\">\n <p>No filters available</p>\n </div>\n }\n</div>\n", styles: ["/* Search Filter Panel */\n\n.filter-panel {\n border: 1px solid var(--mj-border-default);\n border-radius: 8px;\n background: var(--mj-bg-surface);\n overflow: hidden;\n}\n\n.filter-panel-header {\n display: flex;\n align-items: center;\n justify-content: space-between;\n padding: 0.75rem 1rem;\n border-bottom: 1px solid var(--mj-border-subtle);\n}\n\n.filter-panel-title {\n font-weight: 600;\n font-size: 0.85rem;\n color: var(--mj-text-primary);\n display: flex;\n align-items: center;\n gap: 0.5rem;\n}\n\n.filter-clear-all {\n border: none;\n background: none;\n color: var(--mj-brand-primary);\n font-size: 0.78rem;\n cursor: pointer;\n padding: 0.15rem 0.4rem;\n border-radius: 4px;\n}\n\n.filter-clear-all:hover {\n background: color-mix(in srgb, var(--mj-brand-primary) 10%, var(--mj-bg-surface));\n}\n\n/* Category */\n.filter-category {\n border-bottom: 1px solid var(--mj-border-subtle);\n}\n\n.filter-category:last-child {\n border-bottom: none;\n}\n\n.filter-category-header {\n display: flex;\n align-items: center;\n justify-content: space-between;\n padding: 0.6rem 1rem;\n cursor: pointer;\n transition: background 0.1s ease;\n}\n\n.filter-category-header:hover {\n background: var(--mj-bg-surface-hover);\n}\n\n.filter-category-name {\n font-weight: 500;\n font-size: 0.82rem;\n color: var(--mj-text-primary);\n}\n\n.filter-category-chevron {\n font-size: 0.65rem;\n color: var(--mj-text-muted);\n}\n\n/* Options */\n.filter-options {\n padding: 0.25rem 0;\n}\n\n.filter-option {\n display: flex;\n align-items: center;\n gap: 0.5rem;\n padding: 0.4rem 1rem;\n cursor: pointer;\n transition: background 0.1s ease;\n font-size: 0.82rem;\n}\n\n.filter-option:hover {\n background: var(--mj-bg-surface-hover);\n}\n\n.filter-checkbox {\n width: 1rem;\n height: 1rem;\n border: 1.5px solid var(--mj-border-strong);\n border-radius: 3px;\n display: flex;\n align-items: center;\n justify-content: center;\n flex-shrink: 0;\n font-size: 0.6rem;\n transition: all 0.15s ease;\n}\n\n.filter-checkbox-checked {\n background: var(--mj-brand-primary);\n border-color: var(--mj-brand-primary);\n color: var(--mj-text-inverse);\n}\n\n.filter-option-icon {\n color: var(--mj-text-muted);\n font-size: 0.78rem;\n width: 1rem;\n text-align: center;\n}\n\n.filter-option-label {\n flex: 1;\n color: var(--mj-text-secondary);\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n}\n\n.filter-option-count {\n color: var(--mj-text-muted);\n font-size: 0.72rem;\n flex-shrink: 0;\n}\n\n/* Empty state */\n.filter-empty {\n padding: 1.5rem 1rem;\n text-align: center;\n color: var(--mj-text-muted);\n font-size: 0.82rem;\n}\n"] }]
188
+ }], null, { Filters: [{
189
+ type: Input
190
+ }], ActiveFilters: [{
191
+ type: Input
192
+ }], Collapsible: [{
193
+ type: Input
194
+ }], FilterChanged: [{
195
+ type: Output
196
+ }], FiltersCleared: [{
197
+ type: Output
198
+ }] }); })();
199
+ (() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassDebugInfo(SearchFilterComponent, { className: "SearchFilterComponent", filePath: "src/lib/search-filter.component.ts", lineNumber: 24 }); })();
200
+ //# sourceMappingURL=search-filter.component.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"search-filter.component.js","sourceRoot":"","sources":["../../src/lib/search-filter.component.ts","../../src/lib/search-filter.component.html"],"names":[],"mappings":"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","sourcesContent":["/**\n * @fileoverview Search Filter Component\n *\n * Faceted filter sidebar for narrowing search results.\n * Displays filter categories with checkable options and counts.\n */\n\nimport {\n Component,\n EventEmitter,\n Input,\n Output,\n ChangeDetectorRef,\n inject\n} from '@angular/core';\nimport { SearchFilter, SearchFilterChangeEvent } from './search-types';\n\n@Component({\n standalone: false,\n selector: 'mj-search-filter',\n templateUrl: './search-filter.component.html',\n styleUrls: ['./search-filter.component.css']\n})\nexport class SearchFilterComponent {\n private cdr = inject(ChangeDetectorRef);\n\n /** Available filters to display */\n @Input() Filters: SearchFilter[] = [];\n\n /** Currently active filter selections */\n @Input() ActiveFilters: Record<string, string[]> = {};\n\n /** Whether the filter panel is collapsible */\n @Input() Collapsible = true;\n\n @Output() FilterChanged = new EventEmitter<SearchFilterChangeEvent>();\n @Output() FiltersCleared = new EventEmitter<void>();\n\n /** Collapsed state per category */\n public CollapsedCategories = new Set<string>();\n\n /** Toggle a filter option */\n public ToggleOption(category: string, value: string): void {\n const current = this.ActiveFilters[category] ? [...this.ActiveFilters[category]] : [];\n const index = current.indexOf(value);\n if (index >= 0) {\n current.splice(index, 1);\n } else {\n current.push(value);\n }\n // Update local state to reflect change\n this.ActiveFilters = { ...this.ActiveFilters, [category]: current };\n this.FilterChanged.emit({ Category: category, SelectedValues: current });\n this.cdr.detectChanges();\n }\n\n /** Toggle category collapse */\n public ToggleCategory(category: string): void {\n if (!this.Collapsible) return;\n if (this.CollapsedCategories.has(category)) {\n this.CollapsedCategories.delete(category);\n } else {\n this.CollapsedCategories.add(category);\n }\n this.cdr.detectChanges();\n }\n\n /** Check if a category is collapsed */\n public IsCategoryCollapsed(category: string): boolean {\n return this.CollapsedCategories.has(category);\n }\n\n /** Check if an option is selected */\n public IsOptionSelected(category: string, value: string): boolean {\n return (this.ActiveFilters[category] ?? []).includes(value);\n }\n\n /** Check if any filters are active */\n public HasActiveFilters(): boolean {\n return Object.values(this.ActiveFilters).some(v => v.length > 0);\n }\n\n /** Get total active filter count */\n public GetActiveFilterCount(): number {\n return Object.values(this.ActiveFilters).reduce((sum, v) => sum + v.length, 0);\n }\n\n /** Clear all filters */\n public ClearAll(): void {\n this.ActiveFilters = {};\n this.FiltersCleared.emit();\n this.cdr.detectChanges();\n }\n}\n","<div class=\"filter-panel\">\n <div class=\"filter-panel-header\">\n <span class=\"filter-panel-title\">\n <i class=\"fa-solid fa-filter\"></i> Filters\n </span>\n @if (HasActiveFilters()) {\n <button class=\"filter-clear-all\" (click)=\"ClearAll()\">\n Clear ({{ GetActiveFilterCount() }})\n </button>\n }\n </div>\n\n @for (filter of Filters; track filter.Category) {\n <div class=\"filter-category\">\n <div\n class=\"filter-category-header\"\n (click)=\"ToggleCategory(filter.Category)\"\n [class.filter-category-collapsed]=\"IsCategoryCollapsed(filter.Category)\"\n >\n <span class=\"filter-category-name\">{{ filter.Category }}</span>\n @if (Collapsible) {\n <i class=\"fa-solid filter-category-chevron\"\n [class.fa-chevron-down]=\"IsCategoryCollapsed(filter.Category)\"\n [class.fa-chevron-up]=\"!IsCategoryCollapsed(filter.Category)\"></i>\n }\n </div>\n\n @if (!IsCategoryCollapsed(filter.Category)) {\n <div class=\"filter-options\">\n @for (option of filter.Options; track option.Value) {\n <label class=\"filter-option\" (click)=\"ToggleOption(filter.Category, option.Value); $event.preventDefault()\">\n <span class=\"filter-checkbox\" [class.filter-checkbox-checked]=\"IsOptionSelected(filter.Category, option.Value)\">\n @if (IsOptionSelected(filter.Category, option.Value)) {\n <i class=\"fa-solid fa-check\"></i>\n }\n </span>\n @if (option.Icon) {\n <i [class]=\"option.Icon + ' filter-option-icon'\"></i>\n }\n <span class=\"filter-option-label\">{{ option.Label }}</span>\n <span class=\"filter-option-count\">{{ option.Count }}</span>\n </label>\n }\n </div>\n }\n </div>\n }\n\n @if (Filters.length === 0) {\n <div class=\"filter-empty\">\n <p>No filters available</p>\n </div>\n }\n</div>\n"]}
@@ -0,0 +1,103 @@
1
+ /**
2
+ * @fileoverview Search Overlay Component
3
+ *
4
+ * A floating search overlay inspired by command palette / Spotlight style.
5
+ * Triggered by Cmd+K (Mac) or Ctrl+K (Windows), appears as a centered
6
+ * floating panel with backdrop blur, search input, and grouped results.
7
+ *
8
+ * Supports keyboard navigation (up/down/enter/escape), filter facets,
9
+ * and responsive mobile layout.
10
+ */
11
+ import { EventEmitter, OnDestroy, OnInit, ElementRef } from '@angular/core';
12
+ import { SearchService } from './search.service';
13
+ import { SearchResultItem, SearchResultGroup, SearchFilter, SearchResultSelectedEvent, SearchFilterChangeEvent, SearchExecutedEvent } from './search-types';
14
+ import * as i0 from "@angular/core";
15
+ export declare class SearchOverlayComponent implements OnInit, OnDestroy {
16
+ private cdr;
17
+ protected searchService: SearchService;
18
+ private destroy$;
19
+ private searchInput$;
20
+ searchInputRef: ElementRef<HTMLInputElement>;
21
+ /** Placeholder text for the search input */
22
+ Placeholder: string;
23
+ /** Maximum number of results to fetch */
24
+ MaxResults: number;
25
+ /** Whether the overlay is currently visible */
26
+ private _IsOpen;
27
+ set IsOpen(value: boolean);
28
+ get IsOpen(): boolean;
29
+ /** Debounce time in ms before search fires */
30
+ DebounceMs: number;
31
+ /** Which search sources to include */
32
+ IncludeSources: ('vector' | 'fulltext' | 'entity')[];
33
+ /** Whether to show filter facets */
34
+ ShowFilters: boolean;
35
+ /** Text for the agent CTA button */
36
+ AgentCtaText: string;
37
+ /** Whether to show the agent CTA */
38
+ ShowAgentCta: boolean;
39
+ IsOpenChange: EventEmitter<boolean>;
40
+ ResultSelected: EventEmitter<SearchResultSelectedEvent>;
41
+ FilterChanged: EventEmitter<SearchFilterChangeEvent>;
42
+ SearchExecuted: EventEmitter<SearchExecutedEvent>;
43
+ AgentCtaClicked: EventEmitter<string>;
44
+ Query: string;
45
+ IsSearching: boolean;
46
+ ResultGroups: SearchResultGroup[];
47
+ AllResults: SearchResultItem[];
48
+ Filters: SearchFilter[];
49
+ ActiveFilters: Record<string, string[]>;
50
+ TotalCount: number;
51
+ ElapsedMs: number;
52
+ HighlightedIndex: number;
53
+ HasSearched: boolean;
54
+ /** All results flattened for keyboard navigation */
55
+ get FlatResults(): SearchResultItem[];
56
+ ngOnInit(): void;
57
+ ngOnDestroy(): void;
58
+ HandleGlobalKeydown(event: KeyboardEvent): void;
59
+ /** Toggle the overlay open/closed */
60
+ ToggleOverlay(): void;
61
+ /** Open the overlay */
62
+ Open(): void;
63
+ /** Close the overlay */
64
+ Close(): void;
65
+ /** Handle query input changes */
66
+ OnQueryInput(value: string): void;
67
+ /** Handle clicking a result */
68
+ OnResultClick(result: SearchResultItem, event: MouseEvent): void;
69
+ /** Handle selecting the highlighted result */
70
+ SelectHighlighted(): void;
71
+ /** Handle filter option toggle */
72
+ OnFilterToggle(category: string, value: string): void;
73
+ /** Clear all active filters */
74
+ ClearAllFilters(): void;
75
+ /** Handle clicking the agent CTA */
76
+ OnAgentCtaClick(): void;
77
+ /** Handle clicking the backdrop to close */
78
+ OnBackdropClick(): void;
79
+ /** Check if a filter option is active */
80
+ IsFilterActive(category: string, value: string): boolean;
81
+ /** Get a score display value (percentage) */
82
+ FormatScore(score: number): string;
83
+ /** Format elapsed time display */
84
+ FormatElapsedTime(ms: number): string;
85
+ private isToggleShortcut;
86
+ private handleOverlayKeydown;
87
+ private moveHighlight;
88
+ private setupSearchDebounce;
89
+ private subscribeToSearchState;
90
+ private executeSearch;
91
+ private clearResults;
92
+ private onOverlayOpened;
93
+ private onOverlayClosed;
94
+ /** Check if any filters are active (used by template) */
95
+ hasActiveFilters(): boolean;
96
+ /** Check if a result is currently keyboard-highlighted */
97
+ isResultHighlighted(result: SearchResultItem): boolean;
98
+ /** Get the flat index of a result for keyboard navigation */
99
+ getFlatIndex(result: SearchResultItem): number;
100
+ static ɵfac: i0.ɵɵFactoryDeclaration<SearchOverlayComponent, never>;
101
+ static ɵcmp: i0.ɵɵComponentDeclaration<SearchOverlayComponent, "mj-search-overlay", never, { "Placeholder": { "alias": "Placeholder"; "required": false; }; "MaxResults": { "alias": "MaxResults"; "required": false; }; "IsOpen": { "alias": "IsOpen"; "required": false; }; "DebounceMs": { "alias": "DebounceMs"; "required": false; }; "IncludeSources": { "alias": "IncludeSources"; "required": false; }; "ShowFilters": { "alias": "ShowFilters"; "required": false; }; "AgentCtaText": { "alias": "AgentCtaText"; "required": false; }; "ShowAgentCta": { "alias": "ShowAgentCta"; "required": false; }; }, { "IsOpenChange": "IsOpenChange"; "ResultSelected": "ResultSelected"; "FilterChanged": "FilterChanged"; "SearchExecuted": "SearchExecuted"; "AgentCtaClicked": "AgentCtaClicked"; }, never, never, false, never>;
102
+ }
103
+ //# sourceMappingURL=search-overlay.component.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"search-overlay.component.d.ts","sourceRoot":"","sources":["../../src/lib/search-overlay.component.ts"],"names":[],"mappings":"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"}