@memberjunction/ng-ui-components 5.43.0 → 5.45.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (31) hide show
  1. package/dist/lib/accordion/accordion.component.d.ts +137 -2
  2. package/dist/lib/accordion/accordion.component.d.ts.map +1 -1
  3. package/dist/lib/accordion/accordion.component.js +300 -43
  4. package/dist/lib/accordion/accordion.component.js.map +1 -1
  5. package/dist/lib/accordion/accordion.scss +256 -13
  6. package/dist/lib/alert/alert.component.d.ts +97 -0
  7. package/dist/lib/alert/alert.component.d.ts.map +1 -0
  8. package/dist/lib/alert/alert.component.js +235 -0
  9. package/dist/lib/alert/alert.component.js.map +1 -0
  10. package/dist/lib/confirm-dialog/confirm-dialog.component.d.ts +102 -0
  11. package/dist/lib/confirm-dialog/confirm-dialog.component.d.ts.map +1 -0
  12. package/dist/lib/confirm-dialog/confirm-dialog.component.js +259 -0
  13. package/dist/lib/confirm-dialog/confirm-dialog.component.js.map +1 -0
  14. package/dist/lib/confirm-dialog/confirm-dialog.service.d.ts +78 -0
  15. package/dist/lib/confirm-dialog/confirm-dialog.service.d.ts.map +1 -0
  16. package/dist/lib/confirm-dialog/confirm-dialog.service.js +125 -0
  17. package/dist/lib/confirm-dialog/confirm-dialog.service.js.map +1 -0
  18. package/dist/lib/dialog/dialog.component.d.ts +8 -1
  19. package/dist/lib/dialog/dialog.component.d.ts.map +1 -1
  20. package/dist/lib/dialog/dialog.component.js +15 -6
  21. package/dist/lib/dialog/dialog.component.js.map +1 -1
  22. package/dist/lib/empty-state/empty-state.component.d.ts +114 -0
  23. package/dist/lib/empty-state/empty-state.component.d.ts.map +1 -0
  24. package/dist/lib/empty-state/empty-state.component.js +268 -0
  25. package/dist/lib/empty-state/empty-state.component.js.map +1 -0
  26. package/dist/lib/slide-panel/slide-panel.component.js +2 -2
  27. package/dist/public-api.d.ts +4 -0
  28. package/dist/public-api.d.ts.map +1 -1
  29. package/dist/public-api.js +4 -0
  30. package/dist/public-api.js.map +1 -1
  31. package/package.json +2 -2
@@ -0,0 +1 @@
1
+ {"version":3,"file":"confirm-dialog.service.js","sourceRoot":"","sources":["../../../src/lib/confirm-dialog/confirm-dialog.service.ts"],"names":[],"mappings":"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","sourcesContent":["import { ApplicationRef, ComponentRef, Injectable, createComponent, inject } from '@angular/core';\nimport { MJConfirmDialogComponent, MJConfirmDialogType } from './confirm-dialog.component';\n\n/**\n * Options for {@link MJConfirmService.Confirm}. Mirror the `<mj-confirm-dialog>`\n * inputs, but in a flat options bag suited to an imperative call.\n */\nexport interface MJConfirmOptions {\n /** Primary prompt text. */\n message: string;\n /** Title-bar heading. Defaults to 'Confirm'. */\n title?: string;\n /** Optional secondary line, rendered smaller/muted beneath the message. */\n detail?: string;\n /** Visual intent — drives the header icon + confirm button color. Defaults to 'default'. */\n type?: MJConfirmDialogType;\n /** Affirmative button label. Defaults to 'Confirm'. */\n confirmText?: string;\n /** Dismiss button label. Defaults to 'Cancel'. */\n cancelText?: string;\n /** Font Awesome icon override (e.g. \"fa-solid fa-trash\"). `''` suppresses the icon. */\n icon?: string;\n}\n\n/**\n * MJConfirmService — Imperative, Promise-based confirmation prompts.\n *\n * The one-liner replacement for native `window.confirm()` (an anti-pattern this\n * codebase bans) and for the boilerplate of wiring `<mj-confirm-dialog>` into a\n * template just to ask a yes/no question. It dynamically mounts an\n * `MJConfirmDialogComponent` to `document.body`, shows it, and resolves a\n * `Promise<boolean>` — `true` on confirm, `false` on cancel/backdrop/Esc — then\n * tears the component down.\n *\n * @example\n * ```typescript\n * private confirm = inject(MJConfirmService);\n *\n * // Simplest — replaces `if (window.confirm('Discard changes?')) { ... }`\n * if (await this.confirm.Confirm('Discard unsaved changes?')) {\n * this.discard();\n * }\n *\n * // Destructive delete with a detail line\n * if (await this.confirm.ConfirmDelete({\n * message: 'Delete this user?',\n * detail: 'This action cannot be undone.',\n * })) {\n * await this.deleteUser();\n * }\n * ```\n *\n * **Async work after confirm:** because this resolves a boolean, the dialog has\n * already closed by the time your `await` continues — there's no in-dialog\n * spinner. When you need a \"keep open + spinner while I save\" UX, use the\n * `<mj-confirm-dialog>` component directly with its `Processing` input instead.\n *\n * **Synchronous guards:** `window.confirm` blocks the thread; a synchronous\n * `CanClose`/`beforeunload` guard that must return a boolean *immediately*\n * cannot use this async service. Those rare cases stay on `window.confirm` as a\n * documented exception.\n */\n@Injectable({ providedIn: 'root' })\nexport class MJConfirmService {\n private appRef = inject(ApplicationRef);\n\n /**\n * Ask the user to confirm. Pass a bare string for the simplest case, or an\n * options bag for control over title/type/labels/detail.\n * @returns a Promise resolving `true` if confirmed, `false` otherwise.\n */\n Confirm(options: MJConfirmOptions | string): Promise<boolean> {\n const opts: MJConfirmOptions = typeof options === 'string' ? { message: options } : options;\n\n return new Promise<boolean>((resolve) => {\n const ref = createComponent(MJConfirmDialogComponent, {\n environmentInjector: this.appRef.injector,\n });\n this.applyInputs(ref, opts);\n // An imperative confirm must layer above whatever surface launched it —\n // bespoke drawers/panels go up to ~1101 and mj-window sits at 10000,\n // all above the shared mj-dialog backdrop (1000). Without this, a\n // confirm opened from such an overlay renders UNDER its backdrop:\n // unclickable, and each swallowed click can re-trigger the caller and\n // stack another dialog. position:relative + z-index forms a stacking\n // context on the host that lifts the fixed backdrop/dialog inside it\n // to this level (20000 — above mj-window, below toasts at 100000)\n // without touching the fixed element's viewport-relative geometry.\n const host = ref.location.nativeElement as HTMLElement;\n host.style.position = 'relative';\n host.style.zIndex = '20000';\n document.body.appendChild(host);\n this.appRef.attachView(ref.hostView);\n\n let settled = false;\n const finish = (result: boolean): void => {\n if (settled) {\n return;\n }\n settled = true;\n confirmedSub.unsubscribe();\n cancelledSub.unsubscribe();\n this.appRef.detachView(ref.hostView);\n ref.location.nativeElement.remove();\n ref.destroy();\n resolve(result);\n };\n\n const confirmedSub = ref.instance.Confirmed.subscribe(() => finish(true));\n const cancelledSub = ref.instance.Cancelled.subscribe(() => finish(false));\n\n ref.instance.Visible = true;\n ref.changeDetectorRef.detectChanges();\n });\n }\n\n /**\n * Convenience for destructive deletes — `type: 'danger'` and a 'Delete'\n * confirm label by default (both overridable via `options`).\n */\n ConfirmDelete(options: Omit<MJConfirmOptions, 'type'>): Promise<boolean> {\n return this.Confirm({ confirmText: 'Delete', ...options, type: 'danger' });\n }\n\n private applyInputs(ref: ComponentRef<MJConfirmDialogComponent>, opts: MJConfirmOptions): void {\n const i = ref.instance;\n i.Message = opts.message;\n if (opts.title != null) {\n i.Title = opts.title;\n }\n if (opts.detail != null) {\n i.DetailMessage = opts.detail;\n }\n if (opts.type != null) {\n i.Type = opts.type;\n }\n if (opts.confirmText != null) {\n i.ConfirmText = opts.confirmText;\n }\n if (opts.cancelText != null) {\n i.CancelText = opts.cancelText;\n }\n if (opts.icon != null) {\n i.Icon = opts.icon;\n }\n }\n}\n"]}
@@ -31,6 +31,13 @@ export declare class MJDialogComponent implements OnDestroy {
31
31
  Size: MjDialogSize;
32
32
  Closeable: boolean;
33
33
  MinWidth: number | null;
34
+ /**
35
+ * ARIA role for the dialog container. Defaults to `'dialog'`; pass
36
+ * `'alertdialog'` for confirmation / destructive prompts that interrupt the
37
+ * user (per WAI-ARIA, an alertdialog conveys an urgent message requiring a
38
+ * response). Backward compatible — existing callers keep `'dialog'`.
39
+ */
40
+ Role: 'dialog' | 'alertdialog';
34
41
  Close: EventEmitter<void>;
35
42
  DialogId: number;
36
43
  get dialogId(): number;
@@ -43,7 +50,7 @@ export declare class MJDialogComponent implements OnDestroy {
43
50
  private onCloseInternal;
44
51
  ngOnDestroy(): void;
45
52
  static ɵfac: i0.ɵɵFactoryDeclaration<MJDialogComponent, never>;
46
- static ɵcmp: i0.ɵɵComponentDeclaration<MJDialogComponent, "mj-dialog", never, { "Visible": { "alias": "Visible"; "required": false; }; "Title": { "alias": "Title"; "required": false; }; "Width": { "alias": "Width"; "required": false; }; "Height": { "alias": "Height"; "required": false; }; "Size": { "alias": "Size"; "required": false; }; "Closeable": { "alias": "Closeable"; "required": false; }; "MinWidth": { "alias": "MinWidth"; "required": false; }; }, { "Close": "Close"; }, never, ["mj-dialog-titlebar", "*", "mj-dialog-actions"], true, never>;
53
+ static ɵcmp: i0.ɵɵComponentDeclaration<MJDialogComponent, "mj-dialog", never, { "Visible": { "alias": "Visible"; "required": false; }; "Title": { "alias": "Title"; "required": false; }; "Width": { "alias": "Width"; "required": false; }; "Height": { "alias": "Height"; "required": false; }; "Size": { "alias": "Size"; "required": false; }; "Closeable": { "alias": "Closeable"; "required": false; }; "MinWidth": { "alias": "MinWidth"; "required": false; }; "Role": { "alias": "Role"; "required": false; }; }, { "Close": "Close"; }, never, ["mj-dialog-titlebar", "*", "mj-dialog-actions"], true, never>;
47
54
  }
48
55
  /**
49
56
  * mj-dialog-titlebar — Custom titlebar content for mj-dialog.
@@ -1 +1 @@
1
- {"version":3,"file":"dialog.component.d.ts","sourceRoot":"","sources":["../../../src/lib/dialog/dialog.component.ts"],"names":[],"mappings":"AAAA,OAAO,EAIL,YAAY,EAKZ,SAAS,EAEV,MAAM,eAAe,CAAC;;AAEvB,MAAM,MAAM,YAAY,GAAG,IAAI,GAAG,IAAI,GAAG,IAAI,GAAG,IAAI,GAAG,MAAM,CAAC;AAU9D;;;;;;;;;;;;;;;;;;GAkBG;AACH,qBA2Ca,iBAAkB,YAAW,SAAS;IACjD,OAAO,CAAC,QAAQ,CAAS;IACzB,OAAO,CAAC,MAAM,CAAC,MAAM,CAAK;IAE1B,IACI,OAAO,CAAC,KAAK,EAAE,OAAO,EASzB;IACD,IAAI,OAAO,IAAI,OAAO,CAErB;IAEQ,KAAK,SAAM;IACX,KAAK,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAAQ;IACrC,MAAM,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAAQ;IACtC,IAAI,EAAE,YAAY,CAAU;IAC5B,SAAS,UAAQ;IACjB,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAQ;IAE9B,KAAK,qBAA4B;IAE3C,QAAQ,SAA8B;IAEtC,IAAI,QAAQ,IAAI,MAAM,CAErB;IAED,IAAI,aAAa,IAAI,MAAM,CAK1B;IAED,IAAI,cAAc,IAAI,MAAM,CAK3B;IAGD,WAAW,IAAI,IAAI;IAMnB,eAAe,CAAC,KAAK,EAAE,KAAK,GAAG,IAAI;IAMnC,YAAY,IAAI,IAAI;IAIpB,OAAO,CAAC,MAAM;IAId,OAAO,CAAC,eAAe;IAIvB,WAAW,IAAI,IAAI;yCAzER,iBAAiB;2CAAjB,iBAAiB;CA4E7B;AAED;;;;;;;;;;;;;;GAcG;AACH,qBAKa,yBAAyB;yCAAzB,yBAAyB;2CAAzB,yBAAyB;CAAG;AAEzC;;;;;;;;;;;;GAYG;AACH,qBASa,wBAAwB;yCAAxB,wBAAwB;2CAAxB,wBAAwB;CAAG"}
1
+ {"version":3,"file":"dialog.component.d.ts","sourceRoot":"","sources":["../../../src/lib/dialog/dialog.component.ts"],"names":[],"mappings":"AAAA,OAAO,EAIL,YAAY,EAKZ,SAAS,EAEV,MAAM,eAAe,CAAC;;AAEvB,MAAM,MAAM,YAAY,GAAG,IAAI,GAAG,IAAI,GAAG,IAAI,GAAG,IAAI,GAAG,MAAM,CAAC;AAU9D;;;;;;;;;;;;;;;;;;GAkBG;AACH,qBA2Ca,iBAAkB,YAAW,SAAS;IACjD,OAAO,CAAC,QAAQ,CAAS;IACzB,OAAO,CAAC,MAAM,CAAC,MAAM,CAAK;IAE1B,IACI,OAAO,CAAC,KAAK,EAAE,OAAO,EASzB;IACD,IAAI,OAAO,IAAI,OAAO,CAErB;IAEQ,KAAK,SAAM;IACX,KAAK,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAAQ;IACrC,MAAM,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAAQ;IACtC,IAAI,EAAE,YAAY,CAAU;IAC5B,SAAS,UAAQ;IACjB,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAQ;IAExC;;;;;OAKG;IACM,IAAI,EAAE,QAAQ,GAAG,aAAa,CAAY;IAEzC,KAAK,qBAA4B;IAE3C,QAAQ,SAA8B;IAEtC,IAAI,QAAQ,IAAI,MAAM,CAErB;IAED,IAAI,aAAa,IAAI,MAAM,CAK1B;IAED,IAAI,cAAc,IAAI,MAAM,CAK3B;IAGD,WAAW,IAAI,IAAI;IAMnB,eAAe,CAAC,KAAK,EAAE,KAAK,GAAG,IAAI;IAMnC,YAAY,IAAI,IAAI;IAIpB,OAAO,CAAC,MAAM;IAId,OAAO,CAAC,eAAe;IAIvB,WAAW,IAAI,IAAI;yCAjFR,iBAAiB;2CAAjB,iBAAiB;CAoF7B;AAED;;;;;;;;;;;;;;GAcG;AACH,qBAKa,yBAAyB;yCAAzB,yBAAyB;2CAAzB,yBAAyB;CAAG;AAEzC;;;;;;;;;;;;GAYG;AACH,qBASa,wBAAwB;yCAAxB,wBAAwB;2CAAxB,wBAAwB;CAAG"}
@@ -48,7 +48,7 @@ function MJDialogComponent_Conditional_0_Template(rf, ctx) { if (rf & 1) {
48
48
  const ctx_r1 = i0.ɵɵnextContext();
49
49
  i0.ɵɵadvance();
50
50
  i0.ɵɵstyleProp("width", ctx_r1.resolvedWidth)("height", ctx_r1.resolvedHeight)("max-width", "90vw")("max-height", "90vh");
51
- i0.ɵɵattribute("aria-labelledby", ctx_r1.Title ? "mj-dialog-title-" + ctx_r1.dialogId : null);
51
+ i0.ɵɵattribute("role", ctx_r1.Role)("aria-labelledby", ctx_r1.Title ? "mj-dialog-title-" + ctx_r1.dialogId : null);
52
52
  i0.ɵɵadvance();
53
53
  i0.ɵɵconditional(ctx_r1.Title || ctx_r1.Closeable ? 2 : -1);
54
54
  } }
@@ -101,6 +101,13 @@ export class MJDialogComponent {
101
101
  Size = 'auto';
102
102
  Closeable = true;
103
103
  MinWidth = null;
104
+ /**
105
+ * ARIA role for the dialog container. Defaults to `'dialog'`; pass
106
+ * `'alertdialog'` for confirmation / destructive prompts that interrupt the
107
+ * user (per WAI-ARIA, an alertdialog conveys an urgent message requiring a
108
+ * response). Backward compatible — existing callers keep `'dialog'`.
109
+ */
110
+ Role = 'dialog';
104
111
  Close = new EventEmitter();
105
112
  DialogId = MJDialogComponent.nextId++;
106
113
  get dialogId() {
@@ -143,9 +150,9 @@ export class MJDialogComponent {
143
150
  static ɵfac = function MJDialogComponent_Factory(__ngFactoryType__) { return new (__ngFactoryType__ || MJDialogComponent)(); };
144
151
  static ɵcmp = /*@__PURE__*/ i0.ɵɵdefineComponent({ type: MJDialogComponent, selectors: [["mj-dialog"]], hostBindings: function MJDialogComponent_HostBindings(rf, ctx) { if (rf & 1) {
145
152
  i0.ɵɵlistener("keydown.escape", function MJDialogComponent_keydown_escape_HostBindingHandler() { return ctx.OnEscapeKey(); }, i0.ɵɵresolveDocument);
146
- } }, inputs: { Visible: "Visible", Title: "Title", Width: "Width", Height: "Height", Size: "Size", Closeable: "Closeable", MinWidth: "MinWidth" }, outputs: { Close: "Close" }, ngContentSelectors: _c1, decls: 1, vars: 1, consts: [[1, "mj-dialog-backdrop"], [1, "mj-dialog-backdrop", 3, "click"], ["role", "dialog", "aria-modal", "true", 1, "mj-dialog-container", 3, "click"], [1, "mj-dialog-titlebar"], [1, "mj-dialog-body"], [1, "mj-dialog-title", 3, "id"], ["aria-label", "Close dialog", 1, "mj-dialog-close"], ["aria-label", "Close dialog", 1, "mj-dialog-close", 3, "click"], [1, "fa-solid", "fa-times"]], template: function MJDialogComponent_Template(rf, ctx) { if (rf & 1) {
153
+ } }, inputs: { Visible: "Visible", Title: "Title", Width: "Width", Height: "Height", Size: "Size", Closeable: "Closeable", MinWidth: "MinWidth", Role: "Role" }, outputs: { Close: "Close" }, ngContentSelectors: _c1, decls: 1, vars: 1, consts: [[1, "mj-dialog-backdrop"], [1, "mj-dialog-backdrop", 3, "click"], ["aria-modal", "true", 1, "mj-dialog-container", 3, "click"], [1, "mj-dialog-titlebar"], [1, "mj-dialog-body"], [1, "mj-dialog-title", 3, "id"], ["aria-label", "Close dialog", 1, "mj-dialog-close"], ["aria-label", "Close dialog", 1, "mj-dialog-close", 3, "click"], [1, "fa-solid", "fa-times"]], template: function MJDialogComponent_Template(rf, ctx) { if (rf & 1) {
147
154
  i0.ɵɵprojectionDef(_c0);
148
- i0.ɵɵconditionalCreate(0, MJDialogComponent_Conditional_0_Template, 6, 10, "div", 0);
155
+ i0.ɵɵconditionalCreate(0, MJDialogComponent_Conditional_0_Template, 6, 11, "div", 0);
149
156
  } if (rf & 2) {
150
157
  i0.ɵɵconditional(ctx.Visible ? 0 : -1);
151
158
  } }, encapsulation: 2 });
@@ -159,7 +166,7 @@ export class MJDialogComponent {
159
166
  @if (Visible) {
160
167
  <div class="mj-dialog-backdrop" (click)="OnBackdropClick($event)">
161
168
  <div class="mj-dialog-container"
162
- role="dialog"
169
+ [attr.role]="Role"
163
170
  aria-modal="true"
164
171
  [attr.aria-labelledby]="Title ? 'mj-dialog-title-' + dialogId : null"
165
172
  [style.width]="resolvedWidth"
@@ -209,6 +216,8 @@ export class MJDialogComponent {
209
216
  type: Input
210
217
  }], MinWidth: [{
211
218
  type: Input
219
+ }], Role: [{
220
+ type: Input
212
221
  }], Close: [{
213
222
  type: Output
214
223
  }], OnEscapeKey: [{
@@ -246,7 +255,7 @@ export class MJDialogTitlebarComponent {
246
255
  template: `<ng-content></ng-content>`
247
256
  }]
248
257
  }], null, null); })();
249
- (() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassDebugInfo(MJDialogTitlebarComponent, { className: "MJDialogTitlebarComponent", filePath: "lib/dialog/dialog.component.ts", lineNumber: 184 }); })();
258
+ (() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassDebugInfo(MJDialogTitlebarComponent, { className: "MJDialogTitlebarComponent", filePath: "lib/dialog/dialog.component.ts", lineNumber: 192 }); })();
250
259
  /**
251
260
  * mj-dialog-actions — Footer action bar for mj-dialog.
252
261
  *
@@ -281,5 +290,5 @@ export class MJDialogActionsComponent {
281
290
  `
282
291
  }]
283
292
  }], null, null); })();
284
- (() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassDebugInfo(MJDialogActionsComponent, { className: "MJDialogActionsComponent", filePath: "lib/dialog/dialog.component.ts", lineNumber: 208 }); })();
293
+ (() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassDebugInfo(MJDialogActionsComponent, { className: "MJDialogActionsComponent", filePath: "lib/dialog/dialog.component.ts", lineNumber: 216 }); })();
285
294
  //# sourceMappingURL=dialog.component.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"dialog.component.js","sourceRoot":"","sources":["../../../src/lib/dialog/dialog.component.ts"],"names":[],"mappings":"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","sourcesContent":["import {\n Component,\n Input,\n Output,\n EventEmitter,\n HostListener,\n ElementRef,\n ViewChild,\n AfterViewInit,\n OnDestroy,\n inject\n} from '@angular/core';\n\nexport type MjDialogSize = 'sm' | 'md' | 'lg' | 'xl' | 'auto';\n\nconst SIZE_MAP: Record<MjDialogSize, string> = {\n sm: '400px',\n md: '600px',\n lg: '800px',\n xl: '1000px',\n auto: 'auto'\n};\n\n/**\n * mj-dialog — Modal dialog component using native `<dialog>` element.\n *\n * Replaces `<kendo-dialog>`.\n *\n * Supports both explicit width/height and size presets.\n * Content is projected, with an optional `<mj-dialog-actions>` for the footer.\n *\n * @example\n * ```html\n * <mj-dialog [Visible]=\"showDialog\" Title=\"Confirm\" (Close)=\"onClose()\">\n * <p>Are you sure?</p>\n * <mj-dialog-actions>\n * <button mjButton variant=\"primary\" (click)=\"onConfirm()\">Yes</button>\n * <button mjButton (click)=\"onClose()\">No</button>\n * </mj-dialog-actions>\n * </mj-dialog>\n * ```\n */\n@Component({\n selector: 'mj-dialog',\n standalone: true,\n template: `\n @if (Visible) {\n <div class=\"mj-dialog-backdrop\" (click)=\"OnBackdropClick($event)\">\n <div class=\"mj-dialog-container\"\n role=\"dialog\"\n aria-modal=\"true\"\n [attr.aria-labelledby]=\"Title ? 'mj-dialog-title-' + dialogId : null\"\n [style.width]=\"resolvedWidth\"\n [style.height]=\"resolvedHeight\"\n [style.max-width]=\"'90vw'\"\n [style.max-height]=\"'90vh'\"\n (click)=\"$event.stopPropagation()\">\n\n <!-- Title bar -->\n @if (Title || Closeable) {\n <div class=\"mj-dialog-titlebar\">\n @if (Title) {\n <h2 class=\"mj-dialog-title\" [id]=\"'mj-dialog-title-' + dialogId\">{{ Title }}</h2>\n }\n <ng-content select=\"mj-dialog-titlebar\"></ng-content>\n @if (Closeable) {\n <button class=\"mj-dialog-close\" (click)=\"OnCloseClick()\" aria-label=\"Close dialog\">\n <i class=\"fa-solid fa-times\"></i>\n </button>\n }\n </div>\n }\n\n <!-- Body -->\n <div class=\"mj-dialog-body\">\n <ng-content></ng-content>\n </div>\n\n <!-- Actions (projected) -->\n <ng-content select=\"mj-dialog-actions\"></ng-content>\n </div>\n </div>\n }\n `\n})\nexport class MJDialogComponent implements OnDestroy {\n private _visible = false;\n private static nextId = 0;\n\n @Input()\n set Visible(value: boolean) {\n const wasVisible = this._visible;\n this._visible = value;\n if (value && !wasVisible) {\n this.onOpen();\n }\n if (!value && wasVisible) {\n this.onCloseInternal();\n }\n }\n get Visible(): boolean {\n return this._visible;\n }\n\n @Input() Title = '';\n @Input() Width: number | string | null = null;\n @Input() Height: number | string | null = null;\n @Input() Size: MjDialogSize = 'auto';\n @Input() Closeable = true;\n @Input() MinWidth: number | null = null;\n\n @Output() Close = new EventEmitter<void>();\n\n DialogId = MJDialogComponent.nextId++;\n\n get dialogId(): number {\n return this.DialogId;\n }\n\n get resolvedWidth(): string {\n if (this.Width) {\n return typeof this.Width === 'number' ? `${this.Width}px` : this.Width;\n }\n return SIZE_MAP[this.Size] ?? 'auto';\n }\n\n get resolvedHeight(): string {\n if (this.Height) {\n return typeof this.Height === 'number' ? `${this.Height}px` : this.Height;\n }\n return 'auto';\n }\n\n @HostListener('document:keydown.escape')\n OnEscapeKey(): void {\n if (this.Visible && this.Closeable) {\n this.OnCloseClick();\n }\n }\n\n OnBackdropClick(event: Event): void {\n if (this.Closeable) {\n this.OnCloseClick();\n }\n }\n\n OnCloseClick(): void {\n this.Close.emit();\n }\n\n private onOpen(): void {\n document.body.style.overflow = 'hidden';\n }\n\n private onCloseInternal(): void {\n document.body.style.overflow = '';\n }\n\n ngOnDestroy(): void {\n document.body.style.overflow = '';\n }\n}\n\n/**\n * mj-dialog-titlebar — Custom titlebar content for mj-dialog.\n *\n * Replaces `<kendo-dialog-titlebar>`.\n *\n * @example\n * ```html\n * <mj-dialog [Visible]=\"show\" (Close)=\"onClose()\">\n * <mj-dialog-titlebar>\n * <i class=\"fa-solid fa-save\"></i> Custom Title\n * </mj-dialog-titlebar>\n * <p>Dialog content</p>\n * </mj-dialog>\n * ```\n */\n@Component({\n selector: 'mj-dialog-titlebar',\n standalone: true,\n template: `<ng-content></ng-content>`\n})\nexport class MJDialogTitlebarComponent {}\n\n/**\n * mj-dialog-actions — Footer action bar for mj-dialog.\n *\n * Replaces `<kendo-dialog-actions>`.\n *\n * @example\n * ```html\n * <mj-dialog-actions>\n * <button mjButton variant=\"primary\">Save</button>\n * <button mjButton>Cancel</button>\n * </mj-dialog-actions>\n * ```\n */\n@Component({\n selector: 'mj-dialog-actions',\n standalone: true,\n template: `\n <div class=\"mj-dialog-actions\">\n <ng-content></ng-content>\n </div>\n `\n})\nexport class MJDialogActionsComponent {}\n"]}
1
+ {"version":3,"file":"dialog.component.js","sourceRoot":"","sources":["../../../src/lib/dialog/dialog.component.ts"],"names":[],"mappings":"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","sourcesContent":["import {\n Component,\n Input,\n Output,\n EventEmitter,\n HostListener,\n ElementRef,\n ViewChild,\n AfterViewInit,\n OnDestroy,\n inject\n} from '@angular/core';\n\nexport type MjDialogSize = 'sm' | 'md' | 'lg' | 'xl' | 'auto';\n\nconst SIZE_MAP: Record<MjDialogSize, string> = {\n sm: '400px',\n md: '600px',\n lg: '800px',\n xl: '1000px',\n auto: 'auto'\n};\n\n/**\n * mj-dialog — Modal dialog component using native `<dialog>` element.\n *\n * Replaces `<kendo-dialog>`.\n *\n * Supports both explicit width/height and size presets.\n * Content is projected, with an optional `<mj-dialog-actions>` for the footer.\n *\n * @example\n * ```html\n * <mj-dialog [Visible]=\"showDialog\" Title=\"Confirm\" (Close)=\"onClose()\">\n * <p>Are you sure?</p>\n * <mj-dialog-actions>\n * <button mjButton variant=\"primary\" (click)=\"onConfirm()\">Yes</button>\n * <button mjButton (click)=\"onClose()\">No</button>\n * </mj-dialog-actions>\n * </mj-dialog>\n * ```\n */\n@Component({\n selector: 'mj-dialog',\n standalone: true,\n template: `\n @if (Visible) {\n <div class=\"mj-dialog-backdrop\" (click)=\"OnBackdropClick($event)\">\n <div class=\"mj-dialog-container\"\n [attr.role]=\"Role\"\n aria-modal=\"true\"\n [attr.aria-labelledby]=\"Title ? 'mj-dialog-title-' + dialogId : null\"\n [style.width]=\"resolvedWidth\"\n [style.height]=\"resolvedHeight\"\n [style.max-width]=\"'90vw'\"\n [style.max-height]=\"'90vh'\"\n (click)=\"$event.stopPropagation()\">\n\n <!-- Title bar -->\n @if (Title || Closeable) {\n <div class=\"mj-dialog-titlebar\">\n @if (Title) {\n <h2 class=\"mj-dialog-title\" [id]=\"'mj-dialog-title-' + dialogId\">{{ Title }}</h2>\n }\n <ng-content select=\"mj-dialog-titlebar\"></ng-content>\n @if (Closeable) {\n <button class=\"mj-dialog-close\" (click)=\"OnCloseClick()\" aria-label=\"Close dialog\">\n <i class=\"fa-solid fa-times\"></i>\n </button>\n }\n </div>\n }\n\n <!-- Body -->\n <div class=\"mj-dialog-body\">\n <ng-content></ng-content>\n </div>\n\n <!-- Actions (projected) -->\n <ng-content select=\"mj-dialog-actions\"></ng-content>\n </div>\n </div>\n }\n `\n})\nexport class MJDialogComponent implements OnDestroy {\n private _visible = false;\n private static nextId = 0;\n\n @Input()\n set Visible(value: boolean) {\n const wasVisible = this._visible;\n this._visible = value;\n if (value && !wasVisible) {\n this.onOpen();\n }\n if (!value && wasVisible) {\n this.onCloseInternal();\n }\n }\n get Visible(): boolean {\n return this._visible;\n }\n\n @Input() Title = '';\n @Input() Width: number | string | null = null;\n @Input() Height: number | string | null = null;\n @Input() Size: MjDialogSize = 'auto';\n @Input() Closeable = true;\n @Input() MinWidth: number | null = null;\n\n /**\n * ARIA role for the dialog container. Defaults to `'dialog'`; pass\n * `'alertdialog'` for confirmation / destructive prompts that interrupt the\n * user (per WAI-ARIA, an alertdialog conveys an urgent message requiring a\n * response). Backward compatible — existing callers keep `'dialog'`.\n */\n @Input() Role: 'dialog' | 'alertdialog' = 'dialog';\n\n @Output() Close = new EventEmitter<void>();\n\n DialogId = MJDialogComponent.nextId++;\n\n get dialogId(): number {\n return this.DialogId;\n }\n\n get resolvedWidth(): string {\n if (this.Width) {\n return typeof this.Width === 'number' ? `${this.Width}px` : this.Width;\n }\n return SIZE_MAP[this.Size] ?? 'auto';\n }\n\n get resolvedHeight(): string {\n if (this.Height) {\n return typeof this.Height === 'number' ? `${this.Height}px` : this.Height;\n }\n return 'auto';\n }\n\n @HostListener('document:keydown.escape')\n OnEscapeKey(): void {\n if (this.Visible && this.Closeable) {\n this.OnCloseClick();\n }\n }\n\n OnBackdropClick(event: Event): void {\n if (this.Closeable) {\n this.OnCloseClick();\n }\n }\n\n OnCloseClick(): void {\n this.Close.emit();\n }\n\n private onOpen(): void {\n document.body.style.overflow = 'hidden';\n }\n\n private onCloseInternal(): void {\n document.body.style.overflow = '';\n }\n\n ngOnDestroy(): void {\n document.body.style.overflow = '';\n }\n}\n\n/**\n * mj-dialog-titlebar — Custom titlebar content for mj-dialog.\n *\n * Replaces `<kendo-dialog-titlebar>`.\n *\n * @example\n * ```html\n * <mj-dialog [Visible]=\"show\" (Close)=\"onClose()\">\n * <mj-dialog-titlebar>\n * <i class=\"fa-solid fa-save\"></i> Custom Title\n * </mj-dialog-titlebar>\n * <p>Dialog content</p>\n * </mj-dialog>\n * ```\n */\n@Component({\n selector: 'mj-dialog-titlebar',\n standalone: true,\n template: `<ng-content></ng-content>`\n})\nexport class MJDialogTitlebarComponent {}\n\n/**\n * mj-dialog-actions — Footer action bar for mj-dialog.\n *\n * Replaces `<kendo-dialog-actions>`.\n *\n * @example\n * ```html\n * <mj-dialog-actions>\n * <button mjButton variant=\"primary\">Save</button>\n * <button mjButton>Cancel</button>\n * </mj-dialog-actions>\n * ```\n */\n@Component({\n selector: 'mj-dialog-actions',\n standalone: true,\n template: `\n <div class=\"mj-dialog-actions\">\n <ng-content></ng-content>\n </div>\n `\n})\nexport class MJDialogActionsComponent {}\n"]}
@@ -0,0 +1,114 @@
1
+ import { EventEmitter } from '@angular/core';
2
+ import * as i0 from "@angular/core";
3
+ /**
4
+ * Visual intent of an `<mj-empty-state>`. Drives the default icon and the icon's
5
+ * color treatment so callers don't restate either for the common cases.
6
+ *
7
+ * - `empty` — nothing exists yet (default). Neutral/disabled icon tone.
8
+ * - `no-results` — a search/filter matched nothing. Muted icon tone, magnifier default.
9
+ * - `success` — a positive "all clear" empty (e.g. "No Errors Found"). Success icon tone, check default.
10
+ * - `warning` — a non-error blocking condition (disabled/misconfigured feature). Warning icon tone.
11
+ * - `error` — a load/operation failed. Error icon tone, triangle default.
12
+ */
13
+ export type MJEmptyStateVariant = 'empty' | 'no-results' | 'success' | 'warning' | 'error';
14
+ /** Density of an `<mj-empty-state>` — controls padding and icon size. */
15
+ export type MJEmptyStateSize = 'compact' | 'default' | 'large';
16
+ /**
17
+ * mj-empty-state — Canonical centered empty/no-results/error placeholder.
18
+ *
19
+ * Replaces the ~213 inline empty-state `<div>`s that pages were each hand-rolling
20
+ * (icon + title + message, optionally a CTA), e.g.:
21
+ * ```html
22
+ * <div class="empty-state">
23
+ * <i class="fa-solid fa-inbox"></i>
24
+ * <h3>No Permissions Found</h3>
25
+ * <p>Try adjusting your filters or refresh the data.</p>
26
+ * <button mjButton variant="primary" (click)="refreshData()">Refresh</button>
27
+ * </div>
28
+ * ```
29
+ *
30
+ * Usage:
31
+ * ```html
32
+ * <!-- Simplest: nothing-here placeholder -->
33
+ * <mj-empty-state Title="No runs found" Message="No runs match the selected filters." />
34
+ *
35
+ * <!-- Search/filter produced nothing -->
36
+ * <mj-empty-state Variant="no-results" Title="No icons found" Message="Try a different search term." />
37
+ *
38
+ * <!-- Load failed, retry CTA -->
39
+ * <mj-empty-state Variant="error" Title="Couldn't load permissions" [Message]="error"
40
+ * ActionText="Try Again" ActionIcon="fa-solid fa-rotate-right" (Action)="loadData()" />
41
+ *
42
+ * <!-- Invitation to create the first record -->
43
+ * <mj-empty-state Icon="fa-solid fa-key" Title="No API keys yet"
44
+ * Message="Generate a key to start calling the API."
45
+ * ActionText="Generate Your First Key" ActionIcon="fa-solid fa-plus"
46
+ * (Action)="requestCreate()" />
47
+ *
48
+ * <!-- Multiple / bespoke CTAs: project them into the [actions] slot -->
49
+ * <mj-empty-state Title="No pinned items yet" Message="Pin dashboards for quick access.">
50
+ * <button mjButton variant="primary" (click)="addPin()">Add your first pin</button>
51
+ * <button mjButton variant="flat" (click)="dismiss()">Don't show again</button>
52
+ * </mj-empty-state>
53
+ * ```
54
+ *
55
+ * For dynamic messages (e.g. "No keys matching X" vs "No keys yet"), compute the
56
+ * string in the parent and bind it to `[Message]`, or project richer body content
57
+ * as default `<ng-content>` (rendered between the message and the actions).
58
+ */
59
+ export declare class MJEmptyStateComponent {
60
+ /**
61
+ * Font Awesome icon class string (e.g. "fa-solid fa-key"). When omitted, a
62
+ * sensible default is chosen from `Variant`. Pass an empty string AND no
63
+ * variant default applies — set this explicitly to "" to render no icon.
64
+ */
65
+ Icon: string | null;
66
+ /** Bold heading line (e.g. "No API keys yet"). */
67
+ Title: string;
68
+ /** Supporting/help text below the title. */
69
+ Message: string;
70
+ /** When set, renders a primary CTA button with this label. */
71
+ ActionText: string;
72
+ /** Optional Font Awesome icon shown inside the CTA button. */
73
+ ActionIcon: string;
74
+ /** mjButton variant for the built-in CTA. Defaults to 'primary'. */
75
+ ActionVariant: 'primary' | 'secondary' | 'outline' | 'flat';
76
+ /** Visual intent — drives the default icon and icon color. Defaults to 'empty'. */
77
+ Variant: MJEmptyStateVariant;
78
+ /** Density — controls padding and icon size. Defaults to 'default'. */
79
+ Size: MJEmptyStateSize;
80
+ /**
81
+ * ARIA live-region role on the host. When unset, it defaults from `Variant`:
82
+ * `error` → `'alert'` (assertive), everything else → `'status'` (polite). This
83
+ * makes a dynamically-appearing empty state announce itself to screen readers —
84
+ * the title + message are read together via the role's implicit
85
+ * `aria-live`/`aria-atomic`. (Empty states present at page load are not
86
+ * announced, per the live-region spec, so static placeholders stay quiet.)
87
+ * Pass an explicit role to override, or `''` to opt out of the live region.
88
+ */
89
+ Role: string | null;
90
+ /** Emitted when the built-in CTA button is clicked. */
91
+ Action: EventEmitter<MouseEvent>;
92
+ get IsCompact(): boolean;
93
+ get IsLarge(): boolean;
94
+ get IsNoResults(): boolean;
95
+ get IsSuccess(): boolean;
96
+ get IsWarning(): boolean;
97
+ get IsError(): boolean;
98
+ /**
99
+ * Live-region role applied to the host. Explicit `Role` wins (`''` ⇒ no role);
100
+ * otherwise an error state is an assertive `alert`, everything else a polite `status`.
101
+ */
102
+ get HostRole(): string | null;
103
+ /**
104
+ * Icon actually rendered: the explicit `Icon` when provided (including ""
105
+ * to suppress the icon), otherwise the per-variant default.
106
+ */
107
+ get ResolvedIcon(): string;
108
+ /** Default Font Awesome icon for each variant. */
109
+ static DefaultIconForVariant(variant: MJEmptyStateVariant): string;
110
+ OnAction(event: MouseEvent): void;
111
+ static ɵfac: i0.ɵɵFactoryDeclaration<MJEmptyStateComponent, never>;
112
+ static ɵcmp: i0.ɵɵComponentDeclaration<MJEmptyStateComponent, "mj-empty-state", never, { "Icon": { "alias": "Icon"; "required": false; }; "Title": { "alias": "Title"; "required": false; }; "Message": { "alias": "Message"; "required": false; }; "ActionText": { "alias": "ActionText"; "required": false; }; "ActionIcon": { "alias": "ActionIcon"; "required": false; }; "ActionVariant": { "alias": "ActionVariant"; "required": false; }; "Variant": { "alias": "Variant"; "required": false; }; "Size": { "alias": "Size"; "required": false; }; "Role": { "alias": "Role"; "required": false; }; }, { "Action": "Action"; }, never, ["*", "[actions]"], true, never>;
113
+ }
114
+ //# sourceMappingURL=empty-state.component.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"empty-state.component.d.ts","sourceRoot":"","sources":["../../../src/lib/empty-state/empty-state.component.ts"],"names":[],"mappings":"AAAA,OAAO,EAAa,YAAY,EAA8B,MAAM,eAAe,CAAC;;AAGpF;;;;;;;;;GASG;AACH,MAAM,MAAM,mBAAmB,GAAG,OAAO,GAAG,YAAY,GAAG,SAAS,GAAG,SAAS,GAAG,OAAO,CAAC;AAE3F,yEAAyE;AACzE,MAAM,MAAM,gBAAgB,GAAG,SAAS,GAAG,SAAS,GAAG,OAAO,CAAC;AAE/D;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA0CG;AACH,qBA6Ga,qBAAqB;IAChC;;;;OAIG;IACM,IAAI,EAAE,MAAM,GAAG,IAAI,CAAQ;IAEpC,kDAAkD;IACzC,KAAK,EAAE,MAAM,CAAM;IAE5B,4CAA4C;IACnC,OAAO,EAAE,MAAM,CAAM;IAE9B,8DAA8D;IACrD,UAAU,EAAE,MAAM,CAAM;IAEjC,8DAA8D;IACrD,UAAU,EAAE,MAAM,CAAM;IAEjC,oEAAoE;IAC3D,aAAa,EAAE,SAAS,GAAG,WAAW,GAAG,SAAS,GAAG,MAAM,CAAa;IAEjF,mFAAmF;IAC1E,OAAO,EAAE,mBAAmB,CAAW;IAEhD,uEAAuE;IAC9D,IAAI,EAAE,gBAAgB,CAAa;IAE5C;;;;;;;;OAQG;IACM,IAAI,EAAE,MAAM,GAAG,IAAI,CAAQ;IAEpC,uDAAuD;IAC7C,MAAM,2BAAkC;IAElD,IACI,SAAS,IAAI,OAAO,CAAoC;IAE5D,IACI,OAAO,IAAI,OAAO,CAAkC;IAExD,IACI,WAAW,IAAI,OAAO,CAA0C;IAEpE,IACI,SAAS,IAAI,OAAO,CAAuC;IAE/D,IACI,SAAS,IAAI,OAAO,CAAuC;IAE/D,IACI,OAAO,IAAI,OAAO,CAAqC;IAE3D;;;OAGG;IACH,IACI,QAAQ,IAAI,MAAM,GAAG,IAAI,CAK5B;IAED;;;OAGG;IACH,IAAI,YAAY,IAAI,MAAM,CAKzB;IAED,kDAAkD;IAClD,MAAM,CAAC,qBAAqB,CAAC,OAAO,EAAE,mBAAmB,GAAG,MAAM;IAelE,QAAQ,CAAC,KAAK,EAAE,UAAU,GAAG,IAAI;yCApGtB,qBAAqB;2CAArB,qBAAqB;CAuGjC"}
@@ -0,0 +1,268 @@
1
+ import { Component, EventEmitter, HostBinding, Input, Output } from '@angular/core';
2
+ import { MJButtonDirective } from '../button/button.directive';
3
+ import * as i0 from "@angular/core";
4
+ const _c0 = ["*", [["", "actions", ""]]];
5
+ const _c1 = ["*", "[actions]"];
6
+ function MJEmptyStateComponent_Conditional_0_Template(rf, ctx) { if (rf & 1) {
7
+ i0.ɵɵelement(0, "i", 5);
8
+ } if (rf & 2) {
9
+ const ctx_r0 = i0.ɵɵnextContext();
10
+ i0.ɵɵclassMap(i0.ɵɵinterpolate1("mj-empty-state__icon ", ctx_r0.ResolvedIcon));
11
+ } }
12
+ function MJEmptyStateComponent_Conditional_1_Template(rf, ctx) { if (rf & 1) {
13
+ i0.ɵɵelementStart(0, "h3", 1);
14
+ i0.ɵɵtext(1);
15
+ i0.ɵɵelementEnd();
16
+ } if (rf & 2) {
17
+ const ctx_r0 = i0.ɵɵnextContext();
18
+ i0.ɵɵadvance();
19
+ i0.ɵɵtextInterpolate(ctx_r0.Title);
20
+ } }
21
+ function MJEmptyStateComponent_Conditional_2_Template(rf, ctx) { if (rf & 1) {
22
+ i0.ɵɵelementStart(0, "p", 2);
23
+ i0.ɵɵtext(1);
24
+ i0.ɵɵelementEnd();
25
+ } if (rf & 2) {
26
+ const ctx_r0 = i0.ɵɵnextContext();
27
+ i0.ɵɵadvance();
28
+ i0.ɵɵtextInterpolate(ctx_r0.Message);
29
+ } }
30
+ function MJEmptyStateComponent_Conditional_5_Conditional_1_Template(rf, ctx) { if (rf & 1) {
31
+ i0.ɵɵelement(0, "i", 5);
32
+ } if (rf & 2) {
33
+ const ctx_r0 = i0.ɵɵnextContext(2);
34
+ i0.ɵɵclassMap(ctx_r0.ActionIcon);
35
+ } }
36
+ function MJEmptyStateComponent_Conditional_5_Template(rf, ctx) { if (rf & 1) {
37
+ const _r2 = i0.ɵɵgetCurrentView();
38
+ i0.ɵɵelementStart(0, "button", 6);
39
+ i0.ɵɵlistener("click", function MJEmptyStateComponent_Conditional_5_Template_button_click_0_listener($event) { i0.ɵɵrestoreView(_r2); const ctx_r0 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r0.OnAction($event)); });
40
+ i0.ɵɵconditionalCreate(1, MJEmptyStateComponent_Conditional_5_Conditional_1_Template, 1, 2, "i", 0);
41
+ i0.ɵɵtext(2);
42
+ i0.ɵɵelementEnd();
43
+ } if (rf & 2) {
44
+ const ctx_r0 = i0.ɵɵnextContext();
45
+ i0.ɵɵproperty("variant", ctx_r0.ActionVariant);
46
+ i0.ɵɵadvance();
47
+ i0.ɵɵconditional(ctx_r0.ActionIcon ? 1 : -1);
48
+ i0.ɵɵadvance();
49
+ i0.ɵɵtextInterpolate1(" ", ctx_r0.ActionText, " ");
50
+ } }
51
+ /**
52
+ * mj-empty-state — Canonical centered empty/no-results/error placeholder.
53
+ *
54
+ * Replaces the ~213 inline empty-state `<div>`s that pages were each hand-rolling
55
+ * (icon + title + message, optionally a CTA), e.g.:
56
+ * ```html
57
+ * <div class="empty-state">
58
+ * <i class="fa-solid fa-inbox"></i>
59
+ * <h3>No Permissions Found</h3>
60
+ * <p>Try adjusting your filters or refresh the data.</p>
61
+ * <button mjButton variant="primary" (click)="refreshData()">Refresh</button>
62
+ * </div>
63
+ * ```
64
+ *
65
+ * Usage:
66
+ * ```html
67
+ * <!-- Simplest: nothing-here placeholder -->
68
+ * <mj-empty-state Title="No runs found" Message="No runs match the selected filters." />
69
+ *
70
+ * <!-- Search/filter produced nothing -->
71
+ * <mj-empty-state Variant="no-results" Title="No icons found" Message="Try a different search term." />
72
+ *
73
+ * <!-- Load failed, retry CTA -->
74
+ * <mj-empty-state Variant="error" Title="Couldn't load permissions" [Message]="error"
75
+ * ActionText="Try Again" ActionIcon="fa-solid fa-rotate-right" (Action)="loadData()" />
76
+ *
77
+ * <!-- Invitation to create the first record -->
78
+ * <mj-empty-state Icon="fa-solid fa-key" Title="No API keys yet"
79
+ * Message="Generate a key to start calling the API."
80
+ * ActionText="Generate Your First Key" ActionIcon="fa-solid fa-plus"
81
+ * (Action)="requestCreate()" />
82
+ *
83
+ * <!-- Multiple / bespoke CTAs: project them into the [actions] slot -->
84
+ * <mj-empty-state Title="No pinned items yet" Message="Pin dashboards for quick access.">
85
+ * <button mjButton variant="primary" (click)="addPin()">Add your first pin</button>
86
+ * <button mjButton variant="flat" (click)="dismiss()">Don't show again</button>
87
+ * </mj-empty-state>
88
+ * ```
89
+ *
90
+ * For dynamic messages (e.g. "No keys matching X" vs "No keys yet"), compute the
91
+ * string in the parent and bind it to `[Message]`, or project richer body content
92
+ * as default `<ng-content>` (rendered between the message and the actions).
93
+ */
94
+ export class MJEmptyStateComponent {
95
+ /**
96
+ * Font Awesome icon class string (e.g. "fa-solid fa-key"). When omitted, a
97
+ * sensible default is chosen from `Variant`. Pass an empty string AND no
98
+ * variant default applies — set this explicitly to "" to render no icon.
99
+ */
100
+ Icon = null;
101
+ /** Bold heading line (e.g. "No API keys yet"). */
102
+ Title = '';
103
+ /** Supporting/help text below the title. */
104
+ Message = '';
105
+ /** When set, renders a primary CTA button with this label. */
106
+ ActionText = '';
107
+ /** Optional Font Awesome icon shown inside the CTA button. */
108
+ ActionIcon = '';
109
+ /** mjButton variant for the built-in CTA. Defaults to 'primary'. */
110
+ ActionVariant = 'primary';
111
+ /** Visual intent — drives the default icon and icon color. Defaults to 'empty'. */
112
+ Variant = 'empty';
113
+ /** Density — controls padding and icon size. Defaults to 'default'. */
114
+ Size = 'default';
115
+ /**
116
+ * ARIA live-region role on the host. When unset, it defaults from `Variant`:
117
+ * `error` → `'alert'` (assertive), everything else → `'status'` (polite). This
118
+ * makes a dynamically-appearing empty state announce itself to screen readers —
119
+ * the title + message are read together via the role's implicit
120
+ * `aria-live`/`aria-atomic`. (Empty states present at page load are not
121
+ * announced, per the live-region spec, so static placeholders stay quiet.)
122
+ * Pass an explicit role to override, or `''` to opt out of the live region.
123
+ */
124
+ Role = null;
125
+ /** Emitted when the built-in CTA button is clicked. */
126
+ Action = new EventEmitter();
127
+ get IsCompact() { return this.Size === 'compact'; }
128
+ get IsLarge() { return this.Size === 'large'; }
129
+ get IsNoResults() { return this.Variant === 'no-results'; }
130
+ get IsSuccess() { return this.Variant === 'success'; }
131
+ get IsWarning() { return this.Variant === 'warning'; }
132
+ get IsError() { return this.Variant === 'error'; }
133
+ /**
134
+ * Live-region role applied to the host. Explicit `Role` wins (`''` ⇒ no role);
135
+ * otherwise an error state is an assertive `alert`, everything else a polite `status`.
136
+ */
137
+ get HostRole() {
138
+ if (this.Role != null) {
139
+ return this.Role || null;
140
+ }
141
+ return this.Variant === 'error' ? 'alert' : 'status';
142
+ }
143
+ /**
144
+ * Icon actually rendered: the explicit `Icon` when provided (including ""
145
+ * to suppress the icon), otherwise the per-variant default.
146
+ */
147
+ get ResolvedIcon() {
148
+ if (this.Icon != null) {
149
+ return this.Icon;
150
+ }
151
+ return MJEmptyStateComponent.DefaultIconForVariant(this.Variant);
152
+ }
153
+ /** Default Font Awesome icon for each variant. */
154
+ static DefaultIconForVariant(variant) {
155
+ switch (variant) {
156
+ case 'no-results':
157
+ return 'fa-solid fa-magnifying-glass';
158
+ case 'success':
159
+ return 'fa-solid fa-circle-check';
160
+ case 'warning':
161
+ case 'error':
162
+ return 'fa-solid fa-triangle-exclamation';
163
+ case 'empty':
164
+ default:
165
+ return 'fa-solid fa-inbox';
166
+ }
167
+ }
168
+ OnAction(event) {
169
+ this.Action.emit(event);
170
+ }
171
+ static ɵfac = function MJEmptyStateComponent_Factory(__ngFactoryType__) { return new (__ngFactoryType__ || MJEmptyStateComponent)(); };
172
+ static ɵcmp = /*@__PURE__*/ i0.ɵɵdefineComponent({ type: MJEmptyStateComponent, selectors: [["mj-empty-state"]], hostVars: 13, hostBindings: function MJEmptyStateComponent_HostBindings(rf, ctx) { if (rf & 2) {
173
+ i0.ɵɵattribute("role", ctx.HostRole);
174
+ i0.ɵɵclassProp("mj-empty-state--compact", ctx.IsCompact)("mj-empty-state--large", ctx.IsLarge)("mj-empty-state--no-results", ctx.IsNoResults)("mj-empty-state--success", ctx.IsSuccess)("mj-empty-state--warning", ctx.IsWarning)("mj-empty-state--error", ctx.IsError);
175
+ } }, inputs: { Icon: "Icon", Title: "Title", Message: "Message", ActionText: "ActionText", ActionIcon: "ActionIcon", ActionVariant: "ActionVariant", Variant: "Variant", Size: "Size", Role: "Role" }, outputs: { Action: "Action" }, ngContentSelectors: _c1, decls: 7, vars: 4, consts: [["aria-hidden", "true", 3, "class"], [1, "mj-empty-state__title"], [1, "mj-empty-state__message"], [1, "mj-empty-state__actions"], ["type", "button", "mjButton", "", 3, "variant"], ["aria-hidden", "true"], ["type", "button", "mjButton", "", 3, "click", "variant"]], template: function MJEmptyStateComponent_Template(rf, ctx) { if (rf & 1) {
176
+ i0.ɵɵprojectionDef(_c0);
177
+ i0.ɵɵconditionalCreate(0, MJEmptyStateComponent_Conditional_0_Template, 1, 3, "i", 0);
178
+ i0.ɵɵconditionalCreate(1, MJEmptyStateComponent_Conditional_1_Template, 2, 1, "h3", 1);
179
+ i0.ɵɵconditionalCreate(2, MJEmptyStateComponent_Conditional_2_Template, 2, 1, "p", 2);
180
+ i0.ɵɵprojection(3);
181
+ i0.ɵɵelementStart(4, "div", 3);
182
+ i0.ɵɵconditionalCreate(5, MJEmptyStateComponent_Conditional_5_Template, 3, 3, "button", 4);
183
+ i0.ɵɵprojection(6, 1);
184
+ i0.ɵɵelementEnd();
185
+ } if (rf & 2) {
186
+ i0.ɵɵconditional(ctx.ResolvedIcon ? 0 : -1);
187
+ i0.ɵɵadvance();
188
+ i0.ɵɵconditional(ctx.Title ? 1 : -1);
189
+ i0.ɵɵadvance();
190
+ i0.ɵɵconditional(ctx.Message ? 2 : -1);
191
+ i0.ɵɵadvance(3);
192
+ i0.ɵɵconditional(ctx.ActionText ? 5 : -1);
193
+ } }, dependencies: [MJButtonDirective], styles: ["[_nghost-%COMP%] {\n display: flex;\n flex-direction: column;\n align-items: center;\n justify-content: center;\n text-align: center;\n padding: var(--mj-space-12);\n color: var(--mj-text-secondary);\n }\n\n .mj-empty-state__icon[_ngcontent-%COMP%] {\n font-size: 3rem;\n line-height: 1;\n margin-bottom: var(--mj-space-4);\n color: var(--mj-text-disabled);\n }\n\n .mj-empty-state__title[_ngcontent-%COMP%] {\n margin: 0;\n font-size: var(--mj-text-lg);\n font-weight: 600;\n color: var(--mj-text-primary);\n }\n\n .mj-empty-state__message[_ngcontent-%COMP%] {\n margin: var(--mj-space-2) 0 0;\n font-size: var(--mj-text-sm);\n color: var(--mj-text-muted);\n max-width: 420px;\n }\n\n .mj-empty-state__actions[_ngcontent-%COMP%] {\n display: flex;\n flex-wrap: wrap;\n align-items: center;\n justify-content: center;\n gap: var(--mj-space-2);\n margin-top: var(--mj-space-6);\n }\n \n\n\n .mj-empty-state__actions[_ngcontent-%COMP%]:empty {\n display: none;\n }\n\n \n\n .mj-empty-state--compact[_nghost-%COMP%] {\n padding: var(--mj-space-8);\n }\n .mj-empty-state--compact[_nghost-%COMP%] .mj-empty-state__icon[_ngcontent-%COMP%] {\n font-size: 2rem;\n margin-bottom: var(--mj-space-3);\n }\n\n .mj-empty-state--large[_nghost-%COMP%] {\n padding: var(--mj-space-16) var(--mj-space-10);\n }\n .mj-empty-state--large[_nghost-%COMP%] .mj-empty-state__icon[_ngcontent-%COMP%] {\n font-size: 4rem;\n }\n\n \n\n .mj-empty-state--no-results[_nghost-%COMP%] .mj-empty-state__icon[_ngcontent-%COMP%] {\n color: var(--mj-text-muted);\n }\n .mj-empty-state--success[_nghost-%COMP%] .mj-empty-state__icon[_ngcontent-%COMP%] {\n color: var(--mj-status-success);\n }\n .mj-empty-state--warning[_nghost-%COMP%] .mj-empty-state__icon[_ngcontent-%COMP%] {\n color: var(--mj-status-warning);\n }\n .mj-empty-state--error[_nghost-%COMP%] .mj-empty-state__icon[_ngcontent-%COMP%] {\n color: var(--mj-status-error);\n }"] });
194
+ }
195
+ (() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassMetadata(MJEmptyStateComponent, [{
196
+ type: Component,
197
+ args: [{ selector: 'mj-empty-state', standalone: true, imports: [MJButtonDirective], template: `
198
+ @if (ResolvedIcon) {
199
+ <i class="mj-empty-state__icon {{ ResolvedIcon }}" aria-hidden="true"></i>
200
+ }
201
+ @if (Title) {
202
+ <h3 class="mj-empty-state__title">{{ Title }}</h3>
203
+ }
204
+ @if (Message) {
205
+ <p class="mj-empty-state__message">{{ Message }}</p>
206
+ }
207
+
208
+ <!-- Optional richer body content (feature lists, dynamic text, links) -->
209
+ <ng-content></ng-content>
210
+
211
+ <!-- Actions: the built-in single CTA and/or projected [actions] buttons.
212
+ Hidden via :empty when neither is present. -->
213
+ <div class="mj-empty-state__actions">
214
+ @if (ActionText) {
215
+ <button type="button" mjButton [variant]="ActionVariant" (click)="OnAction($event)">
216
+ @if (ActionIcon) {
217
+ <i class="{{ ActionIcon }}" aria-hidden="true"></i>
218
+ }
219
+ {{ ActionText }}
220
+ </button>
221
+ }
222
+ <ng-content select="[actions]"></ng-content>
223
+ </div>
224
+ `, styles: ["\n :host {\n display: flex;\n flex-direction: column;\n align-items: center;\n justify-content: center;\n text-align: center;\n padding: var(--mj-space-12);\n color: var(--mj-text-secondary);\n }\n\n .mj-empty-state__icon {\n font-size: 3rem;\n line-height: 1;\n margin-bottom: var(--mj-space-4);\n color: var(--mj-text-disabled);\n }\n\n .mj-empty-state__title {\n margin: 0;\n font-size: var(--mj-text-lg);\n font-weight: 600;\n color: var(--mj-text-primary);\n }\n\n .mj-empty-state__message {\n margin: var(--mj-space-2) 0 0;\n font-size: var(--mj-text-sm);\n color: var(--mj-text-muted);\n max-width: 420px;\n }\n\n .mj-empty-state__actions {\n display: flex;\n flex-wrap: wrap;\n align-items: center;\n justify-content: center;\n gap: var(--mj-space-2);\n margin-top: var(--mj-space-6);\n }\n /* Collapse the actions row entirely when no CTA is rendered (modern browsers\n treat an element containing only Angular's @if comment-anchors as :empty). */\n .mj-empty-state__actions:empty {\n display: none;\n }\n\n /* \u2500\u2500 Sizes \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */\n :host(.mj-empty-state--compact) {\n padding: var(--mj-space-8);\n }\n :host(.mj-empty-state--compact) .mj-empty-state__icon {\n font-size: 2rem;\n margin-bottom: var(--mj-space-3);\n }\n\n :host(.mj-empty-state--large) {\n padding: var(--mj-space-16) var(--mj-space-10);\n }\n :host(.mj-empty-state--large) .mj-empty-state__icon {\n font-size: 4rem;\n }\n\n /* \u2500\u2500 Variants (icon tone) \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */\n :host(.mj-empty-state--no-results) .mj-empty-state__icon {\n color: var(--mj-text-muted);\n }\n :host(.mj-empty-state--success) .mj-empty-state__icon {\n color: var(--mj-status-success);\n }\n :host(.mj-empty-state--warning) .mj-empty-state__icon {\n color: var(--mj-status-warning);\n }\n :host(.mj-empty-state--error) .mj-empty-state__icon {\n color: var(--mj-status-error);\n }\n "] }]
225
+ }], null, { Icon: [{
226
+ type: Input
227
+ }], Title: [{
228
+ type: Input
229
+ }], Message: [{
230
+ type: Input
231
+ }], ActionText: [{
232
+ type: Input
233
+ }], ActionIcon: [{
234
+ type: Input
235
+ }], ActionVariant: [{
236
+ type: Input
237
+ }], Variant: [{
238
+ type: Input
239
+ }], Size: [{
240
+ type: Input
241
+ }], Role: [{
242
+ type: Input
243
+ }], Action: [{
244
+ type: Output
245
+ }], IsCompact: [{
246
+ type: HostBinding,
247
+ args: ['class.mj-empty-state--compact']
248
+ }], IsLarge: [{
249
+ type: HostBinding,
250
+ args: ['class.mj-empty-state--large']
251
+ }], IsNoResults: [{
252
+ type: HostBinding,
253
+ args: ['class.mj-empty-state--no-results']
254
+ }], IsSuccess: [{
255
+ type: HostBinding,
256
+ args: ['class.mj-empty-state--success']
257
+ }], IsWarning: [{
258
+ type: HostBinding,
259
+ args: ['class.mj-empty-state--warning']
260
+ }], IsError: [{
261
+ type: HostBinding,
262
+ args: ['class.mj-empty-state--error']
263
+ }], HostRole: [{
264
+ type: HostBinding,
265
+ args: ['attr.role']
266
+ }] }); })();
267
+ (() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassDebugInfo(MJEmptyStateComponent, { className: "MJEmptyStateComponent", filePath: "lib/empty-state/empty-state.component.ts", lineNumber: 171 }); })();
268
+ //# sourceMappingURL=empty-state.component.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"empty-state.component.js","sourceRoot":"","sources":["../../../src/lib/empty-state/empty-state.component.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,YAAY,EAAE,WAAW,EAAE,KAAK,EAAE,MAAM,EAAE,MAAM,eAAe,CAAC;AACpF,OAAO,EAAE,iBAAiB,EAAE,MAAM,4BAA4B,CAAC;;;;;IAkEzD,uBAA0E;;;IAAvE,cAAA,+DAA+C,CAAA;;;IAGlD,6BAAkC;IAAA,YAAW;IAAA,iBAAK;;;IAAhB,cAAW;IAAX,kCAAW;;;IAG7C,4BAAmC;IAAA,YAAa;IAAA,iBAAI;;;IAAjB,cAAa;IAAb,oCAAa;;;IAY1C,uBAAmD;;;IAAhD,gCAAwB;;;;IAF/B,iCAAoF;IAA3B,+LAAS,uBAAgB,KAAC;IACjF,mGAAkB;IAGlB,YACF;IAAA,iBAAS;;;IALsB,8CAAyB;IACtD,cAEC;IAFD,4CAEC;IACD,cACF;IADE,kDACF;;AAtER;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA0CG;AA8GH,MAAM,OAAO,qBAAqB;IAChC;;;;OAIG;IACM,IAAI,GAAkB,IAAI,CAAC;IAEpC,kDAAkD;IACzC,KAAK,GAAW,EAAE,CAAC;IAE5B,4CAA4C;IACnC,OAAO,GAAW,EAAE,CAAC;IAE9B,8DAA8D;IACrD,UAAU,GAAW,EAAE,CAAC;IAEjC,8DAA8D;IACrD,UAAU,GAAW,EAAE,CAAC;IAEjC,oEAAoE;IAC3D,aAAa,GAAiD,SAAS,CAAC;IAEjF,mFAAmF;IAC1E,OAAO,GAAwB,OAAO,CAAC;IAEhD,uEAAuE;IAC9D,IAAI,GAAqB,SAAS,CAAC;IAE5C;;;;;;;;OAQG;IACM,IAAI,GAAkB,IAAI,CAAC;IAEpC,uDAAuD;IAC7C,MAAM,GAAG,IAAI,YAAY,EAAc,CAAC;IAElD,IACI,SAAS,KAAc,OAAO,IAAI,CAAC,IAAI,KAAK,SAAS,CAAC,CAAC,CAAC;IAE5D,IACI,OAAO,KAAc,OAAO,IAAI,CAAC,IAAI,KAAK,OAAO,CAAC,CAAC,CAAC;IAExD,IACI,WAAW,KAAc,OAAO,IAAI,CAAC,OAAO,KAAK,YAAY,CAAC,CAAC,CAAC;IAEpE,IACI,SAAS,KAAc,OAAO,IAAI,CAAC,OAAO,KAAK,SAAS,CAAC,CAAC,CAAC;IAE/D,IACI,SAAS,KAAc,OAAO,IAAI,CAAC,OAAO,KAAK,SAAS,CAAC,CAAC,CAAC;IAE/D,IACI,OAAO,KAAc,OAAO,IAAI,CAAC,OAAO,KAAK,OAAO,CAAC,CAAC,CAAC;IAE3D;;;OAGG;IACH,IACI,QAAQ;QACV,IAAI,IAAI,CAAC,IAAI,IAAI,IAAI,EAAE,CAAC;YACtB,OAAO,IAAI,CAAC,IAAI,IAAI,IAAI,CAAC;QAC3B,CAAC;QACD,OAAO,IAAI,CAAC,OAAO,KAAK,OAAO,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,QAAQ,CAAC;IACvD,CAAC;IAED;;;OAGG;IACH,IAAI,YAAY;QACd,IAAI,IAAI,CAAC,IAAI,IAAI,IAAI,EAAE,CAAC;YACtB,OAAO,IAAI,CAAC,IAAI,CAAC;QACnB,CAAC;QACD,OAAO,qBAAqB,CAAC,qBAAqB,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;IACnE,CAAC;IAED,kDAAkD;IAClD,MAAM,CAAC,qBAAqB,CAAC,OAA4B;QACvD,QAAQ,OAAO,EAAE,CAAC;YAChB,KAAK,YAAY;gBACf,OAAO,8BAA8B,CAAC;YACxC,KAAK,SAAS;gBACZ,OAAO,0BAA0B,CAAC;YACpC,KAAK,SAAS,CAAC;YACf,KAAK,OAAO;gBACV,OAAO,kCAAkC,CAAC;YAC5C,KAAK,OAAO,CAAC;YACb;gBACE,OAAO,mBAAmB,CAAC;QAC/B,CAAC;IACH,CAAC;IAED,QAAQ,CAAC,KAAiB;QACxB,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;IAC1B,CAAC;+GAtGU,qBAAqB;6DAArB,qBAAqB;;YAArB,wDAAqB,sCAAA,+CAAA,0CAAA,0CAAA,sCAAA;;;YAxG9B,qFAAoB;YAGpB,sFAAa;YAGb,qFAAe;YAKf,kBAAyB;YAIzB,8BAAqC;YACnC,0FAAkB;YAQlB,qBAA4C;YAC9C,iBAAM;;YAzBN,2CAEC;YACD,cAEC;YAFD,oCAEC;YACD,cAEC;YAFD,sCAEC;YAQC,eAOC;YAPD,yCAOC;4BAzBK,iBAAiB;;iFA0GhB,qBAAqB;cA7GjC,SAAS;2BACE,gBAAgB,cACd,IAAI,WACP,CAAC,iBAAiB,CAAC,YAClB;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2BT;;kBAoFA,KAAK;;kBAGL,KAAK;;kBAGL,KAAK;;kBAGL,KAAK;;kBAGL,KAAK;;kBAGL,KAAK;;kBAGL,KAAK;;kBAGL,KAAK;;kBAWL,KAAK;;kBAGL,MAAM;;kBAEN,WAAW;mBAAC,+BAA+B;;kBAG3C,WAAW;mBAAC,6BAA6B;;kBAGzC,WAAW;mBAAC,kCAAkC;;kBAG9C,WAAW;mBAAC,+BAA+B;;kBAG3C,WAAW;mBAAC,+BAA+B;;kBAG3C,WAAW;mBAAC,6BAA6B;;kBAOzC,WAAW;mBAAC,WAAW;;kFAjEb,qBAAqB","sourcesContent":["import { Component, EventEmitter, HostBinding, Input, Output } from '@angular/core';\nimport { MJButtonDirective } from '../button/button.directive';\n\n/**\n * Visual intent of an `<mj-empty-state>`. Drives the default icon and the icon's\n * color treatment so callers don't restate either for the common cases.\n *\n * - `empty` — nothing exists yet (default). Neutral/disabled icon tone.\n * - `no-results` — a search/filter matched nothing. Muted icon tone, magnifier default.\n * - `success` — a positive \"all clear\" empty (e.g. \"No Errors Found\"). Success icon tone, check default.\n * - `warning` — a non-error blocking condition (disabled/misconfigured feature). Warning icon tone.\n * - `error` — a load/operation failed. Error icon tone, triangle default.\n */\nexport type MJEmptyStateVariant = 'empty' | 'no-results' | 'success' | 'warning' | 'error';\n\n/** Density of an `<mj-empty-state>` — controls padding and icon size. */\nexport type MJEmptyStateSize = 'compact' | 'default' | 'large';\n\n/**\n * mj-empty-state — Canonical centered empty/no-results/error placeholder.\n *\n * Replaces the ~213 inline empty-state `<div>`s that pages were each hand-rolling\n * (icon + title + message, optionally a CTA), e.g.:\n * ```html\n * <div class=\"empty-state\">\n * <i class=\"fa-solid fa-inbox\"></i>\n * <h3>No Permissions Found</h3>\n * <p>Try adjusting your filters or refresh the data.</p>\n * <button mjButton variant=\"primary\" (click)=\"refreshData()\">Refresh</button>\n * </div>\n * ```\n *\n * Usage:\n * ```html\n * <!-- Simplest: nothing-here placeholder -->\n * <mj-empty-state Title=\"No runs found\" Message=\"No runs match the selected filters.\" />\n *\n * <!-- Search/filter produced nothing -->\n * <mj-empty-state Variant=\"no-results\" Title=\"No icons found\" Message=\"Try a different search term.\" />\n *\n * <!-- Load failed, retry CTA -->\n * <mj-empty-state Variant=\"error\" Title=\"Couldn't load permissions\" [Message]=\"error\"\n * ActionText=\"Try Again\" ActionIcon=\"fa-solid fa-rotate-right\" (Action)=\"loadData()\" />\n *\n * <!-- Invitation to create the first record -->\n * <mj-empty-state Icon=\"fa-solid fa-key\" Title=\"No API keys yet\"\n * Message=\"Generate a key to start calling the API.\"\n * ActionText=\"Generate Your First Key\" ActionIcon=\"fa-solid fa-plus\"\n * (Action)=\"requestCreate()\" />\n *\n * <!-- Multiple / bespoke CTAs: project them into the [actions] slot -->\n * <mj-empty-state Title=\"No pinned items yet\" Message=\"Pin dashboards for quick access.\">\n * <button mjButton variant=\"primary\" (click)=\"addPin()\">Add your first pin</button>\n * <button mjButton variant=\"flat\" (click)=\"dismiss()\">Don't show again</button>\n * </mj-empty-state>\n * ```\n *\n * For dynamic messages (e.g. \"No keys matching X\" vs \"No keys yet\"), compute the\n * string in the parent and bind it to `[Message]`, or project richer body content\n * as default `<ng-content>` (rendered between the message and the actions).\n */\n@Component({\n selector: 'mj-empty-state',\n standalone: true,\n imports: [MJButtonDirective],\n template: `\n @if (ResolvedIcon) {\n <i class=\"mj-empty-state__icon {{ ResolvedIcon }}\" aria-hidden=\"true\"></i>\n }\n @if (Title) {\n <h3 class=\"mj-empty-state__title\">{{ Title }}</h3>\n }\n @if (Message) {\n <p class=\"mj-empty-state__message\">{{ Message }}</p>\n }\n\n <!-- Optional richer body content (feature lists, dynamic text, links) -->\n <ng-content></ng-content>\n\n <!-- Actions: the built-in single CTA and/or projected [actions] buttons.\n Hidden via :empty when neither is present. -->\n <div class=\"mj-empty-state__actions\">\n @if (ActionText) {\n <button type=\"button\" mjButton [variant]=\"ActionVariant\" (click)=\"OnAction($event)\">\n @if (ActionIcon) {\n <i class=\"{{ ActionIcon }}\" aria-hidden=\"true\"></i>\n }\n {{ ActionText }}\n </button>\n }\n <ng-content select=\"[actions]\"></ng-content>\n </div>\n `,\n styles: [`\n :host {\n display: flex;\n flex-direction: column;\n align-items: center;\n justify-content: center;\n text-align: center;\n padding: var(--mj-space-12);\n color: var(--mj-text-secondary);\n }\n\n .mj-empty-state__icon {\n font-size: 3rem;\n line-height: 1;\n margin-bottom: var(--mj-space-4);\n color: var(--mj-text-disabled);\n }\n\n .mj-empty-state__title {\n margin: 0;\n font-size: var(--mj-text-lg);\n font-weight: 600;\n color: var(--mj-text-primary);\n }\n\n .mj-empty-state__message {\n margin: var(--mj-space-2) 0 0;\n font-size: var(--mj-text-sm);\n color: var(--mj-text-muted);\n max-width: 420px;\n }\n\n .mj-empty-state__actions {\n display: flex;\n flex-wrap: wrap;\n align-items: center;\n justify-content: center;\n gap: var(--mj-space-2);\n margin-top: var(--mj-space-6);\n }\n /* Collapse the actions row entirely when no CTA is rendered (modern browsers\n treat an element containing only Angular's @if comment-anchors as :empty). */\n .mj-empty-state__actions:empty {\n display: none;\n }\n\n /* ── Sizes ────────────────────────────────────────────────── */\n :host(.mj-empty-state--compact) {\n padding: var(--mj-space-8);\n }\n :host(.mj-empty-state--compact) .mj-empty-state__icon {\n font-size: 2rem;\n margin-bottom: var(--mj-space-3);\n }\n\n :host(.mj-empty-state--large) {\n padding: var(--mj-space-16) var(--mj-space-10);\n }\n :host(.mj-empty-state--large) .mj-empty-state__icon {\n font-size: 4rem;\n }\n\n /* ── Variants (icon tone) ─────────────────────────────────── */\n :host(.mj-empty-state--no-results) .mj-empty-state__icon {\n color: var(--mj-text-muted);\n }\n :host(.mj-empty-state--success) .mj-empty-state__icon {\n color: var(--mj-status-success);\n }\n :host(.mj-empty-state--warning) .mj-empty-state__icon {\n color: var(--mj-status-warning);\n }\n :host(.mj-empty-state--error) .mj-empty-state__icon {\n color: var(--mj-status-error);\n }\n `]\n})\nexport class MJEmptyStateComponent {\n /**\n * Font Awesome icon class string (e.g. \"fa-solid fa-key\"). When omitted, a\n * sensible default is chosen from `Variant`. Pass an empty string AND no\n * variant default applies — set this explicitly to \"\" to render no icon.\n */\n @Input() Icon: string | null = null;\n\n /** Bold heading line (e.g. \"No API keys yet\"). */\n @Input() Title: string = '';\n\n /** Supporting/help text below the title. */\n @Input() Message: string = '';\n\n /** When set, renders a primary CTA button with this label. */\n @Input() ActionText: string = '';\n\n /** Optional Font Awesome icon shown inside the CTA button. */\n @Input() ActionIcon: string = '';\n\n /** mjButton variant for the built-in CTA. Defaults to 'primary'. */\n @Input() ActionVariant: 'primary' | 'secondary' | 'outline' | 'flat' = 'primary';\n\n /** Visual intent — drives the default icon and icon color. Defaults to 'empty'. */\n @Input() Variant: MJEmptyStateVariant = 'empty';\n\n /** Density — controls padding and icon size. Defaults to 'default'. */\n @Input() Size: MJEmptyStateSize = 'default';\n\n /**\n * ARIA live-region role on the host. When unset, it defaults from `Variant`:\n * `error` → `'alert'` (assertive), everything else → `'status'` (polite). This\n * makes a dynamically-appearing empty state announce itself to screen readers —\n * the title + message are read together via the role's implicit\n * `aria-live`/`aria-atomic`. (Empty states present at page load are not\n * announced, per the live-region spec, so static placeholders stay quiet.)\n * Pass an explicit role to override, or `''` to opt out of the live region.\n */\n @Input() Role: string | null = null;\n\n /** Emitted when the built-in CTA button is clicked. */\n @Output() Action = new EventEmitter<MouseEvent>();\n\n @HostBinding('class.mj-empty-state--compact')\n get IsCompact(): boolean { return this.Size === 'compact'; }\n\n @HostBinding('class.mj-empty-state--large')\n get IsLarge(): boolean { return this.Size === 'large'; }\n\n @HostBinding('class.mj-empty-state--no-results')\n get IsNoResults(): boolean { return this.Variant === 'no-results'; }\n\n @HostBinding('class.mj-empty-state--success')\n get IsSuccess(): boolean { return this.Variant === 'success'; }\n\n @HostBinding('class.mj-empty-state--warning')\n get IsWarning(): boolean { return this.Variant === 'warning'; }\n\n @HostBinding('class.mj-empty-state--error')\n get IsError(): boolean { return this.Variant === 'error'; }\n\n /**\n * Live-region role applied to the host. Explicit `Role` wins (`''` ⇒ no role);\n * otherwise an error state is an assertive `alert`, everything else a polite `status`.\n */\n @HostBinding('attr.role')\n get HostRole(): string | null {\n if (this.Role != null) {\n return this.Role || null;\n }\n return this.Variant === 'error' ? 'alert' : 'status';\n }\n\n /**\n * Icon actually rendered: the explicit `Icon` when provided (including \"\"\n * to suppress the icon), otherwise the per-variant default.\n */\n get ResolvedIcon(): string {\n if (this.Icon != null) {\n return this.Icon;\n }\n return MJEmptyStateComponent.DefaultIconForVariant(this.Variant);\n }\n\n /** Default Font Awesome icon for each variant. */\n static DefaultIconForVariant(variant: MJEmptyStateVariant): string {\n switch (variant) {\n case 'no-results':\n return 'fa-solid fa-magnifying-glass';\n case 'success':\n return 'fa-solid fa-circle-check';\n case 'warning':\n case 'error':\n return 'fa-solid fa-triangle-exclamation';\n case 'empty':\n default:\n return 'fa-solid fa-inbox';\n }\n }\n\n OnAction(event: MouseEvent): void {\n this.Action.emit(event);\n }\n}\n"]}