@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":"alert.component.js","sourceRoot":"","sources":["../../../src/lib/alert/alert.component.ts"],"names":[],"mappings":"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","sourcesContent":["import { booleanAttribute, Component, EventEmitter, HostBinding, Input, Output } from '@angular/core';\n\n/**\n * Visual intent of an `<mj-alert>`. Drives the color treatment and the default\n * icon, so callers don't restate either for the common cases.\n *\n * - `info` — neutral informational notice (default).\n * - `success` — a positive confirmation that stays on screen.\n * - `warning` — a non-blocking caution.\n * - `error` — a failure / blocking problem.\n */\nexport type MJAlertVariant = 'info' | 'success' | 'warning' | 'error';\n\n/** Density of an `<mj-alert>` — controls padding and font size. */\nexport type MJAlertSize = 'sm' | 'md';\n\nconst DEFAULT_ICONS: Record<MJAlertVariant, string> = {\n info: 'fa-solid fa-circle-info',\n success: 'fa-solid fa-circle-check',\n warning: 'fa-solid fa-triangle-exclamation',\n error: 'fa-solid fa-circle-exclamation',\n};\n\n/**\n * mj-alert — Canonical inline alert / banner. The persistent, in-flow message box\n * (info / success / warning / error) — NOT the transient corner toast (that's\n * `NotificationService` from `@memberjunction/ng-notifications`).\n *\n * Replaces the ~50 hand-rolled `.error-message` / `.alert` / `.warning-banner`\n * `<div>`s that pages each style themselves, e.g.:\n * ```html\n * <div class=\"error-message\">\n * <i class=\"fa-solid fa-circle-exclamation\"></i> Couldn't save changes.\n * </div>\n * ```\n *\n * Usage:\n * ```html\n * <!-- Simplest -->\n * <mj-alert Variant=\"error\" Message=\"Couldn't save changes.\" />\n *\n * <!-- Title + message + dismiss -->\n * <mj-alert Variant=\"warning\" Title=\"Unsaved changes\"\n * Message=\"Leaving now will discard them.\" Dismissible\n * (Dismissed)=\"onDismiss()\" />\n *\n * <!-- Rich body + action buttons -->\n * <mj-alert Variant=\"info\" Title=\"Read-only mode\">\n * You don't have edit permission for this record.\n * <button mjButton variant=\"primary\" actions (click)=\"requestAccess()\">Request access</button>\n * </mj-alert>\n * ```\n *\n * Colors come from the `--mj-status-*` design tokens, so it's dark-mode-safe and\n * themeable. The host gets an ARIA live role (`alert` for error/warning, `status`\n * for info/success) so dynamically-shown alerts announce themselves.\n */\n@Component({\n selector: 'mj-alert',\n standalone: true,\n template: `\n @if (!isDismissed) {\n @if (ResolvedIcon) {\n <i class=\"mj-alert__icon {{ ResolvedIcon }}\" aria-hidden=\"true\"></i>\n }\n <div class=\"mj-alert__content\">\n @if (Title) {\n <div class=\"mj-alert__title\">{{ Title }}</div>\n }\n @if (Message) {\n <div class=\"mj-alert__message\">{{ Message }}</div>\n }\n <ng-content></ng-content>\n </div>\n <div class=\"mj-alert__actions\">\n <ng-content select=\"[actions]\"></ng-content>\n </div>\n @if (Dismissible) {\n <button type=\"button\" class=\"mj-alert__dismiss\" aria-label=\"Dismiss\" (click)=\"Dismiss()\">\n <i class=\"fa-solid fa-xmark\" aria-hidden=\"true\"></i>\n </button>\n }\n }\n `,\n styles: [`\n :host {\n display: flex;\n align-items: flex-start;\n gap: var(--mj-space-3);\n padding: var(--mj-space-3) var(--mj-space-4);\n margin-bottom: var(--mj-space-4);\n border: 1px solid var(--mj-border-default);\n border-radius: var(--mj-radius-md);\n font-size: var(--mj-text-sm);\n line-height: 1.45;\n }\n /* Alerts are flow content almost always followed by other content, so they\n carry a default bottom margin (like a <p>; cf. Bootstrap's .alert). When an\n alert is the only/last child of its container, drop the trailing gap. */\n :host(:last-child) { margin-bottom: 0; }\n :host(.mj-alert--dismissed) { display: none; }\n\n .mj-alert__icon {\n flex-shrink: 0;\n font-size: 1rem;\n margin-top: 0.1em;\n }\n .mj-alert__content { flex: 1; min-width: 0; }\n .mj-alert__title { font-weight: var(--mj-font-semibold); }\n .mj-alert__title + .mj-alert__message { margin-top: var(--mj-space-1); }\n .mj-alert__message { color: inherit; opacity: 0.9; }\n\n .mj-alert__actions {\n display: flex;\n align-items: center;\n gap: var(--mj-space-2);\n flex-shrink: 0;\n }\n .mj-alert__actions:empty { display: none; }\n\n .mj-alert__dismiss {\n flex-shrink: 0;\n border: none;\n background: transparent;\n color: inherit;\n opacity: 0.6;\n cursor: pointer;\n padding: 0;\n width: 20px; height: 20px;\n display: flex; align-items: center; justify-content: center;\n border-radius: var(--mj-radius-sm);\n transition: opacity var(--mj-transition-fast), background var(--mj-transition-fast);\n }\n .mj-alert__dismiss:hover { opacity: 1; background: color-mix(in srgb, currentColor 12%, transparent); }\n\n /* ── Density ───────────────────────────────────────────────── */\n :host(.mj-alert--sm) {\n padding: var(--mj-space-2) var(--mj-space-3);\n font-size: var(--mj-text-xs);\n gap: var(--mj-space-2);\n }\n :host(.mj-alert--sm) .mj-alert__icon { font-size: 0.875rem; }\n\n /* ── Variants (token-driven, dark-mode-safe) ───────────────────\n Background is an OPAQUE tint (status color mixed into the surface), NOT the\n translucent --mj-status-*-bg token. Translucent backgrounds let whatever\n sits behind the alert show through, so the same alert rendered on two\n different dialog backdrops looked different. An opaque tint is identical\n regardless of what's behind it, and still adapts to light/dark via the\n surface + status tokens. */\n :host(.mj-alert--info) {\n background: color-mix(in srgb, var(--mj-status-info) 12%, var(--mj-bg-surface));\n border-color: var(--mj-status-info-border);\n color: var(--mj-status-info-text);\n }\n :host(.mj-alert--info) .mj-alert__icon { color: var(--mj-status-info); }\n\n :host(.mj-alert--success) {\n background: color-mix(in srgb, var(--mj-status-success) 12%, var(--mj-bg-surface));\n border-color: var(--mj-status-success-border);\n color: var(--mj-status-success-text);\n }\n :host(.mj-alert--success) .mj-alert__icon { color: var(--mj-status-success); }\n\n :host(.mj-alert--warning) {\n background: color-mix(in srgb, var(--mj-status-warning) 12%, var(--mj-bg-surface));\n border-color: var(--mj-status-warning-border);\n color: var(--mj-status-warning-text);\n }\n :host(.mj-alert--warning) .mj-alert__icon { color: var(--mj-status-warning); }\n\n :host(.mj-alert--error) {\n background: color-mix(in srgb, var(--mj-status-error) 12%, var(--mj-bg-surface));\n border-color: var(--mj-status-error-border);\n color: var(--mj-status-error-text);\n }\n :host(.mj-alert--error) .mj-alert__icon { color: var(--mj-status-error); }\n `]\n})\nexport class MJAlertComponent {\n /** Visual intent — drives color + default icon. Defaults to 'info'. */\n @Input() Variant: MJAlertVariant = 'info';\n\n /** Density — 'sm' tightens padding/font for inline/dense placements. */\n @Input() Size: MJAlertSize = 'md';\n\n /** Optional bold lead line. */\n @Input() Title = '';\n\n /** Body text. For rich content, project default `<ng-content>` instead. */\n @Input() Message = '';\n\n /**\n * Font Awesome icon class (e.g. \"fa-solid fa-key\"). When omitted, a sensible\n * default is chosen from `Variant`. Set to `''` to render no icon.\n */\n @Input() Icon: string | null = null;\n\n /** Show a dismiss (×) button. Accepts a bare attribute (`Dismissible`) or `[Dismissible]=\"expr\"`. */\n @Input({ transform: booleanAttribute }) Dismissible = false;\n\n /**\n * ARIA live role on the host. When unset, defaults from `Variant`:\n * `error`/`warning` → `'alert'` (assertive), `info`/`success` → `'status'`\n * (polite), so a dynamically-shown alert announces itself. Pass `''` to opt out.\n */\n @Input() Role: string | null = null;\n\n /** Fired when the user dismisses the alert. */\n @Output() Dismissed = new EventEmitter<void>();\n\n protected isDismissed = false;\n\n // Host classes — individual ADDITIVE bindings so a consumer's own `class=\"…\"`\n // on <mj-alert> is never clobbered (a single `@HostBinding('class')` would).\n @HostBinding('class.mj-alert--info') get IsInfo(): boolean { return this.Variant === 'info'; }\n @HostBinding('class.mj-alert--success') get IsSuccess(): boolean { return this.Variant === 'success'; }\n @HostBinding('class.mj-alert--warning') get IsWarning(): boolean { return this.Variant === 'warning'; }\n @HostBinding('class.mj-alert--error') get IsError(): boolean { return this.Variant === 'error'; }\n @HostBinding('class.mj-alert--sm') get IsSmall(): boolean { return this.Size === 'sm'; }\n @HostBinding('class.mj-alert--dismissed') get IsHidden(): boolean { return this.isDismissed; }\n\n /**\n * Live-region role applied to the host. Explicit `Role` wins (`''` ⇒ no role);\n * otherwise error/warning are an assertive `alert`, info/success 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' || this.Variant === 'warning' ? '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 MJAlertComponent.DefaultIconForVariant(this.Variant);\n }\n\n /** Default Font Awesome icon for each variant. */\n static DefaultIconForVariant(variant: MJAlertVariant): string {\n return DEFAULT_ICONS[variant] ?? DEFAULT_ICONS.info;\n }\n\n Dismiss(): void {\n this.isDismissed = true;\n this.Dismissed.emit();\n }\n}\n"]}
@@ -0,0 +1,102 @@
1
+ import { EventEmitter } from '@angular/core';
2
+ import * as i0 from "@angular/core";
3
+ /**
4
+ * Visual intent of an `<mj-confirm-dialog>`. Drives the header icon and the
5
+ * confirm button's color, so callers rarely restate either.
6
+ *
7
+ * - `default` — a neutral question (e.g. "Discard unsaved changes?"). Blue confirm button.
8
+ * - `danger` — a destructive / irreversible action (delete). Red confirm button.
9
+ * - `warning` — a non-destructive but consequential action. Blue confirm button, caution icon.
10
+ * - `info` — an informational confirmation. Blue confirm button, info icon.
11
+ */
12
+ export type MJConfirmDialogType = 'default' | 'danger' | 'warning' | 'info';
13
+ /**
14
+ * mj-confirm-dialog — Canonical confirmation prompt. The shared replacement for
15
+ * native `window.confirm()` and the many hand-rolled "Are you sure?" modals
16
+ * (`@if (showDeleteConfirm) { … backdrop + centered dialog }`) scattered across
17
+ * the app, plus the duplicate local `mj-confirm-dialog` / `mj-ev-confirm-dialog`
18
+ * components.
19
+ *
20
+ * Built on `<mj-dialog>` (so it inherits the backdrop, animations, mobile
21
+ * full-screen behavior, and Esc/backdrop handling) and uses `role="alertdialog"`
22
+ * for screen readers. Buttons follow the MJ convention: the affirmative action
23
+ * is **leftmost**, Cancel on the right.
24
+ *
25
+ * Visibility is two-way bindable. Cancelling (Cancel button, backdrop, Esc, or
26
+ * the ✕) auto-closes and emits `Cancelled`. Confirming emits `Confirmed` and
27
+ * **leaves the dialog open** so the handler can run async work — set `Visible`
28
+ * to `false` (or update your bound property) when done. Bind `[Processing]` to a
29
+ * loading flag during that async work to show a spinner, disable both buttons,
30
+ * and block dismissal until it completes.
31
+ *
32
+ * Usage:
33
+ * ```html
34
+ * <!-- Simple destructive confirm -->
35
+ * <mj-confirm-dialog
36
+ * [(Visible)]="showDeleteConfirm"
37
+ * Type="danger"
38
+ * Title="Delete view"
39
+ * Message="Are you sure you want to delete this view?"
40
+ * DetailMessage="This action cannot be undone."
41
+ * ConfirmText="Delete"
42
+ * (Confirmed)="onDeleteConfirmed()">
43
+ * </mj-confirm-dialog>
44
+ *
45
+ * <!-- Async confirm with a spinner while the work runs -->
46
+ * <mj-confirm-dialog
47
+ * [(Visible)]="confirmOpen"
48
+ * [Processing]="isDeleting"
49
+ * Type="danger" Title="Delete user" Message="Remove this user permanently?"
50
+ * ConfirmText="Delete" (Confirmed)="deleteUser()">
51
+ * </mj-confirm-dialog>
52
+ * ```
53
+ */
54
+ export declare class MJConfirmDialogComponent {
55
+ /** Whether the dialog is shown. Two-way bindable: `[(Visible)]`. */
56
+ Visible: boolean;
57
+ /** Two-way `Visible` change channel — fires when the dialog auto-closes on cancel. */
58
+ VisibleChange: EventEmitter<boolean>;
59
+ /** Heading shown in the dialog title bar. */
60
+ Title: string;
61
+ /** Primary prompt text. For rich content, project default `<ng-content>` instead. */
62
+ Message: string;
63
+ /** Optional secondary line, rendered smaller/muted beneath the message. */
64
+ DetailMessage: string;
65
+ /** Visual intent — drives the header icon + confirm button color. Defaults to 'default'. */
66
+ Type: MJConfirmDialogType;
67
+ /** Affirmative button label. */
68
+ ConfirmText: string;
69
+ /** Dismiss button label. */
70
+ CancelText: string;
71
+ /**
72
+ * Font Awesome icon class (e.g. "fa-solid fa-trash") for the header. When
73
+ * omitted, a sensible default is chosen from `Type`. Set to `''` for no icon.
74
+ */
75
+ Icon: string | null;
76
+ /**
77
+ * When true, shows a spinner on the confirm button, disables both buttons, and
78
+ * blocks dismissal (Esc / backdrop / ✕) — bind this to your loading flag while
79
+ * the `Confirmed` handler runs async work.
80
+ */
81
+ Processing: boolean;
82
+ /** Fired when the user confirms. The dialog stays open; close it when ready. */
83
+ Confirmed: EventEmitter<void>;
84
+ /** Fired when the user cancels (button, backdrop, Esc, or ✕). The dialog auto-closes. */
85
+ Cancelled: EventEmitter<void>;
86
+ /** mjButton variant for the confirm button — red for `danger`, blue otherwise. */
87
+ get ConfirmVariant(): 'primary' | 'danger';
88
+ /**
89
+ * Icon actually rendered: the explicit `Icon` when provided (including `""`
90
+ * to suppress it), otherwise the per-type default.
91
+ */
92
+ get ResolvedIcon(): string;
93
+ onConfirm(): void;
94
+ onCancel(): void;
95
+ /** Backdrop / Esc / ✕ from the underlying dialog — ignored while Processing. */
96
+ onDismiss(): void;
97
+ private close;
98
+ static ɵfac: i0.ɵɵFactoryDeclaration<MJConfirmDialogComponent, never>;
99
+ static ɵcmp: i0.ɵɵComponentDeclaration<MJConfirmDialogComponent, "mj-confirm-dialog", never, { "Visible": { "alias": "Visible"; "required": false; }; "Title": { "alias": "Title"; "required": false; }; "Message": { "alias": "Message"; "required": false; }; "DetailMessage": { "alias": "DetailMessage"; "required": false; }; "Type": { "alias": "Type"; "required": false; }; "ConfirmText": { "alias": "ConfirmText"; "required": false; }; "CancelText": { "alias": "CancelText"; "required": false; }; "Icon": { "alias": "Icon"; "required": false; }; "Processing": { "alias": "Processing"; "required": false; }; }, { "VisibleChange": "VisibleChange"; "Confirmed": "Confirmed"; "Cancelled": "Cancelled"; }, never, ["*"], true, never>;
100
+ static ngAcceptInputType_Processing: unknown;
101
+ }
102
+ //# sourceMappingURL=confirm-dialog.component.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"confirm-dialog.component.d.ts","sourceRoot":"","sources":["../../../src/lib/confirm-dialog/confirm-dialog.component.ts"],"names":[],"mappings":"AAAA,OAAO,EAAa,YAAY,EAAmC,MAAM,eAAe,CAAC;;AAIzF;;;;;;;;GAQG;AACH,MAAM,MAAM,mBAAmB,GAAG,SAAS,GAAG,QAAQ,GAAG,SAAS,GAAG,MAAM,CAAC;AAS5E;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAwCG;AACH,qBA+Ea,wBAAwB;IACnC,oEAAoE;IAC3D,OAAO,UAAS;IACzB,sFAAsF;IAC5E,aAAa,wBAA+B;IAEtD,6CAA6C;IACpC,KAAK,SAAa;IAE3B,qFAAqF;IAC5E,OAAO,SAAmB;IAEnC,2EAA2E;IAClE,aAAa,SAAM;IAE5B,4FAA4F;IACnF,IAAI,EAAE,mBAAmB,CAAa;IAE/C,gCAAgC;IACvB,WAAW,SAAa;IAEjC,4BAA4B;IACnB,UAAU,SAAY;IAE/B;;;OAGG;IACM,IAAI,EAAE,MAAM,GAAG,IAAI,CAAQ;IAEpC;;;;OAIG;IACqC,UAAU,UAAS;IAE3D,gFAAgF;IACtE,SAAS,qBAA4B;IAE/C,yFAAyF;IAC/E,SAAS,qBAA4B;IAE/C,kFAAkF;IAClF,IAAI,cAAc,IAAI,SAAS,GAAG,QAAQ,CAEzC;IAED;;;OAGG;IACH,IAAI,YAAY,IAAI,MAAM,CAKzB;IAED,SAAS,IAAI,IAAI;IAIjB,QAAQ,IAAI,IAAI;IAKhB,gFAAgF;IAChF,SAAS,IAAI,IAAI;IAOjB,OAAO,CAAC,KAAK;yCA5EF,wBAAwB;2CAAxB,wBAAwB;yCAiFms7L,OAAQ;CAD/u7L"}
@@ -0,0 +1,259 @@
1
+ import { Component, EventEmitter, Input, Output, booleanAttribute } from '@angular/core';
2
+ import { MJDialogComponent, MJDialogActionsComponent } from '../dialog/dialog.component';
3
+ import { MJButtonDirective } from '../button/button.directive';
4
+ import * as i0 from "@angular/core";
5
+ const _c0 = ["*"];
6
+ function MJConfirmDialogComponent_Conditional_2_Template(rf, ctx) { if (rf & 1) {
7
+ i0.ɵɵelement(0, "i", 9);
8
+ } if (rf & 2) {
9
+ const ctx_r0 = i0.ɵɵnextContext();
10
+ i0.ɵɵclassMap(i0.ɵɵinterpolate2("mj-confirm__icon mj-confirm__icon--", ctx_r0.Type, " ", ctx_r0.ResolvedIcon));
11
+ } }
12
+ function MJConfirmDialogComponent_Conditional_4_Template(rf, ctx) { if (rf & 1) {
13
+ i0.ɵɵelementStart(0, "p", 4);
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.Message);
20
+ } }
21
+ function MJConfirmDialogComponent_Conditional_5_Template(rf, ctx) { if (rf & 1) {
22
+ i0.ɵɵelementStart(0, "p", 5);
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.DetailMessage);
29
+ } }
30
+ function MJConfirmDialogComponent_Conditional_9_Template(rf, ctx) { if (rf & 1) {
31
+ i0.ɵɵelement(0, "i", 7);
32
+ } }
33
+ const DEFAULT_ICONS = {
34
+ default: 'fa-solid fa-circle-question',
35
+ danger: 'fa-solid fa-triangle-exclamation',
36
+ warning: 'fa-solid fa-triangle-exclamation',
37
+ info: 'fa-solid fa-circle-info',
38
+ };
39
+ /**
40
+ * mj-confirm-dialog — Canonical confirmation prompt. The shared replacement for
41
+ * native `window.confirm()` and the many hand-rolled "Are you sure?" modals
42
+ * (`@if (showDeleteConfirm) { … backdrop + centered dialog }`) scattered across
43
+ * the app, plus the duplicate local `mj-confirm-dialog` / `mj-ev-confirm-dialog`
44
+ * components.
45
+ *
46
+ * Built on `<mj-dialog>` (so it inherits the backdrop, animations, mobile
47
+ * full-screen behavior, and Esc/backdrop handling) and uses `role="alertdialog"`
48
+ * for screen readers. Buttons follow the MJ convention: the affirmative action
49
+ * is **leftmost**, Cancel on the right.
50
+ *
51
+ * Visibility is two-way bindable. Cancelling (Cancel button, backdrop, Esc, or
52
+ * the ✕) auto-closes and emits `Cancelled`. Confirming emits `Confirmed` and
53
+ * **leaves the dialog open** so the handler can run async work — set `Visible`
54
+ * to `false` (or update your bound property) when done. Bind `[Processing]` to a
55
+ * loading flag during that async work to show a spinner, disable both buttons,
56
+ * and block dismissal until it completes.
57
+ *
58
+ * Usage:
59
+ * ```html
60
+ * <!-- Simple destructive confirm -->
61
+ * <mj-confirm-dialog
62
+ * [(Visible)]="showDeleteConfirm"
63
+ * Type="danger"
64
+ * Title="Delete view"
65
+ * Message="Are you sure you want to delete this view?"
66
+ * DetailMessage="This action cannot be undone."
67
+ * ConfirmText="Delete"
68
+ * (Confirmed)="onDeleteConfirmed()">
69
+ * </mj-confirm-dialog>
70
+ *
71
+ * <!-- Async confirm with a spinner while the work runs -->
72
+ * <mj-confirm-dialog
73
+ * [(Visible)]="confirmOpen"
74
+ * [Processing]="isDeleting"
75
+ * Type="danger" Title="Delete user" Message="Remove this user permanently?"
76
+ * ConfirmText="Delete" (Confirmed)="deleteUser()">
77
+ * </mj-confirm-dialog>
78
+ * ```
79
+ */
80
+ export class MJConfirmDialogComponent {
81
+ /** Whether the dialog is shown. Two-way bindable: `[(Visible)]`. */
82
+ Visible = false;
83
+ /** Two-way `Visible` change channel — fires when the dialog auto-closes on cancel. */
84
+ VisibleChange = new EventEmitter();
85
+ /** Heading shown in the dialog title bar. */
86
+ Title = 'Confirm';
87
+ /** Primary prompt text. For rich content, project default `<ng-content>` instead. */
88
+ Message = 'Are you sure?';
89
+ /** Optional secondary line, rendered smaller/muted beneath the message. */
90
+ DetailMessage = '';
91
+ /** Visual intent — drives the header icon + confirm button color. Defaults to 'default'. */
92
+ Type = 'default';
93
+ /** Affirmative button label. */
94
+ ConfirmText = 'Confirm';
95
+ /** Dismiss button label. */
96
+ CancelText = 'Cancel';
97
+ /**
98
+ * Font Awesome icon class (e.g. "fa-solid fa-trash") for the header. When
99
+ * omitted, a sensible default is chosen from `Type`. Set to `''` for no icon.
100
+ */
101
+ Icon = null;
102
+ /**
103
+ * When true, shows a spinner on the confirm button, disables both buttons, and
104
+ * blocks dismissal (Esc / backdrop / ✕) — bind this to your loading flag while
105
+ * the `Confirmed` handler runs async work.
106
+ */
107
+ Processing = false;
108
+ /** Fired when the user confirms. The dialog stays open; close it when ready. */
109
+ Confirmed = new EventEmitter();
110
+ /** Fired when the user cancels (button, backdrop, Esc, or ✕). The dialog auto-closes. */
111
+ Cancelled = new EventEmitter();
112
+ /** mjButton variant for the confirm button — red for `danger`, blue otherwise. */
113
+ get ConfirmVariant() {
114
+ return this.Type === 'danger' ? 'danger' : 'primary';
115
+ }
116
+ /**
117
+ * Icon actually rendered: the explicit `Icon` when provided (including `""`
118
+ * to suppress it), otherwise the per-type default.
119
+ */
120
+ get ResolvedIcon() {
121
+ if (this.Icon != null) {
122
+ return this.Icon;
123
+ }
124
+ return DEFAULT_ICONS[this.Type] ?? DEFAULT_ICONS.default;
125
+ }
126
+ onConfirm() {
127
+ this.Confirmed.emit();
128
+ }
129
+ onCancel() {
130
+ this.close();
131
+ this.Cancelled.emit();
132
+ }
133
+ /** Backdrop / Esc / ✕ from the underlying dialog — ignored while Processing. */
134
+ onDismiss() {
135
+ if (this.Processing) {
136
+ return;
137
+ }
138
+ this.onCancel();
139
+ }
140
+ close() {
141
+ this.Visible = false;
142
+ this.VisibleChange.emit(false);
143
+ }
144
+ static ɵfac = function MJConfirmDialogComponent_Factory(__ngFactoryType__) { return new (__ngFactoryType__ || MJConfirmDialogComponent)(); };
145
+ static ɵcmp = /*@__PURE__*/ i0.ɵɵdefineComponent({ type: MJConfirmDialogComponent, selectors: [["mj-confirm-dialog"]], inputs: { Visible: "Visible", Title: "Title", Message: "Message", DetailMessage: "DetailMessage", Type: "Type", ConfirmText: "ConfirmText", CancelText: "CancelText", Icon: "Icon", Processing: [2, "Processing", "Processing", booleanAttribute] }, outputs: { VisibleChange: "VisibleChange", Confirmed: "Confirmed", Cancelled: "Cancelled" }, ngContentSelectors: _c0, decls: 13, vars: 12, consts: [["Size", "sm", "Role", "alertdialog", 3, "Close", "Visible", "Title", "Closeable"], [1, "mj-confirm"], ["aria-hidden", "true", 3, "class"], [1, "mj-confirm__body"], [1, "mj-confirm__message"], [1, "mj-confirm__detail"], ["mjButton", "", 3, "click", "variant", "disabled"], ["aria-hidden", "true", 1, "fa-solid", "fa-spinner", "fa-spin"], ["mjButton", "", "variant", "secondary", 3, "click", "disabled"], ["aria-hidden", "true"]], template: function MJConfirmDialogComponent_Template(rf, ctx) { if (rf & 1) {
146
+ i0.ɵɵprojectionDef();
147
+ i0.ɵɵelementStart(0, "mj-dialog", 0);
148
+ i0.ɵɵlistener("Close", function MJConfirmDialogComponent_Template_mj_dialog_Close_0_listener() { return ctx.onDismiss(); });
149
+ i0.ɵɵelementStart(1, "div", 1);
150
+ i0.ɵɵconditionalCreate(2, MJConfirmDialogComponent_Conditional_2_Template, 1, 4, "i", 2);
151
+ i0.ɵɵelementStart(3, "div", 3);
152
+ i0.ɵɵconditionalCreate(4, MJConfirmDialogComponent_Conditional_4_Template, 2, 1, "p", 4);
153
+ i0.ɵɵconditionalCreate(5, MJConfirmDialogComponent_Conditional_5_Template, 2, 1, "p", 5);
154
+ i0.ɵɵprojection(6);
155
+ i0.ɵɵelementEnd()();
156
+ i0.ɵɵelementStart(7, "mj-dialog-actions")(8, "button", 6);
157
+ i0.ɵɵlistener("click", function MJConfirmDialogComponent_Template_button_click_8_listener() { return ctx.onConfirm(); });
158
+ i0.ɵɵconditionalCreate(9, MJConfirmDialogComponent_Conditional_9_Template, 1, 0, "i", 7);
159
+ i0.ɵɵtext(10);
160
+ i0.ɵɵelementEnd();
161
+ i0.ɵɵelementStart(11, "button", 8);
162
+ i0.ɵɵlistener("click", function MJConfirmDialogComponent_Template_button_click_11_listener() { return ctx.onCancel(); });
163
+ i0.ɵɵtext(12);
164
+ i0.ɵɵelementEnd()()();
165
+ } if (rf & 2) {
166
+ i0.ɵɵproperty("Visible", ctx.Visible)("Title", ctx.Title)("Closeable", !ctx.Processing);
167
+ i0.ɵɵadvance(2);
168
+ i0.ɵɵconditional(ctx.ResolvedIcon ? 2 : -1);
169
+ i0.ɵɵadvance(2);
170
+ i0.ɵɵconditional(ctx.Message ? 4 : -1);
171
+ i0.ɵɵadvance();
172
+ i0.ɵɵconditional(ctx.DetailMessage ? 5 : -1);
173
+ i0.ɵɵadvance(3);
174
+ i0.ɵɵproperty("variant", ctx.ConfirmVariant)("disabled", ctx.Processing);
175
+ i0.ɵɵadvance();
176
+ i0.ɵɵconditional(ctx.Processing ? 9 : -1);
177
+ i0.ɵɵadvance();
178
+ i0.ɵɵtextInterpolate1(" ", ctx.ConfirmText, " ");
179
+ i0.ɵɵadvance();
180
+ i0.ɵɵproperty("disabled", ctx.Processing);
181
+ i0.ɵɵadvance();
182
+ i0.ɵɵtextInterpolate1(" ", ctx.CancelText, " ");
183
+ } }, dependencies: [MJDialogComponent, MJDialogActionsComponent, MJButtonDirective], styles: [".mj-confirm[_ngcontent-%COMP%] {\n display: flex;\n align-items: flex-start;\n gap: var(--mj-space-3);\n }\n .mj-confirm__icon[_ngcontent-%COMP%] {\n flex-shrink: 0;\n font-size: 1.5rem;\n margin-top: 0.05em;\n color: var(--mj-text-muted);\n }\n .mj-confirm__icon--danger[_ngcontent-%COMP%] { color: var(--mj-status-error); }\n .mj-confirm__icon--warning[_ngcontent-%COMP%] { color: var(--mj-status-warning); }\n .mj-confirm__icon--info[_ngcontent-%COMP%] { color: var(--mj-status-info); }\n\n .mj-confirm__body[_ngcontent-%COMP%] { flex: 1; min-width: 0; }\n .mj-confirm__message[_ngcontent-%COMP%] {\n margin: 0;\n color: var(--mj-text-primary);\n line-height: 1.5;\n }\n .mj-confirm__detail[_ngcontent-%COMP%] {\n margin: var(--mj-space-2) 0 0;\n font-size: var(--mj-text-sm);\n color: var(--mj-text-secondary);\n line-height: 1.45;\n }"] });
184
+ }
185
+ (() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassMetadata(MJConfirmDialogComponent, [{
186
+ type: Component,
187
+ args: [{ selector: 'mj-confirm-dialog', standalone: true, imports: [MJDialogComponent, MJDialogActionsComponent, MJButtonDirective], template: `
188
+ <mj-dialog
189
+ [Visible]="Visible"
190
+ [Title]="Title"
191
+ Size="sm"
192
+ Role="alertdialog"
193
+ [Closeable]="!Processing"
194
+ (Close)="onDismiss()">
195
+
196
+ <div class="mj-confirm">
197
+ @if (ResolvedIcon) {
198
+ <i class="mj-confirm__icon mj-confirm__icon--{{ Type }} {{ ResolvedIcon }}" aria-hidden="true"></i>
199
+ }
200
+ <div class="mj-confirm__body">
201
+ @if (Message) {
202
+ <p class="mj-confirm__message">{{ Message }}</p>
203
+ }
204
+ @if (DetailMessage) {
205
+ <p class="mj-confirm__detail">{{ DetailMessage }}</p>
206
+ }
207
+ <ng-content></ng-content>
208
+ </div>
209
+ </div>
210
+
211
+ <mj-dialog-actions>
212
+ <button
213
+ mjButton
214
+ [variant]="ConfirmVariant"
215
+ [disabled]="Processing"
216
+ (click)="onConfirm()">
217
+ @if (Processing) {
218
+ <i class="fa-solid fa-spinner fa-spin" aria-hidden="true"></i>
219
+ }
220
+ {{ ConfirmText }}
221
+ </button>
222
+ <button
223
+ mjButton
224
+ variant="secondary"
225
+ [disabled]="Processing"
226
+ (click)="onCancel()">
227
+ {{ CancelText }}
228
+ </button>
229
+ </mj-dialog-actions>
230
+ </mj-dialog>
231
+ `, styles: ["\n .mj-confirm {\n display: flex;\n align-items: flex-start;\n gap: var(--mj-space-3);\n }\n .mj-confirm__icon {\n flex-shrink: 0;\n font-size: 1.5rem;\n margin-top: 0.05em;\n color: var(--mj-text-muted);\n }\n .mj-confirm__icon--danger { color: var(--mj-status-error); }\n .mj-confirm__icon--warning { color: var(--mj-status-warning); }\n .mj-confirm__icon--info { color: var(--mj-status-info); }\n\n .mj-confirm__body { flex: 1; min-width: 0; }\n .mj-confirm__message {\n margin: 0;\n color: var(--mj-text-primary);\n line-height: 1.5;\n }\n .mj-confirm__detail {\n margin: var(--mj-space-2) 0 0;\n font-size: var(--mj-text-sm);\n color: var(--mj-text-secondary);\n line-height: 1.45;\n }\n "] }]
232
+ }], null, { Visible: [{
233
+ type: Input
234
+ }], VisibleChange: [{
235
+ type: Output
236
+ }], Title: [{
237
+ type: Input
238
+ }], Message: [{
239
+ type: Input
240
+ }], DetailMessage: [{
241
+ type: Input
242
+ }], Type: [{
243
+ type: Input
244
+ }], ConfirmText: [{
245
+ type: Input
246
+ }], CancelText: [{
247
+ type: Input
248
+ }], Icon: [{
249
+ type: Input
250
+ }], Processing: [{
251
+ type: Input,
252
+ args: [{ transform: booleanAttribute }]
253
+ }], Confirmed: [{
254
+ type: Output
255
+ }], Cancelled: [{
256
+ type: Output
257
+ }] }); })();
258
+ (() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassDebugInfo(MJConfirmDialogComponent, { className: "MJConfirmDialogComponent", filePath: "lib/confirm-dialog/confirm-dialog.component.ts", lineNumber: 143 }); })();
259
+ //# sourceMappingURL=confirm-dialog.component.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"confirm-dialog.component.js","sourceRoot":"","sources":["../../../src/lib/confirm-dialog/confirm-dialog.component.ts"],"names":[],"mappings":"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","sourcesContent":["import { Component, EventEmitter, Input, Output, booleanAttribute } from '@angular/core';\nimport { MJDialogComponent, MJDialogActionsComponent } from '../dialog/dialog.component';\nimport { MJButtonDirective } from '../button/button.directive';\n\n/**\n * Visual intent of an `<mj-confirm-dialog>`. Drives the header icon and the\n * confirm button's color, so callers rarely restate either.\n *\n * - `default` — a neutral question (e.g. \"Discard unsaved changes?\"). Blue confirm button.\n * - `danger` — a destructive / irreversible action (delete). Red confirm button.\n * - `warning` — a non-destructive but consequential action. Blue confirm button, caution icon.\n * - `info` — an informational confirmation. Blue confirm button, info icon.\n */\nexport type MJConfirmDialogType = 'default' | 'danger' | 'warning' | 'info';\n\nconst DEFAULT_ICONS: Record<MJConfirmDialogType, string> = {\n default: 'fa-solid fa-circle-question',\n danger: 'fa-solid fa-triangle-exclamation',\n warning: 'fa-solid fa-triangle-exclamation',\n info: 'fa-solid fa-circle-info',\n};\n\n/**\n * mj-confirm-dialog — Canonical confirmation prompt. The shared replacement for\n * native `window.confirm()` and the many hand-rolled \"Are you sure?\" modals\n * (`@if (showDeleteConfirm) { … backdrop + centered dialog }`) scattered across\n * the app, plus the duplicate local `mj-confirm-dialog` / `mj-ev-confirm-dialog`\n * components.\n *\n * Built on `<mj-dialog>` (so it inherits the backdrop, animations, mobile\n * full-screen behavior, and Esc/backdrop handling) and uses `role=\"alertdialog\"`\n * for screen readers. Buttons follow the MJ convention: the affirmative action\n * is **leftmost**, Cancel on the right.\n *\n * Visibility is two-way bindable. Cancelling (Cancel button, backdrop, Esc, or\n * the ✕) auto-closes and emits `Cancelled`. Confirming emits `Confirmed` and\n * **leaves the dialog open** so the handler can run async work — set `Visible`\n * to `false` (or update your bound property) when done. Bind `[Processing]` to a\n * loading flag during that async work to show a spinner, disable both buttons,\n * and block dismissal until it completes.\n *\n * Usage:\n * ```html\n * <!-- Simple destructive confirm -->\n * <mj-confirm-dialog\n * [(Visible)]=\"showDeleteConfirm\"\n * Type=\"danger\"\n * Title=\"Delete view\"\n * Message=\"Are you sure you want to delete this view?\"\n * DetailMessage=\"This action cannot be undone.\"\n * ConfirmText=\"Delete\"\n * (Confirmed)=\"onDeleteConfirmed()\">\n * </mj-confirm-dialog>\n *\n * <!-- Async confirm with a spinner while the work runs -->\n * <mj-confirm-dialog\n * [(Visible)]=\"confirmOpen\"\n * [Processing]=\"isDeleting\"\n * Type=\"danger\" Title=\"Delete user\" Message=\"Remove this user permanently?\"\n * ConfirmText=\"Delete\" (Confirmed)=\"deleteUser()\">\n * </mj-confirm-dialog>\n * ```\n */\n@Component({\n selector: 'mj-confirm-dialog',\n standalone: true,\n imports: [MJDialogComponent, MJDialogActionsComponent, MJButtonDirective],\n template: `\n <mj-dialog\n [Visible]=\"Visible\"\n [Title]=\"Title\"\n Size=\"sm\"\n Role=\"alertdialog\"\n [Closeable]=\"!Processing\"\n (Close)=\"onDismiss()\">\n\n <div class=\"mj-confirm\">\n @if (ResolvedIcon) {\n <i class=\"mj-confirm__icon mj-confirm__icon--{{ Type }} {{ ResolvedIcon }}\" aria-hidden=\"true\"></i>\n }\n <div class=\"mj-confirm__body\">\n @if (Message) {\n <p class=\"mj-confirm__message\">{{ Message }}</p>\n }\n @if (DetailMessage) {\n <p class=\"mj-confirm__detail\">{{ DetailMessage }}</p>\n }\n <ng-content></ng-content>\n </div>\n </div>\n\n <mj-dialog-actions>\n <button\n mjButton\n [variant]=\"ConfirmVariant\"\n [disabled]=\"Processing\"\n (click)=\"onConfirm()\">\n @if (Processing) {\n <i class=\"fa-solid fa-spinner fa-spin\" aria-hidden=\"true\"></i>\n }\n {{ ConfirmText }}\n </button>\n <button\n mjButton\n variant=\"secondary\"\n [disabled]=\"Processing\"\n (click)=\"onCancel()\">\n {{ CancelText }}\n </button>\n </mj-dialog-actions>\n </mj-dialog>\n `,\n styles: [`\n .mj-confirm {\n display: flex;\n align-items: flex-start;\n gap: var(--mj-space-3);\n }\n .mj-confirm__icon {\n flex-shrink: 0;\n font-size: 1.5rem;\n margin-top: 0.05em;\n color: var(--mj-text-muted);\n }\n .mj-confirm__icon--danger { color: var(--mj-status-error); }\n .mj-confirm__icon--warning { color: var(--mj-status-warning); }\n .mj-confirm__icon--info { color: var(--mj-status-info); }\n\n .mj-confirm__body { flex: 1; min-width: 0; }\n .mj-confirm__message {\n margin: 0;\n color: var(--mj-text-primary);\n line-height: 1.5;\n }\n .mj-confirm__detail {\n margin: var(--mj-space-2) 0 0;\n font-size: var(--mj-text-sm);\n color: var(--mj-text-secondary);\n line-height: 1.45;\n }\n `]\n})\nexport class MJConfirmDialogComponent {\n /** Whether the dialog is shown. Two-way bindable: `[(Visible)]`. */\n @Input() Visible = false;\n /** Two-way `Visible` change channel — fires when the dialog auto-closes on cancel. */\n @Output() VisibleChange = new EventEmitter<boolean>();\n\n /** Heading shown in the dialog title bar. */\n @Input() Title = 'Confirm';\n\n /** Primary prompt text. For rich content, project default `<ng-content>` instead. */\n @Input() Message = 'Are you sure?';\n\n /** Optional secondary line, rendered smaller/muted beneath the message. */\n @Input() DetailMessage = '';\n\n /** Visual intent — drives the header icon + confirm button color. Defaults to 'default'. */\n @Input() Type: MJConfirmDialogType = 'default';\n\n /** Affirmative button label. */\n @Input() ConfirmText = 'Confirm';\n\n /** Dismiss button label. */\n @Input() CancelText = 'Cancel';\n\n /**\n * Font Awesome icon class (e.g. \"fa-solid fa-trash\") for the header. When\n * omitted, a sensible default is chosen from `Type`. Set to `''` for no icon.\n */\n @Input() Icon: string | null = null;\n\n /**\n * When true, shows a spinner on the confirm button, disables both buttons, and\n * blocks dismissal (Esc / backdrop / ✕) — bind this to your loading flag while\n * the `Confirmed` handler runs async work.\n */\n @Input({ transform: booleanAttribute }) Processing = false;\n\n /** Fired when the user confirms. The dialog stays open; close it when ready. */\n @Output() Confirmed = new EventEmitter<void>();\n\n /** Fired when the user cancels (button, backdrop, Esc, or ✕). The dialog auto-closes. */\n @Output() Cancelled = new EventEmitter<void>();\n\n /** mjButton variant for the confirm button — red for `danger`, blue otherwise. */\n get ConfirmVariant(): 'primary' | 'danger' {\n return this.Type === 'danger' ? 'danger' : 'primary';\n }\n\n /**\n * Icon actually rendered: the explicit `Icon` when provided (including `\"\"`\n * to suppress it), otherwise the per-type default.\n */\n get ResolvedIcon(): string {\n if (this.Icon != null) {\n return this.Icon;\n }\n return DEFAULT_ICONS[this.Type] ?? DEFAULT_ICONS.default;\n }\n\n onConfirm(): void {\n this.Confirmed.emit();\n }\n\n onCancel(): void {\n this.close();\n this.Cancelled.emit();\n }\n\n /** Backdrop / Esc / ✕ from the underlying dialog — ignored while Processing. */\n onDismiss(): void {\n if (this.Processing) {\n return;\n }\n this.onCancel();\n }\n\n private close(): void {\n this.Visible = false;\n this.VisibleChange.emit(false);\n }\n}\n"]}
@@ -0,0 +1,78 @@
1
+ import { MJConfirmDialogType } from './confirm-dialog.component';
2
+ import * as i0 from "@angular/core";
3
+ /**
4
+ * Options for {@link MJConfirmService.Confirm}. Mirror the `<mj-confirm-dialog>`
5
+ * inputs, but in a flat options bag suited to an imperative call.
6
+ */
7
+ export interface MJConfirmOptions {
8
+ /** Primary prompt text. */
9
+ message: string;
10
+ /** Title-bar heading. Defaults to 'Confirm'. */
11
+ title?: string;
12
+ /** Optional secondary line, rendered smaller/muted beneath the message. */
13
+ detail?: string;
14
+ /** Visual intent — drives the header icon + confirm button color. Defaults to 'default'. */
15
+ type?: MJConfirmDialogType;
16
+ /** Affirmative button label. Defaults to 'Confirm'. */
17
+ confirmText?: string;
18
+ /** Dismiss button label. Defaults to 'Cancel'. */
19
+ cancelText?: string;
20
+ /** Font Awesome icon override (e.g. "fa-solid fa-trash"). `''` suppresses the icon. */
21
+ icon?: string;
22
+ }
23
+ /**
24
+ * MJConfirmService — Imperative, Promise-based confirmation prompts.
25
+ *
26
+ * The one-liner replacement for native `window.confirm()` (an anti-pattern this
27
+ * codebase bans) and for the boilerplate of wiring `<mj-confirm-dialog>` into a
28
+ * template just to ask a yes/no question. It dynamically mounts an
29
+ * `MJConfirmDialogComponent` to `document.body`, shows it, and resolves a
30
+ * `Promise<boolean>` — `true` on confirm, `false` on cancel/backdrop/Esc — then
31
+ * tears the component down.
32
+ *
33
+ * @example
34
+ * ```typescript
35
+ * private confirm = inject(MJConfirmService);
36
+ *
37
+ * // Simplest — replaces `if (window.confirm('Discard changes?')) { ... }`
38
+ * if (await this.confirm.Confirm('Discard unsaved changes?')) {
39
+ * this.discard();
40
+ * }
41
+ *
42
+ * // Destructive delete with a detail line
43
+ * if (await this.confirm.ConfirmDelete({
44
+ * message: 'Delete this user?',
45
+ * detail: 'This action cannot be undone.',
46
+ * })) {
47
+ * await this.deleteUser();
48
+ * }
49
+ * ```
50
+ *
51
+ * **Async work after confirm:** because this resolves a boolean, the dialog has
52
+ * already closed by the time your `await` continues — there's no in-dialog
53
+ * spinner. When you need a "keep open + spinner while I save" UX, use the
54
+ * `<mj-confirm-dialog>` component directly with its `Processing` input instead.
55
+ *
56
+ * **Synchronous guards:** `window.confirm` blocks the thread; a synchronous
57
+ * `CanClose`/`beforeunload` guard that must return a boolean *immediately*
58
+ * cannot use this async service. Those rare cases stay on `window.confirm` as a
59
+ * documented exception.
60
+ */
61
+ export declare class MJConfirmService {
62
+ private appRef;
63
+ /**
64
+ * Ask the user to confirm. Pass a bare string for the simplest case, or an
65
+ * options bag for control over title/type/labels/detail.
66
+ * @returns a Promise resolving `true` if confirmed, `false` otherwise.
67
+ */
68
+ Confirm(options: MJConfirmOptions | string): Promise<boolean>;
69
+ /**
70
+ * Convenience for destructive deletes — `type: 'danger'` and a 'Delete'
71
+ * confirm label by default (both overridable via `options`).
72
+ */
73
+ ConfirmDelete(options: Omit<MJConfirmOptions, 'type'>): Promise<boolean>;
74
+ private applyInputs;
75
+ static ɵfac: i0.ɵɵFactoryDeclaration<MJConfirmService, never>;
76
+ static ɵprov: i0.ɵɵInjectableDeclaration<MJConfirmService>;
77
+ }
78
+ //# sourceMappingURL=confirm-dialog.service.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"confirm-dialog.service.d.ts","sourceRoot":"","sources":["../../../src/lib/confirm-dialog/confirm-dialog.service.ts"],"names":[],"mappings":"AACA,OAAO,EAA4B,mBAAmB,EAAE,MAAM,4BAA4B,CAAC;;AAE3F;;;GAGG;AACH,MAAM,WAAW,gBAAgB;IAC/B,2BAA2B;IAC3B,OAAO,EAAE,MAAM,CAAC;IAChB,gDAAgD;IAChD,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,2EAA2E;IAC3E,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,4FAA4F;IAC5F,IAAI,CAAC,EAAE,mBAAmB,CAAC;IAC3B,uDAAuD;IACvD,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,kDAAkD;IAClD,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,uFAAuF;IACvF,IAAI,CAAC,EAAE,MAAM,CAAC;CACf;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAqCG;AACH,qBACa,gBAAgB;IAC3B,OAAO,CAAC,MAAM,CAA0B;IAExC;;;;OAIG;IACH,OAAO,CAAC,OAAO,EAAE,gBAAgB,GAAG,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;IA6C7D;;;OAGG;IACH,aAAa,CAAC,OAAO,EAAE,IAAI,CAAC,gBAAgB,EAAE,MAAM,CAAC,GAAG,OAAO,CAAC,OAAO,CAAC;IAIxE,OAAO,CAAC,WAAW;yCA7DR,gBAAgB;6CAAhB,gBAAgB;CAmF5B"}
@@ -0,0 +1,125 @@
1
+ import { ApplicationRef, Injectable, createComponent, inject } from '@angular/core';
2
+ import { MJConfirmDialogComponent } from './confirm-dialog.component';
3
+ import * as i0 from "@angular/core";
4
+ /**
5
+ * MJConfirmService — Imperative, Promise-based confirmation prompts.
6
+ *
7
+ * The one-liner replacement for native `window.confirm()` (an anti-pattern this
8
+ * codebase bans) and for the boilerplate of wiring `<mj-confirm-dialog>` into a
9
+ * template just to ask a yes/no question. It dynamically mounts an
10
+ * `MJConfirmDialogComponent` to `document.body`, shows it, and resolves a
11
+ * `Promise<boolean>` — `true` on confirm, `false` on cancel/backdrop/Esc — then
12
+ * tears the component down.
13
+ *
14
+ * @example
15
+ * ```typescript
16
+ * private confirm = inject(MJConfirmService);
17
+ *
18
+ * // Simplest — replaces `if (window.confirm('Discard changes?')) { ... }`
19
+ * if (await this.confirm.Confirm('Discard unsaved changes?')) {
20
+ * this.discard();
21
+ * }
22
+ *
23
+ * // Destructive delete with a detail line
24
+ * if (await this.confirm.ConfirmDelete({
25
+ * message: 'Delete this user?',
26
+ * detail: 'This action cannot be undone.',
27
+ * })) {
28
+ * await this.deleteUser();
29
+ * }
30
+ * ```
31
+ *
32
+ * **Async work after confirm:** because this resolves a boolean, the dialog has
33
+ * already closed by the time your `await` continues — there's no in-dialog
34
+ * spinner. When you need a "keep open + spinner while I save" UX, use the
35
+ * `<mj-confirm-dialog>` component directly with its `Processing` input instead.
36
+ *
37
+ * **Synchronous guards:** `window.confirm` blocks the thread; a synchronous
38
+ * `CanClose`/`beforeunload` guard that must return a boolean *immediately*
39
+ * cannot use this async service. Those rare cases stay on `window.confirm` as a
40
+ * documented exception.
41
+ */
42
+ export class MJConfirmService {
43
+ appRef = inject(ApplicationRef);
44
+ /**
45
+ * Ask the user to confirm. Pass a bare string for the simplest case, or an
46
+ * options bag for control over title/type/labels/detail.
47
+ * @returns a Promise resolving `true` if confirmed, `false` otherwise.
48
+ */
49
+ Confirm(options) {
50
+ const opts = typeof options === 'string' ? { message: options } : options;
51
+ return new Promise((resolve) => {
52
+ const ref = createComponent(MJConfirmDialogComponent, {
53
+ environmentInjector: this.appRef.injector,
54
+ });
55
+ this.applyInputs(ref, opts);
56
+ // An imperative confirm must layer above whatever surface launched it —
57
+ // bespoke drawers/panels go up to ~1101 and mj-window sits at 10000,
58
+ // all above the shared mj-dialog backdrop (1000). Without this, a
59
+ // confirm opened from such an overlay renders UNDER its backdrop:
60
+ // unclickable, and each swallowed click can re-trigger the caller and
61
+ // stack another dialog. position:relative + z-index forms a stacking
62
+ // context on the host that lifts the fixed backdrop/dialog inside it
63
+ // to this level (20000 — above mj-window, below toasts at 100000)
64
+ // without touching the fixed element's viewport-relative geometry.
65
+ const host = ref.location.nativeElement;
66
+ host.style.position = 'relative';
67
+ host.style.zIndex = '20000';
68
+ document.body.appendChild(host);
69
+ this.appRef.attachView(ref.hostView);
70
+ let settled = false;
71
+ const finish = (result) => {
72
+ if (settled) {
73
+ return;
74
+ }
75
+ settled = true;
76
+ confirmedSub.unsubscribe();
77
+ cancelledSub.unsubscribe();
78
+ this.appRef.detachView(ref.hostView);
79
+ ref.location.nativeElement.remove();
80
+ ref.destroy();
81
+ resolve(result);
82
+ };
83
+ const confirmedSub = ref.instance.Confirmed.subscribe(() => finish(true));
84
+ const cancelledSub = ref.instance.Cancelled.subscribe(() => finish(false));
85
+ ref.instance.Visible = true;
86
+ ref.changeDetectorRef.detectChanges();
87
+ });
88
+ }
89
+ /**
90
+ * Convenience for destructive deletes — `type: 'danger'` and a 'Delete'
91
+ * confirm label by default (both overridable via `options`).
92
+ */
93
+ ConfirmDelete(options) {
94
+ return this.Confirm({ confirmText: 'Delete', ...options, type: 'danger' });
95
+ }
96
+ applyInputs(ref, opts) {
97
+ const i = ref.instance;
98
+ i.Message = opts.message;
99
+ if (opts.title != null) {
100
+ i.Title = opts.title;
101
+ }
102
+ if (opts.detail != null) {
103
+ i.DetailMessage = opts.detail;
104
+ }
105
+ if (opts.type != null) {
106
+ i.Type = opts.type;
107
+ }
108
+ if (opts.confirmText != null) {
109
+ i.ConfirmText = opts.confirmText;
110
+ }
111
+ if (opts.cancelText != null) {
112
+ i.CancelText = opts.cancelText;
113
+ }
114
+ if (opts.icon != null) {
115
+ i.Icon = opts.icon;
116
+ }
117
+ }
118
+ static ɵfac = function MJConfirmService_Factory(__ngFactoryType__) { return new (__ngFactoryType__ || MJConfirmService)(); };
119
+ static ɵprov = /*@__PURE__*/ i0.ɵɵdefineInjectable({ token: MJConfirmService, factory: MJConfirmService.ɵfac, providedIn: 'root' });
120
+ }
121
+ (() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassMetadata(MJConfirmService, [{
122
+ type: Injectable,
123
+ args: [{ providedIn: 'root' }]
124
+ }], null, null); })();
125
+ //# sourceMappingURL=confirm-dialog.service.js.map