@memberjunction/ng-ui-components 5.37.0 → 5.39.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 (39) hide show
  1. package/dist/lib/applied-filters/applied-filters.component.d.ts +55 -0
  2. package/dist/lib/applied-filters/applied-filters.component.d.ts.map +1 -0
  3. package/dist/lib/applied-filters/applied-filters.component.js +128 -0
  4. package/dist/lib/applied-filters/applied-filters.component.js.map +1 -0
  5. package/dist/lib/filter-panel/filter-panel.component.d.ts +14 -0
  6. package/dist/lib/filter-panel/filter-panel.component.d.ts.map +1 -1
  7. package/dist/lib/filter-panel/filter-panel.component.js +30 -5
  8. package/dist/lib/filter-panel/filter-panel.component.js.map +1 -1
  9. package/dist/lib/filter-popover/filter-popover.component.d.ts +14 -2
  10. package/dist/lib/filter-popover/filter-popover.component.d.ts.map +1 -1
  11. package/dist/lib/filter-popover/filter-popover.component.js +153 -52
  12. package/dist/lib/filter-popover/filter-popover.component.js.map +1 -1
  13. package/dist/lib/left-nav/left-nav-content.component.d.ts.map +1 -1
  14. package/dist/lib/left-nav/left-nav-content.component.js +3 -3
  15. package/dist/lib/left-nav/left-nav-content.component.js.map +1 -1
  16. package/dist/lib/left-nav/left-nav.component.d.ts +36 -9
  17. package/dist/lib/left-nav/left-nav.component.d.ts.map +1 -1
  18. package/dist/lib/left-nav/left-nav.component.js +253 -117
  19. package/dist/lib/left-nav/left-nav.component.js.map +1 -1
  20. package/dist/lib/page-body/page-body.component.d.ts.map +1 -1
  21. package/dist/lib/page-body/page-body.component.js +3 -3
  22. package/dist/lib/page-body/page-body.component.js.map +1 -1
  23. package/dist/lib/page-header/page-header.component.js +2 -2
  24. package/dist/lib/page-header/page-header.scss +51 -4
  25. package/dist/lib/page-header-interior/page-header-interior.component.d.ts.map +1 -1
  26. package/dist/lib/page-header-interior/page-header-interior.component.js +3 -3
  27. package/dist/lib/page-header-interior/page-header-interior.component.js.map +1 -1
  28. package/dist/lib/refresh-button/refresh-button.component.d.ts.map +1 -1
  29. package/dist/lib/refresh-button/refresh-button.component.js +13 -10
  30. package/dist/lib/refresh-button/refresh-button.component.js.map +1 -1
  31. package/dist/lib/slide-panel/slide-panel.component.d.ts +64 -0
  32. package/dist/lib/slide-panel/slide-panel.component.d.ts.map +1 -0
  33. package/dist/lib/slide-panel/slide-panel.component.js +256 -0
  34. package/dist/lib/slide-panel/slide-panel.component.js.map +1 -0
  35. package/dist/public-api.d.ts +1 -0
  36. package/dist/public-api.d.ts.map +1 -1
  37. package/dist/public-api.js +1 -0
  38. package/dist/public-api.js.map +1 -1
  39. package/package.json +1 -1
@@ -0,0 +1,64 @@
1
+ import { EventEmitter, OnInit, OnDestroy, ChangeDetectorRef, ElementRef, NgZone } from '@angular/core';
2
+ import * as i0 from "@angular/core";
3
+ /** Display mode for the slide panel container. */
4
+ export type SlidePanelMode = 'slide' | 'dialog';
5
+ /**
6
+ * Generic slide-in / centered-dialog panel primitive.
7
+ *
8
+ * - `Mode='slide'` → slides in from the right edge, full viewport height, optionally resizable.
9
+ * - `Mode='dialog'` → centered modal card.
10
+ *
11
+ * Pure chrome: it owns the backdrop, open/close animation, resize handle, optional
12
+ * title bar, and content projection. It performs no data work and has no routing.
13
+ * Consumers project their content and handle Save/close via the projected UI and the
14
+ * `Closed` output.
15
+ *
16
+ * @example
17
+ * ```html
18
+ * <mj-slide-panel [Visible]="open" Title="Details" (Closed)="open = false">
19
+ * <my-content></my-content>
20
+ * </mj-slide-panel>
21
+ * ```
22
+ */
23
+ export declare class MjSlidePanelComponent implements OnInit, OnDestroy {
24
+ private cdr;
25
+ private ngZone;
26
+ private elRef;
27
+ Mode: SlidePanelMode;
28
+ Title: string;
29
+ set Visible(value: boolean);
30
+ get Visible(): boolean;
31
+ private _visible;
32
+ private initialized;
33
+ Resizable: boolean;
34
+ MinWidthPx: number;
35
+ MaxWidthRatio: number;
36
+ /** Initial width in pixels. Defaults to 65% of viewport for slide, 800px for dialog. */
37
+ set WidthPx(value: number);
38
+ get WidthPx(): number;
39
+ Closed: EventEmitter<void>;
40
+ WidthChanged: EventEmitter<number>;
41
+ /**
42
+ * Optional guard called before any close gesture (X button, backdrop click, Escape).
43
+ * Return `false` to cancel the close — e.g., when an in-progress operation is running.
44
+ * The panel itself never shows a dialog; the consumer is responsible for any confirmation UI.
45
+ */
46
+ CanClose: (() => boolean) | null;
47
+ IsVisible: boolean;
48
+ private _widthPx;
49
+ private isResizing;
50
+ private boundOnResizeMove;
51
+ private boundOnResizeEnd;
52
+ constructor(cdr: ChangeDetectorRef, ngZone: NgZone, elRef: ElementRef);
53
+ ngOnInit(): void;
54
+ ngOnDestroy(): void;
55
+ OnEscapeKey(): void;
56
+ OnClose(): void;
57
+ OnBackdropClick(): void;
58
+ OnResizeStart(event: MouseEvent): void;
59
+ private onResizeMove;
60
+ private onResizeEnd;
61
+ static ɵfac: i0.ɵɵFactoryDeclaration<MjSlidePanelComponent, never>;
62
+ static ɵcmp: i0.ɵɵComponentDeclaration<MjSlidePanelComponent, "mj-slide-panel", never, { "Mode": { "alias": "Mode"; "required": false; }; "Title": { "alias": "Title"; "required": false; }; "Visible": { "alias": "Visible"; "required": false; }; "Resizable": { "alias": "Resizable"; "required": false; }; "MinWidthPx": { "alias": "MinWidthPx"; "required": false; }; "MaxWidthRatio": { "alias": "MaxWidthRatio"; "required": false; }; "WidthPx": { "alias": "WidthPx"; "required": false; }; "CanClose": { "alias": "CanClose"; "required": false; }; }, { "Closed": "Closed"; "WidthChanged": "WidthChanged"; }, never, ["*", "[dialog-content]"], true, never>;
63
+ }
64
+ //# sourceMappingURL=slide-panel.component.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"slide-panel.component.d.ts","sourceRoot":"","sources":["../../../src/lib/slide-panel/slide-panel.component.ts"],"names":[],"mappings":"AAAA,OAAO,EACqB,YAAY,EAAE,MAAM,EAAE,SAAS,EACzD,iBAAiB,EAAyC,UAAU,EAAE,MAAM,EAC7E,MAAM,eAAe,CAAC;;AAEvB,kDAAkD;AAClD,MAAM,MAAM,cAAc,GAAG,OAAO,GAAG,QAAQ,CAAC;AAEhD;;;;;;;;;;;;;;;;;GAiBG;AACH,qBAOa,qBAAsB,YAAW,MAAM,EAAE,SAAS;IAyD3D,OAAO,CAAC,GAAG;IACX,OAAO,CAAC,MAAM;IACd,OAAO,CAAC,KAAK;IA1DN,IAAI,EAAE,cAAc,CAAW;IAC/B,KAAK,SAAM;IACpB,IACI,OAAO,CAAC,KAAK,EAAE,OAAO,EAezB;IACD,IAAI,OAAO,IAAI,OAAO,CAErB;IACD,OAAO,CAAC,QAAQ,CAAQ;IACxB,OAAO,CAAC,WAAW,CAAS;IAEnB,SAAS,UAAQ;IACjB,UAAU,SAAO;IACjB,aAAa,SAAQ;IAE9B,wFAAwF;IACxF,IACI,OAAO,CAAC,KAAK,EAAE,MAAM,EAExB;IACD,IAAI,OAAO,IAAI,MAAM,CAEpB;IAES,MAAM,qBAA4B;IAClC,YAAY,uBAA8B;IAEpD;;;;OAIG;IACM,QAAQ,EAAE,CAAC,MAAM,OAAO,CAAC,GAAG,IAAI,CAAQ;IAE1C,SAAS,UAAS;IACzB,OAAO,CAAC,QAAQ,CAAK;IACrB,OAAO,CAAC,UAAU,CAAS;IAE3B,OAAO,CAAC,iBAAiB,CAAgC;IACzD,OAAO,CAAC,gBAAgB,CAA+B;gBAG7C,GAAG,EAAE,iBAAiB,EACtB,MAAM,EAAE,MAAM,EACd,KAAK,EAAE,UAAU;IAG3B,QAAQ,IAAI,IAAI;IAkBhB,WAAW,IAAI,IAAI;IAMZ,WAAW,IAAI,IAAI;IAInB,OAAO,IAAI,IAAI;IASf,eAAe,IAAI,IAAI;IAQvB,aAAa,CAAC,KAAK,EAAE,UAAU,GAAG,IAAI;IAa7C,OAAO,CAAC,YAAY;IAQpB,OAAO,CAAC,WAAW;yCAhIR,qBAAqB;2CAArB,qBAAqB;CAyIjC"}
@@ -0,0 +1,256 @@
1
+ import { Component, Input, Output, EventEmitter, ChangeDetectionStrategy, HostListener } from '@angular/core';
2
+ import * as i0 from "@angular/core";
3
+ const _c0 = ["*", [["", "dialog-content", ""]]];
4
+ const _c1 = ["*", "[dialog-content]"];
5
+ function MjSlidePanelComponent_Conditional_1_Conditional_1_Template(rf, ctx) { if (rf & 1) {
6
+ const _r1 = i0.ɵɵgetCurrentView();
7
+ i0.ɵɵdomElementStart(0, "div", 7);
8
+ i0.ɵɵdomListener("mousedown", function MjSlidePanelComponent_Conditional_1_Conditional_1_Template_div_mousedown_0_listener($event) { i0.ɵɵrestoreView(_r1); const ctx_r1 = i0.ɵɵnextContext(2); return i0.ɵɵresetView(ctx_r1.OnResizeStart($event)); });
9
+ i0.ɵɵdomElement(1, "div", 8);
10
+ i0.ɵɵdomElementEnd();
11
+ } }
12
+ function MjSlidePanelComponent_Conditional_1_Conditional_2_Template(rf, ctx) { if (rf & 1) {
13
+ const _r3 = i0.ɵɵgetCurrentView();
14
+ i0.ɵɵdomElementStart(0, "div", 5)(1, "h2", 9);
15
+ i0.ɵɵtext(2);
16
+ i0.ɵɵdomElementEnd();
17
+ i0.ɵɵdomElementStart(3, "button", 10);
18
+ i0.ɵɵdomListener("click", function MjSlidePanelComponent_Conditional_1_Conditional_2_Template_button_click_3_listener() { i0.ɵɵrestoreView(_r3); const ctx_r1 = i0.ɵɵnextContext(2); return i0.ɵɵresetView(ctx_r1.OnClose()); });
19
+ i0.ɵɵdomElement(4, "i", 11);
20
+ i0.ɵɵdomElementEnd()();
21
+ } if (rf & 2) {
22
+ const ctx_r1 = i0.ɵɵnextContext(2);
23
+ i0.ɵɵadvance(2);
24
+ i0.ɵɵtextInterpolate(ctx_r1.Title);
25
+ } }
26
+ function MjSlidePanelComponent_Conditional_1_Template(rf, ctx) { if (rf & 1) {
27
+ i0.ɵɵdomElementStart(0, "div", 3);
28
+ i0.ɵɵconditionalCreate(1, MjSlidePanelComponent_Conditional_1_Conditional_1_Template, 2, 0, "div", 4);
29
+ i0.ɵɵconditionalCreate(2, MjSlidePanelComponent_Conditional_1_Conditional_2_Template, 5, 1, "div", 5);
30
+ i0.ɵɵdomElementStart(3, "div", 6);
31
+ i0.ɵɵprojection(4);
32
+ i0.ɵɵdomElementEnd()();
33
+ } if (rf & 2) {
34
+ const ctx_r1 = i0.ɵɵnextContext();
35
+ i0.ɵɵstyleProp("width", ctx_r1.WidthPx, "px")("max-width", ctx_r1.MaxWidthRatio * 100 + "vw");
36
+ i0.ɵɵclassProp("visible", ctx_r1.IsVisible);
37
+ i0.ɵɵadvance();
38
+ i0.ɵɵconditional(ctx_r1.Resizable ? 1 : -1);
39
+ i0.ɵɵadvance();
40
+ i0.ɵɵconditional(ctx_r1.Title ? 2 : -1);
41
+ } }
42
+ function MjSlidePanelComponent_Conditional_2_Conditional_1_Template(rf, ctx) { if (rf & 1) {
43
+ const _r4 = i0.ɵɵgetCurrentView();
44
+ i0.ɵɵdomElementStart(0, "div", 5)(1, "h2", 9);
45
+ i0.ɵɵtext(2);
46
+ i0.ɵɵdomElementEnd();
47
+ i0.ɵɵdomElementStart(3, "button", 10);
48
+ i0.ɵɵdomListener("click", function MjSlidePanelComponent_Conditional_2_Conditional_1_Template_button_click_3_listener() { i0.ɵɵrestoreView(_r4); const ctx_r1 = i0.ɵɵnextContext(2); return i0.ɵɵresetView(ctx_r1.OnClose()); });
49
+ i0.ɵɵdomElement(4, "i", 11);
50
+ i0.ɵɵdomElementEnd()();
51
+ } if (rf & 2) {
52
+ const ctx_r1 = i0.ɵɵnextContext(2);
53
+ i0.ɵɵadvance(2);
54
+ i0.ɵɵtextInterpolate(ctx_r1.Title);
55
+ } }
56
+ function MjSlidePanelComponent_Conditional_2_Template(rf, ctx) { if (rf & 1) {
57
+ i0.ɵɵdomElementStart(0, "div", 12);
58
+ i0.ɵɵconditionalCreate(1, MjSlidePanelComponent_Conditional_2_Conditional_1_Template, 5, 1, "div", 5);
59
+ i0.ɵɵdomElementStart(2, "div", 13);
60
+ i0.ɵɵprojection(3, 1);
61
+ i0.ɵɵdomElementEnd()();
62
+ } if (rf & 2) {
63
+ const ctx_r1 = i0.ɵɵnextContext();
64
+ i0.ɵɵstyleProp("width", ctx_r1.WidthPx, "px");
65
+ i0.ɵɵclassProp("visible", ctx_r1.IsVisible);
66
+ i0.ɵɵadvance();
67
+ i0.ɵɵconditional(ctx_r1.Title ? 1 : -1);
68
+ } }
69
+ /**
70
+ * Generic slide-in / centered-dialog panel primitive.
71
+ *
72
+ * - `Mode='slide'` → slides in from the right edge, full viewport height, optionally resizable.
73
+ * - `Mode='dialog'` → centered modal card.
74
+ *
75
+ * Pure chrome: it owns the backdrop, open/close animation, resize handle, optional
76
+ * title bar, and content projection. It performs no data work and has no routing.
77
+ * Consumers project their content and handle Save/close via the projected UI and the
78
+ * `Closed` output.
79
+ *
80
+ * @example
81
+ * ```html
82
+ * <mj-slide-panel [Visible]="open" Title="Details" (Closed)="open = false">
83
+ * <my-content></my-content>
84
+ * </mj-slide-panel>
85
+ * ```
86
+ */
87
+ export class MjSlidePanelComponent {
88
+ cdr;
89
+ ngZone;
90
+ elRef;
91
+ Mode = 'slide';
92
+ Title = '';
93
+ set Visible(value) {
94
+ const changed = this._visible !== value;
95
+ this._visible = value;
96
+ if (changed && this.initialized) {
97
+ if (value) {
98
+ // Opening: animate in on next microtask
99
+ Promise.resolve().then(() => {
100
+ this.IsVisible = true;
101
+ this.cdr.markForCheck();
102
+ });
103
+ }
104
+ else {
105
+ this.IsVisible = false;
106
+ this.cdr.markForCheck();
107
+ }
108
+ }
109
+ }
110
+ get Visible() {
111
+ return this._visible;
112
+ }
113
+ _visible = true;
114
+ initialized = false;
115
+ Resizable = true;
116
+ MinWidthPx = 400;
117
+ MaxWidthRatio = 0.92;
118
+ /** Initial width in pixels. Defaults to 65% of viewport for slide, 800px for dialog. */
119
+ set WidthPx(value) {
120
+ this._widthPx = value;
121
+ }
122
+ get WidthPx() {
123
+ return this._widthPx;
124
+ }
125
+ Closed = new EventEmitter();
126
+ WidthChanged = new EventEmitter();
127
+ /**
128
+ * Optional guard called before any close gesture (X button, backdrop click, Escape).
129
+ * Return `false` to cancel the close — e.g., when an in-progress operation is running.
130
+ * The panel itself never shows a dialog; the consumer is responsible for any confirmation UI.
131
+ */
132
+ CanClose = null;
133
+ IsVisible = false;
134
+ _widthPx = 0;
135
+ isResizing = false;
136
+ boundOnResizeMove = this.onResizeMove.bind(this);
137
+ boundOnResizeEnd = this.onResizeEnd.bind(this);
138
+ constructor(cdr, ngZone, elRef) {
139
+ this.cdr = cdr;
140
+ this.ngZone = ngZone;
141
+ this.elRef = elRef;
142
+ }
143
+ ngOnInit() {
144
+ if (this._widthPx === 0) {
145
+ this._widthPx = this.Mode === 'dialog'
146
+ ? 800
147
+ : Math.max(this.MinWidthPx, Math.min(window.innerWidth * 0.65, 1000));
148
+ }
149
+ this.initialized = true;
150
+ // Animate in on next microtask if initially visible
151
+ if (this._visible) {
152
+ Promise.resolve().then(() => {
153
+ this.IsVisible = true;
154
+ this.cdr.markForCheck();
155
+ });
156
+ }
157
+ }
158
+ ngOnDestroy() {
159
+ document.removeEventListener('mousemove', this.boundOnResizeMove);
160
+ document.removeEventListener('mouseup', this.boundOnResizeEnd);
161
+ }
162
+ OnEscapeKey() {
163
+ this.OnClose();
164
+ }
165
+ OnClose() {
166
+ if (this.CanClose && !this.CanClose())
167
+ return;
168
+ this.IsVisible = false;
169
+ this._visible = false;
170
+ this.cdr.markForCheck();
171
+ // Wait for CSS transition to complete
172
+ setTimeout(() => this.Closed.emit(), 300);
173
+ }
174
+ OnBackdropClick() {
175
+ this.OnClose();
176
+ }
177
+ // =========================================================================
178
+ // Resize
179
+ // =========================================================================
180
+ OnResizeStart(event) {
181
+ if (!this.Resizable || this.Mode === 'dialog')
182
+ return;
183
+ event.preventDefault();
184
+ this.isResizing = true;
185
+ document.body.style.cursor = 'col-resize';
186
+ document.body.style.userSelect = 'none';
187
+ this.ngZone.runOutsideAngular(() => {
188
+ document.addEventListener('mousemove', this.boundOnResizeMove);
189
+ document.addEventListener('mouseup', this.boundOnResizeEnd);
190
+ });
191
+ }
192
+ onResizeMove(event) {
193
+ if (!this.isResizing)
194
+ return;
195
+ const viewportWidth = window.innerWidth;
196
+ const maxWidth = viewportWidth * this.MaxWidthRatio;
197
+ this._widthPx = Math.max(this.MinWidthPx, Math.min(maxWidth, viewportWidth - event.clientX));
198
+ this.ngZone.run(() => this.cdr.markForCheck());
199
+ }
200
+ onResizeEnd() {
201
+ if (!this.isResizing)
202
+ return;
203
+ this.isResizing = false;
204
+ document.body.style.cursor = '';
205
+ document.body.style.userSelect = '';
206
+ document.removeEventListener('mousemove', this.boundOnResizeMove);
207
+ document.removeEventListener('mouseup', this.boundOnResizeEnd);
208
+ this.WidthChanged.emit(this._widthPx);
209
+ }
210
+ static ɵfac = function MjSlidePanelComponent_Factory(__ngFactoryType__) { return new (__ngFactoryType__ || MjSlidePanelComponent)(i0.ɵɵdirectiveInject(i0.ChangeDetectorRef), i0.ɵɵdirectiveInject(i0.NgZone), i0.ɵɵdirectiveInject(i0.ElementRef)); };
211
+ static ɵcmp = /*@__PURE__*/ i0.ɵɵdefineComponent({ type: MjSlidePanelComponent, selectors: [["mj-slide-panel"]], hostBindings: function MjSlidePanelComponent_HostBindings(rf, ctx) { if (rf & 1) {
212
+ i0.ɵɵlistener("keydown.escape", function MjSlidePanelComponent_keydown_escape_HostBindingHandler() { return ctx.OnEscapeKey(); }, i0.ɵɵresolveDocument);
213
+ } }, inputs: { Mode: "Mode", Title: "Title", Visible: "Visible", Resizable: "Resizable", MinWidthPx: "MinWidthPx", MaxWidthRatio: "MaxWidthRatio", WidthPx: "WidthPx", CanClose: "CanClose" }, outputs: { Closed: "Closed", WidthChanged: "WidthChanged" }, ngContentSelectors: _c1, decls: 3, vars: 6, consts: [[1, "sp-backdrop", 3, "click"], [1, "sp-panel", 3, "visible", "width", "max-width"], [1, "sp-dialog", 3, "visible", "width"], [1, "sp-panel"], [1, "sp-resize-handle"], [1, "sp-header"], [1, "sp-body"], [1, "sp-resize-handle", 3, "mousedown"], [1, "sp-resize-grip"], [1, "sp-title"], [1, "sp-close-btn", 3, "click"], [1, "fa-solid", "fa-xmark"], [1, "sp-dialog"], [1, "sp-body", "sp-dialog-body"]], template: function MjSlidePanelComponent_Template(rf, ctx) { if (rf & 1) {
214
+ i0.ɵɵprojectionDef(_c0);
215
+ i0.ɵɵdomElementStart(0, "div", 0);
216
+ i0.ɵɵdomListener("click", function MjSlidePanelComponent_Template_div_click_0_listener() { return ctx.OnBackdropClick(); });
217
+ i0.ɵɵdomElementEnd();
218
+ i0.ɵɵconditionalCreate(1, MjSlidePanelComponent_Conditional_1_Template, 5, 8, "div", 1);
219
+ i0.ɵɵconditionalCreate(2, MjSlidePanelComponent_Conditional_2_Template, 4, 5, "div", 2);
220
+ } if (rf & 2) {
221
+ i0.ɵɵclassProp("visible", ctx.IsVisible)("sp-dialog-backdrop", ctx.Mode === "dialog");
222
+ i0.ɵɵadvance();
223
+ i0.ɵɵconditional(ctx.Mode === "slide" ? 1 : -1);
224
+ i0.ɵɵadvance();
225
+ i0.ɵɵconditional(ctx.Mode === "dialog" ? 2 : -1);
226
+ } }, styles: ["\n\n\n\n\n\n\n.sp-backdrop[_ngcontent-%COMP%] {\n position: fixed;\n inset: 0;\n background: transparent;\n z-index: 1000;\n transition: background 0.3s ease;\n pointer-events: none;\n}\n\n.sp-backdrop.visible[_ngcontent-%COMP%] {\n background: var(--mj-bg-overlay);\n pointer-events: auto;\n}\n\n.sp-dialog-backdrop.visible[_ngcontent-%COMP%] {\n background: var(--mj-bg-overlay);\n}\n\n\n\n\n\n\n\n\n.sp-panel[_ngcontent-%COMP%] {\n position: fixed;\n top: 0;\n right: 0;\n height: 100vh;\n background: var(--mj-bg-surface);\n box-shadow: var(--mj-shadow-lg);\n z-index: 1001;\n display: flex;\n flex-direction: column;\n transform: translateX(100%);\n transition: transform 0.3s cubic-bezier(0.16, 1, 0.3, 1);\n min-width: 400px;\n max-width: 92vw;\n}\n\n.sp-panel.visible[_ngcontent-%COMP%] {\n transform: translateX(0);\n}\n\n\n\n\n\n\n\n\n.sp-dialog[_ngcontent-%COMP%] {\n position: fixed;\n top: 50%;\n left: 50%;\n transform: translate(-50%, -50%) scale(0.95);\n max-height: 85vh;\n background: var(--mj-bg-surface);\n border-radius: 16px;\n box-shadow: var(--mj-shadow-lg);\n z-index: 1001;\n display: flex;\n flex-direction: column;\n opacity: 0;\n transition: opacity 0.25s ease, transform 0.25s cubic-bezier(0.16, 1, 0.3, 1);\n min-width: 360px;\n max-width: 95vw;\n}\n\n.sp-dialog.visible[_ngcontent-%COMP%] {\n opacity: 1;\n transform: translate(-50%, -50%) scale(1);\n}\n\n\n\n\n\n\n\n\n.sp-resize-handle[_ngcontent-%COMP%] {\n position: absolute;\n left: -4px;\n top: 0;\n width: 8px;\n height: 100%;\n cursor: col-resize;\n z-index: 10;\n display: flex;\n align-items: center;\n justify-content: center;\n}\n\n.sp-resize-handle[_ngcontent-%COMP%]:hover .sp-resize-grip[_ngcontent-%COMP%], \n.sp-resize-handle[_ngcontent-%COMP%]:active .sp-resize-grip[_ngcontent-%COMP%] {\n opacity: 1;\n background: var(--mj-brand-primary);\n}\n\n.sp-resize-grip[_ngcontent-%COMP%] {\n width: 3px;\n height: 40px;\n background: var(--mj-border-strong);\n border-radius: 3px;\n opacity: 0;\n transition: opacity 0.2s ease, background 0.2s ease;\n}\n\n.sp-resize-handle[_ngcontent-%COMP%]:hover {\n background: color-mix(in srgb, var(--mj-brand-primary) 4%, transparent);\n}\n\n\n\n\n\n\n\n\n.sp-header[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n justify-content: space-between;\n padding: 16px 24px;\n border-bottom: 1px solid var(--mj-border-default);\n flex-shrink: 0;\n}\n\n.sp-title[_ngcontent-%COMP%] {\n font-size: 18px;\n font-weight: 700;\n color: var(--mj-text-primary);\n margin: 0;\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n flex: 1;\n}\n\n.sp-close-btn[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n justify-content: center;\n width: 36px;\n height: 36px;\n background: none;\n border: none;\n border-radius: 8px;\n color: var(--mj-text-secondary);\n cursor: pointer;\n transition: all 0.15s ease;\n font-size: 16px;\n flex-shrink: 0;\n}\n\n.sp-close-btn[_ngcontent-%COMP%]:hover {\n background: var(--mj-bg-surface-sunken);\n color: var(--mj-text-primary);\n}\n\n\n\n\n\n\n\n\n.sp-body[_ngcontent-%COMP%] {\n flex: 1;\n overflow-y: auto;\n overflow-x: hidden;\n}\n\n.sp-dialog-body[_ngcontent-%COMP%] {\n padding: 0;\n}\n\n\n\n\n\n\n\n\n@media (max-width: 768px) {\n .sp-panel[_ngcontent-%COMP%] {\n width: 100% !important;\n min-width: unset;\n }\n\n .sp-resize-handle[_ngcontent-%COMP%] {\n display: none;\n }\n\n .sp-dialog[_ngcontent-%COMP%] {\n width: 95vw !important;\n max-height: 90vh;\n }\n}"], changeDetection: 0 });
227
+ }
228
+ (() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassMetadata(MjSlidePanelComponent, [{
229
+ type: Component,
230
+ args: [{ standalone: true, selector: 'mj-slide-panel', changeDetection: ChangeDetectionStrategy.OnPush, template: "<!-- Backdrop overlay -->\n<div class=\"sp-backdrop\"\n [class.visible]=\"IsVisible\"\n [class.sp-dialog-backdrop]=\"Mode === 'dialog'\"\n (click)=\"OnBackdropClick()\">\n</div>\n\n<!-- Panel (slide-in from right) -->\n@if (Mode === 'slide') {\n <div\n class=\"sp-panel\"\n [class.visible]=\"IsVisible\"\n [style.width.px]=\"WidthPx\"\n [style.max-width]=\"(MaxWidthRatio * 100) + 'vw'\">\n <!-- Resize handle -->\n @if (Resizable) {\n <div class=\"sp-resize-handle\" (mousedown)=\"OnResizeStart($event)\">\n <div class=\"sp-resize-grip\"></div>\n </div>\n }\n <!-- Header (if Title provided) -->\n @if (Title) {\n <div class=\"sp-header\">\n <h2 class=\"sp-title\">{{Title}}</h2>\n <button class=\"sp-close-btn\" (click)=\"OnClose()\">\n <i class=\"fa-solid fa-xmark\"></i>\n </button>\n </div>\n }\n <!-- Content projection -->\n <div class=\"sp-body\">\n <ng-content></ng-content>\n </div>\n </div>\n}\n\n<!-- Dialog (centered modal) -->\n@if (Mode === 'dialog') {\n <div\n class=\"sp-dialog\"\n [class.visible]=\"IsVisible\"\n [style.width.px]=\"WidthPx\">\n <!-- Header (if Title provided) -->\n @if (Title) {\n <div class=\"sp-header\">\n <h2 class=\"sp-title\">{{Title}}</h2>\n <button class=\"sp-close-btn\" (click)=\"OnClose()\">\n <i class=\"fa-solid fa-xmark\"></i>\n </button>\n </div>\n }\n <!-- Content projection -->\n <div class=\"sp-body sp-dialog-body\">\n <ng-content select=\"[dialog-content]\"></ng-content>\n </div>\n </div>\n}\n", styles: ["/* ================================================================= */\n/* BACKDROP */\n/* ================================================================= */\n\n.sp-backdrop {\n position: fixed;\n inset: 0;\n background: transparent;\n z-index: 1000;\n transition: background 0.3s ease;\n pointer-events: none;\n}\n\n.sp-backdrop.visible {\n background: var(--mj-bg-overlay);\n pointer-events: auto;\n}\n\n.sp-dialog-backdrop.visible {\n background: var(--mj-bg-overlay);\n}\n\n/* ================================================================= */\n/* SLIDE PANEL */\n/* ================================================================= */\n\n.sp-panel {\n position: fixed;\n top: 0;\n right: 0;\n height: 100vh;\n background: var(--mj-bg-surface);\n box-shadow: var(--mj-shadow-lg);\n z-index: 1001;\n display: flex;\n flex-direction: column;\n transform: translateX(100%);\n transition: transform 0.3s cubic-bezier(0.16, 1, 0.3, 1);\n min-width: 400px;\n max-width: 92vw;\n}\n\n.sp-panel.visible {\n transform: translateX(0);\n}\n\n/* ================================================================= */\n/* DIALOG (centered modal) */\n/* ================================================================= */\n\n.sp-dialog {\n position: fixed;\n top: 50%;\n left: 50%;\n transform: translate(-50%, -50%) scale(0.95);\n max-height: 85vh;\n background: var(--mj-bg-surface);\n border-radius: 16px;\n box-shadow: var(--mj-shadow-lg);\n z-index: 1001;\n display: flex;\n flex-direction: column;\n opacity: 0;\n transition: opacity 0.25s ease, transform 0.25s cubic-bezier(0.16, 1, 0.3, 1);\n min-width: 360px;\n max-width: 95vw;\n}\n\n.sp-dialog.visible {\n opacity: 1;\n transform: translate(-50%, -50%) scale(1);\n}\n\n/* ================================================================= */\n/* RESIZE HANDLE */\n/* ================================================================= */\n\n.sp-resize-handle {\n position: absolute;\n left: -4px;\n top: 0;\n width: 8px;\n height: 100%;\n cursor: col-resize;\n z-index: 10;\n display: flex;\n align-items: center;\n justify-content: center;\n}\n\n.sp-resize-handle:hover .sp-resize-grip,\n.sp-resize-handle:active .sp-resize-grip {\n opacity: 1;\n background: var(--mj-brand-primary);\n}\n\n.sp-resize-grip {\n width: 3px;\n height: 40px;\n background: var(--mj-border-strong);\n border-radius: 3px;\n opacity: 0;\n transition: opacity 0.2s ease, background 0.2s ease;\n}\n\n.sp-resize-handle:hover {\n background: color-mix(in srgb, var(--mj-brand-primary) 4%, transparent);\n}\n\n/* ================================================================= */\n/* HEADER */\n/* ================================================================= */\n\n.sp-header {\n display: flex;\n align-items: center;\n justify-content: space-between;\n padding: 16px 24px;\n border-bottom: 1px solid var(--mj-border-default);\n flex-shrink: 0;\n}\n\n.sp-title {\n font-size: 18px;\n font-weight: 700;\n color: var(--mj-text-primary);\n margin: 0;\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n flex: 1;\n}\n\n.sp-close-btn {\n display: flex;\n align-items: center;\n justify-content: center;\n width: 36px;\n height: 36px;\n background: none;\n border: none;\n border-radius: 8px;\n color: var(--mj-text-secondary);\n cursor: pointer;\n transition: all 0.15s ease;\n font-size: 16px;\n flex-shrink: 0;\n}\n\n.sp-close-btn:hover {\n background: var(--mj-bg-surface-sunken);\n color: var(--mj-text-primary);\n}\n\n/* ================================================================= */\n/* BODY */\n/* ================================================================= */\n\n.sp-body {\n flex: 1;\n overflow-y: auto;\n overflow-x: hidden;\n}\n\n.sp-dialog-body {\n padding: 0;\n}\n\n/* ================================================================= */\n/* RESPONSIVE */\n/* ================================================================= */\n\n@media (max-width: 768px) {\n .sp-panel {\n width: 100% !important;\n min-width: unset;\n }\n\n .sp-resize-handle {\n display: none;\n }\n\n .sp-dialog {\n width: 95vw !important;\n max-height: 90vh;\n }\n}\n"] }]
231
+ }], () => [{ type: i0.ChangeDetectorRef }, { type: i0.NgZone }, { type: i0.ElementRef }], { Mode: [{
232
+ type: Input
233
+ }], Title: [{
234
+ type: Input
235
+ }], Visible: [{
236
+ type: Input
237
+ }], Resizable: [{
238
+ type: Input
239
+ }], MinWidthPx: [{
240
+ type: Input
241
+ }], MaxWidthRatio: [{
242
+ type: Input
243
+ }], WidthPx: [{
244
+ type: Input
245
+ }], Closed: [{
246
+ type: Output
247
+ }], WidthChanged: [{
248
+ type: Output
249
+ }], CanClose: [{
250
+ type: Input
251
+ }], OnEscapeKey: [{
252
+ type: HostListener,
253
+ args: ['document:keydown.escape']
254
+ }] }); })();
255
+ (() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassDebugInfo(MjSlidePanelComponent, { className: "MjSlidePanelComponent", filePath: "lib/slide-panel/slide-panel.component.ts", lineNumber: 34 }); })();
256
+ //# sourceMappingURL=slide-panel.component.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"slide-panel.component.js","sourceRoot":"","sources":["../../../src/lib/slide-panel/slide-panel.component.ts","../../../src/lib/slide-panel/slide-panel.component.html"],"names":[],"mappings":"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","sourcesContent":["import {\n Component, Input, Output, EventEmitter, OnInit, OnDestroy,\n ChangeDetectorRef, ChangeDetectionStrategy, HostListener, ElementRef, NgZone\n} from '@angular/core';\n\n/** Display mode for the slide panel container. */\nexport type SlidePanelMode = 'slide' | 'dialog';\n\n/**\n * Generic slide-in / centered-dialog panel primitive.\n *\n * - `Mode='slide'` → slides in from the right edge, full viewport height, optionally resizable.\n * - `Mode='dialog'` → centered modal card.\n *\n * Pure chrome: it owns the backdrop, open/close animation, resize handle, optional\n * title bar, and content projection. It performs no data work and has no routing.\n * Consumers project their content and handle Save/close via the projected UI and the\n * `Closed` output.\n *\n * @example\n * ```html\n * <mj-slide-panel [Visible]=\"open\" Title=\"Details\" (Closed)=\"open = false\">\n * <my-content></my-content>\n * </mj-slide-panel>\n * ```\n */\n@Component({\n standalone: true,\n selector: 'mj-slide-panel',\n templateUrl: './slide-panel.component.html',\n styleUrls: ['./slide-panel.component.css'],\n changeDetection: ChangeDetectionStrategy.OnPush\n})\nexport class MjSlidePanelComponent implements OnInit, OnDestroy {\n @Input() Mode: SlidePanelMode = 'slide';\n @Input() Title = '';\n @Input()\n set Visible(value: boolean) {\n const changed = this._visible !== value;\n this._visible = value;\n if (changed && this.initialized) {\n if (value) {\n // Opening: animate in on next microtask\n Promise.resolve().then(() => {\n this.IsVisible = true;\n this.cdr.markForCheck();\n });\n } else {\n this.IsVisible = false;\n this.cdr.markForCheck();\n }\n }\n }\n get Visible(): boolean {\n return this._visible;\n }\n private _visible = true;\n private initialized = false;\n\n @Input() Resizable = true;\n @Input() MinWidthPx = 400;\n @Input() MaxWidthRatio = 0.92;\n\n /** Initial width in pixels. Defaults to 65% of viewport for slide, 800px for dialog. */\n @Input()\n set WidthPx(value: number) {\n this._widthPx = value;\n }\n get WidthPx(): number {\n return this._widthPx;\n }\n\n @Output() Closed = new EventEmitter<void>();\n @Output() WidthChanged = new EventEmitter<number>();\n\n /**\n * Optional guard called before any close gesture (X button, backdrop click, Escape).\n * Return `false` to cancel the close — e.g., when an in-progress operation is running.\n * The panel itself never shows a dialog; the consumer is responsible for any confirmation UI.\n */\n @Input() CanClose: (() => boolean) | null = null;\n\n public IsVisible = false;\n private _widthPx = 0;\n private isResizing = false;\n\n private boundOnResizeMove = this.onResizeMove.bind(this);\n private boundOnResizeEnd = this.onResizeEnd.bind(this);\n\n constructor(\n private cdr: ChangeDetectorRef,\n private ngZone: NgZone,\n private elRef: ElementRef\n ) {}\n\n ngOnInit(): void {\n if (this._widthPx === 0) {\n this._widthPx = this.Mode === 'dialog'\n ? 800\n : Math.max(this.MinWidthPx, Math.min(window.innerWidth * 0.65, 1000));\n }\n\n this.initialized = true;\n\n // Animate in on next microtask if initially visible\n if (this._visible) {\n Promise.resolve().then(() => {\n this.IsVisible = true;\n this.cdr.markForCheck();\n });\n }\n }\n\n ngOnDestroy(): void {\n document.removeEventListener('mousemove', this.boundOnResizeMove);\n document.removeEventListener('mouseup', this.boundOnResizeEnd);\n }\n\n @HostListener('document:keydown.escape')\n public OnEscapeKey(): void {\n this.OnClose();\n }\n\n public OnClose(): void {\n if (this.CanClose && !this.CanClose()) return;\n this.IsVisible = false;\n this._visible = false;\n this.cdr.markForCheck();\n // Wait for CSS transition to complete\n setTimeout(() => this.Closed.emit(), 300);\n }\n\n public OnBackdropClick(): void {\n this.OnClose();\n }\n\n // =========================================================================\n // Resize\n // =========================================================================\n\n public OnResizeStart(event: MouseEvent): void {\n if (!this.Resizable || this.Mode === 'dialog') return;\n event.preventDefault();\n this.isResizing = true;\n document.body.style.cursor = 'col-resize';\n document.body.style.userSelect = 'none';\n\n this.ngZone.runOutsideAngular(() => {\n document.addEventListener('mousemove', this.boundOnResizeMove);\n document.addEventListener('mouseup', this.boundOnResizeEnd);\n });\n }\n\n private onResizeMove(event: MouseEvent): void {\n if (!this.isResizing) return;\n const viewportWidth = window.innerWidth;\n const maxWidth = viewportWidth * this.MaxWidthRatio;\n this._widthPx = Math.max(this.MinWidthPx, Math.min(maxWidth, viewportWidth - event.clientX));\n this.ngZone.run(() => this.cdr.markForCheck());\n }\n\n private onResizeEnd(): void {\n if (!this.isResizing) return;\n this.isResizing = false;\n document.body.style.cursor = '';\n document.body.style.userSelect = '';\n document.removeEventListener('mousemove', this.boundOnResizeMove);\n document.removeEventListener('mouseup', this.boundOnResizeEnd);\n this.WidthChanged.emit(this._widthPx);\n }\n}\n","<!-- Backdrop overlay -->\n<div class=\"sp-backdrop\"\n [class.visible]=\"IsVisible\"\n [class.sp-dialog-backdrop]=\"Mode === 'dialog'\"\n (click)=\"OnBackdropClick()\">\n</div>\n\n<!-- Panel (slide-in from right) -->\n@if (Mode === 'slide') {\n <div\n class=\"sp-panel\"\n [class.visible]=\"IsVisible\"\n [style.width.px]=\"WidthPx\"\n [style.max-width]=\"(MaxWidthRatio * 100) + 'vw'\">\n <!-- Resize handle -->\n @if (Resizable) {\n <div class=\"sp-resize-handle\" (mousedown)=\"OnResizeStart($event)\">\n <div class=\"sp-resize-grip\"></div>\n </div>\n }\n <!-- Header (if Title provided) -->\n @if (Title) {\n <div class=\"sp-header\">\n <h2 class=\"sp-title\">{{Title}}</h2>\n <button class=\"sp-close-btn\" (click)=\"OnClose()\">\n <i class=\"fa-solid fa-xmark\"></i>\n </button>\n </div>\n }\n <!-- Content projection -->\n <div class=\"sp-body\">\n <ng-content></ng-content>\n </div>\n </div>\n}\n\n<!-- Dialog (centered modal) -->\n@if (Mode === 'dialog') {\n <div\n class=\"sp-dialog\"\n [class.visible]=\"IsVisible\"\n [style.width.px]=\"WidthPx\">\n <!-- Header (if Title provided) -->\n @if (Title) {\n <div class=\"sp-header\">\n <h2 class=\"sp-title\">{{Title}}</h2>\n <button class=\"sp-close-btn\" (click)=\"OnClose()\">\n <i class=\"fa-solid fa-xmark\"></i>\n </button>\n </div>\n }\n <!-- Content projection -->\n <div class=\"sp-body sp-dialog-body\">\n <ng-content select=\"[dialog-content]\"></ng-content>\n </div>\n </div>\n}\n"]}
@@ -10,6 +10,7 @@ export * from './lib/datepicker/datepicker.component';
10
10
  export * from './lib/splitter/splitter.component';
11
11
  export * from './lib/accordion/accordion.component';
12
12
  export * from './lib/window/window.component';
13
+ export * from './lib/slide-panel/slide-panel.component';
13
14
  export * from './lib/combobox/combobox.component';
14
15
  export * from './lib/page-header/page-header.component';
15
16
  export * from './lib/page-layout/page-layout.component';
@@ -1 +1 @@
1
- {"version":3,"file":"public-api.d.ts","sourceRoot":"","sources":["../src/public-api.ts"],"names":[],"mappings":"AAGA,cAAc,+BAA+B,CAAC;AAC9C,cAAc,+BAA+B,CAAC;AAC9C,cAAc,6BAA6B,CAAC;AAC5C,cAAc,mCAAmC,CAAC;AAClD,cAAc,+BAA+B,CAAC;AAC9C,cAAc,6CAA6C,CAAC;AAC5D,cAAc,2CAA2C,CAAC;AAC1D,cAAc,+BAA+B,CAAC;AAC9C,cAAc,uCAAuC,CAAC;AACtD,cAAc,mCAAmC,CAAC;AAClD,cAAc,qCAAqC,CAAC;AACpD,cAAc,+BAA+B,CAAC;AAC9C,cAAc,mCAAmC,CAAC;AAClD,cAAc,yCAAyC,CAAC;AACxD,cAAc,yCAAyC,CAAC;AACxD,cAAc,qCAAqC,CAAC;AACpD,cAAc,uCAAuC,CAAC;AACtD,cAAc,+CAA+C,CAAC;AAC9D,cAAc,+CAA+C,CAAC;AAC9D,cAAc,yCAAyC,CAAC;AACxD,cAAc,yCAAyC,CAAC;AACxD,cAAc,2CAA2C,CAAC;AAC1D,cAAc,2CAA2C,CAAC;AAC1D,cAAc,iCAAiC,CAAC;AAChD,cAAc,yCAAyC,CAAC;AACxD,cAAc,mCAAmC,CAAC;AAClD,cAAc,2CAA2C,CAAC;AAC1D,cAAc,2DAA2D,CAAC;AAC1E,cAAc,uDAAuD,CAAC"}
1
+ {"version":3,"file":"public-api.d.ts","sourceRoot":"","sources":["../src/public-api.ts"],"names":[],"mappings":"AAGA,cAAc,+BAA+B,CAAC;AAC9C,cAAc,+BAA+B,CAAC;AAC9C,cAAc,6BAA6B,CAAC;AAC5C,cAAc,mCAAmC,CAAC;AAClD,cAAc,+BAA+B,CAAC;AAC9C,cAAc,6CAA6C,CAAC;AAC5D,cAAc,2CAA2C,CAAC;AAC1D,cAAc,+BAA+B,CAAC;AAC9C,cAAc,uCAAuC,CAAC;AACtD,cAAc,mCAAmC,CAAC;AAClD,cAAc,qCAAqC,CAAC;AACpD,cAAc,+BAA+B,CAAC;AAC9C,cAAc,yCAAyC,CAAC;AACxD,cAAc,mCAAmC,CAAC;AAClD,cAAc,yCAAyC,CAAC;AACxD,cAAc,yCAAyC,CAAC;AACxD,cAAc,qCAAqC,CAAC;AACpD,cAAc,uCAAuC,CAAC;AACtD,cAAc,+CAA+C,CAAC;AAC9D,cAAc,+CAA+C,CAAC;AAC9D,cAAc,yCAAyC,CAAC;AACxD,cAAc,yCAAyC,CAAC;AACxD,cAAc,2CAA2C,CAAC;AAC1D,cAAc,2CAA2C,CAAC;AAC1D,cAAc,iCAAiC,CAAC;AAChD,cAAc,yCAAyC,CAAC;AACxD,cAAc,mCAAmC,CAAC;AAClD,cAAc,2CAA2C,CAAC;AAC1D,cAAc,2DAA2D,CAAC;AAC1E,cAAc,uDAAuD,CAAC"}
@@ -12,6 +12,7 @@ export * from './lib/datepicker/datepicker.component';
12
12
  export * from './lib/splitter/splitter.component';
13
13
  export * from './lib/accordion/accordion.component';
14
14
  export * from './lib/window/window.component';
15
+ export * from './lib/slide-panel/slide-panel.component';
15
16
  export * from './lib/combobox/combobox.component';
16
17
  export * from './lib/page-header/page-header.component';
17
18
  export * from './lib/page-layout/page-layout.component';
@@ -1 +1 @@
1
- {"version":3,"file":"public-api.js","sourceRoot":"","sources":["../src/public-api.ts"],"names":[],"mappings":"AAAA,mCAAmC;AACnC,+DAA+D;AAE/D,cAAc,+BAA+B,CAAC;AAC9C,cAAc,+BAA+B,CAAC;AAC9C,cAAc,6BAA6B,CAAC;AAC5C,cAAc,mCAAmC,CAAC;AAClD,cAAc,+BAA+B,CAAC;AAC9C,cAAc,6CAA6C,CAAC;AAC5D,cAAc,2CAA2C,CAAC;AAC1D,cAAc,+BAA+B,CAAC;AAC9C,cAAc,uCAAuC,CAAC;AACtD,cAAc,mCAAmC,CAAC;AAClD,cAAc,qCAAqC,CAAC;AACpD,cAAc,+BAA+B,CAAC;AAC9C,cAAc,mCAAmC,CAAC;AAClD,cAAc,yCAAyC,CAAC;AACxD,cAAc,yCAAyC,CAAC;AACxD,cAAc,qCAAqC,CAAC;AACpD,cAAc,uCAAuC,CAAC;AACtD,cAAc,+CAA+C,CAAC;AAC9D,cAAc,+CAA+C,CAAC;AAC9D,cAAc,yCAAyC,CAAC;AACxD,cAAc,yCAAyC,CAAC;AACxD,cAAc,2CAA2C,CAAC;AAC1D,cAAc,2CAA2C,CAAC;AAC1D,cAAc,iCAAiC,CAAC;AAChD,cAAc,yCAAyC,CAAC;AACxD,cAAc,mCAAmC,CAAC;AAClD,cAAc,2CAA2C,CAAC;AAC1D,cAAc,2DAA2D,CAAC;AAC1E,cAAc,uDAAuD,CAAC","sourcesContent":["// @memberjunction/ng-ui-components\n// Reusable standalone Angular UI components for MemberJunction\n\nexport * from './lib/button/button.directive';\nexport * from './lib/dialog/dialog.component';\nexport * from './lib/dialog/dialog.service';\nexport * from './lib/dropdown/dropdown.component';\nexport * from './lib/switch/switch.component';\nexport * from './lib/numeric-input/numeric-input.component';\nexport * from './lib/progress-bar/progress-bar.component';\nexport * from './lib/calendar/calendar-utils';\nexport * from './lib/datepicker/datepicker.component';\nexport * from './lib/splitter/splitter.component';\nexport * from './lib/accordion/accordion.component';\nexport * from './lib/window/window.component';\nexport * from './lib/combobox/combobox.component';\nexport * from './lib/page-header/page-header.component';\nexport * from './lib/page-layout/page-layout.component';\nexport * from './lib/page-body/page-body.component';\nexport * from './lib/stat-badge/stat-badge.component';\nexport * from './lib/refresh-button/refresh-button.component';\nexport * from './lib/filter-popover/filter-popover.component';\nexport * from './lib/page-search/page-search.component';\nexport * from './lib/filter-chip/filter-chip.component';\nexport * from './lib/filter-field/filter-field.component';\nexport * from './lib/filter-panel/filter-panel.component';\nexport * from './lib/tab-nav/tab-nav.component';\nexport * from './lib/view-toggle/view-toggle.component';\nexport * from './lib/left-nav/left-nav.component';\nexport * from './lib/left-nav/left-nav-content.component';\nexport * from './lib/page-header-interior/page-header-interior.component';\nexport * from './lib/page-body-interior/page-body-interior.component';\n"]}
1
+ {"version":3,"file":"public-api.js","sourceRoot":"","sources":["../src/public-api.ts"],"names":[],"mappings":"AAAA,mCAAmC;AACnC,+DAA+D;AAE/D,cAAc,+BAA+B,CAAC;AAC9C,cAAc,+BAA+B,CAAC;AAC9C,cAAc,6BAA6B,CAAC;AAC5C,cAAc,mCAAmC,CAAC;AAClD,cAAc,+BAA+B,CAAC;AAC9C,cAAc,6CAA6C,CAAC;AAC5D,cAAc,2CAA2C,CAAC;AAC1D,cAAc,+BAA+B,CAAC;AAC9C,cAAc,uCAAuC,CAAC;AACtD,cAAc,mCAAmC,CAAC;AAClD,cAAc,qCAAqC,CAAC;AACpD,cAAc,+BAA+B,CAAC;AAC9C,cAAc,yCAAyC,CAAC;AACxD,cAAc,mCAAmC,CAAC;AAClD,cAAc,yCAAyC,CAAC;AACxD,cAAc,yCAAyC,CAAC;AACxD,cAAc,qCAAqC,CAAC;AACpD,cAAc,uCAAuC,CAAC;AACtD,cAAc,+CAA+C,CAAC;AAC9D,cAAc,+CAA+C,CAAC;AAC9D,cAAc,yCAAyC,CAAC;AACxD,cAAc,yCAAyC,CAAC;AACxD,cAAc,2CAA2C,CAAC;AAC1D,cAAc,2CAA2C,CAAC;AAC1D,cAAc,iCAAiC,CAAC;AAChD,cAAc,yCAAyC,CAAC;AACxD,cAAc,mCAAmC,CAAC;AAClD,cAAc,2CAA2C,CAAC;AAC1D,cAAc,2DAA2D,CAAC;AAC1E,cAAc,uDAAuD,CAAC","sourcesContent":["// @memberjunction/ng-ui-components\n// Reusable standalone Angular UI components for MemberJunction\n\nexport * from './lib/button/button.directive';\nexport * from './lib/dialog/dialog.component';\nexport * from './lib/dialog/dialog.service';\nexport * from './lib/dropdown/dropdown.component';\nexport * from './lib/switch/switch.component';\nexport * from './lib/numeric-input/numeric-input.component';\nexport * from './lib/progress-bar/progress-bar.component';\nexport * from './lib/calendar/calendar-utils';\nexport * from './lib/datepicker/datepicker.component';\nexport * from './lib/splitter/splitter.component';\nexport * from './lib/accordion/accordion.component';\nexport * from './lib/window/window.component';\nexport * from './lib/slide-panel/slide-panel.component';\nexport * from './lib/combobox/combobox.component';\nexport * from './lib/page-header/page-header.component';\nexport * from './lib/page-layout/page-layout.component';\nexport * from './lib/page-body/page-body.component';\nexport * from './lib/stat-badge/stat-badge.component';\nexport * from './lib/refresh-button/refresh-button.component';\nexport * from './lib/filter-popover/filter-popover.component';\nexport * from './lib/page-search/page-search.component';\nexport * from './lib/filter-chip/filter-chip.component';\nexport * from './lib/filter-field/filter-field.component';\nexport * from './lib/filter-panel/filter-panel.component';\nexport * from './lib/tab-nav/tab-nav.component';\nexport * from './lib/view-toggle/view-toggle.component';\nexport * from './lib/left-nav/left-nav.component';\nexport * from './lib/left-nav/left-nav-content.component';\nexport * from './lib/page-header-interior/page-header-interior.component';\nexport * from './lib/page-body-interior/page-body-interior.component';\n"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@memberjunction/ng-ui-components",
3
- "version": "5.37.0",
3
+ "version": "5.39.0",
4
4
  "description": "MemberJunction: Angular UI Components - reusable standalone components replacing Kendo UI dependencies.",
5
5
  "main": "./dist/public-api.js",
6
6
  "typings": "./dist/public-api.d.ts",