@memberjunction/ng-ui-components 6.1.0-edge.1 → 6.1.0-edge.3

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.
@@ -0,0 +1,640 @@
1
+ import { Component, Directive, Input, Output, EventEmitter, ContentChild, HostListener, ChangeDetectionStrategy, ChangeDetectorRef, inject } from '@angular/core';
2
+ import { CommonModule } from '@angular/common';
3
+ import { BehaviorSubject } from 'rxjs';
4
+ import * as i0 from "@angular/core";
5
+ import * as i1 from "@angular/common";
6
+ const _c0 = ["*"];
7
+ function MJCardComponent_Conditional_1_Conditional_3_Template(rf, ctx) { if (rf & 1) {
8
+ i0.ɵɵelementStart(0, "span", 6);
9
+ i0.ɵɵelement(1, "i");
10
+ i0.ɵɵelementEnd();
11
+ } if (rf & 2) {
12
+ const ctx_r0 = i0.ɵɵnextContext(2);
13
+ i0.ɵɵadvance();
14
+ i0.ɵɵclassMap(ctx_r0.Icon);
15
+ } }
16
+ function MJCardComponent_Conditional_1_Conditional_4_Template(rf, ctx) { if (rf & 1) {
17
+ i0.ɵɵelementContainer(0, 7);
18
+ } if (rf & 2) {
19
+ const ctx_r0 = i0.ɵɵnextContext(2);
20
+ i0.ɵɵproperty("ngTemplateOutlet", ctx_r0.TitleTemplate.templateRef);
21
+ } }
22
+ function MJCardComponent_Conditional_1_Conditional_5_Template(rf, ctx) { if (rf & 1) {
23
+ i0.ɵɵelementStart(0, "h3", 8);
24
+ i0.ɵɵtext(1);
25
+ i0.ɵɵelementEnd();
26
+ } if (rf & 2) {
27
+ const ctx_r0 = i0.ɵɵnextContext(2);
28
+ i0.ɵɵadvance();
29
+ i0.ɵɵtextInterpolate(ctx_r0.Title);
30
+ } }
31
+ function MJCardComponent_Conditional_1_Conditional_6_Template(rf, ctx) { if (rf & 1) {
32
+ i0.ɵɵelementStart(0, "span", 9);
33
+ i0.ɵɵtext(1);
34
+ i0.ɵɵelementEnd();
35
+ } if (rf & 2) {
36
+ const ctx_r0 = i0.ɵɵnextContext(2);
37
+ i0.ɵɵadvance();
38
+ i0.ɵɵtextInterpolate(ctx_r0.Subtitle);
39
+ } }
40
+ function MJCardComponent_Conditional_1_Conditional_8_Template(rf, ctx) { if (rf & 1) {
41
+ i0.ɵɵelementContainer(0, 7);
42
+ } if (rf & 2) {
43
+ const ctx_r0 = i0.ɵɵnextContext(2);
44
+ i0.ɵɵproperty("ngTemplateOutlet", ctx_r0.ToolsTemplate.templateRef);
45
+ } }
46
+ function MJCardComponent_Conditional_1_Conditional_9_Template(rf, ctx) { if (rf & 1) {
47
+ i0.ɵɵelementContainer(0, 7);
48
+ } if (rf & 2) {
49
+ const ctx_r0 = i0.ɵɵnextContext(2);
50
+ i0.ɵɵproperty("ngTemplateOutlet", ctx_r0.ActionsTemplate.templateRef);
51
+ } }
52
+ function MJCardComponent_Conditional_1_Conditional_10_Conditional_1_Template(rf, ctx) { if (rf & 1) {
53
+ i0.ɵɵelement(0, "i", 13);
54
+ } }
55
+ function MJCardComponent_Conditional_1_Conditional_10_Conditional_2_Template(rf, ctx) { if (rf & 1) {
56
+ i0.ɵɵelement(0, "i", 14);
57
+ } }
58
+ function MJCardComponent_Conditional_1_Conditional_10_Template(rf, ctx) { if (rf & 1) {
59
+ const _r2 = i0.ɵɵgetCurrentView();
60
+ i0.ɵɵelementStart(0, "button", 12);
61
+ i0.ɵɵlistener("click", function MJCardComponent_Conditional_1_Conditional_10_Template_button_click_0_listener($event) { i0.ɵɵrestoreView(_r2); const ctx_r0 = i0.ɵɵnextContext(2); return i0.ɵɵresetView(ctx_r0.ToggleMaximize($event)); });
62
+ i0.ɵɵconditionalCreate(1, MJCardComponent_Conditional_1_Conditional_10_Conditional_1_Template, 1, 0, "i", 13)(2, MJCardComponent_Conditional_1_Conditional_10_Conditional_2_Template, 1, 0, "i", 14);
63
+ i0.ɵɵelementEnd();
64
+ } if (rf & 2) {
65
+ const ctx_r0 = i0.ɵɵnextContext(2);
66
+ i0.ɵɵproperty("title", ctx_r0.IsMaximized ? ctx_r0.RestoreTooltip : ctx_r0.MaximizeTooltip);
67
+ i0.ɵɵattribute("aria-label", ctx_r0.IsMaximized ? ctx_r0.RestoreTooltip : ctx_r0.MaximizeTooltip);
68
+ i0.ɵɵadvance();
69
+ i0.ɵɵconditional(ctx_r0.IsMaximized ? 1 : 2);
70
+ } }
71
+ function MJCardComponent_Conditional_1_Template(rf, ctx) { if (rf & 1) {
72
+ i0.ɵɵelementStart(0, "div", 1)(1, "div", 4)(2, "div", 5);
73
+ i0.ɵɵconditionalCreate(3, MJCardComponent_Conditional_1_Conditional_3_Template, 2, 2, "span", 6);
74
+ i0.ɵɵconditionalCreate(4, MJCardComponent_Conditional_1_Conditional_4_Template, 1, 1, "ng-container", 7)(5, MJCardComponent_Conditional_1_Conditional_5_Template, 2, 1, "h3", 8);
75
+ i0.ɵɵelementEnd();
76
+ i0.ɵɵconditionalCreate(6, MJCardComponent_Conditional_1_Conditional_6_Template, 2, 1, "span", 9);
77
+ i0.ɵɵelementEnd();
78
+ i0.ɵɵelementStart(7, "div", 10);
79
+ i0.ɵɵconditionalCreate(8, MJCardComponent_Conditional_1_Conditional_8_Template, 1, 1, "ng-container", 7);
80
+ i0.ɵɵconditionalCreate(9, MJCardComponent_Conditional_1_Conditional_9_Template, 1, 1, "ng-container", 7);
81
+ i0.ɵɵconditionalCreate(10, MJCardComponent_Conditional_1_Conditional_10_Template, 3, 3, "button", 11);
82
+ i0.ɵɵelementEnd()();
83
+ } if (rf & 2) {
84
+ const ctx_r0 = i0.ɵɵnextContext();
85
+ i0.ɵɵadvance(3);
86
+ i0.ɵɵconditional(ctx_r0.Icon ? 3 : -1);
87
+ i0.ɵɵadvance();
88
+ i0.ɵɵconditional(ctx_r0.TitleTemplate ? 4 : ctx_r0.Title ? 5 : -1);
89
+ i0.ɵɵadvance(2);
90
+ i0.ɵɵconditional(ctx_r0.Subtitle ? 6 : -1);
91
+ i0.ɵɵadvance(2);
92
+ i0.ɵɵconditional(ctx_r0.ToolsTemplate ? 8 : -1);
93
+ i0.ɵɵadvance();
94
+ i0.ɵɵconditional(ctx_r0.ActionsTemplate ? 9 : -1);
95
+ i0.ɵɵadvance();
96
+ i0.ɵɵconditional(ctx_r0.AllowMaximize ? 10 : -1);
97
+ } }
98
+ function MJCardComponent_Conditional_4_Template(rf, ctx) { if (rf & 1) {
99
+ i0.ɵɵelementStart(0, "div", 3);
100
+ i0.ɵɵelementContainer(1, 7);
101
+ i0.ɵɵelementEnd();
102
+ } if (rf & 2) {
103
+ const ctx_r0 = i0.ɵɵnextContext();
104
+ i0.ɵɵadvance();
105
+ i0.ɵɵproperty("ngTemplateOutlet", ctx_r0.FooterTemplate.templateRef);
106
+ } }
107
+ const _c1 = "[_nghost-%COMP%] {\n display: flex;\n flex-direction: column;\n width: 100%;\n height: 100%;\n min-width: 0;\n box-sizing: border-box;\n}\n\n.mj-card-grid[_ngcontent-%COMP%] {\n display: grid;\n grid-template-columns: repeat(2, minmax(0, 1fr));\n align-items: stretch;\n gap: var(--mj-card-grid-gap, var(--mj-space-4, 16px));\n width: 100%;\n position: relative;\n box-sizing: border-box;\n transition: all 0.25s cubic-bezier(0.4, 0, 0.2, 1);\n}\n\n.mj-card-grid--has-maximized[_ngcontent-%COMP%] {\n grid-template-columns: 1fr !important;\n}\n\n@media (max-width: 640px) {\n .mj-card-grid[_ngcontent-%COMP%] {\n grid-template-columns: 1fr !important;\n }\n}\n\nmj-card[_ngcontent-%COMP%] {\n display: flex;\n flex-direction: column;\n height: 100%;\n min-width: 0;\n width: 100%;\n box-sizing: border-box;\n}\n\n.mj-card[_ngcontent-%COMP%] {\n display: flex;\n flex-direction: column;\n flex: 1 1 100%;\n height: 100%;\n min-height: 290px;\n background: var(--mj-bg-surface-card, var(--mj-bg-surface, #141f33));\n border: 1px solid var(--mj-border-default, #2a3852);\n border-radius: var(--mj-radius-xl, 16px);\n box-shadow: var(--mj-shadow-sm, 0 1px 3px rgba(0, 0, 0, 0.08));\n padding: var(--mj-space-4, 16px) var(--mj-space-5, 20px);\n box-sizing: border-box;\n transition: border-color 0.2s ease, box-shadow 0.2s ease, transform 0.2s ease;\n position: relative;\n min-width: 0;\n}\n\n.mj-card[_ngcontent-%COMP%]:hover {\n border-color: color-mix(in srgb, var(--mj-brand-primary, #38bdf8) 40%, var(--mj-border-default, #2a3852));\n}\n\n.mj-card--maximized[_ngcontent-%COMP%] {\n grid-column: 1 / -1;\n width: 100%;\n min-height: 480px;\n box-shadow: var(--mj-shadow-lg, 0 10px 25px rgba(0, 0, 0, 0.25));\n border-color: var(--mj-brand-primary, #38bdf8);\n z-index: 10;\n}\n\n.mj-card--hidden[_ngcontent-%COMP%] {\n display: none !important;\n}\n\n.mj-card__header[_ngcontent-%COMP%] {\n display: flex;\n flex-direction: row;\n align-items: flex-start;\n justify-content: space-between;\n gap: var(--mj-space-3, 12px);\n margin-bottom: var(--mj-space-3, 12px);\n min-height: 28px;\n width: 100%;\n}\n\n.mj-card__title-group[_ngcontent-%COMP%] {\n display: flex;\n flex-direction: column;\n gap: 2px;\n min-width: 0;\n flex: 1 1 auto;\n}\n\n.mj-card__title-row[_ngcontent-%COMP%] {\n display: flex;\n flex-direction: row;\n align-items: center;\n gap: var(--mj-space-2, 8px);\n min-width: 0;\n}\n\n.mj-card__icon[_ngcontent-%COMP%] {\n color: var(--mj-brand-primary, #38bdf8);\n font-size: 14px;\n display: inline-flex;\n align-items: center;\n justify-content: center;\n flex-shrink: 0;\n}\n\n.mj-card__title[_ngcontent-%COMP%] {\n font-size: 14px;\n font-weight: 700;\n color: var(--mj-text-primary, #ffffff);\n letter-spacing: -0.01em;\n margin: 0;\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n}\n\n.mj-card__subtitle[_ngcontent-%COMP%] {\n font-size: 11.5px;\n font-weight: 500;\n color: var(--mj-text-muted, #94a3b8);\n margin: 0;\n padding-left: 22px;\n}\n\n.mj-card__actions[_ngcontent-%COMP%] {\n display: flex;\n flex-direction: row;\n align-items: center;\n gap: var(--mj-space-2, 8px);\n flex-shrink: 0;\n margin-left: auto;\n}\n\n.mj-card__toggle-btn[_ngcontent-%COMP%] {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n width: 28px;\n height: 28px;\n border-radius: var(--mj-radius-sm, 6px);\n background: transparent;\n border: 1px solid transparent;\n color: var(--mj-text-muted, #94a3b8);\n cursor: pointer;\n padding: 0;\n font-size: 12px;\n transition: all 0.15s ease;\n}\n\n.mj-card__toggle-btn[_ngcontent-%COMP%]:hover {\n color: var(--mj-text-primary, #ffffff);\n background: var(--mj-bg-surface-sunken, rgba(255, 255, 255, 0.06));\n border-color: var(--mj-border-default, #2a3852);\n}\n\n.mj-card__toggle-btn[_ngcontent-%COMP%]:focus-visible {\n outline: 2px solid var(--mj-brand-primary, #38bdf8);\n outline-offset: 1px;\n}\n\n.mj-card__body[_ngcontent-%COMP%] {\n flex: 1 1 auto;\n display: flex;\n flex-direction: column;\n justify-content: space-between;\n min-width: 0;\n}\n\n.mj-card__footer[_ngcontent-%COMP%] {\n margin-top: auto;\n padding-top: var(--mj-space-3, 12px);\n border-top: 1px solid var(--mj-border-default, #2a3852);\n}";
108
+ let nextCardId = 0;
109
+ /**
110
+ * Directive to provide a custom template for the Card Title.
111
+ */
112
+ export class MJCardTitleDirective {
113
+ templateRef;
114
+ constructor(templateRef) {
115
+ this.templateRef = templateRef;
116
+ }
117
+ static ɵfac = function MJCardTitleDirective_Factory(__ngFactoryType__) { return new (__ngFactoryType__ || MJCardTitleDirective)(i0.ɵɵdirectiveInject(i0.TemplateRef)); };
118
+ static ɵdir = /*@__PURE__*/ i0.ɵɵdefineDirective({ type: MJCardTitleDirective, selectors: [["", "mjCardTitle", ""]] });
119
+ }
120
+ (() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassMetadata(MJCardTitleDirective, [{
121
+ type: Directive,
122
+ args: [{
123
+ selector: '[mjCardTitle]',
124
+ standalone: true,
125
+ }]
126
+ }], () => [{ type: i0.TemplateRef }], null); })();
127
+ /**
128
+ * Directive to provide custom action controls in the Card Header.
129
+ */
130
+ export class MJCardActionsDirective {
131
+ templateRef;
132
+ constructor(templateRef) {
133
+ this.templateRef = templateRef;
134
+ }
135
+ static ɵfac = function MJCardActionsDirective_Factory(__ngFactoryType__) { return new (__ngFactoryType__ || MJCardActionsDirective)(i0.ɵɵdirectiveInject(i0.TemplateRef)); };
136
+ static ɵdir = /*@__PURE__*/ i0.ɵɵdefineDirective({ type: MJCardActionsDirective, selectors: [["", "mjCardActions", ""]] });
137
+ }
138
+ (() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassMetadata(MJCardActionsDirective, [{
139
+ type: Directive,
140
+ args: [{
141
+ selector: '[mjCardActions]',
142
+ standalone: true,
143
+ }]
144
+ }], () => [{ type: i0.TemplateRef }], null); })();
145
+ /**
146
+ * Directive to provide custom tools/badges in the Card Header.
147
+ */
148
+ export class MJCardToolsDirective {
149
+ templateRef;
150
+ constructor(templateRef) {
151
+ this.templateRef = templateRef;
152
+ }
153
+ static ɵfac = function MJCardToolsDirective_Factory(__ngFactoryType__) { return new (__ngFactoryType__ || MJCardToolsDirective)(i0.ɵɵdirectiveInject(i0.TemplateRef)); };
154
+ static ɵdir = /*@__PURE__*/ i0.ɵɵdefineDirective({ type: MJCardToolsDirective, selectors: [["", "mjCardTools", ""]] });
155
+ }
156
+ (() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassMetadata(MJCardToolsDirective, [{
157
+ type: Directive,
158
+ args: [{
159
+ selector: '[mjCardTools]',
160
+ standalone: true,
161
+ }]
162
+ }], () => [{ type: i0.TemplateRef }], null); })();
163
+ /**
164
+ * Directive to provide a custom template for the Card Footer.
165
+ */
166
+ export class MJCardFooterDirective {
167
+ templateRef;
168
+ constructor(templateRef) {
169
+ this.templateRef = templateRef;
170
+ }
171
+ static ɵfac = function MJCardFooterDirective_Factory(__ngFactoryType__) { return new (__ngFactoryType__ || MJCardFooterDirective)(i0.ɵɵdirectiveInject(i0.TemplateRef)); };
172
+ static ɵdir = /*@__PURE__*/ i0.ɵɵdefineDirective({ type: MJCardFooterDirective, selectors: [["", "mjCardFooter", ""]] });
173
+ }
174
+ (() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassMetadata(MJCardFooterDirective, [{
175
+ type: Directive,
176
+ args: [{
177
+ selector: '[mjCardFooter]',
178
+ standalone: true,
179
+ }]
180
+ }], () => [{ type: i0.TemplateRef }], null); })();
181
+ const CARD_GRID_CSS = `
182
+ :host {
183
+ display: flex;
184
+ flex-direction: column;
185
+ width: 100%;
186
+ height: 100%;
187
+ min-width: 0;
188
+ box-sizing: border-box;
189
+ }
190
+
191
+ .mj-card-grid {
192
+ display: grid;
193
+ grid-template-columns: repeat(2, minmax(0, 1fr));
194
+ align-items: stretch;
195
+ gap: var(--mj-card-grid-gap, var(--mj-space-4, 16px));
196
+ width: 100%;
197
+ position: relative;
198
+ box-sizing: border-box;
199
+ transition: all 0.25s cubic-bezier(0.4, 0, 0.2, 1);
200
+ }
201
+
202
+ .mj-card-grid--has-maximized {
203
+ grid-template-columns: 1fr !important;
204
+ }
205
+
206
+ @media (max-width: 640px) {
207
+ .mj-card-grid {
208
+ grid-template-columns: 1fr !important;
209
+ }
210
+ }
211
+
212
+ mj-card {
213
+ display: flex;
214
+ flex-direction: column;
215
+ height: 100%;
216
+ min-width: 0;
217
+ width: 100%;
218
+ box-sizing: border-box;
219
+ }
220
+
221
+ .mj-card {
222
+ display: flex;
223
+ flex-direction: column;
224
+ flex: 1 1 100%;
225
+ height: 100%;
226
+ min-height: 290px;
227
+ background: var(--mj-bg-surface-card, var(--mj-bg-surface, #141f33));
228
+ border: 1px solid var(--mj-border-default, #2a3852);
229
+ border-radius: var(--mj-radius-xl, 16px);
230
+ box-shadow: var(--mj-shadow-sm, 0 1px 3px rgba(0, 0, 0, 0.08));
231
+ padding: var(--mj-space-4, 16px) var(--mj-space-5, 20px);
232
+ box-sizing: border-box;
233
+ transition: border-color 0.2s ease, box-shadow 0.2s ease, transform 0.2s ease;
234
+ position: relative;
235
+ min-width: 0;
236
+ }
237
+
238
+ .mj-card:hover {
239
+ border-color: color-mix(in srgb, var(--mj-brand-primary, #38bdf8) 40%, var(--mj-border-default, #2a3852));
240
+ }
241
+
242
+ .mj-card--maximized {
243
+ grid-column: 1 / -1;
244
+ width: 100%;
245
+ min-height: 480px;
246
+ box-shadow: var(--mj-shadow-lg, 0 10px 25px rgba(0, 0, 0, 0.25));
247
+ border-color: var(--mj-brand-primary, #38bdf8);
248
+ z-index: 10;
249
+ }
250
+
251
+ .mj-card--hidden {
252
+ display: none !important;
253
+ }
254
+
255
+ .mj-card__header {
256
+ display: flex;
257
+ flex-direction: row;
258
+ align-items: flex-start;
259
+ justify-content: space-between;
260
+ gap: var(--mj-space-3, 12px);
261
+ margin-bottom: var(--mj-space-3, 12px);
262
+ min-height: 28px;
263
+ width: 100%;
264
+ }
265
+
266
+ .mj-card__title-group {
267
+ display: flex;
268
+ flex-direction: column;
269
+ gap: 2px;
270
+ min-width: 0;
271
+ flex: 1 1 auto;
272
+ }
273
+
274
+ .mj-card__title-row {
275
+ display: flex;
276
+ flex-direction: row;
277
+ align-items: center;
278
+ gap: var(--mj-space-2, 8px);
279
+ min-width: 0;
280
+ }
281
+
282
+ .mj-card__icon {
283
+ color: var(--mj-brand-primary, #38bdf8);
284
+ font-size: 14px;
285
+ display: inline-flex;
286
+ align-items: center;
287
+ justify-content: center;
288
+ flex-shrink: 0;
289
+ }
290
+
291
+ .mj-card__title {
292
+ font-size: 14px;
293
+ font-weight: 700;
294
+ color: var(--mj-text-primary, #ffffff);
295
+ letter-spacing: -0.01em;
296
+ margin: 0;
297
+ white-space: nowrap;
298
+ overflow: hidden;
299
+ text-overflow: ellipsis;
300
+ }
301
+
302
+ .mj-card__subtitle {
303
+ font-size: 11.5px;
304
+ font-weight: 500;
305
+ color: var(--mj-text-muted, #94a3b8);
306
+ margin: 0;
307
+ padding-left: 22px;
308
+ }
309
+
310
+ .mj-card__actions {
311
+ display: flex;
312
+ flex-direction: row;
313
+ align-items: center;
314
+ gap: var(--mj-space-2, 8px);
315
+ flex-shrink: 0;
316
+ margin-left: auto;
317
+ }
318
+
319
+ .mj-card__toggle-btn {
320
+ display: inline-flex;
321
+ align-items: center;
322
+ justify-content: center;
323
+ width: 28px;
324
+ height: 28px;
325
+ border-radius: var(--mj-radius-sm, 6px);
326
+ background: transparent;
327
+ border: 1px solid transparent;
328
+ color: var(--mj-text-muted, #94a3b8);
329
+ cursor: pointer;
330
+ padding: 0;
331
+ font-size: 12px;
332
+ transition: all 0.15s ease;
333
+ }
334
+
335
+ .mj-card__toggle-btn:hover {
336
+ color: var(--mj-text-primary, #ffffff);
337
+ background: var(--mj-bg-surface-sunken, rgba(255, 255, 255, 0.06));
338
+ border-color: var(--mj-border-default, #2a3852);
339
+ }
340
+
341
+ .mj-card__toggle-btn:focus-visible {
342
+ outline: 2px solid var(--mj-brand-primary, #38bdf8);
343
+ outline-offset: 1px;
344
+ }
345
+
346
+ .mj-card__body {
347
+ flex: 1 1 auto;
348
+ display: flex;
349
+ flex-direction: column;
350
+ justify-content: space-between;
351
+ min-width: 0;
352
+ }
353
+
354
+ .mj-card__footer {
355
+ margin-top: auto;
356
+ padding-top: var(--mj-space-3, 12px);
357
+ border-top: 1px solid var(--mj-border-default, #2a3852);
358
+ }
359
+ `;
360
+ /**
361
+ * Responsive Card Grid container that manages responsive layout and card maximization state.
362
+ */
363
+ export class MJCardGridComponent {
364
+ cdr = inject(ChangeDetectorRef);
365
+ /** Stream of the currently maximized card ID across all children. */
366
+ maximizedCard$ = new BehaviorSubject(null);
367
+ /** Number of columns for standard layout (defaults to 2). */
368
+ Columns = 2;
369
+ /** CSS gap between cards (defaults to var(--mj-space-4)). */
370
+ Gap = 'var(--mj-space-4, 16px)';
371
+ /** Currently maximized card ID. When set, only this card is shown full-width. */
372
+ MaximizedCardId = null;
373
+ /** Emits when the maximized card ID changes (two-way binding support). */
374
+ MaximizedCardIdChange = new EventEmitter();
375
+ /** Emits the card ID when a card is maximized. */
376
+ CardMaximized = new EventEmitter();
377
+ /** Emits when the maximized card is restored back to the grid view. */
378
+ CardRestored = new EventEmitter();
379
+ ngOnChanges(changes) {
380
+ if (changes['MaximizedCardId'] && !changes['MaximizedCardId'].firstChange) {
381
+ this.maximizedCard$.next(this.MaximizedCardId);
382
+ }
383
+ }
384
+ /** Pressing Escape restores the grid view if a card is maximized. */
385
+ OnEscape() {
386
+ if (this.MaximizedCardId) {
387
+ this.Restore();
388
+ }
389
+ }
390
+ MaximizeCard(cardId) {
391
+ this.MaximizedCardId = cardId;
392
+ this.maximizedCard$.next(cardId);
393
+ this.MaximizedCardIdChange.emit(cardId);
394
+ this.CardMaximized.emit(cardId);
395
+ this.cdr.markForCheck();
396
+ }
397
+ Restore() {
398
+ if (!this.MaximizedCardId)
399
+ return;
400
+ this.MaximizedCardId = null;
401
+ this.maximizedCard$.next(null);
402
+ this.MaximizedCardIdChange.emit(null);
403
+ this.CardRestored.emit();
404
+ this.cdr.markForCheck();
405
+ }
406
+ IsCardMaximized(cardId) {
407
+ return this.MaximizedCardId === cardId;
408
+ }
409
+ IsCardHidden(cardId) {
410
+ return !!this.MaximizedCardId && this.MaximizedCardId !== cardId;
411
+ }
412
+ static ɵfac = function MJCardGridComponent_Factory(__ngFactoryType__) { return new (__ngFactoryType__ || MJCardGridComponent)(); };
413
+ static ɵcmp = /*@__PURE__*/ i0.ɵɵdefineComponent({ type: MJCardGridComponent, selectors: [["mj-card-grid"]], hostBindings: function MJCardGridComponent_HostBindings(rf, ctx) { if (rf & 1) {
414
+ i0.ɵɵlistener("keydown.escape", function MJCardGridComponent_keydown_escape_HostBindingHandler() { return ctx.OnEscape(); }, i0.ɵɵresolveWindow);
415
+ } }, inputs: { Columns: "Columns", Gap: "Gap", MaximizedCardId: "MaximizedCardId" }, outputs: { MaximizedCardIdChange: "MaximizedCardIdChange", CardMaximized: "CardMaximized", CardRestored: "CardRestored" }, features: [i0.ɵɵNgOnChangesFeature], ngContentSelectors: _c0, decls: 2, vars: 6, consts: [[1, "mj-card-grid"]], template: function MJCardGridComponent_Template(rf, ctx) { if (rf & 1) {
416
+ i0.ɵɵprojectionDef();
417
+ i0.ɵɵdomElementStart(0, "div", 0);
418
+ i0.ɵɵprojection(1);
419
+ i0.ɵɵdomElementEnd();
420
+ } if (rf & 2) {
421
+ i0.ɵɵstyleProp("--mj-card-grid-columns", ctx.Columns)("--mj-card-grid-gap", ctx.Gap);
422
+ i0.ɵɵclassProp("mj-card-grid--has-maximized", !!ctx.MaximizedCardId);
423
+ } }, dependencies: [CommonModule], styles: [_c1], changeDetection: 0 });
424
+ }
425
+ (() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassMetadata(MJCardGridComponent, [{
426
+ type: Component,
427
+ args: [{ selector: 'mj-card-grid', standalone: true, imports: [CommonModule], changeDetection: ChangeDetectionStrategy.OnPush, template: `
428
+ <div class="mj-card-grid"
429
+ [class.mj-card-grid--has-maximized]="!!MaximizedCardId"
430
+ [style.--mj-card-grid-columns]="Columns"
431
+ [style.--mj-card-grid-gap]="Gap">
432
+ <ng-content></ng-content>
433
+ </div>
434
+ `, styles: ["\n:host {\n display: flex;\n flex-direction: column;\n width: 100%;\n height: 100%;\n min-width: 0;\n box-sizing: border-box;\n}\n\n.mj-card-grid {\n display: grid;\n grid-template-columns: repeat(2, minmax(0, 1fr));\n align-items: stretch;\n gap: var(--mj-card-grid-gap, var(--mj-space-4, 16px));\n width: 100%;\n position: relative;\n box-sizing: border-box;\n transition: all 0.25s cubic-bezier(0.4, 0, 0.2, 1);\n}\n\n.mj-card-grid--has-maximized {\n grid-template-columns: 1fr !important;\n}\n\n@media (max-width: 640px) {\n .mj-card-grid {\n grid-template-columns: 1fr !important;\n }\n}\n\nmj-card {\n display: flex;\n flex-direction: column;\n height: 100%;\n min-width: 0;\n width: 100%;\n box-sizing: border-box;\n}\n\n.mj-card {\n display: flex;\n flex-direction: column;\n flex: 1 1 100%;\n height: 100%;\n min-height: 290px;\n background: var(--mj-bg-surface-card, var(--mj-bg-surface, #141f33));\n border: 1px solid var(--mj-border-default, #2a3852);\n border-radius: var(--mj-radius-xl, 16px);\n box-shadow: var(--mj-shadow-sm, 0 1px 3px rgba(0, 0, 0, 0.08));\n padding: var(--mj-space-4, 16px) var(--mj-space-5, 20px);\n box-sizing: border-box;\n transition: border-color 0.2s ease, box-shadow 0.2s ease, transform 0.2s ease;\n position: relative;\n min-width: 0;\n}\n\n.mj-card:hover {\n border-color: color-mix(in srgb, var(--mj-brand-primary, #38bdf8) 40%, var(--mj-border-default, #2a3852));\n}\n\n.mj-card--maximized {\n grid-column: 1 / -1;\n width: 100%;\n min-height: 480px;\n box-shadow: var(--mj-shadow-lg, 0 10px 25px rgba(0, 0, 0, 0.25));\n border-color: var(--mj-brand-primary, #38bdf8);\n z-index: 10;\n}\n\n.mj-card--hidden {\n display: none !important;\n}\n\n.mj-card__header {\n display: flex;\n flex-direction: row;\n align-items: flex-start;\n justify-content: space-between;\n gap: var(--mj-space-3, 12px);\n margin-bottom: var(--mj-space-3, 12px);\n min-height: 28px;\n width: 100%;\n}\n\n.mj-card__title-group {\n display: flex;\n flex-direction: column;\n gap: 2px;\n min-width: 0;\n flex: 1 1 auto;\n}\n\n.mj-card__title-row {\n display: flex;\n flex-direction: row;\n align-items: center;\n gap: var(--mj-space-2, 8px);\n min-width: 0;\n}\n\n.mj-card__icon {\n color: var(--mj-brand-primary, #38bdf8);\n font-size: 14px;\n display: inline-flex;\n align-items: center;\n justify-content: center;\n flex-shrink: 0;\n}\n\n.mj-card__title {\n font-size: 14px;\n font-weight: 700;\n color: var(--mj-text-primary, #ffffff);\n letter-spacing: -0.01em;\n margin: 0;\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n}\n\n.mj-card__subtitle {\n font-size: 11.5px;\n font-weight: 500;\n color: var(--mj-text-muted, #94a3b8);\n margin: 0;\n padding-left: 22px;\n}\n\n.mj-card__actions {\n display: flex;\n flex-direction: row;\n align-items: center;\n gap: var(--mj-space-2, 8px);\n flex-shrink: 0;\n margin-left: auto;\n}\n\n.mj-card__toggle-btn {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n width: 28px;\n height: 28px;\n border-radius: var(--mj-radius-sm, 6px);\n background: transparent;\n border: 1px solid transparent;\n color: var(--mj-text-muted, #94a3b8);\n cursor: pointer;\n padding: 0;\n font-size: 12px;\n transition: all 0.15s ease;\n}\n\n.mj-card__toggle-btn:hover {\n color: var(--mj-text-primary, #ffffff);\n background: var(--mj-bg-surface-sunken, rgba(255, 255, 255, 0.06));\n border-color: var(--mj-border-default, #2a3852);\n}\n\n.mj-card__toggle-btn:focus-visible {\n outline: 2px solid var(--mj-brand-primary, #38bdf8);\n outline-offset: 1px;\n}\n\n.mj-card__body {\n flex: 1 1 auto;\n display: flex;\n flex-direction: column;\n justify-content: space-between;\n min-width: 0;\n}\n\n.mj-card__footer {\n margin-top: auto;\n padding-top: var(--mj-space-3, 12px);\n border-top: 1px solid var(--mj-border-default, #2a3852);\n}\n"] }]
435
+ }], null, { Columns: [{
436
+ type: Input
437
+ }], Gap: [{
438
+ type: Input
439
+ }], MaximizedCardId: [{
440
+ type: Input
441
+ }], MaximizedCardIdChange: [{
442
+ type: Output
443
+ }], CardMaximized: [{
444
+ type: Output
445
+ }], CardRestored: [{
446
+ type: Output
447
+ }], OnEscape: [{
448
+ type: HostListener,
449
+ args: ['window:keydown.escape']
450
+ }] }); })();
451
+ (() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassDebugInfo(MJCardGridComponent, { className: "MJCardGridComponent", filePath: "lib/card-grid/card-grid.component.ts", lineNumber: 265 }); })();
452
+ /**
453
+ * Modular card component with header title, icon, actions, and maximize/restore capability.
454
+ */
455
+ export class MJCardComponent {
456
+ grid = inject(MJCardGridComponent, { optional: true });
457
+ cdr = inject(ChangeDetectorRef);
458
+ sub;
459
+ CardId = `mj-card-${++nextCardId}`;
460
+ Title;
461
+ Subtitle;
462
+ Icon;
463
+ AllowMaximize = true;
464
+ MaximizeTooltip = 'Expand card';
465
+ RestoreTooltip = 'Restore view';
466
+ ShowHeader = true;
467
+ Maximize = new EventEmitter();
468
+ Restore = new EventEmitter();
469
+ TitleTemplate;
470
+ ActionsTemplate;
471
+ ToolsTemplate;
472
+ FooterTemplate;
473
+ get IsMaximized() {
474
+ if (this.grid) {
475
+ return this.grid.IsCardMaximized(this.CardId);
476
+ }
477
+ return false;
478
+ }
479
+ get IsHidden() {
480
+ if (this.grid) {
481
+ return this.grid.IsCardHidden(this.CardId);
482
+ }
483
+ return false;
484
+ }
485
+ ngOnInit() {
486
+ if (!this.CardId) {
487
+ this.CardId = `mj-card-${++nextCardId}`;
488
+ }
489
+ if (this.grid) {
490
+ this.sub = this.grid.maximizedCard$.subscribe(() => {
491
+ this.cdr.markForCheck();
492
+ });
493
+ }
494
+ }
495
+ ngOnDestroy() {
496
+ this.sub?.unsubscribe();
497
+ }
498
+ ToggleMaximize(event) {
499
+ if (event) {
500
+ event.stopPropagation();
501
+ }
502
+ if (this.IsMaximized) {
503
+ this.grid?.Restore();
504
+ this.Restore.emit();
505
+ }
506
+ else {
507
+ this.grid?.MaximizeCard(this.CardId);
508
+ this.Maximize.emit();
509
+ }
510
+ this.cdr.markForCheck();
511
+ }
512
+ static ɵfac = function MJCardComponent_Factory(__ngFactoryType__) { return new (__ngFactoryType__ || MJCardComponent)(); };
513
+ static ɵcmp = /*@__PURE__*/ i0.ɵɵdefineComponent({ type: MJCardComponent, selectors: [["mj-card"]], contentQueries: function MJCardComponent_ContentQueries(rf, ctx, dirIndex) { if (rf & 1) {
514
+ i0.ɵɵcontentQuery(dirIndex, MJCardTitleDirective, 5)(dirIndex, MJCardActionsDirective, 5)(dirIndex, MJCardToolsDirective, 5)(dirIndex, MJCardFooterDirective, 5);
515
+ } if (rf & 2) {
516
+ let _t;
517
+ i0.ɵɵqueryRefresh(_t = i0.ɵɵloadQuery()) && (ctx.TitleTemplate = _t.first);
518
+ i0.ɵɵqueryRefresh(_t = i0.ɵɵloadQuery()) && (ctx.ActionsTemplate = _t.first);
519
+ i0.ɵɵqueryRefresh(_t = i0.ɵɵloadQuery()) && (ctx.ToolsTemplate = _t.first);
520
+ i0.ɵɵqueryRefresh(_t = i0.ɵɵloadQuery()) && (ctx.FooterTemplate = _t.first);
521
+ } }, inputs: { CardId: "CardId", Title: "Title", Subtitle: "Subtitle", Icon: "Icon", AllowMaximize: "AllowMaximize", MaximizeTooltip: "MaximizeTooltip", RestoreTooltip: "RestoreTooltip", ShowHeader: "ShowHeader" }, outputs: { Maximize: "Maximize", Restore: "Restore" }, ngContentSelectors: _c0, decls: 5, vars: 7, consts: [["role", "region", 1, "mj-card"], [1, "mj-card__header"], [1, "mj-card__body"], [1, "mj-card__footer"], [1, "mj-card__title-group"], [1, "mj-card__title-row"], ["aria-hidden", "true", 1, "mj-card__icon"], [3, "ngTemplateOutlet"], [1, "mj-card__title"], [1, "mj-card__subtitle"], [1, "mj-card__actions"], ["type", "button", 1, "mj-card__toggle-btn", 3, "title"], ["type", "button", 1, "mj-card__toggle-btn", 3, "click", "title"], ["aria-hidden", "true", 1, "fa-solid", "fa-compress"], ["aria-hidden", "true", 1, "fa-solid", "fa-expand"]], template: function MJCardComponent_Template(rf, ctx) { if (rf & 1) {
522
+ i0.ɵɵprojectionDef();
523
+ i0.ɵɵelementStart(0, "div", 0);
524
+ i0.ɵɵconditionalCreate(1, MJCardComponent_Conditional_1_Template, 11, 6, "div", 1);
525
+ i0.ɵɵelementStart(2, "div", 2);
526
+ i0.ɵɵprojection(3);
527
+ i0.ɵɵelementEnd();
528
+ i0.ɵɵconditionalCreate(4, MJCardComponent_Conditional_4_Template, 2, 1, "div", 3);
529
+ i0.ɵɵelementEnd();
530
+ } if (rf & 2) {
531
+ i0.ɵɵclassProp("mj-card--maximized", ctx.IsMaximized)("mj-card--hidden", ctx.IsHidden);
532
+ i0.ɵɵattribute("aria-label", ctx.Title || "Card");
533
+ i0.ɵɵadvance();
534
+ i0.ɵɵconditional(ctx.ShowHeader ? 1 : -1);
535
+ i0.ɵɵadvance(3);
536
+ i0.ɵɵconditional(ctx.FooterTemplate ? 4 : -1);
537
+ } }, dependencies: [CommonModule, i1.NgTemplateOutlet], styles: [_c1], changeDetection: 0 });
538
+ }
539
+ (() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassMetadata(MJCardComponent, [{
540
+ type: Component,
541
+ args: [{ selector: 'mj-card', standalone: true, imports: [CommonModule], changeDetection: ChangeDetectionStrategy.OnPush, template: `
542
+ <div class="mj-card"
543
+ [class.mj-card--maximized]="IsMaximized"
544
+ [class.mj-card--hidden]="IsHidden"
545
+ role="region"
546
+ [attr.aria-label]="Title || 'Card'">
547
+
548
+ <!-- Card Header -->
549
+ @if (ShowHeader) {
550
+ <div class="mj-card__header">
551
+ <div class="mj-card__title-group">
552
+ <div class="mj-card__title-row">
553
+ @if (Icon) {
554
+ <span class="mj-card__icon" aria-hidden="true">
555
+ <i [class]="Icon"></i>
556
+ </span>
557
+ }
558
+ @if (TitleTemplate) {
559
+ <ng-container [ngTemplateOutlet]="TitleTemplate.templateRef"></ng-container>
560
+ } @else if (Title) {
561
+ <h3 class="mj-card__title">{{ Title }}</h3>
562
+ }
563
+ </div>
564
+ @if (Subtitle) {
565
+ <span class="mj-card__subtitle">{{ Subtitle }}</span>
566
+ }
567
+ </div>
568
+
569
+ <div class="mj-card__actions">
570
+ @if (ToolsTemplate) {
571
+ <ng-container [ngTemplateOutlet]="ToolsTemplate.templateRef"></ng-container>
572
+ }
573
+ @if (ActionsTemplate) {
574
+ <ng-container [ngTemplateOutlet]="ActionsTemplate.templateRef"></ng-container>
575
+ }
576
+ @if (AllowMaximize) {
577
+ <button type="button"
578
+ class="mj-card__toggle-btn"
579
+ [title]="IsMaximized ? RestoreTooltip : MaximizeTooltip"
580
+ [attr.aria-label]="IsMaximized ? RestoreTooltip : MaximizeTooltip"
581
+ (click)="ToggleMaximize($event)">
582
+ @if (IsMaximized) {
583
+ <i class="fa-solid fa-compress" aria-hidden="true"></i>
584
+ } @else {
585
+ <i class="fa-solid fa-expand" aria-hidden="true"></i>
586
+ }
587
+ </button>
588
+ }
589
+ </div>
590
+ </div>
591
+ }
592
+
593
+ <!-- Card Body -->
594
+ <div class="mj-card__body">
595
+ <ng-content></ng-content>
596
+ </div>
597
+
598
+ <!-- Card Footer -->
599
+ @if (FooterTemplate) {
600
+ <div class="mj-card__footer">
601
+ <ng-container [ngTemplateOutlet]="FooterTemplate.templateRef"></ng-container>
602
+ </div>
603
+ }
604
+ </div>
605
+ `, styles: ["\n:host {\n display: flex;\n flex-direction: column;\n width: 100%;\n height: 100%;\n min-width: 0;\n box-sizing: border-box;\n}\n\n.mj-card-grid {\n display: grid;\n grid-template-columns: repeat(2, minmax(0, 1fr));\n align-items: stretch;\n gap: var(--mj-card-grid-gap, var(--mj-space-4, 16px));\n width: 100%;\n position: relative;\n box-sizing: border-box;\n transition: all 0.25s cubic-bezier(0.4, 0, 0.2, 1);\n}\n\n.mj-card-grid--has-maximized {\n grid-template-columns: 1fr !important;\n}\n\n@media (max-width: 640px) {\n .mj-card-grid {\n grid-template-columns: 1fr !important;\n }\n}\n\nmj-card {\n display: flex;\n flex-direction: column;\n height: 100%;\n min-width: 0;\n width: 100%;\n box-sizing: border-box;\n}\n\n.mj-card {\n display: flex;\n flex-direction: column;\n flex: 1 1 100%;\n height: 100%;\n min-height: 290px;\n background: var(--mj-bg-surface-card, var(--mj-bg-surface, #141f33));\n border: 1px solid var(--mj-border-default, #2a3852);\n border-radius: var(--mj-radius-xl, 16px);\n box-shadow: var(--mj-shadow-sm, 0 1px 3px rgba(0, 0, 0, 0.08));\n padding: var(--mj-space-4, 16px) var(--mj-space-5, 20px);\n box-sizing: border-box;\n transition: border-color 0.2s ease, box-shadow 0.2s ease, transform 0.2s ease;\n position: relative;\n min-width: 0;\n}\n\n.mj-card:hover {\n border-color: color-mix(in srgb, var(--mj-brand-primary, #38bdf8) 40%, var(--mj-border-default, #2a3852));\n}\n\n.mj-card--maximized {\n grid-column: 1 / -1;\n width: 100%;\n min-height: 480px;\n box-shadow: var(--mj-shadow-lg, 0 10px 25px rgba(0, 0, 0, 0.25));\n border-color: var(--mj-brand-primary, #38bdf8);\n z-index: 10;\n}\n\n.mj-card--hidden {\n display: none !important;\n}\n\n.mj-card__header {\n display: flex;\n flex-direction: row;\n align-items: flex-start;\n justify-content: space-between;\n gap: var(--mj-space-3, 12px);\n margin-bottom: var(--mj-space-3, 12px);\n min-height: 28px;\n width: 100%;\n}\n\n.mj-card__title-group {\n display: flex;\n flex-direction: column;\n gap: 2px;\n min-width: 0;\n flex: 1 1 auto;\n}\n\n.mj-card__title-row {\n display: flex;\n flex-direction: row;\n align-items: center;\n gap: var(--mj-space-2, 8px);\n min-width: 0;\n}\n\n.mj-card__icon {\n color: var(--mj-brand-primary, #38bdf8);\n font-size: 14px;\n display: inline-flex;\n align-items: center;\n justify-content: center;\n flex-shrink: 0;\n}\n\n.mj-card__title {\n font-size: 14px;\n font-weight: 700;\n color: var(--mj-text-primary, #ffffff);\n letter-spacing: -0.01em;\n margin: 0;\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n}\n\n.mj-card__subtitle {\n font-size: 11.5px;\n font-weight: 500;\n color: var(--mj-text-muted, #94a3b8);\n margin: 0;\n padding-left: 22px;\n}\n\n.mj-card__actions {\n display: flex;\n flex-direction: row;\n align-items: center;\n gap: var(--mj-space-2, 8px);\n flex-shrink: 0;\n margin-left: auto;\n}\n\n.mj-card__toggle-btn {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n width: 28px;\n height: 28px;\n border-radius: var(--mj-radius-sm, 6px);\n background: transparent;\n border: 1px solid transparent;\n color: var(--mj-text-muted, #94a3b8);\n cursor: pointer;\n padding: 0;\n font-size: 12px;\n transition: all 0.15s ease;\n}\n\n.mj-card__toggle-btn:hover {\n color: var(--mj-text-primary, #ffffff);\n background: var(--mj-bg-surface-sunken, rgba(255, 255, 255, 0.06));\n border-color: var(--mj-border-default, #2a3852);\n}\n\n.mj-card__toggle-btn:focus-visible {\n outline: 2px solid var(--mj-brand-primary, #38bdf8);\n outline-offset: 1px;\n}\n\n.mj-card__body {\n flex: 1 1 auto;\n display: flex;\n flex-direction: column;\n justify-content: space-between;\n min-width: 0;\n}\n\n.mj-card__footer {\n margin-top: auto;\n padding-top: var(--mj-space-3, 12px);\n border-top: 1px solid var(--mj-border-default, #2a3852);\n}\n"] }]
606
+ }], null, { CardId: [{
607
+ type: Input
608
+ }], Title: [{
609
+ type: Input
610
+ }], Subtitle: [{
611
+ type: Input
612
+ }], Icon: [{
613
+ type: Input
614
+ }], AllowMaximize: [{
615
+ type: Input
616
+ }], MaximizeTooltip: [{
617
+ type: Input
618
+ }], RestoreTooltip: [{
619
+ type: Input
620
+ }], ShowHeader: [{
621
+ type: Input
622
+ }], Maximize: [{
623
+ type: Output
624
+ }], Restore: [{
625
+ type: Output
626
+ }], TitleTemplate: [{
627
+ type: ContentChild,
628
+ args: [MJCardTitleDirective]
629
+ }], ActionsTemplate: [{
630
+ type: ContentChild,
631
+ args: [MJCardActionsDirective]
632
+ }], ToolsTemplate: [{
633
+ type: ContentChild,
634
+ args: [MJCardToolsDirective]
635
+ }], FooterTemplate: [{
636
+ type: ContentChild,
637
+ args: [MJCardFooterDirective]
638
+ }] }); })();
639
+ (() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassDebugInfo(MJCardComponent, { className: "MJCardComponent", filePath: "lib/card-grid/card-grid.component.ts", lineNumber: 404 }); })();
640
+ //# sourceMappingURL=card-grid.component.js.map