@memberjunction/ng-ui-components 5.34.1 → 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.
- package/dist/lib/button/button.scss +7 -3
- package/dist/lib/filter-chip/filter-chip.component.d.ts +31 -0
- package/dist/lib/filter-chip/filter-chip.component.d.ts.map +1 -0
- package/dist/lib/filter-chip/filter-chip.component.js +94 -0
- package/dist/lib/filter-chip/filter-chip.component.js.map +1 -0
- package/dist/lib/filter-field/filter-field.component.d.ts +22 -0
- package/dist/lib/filter-field/filter-field.component.d.ts.map +1 -0
- package/dist/lib/filter-field/filter-field.component.js +60 -0
- package/dist/lib/filter-field/filter-field.component.js.map +1 -0
- package/dist/lib/filter-panel/filter-panel.component.d.ts +69 -0
- package/dist/lib/filter-panel/filter-panel.component.d.ts.map +1 -0
- package/dist/lib/filter-panel/filter-panel.component.js +203 -0
- package/dist/lib/filter-panel/filter-panel.component.js.map +1 -0
- package/dist/lib/filter-popover/filter-popover.component.d.ts +38 -0
- package/dist/lib/filter-popover/filter-popover.component.d.ts.map +1 -0
- package/dist/lib/filter-popover/filter-popover.component.js +170 -0
- package/dist/lib/filter-popover/filter-popover.component.js.map +1 -0
- package/dist/lib/left-nav/left-nav-content.component.d.ts +53 -0
- package/dist/lib/left-nav/left-nav-content.component.d.ts.map +1 -0
- package/dist/lib/left-nav/left-nav-content.component.js +121 -0
- package/dist/lib/left-nav/left-nav-content.component.js.map +1 -0
- package/dist/lib/left-nav/left-nav.component.d.ts +137 -0
- package/dist/lib/left-nav/left-nav.component.d.ts.map +1 -0
- package/dist/lib/left-nav/left-nav.component.js +399 -0
- package/dist/lib/left-nav/left-nav.component.js.map +1 -0
- package/dist/lib/page-body/page-body.component.d.ts +56 -0
- package/dist/lib/page-body/page-body.component.d.ts.map +1 -0
- package/dist/lib/page-body/page-body.component.js +89 -0
- package/dist/lib/page-body/page-body.component.js.map +1 -0
- package/dist/lib/page-body-interior/page-body-interior.component.d.ts +62 -0
- package/dist/lib/page-body-interior/page-body-interior.component.d.ts.map +1 -0
- package/dist/lib/page-body-interior/page-body-interior.component.js +95 -0
- package/dist/lib/page-body-interior/page-body-interior.component.js.map +1 -0
- package/dist/lib/page-header/page-header.component.d.ts +43 -0
- package/dist/lib/page-header/page-header.component.d.ts.map +1 -0
- package/dist/lib/page-header/page-header.component.js +126 -0
- package/dist/lib/page-header/page-header.component.js.map +1 -0
- package/dist/lib/page-header/page-header.scss +160 -0
- package/dist/lib/page-header-interior/page-header-interior.component.d.ts +96 -0
- package/dist/lib/page-header-interior/page-header-interior.component.d.ts.map +1 -0
- package/dist/lib/page-header-interior/page-header-interior.component.js +176 -0
- package/dist/lib/page-header-interior/page-header-interior.component.js.map +1 -0
- package/dist/lib/page-layout/page-layout.component.d.ts +20 -0
- package/dist/lib/page-layout/page-layout.component.d.ts.map +1 -0
- package/dist/lib/page-layout/page-layout.component.js +30 -0
- package/dist/lib/page-layout/page-layout.component.js.map +1 -0
- package/dist/lib/page-search/page-search.component.d.ts +29 -0
- package/dist/lib/page-search/page-search.component.d.ts.map +1 -0
- package/dist/lib/page-search/page-search.component.js +69 -0
- package/dist/lib/page-search/page-search.component.js.map +1 -0
- package/dist/lib/refresh-button/refresh-button.component.d.ts +46 -0
- package/dist/lib/refresh-button/refresh-button.component.d.ts.map +1 -0
- package/dist/lib/refresh-button/refresh-button.component.js +106 -0
- package/dist/lib/refresh-button/refresh-button.component.js.map +1 -0
- package/dist/lib/stat-badge/stat-badge.component.d.ts +54 -0
- package/dist/lib/stat-badge/stat-badge.component.d.ts.map +1 -0
- package/dist/lib/stat-badge/stat-badge.component.js +162 -0
- package/dist/lib/stat-badge/stat-badge.component.js.map +1 -0
- package/dist/lib/tab-nav/tab-nav.component.d.ts +41 -0
- package/dist/lib/tab-nav/tab-nav.component.d.ts.map +1 -0
- package/dist/lib/tab-nav/tab-nav.component.js +111 -0
- package/dist/lib/tab-nav/tab-nav.component.js.map +1 -0
- package/dist/lib/view-toggle/view-toggle.component.d.ts +42 -0
- package/dist/lib/view-toggle/view-toggle.component.d.ts.map +1 -0
- package/dist/lib/view-toggle/view-toggle.component.js +104 -0
- package/dist/lib/view-toggle/view-toggle.component.js.map +1 -0
- package/dist/public-api.d.ts +16 -0
- package/dist/public-api.d.ts.map +1 -1
- package/dist/public-api.js +16 -0
- package/dist/public-api.js.map +1 -1
- package/package.json +2 -2
|
@@ -0,0 +1,170 @@
|
|
|
1
|
+
import { Component, EventEmitter, Input, Output } from '@angular/core';
|
|
2
|
+
import { OverlayModule } from '@angular/cdk/overlay';
|
|
3
|
+
import * as i0 from "@angular/core";
|
|
4
|
+
import * as i1 from "@angular/cdk/overlay";
|
|
5
|
+
const _c0 = ["*"];
|
|
6
|
+
function MJFilterPopoverComponent_Conditional_5_Template(rf, ctx) { if (rf & 1) {
|
|
7
|
+
i0.ɵɵelementStart(0, "span", 2);
|
|
8
|
+
i0.ɵɵtext(1);
|
|
9
|
+
i0.ɵɵelementEnd();
|
|
10
|
+
} if (rf & 2) {
|
|
11
|
+
const ctx_r1 = i0.ɵɵnextContext();
|
|
12
|
+
i0.ɵɵattribute("aria-label", ctx_r1.ActiveCount + " active filters");
|
|
13
|
+
i0.ɵɵadvance();
|
|
14
|
+
i0.ɵɵtextInterpolate1(" ", ctx_r1.ActiveCount, " ");
|
|
15
|
+
} }
|
|
16
|
+
function MJFilterPopoverComponent_ng_template_7_Conditional_4_Template(rf, ctx) { if (rf & 1) {
|
|
17
|
+
const _r3 = i0.ɵɵgetCurrentView();
|
|
18
|
+
i0.ɵɵelementStart(0, "button", 10);
|
|
19
|
+
i0.ɵɵlistener("click", function MJFilterPopoverComponent_ng_template_7_Conditional_4_Template_button_click_0_listener() { i0.ɵɵrestoreView(_r3); const ctx_r1 = i0.ɵɵnextContext(2); return i0.ɵɵresetView(ctx_r1.ClearAll()); });
|
|
20
|
+
i0.ɵɵtext(1, " Clear all ");
|
|
21
|
+
i0.ɵɵelementEnd();
|
|
22
|
+
} }
|
|
23
|
+
function MJFilterPopoverComponent_ng_template_7_Template(rf, ctx) { if (rf & 1) {
|
|
24
|
+
i0.ɵɵelementStart(0, "div", 5)(1, "div", 6)(2, "span", 7);
|
|
25
|
+
i0.ɵɵtext(3);
|
|
26
|
+
i0.ɵɵelementEnd();
|
|
27
|
+
i0.ɵɵconditionalCreate(4, MJFilterPopoverComponent_ng_template_7_Conditional_4_Template, 2, 0, "button", 8);
|
|
28
|
+
i0.ɵɵelementEnd();
|
|
29
|
+
i0.ɵɵelementStart(5, "div", 9);
|
|
30
|
+
i0.ɵɵprojection(6);
|
|
31
|
+
i0.ɵɵelementEnd()();
|
|
32
|
+
} if (rf & 2) {
|
|
33
|
+
const ctx_r1 = i0.ɵɵnextContext();
|
|
34
|
+
i0.ɵɵattribute("aria-label", ctx_r1.Label);
|
|
35
|
+
i0.ɵɵadvance(3);
|
|
36
|
+
i0.ɵɵtextInterpolate(ctx_r1.Label);
|
|
37
|
+
i0.ɵɵadvance();
|
|
38
|
+
i0.ɵɵconditional(ctx_r1.ActiveCount > 0 && ctx_r1.ShowClearAll ? 4 : -1);
|
|
39
|
+
} }
|
|
40
|
+
/**
|
|
41
|
+
* mj-filter-popover — Compact "Filters" trigger button that opens a popover
|
|
42
|
+
* containing arbitrary filter UI. Use this in a dashboard's page-header to
|
|
43
|
+
* keep the header chrome consistent regardless of filter density.
|
|
44
|
+
*
|
|
45
|
+
* Pass the popover content via `<ng-content>`. Drive the active-count badge
|
|
46
|
+
* via the `ActiveCount` input.
|
|
47
|
+
*
|
|
48
|
+
* Example:
|
|
49
|
+
* ```html
|
|
50
|
+
* <mj-filter-popover [ActiveCount]="activeFilters.length">
|
|
51
|
+
* <div class="my-filter-grid">
|
|
52
|
+
* <mj-dropdown ...></mj-dropdown>
|
|
53
|
+
* <mj-dropdown ...></mj-dropdown>
|
|
54
|
+
* </div>
|
|
55
|
+
* </mj-filter-popover>
|
|
56
|
+
* ```
|
|
57
|
+
*/
|
|
58
|
+
export class MJFilterPopoverComponent {
|
|
59
|
+
Label = 'Filters';
|
|
60
|
+
Icon = 'fa-solid fa-filter';
|
|
61
|
+
ActiveCount = 0;
|
|
62
|
+
ShowClearAll = false;
|
|
63
|
+
IsOpen = false;
|
|
64
|
+
// Note: NO offsetY here — CDK applies offsetY as `transform: translateY(...)` on the
|
|
65
|
+
// overlay pane, which creates a containing block for `position: fixed` descendants.
|
|
66
|
+
// Tree dropdowns (and any other component using position: fixed) would then mis-position.
|
|
67
|
+
// The 6px spacing below the trigger is applied via margin-top on .mj-filter-popover-panel.
|
|
68
|
+
Positions = [
|
|
69
|
+
{ originX: 'end', originY: 'bottom', overlayX: 'end', overlayY: 'top' },
|
|
70
|
+
{ originX: 'start', originY: 'bottom', overlayX: 'start', overlayY: 'top' },
|
|
71
|
+
{ originX: 'end', originY: 'top', overlayX: 'end', overlayY: 'bottom' }
|
|
72
|
+
];
|
|
73
|
+
Toggle() { this.IsOpen = !this.IsOpen; }
|
|
74
|
+
Open() { this.IsOpen = true; }
|
|
75
|
+
Close() { this.IsOpen = false; }
|
|
76
|
+
/** Emitted when the user clicks the "Clear all" link inside the popover header. */
|
|
77
|
+
ClearAllRequested = new EventEmitter();
|
|
78
|
+
ClearAll() {
|
|
79
|
+
this.ClearAllRequested.emit();
|
|
80
|
+
}
|
|
81
|
+
static ɵfac = function MJFilterPopoverComponent_Factory(__ngFactoryType__) { return new (__ngFactoryType__ || MJFilterPopoverComponent)(); };
|
|
82
|
+
static ɵcmp = /*@__PURE__*/ i0.ɵɵdefineComponent({ type: MJFilterPopoverComponent, selectors: [["mj-filter-popover"]], inputs: { Label: "Label", Icon: "Icon", ActiveCount: "ActiveCount", ShowClearAll: "ShowClearAll" }, outputs: { ClearAllRequested: "ClearAllRequested" }, ngContentSelectors: _c0, decls: 8, vars: 14, consts: [["overlayOrigin", "cdkOverlayOrigin"], ["type", "button", "cdkOverlayOrigin", "", 1, "mj-filter-popover-trigger", 3, "click"], [1, "mj-filter-popover-badge"], [1, "fa-solid", "fa-chevron-down", "mj-filter-popover-chevron"], ["cdkConnectedOverlay", "", "cdkConnectedOverlayBackdropClass", "mj-filter-popover-backdrop", 3, "backdropClick", "detach", "cdkConnectedOverlayOrigin", "cdkConnectedOverlayOpen", "cdkConnectedOverlayPositions", "cdkConnectedOverlayHasBackdrop"], ["role", "dialog", 1, "mj-filter-popover-panel"], [1, "mj-filter-popover-header"], [1, "mj-filter-popover-title"], ["type", "button", 1, "mj-filter-popover-clear"], [1, "mj-filter-popover-content"], ["type", "button", 1, "mj-filter-popover-clear", 3, "click"]], template: function MJFilterPopoverComponent_Template(rf, ctx) { if (rf & 1) {
|
|
83
|
+
const _r1 = i0.ɵɵgetCurrentView();
|
|
84
|
+
i0.ɵɵprojectionDef();
|
|
85
|
+
i0.ɵɵelementStart(0, "button", 1, 0);
|
|
86
|
+
i0.ɵɵlistener("click", function MJFilterPopoverComponent_Template_button_click_0_listener() { i0.ɵɵrestoreView(_r1); return i0.ɵɵresetView(ctx.Toggle()); });
|
|
87
|
+
i0.ɵɵelement(2, "i");
|
|
88
|
+
i0.ɵɵelementStart(3, "span");
|
|
89
|
+
i0.ɵɵtext(4);
|
|
90
|
+
i0.ɵɵelementEnd();
|
|
91
|
+
i0.ɵɵconditionalCreate(5, MJFilterPopoverComponent_Conditional_5_Template, 2, 2, "span", 2);
|
|
92
|
+
i0.ɵɵelement(6, "i", 3);
|
|
93
|
+
i0.ɵɵelementEnd();
|
|
94
|
+
i0.ɵɵtemplate(7, MJFilterPopoverComponent_ng_template_7_Template, 7, 3, "ng-template", 4);
|
|
95
|
+
i0.ɵɵlistener("backdropClick", function MJFilterPopoverComponent_Template_ng_template_backdropClick_7_listener() { i0.ɵɵrestoreView(_r1); return i0.ɵɵresetView(ctx.Close()); })("detach", function MJFilterPopoverComponent_Template_ng_template_detach_7_listener() { i0.ɵɵrestoreView(_r1); return i0.ɵɵresetView(ctx.Close()); });
|
|
96
|
+
} if (rf & 2) {
|
|
97
|
+
const overlayOrigin_r4 = i0.ɵɵreference(1);
|
|
98
|
+
i0.ɵɵclassProp("mj-filter-popover-trigger--active", ctx.IsOpen || ctx.ActiveCount > 0);
|
|
99
|
+
i0.ɵɵattribute("aria-expanded", ctx.IsOpen)("aria-haspopup", true);
|
|
100
|
+
i0.ɵɵadvance(2);
|
|
101
|
+
i0.ɵɵclassMap(ctx.Icon);
|
|
102
|
+
i0.ɵɵadvance(2);
|
|
103
|
+
i0.ɵɵtextInterpolate(ctx.Label);
|
|
104
|
+
i0.ɵɵadvance();
|
|
105
|
+
i0.ɵɵconditional(ctx.ActiveCount > 0 ? 5 : -1);
|
|
106
|
+
i0.ɵɵadvance();
|
|
107
|
+
i0.ɵɵclassProp("mj-filter-popover-chevron--open", ctx.IsOpen);
|
|
108
|
+
i0.ɵɵadvance();
|
|
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 \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
|
+
}
|
|
112
|
+
(() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassMetadata(MJFilterPopoverComponent, [{
|
|
113
|
+
type: Component,
|
|
114
|
+
args: [{ selector: 'mj-filter-popover', standalone: true, imports: [OverlayModule], template: `
|
|
115
|
+
<button
|
|
116
|
+
type="button"
|
|
117
|
+
class="mj-filter-popover-trigger"
|
|
118
|
+
[class.mj-filter-popover-trigger--active]="IsOpen || ActiveCount > 0"
|
|
119
|
+
cdkOverlayOrigin
|
|
120
|
+
#overlayOrigin="cdkOverlayOrigin"
|
|
121
|
+
[attr.aria-expanded]="IsOpen"
|
|
122
|
+
[attr.aria-haspopup]="true"
|
|
123
|
+
(click)="Toggle()">
|
|
124
|
+
<i [class]="Icon"></i>
|
|
125
|
+
<span>{{ Label }}</span>
|
|
126
|
+
@if (ActiveCount > 0) {
|
|
127
|
+
<span class="mj-filter-popover-badge" [attr.aria-label]="ActiveCount + ' active filters'">
|
|
128
|
+
{{ ActiveCount }}
|
|
129
|
+
</span>
|
|
130
|
+
}
|
|
131
|
+
<i class="fa-solid fa-chevron-down mj-filter-popover-chevron" [class.mj-filter-popover-chevron--open]="IsOpen"></i>
|
|
132
|
+
</button>
|
|
133
|
+
|
|
134
|
+
<ng-template
|
|
135
|
+
cdkConnectedOverlay
|
|
136
|
+
[cdkConnectedOverlayOrigin]="overlayOrigin"
|
|
137
|
+
[cdkConnectedOverlayOpen]="IsOpen"
|
|
138
|
+
[cdkConnectedOverlayPositions]="Positions"
|
|
139
|
+
[cdkConnectedOverlayHasBackdrop]="true"
|
|
140
|
+
cdkConnectedOverlayBackdropClass="mj-filter-popover-backdrop"
|
|
141
|
+
(backdropClick)="Close()"
|
|
142
|
+
(detach)="Close()">
|
|
143
|
+
<div class="mj-filter-popover-panel" role="dialog" [attr.aria-label]="Label">
|
|
144
|
+
<div class="mj-filter-popover-header">
|
|
145
|
+
<span class="mj-filter-popover-title">{{ Label }}</span>
|
|
146
|
+
@if (ActiveCount > 0 && ShowClearAll) {
|
|
147
|
+
<button type="button" class="mj-filter-popover-clear" (click)="ClearAll()">
|
|
148
|
+
Clear all
|
|
149
|
+
</button>
|
|
150
|
+
}
|
|
151
|
+
</div>
|
|
152
|
+
<div class="mj-filter-popover-content">
|
|
153
|
+
<ng-content></ng-content>
|
|
154
|
+
</div>
|
|
155
|
+
</div>
|
|
156
|
+
</ng-template>
|
|
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
|
+
}], null, { Label: [{
|
|
159
|
+
type: Input
|
|
160
|
+
}], Icon: [{
|
|
161
|
+
type: Input
|
|
162
|
+
}], ActiveCount: [{
|
|
163
|
+
type: Input
|
|
164
|
+
}], ShowClearAll: [{
|
|
165
|
+
type: Input
|
|
166
|
+
}], ClearAllRequested: [{
|
|
167
|
+
type: Output
|
|
168
|
+
}] }); })();
|
|
169
|
+
(() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassDebugInfo(MJFilterPopoverComponent, { className: "MJFilterPopoverComponent", filePath: "lib/filter-popover/filter-popover.component.ts", lineNumber: 189 }); })();
|
|
170
|
+
//# sourceMappingURL=filter-popover.component.js.map
|
|
@@ -0,0 +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;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"}
|