@memberjunction/ng-explorer-core 5.46.0 → 5.48.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 (69) hide show
  1. package/dist/generated/lazy-feature-config.js +126 -126
  2. package/dist/generated/lazy-feature-config.js.map +1 -1
  3. package/dist/lib/omnibar/index.d.ts +15 -0
  4. package/dist/lib/omnibar/index.d.ts.map +1 -0
  5. package/dist/lib/omnibar/index.js +24 -0
  6. package/dist/lib/omnibar/index.js.map +1 -0
  7. package/dist/lib/omnibar/omnibar-palette.component.d.ts +130 -0
  8. package/dist/lib/omnibar/omnibar-palette.component.d.ts.map +1 -0
  9. package/dist/lib/omnibar/omnibar-palette.component.js +829 -0
  10. package/dist/lib/omnibar/omnibar-palette.component.js.map +1 -0
  11. package/dist/lib/omnibar/omnibar-provider.d.ts +94 -0
  12. package/dist/lib/omnibar/omnibar-provider.d.ts.map +1 -0
  13. package/dist/lib/omnibar/omnibar-provider.js +84 -0
  14. package/dist/lib/omnibar/omnibar-provider.js.map +1 -0
  15. package/dist/lib/omnibar/omnibar-shortcut.d.ts +12 -0
  16. package/dist/lib/omnibar/omnibar-shortcut.d.ts.map +1 -0
  17. package/dist/lib/omnibar/omnibar-shortcut.js +16 -0
  18. package/dist/lib/omnibar/omnibar-shortcut.js.map +1 -0
  19. package/dist/lib/omnibar/omnibar-user-setting.d.ts +38 -0
  20. package/dist/lib/omnibar/omnibar-user-setting.d.ts.map +1 -0
  21. package/dist/lib/omnibar/omnibar-user-setting.js +53 -0
  22. package/dist/lib/omnibar/omnibar-user-setting.js.map +1 -0
  23. package/dist/lib/omnibar/providers/omnibar-agent.provider.d.ts +24 -0
  24. package/dist/lib/omnibar/providers/omnibar-agent.provider.d.ts.map +1 -0
  25. package/dist/lib/omnibar/providers/omnibar-agent.provider.js +69 -0
  26. package/dist/lib/omnibar/providers/omnibar-agent.provider.js.map +1 -0
  27. package/dist/lib/omnibar/providers/omnibar-command.provider.d.ts +29 -0
  28. package/dist/lib/omnibar/providers/omnibar-command.provider.d.ts.map +1 -0
  29. package/dist/lib/omnibar/providers/omnibar-command.provider.js +130 -0
  30. package/dist/lib/omnibar/providers/omnibar-command.provider.js.map +1 -0
  31. package/dist/lib/omnibar/providers/omnibar-record.provider.d.ts +35 -0
  32. package/dist/lib/omnibar/providers/omnibar-record.provider.d.ts.map +1 -0
  33. package/dist/lib/omnibar/providers/omnibar-record.provider.js +176 -0
  34. package/dist/lib/omnibar/providers/omnibar-record.provider.js.map +1 -0
  35. package/dist/lib/omnibar/providers/omnibar-search.provider.d.ts +21 -0
  36. package/dist/lib/omnibar/providers/omnibar-search.provider.d.ts.map +1 -0
  37. package/dist/lib/omnibar/providers/omnibar-search.provider.js +94 -0
  38. package/dist/lib/omnibar/providers/omnibar-search.provider.js.map +1 -0
  39. package/dist/lib/profile/profile-dialog.component.d.ts +12 -0
  40. package/dist/lib/profile/profile-dialog.component.d.ts.map +1 -1
  41. package/dist/lib/profile/profile-dialog.component.js +189 -78
  42. package/dist/lib/profile/profile-dialog.component.js.map +1 -1
  43. package/dist/lib/resource-wrappers/chat-conversations-resource.component.d.ts +16 -0
  44. package/dist/lib/resource-wrappers/chat-conversations-resource.component.d.ts.map +1 -1
  45. package/dist/lib/resource-wrappers/chat-conversations-resource.component.js +66 -6
  46. package/dist/lib/resource-wrappers/chat-conversations-resource.component.js.map +1 -1
  47. package/dist/lib/resource-wrappers/view-resource.component.d.ts.map +1 -1
  48. package/dist/lib/resource-wrappers/view-resource.component.js +6 -2
  49. package/dist/lib/resource-wrappers/view-resource.component.js.map +1 -1
  50. package/dist/lib/shell/components/tabs/tab-container.component.d.ts +7 -0
  51. package/dist/lib/shell/components/tabs/tab-container.component.d.ts.map +1 -1
  52. package/dist/lib/shell/components/tabs/tab-container.component.js +26 -4
  53. package/dist/lib/shell/components/tabs/tab-container.component.js.map +1 -1
  54. package/dist/lib/shell/shell.component.d.ts +62 -2
  55. package/dist/lib/shell/shell.component.d.ts.map +1 -1
  56. package/dist/lib/shell/shell.component.js +341 -162
  57. package/dist/lib/shell/shell.component.js.map +1 -1
  58. package/dist/lib/shell/shell.module.d.ts +8 -7
  59. package/dist/lib/shell/shell.module.d.ts.map +1 -1
  60. package/dist/lib/shell/shell.module.js +5 -2
  61. package/dist/lib/shell/shell.module.js.map +1 -1
  62. package/dist/lib/single-list-detail/single-list-detail.component.d.ts.map +1 -1
  63. package/dist/lib/single-list-detail/single-list-detail.component.js +29 -20
  64. package/dist/lib/single-list-detail/single-list-detail.component.js.map +1 -1
  65. package/dist/public-api.d.ts +1 -0
  66. package/dist/public-api.d.ts.map +1 -1
  67. package/dist/public-api.js +2 -0
  68. package/dist/public-api.js.map +1 -1
  69. package/package.json +49 -49
@@ -0,0 +1,829 @@
1
+ import { ChangeDetectionStrategy, ChangeDetectorRef, Component, ElementRef, EventEmitter, Output, ViewChild, inject, } from '@angular/core';
2
+ import { CompositeKey } from '@memberjunction/core';
3
+ import { Metadata } from '@memberjunction/core';
4
+ import { NavigationService } from '@memberjunction/ng-shared';
5
+ import { ApplicationManager } from '@memberjunction/ng-base-application';
6
+ import { SearchService } from '@memberjunction/ng-search';
7
+ import { FileOpenService } from '@memberjunction/ng-file-storage';
8
+ import { firstValueFrom, skip } from 'rxjs';
9
+ import { CommandPaletteService } from '../command-palette/command-palette.service';
10
+ import { DiscoverOmnibarProviders, GetOmnibarNavPayload, } from './omnibar-provider';
11
+ import { LoadOmnibarProviders } from './index';
12
+ import * as i0 from "@angular/core";
13
+ import * as i1 from "@angular/forms";
14
+ const _c0 = ["paletteInput"];
15
+ const _forTrack0 = ($index, $item) => $item.ID;
16
+ const _forTrack1 = ($index, $item) => $item.Char;
17
+ const _forTrack2 = ($index, $item) => $item.Suggestion.id;
18
+ function OmnibarPaletteComponent_Conditional_0_Conditional_4_Template(rf, ctx) { if (rf & 1) {
19
+ i0.ɵɵelementStart(0, "b");
20
+ i0.ɵɵtext(1);
21
+ i0.ɵɵelementEnd();
22
+ } if (rf & 2) {
23
+ const ctx_r1 = i0.ɵɵnextContext(2);
24
+ i0.ɵɵadvance();
25
+ i0.ɵɵtextInterpolate(ctx_r1.ActiveTriggerChar);
26
+ } }
27
+ function OmnibarPaletteComponent_Conditional_0_Conditional_5_Template(rf, ctx) { if (rf & 1) {
28
+ i0.ɵɵelement(0, "i", 5);
29
+ } }
30
+ function OmnibarPaletteComponent_Conditional_0_Conditional_14_For_4_Template(rf, ctx) { if (rf & 1) {
31
+ const _r4 = i0.ɵɵgetCurrentView();
32
+ i0.ɵɵelementStart(0, "button", 20);
33
+ i0.ɵɵlistener("click", function OmnibarPaletteComponent_Conditional_0_Conditional_14_For_4_Template_button_click_0_listener() { const scope_r5 = i0.ɵɵrestoreView(_r4).$implicit; const ctx_r1 = i0.ɵɵnextContext(3); return i0.ɵɵresetView(ctx_r1.ToggleScope(scope_r5.ID)); });
34
+ i0.ɵɵtext(1);
35
+ i0.ɵɵelementEnd();
36
+ } if (rf & 2) {
37
+ const scope_r5 = ctx.$implicit;
38
+ const ctx_r1 = i0.ɵɵnextContext(3);
39
+ i0.ɵɵclassProp("ob-scope--on", ctx_r1.IsScopeSelected(scope_r5.ID));
40
+ i0.ɵɵadvance();
41
+ i0.ɵɵtextInterpolate(scope_r5.Name);
42
+ } }
43
+ function OmnibarPaletteComponent_Conditional_0_Conditional_14_Template(rf, ctx) { if (rf & 1) {
44
+ const _r3 = i0.ɵɵgetCurrentView();
45
+ i0.ɵɵelementStart(0, "div", 11)(1, "button", 20);
46
+ i0.ɵɵlistener("click", function OmnibarPaletteComponent_Conditional_0_Conditional_14_Template_button_click_1_listener() { i0.ɵɵrestoreView(_r3); const ctx_r1 = i0.ɵɵnextContext(2); return i0.ɵɵresetView(ctx_r1.ClearScopes()); });
47
+ i0.ɵɵtext(2, "All sources");
48
+ i0.ɵɵelementEnd();
49
+ i0.ɵɵrepeaterCreate(3, OmnibarPaletteComponent_Conditional_0_Conditional_14_For_4_Template, 2, 3, "button", 21, _forTrack0);
50
+ i0.ɵɵelementEnd();
51
+ } if (rf & 2) {
52
+ const ctx_r1 = i0.ɵɵnextContext(2);
53
+ i0.ɵɵadvance();
54
+ i0.ɵɵclassProp("ob-scope--on", ctx_r1.SelectedScopeIDs.length === 0);
55
+ i0.ɵɵadvance(2);
56
+ i0.ɵɵrepeater(ctx_r1.Scopes);
57
+ } }
58
+ function OmnibarPaletteComponent_Conditional_0_Conditional_16_Template(rf, ctx) { if (rf & 1) {
59
+ i0.ɵɵelementStart(0, "div", 13);
60
+ i0.ɵɵelement(1, "i", 22);
61
+ i0.ɵɵtext(2, " Searching\u2026");
62
+ i0.ɵɵelementEnd();
63
+ } }
64
+ function OmnibarPaletteComponent_Conditional_0_Conditional_17_For_2_Template(rf, ctx) { if (rf & 1) {
65
+ const _r6 = i0.ɵɵgetCurrentView();
66
+ i0.ɵɵelementStart(0, "button", 25);
67
+ i0.ɵɵlistener("click", function OmnibarPaletteComponent_Conditional_0_Conditional_17_For_2_Template_button_click_0_listener() { const hint_r7 = i0.ɵɵrestoreView(_r6).$implicit; const ctx_r1 = i0.ɵɵnextContext(3); return i0.ɵɵresetView(ctx_r1.SeedTrigger(hint_r7.Char)); });
68
+ i0.ɵɵelementStart(1, "b");
69
+ i0.ɵɵtext(2);
70
+ i0.ɵɵelementEnd();
71
+ i0.ɵɵelementStart(3, "span");
72
+ i0.ɵɵtext(4);
73
+ i0.ɵɵelementEnd()();
74
+ } if (rf & 2) {
75
+ const hint_r7 = ctx.$implicit;
76
+ i0.ɵɵadvance(2);
77
+ i0.ɵɵtextInterpolate(hint_r7.Char);
78
+ i0.ɵɵadvance(2);
79
+ i0.ɵɵtextInterpolate(hint_r7.Label);
80
+ } }
81
+ function OmnibarPaletteComponent_Conditional_0_Conditional_17_Conditional_3_For_4_Template(rf, ctx) { if (rf & 1) {
82
+ const _r8 = i0.ɵɵgetCurrentView();
83
+ i0.ɵɵelementStart(0, "div", 28);
84
+ i0.ɵɵlistener("focus", function OmnibarPaletteComponent_Conditional_0_Conditional_17_Conditional_3_For_4_Template_div_focus_0_listener() { const ɵ$index_65_r9 = i0.ɵɵrestoreView(_r8).$index; const ctx_r1 = i0.ɵɵnextContext(4); return i0.ɵɵresetView(ctx_r1.SelectedIndex = ctx_r1.RecentBaseIndex + ɵ$index_65_r9); })("keydown", function OmnibarPaletteComponent_Conditional_0_Conditional_17_Conditional_3_For_4_Template_div_keydown_0_listener($event) { const row_r10 = i0.ɵɵrestoreView(_r8).$implicit; const ctx_r1 = i0.ɵɵnextContext(4); return i0.ɵɵresetView(ctx_r1.OnRowKeydown($event, row_r10.Suggestion)); })("mouseenter", function OmnibarPaletteComponent_Conditional_0_Conditional_17_Conditional_3_For_4_Template_div_mouseenter_0_listener() { const ɵ$index_65_r9 = i0.ɵɵrestoreView(_r8).$index; const ctx_r1 = i0.ɵɵnextContext(4); return i0.ɵɵresetView(ctx_r1.SelectedIndex = ctx_r1.RecentBaseIndex + ɵ$index_65_r9); })("click", function OmnibarPaletteComponent_Conditional_0_Conditional_17_Conditional_3_For_4_Template_div_click_0_listener() { const row_r10 = i0.ɵɵrestoreView(_r8).$implicit; const ctx_r1 = i0.ɵɵnextContext(4); return i0.ɵɵresetView(ctx_r1.Execute(row_r10.Suggestion)); });
85
+ i0.ɵɵelementStart(1, "span", 29);
86
+ i0.ɵɵelement(2, "i");
87
+ i0.ɵɵelementEnd();
88
+ i0.ɵɵelementStart(3, "span", 30)(4, "span", 31);
89
+ i0.ɵɵtext(5);
90
+ i0.ɵɵelementEnd();
91
+ i0.ɵɵelementStart(6, "span", 32);
92
+ i0.ɵɵtext(7);
93
+ i0.ɵɵelementEnd()();
94
+ i0.ɵɵelementStart(8, "span", 33)(9, "span", 34);
95
+ i0.ɵɵtext(10);
96
+ i0.ɵɵelementEnd()()();
97
+ } if (rf & 2) {
98
+ const row_r10 = ctx.$implicit;
99
+ const ɵ$index_65_r9 = ctx.$index;
100
+ const ctx_r1 = i0.ɵɵnextContext(4);
101
+ i0.ɵɵclassProp("ob-row--sel", ctx_r1.RecentBaseIndex + ɵ$index_65_r9 === ctx_r1.SelectedIndex);
102
+ i0.ɵɵattribute("id", "ob-opt-" + (ctx_r1.RecentBaseIndex + ɵ$index_65_r9))("tabindex", ctx_r1.RecentBaseIndex + ɵ$index_65_r9 === ctx_r1.SelectedIndex ? 0 : -1)("aria-selected", ctx_r1.RecentBaseIndex + ɵ$index_65_r9 === ctx_r1.SelectedIndex);
103
+ i0.ɵɵadvance(2);
104
+ i0.ɵɵclassMap(row_r10.Suggestion.icon || "fa-solid fa-clock-rotate-left");
105
+ i0.ɵɵadvance(3);
106
+ i0.ɵɵtextInterpolate(row_r10.Suggestion.displayName);
107
+ i0.ɵɵadvance(2);
108
+ i0.ɵɵtextInterpolate(row_r10.Suggestion.description);
109
+ i0.ɵɵadvance(3);
110
+ i0.ɵɵtextInterpolate(row_r10.Suggestion.type);
111
+ } }
112
+ function OmnibarPaletteComponent_Conditional_0_Conditional_17_Conditional_3_Template(rf, ctx) { if (rf & 1) {
113
+ i0.ɵɵelementStart(0, "div", 26);
114
+ i0.ɵɵtext(1, "Recent");
115
+ i0.ɵɵelementEnd();
116
+ i0.ɵɵelementStart(2, "div", 15);
117
+ i0.ɵɵrepeaterCreate(3, OmnibarPaletteComponent_Conditional_0_Conditional_17_Conditional_3_For_4_Template, 11, 10, "div", 27, _forTrack2);
118
+ i0.ɵɵelementEnd();
119
+ } if (rf & 2) {
120
+ const ctx_r1 = i0.ɵɵnextContext(3);
121
+ i0.ɵɵadvance(3);
122
+ i0.ɵɵrepeater(ctx_r1.RecentRows);
123
+ } }
124
+ function OmnibarPaletteComponent_Conditional_0_Conditional_17_Template(rf, ctx) { if (rf & 1) {
125
+ i0.ɵɵelementStart(0, "div", 23);
126
+ i0.ɵɵrepeaterCreate(1, OmnibarPaletteComponent_Conditional_0_Conditional_17_For_2_Template, 5, 2, "button", 24, _forTrack1);
127
+ i0.ɵɵelementEnd();
128
+ i0.ɵɵconditionalCreate(3, OmnibarPaletteComponent_Conditional_0_Conditional_17_Conditional_3_Template, 5, 0);
129
+ } if (rf & 2) {
130
+ const ctx_r1 = i0.ɵɵnextContext(2);
131
+ i0.ɵɵadvance();
132
+ i0.ɵɵrepeater(ctx_r1.TriggerHints);
133
+ i0.ɵɵadvance(2);
134
+ i0.ɵɵconditional(ctx_r1.RecentRows.length > 0 ? 3 : -1);
135
+ } }
136
+ function OmnibarPaletteComponent_Conditional_0_Conditional_18_Template(rf, ctx) { if (rf & 1) {
137
+ i0.ɵɵelementStart(0, "div", 14);
138
+ i0.ɵɵtext(1, "No matches \u2014 press ");
139
+ i0.ɵɵelementStart(2, "kbd", 8);
140
+ i0.ɵɵtext(3, "\u21B5");
141
+ i0.ɵɵelementEnd();
142
+ i0.ɵɵtext(4);
143
+ i0.ɵɵelementEnd();
144
+ } if (rf & 2) {
145
+ const ctx_r1 = i0.ɵɵnextContext(2);
146
+ i0.ɵɵadvance(4);
147
+ i0.ɵɵtextInterpolate1(" to search everything for \u201C", ctx_r1.EffectiveQuery, "\u201D.");
148
+ } }
149
+ function OmnibarPaletteComponent_Conditional_0_Conditional_19_For_2_Conditional_0_Template(rf, ctx) { if (rf & 1) {
150
+ i0.ɵɵelementStart(0, "div", 26);
151
+ i0.ɵɵtext(1);
152
+ i0.ɵɵelementEnd();
153
+ } if (rf & 2) {
154
+ const row_r12 = i0.ɵɵnextContext().$implicit;
155
+ i0.ɵɵadvance();
156
+ i0.ɵɵtextInterpolate(row_r12.GroupLabel);
157
+ } }
158
+ function OmnibarPaletteComponent_Conditional_0_Conditional_19_For_2_Conditional_7_Template(rf, ctx) { if (rf & 1) {
159
+ i0.ɵɵelementStart(0, "span", 32);
160
+ i0.ɵɵtext(1);
161
+ i0.ɵɵelementEnd();
162
+ } if (rf & 2) {
163
+ const row_r12 = i0.ɵɵnextContext().$implicit;
164
+ i0.ɵɵadvance();
165
+ i0.ɵɵtextInterpolate(row_r12.Suggestion.description);
166
+ } }
167
+ function OmnibarPaletteComponent_Conditional_0_Conditional_19_For_2_Conditional_9_Template(rf, ctx) { if (rf & 1) {
168
+ i0.ɵɵelementStart(0, "span", 35);
169
+ i0.ɵɵelement(1, "i");
170
+ i0.ɵɵelementEnd();
171
+ } if (rf & 2) {
172
+ const row_r12 = i0.ɵɵnextContext().$implicit;
173
+ i0.ɵɵadvance();
174
+ i0.ɵɵstyleProp("width", row_r12.ScorePercent, "%");
175
+ } }
176
+ function OmnibarPaletteComponent_Conditional_0_Conditional_19_For_2_Template(rf, ctx) { if (rf & 1) {
177
+ const _r11 = i0.ɵɵgetCurrentView();
178
+ i0.ɵɵconditionalCreate(0, OmnibarPaletteComponent_Conditional_0_Conditional_19_For_2_Conditional_0_Template, 2, 1, "div", 26);
179
+ i0.ɵɵelementStart(1, "div", 28);
180
+ i0.ɵɵlistener("focus", function OmnibarPaletteComponent_Conditional_0_Conditional_19_For_2_Template_div_focus_1_listener() { const ɵ$index_96_r13 = i0.ɵɵrestoreView(_r11).$index; const ctx_r1 = i0.ɵɵnextContext(3); return i0.ɵɵresetView(ctx_r1.SelectedIndex = ɵ$index_96_r13); })("keydown", function OmnibarPaletteComponent_Conditional_0_Conditional_19_For_2_Template_div_keydown_1_listener($event) { const row_r12 = i0.ɵɵrestoreView(_r11).$implicit; const ctx_r1 = i0.ɵɵnextContext(3); return i0.ɵɵresetView(ctx_r1.OnRowKeydown($event, row_r12.Suggestion)); })("mouseenter", function OmnibarPaletteComponent_Conditional_0_Conditional_19_For_2_Template_div_mouseenter_1_listener() { const ɵ$index_96_r13 = i0.ɵɵrestoreView(_r11).$index; const ctx_r1 = i0.ɵɵnextContext(3); return i0.ɵɵresetView(ctx_r1.SelectedIndex = ɵ$index_96_r13); })("click", function OmnibarPaletteComponent_Conditional_0_Conditional_19_For_2_Template_div_click_1_listener() { const row_r12 = i0.ɵɵrestoreView(_r11).$implicit; const ctx_r1 = i0.ɵɵnextContext(3); return i0.ɵɵresetView(ctx_r1.Execute(row_r12.Suggestion)); });
181
+ i0.ɵɵelementStart(2, "span", 29);
182
+ i0.ɵɵelement(3, "i");
183
+ i0.ɵɵelementEnd();
184
+ i0.ɵɵelementStart(4, "span", 30)(5, "span", 31);
185
+ i0.ɵɵtext(6);
186
+ i0.ɵɵelementEnd();
187
+ i0.ɵɵconditionalCreate(7, OmnibarPaletteComponent_Conditional_0_Conditional_19_For_2_Conditional_7_Template, 2, 1, "span", 32);
188
+ i0.ɵɵelementEnd();
189
+ i0.ɵɵelementStart(8, "span", 33);
190
+ i0.ɵɵconditionalCreate(9, OmnibarPaletteComponent_Conditional_0_Conditional_19_For_2_Conditional_9_Template, 2, 2, "span", 35);
191
+ i0.ɵɵelementStart(10, "span", 34);
192
+ i0.ɵɵtext(11);
193
+ i0.ɵɵelementEnd();
194
+ i0.ɵɵelementStart(12, "span", 36);
195
+ i0.ɵɵtext(13, "open ");
196
+ i0.ɵɵelementStart(14, "kbd", 8);
197
+ i0.ɵɵtext(15, "\u21B5");
198
+ i0.ɵɵelementEnd()()()();
199
+ } if (rf & 2) {
200
+ const row_r12 = ctx.$implicit;
201
+ const ɵ$index_96_r13 = ctx.$index;
202
+ const ctx_r1 = i0.ɵɵnextContext(3);
203
+ i0.ɵɵconditional(row_r12.GroupLabel ? 0 : -1);
204
+ i0.ɵɵadvance();
205
+ i0.ɵɵclassProp("ob-row--sel", ɵ$index_96_r13 === ctx_r1.SelectedIndex);
206
+ i0.ɵɵattribute("id", "ob-opt-" + ɵ$index_96_r13)("tabindex", ɵ$index_96_r13 === ctx_r1.SelectedIndex ? 0 : -1)("aria-selected", ɵ$index_96_r13 === ctx_r1.SelectedIndex);
207
+ i0.ɵɵadvance(2);
208
+ i0.ɵɵclassMap(row_r12.Suggestion.icon || "fa-solid fa-circle");
209
+ i0.ɵɵadvance(3);
210
+ i0.ɵɵtextInterpolate(row_r12.Suggestion.displayName);
211
+ i0.ɵɵadvance();
212
+ i0.ɵɵconditional(row_r12.Suggestion.description ? 7 : -1);
213
+ i0.ɵɵadvance(2);
214
+ i0.ɵɵconditional(row_r12.ScorePercent != null ? 9 : -1);
215
+ i0.ɵɵadvance(2);
216
+ i0.ɵɵtextInterpolate(row_r12.Suggestion.type);
217
+ } }
218
+ function OmnibarPaletteComponent_Conditional_0_Conditional_19_Template(rf, ctx) { if (rf & 1) {
219
+ i0.ɵɵelementStart(0, "div", 15);
220
+ i0.ɵɵrepeaterCreate(1, OmnibarPaletteComponent_Conditional_0_Conditional_19_For_2_Template, 16, 12, null, null, _forTrack2);
221
+ i0.ɵɵelementEnd();
222
+ } if (rf & 2) {
223
+ const ctx_r1 = i0.ɵɵnextContext(2);
224
+ i0.ɵɵadvance();
225
+ i0.ɵɵrepeater(ctx_r1.Rows);
226
+ } }
227
+ function OmnibarPaletteComponent_Conditional_0_Template(rf, ctx) { if (rf & 1) {
228
+ const _r1 = i0.ɵɵgetCurrentView();
229
+ i0.ɵɵelementStart(0, "div", 1);
230
+ i0.ɵɵlistener("click", function OmnibarPaletteComponent_Conditional_0_Template_div_click_0_listener() { i0.ɵɵrestoreView(_r1); const ctx_r1 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r1.Close()); });
231
+ i0.ɵɵelementEnd();
232
+ i0.ɵɵelementStart(1, "div", 2);
233
+ i0.ɵɵlistener("keydown", function OmnibarPaletteComponent_Conditional_0_Template_div_keydown_1_listener($event) { i0.ɵɵrestoreView(_r1); const ctx_r1 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r1.OnPaletteKeydown($event)); });
234
+ i0.ɵɵelementStart(2, "div", 3)(3, "span", 4);
235
+ i0.ɵɵconditionalCreate(4, OmnibarPaletteComponent_Conditional_0_Conditional_4_Template, 2, 1, "b")(5, OmnibarPaletteComponent_Conditional_0_Conditional_5_Template, 1, 0, "i", 5);
236
+ i0.ɵɵelementEnd();
237
+ i0.ɵɵelementStart(6, "input", 6, 0);
238
+ i0.ɵɵlistener("ngModelChange", function OmnibarPaletteComponent_Conditional_0_Template_input_ngModelChange_6_listener($event) { i0.ɵɵrestoreView(_r1); const ctx_r1 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r1.OnQueryChange($event)); })("keydown", function OmnibarPaletteComponent_Conditional_0_Template_input_keydown_6_listener($event) { i0.ɵɵrestoreView(_r1); const ctx_r1 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r1.OnInputKeydown($event)); });
239
+ i0.ɵɵelementEnd();
240
+ i0.ɵɵelementStart(8, "span", 7);
241
+ i0.ɵɵtext(9);
242
+ i0.ɵɵelementEnd();
243
+ i0.ɵɵelementStart(10, "kbd", 8);
244
+ i0.ɵɵtext(11, "esc");
245
+ i0.ɵɵelementEnd();
246
+ i0.ɵɵelementStart(12, "button", 9);
247
+ i0.ɵɵlistener("click", function OmnibarPaletteComponent_Conditional_0_Template_button_click_12_listener() { i0.ɵɵrestoreView(_r1); const ctx_r1 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r1.Close()); });
248
+ i0.ɵɵelement(13, "i", 10);
249
+ i0.ɵɵelementEnd()();
250
+ i0.ɵɵconditionalCreate(14, OmnibarPaletteComponent_Conditional_0_Conditional_14_Template, 5, 2, "div", 11);
251
+ i0.ɵɵelementStart(15, "div", 12);
252
+ i0.ɵɵconditionalCreate(16, OmnibarPaletteComponent_Conditional_0_Conditional_16_Template, 3, 0, "div", 13)(17, OmnibarPaletteComponent_Conditional_0_Conditional_17_Template, 4, 1)(18, OmnibarPaletteComponent_Conditional_0_Conditional_18_Template, 5, 1, "div", 14)(19, OmnibarPaletteComponent_Conditional_0_Conditional_19_Template, 3, 0, "div", 15);
253
+ i0.ɵɵelementEnd();
254
+ i0.ɵɵelementStart(20, "div", 16)(21, "span", 17)(22, "kbd", 8);
255
+ i0.ɵɵtext(23, "\u2191");
256
+ i0.ɵɵelementEnd();
257
+ i0.ɵɵelementStart(24, "kbd", 8);
258
+ i0.ɵɵtext(25, "\u2193");
259
+ i0.ɵɵelementEnd();
260
+ i0.ɵɵtext(26, " navigate");
261
+ i0.ɵɵelementEnd();
262
+ i0.ɵɵelementStart(27, "span", 17)(28, "kbd", 8);
263
+ i0.ɵɵtext(29, "\u21B5");
264
+ i0.ɵɵelementEnd();
265
+ i0.ɵɵtext(30, " open");
266
+ i0.ɵɵelementEnd();
267
+ i0.ɵɵelementStart(31, "button", 18);
268
+ i0.ɵɵlistener("click", function OmnibarPaletteComponent_Conditional_0_Template_button_click_31_listener() { i0.ɵɵrestoreView(_r1); const ctx_r1 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r1.RequestSettings()); });
269
+ i0.ɵɵelement(32, "i", 19);
270
+ i0.ɵɵelementEnd()()();
271
+ } if (rf & 2) {
272
+ const ctx_r1 = i0.ɵɵnextContext();
273
+ i0.ɵɵadvance(3);
274
+ i0.ɵɵclassProp("ob-lead--trigger", ctx_r1.ActiveTriggerChar.length > 0);
275
+ i0.ɵɵadvance();
276
+ i0.ɵɵconditional(ctx_r1.ActiveTriggerChar.length > 0 ? 4 : 5);
277
+ i0.ɵɵadvance(2);
278
+ i0.ɵɵproperty("placeholder", ctx_r1.ActivePlaceholder)("ngModel", ctx_r1.Query);
279
+ i0.ɵɵattribute("aria-expanded", ctx_r1.HasOptions)("aria-activedescendant", ctx_r1.ActiveDescendantId);
280
+ i0.ɵɵadvance(3);
281
+ i0.ɵɵtextInterpolate(ctx_r1.ActiveModeLabel);
282
+ i0.ɵɵadvance(5);
283
+ i0.ɵɵconditional(ctx_r1.ShowScopes && ctx_r1.Scopes.length > 0 ? 14 : -1);
284
+ i0.ɵɵadvance(2);
285
+ i0.ɵɵconditional(ctx_r1.IsLoading ? 16 : ctx_r1.Rows.length === 0 && ctx_r1.Query.length === 0 ? 17 : ctx_r1.Rows.length === 0 ? 18 : 19);
286
+ } }
287
+ /** Debounce for the default (network-backed) search mode; trigger modes serve warm caches. */
288
+ const SEARCH_DEBOUNCE_MS = 300;
289
+ /** Max suggestions requested per keystroke. */
290
+ const MAX_RESULTS = 9;
291
+ /**
292
+ * The unified Explorer command palette (Ctrl/Cmd+K): one surface for global
293
+ * cross-source search (plain text), jump-to-record ('#'), commands & apps ('/'),
294
+ * and agents ('@') — every mode a pluggable {@link OmnibarProvider}, discovered via
295
+ * the MJ ClassFactory so OpenApps can add modes without touching this component.
296
+ *
297
+ * Design source of truth: plans/composer-adoption/mockups/omnibar-command-palette.html.
298
+ */
299
+ export class OmnibarPaletteComponent {
300
+ cdr = inject(ChangeDetectorRef);
301
+ host = inject(ElementRef);
302
+ navigation = inject(NavigationService);
303
+ appManager = inject(ApplicationManager);
304
+ search = inject(SearchService);
305
+ paletteService = inject(CommandPaletteService);
306
+ fileOpen = inject(FileOpenService);
307
+ inputRef;
308
+ /** Palette visibility (open via {@link Open}; Escape/backdrop close). */
309
+ IsOpen = false;
310
+ /** Raw input text including any leading trigger char. */
311
+ Query = '';
312
+ Rows = [];
313
+ RecentRows = [];
314
+ SelectedIndex = 0;
315
+ IsLoading = false;
316
+ Scopes = [];
317
+ SelectedScopeIDs = [];
318
+ Opened = new EventEmitter();
319
+ Closed = new EventEmitter();
320
+ /** Footer gear clicked — the host opens its settings surface (Explorer: My
321
+ Profile, where the Command Palette opt-in section lives). The palette
322
+ closes first so the settings dialog isn't buried under it. */
323
+ SettingsRequested = new EventEmitter();
324
+ providers = [];
325
+ defaultProvider = null;
326
+ byTrigger = new Map();
327
+ queryGeneration = 0;
328
+ debounceHandle = null;
329
+ /** Element focused before the palette opened — restored on close (a11y). */
330
+ previousFocus = null;
331
+ recentsSub = null;
332
+ // ---------------------------------------------------------------
333
+ // Derived view state
334
+ // ---------------------------------------------------------------
335
+ /** The active trigger char ('' = default/global-search mode). */
336
+ get ActiveTriggerChar() {
337
+ const first = this.Query.charAt(0);
338
+ return this.byTrigger.has(first) ? first : '';
339
+ }
340
+ /** Query text with the trigger char stripped. */
341
+ get EffectiveQuery() {
342
+ return this.ActiveTriggerChar ? this.Query.substring(1) : this.Query;
343
+ }
344
+ get ActiveModeLabel() {
345
+ return this.activeProvider?.ModeLabel ?? 'Search';
346
+ }
347
+ get ActivePlaceholder() {
348
+ return this.activeProvider?.Placeholder ?? 'Search everything — or type #, /, @ …';
349
+ }
350
+ /** Scope pills only apply to the cross-source search mode. */
351
+ get ShowScopes() {
352
+ return this.ActiveTriggerChar === '' && this.EffectiveQuery.trim().length > 0;
353
+ }
354
+ /** Footer gear: close, then let the host present its settings surface. */
355
+ RequestSettings() {
356
+ this.Close();
357
+ this.SettingsRequested.emit();
358
+ }
359
+ /** Hint chips for the empty state — one per non-default provider. */
360
+ get TriggerHints() {
361
+ return this.providers
362
+ .filter((p) => p.TriggerChar !== '')
363
+ .map((p) => ({ Char: p.TriggerChar, Label: p.ModeLabel }));
364
+ }
365
+ /** RecentRows render after the hint bar; selection indexes continue into them. */
366
+ get RecentBaseIndex() {
367
+ return 0;
368
+ }
369
+ get activeProvider() {
370
+ const char = this.ActiveTriggerChar;
371
+ return char ? (this.byTrigger.get(char) ?? null) : this.defaultProvider;
372
+ }
373
+ get selectableRows() {
374
+ return this.Rows.length > 0 ? this.Rows : this.RecentRows;
375
+ }
376
+ /**
377
+ * ARIA combobox wiring: the input keeps DOM focus while this points at the
378
+ * virtually-highlighted option row, so screen readers announce selection moves.
379
+ */
380
+ get ActiveDescendantId() {
381
+ return this.selectableRows.length > 0 ? `ob-opt-${this.SelectedIndex}` : null;
382
+ }
383
+ /** Whether any option rows exist — drives the combobox's aria-expanded. */
384
+ get HasOptions() {
385
+ return this.selectableRows.length > 0;
386
+ }
387
+ // ---------------------------------------------------------------
388
+ // Public API
389
+ // ---------------------------------------------------------------
390
+ /** Opens the palette, optionally pre-seeded (e.g. '/' from the legacy Ctrl+/ path). */
391
+ Open(initialQuery = '') {
392
+ this.ensureProviders();
393
+ this.previousFocus = document.activeElement instanceof HTMLElement ? document.activeElement : null;
394
+ this.IsOpen = true;
395
+ this.Query = initialQuery;
396
+ this.Rows = [];
397
+ this.SelectedIndex = 0;
398
+ void this.loadScopes();
399
+ void this.loadRecents();
400
+ if (initialQuery.length > 0) {
401
+ this.runQuery();
402
+ }
403
+ this.Opened.emit();
404
+ this.cdr.markForCheck();
405
+ // Input mounts via @if — focus next tick.
406
+ setTimeout(() => this.inputRef?.nativeElement.focus(), 30);
407
+ }
408
+ Close() {
409
+ if (!this.IsOpen) {
410
+ return;
411
+ }
412
+ this.IsOpen = false;
413
+ this.Query = '';
414
+ this.Rows = [];
415
+ this.Closed.emit();
416
+ this.cdr.markForCheck();
417
+ // Return focus to where the user was (skip if that element left the DOM).
418
+ if (this.previousFocus?.isConnected) {
419
+ this.previousFocus.focus();
420
+ }
421
+ this.previousFocus = null;
422
+ }
423
+ Toggle(initialQuery = '') {
424
+ if (this.IsOpen) {
425
+ this.Close();
426
+ }
427
+ else {
428
+ this.Open(initialQuery);
429
+ }
430
+ }
431
+ ngOnDestroy() {
432
+ if (this.debounceHandle != null) {
433
+ clearTimeout(this.debounceHandle);
434
+ }
435
+ this.recentsSub?.unsubscribe();
436
+ }
437
+ // ---------------------------------------------------------------
438
+ // Input handling
439
+ // ---------------------------------------------------------------
440
+ OnQueryChange(value) {
441
+ this.Query = value;
442
+ this.SelectedIndex = 0;
443
+ this.runQuery();
444
+ }
445
+ OnInputKeydown(event) {
446
+ const rows = this.selectableRows;
447
+ switch (event.key) {
448
+ case 'ArrowDown':
449
+ event.preventDefault();
450
+ this.moveSelection(1);
451
+ break;
452
+ case 'ArrowUp':
453
+ event.preventDefault();
454
+ this.moveSelection(-1);
455
+ break;
456
+ case 'Enter': {
457
+ event.preventDefault();
458
+ const row = rows[this.SelectedIndex];
459
+ if (row) {
460
+ this.Execute(row.Suggestion);
461
+ }
462
+ else if (this.ActiveTriggerChar === '' && this.EffectiveQuery.trim().length > 1) {
463
+ // No rows yet (still loading / no matches): honest escape hatch to full search.
464
+ this.openFullSearch(this.EffectiveQuery.trim());
465
+ }
466
+ break;
467
+ }
468
+ }
469
+ }
470
+ /**
471
+ * Dialog-level keys (bubbled from anywhere inside the palette):
472
+ * - Escape closes from any focused element, not just the input.
473
+ * - Tab follows the natural visual order — input → scope pills → mode chips →
474
+ * the selected result row (roving tabindex) — and TRAPS at the ends so focus
475
+ * cycles inside the dialog instead of escaping to the page underneath.
476
+ * (Design review: Tab must reach the three mode chips, not skip them.)
477
+ */
478
+ OnPaletteKeydown(event) {
479
+ if (event.key === 'Escape') {
480
+ event.preventDefault();
481
+ this.Close();
482
+ return;
483
+ }
484
+ if (event.key !== 'Tab') {
485
+ return;
486
+ }
487
+ // On a result row, Tab / Shift+Tab step through the RESULTS themselves
488
+ // (mirrors ArrowDown/Up) until walking off either end of the list — then
489
+ // the trap logic below takes over. Same model as mj-search-overlay.
490
+ const activeEl = document.activeElement;
491
+ if (activeEl?.classList.contains('ob-row')) {
492
+ const last = this.selectableRows.length - 1;
493
+ if (!event.shiftKey && this.SelectedIndex < last) {
494
+ event.preventDefault();
495
+ this.moveSelection(1, true);
496
+ return;
497
+ }
498
+ if (event.shiftKey && this.SelectedIndex > 0) {
499
+ event.preventDefault();
500
+ this.moveSelection(-1, true);
501
+ return;
502
+ }
503
+ // At either end: fall through so Tab leaves the list naturally.
504
+ }
505
+ const root = this.host.nativeElement.querySelector('.omnibar-palette');
506
+ if (!root) {
507
+ return;
508
+ }
509
+ const focusables = Array.from(root.querySelectorAll('input, button, .ob-row[tabindex="0"]'))
510
+ .filter((el) => el.offsetParent !== null);
511
+ if (focusables.length === 0) {
512
+ return;
513
+ }
514
+ const active = document.activeElement;
515
+ if (!event.shiftKey && active === focusables[focusables.length - 1]) {
516
+ event.preventDefault();
517
+ focusables[0].focus();
518
+ }
519
+ else if (event.shiftKey && active === focusables[0]) {
520
+ event.preventDefault();
521
+ focusables[focusables.length - 1].focus();
522
+ }
523
+ }
524
+ /** Keys on a focused result row (rows are real focus stops via roving tabindex). */
525
+ OnRowKeydown(event, suggestion) {
526
+ switch (event.key) {
527
+ case 'ArrowDown':
528
+ event.preventDefault();
529
+ this.moveSelection(1, true);
530
+ break;
531
+ case 'ArrowUp':
532
+ event.preventDefault();
533
+ this.moveSelection(-1, true);
534
+ break;
535
+ case 'Enter':
536
+ event.preventDefault();
537
+ this.Execute(suggestion);
538
+ break;
539
+ }
540
+ }
541
+ /**
542
+ * Keyboard-driven selection move: wraps at both ends (standard picker behavior)
543
+ * and keeps the highlighted row visible. Mouse hover sets SelectedIndex directly
544
+ * in the template and deliberately does NOT scroll — auto-scrolling under the
545
+ * pointer would fight the user's hand. When the move originates from a focused
546
+ * row (roving tabindex), DOM focus follows the selection.
547
+ */
548
+ moveSelection(delta, focusRow = false) {
549
+ const count = this.selectableRows.length;
550
+ if (count === 0) {
551
+ return;
552
+ }
553
+ this.SelectedIndex = (this.SelectedIndex + delta + count) % count;
554
+ this.cdr.markForCheck();
555
+ const row = this.host.nativeElement.querySelector(`#ob-opt-${this.SelectedIndex}`);
556
+ row?.scrollIntoView({ block: 'nearest' });
557
+ if (focusRow) {
558
+ row?.focus();
559
+ }
560
+ }
561
+ /** Hint-chip click: seed the trigger char and refocus. */
562
+ SeedTrigger(char) {
563
+ this.Query = char;
564
+ this.SelectedIndex = 0;
565
+ this.runQuery();
566
+ this.inputRef?.nativeElement.focus();
567
+ }
568
+ // ---------------------------------------------------------------
569
+ // Scopes
570
+ // ---------------------------------------------------------------
571
+ IsScopeSelected(id) {
572
+ return this.SelectedScopeIDs.includes(id);
573
+ }
574
+ ToggleScope(id) {
575
+ this.SelectedScopeIDs = this.IsScopeSelected(id)
576
+ ? this.SelectedScopeIDs.filter((s) => s !== id)
577
+ : [...this.SelectedScopeIDs, id];
578
+ this.cdr.markForCheck();
579
+ }
580
+ ClearScopes() {
581
+ this.SelectedScopeIDs = [];
582
+ this.cdr.markForCheck();
583
+ }
584
+ // ---------------------------------------------------------------
585
+ // Execution
586
+ // ---------------------------------------------------------------
587
+ /** Executes a suggestion: navigate per its payload, or re-seed for entity drill-in. */
588
+ Execute(suggestion) {
589
+ const nav = GetOmnibarNavPayload(suggestion);
590
+ if (!nav) {
591
+ return; // foreign suggestion with no navigation — nothing to execute
592
+ }
593
+ // Default-mode queries count as "searches" even when the user executes a
594
+ // suggestion that navigates directly (no full ExecuteSearch downstream to
595
+ // record them). Trigger-mode fragments ('#accounts ac…') are NOT searches —
596
+ // recording those would pollute recents. 'search' payloads skip too: the
597
+ // results page records them with the real result count.
598
+ const typed = this.EffectiveQuery.trim();
599
+ if (this.ActiveTriggerChar === '' && typed.length > 0 && nav.kind !== 'search') {
600
+ this.search.RecordRecentSearch(typed);
601
+ }
602
+ switch (nav.kind) {
603
+ case 'record':
604
+ this.navigation.OpenEntityRecord(nav.entityName, CompositeKey.FromID(nav.recordId));
605
+ break;
606
+ case 'entity-list':
607
+ this.navigation.OpenDynamicView(nav.entityName);
608
+ break;
609
+ case 'search':
610
+ this.openFullSearch(nav.query);
611
+ return; // openFullSearch closes
612
+ case 'app':
613
+ void this.paletteService.TrackAppAccess(nav.appId);
614
+ void this.navigation.SwitchToApp(nav.appId);
615
+ break;
616
+ case 'nav':
617
+ void this.navigation.SwitchToApp(nav.appId, nav.navItemName);
618
+ break;
619
+ case 'agent':
620
+ void this.openAgentChat(nav.agentName);
621
+ break;
622
+ case 'file':
623
+ if (!this.fileOpen.OpenPreviewFromSearchResult(nav.rawMetadata)) {
624
+ void this.fileOpen.OpenFileFromSearchResult(nav.rawMetadata);
625
+ }
626
+ break;
627
+ }
628
+ this.Close();
629
+ }
630
+ openFullSearch(query) {
631
+ const opts = this.SelectedScopeIDs.length > 0 ? { scopeIDs: [...this.SelectedScopeIDs] } : undefined;
632
+ this.navigation.OpenSearch(query, opts);
633
+ this.Close();
634
+ }
635
+ /** '@' selection: switch to the Chat app pre-addressed to the agent. */
636
+ async openAgentChat(agentName) {
637
+ const apps = await firstValueFrom(this.appManager.Applications).catch(() => []);
638
+ const chat = apps.find((a) => a.Name.trim().toLowerCase() === 'chat');
639
+ if (chat) {
640
+ // agentReq is a one-shot request nonce: the chat wrapper applies each
641
+ // agent|nonce instruction exactly once, so URL↔tab-config sync echoes
642
+ // of an already-consumed param can never re-stage the pre-address (and
643
+ // wipe an in-progress composer draft), while a genuine re-tag of the
644
+ // SAME agent still applies because it carries a fresh nonce.
645
+ await this.navigation.SwitchToApp(chat.ID, undefined, {
646
+ agent: agentName,
647
+ agentReq: Date.now().toString(36),
648
+ });
649
+ }
650
+ }
651
+ // ---------------------------------------------------------------
652
+ // Query execution
653
+ // ---------------------------------------------------------------
654
+ ensureProviders() {
655
+ if (this.providers.length > 0) {
656
+ return;
657
+ }
658
+ // Kick off the persisted-recents load (idempotent; resolves via LoggedIn
659
+ // replay). The legacy search composite used to be the only caller — with
660
+ // the omnibar enabled it never renders, so prior-session recents were
661
+ // invisible until the palette started requesting them itself.
662
+ void this.search.LoadRecentSearches();
663
+ // Refresh the empty-state Recent rows whenever recents change while the
664
+ // palette is idle-open (skip(1): BehaviorSubject replays its current
665
+ // value on subscribe, which loadRecents already read directly).
666
+ this.recentsSub = this.search.RecentSearches$.pipe(skip(1)).subscribe(() => {
667
+ if (this.IsOpen && this.Query.length === 0) {
668
+ void this.loadRecents();
669
+ }
670
+ });
671
+ LoadOmnibarProviders();
672
+ this.providers = DiscoverOmnibarProviders();
673
+ const context = {
674
+ Search: this.search,
675
+ Apps: this.appManager,
676
+ PaletteService: this.paletteService,
677
+ Navigation: this.navigation,
678
+ };
679
+ for (const provider of this.providers) {
680
+ provider.Attach(context);
681
+ if (provider.TriggerChar === '') {
682
+ this.defaultProvider = this.defaultProvider ?? provider;
683
+ }
684
+ else if (!this.byTrigger.has(provider.TriggerChar)) {
685
+ this.byTrigger.set(provider.TriggerChar, provider);
686
+ }
687
+ }
688
+ }
689
+ runQuery() {
690
+ if (this.debounceHandle != null) {
691
+ clearTimeout(this.debounceHandle);
692
+ this.debounceHandle = null;
693
+ }
694
+ const generation = ++this.queryGeneration;
695
+ const provider = this.activeProvider;
696
+ const query = this.EffectiveQuery;
697
+ const isTriggerMode = this.ActiveTriggerChar !== '';
698
+ if (!provider || (query.trim().length === 0 && !isTriggerMode)) {
699
+ this.Rows = [];
700
+ this.IsLoading = false;
701
+ this.cdr.markForCheck();
702
+ return;
703
+ }
704
+ const fire = () => void this.fetchSuggestions(provider, query, generation);
705
+ if (isTriggerMode) {
706
+ fire(); // warm caches — no debounce
707
+ }
708
+ else {
709
+ this.IsLoading = this.Rows.length === 0;
710
+ this.cdr.markForCheck();
711
+ this.debounceHandle = setTimeout(fire, SEARCH_DEBOUNCE_MS);
712
+ }
713
+ }
714
+ async fetchSuggestions(provider, query, generation) {
715
+ const request = {
716
+ Query: query,
717
+ MaxResults: MAX_RESULTS,
718
+ ContextUser: this.currentUser,
719
+ Provider: null,
720
+ };
721
+ const suggestions = query.trim().length === 0
722
+ ? await provider.EmptyStateSuggestions(request)
723
+ : await provider.GetSuggestions(request);
724
+ if (generation !== this.queryGeneration) {
725
+ return; // stale response — a newer keystroke superseded it
726
+ }
727
+ this.Rows = this.toRows(suggestions);
728
+ this.SelectedIndex = 0;
729
+ this.IsLoading = false;
730
+ this.cdr.markForCheck();
731
+ }
732
+ toRows(suggestions) {
733
+ let lastGroup = null;
734
+ return suggestions.map((s) => {
735
+ const group = typeof s.data?.['group'] === 'string' ? s.data['group'] : '';
736
+ const isNewGroup = group.length > 0 && group !== lastGroup;
737
+ if (group.length > 0) {
738
+ lastGroup = group;
739
+ }
740
+ const score = typeof s.data?.['score'] === 'number' ? s.data['score'] : null;
741
+ return {
742
+ Suggestion: s,
743
+ GroupLabel: isNewGroup ? group : null,
744
+ ScorePercent: score != null ? Math.round(Math.max(0, Math.min(1, score)) * 100) : null,
745
+ };
746
+ });
747
+ }
748
+ async loadScopes() {
749
+ try {
750
+ this.Scopes = await this.search.LoadScopes();
751
+ this.cdr.markForCheck();
752
+ }
753
+ catch {
754
+ this.Scopes = [];
755
+ }
756
+ }
757
+ /** Empty-state recents: recent searches + recent apps (best-effort). */
758
+ async loadRecents() {
759
+ const rows = [];
760
+ try {
761
+ const recentSearches = this.search.RecentSearches$.value.slice(0, 3);
762
+ for (const recent of recentSearches) {
763
+ rows.push({
764
+ Suggestion: {
765
+ type: 'search',
766
+ id: `recent-search:${recent.Query}`,
767
+ name: recent.Query,
768
+ displayName: recent.Query,
769
+ description: 'Recent search',
770
+ icon: 'fa-solid fa-clock-rotate-left',
771
+ data: { nav: { kind: 'search', query: recent.Query } },
772
+ },
773
+ GroupLabel: null,
774
+ ScorePercent: null,
775
+ });
776
+ }
777
+ }
778
+ catch {
779
+ // recents are decorative — never block the palette
780
+ }
781
+ try {
782
+ const commandProvider = this.byTrigger.get('/');
783
+ if (commandProvider) {
784
+ const apps = await commandProvider.EmptyStateSuggestions({
785
+ Query: '', MaxResults: 3, ContextUser: this.currentUser, Provider: null,
786
+ });
787
+ rows.push(...apps.map((s) => ({ Suggestion: s, GroupLabel: null, ScorePercent: null })));
788
+ }
789
+ }
790
+ catch {
791
+ // ditto
792
+ }
793
+ this.RecentRows = rows;
794
+ this.cdr.markForCheck();
795
+ }
796
+ get currentUser() {
797
+ return Metadata.Provider?.CurrentUser ?? null; // global-provider-ok: Explorer shell palette is app chrome bound to the session's default provider
798
+ }
799
+ static ɵfac = function OmnibarPaletteComponent_Factory(__ngFactoryType__) { return new (__ngFactoryType__ || OmnibarPaletteComponent)(); };
800
+ static ɵcmp = /*@__PURE__*/ i0.ɵɵdefineComponent({ type: OmnibarPaletteComponent, selectors: [["mj-omnibar-palette"]], viewQuery: function OmnibarPaletteComponent_Query(rf, ctx) { if (rf & 1) {
801
+ i0.ɵɵviewQuery(_c0, 5);
802
+ } if (rf & 2) {
803
+ let _t;
804
+ i0.ɵɵqueryRefresh(_t = i0.ɵɵloadQuery()) && (ctx.inputRef = _t.first);
805
+ } }, outputs: { Opened: "Opened", Closed: "Closed", SettingsRequested: "SettingsRequested" }, standalone: false, decls: 1, vars: 1, consts: [["paletteInput", ""], [1, "omnibar-overlay", 3, "click"], ["role", "dialog", "aria-modal", "true", "aria-label", "Command palette", 1, "omnibar-palette", 3, "keydown"], [1, "ob-input-row"], [1, "ob-lead"], [1, "fa-solid", "fa-magnifying-glass"], ["type", "text", "autocomplete", "off", "spellcheck", "false", "role", "combobox", "aria-controls", "ob-listbox", "aria-autocomplete", "list", 1, "ob-input", 3, "ngModelChange", "keydown", "placeholder", "ngModel"], [1, "ob-mode-badge"], [1, "ob-kbd"], ["type", "button", "aria-label", "Close", "title", "Close", 1, "ob-close", 3, "click"], [1, "fa-solid", "fa-xmark"], [1, "ob-scopes"], [1, "ob-body"], [1, "ob-loading"], [1, "ob-empty"], ["id", "ob-listbox", "role", "listbox", "aria-label", "Suggestions"], [1, "ob-foot"], [1, "ob-k"], ["type", "button", "aria-label", "Command Palette settings", "title", "Command Palette settings", 1, "ob-settings", 3, "click"], [1, "fa-solid", "fa-gear"], ["type", "button", 1, "ob-scope", 3, "click"], ["type", "button", 1, "ob-scope", 3, "ob-scope--on"], [1, "fa-solid", "fa-circle-notch", "fa-spin"], [1, "ob-hintbar"], ["type", "button", 1, "ob-hint-chip"], ["type", "button", 1, "ob-hint-chip", 3, "click"], ["role", "presentation", 1, "ob-group-label"], ["role", "option", 1, "ob-row", 3, "ob-row--sel"], ["role", "option", 1, "ob-row", 3, "focus", "keydown", "mouseenter", "click"], [1, "ob-ric"], [1, "ob-rmain"], [1, "ob-rname"], [1, "ob-rsub"], [1, "ob-raux"], [1, "ob-rtype"], [1, "ob-score"], [1, "ob-go"]], template: function OmnibarPaletteComponent_Template(rf, ctx) { if (rf & 1) {
806
+ i0.ɵɵconditionalCreate(0, OmnibarPaletteComponent_Conditional_0_Template, 33, 10);
807
+ } if (rf & 2) {
808
+ i0.ɵɵconditional(ctx.IsOpen ? 0 : -1);
809
+ } }, dependencies: [i1.DefaultValueAccessor, i1.NgControlStatus, i1.NgModel], styles: ["\n\n\n.omnibar-overlay[_ngcontent-%COMP%] {\n position: fixed;\n inset: 0;\n background: var(--mj-bg-overlay);\n z-index: 1400;\n}\n\n.omnibar-palette[_ngcontent-%COMP%] {\n position: fixed;\n left: 50%;\n top: 96px;\n transform: translateX(-50%);\n width: min(680px, 92vw);\n \n\n\n\n display: flex;\n flex-direction: column;\n max-height: calc(100vh - 96px - 24px);\n background: var(--mj-bg-surface-elevated);\n border: 1px solid var(--mj-border-default);\n border-radius: var(--mj-radius-xl);\n box-shadow: var(--mj-shadow-lg, 0 20px 60px color-mix(in srgb, var(--mj-text-primary) 22%, transparent));\n z-index: 1401;\n overflow: hidden;\n animation: _ngcontent-%COMP%_ob-pop .13s ease-out;\n}\n\n@keyframes _ngcontent-%COMP%_ob-pop {\n from { opacity: 0; transform: translateX(-50%) scale(.985) translateY(-4px); }\n to { opacity: 1; transform: translateX(-50%) scale(1); }\n}\n\n.ob-input-row[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: 12px;\n padding: 15px 18px;\n border-bottom: 1px solid var(--mj-border-subtle);\n}\n\n.ob-lead[_ngcontent-%COMP%] {\n color: var(--mj-text-muted);\n font-size: 15px;\n width: 18px;\n text-align: center;\n}\n\n.ob-lead--trigger[_ngcontent-%COMP%] { color: var(--mj-brand-primary); }\n.ob-lead[_ngcontent-%COMP%] b[_ngcontent-%COMP%] { font-family: ui-monospace, monospace; }\n\n.ob-input[_ngcontent-%COMP%] {\n flex: 1;\n border: none;\n outline: none;\n background: transparent;\n font-size: 16px;\n color: var(--mj-text-primary);\n font-family: inherit;\n}\n\n.ob-input[_ngcontent-%COMP%]::placeholder { color: var(--mj-text-muted); }\n\n.ob-mode-badge[_ngcontent-%COMP%] {\n font-size: 10.5px;\n font-weight: 700;\n letter-spacing: .4px;\n text-transform: uppercase;\n padding: 3px 9px;\n border-radius: var(--mj-radius-full, 999px);\n background: color-mix(in srgb, var(--mj-brand-primary) 14%, transparent);\n color: var(--mj-brand-primary);\n white-space: nowrap;\n}\n\n.ob-kbd[_ngcontent-%COMP%] {\n font-family: inherit;\n font-size: 10.5px;\n font-weight: 600;\n color: var(--mj-text-muted);\n background: var(--mj-bg-surface);\n border: 1px solid var(--mj-border-strong);\n border-bottom-width: 2px;\n border-radius: 5px;\n padding: 1.5px 6px;\n}\n\n.ob-close[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n justify-content: center;\n width: 28px;\n height: 28px;\n padding: 0;\n border: none;\n border-radius: var(--mj-radius-full);\n background: transparent;\n color: var(--mj-text-muted);\n font-size: var(--mj-text-sm);\n cursor: pointer;\n transition: var(--mj-transition-colors);\n flex-shrink: 0;\n}\n.ob-close[_ngcontent-%COMP%]:hover {\n background: var(--mj-bg-surface-hover);\n color: var(--mj-text-primary);\n}\n\n.ob-scopes[_ngcontent-%COMP%] {\n display: flex;\n gap: 6px;\n padding: 9px 18px;\n border-bottom: 1px solid var(--mj-border-subtle);\n flex-wrap: wrap;\n}\n\n.ob-scope[_ngcontent-%COMP%] {\n font-size: 11px;\n padding: 3px 10px;\n border-radius: var(--mj-radius-full, 999px);\n border: 1px solid var(--mj-border-default);\n color: var(--mj-text-secondary);\n cursor: pointer;\n background: transparent;\n}\n\n.ob-scope--on[_ngcontent-%COMP%] {\n background: color-mix(in srgb, var(--mj-brand-primary) 12%, transparent);\n border-color: var(--mj-brand-primary);\n color: var(--mj-brand-primary);\n font-weight: 600;\n}\n\n.ob-body[_ngcontent-%COMP%] {\n flex: 1 1 auto;\n min-height: 0;\n overflow-y: auto;\n padding: 6px 0;\n}\n\n.ob-loading[_ngcontent-%COMP%], \n.ob-empty[_ngcontent-%COMP%] {\n padding: 18px;\n text-align: center;\n color: var(--mj-text-muted);\n font-size: 13px;\n}\n\n.ob-group-label[_ngcontent-%COMP%] {\n font-size: 10.5px;\n font-weight: 700;\n letter-spacing: .6px;\n text-transform: uppercase;\n color: var(--mj-text-muted);\n padding: 10px 18px 5px;\n}\n\n.ob-row[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: 12px;\n padding: 9px 18px;\n cursor: pointer;\n}\n\n\n\n\n.ob-row[_ngcontent-%COMP%]:focus { outline: none; }\n.ob-row[_ngcontent-%COMP%]:focus-visible { outline: 2px solid var(--mj-border-focus); outline-offset: -2px; }\n\n.ob-row--sel[_ngcontent-%COMP%] {\n background: color-mix(in srgb, var(--mj-brand-primary) 9%, transparent);\n box-shadow: inset 3px 0 0 var(--mj-brand-primary);\n}\n\n.ob-ric[_ngcontent-%COMP%] {\n width: 30px;\n height: 30px;\n border-radius: 8px;\n display: flex;\n align-items: center;\n justify-content: center;\n font-size: 13px;\n flex-shrink: 0;\n background: var(--mj-bg-surface-sunken);\n color: var(--mj-text-secondary);\n}\n\n.ob-row--sel[_ngcontent-%COMP%] .ob-ric[_ngcontent-%COMP%] {\n background: color-mix(in srgb, var(--mj-brand-primary) 16%, transparent);\n color: var(--mj-brand-primary);\n}\n\n.ob-rmain[_ngcontent-%COMP%] { flex: 1; min-width: 0; display: flex; flex-direction: column; }\n\n.ob-rname[_ngcontent-%COMP%] {\n font-size: 13.5px;\n font-weight: 500;\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n color: var(--mj-text-primary);\n}\n\n.ob-rsub[_ngcontent-%COMP%] {\n font-size: 11.5px;\n color: var(--mj-text-muted);\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n margin-top: 1px;\n}\n\n.ob-raux[_ngcontent-%COMP%] { display: flex; align-items: center; gap: 8px; flex-shrink: 0; }\n\n.ob-rtype[_ngcontent-%COMP%] {\n font-size: 10px;\n font-weight: 600;\n padding: 2px 8px;\n border-radius: var(--mj-radius-full, 999px);\n background: var(--mj-bg-surface-sunken);\n color: var(--mj-text-muted);\n text-transform: capitalize;\n}\n\n.ob-score[_ngcontent-%COMP%] {\n width: 52px;\n height: 4px;\n border-radius: 2px;\n background: var(--mj-bg-surface-sunken);\n overflow: hidden;\n}\n\n.ob-score[_ngcontent-%COMP%] i[_ngcontent-%COMP%] { display: block; height: 100%; background: var(--mj-brand-primary); }\n\n.ob-go[_ngcontent-%COMP%] {\n font-size: 11px;\n color: var(--mj-text-muted);\n opacity: 0;\n display: flex;\n gap: 6px;\n align-items: center;\n}\n\n.ob-row--sel[_ngcontent-%COMP%] .ob-go[_ngcontent-%COMP%] { opacity: 1; }\n\n.ob-hintbar[_ngcontent-%COMP%] { display: flex; gap: 8px; padding: 12px 18px; flex-wrap: wrap; }\n\n.ob-hint-chip[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: 9px;\n padding: 9px 13px;\n border: 1px dashed var(--mj-border-strong);\n border-radius: 10px;\n cursor: pointer;\n background: transparent;\n}\n\n.ob-hint-chip[_ngcontent-%COMP%]:hover {\n border-color: var(--mj-brand-primary);\n background: color-mix(in srgb, var(--mj-brand-primary) 6%, transparent);\n}\n\n.ob-hint-chip[_ngcontent-%COMP%] b[_ngcontent-%COMP%] { font-family: ui-monospace, monospace; color: var(--mj-brand-primary); font-size: 14px; }\n.ob-hint-chip[_ngcontent-%COMP%] span[_ngcontent-%COMP%] { font-size: 12px; color: var(--mj-text-secondary); }\n\n.ob-foot[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: 16px;\n padding: 10px 18px;\n border-top: 1px solid var(--mj-border-subtle);\n background: var(--mj-bg-surface-card);\n font-size: 11.5px;\n color: var(--mj-text-muted);\n}\n\n.ob-k[_ngcontent-%COMP%] { display: flex; align-items: center; gap: 5px; }\n\n\n\n.ob-settings[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n justify-content: center;\n width: 24px;\n height: 24px;\n padding: 0;\n margin-left: auto;\n border: none;\n border-radius: var(--mj-radius-full);\n background: transparent;\n color: var(--mj-text-muted);\n font-size: var(--mj-text-xs);\n cursor: pointer;\n transition: var(--mj-transition-colors);\n}\n.ob-settings[_ngcontent-%COMP%]:hover {\n background: var(--mj-bg-surface-hover);\n color: var(--mj-text-primary);\n}\n\n\n\n\n\n\n@media (max-width: 640px) {\n .omnibar-palette[_ngcontent-%COMP%] {\n top: 0;\n left: 0;\n right: 0;\n bottom: 0;\n transform: none;\n width: 100%;\n height: 100dvh;\n max-height: none; \n\n border-radius: 0;\n animation: none; \n\n display: flex;\n flex-direction: column;\n }\n\n \n\n .ob-body[_ngcontent-%COMP%] {\n flex: 1;\n min-height: 0;\n max-height: none;\n }\n\n \n\n\n\n\n .ob-kbd[_ngcontent-%COMP%], \n .ob-go[_ngcontent-%COMP%], \n .ob-k[_ngcontent-%COMP%] {\n display: none;\n }\n\n \n\n .ob-close[_ngcontent-%COMP%], \n .ob-settings[_ngcontent-%COMP%] {\n width: 40px;\n height: 40px;\n font-size: var(--mj-text-base);\n }\n}"], changeDetection: 0 });
810
+ }
811
+ (() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassMetadata(OmnibarPaletteComponent, [{
812
+ type: Component,
813
+ args: [{ standalone: false, selector: 'mj-omnibar-palette', changeDetection: ChangeDetectionStrategy.OnPush, template: "@if (IsOpen) {\n <div class=\"omnibar-overlay\" (click)=\"Close()\"></div>\n <div class=\"omnibar-palette\" role=\"dialog\" aria-modal=\"true\" aria-label=\"Command palette\"\n (keydown)=\"OnPaletteKeydown($event)\">\n\n <div class=\"ob-input-row\">\n <span class=\"ob-lead\" [class.ob-lead--trigger]=\"ActiveTriggerChar.length > 0\">\n @if (ActiveTriggerChar.length > 0) {\n <b>{{ ActiveTriggerChar }}</b>\n } @else {\n <i class=\"fa-solid fa-magnifying-glass\"></i>\n }\n </span>\n <input #paletteInput class=\"ob-input\" type=\"text\" autocomplete=\"off\" spellcheck=\"false\"\n role=\"combobox\" aria-controls=\"ob-listbox\" aria-autocomplete=\"list\"\n [attr.aria-expanded]=\"HasOptions\"\n [attr.aria-activedescendant]=\"ActiveDescendantId\"\n [placeholder]=\"ActivePlaceholder\"\n [ngModel]=\"Query\" (ngModelChange)=\"OnQueryChange($event)\"\n (keydown)=\"OnInputKeydown($event)\" />\n <span class=\"ob-mode-badge\">{{ ActiveModeLabel }}</span>\n <kbd class=\"ob-kbd\">esc</kbd>\n <button type=\"button\" class=\"ob-close\" aria-label=\"Close\" title=\"Close\" (click)=\"Close()\">\n <i class=\"fa-solid fa-xmark\"></i>\n </button>\n </div>\n\n @if (ShowScopes && Scopes.length > 0) {\n <div class=\"ob-scopes\">\n <button type=\"button\" class=\"ob-scope\" [class.ob-scope--on]=\"SelectedScopeIDs.length === 0\"\n (click)=\"ClearScopes()\">All sources</button>\n @for (scope of Scopes; track scope.ID) {\n <button type=\"button\" class=\"ob-scope\" [class.ob-scope--on]=\"IsScopeSelected(scope.ID)\"\n (click)=\"ToggleScope(scope.ID)\">{{ scope.Name }}</button>\n }\n </div>\n }\n\n <div class=\"ob-body\">\n @if (IsLoading) {\n <div class=\"ob-loading\"><i class=\"fa-solid fa-circle-notch fa-spin\"></i> Searching\u2026</div>\n } @else if (Rows.length === 0 && Query.length === 0) {\n <div class=\"ob-hintbar\">\n @for (hint of TriggerHints; track hint.Char) {\n <button type=\"button\" class=\"ob-hint-chip\" (click)=\"SeedTrigger(hint.Char)\">\n <b>{{ hint.Char }}</b><span>{{ hint.Label }}</span>\n </button>\n }\n </div>\n @if (RecentRows.length > 0) {\n <div class=\"ob-group-label\" role=\"presentation\">Recent</div>\n <div id=\"ob-listbox\" role=\"listbox\" aria-label=\"Suggestions\">\n @for (row of RecentRows; track row.Suggestion.id; let i = $index) {\n <div class=\"ob-row\" role=\"option\" [attr.id]=\"'ob-opt-' + (RecentBaseIndex + i)\"\n [attr.tabindex]=\"RecentBaseIndex + i === SelectedIndex ? 0 : -1\"\n [attr.aria-selected]=\"RecentBaseIndex + i === SelectedIndex\"\n [class.ob-row--sel]=\"RecentBaseIndex + i === SelectedIndex\"\n (focus)=\"SelectedIndex = RecentBaseIndex + i\"\n (keydown)=\"OnRowKeydown($event, row.Suggestion)\"\n (mouseenter)=\"SelectedIndex = RecentBaseIndex + i\" (click)=\"Execute(row.Suggestion)\">\n <span class=\"ob-ric\"><i [class]=\"row.Suggestion.icon || 'fa-solid fa-clock-rotate-left'\"></i></span>\n <span class=\"ob-rmain\">\n <span class=\"ob-rname\">{{ row.Suggestion.displayName }}</span>\n <span class=\"ob-rsub\">{{ row.Suggestion.description }}</span>\n </span>\n <span class=\"ob-raux\"><span class=\"ob-rtype\">{{ row.Suggestion.type }}</span></span>\n </div>\n }\n </div>\n }\n } @else if (Rows.length === 0) {\n <div class=\"ob-empty\">No matches \u2014 press <kbd class=\"ob-kbd\">\u21B5</kbd> to search everything for \u201C{{ EffectiveQuery }}\u201D.</div>\n } @else {\n <div id=\"ob-listbox\" role=\"listbox\" aria-label=\"Suggestions\">\n @for (row of Rows; track row.Suggestion.id; let i = $index) {\n @if (row.GroupLabel) {\n <div class=\"ob-group-label\" role=\"presentation\">{{ row.GroupLabel }}</div>\n }\n <div class=\"ob-row\" role=\"option\" [attr.id]=\"'ob-opt-' + i\"\n [attr.tabindex]=\"i === SelectedIndex ? 0 : -1\"\n [attr.aria-selected]=\"i === SelectedIndex\"\n [class.ob-row--sel]=\"i === SelectedIndex\"\n (focus)=\"SelectedIndex = i\"\n (keydown)=\"OnRowKeydown($event, row.Suggestion)\"\n (mouseenter)=\"SelectedIndex = i\" (click)=\"Execute(row.Suggestion)\">\n <span class=\"ob-ric\"><i [class]=\"row.Suggestion.icon || 'fa-solid fa-circle'\"></i></span>\n <span class=\"ob-rmain\">\n <span class=\"ob-rname\">{{ row.Suggestion.displayName }}</span>\n @if (row.Suggestion.description) {\n <span class=\"ob-rsub\">{{ row.Suggestion.description }}</span>\n }\n </span>\n <span class=\"ob-raux\">\n @if (row.ScorePercent != null) {\n <span class=\"ob-score\"><i [style.width.%]=\"row.ScorePercent\"></i></span>\n }\n <span class=\"ob-rtype\">{{ row.Suggestion.type }}</span>\n <span class=\"ob-go\">open <kbd class=\"ob-kbd\">\u21B5</kbd></span>\n </span>\n </div>\n }\n </div>\n }\n </div>\n\n <div class=\"ob-foot\">\n <span class=\"ob-k\"><kbd class=\"ob-kbd\">\u2191</kbd><kbd class=\"ob-kbd\">\u2193</kbd> navigate</span>\n <span class=\"ob-k\"><kbd class=\"ob-kbd\">\u21B5</kbd> open</span>\n <button type=\"button\" class=\"ob-settings\" aria-label=\"Command Palette settings\"\n title=\"Command Palette settings\" (click)=\"RequestSettings()\">\n <i class=\"fa-solid fa-gear\"></i>\n </button>\n </div>\n </div>\n}\n", styles: ["/* \u2500\u2500 Unified command palette (design source: plans/composer-adoption/mockups/omnibar-command-palette.html) \u2500\u2500 */\n\n.omnibar-overlay {\n position: fixed;\n inset: 0;\n background: var(--mj-bg-overlay);\n z-index: 1400;\n}\n\n.omnibar-palette {\n position: fixed;\n left: 50%;\n top: 96px;\n transform: translateX(-50%);\n width: min(680px, 92vw);\n /* Grow to content \u2014 every fetched row plus the footer stays visible without\n internal scroll on desktop. The viewport bound below is the only cap, so\n .ob-body only scrolls when the screen genuinely can't fit the panel. */\n display: flex;\n flex-direction: column;\n max-height: calc(100vh - 96px - 24px);\n background: var(--mj-bg-surface-elevated);\n border: 1px solid var(--mj-border-default);\n border-radius: var(--mj-radius-xl);\n box-shadow: var(--mj-shadow-lg, 0 20px 60px color-mix(in srgb, var(--mj-text-primary) 22%, transparent));\n z-index: 1401;\n overflow: hidden;\n animation: ob-pop .13s ease-out;\n}\n\n@keyframes ob-pop {\n from { opacity: 0; transform: translateX(-50%) scale(.985) translateY(-4px); }\n to { opacity: 1; transform: translateX(-50%) scale(1); }\n}\n\n.ob-input-row {\n display: flex;\n align-items: center;\n gap: 12px;\n padding: 15px 18px;\n border-bottom: 1px solid var(--mj-border-subtle);\n}\n\n.ob-lead {\n color: var(--mj-text-muted);\n font-size: 15px;\n width: 18px;\n text-align: center;\n}\n\n.ob-lead--trigger { color: var(--mj-brand-primary); }\n.ob-lead b { font-family: ui-monospace, monospace; }\n\n.ob-input {\n flex: 1;\n border: none;\n outline: none;\n background: transparent;\n font-size: 16px;\n color: var(--mj-text-primary);\n font-family: inherit;\n}\n\n.ob-input::placeholder { color: var(--mj-text-muted); }\n\n.ob-mode-badge {\n font-size: 10.5px;\n font-weight: 700;\n letter-spacing: .4px;\n text-transform: uppercase;\n padding: 3px 9px;\n border-radius: var(--mj-radius-full, 999px);\n background: color-mix(in srgb, var(--mj-brand-primary) 14%, transparent);\n color: var(--mj-brand-primary);\n white-space: nowrap;\n}\n\n.ob-kbd {\n font-family: inherit;\n font-size: 10.5px;\n font-weight: 600;\n color: var(--mj-text-muted);\n background: var(--mj-bg-surface);\n border: 1px solid var(--mj-border-strong);\n border-bottom-width: 2px;\n border-radius: 5px;\n padding: 1.5px 6px;\n}\n\n.ob-close {\n display: flex;\n align-items: center;\n justify-content: center;\n width: 28px;\n height: 28px;\n padding: 0;\n border: none;\n border-radius: var(--mj-radius-full);\n background: transparent;\n color: var(--mj-text-muted);\n font-size: var(--mj-text-sm);\n cursor: pointer;\n transition: var(--mj-transition-colors);\n flex-shrink: 0;\n}\n.ob-close:hover {\n background: var(--mj-bg-surface-hover);\n color: var(--mj-text-primary);\n}\n\n.ob-scopes {\n display: flex;\n gap: 6px;\n padding: 9px 18px;\n border-bottom: 1px solid var(--mj-border-subtle);\n flex-wrap: wrap;\n}\n\n.ob-scope {\n font-size: 11px;\n padding: 3px 10px;\n border-radius: var(--mj-radius-full, 999px);\n border: 1px solid var(--mj-border-default);\n color: var(--mj-text-secondary);\n cursor: pointer;\n background: transparent;\n}\n\n.ob-scope--on {\n background: color-mix(in srgb, var(--mj-brand-primary) 12%, transparent);\n border-color: var(--mj-brand-primary);\n color: var(--mj-brand-primary);\n font-weight: 600;\n}\n\n.ob-body {\n flex: 1 1 auto;\n min-height: 0;\n overflow-y: auto;\n padding: 6px 0;\n}\n\n.ob-loading,\n.ob-empty {\n padding: 18px;\n text-align: center;\n color: var(--mj-text-muted);\n font-size: 13px;\n}\n\n.ob-group-label {\n font-size: 10.5px;\n font-weight: 700;\n letter-spacing: .6px;\n text-transform: uppercase;\n color: var(--mj-text-muted);\n padding: 10px 18px 5px;\n}\n\n.ob-row {\n display: flex;\n align-items: center;\n gap: 12px;\n padding: 9px 18px;\n cursor: pointer;\n}\n\n/* Rows are focus stops (roving tabindex): the --sel background tracks focus, so\n suppress the default outline but keep a ring for keyboard :focus-visible. */\n.ob-row:focus { outline: none; }\n.ob-row:focus-visible { outline: 2px solid var(--mj-border-focus); outline-offset: -2px; }\n\n.ob-row--sel {\n background: color-mix(in srgb, var(--mj-brand-primary) 9%, transparent);\n box-shadow: inset 3px 0 0 var(--mj-brand-primary);\n}\n\n.ob-ric {\n width: 30px;\n height: 30px;\n border-radius: 8px;\n display: flex;\n align-items: center;\n justify-content: center;\n font-size: 13px;\n flex-shrink: 0;\n background: var(--mj-bg-surface-sunken);\n color: var(--mj-text-secondary);\n}\n\n.ob-row--sel .ob-ric {\n background: color-mix(in srgb, var(--mj-brand-primary) 16%, transparent);\n color: var(--mj-brand-primary);\n}\n\n.ob-rmain { flex: 1; min-width: 0; display: flex; flex-direction: column; }\n\n.ob-rname {\n font-size: 13.5px;\n font-weight: 500;\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n color: var(--mj-text-primary);\n}\n\n.ob-rsub {\n font-size: 11.5px;\n color: var(--mj-text-muted);\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n margin-top: 1px;\n}\n\n.ob-raux { display: flex; align-items: center; gap: 8px; flex-shrink: 0; }\n\n.ob-rtype {\n font-size: 10px;\n font-weight: 600;\n padding: 2px 8px;\n border-radius: var(--mj-radius-full, 999px);\n background: var(--mj-bg-surface-sunken);\n color: var(--mj-text-muted);\n text-transform: capitalize;\n}\n\n.ob-score {\n width: 52px;\n height: 4px;\n border-radius: 2px;\n background: var(--mj-bg-surface-sunken);\n overflow: hidden;\n}\n\n.ob-score i { display: block; height: 100%; background: var(--mj-brand-primary); }\n\n.ob-go {\n font-size: 11px;\n color: var(--mj-text-muted);\n opacity: 0;\n display: flex;\n gap: 6px;\n align-items: center;\n}\n\n.ob-row--sel .ob-go { opacity: 1; }\n\n.ob-hintbar { display: flex; gap: 8px; padding: 12px 18px; flex-wrap: wrap; }\n\n.ob-hint-chip {\n display: flex;\n align-items: center;\n gap: 9px;\n padding: 9px 13px;\n border: 1px dashed var(--mj-border-strong);\n border-radius: 10px;\n cursor: pointer;\n background: transparent;\n}\n\n.ob-hint-chip:hover {\n border-color: var(--mj-brand-primary);\n background: color-mix(in srgb, var(--mj-brand-primary) 6%, transparent);\n}\n\n.ob-hint-chip b { font-family: ui-monospace, monospace; color: var(--mj-brand-primary); font-size: 14px; }\n.ob-hint-chip span { font-size: 12px; color: var(--mj-text-secondary); }\n\n.ob-foot {\n display: flex;\n align-items: center;\n gap: 16px;\n padding: 10px 18px;\n border-top: 1px solid var(--mj-border-subtle);\n background: var(--mj-bg-surface-card);\n font-size: 11.5px;\n color: var(--mj-text-muted);\n}\n\n.ob-k { display: flex; align-items: center; gap: 5px; }\n\n/* Footer gear \u2014 the reverse door to My Profile \u2192 Command Palette. */\n.ob-settings {\n display: flex;\n align-items: center;\n justify-content: center;\n width: 24px;\n height: 24px;\n padding: 0;\n margin-left: auto;\n border: none;\n border-radius: var(--mj-radius-full);\n background: transparent;\n color: var(--mj-text-muted);\n font-size: var(--mj-text-xs);\n cursor: pointer;\n transition: var(--mj-transition-colors);\n}\n.ob-settings:hover {\n background: var(--mj-bg-surface-hover);\n color: var(--mj-text-primary);\n}\n\n/* ========================================\n MOBILE (matches mj-search-overlay's 640px sheet treatment so the two search\n surfaces sit identically on small viewports)\n ======================================== */\n@media (max-width: 640px) {\n .omnibar-palette {\n top: 0;\n left: 0;\n right: 0;\n bottom: 0;\n transform: none;\n width: 100%;\n height: 100dvh;\n max-height: none; /* desktop viewport bound would clamp the full-height sheet */\n border-radius: 0;\n animation: none; /* ob-pop animates a translateX(-50%) that no longer applies */\n display: flex;\n flex-direction: column;\n }\n\n /* Full-height sheet: the results area absorbs all remaining space. */\n .ob-body {\n flex: 1;\n min-height: 0;\n max-height: none;\n }\n\n /* Keyboard chrome is meaningless on touch: esc/\u21B5 chips, per-row 'open \u21B5'\n hints, and the footer's nav-hint spans. The footer itself stays because it\n carries the settings gear \u2014 the only in-surface door to the opt-in toggle,\n which mobile users need too. The \u2715 close button also stays. */\n .ob-kbd,\n .ob-go,\n .ob-k {\n display: none;\n }\n\n /* Touch-friendly hit areas for the surviving controls. */\n .ob-close,\n .ob-settings {\n width: 40px;\n height: 40px;\n font-size: var(--mj-text-base);\n }\n}\n"] }]
814
+ }], null, { inputRef: [{
815
+ type: ViewChild,
816
+ args: ['paletteInput']
817
+ }], Opened: [{
818
+ type: Output
819
+ }], Closed: [{
820
+ type: Output
821
+ }], SettingsRequested: [{
822
+ type: Output
823
+ }] }); })();
824
+ (() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassDebugInfo(OmnibarPaletteComponent, { className: "OmnibarPaletteComponent", filePath: "src/lib/omnibar/omnibar-palette.component.ts", lineNumber: 49 }); })();
825
+ /** Tree-shaking guard for the palette component. */
826
+ export function LoadOmnibarPaletteComponent() {
827
+ // intentional no-op
828
+ }
829
+ //# sourceMappingURL=omnibar-palette.component.js.map