@memberjunction/ng-ui-components 5.35.0 → 5.36.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 (34) hide show
  1. package/dist/lib/button/button.scss +7 -3
  2. package/dist/lib/filter-popover/filter-popover.component.d.ts.map +1 -1
  3. package/dist/lib/filter-popover/filter-popover.component.js +3 -3
  4. package/dist/lib/filter-popover/filter-popover.component.js.map +1 -1
  5. package/dist/lib/left-nav/left-nav-content.component.d.ts +53 -0
  6. package/dist/lib/left-nav/left-nav-content.component.d.ts.map +1 -0
  7. package/dist/lib/left-nav/left-nav-content.component.js +121 -0
  8. package/dist/lib/left-nav/left-nav-content.component.js.map +1 -0
  9. package/dist/lib/left-nav/left-nav.component.d.ts +137 -0
  10. package/dist/lib/left-nav/left-nav.component.d.ts.map +1 -0
  11. package/dist/lib/left-nav/left-nav.component.js +399 -0
  12. package/dist/lib/left-nav/left-nav.component.js.map +1 -0
  13. package/dist/lib/page-body/page-body.component.d.ts +12 -2
  14. package/dist/lib/page-body/page-body.component.d.ts.map +1 -1
  15. package/dist/lib/page-body/page-body.component.js +24 -7
  16. package/dist/lib/page-body/page-body.component.js.map +1 -1
  17. package/dist/lib/page-body-interior/page-body-interior.component.d.ts +62 -0
  18. package/dist/lib/page-body-interior/page-body-interior.component.d.ts.map +1 -0
  19. package/dist/lib/page-body-interior/page-body-interior.component.js +95 -0
  20. package/dist/lib/page-body-interior/page-body-interior.component.js.map +1 -0
  21. package/dist/lib/page-header/page-header.component.d.ts +12 -4
  22. package/dist/lib/page-header/page-header.component.d.ts.map +1 -1
  23. package/dist/lib/page-header/page-header.component.js +33 -28
  24. package/dist/lib/page-header/page-header.component.js.map +1 -1
  25. package/dist/lib/page-header/page-header.scss +30 -9
  26. package/dist/lib/page-header-interior/page-header-interior.component.d.ts +96 -0
  27. package/dist/lib/page-header-interior/page-header-interior.component.d.ts.map +1 -0
  28. package/dist/lib/page-header-interior/page-header-interior.component.js +176 -0
  29. package/dist/lib/page-header-interior/page-header-interior.component.js.map +1 -0
  30. package/dist/public-api.d.ts +4 -0
  31. package/dist/public-api.d.ts.map +1 -1
  32. package/dist/public-api.js +4 -0
  33. package/dist/public-api.js.map +1 -1
  34. package/package.json +1 -1
@@ -84,17 +84,21 @@
84
84
  }
85
85
 
86
86
  .mj-btn--secondary {
87
- background: var(--mj-bg-surface);
87
+ /* Tinted background so the button is visible on white surfaces (cards, page
88
+ headers, dialogs). Pre-2026-05-19 secondary used `--mj-bg-surface` which
89
+ blended into any white container; --mj-bg-surface-sunken gives just enough
90
+ contrast to read as a button on both white and sunken backgrounds. */
91
+ background: var(--mj-bg-surface-sunken);
88
92
  color: var(--mj-text-primary);
89
93
  border-color: var(--mj-border-default);
90
94
 
91
95
  &:hover:not(:disabled) {
92
- background: var(--mj-bg-surface-hover);
96
+ background: var(--mj-bg-surface-active);
93
97
  border-color: var(--mj-border-strong);
94
98
  }
95
99
 
96
100
  &:active:not(:disabled) {
97
- background: var(--mj-bg-surface-active);
101
+ background: color-mix(in srgb, var(--mj-text-primary) 8%, var(--mj-bg-surface-active));
98
102
  }
99
103
  }
100
104
 
@@ -1 +1 @@
1
- {"version":3,"file":"filter-popover.component.d.ts","sourceRoot":"","sources":["../../../src/lib/filter-popover/filter-popover.component.ts"],"names":[],"mappings":"AAAA,OAAO,EAAa,YAAY,EAAiB,MAAM,eAAe,CAAC;AACvE,OAAO,EAAiB,iBAAiB,EAAE,MAAM,sBAAsB,CAAC;;AAExE;;;;;;;;;;;;;;;;;GAiBG;AACH,qBAoKa,wBAAwB;IAC1B,KAAK,EAAE,MAAM,CAAa;IAC1B,IAAI,EAAE,MAAM,CAAwB;IACpC,WAAW,EAAE,MAAM,CAAK;IACxB,YAAY,EAAE,OAAO,CAAS;IAEhC,MAAM,EAAE,OAAO,CAAS;IAM/B,SAAgB,SAAS,EAAE,iBAAiB,EAAE,CAI5C;IAEK,MAAM,IAAI,IAAI;IACd,IAAI,IAAI,IAAI;IACZ,KAAK,IAAI,IAAI;IAEpB,mFAAmF;IAClE,iBAAiB,qBAA4B;IAEvD,QAAQ,IAAI,IAAI;yCAzBZ,wBAAwB;2CAAxB,wBAAwB;CA4BpC"}
1
+ {"version":3,"file":"filter-popover.component.d.ts","sourceRoot":"","sources":["../../../src/lib/filter-popover/filter-popover.component.ts"],"names":[],"mappings":"AAAA,OAAO,EAAa,YAAY,EAAiB,MAAM,eAAe,CAAC;AACvE,OAAO,EAAiB,iBAAiB,EAAE,MAAM,sBAAsB,CAAC;;AAExE;;;;;;;;;;;;;;;;;GAiBG;AACH,qBAuKa,wBAAwB;IAC1B,KAAK,EAAE,MAAM,CAAa;IAC1B,IAAI,EAAE,MAAM,CAAwB;IACpC,WAAW,EAAE,MAAM,CAAK;IACxB,YAAY,EAAE,OAAO,CAAS;IAEhC,MAAM,EAAE,OAAO,CAAS;IAM/B,SAAgB,SAAS,EAAE,iBAAiB,EAAE,CAI5C;IAEK,MAAM,IAAI,IAAI;IACd,IAAI,IAAI,IAAI;IACZ,KAAK,IAAI,IAAI;IAEpB,mFAAmF;IAClE,iBAAiB,qBAA4B;IAEvD,QAAQ,IAAI,IAAI;yCAzBZ,wBAAwB;2CAAxB,wBAAwB;CA4BpC"}
@@ -107,7 +107,7 @@ export class MJFilterPopoverComponent {
107
107
  i0.ɵɵclassProp("mj-filter-popover-chevron--open", ctx.IsOpen);
108
108
  i0.ɵɵadvance();
109
109
  i0.ɵɵproperty("cdkConnectedOverlayOrigin", overlayOrigin_r4)("cdkConnectedOverlayOpen", ctx.IsOpen)("cdkConnectedOverlayPositions", ctx.Positions)("cdkConnectedOverlayHasBackdrop", true);
110
- } }, dependencies: [OverlayModule, i1.CdkConnectedOverlay, i1.CdkOverlayOrigin], styles: ["[_nghost-%COMP%] {\n display: inline-flex;\n }\n\n .mj-filter-popover-trigger[_ngcontent-%COMP%] {\n display: inline-flex;\n align-items: center;\n gap: var(--mj-space-2);\n padding: var(--mj-space-2) var(--mj-space-3-5);\n background: var(--mj-bg-surface-card);\n border: 1px solid var(--mj-border-default);\n border-radius: var(--mj-radius-md);\n color: var(--mj-text-secondary);\n font-family: inherit;\n font-size: 13px;\n font-weight: 500;\n line-height: 1.2;\n cursor: pointer;\n transition: background-color 0.2s ease, border-color 0.2s ease, color 0.2s ease;\n white-space: nowrap;\n }\n\n .mj-filter-popover-trigger[_ngcontent-%COMP%]:hover {\n background: var(--mj-bg-surface-sunken);\n border-color: var(--mj-border-strong);\n color: var(--mj-text-primary);\n }\n\n .mj-filter-popover-trigger--active[_ngcontent-%COMP%] {\n background: color-mix(in srgb, var(--mj-brand-primary) 10%, var(--mj-bg-surface));\n border-color: color-mix(in srgb, var(--mj-brand-primary) 30%, var(--mj-border-default));\n color: var(--mj-brand-primary);\n }\n\n .mj-filter-popover-trigger--active[_ngcontent-%COMP%]:hover {\n background: color-mix(in srgb, var(--mj-brand-primary) 14%, var(--mj-bg-surface));\n }\n\n .mj-filter-popover-trigger[_ngcontent-%COMP%] > i[_ngcontent-%COMP%]:first-child {\n font-size: var(--mj-text-xs);\n color: var(--mj-brand-primary);\n }\n\n .mj-filter-popover-badge[_ngcontent-%COMP%] {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n min-width: 20px;\n height: 20px;\n padding: 0 var(--mj-space-1-5);\n border-radius: 10px;\n background: var(--mj-brand-primary);\n color: var(--mj-text-inverse);\n font-size: 11px;\n font-weight: 700;\n line-height: 1;\n }\n\n .mj-filter-popover-chevron[_ngcontent-%COMP%] {\n font-size: 10px;\n transition: transform 0.2s ease;\n color: var(--mj-text-muted);\n }\n\n .mj-filter-popover-chevron--open[_ngcontent-%COMP%] {\n transform: rotate(180deg);\n }\n\n .mj-filter-popover-panel[_ngcontent-%COMP%] {\n min-width: 320px;\n max-width: 480px;\n background: var(--mj-bg-surface);\n border: 1px solid var(--mj-border-default);\n border-radius: var(--mj-radius-md);\n box-shadow: var(--mj-shadow-md);\n margin-top: var(--mj-space-1-5);\n overflow: hidden;\n }\n\n .mj-filter-popover-header[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n justify-content: space-between;\n padding: var(--mj-space-3) var(--mj-space-4) 0;\n }\n\n .mj-filter-popover-title[_ngcontent-%COMP%] {\n font-size: 13px;\n font-weight: 600;\n color: var(--mj-text-primary);\n }\n\n .mj-filter-popover-clear[_ngcontent-%COMP%] {\n background: transparent;\n border: none;\n color: var(--mj-brand-primary);\n font-size: var(--mj-text-xs);\n font-weight: 500;\n cursor: pointer;\n padding: var(--mj-space-1) var(--mj-space-2);\n border-radius: var(--mj-radius-sm);\n }\n\n .mj-filter-popover-clear[_ngcontent-%COMP%]:hover {\n background: var(--mj-bg-surface-hover);\n }\n\n .mj-filter-popover-content[_ngcontent-%COMP%] {\n padding: var(--mj-space-3) var(--mj-space-4) var(--mj-space-4);\n display: flex;\n flex-direction: column;\n gap: var(--mj-space-2-5);\n }"] });
110
+ } }, dependencies: [OverlayModule, i1.CdkConnectedOverlay, i1.CdkOverlayOrigin], styles: ["[_nghost-%COMP%] {\n display: inline-flex;\n }\n\n \n\n\n\n .mj-filter-popover-trigger[_ngcontent-%COMP%] {\n display: inline-flex;\n align-items: center;\n gap: 6px;\n padding: 6px 12px;\n min-height: 32px;\n background: var(--mj-bg-surface-sunken);\n border: 1px solid var(--mj-border-default);\n border-radius: var(--mj-radius-md);\n color: var(--mj-text-primary);\n font-family: inherit;\n font-size: 0.8125rem;\n font-weight: var(--mj-font-semibold);\n line-height: 1.5;\n cursor: pointer;\n transition: background-color 0.2s ease, border-color 0.2s ease, color 0.2s ease;\n white-space: nowrap;\n }\n\n .mj-filter-popover-trigger[_ngcontent-%COMP%]:hover {\n background: var(--mj-bg-surface-active);\n border-color: var(--mj-border-strong);\n }\n\n .mj-filter-popover-trigger--active[_ngcontent-%COMP%] {\n background: color-mix(in srgb, var(--mj-brand-primary) 10%, var(--mj-bg-surface));\n border-color: color-mix(in srgb, var(--mj-brand-primary) 30%, var(--mj-border-default));\n color: var(--mj-brand-primary);\n }\n\n .mj-filter-popover-trigger--active[_ngcontent-%COMP%]:hover {\n background: color-mix(in srgb, var(--mj-brand-primary) 14%, var(--mj-bg-surface));\n }\n\n .mj-filter-popover-trigger[_ngcontent-%COMP%] > i[_ngcontent-%COMP%]:first-child {\n font-size: var(--mj-text-xs);\n color: var(--mj-brand-primary);\n }\n\n .mj-filter-popover-badge[_ngcontent-%COMP%] {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n min-width: 20px;\n height: 20px;\n padding: 0 var(--mj-space-1-5);\n border-radius: 10px;\n background: var(--mj-brand-primary);\n color: var(--mj-text-inverse);\n font-size: 11px;\n font-weight: 700;\n line-height: 1;\n }\n\n .mj-filter-popover-chevron[_ngcontent-%COMP%] {\n font-size: 10px;\n transition: transform 0.2s ease;\n color: var(--mj-text-muted);\n }\n\n .mj-filter-popover-chevron--open[_ngcontent-%COMP%] {\n transform: rotate(180deg);\n }\n\n .mj-filter-popover-panel[_ngcontent-%COMP%] {\n min-width: 320px;\n max-width: 480px;\n background: var(--mj-bg-surface);\n border: 1px solid var(--mj-border-default);\n border-radius: var(--mj-radius-md);\n box-shadow: var(--mj-shadow-md);\n margin-top: var(--mj-space-1-5);\n overflow: hidden;\n }\n\n .mj-filter-popover-header[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n justify-content: space-between;\n padding: var(--mj-space-3) var(--mj-space-4) 0;\n }\n\n .mj-filter-popover-title[_ngcontent-%COMP%] {\n font-size: 13px;\n font-weight: 600;\n color: var(--mj-text-primary);\n }\n\n .mj-filter-popover-clear[_ngcontent-%COMP%] {\n background: transparent;\n border: none;\n color: var(--mj-brand-primary);\n font-size: var(--mj-text-xs);\n font-weight: 500;\n cursor: pointer;\n padding: var(--mj-space-1) var(--mj-space-2);\n border-radius: var(--mj-radius-sm);\n }\n\n .mj-filter-popover-clear[_ngcontent-%COMP%]:hover {\n background: var(--mj-bg-surface-hover);\n }\n\n .mj-filter-popover-content[_ngcontent-%COMP%] {\n padding: var(--mj-space-3) var(--mj-space-4) var(--mj-space-4);\n display: flex;\n flex-direction: column;\n gap: var(--mj-space-2-5);\n }"] });
111
111
  }
112
112
  (() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassMetadata(MJFilterPopoverComponent, [{
113
113
  type: Component,
@@ -154,7 +154,7 @@ export class MJFilterPopoverComponent {
154
154
  </div>
155
155
  </div>
156
156
  </ng-template>
157
- `, styles: ["\n :host {\n display: inline-flex;\n }\n\n .mj-filter-popover-trigger {\n display: inline-flex;\n align-items: center;\n gap: var(--mj-space-2);\n padding: var(--mj-space-2) var(--mj-space-3-5);\n background: var(--mj-bg-surface-card);\n border: 1px solid var(--mj-border-default);\n border-radius: var(--mj-radius-md);\n color: var(--mj-text-secondary);\n font-family: inherit;\n font-size: 13px;\n font-weight: 500;\n line-height: 1.2;\n cursor: pointer;\n transition: background-color 0.2s ease, border-color 0.2s ease, color 0.2s ease;\n white-space: nowrap;\n }\n\n .mj-filter-popover-trigger:hover {\n background: var(--mj-bg-surface-sunken);\n border-color: var(--mj-border-strong);\n color: var(--mj-text-primary);\n }\n\n .mj-filter-popover-trigger--active {\n background: color-mix(in srgb, var(--mj-brand-primary) 10%, var(--mj-bg-surface));\n border-color: color-mix(in srgb, var(--mj-brand-primary) 30%, var(--mj-border-default));\n color: var(--mj-brand-primary);\n }\n\n .mj-filter-popover-trigger--active:hover {\n background: color-mix(in srgb, var(--mj-brand-primary) 14%, var(--mj-bg-surface));\n }\n\n .mj-filter-popover-trigger > i:first-child {\n font-size: var(--mj-text-xs);\n color: var(--mj-brand-primary);\n }\n\n .mj-filter-popover-badge {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n min-width: 20px;\n height: 20px;\n padding: 0 var(--mj-space-1-5);\n border-radius: 10px;\n background: var(--mj-brand-primary);\n color: var(--mj-text-inverse);\n font-size: 11px;\n font-weight: 700;\n line-height: 1;\n }\n\n .mj-filter-popover-chevron {\n font-size: 10px;\n transition: transform 0.2s ease;\n color: var(--mj-text-muted);\n }\n\n .mj-filter-popover-chevron--open {\n transform: rotate(180deg);\n }\n\n .mj-filter-popover-panel {\n min-width: 320px;\n max-width: 480px;\n background: var(--mj-bg-surface);\n border: 1px solid var(--mj-border-default);\n border-radius: var(--mj-radius-md);\n box-shadow: var(--mj-shadow-md);\n margin-top: var(--mj-space-1-5);\n overflow: hidden;\n }\n\n .mj-filter-popover-header {\n display: flex;\n align-items: center;\n justify-content: space-between;\n padding: var(--mj-space-3) var(--mj-space-4) 0;\n }\n\n .mj-filter-popover-title {\n font-size: 13px;\n font-weight: 600;\n color: var(--mj-text-primary);\n }\n\n .mj-filter-popover-clear {\n background: transparent;\n border: none;\n color: var(--mj-brand-primary);\n font-size: var(--mj-text-xs);\n font-weight: 500;\n cursor: pointer;\n padding: var(--mj-space-1) var(--mj-space-2);\n border-radius: var(--mj-radius-sm);\n }\n\n .mj-filter-popover-clear:hover {\n background: var(--mj-bg-surface-hover);\n }\n\n .mj-filter-popover-content {\n padding: var(--mj-space-3) var(--mj-space-4) var(--mj-space-4);\n display: flex;\n flex-direction: column;\n gap: var(--mj-space-2-5);\n }\n "] }]
157
+ `, styles: ["\n :host {\n display: inline-flex;\n }\n\n /* Trigger button \u2014 visually aligned with mjButton size=\"sm\" variant=\"secondary\"\n (same height, padding, font-size, font-weight, background) so it sits\n cleanly next to Refresh/Export/+Add in chrome and filter-card rows. */\n .mj-filter-popover-trigger {\n display: inline-flex;\n align-items: center;\n gap: 6px;\n padding: 6px 12px;\n min-height: 32px;\n background: var(--mj-bg-surface-sunken);\n border: 1px solid var(--mj-border-default);\n border-radius: var(--mj-radius-md);\n color: var(--mj-text-primary);\n font-family: inherit;\n font-size: 0.8125rem;\n font-weight: var(--mj-font-semibold);\n line-height: 1.5;\n cursor: pointer;\n transition: background-color 0.2s ease, border-color 0.2s ease, color 0.2s ease;\n white-space: nowrap;\n }\n\n .mj-filter-popover-trigger:hover {\n background: var(--mj-bg-surface-active);\n border-color: var(--mj-border-strong);\n }\n\n .mj-filter-popover-trigger--active {\n background: color-mix(in srgb, var(--mj-brand-primary) 10%, var(--mj-bg-surface));\n border-color: color-mix(in srgb, var(--mj-brand-primary) 30%, var(--mj-border-default));\n color: var(--mj-brand-primary);\n }\n\n .mj-filter-popover-trigger--active:hover {\n background: color-mix(in srgb, var(--mj-brand-primary) 14%, var(--mj-bg-surface));\n }\n\n .mj-filter-popover-trigger > i:first-child {\n font-size: var(--mj-text-xs);\n color: var(--mj-brand-primary);\n }\n\n .mj-filter-popover-badge {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n min-width: 20px;\n height: 20px;\n padding: 0 var(--mj-space-1-5);\n border-radius: 10px;\n background: var(--mj-brand-primary);\n color: var(--mj-text-inverse);\n font-size: 11px;\n font-weight: 700;\n line-height: 1;\n }\n\n .mj-filter-popover-chevron {\n font-size: 10px;\n transition: transform 0.2s ease;\n color: var(--mj-text-muted);\n }\n\n .mj-filter-popover-chevron--open {\n transform: rotate(180deg);\n }\n\n .mj-filter-popover-panel {\n min-width: 320px;\n max-width: 480px;\n background: var(--mj-bg-surface);\n border: 1px solid var(--mj-border-default);\n border-radius: var(--mj-radius-md);\n box-shadow: var(--mj-shadow-md);\n margin-top: var(--mj-space-1-5);\n overflow: hidden;\n }\n\n .mj-filter-popover-header {\n display: flex;\n align-items: center;\n justify-content: space-between;\n padding: var(--mj-space-3) var(--mj-space-4) 0;\n }\n\n .mj-filter-popover-title {\n font-size: 13px;\n font-weight: 600;\n color: var(--mj-text-primary);\n }\n\n .mj-filter-popover-clear {\n background: transparent;\n border: none;\n color: var(--mj-brand-primary);\n font-size: var(--mj-text-xs);\n font-weight: 500;\n cursor: pointer;\n padding: var(--mj-space-1) var(--mj-space-2);\n border-radius: var(--mj-radius-sm);\n }\n\n .mj-filter-popover-clear:hover {\n background: var(--mj-bg-surface-hover);\n }\n\n .mj-filter-popover-content {\n padding: var(--mj-space-3) var(--mj-space-4) var(--mj-space-4);\n display: flex;\n flex-direction: column;\n gap: var(--mj-space-2-5);\n }\n "] }]
158
158
  }], null, { Label: [{
159
159
  type: Input
160
160
  }], Icon: [{
@@ -166,5 +166,5 @@ export class MJFilterPopoverComponent {
166
166
  }], ClearAllRequested: [{
167
167
  type: Output
168
168
  }] }); })();
169
- (() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassDebugInfo(MJFilterPopoverComponent, { className: "MJFilterPopoverComponent", filePath: "lib/filter-popover/filter-popover.component.ts", lineNumber: 186 }); })();
169
+ (() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassDebugInfo(MJFilterPopoverComponent, { className: "MJFilterPopoverComponent", filePath: "lib/filter-popover/filter-popover.component.ts", lineNumber: 189 }); })();
170
170
  //# sourceMappingURL=filter-popover.component.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"filter-popover.component.js","sourceRoot":"","sources":["../../../src/lib/filter-popover/filter-popover.component.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,YAAY,EAAE,KAAK,EAAE,MAAM,EAAE,MAAM,eAAe,CAAC;AACvE,OAAO,EAAE,aAAa,EAAqB,MAAM,sBAAsB,CAAC;;;;;IAqChE,+BAA0F;IACxF,YACF;IAAA,iBAAO;;;;IADL,cACF;IADE,mDACF;;;;IAkBI,kCAA2E;IAArB,2MAAS,iBAAU,KAAC;IACxE,2BACF;IAAA,iBAAS;;;IAJX,AADF,AADF,8BAA6E,aACrC,cACE;IAAA,YAAW;IAAA,iBAAO;IACxD,2GAAuC;IAKzC,iBAAM;IACN,8BAAuC;IACrC,kBAAyB;IAE7B,AADE,iBAAM,EACF;;;;IAVoC,eAAW;IAAX,kCAAW;IACjD,cAIC;IAJD,wEAIC;;AA1DX;;;;;;;;;;;;;;;;;GAiBG;AAqKH,MAAM,OAAO,wBAAwB;IAC1B,KAAK,GAAW,SAAS,CAAC;IAC1B,IAAI,GAAW,oBAAoB,CAAC;IACpC,WAAW,GAAW,CAAC,CAAC;IACxB,YAAY,GAAY,KAAK,CAAC;IAEhC,MAAM,GAAY,KAAK,CAAC;IAE/B,qFAAqF;IACrF,oFAAoF;IACpF,0FAA0F;IAC1F,2FAA2F;IAC3E,SAAS,GAAwB;QAC/C,EAAE,OAAO,EAAE,KAAK,EAAI,OAAO,EAAE,QAAQ,EAAE,QAAQ,EAAE,KAAK,EAAI,QAAQ,EAAE,KAAK,EAAE;QAC3E,EAAE,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,QAAQ,EAAE,QAAQ,EAAE,OAAO,EAAE,QAAQ,EAAE,KAAK,EAAE;QAC3E,EAAE,OAAO,EAAE,KAAK,EAAI,OAAO,EAAE,KAAK,EAAK,QAAQ,EAAE,KAAK,EAAI,QAAQ,EAAE,QAAQ,EAAE;KAC/E,CAAC;IAEK,MAAM,KAAW,IAAI,CAAC,MAAM,GAAG,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC;IAC9C,IAAI,KAAW,IAAI,CAAC,MAAM,GAAG,IAAI,CAAC,CAAC,CAAC;IACpC,KAAK,KAAW,IAAI,CAAC,MAAM,GAAG,KAAK,CAAC,CAAC,CAAC;IAE7C,mFAAmF;IAClE,iBAAiB,GAAG,IAAI,YAAY,EAAQ,CAAC;IAEvD,QAAQ;QACb,IAAI,CAAC,iBAAiB,CAAC,IAAI,EAAE,CAAC;IAChC,CAAC;kHA3BU,wBAAwB;6DAAxB,wBAAwB;;;YA/JjC,oCAQqB;YAAnB,2IAAS,YAAQ,KAAC;YAClB,oBAAsB;YACtB,4BAAM;YAAA,YAAW;YAAA,iBAAO;YACxB,2FAAuB;YAKvB,uBAAmH;YACrH,iBAAS;YAET,yFAQqB;YAAnB,AADA,gKAAiB,WAAO,KAAC,qIACf,WAAO,KAAC;;;YAxBlB,sFAAqE;;YAMlE,eAAc;YAAd,uBAAc;YACX,eAAW;YAAX,+BAAW;YACjB,cAIC;YAJD,8CAIC;YAC6D,cAAgD;YAAhD,6DAAgD;YAK9G,cAA2C;YAG3C,AADA,AADA,AADA,4DAA2C,uCACT,+CACQ,wCACH;4BA1BjC,aAAa;;iFAiKZ,wBAAwB;cApKpC,SAAS;2BACE,mBAAmB,cACjB,IAAI,WACP,CAAC,aAAa,CAAC,YACd;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2CT;;kBAsHA,KAAK;;kBACL,KAAK;;kBACL,KAAK;;kBACL,KAAK;;kBAmBL,MAAM;;kFAvBI,wBAAwB","sourcesContent":["import { Component, EventEmitter, Input, Output } from '@angular/core';\nimport { OverlayModule, ConnectedPosition } from '@angular/cdk/overlay';\n\n/**\n * mj-filter-popover — Compact \"Filters\" trigger button that opens a popover\n * containing arbitrary filter UI. Use this in a dashboard's page-header to\n * keep the header chrome consistent regardless of filter density.\n *\n * Pass the popover content via `<ng-content>`. Drive the active-count badge\n * via the `ActiveCount` input.\n *\n * Example:\n * ```html\n * <mj-filter-popover [ActiveCount]=\"activeFilters.length\">\n * <div class=\"my-filter-grid\">\n * <mj-dropdown ...></mj-dropdown>\n * <mj-dropdown ...></mj-dropdown>\n * </div>\n * </mj-filter-popover>\n * ```\n */\n@Component({\n selector: 'mj-filter-popover',\n standalone: true,\n imports: [OverlayModule],\n template: `\n <button\n type=\"button\"\n class=\"mj-filter-popover-trigger\"\n [class.mj-filter-popover-trigger--active]=\"IsOpen || ActiveCount > 0\"\n cdkOverlayOrigin\n #overlayOrigin=\"cdkOverlayOrigin\"\n [attr.aria-expanded]=\"IsOpen\"\n [attr.aria-haspopup]=\"true\"\n (click)=\"Toggle()\">\n <i [class]=\"Icon\"></i>\n <span>{{ Label }}</span>\n @if (ActiveCount > 0) {\n <span class=\"mj-filter-popover-badge\" [attr.aria-label]=\"ActiveCount + ' active filters'\">\n {{ ActiveCount }}\n </span>\n }\n <i class=\"fa-solid fa-chevron-down mj-filter-popover-chevron\" [class.mj-filter-popover-chevron--open]=\"IsOpen\"></i>\n </button>\n\n <ng-template\n cdkConnectedOverlay\n [cdkConnectedOverlayOrigin]=\"overlayOrigin\"\n [cdkConnectedOverlayOpen]=\"IsOpen\"\n [cdkConnectedOverlayPositions]=\"Positions\"\n [cdkConnectedOverlayHasBackdrop]=\"true\"\n cdkConnectedOverlayBackdropClass=\"mj-filter-popover-backdrop\"\n (backdropClick)=\"Close()\"\n (detach)=\"Close()\">\n <div class=\"mj-filter-popover-panel\" role=\"dialog\" [attr.aria-label]=\"Label\">\n <div class=\"mj-filter-popover-header\">\n <span class=\"mj-filter-popover-title\">{{ Label }}</span>\n @if (ActiveCount > 0 && ShowClearAll) {\n <button type=\"button\" class=\"mj-filter-popover-clear\" (click)=\"ClearAll()\">\n Clear all\n </button>\n }\n </div>\n <div class=\"mj-filter-popover-content\">\n <ng-content></ng-content>\n </div>\n </div>\n </ng-template>\n `,\n styles: [`\n :host {\n display: inline-flex;\n }\n\n .mj-filter-popover-trigger {\n display: inline-flex;\n align-items: center;\n gap: var(--mj-space-2);\n padding: var(--mj-space-2) var(--mj-space-3-5);\n background: var(--mj-bg-surface-card);\n border: 1px solid var(--mj-border-default);\n border-radius: var(--mj-radius-md);\n color: var(--mj-text-secondary);\n font-family: inherit;\n font-size: 13px;\n font-weight: 500;\n line-height: 1.2;\n cursor: pointer;\n transition: background-color 0.2s ease, border-color 0.2s ease, color 0.2s ease;\n white-space: nowrap;\n }\n\n .mj-filter-popover-trigger:hover {\n background: var(--mj-bg-surface-sunken);\n border-color: var(--mj-border-strong);\n color: var(--mj-text-primary);\n }\n\n .mj-filter-popover-trigger--active {\n background: color-mix(in srgb, var(--mj-brand-primary) 10%, var(--mj-bg-surface));\n border-color: color-mix(in srgb, var(--mj-brand-primary) 30%, var(--mj-border-default));\n color: var(--mj-brand-primary);\n }\n\n .mj-filter-popover-trigger--active:hover {\n background: color-mix(in srgb, var(--mj-brand-primary) 14%, var(--mj-bg-surface));\n }\n\n .mj-filter-popover-trigger > i:first-child {\n font-size: var(--mj-text-xs);\n color: var(--mj-brand-primary);\n }\n\n .mj-filter-popover-badge {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n min-width: 20px;\n height: 20px;\n padding: 0 var(--mj-space-1-5);\n border-radius: 10px;\n background: var(--mj-brand-primary);\n color: var(--mj-text-inverse);\n font-size: 11px;\n font-weight: 700;\n line-height: 1;\n }\n\n .mj-filter-popover-chevron {\n font-size: 10px;\n transition: transform 0.2s ease;\n color: var(--mj-text-muted);\n }\n\n .mj-filter-popover-chevron--open {\n transform: rotate(180deg);\n }\n\n .mj-filter-popover-panel {\n min-width: 320px;\n max-width: 480px;\n background: var(--mj-bg-surface);\n border: 1px solid var(--mj-border-default);\n border-radius: var(--mj-radius-md);\n box-shadow: var(--mj-shadow-md);\n margin-top: var(--mj-space-1-5);\n overflow: hidden;\n }\n\n .mj-filter-popover-header {\n display: flex;\n align-items: center;\n justify-content: space-between;\n padding: var(--mj-space-3) var(--mj-space-4) 0;\n }\n\n .mj-filter-popover-title {\n font-size: 13px;\n font-weight: 600;\n color: var(--mj-text-primary);\n }\n\n .mj-filter-popover-clear {\n background: transparent;\n border: none;\n color: var(--mj-brand-primary);\n font-size: var(--mj-text-xs);\n font-weight: 500;\n cursor: pointer;\n padding: var(--mj-space-1) var(--mj-space-2);\n border-radius: var(--mj-radius-sm);\n }\n\n .mj-filter-popover-clear:hover {\n background: var(--mj-bg-surface-hover);\n }\n\n .mj-filter-popover-content {\n padding: var(--mj-space-3) var(--mj-space-4) var(--mj-space-4);\n display: flex;\n flex-direction: column;\n gap: var(--mj-space-2-5);\n }\n `]\n})\nexport class MJFilterPopoverComponent {\n @Input() Label: string = 'Filters';\n @Input() Icon: string = 'fa-solid fa-filter';\n @Input() ActiveCount: number = 0;\n @Input() ShowClearAll: boolean = false;\n\n public IsOpen: boolean = false;\n\n // Note: NO offsetY here — CDK applies offsetY as `transform: translateY(...)` on the\n // overlay pane, which creates a containing block for `position: fixed` descendants.\n // Tree dropdowns (and any other component using position: fixed) would then mis-position.\n // The 6px spacing below the trigger is applied via margin-top on .mj-filter-popover-panel.\n public readonly Positions: ConnectedPosition[] = [\n { originX: 'end', originY: 'bottom', overlayX: 'end', overlayY: 'top' },\n { originX: 'start', originY: 'bottom', overlayX: 'start', overlayY: 'top' },\n { originX: 'end', originY: 'top', overlayX: 'end', overlayY: 'bottom' }\n ];\n\n public Toggle(): void { this.IsOpen = !this.IsOpen; }\n public Open(): void { this.IsOpen = true; }\n public Close(): void { this.IsOpen = false; }\n\n /** Emitted when the user clicks the \"Clear all\" link inside the popover header. */\n @Output() public ClearAllRequested = new EventEmitter<void>();\n\n public ClearAll(): void {\n this.ClearAllRequested.emit();\n }\n}\n"]}
1
+ {"version":3,"file":"filter-popover.component.js","sourceRoot":"","sources":["../../../src/lib/filter-popover/filter-popover.component.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,YAAY,EAAE,KAAK,EAAE,MAAM,EAAE,MAAM,eAAe,CAAC;AACvE,OAAO,EAAE,aAAa,EAAqB,MAAM,sBAAsB,CAAC;;;;;IAqChE,+BAA0F;IACxF,YACF;IAAA,iBAAO;;;;IADL,cACF;IADE,mDACF;;;;IAkBI,kCAA2E;IAArB,2MAAS,iBAAU,KAAC;IACxE,2BACF;IAAA,iBAAS;;;IAJX,AADF,AADF,8BAA6E,aACrC,cACE;IAAA,YAAW;IAAA,iBAAO;IACxD,2GAAuC;IAKzC,iBAAM;IACN,8BAAuC;IACrC,kBAAyB;IAE7B,AADE,iBAAM,EACF;;;;IAVoC,eAAW;IAAX,kCAAW;IACjD,cAIC;IAJD,wEAIC;;AA1DX;;;;;;;;;;;;;;;;;GAiBG;AAwKH,MAAM,OAAO,wBAAwB;IAC1B,KAAK,GAAW,SAAS,CAAC;IAC1B,IAAI,GAAW,oBAAoB,CAAC;IACpC,WAAW,GAAW,CAAC,CAAC;IACxB,YAAY,GAAY,KAAK,CAAC;IAEhC,MAAM,GAAY,KAAK,CAAC;IAE/B,qFAAqF;IACrF,oFAAoF;IACpF,0FAA0F;IAC1F,2FAA2F;IAC3E,SAAS,GAAwB;QAC/C,EAAE,OAAO,EAAE,KAAK,EAAI,OAAO,EAAE,QAAQ,EAAE,QAAQ,EAAE,KAAK,EAAI,QAAQ,EAAE,KAAK,EAAE;QAC3E,EAAE,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,QAAQ,EAAE,QAAQ,EAAE,OAAO,EAAE,QAAQ,EAAE,KAAK,EAAE;QAC3E,EAAE,OAAO,EAAE,KAAK,EAAI,OAAO,EAAE,KAAK,EAAK,QAAQ,EAAE,KAAK,EAAI,QAAQ,EAAE,QAAQ,EAAE;KAC/E,CAAC;IAEK,MAAM,KAAW,IAAI,CAAC,MAAM,GAAG,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC;IAC9C,IAAI,KAAW,IAAI,CAAC,MAAM,GAAG,IAAI,CAAC,CAAC,CAAC;IACpC,KAAK,KAAW,IAAI,CAAC,MAAM,GAAG,KAAK,CAAC,CAAC,CAAC;IAE7C,mFAAmF;IAClE,iBAAiB,GAAG,IAAI,YAAY,EAAQ,CAAC;IAEvD,QAAQ;QACb,IAAI,CAAC,iBAAiB,CAAC,IAAI,EAAE,CAAC;IAChC,CAAC;kHA3BU,wBAAwB;6DAAxB,wBAAwB;;;YAlKjC,oCAQqB;YAAnB,2IAAS,YAAQ,KAAC;YAClB,oBAAsB;YACtB,4BAAM;YAAA,YAAW;YAAA,iBAAO;YACxB,2FAAuB;YAKvB,uBAAmH;YACrH,iBAAS;YAET,yFAQqB;YAAnB,AADA,gKAAiB,WAAO,KAAC,qIACf,WAAO,KAAC;;;YAxBlB,sFAAqE;;YAMlE,eAAc;YAAd,uBAAc;YACX,eAAW;YAAX,+BAAW;YACjB,cAIC;YAJD,8CAIC;YAC6D,cAAgD;YAAhD,6DAAgD;YAK9G,cAA2C;YAG3C,AADA,AADA,AADA,4DAA2C,uCACT,+CACQ,wCACH;4BA1BjC,aAAa;;iFAoKZ,wBAAwB;cAvKpC,SAAS;2BACE,mBAAmB,cACjB,IAAI,WACP,CAAC,aAAa,CAAC,YACd;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2CT;;kBAyHA,KAAK;;kBACL,KAAK;;kBACL,KAAK;;kBACL,KAAK;;kBAmBL,MAAM;;kFAvBI,wBAAwB","sourcesContent":["import { Component, EventEmitter, Input, Output } from '@angular/core';\nimport { OverlayModule, ConnectedPosition } from '@angular/cdk/overlay';\n\n/**\n * mj-filter-popover — Compact \"Filters\" trigger button that opens a popover\n * containing arbitrary filter UI. Use this in a dashboard's page-header to\n * keep the header chrome consistent regardless of filter density.\n *\n * Pass the popover content via `<ng-content>`. Drive the active-count badge\n * via the `ActiveCount` input.\n *\n * Example:\n * ```html\n * <mj-filter-popover [ActiveCount]=\"activeFilters.length\">\n * <div class=\"my-filter-grid\">\n * <mj-dropdown ...></mj-dropdown>\n * <mj-dropdown ...></mj-dropdown>\n * </div>\n * </mj-filter-popover>\n * ```\n */\n@Component({\n selector: 'mj-filter-popover',\n standalone: true,\n imports: [OverlayModule],\n template: `\n <button\n type=\"button\"\n class=\"mj-filter-popover-trigger\"\n [class.mj-filter-popover-trigger--active]=\"IsOpen || ActiveCount > 0\"\n cdkOverlayOrigin\n #overlayOrigin=\"cdkOverlayOrigin\"\n [attr.aria-expanded]=\"IsOpen\"\n [attr.aria-haspopup]=\"true\"\n (click)=\"Toggle()\">\n <i [class]=\"Icon\"></i>\n <span>{{ Label }}</span>\n @if (ActiveCount > 0) {\n <span class=\"mj-filter-popover-badge\" [attr.aria-label]=\"ActiveCount + ' active filters'\">\n {{ ActiveCount }}\n </span>\n }\n <i class=\"fa-solid fa-chevron-down mj-filter-popover-chevron\" [class.mj-filter-popover-chevron--open]=\"IsOpen\"></i>\n </button>\n\n <ng-template\n cdkConnectedOverlay\n [cdkConnectedOverlayOrigin]=\"overlayOrigin\"\n [cdkConnectedOverlayOpen]=\"IsOpen\"\n [cdkConnectedOverlayPositions]=\"Positions\"\n [cdkConnectedOverlayHasBackdrop]=\"true\"\n cdkConnectedOverlayBackdropClass=\"mj-filter-popover-backdrop\"\n (backdropClick)=\"Close()\"\n (detach)=\"Close()\">\n <div class=\"mj-filter-popover-panel\" role=\"dialog\" [attr.aria-label]=\"Label\">\n <div class=\"mj-filter-popover-header\">\n <span class=\"mj-filter-popover-title\">{{ Label }}</span>\n @if (ActiveCount > 0 && ShowClearAll) {\n <button type=\"button\" class=\"mj-filter-popover-clear\" (click)=\"ClearAll()\">\n Clear all\n </button>\n }\n </div>\n <div class=\"mj-filter-popover-content\">\n <ng-content></ng-content>\n </div>\n </div>\n </ng-template>\n `,\n styles: [`\n :host {\n display: inline-flex;\n }\n\n /* Trigger button — visually aligned with mjButton size=\"sm\" variant=\"secondary\"\n (same height, padding, font-size, font-weight, background) so it sits\n cleanly next to Refresh/Export/+Add in chrome and filter-card rows. */\n .mj-filter-popover-trigger {\n display: inline-flex;\n align-items: center;\n gap: 6px;\n padding: 6px 12px;\n min-height: 32px;\n background: var(--mj-bg-surface-sunken);\n border: 1px solid var(--mj-border-default);\n border-radius: var(--mj-radius-md);\n color: var(--mj-text-primary);\n font-family: inherit;\n font-size: 0.8125rem;\n font-weight: var(--mj-font-semibold);\n line-height: 1.5;\n cursor: pointer;\n transition: background-color 0.2s ease, border-color 0.2s ease, color 0.2s ease;\n white-space: nowrap;\n }\n\n .mj-filter-popover-trigger:hover {\n background: var(--mj-bg-surface-active);\n border-color: var(--mj-border-strong);\n }\n\n .mj-filter-popover-trigger--active {\n background: color-mix(in srgb, var(--mj-brand-primary) 10%, var(--mj-bg-surface));\n border-color: color-mix(in srgb, var(--mj-brand-primary) 30%, var(--mj-border-default));\n color: var(--mj-brand-primary);\n }\n\n .mj-filter-popover-trigger--active:hover {\n background: color-mix(in srgb, var(--mj-brand-primary) 14%, var(--mj-bg-surface));\n }\n\n .mj-filter-popover-trigger > i:first-child {\n font-size: var(--mj-text-xs);\n color: var(--mj-brand-primary);\n }\n\n .mj-filter-popover-badge {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n min-width: 20px;\n height: 20px;\n padding: 0 var(--mj-space-1-5);\n border-radius: 10px;\n background: var(--mj-brand-primary);\n color: var(--mj-text-inverse);\n font-size: 11px;\n font-weight: 700;\n line-height: 1;\n }\n\n .mj-filter-popover-chevron {\n font-size: 10px;\n transition: transform 0.2s ease;\n color: var(--mj-text-muted);\n }\n\n .mj-filter-popover-chevron--open {\n transform: rotate(180deg);\n }\n\n .mj-filter-popover-panel {\n min-width: 320px;\n max-width: 480px;\n background: var(--mj-bg-surface);\n border: 1px solid var(--mj-border-default);\n border-radius: var(--mj-radius-md);\n box-shadow: var(--mj-shadow-md);\n margin-top: var(--mj-space-1-5);\n overflow: hidden;\n }\n\n .mj-filter-popover-header {\n display: flex;\n align-items: center;\n justify-content: space-between;\n padding: var(--mj-space-3) var(--mj-space-4) 0;\n }\n\n .mj-filter-popover-title {\n font-size: 13px;\n font-weight: 600;\n color: var(--mj-text-primary);\n }\n\n .mj-filter-popover-clear {\n background: transparent;\n border: none;\n color: var(--mj-brand-primary);\n font-size: var(--mj-text-xs);\n font-weight: 500;\n cursor: pointer;\n padding: var(--mj-space-1) var(--mj-space-2);\n border-radius: var(--mj-radius-sm);\n }\n\n .mj-filter-popover-clear:hover {\n background: var(--mj-bg-surface-hover);\n }\n\n .mj-filter-popover-content {\n padding: var(--mj-space-3) var(--mj-space-4) var(--mj-space-4);\n display: flex;\n flex-direction: column;\n gap: var(--mj-space-2-5);\n }\n `]\n})\nexport class MJFilterPopoverComponent {\n @Input() Label: string = 'Filters';\n @Input() Icon: string = 'fa-solid fa-filter';\n @Input() ActiveCount: number = 0;\n @Input() ShowClearAll: boolean = false;\n\n public IsOpen: boolean = false;\n\n // Note: NO offsetY here — CDK applies offsetY as `transform: translateY(...)` on the\n // overlay pane, which creates a containing block for `position: fixed` descendants.\n // Tree dropdowns (and any other component using position: fixed) would then mis-position.\n // The 6px spacing below the trigger is applied via margin-top on .mj-filter-popover-panel.\n public readonly Positions: ConnectedPosition[] = [\n { originX: 'end', originY: 'bottom', overlayX: 'end', overlayY: 'top' },\n { originX: 'start', originY: 'bottom', overlayX: 'start', overlayY: 'top' },\n { originX: 'end', originY: 'top', overlayX: 'end', overlayY: 'bottom' }\n ];\n\n public Toggle(): void { this.IsOpen = !this.IsOpen; }\n public Open(): void { this.IsOpen = true; }\n public Close(): void { this.IsOpen = false; }\n\n /** Emitted when the user clicks the \"Clear all\" link inside the popover header. */\n @Output() public ClearAllRequested = new EventEmitter<void>();\n\n public ClearAll(): void {\n this.ClearAllRequested.emit();\n }\n}\n"]}
@@ -0,0 +1,53 @@
1
+ import * as i0 from "@angular/core";
2
+ /**
3
+ * `<mj-left-nav-content>` — Content pane paired with `<mj-left-nav>`.
4
+ *
5
+ * Sits to the right of `<mj-left-nav>` inside `<mj-page-body [Flex]="true"
6
+ * Direction="row">` and holds the active section's content. Provides the
7
+ * standard layout box (`flex: 1`, page background, vertical overflow control)
8
+ * plus built-in `[Loading]` / `[Error]` states so each shell doesn't reinvent
9
+ * them.
10
+ *
11
+ * Projected content stays attached but hides via CSS when loading or errored —
12
+ * matches the cached-component pattern used by admin shells where dynamically
13
+ * loaded sub-pages should retain their state across section switches.
14
+ *
15
+ * ## Example
16
+ *
17
+ * ```html
18
+ * <mj-page-body [Flex]="true" [Padding]="false" Direction="row">
19
+ * <mj-left-nav [Sections]="NavSections" [ActiveId]="ActiveSection"
20
+ * (ItemClicked)="OnNavItemClicked($event)" />
21
+ * <mj-left-nav-content [Loading]="IsLoading" [Error]="LoadError">
22
+ * <ng-container #contentHost></ng-container>
23
+ * </mj-left-nav-content>
24
+ * </mj-page-body>
25
+ * ```
26
+ *
27
+ * Replaces the bespoke `.{shell}-container__content` + `.{shell}-container__host`
28
+ * + `.{shell}-container__loading` + `.{shell}-container__error` pattern that
29
+ * every left-nav shell used to declare independently.
30
+ */
31
+ export declare class MJLeftNavContentComponent {
32
+ /**
33
+ * When `true`, shows a centered loading state (spinner + label) and hides
34
+ * any projected content via CSS. Cached components remain attached.
35
+ */
36
+ Loading: boolean;
37
+ /**
38
+ * When non-empty, shows a centered error state with this message and hides
39
+ * any projected content.
40
+ */
41
+ Error: string | null;
42
+ /** Label shown in the loading state. Defaults to "Loading…". */
43
+ LoadingLabel: string;
44
+ /**
45
+ * Drives the busy-state class on the host. When set, CSS hides projected
46
+ * content (cached components stay attached, just not visible).
47
+ */
48
+ get IsBusy(): boolean;
49
+ get AriaBusy(): string | null;
50
+ static ɵfac: i0.ɵɵFactoryDeclaration<MJLeftNavContentComponent, never>;
51
+ static ɵcmp: i0.ɵɵComponentDeclaration<MJLeftNavContentComponent, "mj-left-nav-content", never, { "Loading": { "alias": "Loading"; "required": false; }; "Error": { "alias": "Error"; "required": false; }; "LoadingLabel": { "alias": "LoadingLabel"; "required": false; }; }, {}, never, ["*"], true, never>;
52
+ }
53
+ //# sourceMappingURL=left-nav-content.component.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"left-nav-content.component.d.ts","sourceRoot":"","sources":["../../../src/lib/left-nav/left-nav-content.component.ts"],"names":[],"mappings":";AAGA;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4BG;AACH,qBAiFa,yBAAyB;IACpC;;;OAGG;IACM,OAAO,EAAE,OAAO,CAAS;IAElC;;;OAGG;IACM,KAAK,EAAE,MAAM,GAAG,IAAI,CAAQ;IAErC,gEAAgE;IACvD,YAAY,EAAE,MAAM,CAAc;IAE3C;;;OAGG;IACH,IACI,MAAM,IAAI,OAAO,CAEpB;IAED,IACI,QAAQ,IAAI,MAAM,GAAG,IAAI,CAE5B;yCA5BU,yBAAyB;2CAAzB,yBAAyB;CA6BrC"}
@@ -0,0 +1,121 @@
1
+ import { Component, HostBinding, Input } from '@angular/core';
2
+ import { CommonModule } from '@angular/common';
3
+ import * as i0 from "@angular/core";
4
+ const _c0 = ["*"];
5
+ function MJLeftNavContentComponent_Conditional_0_Template(rf, ctx) { if (rf & 1) {
6
+ i0.ɵɵdomElementStart(0, "div", 0);
7
+ i0.ɵɵdomElement(1, "i", 2);
8
+ i0.ɵɵdomElementStart(2, "span");
9
+ i0.ɵɵtext(3);
10
+ i0.ɵɵdomElementEnd()();
11
+ } if (rf & 2) {
12
+ const ctx_r0 = i0.ɵɵnextContext();
13
+ i0.ɵɵadvance(3);
14
+ i0.ɵɵtextInterpolate(ctx_r0.Error);
15
+ } }
16
+ function MJLeftNavContentComponent_Conditional_1_Template(rf, ctx) { if (rf & 1) {
17
+ i0.ɵɵdomElementStart(0, "div", 1);
18
+ i0.ɵɵdomElement(1, "i", 3);
19
+ i0.ɵɵdomElementStart(2, "span");
20
+ i0.ɵɵtext(3);
21
+ i0.ɵɵdomElementEnd()();
22
+ } if (rf & 2) {
23
+ const ctx_r0 = i0.ɵɵnextContext();
24
+ i0.ɵɵadvance(3);
25
+ i0.ɵɵtextInterpolate(ctx_r0.LoadingLabel);
26
+ } }
27
+ /**
28
+ * `<mj-left-nav-content>` — Content pane paired with `<mj-left-nav>`.
29
+ *
30
+ * Sits to the right of `<mj-left-nav>` inside `<mj-page-body [Flex]="true"
31
+ * Direction="row">` and holds the active section's content. Provides the
32
+ * standard layout box (`flex: 1`, page background, vertical overflow control)
33
+ * plus built-in `[Loading]` / `[Error]` states so each shell doesn't reinvent
34
+ * them.
35
+ *
36
+ * Projected content stays attached but hides via CSS when loading or errored —
37
+ * matches the cached-component pattern used by admin shells where dynamically
38
+ * loaded sub-pages should retain their state across section switches.
39
+ *
40
+ * ## Example
41
+ *
42
+ * ```html
43
+ * <mj-page-body [Flex]="true" [Padding]="false" Direction="row">
44
+ * <mj-left-nav [Sections]="NavSections" [ActiveId]="ActiveSection"
45
+ * (ItemClicked)="OnNavItemClicked($event)" />
46
+ * <mj-left-nav-content [Loading]="IsLoading" [Error]="LoadError">
47
+ * <ng-container #contentHost></ng-container>
48
+ * </mj-left-nav-content>
49
+ * </mj-page-body>
50
+ * ```
51
+ *
52
+ * Replaces the bespoke `.{shell}-container__content` + `.{shell}-container__host`
53
+ * + `.{shell}-container__loading` + `.{shell}-container__error` pattern that
54
+ * every left-nav shell used to declare independently.
55
+ */
56
+ export class MJLeftNavContentComponent {
57
+ /**
58
+ * When `true`, shows a centered loading state (spinner + label) and hides
59
+ * any projected content via CSS. Cached components remain attached.
60
+ */
61
+ Loading = false;
62
+ /**
63
+ * When non-empty, shows a centered error state with this message and hides
64
+ * any projected content.
65
+ */
66
+ Error = null;
67
+ /** Label shown in the loading state. Defaults to "Loading…". */
68
+ LoadingLabel = 'Loading…';
69
+ /**
70
+ * Drives the busy-state class on the host. When set, CSS hides projected
71
+ * content (cached components stay attached, just not visible).
72
+ */
73
+ get IsBusy() {
74
+ return this.Loading || !!this.Error;
75
+ }
76
+ get AriaBusy() {
77
+ return this.Loading ? 'true' : null;
78
+ }
79
+ static ɵfac = function MJLeftNavContentComponent_Factory(__ngFactoryType__) { return new (__ngFactoryType__ || MJLeftNavContentComponent)(); };
80
+ static ɵcmp = /*@__PURE__*/ i0.ɵɵdefineComponent({ type: MJLeftNavContentComponent, selectors: [["mj-left-nav-content"]], hostVars: 3, hostBindings: function MJLeftNavContentComponent_HostBindings(rf, ctx) { if (rf & 2) {
81
+ i0.ɵɵattribute("aria-busy", ctx.AriaBusy);
82
+ i0.ɵɵclassProp("mj-left-nav-content--busy", ctx.IsBusy);
83
+ } }, inputs: { Loading: "Loading", Error: "Error", LoadingLabel: "LoadingLabel" }, ngContentSelectors: _c0, decls: 3, vars: 1, consts: [["role", "alert", 1, "mj-left-nav-content__error"], ["role", "status", "aria-live", "polite", 1, "mj-left-nav-content__loading"], ["aria-hidden", "true", 1, "fa-solid", "fa-triangle-exclamation"], ["aria-hidden", "true", 1, "fa-solid", "fa-spinner", "fa-spin"]], template: function MJLeftNavContentComponent_Template(rf, ctx) { if (rf & 1) {
84
+ i0.ɵɵprojectionDef();
85
+ i0.ɵɵconditionalCreate(0, MJLeftNavContentComponent_Conditional_0_Template, 4, 1, "div", 0)(1, MJLeftNavContentComponent_Conditional_1_Template, 4, 1, "div", 1);
86
+ i0.ɵɵprojection(2);
87
+ } if (rf & 2) {
88
+ i0.ɵɵconditional(ctx.Error ? 0 : ctx.Loading ? 1 : -1);
89
+ } }, dependencies: [CommonModule], styles: ["[_nghost-%COMP%] {\n flex: 1;\n min-width: 0;\n display: flex;\n flex-direction: column;\n background: var(--mj-bg-page);\n overflow: hidden;\n }\n\n \n\n\n\n\n\n\n\n\n\n\n\n [_nghost-%COMP%] > *:not(.mj-left-nav-content__error):not(.mj-left-nav-content__loading):not(mj-page-header-interior):not(mj-page-body-interior) {\n flex: 1 1 auto;\n min-height: 0;\n height: 100%;\n display: flex;\n flex-direction: column;\n overflow: hidden;\n }\n\n \n\n\n .mj-left-nav-content--busy[_nghost-%COMP%] > *:not(.mj-left-nav-content__error):not(.mj-left-nav-content__loading) {\n display: none;\n }\n\n .mj-left-nav-content__error[_ngcontent-%COMP%], \n .mj-left-nav-content__loading[_ngcontent-%COMP%] {\n flex: 1;\n display: flex;\n align-items: center;\n justify-content: center;\n gap: 10px;\n color: var(--mj-text-muted);\n font-size: 13px;\n padding: 32px;\n text-align: center;\n }\n\n .mj-left-nav-content__error[_ngcontent-%COMP%] {\n color: var(--mj-status-error);\n }\n\n .mj-left-nav-content__error[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n font-size: 20px;\n }\n\n .mj-left-nav-content__loading[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n font-size: 16px;\n color: var(--mj-brand-primary);\n }"] });
90
+ }
91
+ (() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassMetadata(MJLeftNavContentComponent, [{
92
+ type: Component,
93
+ args: [{ selector: 'mj-left-nav-content', standalone: true, imports: [CommonModule], template: `
94
+ @if (Error) {
95
+ <div class="mj-left-nav-content__error" role="alert">
96
+ <i class="fa-solid fa-triangle-exclamation" aria-hidden="true"></i>
97
+ <span>{{ Error }}</span>
98
+ </div>
99
+ } @else if (Loading) {
100
+ <div class="mj-left-nav-content__loading" role="status" aria-live="polite">
101
+ <i class="fa-solid fa-spinner fa-spin" aria-hidden="true"></i>
102
+ <span>{{ LoadingLabel }}</span>
103
+ </div>
104
+ }
105
+ <ng-content></ng-content>
106
+ `, styles: ["\n :host {\n flex: 1;\n min-width: 0;\n display: flex;\n flex-direction: column;\n background: var(--mj-bg-page);\n overflow: hidden;\n }\n\n /* Force dynamically-projected components (via ViewContainerRef.createComponent\n or ng-content) to fill the host with a proper flex-column layout. ::ng-deep\n is required because Angular's emulated encapsulation gives the host a scope\n attribute that dynamically-created components do not inherit, so a plain\n direct-child selector would not match them. The :not() filters skip our own\n error / loading elements AND the interior chrome primitives, which already\n self-declare their flex behavior on :host (header-interior is display:block\n with natural height; body-interior is flex:1 1 auto with overflow-y:auto)\n and competing with them would break multi-sibling chrome layouts inside a\n single content pane. This replaces the bespoke inline-style hack admin\n shells used to apply via applyHostSizing(). */\n :host ::ng-deep > *:not(.mj-left-nav-content__error):not(.mj-left-nav-content__loading):not(mj-page-header-interior):not(mj-page-body-interior) {\n flex: 1 1 auto;\n min-height: 0;\n height: 100%;\n display: flex;\n flex-direction: column;\n overflow: hidden;\n }\n\n /* When busy, hide projected content but keep cached components attached\n to the DOM so their state survives the loading / error transition. */\n :host(.mj-left-nav-content--busy) ::ng-deep > *:not(.mj-left-nav-content__error):not(.mj-left-nav-content__loading) {\n display: none;\n }\n\n .mj-left-nav-content__error,\n .mj-left-nav-content__loading {\n flex: 1;\n display: flex;\n align-items: center;\n justify-content: center;\n gap: 10px;\n color: var(--mj-text-muted);\n font-size: 13px;\n padding: 32px;\n text-align: center;\n }\n\n .mj-left-nav-content__error {\n color: var(--mj-status-error);\n }\n\n .mj-left-nav-content__error i {\n font-size: 20px;\n }\n\n .mj-left-nav-content__loading i {\n font-size: 16px;\n color: var(--mj-brand-primary);\n }\n "] }]
107
+ }], null, { Loading: [{
108
+ type: Input
109
+ }], Error: [{
110
+ type: Input
111
+ }], LoadingLabel: [{
112
+ type: Input
113
+ }], IsBusy: [{
114
+ type: HostBinding,
115
+ args: ['class.mj-left-nav-content--busy']
116
+ }], AriaBusy: [{
117
+ type: HostBinding,
118
+ args: ['attr.aria-busy']
119
+ }] }); })();
120
+ (() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassDebugInfo(MJLeftNavContentComponent, { className: "MJLeftNavContentComponent", filePath: "lib/left-nav/left-nav-content.component.ts", lineNumber: 114 }); })();
121
+ //# sourceMappingURL=left-nav-content.component.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"left-nav-content.component.js","sourceRoot":"","sources":["../../../src/lib/left-nav/left-nav-content.component.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,WAAW,EAAE,KAAK,EAAE,MAAM,eAAe,CAAC;AAC9D,OAAO,EAAE,YAAY,EAAE,MAAM,iBAAiB,CAAC;;;;IAqCzC,iCAAqD;IACnD,0BAAmE;IACnE,+BAAM;IAAA,YAAW;IACnB,AADmB,oBAAO,EACpB;;;IADE,eAAW;IAAX,kCAAW;;;IAGnB,iCAA2E;IACzE,0BAA8D;IAC9D,+BAAM;IAAA,YAAkB;IAC1B,AAD0B,oBAAO,EAC3B;;;IADE,eAAkB;IAAlB,yCAAkB;;AA1ChC;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4BG;AAkFH,MAAM,OAAO,yBAAyB;IACpC;;;OAGG;IACM,OAAO,GAAY,KAAK,CAAC;IAElC;;;OAGG;IACM,KAAK,GAAkB,IAAI,CAAC;IAErC,gEAAgE;IACvD,YAAY,GAAW,UAAU,CAAC;IAE3C;;;OAGG;IACH,IACI,MAAM;QACR,OAAO,IAAI,CAAC,OAAO,IAAI,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC;IACtC,CAAC;IAED,IACI,QAAQ;QACV,OAAO,IAAI,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,IAAI,CAAC;IACtC,CAAC;mHA5BU,yBAAyB;6DAAzB,yBAAyB;;YAAzB,uDAAyB;;;YAvEhC,AALF,2FAAa,qEAKS;YAMtB,kBAAyB;;YAXzB,sDAUC;4BAZO,YAAY;;iFA8EX,yBAAyB;cAjFrC,SAAS;2BACE,qBAAqB,cACnB,IAAI,WACP,CAAC,YAAY,CAAC,YACb;;;;;;;;;;;;;GAaT;;kBAqEA,KAAK;;kBAML,KAAK;;kBAGL,KAAK;;kBAML,WAAW;mBAAC,iCAAiC;;kBAK7C,WAAW;mBAAC,gBAAgB;;kFAzBlB,yBAAyB","sourcesContent":["import { Component, HostBinding, Input } from '@angular/core';\nimport { CommonModule } from '@angular/common';\n\n/**\n * `<mj-left-nav-content>` — Content pane paired with `<mj-left-nav>`.\n *\n * Sits to the right of `<mj-left-nav>` inside `<mj-page-body [Flex]=\"true\"\n * Direction=\"row\">` and holds the active section's content. Provides the\n * standard layout box (`flex: 1`, page background, vertical overflow control)\n * plus built-in `[Loading]` / `[Error]` states so each shell doesn't reinvent\n * them.\n *\n * Projected content stays attached but hides via CSS when loading or errored —\n * matches the cached-component pattern used by admin shells where dynamically\n * loaded sub-pages should retain their state across section switches.\n *\n * ## Example\n *\n * ```html\n * <mj-page-body [Flex]=\"true\" [Padding]=\"false\" Direction=\"row\">\n * <mj-left-nav [Sections]=\"NavSections\" [ActiveId]=\"ActiveSection\"\n * (ItemClicked)=\"OnNavItemClicked($event)\" />\n * <mj-left-nav-content [Loading]=\"IsLoading\" [Error]=\"LoadError\">\n * <ng-container #contentHost></ng-container>\n * </mj-left-nav-content>\n * </mj-page-body>\n * ```\n *\n * Replaces the bespoke `.{shell}-container__content` + `.{shell}-container__host`\n * + `.{shell}-container__loading` + `.{shell}-container__error` pattern that\n * every left-nav shell used to declare independently.\n */\n@Component({\n selector: 'mj-left-nav-content',\n standalone: true,\n imports: [CommonModule],\n template: `\n @if (Error) {\n <div class=\"mj-left-nav-content__error\" role=\"alert\">\n <i class=\"fa-solid fa-triangle-exclamation\" aria-hidden=\"true\"></i>\n <span>{{ Error }}</span>\n </div>\n } @else if (Loading) {\n <div class=\"mj-left-nav-content__loading\" role=\"status\" aria-live=\"polite\">\n <i class=\"fa-solid fa-spinner fa-spin\" aria-hidden=\"true\"></i>\n <span>{{ LoadingLabel }}</span>\n </div>\n }\n <ng-content></ng-content>\n `,\n styles: [`\n :host {\n flex: 1;\n min-width: 0;\n display: flex;\n flex-direction: column;\n background: var(--mj-bg-page);\n overflow: hidden;\n }\n\n /* Force dynamically-projected components (via ViewContainerRef.createComponent\n or ng-content) to fill the host with a proper flex-column layout. ::ng-deep\n is required because Angular's emulated encapsulation gives the host a scope\n attribute that dynamically-created components do not inherit, so a plain\n direct-child selector would not match them. The :not() filters skip our own\n error / loading elements AND the interior chrome primitives, which already\n self-declare their flex behavior on :host (header-interior is display:block\n with natural height; body-interior is flex:1 1 auto with overflow-y:auto)\n and competing with them would break multi-sibling chrome layouts inside a\n single content pane. This replaces the bespoke inline-style hack admin\n shells used to apply via applyHostSizing(). */\n :host ::ng-deep > *:not(.mj-left-nav-content__error):not(.mj-left-nav-content__loading):not(mj-page-header-interior):not(mj-page-body-interior) {\n flex: 1 1 auto;\n min-height: 0;\n height: 100%;\n display: flex;\n flex-direction: column;\n overflow: hidden;\n }\n\n /* When busy, hide projected content but keep cached components attached\n to the DOM so their state survives the loading / error transition. */\n :host(.mj-left-nav-content--busy) ::ng-deep > *:not(.mj-left-nav-content__error):not(.mj-left-nav-content__loading) {\n display: none;\n }\n\n .mj-left-nav-content__error,\n .mj-left-nav-content__loading {\n flex: 1;\n display: flex;\n align-items: center;\n justify-content: center;\n gap: 10px;\n color: var(--mj-text-muted);\n font-size: 13px;\n padding: 32px;\n text-align: center;\n }\n\n .mj-left-nav-content__error {\n color: var(--mj-status-error);\n }\n\n .mj-left-nav-content__error i {\n font-size: 20px;\n }\n\n .mj-left-nav-content__loading i {\n font-size: 16px;\n color: var(--mj-brand-primary);\n }\n `]\n})\nexport class MJLeftNavContentComponent {\n /**\n * When `true`, shows a centered loading state (spinner + label) and hides\n * any projected content via CSS. Cached components remain attached.\n */\n @Input() Loading: boolean = false;\n\n /**\n * When non-empty, shows a centered error state with this message and hides\n * any projected content.\n */\n @Input() Error: string | null = null;\n\n /** Label shown in the loading state. Defaults to \"Loading…\". */\n @Input() LoadingLabel: string = 'Loading…';\n\n /**\n * Drives the busy-state class on the host. When set, CSS hides projected\n * content (cached components stay attached, just not visible).\n */\n @HostBinding('class.mj-left-nav-content--busy')\n get IsBusy(): boolean {\n return this.Loading || !!this.Error;\n }\n\n @HostBinding('attr.aria-busy')\n get AriaBusy(): string | null {\n return this.Loading ? 'true' : null;\n }\n}\n"]}
@@ -0,0 +1,137 @@
1
+ import { EventEmitter } from '@angular/core';
2
+ import * as i0 from "@angular/core";
3
+ /**
4
+ * A single item in an `<mj-left-nav>`.
5
+ */
6
+ export interface MJLeftNavItem {
7
+ /** Stable identifier — used for active-state matching and emitted on click. */
8
+ id: string;
9
+ /** Primary label rendered as the item's main text. */
10
+ label: string;
11
+ /** Optional Font Awesome icon class (e.g. `'fa-solid fa-users'`). */
12
+ icon?: string;
13
+ /** Optional muted secondary line shown under the label. */
14
+ description?: string;
15
+ /** Optional count badge rendered at the right of the item. */
16
+ badge?: string | number;
17
+ /** When `true`, the item renders dimmed and is not clickable. */
18
+ disabled?: boolean;
19
+ /**
20
+ * Optional child items for tree-structured nav (e.g. Testing Explorer's
21
+ * Test Suites tree). When `children` is `undefined` the item renders as a
22
+ * plain flat-list item (existing behavior). When defined — even as an empty
23
+ * array — the item participates in tree rendering: a chevron toggle shows
24
+ * for non-empty arrays, and an equal-width placeholder reserves alignment
25
+ * space for leaves so siblings line up. Expansion state is owned by the
26
+ * consumer via `[ExpandedIds]` on `<mj-left-nav>`.
27
+ */
28
+ children?: MJLeftNavItem[];
29
+ }
30
+ /**
31
+ * A grouped section in an `<mj-left-nav>`. The optional `label` renders as an
32
+ * uppercase section header above the items. Sections WITHOUT a label still
33
+ * group items together (use multiple unlabeled sections to get visual dividers
34
+ * without headers).
35
+ */
36
+ export interface MJLeftNavSection {
37
+ /** Optional uppercase header above the items in this section. */
38
+ label?: string;
39
+ /** The clickable items in this section. */
40
+ items: MJLeftNavItem[];
41
+ }
42
+ /**
43
+ * `<mj-left-nav>` — Canonical left rail for MJ Explorer dashboards that have
44
+ * an internal section-nav (Admin shells, KH Config, KH Analytics, AI Analytics,
45
+ * Communication, Credentials, APIKeys, etc.).
46
+ *
47
+ * Replaces the bespoke `.{name}-nav` / `.{name}-nav-item` patterns each of
48
+ * those dashboards used to declare in their own CSS files.
49
+ *
50
+ * Supports:
51
+ * - Plain items (icon + label)
52
+ * - Items with a muted secondary description line (Admin shells pattern)
53
+ * - Items with a count badge (APIKeys pattern)
54
+ * - Sections with uppercase headers (Communication / Credentials pattern)
55
+ * - Optional `[header]` and `[footer]` content slots (KH Config logo header, etc.)
56
+ * - Responsive collapse-to-row at narrow viewports (consumer controls parent's
57
+ * flex-direction switch; the rail's own styles handle item wrapping + the
58
+ * description-hide behavior)
59
+ *
60
+ * ## Example
61
+ *
62
+ * ```typescript
63
+ * sections: MJLeftNavSection[] = [
64
+ * {
65
+ * items: [
66
+ * { id: 'users', icon: 'fa-solid fa-users', label: 'Users', description: 'Manage user accounts' },
67
+ * { id: 'roles', icon: 'fa-solid fa-user-shield', label: 'Roles', description: 'Define roles and assignments' },
68
+ * ]
69
+ * }
70
+ * ];
71
+ * activeId = 'users';
72
+ * ```
73
+ *
74
+ * ```html
75
+ * <mj-left-nav
76
+ * [Sections]="sections"
77
+ * [ActiveId]="activeId"
78
+ * (ItemClicked)="onItemClicked($event)">
79
+ * </mj-left-nav>
80
+ * ```
81
+ *
82
+ * Responsive collapse — the rail's own CSS handles narrow-viewport item
83
+ * wrapping. The consumer is responsible for switching the parent's
84
+ * flex-direction from row → column at the same breakpoint, e.g. via
85
+ * `<mj-page-body>` Direction="row" with a `@media` override in the shell's CSS.
86
+ */
87
+ export declare class MJLeftNavComponent {
88
+ /**
89
+ * The sections + items that make up the rail. Sections render top-to-bottom
90
+ * in array order; items inside each section render in array order.
91
+ */
92
+ Sections: MJLeftNavSection[];
93
+ /**
94
+ * The id of the currently active item. Items matching this id get the
95
+ * active styling and `aria-current="page"`.
96
+ */
97
+ ActiveId: string | null;
98
+ /**
99
+ * Width of the rail in pixels. Defaults to 240. Set to a smaller value
100
+ * (e.g., 200) for denser shells.
101
+ */
102
+ Width: number;
103
+ /**
104
+ * Ids of currently-expanded tree items. Items whose id appears here render
105
+ * with a down-chevron and their `children` are visible; items not in this
106
+ * list render with a right-chevron and their children stay collapsed.
107
+ * Consumer owns the state — toggle in response to `(ItemToggled)`.
108
+ *
109
+ * Only applies to items where `children !== undefined`; flat items ignore it.
110
+ */
111
+ ExpandedIds: string[];
112
+ /**
113
+ * Emitted when a non-disabled item is clicked.
114
+ */
115
+ ItemClicked: EventEmitter<MJLeftNavItem>;
116
+ /**
117
+ * Emitted when a tree item's chevron is clicked. Consumer should toggle
118
+ * the item's id in / out of `ExpandedIds`. Does NOT also fire `ItemClicked`.
119
+ */
120
+ ItemToggled: EventEmitter<MJLeftNavItem>;
121
+ OnItemClick(item: MJLeftNavItem): void;
122
+ OnItemToggle(event: Event, item: MJLeftNavItem): void;
123
+ IsExpanded(id: string): boolean;
124
+ /**
125
+ * Whether any top-level item in this section actually has children to expand.
126
+ * The template calls this once per section; the result is threaded through
127
+ * the recursive itemTpl so leaf nodes only reserve a chevron-column
128
+ * placeholder when a sibling will actually render a chevron.
129
+ *
130
+ * Top-level check is sufficient — if a deeply-nested item has children, its
131
+ * parent's `children.length > 0` already qualifies the section as expandable.
132
+ */
133
+ HasExpandableItems(items: MJLeftNavItem[]): boolean;
134
+ static ɵfac: i0.ɵɵFactoryDeclaration<MJLeftNavComponent, never>;
135
+ static ɵcmp: i0.ɵɵComponentDeclaration<MJLeftNavComponent, "mj-left-nav", never, { "Sections": { "alias": "Sections"; "required": false; }; "ActiveId": { "alias": "ActiveId"; "required": false; }; "Width": { "alias": "Width"; "required": false; }; "ExpandedIds": { "alias": "ExpandedIds"; "required": false; }; }, { "ItemClicked": "ItemClicked"; "ItemToggled": "ItemToggled"; }, never, ["[header]", "[footer]"], true, never>;
136
+ }
137
+ //# sourceMappingURL=left-nav.component.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"left-nav.component.d.ts","sourceRoot":"","sources":["../../../src/lib/left-nav/left-nav.component.ts"],"names":[],"mappings":"AAAA,OAAO,EAAa,YAAY,EAAiB,MAAM,eAAe,CAAC;;AAGvE;;GAEG;AACH,MAAM,WAAW,aAAa;IAC5B,+EAA+E;IAC/E,EAAE,EAAE,MAAM,CAAC;IACX,sDAAsD;IACtD,KAAK,EAAE,MAAM,CAAC;IACd,qEAAqE;IACrE,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,2DAA2D;IAC3D,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,8DAA8D;IAC9D,KAAK,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC;IACxB,iEAAiE;IACjE,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB;;;;;;;;OAQG;IACH,QAAQ,CAAC,EAAE,aAAa,EAAE,CAAC;CAC5B;AAED;;;;;GAKG;AACH,MAAM,WAAW,gBAAgB;IAC/B,iEAAiE;IACjE,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,2CAA2C;IAC3C,KAAK,EAAE,aAAa,EAAE,CAAC;CACxB;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4CG;AACH,qBAqSa,kBAAkB;IAC7B;;;OAGG;IACM,QAAQ,EAAE,gBAAgB,EAAE,CAAM;IAE3C;;;OAGG;IACM,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAQ;IAExC;;;OAGG;IACM,KAAK,EAAE,MAAM,CAAO;IAE7B;;;;;;;OAOG;IACM,WAAW,EAAE,MAAM,EAAE,CAAM;IAEpC;;OAEG;IACO,WAAW,8BAAqC;IAE1D;;;OAGG;IACO,WAAW,8BAAqC;IAE1D,WAAW,CAAC,IAAI,EAAE,aAAa,GAAG,IAAI;IAKtC,YAAY,CAAC,KAAK,EAAE,KAAK,EAAE,IAAI,EAAE,aAAa,GAAG,IAAI;IAKrD,UAAU,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO;IAI/B;;;;;;;;OAQG;IACH,kBAAkB,CAAC,KAAK,EAAE,aAAa,EAAE,GAAG,OAAO;yCA/DxC,kBAAkB;2CAAlB,kBAAkB;CAqE9B"}