@memberjunction/ng-base-forms 5.38.0 → 5.39.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 (79) hide show
  1. package/README.md +53 -0
  2. package/dist/lib/base-form-component.d.ts +18 -0
  3. package/dist/lib/base-form-component.d.ts.map +1 -1
  4. package/dist/lib/base-form-component.js +31 -2
  5. package/dist/lib/base-form-component.js.map +1 -1
  6. package/dist/lib/container/record-form-container.component.d.ts +14 -0
  7. package/dist/lib/container/record-form-container.component.d.ts.map +1 -1
  8. package/dist/lib/container/record-form-container.component.js +59 -33
  9. package/dist/lib/container/record-form-container.component.js.map +1 -1
  10. package/dist/lib/field/fk-search-utils.d.ts +31 -0
  11. package/dist/lib/field/fk-search-utils.d.ts.map +1 -0
  12. package/dist/lib/field/fk-search-utils.js +47 -0
  13. package/dist/lib/field/fk-search-utils.js.map +1 -0
  14. package/dist/lib/field/form-field.component.d.ts +401 -6
  15. package/dist/lib/field/form-field.component.d.ts.map +1 -1
  16. package/dist/lib/field/form-field.component.js +1646 -214
  17. package/dist/lib/field/form-field.component.js.map +1 -1
  18. package/dist/lib/field/linked-field-options.d.ts +76 -0
  19. package/dist/lib/field/linked-field-options.d.ts.map +1 -0
  20. package/dist/lib/field/linked-field-options.js +80 -0
  21. package/dist/lib/field/linked-field-options.js.map +1 -0
  22. package/dist/lib/host/entity-form-host.component.d.ts +159 -0
  23. package/dist/lib/host/entity-form-host.component.d.ts.map +1 -0
  24. package/dist/lib/host/entity-form-host.component.js +539 -0
  25. package/dist/lib/host/entity-form-host.component.js.map +1 -0
  26. package/dist/lib/isa-related-panel/isa-related-card.component.js +2 -2
  27. package/dist/lib/overlays/base-form-overlay.d.ts +114 -0
  28. package/dist/lib/overlays/base-form-overlay.d.ts.map +1 -0
  29. package/dist/lib/overlays/base-form-overlay.js +227 -0
  30. package/dist/lib/overlays/base-form-overlay.js.map +1 -0
  31. package/dist/lib/overlays/form-dialog.component.d.ts +35 -0
  32. package/dist/lib/overlays/form-dialog.component.d.ts.map +1 -0
  33. package/dist/lib/overlays/form-dialog.component.js +92 -0
  34. package/dist/lib/overlays/form-dialog.component.js.map +1 -0
  35. package/dist/lib/overlays/form-presenter.service.d.ts +37 -0
  36. package/dist/lib/overlays/form-presenter.service.d.ts.map +1 -0
  37. package/dist/lib/overlays/form-presenter.service.js +130 -0
  38. package/dist/lib/overlays/form-presenter.service.js.map +1 -0
  39. package/dist/lib/overlays/form-presenter.types.d.ts +65 -0
  40. package/dist/lib/overlays/form-presenter.types.d.ts.map +1 -0
  41. package/dist/lib/overlays/form-presenter.types.js +25 -0
  42. package/dist/lib/overlays/form-presenter.types.js.map +1 -0
  43. package/dist/lib/overlays/form-slide-in.component.d.ts +38 -0
  44. package/dist/lib/overlays/form-slide-in.component.d.ts.map +1 -0
  45. package/dist/lib/overlays/form-slide-in.component.js +106 -0
  46. package/dist/lib/overlays/form-slide-in.component.js.map +1 -0
  47. package/dist/lib/overlays/form-window.component.d.ts +32 -0
  48. package/dist/lib/overlays/form-window.component.d.ts.map +1 -0
  49. package/dist/lib/overlays/form-window.component.js +93 -0
  50. package/dist/lib/overlays/form-window.component.js.map +1 -0
  51. package/dist/lib/panel/collapsible-panel.component.d.ts +19 -2
  52. package/dist/lib/panel/collapsible-panel.component.d.ts.map +1 -1
  53. package/dist/lib/panel/collapsible-panel.component.js +70 -13
  54. package/dist/lib/panel/collapsible-panel.component.js.map +1 -1
  55. package/dist/lib/resolver/form-resolver.service.d.ts +139 -0
  56. package/dist/lib/resolver/form-resolver.service.d.ts.map +1 -0
  57. package/dist/lib/resolver/form-resolver.service.js +235 -0
  58. package/dist/lib/resolver/form-resolver.service.js.map +1 -0
  59. package/dist/lib/section-manager/section-manager.component.js +2 -2
  60. package/dist/lib/toolbar/form-toolbar.component.js +2 -2
  61. package/dist/lib/types/entity-form-config.d.ts +125 -0
  62. package/dist/lib/types/entity-form-config.d.ts.map +1 -0
  63. package/dist/lib/types/entity-form-config.js +75 -0
  64. package/dist/lib/types/entity-form-config.js.map +1 -0
  65. package/dist/lib/types/form-types.d.ts +24 -0
  66. package/dist/lib/types/form-types.d.ts.map +1 -1
  67. package/dist/lib/types/form-types.js.map +1 -1
  68. package/dist/lib/types/navigation-events.d.ts +46 -2
  69. package/dist/lib/types/navigation-events.d.ts.map +1 -1
  70. package/dist/lib/types/navigation-events.js.map +1 -1
  71. package/dist/module.d.ts +12 -8
  72. package/dist/module.d.ts.map +1 -1
  73. package/dist/module.js +26 -7
  74. package/dist/module.js.map +1 -1
  75. package/dist/public-api.d.ts +11 -0
  76. package/dist/public-api.d.ts.map +1 -1
  77. package/dist/public-api.js +14 -0
  78. package/dist/public-api.js.map +1 -1
  79. package/package.json +17 -13
@@ -1,34 +1,57 @@
1
- import { Component, Input, Output, EventEmitter, ChangeDetectionStrategy, ChangeDetectorRef, inject } from '@angular/core';
1
+ import { Component, Input, Output, EventEmitter, ChangeDetectionStrategy, ChangeDetectorRef, inject, ElementRef, Renderer2 } from '@angular/core';
2
2
  import { BaseAngularComponent } from '@memberjunction/ng-base-types';
3
- import { CompositeKey, KeyValuePair, RunView } from '@memberjunction/core';
4
- import { HighlightSearchMatches } from '@memberjunction/global';
3
+ import { EntityFieldTSType, CompositeKey, KeyValuePair, RunView } from '@memberjunction/core';
4
+ import { BaseEngineRegistry } from '@memberjunction/core';
5
+ import { HighlightSearchMatches, detectRichTextFormat, UUIDsEqual } from '@memberjunction/global';
6
+ import { FormatFKCell, FilterCachedFKRows } from './fk-search-utils';
7
+ import { LinkedFieldOptionsStore } from './linked-field-options';
5
8
  import * as i0 from "@angular/core";
6
9
  import * as i1 from "@angular/common";
7
- const _forTrack0 = ($index, $item) => $item.PrimaryKeyValue;
8
- const _forTrack1 = ($index, $item) => $item.Message;
10
+ import * as i2 from "@memberjunction/ng-markdown";
11
+ import * as i3 from "@memberjunction/ng-code-editor";
12
+ import * as i4 from "@memberjunction/ng-shared-generic";
13
+ const _c0 = a0 => ({ $implicit: a0 });
14
+ const _forTrack0 = ($index, $item) => $item.FieldName;
15
+ const _forTrack1 = ($index, $item) => $item.PrimaryKeyValue;
16
+ const _forTrack2 = ($index, $item) => $item.Message;
9
17
  function MjFormFieldComponent_Conditional_0_Conditional_0_Conditional_1_Template(rf, ctx) { if (rf & 1) {
10
- i0.ɵɵelement(0, "label", 3);
18
+ i0.ɵɵelement(0, "label", 4);
11
19
  } if (rf & 2) {
12
20
  const ctx_r0 = i0.ɵɵnextContext(3);
13
21
  i0.ɵɵproperty("innerHTML", ctx_r0.HighlightedDisplayName, i0.ɵɵsanitizeHtml);
14
22
  } }
15
- function MjFormFieldComponent_Conditional_0_Conditional_0_Conditional_3_Template(rf, ctx) { if (rf & 1) {
23
+ function MjFormFieldComponent_Conditional_0_Conditional_0_Conditional_3_Conditional_1_Template(rf, ctx) { if (rf & 1) {
16
24
  const _r2 = i0.ɵɵgetCurrentView();
17
- i0.ɵɵelementStart(0, "span", 5)(1, "a", 6);
18
- i0.ɵɵlistener("click", function MjFormFieldComponent_Conditional_0_Conditional_0_Conditional_3_Template_a_click_1_listener($event) { i0.ɵɵrestoreView(_r2); const ctx_r0 = i0.ɵɵnextContext(3); return i0.ɵɵresetView(ctx_r0.OnRecordLinkClick($event)); });
19
- i0.ɵɵtext(2);
20
- i0.ɵɵelementEnd()();
25
+ i0.ɵɵelementStart(0, "a", 8);
26
+ i0.ɵɵlistener("click", function MjFormFieldComponent_Conditional_0_Conditional_0_Conditional_3_Conditional_1_Template_a_click_0_listener($event) { i0.ɵɵrestoreView(_r2); const ctx_r0 = i0.ɵɵnextContext(4); return i0.ɵɵresetView(ctx_r0.OnRecordLinkClick($event)); });
27
+ i0.ɵɵtext(1);
28
+ i0.ɵɵelementEnd();
21
29
  } if (rf & 2) {
22
- const ctx_r0 = i0.ɵɵnextContext(3);
23
- i0.ɵɵadvance(2);
30
+ const ctx_r0 = i0.ɵɵnextContext(4);
31
+ i0.ɵɵadvance();
32
+ i0.ɵɵtextInterpolate1(" ", ctx_r0.FKDisplayName, " ");
33
+ } }
34
+ function MjFormFieldComponent_Conditional_0_Conditional_0_Conditional_3_Conditional_2_Template(rf, ctx) { if (rf & 1) {
35
+ i0.ɵɵtext(0);
36
+ } if (rf & 2) {
37
+ const ctx_r0 = i0.ɵɵnextContext(4);
24
38
  i0.ɵɵtextInterpolate1(" ", ctx_r0.FKDisplayName, " ");
25
39
  } }
40
+ function MjFormFieldComponent_Conditional_0_Conditional_0_Conditional_3_Template(rf, ctx) { if (rf & 1) {
41
+ i0.ɵɵelementStart(0, "span", 6);
42
+ i0.ɵɵconditionalCreate(1, MjFormFieldComponent_Conditional_0_Conditional_0_Conditional_3_Conditional_1_Template, 2, 1, "a", 7)(2, MjFormFieldComponent_Conditional_0_Conditional_0_Conditional_3_Conditional_2_Template, 1, 1);
43
+ i0.ɵɵelementEnd();
44
+ } if (rf & 2) {
45
+ const ctx_r0 = i0.ɵɵnextContext(3);
46
+ i0.ɵɵadvance();
47
+ i0.ɵɵconditional(ctx_r0.RecordLinksEnabled ? 1 : 2);
48
+ } }
26
49
  function MjFormFieldComponent_Conditional_0_Conditional_0_Conditional_4_Case_0_Template(rf, ctx) { if (rf & 1) {
27
50
  const _r3 = i0.ɵɵgetCurrentView();
28
- i0.ɵɵelementStart(0, "span", 5)(1, "a", 7);
51
+ i0.ɵɵelementStart(0, "span", 6)(1, "a", 9);
29
52
  i0.ɵɵlistener("click", function MjFormFieldComponent_Conditional_0_Conditional_0_Conditional_4_Case_0_Template_a_click_1_listener($event) { i0.ɵɵrestoreView(_r3); const ctx_r0 = i0.ɵɵnextContext(4); return i0.ɵɵresetView(ctx_r0.OnEmailLinkClick($event)); });
30
53
  i0.ɵɵtext(2);
31
- i0.ɵɵelement(3, "i", 8);
54
+ i0.ɵɵelement(3, "i", 10);
32
55
  i0.ɵɵelementEnd()();
33
56
  } if (rf & 2) {
34
57
  const ctx_r0 = i0.ɵɵnextContext(4);
@@ -37,31 +60,46 @@ function MjFormFieldComponent_Conditional_0_Conditional_0_Conditional_4_Case_0_T
37
60
  } }
38
61
  function MjFormFieldComponent_Conditional_0_Conditional_0_Conditional_4_Case_1_Template(rf, ctx) { if (rf & 1) {
39
62
  const _r4 = i0.ɵɵgetCurrentView();
40
- i0.ɵɵelementStart(0, "span", 5)(1, "a", 9);
63
+ i0.ɵɵelementStart(0, "span", 6)(1, "a", 11);
41
64
  i0.ɵɵlistener("click", function MjFormFieldComponent_Conditional_0_Conditional_0_Conditional_4_Case_1_Template_a_click_1_listener($event) { i0.ɵɵrestoreView(_r4); const ctx_r0 = i0.ɵɵnextContext(4); return i0.ɵɵresetView(ctx_r0.OnUrlLinkClick($event)); });
42
65
  i0.ɵɵtext(2);
43
- i0.ɵɵelement(3, "i", 10);
66
+ i0.ɵɵelement(3, "i", 12);
44
67
  i0.ɵɵelementEnd()();
45
68
  } if (rf & 2) {
46
69
  const ctx_r0 = i0.ɵɵnextContext(4);
47
70
  i0.ɵɵadvance(2);
48
71
  i0.ɵɵtextInterpolate1(" ", ctx_r0.FormatValue(), " ");
49
72
  } }
50
- function MjFormFieldComponent_Conditional_0_Conditional_0_Conditional_4_Case_2_Template(rf, ctx) { if (rf & 1) {
73
+ function MjFormFieldComponent_Conditional_0_Conditional_0_Conditional_4_Case_2_Conditional_1_Template(rf, ctx) { if (rf & 1) {
51
74
  const _r5 = i0.ɵɵgetCurrentView();
52
- i0.ɵɵelementStart(0, "span", 5)(1, "a", 11);
53
- i0.ɵɵlistener("click", function MjFormFieldComponent_Conditional_0_Conditional_0_Conditional_4_Case_2_Template_a_click_1_listener($event) { i0.ɵɵrestoreView(_r5); const ctx_r0 = i0.ɵɵnextContext(4); return i0.ɵɵresetView(ctx_r0.OnRecordLinkClick($event)); });
54
- i0.ɵɵtext(2);
55
- i0.ɵɵelement(3, "i", 10);
56
- i0.ɵɵelementEnd()();
75
+ i0.ɵɵelementStart(0, "a", 14);
76
+ i0.ɵɵlistener("click", function MjFormFieldComponent_Conditional_0_Conditional_0_Conditional_4_Case_2_Conditional_1_Template_a_click_0_listener($event) { i0.ɵɵrestoreView(_r5); const ctx_r0 = i0.ɵɵnextContext(5); return i0.ɵɵresetView(ctx_r0.OnRecordLinkClick($event)); });
77
+ i0.ɵɵtext(1);
78
+ i0.ɵɵelement(2, "i", 12);
79
+ i0.ɵɵelementEnd();
57
80
  } if (rf & 2) {
58
- const ctx_r0 = i0.ɵɵnextContext(4);
59
- i0.ɵɵadvance(2);
81
+ const ctx_r0 = i0.ɵɵnextContext(5);
82
+ i0.ɵɵadvance();
60
83
  i0.ɵɵtextInterpolate1(" ", ctx_r0.FormatValue(), " ");
61
84
  } }
85
+ function MjFormFieldComponent_Conditional_0_Conditional_0_Conditional_4_Case_2_Conditional_2_Template(rf, ctx) { if (rf & 1) {
86
+ i0.ɵɵtext(0);
87
+ } if (rf & 2) {
88
+ const ctx_r0 = i0.ɵɵnextContext(5);
89
+ i0.ɵɵtextInterpolate1(" ", ctx_r0.FormatValue(), " ");
90
+ } }
91
+ function MjFormFieldComponent_Conditional_0_Conditional_0_Conditional_4_Case_2_Template(rf, ctx) { if (rf & 1) {
92
+ i0.ɵɵelementStart(0, "span", 6);
93
+ i0.ɵɵconditionalCreate(1, MjFormFieldComponent_Conditional_0_Conditional_0_Conditional_4_Case_2_Conditional_1_Template, 3, 1, "a", 13)(2, MjFormFieldComponent_Conditional_0_Conditional_0_Conditional_4_Case_2_Conditional_2_Template, 1, 1);
94
+ i0.ɵɵelementEnd();
95
+ } if (rf & 2) {
96
+ const ctx_r0 = i0.ɵɵnextContext(4);
97
+ i0.ɵɵadvance();
98
+ i0.ɵɵconditional(ctx_r0.RecordLinksEnabled ? 1 : 2);
99
+ } }
62
100
  function MjFormFieldComponent_Conditional_0_Conditional_0_Conditional_4_Case_3_Conditional_0_Template(rf, ctx) { if (rf & 1) {
63
- i0.ɵɵelementStart(0, "span", 5)(1, "div", 13);
64
- i0.ɵɵelement(2, "input", 14);
101
+ i0.ɵɵelementStart(0, "span", 6)(1, "div", 19);
102
+ i0.ɵɵelement(2, "input", 20);
65
103
  i0.ɵɵelementEnd()();
66
104
  } if (rf & 2) {
67
105
  const ctx_r0 = i0.ɵɵnextContext(5);
@@ -69,7 +107,32 @@ function MjFormFieldComponent_Conditional_0_Conditional_0_Conditional_4_Case_3_C
69
107
  i0.ɵɵproperty("checked", !!ctx_r0.Value);
70
108
  } }
71
109
  function MjFormFieldComponent_Conditional_0_Conditional_0_Conditional_4_Case_3_Conditional_1_Template(rf, ctx) { if (rf & 1) {
72
- i0.ɵɵelementStart(0, "span", 12);
110
+ i0.ɵɵelementStart(0, "div", 15);
111
+ i0.ɵɵelement(1, "mj-markdown", 21);
112
+ i0.ɵɵelementEnd();
113
+ } if (rf & 2) {
114
+ const ctx_r0 = i0.ɵɵnextContext(5);
115
+ i0.ɵɵadvance();
116
+ i0.ɵɵproperty("data", ctx_r0.FormatValue());
117
+ } }
118
+ function MjFormFieldComponent_Conditional_0_Conditional_0_Conditional_4_Case_3_Conditional_2_Template(rf, ctx) { if (rf & 1) {
119
+ i0.ɵɵelement(0, "div", 16);
120
+ i0.ɵɵpipe(1, "mjSafeRichHtml");
121
+ } if (rf & 2) {
122
+ const ctx_r0 = i0.ɵɵnextContext(5);
123
+ i0.ɵɵproperty("innerHTML", i0.ɵɵpipeBind1(1, 1, ctx_r0.FormatValue()), i0.ɵɵsanitizeHtml);
124
+ } }
125
+ function MjFormFieldComponent_Conditional_0_Conditional_0_Conditional_4_Case_3_Conditional_3_Template(rf, ctx) { if (rf & 1) {
126
+ i0.ɵɵelementStart(0, "div", 17);
127
+ i0.ɵɵelement(1, "mj-code-editor", 22);
128
+ i0.ɵɵelementEnd();
129
+ } if (rf & 2) {
130
+ const ctx_r0 = i0.ɵɵnextContext(5);
131
+ i0.ɵɵadvance();
132
+ i0.ɵɵproperty("value", ctx_r0.FormatValue())("language", ctx_r0.CodeEditorLanguage)("readonly", true);
133
+ } }
134
+ function MjFormFieldComponent_Conditional_0_Conditional_0_Conditional_4_Case_3_Conditional_4_Template(rf, ctx) { if (rf & 1) {
135
+ i0.ɵɵelementStart(0, "span", 18);
73
136
  i0.ɵɵtext(1);
74
137
  i0.ɵɵelementEnd();
75
138
  } if (rf & 2) {
@@ -77,8 +140,8 @@ function MjFormFieldComponent_Conditional_0_Conditional_0_Conditional_4_Case_3_C
77
140
  i0.ɵɵadvance();
78
141
  i0.ɵɵtextInterpolate(ctx_r0.FormatValue());
79
142
  } }
80
- function MjFormFieldComponent_Conditional_0_Conditional_0_Conditional_4_Case_3_Conditional_2_Template(rf, ctx) { if (rf & 1) {
81
- i0.ɵɵelementStart(0, "span", 5);
143
+ function MjFormFieldComponent_Conditional_0_Conditional_0_Conditional_4_Case_3_Conditional_5_Template(rf, ctx) { if (rf & 1) {
144
+ i0.ɵɵelementStart(0, "span", 6);
82
145
  i0.ɵɵtext(1);
83
146
  i0.ɵɵelementEnd();
84
147
  } if (rf & 2) {
@@ -87,23 +150,23 @@ function MjFormFieldComponent_Conditional_0_Conditional_0_Conditional_4_Case_3_C
87
150
  i0.ɵɵtextInterpolate(ctx_r0.FormatValue());
88
151
  } }
89
152
  function MjFormFieldComponent_Conditional_0_Conditional_0_Conditional_4_Case_3_Template(rf, ctx) { if (rf & 1) {
90
- i0.ɵɵconditionalCreate(0, MjFormFieldComponent_Conditional_0_Conditional_0_Conditional_4_Case_3_Conditional_0_Template, 3, 1, "span", 5)(1, MjFormFieldComponent_Conditional_0_Conditional_0_Conditional_4_Case_3_Conditional_1_Template, 2, 1, "span", 12)(2, MjFormFieldComponent_Conditional_0_Conditional_0_Conditional_4_Case_3_Conditional_2_Template, 2, 1, "span", 5);
153
+ i0.ɵɵconditionalCreate(0, MjFormFieldComponent_Conditional_0_Conditional_0_Conditional_4_Case_3_Conditional_0_Template, 3, 1, "span", 6)(1, MjFormFieldComponent_Conditional_0_Conditional_0_Conditional_4_Case_3_Conditional_1_Template, 2, 1, "div", 15)(2, MjFormFieldComponent_Conditional_0_Conditional_0_Conditional_4_Case_3_Conditional_2_Template, 2, 3, "div", 16)(3, MjFormFieldComponent_Conditional_0_Conditional_0_Conditional_4_Case_3_Conditional_3_Template, 2, 3, "div", 17)(4, MjFormFieldComponent_Conditional_0_Conditional_0_Conditional_4_Case_3_Conditional_4_Template, 2, 1, "span", 18)(5, MjFormFieldComponent_Conditional_0_Conditional_0_Conditional_4_Case_3_Conditional_5_Template, 2, 1, "span", 6);
91
154
  } if (rf & 2) {
92
155
  const ctx_r0 = i0.ɵɵnextContext(4);
93
- i0.ɵɵconditional(ctx_r0.Type === "checkbox" ? 0 : ctx_r0.IsLongText ? 1 : 2);
156
+ i0.ɵɵconditional(ctx_r0.Type === "checkbox" ? 0 : ctx_r0.RichTextMode === "markdown" ? 1 : ctx_r0.RichTextMode === "html" ? 2 : ctx_r0.RichTextMode === "code" ? 3 : ctx_r0.IsLongText ? 4 : 5);
94
157
  } }
95
158
  function MjFormFieldComponent_Conditional_0_Conditional_0_Conditional_4_Template(rf, ctx) { if (rf & 1) {
96
- i0.ɵɵconditionalCreate(0, MjFormFieldComponent_Conditional_0_Conditional_0_Conditional_4_Case_0_Template, 4, 1, "span", 5)(1, MjFormFieldComponent_Conditional_0_Conditional_0_Conditional_4_Case_1_Template, 4, 1, "span", 5)(2, MjFormFieldComponent_Conditional_0_Conditional_0_Conditional_4_Case_2_Template, 4, 1, "span", 5)(3, MjFormFieldComponent_Conditional_0_Conditional_0_Conditional_4_Case_3_Template, 3, 1);
159
+ i0.ɵɵconditionalCreate(0, MjFormFieldComponent_Conditional_0_Conditional_0_Conditional_4_Case_0_Template, 4, 1, "span", 6)(1, MjFormFieldComponent_Conditional_0_Conditional_0_Conditional_4_Case_1_Template, 4, 1, "span", 6)(2, MjFormFieldComponent_Conditional_0_Conditional_0_Conditional_4_Case_2_Template, 3, 1, "span", 6)(3, MjFormFieldComponent_Conditional_0_Conditional_0_Conditional_4_Case_3_Template, 6, 1);
97
160
  } if (rf & 2) {
98
161
  let tmp_3_0;
99
162
  const ctx_r0 = i0.ɵɵnextContext(3);
100
163
  i0.ɵɵconditional((tmp_3_0 = ctx_r0.LinkType) === "Email" ? 0 : tmp_3_0 === "URL" ? 1 : tmp_3_0 === "Record" ? 2 : 3);
101
164
  } }
102
165
  function MjFormFieldComponent_Conditional_0_Conditional_0_Template(rf, ctx) { if (rf & 1) {
103
- i0.ɵɵelementStart(0, "div", 2);
104
- i0.ɵɵconditionalCreate(1, MjFormFieldComponent_Conditional_0_Conditional_0_Conditional_1_Template, 1, 1, "label", 3);
105
- i0.ɵɵelementStart(2, "div", 4);
106
- i0.ɵɵconditionalCreate(3, MjFormFieldComponent_Conditional_0_Conditional_0_Conditional_3_Template, 3, 1, "span", 5)(4, MjFormFieldComponent_Conditional_0_Conditional_0_Conditional_4_Template, 4, 1);
166
+ i0.ɵɵelementStart(0, "div", 3);
167
+ i0.ɵɵconditionalCreate(1, MjFormFieldComponent_Conditional_0_Conditional_0_Conditional_1_Template, 1, 1, "label", 4);
168
+ i0.ɵɵelementStart(2, "div", 5);
169
+ i0.ɵɵconditionalCreate(3, MjFormFieldComponent_Conditional_0_Conditional_0_Conditional_3_Template, 3, 1, "span", 6)(4, MjFormFieldComponent_Conditional_0_Conditional_0_Conditional_4_Template, 4, 1);
107
170
  i0.ɵɵelementEnd()();
108
171
  } if (rf & 2) {
109
172
  const ctx_r0 = i0.ɵɵnextContext(2);
@@ -114,123 +177,473 @@ function MjFormFieldComponent_Conditional_0_Conditional_0_Template(rf, ctx) { if
114
177
  i0.ɵɵconditional(ctx_r0.IsFKWithNameField ? 3 : 4);
115
178
  } }
116
179
  function MjFormFieldComponent_Conditional_0_Conditional_1_Conditional_1_Template(rf, ctx) { if (rf & 1) {
117
- i0.ɵɵelement(0, "label", 3);
180
+ i0.ɵɵelement(0, "label", 4);
118
181
  } if (rf & 2) {
119
182
  const ctx_r0 = i0.ɵɵnextContext(3);
120
183
  i0.ɵɵproperty("innerHTML", ctx_r0.HighlightedDisplayName, i0.ɵɵsanitizeHtml);
121
184
  } }
122
- function MjFormFieldComponent_Conditional_0_Conditional_1_Conditional_3_Conditional_2_Template(rf, ctx) { if (rf & 1) {
123
- const _r7 = i0.ɵɵgetCurrentView();
124
- i0.ɵɵelementStart(0, "button", 24);
125
- i0.ɵɵlistener("mousedown", function MjFormFieldComponent_Conditional_0_Conditional_1_Conditional_3_Conditional_2_Template_button_mousedown_0_listener($event) { i0.ɵɵrestoreView(_r7); const ctx_r0 = i0.ɵɵnextContext(4); return i0.ɵɵresetView(ctx_r0.OnFKClearClick($event)); });
126
- i0.ɵɵelement(1, "i", 25);
127
- i0.ɵɵelementEnd();
185
+ function MjFormFieldComponent_Conditional_0_Conditional_1_Conditional_3_Conditional_1_Template(rf, ctx) { if (rf & 1) {
186
+ i0.ɵɵelement(0, "i", 29);
128
187
  } }
129
188
  function MjFormFieldComponent_Conditional_0_Conditional_1_Conditional_3_Conditional_3_Template(rf, ctx) { if (rf & 1) {
130
- i0.ɵɵelement(0, "i", 22);
189
+ const _r7 = i0.ɵɵgetCurrentView();
190
+ i0.ɵɵelementStart(0, "button", 35);
191
+ i0.ɵɵlistener("mousedown", function MjFormFieldComponent_Conditional_0_Conditional_1_Conditional_3_Conditional_3_Template_button_mousedown_0_listener($event) { i0.ɵɵrestoreView(_r7); const ctx_r0 = i0.ɵɵnextContext(4); return i0.ɵɵresetView(ctx_r0.OnFKScopeToggle($event)); });
192
+ i0.ɵɵelement(1, "i", 36);
193
+ i0.ɵɵelementStart(2, "span", 37);
194
+ i0.ɵɵtext(3);
195
+ i0.ɵɵelementEnd();
196
+ i0.ɵɵelement(4, "i", 38);
197
+ i0.ɵɵelementEnd();
198
+ } if (rf & 2) {
199
+ const ctx_r0 = i0.ɵɵnextContext(4);
200
+ i0.ɵɵclassProp("mj-fk-scope-pill--open", ctx_r0.FKShowScopeMenu);
201
+ i0.ɵɵproperty("title", "Searching " + ctx_r0.FKSearchFieldLabel + " \u2014 click to change");
202
+ i0.ɵɵadvance(3);
203
+ i0.ɵɵtextInterpolate(ctx_r0.FKSearchFieldLabel);
204
+ i0.ɵɵadvance();
205
+ i0.ɵɵclassProp("fa-chevron-up", ctx_r0.FKShowScopeMenu)("fa-chevron-down", !ctx_r0.FKShowScopeMenu);
131
206
  } }
132
- function MjFormFieldComponent_Conditional_0_Conditional_1_Conditional_3_Conditional_4_For_2_Template(rf, ctx) { if (rf & 1) {
207
+ function MjFormFieldComponent_Conditional_0_Conditional_1_Conditional_3_Conditional_4_Template(rf, ctx) { if (rf & 1) {
133
208
  const _r8 = i0.ɵɵgetCurrentView();
134
- i0.ɵɵelementStart(0, "div", 28);
135
- i0.ɵɵlistener("mousedown", function MjFormFieldComponent_Conditional_0_Conditional_1_Conditional_3_Conditional_4_For_2_Template_div_mousedown_0_listener($event) { const suggestion_r9 = i0.ɵɵrestoreView(_r8).$implicit; const ctx_r0 = i0.ɵɵnextContext(5); return i0.ɵɵresetView(ctx_r0.OnFKSelectItem(suggestion_r9, $event)); });
209
+ i0.ɵɵelementStart(0, "button", 39);
210
+ i0.ɵɵlistener("mousedown", function MjFormFieldComponent_Conditional_0_Conditional_1_Conditional_3_Conditional_4_Template_button_mousedown_0_listener($event) { i0.ɵɵrestoreView(_r8); const ctx_r0 = i0.ɵɵnextContext(4); return i0.ɵɵresetView(ctx_r0.OnFKClearClick($event)); });
211
+ i0.ɵɵelement(1, "i", 40);
212
+ i0.ɵɵelementEnd();
213
+ } }
214
+ function MjFormFieldComponent_Conditional_0_Conditional_1_Conditional_3_Conditional_5_Template(rf, ctx) { if (rf & 1) {
215
+ i0.ɵɵelement(0, "i", 33);
216
+ } }
217
+ function MjFormFieldComponent_Conditional_0_Conditional_1_Conditional_3_Conditional_6_Conditional_1_For_4_Conditional_0_ng_container_0_Template(rf, ctx) { if (rf & 1) {
218
+ i0.ɵɵelementContainer(0);
219
+ } }
220
+ function MjFormFieldComponent_Conditional_0_Conditional_1_Conditional_3_Conditional_6_Conditional_1_For_4_Conditional_0_Template(rf, ctx) { if (rf & 1) {
221
+ i0.ɵɵtemplate(0, MjFormFieldComponent_Conditional_0_Conditional_1_Conditional_3_Conditional_6_Conditional_1_For_4_Conditional_0_ng_container_0_Template, 1, 0, "ng-container", 50);
222
+ } if (rf & 2) {
223
+ const f_r9 = i0.ɵɵnextContext().$implicit;
224
+ i0.ɵɵnextContext(2);
225
+ const scopeRow_r10 = i0.ɵɵreference(3);
226
+ i0.ɵɵproperty("ngTemplateOutlet", scopeRow_r10)("ngTemplateOutletContext", i0.ɵɵpureFunction1(2, _c0, f_r9));
227
+ } }
228
+ function MjFormFieldComponent_Conditional_0_Conditional_1_Conditional_3_Conditional_6_Conditional_1_For_4_Template(rf, ctx) { if (rf & 1) {
229
+ i0.ɵɵconditionalCreate(0, MjFormFieldComponent_Conditional_0_Conditional_1_Conditional_3_Conditional_6_Conditional_1_For_4_Conditional_0_Template, 1, 4, "ng-container");
230
+ } if (rf & 2) {
231
+ const f_r9 = ctx.$implicit;
232
+ i0.ɵɵconditional(f_r9.Group === "shown" ? 0 : -1);
233
+ } }
234
+ function MjFormFieldComponent_Conditional_0_Conditional_1_Conditional_3_Conditional_6_Conditional_1_Conditional_5_For_4_Conditional_0_ng_container_0_Template(rf, ctx) { if (rf & 1) {
235
+ i0.ɵɵelementContainer(0);
236
+ } }
237
+ function MjFormFieldComponent_Conditional_0_Conditional_1_Conditional_3_Conditional_6_Conditional_1_Conditional_5_For_4_Conditional_0_Template(rf, ctx) { if (rf & 1) {
238
+ i0.ɵɵtemplate(0, MjFormFieldComponent_Conditional_0_Conditional_1_Conditional_3_Conditional_6_Conditional_1_Conditional_5_For_4_Conditional_0_ng_container_0_Template, 1, 0, "ng-container", 50);
239
+ } if (rf & 2) {
240
+ const f_r11 = i0.ɵɵnextContext().$implicit;
241
+ i0.ɵɵnextContext(3);
242
+ const scopeRow_r10 = i0.ɵɵreference(3);
243
+ i0.ɵɵproperty("ngTemplateOutlet", scopeRow_r10)("ngTemplateOutletContext", i0.ɵɵpureFunction1(2, _c0, f_r11));
244
+ } }
245
+ function MjFormFieldComponent_Conditional_0_Conditional_1_Conditional_3_Conditional_6_Conditional_1_Conditional_5_For_4_Template(rf, ctx) { if (rf & 1) {
246
+ i0.ɵɵconditionalCreate(0, MjFormFieldComponent_Conditional_0_Conditional_1_Conditional_3_Conditional_6_Conditional_1_Conditional_5_For_4_Conditional_0_Template, 1, 4, "ng-container");
247
+ } if (rf & 2) {
248
+ const f_r11 = ctx.$implicit;
249
+ i0.ɵɵconditional(f_r11.Group === "other" ? 0 : -1);
250
+ } }
251
+ function MjFormFieldComponent_Conditional_0_Conditional_1_Conditional_3_Conditional_6_Conditional_1_Conditional_5_Template(rf, ctx) { if (rf & 1) {
252
+ i0.ɵɵelement(0, "div", 51);
253
+ i0.ɵɵelementStart(1, "div", 49);
254
+ i0.ɵɵtext(2, "Other fields");
255
+ i0.ɵɵelementEnd();
256
+ i0.ɵɵrepeaterCreate(3, MjFormFieldComponent_Conditional_0_Conditional_1_Conditional_3_Conditional_6_Conditional_1_Conditional_5_For_4_Template, 1, 1, null, null, _forTrack0);
257
+ } if (rf & 2) {
258
+ const ctx_r0 = i0.ɵɵnextContext(6);
259
+ i0.ɵɵadvance(3);
260
+ i0.ɵɵrepeater(ctx_r0.FKSearchableFields);
261
+ } }
262
+ function MjFormFieldComponent_Conditional_0_Conditional_1_Conditional_3_Conditional_6_Conditional_1_Template(rf, ctx) { if (rf & 1) {
263
+ i0.ɵɵelementStart(0, "div", 48)(1, "div", 49);
264
+ i0.ɵɵtext(2, "Columns shown");
265
+ i0.ɵɵelementEnd();
266
+ i0.ɵɵrepeaterCreate(3, MjFormFieldComponent_Conditional_0_Conditional_1_Conditional_3_Conditional_6_Conditional_1_For_4_Template, 1, 1, null, null, _forTrack0);
267
+ i0.ɵɵconditionalCreate(5, MjFormFieldComponent_Conditional_0_Conditional_1_Conditional_3_Conditional_6_Conditional_1_Conditional_5_Template, 5, 0);
268
+ i0.ɵɵelementEnd();
269
+ } if (rf & 2) {
270
+ const ctx_r0 = i0.ɵɵnextContext(5);
271
+ i0.ɵɵclassProp("mj-fk-scope-menu--bottom", ctx_r0.OpenAbove);
272
+ i0.ɵɵadvance(3);
273
+ i0.ɵɵrepeater(ctx_r0.FKSearchableFields);
274
+ i0.ɵɵadvance(2);
275
+ i0.ɵɵconditional(ctx_r0.FKHasOtherSearchableFields ? 5 : -1);
276
+ } }
277
+ function MjFormFieldComponent_Conditional_0_Conditional_1_Conditional_3_Conditional_6_ng_template_2_Conditional_2_Template(rf, ctx) { if (rf & 1) {
278
+ const _r14 = i0.ɵɵgetCurrentView();
279
+ i0.ɵɵelementStart(0, "button", 57);
280
+ i0.ɵɵlistener("mousedown", function MjFormFieldComponent_Conditional_0_Conditional_1_Conditional_3_Conditional_6_ng_template_2_Conditional_2_Template_button_mousedown_0_listener($event) { i0.ɵɵrestoreView(_r14); const f_r13 = i0.ɵɵnextContext().$implicit; const ctx_r0 = i0.ɵɵnextContext(5); return i0.ɵɵresetView(ctx_r0.MoveFKColumn($event, f_r13.FieldName, -1)); });
281
+ i0.ɵɵelement(1, "i", 58);
282
+ i0.ɵɵelementEnd();
283
+ i0.ɵɵelementStart(2, "button", 59);
284
+ i0.ɵɵlistener("mousedown", function MjFormFieldComponent_Conditional_0_Conditional_1_Conditional_3_Conditional_6_ng_template_2_Conditional_2_Template_button_mousedown_2_listener($event) { i0.ɵɵrestoreView(_r14); const f_r13 = i0.ɵɵnextContext().$implicit; const ctx_r0 = i0.ɵɵnextContext(5); return i0.ɵɵresetView(ctx_r0.MoveFKColumn($event, f_r13.FieldName, 1)); });
285
+ i0.ɵɵelement(3, "i", 60);
286
+ i0.ɵɵelementEnd();
287
+ } if (rf & 2) {
288
+ const f_r13 = i0.ɵɵnextContext().$implicit;
289
+ const ctx_r0 = i0.ɵɵnextContext(5);
290
+ i0.ɵɵproperty("disabled", !ctx_r0.CanMoveFKColumnUp(f_r13.FieldName));
291
+ i0.ɵɵadvance(2);
292
+ i0.ɵɵproperty("disabled", !ctx_r0.CanMoveFKColumnDown(f_r13.FieldName));
293
+ } }
294
+ function MjFormFieldComponent_Conditional_0_Conditional_1_Conditional_3_Conditional_6_ng_template_2_Conditional_7_Template(rf, ctx) { if (rf & 1) {
295
+ const _r15 = i0.ɵɵgetCurrentView();
296
+ i0.ɵɵelementStart(0, "button", 61);
297
+ i0.ɵɵlistener("mousedown", function MjFormFieldComponent_Conditional_0_Conditional_1_Conditional_3_Conditional_6_ng_template_2_Conditional_7_Template_button_mousedown_0_listener($event) { i0.ɵɵrestoreView(_r15); const f_r13 = i0.ɵɵnextContext().$implicit; const ctx_r0 = i0.ɵɵnextContext(5); return i0.ɵɵresetView(ctx_r0.OnFKColumnToggle($event, f_r13)); });
298
+ i0.ɵɵelement(1, "i", 62);
299
+ i0.ɵɵelementEnd();
300
+ } if (rf & 2) {
301
+ const f_r13 = i0.ɵɵnextContext().$implicit;
302
+ const ctx_r0 = i0.ɵɵnextContext(5);
303
+ i0.ɵɵclassProp("mj-fk-col-toggle--on", ctx_r0.IsFKColumnVisible(f_r13));
304
+ i0.ɵɵproperty("title", ctx_r0.IsFKColumnVisible(f_r13) ? "Hide this column" : "Show as a column");
305
+ i0.ɵɵadvance();
306
+ i0.ɵɵclassProp("fa-eye", ctx_r0.IsFKColumnVisible(f_r13))("fa-eye-slash", !ctx_r0.IsFKColumnVisible(f_r13));
307
+ } }
308
+ function MjFormFieldComponent_Conditional_0_Conditional_1_Conditional_3_Conditional_6_ng_template_2_Template(rf, ctx) { if (rf & 1) {
309
+ const _r12 = i0.ɵɵgetCurrentView();
310
+ i0.ɵɵelementStart(0, "div", 52);
311
+ i0.ɵɵlistener("mousedown", function MjFormFieldComponent_Conditional_0_Conditional_1_Conditional_3_Conditional_6_ng_template_2_Template_div_mousedown_0_listener($event) { const f_r13 = i0.ɵɵrestoreView(_r12).$implicit; const ctx_r0 = i0.ɵɵnextContext(5); return i0.ɵɵresetView(ctx_r0.OnFKScopeSelect($event, f_r13)); });
312
+ i0.ɵɵelementStart(1, "span", 53);
313
+ i0.ɵɵconditionalCreate(2, MjFormFieldComponent_Conditional_0_Conditional_1_Conditional_3_Conditional_6_ng_template_2_Conditional_2_Template, 4, 2);
314
+ i0.ɵɵelementEnd();
315
+ i0.ɵɵelement(3, "i");
316
+ i0.ɵɵelementStart(4, "span", 54);
317
+ i0.ɵɵtext(5);
318
+ i0.ɵɵelementEnd();
319
+ i0.ɵɵelementStart(6, "span", 55);
320
+ i0.ɵɵconditionalCreate(7, MjFormFieldComponent_Conditional_0_Conditional_1_Conditional_3_Conditional_6_ng_template_2_Conditional_7_Template, 2, 7, "button", 56);
321
+ i0.ɵɵelementEnd()();
322
+ } if (rf & 2) {
323
+ const f_r13 = ctx.$implicit;
324
+ const ctx_r0 = i0.ɵɵnextContext(5);
325
+ i0.ɵɵclassProp("mj-fk-scope-mi--on", ctx_r0.IsFKScopeActive(f_r13));
326
+ i0.ɵɵadvance(2);
327
+ i0.ɵɵconditional(f_r13.Group === "shown" ? 2 : -1);
328
+ i0.ɵɵadvance();
329
+ i0.ɵɵclassMap(f_r13.Icon + " mj-fk-scope-mi-icon");
330
+ i0.ɵɵadvance(2);
331
+ i0.ɵɵtextInterpolate(f_r13.Label);
332
+ i0.ɵɵadvance(2);
333
+ i0.ɵɵconditional(ctx_r0.CanToggleFKColumn(f_r13) ? 7 : -1);
334
+ } }
335
+ function MjFormFieldComponent_Conditional_0_Conditional_1_Conditional_3_Conditional_6_Conditional_4_Conditional_6_Template(rf, ctx) { if (rf & 1) {
336
+ i0.ɵɵelement(0, "i", 70);
337
+ } if (rf & 2) {
338
+ const ctx_r0 = i0.ɵɵnextContext(6);
339
+ i0.ɵɵclassMap(ctx_r0.FKSelectedSuggestion.Icon);
340
+ } }
341
+ function MjFormFieldComponent_Conditional_0_Conditional_1_Conditional_3_Conditional_6_Conditional_4_Conditional_8_Template(rf, ctx) { if (rf & 1) {
342
+ i0.ɵɵelementStart(0, "span", 68);
136
343
  i0.ɵɵtext(1);
137
344
  i0.ɵɵelementEnd();
138
345
  } if (rf & 2) {
139
- const suggestion_r9 = ctx.$implicit;
346
+ const ctx_r0 = i0.ɵɵnextContext(6);
140
347
  i0.ɵɵadvance();
141
- i0.ɵɵtextInterpolate1(" ", suggestion_r9.DisplayName, " ");
348
+ i0.ɵɵtextInterpolate(ctx_r0.FKSelectedSuggestion.ExtraColumns[0].Value);
142
349
  } }
143
- function MjFormFieldComponent_Conditional_0_Conditional_1_Conditional_3_Conditional_4_Template(rf, ctx) { if (rf & 1) {
144
- i0.ɵɵelementStart(0, "div", 26);
145
- i0.ɵɵrepeaterCreate(1, MjFormFieldComponent_Conditional_0_Conditional_1_Conditional_3_Conditional_4_For_2_Template, 2, 1, "div", 27, _forTrack0);
350
+ function MjFormFieldComponent_Conditional_0_Conditional_1_Conditional_3_Conditional_6_Conditional_4_Template(rf, ctx) { if (rf & 1) {
351
+ const _r16 = i0.ɵɵgetCurrentView();
352
+ i0.ɵɵelementStart(0, "div", 43)(1, "div", 63);
353
+ i0.ɵɵelement(2, "i", 64);
354
+ i0.ɵɵelementStart(3, "span");
355
+ i0.ɵɵtext(4, "Currently selected");
356
+ i0.ɵɵelementEnd()();
357
+ i0.ɵɵelementStart(5, "div", 65);
358
+ i0.ɵɵlistener("mousedown", function MjFormFieldComponent_Conditional_0_Conditional_1_Conditional_3_Conditional_6_Conditional_4_Template_div_mousedown_5_listener($event) { i0.ɵɵrestoreView(_r16); const ctx_r0 = i0.ɵɵnextContext(5); return i0.ɵɵresetView(ctx_r0.OnFKSelectItem(ctx_r0.FKSelectedSuggestion, $event)); });
359
+ i0.ɵɵconditionalCreate(6, MjFormFieldComponent_Conditional_0_Conditional_1_Conditional_3_Conditional_6_Conditional_4_Conditional_6_Template, 1, 2, "i", 66);
360
+ i0.ɵɵelement(7, "span", 67);
361
+ i0.ɵɵconditionalCreate(8, MjFormFieldComponent_Conditional_0_Conditional_1_Conditional_3_Conditional_6_Conditional_4_Conditional_8_Template, 2, 1, "span", 68);
362
+ i0.ɵɵelementStart(9, "button", 69);
363
+ i0.ɵɵlistener("mousedown", function MjFormFieldComponent_Conditional_0_Conditional_1_Conditional_3_Conditional_6_Conditional_4_Template_button_mousedown_9_listener($event) { i0.ɵɵrestoreView(_r16); const ctx_r0 = i0.ɵɵnextContext(5); return i0.ɵɵresetView(ctx_r0.OnFKClearClick($event)); });
364
+ i0.ɵɵelement(10, "i", 40);
365
+ i0.ɵɵelementEnd()()();
366
+ } if (rf & 2) {
367
+ const ctx_r0 = i0.ɵɵnextContext(5);
368
+ i0.ɵɵadvance(6);
369
+ i0.ɵɵconditional(ctx_r0.FKSelectedSuggestion.Icon ? 6 : -1);
370
+ i0.ɵɵadvance();
371
+ i0.ɵɵproperty("innerHTML", ctx_r0.FKSelectedSuggestion.HighlightedName, i0.ɵɵsanitizeHtml);
372
+ i0.ɵɵadvance();
373
+ i0.ɵɵconditional(ctx_r0.FKSelectedSuggestion.ExtraColumns.length && ctx_r0.FKSelectedSuggestion.ExtraColumns[0].Value ? 8 : -1);
374
+ } }
375
+ function MjFormFieldComponent_Conditional_0_Conditional_1_Conditional_3_Conditional_6_Conditional_5_Template(rf, ctx) { if (rf & 1) {
376
+ i0.ɵɵelementStart(0, "div", 44);
377
+ i0.ɵɵelement(1, "i", 71);
378
+ i0.ɵɵelementStart(2, "span");
379
+ i0.ɵɵtext(3, "Searching\u2026");
380
+ i0.ɵɵelementEnd()();
381
+ } }
382
+ function MjFormFieldComponent_Conditional_0_Conditional_1_Conditional_3_Conditional_6_Conditional_6_Template(rf, ctx) { if (rf & 1) {
383
+ i0.ɵɵelementStart(0, "div", 45);
384
+ i0.ɵɵelement(1, "i", 72);
385
+ i0.ɵɵelementStart(2, "span");
386
+ i0.ɵɵtext(3, "No matches");
387
+ i0.ɵɵelementEnd()();
388
+ } }
389
+ function MjFormFieldComponent_Conditional_0_Conditional_1_Conditional_3_Conditional_6_Conditional_7_Conditional_3_Template(rf, ctx) { if (rf & 1) {
390
+ i0.ɵɵelement(0, "div", 75);
391
+ } }
392
+ function MjFormFieldComponent_Conditional_0_Conditional_1_Conditional_3_Conditional_6_Conditional_7_For_5_Template(rf, ctx) { if (rf & 1) {
393
+ const _r17 = i0.ɵɵgetCurrentView();
394
+ i0.ɵɵelementStart(0, "div", 78);
395
+ i0.ɵɵlistener("mousedown", function MjFormFieldComponent_Conditional_0_Conditional_1_Conditional_3_Conditional_6_Conditional_7_For_5_Template_div_mousedown_0_listener($event) { const col_r18 = i0.ɵɵrestoreView(_r17).$implicit; const ctx_r0 = i0.ɵɵnextContext(6); return i0.ɵɵresetView(ctx_r0.OnFKHeaderSort($event, col_r18)); });
396
+ i0.ɵɵelementStart(1, "span", 79);
397
+ i0.ɵɵtext(2);
398
+ i0.ɵɵelementEnd();
399
+ i0.ɵɵelement(3, "i");
400
+ i0.ɵɵelementStart(4, "span", 80);
401
+ i0.ɵɵlistener("mousedown", function MjFormFieldComponent_Conditional_0_Conditional_1_Conditional_3_Conditional_6_Conditional_7_For_5_Template_span_mousedown_4_listener($event) { const col_r18 = i0.ɵɵrestoreView(_r17).$implicit; const ctx_r0 = i0.ɵɵnextContext(6); return i0.ɵɵresetView(ctx_r0.OnFKColResizeStart($event, col_r18)); });
402
+ i0.ɵɵelementEnd()();
403
+ } if (rf & 2) {
404
+ const col_r18 = ctx.$implicit;
405
+ const ɵ$index_216_r19 = ctx.$index;
406
+ const ctx_r0 = i0.ɵɵnextContext(6);
407
+ i0.ɵɵproperty("title", "Click to sort by " + ctx_r0.FKColumnHeaders[ɵ$index_216_r19]);
408
+ i0.ɵɵadvance(2);
409
+ i0.ɵɵtextInterpolate(ctx_r0.FKColumnHeaders[ɵ$index_216_r19]);
410
+ i0.ɵɵadvance();
411
+ i0.ɵɵclassMap(ctx_r0.FKSortIcon(col_r18));
412
+ } }
413
+ function MjFormFieldComponent_Conditional_0_Conditional_1_Conditional_3_Conditional_6_Conditional_7_For_7_Conditional_1_Conditional_1_Template(rf, ctx) { if (rf & 1) {
414
+ i0.ɵɵelement(0, "i");
415
+ } if (rf & 2) {
416
+ const suggestion_r21 = i0.ɵɵnextContext(2).$implicit;
417
+ i0.ɵɵclassMap(suggestion_r21.Icon);
418
+ } }
419
+ function MjFormFieldComponent_Conditional_0_Conditional_1_Conditional_3_Conditional_6_Conditional_7_For_7_Conditional_1_Template(rf, ctx) { if (rf & 1) {
420
+ i0.ɵɵelementStart(0, "div", 82);
421
+ i0.ɵɵconditionalCreate(1, MjFormFieldComponent_Conditional_0_Conditional_1_Conditional_3_Conditional_6_Conditional_7_For_7_Conditional_1_Conditional_1_Template, 1, 2, "i", 83);
422
+ i0.ɵɵelementEnd();
423
+ } if (rf & 2) {
424
+ const suggestion_r21 = i0.ɵɵnextContext().$implicit;
425
+ i0.ɵɵadvance();
426
+ i0.ɵɵconditional(suggestion_r21.Icon ? 1 : -1);
427
+ } }
428
+ function MjFormFieldComponent_Conditional_0_Conditional_1_Conditional_3_Conditional_6_Conditional_7_For_7_For_3_Conditional_0_Conditional_1_Template(rf, ctx) { if (rf & 1) {
429
+ i0.ɵɵelement(0, "i", 87);
430
+ } }
431
+ function MjFormFieldComponent_Conditional_0_Conditional_1_Conditional_3_Conditional_6_Conditional_7_For_7_For_3_Conditional_0_Template(rf, ctx) { if (rf & 1) {
432
+ i0.ɵɵelementStart(0, "div", 86);
433
+ i0.ɵɵconditionalCreate(1, MjFormFieldComponent_Conditional_0_Conditional_1_Conditional_3_Conditional_6_Conditional_7_For_7_For_3_Conditional_0_Conditional_1_Template, 1, 0, "i", 87);
434
+ i0.ɵɵelement(2, "span", 88);
435
+ i0.ɵɵelementEnd();
436
+ } if (rf & 2) {
437
+ const ctx_r22 = i0.ɵɵnextContext();
438
+ const col_r24 = ctx_r22.$implicit;
439
+ const ɵ$index_235_r25 = ctx_r22.$index;
440
+ const ɵ$count_235_r26 = ctx_r22.$count;
441
+ const suggestion_r21 = i0.ɵɵnextContext().$implicit;
442
+ const ctx_r0 = i0.ɵɵnextContext(6);
443
+ i0.ɵɵclassProp("mj-fk-cell--fill", ctx_r0.FKColumnFillsTrack(col_r24, ɵ$index_235_r25 === ɵ$count_235_r26 - 1));
444
+ i0.ɵɵadvance();
445
+ i0.ɵɵconditional(ctx_r0.IsFKRowSelected(suggestion_r21) ? 1 : -1);
446
+ i0.ɵɵadvance();
447
+ i0.ɵɵproperty("innerHTML", suggestion_r21.HighlightedName, i0.ɵɵsanitizeHtml);
448
+ } }
449
+ function MjFormFieldComponent_Conditional_0_Conditional_1_Conditional_3_Conditional_6_Conditional_7_For_7_For_3_Conditional_1_Template(rf, ctx) { if (rf & 1) {
450
+ i0.ɵɵelementStart(0, "div", 89);
451
+ i0.ɵɵelement(1, "span", 88);
452
+ i0.ɵɵelementEnd();
453
+ } if (rf & 2) {
454
+ let tmp_30_0;
455
+ let tmp_31_0;
456
+ const ctx_r22 = i0.ɵɵnextContext();
457
+ const col_r24 = ctx_r22.$implicit;
458
+ const ɵ$index_235_r25 = ctx_r22.$index;
459
+ const ɵ$count_235_r26 = ctx_r22.$count;
460
+ const suggestion_r21 = i0.ɵɵnextContext().$implicit;
461
+ const ctx_r0 = i0.ɵɵnextContext(6);
462
+ i0.ɵɵclassProp("mj-fk-cell--fill", ctx_r0.FKColumnFillsTrack(col_r24, ɵ$index_235_r25 === ɵ$count_235_r26 - 1));
463
+ i0.ɵɵproperty("title", ((tmp_30_0 = ctx_r0.FKCellFor(suggestion_r21, col_r24)) == null ? null : tmp_30_0.Value) || "");
464
+ i0.ɵɵadvance();
465
+ i0.ɵɵproperty("innerHTML", ((tmp_31_0 = ctx_r0.FKCellFor(suggestion_r21, col_r24)) == null ? null : tmp_31_0.HighlightedValue) || "", i0.ɵɵsanitizeHtml);
466
+ } }
467
+ function MjFormFieldComponent_Conditional_0_Conditional_1_Conditional_3_Conditional_6_Conditional_7_For_7_For_3_Template(rf, ctx) { if (rf & 1) {
468
+ i0.ɵɵconditionalCreate(0, MjFormFieldComponent_Conditional_0_Conditional_1_Conditional_3_Conditional_6_Conditional_7_For_7_For_3_Conditional_0_Template, 3, 4, "div", 84)(1, MjFormFieldComponent_Conditional_0_Conditional_1_Conditional_3_Conditional_6_Conditional_7_For_7_For_3_Conditional_1_Template, 2, 4, "div", 85);
469
+ } if (rf & 2) {
470
+ const col_r24 = ctx.$implicit;
471
+ const ctx_r0 = i0.ɵɵnextContext(7);
472
+ i0.ɵɵconditional(col_r24 === ctx_r0.FKNameField ? 0 : 1);
473
+ } }
474
+ function MjFormFieldComponent_Conditional_0_Conditional_1_Conditional_3_Conditional_6_Conditional_7_For_7_Template(rf, ctx) { if (rf & 1) {
475
+ const _r20 = i0.ɵɵgetCurrentView();
476
+ i0.ɵɵelementStart(0, "div", 81);
477
+ i0.ɵɵlistener("mousedown", function MjFormFieldComponent_Conditional_0_Conditional_1_Conditional_3_Conditional_6_Conditional_7_For_7_Template_div_mousedown_0_listener($event) { const suggestion_r21 = i0.ɵɵrestoreView(_r20).$implicit; const ctx_r0 = i0.ɵɵnextContext(6); return i0.ɵɵresetView(ctx_r0.OnFKSelectItem(suggestion_r21, $event)); })("mouseenter", function MjFormFieldComponent_Conditional_0_Conditional_1_Conditional_3_Conditional_6_Conditional_7_For_7_Template_div_mouseenter_0_listener() { const ɵ$index_226_r22 = i0.ɵɵrestoreView(_r20).$index; const ctx_r0 = i0.ɵɵnextContext(6); return i0.ɵɵresetView(ctx_r0.FKActiveIndex = ɵ$index_226_r22); });
478
+ i0.ɵɵconditionalCreate(1, MjFormFieldComponent_Conditional_0_Conditional_1_Conditional_3_Conditional_6_Conditional_7_For_7_Conditional_1_Template, 2, 1, "div", 82);
479
+ i0.ɵɵrepeaterCreate(2, MjFormFieldComponent_Conditional_0_Conditional_1_Conditional_3_Conditional_6_Conditional_7_For_7_For_3_Template, 2, 1, null, null, i0.ɵɵrepeaterTrackByIdentity);
480
+ i0.ɵɵelementEnd();
481
+ } if (rf & 2) {
482
+ const suggestion_r21 = ctx.$implicit;
483
+ const ɵ$index_226_r22 = ctx.$index;
484
+ const ctx_r0 = i0.ɵɵnextContext(6);
485
+ i0.ɵɵclassProp("mj-fk-grid-row--active", ɵ$index_226_r22 === ctx_r0.FKActiveIndex)("mj-fk-grid-row--selected", ctx_r0.IsFKRowSelected(suggestion_r21));
486
+ i0.ɵɵadvance();
487
+ i0.ɵɵconditional(ctx_r0.FKHasIconColumn ? 1 : -1);
488
+ i0.ɵɵadvance();
489
+ i0.ɵɵrepeater(ctx_r0.FKColumnFields);
490
+ } }
491
+ function MjFormFieldComponent_Conditional_0_Conditional_1_Conditional_3_Conditional_6_Conditional_7_Template(rf, ctx) { if (rf & 1) {
492
+ i0.ɵɵelementStart(0, "div", 46)(1, "div", 73)(2, "div", 74);
493
+ i0.ɵɵconditionalCreate(3, MjFormFieldComponent_Conditional_0_Conditional_1_Conditional_3_Conditional_6_Conditional_7_Conditional_3_Template, 1, 0, "div", 75);
494
+ i0.ɵɵrepeaterCreate(4, MjFormFieldComponent_Conditional_0_Conditional_1_Conditional_3_Conditional_6_Conditional_7_For_5_Template, 5, 4, "div", 76, i0.ɵɵrepeaterTrackByIdentity);
495
+ i0.ɵɵelementEnd();
496
+ i0.ɵɵrepeaterCreate(6, MjFormFieldComponent_Conditional_0_Conditional_1_Conditional_3_Conditional_6_Conditional_7_For_7_Template, 4, 5, "div", 77, _forTrack1);
497
+ i0.ɵɵelementEnd()();
498
+ } if (rf & 2) {
499
+ const ctx_r0 = i0.ɵɵnextContext(5);
500
+ i0.ɵɵadvance();
501
+ i0.ɵɵstyleProp("grid-template-columns", ctx_r0.FKGridTemplateColumns);
502
+ i0.ɵɵadvance(2);
503
+ i0.ɵɵconditional(ctx_r0.FKHasIconColumn ? 3 : -1);
504
+ i0.ɵɵadvance();
505
+ i0.ɵɵrepeater(ctx_r0.FKColumnFields);
506
+ i0.ɵɵadvance(2);
507
+ i0.ɵɵrepeater(ctx_r0.FKSuggestions);
508
+ } }
509
+ function MjFormFieldComponent_Conditional_0_Conditional_1_Conditional_3_Conditional_6_Conditional_8_Template(rf, ctx) { if (rf & 1) {
510
+ const _r27 = i0.ɵɵgetCurrentView();
511
+ i0.ɵɵelementStart(0, "button", 90);
512
+ i0.ɵɵlistener("mousedown", function MjFormFieldComponent_Conditional_0_Conditional_1_Conditional_3_Conditional_6_Conditional_8_Template_button_mousedown_0_listener($event) { i0.ɵɵrestoreView(_r27); const ctx_r0 = i0.ɵɵnextContext(5); return i0.ɵɵresetView(ctx_r0.OnFKCreateNew($event)); });
513
+ i0.ɵɵelement(1, "i", 91);
514
+ i0.ɵɵelementStart(2, "span", 92);
515
+ i0.ɵɵtext(3);
516
+ i0.ɵɵelementEnd()();
517
+ } if (rf & 2) {
518
+ const ctx_r0 = i0.ɵɵnextContext(5);
519
+ i0.ɵɵproperty("title", ctx_r0.FKCreateLabel);
520
+ i0.ɵɵadvance(3);
521
+ i0.ɵɵtextInterpolate(ctx_r0.FKCreateLabel);
522
+ } }
523
+ function MjFormFieldComponent_Conditional_0_Conditional_1_Conditional_3_Conditional_6_Template(rf, ctx) { if (rf & 1) {
524
+ i0.ɵɵelementStart(0, "div", 41);
525
+ i0.ɵɵconditionalCreate(1, MjFormFieldComponent_Conditional_0_Conditional_1_Conditional_3_Conditional_6_Conditional_1_Template, 6, 3, "div", 42);
526
+ i0.ɵɵtemplate(2, MjFormFieldComponent_Conditional_0_Conditional_1_Conditional_3_Conditional_6_ng_template_2_Template, 8, 7, "ng-template", null, 0, i0.ɵɵtemplateRefExtractor);
527
+ i0.ɵɵconditionalCreate(4, MjFormFieldComponent_Conditional_0_Conditional_1_Conditional_3_Conditional_6_Conditional_4_Template, 11, 3, "div", 43);
528
+ i0.ɵɵconditionalCreate(5, MjFormFieldComponent_Conditional_0_Conditional_1_Conditional_3_Conditional_6_Conditional_5_Template, 4, 0, "div", 44);
529
+ i0.ɵɵconditionalCreate(6, MjFormFieldComponent_Conditional_0_Conditional_1_Conditional_3_Conditional_6_Conditional_6_Template, 4, 0, "div", 45);
530
+ i0.ɵɵconditionalCreate(7, MjFormFieldComponent_Conditional_0_Conditional_1_Conditional_3_Conditional_6_Conditional_7_Template, 8, 3, "div", 46);
531
+ i0.ɵɵconditionalCreate(8, MjFormFieldComponent_Conditional_0_Conditional_1_Conditional_3_Conditional_6_Conditional_8_Template, 4, 2, "button", 47);
146
532
  i0.ɵɵelementEnd();
147
533
  } if (rf & 2) {
148
534
  const ctx_r0 = i0.ɵɵnextContext(4);
149
- i0.ɵɵclassProp("mj-fk-dropdown--above", ctx_r0.OpenAbove);
535
+ i0.ɵɵclassProp("mj-fk-dropdown--above", ctx_r0.OpenAbove)("mj-fk-dropdown--scope-open", ctx_r0.FKShowScopeMenu);
150
536
  i0.ɵɵproperty("ngStyle", ctx_r0.DropdownPositionStyle);
151
537
  i0.ɵɵadvance();
152
- i0.ɵɵrepeater(ctx_r0.FKSuggestions);
538
+ i0.ɵɵconditional(ctx_r0.FKShowScopeMenu ? 1 : -1);
539
+ i0.ɵɵadvance(3);
540
+ i0.ɵɵconditional(ctx_r0.FKSelectedSuggestion && !ctx_r0.FKLoading ? 4 : -1);
541
+ i0.ɵɵadvance();
542
+ i0.ɵɵconditional(ctx_r0.FKLoading ? 5 : -1);
543
+ i0.ɵɵadvance();
544
+ i0.ɵɵconditional(!ctx_r0.FKLoading && ctx_r0.FKNoMatches ? 6 : -1);
545
+ i0.ɵɵadvance();
546
+ i0.ɵɵconditional(!ctx_r0.FKLoading && ctx_r0.FKSuggestions.length > 0 ? 7 : -1);
547
+ i0.ɵɵadvance();
548
+ i0.ɵɵconditional(ctx_r0.CanCreateFK ? 8 : -1);
153
549
  } }
154
550
  function MjFormFieldComponent_Conditional_0_Conditional_1_Conditional_3_Template(rf, ctx) { if (rf & 1) {
155
551
  const _r6 = i0.ɵɵgetCurrentView();
156
- i0.ɵɵelementStart(0, "div", 19)(1, "input", 20);
157
- i0.ɵɵlistener("input", function MjFormFieldComponent_Conditional_0_Conditional_1_Conditional_3_Template_input_input_1_listener($event) { i0.ɵɵrestoreView(_r6); const ctx_r0 = i0.ɵɵnextContext(3); return i0.ɵɵresetView(ctx_r0.OnFKInput($event)); })("focus", function MjFormFieldComponent_Conditional_0_Conditional_1_Conditional_3_Template_input_focus_1_listener($event) { i0.ɵɵrestoreView(_r6); const ctx_r0 = i0.ɵɵnextContext(3); return i0.ɵɵresetView(ctx_r0.OnFKFocus($event)); })("blur", function MjFormFieldComponent_Conditional_0_Conditional_1_Conditional_3_Template_input_blur_1_listener() { i0.ɵɵrestoreView(_r6); const ctx_r0 = i0.ɵɵnextContext(3); return i0.ɵɵresetView(ctx_r0.OnFKBlur()); });
552
+ i0.ɵɵelementStart(0, "div", 28);
553
+ i0.ɵɵconditionalCreate(1, MjFormFieldComponent_Conditional_0_Conditional_1_Conditional_3_Conditional_1_Template, 1, 0, "i", 29);
554
+ i0.ɵɵelementStart(2, "input", 30);
555
+ i0.ɵɵlistener("input", function MjFormFieldComponent_Conditional_0_Conditional_1_Conditional_3_Template_input_input_2_listener($event) { i0.ɵɵrestoreView(_r6); const ctx_r0 = i0.ɵɵnextContext(3); return i0.ɵɵresetView(ctx_r0.OnFKInput($event)); })("focus", function MjFormFieldComponent_Conditional_0_Conditional_1_Conditional_3_Template_input_focus_2_listener($event) { i0.ɵɵrestoreView(_r6); const ctx_r0 = i0.ɵɵnextContext(3); return i0.ɵɵresetView(ctx_r0.OnFKFocus($event)); })("blur", function MjFormFieldComponent_Conditional_0_Conditional_1_Conditional_3_Template_input_blur_2_listener() { i0.ɵɵrestoreView(_r6); const ctx_r0 = i0.ɵɵnextContext(3); return i0.ɵɵresetView(ctx_r0.OnFKBlur()); })("keydown", function MjFormFieldComponent_Conditional_0_Conditional_1_Conditional_3_Template_input_keydown_2_listener($event) { i0.ɵɵrestoreView(_r6); const ctx_r0 = i0.ɵɵnextContext(3); return i0.ɵɵresetView(ctx_r0.OnFKKeydown($event)); });
158
556
  i0.ɵɵelementEnd();
159
- i0.ɵɵconditionalCreate(2, MjFormFieldComponent_Conditional_0_Conditional_1_Conditional_3_Conditional_2_Template, 2, 0, "button", 21)(3, MjFormFieldComponent_Conditional_0_Conditional_1_Conditional_3_Conditional_3_Template, 1, 0, "i", 22);
160
- i0.ɵɵconditionalCreate(4, MjFormFieldComponent_Conditional_0_Conditional_1_Conditional_3_Conditional_4_Template, 3, 3, "div", 23);
557
+ i0.ɵɵconditionalCreate(3, MjFormFieldComponent_Conditional_0_Conditional_1_Conditional_3_Conditional_3_Template, 5, 8, "button", 31);
558
+ i0.ɵɵconditionalCreate(4, MjFormFieldComponent_Conditional_0_Conditional_1_Conditional_3_Conditional_4_Template, 2, 0, "button", 32)(5, MjFormFieldComponent_Conditional_0_Conditional_1_Conditional_3_Conditional_5_Template, 1, 0, "i", 33);
559
+ i0.ɵɵconditionalCreate(6, MjFormFieldComponent_Conditional_0_Conditional_1_Conditional_3_Conditional_6_Template, 9, 11, "div", 34);
161
560
  i0.ɵɵelementEnd();
162
561
  } if (rf & 2) {
163
562
  const ctx_r0 = i0.ɵɵnextContext(3);
164
- i0.ɵɵclassProp("mj-fk-search--matched", ctx_r0.FKIsMatched);
563
+ i0.ɵɵclassProp("mj-fk-search--matched", ctx_r0.FKHasLinkedValue)("mj-fk-search--scoped", ctx_r0.FKFocused && ctx_r0.FKSearchableFields.length > 1);
564
+ i0.ɵɵadvance();
565
+ i0.ɵɵconditional(ctx_r0.FKHasLinkedValue && !(ctx_r0.FKFocused && ctx_r0.FKSearchableFields.length > 1) ? 1 : -1);
165
566
  i0.ɵɵadvance();
567
+ i0.ɵɵclassProp("mj-forms-field-input--linked", ctx_r0.FKHasLinkedValue);
166
568
  i0.ɵɵproperty("value", ctx_r0.FKSearchText);
167
569
  i0.ɵɵadvance();
168
- i0.ɵɵconditional(ctx_r0.FKSearchText ? 2 : 3);
570
+ i0.ɵɵconditional(ctx_r0.FKFocused && ctx_r0.FKSearchableFields.length > 1 ? 3 : -1);
571
+ i0.ɵɵadvance();
572
+ i0.ɵɵconditional(ctx_r0.FKSearchText ? 4 : 5);
169
573
  i0.ɵɵadvance(2);
170
- i0.ɵɵconditional(ctx_r0.ShowFKDropdown && ctx_r0.FKSuggestions.length > 0 ? 4 : -1);
574
+ i0.ɵɵconditional(ctx_r0.ShowFKDropdown ? 6 : -1);
575
+ } }
576
+ function MjFormFieldComponent_Conditional_0_Conditional_1_Conditional_4_Template(rf, ctx) { if (rf & 1) {
577
+ const _r28 = i0.ɵɵgetCurrentView();
578
+ i0.ɵɵelementStart(0, "mj-code-editor", 93);
579
+ i0.ɵɵlistener("change", function MjFormFieldComponent_Conditional_0_Conditional_1_Conditional_4_Template_mj_code_editor_change_0_listener($event) { i0.ɵɵrestoreView(_r28); const ctx_r0 = i0.ɵɵnextContext(3); return i0.ɵɵresetView(ctx_r0.OnCodeEditorChange($event)); });
580
+ i0.ɵɵelementEnd();
581
+ } if (rf & 2) {
582
+ const ctx_r0 = i0.ɵɵnextContext(3);
583
+ i0.ɵɵproperty("value", ctx_r0.FormatValue())("language", ctx_r0.CodeEditorLanguage);
171
584
  } }
172
- function MjFormFieldComponent_Conditional_0_Conditional_1_Conditional_4_Case_0_Template(rf, ctx) { if (rf & 1) {
173
- const _r10 = i0.ɵɵgetCurrentView();
174
- i0.ɵɵelementStart(0, "input", 33);
175
- i0.ɵɵlistener("input", function MjFormFieldComponent_Conditional_0_Conditional_1_Conditional_4_Case_0_Template_input_input_0_listener($event) { i0.ɵɵrestoreView(_r10); const ctx_r0 = i0.ɵɵnextContext(4); return i0.ɵɵresetView(ctx_r0.OnInputChange($event)); });
585
+ function MjFormFieldComponent_Conditional_0_Conditional_1_Conditional_5_Case_0_Template(rf, ctx) { if (rf & 1) {
586
+ const _r29 = i0.ɵɵgetCurrentView();
587
+ i0.ɵɵelementStart(0, "input", 98);
588
+ i0.ɵɵlistener("input", function MjFormFieldComponent_Conditional_0_Conditional_1_Conditional_5_Case_0_Template_input_input_0_listener($event) { i0.ɵɵrestoreView(_r29); const ctx_r0 = i0.ɵɵnextContext(4); return i0.ɵɵresetView(ctx_r0.OnInputChange($event)); });
176
589
  i0.ɵɵelementEnd();
177
590
  } if (rf & 2) {
178
591
  const ctx_r0 = i0.ɵɵnextContext(4);
179
592
  i0.ɵɵproperty("value", ctx_r0.FormatValue());
180
593
  } }
181
- function MjFormFieldComponent_Conditional_0_Conditional_1_Conditional_4_Case_1_Template(rf, ctx) { if (rf & 1) {
182
- const _r11 = i0.ɵɵgetCurrentView();
183
- i0.ɵɵelementStart(0, "textarea", 34);
184
- i0.ɵɵlistener("input", function MjFormFieldComponent_Conditional_0_Conditional_1_Conditional_4_Case_1_Template_textarea_input_0_listener($event) { i0.ɵɵrestoreView(_r11); const ctx_r0 = i0.ɵɵnextContext(4); return i0.ɵɵresetView(ctx_r0.OnInputChange($event)); });
594
+ function MjFormFieldComponent_Conditional_0_Conditional_1_Conditional_5_Case_1_Template(rf, ctx) { if (rf & 1) {
595
+ const _r30 = i0.ɵɵgetCurrentView();
596
+ i0.ɵɵelementStart(0, "textarea", 99);
597
+ i0.ɵɵlistener("input", function MjFormFieldComponent_Conditional_0_Conditional_1_Conditional_5_Case_1_Template_textarea_input_0_listener($event) { i0.ɵɵrestoreView(_r30); const ctx_r0 = i0.ɵɵnextContext(4); return i0.ɵɵresetView(ctx_r0.OnInputChange($event)); });
185
598
  i0.ɵɵelementEnd();
186
599
  } if (rf & 2) {
187
600
  const ctx_r0 = i0.ɵɵnextContext(4);
188
601
  i0.ɵɵproperty("value", ctx_r0.FormatValue());
189
602
  } }
190
- function MjFormFieldComponent_Conditional_0_Conditional_1_Conditional_4_Case_2_Template(rf, ctx) { if (rf & 1) {
191
- const _r12 = i0.ɵɵgetCurrentView();
192
- i0.ɵɵelementStart(0, "input", 35);
193
- i0.ɵɵlistener("change", function MjFormFieldComponent_Conditional_0_Conditional_1_Conditional_4_Case_2_Template_input_change_0_listener($event) { i0.ɵɵrestoreView(_r12); const ctx_r0 = i0.ɵɵnextContext(4); return i0.ɵɵresetView(ctx_r0.OnNumberChange($event)); });
603
+ function MjFormFieldComponent_Conditional_0_Conditional_1_Conditional_5_Case_2_Template(rf, ctx) { if (rf & 1) {
604
+ const _r31 = i0.ɵɵgetCurrentView();
605
+ i0.ɵɵelementStart(0, "input", 100);
606
+ i0.ɵɵlistener("change", function MjFormFieldComponent_Conditional_0_Conditional_1_Conditional_5_Case_2_Template_input_change_0_listener($event) { i0.ɵɵrestoreView(_r31); const ctx_r0 = i0.ɵɵnextContext(4); return i0.ɵɵresetView(ctx_r0.OnNumberChange($event)); });
194
607
  i0.ɵɵelementEnd();
195
608
  } if (rf & 2) {
196
609
  const ctx_r0 = i0.ɵɵnextContext(4);
197
610
  i0.ɵɵproperty("value", ctx_r0.Value);
198
611
  } }
199
- function MjFormFieldComponent_Conditional_0_Conditional_1_Conditional_4_Case_3_Template(rf, ctx) { if (rf & 1) {
200
- const _r13 = i0.ɵɵgetCurrentView();
201
- i0.ɵɵelementStart(0, "input", 36);
202
- i0.ɵɵlistener("change", function MjFormFieldComponent_Conditional_0_Conditional_1_Conditional_4_Case_3_Template_input_change_0_listener($event) { i0.ɵɵrestoreView(_r13); const ctx_r0 = i0.ɵɵnextContext(4); return i0.ɵɵresetView(ctx_r0.OnDateChange($event)); });
612
+ function MjFormFieldComponent_Conditional_0_Conditional_1_Conditional_5_Case_3_Template(rf, ctx) { if (rf & 1) {
613
+ const _r32 = i0.ɵɵgetCurrentView();
614
+ i0.ɵɵelementStart(0, "input", 101);
615
+ i0.ɵɵlistener("change", function MjFormFieldComponent_Conditional_0_Conditional_1_Conditional_5_Case_3_Template_input_change_0_listener($event) { i0.ɵɵrestoreView(_r32); const ctx_r0 = i0.ɵɵnextContext(4); return i0.ɵɵresetView(ctx_r0.OnDateChange($event)); });
203
616
  i0.ɵɵelementEnd();
204
617
  } if (rf & 2) {
205
618
  const ctx_r0 = i0.ɵɵnextContext(4);
206
619
  i0.ɵɵproperty("value", ctx_r0.DateInputValue);
207
620
  } }
208
- function MjFormFieldComponent_Conditional_0_Conditional_1_Conditional_4_Case_4_Template(rf, ctx) { if (rf & 1) {
209
- const _r14 = i0.ɵɵgetCurrentView();
210
- i0.ɵɵelementStart(0, "div", 13)(1, "input", 37);
211
- i0.ɵɵlistener("change", function MjFormFieldComponent_Conditional_0_Conditional_1_Conditional_4_Case_4_Template_input_change_1_listener($event) { i0.ɵɵrestoreView(_r14); const ctx_r0 = i0.ɵɵnextContext(4); return i0.ɵɵresetView(ctx_r0.OnCheckboxChange($event)); });
621
+ function MjFormFieldComponent_Conditional_0_Conditional_1_Conditional_5_Case_4_Template(rf, ctx) { if (rf & 1) {
622
+ const _r33 = i0.ɵɵgetCurrentView();
623
+ i0.ɵɵelementStart(0, "div", 19)(1, "input", 102);
624
+ i0.ɵɵlistener("change", function MjFormFieldComponent_Conditional_0_Conditional_1_Conditional_5_Case_4_Template_input_change_1_listener($event) { i0.ɵɵrestoreView(_r33); const ctx_r0 = i0.ɵɵnextContext(4); return i0.ɵɵresetView(ctx_r0.OnCheckboxChange($event)); });
212
625
  i0.ɵɵelementEnd()();
213
626
  } if (rf & 2) {
214
627
  const ctx_r0 = i0.ɵɵnextContext(4);
215
628
  i0.ɵɵadvance();
216
629
  i0.ɵɵproperty("checked", !!ctx_r0.Value);
217
630
  } }
218
- function MjFormFieldComponent_Conditional_0_Conditional_1_Conditional_4_Case_5_Conditional_4_For_2_Template(rf, ctx) { if (rf & 1) {
219
- const _r16 = i0.ɵɵgetCurrentView();
220
- i0.ɵɵelementStart(0, "div", 28);
221
- i0.ɵɵlistener("mousedown", function MjFormFieldComponent_Conditional_0_Conditional_1_Conditional_4_Case_5_Conditional_4_For_2_Template_div_mousedown_0_listener($event) { const option_r17 = i0.ɵɵrestoreView(_r16).$implicit; const ctx_r0 = i0.ɵɵnextContext(6); return i0.ɵɵresetView(ctx_r0.OnSelectOptionClick(option_r17, $event)); });
631
+ function MjFormFieldComponent_Conditional_0_Conditional_1_Conditional_5_Case_5_Conditional_4_For_2_Template(rf, ctx) { if (rf & 1) {
632
+ const _r35 = i0.ɵɵgetCurrentView();
633
+ i0.ɵɵelementStart(0, "div", 109);
634
+ i0.ɵɵlistener("mousedown", function MjFormFieldComponent_Conditional_0_Conditional_1_Conditional_5_Case_5_Conditional_4_For_2_Template_div_mousedown_0_listener($event) { const option_r36 = i0.ɵɵrestoreView(_r35).$implicit; const ctx_r0 = i0.ɵɵnextContext(6); return i0.ɵɵresetView(ctx_r0.OnSelectOptionClick(option_r36, $event)); });
222
635
  i0.ɵɵtext(1);
223
636
  i0.ɵɵelementEnd();
224
637
  } if (rf & 2) {
225
- const option_r17 = ctx.$implicit;
638
+ const option_r36 = ctx.$implicit;
226
639
  const ctx_r0 = i0.ɵɵnextContext(6);
227
- i0.ɵɵclassProp("mj-fk-option--selected", ctx_r0.FormatValue() === option_r17);
640
+ i0.ɵɵclassProp("mj-fk-option--selected", ctx_r0.FormatValue() === option_r36);
228
641
  i0.ɵɵadvance();
229
- i0.ɵɵtextInterpolate1(" ", option_r17, " ");
642
+ i0.ɵɵtextInterpolate1(" ", option_r36, " ");
230
643
  } }
231
- function MjFormFieldComponent_Conditional_0_Conditional_1_Conditional_4_Case_5_Conditional_4_Template(rf, ctx) { if (rf & 1) {
232
- i0.ɵɵelementStart(0, "div", 26);
233
- i0.ɵɵrepeaterCreate(1, MjFormFieldComponent_Conditional_0_Conditional_1_Conditional_4_Case_5_Conditional_4_For_2_Template, 2, 3, "div", 41, i0.ɵɵrepeaterTrackByIdentity);
644
+ function MjFormFieldComponent_Conditional_0_Conditional_1_Conditional_5_Case_5_Conditional_4_Template(rf, ctx) { if (rf & 1) {
645
+ i0.ɵɵelementStart(0, "div", 107);
646
+ i0.ɵɵrepeaterCreate(1, MjFormFieldComponent_Conditional_0_Conditional_1_Conditional_5_Case_5_Conditional_4_For_2_Template, 2, 3, "div", 108, i0.ɵɵrepeaterTrackByIdentity);
234
647
  i0.ɵɵelementEnd();
235
648
  } if (rf & 2) {
236
649
  const ctx_r0 = i0.ɵɵnextContext(5);
@@ -239,16 +652,16 @@ function MjFormFieldComponent_Conditional_0_Conditional_1_Conditional_4_Case_5_C
239
652
  i0.ɵɵadvance();
240
653
  i0.ɵɵrepeater(ctx_r0.PossibleValues);
241
654
  } }
242
- function MjFormFieldComponent_Conditional_0_Conditional_1_Conditional_4_Case_5_Template(rf, ctx) { if (rf & 1) {
243
- const _r15 = i0.ɵɵgetCurrentView();
244
- i0.ɵɵelementStart(0, "div", 38);
245
- i0.ɵɵlistener("click", function MjFormFieldComponent_Conditional_0_Conditional_1_Conditional_4_Case_5_Template_div_click_0_listener($event) { i0.ɵɵrestoreView(_r15); const ctx_r0 = i0.ɵɵnextContext(4); return i0.ɵɵresetView(ctx_r0.OnSelectTriggerClick($event)); })("blur", function MjFormFieldComponent_Conditional_0_Conditional_1_Conditional_4_Case_5_Template_div_blur_0_listener() { i0.ɵɵrestoreView(_r15); const ctx_r0 = i0.ɵɵnextContext(4); return i0.ɵɵresetView(ctx_r0.OnSelectTriggerBlur()); });
246
- i0.ɵɵelementStart(1, "span", 39);
655
+ function MjFormFieldComponent_Conditional_0_Conditional_1_Conditional_5_Case_5_Template(rf, ctx) { if (rf & 1) {
656
+ const _r34 = i0.ɵɵgetCurrentView();
657
+ i0.ɵɵelementStart(0, "div", 103);
658
+ i0.ɵɵlistener("click", function MjFormFieldComponent_Conditional_0_Conditional_1_Conditional_5_Case_5_Template_div_click_0_listener($event) { i0.ɵɵrestoreView(_r34); const ctx_r0 = i0.ɵɵnextContext(4); return i0.ɵɵresetView(ctx_r0.OnSelectTriggerClick($event)); })("blur", function MjFormFieldComponent_Conditional_0_Conditional_1_Conditional_5_Case_5_Template_div_blur_0_listener() { i0.ɵɵrestoreView(_r34); const ctx_r0 = i0.ɵɵnextContext(4); return i0.ɵɵresetView(ctx_r0.OnSelectTriggerBlur()); });
659
+ i0.ɵɵelementStart(1, "span", 104);
247
660
  i0.ɵɵtext(2);
248
661
  i0.ɵɵelementEnd();
249
- i0.ɵɵelement(3, "i", 40);
662
+ i0.ɵɵelement(3, "i", 105);
250
663
  i0.ɵɵelementEnd();
251
- i0.ɵɵconditionalCreate(4, MjFormFieldComponent_Conditional_0_Conditional_1_Conditional_4_Case_5_Conditional_4_Template, 3, 3, "div", 23);
664
+ i0.ɵɵconditionalCreate(4, MjFormFieldComponent_Conditional_0_Conditional_1_Conditional_5_Case_5_Conditional_4_Template, 3, 3, "div", 106);
252
665
  } if (rf & 2) {
253
666
  const ctx_r0 = i0.ɵɵnextContext(4);
254
667
  i0.ɵɵadvance();
@@ -260,20 +673,20 @@ function MjFormFieldComponent_Conditional_0_Conditional_1_Conditional_4_Case_5_T
260
673
  i0.ɵɵadvance();
261
674
  i0.ɵɵconditional(ctx_r0.ShowSelectDropdown && ctx_r0.PossibleValues.length > 0 ? 4 : -1);
262
675
  } }
263
- function MjFormFieldComponent_Conditional_0_Conditional_1_Conditional_4_Case_6_Conditional_3_For_2_Template(rf, ctx) { if (rf & 1) {
264
- const _r19 = i0.ɵɵgetCurrentView();
265
- i0.ɵɵelementStart(0, "div", 28);
266
- i0.ɵɵlistener("mousedown", function MjFormFieldComponent_Conditional_0_Conditional_1_Conditional_4_Case_6_Conditional_3_For_2_Template_div_mousedown_0_listener($event) { const option_r20 = i0.ɵɵrestoreView(_r19).$implicit; const ctx_r0 = i0.ɵɵnextContext(6); return i0.ɵɵresetView(ctx_r0.OnValueListSelect(option_r20, $event)); });
676
+ function MjFormFieldComponent_Conditional_0_Conditional_1_Conditional_5_Case_6_Conditional_3_For_2_Template(rf, ctx) { if (rf & 1) {
677
+ const _r38 = i0.ɵɵgetCurrentView();
678
+ i0.ɵɵelementStart(0, "div", 109);
679
+ i0.ɵɵlistener("mousedown", function MjFormFieldComponent_Conditional_0_Conditional_1_Conditional_5_Case_6_Conditional_3_For_2_Template_div_mousedown_0_listener($event) { const option_r39 = i0.ɵɵrestoreView(_r38).$implicit; const ctx_r0 = i0.ɵɵnextContext(6); return i0.ɵɵresetView(ctx_r0.OnValueListSelect(option_r39, $event)); });
267
680
  i0.ɵɵtext(1);
268
681
  i0.ɵɵelementEnd();
269
682
  } if (rf & 2) {
270
- const option_r20 = ctx.$implicit;
683
+ const option_r39 = ctx.$implicit;
271
684
  i0.ɵɵadvance();
272
- i0.ɵɵtextInterpolate1(" ", option_r20, " ");
685
+ i0.ɵɵtextInterpolate1(" ", option_r39, " ");
273
686
  } }
274
- function MjFormFieldComponent_Conditional_0_Conditional_1_Conditional_4_Case_6_Conditional_3_Template(rf, ctx) { if (rf & 1) {
275
- i0.ɵɵelementStart(0, "div", 26);
276
- i0.ɵɵrepeaterCreate(1, MjFormFieldComponent_Conditional_0_Conditional_1_Conditional_4_Case_6_Conditional_3_For_2_Template, 2, 1, "div", 27, i0.ɵɵrepeaterTrackByIdentity);
687
+ function MjFormFieldComponent_Conditional_0_Conditional_1_Conditional_5_Case_6_Conditional_3_Template(rf, ctx) { if (rf & 1) {
688
+ i0.ɵɵelementStart(0, "div", 107);
689
+ i0.ɵɵrepeaterCreate(1, MjFormFieldComponent_Conditional_0_Conditional_1_Conditional_5_Case_6_Conditional_3_For_2_Template, 2, 1, "div", 111, i0.ɵɵrepeaterTrackByIdentity);
277
690
  i0.ɵɵelementEnd();
278
691
  } if (rf & 2) {
279
692
  const ctx_r0 = i0.ɵɵnextContext(5);
@@ -282,13 +695,13 @@ function MjFormFieldComponent_Conditional_0_Conditional_1_Conditional_4_Case_6_C
282
695
  i0.ɵɵadvance();
283
696
  i0.ɵɵrepeater(ctx_r0.FilteredPossibleValues);
284
697
  } }
285
- function MjFormFieldComponent_Conditional_0_Conditional_1_Conditional_4_Case_6_Template(rf, ctx) { if (rf & 1) {
286
- const _r18 = i0.ɵɵgetCurrentView();
287
- i0.ɵɵelementStart(0, "div", 19)(1, "input", 42);
288
- i0.ɵɵlistener("input", function MjFormFieldComponent_Conditional_0_Conditional_1_Conditional_4_Case_6_Template_input_input_1_listener($event) { i0.ɵɵrestoreView(_r18); const ctx_r0 = i0.ɵɵnextContext(4); return i0.ɵɵresetView(ctx_r0.OnValueListInput($event)); })("focus", function MjFormFieldComponent_Conditional_0_Conditional_1_Conditional_4_Case_6_Template_input_focus_1_listener($event) { i0.ɵɵrestoreView(_r18); const ctx_r0 = i0.ɵɵnextContext(4); return i0.ɵɵresetView(ctx_r0.OnValueListFocus($event)); })("blur", function MjFormFieldComponent_Conditional_0_Conditional_1_Conditional_4_Case_6_Template_input_blur_1_listener() { i0.ɵɵrestoreView(_r18); const ctx_r0 = i0.ɵɵnextContext(4); return i0.ɵɵresetView(ctx_r0.OnValueListBlur()); });
698
+ function MjFormFieldComponent_Conditional_0_Conditional_1_Conditional_5_Case_6_Template(rf, ctx) { if (rf & 1) {
699
+ const _r37 = i0.ɵɵgetCurrentView();
700
+ i0.ɵɵelementStart(0, "div", 28)(1, "input", 110);
701
+ i0.ɵɵlistener("input", function MjFormFieldComponent_Conditional_0_Conditional_1_Conditional_5_Case_6_Template_input_input_1_listener($event) { i0.ɵɵrestoreView(_r37); const ctx_r0 = i0.ɵɵnextContext(4); return i0.ɵɵresetView(ctx_r0.OnValueListInput($event)); })("focus", function MjFormFieldComponent_Conditional_0_Conditional_1_Conditional_5_Case_6_Template_input_focus_1_listener($event) { i0.ɵɵrestoreView(_r37); const ctx_r0 = i0.ɵɵnextContext(4); return i0.ɵɵresetView(ctx_r0.OnValueListFocus($event)); })("blur", function MjFormFieldComponent_Conditional_0_Conditional_1_Conditional_5_Case_6_Template_input_blur_1_listener() { i0.ɵɵrestoreView(_r37); const ctx_r0 = i0.ɵɵnextContext(4); return i0.ɵɵresetView(ctx_r0.OnValueListBlur()); });
289
702
  i0.ɵɵelementEnd();
290
- i0.ɵɵelement(2, "i", 22);
291
- i0.ɵɵconditionalCreate(3, MjFormFieldComponent_Conditional_0_Conditional_1_Conditional_4_Case_6_Conditional_3_Template, 3, 3, "div", 23);
703
+ i0.ɵɵelement(2, "i", 33);
704
+ i0.ɵɵconditionalCreate(3, MjFormFieldComponent_Conditional_0_Conditional_1_Conditional_5_Case_6_Conditional_3_Template, 3, 3, "div", 106);
292
705
  i0.ɵɵelementEnd();
293
706
  } if (rf & 2) {
294
707
  const ctx_r0 = i0.ɵɵnextContext(4);
@@ -297,56 +710,56 @@ function MjFormFieldComponent_Conditional_0_Conditional_1_Conditional_4_Case_6_T
297
710
  i0.ɵɵadvance(2);
298
711
  i0.ɵɵconditional(ctx_r0.ShowValueListDropdown && ctx_r0.FilteredPossibleValues.length > 0 ? 3 : -1);
299
712
  } }
300
- function MjFormFieldComponent_Conditional_0_Conditional_1_Conditional_4_Case_7_Template(rf, ctx) { if (rf & 1) {
301
- const _r21 = i0.ɵɵgetCurrentView();
302
- i0.ɵɵelementStart(0, "input", 43);
303
- i0.ɵɵlistener("change", function MjFormFieldComponent_Conditional_0_Conditional_1_Conditional_4_Case_7_Template_input_change_0_listener($event) { i0.ɵɵrestoreView(_r21); const ctx_r0 = i0.ɵɵnextContext(4); return i0.ɵɵresetView(ctx_r0.OnInputChange($event)); });
713
+ function MjFormFieldComponent_Conditional_0_Conditional_1_Conditional_5_Case_7_Template(rf, ctx) { if (rf & 1) {
714
+ const _r40 = i0.ɵɵgetCurrentView();
715
+ i0.ɵɵelementStart(0, "input", 112);
716
+ i0.ɵɵlistener("change", function MjFormFieldComponent_Conditional_0_Conditional_1_Conditional_5_Case_7_Template_input_change_0_listener($event) { i0.ɵɵrestoreView(_r40); const ctx_r0 = i0.ɵɵnextContext(4); return i0.ɵɵresetView(ctx_r0.OnInputChange($event)); });
304
717
  i0.ɵɵelementEnd();
305
718
  } if (rf & 2) {
306
719
  const ctx_r0 = i0.ɵɵnextContext(4);
307
720
  i0.ɵɵproperty("value", ctx_r0.FormatValue());
308
721
  } }
309
- function MjFormFieldComponent_Conditional_0_Conditional_1_Conditional_4_Template(rf, ctx) { if (rf & 1) {
310
- i0.ɵɵconditionalCreate(0, MjFormFieldComponent_Conditional_0_Conditional_1_Conditional_4_Case_0_Template, 1, 1, "input", 29)(1, MjFormFieldComponent_Conditional_0_Conditional_1_Conditional_4_Case_1_Template, 1, 1, "textarea", 30)(2, MjFormFieldComponent_Conditional_0_Conditional_1_Conditional_4_Case_2_Template, 1, 1, "input", 31)(3, MjFormFieldComponent_Conditional_0_Conditional_1_Conditional_4_Case_3_Template, 1, 1, "input", 32)(4, MjFormFieldComponent_Conditional_0_Conditional_1_Conditional_4_Case_4_Template, 2, 1, "div", 13)(5, MjFormFieldComponent_Conditional_0_Conditional_1_Conditional_4_Case_5_Template, 5, 6)(6, MjFormFieldComponent_Conditional_0_Conditional_1_Conditional_4_Case_6_Template, 4, 2, "div", 19)(7, MjFormFieldComponent_Conditional_0_Conditional_1_Conditional_4_Case_7_Template, 1, 1, "input", 29);
722
+ function MjFormFieldComponent_Conditional_0_Conditional_1_Conditional_5_Template(rf, ctx) { if (rf & 1) {
723
+ i0.ɵɵconditionalCreate(0, MjFormFieldComponent_Conditional_0_Conditional_1_Conditional_5_Case_0_Template, 1, 1, "input", 94)(1, MjFormFieldComponent_Conditional_0_Conditional_1_Conditional_5_Case_1_Template, 1, 1, "textarea", 95)(2, MjFormFieldComponent_Conditional_0_Conditional_1_Conditional_5_Case_2_Template, 1, 1, "input", 96)(3, MjFormFieldComponent_Conditional_0_Conditional_1_Conditional_5_Case_3_Template, 1, 1, "input", 97)(4, MjFormFieldComponent_Conditional_0_Conditional_1_Conditional_5_Case_4_Template, 2, 1, "div", 19)(5, MjFormFieldComponent_Conditional_0_Conditional_1_Conditional_5_Case_5_Template, 5, 6)(6, MjFormFieldComponent_Conditional_0_Conditional_1_Conditional_5_Case_6_Template, 4, 2, "div", 28)(7, MjFormFieldComponent_Conditional_0_Conditional_1_Conditional_5_Case_7_Template, 1, 1, "input", 94);
311
724
  } if (rf & 2) {
312
725
  let tmp_3_0;
313
726
  const ctx_r0 = i0.ɵɵnextContext(3);
314
727
  i0.ɵɵconditional((tmp_3_0 = ctx_r0.Type) === "textbox" ? 0 : tmp_3_0 === "textarea" ? 1 : tmp_3_0 === "number" ? 2 : tmp_3_0 === "datepicker" ? 3 : tmp_3_0 === "checkbox" ? 4 : tmp_3_0 === "select" ? 5 : tmp_3_0 === "autocomplete" ? 6 : 7);
315
728
  } }
316
- function MjFormFieldComponent_Conditional_0_Conditional_1_Conditional_5_For_2_Template(rf, ctx) { if (rf & 1) {
317
- i0.ɵɵelementStart(0, "div", 44);
318
- i0.ɵɵelement(1, "i", 45);
729
+ function MjFormFieldComponent_Conditional_0_Conditional_1_Conditional_6_For_2_Template(rf, ctx) { if (rf & 1) {
730
+ i0.ɵɵelementStart(0, "div", 113);
731
+ i0.ɵɵelement(1, "i", 114);
319
732
  i0.ɵɵelementStart(2, "span");
320
733
  i0.ɵɵtext(3);
321
734
  i0.ɵɵelementEnd()();
322
735
  } if (rf & 2) {
323
- const error_r22 = ctx.$implicit;
736
+ const error_r41 = ctx.$implicit;
324
737
  i0.ɵɵadvance(3);
325
- i0.ɵɵtextInterpolate(error_r22.Message);
738
+ i0.ɵɵtextInterpolate(error_r41.Message);
326
739
  } }
327
- function MjFormFieldComponent_Conditional_0_Conditional_1_Conditional_5_Template(rf, ctx) { if (rf & 1) {
328
- i0.ɵɵelementStart(0, "div", 17);
329
- i0.ɵɵrepeaterCreate(1, MjFormFieldComponent_Conditional_0_Conditional_1_Conditional_5_For_2_Template, 4, 1, "div", 44, _forTrack1);
740
+ function MjFormFieldComponent_Conditional_0_Conditional_1_Conditional_6_Template(rf, ctx) { if (rf & 1) {
741
+ i0.ɵɵelementStart(0, "div", 26);
742
+ i0.ɵɵrepeaterCreate(1, MjFormFieldComponent_Conditional_0_Conditional_1_Conditional_6_For_2_Template, 4, 1, "div", 113, _forTrack2);
330
743
  i0.ɵɵelementEnd();
331
744
  } if (rf & 2) {
332
745
  const ctx_r0 = i0.ɵɵnextContext(3);
333
746
  i0.ɵɵadvance();
334
747
  i0.ɵɵrepeater(ctx_r0.DisplayErrors);
335
748
  } }
336
- function MjFormFieldComponent_Conditional_0_Conditional_1_Conditional_6_For_2_Template(rf, ctx) { if (rf & 1) {
337
- i0.ɵɵelementStart(0, "div", 44);
338
- i0.ɵɵelement(1, "i", 46);
749
+ function MjFormFieldComponent_Conditional_0_Conditional_1_Conditional_7_For_2_Template(rf, ctx) { if (rf & 1) {
750
+ i0.ɵɵelementStart(0, "div", 113);
751
+ i0.ɵɵelement(1, "i", 115);
339
752
  i0.ɵɵelementStart(2, "span");
340
753
  i0.ɵɵtext(3);
341
754
  i0.ɵɵelementEnd()();
342
755
  } if (rf & 2) {
343
- const warning_r23 = ctx.$implicit;
756
+ const warning_r42 = ctx.$implicit;
344
757
  i0.ɵɵadvance(3);
345
- i0.ɵɵtextInterpolate(warning_r23.Message);
758
+ i0.ɵɵtextInterpolate(warning_r42.Message);
346
759
  } }
347
- function MjFormFieldComponent_Conditional_0_Conditional_1_Conditional_6_Template(rf, ctx) { if (rf & 1) {
348
- i0.ɵɵelementStart(0, "div", 18);
349
- i0.ɵɵrepeaterCreate(1, MjFormFieldComponent_Conditional_0_Conditional_1_Conditional_6_For_2_Template, 4, 1, "div", 44, _forTrack1);
760
+ function MjFormFieldComponent_Conditional_0_Conditional_1_Conditional_7_Template(rf, ctx) { if (rf & 1) {
761
+ i0.ɵɵelementStart(0, "div", 27);
762
+ i0.ɵɵrepeaterCreate(1, MjFormFieldComponent_Conditional_0_Conditional_1_Conditional_7_For_2_Template, 4, 1, "div", 113, _forTrack2);
350
763
  i0.ɵɵelementEnd();
351
764
  } if (rf & 2) {
352
765
  const ctx_r0 = i0.ɵɵnextContext(3);
@@ -354,13 +767,13 @@ function MjFormFieldComponent_Conditional_0_Conditional_1_Conditional_6_Template
354
767
  i0.ɵɵrepeater(ctx_r0.DisplayWarnings);
355
768
  } }
356
769
  function MjFormFieldComponent_Conditional_0_Conditional_1_Template(rf, ctx) { if (rf & 1) {
357
- i0.ɵɵelementStart(0, "div", 15);
358
- i0.ɵɵconditionalCreate(1, MjFormFieldComponent_Conditional_0_Conditional_1_Conditional_1_Template, 1, 1, "label", 3);
359
- i0.ɵɵelementStart(2, "div", 4);
360
- i0.ɵɵconditionalCreate(3, MjFormFieldComponent_Conditional_0_Conditional_1_Conditional_3_Template, 5, 5, "div", 16)(4, MjFormFieldComponent_Conditional_0_Conditional_1_Conditional_4_Template, 8, 1);
770
+ i0.ɵɵelementStart(0, "div", 23);
771
+ i0.ɵɵconditionalCreate(1, MjFormFieldComponent_Conditional_0_Conditional_1_Conditional_1_Template, 1, 1, "label", 4);
772
+ i0.ɵɵelementStart(2, "div", 5);
773
+ i0.ɵɵconditionalCreate(3, MjFormFieldComponent_Conditional_0_Conditional_1_Conditional_3_Template, 7, 11, "div", 24)(4, MjFormFieldComponent_Conditional_0_Conditional_1_Conditional_4_Template, 1, 2, "mj-code-editor", 25)(5, MjFormFieldComponent_Conditional_0_Conditional_1_Conditional_5_Template, 8, 1);
361
774
  i0.ɵɵelementEnd();
362
- i0.ɵɵconditionalCreate(5, MjFormFieldComponent_Conditional_0_Conditional_1_Conditional_5_Template, 3, 0, "div", 17);
363
- i0.ɵɵconditionalCreate(6, MjFormFieldComponent_Conditional_0_Conditional_1_Conditional_6_Template, 3, 0, "div", 18);
775
+ i0.ɵɵconditionalCreate(6, MjFormFieldComponent_Conditional_0_Conditional_1_Conditional_6_Template, 3, 0, "div", 26);
776
+ i0.ɵɵconditionalCreate(7, MjFormFieldComponent_Conditional_0_Conditional_1_Conditional_7_Template, 3, 0, "div", 27);
364
777
  i0.ɵɵelementEnd();
365
778
  } if (rf & 2) {
366
779
  const ctx_r0 = i0.ɵɵnextContext(2);
@@ -368,15 +781,15 @@ function MjFormFieldComponent_Conditional_0_Conditional_1_Template(rf, ctx) { if
368
781
  i0.ɵɵadvance();
369
782
  i0.ɵɵconditional(ctx_r0.ShowLabel ? 1 : -1);
370
783
  i0.ɵɵadvance(2);
371
- i0.ɵɵconditional(ctx_r0.HasRelatedEntity ? 3 : 4);
372
- i0.ɵɵadvance(2);
373
- i0.ɵɵconditional(ctx_r0.DisplayErrors.length > 0 ? 5 : -1);
784
+ i0.ɵɵconditional(ctx_r0.HasRelatedEntity ? 3 : ctx_r0.EditRichTextMode !== "plain" ? 4 : 5);
785
+ i0.ɵɵadvance(3);
786
+ i0.ɵɵconditional(ctx_r0.DisplayErrors.length > 0 ? 6 : -1);
374
787
  i0.ɵɵadvance();
375
- i0.ɵɵconditional(ctx_r0.DisplayWarnings.length > 0 ? 6 : -1);
788
+ i0.ɵɵconditional(ctx_r0.DisplayWarnings.length > 0 ? 7 : -1);
376
789
  } }
377
790
  function MjFormFieldComponent_Conditional_0_Template(rf, ctx) { if (rf & 1) {
378
- i0.ɵɵconditionalCreate(0, MjFormFieldComponent_Conditional_0_Conditional_0_Template, 5, 6, "div", 0);
379
- i0.ɵɵconditionalCreate(1, MjFormFieldComponent_Conditional_0_Conditional_1_Template, 7, 12, "div", 1);
791
+ i0.ɵɵconditionalCreate(0, MjFormFieldComponent_Conditional_0_Conditional_0_Template, 5, 6, "div", 1);
792
+ i0.ɵɵconditionalCreate(1, MjFormFieldComponent_Conditional_0_Conditional_1_Template, 8, 12, "div", 2);
380
793
  } if (rf & 2) {
381
794
  const ctx_r0 = i0.ɵɵnextContext();
382
795
  i0.ɵɵconditional((!ctx_r0.EditMode || ctx_r0.IsFieldReadOnly) && !ctx_r0.ShouldHideField ? 0 : -1);
@@ -412,6 +825,8 @@ function MjFormFieldComponent_Conditional_0_Template(rf, ctx) { if (rf & 1) {
412
825
  */
413
826
  export class MjFormFieldComponent extends BaseAngularComponent {
414
827
  cdr = inject(ChangeDetectorRef);
828
+ renderer = inject(Renderer2);
829
+ hostRef = inject((ElementRef));
415
830
  /** The entity record containing this field */
416
831
  Record;
417
832
  /** Whether the form is in edit mode */
@@ -456,6 +871,14 @@ export class MjFormFieldComponent extends BaseAngularComponent {
456
871
  ShowLabel = true;
457
872
  /** Form-level context (search filter, showEmptyFields) */
458
873
  FormContext;
874
+ /**
875
+ * Whether FK / record links are interactive. Driven by
876
+ * `FormContext.enableRecordLinks`; false renders FK values as plain text
877
+ * (dialog/slide-in surfaces). Undefined / true means links are live.
878
+ */
879
+ get RecordLinksEnabled() {
880
+ return this.FormContext?.enableRecordLinks !== false;
881
+ }
459
882
  // ---- Deprecated camelCase aliases (backward compat) ----
460
883
  /** @deprecated Use [Record] instead */
461
884
  set _deprecatedRecord(value) { this.Record = value; }
@@ -711,19 +1134,51 @@ export class MjFormFieldComponent extends BaseAngularComponent {
711
1134
  /** Calculated position for fixed-position dropdowns */
712
1135
  DropdownTop = 0;
713
1136
  DropdownLeft = 0;
714
- DropdownWidth = 0;
1137
+ /** Computed: dropdown is at least the trigger width, at most {@link DropdownMaxWidth}. */
1138
+ DropdownMinWidth = 0;
1139
+ DropdownMaxWidth = 0;
715
1140
  OpenAbove = false;
1141
+ /**
1142
+ * Max width (px) of the FK suggestion dropdown. The panel grows to fit its
1143
+ * columns up to this cap (then scrolls horizontally). When null, defaults to
1144
+ * 2× the trigger width so multi-column rows aren't cramped by a narrow field.
1145
+ * Always additionally bounded by the viewport's right edge.
1146
+ */
1147
+ FKDropdownMaxWidth = null;
1148
+ /**
1149
+ * Whether to highlight the typed query substring within each suggestion's name
1150
+ * in the FK dropdown. On by default — uses the muted, theme-aware
1151
+ * `--mj-status-warning` highlight (not the old bright yellow). Set false for
1152
+ * plain, un-marked names.
1153
+ */
1154
+ FKHighlightMatches = true;
1155
+ /**
1156
+ * Whether to offer inline "create new" for the related record when the one you need
1157
+ * isn't found. The affordance only renders when this is true AND the current user can
1158
+ * create records of the related entity (entity allows creation + role permits it).
1159
+ */
1160
+ AllowFKCreate = true;
1161
+ /** Surface used for the inline create form: a modal dialog (default) or a slide-in. */
1162
+ FKCreatePresentation = 'dialog';
716
1163
  /** Cleanup function for scroll/resize listeners */
717
1164
  _scrollCleanup = null;
718
1165
  /** Inline style for the fixed-position dropdown */
719
1166
  get DropdownPositionStyle() {
1167
+ // min-width floors at the trigger width; max-width caps growth; the auto
1168
+ // intrinsic width then shrink-to-fits the columns between the two, and
1169
+ // `.mj-fk-options` scrolls horizontally once content exceeds the cap.
1170
+ const sizing = {
1171
+ 'min-width': this.DropdownMinWidth + 'px',
1172
+ 'max-width': this.DropdownMaxWidth + 'px',
1173
+ 'width': 'max-content',
1174
+ };
720
1175
  if (this.OpenAbove) {
721
1176
  return {
722
1177
  'position': 'fixed',
723
1178
  'bottom': (window.innerHeight - this.DropdownTop) + 'px',
724
1179
  'top': 'auto',
725
1180
  'left': this.DropdownLeft + 'px',
726
- 'width': this.DropdownWidth + 'px',
1181
+ ...sizing,
727
1182
  'z-index': '10000'
728
1183
  };
729
1184
  }
@@ -732,7 +1187,7 @@ export class MjFormFieldComponent extends BaseAngularComponent {
732
1187
  'top': this.DropdownTop + 'px',
733
1188
  'bottom': 'auto',
734
1189
  'left': this.DropdownLeft + 'px',
735
- 'width': this.DropdownWidth + 'px',
1190
+ ...sizing,
736
1191
  'z-index': '10000'
737
1192
  };
738
1193
  }
@@ -752,12 +1207,63 @@ export class MjFormFieldComponent extends BaseAngularComponent {
752
1207
  this.DropdownTop = rect.bottom + gap;
753
1208
  }
754
1209
  this.DropdownLeft = rect.left;
755
- this.DropdownWidth = rect.width;
1210
+ // At least the trigger width; up to FKDropdownMaxWidth (default 2×), but never
1211
+ // past the viewport's right edge. Content fills between min and max; overflow
1212
+ // scrolls horizontally.
1213
+ this.DropdownMinWidth = rect.width;
1214
+ const desiredMax = this.FKDropdownMaxWidth ?? rect.width * 2;
1215
+ this.DropdownMaxWidth = Math.max(rect.width, Math.min(desiredMax, window.innerWidth - rect.left - 8));
756
1216
  }
1217
+ // ---- Dropdown portal (escape transformed ancestors) ----
1218
+ /**
1219
+ * The dropdown is `position: fixed` with viewport coords. Inside the slide-in /
1220
+ * dialog overlays (which use CSS `transform`), a `fixed` descendant is positioned
1221
+ * relative to the transformed ancestor instead of the viewport, so it renders
1222
+ * off-screen. Re-parenting the dropdown element to `document.body` removes it from
1223
+ * any transformed containing block, restoring true viewport-fixed positioning.
1224
+ *
1225
+ * Call after change detection has rendered the dropdown (microtask). Angular still
1226
+ * owns the node — when the structural `@if` tears it down it removes the node by
1227
+ * reference regardless of where it currently lives, so no manual cleanup is needed
1228
+ * beyond clearing our tracking pointer.
1229
+ */
1230
+ portalDropdownToBody() {
1231
+ // Already portaled and still in the DOM → nothing to do (e.g. typing while open).
1232
+ if (this._portaledDropdownEl?.isConnected)
1233
+ return;
1234
+ // The dropdown is rendered by `@if (ShowFKDropdown)`. On the synchronous cached
1235
+ // path (focus → searchCachedEntity → applySuggestions) the element may not be in
1236
+ // the DOM yet when we first look, so retry across a few frames until it renders.
1237
+ // (The async DB path lands here post-render, so it succeeds on the first try.)
1238
+ const tryPortal = (retriesLeft) => {
1239
+ const host = this.hostRef?.nativeElement;
1240
+ if (!host)
1241
+ return;
1242
+ const dropdown = host.querySelector('.mj-fk-dropdown');
1243
+ if (dropdown) {
1244
+ if (dropdown.parentElement !== document.body) {
1245
+ this.renderer.appendChild(document.body, dropdown);
1246
+ this._portaledDropdownEl = dropdown;
1247
+ }
1248
+ }
1249
+ else if (retriesLeft > 0) {
1250
+ setTimeout(() => tryPortal(retriesLeft - 1), 0);
1251
+ }
1252
+ };
1253
+ Promise.resolve().then(() => tryPortal(5));
1254
+ }
1255
+ /** Tracks a dropdown element we relocated to body so we can drop the reference on close. */
1256
+ _portaledDropdownEl = null;
757
1257
  /** Start listening for scroll/resize to close dropdowns */
758
1258
  startScrollListener() {
759
1259
  this.stopScrollListener();
760
- const onScroll = () => {
1260
+ const onScroll = (e) => {
1261
+ // Scrolling WITHIN the dropdown (vertical list or horizontal column scroll)
1262
+ // must not close it — only an ancestor/page scroll, which would detach the
1263
+ // fixed-position panel from its trigger, should.
1264
+ const target = e.target;
1265
+ if (this._portaledDropdownEl && target && this._portaledDropdownEl.contains(target))
1266
+ return;
761
1267
  this.closeAllDropdowns();
762
1268
  this.cdr.markForCheck();
763
1269
  };
@@ -782,6 +1288,10 @@ export class MjFormFieldComponent extends BaseAngularComponent {
782
1288
  /** Close all dropdown types */
783
1289
  closeAllDropdowns() {
784
1290
  this.ShowFKDropdown = false;
1291
+ this.FKActiveIndex = -1;
1292
+ this.FKLoading = false;
1293
+ this.FKNoMatches = false;
1294
+ this._portaledDropdownEl = null;
785
1295
  this.ShowValueListDropdown = false;
786
1296
  this.ShowSelectDropdown = false;
787
1297
  this.stopScrollListener();
@@ -789,62 +1299,722 @@ export class MjFormFieldComponent extends BaseAngularComponent {
789
1299
  // ============================================
790
1300
  // FK AUTOCOMPLETE (custom implementation)
791
1301
  // ============================================
1302
+ /** Max rows shown on an empty-input focus-show (cached fast path only). */
1303
+ static FK_FOCUS_SHOW_LIMIT = 50;
1304
+ /** Max rows returned from a DB search. */
1305
+ static FK_DB_SEARCH_LIMIT = 20;
792
1306
  /** Suggestions returned from the FK entity search */
793
1307
  FKSuggestions = [];
1308
+ /**
1309
+ * The currently-linked record, pinned as a sticky "Currently selected" section at the
1310
+ * top of the dropdown (browse mode only). Null when there's no selection or the user is
1311
+ * actively filtering. Removed from {@link FKSuggestions} so it isn't listed twice.
1312
+ */
1313
+ FKSelectedSuggestion = null;
794
1314
  /** Whether the current FK value is a confirmed match (user selected from dropdown) */
795
1315
  FKIsMatched = false;
796
1316
  /** Whether the FK dropdown is visible */
797
1317
  ShowFKDropdown = false;
1318
+ /** Whether a DB search is currently in flight (drives the loading indicator). */
1319
+ FKLoading = false;
1320
+ /** True when a search completed with zero results (drives the "No matches" row). */
1321
+ FKNoMatches = false;
1322
+ /** Index of the keyboard-highlighted active suggestion (-1 = none). */
1323
+ FKActiveIndex = -1;
1324
+ /** Headers for the extra (DefaultInView) columns shown in the dropdown. */
1325
+ FKColumnHeaders = [];
1326
+ /** Field code names for the extra columns, index-aligned with {@link FKColumnHeaders}. */
1327
+ FKColumnFields = [];
1328
+ /** Code name of the name column (used as its sort key). */
1329
+ FKNameField = '';
1330
+ /** Whether rows render a leading icon column (drives the header's empty icon cell). */
1331
+ FKHasIconColumn = false;
1332
+ /** Active sort column (field code name), or null for natural (unsorted) order. */
1333
+ FKSortField = null;
1334
+ /** Active sort direction; only meaningful when {@link FKSortField} is set. */
1335
+ FKSortDir = 'asc';
1336
+ /** Unsorted snapshot of the current suggestions, used to restore natural order. */
1337
+ _fkSuggestionsNatural = [];
798
1338
  /** Text the user is currently typing in the FK search input. null = use display name. */
799
1339
  _fkInputText = null;
1340
+ /**
1341
+ * The active search query that produced the current results — `''` on a focus/clear
1342
+ * browse (full list), the typed text when filtering. Distinct from {@link _fkInputText},
1343
+ * which holds the *displayed* text (the selected record's name when not typing). This is
1344
+ * the correct signal for "browse mode" and for the create-footer label.
1345
+ */
1346
+ _fkQuery = '';
800
1347
  /** Debounce timer for FK search */
801
1348
  _fkSearchTimeout = null;
802
1349
  /** Last known FK input element for position recalculation */
803
1350
  _lastFKInputEl = null;
1351
+ /** Monotonic token so a slow DB response from a stale query can't clobber a newer one. */
1352
+ _fkSearchSeq = 0;
1353
+ /** Cached column plan for the current related entity (rebuilt on demand). */
1354
+ _fkColumnPlan = null;
1355
+ // ---- Scope / search-field picker (Option B) ----
1356
+ /** Related-entity field code name currently searched against (defaults to the name field). */
1357
+ FKSearchField = '';
1358
+ /** Friendly label of {@link FKSearchField}, shown on the scope pill. */
1359
+ FKSearchFieldLabel = '';
1360
+ /** Whether the scope-picker menu is open. */
1361
+ FKShowScopeMenu = false;
1362
+ /** Whether the FK input is focused — the scope pill only appears while focused. */
1363
+ FKFocused = false;
1364
+ /** Fields the user can scope the search to (name + shown columns + other fields). */
1365
+ FKSearchableFields = [];
1366
+ // ---- Per-user persisted prefs (scope / sort / column widths) ----
1367
+ /** User-resized column widths in px, keyed by related-entity field code name. */
1368
+ _fkColWidths = {};
1369
+ /** The (host entity|field) pref key currently loaded; reload when it changes. */
1370
+ _fkPrefKey = null;
1371
+ /** Active column-resize drag, or null when not resizing. */
1372
+ _fkResize = null;
1373
+ _fkResizeMove = null;
1374
+ _fkResizeUp = null;
804
1375
  /** The display text shown in the FK search input */
805
1376
  get FKSearchText() {
806
1377
  if (this._fkInputText !== null)
807
1378
  return this._fkInputText;
808
1379
  return this.FKDisplayName || '';
809
1380
  }
1381
+ /**
1382
+ * True when this FK currently points at a real record (has a value AND we can show
1383
+ * its name). Drives the "linked" affordance — the chain icon + accent — so the user
1384
+ * can tell at a glance this is a resolved link, not free text.
1385
+ */
1386
+ get FKHasLinkedValue() {
1387
+ return this.Value != null && this.Value !== '' && this.FKDisplayName != null;
1388
+ }
1389
+ /** Whether a dropdown row is the record currently linked by this FK (UUID-safe compare). */
1390
+ IsFKRowSelected(suggestion) {
1391
+ const v = this.Value;
1392
+ const pk = suggestion.PrimaryKeyValue;
1393
+ if (v == null || pk == null)
1394
+ return false;
1395
+ return UUIDsEqual(String(v), String(pk));
1396
+ }
1397
+ /**
1398
+ * Resolves the related `EntityInfo` for this FK field via the instance provider
1399
+ * (multi-provider safe — never the global `Metadata`).
1400
+ */
1401
+ getRelatedEntityInfo() {
1402
+ const relatedName = this.FieldInfo?.RelatedEntity;
1403
+ if (!relatedName)
1404
+ return undefined;
1405
+ return this.ProviderToUse.EntityByName(relatedName);
1406
+ }
1407
+ /**
1408
+ * Returns the LIVE cached array of records for the related entity IF a loaded
1409
+ * engine holds the full (unfiltered) set; otherwise null. Records are read-only —
1410
+ * never mutate. Wraps {@link BaseEngineRegistry.TryGetCachedRecords}.
1411
+ */
1412
+ getCachedRecordsForRelatedEntity() {
1413
+ const relatedName = this.FieldInfo?.RelatedEntity;
1414
+ if (!relatedName)
1415
+ return null;
1416
+ const registry = BaseEngineRegistry.Instance;
1417
+ const records = registry.TryGetCachedRecords(relatedName, { unfilteredOnly: true });
1418
+ // Treat an empty (or absent) cache as "no usable cache" so callers fall through
1419
+ // to the DB path and still show options on focus — never a blank dropdown.
1420
+ return records && records.length > 0 ? records : null;
1421
+ }
1422
+ /**
1423
+ * Builds (and memoizes) the column plan for the related entity: the name field,
1424
+ * the PK field used as the FK value, and the extra `DefaultInView` columns
1425
+ * (excluding the name + PK). Returns null when the related entity can't be resolved
1426
+ * or has no usable name/PK.
1427
+ */
1428
+ buildColumnPlan() {
1429
+ if (this._fkColumnPlan) {
1430
+ this.ensureLinkedFieldPrefsLoaded(this._fkColumnPlan);
1431
+ return this._fkColumnPlan;
1432
+ }
1433
+ const relatedEntity = this.getRelatedEntityInfo();
1434
+ if (!relatedEntity)
1435
+ return null;
1436
+ const nameField = relatedEntity.NameField;
1437
+ const pkFields = relatedEntity.PrimaryKeys;
1438
+ if (!nameField && (!pkFields || pkFields.length !== 1))
1439
+ return null;
1440
+ const nameFieldName = nameField ? nameField.Name : pkFields[0].Name;
1441
+ const pkFieldName = this.FieldInfo?.RelatedEntityFieldName || (pkFields?.[0]?.Name ?? 'ID');
1442
+ // A field flagged ExtendedType='Icon' holds a per-row icon class — render it
1443
+ // as the row's leading glyph, not as a text column.
1444
+ const iconField = relatedEntity.Fields.find(f => f.ExtendedType === 'Icon');
1445
+ const iconFieldName = iconField?.Name ?? null;
1446
+ const columnFields = this.computeOrderedColumns(relatedEntity, nameFieldName, pkFieldName, iconFieldName);
1447
+ const extraFieldNames = columnFields.filter(c => c !== nameFieldName);
1448
+ this._fkColumnPlan = {
1449
+ NameFieldName: nameFieldName,
1450
+ PkFieldName: pkFieldName,
1451
+ ColumnFields: columnFields,
1452
+ ExtraFieldNames: extraFieldNames,
1453
+ ExtraHeaders: extraFieldNames.map(n => this.labelForRelatedField(n)),
1454
+ IconFieldName: iconFieldName,
1455
+ EntityIcon: relatedEntity.Icon || null
1456
+ };
1457
+ this.FKSearchableFields = this.buildSearchableFields(this._fkColumnPlan);
1458
+ this.ensureLinkedFieldPrefsLoaded(this._fkColumnPlan);
1459
+ return this._fkColumnPlan;
1460
+ }
1461
+ /**
1462
+ * Whether a `DefaultInView` field is worth showing as an extra dropdown column.
1463
+ * Excludes columns that read as opaque noise to a human picking a record:
1464
+ * • Primary keys (UUIDs/identities).
1465
+ * • Foreign-key columns — these hold the related record's raw ID (e.g. `ParentID`
1466
+ * → a GUID), not a human-readable label. The view's joined *name* field (if it's
1467
+ * itself `DefaultInView`) is the readable substitute and is kept.
1468
+ */
1469
+ isUsefulExtraColumn(f) {
1470
+ if (f.IsPrimaryKey)
1471
+ return false;
1472
+ if (f.RelatedEntityID && f.RelatedEntityID.length > 0)
1473
+ return false; // foreign key → raw ID
1474
+ return true;
1475
+ }
1476
+ /**
1477
+ * The ordered list of display columns INCLUDING the name field — the user-reorderable
1478
+ * column order. Honors a user `visibleFields` override (exact set + order, letting them
1479
+ * add fields like ID, drop defaults, or move the name field); otherwise falls back to
1480
+ * `[name, ...DefaultInView columns]`. The name field is always guaranteed present, and
1481
+ * the icon field is never a text column.
1482
+ */
1483
+ computeOrderedColumns(relatedEntity, nameFieldName, pkFieldName, iconFieldName) {
1484
+ const exists = (n) => n !== iconFieldName && !!relatedEntity.Fields.find(f => f.Name === n);
1485
+ const saved = this.fkHostEntityName && this.fkFieldCodeName
1486
+ ? LinkedFieldOptionsStore.Instance.Get(this.fkHostEntityName, this.fkFieldCodeName) : undefined;
1487
+ let cols;
1488
+ if (saved?.visibleFields) {
1489
+ cols = saved.visibleFields.filter(exists);
1490
+ // Migrate older prefs (stored extras-only, without the name field) and guarantee
1491
+ // the name field is always present.
1492
+ if (!cols.includes(nameFieldName))
1493
+ cols = [nameFieldName, ...cols];
1494
+ }
1495
+ else {
1496
+ const defaults = relatedEntity.Fields
1497
+ .filter(f => f.DefaultInView && f.Name !== nameFieldName && f.Name !== pkFieldName
1498
+ && f.Name !== iconFieldName && this.isUsefulExtraColumn(f))
1499
+ .map(f => f.Name);
1500
+ cols = [nameFieldName, ...defaults];
1501
+ }
1502
+ // De-dupe (preserve order) and ensure the name field is present.
1503
+ const seen = new Set();
1504
+ const ordered = cols.filter(c => (seen.has(c) ? false : (seen.add(c), true)));
1505
+ if (!ordered.includes(nameFieldName))
1506
+ ordered.unshift(nameFieldName);
1507
+ return ordered;
1508
+ }
1509
+ // ============================================
1510
+ // SCOPE PICKER + PER-USER PREFS
1511
+ // ============================================
1512
+ /** Host entity name (the entity whose form this field belongs to), or null. */
1513
+ get fkHostEntityName() {
1514
+ return this.Record?.EntityInfo?.Name ?? null;
1515
+ }
1516
+ /** This FK field's code name on the host entity, or null. */
1517
+ get fkFieldCodeName() {
1518
+ return this.FieldInfo?.Name ?? null;
1519
+ }
1520
+ /** Whether the active search column is the name field (drives where we highlight). */
1521
+ isSearchingNameField(plan) {
1522
+ return !this.FKSearchField || this.FKSearchField === plan.NameFieldName;
1523
+ }
1524
+ /** A field is scope-searchable if it's a string column (LIKE-able) and not a system column. */
1525
+ isScopeSearchableField(f) {
1526
+ if (f.TSType !== EntityFieldTSType.String)
1527
+ return false;
1528
+ if (f.Name.startsWith('__mj_'))
1529
+ return false;
1530
+ return true;
1531
+ }
1532
+ /** Friendly label for a related-entity field code name. */
1533
+ labelForRelatedField(name) {
1534
+ return this.getRelatedEntityInfo()?.Fields.find(x => x.Name === name)?.DisplayNameOrName ?? name;
1535
+ }
1536
+ /** Whether a field code name exists on the related entity (guards stale saved prefs). */
1537
+ isValidRelatedField(name) {
1538
+ return !!this.getRelatedEntityInfo()?.Fields.find(x => x.Name === name);
1539
+ }
1540
+ /**
1541
+ * Build the scope-picker field list: the name + shown columns ('shown' group),
1542
+ * then any other searchable string fields like ID/Status ('other' group).
1543
+ */
1544
+ buildSearchableFields(plan) {
1545
+ const re = this.getRelatedEntityInfo();
1546
+ if (!re)
1547
+ return [];
1548
+ const iconFor = (fieldName) => {
1549
+ if (fieldName === plan.NameFieldName)
1550
+ return 'fa-solid fa-font';
1551
+ return re.Fields.find(x => x.Name === fieldName)?.IsPrimaryKey ? 'fa-solid fa-hashtag' : 'fa-solid fa-tag';
1552
+ };
1553
+ // 'shown' group rendered in the actual column order so the menu matches the grid
1554
+ // (and so the up/down arrows hide correctly on the true first/last columns).
1555
+ const shown = new Set(plan.ColumnFields);
1556
+ const list = plan.ColumnFields.map(fieldName => ({
1557
+ FieldName: fieldName,
1558
+ Label: this.labelForRelatedField(fieldName),
1559
+ Icon: iconFor(fieldName),
1560
+ Group: 'shown'
1561
+ }));
1562
+ for (const f of re.Fields) {
1563
+ if (shown.has(f.Name) || f.Name === plan.IconFieldName)
1564
+ continue;
1565
+ if (!this.isScopeSearchableField(f))
1566
+ continue;
1567
+ list.push({
1568
+ FieldName: f.Name,
1569
+ Label: f.DisplayNameOrName,
1570
+ Icon: f.IsPrimaryKey ? 'fa-solid fa-hashtag' : 'fa-solid fa-font',
1571
+ Group: 'other'
1572
+ });
1573
+ }
1574
+ return list;
1575
+ }
1576
+ /**
1577
+ * Load this (host entity, FK field)'s saved prefs — search scope, sort, column
1578
+ * widths — once per field. No-ops when the field hasn't changed. Falls back to
1579
+ * defaults (search the name field, natural sort, content-sized columns) and only
1580
+ * applies a saved value when it still resolves to a real field.
1581
+ */
1582
+ ensureLinkedFieldPrefsLoaded(plan) {
1583
+ const key = this.fkHostEntityName && this.fkFieldCodeName
1584
+ ? `${this.fkHostEntityName}|${this.fkFieldCodeName}` : null;
1585
+ if (key === this._fkPrefKey)
1586
+ return;
1587
+ this._fkPrefKey = key;
1588
+ // Defaults
1589
+ this.FKSearchField = plan.NameFieldName;
1590
+ this._fkColWidths = {};
1591
+ const saved = this.fkHostEntityName && this.fkFieldCodeName
1592
+ ? LinkedFieldOptionsStore.Instance.Get(this.fkHostEntityName, this.fkFieldCodeName) : undefined;
1593
+ if (saved) {
1594
+ if (saved.searchField && this.isValidRelatedField(saved.searchField)) {
1595
+ this.FKSearchField = saved.searchField;
1596
+ }
1597
+ if (saved.sortField !== undefined && (saved.sortField === null || this.isValidRelatedField(saved.sortField))) {
1598
+ this.FKSortField = saved.sortField;
1599
+ this.FKSortDir = saved.sortDir ?? 'asc';
1600
+ }
1601
+ if (saved.colWidths)
1602
+ this._fkColWidths = { ...saved.colWidths };
1603
+ }
1604
+ this.FKSearchFieldLabel = this.labelForRelatedField(this.FKSearchField);
1605
+ }
1606
+ /** Format a raw cell value for display in the dropdown (delegates to the pure helper). */
1607
+ formatCell(val) {
1608
+ return FormatFKCell(val);
1609
+ }
1610
+ /**
1611
+ * Build the suggestion view-models from a set of plain rows (cached or DB),
1612
+ * applying the typed-query substring highlight to the name column.
1613
+ * `getField` abstracts cached BaseEntity rows (`.Get(name)`) vs simple objects.
1614
+ */
1615
+ buildSuggestions(rows, plan, query) {
1616
+ const searchField = this.FKSearchField || plan.NameFieldName;
1617
+ // Only highlight the column actually being searched, and only when enabled.
1618
+ const nameQuery = (this.FKHighlightMatches && this.isSearchingNameField(plan)) ? query : '';
1619
+ return rows.map(row => {
1620
+ const name = this.formatCell(row.get(plan.NameFieldName));
1621
+ // Per-row icon from the entity's ExtendedType='Icon' field; else the
1622
+ // entity-level icon; else none.
1623
+ const rowIcon = plan.IconFieldName ? this.formatCell(row.get(plan.IconFieldName)).trim() : '';
1624
+ return {
1625
+ PrimaryKeyValue: row.get(plan.PkFieldName),
1626
+ DisplayName: name,
1627
+ // Empty query yields the (still HTML-escaped) plain name — no marks.
1628
+ HighlightedName: HighlightSearchMatches(name, nameQuery, 'mj-forms-search-highlight'),
1629
+ ExtraColumns: plan.ExtraFieldNames.map((fieldName, i) => {
1630
+ const value = this.formatCell(row.get(fieldName));
1631
+ const colQuery = (this.FKHighlightMatches && fieldName === searchField) ? query : '';
1632
+ return {
1633
+ FieldName: fieldName,
1634
+ Header: plan.ExtraHeaders[i],
1635
+ Value: value,
1636
+ HighlightedValue: HighlightSearchMatches(value, colQuery, 'mj-forms-search-highlight')
1637
+ };
1638
+ }),
1639
+ Icon: (rowIcon || plan.EntityIcon) || null
1640
+ };
1641
+ });
1642
+ }
1643
+ /** Apply a freshly-built suggestion list to the dropdown state + reposition + portal. */
1644
+ applySuggestions(suggestions, plan) {
1645
+ // Pinned "currently selected" row: in browse mode (empty query) with a valid linked
1646
+ // value, lift the selected record into a sticky section and remove it from the list so
1647
+ // the user can keep it or pick another without clearing first.
1648
+ this.FKSelectedSuggestion = null;
1649
+ const browseMode = this._fkQuery.trim().length === 0;
1650
+ if (browseMode && this.FKHasLinkedValue) {
1651
+ const idx = suggestions.findIndex(s => this.IsFKRowSelected(s));
1652
+ if (idx >= 0) {
1653
+ this.FKSelectedSuggestion = suggestions[idx];
1654
+ suggestions = suggestions.filter((_, i) => i !== idx);
1655
+ }
1656
+ else {
1657
+ // Selected record isn't in the (first-N) result — show a lightweight pinned row.
1658
+ this.FKSelectedSuggestion = this.buildSelectedFallbackSuggestion(plan);
1659
+ }
1660
+ }
1661
+ this._fkSuggestionsNatural = suggestions;
1662
+ this.FKNameField = plan.NameFieldName;
1663
+ // Full ordered column list (incl. the name field) + matching headers.
1664
+ this.FKColumnFields = plan.ColumnFields;
1665
+ this.FKColumnHeaders = plan.ColumnFields.map(c => c === plan.NameFieldName ? 'Name' : this.labelForRelatedField(c));
1666
+ this.FKHasIconColumn = (this.FKSelectedSuggestion?.Icon != null) || suggestions.some(s => s.Icon != null);
1667
+ this.FKSuggestions = this.sortSuggestions(suggestions);
1668
+ this.FKActiveIndex = this.FKSuggestions.length > 0 ? 0 : -1;
1669
+ this.FKNoMatches = suggestions.length === 0 && !this.FKSelectedSuggestion;
1670
+ // Show the dropdown for rows, a "no matches" state, or just the pinned selection.
1671
+ this.ShowFKDropdown = suggestions.length > 0 || this.FKNoMatches || !!this.FKSelectedSuggestion;
1672
+ if (this.ShowFKDropdown && this._lastFKInputEl) {
1673
+ this.updateDropdownPosition(this._lastFKInputEl);
1674
+ this.startScrollListener();
1675
+ this.portalDropdownToBody();
1676
+ }
1677
+ this.cdr.markForCheck();
1678
+ }
1679
+ /**
1680
+ * Build a lightweight pinned row for the selected record when it isn't present in the
1681
+ * current result set (DB beyond first-N, or cached beyond the focus-show limit). We have
1682
+ * its display name from the FK name resolution; extra-column values are left blank.
1683
+ */
1684
+ buildSelectedFallbackSuggestion(plan) {
1685
+ const name = this.FKDisplayName;
1686
+ if (this.Value == null || this.Value === '' || !name)
1687
+ return null;
1688
+ return {
1689
+ PrimaryKeyValue: this.Value,
1690
+ DisplayName: name,
1691
+ HighlightedName: HighlightSearchMatches(name, '', 'mj-forms-search-highlight'),
1692
+ ExtraColumns: plan.ExtraFieldNames.map((fn, i) => ({
1693
+ FieldName: fn, Header: plan.ExtraHeaders[i], Value: '', HighlightedValue: ''
1694
+ })),
1695
+ Icon: plan.EntityIcon ?? null
1696
+ };
1697
+ }
1698
+ /**
1699
+ * Returns a sorted copy of the suggestions per the active sort column/direction.
1700
+ * Null sort field → natural order (original array, untouched). Sorts on the name
1701
+ * column's `DisplayName` or the matching extra column's formatted `Value`,
1702
+ * case-insensitively.
1703
+ */
1704
+ sortSuggestions(suggestions) {
1705
+ const field = this.FKSortField;
1706
+ if (!field)
1707
+ return suggestions;
1708
+ const keyOf = (s) => {
1709
+ if (field === this.FKNameField)
1710
+ return s.DisplayName ?? '';
1711
+ return s.ExtraColumns.find(c => c.FieldName === field)?.Value ?? '';
1712
+ };
1713
+ const dir = this.FKSortDir === 'desc' ? -1 : 1;
1714
+ return [...suggestions].sort((a, b) => dir * keyOf(a).localeCompare(keyOf(b), undefined, { numeric: true, sensitivity: 'base' }));
1715
+ }
1716
+ /**
1717
+ * Toggle the sort on a column header: same column cycles asc → desc → none;
1718
+ * a new column starts at asc. Re-derives the visible list from the natural snapshot.
1719
+ */
1720
+ OnFKSortToggle(fieldName) {
1721
+ if (this.FKSortField === fieldName) {
1722
+ if (this.FKSortDir === 'asc')
1723
+ this.FKSortDir = 'desc';
1724
+ else {
1725
+ this.FKSortField = null;
1726
+ this.FKSortDir = 'asc';
1727
+ } // desc → cleared
1728
+ }
1729
+ else {
1730
+ this.FKSortField = fieldName;
1731
+ this.FKSortDir = 'asc';
1732
+ }
1733
+ this.FKSuggestions = this.sortSuggestions(this._fkSuggestionsNatural);
1734
+ this.FKActiveIndex = this.FKSuggestions.length > 0 ? 0 : -1;
1735
+ this.persistLinkedFieldSort();
1736
+ this.cdr.markForCheck();
1737
+ }
1738
+ /** Persist the active sort for this (host entity, FK field) pair. */
1739
+ persistLinkedFieldSort() {
1740
+ if (this.fkHostEntityName && this.fkFieldCodeName) {
1741
+ LinkedFieldOptionsStore.Instance.SetSort(this.fkHostEntityName, this.fkFieldCodeName, this.FKSortField, this.FKSortDir);
1742
+ }
1743
+ }
1744
+ /** FontAwesome class for a column header's sort indicator (idle / asc / desc). */
1745
+ FKSortIcon(fieldName) {
1746
+ if (this.FKSortField !== fieldName)
1747
+ return 'fa-solid fa-sort mj-fk-sort-icon mj-fk-sort-icon--idle';
1748
+ return this.FKSortDir === 'asc'
1749
+ ? 'fa-solid fa-sort-up mj-fk-sort-icon'
1750
+ : 'fa-solid fa-sort-down mj-fk-sort-icon';
1751
+ }
1752
+ // ---- Scope pill (search-field picker) ----
1753
+ /** Toggle the scope-picker menu. mousedown+preventDefault keeps the input focused. */
1754
+ OnFKScopeToggle(event) {
1755
+ event.preventDefault();
1756
+ event.stopPropagation();
1757
+ this.FKShowScopeMenu = !this.FKShowScopeMenu;
1758
+ this.cdr.markForCheck();
1759
+ }
1760
+ /** Whether a scope-menu row is the active search field. */
1761
+ IsFKScopeActive(field) {
1762
+ return field.FieldName === (this.FKSearchField || this.FKNameField);
1763
+ }
1764
+ /** Whether there are non-visible searchable fields (drives the "Other fields" group). */
1765
+ get FKHasOtherSearchableFields() {
1766
+ return this.FKSearchableFields.some(f => f.Group === 'other');
1767
+ }
1768
+ /** User picked a field to search by — persist the override and re-run the search. */
1769
+ OnFKScopeSelect(event, field) {
1770
+ event.preventDefault();
1771
+ this.selectScope(field);
1772
+ }
1773
+ /** Set the active search field (used by click + the no-drag path of menu drag). */
1774
+ selectScope(field) {
1775
+ this.FKSearchField = field.FieldName;
1776
+ this.FKSearchFieldLabel = field.Label;
1777
+ this.FKShowScopeMenu = false;
1778
+ if (this.fkHostEntityName && this.fkFieldCodeName) {
1779
+ LinkedFieldOptionsStore.Instance.SetSearchField(this.fkHostEntityName, this.fkFieldCodeName, field.FieldName);
1780
+ }
1781
+ this.rerunCurrentFKSearch();
1782
+ this.cdr.markForCheck();
1783
+ }
1784
+ /** Re-run the active query against the (possibly newly-chosen) search field. */
1785
+ rerunCurrentFKSearch() {
1786
+ const query = this._fkQuery;
1787
+ const cached = this.getCachedRecordsForRelatedEntity();
1788
+ if (cached)
1789
+ this.searchCachedEntity(cached, query);
1790
+ else
1791
+ void this.searchRelatedEntity(query);
1792
+ }
1793
+ // ---- Column visibility (show/hide a field as a column) ----
1794
+ /** Whether a field is currently rendered as a column (the Name column is always shown). */
1795
+ IsFKColumnVisible(field) {
1796
+ return field.FieldName === this.FKNameField || this.FKColumnFields.includes(field.FieldName);
1797
+ }
1798
+ /** Whether this field's column visibility can be toggled (Name is always shown). */
1799
+ CanToggleFKColumn(field) {
1800
+ return field.FieldName !== this.FKNameField;
1801
+ }
1802
+ /**
1803
+ * Toggle whether a field shows as a column. Persists the full visible set, then
1804
+ * rebuilds the column plan + re-runs the search so the grid reflects it live.
1805
+ * stopPropagation so the row's search-scope click doesn't also fire.
1806
+ */
1807
+ OnFKColumnToggle(event, field) {
1808
+ event.preventDefault();
1809
+ event.stopPropagation();
1810
+ if (!this.CanToggleFKColumn(field))
1811
+ return;
1812
+ const next = [...this.FKColumnFields];
1813
+ const idx = next.indexOf(field.FieldName);
1814
+ if (idx >= 0)
1815
+ next.splice(idx, 1);
1816
+ else
1817
+ next.push(field.FieldName);
1818
+ this.applyVisibleColumns(next);
1819
+ }
1820
+ /** Persist a new visible-column set/order and rebuild the grid live. */
1821
+ applyVisibleColumns(cols) {
1822
+ if (this.fkHostEntityName && this.fkFieldCodeName) {
1823
+ LinkedFieldOptionsStore.Instance.SetVisibleFields(this.fkHostEntityName, this.fkFieldCodeName, cols);
1824
+ }
1825
+ this._fkColumnPlan = null; // force rebuild with the new column set/order
1826
+ this.rerunCurrentFKSearch();
1827
+ this.cdr.markForCheck();
1828
+ }
1829
+ // ---- Column reorder (up/down arrows in the field-selector menu) ----
1830
+ /** Whether the column can move up (it's a column and not already first). */
1831
+ CanMoveFKColumnUp(field) {
1832
+ return this.FKColumnFields.indexOf(field) > 0;
1833
+ }
1834
+ /** Whether the column can move down (it's a column and not already last). */
1835
+ CanMoveFKColumnDown(field) {
1836
+ const i = this.FKColumnFields.indexOf(field);
1837
+ return i >= 0 && i < this.FKColumnFields.length - 1;
1838
+ }
1839
+ /**
1840
+ * Move a column one slot up (delta -1) or down (delta +1) and persist. mousedown +
1841
+ * stopPropagation so the row's select-scope handler doesn't fire and the menu stays open.
1842
+ */
1843
+ MoveFKColumn(event, field, delta) {
1844
+ event.preventDefault();
1845
+ event.stopPropagation();
1846
+ const cols = [...this.FKColumnFields];
1847
+ const i = cols.indexOf(field);
1848
+ const j = i + delta;
1849
+ if (i < 0 || j < 0 || j >= cols.length)
1850
+ return;
1851
+ [cols[i], cols[j]] = [cols[j], cols[i]];
1852
+ this.applyVisibleColumns(cols);
1853
+ }
1854
+ /**
1855
+ * CSS `grid-template-columns` for the dropdown grid: optional icon column, then one
1856
+ * track per ordered column. The LAST column grows to fill any remaining width (`1fr`)
1857
+ * so the grid never leaves dead space on the right; earlier columns size to content.
1858
+ * A user-resized column uses its saved pixel width as the floor.
1859
+ */
1860
+ get FKGridTemplateColumns() {
1861
+ const cols = [];
1862
+ if (this.FKHasIconColumn)
1863
+ cols.push('min-content');
1864
+ const lastIdx = this.FKColumnFields.length - 1;
1865
+ this.FKColumnFields.forEach((field, i) => cols.push(this.fkColumnTrack(field, i === lastIdx)));
1866
+ return cols.join(' ');
1867
+ }
1868
+ /**
1869
+ * Track sizing for one column. Resized → fixed px (the last column still grows past it
1870
+ * via `1fr` when there's room). Default → content-sized, except the last column which
1871
+ * fills remaining space.
1872
+ */
1873
+ fkColumnTrack(field, isLast) {
1874
+ const w = this._fkColWidths[field];
1875
+ const min = field === this.FKNameField ? 120 : 80;
1876
+ if (w)
1877
+ return isLast ? `minmax(${w}px, 1fr)` : `${w}px`;
1878
+ return isLast ? `minmax(${min}px, 1fr)` : `minmax(${min}px, max-content)`;
1879
+ }
1880
+ /** Whether a column's cells should stretch to fill their track (last column or resized). */
1881
+ FKColumnFillsTrack(field, isLast) {
1882
+ return isLast || this._fkColWidths[field] != null;
1883
+ }
1884
+ /** The built cell (value + highlighted html) for a non-name column of a suggestion. */
1885
+ FKCellFor(suggestion, field) {
1886
+ return suggestion.ExtraColumns.find(c => c.FieldName === field);
1887
+ }
1888
+ /** Header sort handler (grid headers click-to-sort only; drag-reorder is menu-only). */
1889
+ OnFKHeaderSort(event, field) {
1890
+ event.preventDefault(); // keep input focus so the body-portaled dropdown stays open
1891
+ this.OnFKSortToggle(field);
1892
+ }
1893
+ // ---- Column resize (drag a header's right edge) ----
1894
+ /** Begin resizing a column. stopPropagation so the header's sort handler doesn't fire. */
1895
+ OnFKColResizeStart(event, field) {
1896
+ event.preventDefault();
1897
+ event.stopPropagation();
1898
+ const headerCell = event.target.closest('.mj-fk-hcell');
1899
+ const startWidth = headerCell ? headerCell.offsetWidth : 120;
1900
+ this._fkResize = { field, startX: event.clientX, startWidth };
1901
+ this._fkResizeMove = (e) => this.onFKColResizeMove(e);
1902
+ this._fkResizeUp = () => this.onFKColResizeEnd();
1903
+ document.addEventListener('mousemove', this._fkResizeMove);
1904
+ document.addEventListener('mouseup', this._fkResizeUp);
1905
+ }
1906
+ onFKColResizeMove(e) {
1907
+ if (!this._fkResize)
1908
+ return;
1909
+ const width = Math.max(60, Math.round(this._fkResize.startWidth + (e.clientX - this._fkResize.startX)));
1910
+ this._fkColWidths = { ...this._fkColWidths, [this._fkResize.field]: width };
1911
+ this.cdr.markForCheck();
1912
+ }
1913
+ onFKColResizeEnd() {
1914
+ if (this._fkResize) {
1915
+ const width = this._fkColWidths[this._fkResize.field];
1916
+ if (width && this.fkHostEntityName && this.fkFieldCodeName) {
1917
+ LinkedFieldOptionsStore.Instance.SetColWidth(this.fkHostEntityName, this.fkFieldCodeName, this._fkResize.field, width);
1918
+ }
1919
+ }
1920
+ this.teardownFKResizeListeners();
1921
+ this.cdr.markForCheck();
1922
+ }
1923
+ teardownFKResizeListeners() {
1924
+ if (this._fkResizeMove)
1925
+ document.removeEventListener('mousemove', this._fkResizeMove);
1926
+ if (this._fkResizeUp)
1927
+ document.removeEventListener('mouseup', this._fkResizeUp);
1928
+ this._fkResize = null;
1929
+ this._fkResizeMove = null;
1930
+ this._fkResizeUp = null;
1931
+ }
810
1932
  /** Handle typing in the FK search input */
811
1933
  OnFKInput(event) {
812
1934
  const input = event.target;
813
1935
  this._fkInputText = input.value;
814
1936
  this._lastFKInputEl = input;
815
1937
  this.FKIsMatched = false;
816
- // Debounce search
1938
+ const query = this._fkInputText;
1939
+ // Cached fast path: filter the in-memory array immediately (no DB, no debounce).
1940
+ const cached = this.getCachedRecordsForRelatedEntity();
1941
+ if (cached) {
1942
+ if (this._fkSearchTimeout) {
1943
+ clearTimeout(this._fkSearchTimeout);
1944
+ this._fkSearchTimeout = null;
1945
+ }
1946
+ this.searchCachedEntity(cached, query);
1947
+ return;
1948
+ }
1949
+ // DB path: debounce a RunView search. Empty query (cleared field) → first N,
1950
+ // so clearing the field reveals the list rather than closing it.
817
1951
  if (this._fkSearchTimeout)
818
1952
  clearTimeout(this._fkSearchTimeout);
819
1953
  this._fkSearchTimeout = setTimeout(() => {
820
- if (this._fkInputText && this._fkInputText.length >= 1) {
821
- this.searchRelatedEntity(this._fkInputText);
822
- }
823
- else {
824
- this.FKSuggestions = [];
825
- this.ShowFKDropdown = false;
826
- this.stopScrollListener();
827
- this.cdr.markForCheck();
828
- }
1954
+ void this.searchRelatedEntity(this._fkInputText ?? '');
829
1955
  }, 300);
830
1956
  }
831
- /** Show dropdown on focus if suggestions exist */
1957
+ /**
1958
+ * Show dropdown on focus. With a cached-unfiltered entity we immediately show the
1959
+ * first N rows (sorted by name) even on empty input — zero DB round-trips. Without
1960
+ * a cache we keep prior behavior: only re-open if we already have suggestions.
1961
+ */
832
1962
  OnFKFocus(event) {
833
1963
  const input = event.target;
834
1964
  this._lastFKInputEl = input;
835
- if (this.FKSuggestions.length > 0) {
836
- this.updateDropdownPosition(input);
837
- this.startScrollListener();
838
- this.ShowFKDropdown = true;
1965
+ this.FKFocused = true; // reveal the scope pill while focused
1966
+ // Select any pre-filled (linked) text so the first keystroke replaces it instead
1967
+ // of appending — matches how a searchable dropdown behaves.
1968
+ if (input.value)
1969
+ input.select();
1970
+ this.showInitialFKSuggestions();
1971
+ }
1972
+ /**
1973
+ * Show the initial suggestion list (no/empty query): the full set from a cached
1974
+ * unfiltered engine, otherwise the first N rows via a DB query. Used on focus and
1975
+ * when the field is cleared, so the user always sees options without typing.
1976
+ */
1977
+ showInitialFKSuggestions() {
1978
+ // Always show the FULL list (empty query) on focus/clear — even when a value is
1979
+ // already selected — so the user can browse and re-pick like a normal dropdown.
1980
+ // Filtering only kicks in once they actually type (OnFKInput).
1981
+ const cached = this.getCachedRecordsForRelatedEntity();
1982
+ if (cached) {
1983
+ if (this._fkSearchTimeout) {
1984
+ clearTimeout(this._fkSearchTimeout);
1985
+ this._fkSearchTimeout = null;
1986
+ }
1987
+ this.searchCachedEntity(cached, '');
1988
+ return;
1989
+ }
1990
+ void this.searchRelatedEntity('');
1991
+ }
1992
+ /**
1993
+ * In-memory search over a cached-unfiltered entity array. Case-insensitive substring
1994
+ * on the name field. Empty query → first N rows sorted by name (focus-show). Instant,
1995
+ * no spinner, no DB.
1996
+ */
1997
+ searchCachedEntity(records, query) {
1998
+ const plan = this.buildColumnPlan();
1999
+ if (!plan) {
2000
+ this.closeFKDropdown();
839
2001
  this.cdr.markForCheck();
2002
+ return;
840
2003
  }
2004
+ this._fkQuery = query;
2005
+ const accessor = (r) => ({ get: (field) => r.Get(field) });
2006
+ const searchField = this.FKSearchField || plan.NameFieldName;
2007
+ const matches = FilterCachedFKRows(records, query, MjFormFieldComponent.FK_FOCUS_SHOW_LIMIT, r => r.Get(searchField));
2008
+ this.FKLoading = false;
2009
+ this.applySuggestions(this.buildSuggestions(matches.map(accessor), plan, query), plan);
841
2010
  }
842
2011
  /** Hide dropdown on blur, revert to matched name if user didn't select */
843
2012
  OnFKBlur() {
844
- // Small delay so mousedown on dropdown items fires first
2013
+ // Small delay so mousedown on dropdown items / scope menu fires first
845
2014
  setTimeout(() => {
846
- this.ShowFKDropdown = false;
847
- this.stopScrollListener();
2015
+ this.closeFKDropdown();
2016
+ this.FKShowScopeMenu = false;
2017
+ this.FKFocused = false; // hide the scope pill
848
2018
  // If user was typing but didn't select, revert to display name
849
2019
  if (!this.FKIsMatched && this._fkInputText !== null) {
850
2020
  this._fkInputText = null;
@@ -852,14 +2022,66 @@ export class MjFormFieldComponent extends BaseAngularComponent {
852
2022
  this.cdr.markForCheck();
853
2023
  }, 200);
854
2024
  }
855
- /** Select an item from the FK dropdown */
2025
+ /**
2026
+ * Keyboard navigation in the FK input: ArrowDown/ArrowUp move the active row,
2027
+ * Enter selects it, Escape closes the dropdown.
2028
+ */
2029
+ OnFKKeydown(event) {
2030
+ if (!this.ShowFKDropdown || this.FKSuggestions.length === 0) {
2031
+ if (event.key === 'Escape') {
2032
+ this.closeFKDropdown();
2033
+ this.cdr.markForCheck();
2034
+ }
2035
+ return;
2036
+ }
2037
+ switch (event.key) {
2038
+ case 'ArrowDown':
2039
+ event.preventDefault();
2040
+ this.FKActiveIndex = Math.min(this.FKActiveIndex + 1, this.FKSuggestions.length - 1);
2041
+ this.scrollActiveOptionIntoView();
2042
+ this.cdr.markForCheck();
2043
+ break;
2044
+ case 'ArrowUp':
2045
+ event.preventDefault();
2046
+ this.FKActiveIndex = Math.max(this.FKActiveIndex - 1, 0);
2047
+ this.scrollActiveOptionIntoView();
2048
+ this.cdr.markForCheck();
2049
+ break;
2050
+ case 'Enter': {
2051
+ const active = this.FKSuggestions[this.FKActiveIndex];
2052
+ if (active) {
2053
+ event.preventDefault();
2054
+ this.selectFKSuggestion(active);
2055
+ }
2056
+ break;
2057
+ }
2058
+ case 'Escape':
2059
+ event.preventDefault();
2060
+ this.closeFKDropdown();
2061
+ this.cdr.markForCheck();
2062
+ break;
2063
+ }
2064
+ }
2065
+ /** Scroll the keyboard-active option into view inside the (possibly portaled) dropdown. */
2066
+ scrollActiveOptionIntoView() {
2067
+ Promise.resolve().then(() => {
2068
+ const dropdown = this._portaledDropdownEl
2069
+ ?? this.hostRef?.nativeElement?.querySelector('.mj-fk-dropdown');
2070
+ const active = dropdown?.querySelectorAll('.mj-fk-option')[this.FKActiveIndex];
2071
+ active?.scrollIntoView({ block: 'nearest' });
2072
+ });
2073
+ }
2074
+ /** Select an item from the FK dropdown (mouse) */
856
2075
  OnFKSelectItem(suggestion, event) {
857
2076
  event.preventDefault();
2077
+ this.selectFKSuggestion(suggestion);
2078
+ }
2079
+ /** Shared selection logic for mouse-click and keyboard-Enter. */
2080
+ selectFKSuggestion(suggestion) {
858
2081
  this._fkInputText = suggestion.DisplayName;
859
2082
  this.Value = suggestion.PrimaryKeyValue;
860
2083
  this.FKIsMatched = true;
861
- this.ShowFKDropdown = false;
862
- this.stopScrollListener();
2084
+ this.closeFKDropdown();
863
2085
  // Update virtual name field for visual consistency after save
864
2086
  const nameFieldMap = this.FieldInfo?.RelatedEntityNameFieldMap;
865
2087
  if (nameFieldMap) {
@@ -867,72 +2089,150 @@ export class MjFormFieldComponent extends BaseAngularComponent {
867
2089
  }
868
2090
  this.cdr.markForCheck();
869
2091
  }
2092
+ // ---- Inline "create new related record" ----
2093
+ /**
2094
+ * Whether to show the inline-create affordance: the field opts in (`AllowFKCreate`),
2095
+ * the related entity resolves, and the current user can create records of it (entity
2096
+ * allows creation + role permits — `GetUserPermisions().CanCreate` folds in `AllowCreateAPI`).
2097
+ */
2098
+ get CanCreateFK() {
2099
+ if (!this.AllowFKCreate)
2100
+ return false;
2101
+ const re = this.getRelatedEntityInfo();
2102
+ const user = this.ProviderToUse?.CurrentUser;
2103
+ if (!re || !user)
2104
+ return false;
2105
+ return re.GetUserPermisions(user)?.CanCreate === true;
2106
+ }
2107
+ /** Footer label: prefilled with the typed text when present, else generic "create new". */
2108
+ get FKCreateLabel() {
2109
+ const entityLabel = this.getRelatedEntityInfo()?.DisplayName || this.FieldInfo?.RelatedEntity || 'record';
2110
+ const query = this._fkQuery.trim();
2111
+ return query ? `Create "${query}"` : `Create new ${entityLabel}`;
2112
+ }
2113
+ /**
2114
+ * Ask the host (app layer) to create a new related record, prefilled with the typed
2115
+ * text as the name. We only EMIT the request — opening the form is the app's job (the
2116
+ * generic forms layer must not depend on the app-level form presenter). The host calls
2117
+ * `Complete(record)` when saved and we select it.
2118
+ */
2119
+ OnFKCreateNew(event) {
2120
+ event.preventDefault(); // don't blur the input before we capture the query
2121
+ const plan = this.buildColumnPlan();
2122
+ const relatedEntity = this.FieldInfo?.RelatedEntity;
2123
+ if (!plan || !relatedEntity)
2124
+ return;
2125
+ const query = this._fkQuery.trim();
2126
+ this.FKShowScopeMenu = false;
2127
+ this.FKFocused = false;
2128
+ this.closeFKDropdown();
2129
+ this.cdr.markForCheck();
2130
+ const newRecordValues = {};
2131
+ if (query)
2132
+ newRecordValues[plan.NameFieldName] = query;
2133
+ this.Navigate.emit({
2134
+ Kind: 'create-related',
2135
+ EntityName: relatedEntity,
2136
+ NewRecordValues: Object.keys(newRecordValues).length ? newRecordValues : undefined,
2137
+ Presentation: this.FKCreatePresentation,
2138
+ Provider: this.Provider ?? undefined,
2139
+ Complete: (created) => { if (created)
2140
+ this.selectCreatedFKRecord(created, plan); },
2141
+ });
2142
+ }
2143
+ /** Select a freshly-created related record as this field's value. */
2144
+ selectCreatedFKRecord(created, plan) {
2145
+ const pk = created.Get(plan.PkFieldName);
2146
+ if (pk == null)
2147
+ return;
2148
+ const name = this.formatCell(created.Get(plan.NameFieldName));
2149
+ this._fkInputText = name;
2150
+ this.Value = pk;
2151
+ this.FKIsMatched = true;
2152
+ const nameFieldMap = this.FieldInfo?.RelatedEntityNameFieldMap;
2153
+ if (nameFieldMap)
2154
+ this.Record.Set(nameFieldMap, name);
2155
+ this.closeFKDropdown();
2156
+ this.cdr.markForCheck();
2157
+ }
870
2158
  /** Clear FK value via the X button */
871
2159
  OnFKClearClick(event) {
2160
+ // preventDefault keeps focus on the input (the button never steals it), so the
2161
+ // freshly-opened dropdown stays open for the user to pick a replacement.
872
2162
  event.preventDefault();
873
2163
  this.Value = null;
874
2164
  this._fkInputText = null;
875
2165
  this.FKIsMatched = false;
876
- this.FKSuggestions = [];
877
- this.ShowFKDropdown = false;
878
- this.stopScrollListener();
879
2166
  this._resolvedFKName = undefined;
880
2167
  this._resolvedFKValue = undefined;
881
2168
  const nameFieldMap = this.FieldInfo?.RelatedEntityNameFieldMap;
882
2169
  if (nameFieldMap) {
883
2170
  this.Record.Set(nameFieldMap, '');
884
2171
  }
2172
+ // Re-open the full list — clearing almost always precedes picking something else.
2173
+ this.showInitialFKSuggestions();
885
2174
  this.cdr.markForCheck();
886
2175
  }
2176
+ /** Close the FK dropdown and reset its transient view state. */
2177
+ closeFKDropdown() {
2178
+ this.ShowFKDropdown = false;
2179
+ this.FKLoading = false;
2180
+ this.FKNoMatches = false;
2181
+ this.FKActiveIndex = -1;
2182
+ this.FKSelectedSuggestion = null;
2183
+ this._portaledDropdownEl = null;
2184
+ this.stopScrollListener();
2185
+ }
887
2186
  /**
888
- * Perform a RunView search on the related entity's name field.
2187
+ * Perform a RunView search on the related entity's name field (DB path — used only
2188
+ * when no loaded engine caches the related entity unfiltered).
889
2189
  * Falls back to searching by primary key when no NameField exists (single-field PKs only).
890
2190
  */
891
2191
  async searchRelatedEntity(query) {
2192
+ const plan = this.buildColumnPlan();
892
2193
  const fieldInfo = this.FieldInfo;
893
- if (!fieldInfo?.RelatedEntity)
894
- return;
895
- const md = this.ProviderToUse;
896
- const relatedEntity = md.Entities.find(e => e.Name === fieldInfo.RelatedEntity);
897
- if (!relatedEntity)
2194
+ if (!plan || !fieldInfo?.RelatedEntity)
898
2195
  return;
899
- const nameField = relatedEntity.NameField;
900
- const pkFields = relatedEntity.PrimaryKeys;
901
- // If no NameField, fall back to PK — but only for single-field PKs
902
- if (!nameField) {
903
- if (!pkFields || pkFields.length !== 1)
904
- return;
2196
+ this._fkQuery = query;
2197
+ const seq = ++this._fkSearchSeq;
2198
+ this.FKLoading = true;
2199
+ this.FKNoMatches = false;
2200
+ this.ShowFKDropdown = true;
2201
+ if (this._lastFKInputEl) {
2202
+ this.updateDropdownPosition(this._lastFKInputEl);
2203
+ this.startScrollListener();
2204
+ this.portalDropdownToBody();
905
2205
  }
906
- const nameFieldName = nameField ? nameField.Name : pkFields[0].Name;
907
- const pkFieldName = fieldInfo.RelatedEntityFieldName || 'ID';
908
- // Build Fields array, avoiding duplicates when nameField IS the PK
909
- const fields = nameFieldName === pkFieldName
910
- ? [pkFieldName]
911
- : [pkFieldName, nameFieldName];
912
- const escapedQuery = query.replace(/'/g, "''");
2206
+ this.cdr.markForCheck();
2207
+ // Build Fields: PK + name + extra DefaultInView columns + the searched field +
2208
+ // the per-row icon field (when present), deduped via Set.
2209
+ const searchField = this.FKSearchField || plan.NameFieldName;
2210
+ const fields = Array.from(new Set([
2211
+ plan.PkFieldName, plan.NameFieldName, ...plan.ExtraFieldNames, searchField,
2212
+ ...(plan.IconFieldName ? [plan.IconFieldName] : [])
2213
+ ]));
2214
+ const escapedQuery = query.replace(/'/g, "''").trim();
913
2215
  const rv = RunView.FromMetadataProvider(this.ProviderToUse);
914
2216
  const result = await rv.RunView({
915
2217
  EntityName: fieldInfo.RelatedEntity,
916
- ExtraFilter: `[${nameFieldName}] LIKE '%${escapedQuery}%'`,
917
- MaxRows: 20,
2218
+ // Empty query (focus / cleared field) → no filter → first N rows.
2219
+ ExtraFilter: escapedQuery ? `[${searchField}] LIKE '%${escapedQuery}%'` : '',
2220
+ MaxRows: MjFormFieldComponent.FK_DB_SEARCH_LIMIT,
918
2221
  ResultType: 'simple',
919
2222
  Fields: fields
920
2223
  });
2224
+ // Ignore stale responses (a newer keystroke already fired).
2225
+ if (seq !== this._fkSearchSeq)
2226
+ return;
2227
+ this.FKLoading = false;
921
2228
  if (result.Success) {
922
- this.FKSuggestions = result.Results.map(r => ({
923
- PrimaryKeyValue: r[pkFieldName],
924
- DisplayName: String(r[nameFieldName] || '')
925
- }));
926
- if (this.FKSuggestions.length > 0 && this._lastFKInputEl) {
927
- this.updateDropdownPosition(this._lastFKInputEl);
928
- this.startScrollListener();
929
- }
930
- this.ShowFKDropdown = this.FKSuggestions.length > 0;
2229
+ const accessor = (r) => ({ get: (field) => r[field] });
2230
+ this.applySuggestions(this.buildSuggestions(result.Results.map(accessor), plan, query), plan);
931
2231
  }
932
2232
  else {
933
2233
  this.FKSuggestions = [];
934
- this.ShowFKDropdown = false;
935
- this.stopScrollListener();
2234
+ this.FKNoMatches = true;
2235
+ this.ShowFKDropdown = true;
936
2236
  }
937
2237
  this.cdr.markForCheck();
938
2238
  }
@@ -1025,10 +2325,101 @@ export class MjFormFieldComponent extends BaseAngularComponent {
1025
2325
  // ============================================
1026
2326
  // GENERAL PROPERTIES
1027
2327
  // ============================================
1028
- /** Whether the field's varchar(max) - long text that gets markdown rendering */
2328
+ /** Whether the field's varchar(max) - long text that gets the wide read-only style */
1029
2329
  get IsLongText() {
1030
2330
  return this.FieldInfo?.Length === -1;
1031
2331
  }
2332
+ /**
2333
+ * Whether this field is large enough to be a candidate for rich-text (markdown/html)
2334
+ * auto-detection. Generic & multi-platform: keys off the TS type and character length
2335
+ * rather than a specific SQL type, so nvarchar(max)/ntext (MaxLength === 0 means
2336
+ * unlimited) and longer fixed fields (nvarchar(400)/varchar(500)/...) all qualify,
2337
+ * while short strings, UUIDs, numbers, dates, etc. do not.
2338
+ */
2339
+ get IsRichTextEligible() {
2340
+ const fi = this.FieldInfo;
2341
+ if (!fi || fi.TSType !== EntityFieldTSType.String)
2342
+ return false;
2343
+ const maxLen = fi.MaxLength;
2344
+ return maxLen === 0 || maxLen >= 255;
2345
+ }
2346
+ /**
2347
+ * Resolved rendering mode for this field. Honors an explicit `ExtendedType` first
2348
+ * ('Markdown' | 'HTML' | 'Code'); when `ExtendedType` is null, falls back to lightweight
2349
+ * client-side content detection — but only for {@link IsRichTextEligible} long-text fields.
2350
+ */
2351
+ get RichTextMode() {
2352
+ const fi = this.FieldInfo;
2353
+ if (!fi)
2354
+ return 'plain';
2355
+ switch (fi.ExtendedType) {
2356
+ case 'Markdown': return 'markdown';
2357
+ case 'HTML': return 'html';
2358
+ case 'Code': return 'code';
2359
+ }
2360
+ // Any other explicit ExtendedType (Email, URL, Geo*, Tel, ...) is not rich text here.
2361
+ if (fi.ExtendedType != null)
2362
+ return 'plain';
2363
+ // ExtendedType is null → auto-detect, but only on eligible long-text fields.
2364
+ if (!this.IsRichTextEligible)
2365
+ return 'plain';
2366
+ return this.detectFormat();
2367
+ }
2368
+ /** Backing snapshot for {@link EditRichTextMode}; null until first computed for the session. */
2369
+ _editRichTextMode = null;
2370
+ /**
2371
+ * Stable rendering mode for EDIT mode. Unlike {@link RichTextMode} (which re-detects on the
2372
+ * live value), this is snapshotted when edit mode is entered so that typing markdown/html into
2373
+ * a plain textarea doesn't swap the control out from under the user mid-keystroke. Explicit
2374
+ * ExtendedType always wins regardless; only the auto-detect branch is frozen for the session.
2375
+ */
2376
+ get EditRichTextMode() {
2377
+ if (this._editRichTextMode === null) {
2378
+ this._editRichTextMode = this.RichTextMode;
2379
+ }
2380
+ return this._editRichTextMode;
2381
+ }
2382
+ /** Cached detection result, keyed by the exact string value it was computed from. */
2383
+ _detectCacheValue = null;
2384
+ _detectCacheResult = 'plain';
2385
+ /** Memoized content detection so the getter stays cheap under OnPush change detection. */
2386
+ detectFormat() {
2387
+ const raw = this.Value;
2388
+ const text = raw == null ? '' : String(raw);
2389
+ if (text !== this._detectCacheValue) {
2390
+ this._detectCacheValue = text;
2391
+ this._detectCacheResult = detectRichTextFormat(text);
2392
+ }
2393
+ return this._detectCacheResult;
2394
+ }
2395
+ /**
2396
+ * Editor language for the code editor. In edit mode it tracks the frozen
2397
+ * {@link EditRichTextMode}; in read mode it tracks the live {@link RichTextMode}.
2398
+ */
2399
+ get CodeEditorLanguage() {
2400
+ const mode = this.EditMode ? this.EditRichTextMode : this.RichTextMode;
2401
+ switch (mode) {
2402
+ case 'markdown': return 'markdown';
2403
+ case 'html': return 'html';
2404
+ case 'code': return this.codeTypeToLanguage(this.FieldInfo?.CodeType);
2405
+ default: return '';
2406
+ }
2407
+ }
2408
+ /** Map the field's CodeType metadata value to a CodeMirror language id. */
2409
+ codeTypeToLanguage(codeType) {
2410
+ switch (codeType) {
2411
+ case 'CSS': return 'css';
2412
+ case 'HTML': return 'html';
2413
+ case 'JavaScript': return 'javascript';
2414
+ case 'SQL': return 'sql';
2415
+ case 'TypeScript': return 'typescript';
2416
+ default: return ''; // 'Other' / null → plain code editing
2417
+ }
2418
+ }
2419
+ /** Handle value changes coming from the embedded code editor (emits a plain string). */
2420
+ OnCodeEditorChange(value) {
2421
+ this.Value = value;
2422
+ }
1032
2423
  /** Format a value for display */
1033
2424
  FormatValue() {
1034
2425
  const val = this.Value;
@@ -1045,20 +2436,45 @@ export class MjFormFieldComponent extends BaseAngularComponent {
1045
2436
  if (changes['Record']) {
1046
2437
  this._fkInputText = null;
1047
2438
  this.FKIsMatched = false;
2439
+ this._fkQuery = '';
1048
2440
  this.FKSuggestions = [];
2441
+ this.FKSelectedSuggestion = null;
1049
2442
  this.ShowFKDropdown = false;
2443
+ this.FKActiveIndex = -1;
2444
+ this.FKLoading = false;
2445
+ this.FKNoMatches = false;
2446
+ this.FKColumnHeaders = [];
2447
+ this.FKColumnFields = [];
2448
+ this.FKSortField = null;
2449
+ this.FKSortDir = 'asc';
2450
+ this._fkSuggestionsNatural = [];
2451
+ this.FKSearchableFields = [];
2452
+ this.FKShowScopeMenu = false;
2453
+ this.FKFocused = false;
2454
+ this._fkColWidths = {};
2455
+ this._fkPrefKey = null; // force prefs reload for the new field
2456
+ this._portaledDropdownEl = null;
2457
+ this._fkColumnPlan = null;
1050
2458
  this._resolvedFKName = undefined;
1051
2459
  this._resolvedFKValue = undefined;
1052
2460
  this._fkNameLoading = false;
1053
2461
  // Reset validation state for new record
1054
2462
  this._touched = false;
1055
2463
  this._fieldErrors = [];
2464
+ // Invalidate cached rich-text detection (recomputed lazily for the new value)
2465
+ this._detectCacheValue = null;
2466
+ this._detectCacheResult = 'plain';
2467
+ this._editRichTextMode = null;
1056
2468
  }
1057
2469
  // Reset validation state when exiting edit mode
1058
2470
  if (changes['EditMode'] && !this.EditMode) {
1059
2471
  this._touched = false;
1060
2472
  this._fieldErrors = [];
1061
2473
  }
2474
+ // Re-snapshot the edit-mode rendering decision whenever edit mode toggles
2475
+ if (changes['EditMode']) {
2476
+ this._editRichTextMode = null;
2477
+ }
1062
2478
  this.cdr.markForCheck();
1063
2479
  }
1064
2480
  }
@@ -1066,7 +2482,15 @@ export class MjFormFieldComponent extends BaseAngularComponent {
1066
2482
  if (this._fkSearchTimeout) {
1067
2483
  clearTimeout(this._fkSearchTimeout);
1068
2484
  }
2485
+ this.teardownFKResizeListeners();
1069
2486
  this.stopScrollListener();
2487
+ // If we relocated the dropdown to <body> and Angular tears us down while it's
2488
+ // still open, remove the orphaned node ourselves (Angular removes by reference,
2489
+ // but guard against a race where the view is destroyed before the @if updates).
2490
+ if (this._portaledDropdownEl && this._portaledDropdownEl.parentElement === document.body) {
2491
+ this.renderer.removeChild(document.body, this._portaledDropdownEl);
2492
+ }
2493
+ this._portaledDropdownEl = null;
1070
2494
  }
1071
2495
  // ---- Navigation Handlers ----
1072
2496
  /**
@@ -1164,15 +2588,15 @@ export class MjFormFieldComponent extends BaseAngularComponent {
1164
2588
  return date.toISOString().split('T')[0];
1165
2589
  }
1166
2590
  static ɵfac = /*@__PURE__*/ (() => { let ɵMjFormFieldComponent_BaseFactory; return function MjFormFieldComponent_Factory(__ngFactoryType__) { return (ɵMjFormFieldComponent_BaseFactory || (ɵMjFormFieldComponent_BaseFactory = i0.ɵɵgetInheritedFactory(MjFormFieldComponent)))(__ngFactoryType__ || MjFormFieldComponent); }; })();
1167
- static ɵcmp = /*@__PURE__*/ i0.ɵɵdefineComponent({ type: MjFormFieldComponent, selectors: [["mj-form-field"]], inputs: { Record: "Record", EditMode: "EditMode", FieldName: "FieldName", Type: "Type", LinkType: "LinkType", ShowLabel: "ShowLabel", FormContext: "FormContext", _deprecatedRecord: [0, "record", "_deprecatedRecord"], _deprecatedFormContext: [0, "formContext", "_deprecatedFormContext"], HideWhenEmptyInReadOnlyMode: "HideWhenEmptyInReadOnlyMode", DisplayNameOverride: "DisplayNameOverride", PossibleValuesOverride: "PossibleValuesOverride" }, outputs: { ValueChange: "ValueChange", Navigate: "Navigate" }, standalone: false, features: [i0.ɵɵInheritDefinitionFeature, i0.ɵɵNgOnChangesFeature], decls: 1, vars: 1, consts: [[1, "mj-forms-field", 3, "mj-forms-field--readonly", "mj-forms-field--dirty"], [1, "mj-forms-field", "mj-forms-field--editing", 3, "mj-forms-field--dirty", "mj-forms-field--required-empty", "mj-forms-field--has-error", "mj-forms-field--has-warning"], [1, "mj-forms-field"], [1, "mj-forms-field-label", 3, "innerHTML"], [1, "mj-forms-field-control"], [1, "mj-forms-field-value"], ["title", "View related record", 1, "mj-forms-field-link", "mj-forms-field-link--fk", 3, "click"], ["title", "Send email", 1, "mj-forms-field-link", 3, "click"], [1, "fa-solid", "fa-envelope", "mj-forms-field-link-icon"], ["title", "Open link", 1, "mj-forms-field-link", 3, "click"], [1, "fa-solid", "fa-arrow-up-right-from-square", "mj-forms-field-link-icon"], ["title", "View related record", 1, "mj-forms-field-link", 3, "click"], [1, "mj-forms-field-value", "mj-forms-field-value--long"], [1, "mj-forms-field-checkbox"], ["type", "checkbox", "disabled", "", 3, "checked"], [1, "mj-forms-field", "mj-forms-field--editing"], [1, "mj-fk-search", 3, "mj-fk-search--matched"], [1, "mj-forms-field-validation", "mj-forms-field-validation--error"], [1, "mj-forms-field-validation", "mj-forms-field-validation--warning"], [1, "mj-fk-search"], ["type", "text", "placeholder", "Search...", 1, "mj-forms-field-input", 3, "input", "focus", "blur", "value"], ["title", "Clear", 1, "mj-fk-clear"], [1, "fa-solid", "fa-magnifying-glass", "mj-fk-search-icon"], [1, "mj-fk-dropdown", 3, "ngStyle", "mj-fk-dropdown--above"], ["title", "Clear", 1, "mj-fk-clear", 3, "mousedown"], [1, "fa-solid", "fa-xmark"], [1, "mj-fk-dropdown", 3, "ngStyle"], [1, "mj-fk-option"], [1, "mj-fk-option", 3, "mousedown"], ["type", "text", 1, "mj-forms-field-input", 3, "value"], [1, "mj-forms-field-input", "mj-forms-field-input--textarea", 3, "value"], ["type", "number", 1, "mj-forms-field-input", "mj-forms-field-input--number", 3, "value"], ["type", "date", 1, "mj-forms-field-input", "mj-forms-field-input--date", 3, "value"], ["type", "text", 1, "mj-forms-field-input", 3, "input", "value"], [1, "mj-forms-field-input", "mj-forms-field-input--textarea", 3, "input", "value"], ["type", "number", 1, "mj-forms-field-input", "mj-forms-field-input--number", 3, "change", "value"], ["type", "date", 1, "mj-forms-field-input", "mj-forms-field-input--date", 3, "change", "value"], ["type", "checkbox", 3, "change", "checked"], ["tabindex", "0", 1, "mj-custom-select-trigger", 3, "click", "blur"], [1, "mj-custom-select-value"], [1, "fa-solid", "fa-chevron-down", "mj-custom-select-chevron"], [1, "mj-fk-option", 3, "mj-fk-option--selected"], ["type", "text", "placeholder", "Type to search...", 1, "mj-forms-field-input", 3, "input", "focus", "blur", "value"], ["type", "text", 1, "mj-forms-field-input", 3, "change", "value"], [1, "mj-forms-field-validation-item"], [1, "fa-solid", "fa-circle-exclamation"], [1, "fa-solid", "fa-triangle-exclamation"]], template: function MjFormFieldComponent_Template(rf, ctx) { if (rf & 1) {
2591
+ static ɵcmp = /*@__PURE__*/ i0.ɵɵdefineComponent({ type: MjFormFieldComponent, selectors: [["mj-form-field"]], inputs: { Record: "Record", EditMode: "EditMode", FieldName: "FieldName", Type: "Type", LinkType: "LinkType", ShowLabel: "ShowLabel", FormContext: "FormContext", _deprecatedRecord: [0, "record", "_deprecatedRecord"], _deprecatedFormContext: [0, "formContext", "_deprecatedFormContext"], HideWhenEmptyInReadOnlyMode: "HideWhenEmptyInReadOnlyMode", DisplayNameOverride: "DisplayNameOverride", PossibleValuesOverride: "PossibleValuesOverride", FKDropdownMaxWidth: "FKDropdownMaxWidth", FKHighlightMatches: "FKHighlightMatches", AllowFKCreate: "AllowFKCreate", FKCreatePresentation: "FKCreatePresentation" }, outputs: { ValueChange: "ValueChange", Navigate: "Navigate" }, standalone: false, features: [i0.ɵɵInheritDefinitionFeature, i0.ɵɵNgOnChangesFeature], decls: 1, vars: 1, consts: [["scopeRow", ""], [1, "mj-forms-field", 3, "mj-forms-field--readonly", "mj-forms-field--dirty"], [1, "mj-forms-field", "mj-forms-field--editing", 3, "mj-forms-field--dirty", "mj-forms-field--required-empty", "mj-forms-field--has-error", "mj-forms-field--has-warning"], [1, "mj-forms-field"], [1, "mj-forms-field-label", 3, "innerHTML"], [1, "mj-forms-field-control"], [1, "mj-forms-field-value"], ["title", "View related record", 1, "mj-forms-field-link", "mj-forms-field-link--fk"], ["title", "View related record", 1, "mj-forms-field-link", "mj-forms-field-link--fk", 3, "click"], ["title", "Send email", 1, "mj-forms-field-link", 3, "click"], [1, "fa-solid", "fa-envelope", "mj-forms-field-link-icon"], ["title", "Open link", 1, "mj-forms-field-link", 3, "click"], [1, "fa-solid", "fa-arrow-up-right-from-square", "mj-forms-field-link-icon"], ["title", "View related record", 1, "mj-forms-field-link"], ["title", "View related record", 1, "mj-forms-field-link", 3, "click"], [1, "mj-forms-field-value", "mj-forms-field-value--rich"], [1, "mj-forms-field-value", "mj-forms-field-value--rich", 3, "innerHTML"], [1, "mj-forms-field-value", "mj-forms-field-value--code"], [1, "mj-forms-field-value", "mj-forms-field-value--long"], [1, "mj-forms-field-checkbox"], ["type", "checkbox", "disabled", "", 3, "checked"], [3, "data"], [3, "value", "language", "readonly"], [1, "mj-forms-field", "mj-forms-field--editing"], [1, "mj-fk-search", 3, "mj-fk-search--matched", "mj-fk-search--scoped"], [1, "mj-forms-field-input--code", 3, "value", "language"], [1, "mj-forms-field-validation", "mj-forms-field-validation--error"], [1, "mj-forms-field-validation", "mj-forms-field-validation--warning"], [1, "mj-fk-search"], ["title", "Linked record", 1, "fa-solid", "fa-link", "mj-fk-link-icon"], ["type", "text", "placeholder", "Search...", 1, "mj-forms-field-input", 3, "input", "focus", "blur", "keydown", "value"], [1, "mj-fk-scope-pill", 3, "mj-fk-scope-pill--open", "title"], ["title", "Clear", 1, "mj-fk-clear"], [1, "fa-solid", "fa-magnifying-glass", "mj-fk-search-icon"], [1, "mj-fk-dropdown", "mj-fk-dropdown--multi", 3, "ngStyle", "mj-fk-dropdown--above", "mj-fk-dropdown--scope-open"], [1, "mj-fk-scope-pill", 3, "mousedown", "title"], [1, "fa-solid", "fa-magnifying-glass", "mj-fk-scope-pill-icon"], [1, "mj-fk-scope-pill-label"], [1, "fa-solid", "mj-fk-scope-pill-caret"], ["title", "Clear", 1, "mj-fk-clear", 3, "mousedown"], [1, "fa-solid", "fa-xmark"], [1, "mj-fk-dropdown", "mj-fk-dropdown--multi", 3, "ngStyle"], [1, "mj-fk-scope-menu", 3, "mj-fk-scope-menu--bottom"], [1, "mj-fk-current"], [1, "mj-fk-status"], [1, "mj-fk-status", "mj-fk-status--empty"], [1, "mj-fk-options"], ["type", "button", 1, "mj-fk-create-footer", 3, "title"], [1, "mj-fk-scope-menu"], [1, "mj-fk-scope-grp"], [4, "ngTemplateOutlet", "ngTemplateOutletContext"], [1, "mj-fk-scope-divider"], [1, "mj-fk-scope-mi", 3, "mousedown"], [1, "mj-fk-col-reorder"], [1, "mj-fk-scope-mi-label"], [1, "mj-fk-col-eye-slot"], ["type", "button", 1, "mj-fk-col-toggle", 3, "mj-fk-col-toggle--on", "title"], ["type", "button", "title", "Move column up", 1, "mj-fk-col-move", "mj-fk-col-move--up", 3, "mousedown", "disabled"], [1, "fa-solid", "fa-chevron-up"], ["type", "button", "title", "Move column down", 1, "mj-fk-col-move", "mj-fk-col-move--down", 3, "mousedown", "disabled"], [1, "fa-solid", "fa-chevron-down"], ["type", "button", 1, "mj-fk-col-toggle", 3, "mousedown", "title"], [1, "fa-solid"], [1, "mj-fk-current-head"], [1, "fa-solid", "fa-circle-check"], ["title", "Keep this selection", 1, "mj-fk-current-row", 3, "mousedown"], [1, "mj-fk-current-icon", 3, "class"], [1, "mj-fk-current-name", 3, "innerHTML"], [1, "mj-fk-current-detail"], ["type", "button", "title", "Clear selection", 1, "mj-fk-current-clear", 3, "mousedown"], [1, "mj-fk-current-icon"], [1, "fa-solid", "fa-circle-notch", "fa-spin"], [1, "fa-solid", "fa-magnifying-glass"], [1, "mj-fk-grid"], [1, "mj-fk-grid-row", "mj-fk-grid-row--header"], [1, "mj-fk-hcell", "mj-fk-hcell--icon"], [1, "mj-fk-hcell", 3, "title"], [1, "mj-fk-grid-row", 3, "mj-fk-grid-row--active", "mj-fk-grid-row--selected"], [1, "mj-fk-hcell", 3, "mousedown", "title"], [1, "mj-fk-hcell-label"], ["title", "Drag to resize", 1, "mj-fk-resizer", 3, "mousedown"], [1, "mj-fk-grid-row", 3, "mousedown", "mouseenter"], [1, "mj-fk-cell", "mj-fk-cell--icon"], [3, "class"], [1, "mj-fk-cell", "mj-fk-cell--name", 3, "mj-fk-cell--fill"], [1, "mj-fk-cell", 3, "mj-fk-cell--fill", "title"], [1, "mj-fk-cell", "mj-fk-cell--name"], ["title", "Currently selected", 1, "fa-solid", "fa-check", "mj-fk-selected-check"], [3, "innerHTML"], [1, "mj-fk-cell", 3, "title"], ["type", "button", 1, "mj-fk-create-footer", 3, "mousedown", "title"], [1, "fa-solid", "fa-plus", "mj-fk-create-icon"], [1, "mj-fk-create-label"], [1, "mj-forms-field-input--code", 3, "change", "value", "language"], ["type", "text", 1, "mj-forms-field-input", 3, "value"], [1, "mj-forms-field-input", "mj-forms-field-input--textarea", 3, "value"], ["type", "number", 1, "mj-forms-field-input", "mj-forms-field-input--number", 3, "value"], ["type", "date", 1, "mj-forms-field-input", "mj-forms-field-input--date", 3, "value"], ["type", "text", 1, "mj-forms-field-input", 3, "input", "value"], [1, "mj-forms-field-input", "mj-forms-field-input--textarea", 3, "input", "value"], ["type", "number", 1, "mj-forms-field-input", "mj-forms-field-input--number", 3, "change", "value"], ["type", "date", 1, "mj-forms-field-input", "mj-forms-field-input--date", 3, "change", "value"], ["type", "checkbox", 3, "change", "checked"], ["tabindex", "0", 1, "mj-custom-select-trigger", 3, "click", "blur"], [1, "mj-custom-select-value"], [1, "fa-solid", "fa-chevron-down", "mj-custom-select-chevron"], [1, "mj-fk-dropdown", 3, "ngStyle", "mj-fk-dropdown--above"], [1, "mj-fk-dropdown", 3, "ngStyle"], [1, "mj-fk-option", 3, "mj-fk-option--selected"], [1, "mj-fk-option", 3, "mousedown"], ["type", "text", "placeholder", "Type to search...", 1, "mj-forms-field-input", 3, "input", "focus", "blur", "value"], [1, "mj-fk-option"], ["type", "text", 1, "mj-forms-field-input", 3, "change", "value"], [1, "mj-forms-field-validation-item"], [1, "fa-solid", "fa-circle-exclamation"], [1, "fa-solid", "fa-triangle-exclamation"]], template: function MjFormFieldComponent_Template(rf, ctx) { if (rf & 1) {
1168
2592
  i0.ɵɵconditionalCreate(0, MjFormFieldComponent_Conditional_0_Template, 2, 2);
1169
2593
  } if (rf & 2) {
1170
2594
  i0.ɵɵconditional(ctx.Record && (ctx.Record.IsSaved || !ctx.IsFieldReadOnly) ? 0 : -1);
1171
- } }, dependencies: [i1.NgStyle], styles: ["\n\n\n\n[_nghost-%COMP%] {\n --mj-forms-field-label-width: 200px;\n --mj-forms-field-gap: 12px;\n\n display: contents;\n}\n\n.mj-forms-field[_ngcontent-%COMP%] {\n display: grid;\n grid-template-columns: var(--mj-forms-field-label-width) 1fr;\n gap: var(--mj-forms-field-gap);\n align-items: baseline;\n padding: 8px 0;\n transition: all var(--mj-transition-base) ease;\n}\n\n\n\n.mj-forms-field--editing[_ngcontent-%COMP%]:hover {\n background: color-mix(in srgb, var(--mj-brand-primary) 8%, transparent);\n border-radius: 6px;\n margin: 0 -8px;\n padding: 8px 8px;\n}\n\n\n\n\n\n.mj-forms-field-label[_ngcontent-%COMP%] {\n font-size: 13px;\n font-weight: 600;\n color: var(--mj-text-secondary);\n padding-top: 2px;\n word-break: break-word;\n}\n\n\n\n\n\n.mj-forms-field-control[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: 8px;\n min-width: 0;\n}\n\n.mj-forms-field-control[_ngcontent-%COMP%] > *[_ngcontent-%COMP%] {\n flex: 1;\n min-width: 0;\n}\n\n\n\n\n\n.mj-forms-field--dirty[_ngcontent-%COMP%] .mj-forms-field-label[_ngcontent-%COMP%]::after {\n content: '';\n display: inline-block;\n width: 6px;\n height: 6px;\n border-radius: 50%;\n background: var(--mj-status-warning);\n margin-left: 6px;\n vertical-align: middle;\n}\n\n\n\n\n\n.mj-forms-field--required-empty[_ngcontent-%COMP%] .mj-forms-field-input[_ngcontent-%COMP%] {\n border-bottom-color: var(--mj-status-error);\n}\n\n.mj-forms-field--required-empty[_ngcontent-%COMP%] .mj-forms-field-input[_ngcontent-%COMP%]:focus {\n background: color-mix(in srgb, var(--mj-status-error) 5%, var(--mj-bg-surface));\n border-bottom-color: var(--mj-status-error);\n}\n\n.mj-forms-field--required-empty[_ngcontent-%COMP%] .mj-custom-select-trigger[_ngcontent-%COMP%] {\n border-bottom-color: var(--mj-status-error);\n}\n\n.mj-forms-field--required-empty[_ngcontent-%COMP%] .mj-fk-search[_ngcontent-%COMP%] .mj-forms-field-input[_ngcontent-%COMP%] {\n border-bottom-color: var(--mj-status-error);\n}\n\n\n\n\n\n.mj-forms-field-value[_ngcontent-%COMP%] {\n font-size: 14px;\n color: var(--mj-text-primary);\n min-height: 24px;\n display: flex;\n align-items: center;\n overflow-wrap: break-word;\n word-break: break-word;\n}\n\n.mj-forms-field-value--long[_ngcontent-%COMP%] {\n white-space: pre-line;\n max-height: 300px;\n overflow: auto;\n}\n\n\n\n.mj-forms-field--readonly[_ngcontent-%COMP%] {\n opacity: 0.7;\n}\n\n.mj-forms-field--readonly[_ngcontent-%COMP%] .mj-forms-field-value[_ngcontent-%COMP%] {\n color: var(--mj-text-secondary);\n}\n\n\n\n\n\n.mj-forms-field-link[_ngcontent-%COMP%] {\n display: inline-flex;\n align-items: center;\n gap: 6px;\n color: var(--mj-brand-primary);\n cursor: pointer;\n font-weight: 400;\n font-size: 14px;\n transition: color var(--mj-transition-base);\n text-decoration: none;\n}\n\n.mj-forms-field-link[_ngcontent-%COMP%]:hover {\n color: var(--mj-brand-primary-hover);\n}\n\n.mj-forms-field-link-icon[_ngcontent-%COMP%] {\n font-size: 11px;\n opacity: 0;\n transition: opacity var(--mj-transition-base);\n}\n\n.mj-forms-field-link[_ngcontent-%COMP%]:hover .mj-forms-field-link-icon[_ngcontent-%COMP%] {\n opacity: 1;\n}\n\n\n\n.mj-forms-field-link--fk[_ngcontent-%COMP%] {\n font-size: 14px;\n font-weight: 400;\n}\n\n\n\n\n\n.mj-forms-field-input[_ngcontent-%COMP%] {\n font-size: 14px;\n font-family: inherit;\n color: var(--mj-text-primary);\n background: transparent;\n border: none;\n border-bottom: 1.5px solid var(--mj-border-default);\n padding: 4px 0;\n width: 100%;\n outline: none;\n transition: border-color var(--mj-transition-base) ease,\n background var(--mj-transition-base) ease;\n}\n\n.mj-forms-field-input[_ngcontent-%COMP%]:focus {\n border-bottom-color: var(--mj-brand-primary);\n background: color-mix(in srgb, var(--mj-brand-primary) 8%, transparent);\n border-radius: 4px 4px 0 0;\n padding: 4px 6px;\n}\n\n.mj-forms-field-input[_ngcontent-%COMP%]::placeholder {\n color: var(--mj-text-muted);\n font-style: italic;\n}\n\n\n\n.mj-forms-field-input--textarea[_ngcontent-%COMP%] {\n resize: vertical;\n min-height: 60px;\n border: 1.5px solid var(--mj-border-default);\n border-radius: 6px;\n padding: 8px 10px;\n background: var(--mj-bg-surface);\n font-family: inherit;\n}\n\n.mj-forms-field-input--textarea[_ngcontent-%COMP%]:focus {\n border-color: var(--mj-brand-primary);\n box-shadow: 0 0 0 3px color-mix(in srgb, var(--mj-brand-primary) 10%, transparent);\n background: var(--mj-bg-surface);\n padding: 8px 10px;\n border-radius: 6px;\n}\n\n\n\n.mj-forms-field-input--number[_ngcontent-%COMP%] {\n max-width: 200px;\n}\n\n\n\n.mj-forms-field-input--date[_ngcontent-%COMP%] {\n max-width: 220px;\n}\n\n\n\n\n\n.mj-forms-field-checkbox[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: 8px;\n}\n\n.mj-forms-field-checkbox[_ngcontent-%COMP%] input[type=\"checkbox\"][_ngcontent-%COMP%] {\n appearance: none;\n width: 18px;\n height: 18px;\n border: 2px solid var(--mj-border-default);\n border-radius: 4px;\n cursor: pointer;\n position: relative;\n transition: all var(--mj-transition-base) ease;\n flex-shrink: 0;\n}\n\n.mj-forms-field-checkbox[_ngcontent-%COMP%] input[type=\"checkbox\"][_ngcontent-%COMP%]:checked {\n background: var(--mj-brand-primary);\n border-color: var(--mj-brand-primary);\n}\n\n.mj-forms-field-checkbox[_ngcontent-%COMP%] input[type=\"checkbox\"][_ngcontent-%COMP%]:checked::after {\n content: '';\n position: absolute;\n left: 5px;\n top: 1px;\n width: 5px;\n height: 9px;\n border: solid var(--mj-text-inverse);\n border-width: 0 2px 2px 0;\n transform: rotate(45deg);\n}\n\n.mj-forms-field-checkbox[_ngcontent-%COMP%] input[type=\"checkbox\"][_ngcontent-%COMP%]:disabled {\n opacity: 0.5;\n cursor: default;\n}\n\n\n\n\n\n.mj-custom-select-trigger[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n justify-content: space-between;\n font-size: 14px;\n font-family: inherit;\n color: var(--mj-text-primary);\n background: transparent;\n border: none;\n border-bottom: 1.5px solid var(--mj-border-default);\n padding: 4px 0;\n width: 100%;\n cursor: pointer;\n outline: none;\n transition: border-color var(--mj-transition-base) ease,\n background var(--mj-transition-base) ease;\n}\n\n.mj-custom-select-trigger[_ngcontent-%COMP%]:focus {\n border-bottom-color: var(--mj-brand-primary);\n background: color-mix(in srgb, var(--mj-brand-primary) 8%, transparent);\n border-radius: 4px 4px 0 0;\n padding: 4px 6px;\n}\n\n.mj-custom-select-value[_ngcontent-%COMP%] {\n flex: 1;\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n\n.mj-custom-select-value--placeholder[_ngcontent-%COMP%] {\n color: var(--mj-text-muted);\n font-style: italic;\n}\n\n.mj-custom-select-chevron[_ngcontent-%COMP%] {\n font-size: 11px;\n color: var(--mj-text-muted);\n transition: transform var(--mj-transition-base) ease;\n flex-shrink: 0;\n margin-left: 8px;\n}\n\n.mj-custom-select-chevron--open[_ngcontent-%COMP%] {\n transform: rotate(180deg);\n}\n\n\n\n\n\n.mj-fk-search[_ngcontent-%COMP%] {\n position: relative;\n display: flex;\n align-items: center;\n width: 100%;\n}\n\n.mj-fk-search[_ngcontent-%COMP%] .mj-forms-field-input[_ngcontent-%COMP%] {\n padding-right: 28px;\n}\n\n.mj-fk-search-icon[_ngcontent-%COMP%] {\n position: absolute;\n right: 4px;\n color: var(--mj-text-muted);\n font-size: 12px;\n pointer-events: none;\n}\n\n.mj-fk-clear[_ngcontent-%COMP%] {\n position: absolute;\n right: 2px;\n background: none;\n border: none;\n color: var(--mj-text-muted);\n cursor: pointer;\n font-size: 11px;\n padding: 4px 6px;\n line-height: 1;\n border-radius: 3px;\n transition: all var(--mj-transition-base);\n}\n\n.mj-fk-clear[_ngcontent-%COMP%]:hover {\n color: var(--mj-status-error);\n background: color-mix(in srgb, var(--mj-status-error) 8%, transparent);\n}\n\n\n\n.mj-fk-search--matched[_ngcontent-%COMP%] .mj-forms-field-input[_ngcontent-%COMP%] {\n border-bottom: 2px solid var(--mj-brand-primary);\n}\n\n\n\n\n\n.mj-fk-dropdown[_ngcontent-%COMP%] {\n background: var(--mj-bg-surface-card);\n border: 1px solid var(--mj-border-default);\n border-radius: var(--mj-radius-md);\n box-shadow: var(--mj-shadow-lg);\n max-height: 240px;\n overflow-y: auto;\n padding: 4px;\n animation: _ngcontent-%COMP%_mj-dropdown-in 150ms ease;\n}\n\n.mj-fk-dropdown--above[_ngcontent-%COMP%] {\n animation: _ngcontent-%COMP%_mj-dropdown-in-above 150ms ease;\n}\n\n.mj-fk-option[_ngcontent-%COMP%] {\n padding: 10px 14px;\n font-size: 14px;\n color: var(--mj-text-primary);\n cursor: pointer;\n transition: background var(--mj-transition-base);\n border-radius: 6px;\n}\n\n.mj-fk-option[_ngcontent-%COMP%]:hover {\n background: color-mix(in srgb, var(--mj-brand-primary) 8%, transparent);\n}\n\n.mj-fk-option--selected[_ngcontent-%COMP%] {\n background: color-mix(in srgb, var(--mj-brand-primary) 8%, transparent);\n font-weight: 600;\n color: var(--mj-brand-primary);\n}\n\n.mj-fk-option--selected[_ngcontent-%COMP%]:hover {\n background: color-mix(in srgb, var(--mj-brand-primary) 15%, transparent);\n}\n\n@keyframes _ngcontent-%COMP%_mj-dropdown-in {\n from { opacity: 0; transform: translateY(-4px); }\n to { opacity: 1; transform: translateY(0); }\n}\n\n@keyframes _ngcontent-%COMP%_mj-dropdown-in-above {\n from { opacity: 0; transform: translateY(4px); }\n to { opacity: 1; transform: translateY(0); }\n}\n\n\n\n\n\n.mj-forms-field-label[_ngcontent-%COMP%] [_ngcontent-%COMP%]:global(.mj-forms-search-highlight) {\n background-color: var(--mj-color-warning-200, #fef08a);\n color: var(--mj-color-warning-800, #854d0e);\n padding: 0;\n border-radius: 2px;\n font-weight: 700;\n box-shadow: 0 0 0 2px var(--mj-color-warning-200, #fef08a);\n}\n\n\n\n\n\n.mj-forms-field--has-error[_ngcontent-%COMP%] .mj-forms-field-input[_ngcontent-%COMP%] {\n border-bottom-color: var(--mj-status-error);\n border-bottom-width: 2px;\n}\n\n.mj-forms-field--has-error[_ngcontent-%COMP%] .mj-forms-field-input[_ngcontent-%COMP%]:focus {\n background: color-mix(in srgb, var(--mj-status-error) 5%, var(--mj-bg-surface));\n border-bottom-color: var(--mj-status-error);\n}\n\n.mj-forms-field--has-error[_ngcontent-%COMP%] .mj-forms-field-input--textarea[_ngcontent-%COMP%] {\n border-color: var(--mj-status-error);\n}\n\n.mj-forms-field--has-error[_ngcontent-%COMP%] .mj-forms-field-input--textarea[_ngcontent-%COMP%]:focus {\n border-color: var(--mj-status-error);\n box-shadow: 0 0 0 3px color-mix(in srgb, var(--mj-status-error) 8%, transparent);\n}\n\n.mj-forms-field--has-error[_ngcontent-%COMP%] .mj-custom-select-trigger[_ngcontent-%COMP%] {\n border-bottom-color: var(--mj-status-error);\n border-bottom-width: 2px;\n}\n\n.mj-forms-field--has-error[_ngcontent-%COMP%] .mj-fk-search[_ngcontent-%COMP%] .mj-forms-field-input[_ngcontent-%COMP%] {\n border-bottom-color: var(--mj-status-error);\n border-bottom-width: 2px;\n}\n\n\n\n\n\n.mj-forms-field--has-warning[_ngcontent-%COMP%] .mj-forms-field-input[_ngcontent-%COMP%] {\n border-bottom-color: var(--mj-status-warning);\n border-bottom-width: 2px;\n}\n\n.mj-forms-field--has-warning[_ngcontent-%COMP%] .mj-forms-field-input[_ngcontent-%COMP%]:focus {\n background: color-mix(in srgb, var(--mj-status-warning) 5%, var(--mj-bg-surface));\n border-bottom-color: var(--mj-status-warning);\n}\n\n.mj-forms-field--has-warning[_ngcontent-%COMP%] .mj-forms-field-input--textarea[_ngcontent-%COMP%] {\n border-color: var(--mj-status-warning);\n}\n\n.mj-forms-field--has-warning[_ngcontent-%COMP%] .mj-forms-field-input--textarea[_ngcontent-%COMP%]:focus {\n border-color: var(--mj-status-warning);\n box-shadow: 0 0 0 3px color-mix(in srgb, var(--mj-status-warning) 8%, transparent);\n}\n\n.mj-forms-field--has-warning[_ngcontent-%COMP%] .mj-custom-select-trigger[_ngcontent-%COMP%] {\n border-bottom-color: var(--mj-status-warning);\n border-bottom-width: 2px;\n}\n\n.mj-forms-field--has-warning[_ngcontent-%COMP%] .mj-fk-search[_ngcontent-%COMP%] .mj-forms-field-input[_ngcontent-%COMP%] {\n border-bottom-color: var(--mj-status-warning);\n border-bottom-width: 2px;\n}\n\n\n\n\n\n.mj-forms-field-validation[_ngcontent-%COMP%] {\n grid-column: 2;\n display: flex;\n flex-direction: column;\n gap: 2px;\n margin-top: -2px;\n overflow: hidden;\n animation: _ngcontent-%COMP%_mj-validation-slide-in 200ms ease-out;\n}\n\n.mj-forms-field-validation-item[_ngcontent-%COMP%] {\n display: flex;\n align-items: flex-start;\n gap: 6px;\n font-size: 12px;\n line-height: 1.4;\n padding: 3px 0 1px;\n}\n\n.mj-forms-field-validation-item[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n font-size: 11px;\n margin-top: 2px;\n flex-shrink: 0;\n}\n\n\n\n.mj-forms-field-validation--error[_ngcontent-%COMP%] .mj-forms-field-validation-item[_ngcontent-%COMP%] {\n color: var(--mj-status-error);\n}\n\n.mj-forms-field-validation--error[_ngcontent-%COMP%] .mj-forms-field-validation-item[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n color: var(--mj-status-error);\n}\n\n\n\n.mj-forms-field-validation--warning[_ngcontent-%COMP%] .mj-forms-field-validation-item[_ngcontent-%COMP%] {\n color: var(--mj-color-warning-700);\n}\n\n.mj-forms-field-validation--warning[_ngcontent-%COMP%] .mj-forms-field-validation-item[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n color: var(--mj-status-warning);\n}\n\n@keyframes _ngcontent-%COMP%_mj-validation-slide-in {\n from {\n opacity: 0;\n max-height: 0;\n transform: translateY(-4px);\n }\n to {\n opacity: 1;\n max-height: 100px;\n transform: translateY(0);\n }\n}\n\n\n\n\n\n@media (max-width: 640px) {\n .mj-forms-field[_ngcontent-%COMP%] {\n grid-template-columns: 1fr;\n gap: 4px;\n }\n\n .mj-forms-field-label[_ngcontent-%COMP%] {\n font-size: 12px;\n }\n\n .mj-forms-field-validation[_ngcontent-%COMP%] {\n grid-column: 1;\n }\n}"], changeDetection: 0 });
2595
+ } }, dependencies: [i1.NgTemplateOutlet, i1.NgStyle, i2.MarkdownComponent, i3.CodeEditorComponent, i4.MJSafeRichHtmlPipe], styles: ["\n\n\n\n[_nghost-%COMP%] {\n --mj-forms-field-label-width: 200px;\n --mj-forms-field-gap: 12px;\n\n display: contents;\n}\n\n.mj-forms-field[_ngcontent-%COMP%] {\n display: grid;\n grid-template-columns: var(--mj-forms-field-label-width) 1fr;\n gap: var(--mj-forms-field-gap);\n align-items: baseline;\n padding: 8px 0;\n transition: all var(--mj-transition-base) ease;\n}\n\n\n\n.mj-forms-field--editing[_ngcontent-%COMP%]:hover {\n background: color-mix(in srgb, var(--mj-brand-primary) 8%, transparent);\n border-radius: 6px;\n margin: 0 -8px;\n padding: 8px 8px;\n}\n\n\n\n\n\n.mj-forms-field-label[_ngcontent-%COMP%] {\n font-size: 13px;\n font-weight: 600;\n color: var(--mj-text-secondary);\n padding-top: 2px;\n word-break: break-word;\n}\n\n\n\n\n\n.mj-forms-field-control[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: 8px;\n min-width: 0;\n}\n\n.mj-forms-field-control[_ngcontent-%COMP%] > *[_ngcontent-%COMP%] {\n flex: 1;\n min-width: 0;\n}\n\n\n\n\n\n.mj-forms-field--dirty[_ngcontent-%COMP%] .mj-forms-field-label[_ngcontent-%COMP%]::after {\n content: '';\n display: inline-block;\n width: 6px;\n height: 6px;\n border-radius: 50%;\n background: var(--mj-status-warning);\n margin-left: 6px;\n vertical-align: middle;\n}\n\n\n\n\n\n.mj-forms-field--required-empty[_ngcontent-%COMP%] .mj-forms-field-input[_ngcontent-%COMP%] {\n border-bottom-color: var(--mj-status-error);\n}\n\n.mj-forms-field--required-empty[_ngcontent-%COMP%] .mj-forms-field-input[_ngcontent-%COMP%]:focus {\n background: color-mix(in srgb, var(--mj-status-error) 5%, var(--mj-bg-surface));\n border-bottom-color: var(--mj-status-error);\n}\n\n.mj-forms-field--required-empty[_ngcontent-%COMP%] .mj-custom-select-trigger[_ngcontent-%COMP%] {\n border-bottom-color: var(--mj-status-error);\n}\n\n.mj-forms-field--required-empty[_ngcontent-%COMP%] .mj-fk-search[_ngcontent-%COMP%] .mj-forms-field-input[_ngcontent-%COMP%] {\n border-bottom-color: var(--mj-status-error);\n}\n\n\n\n\n\n.mj-forms-field-value[_ngcontent-%COMP%] {\n font-size: 14px;\n color: var(--mj-text-primary);\n min-height: 24px;\n display: flex;\n align-items: center;\n overflow-wrap: break-word;\n word-break: break-word;\n}\n\n.mj-forms-field-value--long[_ngcontent-%COMP%] {\n white-space: pre-line;\n max-height: 300px;\n overflow: auto;\n}\n\n\n\n.mj-forms-field-value--rich[_ngcontent-%COMP%] {\n display: block;\n align-items: initial;\n max-height: 480px;\n overflow: auto;\n width: 100%;\n}\n\n\n\n.mj-forms-field-value--code[_ngcontent-%COMP%] {\n display: block;\n align-items: initial;\n width: 100%;\n}\n\n.mj-forms-field-value--code[_ngcontent-%COMP%] mj-code-editor[_ngcontent-%COMP%], \n.mj-forms-field-input--code[_ngcontent-%COMP%] {\n display: block;\n width: 100%;\n min-height: 160px;\n max-height: 480px;\n border: 1px solid var(--mj-border-default);\n border-radius: var(--mj-radius, 4px);\n overflow: auto;\n}\n\n\n\n.mj-forms-field--readonly[_ngcontent-%COMP%] {\n opacity: 0.7;\n}\n\n.mj-forms-field--readonly[_ngcontent-%COMP%] .mj-forms-field-value[_ngcontent-%COMP%] {\n color: var(--mj-text-secondary);\n}\n\n\n\n\n\n.mj-forms-field-link[_ngcontent-%COMP%] {\n display: inline-flex;\n align-items: center;\n gap: 6px;\n color: var(--mj-brand-primary);\n cursor: pointer;\n font-weight: 400;\n font-size: 14px;\n transition: color var(--mj-transition-base);\n text-decoration: none;\n}\n\n.mj-forms-field-link[_ngcontent-%COMP%]:hover {\n color: var(--mj-brand-primary-hover);\n}\n\n.mj-forms-field-link-icon[_ngcontent-%COMP%] {\n font-size: 11px;\n opacity: 0;\n transition: opacity var(--mj-transition-base);\n}\n\n.mj-forms-field-link[_ngcontent-%COMP%]:hover .mj-forms-field-link-icon[_ngcontent-%COMP%] {\n opacity: 1;\n}\n\n\n\n.mj-forms-field-link--fk[_ngcontent-%COMP%] {\n font-size: 14px;\n font-weight: 400;\n}\n\n\n\n\n\n.mj-forms-field-input[_ngcontent-%COMP%] {\n font-size: 14px;\n font-family: inherit;\n color: var(--mj-text-primary);\n background: transparent;\n border: none;\n border-bottom: 1.5px solid var(--mj-border-default);\n padding: 4px 0;\n width: 100%;\n outline: none;\n transition: border-color var(--mj-transition-base) ease,\n background var(--mj-transition-base) ease;\n}\n\n.mj-forms-field-input[_ngcontent-%COMP%]:focus {\n border-bottom-color: var(--mj-brand-primary);\n background: color-mix(in srgb, var(--mj-brand-primary) 8%, transparent);\n border-radius: 4px 4px 0 0;\n padding: 4px 6px;\n}\n\n.mj-forms-field-input[_ngcontent-%COMP%]::placeholder {\n color: var(--mj-text-muted);\n font-style: italic;\n}\n\n\n\n.mj-forms-field-input--textarea[_ngcontent-%COMP%] {\n resize: vertical;\n min-height: 60px;\n border: 1.5px solid var(--mj-border-default);\n border-radius: 6px;\n padding: 8px 10px;\n background: var(--mj-bg-surface);\n font-family: inherit;\n}\n\n.mj-forms-field-input--textarea[_ngcontent-%COMP%]:focus {\n border-color: var(--mj-brand-primary);\n box-shadow: 0 0 0 3px color-mix(in srgb, var(--mj-brand-primary) 10%, transparent);\n background: var(--mj-bg-surface);\n padding: 8px 10px;\n border-radius: 6px;\n}\n\n\n\n.mj-forms-field-input--number[_ngcontent-%COMP%] {\n max-width: 200px;\n}\n\n\n\n.mj-forms-field-input--date[_ngcontent-%COMP%] {\n max-width: 220px;\n}\n\n\n\n\n\n.mj-forms-field-checkbox[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: 8px;\n}\n\n.mj-forms-field-checkbox[_ngcontent-%COMP%] input[type=\"checkbox\"][_ngcontent-%COMP%] {\n appearance: none;\n width: 18px;\n height: 18px;\n border: 2px solid var(--mj-border-default);\n border-radius: 4px;\n cursor: pointer;\n position: relative;\n transition: all var(--mj-transition-base) ease;\n flex-shrink: 0;\n}\n\n.mj-forms-field-checkbox[_ngcontent-%COMP%] input[type=\"checkbox\"][_ngcontent-%COMP%]:checked {\n background: var(--mj-brand-primary);\n border-color: var(--mj-brand-primary);\n}\n\n.mj-forms-field-checkbox[_ngcontent-%COMP%] input[type=\"checkbox\"][_ngcontent-%COMP%]:checked::after {\n content: '';\n position: absolute;\n left: 5px;\n top: 1px;\n width: 5px;\n height: 9px;\n border: solid var(--mj-text-inverse);\n border-width: 0 2px 2px 0;\n transform: rotate(45deg);\n}\n\n.mj-forms-field-checkbox[_ngcontent-%COMP%] input[type=\"checkbox\"][_ngcontent-%COMP%]:disabled {\n opacity: 0.5;\n cursor: default;\n}\n\n\n\n\n\n.mj-custom-select-trigger[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n justify-content: space-between;\n font-size: 14px;\n font-family: inherit;\n color: var(--mj-text-primary);\n background: transparent;\n border: none;\n border-bottom: 1.5px solid var(--mj-border-default);\n padding: 4px 0;\n width: 100%;\n cursor: pointer;\n outline: none;\n transition: border-color var(--mj-transition-base) ease,\n background var(--mj-transition-base) ease;\n}\n\n.mj-custom-select-trigger[_ngcontent-%COMP%]:focus {\n border-bottom-color: var(--mj-brand-primary);\n background: color-mix(in srgb, var(--mj-brand-primary) 8%, transparent);\n border-radius: 4px 4px 0 0;\n padding: 4px 6px;\n}\n\n.mj-custom-select-value[_ngcontent-%COMP%] {\n flex: 1;\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n\n.mj-custom-select-value--placeholder[_ngcontent-%COMP%] {\n color: var(--mj-text-muted);\n font-style: italic;\n}\n\n.mj-custom-select-chevron[_ngcontent-%COMP%] {\n font-size: 11px;\n color: var(--mj-text-muted);\n transition: transform var(--mj-transition-base) ease;\n flex-shrink: 0;\n margin-left: 8px;\n}\n\n.mj-custom-select-chevron--open[_ngcontent-%COMP%] {\n transform: rotate(180deg);\n}\n\n\n\n\n\n.mj-fk-search[_ngcontent-%COMP%] {\n position: relative;\n display: flex;\n align-items: center;\n width: 100%;\n}\n\n.mj-fk-search[_ngcontent-%COMP%] .mj-forms-field-input[_ngcontent-%COMP%] {\n padding-right: 28px;\n}\n\n.mj-fk-search-icon[_ngcontent-%COMP%] {\n position: absolute;\n right: 4px;\n color: var(--mj-text-muted);\n font-size: 12px;\n pointer-events: none;\n}\n\n.mj-fk-clear[_ngcontent-%COMP%] {\n position: absolute;\n right: 2px;\n background: none;\n border: none;\n color: var(--mj-text-muted);\n cursor: pointer;\n font-size: 11px;\n padding: 4px 6px;\n line-height: 1;\n border-radius: 3px;\n transition: all var(--mj-transition-base);\n}\n\n.mj-fk-clear[_ngcontent-%COMP%]:hover {\n color: var(--mj-status-error);\n background: color-mix(in srgb, var(--mj-status-error) 8%, transparent);\n}\n\n\n\n\n.mj-fk-search--matched[_ngcontent-%COMP%] .mj-forms-field-input[_ngcontent-%COMP%] {\n border-bottom: 2px solid var(--mj-brand-primary);\n}\n\n\n\n\n.mj-fk-link-icon[_ngcontent-%COMP%] {\n position: absolute;\n right: 26px;\n color: var(--mj-brand-primary);\n font-size: 10px;\n pointer-events: none;\n z-index: 1;\n}\n\n\n\n.mj-forms-field-input--linked[_ngcontent-%COMP%] {\n padding-right: 46px;\n}\n\n\n\n\n\n\n\n.mj-fk-search--scoped[_ngcontent-%COMP%] .mj-forms-field-input[_ngcontent-%COMP%] {\n padding-right: 150px;\n}\n\n.mj-fk-scope-pill[_ngcontent-%COMP%] {\n position: absolute;\n right: 30px;\n \n\n top: 50%;\n transform: translateY(-50%);\n display: inline-flex;\n align-items: center;\n gap: 5px;\n max-width: 120px;\n background: var(--mj-bg-surface-elevated);\n border: 1px solid var(--mj-border-strong);\n color: var(--mj-text-secondary);\n font-size: 10.5px;\n font-weight: 600;\n font-family: inherit;\n \n\n padding: 1px 7px;\n border-radius: 999px;\n cursor: pointer;\n white-space: nowrap;\n line-height: 1.35;\n transition: background var(--mj-transition-base), border-color var(--mj-transition-base), color var(--mj-transition-base);\n}\n\n.mj-fk-scope-pill[_ngcontent-%COMP%]:hover, \n.mj-fk-scope-pill--open[_ngcontent-%COMP%] {\n border-color: var(--mj-brand-primary);\n color: var(--mj-text-primary);\n}\n\n.mj-fk-scope-pill-icon[_ngcontent-%COMP%] {\n font-size: 9px;\n opacity: 0.7;\n flex-shrink: 0;\n}\n\n.mj-fk-scope-pill-label[_ngcontent-%COMP%] {\n overflow: hidden;\n text-overflow: ellipsis;\n}\n\n.mj-fk-scope-pill-caret[_ngcontent-%COMP%] {\n font-size: 8px;\n opacity: 0.7;\n flex-shrink: 0;\n}\n\n\n\n\n\n.mj-fk-scope-menu[_ngcontent-%COMP%] {\n position: absolute;\n top: 4px;\n right: 8px;\n z-index: 5;\n min-width: 180px;\n max-width: calc(100vw - 24px);\n max-height: 260px;\n overflow-y: auto;\n background: var(--mj-bg-surface-elevated);\n border: 1px solid var(--mj-border-strong);\n border-radius: var(--mj-radius-sm);\n box-shadow: var(--mj-shadow-lg);\n padding: 5px;\n animation: _ngcontent-%COMP%_mj-dropdown-in 120ms ease;\n}\n\n\n\n\n.mj-fk-scope-menu--bottom[_ngcontent-%COMP%] {\n top: auto;\n bottom: 4px;\n}\n\n.mj-fk-scope-grp[_ngcontent-%COMP%] {\n font-size: 10px;\n text-transform: uppercase;\n letter-spacing: 0.06em;\n color: var(--mj-text-muted);\n padding: 7px 10px 4px;\n font-weight: 700;\n}\n\n.mj-fk-scope-mi[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: 9px;\n padding: 7px 10px;\n font-size: 13px;\n border-radius: 5px;\n color: var(--mj-text-secondary);\n cursor: pointer;\n}\n\n.mj-fk-scope-mi[_ngcontent-%COMP%]:hover {\n background: var(--mj-bg-surface-hover);\n}\n\n.mj-fk-scope-mi--on[_ngcontent-%COMP%] {\n color: var(--mj-brand-primary);\n font-weight: 600;\n}\n\n\n\n\n.mj-fk-col-reorder[_ngcontent-%COMP%] {\n display: flex;\n flex-direction: column;\n align-items: center;\n justify-content: center;\n width: 14px;\n height: 22px;\n flex-shrink: 0;\n}\n\n.mj-fk-col-move[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n justify-content: center;\n width: 14px;\n height: 10px;\n padding: 0;\n background: transparent;\n border: none;\n color: var(--mj-text-muted);\n cursor: pointer;\n font-size: 8px;\n opacity: 0; \n\n transition: opacity var(--mj-transition-base), color var(--mj-transition-base);\n}\n\n.mj-fk-scope-mi[_ngcontent-%COMP%]:hover .mj-fk-col-move[_ngcontent-%COMP%]:not(:disabled) {\n opacity: 0.8;\n}\n\n.mj-fk-col-move[_ngcontent-%COMP%]:hover:not(:disabled) {\n opacity: 1;\n color: var(--mj-brand-primary);\n}\n\n\n\n.mj-fk-col-move[_ngcontent-%COMP%]:disabled {\n opacity: 0 !important;\n cursor: default;\n}\n\n.mj-fk-scope-mi-icon[_ngcontent-%COMP%] {\n width: 14px;\n font-size: 11px;\n opacity: 0.75;\n flex-shrink: 0;\n}\n\n.mj-fk-scope-mi-label[_ngcontent-%COMP%] {\n flex: 1;\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n\n\n\n.mj-fk-col-eye-slot[_ngcontent-%COMP%] {\n width: 22px;\n height: 22px;\n flex-shrink: 0;\n display: flex;\n align-items: center;\n justify-content: center;\n}\n\n\n\n.mj-fk-col-toggle[_ngcontent-%COMP%] {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n width: 22px;\n height: 22px;\n background: transparent;\n border: none;\n border-radius: 4px;\n color: var(--mj-text-muted);\n cursor: pointer;\n font-size: 12px;\n transition: background var(--mj-transition-base), color var(--mj-transition-base);\n}\n\n.mj-fk-col-toggle[_ngcontent-%COMP%]:hover {\n background: var(--mj-bg-surface-hover);\n color: var(--mj-text-secondary);\n}\n\n.mj-fk-col-toggle--on[_ngcontent-%COMP%] {\n color: var(--mj-brand-primary);\n}\n\n.mj-fk-scope-divider[_ngcontent-%COMP%] {\n height: 1px;\n background: var(--mj-border-subtle);\n margin: 4px 6px;\n}\n\n\n\n\n@media (max-width: 560px) {\n .mj-fk-search--scoped[_ngcontent-%COMP%] .mj-forms-field-input[_ngcontent-%COMP%] {\n padding-right: 116px;\n }\n .mj-fk-scope-pill[_ngcontent-%COMP%] {\n max-width: 88px;\n }\n .mj-fk-scope-menu[_ngcontent-%COMP%] {\n min-width: 160px;\n }\n .mj-fk-scope-mi[_ngcontent-%COMP%] {\n padding: 10px 10px;\n }\n}\n\n\n\n\n\n.mj-fk-dropdown[_ngcontent-%COMP%] {\n background: var(--mj-bg-surface-card);\n border: 1px solid var(--mj-border-default);\n border-radius: var(--mj-radius-md);\n box-shadow: var(--mj-shadow-lg);\n max-height: 240px;\n overflow-y: auto;\n padding: 4px;\n animation: _ngcontent-%COMP%_mj-dropdown-in 150ms ease;\n}\n\n.mj-fk-dropdown--above[_ngcontent-%COMP%] {\n animation: _ngcontent-%COMP%_mj-dropdown-in-above 150ms ease;\n}\n\n.mj-fk-option[_ngcontent-%COMP%] {\n padding: 10px 14px;\n font-size: 14px;\n color: var(--mj-text-primary);\n cursor: pointer;\n transition: background var(--mj-transition-base);\n border-radius: 6px;\n}\n\n.mj-fk-option[_ngcontent-%COMP%]:hover {\n background: color-mix(in srgb, var(--mj-brand-primary) 8%, transparent);\n}\n\n.mj-fk-option--selected[_ngcontent-%COMP%] {\n background: color-mix(in srgb, var(--mj-brand-primary) 8%, transparent);\n font-weight: 600;\n color: var(--mj-brand-primary);\n}\n\n.mj-fk-option--selected[_ngcontent-%COMP%]:hover {\n background: color-mix(in srgb, var(--mj-brand-primary) 15%, transparent);\n}\n\n\n\n\n\n\n.mj-fk-dropdown--multi[_ngcontent-%COMP%] {\n padding: 4px;\n \n\n\n overflow: hidden;\n max-height: none;\n}\n\n\n\n\n\n.mj-fk-dropdown--multi[_ngcontent-%COMP%] .mj-fk-options[_ngcontent-%COMP%] {\n overflow: auto;\n max-height: 260px;\n}\n\n\n\n\n.mj-fk-dropdown--scope-open[_ngcontent-%COMP%] {\n overflow: visible;\n}\n\n\n\n\n\n\n\n.mj-fk-grid[_ngcontent-%COMP%] {\n display: grid;\n width: 100%;\n min-width: max-content;\n align-items: stretch;\n}\n\n\n\n\n\n.mj-fk-grid-row[_ngcontent-%COMP%] {\n display: contents;\n}\n\n\n\n.mj-fk-hcell[_ngcontent-%COMP%] {\n position: sticky;\n top: 0;\n z-index: 1;\n display: flex;\n align-items: center;\n gap: 6px;\n padding: 7px 12px;\n font-size: 12px;\n font-weight: 600;\n text-transform: uppercase;\n letter-spacing: 0.03em;\n color: var(--mj-text-muted);\n background: var(--mj-bg-surface-elevated);\n border-bottom: 1px solid var(--mj-border-default);\n cursor: pointer;\n user-select: none;\n white-space: nowrap;\n}\n\n.mj-fk-hcell[_ngcontent-%COMP%]:hover {\n color: var(--mj-text-secondary);\n background: var(--mj-bg-surface-hover);\n}\n\n.mj-fk-hcell--icon[_ngcontent-%COMP%] {\n cursor: default;\n padding: 7px 8px;\n}\n\n.mj-fk-hcell--icon[_ngcontent-%COMP%]:hover {\n background: var(--mj-bg-surface-elevated);\n}\n\n.mj-fk-hcell-label[_ngcontent-%COMP%] {\n overflow: hidden;\n text-overflow: ellipsis;\n}\n\n.mj-fk-sort-icon[_ngcontent-%COMP%] {\n font-size: 11px;\n flex-shrink: 0;\n}\n\n\n\n.mj-fk-sort-icon--idle[_ngcontent-%COMP%] {\n opacity: 0.35;\n}\n\n\n\n.mj-fk-cell[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n padding: 8px 12px;\n font-size: 13px;\n color: var(--mj-text-secondary);\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n max-width: 320px;\n cursor: pointer;\n}\n\n\n\n\n.mj-fk-cell--fill[_ngcontent-%COMP%] {\n max-width: none;\n}\n\n\n\n\n.mj-fk-cell[_ngcontent-%COMP%] > span[_ngcontent-%COMP%] {\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n min-width: 0;\n}\n\n.mj-fk-cell--icon[_ngcontent-%COMP%] {\n justify-content: center;\n padding: 8px;\n max-width: none;\n color: var(--mj-text-muted);\n font-size: 13px;\n}\n\n.mj-fk-cell--name[_ngcontent-%COMP%] {\n font-weight: 500;\n font-size: 14px;\n color: var(--mj-text-primary);\n gap: 6px;\n}\n\n.mj-fk-selected-check[_ngcontent-%COMP%] {\n color: var(--mj-brand-primary);\n font-size: 11px;\n flex-shrink: 0;\n}\n\n\n\n\n.mj-fk-grid-row--active[_ngcontent-%COMP%] > .mj-fk-cell[_ngcontent-%COMP%] {\n background: color-mix(in srgb, var(--mj-brand-primary) 12%, transparent);\n}\n\n\n\n\n.mj-fk-grid-row--selected[_ngcontent-%COMP%] > .mj-fk-cell[_ngcontent-%COMP%] {\n background: color-mix(in srgb, var(--mj-brand-primary) 6%, transparent);\n}\n\n.mj-fk-grid-row--selected[_ngcontent-%COMP%] > .mj-fk-cell--name[_ngcontent-%COMP%] {\n font-weight: 600;\n color: var(--mj-brand-primary);\n}\n\n\n\n\n\n\n\n.mj-fk-cell--name[_ngcontent-%COMP%] .mj-forms-search-highlight, \n.mj-fk-cell[_ngcontent-%COMP%] .mj-forms-search-highlight {\n background-color: var(--mj-search-highlight-bg);\n color: var(--mj-search-highlight-text);\n border-radius: 2px;\n padding: 0 1px;\n font-weight: 600;\n}\n\n\n\n.mj-fk-resizer[_ngcontent-%COMP%] {\n position: absolute;\n top: 0;\n right: 0;\n width: 7px;\n height: 100%;\n cursor: col-resize;\n user-select: none;\n}\n\n.mj-fk-resizer[_ngcontent-%COMP%]::after {\n content: '';\n position: absolute;\n top: 20%;\n right: 2px;\n width: 2px;\n height: 60%;\n background: transparent;\n transition: background var(--mj-transition-base);\n}\n\n.mj-fk-hcell[_ngcontent-%COMP%]:hover .mj-fk-resizer[_ngcontent-%COMP%]::after, \n.mj-fk-resizer[_ngcontent-%COMP%]:hover::after {\n background: var(--mj-border-strong);\n}\n\n\n\n.mj-fk-status[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: 8px;\n padding: 10px 14px;\n font-size: 13px;\n color: var(--mj-text-muted);\n}\n\n.mj-fk-status[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n font-size: 12px;\n}\n\n.mj-fk-status--empty[_ngcontent-%COMP%] {\n font-style: italic;\n}\n\n\n\n\n.mj-fk-create-footer[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: 9px;\n width: 100%;\n padding: 10px 14px;\n background: var(--mj-bg-surface-card);\n border: none;\n border-top: 1px solid var(--mj-border-default);\n color: var(--mj-brand-primary);\n font-size: 13px;\n font-weight: 600;\n font-family: inherit;\n text-align: left;\n cursor: pointer;\n transition: background var(--mj-transition-base);\n}\n\n.mj-fk-create-footer[_ngcontent-%COMP%]:hover {\n background: var(--mj-bg-surface-hover);\n}\n\n.mj-fk-create-icon[_ngcontent-%COMP%] {\n font-size: 11px;\n flex-shrink: 0;\n}\n\n.mj-fk-create-label[_ngcontent-%COMP%] {\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n\n\n\n\n\n.mj-fk-current[_ngcontent-%COMP%] {\n border-bottom: 1px solid var(--mj-border-default);\n background: color-mix(in srgb, var(--mj-brand-primary) 7%, var(--mj-bg-surface-card));\n animation: _ngcontent-%COMP%_mj-fk-current-in 220ms cubic-bezier(0.22, 1, 0.36, 1);\n}\n\n@keyframes _ngcontent-%COMP%_mj-fk-current-in {\n from { opacity: 0; transform: translateY(-6px); }\n to { opacity: 1; transform: translateY(0); }\n}\n\n.mj-fk-current-head[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: 6px;\n padding: 8px 12px 3px;\n font-size: 10px;\n font-weight: 700;\n text-transform: uppercase;\n letter-spacing: 0.06em;\n color: var(--mj-brand-primary);\n}\n\n.mj-fk-current-head[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n font-size: 10px;\n}\n\n.mj-fk-current-row[_ngcontent-%COMP%] {\n position: relative;\n display: flex;\n align-items: center;\n gap: 9px;\n padding: 6px 12px 10px;\n cursor: pointer;\n transition: background var(--mj-transition-base);\n}\n\n\n\n.mj-fk-current-row[_ngcontent-%COMP%]::before {\n content: '';\n position: absolute;\n left: 0;\n top: 4px;\n bottom: 8px;\n width: 3px;\n border-radius: 0 2px 2px 0;\n background: var(--mj-brand-primary);\n}\n\n.mj-fk-current-row[_ngcontent-%COMP%]:hover {\n background: color-mix(in srgb, var(--mj-brand-primary) 10%, transparent);\n}\n\n.mj-fk-current-icon[_ngcontent-%COMP%] {\n flex-shrink: 0;\n font-size: 13px;\n color: var(--mj-text-muted);\n}\n\n.mj-fk-current-name[_ngcontent-%COMP%] {\n font-weight: 600;\n font-size: 14px;\n color: var(--mj-text-primary);\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n}\n\n.mj-fk-current-detail[_ngcontent-%COMP%] {\n font-size: 13px;\n color: var(--mj-text-muted);\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n}\n\n.mj-fk-current-clear[_ngcontent-%COMP%] {\n margin-left: auto;\n display: inline-flex;\n align-items: center;\n justify-content: center;\n width: 22px;\n height: 22px;\n flex-shrink: 0;\n background: transparent;\n border: none;\n border-radius: 4px;\n color: var(--mj-text-muted);\n cursor: pointer;\n font-size: 12px;\n transition: background var(--mj-transition-base), color var(--mj-transition-base);\n}\n\n.mj-fk-current-clear[_ngcontent-%COMP%]:hover {\n background: var(--mj-bg-surface-hover);\n color: var(--mj-status-error);\n}\n\n@keyframes _ngcontent-%COMP%_mj-dropdown-in {\n from { opacity: 0; transform: translateY(-4px); }\n to { opacity: 1; transform: translateY(0); }\n}\n\n@keyframes _ngcontent-%COMP%_mj-dropdown-in-above {\n from { opacity: 0; transform: translateY(4px); }\n to { opacity: 1; transform: translateY(0); }\n}\n\n\n\n\n\n.mj-forms-field-label[_ngcontent-%COMP%] .mj-forms-search-highlight {\n \n\n\n background-color: var(--mj-search-highlight-bg);\n color: var(--mj-search-highlight-text);\n border-radius: 2px;\n padding: 0 1px;\n font-weight: 600;\n}\n\n\n\n\n\n.mj-forms-field--has-error[_ngcontent-%COMP%] .mj-forms-field-input[_ngcontent-%COMP%] {\n border-bottom-color: var(--mj-status-error);\n border-bottom-width: 2px;\n}\n\n.mj-forms-field--has-error[_ngcontent-%COMP%] .mj-forms-field-input[_ngcontent-%COMP%]:focus {\n background: color-mix(in srgb, var(--mj-status-error) 5%, var(--mj-bg-surface));\n border-bottom-color: var(--mj-status-error);\n}\n\n.mj-forms-field--has-error[_ngcontent-%COMP%] .mj-forms-field-input--textarea[_ngcontent-%COMP%] {\n border-color: var(--mj-status-error);\n}\n\n.mj-forms-field--has-error[_ngcontent-%COMP%] .mj-forms-field-input--textarea[_ngcontent-%COMP%]:focus {\n border-color: var(--mj-status-error);\n box-shadow: 0 0 0 3px color-mix(in srgb, var(--mj-status-error) 8%, transparent);\n}\n\n.mj-forms-field--has-error[_ngcontent-%COMP%] .mj-custom-select-trigger[_ngcontent-%COMP%] {\n border-bottom-color: var(--mj-status-error);\n border-bottom-width: 2px;\n}\n\n.mj-forms-field--has-error[_ngcontent-%COMP%] .mj-fk-search[_ngcontent-%COMP%] .mj-forms-field-input[_ngcontent-%COMP%] {\n border-bottom-color: var(--mj-status-error);\n border-bottom-width: 2px;\n}\n\n\n\n\n\n.mj-forms-field--has-warning[_ngcontent-%COMP%] .mj-forms-field-input[_ngcontent-%COMP%] {\n border-bottom-color: var(--mj-status-warning);\n border-bottom-width: 2px;\n}\n\n.mj-forms-field--has-warning[_ngcontent-%COMP%] .mj-forms-field-input[_ngcontent-%COMP%]:focus {\n background: color-mix(in srgb, var(--mj-status-warning) 5%, var(--mj-bg-surface));\n border-bottom-color: var(--mj-status-warning);\n}\n\n.mj-forms-field--has-warning[_ngcontent-%COMP%] .mj-forms-field-input--textarea[_ngcontent-%COMP%] {\n border-color: var(--mj-status-warning);\n}\n\n.mj-forms-field--has-warning[_ngcontent-%COMP%] .mj-forms-field-input--textarea[_ngcontent-%COMP%]:focus {\n border-color: var(--mj-status-warning);\n box-shadow: 0 0 0 3px color-mix(in srgb, var(--mj-status-warning) 8%, transparent);\n}\n\n.mj-forms-field--has-warning[_ngcontent-%COMP%] .mj-custom-select-trigger[_ngcontent-%COMP%] {\n border-bottom-color: var(--mj-status-warning);\n border-bottom-width: 2px;\n}\n\n.mj-forms-field--has-warning[_ngcontent-%COMP%] .mj-fk-search[_ngcontent-%COMP%] .mj-forms-field-input[_ngcontent-%COMP%] {\n border-bottom-color: var(--mj-status-warning);\n border-bottom-width: 2px;\n}\n\n\n\n\n\n.mj-forms-field-validation[_ngcontent-%COMP%] {\n grid-column: 2;\n display: flex;\n flex-direction: column;\n gap: 2px;\n margin-top: -2px;\n overflow: hidden;\n animation: _ngcontent-%COMP%_mj-validation-slide-in 200ms ease-out;\n}\n\n.mj-forms-field-validation-item[_ngcontent-%COMP%] {\n display: flex;\n align-items: flex-start;\n gap: 6px;\n font-size: 12px;\n line-height: 1.4;\n padding: 3px 0 1px;\n}\n\n.mj-forms-field-validation-item[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n font-size: 11px;\n margin-top: 2px;\n flex-shrink: 0;\n}\n\n\n\n.mj-forms-field-validation--error[_ngcontent-%COMP%] .mj-forms-field-validation-item[_ngcontent-%COMP%] {\n color: var(--mj-status-error);\n}\n\n.mj-forms-field-validation--error[_ngcontent-%COMP%] .mj-forms-field-validation-item[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n color: var(--mj-status-error);\n}\n\n\n\n.mj-forms-field-validation--warning[_ngcontent-%COMP%] .mj-forms-field-validation-item[_ngcontent-%COMP%] {\n color: var(--mj-status-warning-text);\n}\n\n.mj-forms-field-validation--warning[_ngcontent-%COMP%] .mj-forms-field-validation-item[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n color: var(--mj-status-warning);\n}\n\n@keyframes _ngcontent-%COMP%_mj-validation-slide-in {\n from {\n opacity: 0;\n max-height: 0;\n transform: translateY(-4px);\n }\n to {\n opacity: 1;\n max-height: 100px;\n transform: translateY(0);\n }\n}\n\n\n\n\n\n@media (max-width: 640px) {\n .mj-forms-field[_ngcontent-%COMP%] {\n grid-template-columns: 1fr;\n gap: 4px;\n }\n\n .mj-forms-field-label[_ngcontent-%COMP%] {\n font-size: 12px;\n }\n\n .mj-forms-field-validation[_ngcontent-%COMP%] {\n grid-column: 1;\n }\n}"], changeDetection: 0 });
1172
2596
  }
1173
2597
  (() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassMetadata(MjFormFieldComponent, [{
1174
2598
  type: Component,
1175
- args: [{ standalone: false, selector: 'mj-form-field', changeDetection: ChangeDetectionStrategy.OnPush, template: "@if (Record && (Record.IsSaved || !IsFieldReadOnly)) {\n <!-- READ-ONLY MODE -->\n @if ((!EditMode || IsFieldReadOnly) && !ShouldHideField) {\n <div class=\"mj-forms-field\" [class.mj-forms-field--readonly]=\"EditMode && IsFieldReadOnly\" [class.mj-forms-field--dirty]=\"IsDirty\">\n @if (ShowLabel) {\n <label class=\"mj-forms-field-label\" [innerHTML]=\"HighlightedDisplayName\"></label>\n }\n <div class=\"mj-forms-field-control\">\n <!-- FK fields with a mapped name field: show the name as a hyperlink -->\n @if (IsFKWithNameField) {\n <span class=\"mj-forms-field-value\">\n <a class=\"mj-forms-field-link mj-forms-field-link--fk\" (click)=\"OnRecordLinkClick($event)\" title=\"View related record\">\n {{ FKDisplayName }}\n </a>\n </span>\n }\n @else {\n @switch (LinkType) {\n @case ('Email') {\n <span class=\"mj-forms-field-value\">\n <a class=\"mj-forms-field-link\" (click)=\"OnEmailLinkClick($event)\" title=\"Send email\">\n {{ FormatValue() }}\n <i class=\"fa-solid fa-envelope mj-forms-field-link-icon\"></i>\n </a>\n </span>\n }\n @case ('URL') {\n <span class=\"mj-forms-field-value\">\n <a class=\"mj-forms-field-link\" (click)=\"OnUrlLinkClick($event)\" title=\"Open link\">\n {{ FormatValue() }}\n <i class=\"fa-solid fa-arrow-up-right-from-square mj-forms-field-link-icon\"></i>\n </a>\n </span>\n }\n @case ('Record') {\n <span class=\"mj-forms-field-value\">\n <a class=\"mj-forms-field-link\" (click)=\"OnRecordLinkClick($event)\" title=\"View related record\">\n {{ FormatValue() }}\n <i class=\"fa-solid fa-arrow-up-right-from-square mj-forms-field-link-icon\"></i>\n </a>\n </span>\n }\n @default {\n @if (Type === 'checkbox') {\n <span class=\"mj-forms-field-value\">\n <div class=\"mj-forms-field-checkbox\">\n <input type=\"checkbox\" [checked]=\"!!Value\" disabled>\n </div>\n </span>\n }\n @else if (IsLongText) {\n <span class=\"mj-forms-field-value mj-forms-field-value--long\">{{ FormatValue() }}</span>\n }\n @else {\n <span class=\"mj-forms-field-value\">{{ FormatValue() }}</span>\n }\n }\n }\n }\n </div>\n </div>\n }\n\n <!-- EDIT MODE -->\n @if (EditMode && !IsFieldReadOnly) {\n <div class=\"mj-forms-field mj-forms-field--editing\" [class.mj-forms-field--dirty]=\"IsDirty\" [class.mj-forms-field--required-empty]=\"IsRequiredEmpty\" [class.mj-forms-field--has-error]=\"ShowErrors\" [class.mj-forms-field--has-warning]=\"ShowWarnings\">\n @if (ShowLabel) {\n <label class=\"mj-forms-field-label\" [innerHTML]=\"HighlightedDisplayName\"></label>\n }\n <div class=\"mj-forms-field-control\">\n <!-- Foreign Key fields get custom search autocomplete -->\n @if (HasRelatedEntity) {\n <div class=\"mj-fk-search\" [class.mj-fk-search--matched]=\"FKIsMatched\">\n <input type=\"text\"\n class=\"mj-forms-field-input\"\n [value]=\"FKSearchText\"\n (input)=\"OnFKInput($event)\"\n (focus)=\"OnFKFocus($event)\"\n (blur)=\"OnFKBlur()\"\n placeholder=\"Search...\">\n @if (FKSearchText) {\n <button class=\"mj-fk-clear\" (mousedown)=\"OnFKClearClick($event)\" title=\"Clear\">\n <i class=\"fa-solid fa-xmark\"></i>\n </button>\n } @else {\n <i class=\"fa-solid fa-magnifying-glass mj-fk-search-icon\"></i>\n }\n @if (ShowFKDropdown && FKSuggestions.length > 0) {\n <div class=\"mj-fk-dropdown\" [ngStyle]=\"DropdownPositionStyle\" [class.mj-fk-dropdown--above]=\"OpenAbove\">\n @for (suggestion of FKSuggestions; track suggestion.PrimaryKeyValue) {\n <div class=\"mj-fk-option\" (mousedown)=\"OnFKSelectItem(suggestion, $event)\">\n {{ suggestion.DisplayName }}\n </div>\n }\n </div>\n }\n </div>\n }\n @else {\n @switch (Type) {\n @case ('textbox') {\n <input type=\"text\"\n class=\"mj-forms-field-input\"\n [value]=\"FormatValue()\"\n (input)=\"OnInputChange($event)\">\n }\n @case ('textarea') {\n <textarea\n class=\"mj-forms-field-input mj-forms-field-input--textarea\"\n [value]=\"FormatValue()\"\n (input)=\"OnInputChange($event)\"></textarea>\n }\n @case ('number') {\n <input type=\"number\"\n class=\"mj-forms-field-input mj-forms-field-input--number\"\n [value]=\"Value\"\n (change)=\"OnNumberChange($event)\">\n }\n @case ('datepicker') {\n <input type=\"date\"\n class=\"mj-forms-field-input mj-forms-field-input--date\"\n [value]=\"DateInputValue\"\n (change)=\"OnDateChange($event)\">\n }\n @case ('checkbox') {\n <div class=\"mj-forms-field-checkbox\">\n <input type=\"checkbox\"\n [checked]=\"!!Value\"\n (change)=\"OnCheckboxChange($event)\">\n </div>\n }\n @case ('select') {\n <div class=\"mj-custom-select-trigger\"\n tabindex=\"0\"\n (click)=\"OnSelectTriggerClick($event)\"\n (blur)=\"OnSelectTriggerBlur()\">\n <span class=\"mj-custom-select-value\" [class.mj-custom-select-value--placeholder]=\"!FormatValue()\">\n {{ FormatValue() || '-- Select --' }}\n </span>\n <i class=\"fa-solid fa-chevron-down mj-custom-select-chevron\" [class.mj-custom-select-chevron--open]=\"ShowSelectDropdown\"></i>\n </div>\n @if (ShowSelectDropdown && PossibleValues.length > 0) {\n <div class=\"mj-fk-dropdown\" [ngStyle]=\"DropdownPositionStyle\" [class.mj-fk-dropdown--above]=\"OpenAbove\">\n @for (option of PossibleValues; track option) {\n <div class=\"mj-fk-option\" [class.mj-fk-option--selected]=\"FormatValue() === option\" (mousedown)=\"OnSelectOptionClick(option, $event)\">\n {{ option }}\n </div>\n }\n </div>\n }\n }\n @case ('autocomplete') {\n <div class=\"mj-fk-search\">\n <input type=\"text\"\n class=\"mj-forms-field-input\"\n [value]=\"FormatValue()\"\n (input)=\"OnValueListInput($event)\"\n (focus)=\"OnValueListFocus($event)\"\n (blur)=\"OnValueListBlur()\"\n placeholder=\"Type to search...\">\n <i class=\"fa-solid fa-magnifying-glass mj-fk-search-icon\"></i>\n @if (ShowValueListDropdown && FilteredPossibleValues.length > 0) {\n <div class=\"mj-fk-dropdown\" [ngStyle]=\"DropdownPositionStyle\" [class.mj-fk-dropdown--above]=\"OpenAbove\">\n @for (option of FilteredPossibleValues; track option) {\n <div class=\"mj-fk-option\" (mousedown)=\"OnValueListSelect(option, $event)\">\n {{ option }}\n </div>\n }\n </div>\n }\n </div>\n }\n @default {\n <input type=\"text\"\n class=\"mj-forms-field-input\"\n [value]=\"FormatValue()\"\n (change)=\"OnInputChange($event)\">\n }\n }\n }\n </div>\n <!-- Inline validation messages -->\n @if (DisplayErrors.length > 0) {\n <div class=\"mj-forms-field-validation mj-forms-field-validation--error\">\n @for (error of DisplayErrors; track error.Message) {\n <div class=\"mj-forms-field-validation-item\">\n <i class=\"fa-solid fa-circle-exclamation\"></i>\n <span>{{ error.Message }}</span>\n </div>\n }\n </div>\n }\n @if (DisplayWarnings.length > 0) {\n <div class=\"mj-forms-field-validation mj-forms-field-validation--warning\">\n @for (warning of DisplayWarnings; track warning.Message) {\n <div class=\"mj-forms-field-validation-item\">\n <i class=\"fa-solid fa-triangle-exclamation\"></i>\n <span>{{ warning.Message }}</span>\n </div>\n }\n </div>\n }\n </div>\n }\n}\n", styles: ["/* ============================================\n FORM FIELD - Shared styles for read and edit\n ============================================ */\n:host {\n --mj-forms-field-label-width: 200px;\n --mj-forms-field-gap: 12px;\n\n display: contents;\n}\n\n.mj-forms-field {\n display: grid;\n grid-template-columns: var(--mj-forms-field-label-width) 1fr;\n gap: var(--mj-forms-field-gap);\n align-items: baseline;\n padding: 8px 0;\n transition: all var(--mj-transition-base) ease;\n}\n\n/* Subtle row hover in edit mode */\n.mj-forms-field--editing:hover {\n background: color-mix(in srgb, var(--mj-brand-primary) 8%, transparent);\n border-radius: 6px;\n margin: 0 -8px;\n padding: 8px 8px;\n}\n\n/* ============================================\n LABEL\n ============================================ */\n.mj-forms-field-label {\n font-size: 13px;\n font-weight: 600;\n color: var(--mj-text-secondary);\n padding-top: 2px;\n word-break: break-word;\n}\n\n/* ============================================\n FIELD CONTROL WRAPPER (value + dirty dot)\n ============================================ */\n.mj-forms-field-control {\n display: flex;\n align-items: center;\n gap: 8px;\n min-width: 0;\n}\n\n.mj-forms-field-control > * {\n flex: 1;\n min-width: 0;\n}\n\n/* ============================================\n DIRTY INDICATOR (solid amber dot after label)\n ============================================ */\n.mj-forms-field--dirty .mj-forms-field-label::after {\n content: '';\n display: inline-block;\n width: 6px;\n height: 6px;\n border-radius: 50%;\n background: var(--mj-status-warning);\n margin-left: 6px;\n vertical-align: middle;\n}\n\n/* ============================================\n REQUIRED FIELD - red underline when empty\n ============================================ */\n.mj-forms-field--required-empty .mj-forms-field-input {\n border-bottom-color: var(--mj-status-error);\n}\n\n.mj-forms-field--required-empty .mj-forms-field-input:focus {\n background: color-mix(in srgb, var(--mj-status-error) 5%, var(--mj-bg-surface));\n border-bottom-color: var(--mj-status-error);\n}\n\n.mj-forms-field--required-empty .mj-custom-select-trigger {\n border-bottom-color: var(--mj-status-error);\n}\n\n.mj-forms-field--required-empty .mj-fk-search .mj-forms-field-input {\n border-bottom-color: var(--mj-status-error);\n}\n\n/* ============================================\n READ-ONLY VALUE\n ============================================ */\n.mj-forms-field-value {\n font-size: 14px;\n color: var(--mj-text-primary);\n min-height: 24px;\n display: flex;\n align-items: center;\n overflow-wrap: break-word;\n word-break: break-word;\n}\n\n.mj-forms-field-value--long {\n white-space: pre-line;\n max-height: 300px;\n overflow: auto;\n}\n\n/* Read-only fields in edit mode */\n.mj-forms-field--readonly {\n opacity: 0.7;\n}\n\n.mj-forms-field--readonly .mj-forms-field-value {\n color: var(--mj-text-secondary);\n}\n\n/* ============================================\n LINKS (FK, email, URL)\n ============================================ */\n.mj-forms-field-link {\n display: inline-flex;\n align-items: center;\n gap: 6px;\n color: var(--mj-brand-primary);\n cursor: pointer;\n font-weight: 400;\n font-size: 14px;\n transition: color var(--mj-transition-base);\n text-decoration: none;\n}\n\n.mj-forms-field-link:hover {\n color: var(--mj-brand-primary-hover);\n}\n\n.mj-forms-field-link-icon {\n font-size: 11px;\n opacity: 0;\n transition: opacity var(--mj-transition-base);\n}\n\n.mj-forms-field-link:hover .mj-forms-field-link-icon {\n opacity: 1;\n}\n\n/* FK fields showing entity name instead of raw ID */\n.mj-forms-field-link--fk {\n font-size: 14px;\n font-weight: 400;\n}\n\n/* ============================================\n EDIT MODE INPUTS - Clean underline style\n ============================================ */\n.mj-forms-field-input {\n font-size: 14px;\n font-family: inherit;\n color: var(--mj-text-primary);\n background: transparent;\n border: none;\n border-bottom: 1.5px solid var(--mj-border-default);\n padding: 4px 0;\n width: 100%;\n outline: none;\n transition: border-color var(--mj-transition-base) ease,\n background var(--mj-transition-base) ease;\n}\n\n.mj-forms-field-input:focus {\n border-bottom-color: var(--mj-brand-primary);\n background: color-mix(in srgb, var(--mj-brand-primary) 8%, transparent);\n border-radius: 4px 4px 0 0;\n padding: 4px 6px;\n}\n\n.mj-forms-field-input::placeholder {\n color: var(--mj-text-muted);\n font-style: italic;\n}\n\n/* Textarea variant */\n.mj-forms-field-input--textarea {\n resize: vertical;\n min-height: 60px;\n border: 1.5px solid var(--mj-border-default);\n border-radius: 6px;\n padding: 8px 10px;\n background: var(--mj-bg-surface);\n font-family: inherit;\n}\n\n.mj-forms-field-input--textarea:focus {\n border-color: var(--mj-brand-primary);\n box-shadow: 0 0 0 3px color-mix(in srgb, var(--mj-brand-primary) 10%, transparent);\n background: var(--mj-bg-surface);\n padding: 8px 10px;\n border-radius: 6px;\n}\n\n/* Number input - narrower */\n.mj-forms-field-input--number {\n max-width: 200px;\n}\n\n/* Date input - narrower */\n.mj-forms-field-input--date {\n max-width: 220px;\n}\n\n/* ============================================\n CHECKBOX (custom styled)\n ============================================ */\n.mj-forms-field-checkbox {\n display: flex;\n align-items: center;\n gap: 8px;\n}\n\n.mj-forms-field-checkbox input[type=\"checkbox\"] {\n appearance: none;\n width: 18px;\n height: 18px;\n border: 2px solid var(--mj-border-default);\n border-radius: 4px;\n cursor: pointer;\n position: relative;\n transition: all var(--mj-transition-base) ease;\n flex-shrink: 0;\n}\n\n.mj-forms-field-checkbox input[type=\"checkbox\"]:checked {\n background: var(--mj-brand-primary);\n border-color: var(--mj-brand-primary);\n}\n\n.mj-forms-field-checkbox input[type=\"checkbox\"]:checked::after {\n content: '';\n position: absolute;\n left: 5px;\n top: 1px;\n width: 5px;\n height: 9px;\n border: solid var(--mj-text-inverse);\n border-width: 0 2px 2px 0;\n transform: rotate(45deg);\n}\n\n.mj-forms-field-checkbox input[type=\"checkbox\"]:disabled {\n opacity: 0.5;\n cursor: default;\n}\n\n/* ============================================\n CUSTOM SELECT DROPDOWN (replaces native <select>)\n ============================================ */\n.mj-custom-select-trigger {\n display: flex;\n align-items: center;\n justify-content: space-between;\n font-size: 14px;\n font-family: inherit;\n color: var(--mj-text-primary);\n background: transparent;\n border: none;\n border-bottom: 1.5px solid var(--mj-border-default);\n padding: 4px 0;\n width: 100%;\n cursor: pointer;\n outline: none;\n transition: border-color var(--mj-transition-base) ease,\n background var(--mj-transition-base) ease;\n}\n\n.mj-custom-select-trigger:focus {\n border-bottom-color: var(--mj-brand-primary);\n background: color-mix(in srgb, var(--mj-brand-primary) 8%, transparent);\n border-radius: 4px 4px 0 0;\n padding: 4px 6px;\n}\n\n.mj-custom-select-value {\n flex: 1;\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n\n.mj-custom-select-value--placeholder {\n color: var(--mj-text-muted);\n font-style: italic;\n}\n\n.mj-custom-select-chevron {\n font-size: 11px;\n color: var(--mj-text-muted);\n transition: transform var(--mj-transition-base) ease;\n flex-shrink: 0;\n margin-left: 8px;\n}\n\n.mj-custom-select-chevron--open {\n transform: rotate(180deg);\n}\n\n/* ============================================\n FK SEARCH (custom autocomplete)\n ============================================ */\n.mj-fk-search {\n position: relative;\n display: flex;\n align-items: center;\n width: 100%;\n}\n\n.mj-fk-search .mj-forms-field-input {\n padding-right: 28px;\n}\n\n.mj-fk-search-icon {\n position: absolute;\n right: 4px;\n color: var(--mj-text-muted);\n font-size: 12px;\n pointer-events: none;\n}\n\n.mj-fk-clear {\n position: absolute;\n right: 2px;\n background: none;\n border: none;\n color: var(--mj-text-muted);\n cursor: pointer;\n font-size: 11px;\n padding: 4px 6px;\n line-height: 1;\n border-radius: 3px;\n transition: all var(--mj-transition-base);\n}\n\n.mj-fk-clear:hover {\n color: var(--mj-status-error);\n background: color-mix(in srgb, var(--mj-status-error) 8%, transparent);\n}\n\n/* Matched state: solid accent underline */\n.mj-fk-search--matched .mj-forms-field-input {\n border-bottom: 2px solid var(--mj-brand-primary);\n}\n\n/* ============================================\n FLOATING DROPDOWN PANEL (position: fixed via ngStyle)\n ============================================ */\n.mj-fk-dropdown {\n background: var(--mj-bg-surface-card);\n border: 1px solid var(--mj-border-default);\n border-radius: var(--mj-radius-md);\n box-shadow: var(--mj-shadow-lg);\n max-height: 240px;\n overflow-y: auto;\n padding: 4px;\n animation: mj-dropdown-in 150ms ease;\n}\n\n.mj-fk-dropdown--above {\n animation: mj-dropdown-in-above 150ms ease;\n}\n\n.mj-fk-option {\n padding: 10px 14px;\n font-size: 14px;\n color: var(--mj-text-primary);\n cursor: pointer;\n transition: background var(--mj-transition-base);\n border-radius: 6px;\n}\n\n.mj-fk-option:hover {\n background: color-mix(in srgb, var(--mj-brand-primary) 8%, transparent);\n}\n\n.mj-fk-option--selected {\n background: color-mix(in srgb, var(--mj-brand-primary) 8%, transparent);\n font-weight: 600;\n color: var(--mj-brand-primary);\n}\n\n.mj-fk-option--selected:hover {\n background: color-mix(in srgb, var(--mj-brand-primary) 15%, transparent);\n}\n\n@keyframes mj-dropdown-in {\n from { opacity: 0; transform: translateY(-4px); }\n to { opacity: 1; transform: translateY(0); }\n}\n\n@keyframes mj-dropdown-in-above {\n from { opacity: 0; transform: translateY(4px); }\n to { opacity: 1; transform: translateY(0); }\n}\n\n/* ============================================\n SEARCH HIGHLIGHTING\n ============================================ */\n.mj-forms-field-label :global(.mj-forms-search-highlight) {\n background-color: var(--mj-color-warning-200, #fef08a);\n color: var(--mj-color-warning-800, #854d0e);\n padding: 0;\n border-radius: 2px;\n font-weight: 700;\n box-shadow: 0 0 0 2px var(--mj-color-warning-200, #fef08a);\n}\n\n/* ============================================\n VALIDATION ERROR STATE\n ============================================ */\n.mj-forms-field--has-error .mj-forms-field-input {\n border-bottom-color: var(--mj-status-error);\n border-bottom-width: 2px;\n}\n\n.mj-forms-field--has-error .mj-forms-field-input:focus {\n background: color-mix(in srgb, var(--mj-status-error) 5%, var(--mj-bg-surface));\n border-bottom-color: var(--mj-status-error);\n}\n\n.mj-forms-field--has-error .mj-forms-field-input--textarea {\n border-color: var(--mj-status-error);\n}\n\n.mj-forms-field--has-error .mj-forms-field-input--textarea:focus {\n border-color: var(--mj-status-error);\n box-shadow: 0 0 0 3px color-mix(in srgb, var(--mj-status-error) 8%, transparent);\n}\n\n.mj-forms-field--has-error .mj-custom-select-trigger {\n border-bottom-color: var(--mj-status-error);\n border-bottom-width: 2px;\n}\n\n.mj-forms-field--has-error .mj-fk-search .mj-forms-field-input {\n border-bottom-color: var(--mj-status-error);\n border-bottom-width: 2px;\n}\n\n/* ============================================\n VALIDATION WARNING STATE\n ============================================ */\n.mj-forms-field--has-warning .mj-forms-field-input {\n border-bottom-color: var(--mj-status-warning);\n border-bottom-width: 2px;\n}\n\n.mj-forms-field--has-warning .mj-forms-field-input:focus {\n background: color-mix(in srgb, var(--mj-status-warning) 5%, var(--mj-bg-surface));\n border-bottom-color: var(--mj-status-warning);\n}\n\n.mj-forms-field--has-warning .mj-forms-field-input--textarea {\n border-color: var(--mj-status-warning);\n}\n\n.mj-forms-field--has-warning .mj-forms-field-input--textarea:focus {\n border-color: var(--mj-status-warning);\n box-shadow: 0 0 0 3px color-mix(in srgb, var(--mj-status-warning) 8%, transparent);\n}\n\n.mj-forms-field--has-warning .mj-custom-select-trigger {\n border-bottom-color: var(--mj-status-warning);\n border-bottom-width: 2px;\n}\n\n.mj-forms-field--has-warning .mj-fk-search .mj-forms-field-input {\n border-bottom-color: var(--mj-status-warning);\n border-bottom-width: 2px;\n}\n\n/* ============================================\n VALIDATION MESSAGE AREA\n ============================================ */\n.mj-forms-field-validation {\n grid-column: 2;\n display: flex;\n flex-direction: column;\n gap: 2px;\n margin-top: -2px;\n overflow: hidden;\n animation: mj-validation-slide-in 200ms ease-out;\n}\n\n.mj-forms-field-validation-item {\n display: flex;\n align-items: flex-start;\n gap: 6px;\n font-size: 12px;\n line-height: 1.4;\n padding: 3px 0 1px;\n}\n\n.mj-forms-field-validation-item i {\n font-size: 11px;\n margin-top: 2px;\n flex-shrink: 0;\n}\n\n/* Error message colors */\n.mj-forms-field-validation--error .mj-forms-field-validation-item {\n color: var(--mj-status-error);\n}\n\n.mj-forms-field-validation--error .mj-forms-field-validation-item i {\n color: var(--mj-status-error);\n}\n\n/* Warning message colors */\n.mj-forms-field-validation--warning .mj-forms-field-validation-item {\n color: var(--mj-color-warning-700);\n}\n\n.mj-forms-field-validation--warning .mj-forms-field-validation-item i {\n color: var(--mj-status-warning);\n}\n\n@keyframes mj-validation-slide-in {\n from {\n opacity: 0;\n max-height: 0;\n transform: translateY(-4px);\n }\n to {\n opacity: 1;\n max-height: 100px;\n transform: translateY(0);\n }\n}\n\n/* ============================================\n RESPONSIVE\n ============================================ */\n@media (max-width: 640px) {\n .mj-forms-field {\n grid-template-columns: 1fr;\n gap: 4px;\n }\n\n .mj-forms-field-label {\n font-size: 12px;\n }\n\n .mj-forms-field-validation {\n grid-column: 1;\n }\n}\n"] }]
2599
+ args: [{ standalone: false, selector: 'mj-form-field', changeDetection: ChangeDetectionStrategy.OnPush, template: "@if (Record && (Record.IsSaved || !IsFieldReadOnly)) {\n <!-- READ-ONLY MODE -->\n @if ((!EditMode || IsFieldReadOnly) && !ShouldHideField) {\n <div class=\"mj-forms-field\" [class.mj-forms-field--readonly]=\"EditMode && IsFieldReadOnly\" [class.mj-forms-field--dirty]=\"IsDirty\">\n @if (ShowLabel) {\n <label class=\"mj-forms-field-label\" [innerHTML]=\"HighlightedDisplayName\"></label>\n }\n <div class=\"mj-forms-field-control\">\n <!-- FK fields with a mapped name field: show the name as a hyperlink -->\n @if (IsFKWithNameField) {\n <span class=\"mj-forms-field-value\">\n @if (RecordLinksEnabled) {\n <a class=\"mj-forms-field-link mj-forms-field-link--fk\" (click)=\"OnRecordLinkClick($event)\" title=\"View related record\">\n {{ FKDisplayName }}\n </a>\n } @else {\n {{ FKDisplayName }}\n }\n </span>\n }\n @else {\n @switch (LinkType) {\n @case ('Email') {\n <span class=\"mj-forms-field-value\">\n <a class=\"mj-forms-field-link\" (click)=\"OnEmailLinkClick($event)\" title=\"Send email\">\n {{ FormatValue() }}\n <i class=\"fa-solid fa-envelope mj-forms-field-link-icon\"></i>\n </a>\n </span>\n }\n @case ('URL') {\n <span class=\"mj-forms-field-value\">\n <a class=\"mj-forms-field-link\" (click)=\"OnUrlLinkClick($event)\" title=\"Open link\">\n {{ FormatValue() }}\n <i class=\"fa-solid fa-arrow-up-right-from-square mj-forms-field-link-icon\"></i>\n </a>\n </span>\n }\n @case ('Record') {\n <span class=\"mj-forms-field-value\">\n @if (RecordLinksEnabled) {\n <a class=\"mj-forms-field-link\" (click)=\"OnRecordLinkClick($event)\" title=\"View related record\">\n {{ FormatValue() }}\n <i class=\"fa-solid fa-arrow-up-right-from-square mj-forms-field-link-icon\"></i>\n </a>\n } @else {\n {{ FormatValue() }}\n }\n </span>\n }\n @default {\n @if (Type === 'checkbox') {\n <span class=\"mj-forms-field-value\">\n <div class=\"mj-forms-field-checkbox\">\n <input type=\"checkbox\" [checked]=\"!!Value\" disabled>\n </div>\n </span>\n }\n @else if (RichTextMode === 'markdown') {\n <div class=\"mj-forms-field-value mj-forms-field-value--rich\">\n <mj-markdown [data]=\"FormatValue()\"></mj-markdown>\n </div>\n }\n @else if (RichTextMode === 'html') {\n <!-- XSS: the mjSafeRichHtml pipe sanitizes with DOMPurify (HTML + SVG profiles)\n and then bypasses Angular's redundant re-sanitize. DOMPurify strips <script>,\n on* handlers, javascript:/data: URLs and <foreignObject> while KEEPING safe\n inline SVG + styles \u2014 richer than Angular's built-in sanitizer, still safe for\n untrusted content. -->\n <div class=\"mj-forms-field-value mj-forms-field-value--rich\" [innerHTML]=\"FormatValue() | mjSafeRichHtml\"></div>\n }\n @else if (RichTextMode === 'code') {\n <div class=\"mj-forms-field-value mj-forms-field-value--code\">\n <mj-code-editor [value]=\"FormatValue()\" [language]=\"CodeEditorLanguage\" [readonly]=\"true\"></mj-code-editor>\n </div>\n }\n @else if (IsLongText) {\n <span class=\"mj-forms-field-value mj-forms-field-value--long\">{{ FormatValue() }}</span>\n }\n @else {\n <span class=\"mj-forms-field-value\">{{ FormatValue() }}</span>\n }\n }\n }\n }\n </div>\n </div>\n }\n\n <!-- EDIT MODE -->\n @if (EditMode && !IsFieldReadOnly) {\n <div class=\"mj-forms-field mj-forms-field--editing\" [class.mj-forms-field--dirty]=\"IsDirty\" [class.mj-forms-field--required-empty]=\"IsRequiredEmpty\" [class.mj-forms-field--has-error]=\"ShowErrors\" [class.mj-forms-field--has-warning]=\"ShowWarnings\">\n @if (ShowLabel) {\n <label class=\"mj-forms-field-label\" [innerHTML]=\"HighlightedDisplayName\"></label>\n }\n <div class=\"mj-forms-field-control\">\n <!-- Foreign Key fields get custom search autocomplete -->\n @if (HasRelatedEntity) {\n <div class=\"mj-fk-search\"\n [class.mj-fk-search--matched]=\"FKHasLinkedValue\"\n [class.mj-fk-search--scoped]=\"FKFocused && FKSearchableFields.length > 1\">\n @if (FKHasLinkedValue && !(FKFocused && FKSearchableFields.length > 1)) {\n <i class=\"fa-solid fa-link mj-fk-link-icon\" title=\"Linked record\"></i>\n }\n <input type=\"text\"\n class=\"mj-forms-field-input\"\n [class.mj-forms-field-input--linked]=\"FKHasLinkedValue\"\n [value]=\"FKSearchText\"\n (input)=\"OnFKInput($event)\"\n (focus)=\"OnFKFocus($event)\"\n (blur)=\"OnFKBlur()\"\n (keydown)=\"OnFKKeydown($event)\"\n placeholder=\"Search...\">\n\n <!-- Scope pill: only while focused, only when there's more than one searchable field.\n The menu itself lives INSIDE the results dropdown (below) so it overlays the\n list and rides the same above/below flip. -->\n @if (FKFocused && FKSearchableFields.length > 1) {\n <button class=\"mj-fk-scope-pill\"\n [class.mj-fk-scope-pill--open]=\"FKShowScopeMenu\"\n (mousedown)=\"OnFKScopeToggle($event)\"\n [title]=\"'Searching ' + FKSearchFieldLabel + ' \u2014 click to change'\">\n <i class=\"fa-solid fa-magnifying-glass mj-fk-scope-pill-icon\"></i>\n <span class=\"mj-fk-scope-pill-label\">{{ FKSearchFieldLabel }}</span>\n <i class=\"fa-solid mj-fk-scope-pill-caret\" [class.fa-chevron-up]=\"FKShowScopeMenu\" [class.fa-chevron-down]=\"!FKShowScopeMenu\"></i>\n </button>\n }\n\n @if (FKSearchText) {\n <button class=\"mj-fk-clear\" (mousedown)=\"OnFKClearClick($event)\" title=\"Clear\">\n <i class=\"fa-solid fa-xmark\"></i>\n </button>\n } @else {\n <i class=\"fa-solid fa-magnifying-glass mj-fk-search-icon\"></i>\n }\n @if (ShowFKDropdown) {\n <div class=\"mj-fk-dropdown mj-fk-dropdown--multi\"\n [ngStyle]=\"DropdownPositionStyle\"\n [class.mj-fk-dropdown--above]=\"OpenAbove\"\n [class.mj-fk-dropdown--scope-open]=\"FKShowScopeMenu\">\n\n <!-- Scope (search-field) picker + column toggles \u2014 overlays the list, anchored to the pill edge.\n Click a row to SEARCH that field; click the eye to SHOW/HIDE it as a column. -->\n @if (FKShowScopeMenu) {\n <div class=\"mj-fk-scope-menu\" [class.mj-fk-scope-menu--bottom]=\"OpenAbove\">\n <div class=\"mj-fk-scope-grp\">Columns shown</div>\n @for (f of FKSearchableFields; track f.FieldName) {\n @if (f.Group === 'shown') {\n <ng-container *ngTemplateOutlet=\"scopeRow; context: { $implicit: f }\"></ng-container>\n }\n }\n @if (FKHasOtherSearchableFields) {\n <div class=\"mj-fk-scope-divider\"></div>\n <div class=\"mj-fk-scope-grp\">Other fields</div>\n @for (f of FKSearchableFields; track f.FieldName) {\n @if (f.Group === 'other') {\n <ng-container *ngTemplateOutlet=\"scopeRow; context: { $implicit: f }\"></ng-container>\n }\n }\n }\n </div>\n }\n\n <!-- Shared scope-menu row, fixed-slot layout for clean alignment:\n [reorder \u25B2\u25BC \u2014 hover-reveal] [icon] [label] [eye].\n Click the row = search this field; the active search row is shown bold+accent. -->\n <ng-template #scopeRow let-f>\n <div class=\"mj-fk-scope-mi\"\n [class.mj-fk-scope-mi--on]=\"IsFKScopeActive(f)\"\n (mousedown)=\"OnFKScopeSelect($event, f)\">\n <span class=\"mj-fk-col-reorder\">\n @if (f.Group === 'shown') {\n <button type=\"button\" class=\"mj-fk-col-move mj-fk-col-move--up\" [disabled]=\"!CanMoveFKColumnUp(f.FieldName)\"\n (mousedown)=\"MoveFKColumn($event, f.FieldName, -1)\" title=\"Move column up\">\n <i class=\"fa-solid fa-chevron-up\"></i>\n </button>\n <button type=\"button\" class=\"mj-fk-col-move mj-fk-col-move--down\" [disabled]=\"!CanMoveFKColumnDown(f.FieldName)\"\n (mousedown)=\"MoveFKColumn($event, f.FieldName, 1)\" title=\"Move column down\">\n <i class=\"fa-solid fa-chevron-down\"></i>\n </button>\n }\n </span>\n <i [class]=\"f.Icon + ' mj-fk-scope-mi-icon'\"></i>\n <span class=\"mj-fk-scope-mi-label\">{{ f.Label }}</span>\n <span class=\"mj-fk-col-eye-slot\">\n @if (CanToggleFKColumn(f)) {\n <button type=\"button\" class=\"mj-fk-col-toggle\"\n [class.mj-fk-col-toggle--on]=\"IsFKColumnVisible(f)\"\n (mousedown)=\"OnFKColumnToggle($event, f)\"\n [title]=\"IsFKColumnVisible(f) ? 'Hide this column' : 'Show as a column'\">\n <i class=\"fa-solid\" [class.fa-eye]=\"IsFKColumnVisible(f)\" [class.fa-eye-slash]=\"!IsFKColumnVisible(f)\"></i>\n </button>\n }\n </span>\n </div>\n </ng-template>\n\n <!-- Pinned \"currently selected\" \u2014 sticky at the top while browsing, so you can\n keep it or pick another without clearing first. -->\n @if (FKSelectedSuggestion && !FKLoading) {\n <div class=\"mj-fk-current\">\n <div class=\"mj-fk-current-head\">\n <i class=\"fa-solid fa-circle-check\"></i>\n <span>Currently selected</span>\n </div>\n <div class=\"mj-fk-current-row\" (mousedown)=\"OnFKSelectItem(FKSelectedSuggestion, $event)\" title=\"Keep this selection\">\n @if (FKSelectedSuggestion.Icon) { <i class=\"mj-fk-current-icon\" [class]=\"FKSelectedSuggestion.Icon\"></i> }\n <span class=\"mj-fk-current-name\" [innerHTML]=\"FKSelectedSuggestion.HighlightedName\"></span>\n @if (FKSelectedSuggestion.ExtraColumns.length && FKSelectedSuggestion.ExtraColumns[0].Value) {\n <span class=\"mj-fk-current-detail\">{{ FKSelectedSuggestion.ExtraColumns[0].Value }}</span>\n }\n <button type=\"button\" class=\"mj-fk-current-clear\" (mousedown)=\"OnFKClearClick($event)\" title=\"Clear selection\">\n <i class=\"fa-solid fa-xmark\"></i>\n </button>\n </div>\n </div>\n }\n\n @if (FKLoading) {\n <div class=\"mj-fk-status\">\n <i class=\"fa-solid fa-circle-notch fa-spin\"></i>\n <span>Searching\u2026</span>\n </div>\n }\n @if (!FKLoading && FKNoMatches) {\n <div class=\"mj-fk-status mj-fk-status--empty\">\n <i class=\"fa-solid fa-magnifying-glass\"></i>\n <span>No matches</span>\n </div>\n }\n @if (!FKLoading && FKSuggestions.length > 0) {\n <div class=\"mj-fk-options\">\n <div class=\"mj-fk-grid\" [style.grid-template-columns]=\"FKGridTemplateColumns\">\n <!-- Header row: click to sort, drag the right edge to resize.\n (Column reorder lives in the field-selector menu, not here.) -->\n <div class=\"mj-fk-grid-row mj-fk-grid-row--header\">\n @if (FKHasIconColumn) {\n <div class=\"mj-fk-hcell mj-fk-hcell--icon\"></div>\n }\n @for (col of FKColumnFields; track col; let i = $index) {\n <div class=\"mj-fk-hcell\"\n (mousedown)=\"OnFKHeaderSort($event, col)\"\n [title]=\"'Click to sort by ' + FKColumnHeaders[i]\">\n <span class=\"mj-fk-hcell-label\">{{ FKColumnHeaders[i] }}</span>\n <i [class]=\"FKSortIcon(col)\"></i>\n <span class=\"mj-fk-resizer\" (mousedown)=\"OnFKColResizeStart($event, col)\" title=\"Drag to resize\"></span>\n </div>\n }\n </div>\n <!-- Data rows -->\n @for (suggestion of FKSuggestions; track suggestion.PrimaryKeyValue; let i = $index) {\n <div class=\"mj-fk-grid-row\"\n [class.mj-fk-grid-row--active]=\"i === FKActiveIndex\"\n [class.mj-fk-grid-row--selected]=\"IsFKRowSelected(suggestion)\"\n (mousedown)=\"OnFKSelectItem(suggestion, $event)\"\n (mouseenter)=\"FKActiveIndex = i\">\n @if (FKHasIconColumn) {\n <div class=\"mj-fk-cell mj-fk-cell--icon\">\n @if (suggestion.Icon) { <i [class]=\"suggestion.Icon\"></i> }\n </div>\n }\n @for (col of FKColumnFields; track col; let last = $last) {\n @if (col === FKNameField) {\n <div class=\"mj-fk-cell mj-fk-cell--name\" [class.mj-fk-cell--fill]=\"FKColumnFillsTrack(col, last)\">\n @if (IsFKRowSelected(suggestion)) {\n <i class=\"fa-solid fa-check mj-fk-selected-check\" title=\"Currently selected\"></i>\n }\n <span [innerHTML]=\"suggestion.HighlightedName\"></span>\n </div>\n } @else {\n <div class=\"mj-fk-cell\" [class.mj-fk-cell--fill]=\"FKColumnFillsTrack(col, last)\" [title]=\"FKCellFor(suggestion, col)?.Value || ''\">\n <span [innerHTML]=\"FKCellFor(suggestion, col)?.HighlightedValue || ''\"></span>\n </div>\n }\n }\n </div>\n }\n </div>\n </div>\n }\n\n <!-- Sticky \"create new\" footer \u2014 always visible at the bottom (no scrolling),\n prefilled with the typed text. Gated on create permission. -->\n @if (CanCreateFK) {\n <button type=\"button\" class=\"mj-fk-create-footer\" (mousedown)=\"OnFKCreateNew($event)\" [title]=\"FKCreateLabel\">\n <i class=\"fa-solid fa-plus mj-fk-create-icon\"></i>\n <span class=\"mj-fk-create-label\">{{ FKCreateLabel }}</span>\n </button>\n }\n </div>\n }\n </div>\n }\n @else if (EditRichTextMode !== 'plain') {\n <!-- Markdown / HTML / Code long-text: edit raw with a syntax-highlighted code editor -->\n <mj-code-editor\n class=\"mj-forms-field-input--code\"\n [value]=\"FormatValue()\"\n [language]=\"CodeEditorLanguage\"\n (change)=\"OnCodeEditorChange($event)\"></mj-code-editor>\n }\n @else {\n @switch (Type) {\n @case ('textbox') {\n <input type=\"text\"\n class=\"mj-forms-field-input\"\n [value]=\"FormatValue()\"\n (input)=\"OnInputChange($event)\">\n }\n @case ('textarea') {\n <textarea\n class=\"mj-forms-field-input mj-forms-field-input--textarea\"\n [value]=\"FormatValue()\"\n (input)=\"OnInputChange($event)\"></textarea>\n }\n @case ('number') {\n <input type=\"number\"\n class=\"mj-forms-field-input mj-forms-field-input--number\"\n [value]=\"Value\"\n (change)=\"OnNumberChange($event)\">\n }\n @case ('datepicker') {\n <input type=\"date\"\n class=\"mj-forms-field-input mj-forms-field-input--date\"\n [value]=\"DateInputValue\"\n (change)=\"OnDateChange($event)\">\n }\n @case ('checkbox') {\n <div class=\"mj-forms-field-checkbox\">\n <input type=\"checkbox\"\n [checked]=\"!!Value\"\n (change)=\"OnCheckboxChange($event)\">\n </div>\n }\n @case ('select') {\n <div class=\"mj-custom-select-trigger\"\n tabindex=\"0\"\n (click)=\"OnSelectTriggerClick($event)\"\n (blur)=\"OnSelectTriggerBlur()\">\n <span class=\"mj-custom-select-value\" [class.mj-custom-select-value--placeholder]=\"!FormatValue()\">\n {{ FormatValue() || '-- Select --' }}\n </span>\n <i class=\"fa-solid fa-chevron-down mj-custom-select-chevron\" [class.mj-custom-select-chevron--open]=\"ShowSelectDropdown\"></i>\n </div>\n @if (ShowSelectDropdown && PossibleValues.length > 0) {\n <div class=\"mj-fk-dropdown\" [ngStyle]=\"DropdownPositionStyle\" [class.mj-fk-dropdown--above]=\"OpenAbove\">\n @for (option of PossibleValues; track option) {\n <div class=\"mj-fk-option\" [class.mj-fk-option--selected]=\"FormatValue() === option\" (mousedown)=\"OnSelectOptionClick(option, $event)\">\n {{ option }}\n </div>\n }\n </div>\n }\n }\n @case ('autocomplete') {\n <div class=\"mj-fk-search\">\n <input type=\"text\"\n class=\"mj-forms-field-input\"\n [value]=\"FormatValue()\"\n (input)=\"OnValueListInput($event)\"\n (focus)=\"OnValueListFocus($event)\"\n (blur)=\"OnValueListBlur()\"\n placeholder=\"Type to search...\">\n <i class=\"fa-solid fa-magnifying-glass mj-fk-search-icon\"></i>\n @if (ShowValueListDropdown && FilteredPossibleValues.length > 0) {\n <div class=\"mj-fk-dropdown\" [ngStyle]=\"DropdownPositionStyle\" [class.mj-fk-dropdown--above]=\"OpenAbove\">\n @for (option of FilteredPossibleValues; track option) {\n <div class=\"mj-fk-option\" (mousedown)=\"OnValueListSelect(option, $event)\">\n {{ option }}\n </div>\n }\n </div>\n }\n </div>\n }\n @default {\n <input type=\"text\"\n class=\"mj-forms-field-input\"\n [value]=\"FormatValue()\"\n (change)=\"OnInputChange($event)\">\n }\n }\n }\n </div>\n <!-- Inline validation messages -->\n @if (DisplayErrors.length > 0) {\n <div class=\"mj-forms-field-validation mj-forms-field-validation--error\">\n @for (error of DisplayErrors; track error.Message) {\n <div class=\"mj-forms-field-validation-item\">\n <i class=\"fa-solid fa-circle-exclamation\"></i>\n <span>{{ error.Message }}</span>\n </div>\n }\n </div>\n }\n @if (DisplayWarnings.length > 0) {\n <div class=\"mj-forms-field-validation mj-forms-field-validation--warning\">\n @for (warning of DisplayWarnings; track warning.Message) {\n <div class=\"mj-forms-field-validation-item\">\n <i class=\"fa-solid fa-triangle-exclamation\"></i>\n <span>{{ warning.Message }}</span>\n </div>\n }\n </div>\n }\n </div>\n }\n}\n", styles: ["/* ============================================\n FORM FIELD - Shared styles for read and edit\n ============================================ */\n:host {\n --mj-forms-field-label-width: 200px;\n --mj-forms-field-gap: 12px;\n\n display: contents;\n}\n\n.mj-forms-field {\n display: grid;\n grid-template-columns: var(--mj-forms-field-label-width) 1fr;\n gap: var(--mj-forms-field-gap);\n align-items: baseline;\n padding: 8px 0;\n transition: all var(--mj-transition-base) ease;\n}\n\n/* Subtle row hover in edit mode */\n.mj-forms-field--editing:hover {\n background: color-mix(in srgb, var(--mj-brand-primary) 8%, transparent);\n border-radius: 6px;\n margin: 0 -8px;\n padding: 8px 8px;\n}\n\n/* ============================================\n LABEL\n ============================================ */\n.mj-forms-field-label {\n font-size: 13px;\n font-weight: 600;\n color: var(--mj-text-secondary);\n padding-top: 2px;\n word-break: break-word;\n}\n\n/* ============================================\n FIELD CONTROL WRAPPER (value + dirty dot)\n ============================================ */\n.mj-forms-field-control {\n display: flex;\n align-items: center;\n gap: 8px;\n min-width: 0;\n}\n\n.mj-forms-field-control > * {\n flex: 1;\n min-width: 0;\n}\n\n/* ============================================\n DIRTY INDICATOR (solid amber dot after label)\n ============================================ */\n.mj-forms-field--dirty .mj-forms-field-label::after {\n content: '';\n display: inline-block;\n width: 6px;\n height: 6px;\n border-radius: 50%;\n background: var(--mj-status-warning);\n margin-left: 6px;\n vertical-align: middle;\n}\n\n/* ============================================\n REQUIRED FIELD - red underline when empty\n ============================================ */\n.mj-forms-field--required-empty .mj-forms-field-input {\n border-bottom-color: var(--mj-status-error);\n}\n\n.mj-forms-field--required-empty .mj-forms-field-input:focus {\n background: color-mix(in srgb, var(--mj-status-error) 5%, var(--mj-bg-surface));\n border-bottom-color: var(--mj-status-error);\n}\n\n.mj-forms-field--required-empty .mj-custom-select-trigger {\n border-bottom-color: var(--mj-status-error);\n}\n\n.mj-forms-field--required-empty .mj-fk-search .mj-forms-field-input {\n border-bottom-color: var(--mj-status-error);\n}\n\n/* ============================================\n READ-ONLY VALUE\n ============================================ */\n.mj-forms-field-value {\n font-size: 14px;\n color: var(--mj-text-primary);\n min-height: 24px;\n display: flex;\n align-items: center;\n overflow-wrap: break-word;\n word-break: break-word;\n}\n\n.mj-forms-field-value--long {\n white-space: pre-line;\n max-height: 300px;\n overflow: auto;\n}\n\n/* Rich (markdown / html) read-only rendering \u2014 let content flow as a block, not a flex row */\n.mj-forms-field-value--rich {\n display: block;\n align-items: initial;\n max-height: 480px;\n overflow: auto;\n width: 100%;\n}\n\n/* Code read-only / edit rendering \u2014 the embedded code editor needs an explicit height */\n.mj-forms-field-value--code {\n display: block;\n align-items: initial;\n width: 100%;\n}\n\n.mj-forms-field-value--code mj-code-editor,\n.mj-forms-field-input--code {\n display: block;\n width: 100%;\n min-height: 160px;\n max-height: 480px;\n border: 1px solid var(--mj-border-default);\n border-radius: var(--mj-radius, 4px);\n overflow: auto;\n}\n\n/* Read-only fields in edit mode */\n.mj-forms-field--readonly {\n opacity: 0.7;\n}\n\n.mj-forms-field--readonly .mj-forms-field-value {\n color: var(--mj-text-secondary);\n}\n\n/* ============================================\n LINKS (FK, email, URL)\n ============================================ */\n.mj-forms-field-link {\n display: inline-flex;\n align-items: center;\n gap: 6px;\n color: var(--mj-brand-primary);\n cursor: pointer;\n font-weight: 400;\n font-size: 14px;\n transition: color var(--mj-transition-base);\n text-decoration: none;\n}\n\n.mj-forms-field-link:hover {\n color: var(--mj-brand-primary-hover);\n}\n\n.mj-forms-field-link-icon {\n font-size: 11px;\n opacity: 0;\n transition: opacity var(--mj-transition-base);\n}\n\n.mj-forms-field-link:hover .mj-forms-field-link-icon {\n opacity: 1;\n}\n\n/* FK fields showing entity name instead of raw ID */\n.mj-forms-field-link--fk {\n font-size: 14px;\n font-weight: 400;\n}\n\n/* ============================================\n EDIT MODE INPUTS - Clean underline style\n ============================================ */\n.mj-forms-field-input {\n font-size: 14px;\n font-family: inherit;\n color: var(--mj-text-primary);\n background: transparent;\n border: none;\n border-bottom: 1.5px solid var(--mj-border-default);\n padding: 4px 0;\n width: 100%;\n outline: none;\n transition: border-color var(--mj-transition-base) ease,\n background var(--mj-transition-base) ease;\n}\n\n.mj-forms-field-input:focus {\n border-bottom-color: var(--mj-brand-primary);\n background: color-mix(in srgb, var(--mj-brand-primary) 8%, transparent);\n border-radius: 4px 4px 0 0;\n padding: 4px 6px;\n}\n\n.mj-forms-field-input::placeholder {\n color: var(--mj-text-muted);\n font-style: italic;\n}\n\n/* Textarea variant */\n.mj-forms-field-input--textarea {\n resize: vertical;\n min-height: 60px;\n border: 1.5px solid var(--mj-border-default);\n border-radius: 6px;\n padding: 8px 10px;\n background: var(--mj-bg-surface);\n font-family: inherit;\n}\n\n.mj-forms-field-input--textarea:focus {\n border-color: var(--mj-brand-primary);\n box-shadow: 0 0 0 3px color-mix(in srgb, var(--mj-brand-primary) 10%, transparent);\n background: var(--mj-bg-surface);\n padding: 8px 10px;\n border-radius: 6px;\n}\n\n/* Number input - narrower */\n.mj-forms-field-input--number {\n max-width: 200px;\n}\n\n/* Date input - narrower */\n.mj-forms-field-input--date {\n max-width: 220px;\n}\n\n/* ============================================\n CHECKBOX (custom styled)\n ============================================ */\n.mj-forms-field-checkbox {\n display: flex;\n align-items: center;\n gap: 8px;\n}\n\n.mj-forms-field-checkbox input[type=\"checkbox\"] {\n appearance: none;\n width: 18px;\n height: 18px;\n border: 2px solid var(--mj-border-default);\n border-radius: 4px;\n cursor: pointer;\n position: relative;\n transition: all var(--mj-transition-base) ease;\n flex-shrink: 0;\n}\n\n.mj-forms-field-checkbox input[type=\"checkbox\"]:checked {\n background: var(--mj-brand-primary);\n border-color: var(--mj-brand-primary);\n}\n\n.mj-forms-field-checkbox input[type=\"checkbox\"]:checked::after {\n content: '';\n position: absolute;\n left: 5px;\n top: 1px;\n width: 5px;\n height: 9px;\n border: solid var(--mj-text-inverse);\n border-width: 0 2px 2px 0;\n transform: rotate(45deg);\n}\n\n.mj-forms-field-checkbox input[type=\"checkbox\"]:disabled {\n opacity: 0.5;\n cursor: default;\n}\n\n/* ============================================\n CUSTOM SELECT DROPDOWN (replaces native <select>)\n ============================================ */\n.mj-custom-select-trigger {\n display: flex;\n align-items: center;\n justify-content: space-between;\n font-size: 14px;\n font-family: inherit;\n color: var(--mj-text-primary);\n background: transparent;\n border: none;\n border-bottom: 1.5px solid var(--mj-border-default);\n padding: 4px 0;\n width: 100%;\n cursor: pointer;\n outline: none;\n transition: border-color var(--mj-transition-base) ease,\n background var(--mj-transition-base) ease;\n}\n\n.mj-custom-select-trigger:focus {\n border-bottom-color: var(--mj-brand-primary);\n background: color-mix(in srgb, var(--mj-brand-primary) 8%, transparent);\n border-radius: 4px 4px 0 0;\n padding: 4px 6px;\n}\n\n.mj-custom-select-value {\n flex: 1;\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n\n.mj-custom-select-value--placeholder {\n color: var(--mj-text-muted);\n font-style: italic;\n}\n\n.mj-custom-select-chevron {\n font-size: 11px;\n color: var(--mj-text-muted);\n transition: transform var(--mj-transition-base) ease;\n flex-shrink: 0;\n margin-left: 8px;\n}\n\n.mj-custom-select-chevron--open {\n transform: rotate(180deg);\n}\n\n/* ============================================\n FK SEARCH (custom autocomplete)\n ============================================ */\n.mj-fk-search {\n position: relative;\n display: flex;\n align-items: center;\n width: 100%;\n}\n\n.mj-fk-search .mj-forms-field-input {\n padding-right: 28px;\n}\n\n.mj-fk-search-icon {\n position: absolute;\n right: 4px;\n color: var(--mj-text-muted);\n font-size: 12px;\n pointer-events: none;\n}\n\n.mj-fk-clear {\n position: absolute;\n right: 2px;\n background: none;\n border: none;\n color: var(--mj-text-muted);\n cursor: pointer;\n font-size: 11px;\n padding: 4px 6px;\n line-height: 1;\n border-radius: 3px;\n transition: all var(--mj-transition-base);\n}\n\n.mj-fk-clear:hover {\n color: var(--mj-status-error);\n background: color-mix(in srgb, var(--mj-status-error) 8%, transparent);\n}\n\n/* Linked state: solid accent underline + a leading chain icon, so it's obvious the\n field holds a resolved record reference rather than free-typed text. */\n.mj-fk-search--matched .mj-forms-field-input {\n border-bottom: 2px solid var(--mj-brand-primary);\n}\n\n/* Linked indicator sits on the RIGHT (just left of the clear button) so it never\n interrupts left-to-right reading of the value or overlaps the text. */\n.mj-fk-link-icon {\n position: absolute;\n right: 26px;\n color: var(--mj-brand-primary);\n font-size: 10px;\n pointer-events: none;\n z-index: 1;\n}\n\n/* Make room on the right for the link icon + the clear button. */\n.mj-forms-field-input--linked {\n padding-right: 46px;\n}\n\n/* ============================================\n SCOPE PILL + FIELD-PICKER MENU (search-field scope)\n ============================================ */\n/* When the pill is showing, reserve room on the right of the input for it. */\n.mj-fk-search--scoped .mj-forms-field-input {\n padding-right: 150px;\n}\n\n.mj-fk-scope-pill {\n position: absolute;\n right: 30px;\n /* Vertically centered in the input so it clears the focus underline below. */\n top: 50%;\n transform: translateY(-50%);\n display: inline-flex;\n align-items: center;\n gap: 5px;\n max-width: 120px;\n background: var(--mj-bg-surface-elevated);\n border: 1px solid var(--mj-border-strong);\n color: var(--mj-text-secondary);\n font-size: 10.5px;\n font-weight: 600;\n font-family: inherit;\n /* Kept short so it clears the input's focus underline without making the row taller. */\n padding: 1px 7px;\n border-radius: 999px;\n cursor: pointer;\n white-space: nowrap;\n line-height: 1.35;\n transition: background var(--mj-transition-base), border-color var(--mj-transition-base), color var(--mj-transition-base);\n}\n\n.mj-fk-scope-pill:hover,\n.mj-fk-scope-pill--open {\n border-color: var(--mj-brand-primary);\n color: var(--mj-text-primary);\n}\n\n.mj-fk-scope-pill-icon {\n font-size: 9px;\n opacity: 0.7;\n flex-shrink: 0;\n}\n\n.mj-fk-scope-pill-label {\n overflow: hidden;\n text-overflow: ellipsis;\n}\n\n.mj-fk-scope-pill-caret {\n font-size: 8px;\n opacity: 0.7;\n flex-shrink: 0;\n}\n\n/* The menu is rendered INSIDE the results dropdown panel so it overlays the list\n (correct z-order, no extra real estate) and rides the dropdown's above/below\n flip. Anchored to the dropdown's top-right \u2014 right under the pill. */\n.mj-fk-scope-menu {\n position: absolute;\n top: 4px;\n right: 8px;\n z-index: 5;\n min-width: 180px;\n max-width: calc(100vw - 24px);\n max-height: 260px;\n overflow-y: auto;\n background: var(--mj-bg-surface-elevated);\n border: 1px solid var(--mj-border-strong);\n border-radius: var(--mj-radius-sm);\n box-shadow: var(--mj-shadow-lg);\n padding: 5px;\n animation: mj-dropdown-in 120ms ease;\n}\n\n/* When the dropdown opens ABOVE the input, anchor the menu to its bottom edge so it\n stays next to the pill (which is at the input/dropdown boundary). */\n.mj-fk-scope-menu--bottom {\n top: auto;\n bottom: 4px;\n}\n\n.mj-fk-scope-grp {\n font-size: 10px;\n text-transform: uppercase;\n letter-spacing: 0.06em;\n color: var(--mj-text-muted);\n padding: 7px 10px 4px;\n font-weight: 700;\n}\n\n.mj-fk-scope-mi {\n display: flex;\n align-items: center;\n gap: 9px;\n padding: 7px 10px;\n font-size: 13px;\n border-radius: 5px;\n color: var(--mj-text-secondary);\n cursor: pointer;\n}\n\n.mj-fk-scope-mi:hover {\n background: var(--mj-bg-surface-hover);\n}\n\n.mj-fk-scope-mi--on {\n color: var(--mj-brand-primary);\n font-weight: 600;\n}\n\n/* Fixed-width LEFT slot: a compact stacked up/down reorder control that reveals on row\n hover. Reserved (same width) on every row so the field icons + labels stay aligned. */\n.mj-fk-col-reorder {\n display: flex;\n flex-direction: column;\n align-items: center;\n justify-content: center;\n width: 14px;\n height: 22px;\n flex-shrink: 0;\n}\n\n.mj-fk-col-move {\n display: flex;\n align-items: center;\n justify-content: center;\n width: 14px;\n height: 10px;\n padding: 0;\n background: transparent;\n border: none;\n color: var(--mj-text-muted);\n cursor: pointer;\n font-size: 8px;\n opacity: 0; /* hover-reveal for a clean resting state */\n transition: opacity var(--mj-transition-base), color var(--mj-transition-base);\n}\n\n.mj-fk-scope-mi:hover .mj-fk-col-move:not(:disabled) {\n opacity: 0.8;\n}\n\n.mj-fk-col-move:hover:not(:disabled) {\n opacity: 1;\n color: var(--mj-brand-primary);\n}\n\n/* End-of-range arrows stay hidden (slot still reserved) rather than greyed. */\n.mj-fk-col-move:disabled {\n opacity: 0 !important;\n cursor: default;\n}\n\n.mj-fk-scope-mi-icon {\n width: 14px;\n font-size: 11px;\n opacity: 0.75;\n flex-shrink: 0;\n}\n\n.mj-fk-scope-mi-label {\n flex: 1;\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n\n/* Fixed-width RIGHT slot so the eye (or its empty space, for the name row) aligns. */\n.mj-fk-col-eye-slot {\n width: 22px;\n height: 22px;\n flex-shrink: 0;\n display: flex;\n align-items: center;\n justify-content: center;\n}\n\n/* Eye toggle: show/hide a field as a grid column (independent of search scope). */\n.mj-fk-col-toggle {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n width: 22px;\n height: 22px;\n background: transparent;\n border: none;\n border-radius: 4px;\n color: var(--mj-text-muted);\n cursor: pointer;\n font-size: 12px;\n transition: background var(--mj-transition-base), color var(--mj-transition-base);\n}\n\n.mj-fk-col-toggle:hover {\n background: var(--mj-bg-surface-hover);\n color: var(--mj-text-secondary);\n}\n\n.mj-fk-col-toggle--on {\n color: var(--mj-brand-primary);\n}\n\n.mj-fk-scope-divider {\n height: 1px;\n background: var(--mj-border-subtle);\n margin: 4px 6px;\n}\n\n/* Narrow / mobile screens: shrink the pill + its reserved space, give menu rows a\n larger touch target, and keep the menu within the viewport. */\n@media (max-width: 560px) {\n .mj-fk-search--scoped .mj-forms-field-input {\n padding-right: 116px;\n }\n .mj-fk-scope-pill {\n max-width: 88px;\n }\n .mj-fk-scope-menu {\n min-width: 160px;\n }\n .mj-fk-scope-mi {\n padding: 10px 10px;\n }\n}\n\n/* ============================================\n FLOATING DROPDOWN PANEL (position: fixed via ngStyle)\n ============================================ */\n.mj-fk-dropdown {\n background: var(--mj-bg-surface-card);\n border: 1px solid var(--mj-border-default);\n border-radius: var(--mj-radius-md);\n box-shadow: var(--mj-shadow-lg);\n max-height: 240px;\n overflow-y: auto;\n padding: 4px;\n animation: mj-dropdown-in 150ms ease;\n}\n\n.mj-fk-dropdown--above {\n animation: mj-dropdown-in-above 150ms ease;\n}\n\n.mj-fk-option {\n padding: 10px 14px;\n font-size: 14px;\n color: var(--mj-text-primary);\n cursor: pointer;\n transition: background var(--mj-transition-base);\n border-radius: 6px;\n}\n\n.mj-fk-option:hover {\n background: color-mix(in srgb, var(--mj-brand-primary) 8%, transparent);\n}\n\n.mj-fk-option--selected {\n background: color-mix(in srgb, var(--mj-brand-primary) 8%, transparent);\n font-weight: 600;\n color: var(--mj-brand-primary);\n}\n\n.mj-fk-option--selected:hover {\n background: color-mix(in srgb, var(--mj-brand-primary) 15%, transparent);\n}\n\n/* ============================================\n MULTI-COLUMN FK DROPDOWN \u2014 aligned mini-grid (icon + name + extra cols)\n with sortable headers and horizontal scroll.\n ============================================ */\n.mj-fk-dropdown--multi {\n padding: 4px;\n /* The inner .mj-fk-options is the single scroll container (both axes) so the\n sticky header anchors correctly; the dropdown just clips to its rounded border. */\n overflow: hidden;\n max-height: none;\n}\n\n/* Single scroll region (both axes) for the grid: vertical for long lists, horizontal\n when many DefaultInView columns make rows wider than the dropdown. Being the sole\n scroller lets the sticky column headers anchor to its top edge. */\n.mj-fk-dropdown--multi .mj-fk-options {\n overflow: auto;\n max-height: 260px;\n}\n\n/* While the scope menu is open it must escape the panel's clip (the inner\n .mj-fk-options keeps its own scroll, so the grid still behaves). */\n.mj-fk-dropdown--scope-open {\n overflow: visible;\n}\n\n/* One CSS grid spans the header + all data rows so every column lines up.\n grid-template-columns is supplied inline from FKGridTemplateColumns.\n `width: 100%` (with `min-width: max-content`) lets the last column's `1fr` track\n absorb leftover width, while still overflowing \u2192 horizontal scroll when the columns\n are collectively wider than the dropdown. */\n.mj-fk-grid {\n display: grid;\n width: 100%;\n min-width: max-content;\n align-items: stretch;\n}\n\n/* Rows are layout-transparent so their cells become direct grid items (this is\n what makes columns align across rows). The row element still exists for click\n handling and for the active-state selector below. */\n.mj-fk-grid-row {\n display: contents;\n}\n\n/* Header cells: sticky to the top of the vertical scroll, clickable to sort. */\n.mj-fk-hcell {\n position: sticky;\n top: 0;\n z-index: 1;\n display: flex;\n align-items: center;\n gap: 6px;\n padding: 7px 12px;\n font-size: 12px;\n font-weight: 600;\n text-transform: uppercase;\n letter-spacing: 0.03em;\n color: var(--mj-text-muted);\n background: var(--mj-bg-surface-elevated);\n border-bottom: 1px solid var(--mj-border-default);\n cursor: pointer;\n user-select: none;\n white-space: nowrap;\n}\n\n.mj-fk-hcell:hover {\n color: var(--mj-text-secondary);\n background: var(--mj-bg-surface-hover);\n}\n\n.mj-fk-hcell--icon {\n cursor: default;\n padding: 7px 8px;\n}\n\n.mj-fk-hcell--icon:hover {\n background: var(--mj-bg-surface-elevated);\n}\n\n.mj-fk-hcell-label {\n overflow: hidden;\n text-overflow: ellipsis;\n}\n\n.mj-fk-sort-icon {\n font-size: 11px;\n flex-shrink: 0;\n}\n\n/* Idle (unsorted) columns show a faded sort glyph to signal sortability. */\n.mj-fk-sort-icon--idle {\n opacity: 0.35;\n}\n\n/* Data cells */\n.mj-fk-cell {\n display: flex;\n align-items: center;\n padding: 8px 12px;\n font-size: 13px;\n color: var(--mj-text-secondary);\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n max-width: 320px;\n cursor: pointer;\n}\n\n/* The fill column (last, or a user-resized one) drops the default content cap so its\n cells stretch to the full track width that the header already occupies. */\n.mj-fk-cell--fill {\n max-width: none;\n}\n\n/* Wrapping span keeps the highlighted text+<mark> as one inline run (so flex\n doesn't strip the space next to the mark) while still truncating with ellipsis. */\n.mj-fk-cell > span {\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n min-width: 0;\n}\n\n.mj-fk-cell--icon {\n justify-content: center;\n padding: 8px;\n max-width: none;\n color: var(--mj-text-muted);\n font-size: 13px;\n}\n\n.mj-fk-cell--name {\n font-weight: 500;\n font-size: 14px;\n color: var(--mj-text-primary);\n gap: 6px;\n}\n\n.mj-fk-selected-check {\n color: var(--mj-brand-primary);\n font-size: 11px;\n flex-shrink: 0;\n}\n\n/* Active (keyboard / hover) row \u2014 painted on the cells, since the row box is\n removed by display:contents. The child combinator still matches. */\n.mj-fk-grid-row--active > .mj-fk-cell {\n background: color-mix(in srgb, var(--mj-brand-primary) 12%, transparent);\n}\n\n/* Currently-linked row \u2014 a subtle persistent tint so the user sees which record\n is selected when they reopen the list (stacks under the brighter active tint). */\n.mj-fk-grid-row--selected > .mj-fk-cell {\n background: color-mix(in srgb, var(--mj-brand-primary) 6%, transparent);\n}\n\n.mj-fk-grid-row--selected > .mj-fk-cell--name {\n font-weight: 600;\n color: var(--mj-brand-primary);\n}\n\n/* Matched-substring highlight inside the name column */\n/* ::ng-deep (not :global, which Angular's emulated encapsulation ignores) so the\n style reaches the <mark> injected via [innerHTML]. Color comes from the shared\n theme token so light/dark/white-label all control it centrally. */\n.mj-fk-cell--name ::ng-deep .mj-forms-search-highlight,\n.mj-fk-cell ::ng-deep .mj-forms-search-highlight {\n background-color: var(--mj-search-highlight-bg);\n color: var(--mj-search-highlight-text);\n border-radius: 2px;\n padding: 0 1px;\n font-weight: 600;\n}\n\n/* Column resize handle \u2014 thin grab strip on the right edge of each header cell. */\n.mj-fk-resizer {\n position: absolute;\n top: 0;\n right: 0;\n width: 7px;\n height: 100%;\n cursor: col-resize;\n user-select: none;\n}\n\n.mj-fk-resizer::after {\n content: '';\n position: absolute;\n top: 20%;\n right: 2px;\n width: 2px;\n height: 60%;\n background: transparent;\n transition: background var(--mj-transition-base);\n}\n\n.mj-fk-hcell:hover .mj-fk-resizer::after,\n.mj-fk-resizer:hover::after {\n background: var(--mj-border-strong);\n}\n\n/* Loading / empty status rows */\n.mj-fk-status {\n display: flex;\n align-items: center;\n gap: 8px;\n padding: 10px 14px;\n font-size: 13px;\n color: var(--mj-text-muted);\n}\n\n.mj-fk-status i {\n font-size: 12px;\n}\n\n.mj-fk-status--empty {\n font-style: italic;\n}\n\n/* Sticky \"create new\" footer \u2014 sits below the (scrolling) options as a direct child of\n the dropdown panel, so it's always visible regardless of list length. */\n.mj-fk-create-footer {\n display: flex;\n align-items: center;\n gap: 9px;\n width: 100%;\n padding: 10px 14px;\n background: var(--mj-bg-surface-card);\n border: none;\n border-top: 1px solid var(--mj-border-default);\n color: var(--mj-brand-primary);\n font-size: 13px;\n font-weight: 600;\n font-family: inherit;\n text-align: left;\n cursor: pointer;\n transition: background var(--mj-transition-base);\n}\n\n.mj-fk-create-footer:hover {\n background: var(--mj-bg-surface-hover);\n}\n\n.mj-fk-create-icon {\n font-size: 11px;\n flex-shrink: 0;\n}\n\n.mj-fk-create-label {\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n\n/* ============================================\n PINNED \"CURRENTLY SELECTED\" SECTION\n ============================================ */\n.mj-fk-current {\n border-bottom: 1px solid var(--mj-border-default);\n background: color-mix(in srgb, var(--mj-brand-primary) 7%, var(--mj-bg-surface-card));\n animation: mj-fk-current-in 220ms cubic-bezier(0.22, 1, 0.36, 1);\n}\n\n@keyframes mj-fk-current-in {\n from { opacity: 0; transform: translateY(-6px); }\n to { opacity: 1; transform: translateY(0); }\n}\n\n.mj-fk-current-head {\n display: flex;\n align-items: center;\n gap: 6px;\n padding: 8px 12px 3px;\n font-size: 10px;\n font-weight: 700;\n text-transform: uppercase;\n letter-spacing: 0.06em;\n color: var(--mj-brand-primary);\n}\n\n.mj-fk-current-head i {\n font-size: 10px;\n}\n\n.mj-fk-current-row {\n position: relative;\n display: flex;\n align-items: center;\n gap: 9px;\n padding: 6px 12px 10px;\n cursor: pointer;\n transition: background var(--mj-transition-base);\n}\n\n/* Accent bar on the left for a bit of sizzle. */\n.mj-fk-current-row::before {\n content: '';\n position: absolute;\n left: 0;\n top: 4px;\n bottom: 8px;\n width: 3px;\n border-radius: 0 2px 2px 0;\n background: var(--mj-brand-primary);\n}\n\n.mj-fk-current-row:hover {\n background: color-mix(in srgb, var(--mj-brand-primary) 10%, transparent);\n}\n\n.mj-fk-current-icon {\n flex-shrink: 0;\n font-size: 13px;\n color: var(--mj-text-muted);\n}\n\n.mj-fk-current-name {\n font-weight: 600;\n font-size: 14px;\n color: var(--mj-text-primary);\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n}\n\n.mj-fk-current-detail {\n font-size: 13px;\n color: var(--mj-text-muted);\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n}\n\n.mj-fk-current-clear {\n margin-left: auto;\n display: inline-flex;\n align-items: center;\n justify-content: center;\n width: 22px;\n height: 22px;\n flex-shrink: 0;\n background: transparent;\n border: none;\n border-radius: 4px;\n color: var(--mj-text-muted);\n cursor: pointer;\n font-size: 12px;\n transition: background var(--mj-transition-base), color var(--mj-transition-base);\n}\n\n.mj-fk-current-clear:hover {\n background: var(--mj-bg-surface-hover);\n color: var(--mj-status-error);\n}\n\n@keyframes mj-dropdown-in {\n from { opacity: 0; transform: translateY(-4px); }\n to { opacity: 1; transform: translateY(0); }\n}\n\n@keyframes mj-dropdown-in-above {\n from { opacity: 0; transform: translateY(4px); }\n to { opacity: 1; transform: translateY(0); }\n}\n\n/* ============================================\n SEARCH HIGHLIGHTING\n ============================================ */\n.mj-forms-field-label ::ng-deep .mj-forms-search-highlight {\n /* Shared search-highlight theme token. ::ng-deep (not :global) so it reaches\n innerHTML content. */\n background-color: var(--mj-search-highlight-bg);\n color: var(--mj-search-highlight-text);\n border-radius: 2px;\n padding: 0 1px;\n font-weight: 600;\n}\n\n/* ============================================\n VALIDATION ERROR STATE\n ============================================ */\n.mj-forms-field--has-error .mj-forms-field-input {\n border-bottom-color: var(--mj-status-error);\n border-bottom-width: 2px;\n}\n\n.mj-forms-field--has-error .mj-forms-field-input:focus {\n background: color-mix(in srgb, var(--mj-status-error) 5%, var(--mj-bg-surface));\n border-bottom-color: var(--mj-status-error);\n}\n\n.mj-forms-field--has-error .mj-forms-field-input--textarea {\n border-color: var(--mj-status-error);\n}\n\n.mj-forms-field--has-error .mj-forms-field-input--textarea:focus {\n border-color: var(--mj-status-error);\n box-shadow: 0 0 0 3px color-mix(in srgb, var(--mj-status-error) 8%, transparent);\n}\n\n.mj-forms-field--has-error .mj-custom-select-trigger {\n border-bottom-color: var(--mj-status-error);\n border-bottom-width: 2px;\n}\n\n.mj-forms-field--has-error .mj-fk-search .mj-forms-field-input {\n border-bottom-color: var(--mj-status-error);\n border-bottom-width: 2px;\n}\n\n/* ============================================\n VALIDATION WARNING STATE\n ============================================ */\n.mj-forms-field--has-warning .mj-forms-field-input {\n border-bottom-color: var(--mj-status-warning);\n border-bottom-width: 2px;\n}\n\n.mj-forms-field--has-warning .mj-forms-field-input:focus {\n background: color-mix(in srgb, var(--mj-status-warning) 5%, var(--mj-bg-surface));\n border-bottom-color: var(--mj-status-warning);\n}\n\n.mj-forms-field--has-warning .mj-forms-field-input--textarea {\n border-color: var(--mj-status-warning);\n}\n\n.mj-forms-field--has-warning .mj-forms-field-input--textarea:focus {\n border-color: var(--mj-status-warning);\n box-shadow: 0 0 0 3px color-mix(in srgb, var(--mj-status-warning) 8%, transparent);\n}\n\n.mj-forms-field--has-warning .mj-custom-select-trigger {\n border-bottom-color: var(--mj-status-warning);\n border-bottom-width: 2px;\n}\n\n.mj-forms-field--has-warning .mj-fk-search .mj-forms-field-input {\n border-bottom-color: var(--mj-status-warning);\n border-bottom-width: 2px;\n}\n\n/* ============================================\n VALIDATION MESSAGE AREA\n ============================================ */\n.mj-forms-field-validation {\n grid-column: 2;\n display: flex;\n flex-direction: column;\n gap: 2px;\n margin-top: -2px;\n overflow: hidden;\n animation: mj-validation-slide-in 200ms ease-out;\n}\n\n.mj-forms-field-validation-item {\n display: flex;\n align-items: flex-start;\n gap: 6px;\n font-size: 12px;\n line-height: 1.4;\n padding: 3px 0 1px;\n}\n\n.mj-forms-field-validation-item i {\n font-size: 11px;\n margin-top: 2px;\n flex-shrink: 0;\n}\n\n/* Error message colors */\n.mj-forms-field-validation--error .mj-forms-field-validation-item {\n color: var(--mj-status-error);\n}\n\n.mj-forms-field-validation--error .mj-forms-field-validation-item i {\n color: var(--mj-status-error);\n}\n\n/* Warning message colors */\n.mj-forms-field-validation--warning .mj-forms-field-validation-item {\n color: var(--mj-status-warning-text);\n}\n\n.mj-forms-field-validation--warning .mj-forms-field-validation-item i {\n color: var(--mj-status-warning);\n}\n\n@keyframes mj-validation-slide-in {\n from {\n opacity: 0;\n max-height: 0;\n transform: translateY(-4px);\n }\n to {\n opacity: 1;\n max-height: 100px;\n transform: translateY(0);\n }\n}\n\n/* ============================================\n RESPONSIVE\n ============================================ */\n@media (max-width: 640px) {\n .mj-forms-field {\n grid-template-columns: 1fr;\n gap: 4px;\n }\n\n .mj-forms-field-label {\n font-size: 12px;\n }\n\n .mj-forms-field-validation {\n grid-column: 1;\n }\n}\n"] }]
1176
2600
  }], null, { Record: [{
1177
2601
  type: Input
1178
2602
  }], EditMode: [{
@@ -1203,6 +2627,14 @@ export class MjFormFieldComponent extends BaseAngularComponent {
1203
2627
  type: Output
1204
2628
  }], Navigate: [{
1205
2629
  type: Output
2630
+ }], FKDropdownMaxWidth: [{
2631
+ type: Input
2632
+ }], FKHighlightMatches: [{
2633
+ type: Input
2634
+ }], AllowFKCreate: [{
2635
+ type: Input
2636
+ }], FKCreatePresentation: [{
2637
+ type: Input
1206
2638
  }] }); })();
1207
- (() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassDebugInfo(MjFormFieldComponent, { className: "MjFormFieldComponent", filePath: "src/lib/field/form-field.component.ts", lineNumber: 50 }); })();
2639
+ (() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassDebugInfo(MjFormFieldComponent, { className: "MjFormFieldComponent", filePath: "src/lib/field/form-field.component.ts", lineNumber: 136 }); })();
1208
2640
  //# sourceMappingURL=form-field.component.js.map