@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
|
@@ -84,17 +84,21 @@
|
|
|
84
84
|
}
|
|
85
85
|
|
|
86
86
|
.mj-btn--secondary {
|
|
87
|
-
background
|
|
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-
|
|
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
|
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import { EventEmitter } from '@angular/core';
|
|
2
|
+
import * as i0 from "@angular/core";
|
|
3
|
+
/**
|
|
4
|
+
* mj-filter-chip — Canonical clickable filter chip / segmented option.
|
|
5
|
+
* Replaces per-page `.filter-chip` rules so styling can't drift.
|
|
6
|
+
*
|
|
7
|
+
* Active state highlights with brand-primary. Optional icon + count.
|
|
8
|
+
*
|
|
9
|
+
* Example:
|
|
10
|
+
* ```html
|
|
11
|
+
* <mj-filter-chip
|
|
12
|
+
* Label="Failed"
|
|
13
|
+
* Icon="fa-solid fa-times-circle"
|
|
14
|
+
* [Active]="statusFilter === 'Failed'"
|
|
15
|
+
* (Clicked)="onStatusFilter('Failed')">
|
|
16
|
+
* </mj-filter-chip>
|
|
17
|
+
*
|
|
18
|
+
* <mj-filter-chip Label="All" [Count]="totalCount" [Active]="!categoryFilter"
|
|
19
|
+
* (Clicked)="onCategoryFilter('')"></mj-filter-chip>
|
|
20
|
+
* ```
|
|
21
|
+
*/
|
|
22
|
+
export declare class MJFilterChipComponent {
|
|
23
|
+
Label: string;
|
|
24
|
+
Icon: string | null;
|
|
25
|
+
Count: number | null;
|
|
26
|
+
Active: boolean;
|
|
27
|
+
Clicked: EventEmitter<void>;
|
|
28
|
+
static ɵfac: i0.ɵɵFactoryDeclaration<MJFilterChipComponent, never>;
|
|
29
|
+
static ɵcmp: i0.ɵɵComponentDeclaration<MJFilterChipComponent, "mj-filter-chip", never, { "Label": { "alias": "Label"; "required": false; }; "Icon": { "alias": "Icon"; "required": false; }; "Count": { "alias": "Count"; "required": false; }; "Active": { "alias": "Active"; "required": false; }; }, { "Clicked": "Clicked"; }, never, never, true, never>;
|
|
30
|
+
}
|
|
31
|
+
//# sourceMappingURL=filter-chip.component.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"filter-chip.component.d.ts","sourceRoot":"","sources":["../../../src/lib/filter-chip/filter-chip.component.ts"],"names":[],"mappings":"AAAA,OAAO,EAAa,YAAY,EAAiB,MAAM,eAAe,CAAC;;AAEvE;;;;;;;;;;;;;;;;;;GAkBG;AACH,qBAmEa,qBAAqB;IACvB,KAAK,EAAE,MAAM,CAAM;IACnB,IAAI,EAAE,MAAM,GAAG,IAAI,CAAQ;IAC3B,KAAK,EAAE,MAAM,GAAG,IAAI,CAAQ;IAC5B,MAAM,EAAE,OAAO,CAAS;IACvB,OAAO,qBAA4B;yCALlC,qBAAqB;2CAArB,qBAAqB;CAMjC"}
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
import { Component, EventEmitter, Input, Output } from '@angular/core';
|
|
2
|
+
import * as i0 from "@angular/core";
|
|
3
|
+
function MJFilterChipComponent_Conditional_1_Template(rf, ctx) { if (rf & 1) {
|
|
4
|
+
i0.ɵɵdomElement(0, "i");
|
|
5
|
+
} if (rf & 2) {
|
|
6
|
+
const ctx_r0 = i0.ɵɵnextContext();
|
|
7
|
+
i0.ɵɵclassMap(ctx_r0.Icon);
|
|
8
|
+
} }
|
|
9
|
+
function MJFilterChipComponent_Conditional_4_Template(rf, ctx) { if (rf & 1) {
|
|
10
|
+
i0.ɵɵdomElementStart(0, "span", 2);
|
|
11
|
+
i0.ɵɵtext(1);
|
|
12
|
+
i0.ɵɵdomElementEnd();
|
|
13
|
+
} if (rf & 2) {
|
|
14
|
+
const ctx_r0 = i0.ɵɵnextContext();
|
|
15
|
+
i0.ɵɵadvance();
|
|
16
|
+
i0.ɵɵtextInterpolate1("(", ctx_r0.Count, ")");
|
|
17
|
+
} }
|
|
18
|
+
/**
|
|
19
|
+
* mj-filter-chip — Canonical clickable filter chip / segmented option.
|
|
20
|
+
* Replaces per-page `.filter-chip` rules so styling can't drift.
|
|
21
|
+
*
|
|
22
|
+
* Active state highlights with brand-primary. Optional icon + count.
|
|
23
|
+
*
|
|
24
|
+
* Example:
|
|
25
|
+
* ```html
|
|
26
|
+
* <mj-filter-chip
|
|
27
|
+
* Label="Failed"
|
|
28
|
+
* Icon="fa-solid fa-times-circle"
|
|
29
|
+
* [Active]="statusFilter === 'Failed'"
|
|
30
|
+
* (Clicked)="onStatusFilter('Failed')">
|
|
31
|
+
* </mj-filter-chip>
|
|
32
|
+
*
|
|
33
|
+
* <mj-filter-chip Label="All" [Count]="totalCount" [Active]="!categoryFilter"
|
|
34
|
+
* (Clicked)="onCategoryFilter('')"></mj-filter-chip>
|
|
35
|
+
* ```
|
|
36
|
+
*/
|
|
37
|
+
export class MJFilterChipComponent {
|
|
38
|
+
Label = '';
|
|
39
|
+
Icon = null;
|
|
40
|
+
Count = null;
|
|
41
|
+
Active = false;
|
|
42
|
+
Clicked = new EventEmitter();
|
|
43
|
+
static ɵfac = function MJFilterChipComponent_Factory(__ngFactoryType__) { return new (__ngFactoryType__ || MJFilterChipComponent)(); };
|
|
44
|
+
static ɵcmp = /*@__PURE__*/ i0.ɵɵdefineComponent({ type: MJFilterChipComponent, selectors: [["mj-filter-chip"]], inputs: { Label: "Label", Icon: "Icon", Count: "Count", Active: "Active" }, outputs: { Clicked: "Clicked" }, decls: 5, vars: 6, consts: [["type", "button", 1, "mj-filter-chip", 3, "click"], [3, "class"], [1, "mj-filter-chip-count"]], template: function MJFilterChipComponent_Template(rf, ctx) { if (rf & 1) {
|
|
45
|
+
i0.ɵɵdomElementStart(0, "button", 0);
|
|
46
|
+
i0.ɵɵdomListener("click", function MJFilterChipComponent_Template_button_click_0_listener() { return ctx.Clicked.emit(); });
|
|
47
|
+
i0.ɵɵconditionalCreate(1, MJFilterChipComponent_Conditional_1_Template, 1, 2, "i", 1);
|
|
48
|
+
i0.ɵɵdomElementStart(2, "span");
|
|
49
|
+
i0.ɵɵtext(3);
|
|
50
|
+
i0.ɵɵdomElementEnd();
|
|
51
|
+
i0.ɵɵconditionalCreate(4, MJFilterChipComponent_Conditional_4_Template, 2, 1, "span", 2);
|
|
52
|
+
i0.ɵɵdomElementEnd();
|
|
53
|
+
} if (rf & 2) {
|
|
54
|
+
i0.ɵɵclassProp("mj-filter-chip--active", ctx.Active);
|
|
55
|
+
i0.ɵɵattribute("aria-pressed", ctx.Active);
|
|
56
|
+
i0.ɵɵadvance();
|
|
57
|
+
i0.ɵɵconditional(ctx.Icon ? 1 : -1);
|
|
58
|
+
i0.ɵɵadvance(2);
|
|
59
|
+
i0.ɵɵtextInterpolate(ctx.Label);
|
|
60
|
+
i0.ɵɵadvance();
|
|
61
|
+
i0.ɵɵconditional(ctx.Count != null ? 4 : -1);
|
|
62
|
+
} }, styles: ["[_nghost-%COMP%] { display: inline-flex; }\n\n .mj-filter-chip[_ngcontent-%COMP%] {\n display: inline-flex;\n align-items: center;\n gap: 6px;\n padding: 5px 12px;\n background: var(--mj-bg-surface-card);\n border: 1px solid var(--mj-border-default);\n border-radius: 16px;\n color: var(--mj-text-secondary);\n font-family: inherit;\n font-size: 12px;\n font-weight: 500;\n line-height: 1.4;\n cursor: pointer;\n transition: background-color 0.15s ease, border-color 0.15s ease, color 0.15s ease;\n white-space: nowrap;\n }\n\n .mj-filter-chip[_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-chip--active[_ngcontent-%COMP%] {\n background: color-mix(in srgb, var(--mj-brand-primary) 12%, var(--mj-bg-surface));\n border-color: color-mix(in srgb, var(--mj-brand-primary) 35%, var(--mj-border-default));\n color: var(--mj-brand-primary);\n }\n\n .mj-filter-chip--active[_ngcontent-%COMP%]:hover {\n background: color-mix(in srgb, var(--mj-brand-primary) 16%, var(--mj-bg-surface));\n }\n\n .mj-filter-chip[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n font-size: 10px;\n flex-shrink: 0;\n }\n\n .mj-filter-chip-count[_ngcontent-%COMP%] {\n opacity: 0.7;\n font-weight: 400;\n }"] });
|
|
63
|
+
}
|
|
64
|
+
(() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassMetadata(MJFilterChipComponent, [{
|
|
65
|
+
type: Component,
|
|
66
|
+
args: [{ selector: 'mj-filter-chip', standalone: true, template: `
|
|
67
|
+
<button
|
|
68
|
+
type="button"
|
|
69
|
+
class="mj-filter-chip"
|
|
70
|
+
[class.mj-filter-chip--active]="Active"
|
|
71
|
+
[attr.aria-pressed]="Active"
|
|
72
|
+
(click)="Clicked.emit()">
|
|
73
|
+
@if (Icon) {
|
|
74
|
+
<i [class]="Icon"></i>
|
|
75
|
+
}
|
|
76
|
+
<span>{{ Label }}</span>
|
|
77
|
+
@if (Count != null) {
|
|
78
|
+
<span class="mj-filter-chip-count">({{ Count }})</span>
|
|
79
|
+
}
|
|
80
|
+
</button>
|
|
81
|
+
`, styles: ["\n :host { display: inline-flex; }\n\n .mj-filter-chip {\n display: inline-flex;\n align-items: center;\n gap: 6px;\n padding: 5px 12px;\n background: var(--mj-bg-surface-card);\n border: 1px solid var(--mj-border-default);\n border-radius: 16px;\n color: var(--mj-text-secondary);\n font-family: inherit;\n font-size: 12px;\n font-weight: 500;\n line-height: 1.4;\n cursor: pointer;\n transition: background-color 0.15s ease, border-color 0.15s ease, color 0.15s ease;\n white-space: nowrap;\n }\n\n .mj-filter-chip: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-chip--active {\n background: color-mix(in srgb, var(--mj-brand-primary) 12%, var(--mj-bg-surface));\n border-color: color-mix(in srgb, var(--mj-brand-primary) 35%, var(--mj-border-default));\n color: var(--mj-brand-primary);\n }\n\n .mj-filter-chip--active:hover {\n background: color-mix(in srgb, var(--mj-brand-primary) 16%, var(--mj-bg-surface));\n }\n\n .mj-filter-chip i {\n font-size: 10px;\n flex-shrink: 0;\n }\n\n .mj-filter-chip-count {\n opacity: 0.7;\n font-weight: 400;\n }\n "] }]
|
|
82
|
+
}], null, { Label: [{
|
|
83
|
+
type: Input
|
|
84
|
+
}], Icon: [{
|
|
85
|
+
type: Input
|
|
86
|
+
}], Count: [{
|
|
87
|
+
type: Input
|
|
88
|
+
}], Active: [{
|
|
89
|
+
type: Input
|
|
90
|
+
}], Clicked: [{
|
|
91
|
+
type: Output
|
|
92
|
+
}] }); })();
|
|
93
|
+
(() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassDebugInfo(MJFilterChipComponent, { className: "MJFilterChipComponent", filePath: "lib/filter-chip/filter-chip.component.ts", lineNumber: 89 }); })();
|
|
94
|
+
//# sourceMappingURL=filter-chip.component.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"filter-chip.component.js","sourceRoot":"","sources":["../../../src/lib/filter-chip/filter-chip.component.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,YAAY,EAAE,KAAK,EAAE,MAAM,EAAE,MAAM,eAAe,CAAC;;;IAgC/D,uBAAsB;;;IAAnB,0BAAc;;;IAIjB,kCAAmC;IAAA,YAAa;IAAA,oBAAO;;;IAApB,cAAa;IAAb,6CAAa;;AAlCxD;;;;;;;;;;;;;;;;;;GAkBG;AAoEH,MAAM,OAAO,qBAAqB;IACvB,KAAK,GAAW,EAAE,CAAC;IACnB,IAAI,GAAkB,IAAI,CAAC;IAC3B,KAAK,GAAkB,IAAI,CAAC;IAC5B,MAAM,GAAY,KAAK,CAAC;IACvB,OAAO,GAAG,IAAI,YAAY,EAAQ,CAAC;+GALlC,qBAAqB;6DAArB,qBAAqB;YA/D9B,oCAK2B;YAAzB,qGAAS,kBAAc,IAAC;YACxB,qFAAY;YAGZ,+BAAM;YAAA,YAAW;YAAA,oBAAO;YACxB,wFAAqB;YAGvB,oBAAS;;YAVP,oDAAuC;;YAGvC,cAEC;YAFD,mCAEC;YACK,eAAW;YAAX,+BAAW;YACjB,cAEC;YAFD,4CAEC;;;iFAmDM,qBAAqB;cAnEjC,SAAS;2BACE,gBAAgB,cACd,IAAI,YACN;;;;;;;;;;;;;;;GAeT;;kBAkDA,KAAK;;kBACL,KAAK;;kBACL,KAAK;;kBACL,KAAK;;kBACL,MAAM;;kFALI,qBAAqB","sourcesContent":["import { Component, EventEmitter, Input, Output } from '@angular/core';\n\n/**\n * mj-filter-chip — Canonical clickable filter chip / segmented option.\n * Replaces per-page `.filter-chip` rules so styling can't drift.\n *\n * Active state highlights with brand-primary. Optional icon + count.\n *\n * Example:\n * ```html\n * <mj-filter-chip\n * Label=\"Failed\"\n * Icon=\"fa-solid fa-times-circle\"\n * [Active]=\"statusFilter === 'Failed'\"\n * (Clicked)=\"onStatusFilter('Failed')\">\n * </mj-filter-chip>\n *\n * <mj-filter-chip Label=\"All\" [Count]=\"totalCount\" [Active]=\"!categoryFilter\"\n * (Clicked)=\"onCategoryFilter('')\"></mj-filter-chip>\n * ```\n */\n@Component({\n selector: 'mj-filter-chip',\n standalone: true,\n template: `\n <button\n type=\"button\"\n class=\"mj-filter-chip\"\n [class.mj-filter-chip--active]=\"Active\"\n [attr.aria-pressed]=\"Active\"\n (click)=\"Clicked.emit()\">\n @if (Icon) {\n <i [class]=\"Icon\"></i>\n }\n <span>{{ Label }}</span>\n @if (Count != null) {\n <span class=\"mj-filter-chip-count\">({{ Count }})</span>\n }\n </button>\n `,\n styles: [`\n :host { display: inline-flex; }\n\n .mj-filter-chip {\n display: inline-flex;\n align-items: center;\n gap: 6px;\n padding: 5px 12px;\n background: var(--mj-bg-surface-card);\n border: 1px solid var(--mj-border-default);\n border-radius: 16px;\n color: var(--mj-text-secondary);\n font-family: inherit;\n font-size: 12px;\n font-weight: 500;\n line-height: 1.4;\n cursor: pointer;\n transition: background-color 0.15s ease, border-color 0.15s ease, color 0.15s ease;\n white-space: nowrap;\n }\n\n .mj-filter-chip: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-chip--active {\n background: color-mix(in srgb, var(--mj-brand-primary) 12%, var(--mj-bg-surface));\n border-color: color-mix(in srgb, var(--mj-brand-primary) 35%, var(--mj-border-default));\n color: var(--mj-brand-primary);\n }\n\n .mj-filter-chip--active:hover {\n background: color-mix(in srgb, var(--mj-brand-primary) 16%, var(--mj-bg-surface));\n }\n\n .mj-filter-chip i {\n font-size: 10px;\n flex-shrink: 0;\n }\n\n .mj-filter-chip-count {\n opacity: 0.7;\n font-weight: 400;\n }\n `]\n})\nexport class MJFilterChipComponent {\n @Input() Label: string = '';\n @Input() Icon: string | null = null;\n @Input() Count: number | null = null;\n @Input() Active: boolean = false;\n @Output() Clicked = new EventEmitter<void>();\n}\n"]}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import * as i0 from "@angular/core";
|
|
2
|
+
/**
|
|
3
|
+
* mj-filter-field — Single row inside a filter panel: icon + label above a projected widget.
|
|
4
|
+
* Used either by `<mj-filter-panel>` internally (for config-driven fields) or directly in
|
|
5
|
+
* a page template as the escape hatch for custom widgets (tree-dropdown, date-range, etc.).
|
|
6
|
+
*
|
|
7
|
+
* Example (standalone usage for a custom widget):
|
|
8
|
+
* ```html
|
|
9
|
+
* <mj-filter-panel ...>
|
|
10
|
+
* <mj-filter-field Label="Category" Icon="fa-solid fa-folder">
|
|
11
|
+
* <mj-tree-dropdown ...></mj-tree-dropdown>
|
|
12
|
+
* </mj-filter-field>
|
|
13
|
+
* </mj-filter-panel>
|
|
14
|
+
* ```
|
|
15
|
+
*/
|
|
16
|
+
export declare class MJFilterFieldComponent {
|
|
17
|
+
Label: string;
|
|
18
|
+
Icon: string | null;
|
|
19
|
+
static ɵfac: i0.ɵɵFactoryDeclaration<MJFilterFieldComponent, never>;
|
|
20
|
+
static ɵcmp: i0.ɵɵComponentDeclaration<MJFilterFieldComponent, "mj-filter-field", never, { "Label": { "alias": "Label"; "required": false; }; "Icon": { "alias": "Icon"; "required": false; }; }, {}, never, ["*"], true, never>;
|
|
21
|
+
}
|
|
22
|
+
//# sourceMappingURL=filter-field.component.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"filter-field.component.d.ts","sourceRoot":"","sources":["../../../src/lib/filter-field/filter-field.component.ts"],"names":[],"mappings":";AAEA;;;;;;;;;;;;;GAaG;AACH,qBAsCa,sBAAsB;IACxB,KAAK,EAAE,MAAM,CAAM;IACnB,IAAI,EAAE,MAAM,GAAG,IAAI,CAAQ;yCAFzB,sBAAsB;2CAAtB,sBAAsB;CAGlC"}
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
import { Component, Input } from '@angular/core';
|
|
2
|
+
import * as i0 from "@angular/core";
|
|
3
|
+
const _c0 = ["*"];
|
|
4
|
+
function MJFilterFieldComponent_Conditional_2_Template(rf, ctx) { if (rf & 1) {
|
|
5
|
+
i0.ɵɵdomElement(0, "i");
|
|
6
|
+
} if (rf & 2) {
|
|
7
|
+
const ctx_r0 = i0.ɵɵnextContext();
|
|
8
|
+
i0.ɵɵclassMap(ctx_r0.Icon);
|
|
9
|
+
} }
|
|
10
|
+
/**
|
|
11
|
+
* mj-filter-field — Single row inside a filter panel: icon + label above a projected widget.
|
|
12
|
+
* Used either by `<mj-filter-panel>` internally (for config-driven fields) or directly in
|
|
13
|
+
* a page template as the escape hatch for custom widgets (tree-dropdown, date-range, etc.).
|
|
14
|
+
*
|
|
15
|
+
* Example (standalone usage for a custom widget):
|
|
16
|
+
* ```html
|
|
17
|
+
* <mj-filter-panel ...>
|
|
18
|
+
* <mj-filter-field Label="Category" Icon="fa-solid fa-folder">
|
|
19
|
+
* <mj-tree-dropdown ...></mj-tree-dropdown>
|
|
20
|
+
* </mj-filter-field>
|
|
21
|
+
* </mj-filter-panel>
|
|
22
|
+
* ```
|
|
23
|
+
*/
|
|
24
|
+
export class MJFilterFieldComponent {
|
|
25
|
+
Label = '';
|
|
26
|
+
Icon = null;
|
|
27
|
+
static ɵfac = function MJFilterFieldComponent_Factory(__ngFactoryType__) { return new (__ngFactoryType__ || MJFilterFieldComponent)(); };
|
|
28
|
+
static ɵcmp = /*@__PURE__*/ i0.ɵɵdefineComponent({ type: MJFilterFieldComponent, selectors: [["mj-filter-field"]], inputs: { Label: "Label", Icon: "Icon" }, ngContentSelectors: _c0, decls: 5, vars: 2, consts: [[1, "mj-filter-field"], [1, "mj-filter-field-label"], [3, "class"]], template: function MJFilterFieldComponent_Template(rf, ctx) { if (rf & 1) {
|
|
29
|
+
i0.ɵɵprojectionDef();
|
|
30
|
+
i0.ɵɵdomElementStart(0, "label", 0)(1, "span", 1);
|
|
31
|
+
i0.ɵɵconditionalCreate(2, MJFilterFieldComponent_Conditional_2_Template, 1, 2, "i", 2);
|
|
32
|
+
i0.ɵɵtext(3);
|
|
33
|
+
i0.ɵɵdomElementEnd();
|
|
34
|
+
i0.ɵɵprojection(4);
|
|
35
|
+
i0.ɵɵdomElementEnd();
|
|
36
|
+
} if (rf & 2) {
|
|
37
|
+
i0.ɵɵadvance(2);
|
|
38
|
+
i0.ɵɵconditional(ctx.Icon ? 2 : -1);
|
|
39
|
+
i0.ɵɵadvance();
|
|
40
|
+
i0.ɵɵtextInterpolate1(" ", ctx.Label, " ");
|
|
41
|
+
} }, styles: ["[_nghost-%COMP%] { display: block; }\n\n .mj-filter-field[_ngcontent-%COMP%] {\n display: flex;\n flex-direction: column;\n gap: 6px;\n }\n\n .mj-filter-field-label[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: 6px;\n font-size: 11px;\n font-weight: 600;\n text-transform: uppercase;\n letter-spacing: 0.04em;\n color: var(--mj-brand-primary);\n }\n\n .mj-filter-field-label[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n font-size: 11px;\n color: var(--mj-brand-primary);\n }"] });
|
|
42
|
+
}
|
|
43
|
+
(() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassMetadata(MJFilterFieldComponent, [{
|
|
44
|
+
type: Component,
|
|
45
|
+
args: [{ selector: 'mj-filter-field', standalone: true, template: `
|
|
46
|
+
<label class="mj-filter-field">
|
|
47
|
+
<span class="mj-filter-field-label">
|
|
48
|
+
@if (Icon) { <i [class]="Icon"></i> }
|
|
49
|
+
{{ Label }}
|
|
50
|
+
</span>
|
|
51
|
+
<ng-content></ng-content>
|
|
52
|
+
</label>
|
|
53
|
+
`, styles: ["\n :host { display: block; }\n\n .mj-filter-field {\n display: flex;\n flex-direction: column;\n gap: 6px;\n }\n\n .mj-filter-field-label {\n display: flex;\n align-items: center;\n gap: 6px;\n font-size: 11px;\n font-weight: 600;\n text-transform: uppercase;\n letter-spacing: 0.04em;\n color: var(--mj-brand-primary);\n }\n\n .mj-filter-field-label i {\n font-size: 11px;\n color: var(--mj-brand-primary);\n }\n "] }]
|
|
54
|
+
}], null, { Label: [{
|
|
55
|
+
type: Input
|
|
56
|
+
}], Icon: [{
|
|
57
|
+
type: Input
|
|
58
|
+
}] }); })();
|
|
59
|
+
(() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassDebugInfo(MJFilterFieldComponent, { className: "MJFilterFieldComponent", filePath: "lib/filter-field/filter-field.component.ts", lineNumber: 55 }); })();
|
|
60
|
+
//# sourceMappingURL=filter-field.component.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"filter-field.component.js","sourceRoot":"","sources":["../../../src/lib/filter-field/filter-field.component.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,KAAK,EAAE,MAAM,eAAe,CAAC;;;;IAsB5B,uBAAsB;;;IAAnB,0BAAc;;AApBtC;;;;;;;;;;;;;GAaG;AAuCH,MAAM,OAAO,sBAAsB;IACxB,KAAK,GAAW,EAAE,CAAC;IACnB,IAAI,GAAkB,IAAI,CAAC;gHAFzB,sBAAsB;6DAAtB,sBAAsB;;YAjC7B,AADF,mCAA+B,cACO;YAClC,sFAAY;YACZ,YACF;YAAA,oBAAO;YACP,kBAAyB;YAC3B,oBAAQ;;YAJJ,eAAqC;YAArC,mCAAqC;YACrC,cACF;YADE,0CACF;;;iFA8BO,sBAAsB;cAtClC,SAAS;2BACE,iBAAiB,cACf,IAAI,YACN;;;;;;;;GAQT;;kBA4BA,KAAK;;kBACL,KAAK;;kFAFK,sBAAsB","sourcesContent":["import { Component, Input } from '@angular/core';\n\n/**\n * mj-filter-field — Single row inside a filter panel: icon + label above a projected widget.\n * Used either by `<mj-filter-panel>` internally (for config-driven fields) or directly in\n * a page template as the escape hatch for custom widgets (tree-dropdown, date-range, etc.).\n *\n * Example (standalone usage for a custom widget):\n * ```html\n * <mj-filter-panel ...>\n * <mj-filter-field Label=\"Category\" Icon=\"fa-solid fa-folder\">\n * <mj-tree-dropdown ...></mj-tree-dropdown>\n * </mj-filter-field>\n * </mj-filter-panel>\n * ```\n */\n@Component({\n selector: 'mj-filter-field',\n standalone: true,\n template: `\n <label class=\"mj-filter-field\">\n <span class=\"mj-filter-field-label\">\n @if (Icon) { <i [class]=\"Icon\"></i> }\n {{ Label }}\n </span>\n <ng-content></ng-content>\n </label>\n `,\n styles: [`\n :host { display: block; }\n\n .mj-filter-field {\n display: flex;\n flex-direction: column;\n gap: 6px;\n }\n\n .mj-filter-field-label {\n display: flex;\n align-items: center;\n gap: 6px;\n font-size: 11px;\n font-weight: 600;\n text-transform: uppercase;\n letter-spacing: 0.04em;\n color: var(--mj-brand-primary);\n }\n\n .mj-filter-field-label i {\n font-size: 11px;\n color: var(--mj-brand-primary);\n }\n `]\n})\nexport class MJFilterFieldComponent {\n @Input() Label: string = '';\n @Input() Icon: string | null = null;\n}\n"]}
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
import { EventEmitter } from '@angular/core';
|
|
2
|
+
import * as i0 from "@angular/core";
|
|
3
|
+
/** Field types supported natively by <mj-filter-panel>. */
|
|
4
|
+
export type FilterFieldType = 'text' | 'dropdown' | 'chips';
|
|
5
|
+
/** Per-field config understood by <mj-filter-panel>. */
|
|
6
|
+
export interface FilterFieldConfig {
|
|
7
|
+
/** State key in the Values record. */
|
|
8
|
+
key: string;
|
|
9
|
+
/** Field type — drives which widget is rendered. */
|
|
10
|
+
type: FilterFieldType;
|
|
11
|
+
/** Display label. */
|
|
12
|
+
label: string;
|
|
13
|
+
/** Optional Font Awesome icon class (e.g. 'fa-solid fa-folder'). */
|
|
14
|
+
icon?: string;
|
|
15
|
+
/** Placeholder for text inputs / dropdowns. */
|
|
16
|
+
placeholder?: string;
|
|
17
|
+
/** Dropdown options (when type === 'dropdown'). Each option needs text + value. */
|
|
18
|
+
options?: {
|
|
19
|
+
text: string;
|
|
20
|
+
value: string | number | boolean | null;
|
|
21
|
+
}[];
|
|
22
|
+
/** Whether the dropdown should show an internal search box. */
|
|
23
|
+
filterable?: boolean;
|
|
24
|
+
/** Chip-group options (when type === 'chips'). */
|
|
25
|
+
chipOptions?: {
|
|
26
|
+
text: string;
|
|
27
|
+
value: string | number | boolean | null;
|
|
28
|
+
icon?: string;
|
|
29
|
+
}[];
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
32
|
+
* mj-filter-panel — Single centralized filter panel for all dashboards.
|
|
33
|
+
*
|
|
34
|
+
* Config-driven: pass an array of `FilterFieldConfig` plus a `Values` record;
|
|
35
|
+
* the panel renders each field using the appropriate widget (text input,
|
|
36
|
+
* `<mj-dropdown>`, or chip group), keeps everything visually consistent, and
|
|
37
|
+
* emits state changes via `(ValuesChange)`.
|
|
38
|
+
*
|
|
39
|
+
* For widgets not covered by the config schema (tree-dropdown, date pickers,
|
|
40
|
+
* etc.), project `<mj-filter-field>` elements as content — they render below
|
|
41
|
+
* the config-driven fields with identical chrome.
|
|
42
|
+
*
|
|
43
|
+
* Example:
|
|
44
|
+
* ```html
|
|
45
|
+
* <mj-filter-panel
|
|
46
|
+
* [Fields]="filterFields"
|
|
47
|
+
* [(Values)]="filterValues"
|
|
48
|
+
* (Reset)="onReset()">
|
|
49
|
+
*
|
|
50
|
+
* <!-- escape hatch for custom widgets -->
|
|
51
|
+
* <mj-filter-field Label="Category" Icon="fa-solid fa-folder">
|
|
52
|
+
* <mj-tree-dropdown ...></mj-tree-dropdown>
|
|
53
|
+
* </mj-filter-field>
|
|
54
|
+
* </mj-filter-panel>
|
|
55
|
+
* ```
|
|
56
|
+
*/
|
|
57
|
+
export declare class MJFilterPanelComponent {
|
|
58
|
+
Fields: FilterFieldConfig[];
|
|
59
|
+
Values: Record<string, unknown>;
|
|
60
|
+
ShowReset: boolean;
|
|
61
|
+
ResetLabel: string;
|
|
62
|
+
ValuesChange: EventEmitter<Record<string, unknown>>;
|
|
63
|
+
Reset: EventEmitter<void>;
|
|
64
|
+
getValue(key: string): unknown;
|
|
65
|
+
setValue(key: string, value: unknown): void;
|
|
66
|
+
static ɵfac: i0.ɵɵFactoryDeclaration<MJFilterPanelComponent, never>;
|
|
67
|
+
static ɵcmp: i0.ɵɵComponentDeclaration<MJFilterPanelComponent, "mj-filter-panel", never, { "Fields": { "alias": "Fields"; "required": false; }; "Values": { "alias": "Values"; "required": false; }; "ShowReset": { "alias": "ShowReset"; "required": false; }; "ResetLabel": { "alias": "ResetLabel"; "required": false; }; }, { "ValuesChange": "ValuesChange"; "Reset": "Reset"; }, never, ["*"], true, never>;
|
|
68
|
+
}
|
|
69
|
+
//# sourceMappingURL=filter-panel.component.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"filter-panel.component.d.ts","sourceRoot":"","sources":["../../../src/lib/filter-panel/filter-panel.component.ts"],"names":[],"mappings":"AAAA,OAAO,EAAa,YAAY,EAAiB,MAAM,eAAe,CAAC;;AAOvE,2DAA2D;AAC3D,MAAM,MAAM,eAAe,GAAG,MAAM,GAAG,UAAU,GAAG,OAAO,CAAC;AAE5D,wDAAwD;AACxD,MAAM,WAAW,iBAAiB;IAChC,sCAAsC;IACtC,GAAG,EAAE,MAAM,CAAC;IACZ,oDAAoD;IACpD,IAAI,EAAE,eAAe,CAAC;IACtB,qBAAqB;IACrB,KAAK,EAAE,MAAM,CAAC;IACd,oEAAoE;IACpE,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,+CAA+C;IAC/C,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,mFAAmF;IACnF,OAAO,CAAC,EAAE;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,GAAG,MAAM,GAAG,OAAO,GAAG,IAAI,CAAA;KAAE,EAAE,CAAC;IACtE,+DAA+D;IAC/D,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,kDAAkD;IAClD,WAAW,CAAC,EAAE;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,GAAG,MAAM,GAAG,OAAO,GAAG,IAAI,CAAC;QAAC,IAAI,CAAC,EAAE,MAAM,CAAA;KAAE,EAAE,CAAC;CAC1F;AAED;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG;AACH,qBA0Ia,sBAAsB;IACxB,MAAM,EAAE,iBAAiB,EAAE,CAAM;IACjC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAM;IACrC,SAAS,EAAE,OAAO,CAAQ;IAC1B,UAAU,EAAE,MAAM,CAAmB;IAEpC,YAAY,wCAA+C;IAC3D,KAAK,qBAA4B;IAEpC,QAAQ,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO;IAI9B,QAAQ,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,OAAO,GAAG,IAAI;yCAbvC,sBAAsB;2CAAtB,sBAAsB;CAiBlC"}
|
|
@@ -0,0 +1,203 @@
|
|
|
1
|
+
import { Component, EventEmitter, Input, Output } from '@angular/core';
|
|
2
|
+
import { CommonModule } from '@angular/common';
|
|
3
|
+
import { FormsModule } from '@angular/forms';
|
|
4
|
+
import { MJDropdownComponent } from '../dropdown/dropdown.component';
|
|
5
|
+
import { MJFilterChipComponent } from '../filter-chip/filter-chip.component';
|
|
6
|
+
import { MJFilterFieldComponent } from '../filter-field/filter-field.component';
|
|
7
|
+
import * as i0 from "@angular/core";
|
|
8
|
+
import * as i1 from "@angular/forms";
|
|
9
|
+
const _c0 = ["*"];
|
|
10
|
+
const _c1 = () => [];
|
|
11
|
+
const _forTrack0 = ($index, $item) => $item.key;
|
|
12
|
+
const _forTrack1 = ($index, $item) => $item.value;
|
|
13
|
+
function MJFilterPanelComponent_For_3_Case_1_Template(rf, ctx) { if (rf & 1) {
|
|
14
|
+
const _r1 = i0.ɵɵgetCurrentView();
|
|
15
|
+
i0.ɵɵelementStart(0, "input", 7);
|
|
16
|
+
i0.ɵɵlistener("input", function MJFilterPanelComponent_For_3_Case_1_Template_input_input_0_listener($event) { i0.ɵɵrestoreView(_r1); const field_r2 = i0.ɵɵnextContext().$implicit; const ctx_r2 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r2.setValue(field_r2.key, $event.target.value)); });
|
|
17
|
+
i0.ɵɵelementEnd();
|
|
18
|
+
} if (rf & 2) {
|
|
19
|
+
const field_r2 = i0.ɵɵnextContext().$implicit;
|
|
20
|
+
const ctx_r2 = i0.ɵɵnextContext();
|
|
21
|
+
i0.ɵɵproperty("value", ctx_r2.getValue(field_r2.key) ?? "")("placeholder", field_r2.placeholder ?? "");
|
|
22
|
+
} }
|
|
23
|
+
function MJFilterPanelComponent_For_3_Case_2_Template(rf, ctx) { if (rf & 1) {
|
|
24
|
+
const _r4 = i0.ɵɵgetCurrentView();
|
|
25
|
+
i0.ɵɵelementStart(0, "mj-dropdown", 8);
|
|
26
|
+
i0.ɵɵlistener("ngModelChange", function MJFilterPanelComponent_For_3_Case_2_Template_mj_dropdown_ngModelChange_0_listener($event) { i0.ɵɵrestoreView(_r4); const field_r2 = i0.ɵɵnextContext().$implicit; const ctx_r2 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r2.setValue(field_r2.key, $event)); });
|
|
27
|
+
i0.ɵɵelementEnd();
|
|
28
|
+
} if (rf & 2) {
|
|
29
|
+
const field_r2 = i0.ɵɵnextContext().$implicit;
|
|
30
|
+
const ctx_r2 = i0.ɵɵnextContext();
|
|
31
|
+
i0.ɵɵproperty("Data", field_r2.options ?? i0.ɵɵpureFunction0(5, _c1))("ValuePrimitive", true)("Filterable", !!field_r2.filterable)("Placeholder", field_r2.placeholder ?? "")("ngModel", ctx_r2.getValue(field_r2.key));
|
|
32
|
+
} }
|
|
33
|
+
function MJFilterPanelComponent_For_3_Case_3_For_2_Template(rf, ctx) { if (rf & 1) {
|
|
34
|
+
const _r5 = i0.ɵɵgetCurrentView();
|
|
35
|
+
i0.ɵɵelementStart(0, "mj-filter-chip", 10);
|
|
36
|
+
i0.ɵɵlistener("Clicked", function MJFilterPanelComponent_For_3_Case_3_For_2_Template_mj_filter_chip_Clicked_0_listener() { const opt_r6 = i0.ɵɵrestoreView(_r5).$implicit; const field_r2 = i0.ɵɵnextContext(2).$implicit; const ctx_r2 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r2.setValue(field_r2.key, opt_r6.value)); });
|
|
37
|
+
i0.ɵɵelementEnd();
|
|
38
|
+
} if (rf & 2) {
|
|
39
|
+
const opt_r6 = ctx.$implicit;
|
|
40
|
+
const field_r2 = i0.ɵɵnextContext(2).$implicit;
|
|
41
|
+
const ctx_r2 = i0.ɵɵnextContext();
|
|
42
|
+
i0.ɵɵproperty("Label", opt_r6.text)("Icon", opt_r6.icon ?? null)("Active", ctx_r2.getValue(field_r2.key) === opt_r6.value);
|
|
43
|
+
} }
|
|
44
|
+
function MJFilterPanelComponent_For_3_Case_3_Template(rf, ctx) { if (rf & 1) {
|
|
45
|
+
i0.ɵɵelementStart(0, "div", 6);
|
|
46
|
+
i0.ɵɵrepeaterCreate(1, MJFilterPanelComponent_For_3_Case_3_For_2_Template, 1, 3, "mj-filter-chip", 9, _forTrack1);
|
|
47
|
+
i0.ɵɵelementEnd();
|
|
48
|
+
} if (rf & 2) {
|
|
49
|
+
const field_r2 = i0.ɵɵnextContext().$implicit;
|
|
50
|
+
i0.ɵɵadvance();
|
|
51
|
+
i0.ɵɵrepeater(field_r2.chipOptions ?? i0.ɵɵpureFunction0(0, _c1));
|
|
52
|
+
} }
|
|
53
|
+
function MJFilterPanelComponent_For_3_Template(rf, ctx) { if (rf & 1) {
|
|
54
|
+
i0.ɵɵelementStart(0, "mj-filter-field", 2);
|
|
55
|
+
i0.ɵɵconditionalCreate(1, MJFilterPanelComponent_For_3_Case_1_Template, 1, 2, "input", 4)(2, MJFilterPanelComponent_For_3_Case_2_Template, 1, 6, "mj-dropdown", 5)(3, MJFilterPanelComponent_For_3_Case_3_Template, 3, 1, "div", 6);
|
|
56
|
+
i0.ɵɵelementEnd();
|
|
57
|
+
} if (rf & 2) {
|
|
58
|
+
let tmp_12_0;
|
|
59
|
+
const field_r2 = ctx.$implicit;
|
|
60
|
+
i0.ɵɵproperty("Label", field_r2.label)("Icon", field_r2.icon ?? null);
|
|
61
|
+
i0.ɵɵadvance();
|
|
62
|
+
i0.ɵɵconditional((tmp_12_0 = field_r2.type) === "text" ? 1 : tmp_12_0 === "dropdown" ? 2 : tmp_12_0 === "chips" ? 3 : -1);
|
|
63
|
+
} }
|
|
64
|
+
function MJFilterPanelComponent_Conditional_5_Template(rf, ctx) { if (rf & 1) {
|
|
65
|
+
const _r7 = i0.ɵɵgetCurrentView();
|
|
66
|
+
i0.ɵɵelementStart(0, "div", 3)(1, "button", 11);
|
|
67
|
+
i0.ɵɵlistener("click", function MJFilterPanelComponent_Conditional_5_Template_button_click_1_listener() { i0.ɵɵrestoreView(_r7); const ctx_r2 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r2.Reset.emit()); });
|
|
68
|
+
i0.ɵɵelement(2, "i", 12);
|
|
69
|
+
i0.ɵɵtext(3);
|
|
70
|
+
i0.ɵɵelementEnd()();
|
|
71
|
+
} if (rf & 2) {
|
|
72
|
+
const ctx_r2 = i0.ɵɵnextContext();
|
|
73
|
+
i0.ɵɵadvance(3);
|
|
74
|
+
i0.ɵɵtextInterpolate1(" ", ctx_r2.ResetLabel, " ");
|
|
75
|
+
} }
|
|
76
|
+
/**
|
|
77
|
+
* mj-filter-panel — Single centralized filter panel for all dashboards.
|
|
78
|
+
*
|
|
79
|
+
* Config-driven: pass an array of `FilterFieldConfig` plus a `Values` record;
|
|
80
|
+
* the panel renders each field using the appropriate widget (text input,
|
|
81
|
+
* `<mj-dropdown>`, or chip group), keeps everything visually consistent, and
|
|
82
|
+
* emits state changes via `(ValuesChange)`.
|
|
83
|
+
*
|
|
84
|
+
* For widgets not covered by the config schema (tree-dropdown, date pickers,
|
|
85
|
+
* etc.), project `<mj-filter-field>` elements as content — they render below
|
|
86
|
+
* the config-driven fields with identical chrome.
|
|
87
|
+
*
|
|
88
|
+
* Example:
|
|
89
|
+
* ```html
|
|
90
|
+
* <mj-filter-panel
|
|
91
|
+
* [Fields]="filterFields"
|
|
92
|
+
* [(Values)]="filterValues"
|
|
93
|
+
* (Reset)="onReset()">
|
|
94
|
+
*
|
|
95
|
+
* <!-- escape hatch for custom widgets -->
|
|
96
|
+
* <mj-filter-field Label="Category" Icon="fa-solid fa-folder">
|
|
97
|
+
* <mj-tree-dropdown ...></mj-tree-dropdown>
|
|
98
|
+
* </mj-filter-field>
|
|
99
|
+
* </mj-filter-panel>
|
|
100
|
+
* ```
|
|
101
|
+
*/
|
|
102
|
+
export class MJFilterPanelComponent {
|
|
103
|
+
Fields = [];
|
|
104
|
+
Values = {};
|
|
105
|
+
ShowReset = true;
|
|
106
|
+
ResetLabel = 'Reset filters';
|
|
107
|
+
ValuesChange = new EventEmitter();
|
|
108
|
+
Reset = new EventEmitter();
|
|
109
|
+
getValue(key) {
|
|
110
|
+
return this.Values?.[key];
|
|
111
|
+
}
|
|
112
|
+
setValue(key, value) {
|
|
113
|
+
this.Values = { ...this.Values, [key]: value };
|
|
114
|
+
this.ValuesChange.emit(this.Values);
|
|
115
|
+
}
|
|
116
|
+
static ɵfac = function MJFilterPanelComponent_Factory(__ngFactoryType__) { return new (__ngFactoryType__ || MJFilterPanelComponent)(); };
|
|
117
|
+
static ɵcmp = /*@__PURE__*/ i0.ɵɵdefineComponent({ type: MJFilterPanelComponent, selectors: [["mj-filter-panel"]], inputs: { Fields: "Fields", Values: "Values", ShowReset: "ShowReset", ResetLabel: "ResetLabel" }, outputs: { ValuesChange: "ValuesChange", Reset: "Reset" }, ngContentSelectors: _c0, decls: 6, vars: 1, consts: [[1, "mj-filter-panel"], [1, "mj-filter-panel-body"], [3, "Label", "Icon"], [1, "mj-filter-panel-footer"], ["type", "text", 1, "mj-filter-panel-text-input", 3, "value", "placeholder"], ["TextField", "text", "ValueField", "value", 3, "Data", "ValuePrimitive", "Filterable", "Placeholder", "ngModel"], [1, "mj-filter-panel-chip-group"], ["type", "text", 1, "mj-filter-panel-text-input", 3, "input", "value", "placeholder"], ["TextField", "text", "ValueField", "value", 3, "ngModelChange", "Data", "ValuePrimitive", "Filterable", "Placeholder", "ngModel"], [3, "Label", "Icon", "Active"], [3, "Clicked", "Label", "Icon", "Active"], ["type", "button", 1, "mj-filter-panel-reset", 3, "click"], [1, "fa-solid", "fa-rotate-left"]], template: function MJFilterPanelComponent_Template(rf, ctx) { if (rf & 1) {
|
|
118
|
+
i0.ɵɵprojectionDef();
|
|
119
|
+
i0.ɵɵelementStart(0, "div", 0)(1, "div", 1);
|
|
120
|
+
i0.ɵɵrepeaterCreate(2, MJFilterPanelComponent_For_3_Template, 4, 3, "mj-filter-field", 2, _forTrack0);
|
|
121
|
+
i0.ɵɵprojection(4);
|
|
122
|
+
i0.ɵɵelementEnd();
|
|
123
|
+
i0.ɵɵconditionalCreate(5, MJFilterPanelComponent_Conditional_5_Template, 4, 1, "div", 3);
|
|
124
|
+
i0.ɵɵelementEnd();
|
|
125
|
+
} if (rf & 2) {
|
|
126
|
+
i0.ɵɵadvance(2);
|
|
127
|
+
i0.ɵɵrepeater(ctx.Fields);
|
|
128
|
+
i0.ɵɵadvance(3);
|
|
129
|
+
i0.ɵɵconditional(ctx.ShowReset ? 5 : -1);
|
|
130
|
+
} }, dependencies: [CommonModule, FormsModule, i1.NgControlStatus, i1.NgModel, MJDropdownComponent, MJFilterChipComponent, MJFilterFieldComponent], styles: ["[_nghost-%COMP%] {\n display: block;\n }\n\n .mj-filter-panel[_ngcontent-%COMP%] {\n display: flex;\n flex-direction: column;\n gap: 14px;\n }\n\n .mj-filter-panel-body[_ngcontent-%COMP%] {\n display: flex;\n flex-direction: column;\n gap: 14px;\n }\n\n .mj-filter-panel-text-input[_ngcontent-%COMP%] {\n width: 100%;\n padding: 7px 12px;\n background: var(--mj-bg-surface-card);\n border: 1px solid var(--mj-border-default);\n border-radius: var(--mj-radius-md);\n font: inherit;\n font-size: 13px;\n color: var(--mj-text-primary);\n transition: border-color 0.15s ease, box-shadow 0.15s ease;\n }\n\n .mj-filter-panel-text-input[_ngcontent-%COMP%]:focus {\n outline: none;\n border-color: var(--mj-brand-primary);\n box-shadow: 0 0 0 2px color-mix(in srgb, var(--mj-brand-primary) 15%, transparent);\n }\n\n .mj-filter-panel-text-input[_ngcontent-%COMP%]::placeholder {\n color: var(--mj-text-muted);\n }\n\n .mj-filter-panel-chip-group[_ngcontent-%COMP%] {\n display: flex;\n flex-wrap: wrap;\n gap: 6px;\n }\n\n .mj-filter-panel-footer[_ngcontent-%COMP%] {\n display: flex;\n justify-content: flex-end;\n padding-top: 10px;\n border-top: 1px solid var(--mj-border-subtle);\n }\n\n .mj-filter-panel-reset[_ngcontent-%COMP%] {\n display: inline-flex;\n align-items: center;\n gap: 6px;\n padding: 6px 12px;\n background: transparent;\n border: 1px solid var(--mj-border-default);\n border-radius: var(--mj-radius-md);\n color: var(--mj-text-secondary);\n font: inherit;\n font-size: 12px;\n font-weight: 500;\n cursor: pointer;\n transition: background-color 0.15s ease, border-color 0.15s ease, color 0.15s ease;\n }\n\n .mj-filter-panel-reset[_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-panel-reset[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n font-size: 11px;\n }"] });
|
|
131
|
+
}
|
|
132
|
+
(() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassMetadata(MJFilterPanelComponent, [{
|
|
133
|
+
type: Component,
|
|
134
|
+
args: [{ selector: 'mj-filter-panel', standalone: true, imports: [CommonModule, FormsModule, MJDropdownComponent, MJFilterChipComponent, MJFilterFieldComponent], template: `
|
|
135
|
+
<div class="mj-filter-panel">
|
|
136
|
+
<div class="mj-filter-panel-body">
|
|
137
|
+
@for (field of Fields; track field.key) {
|
|
138
|
+
<mj-filter-field [Label]="field.label" [Icon]="field.icon ?? null">
|
|
139
|
+
@switch (field.type) {
|
|
140
|
+
@case ('text') {
|
|
141
|
+
<input
|
|
142
|
+
type="text"
|
|
143
|
+
class="mj-filter-panel-text-input"
|
|
144
|
+
[value]="getValue(field.key) ?? ''"
|
|
145
|
+
[placeholder]="field.placeholder ?? ''"
|
|
146
|
+
(input)="setValue(field.key, $any($event.target).value)" />
|
|
147
|
+
}
|
|
148
|
+
@case ('dropdown') {
|
|
149
|
+
<mj-dropdown
|
|
150
|
+
[Data]="field.options ?? []"
|
|
151
|
+
TextField="text"
|
|
152
|
+
ValueField="value"
|
|
153
|
+
[ValuePrimitive]="true"
|
|
154
|
+
[Filterable]="!!field.filterable"
|
|
155
|
+
[Placeholder]="field.placeholder ?? ''"
|
|
156
|
+
[ngModel]="getValue(field.key)"
|
|
157
|
+
(ngModelChange)="setValue(field.key, $event)">
|
|
158
|
+
</mj-dropdown>
|
|
159
|
+
}
|
|
160
|
+
@case ('chips') {
|
|
161
|
+
<div class="mj-filter-panel-chip-group">
|
|
162
|
+
@for (opt of field.chipOptions ?? []; track opt.value) {
|
|
163
|
+
<mj-filter-chip
|
|
164
|
+
[Label]="opt.text"
|
|
165
|
+
[Icon]="opt.icon ?? null"
|
|
166
|
+
[Active]="getValue(field.key) === opt.value"
|
|
167
|
+
(Clicked)="setValue(field.key, opt.value)">
|
|
168
|
+
</mj-filter-chip>
|
|
169
|
+
}
|
|
170
|
+
</div>
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
</mj-filter-field>
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
<!-- Escape hatch for custom field widgets (e.g. mj-tree-dropdown, date pickers) -->
|
|
177
|
+
<ng-content></ng-content>
|
|
178
|
+
</div>
|
|
179
|
+
|
|
180
|
+
@if (ShowReset) {
|
|
181
|
+
<div class="mj-filter-panel-footer">
|
|
182
|
+
<button type="button" class="mj-filter-panel-reset" (click)="Reset.emit()">
|
|
183
|
+
<i class="fa-solid fa-rotate-left"></i> {{ ResetLabel }}
|
|
184
|
+
</button>
|
|
185
|
+
</div>
|
|
186
|
+
}
|
|
187
|
+
</div>
|
|
188
|
+
`, styles: ["\n :host {\n display: block;\n }\n\n .mj-filter-panel {\n display: flex;\n flex-direction: column;\n gap: 14px;\n }\n\n .mj-filter-panel-body {\n display: flex;\n flex-direction: column;\n gap: 14px;\n }\n\n .mj-filter-panel-text-input {\n width: 100%;\n padding: 7px 12px;\n background: var(--mj-bg-surface-card);\n border: 1px solid var(--mj-border-default);\n border-radius: var(--mj-radius-md);\n font: inherit;\n font-size: 13px;\n color: var(--mj-text-primary);\n transition: border-color 0.15s ease, box-shadow 0.15s ease;\n }\n\n .mj-filter-panel-text-input:focus {\n outline: none;\n border-color: var(--mj-brand-primary);\n box-shadow: 0 0 0 2px color-mix(in srgb, var(--mj-brand-primary) 15%, transparent);\n }\n\n .mj-filter-panel-text-input::placeholder {\n color: var(--mj-text-muted);\n }\n\n .mj-filter-panel-chip-group {\n display: flex;\n flex-wrap: wrap;\n gap: 6px;\n }\n\n .mj-filter-panel-footer {\n display: flex;\n justify-content: flex-end;\n padding-top: 10px;\n border-top: 1px solid var(--mj-border-subtle);\n }\n\n .mj-filter-panel-reset {\n display: inline-flex;\n align-items: center;\n gap: 6px;\n padding: 6px 12px;\n background: transparent;\n border: 1px solid var(--mj-border-default);\n border-radius: var(--mj-radius-md);\n color: var(--mj-text-secondary);\n font: inherit;\n font-size: 12px;\n font-weight: 500;\n cursor: pointer;\n transition: background-color 0.15s ease, border-color 0.15s ease, color 0.15s ease;\n }\n\n .mj-filter-panel-reset: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-panel-reset i {\n font-size: 11px;\n }\n "] }]
|
|
189
|
+
}], null, { Fields: [{
|
|
190
|
+
type: Input
|
|
191
|
+
}], Values: [{
|
|
192
|
+
type: Input
|
|
193
|
+
}], ShowReset: [{
|
|
194
|
+
type: Input
|
|
195
|
+
}], ResetLabel: [{
|
|
196
|
+
type: Input
|
|
197
|
+
}], ValuesChange: [{
|
|
198
|
+
type: Output
|
|
199
|
+
}], Reset: [{
|
|
200
|
+
type: Output
|
|
201
|
+
}] }); })();
|
|
202
|
+
(() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassDebugInfo(MJFilterPanelComponent, { className: "MJFilterPanelComponent", filePath: "lib/filter-panel/filter-panel.component.ts", lineNumber: 195 }); })();
|
|
203
|
+
//# sourceMappingURL=filter-panel.component.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"filter-panel.component.js","sourceRoot":"","sources":["../../../src/lib/filter-panel/filter-panel.component.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,YAAY,EAAE,KAAK,EAAE,MAAM,EAAE,MAAM,eAAe,CAAC;AACvE,OAAO,EAAE,YAAY,EAAE,MAAM,iBAAiB,CAAC;AAC/C,OAAO,EAAE,WAAW,EAAE,MAAM,gBAAgB,CAAC;AAC7C,OAAO,EAAE,mBAAmB,EAAE,MAAM,gCAAgC,CAAC;AACrE,OAAO,EAAE,qBAAqB,EAAE,MAAM,sCAAsC,CAAC;AAC7E,OAAO,EAAE,sBAAsB,EAAE,MAAM,wCAAwC,CAAC;;;;;;;;;IA8DhE,gCAK6D;IAA3D,6OAAS,kDAA8C,KAAC;IAL1D,iBAK6D;;;;IAD3D,AADA,2DAAmC,2CACI;;;;IAIzC,sCAQgD;IAA9C,mQAAiB,qCAA2B,KAAC;IAC/C,iBAAc;;;;IAFZ,AADA,AADA,AADA,AAHA,qEAA4B,wBAGL,qCACU,2CACM,0CACR;;;;IAO7B,0CAI6C;IAA3C,oRAAW,2CAA8B,KAAC;IAC5C,iBAAiB;;;;;IAFf,AADA,AADA,mCAAkB,6BACO,0DACmB;;;IALlD,8BAAwC;IACtC,iHAOC;IACH,iBAAM;;;IARJ,cAOC;IAPD,iEAOC;;;IA/BT,0CAAmE;IAsB/D,AAZA,AARA,yFAAgB,yEAQI,iEAYH;IAarB,iBAAkB;;;;IAnCqB,AAAtB,sCAAqB,+BAA4B;IAChE,cAiCC;IAjCD,gDAAA,MAAM,oBAAN,UAAU,oBAAV,OAAO,UAiCN;;;;IAUH,AADF,8BAAoC,iBACyC;IAAvB,0LAAS,mBAAY,KAAC;IACxE,wBAAuC;IAAC,YAC1C;IACF,AADE,iBAAS,EACL;;;IAFsC,eAC1C;IAD0C,kDAC1C;;AAhFV;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG;AA2IH,MAAM,OAAO,sBAAsB;IACxB,MAAM,GAAwB,EAAE,CAAC;IACjC,MAAM,GAA4B,EAAE,CAAC;IACrC,SAAS,GAAY,IAAI,CAAC;IAC1B,UAAU,GAAW,eAAe,CAAC;IAEpC,YAAY,GAAG,IAAI,YAAY,EAA2B,CAAC;IAC3D,KAAK,GAAG,IAAI,YAAY,EAAQ,CAAC;IAEpC,QAAQ,CAAC,GAAW;QACzB,OAAO,IAAI,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,CAAC;IAC5B,CAAC;IAEM,QAAQ,CAAC,GAAW,EAAE,KAAc;QACzC,IAAI,CAAC,MAAM,GAAG,EAAE,GAAG,IAAI,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,EAAE,KAAK,EAAE,CAAC;QAC/C,IAAI,CAAC,YAAY,CAAC,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;IACtC,CAAC;gHAhBU,sBAAsB;6DAAtB,sBAAsB;;YApI7B,AADF,8BAA6B,aACO;YAChC,qGAqCC;YAGD,kBAAyB;YAC3B,iBAAM;YAEN,wFAAiB;YAOnB,iBAAM;;YAlDF,eAqCC;YArCD,yBAqCC;YAMH,eAMC;YAND,wCAMC;4BArDK,YAAY,EAAE,WAAW,kCAAE,mBAAmB,EAAE,qBAAqB,EAAE,sBAAsB;;iFAuI5F,sBAAsB;cA1IlC,SAAS;2BACE,iBAAiB,cACf,IAAI,WACP,CAAC,YAAY,EAAE,WAAW,EAAE,mBAAmB,EAAE,qBAAqB,EAAE,sBAAsB,CAAC,YAC9F;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAsDT;;kBAiFA,KAAK;;kBACL,KAAK;;kBACL,KAAK;;kBACL,KAAK;;kBAEL,MAAM;;kBACN,MAAM;;kFAPI,sBAAsB","sourcesContent":["import { Component, EventEmitter, Input, Output } from '@angular/core';\nimport { CommonModule } from '@angular/common';\nimport { FormsModule } from '@angular/forms';\nimport { MJDropdownComponent } from '../dropdown/dropdown.component';\nimport { MJFilterChipComponent } from '../filter-chip/filter-chip.component';\nimport { MJFilterFieldComponent } from '../filter-field/filter-field.component';\n\n/** Field types supported natively by <mj-filter-panel>. */\nexport type FilterFieldType = 'text' | 'dropdown' | 'chips';\n\n/** Per-field config understood by <mj-filter-panel>. */\nexport interface FilterFieldConfig {\n /** State key in the Values record. */\n key: string;\n /** Field type — drives which widget is rendered. */\n type: FilterFieldType;\n /** Display label. */\n label: string;\n /** Optional Font Awesome icon class (e.g. 'fa-solid fa-folder'). */\n icon?: string;\n /** Placeholder for text inputs / dropdowns. */\n placeholder?: string;\n /** Dropdown options (when type === 'dropdown'). Each option needs text + value. */\n options?: { text: string; value: string | number | boolean | null }[];\n /** Whether the dropdown should show an internal search box. */\n filterable?: boolean;\n /** Chip-group options (when type === 'chips'). */\n chipOptions?: { text: string; value: string | number | boolean | null; icon?: string }[];\n}\n\n/**\n * mj-filter-panel — Single centralized filter panel for all dashboards.\n *\n * Config-driven: pass an array of `FilterFieldConfig` plus a `Values` record;\n * the panel renders each field using the appropriate widget (text input,\n * `<mj-dropdown>`, or chip group), keeps everything visually consistent, and\n * emits state changes via `(ValuesChange)`.\n *\n * For widgets not covered by the config schema (tree-dropdown, date pickers,\n * etc.), project `<mj-filter-field>` elements as content — they render below\n * the config-driven fields with identical chrome.\n *\n * Example:\n * ```html\n * <mj-filter-panel\n * [Fields]=\"filterFields\"\n * [(Values)]=\"filterValues\"\n * (Reset)=\"onReset()\">\n *\n * <!-- escape hatch for custom widgets -->\n * <mj-filter-field Label=\"Category\" Icon=\"fa-solid fa-folder\">\n * <mj-tree-dropdown ...></mj-tree-dropdown>\n * </mj-filter-field>\n * </mj-filter-panel>\n * ```\n */\n@Component({\n selector: 'mj-filter-panel',\n standalone: true,\n imports: [CommonModule, FormsModule, MJDropdownComponent, MJFilterChipComponent, MJFilterFieldComponent],\n template: `\n <div class=\"mj-filter-panel\">\n <div class=\"mj-filter-panel-body\">\n @for (field of Fields; track field.key) {\n <mj-filter-field [Label]=\"field.label\" [Icon]=\"field.icon ?? null\">\n @switch (field.type) {\n @case ('text') {\n <input\n type=\"text\"\n class=\"mj-filter-panel-text-input\"\n [value]=\"getValue(field.key) ?? ''\"\n [placeholder]=\"field.placeholder ?? ''\"\n (input)=\"setValue(field.key, $any($event.target).value)\" />\n }\n @case ('dropdown') {\n <mj-dropdown\n [Data]=\"field.options ?? []\"\n TextField=\"text\"\n ValueField=\"value\"\n [ValuePrimitive]=\"true\"\n [Filterable]=\"!!field.filterable\"\n [Placeholder]=\"field.placeholder ?? ''\"\n [ngModel]=\"getValue(field.key)\"\n (ngModelChange)=\"setValue(field.key, $event)\">\n </mj-dropdown>\n }\n @case ('chips') {\n <div class=\"mj-filter-panel-chip-group\">\n @for (opt of field.chipOptions ?? []; track opt.value) {\n <mj-filter-chip\n [Label]=\"opt.text\"\n [Icon]=\"opt.icon ?? null\"\n [Active]=\"getValue(field.key) === opt.value\"\n (Clicked)=\"setValue(field.key, opt.value)\">\n </mj-filter-chip>\n }\n </div>\n }\n }\n </mj-filter-field>\n }\n\n <!-- Escape hatch for custom field widgets (e.g. mj-tree-dropdown, date pickers) -->\n <ng-content></ng-content>\n </div>\n\n @if (ShowReset) {\n <div class=\"mj-filter-panel-footer\">\n <button type=\"button\" class=\"mj-filter-panel-reset\" (click)=\"Reset.emit()\">\n <i class=\"fa-solid fa-rotate-left\"></i> {{ ResetLabel }}\n </button>\n </div>\n }\n </div>\n `,\n styles: [`\n :host {\n display: block;\n }\n\n .mj-filter-panel {\n display: flex;\n flex-direction: column;\n gap: 14px;\n }\n\n .mj-filter-panel-body {\n display: flex;\n flex-direction: column;\n gap: 14px;\n }\n\n .mj-filter-panel-text-input {\n width: 100%;\n padding: 7px 12px;\n background: var(--mj-bg-surface-card);\n border: 1px solid var(--mj-border-default);\n border-radius: var(--mj-radius-md);\n font: inherit;\n font-size: 13px;\n color: var(--mj-text-primary);\n transition: border-color 0.15s ease, box-shadow 0.15s ease;\n }\n\n .mj-filter-panel-text-input:focus {\n outline: none;\n border-color: var(--mj-brand-primary);\n box-shadow: 0 0 0 2px color-mix(in srgb, var(--mj-brand-primary) 15%, transparent);\n }\n\n .mj-filter-panel-text-input::placeholder {\n color: var(--mj-text-muted);\n }\n\n .mj-filter-panel-chip-group {\n display: flex;\n flex-wrap: wrap;\n gap: 6px;\n }\n\n .mj-filter-panel-footer {\n display: flex;\n justify-content: flex-end;\n padding-top: 10px;\n border-top: 1px solid var(--mj-border-subtle);\n }\n\n .mj-filter-panel-reset {\n display: inline-flex;\n align-items: center;\n gap: 6px;\n padding: 6px 12px;\n background: transparent;\n border: 1px solid var(--mj-border-default);\n border-radius: var(--mj-radius-md);\n color: var(--mj-text-secondary);\n font: inherit;\n font-size: 12px;\n font-weight: 500;\n cursor: pointer;\n transition: background-color 0.15s ease, border-color 0.15s ease, color 0.15s ease;\n }\n\n .mj-filter-panel-reset: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-panel-reset i {\n font-size: 11px;\n }\n `]\n})\nexport class MJFilterPanelComponent {\n @Input() Fields: FilterFieldConfig[] = [];\n @Input() Values: Record<string, unknown> = {};\n @Input() ShowReset: boolean = true;\n @Input() ResetLabel: string = 'Reset filters';\n\n @Output() ValuesChange = new EventEmitter<Record<string, unknown>>();\n @Output() Reset = new EventEmitter<void>();\n\n public getValue(key: string): unknown {\n return this.Values?.[key];\n }\n\n public setValue(key: string, value: unknown): void {\n this.Values = { ...this.Values, [key]: value };\n this.ValuesChange.emit(this.Values);\n }\n}\n"]}
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import { EventEmitter } from '@angular/core';
|
|
2
|
+
import { ConnectedPosition } from '@angular/cdk/overlay';
|
|
3
|
+
import * as i0 from "@angular/core";
|
|
4
|
+
/**
|
|
5
|
+
* mj-filter-popover — Compact "Filters" trigger button that opens a popover
|
|
6
|
+
* containing arbitrary filter UI. Use this in a dashboard's page-header to
|
|
7
|
+
* keep the header chrome consistent regardless of filter density.
|
|
8
|
+
*
|
|
9
|
+
* Pass the popover content via `<ng-content>`. Drive the active-count badge
|
|
10
|
+
* via the `ActiveCount` input.
|
|
11
|
+
*
|
|
12
|
+
* Example:
|
|
13
|
+
* ```html
|
|
14
|
+
* <mj-filter-popover [ActiveCount]="activeFilters.length">
|
|
15
|
+
* <div class="my-filter-grid">
|
|
16
|
+
* <mj-dropdown ...></mj-dropdown>
|
|
17
|
+
* <mj-dropdown ...></mj-dropdown>
|
|
18
|
+
* </div>
|
|
19
|
+
* </mj-filter-popover>
|
|
20
|
+
* ```
|
|
21
|
+
*/
|
|
22
|
+
export declare class MJFilterPopoverComponent {
|
|
23
|
+
Label: string;
|
|
24
|
+
Icon: string;
|
|
25
|
+
ActiveCount: number;
|
|
26
|
+
ShowClearAll: boolean;
|
|
27
|
+
IsOpen: boolean;
|
|
28
|
+
readonly Positions: ConnectedPosition[];
|
|
29
|
+
Toggle(): void;
|
|
30
|
+
Open(): void;
|
|
31
|
+
Close(): void;
|
|
32
|
+
/** Emitted when the user clicks the "Clear all" link inside the popover header. */
|
|
33
|
+
ClearAllRequested: EventEmitter<void>;
|
|
34
|
+
ClearAll(): void;
|
|
35
|
+
static ɵfac: i0.ɵɵFactoryDeclaration<MJFilterPopoverComponent, never>;
|
|
36
|
+
static ɵcmp: i0.ɵɵComponentDeclaration<MJFilterPopoverComponent, "mj-filter-popover", never, { "Label": { "alias": "Label"; "required": false; }; "Icon": { "alias": "Icon"; "required": false; }; "ActiveCount": { "alias": "ActiveCount"; "required": false; }; "ShowClearAll": { "alias": "ShowClearAll"; "required": false; }; }, { "ClearAllRequested": "ClearAllRequested"; }, never, ["*"], true, never>;
|
|
37
|
+
}
|
|
38
|
+
//# sourceMappingURL=filter-popover.component.d.ts.map
|
|
@@ -0,0 +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,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"}
|