@memberjunction/ng-ui-components 5.42.0 → 5.44.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.
@@ -21,6 +21,55 @@ export declare class MJAccordionTitleDirective {
21
21
  static ɵfac: i0.ɵɵFactoryDeclaration<MJAccordionTitleDirective, never>;
22
22
  static ɵdir: i0.ɵɵDirectiveDeclaration<MJAccordionTitleDirective, "[mjAccordionTitle]", never, {}, {}, never, never, true, never>;
23
23
  }
24
+ /**
25
+ * Directive to mark a template as the accordion header **actions** — interactive
26
+ * controls (edit / copy / run / checkbox, etc.) that sit in the header row but
27
+ * are NOT the expand/collapse toggle. Rendered as a sibling of the toggle
28
+ * `<button>`, so there's no button-in-button and the toggle stays a clean,
29
+ * accessible control.
30
+ *
31
+ * @example
32
+ * ```html
33
+ * <mj-accordion-panel>
34
+ * <ng-template mjAccordionTitle>Connection</ng-template>
35
+ * <ng-template mjAccordionActions>
36
+ * <button mjButton variant="icon" (click)="edit()"><i class="fa fa-pen"></i></button>
37
+ * </ng-template>
38
+ * …body…
39
+ * </mj-accordion-panel>
40
+ * ```
41
+ */
42
+ export declare class MJAccordionActionsDirective {
43
+ templateRef: TemplateRef<unknown>;
44
+ constructor(templateRef: TemplateRef<unknown>);
45
+ static ɵfac: i0.ɵɵFactoryDeclaration<MJAccordionActionsDirective, never>;
46
+ static ɵdir: i0.ɵɵDirectiveDeclaration<MJAccordionActionsDirective, "[mjAccordionActions]", never, {}, {}, never, never, true, never>;
47
+ }
48
+ /**
49
+ * Directive to mark a template as the accordion **body** — the panel's collapsible
50
+ * content. Use this INSTEAD of placing content directly in the panel when the body
51
+ * may be expensive (code editors, grids, large lists) OR just to be future-proof:
52
+ * the accordion instantiates the template **lazily on first expand** and then keeps
53
+ * it alive, so nothing is created until the user opens the panel, while later
54
+ * open/close still animates. Consumers never have to reason about content weight or
55
+ * write `@if (expanded)` themselves.
56
+ *
57
+ * @example
58
+ * ```html
59
+ * <mj-accordion-panel [Expanded]="open" (ExpandedChange)="open = $event">
60
+ * <ng-template mjAccordionTitle>Configuration</ng-template>
61
+ * <ng-template mjAccordionBody>
62
+ * <mj-code-editor ...></mj-code-editor> <!-- not created until first opened -->
63
+ * </ng-template>
64
+ * </mj-accordion-panel>
65
+ * ```
66
+ */
67
+ export declare class MJAccordionBodyDirective {
68
+ templateRef: TemplateRef<unknown>;
69
+ constructor(templateRef: TemplateRef<unknown>);
70
+ static ɵfac: i0.ɵɵFactoryDeclaration<MJAccordionBodyDirective, never>;
71
+ static ɵdir: i0.ɵɵDirectiveDeclaration<MJAccordionBodyDirective, "[mjAccordionBody]", never, {}, {}, never, never, true, never>;
72
+ }
24
73
  /**
25
74
  * mj-accordion-panel — Collapsible panel. Replaces `<kendo-panelbar-item>` and `<kendo-expansionpanel>`.
26
75
  *
@@ -46,13 +95,99 @@ export declare class MJAccordionTitleDirective {
46
95
  */
47
96
  export declare class MJAccordionPanelComponent {
48
97
  Title: string;
49
- Expanded: boolean;
98
+ private _expanded;
99
+ /** Latches true the first time the panel is expanded; never resets. Lets a
100
+ * [mjAccordionBody] template instantiate lazily on first open and then stay
101
+ * alive so subsequent open/close still animates. */
102
+ private _everExpanded;
103
+ set Expanded(value: boolean);
104
+ get Expanded(): boolean;
105
+ protected get hasBeenExpanded(): boolean;
50
106
  Disabled: boolean;
107
+ /**
108
+ * Emphasis variant for visual hierarchy:
109
+ * - `primary` — bold, solid brand-colored header (use to make a panel stand out)
110
+ * - `secondary` — subtle brand tint
111
+ * - `default` — standard neutral header
112
+ * All brand-token-driven, so dark-mode-safe and themeable.
113
+ */
114
+ Variant: 'default' | 'primary' | 'secondary';
115
+ /**
116
+ * Render icons projected into the title slot in the muted color instead of the
117
+ * header's primary text color. Lets consumers get the common "quiet icon" look
118
+ * without writing CSS. Status/brand-colored icons can still be colored inline.
119
+ */
120
+ TitleIconMuted: boolean;
121
+ /**
122
+ * Density. `md` (default) is the standard size; `sm` tightens header padding and
123
+ * font for dense contexts (sidebars, flyouts, nested panels).
124
+ */
125
+ Size: 'sm' | 'md';
126
+ /**
127
+ * Bare chrome — drop the panel's own border and header background so the panel
128
+ * sits cleanly inside a host that already provides chrome (e.g. an expandable
129
+ * card). The toggle/title/chevron/body still work; only the box styling is removed.
130
+ */
131
+ Bare: boolean;
132
+ /**
133
+ * Remove the body's default padding, for bodies that manage their own spacing
134
+ * (code editors, full-bleed grids, custom forms).
135
+ */
136
+ FlushBody: boolean;
137
+ /**
138
+ * Fill mode — for "rail section that owns the leftover height" cases (e.g. an
139
+ * entity tree or grid that should consume all remaining vertical space and
140
+ * scroll *internally*), rather than the default "reveal stacked content"
141
+ * disclosure. When set AND expanded, the panel becomes a flex column that
142
+ * fills its flex parent and its body becomes a `flex:1; min-height:0` region —
143
+ * the projected content is expected to provide its own scroll child. While
144
+ * collapsed, the panel behaves exactly like a normal panel (header only,
145
+ * natural height) and does NOT claim the leftover space.
146
+ *
147
+ * Requires the panel's parent to be a flex column with `min-height:0`.
148
+ * Note: the open/close height animation is skipped in fill mode (the body
149
+ * fills rather than animating to content height).
150
+ */
151
+ Fill: boolean;
51
152
  ExpandedChange: EventEmitter<boolean>;
52
153
  titleTemplate: MJAccordionTitleDirective | null;
154
+ actionsTemplate: MJAccordionActionsDirective | null;
155
+ bodyTemplate: MJAccordionBodyDirective | null;
53
156
  readonly hostClass = true;
157
+ /** Host claims flex:1 of its parent ONLY while a Fill panel is expanded —
158
+ * so a collapsed Fill panel sits at natural (header) height like any other. */
159
+ get fillActive(): boolean;
160
+ /** Stable per-instance ids that programmatically associate the header
161
+ * `<button>` with its body region (`aria-controls` ↔ `aria-labelledby`),
162
+ * completing the WAI-ARIA accordion pattern so screen readers announce the
163
+ * region with the header's name. */
164
+ private readonly _uid;
165
+ readonly HeaderId: string;
166
+ readonly BodyId: string;
54
167
  Toggle(): void;
55
168
  static ɵfac: i0.ɵɵFactoryDeclaration<MJAccordionPanelComponent, never>;
56
- static ɵcmp: i0.ɵɵComponentDeclaration<MJAccordionPanelComponent, "mj-accordion-panel", never, { "Title": { "alias": "Title"; "required": false; }; "Expanded": { "alias": "Expanded"; "required": false; }; "Disabled": { "alias": "Disabled"; "required": false; }; }, { "ExpandedChange": "ExpandedChange"; }, ["titleTemplate"], ["*"], true, never>;
169
+ static ɵcmp: i0.ɵɵComponentDeclaration<MJAccordionPanelComponent, "mj-accordion-panel", never, { "Title": { "alias": "Title"; "required": false; }; "Expanded": { "alias": "Expanded"; "required": false; }; "Disabled": { "alias": "Disabled"; "required": false; }; "Variant": { "alias": "Variant"; "required": false; }; "TitleIconMuted": { "alias": "TitleIconMuted"; "required": false; }; "Size": { "alias": "Size"; "required": false; }; "Bare": { "alias": "Bare"; "required": false; }; "FlushBody": { "alias": "FlushBody"; "required": false; }; "Fill": { "alias": "Fill"; "required": false; }; }, { "ExpandedChange": "ExpandedChange"; }, ["titleTemplate", "actionsTemplate", "bodyTemplate"], ["*"], true, never>;
170
+ }
171
+ /**
172
+ * Convenience module bundling the accordion panel + all of its slot directives.
173
+ * Import this ONE symbol instead of listing the component and each directive
174
+ * separately:
175
+ *
176
+ * ```ts
177
+ * import { MJAccordionModule } from '@memberjunction/ng-ui-components';
178
+ * @NgModule({ imports: [MJAccordionModule, ...] }) // or @Component standalone imports
179
+ * ```
180
+ *
181
+ * Why a module (not a bare `const [...]` array): Angular's AOT compiler can't
182
+ * statically expand a value-array imported across a compiled-package boundary in
183
+ * an `imports` array (NG1010), and `as const` makes it a readonly tuple the
184
+ * `imports` type rejects (TS2322). An NgModule is always a valid `imports` entry
185
+ * in both NgModule and standalone consumers. Adding a future accordion directive
186
+ * here makes it available to every consumer automatically — no per-module churn.
187
+ */
188
+ export declare class MJAccordionModule {
189
+ static ɵfac: i0.ɵɵFactoryDeclaration<MJAccordionModule, never>;
190
+ static ɵmod: i0.ɵɵNgModuleDeclaration<MJAccordionModule, never, [typeof MJAccordionPanelComponent, typeof MJAccordionTitleDirective, typeof MJAccordionActionsDirective, typeof MJAccordionBodyDirective], [typeof MJAccordionPanelComponent, typeof MJAccordionTitleDirective, typeof MJAccordionActionsDirective, typeof MJAccordionBodyDirective]>;
191
+ static ɵinj: i0.ɵɵInjectorDeclaration<MJAccordionModule>;
57
192
  }
58
193
  //# sourceMappingURL=accordion.component.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"accordion.component.d.ts","sourceRoot":"","sources":["../../../src/lib/accordion/accordion.component.ts"],"names":[],"mappings":"AAAA,OAAO,EAA4B,YAAY,EAA6B,WAAW,EAAa,MAAM,eAAe,CAAC;;AAG1H;;;;;;;;;;;;;;GAcG;AACH,qBAIa,yBAAyB;IACjB,WAAW,EAAE,WAAW,CAAC,OAAO,CAAC;gBAAjC,WAAW,EAAE,WAAW,CAAC,OAAO,CAAC;yCADzC,yBAAyB;2CAAzB,yBAAyB;CAErC;AAED;;;;;;;;;;;;;;;;;;;;;;GAsBG;AACH,qBA2Ba,yBAAyB;IAC3B,KAAK,SAAM;IACX,QAAQ,UAAS;IACjB,QAAQ,UAAS;IAChB,cAAc,wBAA+B;IACd,aAAa,EAAE,yBAAyB,GAAG,IAAI,CAAQ;IAClD,QAAQ,CAAC,SAAS,QAAQ;IAExE,MAAM,IAAI,IAAI;yCARH,yBAAyB;2CAAzB,yBAAyB;CAarC"}
1
+ {"version":3,"file":"accordion.component.d.ts","sourceRoot":"","sources":["../../../src/lib/accordion/accordion.component.ts"],"names":[],"mappings":"AAAA,OAAO,EAA4B,YAAY,EAA6B,WAAW,EAAuB,MAAM,eAAe,CAAC;;AAOpI;;;;;;;;;;;;;;GAcG;AACH,qBAIa,yBAAyB;IACjB,WAAW,EAAE,WAAW,CAAC,OAAO,CAAC;gBAAjC,WAAW,EAAE,WAAW,CAAC,OAAO,CAAC;yCADzC,yBAAyB;2CAAzB,yBAAyB;CAErC;AAED;;;;;;;;;;;;;;;;;GAiBG;AACH,qBAIa,2BAA2B;IACnB,WAAW,EAAE,WAAW,CAAC,OAAO,CAAC;gBAAjC,WAAW,EAAE,WAAW,CAAC,OAAO,CAAC;yCADzC,2BAA2B;2CAA3B,2BAA2B;CAEvC;AAED;;;;;;;;;;;;;;;;;;GAkBG;AACH,qBAIa,wBAAwB;IAChB,WAAW,EAAE,WAAW,CAAC,OAAO,CAAC;gBAAjC,WAAW,EAAE,WAAW,CAAC,OAAO,CAAC;yCADzC,wBAAwB;2CAAxB,wBAAwB;CAEpC;AAED;;;;;;;;;;;;;;;;;;;;;;GAsBG;AACH,qBAwDa,yBAAyB;IAC3B,KAAK,SAAM;IACpB,OAAO,CAAC,SAAS,CAAS;IAC1B;;yDAEqD;IACrD,OAAO,CAAC,aAAa,CAAS;IAC9B,IACI,QAAQ,CAAC,KAAK,EAAE,OAAO,EAG1B;IACD,IAAI,QAAQ,IAAI,OAAO,CAA2B;IAClD,SAAS,KAAK,eAAe,IAAI,OAAO,CAA+B;IAC9D,QAAQ,UAAS;IAC1B;;;;;;OAMG;IACM,OAAO,EAAE,SAAS,GAAG,SAAS,GAAG,WAAW,CAAa;IAClE;;;;OAIG;IACM,cAAc,UAAS;IAChC;;;OAGG;IACM,IAAI,EAAE,IAAI,GAAG,IAAI,CAAQ;IAClC;;;;OAIG;IACM,IAAI,UAAS;IACtB;;;OAGG;IACM,SAAS,UAAS;IAC3B;;;;;;;;;;;;;OAaG;IACM,IAAI,UAAS;IACZ,cAAc,wBAA+B;IACd,aAAa,EAAE,yBAAyB,GAAG,IAAI,CAAQ;IACrD,eAAe,EAAE,2BAA2B,GAAG,IAAI,CAAQ;IAC9D,YAAY,EAAE,wBAAwB,GAAG,IAAI,CAAQ;IAC/C,QAAQ,CAAC,SAAS,QAAQ;IACxE;oFACgF;IAChF,IAAmD,UAAU,IAAI,OAAO,CAEvE;IAED;;;yCAGqC;IACrC,OAAO,CAAC,QAAQ,CAAC,IAAI,CAAsB;IAC3C,QAAQ,CAAC,QAAQ,SAAsC;IACvD,QAAQ,CAAC,MAAM,SAAoC;IAEnD,MAAM,IAAI,IAAI;yCA/EH,yBAAyB;2CAAzB,yBAAyB;CAoFrC;AAED;;;;;;;;;;;;;;;;GAgBG;AACH,qBAca,iBAAiB;yCAAjB,iBAAiB;0CAAjB,iBAAiB,iBArHjB,yBAAyB,SAxIzB,yBAAyB,SA0BzB,2BAA2B,SA2B3B,wBAAwB,WAmFxB,yBAAyB,SAxIzB,yBAAyB,SA0BzB,2BAA2B,SA2B3B,wBAAwB;0CAwMxB,iBAAiB;CAAG"}
@@ -1,14 +1,14 @@
1
- import { Component, Input, Output, EventEmitter, HostBinding, ContentChild, Directive } from '@angular/core';
1
+ import { Component, Input, Output, EventEmitter, HostBinding, ContentChild, Directive, NgModule } from '@angular/core';
2
2
  import { NgTemplateOutlet } from '@angular/common';
3
3
  import * as i0 from "@angular/core";
4
4
  const _c0 = ["*"];
5
- function MJAccordionPanelComponent_Conditional_3_Template(rf, ctx) { if (rf & 1) {
6
- i0.ɵɵelementContainer(0, 3);
5
+ function MJAccordionPanelComponent_Conditional_4_Template(rf, ctx) { if (rf & 1) {
6
+ i0.ɵɵelementContainer(0, 4);
7
7
  } if (rf & 2) {
8
8
  const ctx_r0 = i0.ɵɵnextContext();
9
9
  i0.ɵɵproperty("ngTemplateOutlet", ctx_r0.titleTemplate.templateRef);
10
10
  } }
11
- function MJAccordionPanelComponent_Conditional_4_Template(rf, ctx) { if (rf & 1) {
11
+ function MJAccordionPanelComponent_Conditional_5_Template(rf, ctx) { if (rf & 1) {
12
12
  i0.ɵɵtext(0);
13
13
  } if (rf & 2) {
14
14
  const ctx_r0 = i0.ɵɵnextContext();
@@ -16,9 +16,22 @@ function MJAccordionPanelComponent_Conditional_4_Template(rf, ctx) { if (rf & 1)
16
16
  } }
17
17
  function MJAccordionPanelComponent_Conditional_6_Template(rf, ctx) { if (rf & 1) {
18
18
  i0.ɵɵelementStart(0, "div", 5);
19
- i0.ɵɵprojection(1);
19
+ i0.ɵɵelementContainer(1, 4);
20
20
  i0.ɵɵelementEnd();
21
+ } if (rf & 2) {
22
+ const ctx_r0 = i0.ɵɵnextContext();
23
+ i0.ɵɵadvance();
24
+ i0.ɵɵproperty("ngTemplateOutlet", ctx_r0.actionsTemplate.templateRef);
21
25
  } }
26
+ function MJAccordionPanelComponent_Conditional_13_Template(rf, ctx) { if (rf & 1) {
27
+ i0.ɵɵelementContainer(0, 4);
28
+ } if (rf & 2) {
29
+ const ctx_r0 = i0.ɵɵnextContext();
30
+ i0.ɵɵproperty("ngTemplateOutlet", ctx_r0.bodyTemplate.templateRef);
31
+ } }
32
+ /** Process-wide counter for generating unique, stable accordion element ids
33
+ * (used to wire `aria-controls` / `aria-labelledby` between header and body). */
34
+ let nextAccordionUid = 0;
22
35
  /**
23
36
  * Directive to mark a template as the accordion panel title.
24
37
  * Supports rich HTML content (icons, badges, dynamic text).
@@ -49,6 +62,73 @@ export class MJAccordionTitleDirective {
49
62
  standalone: true
50
63
  }]
51
64
  }], () => [{ type: i0.TemplateRef }], null); })();
65
+ /**
66
+ * Directive to mark a template as the accordion header **actions** — interactive
67
+ * controls (edit / copy / run / checkbox, etc.) that sit in the header row but
68
+ * are NOT the expand/collapse toggle. Rendered as a sibling of the toggle
69
+ * `<button>`, so there's no button-in-button and the toggle stays a clean,
70
+ * accessible control.
71
+ *
72
+ * @example
73
+ * ```html
74
+ * <mj-accordion-panel>
75
+ * <ng-template mjAccordionTitle>Connection</ng-template>
76
+ * <ng-template mjAccordionActions>
77
+ * <button mjButton variant="icon" (click)="edit()"><i class="fa fa-pen"></i></button>
78
+ * </ng-template>
79
+ * …body…
80
+ * </mj-accordion-panel>
81
+ * ```
82
+ */
83
+ export class MJAccordionActionsDirective {
84
+ templateRef;
85
+ constructor(templateRef) {
86
+ this.templateRef = templateRef;
87
+ }
88
+ static ɵfac = function MJAccordionActionsDirective_Factory(__ngFactoryType__) { return new (__ngFactoryType__ || MJAccordionActionsDirective)(i0.ɵɵdirectiveInject(i0.TemplateRef)); };
89
+ static ɵdir = /*@__PURE__*/ i0.ɵɵdefineDirective({ type: MJAccordionActionsDirective, selectors: [["", "mjAccordionActions", ""]] });
90
+ }
91
+ (() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassMetadata(MJAccordionActionsDirective, [{
92
+ type: Directive,
93
+ args: [{
94
+ selector: '[mjAccordionActions]',
95
+ standalone: true
96
+ }]
97
+ }], () => [{ type: i0.TemplateRef }], null); })();
98
+ /**
99
+ * Directive to mark a template as the accordion **body** — the panel's collapsible
100
+ * content. Use this INSTEAD of placing content directly in the panel when the body
101
+ * may be expensive (code editors, grids, large lists) OR just to be future-proof:
102
+ * the accordion instantiates the template **lazily on first expand** and then keeps
103
+ * it alive, so nothing is created until the user opens the panel, while later
104
+ * open/close still animates. Consumers never have to reason about content weight or
105
+ * write `@if (expanded)` themselves.
106
+ *
107
+ * @example
108
+ * ```html
109
+ * <mj-accordion-panel [Expanded]="open" (ExpandedChange)="open = $event">
110
+ * <ng-template mjAccordionTitle>Configuration</ng-template>
111
+ * <ng-template mjAccordionBody>
112
+ * <mj-code-editor ...></mj-code-editor> <!-- not created until first opened -->
113
+ * </ng-template>
114
+ * </mj-accordion-panel>
115
+ * ```
116
+ */
117
+ export class MJAccordionBodyDirective {
118
+ templateRef;
119
+ constructor(templateRef) {
120
+ this.templateRef = templateRef;
121
+ }
122
+ static ɵfac = function MJAccordionBodyDirective_Factory(__ngFactoryType__) { return new (__ngFactoryType__ || MJAccordionBodyDirective)(i0.ɵɵdirectiveInject(i0.TemplateRef)); };
123
+ static ɵdir = /*@__PURE__*/ i0.ɵɵdefineDirective({ type: MJAccordionBodyDirective, selectors: [["", "mjAccordionBody", ""]] });
124
+ }
125
+ (() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassMetadata(MJAccordionBodyDirective, [{
126
+ type: Directive,
127
+ args: [{
128
+ selector: '[mjAccordionBody]',
129
+ standalone: true
130
+ }]
131
+ }], () => [{ type: i0.TemplateRef }], null); })();
52
132
  /**
53
133
  * mj-accordion-panel — Collapsible panel. Replaces `<kendo-panelbar-item>` and `<kendo-expansionpanel>`.
54
134
  *
@@ -74,11 +154,81 @@ export class MJAccordionTitleDirective {
74
154
  */
75
155
  export class MJAccordionPanelComponent {
76
156
  Title = '';
77
- Expanded = false;
157
+ _expanded = false;
158
+ /** Latches true the first time the panel is expanded; never resets. Lets a
159
+ * [mjAccordionBody] template instantiate lazily on first open and then stay
160
+ * alive so subsequent open/close still animates. */
161
+ _everExpanded = false;
162
+ set Expanded(value) {
163
+ this._expanded = value;
164
+ if (value)
165
+ this._everExpanded = true;
166
+ }
167
+ get Expanded() { return this._expanded; }
168
+ get hasBeenExpanded() { return this._everExpanded; }
78
169
  Disabled = false;
170
+ /**
171
+ * Emphasis variant for visual hierarchy:
172
+ * - `primary` — bold, solid brand-colored header (use to make a panel stand out)
173
+ * - `secondary` — subtle brand tint
174
+ * - `default` — standard neutral header
175
+ * All brand-token-driven, so dark-mode-safe and themeable.
176
+ */
177
+ Variant = 'default';
178
+ /**
179
+ * Render icons projected into the title slot in the muted color instead of the
180
+ * header's primary text color. Lets consumers get the common "quiet icon" look
181
+ * without writing CSS. Status/brand-colored icons can still be colored inline.
182
+ */
183
+ TitleIconMuted = false;
184
+ /**
185
+ * Density. `md` (default) is the standard size; `sm` tightens header padding and
186
+ * font for dense contexts (sidebars, flyouts, nested panels).
187
+ */
188
+ Size = 'md';
189
+ /**
190
+ * Bare chrome — drop the panel's own border and header background so the panel
191
+ * sits cleanly inside a host that already provides chrome (e.g. an expandable
192
+ * card). The toggle/title/chevron/body still work; only the box styling is removed.
193
+ */
194
+ Bare = false;
195
+ /**
196
+ * Remove the body's default padding, for bodies that manage their own spacing
197
+ * (code editors, full-bleed grids, custom forms).
198
+ */
199
+ FlushBody = false;
200
+ /**
201
+ * Fill mode — for "rail section that owns the leftover height" cases (e.g. an
202
+ * entity tree or grid that should consume all remaining vertical space and
203
+ * scroll *internally*), rather than the default "reveal stacked content"
204
+ * disclosure. When set AND expanded, the panel becomes a flex column that
205
+ * fills its flex parent and its body becomes a `flex:1; min-height:0` region —
206
+ * the projected content is expected to provide its own scroll child. While
207
+ * collapsed, the panel behaves exactly like a normal panel (header only,
208
+ * natural height) and does NOT claim the leftover space.
209
+ *
210
+ * Requires the panel's parent to be a flex column with `min-height:0`.
211
+ * Note: the open/close height animation is skipped in fill mode (the body
212
+ * fills rather than animating to content height).
213
+ */
214
+ Fill = false;
79
215
  ExpandedChange = new EventEmitter();
80
216
  titleTemplate = null;
217
+ actionsTemplate = null;
218
+ bodyTemplate = null;
81
219
  hostClass = true;
220
+ /** Host claims flex:1 of its parent ONLY while a Fill panel is expanded —
221
+ * so a collapsed Fill panel sits at natural (header) height like any other. */
222
+ get fillActive() {
223
+ return this.Fill && this.Expanded;
224
+ }
225
+ /** Stable per-instance ids that programmatically associate the header
226
+ * `<button>` with its body region (`aria-controls` ↔ `aria-labelledby`),
227
+ * completing the WAI-ARIA accordion pattern so screen readers announce the
228
+ * region with the header's name. */
229
+ _uid = nextAccordionUid++;
230
+ HeaderId = `mj-accordion-header-${this._uid}`;
231
+ BodyId = `mj-accordion-body-${this._uid}`;
82
232
  Toggle() {
83
233
  if (this.Disabled)
84
234
  return;
@@ -87,32 +237,49 @@ export class MJAccordionPanelComponent {
87
237
  }
88
238
  static ɵfac = function MJAccordionPanelComponent_Factory(__ngFactoryType__) { return new (__ngFactoryType__ || MJAccordionPanelComponent)(); };
89
239
  static ɵcmp = /*@__PURE__*/ i0.ɵɵdefineComponent({ type: MJAccordionPanelComponent, selectors: [["mj-accordion-panel"]], contentQueries: function MJAccordionPanelComponent_ContentQueries(rf, ctx, dirIndex) { if (rf & 1) {
90
- i0.ɵɵcontentQuery(dirIndex, MJAccordionTitleDirective, 5);
240
+ i0.ɵɵcontentQuery(dirIndex, MJAccordionTitleDirective, 5)(dirIndex, MJAccordionActionsDirective, 5)(dirIndex, MJAccordionBodyDirective, 5);
91
241
  } if (rf & 2) {
92
242
  let _t;
93
243
  i0.ɵɵqueryRefresh(_t = i0.ɵɵloadQuery()) && (ctx.titleTemplate = _t.first);
94
- } }, hostVars: 2, hostBindings: function MJAccordionPanelComponent_HostBindings(rf, ctx) { if (rf & 2) {
95
- i0.ɵɵclassProp("mj-accordion-panel-host", ctx.hostClass);
96
- } }, inputs: { Title: "Title", Expanded: "Expanded", Disabled: "Disabled" }, outputs: { ExpandedChange: "ExpandedChange" }, ngContentSelectors: _c0, decls: 7, vars: 8, consts: [[1, "mj-accordion-panel"], ["type", "button", 1, "mj-accordion-header", 3, "click", "disabled"], [1, "mj-accordion-title"], [3, "ngTemplateOutlet"], [1, "fa-solid", "fa-chevron-down", "mj-accordion-icon"], ["role", "region", 1, "mj-accordion-body"]], template: function MJAccordionPanelComponent_Template(rf, ctx) { if (rf & 1) {
244
+ i0.ɵɵqueryRefresh(_t = i0.ɵɵloadQuery()) && (ctx.actionsTemplate = _t.first);
245
+ i0.ɵɵqueryRefresh(_t = i0.ɵɵloadQuery()) && (ctx.bodyTemplate = _t.first);
246
+ } }, hostVars: 4, hostBindings: function MJAccordionPanelComponent_HostBindings(rf, ctx) { if (rf & 2) {
247
+ i0.ɵɵclassProp("mj-accordion-panel-host", ctx.hostClass)("mj-accordion-fill-active", ctx.fillActive);
248
+ } }, inputs: { Title: "Title", Expanded: "Expanded", Disabled: "Disabled", Variant: "Variant", TitleIconMuted: "TitleIconMuted", Size: "Size", Bare: "Bare", FlushBody: "FlushBody", Fill: "Fill" }, outputs: { ExpandedChange: "ExpandedChange" }, ngContentSelectors: _c0, decls: 14, vars: 26, consts: [[1, "mj-accordion-panel"], [1, "mj-accordion-header-row"], ["type", "button", 1, "mj-accordion-header", 3, "click", "id", "disabled"], [1, "mj-accordion-title"], [3, "ngTemplateOutlet"], [1, "mj-accordion-actions"], ["type", "button", "tabindex", "-1", "aria-hidden", "true", 1, "mj-accordion-chevron", 3, "click", "disabled"], [1, "fa-solid", "fa-chevron-down", "mj-accordion-icon"], [1, "mj-accordion-body-outer"], [1, "mj-accordion-body-clip"], ["role", "region", 1, "mj-accordion-body", 3, "id"]], template: function MJAccordionPanelComponent_Template(rf, ctx) { if (rf & 1) {
97
249
  i0.ɵɵprojectionDef();
98
- i0.ɵɵelementStart(0, "div", 0)(1, "button", 1);
99
- i0.ɵɵlistener("click", function MJAccordionPanelComponent_Template_button_click_1_listener() { return ctx.Toggle(); });
100
- i0.ɵɵelementStart(2, "span", 2);
101
- i0.ɵɵconditionalCreate(3, MJAccordionPanelComponent_Conditional_3_Template, 1, 1, "ng-container", 3)(4, MJAccordionPanelComponent_Conditional_4_Template, 1, 1);
102
- i0.ɵɵelementEnd();
103
- i0.ɵɵelement(5, "i", 4);
104
- i0.ɵɵelementEnd();
105
- i0.ɵɵconditionalCreate(6, MJAccordionPanelComponent_Conditional_6_Template, 2, 0, "div", 5);
106
- i0.ɵɵelementEnd();
250
+ i0.ɵɵelementStart(0, "div", 0)(1, "div", 1)(2, "button", 2);
251
+ i0.ɵɵlistener("click", function MJAccordionPanelComponent_Template_button_click_2_listener() { return ctx.Toggle(); });
252
+ i0.ɵɵelementStart(3, "span", 3);
253
+ i0.ɵɵconditionalCreate(4, MJAccordionPanelComponent_Conditional_4_Template, 1, 1, "ng-container", 4)(5, MJAccordionPanelComponent_Conditional_5_Template, 1, 1);
254
+ i0.ɵɵelementEnd()();
255
+ i0.ɵɵconditionalCreate(6, MJAccordionPanelComponent_Conditional_6_Template, 2, 1, "div", 5);
256
+ i0.ɵɵelementStart(7, "button", 6);
257
+ i0.ɵɵlistener("click", function MJAccordionPanelComponent_Template_button_click_7_listener() { return ctx.Toggle(); });
258
+ i0.ɵɵelement(8, "i", 7);
259
+ i0.ɵɵelementEnd()();
260
+ i0.ɵɵelementStart(9, "div", 8)(10, "div", 9)(11, "div", 10);
261
+ i0.ɵɵprojection(12);
262
+ i0.ɵɵconditionalCreate(13, MJAccordionPanelComponent_Conditional_13_Template, 1, 1, "ng-container", 4);
263
+ i0.ɵɵelementEnd()()()();
107
264
  } if (rf & 2) {
108
- i0.ɵɵclassProp("mj-accordion-panel--expanded", ctx.Expanded)("mj-accordion-panel--disabled", ctx.Disabled);
265
+ i0.ɵɵclassProp("mj-accordion-panel--expanded", ctx.Expanded)("mj-accordion-panel--disabled", ctx.Disabled)("mj-accordion-panel--muted-icon", ctx.TitleIconMuted)("mj-accordion-panel--sm", ctx.Size === "sm")("mj-accordion-panel--bare", ctx.Bare)("mj-accordion-panel--flush-body", ctx.FlushBody)("mj-accordion-panel--fill", ctx.Fill);
266
+ i0.ɵɵattribute("data-variant", ctx.Variant !== "default" ? ctx.Variant : null);
267
+ i0.ɵɵadvance(2);
268
+ i0.ɵɵproperty("id", ctx.HeaderId)("disabled", ctx.Disabled);
269
+ i0.ɵɵattribute("aria-expanded", ctx.Expanded)("aria-controls", ctx.BodyId);
270
+ i0.ɵɵadvance(2);
271
+ i0.ɵɵconditional(ctx.titleTemplate ? 4 : 5);
272
+ i0.ɵɵadvance(2);
273
+ i0.ɵɵconditional(ctx.actionsTemplate ? 6 : -1);
109
274
  i0.ɵɵadvance();
110
275
  i0.ɵɵproperty("disabled", ctx.Disabled);
111
- i0.ɵɵattribute("aria-expanded", ctx.Expanded);
112
276
  i0.ɵɵadvance(2);
113
- i0.ɵɵconditional(ctx.titleTemplate ? 3 : 4);
114
- i0.ɵɵadvance(3);
115
- i0.ɵɵconditional(ctx.Expanded ? 6 : -1);
277
+ i0.ɵɵattribute("inert", ctx.Expanded ? null : "");
278
+ i0.ɵɵadvance(2);
279
+ i0.ɵɵproperty("id", ctx.BodyId);
280
+ i0.ɵɵattribute("aria-labelledby", ctx.HeaderId);
281
+ i0.ɵɵadvance(2);
282
+ i0.ɵɵconditional(ctx.bodyTemplate && (ctx.Expanded || ctx.hasBeenExpanded) ? 13 : -1);
116
283
  } }, dependencies: [NgTemplateOutlet], encapsulation: 2 });
117
284
  }
118
285
  (() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassMetadata(MJAccordionPanelComponent, [{
@@ -122,25 +289,54 @@ export class MJAccordionPanelComponent {
122
289
  standalone: true,
123
290
  imports: [NgTemplateOutlet],
124
291
  template: `
125
- <div class="mj-accordion-panel" [class.mj-accordion-panel--expanded]="Expanded" [class.mj-accordion-panel--disabled]="Disabled">
126
- <button class="mj-accordion-header" type="button"
127
- [attr.aria-expanded]="Expanded"
128
- [disabled]="Disabled"
129
- (click)="Toggle()">
130
- <span class="mj-accordion-title">
131
- @if (titleTemplate) {
132
- <ng-container [ngTemplateOutlet]="titleTemplate.templateRef"></ng-container>
133
- } @else {
134
- {{ Title }}
135
- }
136
- </span>
137
- <i class="fa-solid fa-chevron-down mj-accordion-icon"></i>
138
- </button>
139
- @if (Expanded) {
140
- <div class="mj-accordion-body" role="region">
141
- <ng-content></ng-content>
292
+ <div class="mj-accordion-panel" [class.mj-accordion-panel--expanded]="Expanded" [class.mj-accordion-panel--disabled]="Disabled"
293
+ [class.mj-accordion-panel--muted-icon]="TitleIconMuted"
294
+ [class.mj-accordion-panel--sm]="Size === 'sm'"
295
+ [class.mj-accordion-panel--bare]="Bare"
296
+ [class.mj-accordion-panel--flush-body]="FlushBody"
297
+ [class.mj-accordion-panel--fill]="Fill"
298
+ [attr.data-variant]="Variant !== 'default' ? Variant : null">
299
+ <div class="mj-accordion-header-row">
300
+ <button class="mj-accordion-header" type="button"
301
+ [id]="HeaderId"
302
+ [attr.aria-expanded]="Expanded"
303
+ [attr.aria-controls]="BodyId"
304
+ [disabled]="Disabled"
305
+ (click)="Toggle()">
306
+ <span class="mj-accordion-title">
307
+ @if (titleTemplate) {
308
+ <ng-container [ngTemplateOutlet]="titleTemplate.templateRef"></ng-container>
309
+ } @else {
310
+ {{ Title }}
311
+ }
312
+ </span>
313
+ </button>
314
+ @if (actionsTemplate) {
315
+ <div class="mj-accordion-actions">
316
+ <ng-container [ngTemplateOutlet]="actionsTemplate.templateRef"></ng-container>
317
+ </div>
318
+ }
319
+ <!-- The chevron is ALWAYS the rightmost element of the header row (after any
320
+ actions). It's a secondary, a11y-hidden toggle affordance — the primary
321
+ disclosure control is the title button above (which owns aria-expanded). -->
322
+ <button class="mj-accordion-chevron" type="button" tabindex="-1" aria-hidden="true"
323
+ [disabled]="Disabled" (click)="Toggle()">
324
+ <i class="fa-solid fa-chevron-down mj-accordion-icon"></i>
325
+ </button>
326
+ </div>
327
+ <div class="mj-accordion-body-outer" [attr.inert]="Expanded ? null : ''">
328
+ <div class="mj-accordion-body-clip">
329
+ <div class="mj-accordion-body" role="region" [id]="BodyId" [attr.aria-labelledby]="HeaderId">
330
+ <!-- Legacy: content placed directly in the panel (eager). -->
331
+ <ng-content></ng-content>
332
+ <!-- Preferred: [mjAccordionBody] template — instantiated lazily on first
333
+ expand, then kept alive so later toggles still animate. -->
334
+ @if (bodyTemplate && (Expanded || hasBeenExpanded)) {
335
+ <ng-container [ngTemplateOutlet]="bodyTemplate.templateRef"></ng-container>
336
+ }
337
+ </div>
142
338
  </div>
143
- }
339
+ </div>
144
340
  </div>
145
341
  `
146
342
  }]
@@ -150,14 +346,75 @@ export class MJAccordionPanelComponent {
150
346
  type: Input
151
347
  }], Disabled: [{
152
348
  type: Input
349
+ }], Variant: [{
350
+ type: Input
351
+ }], TitleIconMuted: [{
352
+ type: Input
353
+ }], Size: [{
354
+ type: Input
355
+ }], Bare: [{
356
+ type: Input
357
+ }], FlushBody: [{
358
+ type: Input
359
+ }], Fill: [{
360
+ type: Input
153
361
  }], ExpandedChange: [{
154
362
  type: Output
155
363
  }], titleTemplate: [{
156
364
  type: ContentChild,
157
365
  args: [MJAccordionTitleDirective]
366
+ }], actionsTemplate: [{
367
+ type: ContentChild,
368
+ args: [MJAccordionActionsDirective]
369
+ }], bodyTemplate: [{
370
+ type: ContentChild,
371
+ args: [MJAccordionBodyDirective]
158
372
  }], hostClass: [{
159
373
  type: HostBinding,
160
374
  args: ['class.mj-accordion-panel-host']
375
+ }], fillActive: [{
376
+ type: HostBinding,
377
+ args: ['class.mj-accordion-fill-active']
161
378
  }] }); })();
162
- (() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassDebugInfo(MJAccordionPanelComponent, { className: "MJAccordionPanelComponent", filePath: "lib/accordion/accordion.component.ts", lineNumber: 77 }); })();
379
+ (() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassDebugInfo(MJAccordionPanelComponent, { className: "MJAccordionPanelComponent", filePath: "lib/accordion/accordion.component.ts", lineNumber: 163 }); })();
380
+ /**
381
+ * Convenience module bundling the accordion panel + all of its slot directives.
382
+ * Import this ONE symbol instead of listing the component and each directive
383
+ * separately:
384
+ *
385
+ * ```ts
386
+ * import { MJAccordionModule } from '@memberjunction/ng-ui-components';
387
+ * @NgModule({ imports: [MJAccordionModule, ...] }) // or @Component standalone imports
388
+ * ```
389
+ *
390
+ * Why a module (not a bare `const [...]` array): Angular's AOT compiler can't
391
+ * statically expand a value-array imported across a compiled-package boundary in
392
+ * an `imports` array (NG1010), and `as const` makes it a readonly tuple the
393
+ * `imports` type rejects (TS2322). An NgModule is always a valid `imports` entry
394
+ * in both NgModule and standalone consumers. Adding a future accordion directive
395
+ * here makes it available to every consumer automatically — no per-module churn.
396
+ */
397
+ export class MJAccordionModule {
398
+ static ɵfac = function MJAccordionModule_Factory(__ngFactoryType__) { return new (__ngFactoryType__ || MJAccordionModule)(); };
399
+ static ɵmod = /*@__PURE__*/ i0.ɵɵdefineNgModule({ type: MJAccordionModule });
400
+ static ɵinj = /*@__PURE__*/ i0.ɵɵdefineInjector({});
401
+ }
402
+ (() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassMetadata(MJAccordionModule, [{
403
+ type: NgModule,
404
+ args: [{
405
+ imports: [
406
+ MJAccordionPanelComponent,
407
+ MJAccordionTitleDirective,
408
+ MJAccordionActionsDirective,
409
+ MJAccordionBodyDirective,
410
+ ],
411
+ exports: [
412
+ MJAccordionPanelComponent,
413
+ MJAccordionTitleDirective,
414
+ MJAccordionActionsDirective,
415
+ MJAccordionBodyDirective,
416
+ ],
417
+ }]
418
+ }], null, null); })();
419
+ (function () { (typeof ngJitMode === "undefined" || ngJitMode) && i0.ɵɵsetNgModuleScope(MJAccordionModule, { imports: [MJAccordionPanelComponent, MJAccordionTitleDirective, MJAccordionActionsDirective, MJAccordionBodyDirective], exports: [MJAccordionPanelComponent, MJAccordionTitleDirective, MJAccordionActionsDirective, MJAccordionBodyDirective] }); })();
163
420
  //# sourceMappingURL=accordion.component.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"accordion.component.js","sourceRoot":"","sources":["../../../src/lib/accordion/accordion.component.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,KAAK,EAAE,MAAM,EAAE,YAAY,EAAE,WAAW,EAAE,YAAY,EAAe,SAAS,EAAE,MAAM,eAAe,CAAC;AAC1H,OAAO,EAAE,gBAAgB,EAAE,MAAM,iBAAiB,CAAC;;;;IA4DvC,2BAA4E;;;IAA9D,mEAA8C;;;IAE5D,YACF;;;IADE,6CACF;;;IAKF,8BAA6C;IAC3C,kBAAyB;IAC3B,iBAAM;;AApEd;;;;;;;;;;;;;;GAcG;AAKH,MAAM,OAAO,yBAAyB;IACjB;IAAnB,YAAmB,WAAiC;QAAjC,gBAAW,GAAX,WAAW,CAAsB;IAAG,CAAC;mHAD7C,yBAAyB;6DAAzB,yBAAyB;;iFAAzB,yBAAyB;cAJrC,SAAS;eAAC;gBACT,QAAQ,EAAE,oBAAoB;gBAC9B,UAAU,EAAE,IAAI;aACjB;;AAKD;;;;;;;;;;;;;;;;;;;;;;GAsBG;AA4BH,MAAM,OAAO,yBAAyB;IAC3B,KAAK,GAAG,EAAE,CAAC;IACX,QAAQ,GAAG,KAAK,CAAC;IACjB,QAAQ,GAAG,KAAK,CAAC;IAChB,cAAc,GAAG,IAAI,YAAY,EAAW,CAAC;IACd,aAAa,GAAqC,IAAI,CAAC;IACzC,SAAS,GAAG,IAAI,CAAC;IAExE,MAAM;QACJ,IAAI,IAAI,CAAC,QAAQ;YAAE,OAAO;QAC1B,IAAI,CAAC,QAAQ,GAAG,CAAC,IAAI,CAAC,QAAQ,CAAC;QAC/B,IAAI,CAAC,cAAc,CAAC,IAAI,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;IAC1C,CAAC;mHAZU,yBAAyB;6DAAzB,yBAAyB;wCAKtB,yBAAyB;;;;;YAL5B,wDAAyB;;;YArBhC,AADF,8BAAgI,gBAIzG;YAAnB,sGAAS,YAAQ,IAAC;YAClB,+BAAiC;YAG7B,AAFF,oGAAqB,2DAEZ;YAGX,iBAAO;YACP,uBAA0D;YAC5D,iBAAS;YACT,2FAAgB;YAKlB,iBAAM;;YAnB0E,AAAhD,4DAA+C,8CAAgD;YAG3H,cAAqB;YAArB,uCAAqB;;YAGnB,eAIC;YAJD,2CAIC;YAIL,eAIC;YAJD,uCAIC;4BApBK,gBAAgB;;iFAwBf,yBAAyB;cA3BrC,SAAS;eAAC;gBACT,QAAQ,EAAE,oBAAoB;gBAC9B,UAAU,EAAE,IAAI;gBAChB,OAAO,EAAE,CAAC,gBAAgB,CAAC;gBAC3B,QAAQ,EAAE;;;;;;;;;;;;;;;;;;;;;GAqBT;aACF;;kBAEE,KAAK;;kBACL,KAAK;;kBACL,KAAK;;kBACL,MAAM;;kBACN,YAAY;mBAAC,yBAAyB;;kBACtC,WAAW;mBAAC,+BAA+B;;kFANjC,yBAAyB","sourcesContent":["import { Component, Input, Output, EventEmitter, HostBinding, ContentChild, TemplateRef, Directive } from '@angular/core';\nimport { NgTemplateOutlet } from '@angular/common';\n\n/**\n * Directive to mark a template as the accordion panel title.\n * Supports rich HTML content (icons, badges, dynamic text).\n *\n * @example\n * ```html\n * <mj-accordion-panel [Expanded]=\"true\">\n * <ng-template mjAccordionTitle>\n * <i class=\"fa-solid fa-code\"></i> Template Editor\n * <span class=\"badge\">3</span>\n * </ng-template>\n * <p>Panel content here</p>\n * </mj-accordion-panel>\n * ```\n */\n@Directive({\n selector: '[mjAccordionTitle]',\n standalone: true\n})\nexport class MJAccordionTitleDirective {\n constructor(public templateRef: TemplateRef<unknown>) {}\n}\n\n/**\n * mj-accordion-panel — Collapsible panel. Replaces `<kendo-panelbar-item>` and `<kendo-expansionpanel>`.\n *\n * Supports two title modes:\n * - Simple string: `[Title]=\"'Details'\"` — plain text title\n * - Rich template: `<ng-template mjAccordionTitle>` — HTML with icons, badges, etc.\n *\n * @example\n * ```html\n * <!-- Simple string title -->\n * <mj-accordion-panel Title=\"Details\" [Expanded]=\"true\">\n * <p>Panel content here</p>\n * </mj-accordion-panel>\n *\n * <!-- Rich HTML title -->\n * <mj-accordion-panel [Expanded]=\"true\">\n * <ng-template mjAccordionTitle>\n * <i class=\"fa-solid fa-code\"></i> Template Editor\n * </ng-template>\n * <p>Panel content here</p>\n * </mj-accordion-panel>\n * ```\n */\n@Component({\n selector: 'mj-accordion-panel',\n standalone: true,\n imports: [NgTemplateOutlet],\n template: `\n <div class=\"mj-accordion-panel\" [class.mj-accordion-panel--expanded]=\"Expanded\" [class.mj-accordion-panel--disabled]=\"Disabled\">\n <button class=\"mj-accordion-header\" type=\"button\"\n [attr.aria-expanded]=\"Expanded\"\n [disabled]=\"Disabled\"\n (click)=\"Toggle()\">\n <span class=\"mj-accordion-title\">\n @if (titleTemplate) {\n <ng-container [ngTemplateOutlet]=\"titleTemplate.templateRef\"></ng-container>\n } @else {\n {{ Title }}\n }\n </span>\n <i class=\"fa-solid fa-chevron-down mj-accordion-icon\"></i>\n </button>\n @if (Expanded) {\n <div class=\"mj-accordion-body\" role=\"region\">\n <ng-content></ng-content>\n </div>\n }\n </div>\n `\n})\nexport class MJAccordionPanelComponent {\n @Input() Title = '';\n @Input() Expanded = false;\n @Input() Disabled = false;\n @Output() ExpandedChange = new EventEmitter<boolean>();\n @ContentChild(MJAccordionTitleDirective) titleTemplate: MJAccordionTitleDirective | null = null;\n @HostBinding('class.mj-accordion-panel-host') readonly hostClass = true;\n\n Toggle(): void {\n if (this.Disabled) return;\n this.Expanded = !this.Expanded;\n this.ExpandedChange.emit(this.Expanded);\n }\n}\n"]}
1
+ {"version":3,"file":"accordion.component.js","sourceRoot":"","sources":["../../../src/lib/accordion/accordion.component.ts"],"names":[],"mappings":"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","sourcesContent":["import { Component, Input, Output, EventEmitter, HostBinding, ContentChild, TemplateRef, Directive, NgModule } from '@angular/core';\nimport { NgTemplateOutlet } from '@angular/common';\n\n/** Process-wide counter for generating unique, stable accordion element ids\n * (used to wire `aria-controls` / `aria-labelledby` between header and body). */\nlet nextAccordionUid = 0;\n\n/**\n * Directive to mark a template as the accordion panel title.\n * Supports rich HTML content (icons, badges, dynamic text).\n *\n * @example\n * ```html\n * <mj-accordion-panel [Expanded]=\"true\">\n * <ng-template mjAccordionTitle>\n * <i class=\"fa-solid fa-code\"></i> Template Editor\n * <span class=\"badge\">3</span>\n * </ng-template>\n * <p>Panel content here</p>\n * </mj-accordion-panel>\n * ```\n */\n@Directive({\n selector: '[mjAccordionTitle]',\n standalone: true\n})\nexport class MJAccordionTitleDirective {\n constructor(public templateRef: TemplateRef<unknown>) {}\n}\n\n/**\n * Directive to mark a template as the accordion header **actions** — interactive\n * controls (edit / copy / run / checkbox, etc.) that sit in the header row but\n * are NOT the expand/collapse toggle. Rendered as a sibling of the toggle\n * `<button>`, so there's no button-in-button and the toggle stays a clean,\n * accessible control.\n *\n * @example\n * ```html\n * <mj-accordion-panel>\n * <ng-template mjAccordionTitle>Connection</ng-template>\n * <ng-template mjAccordionActions>\n * <button mjButton variant=\"icon\" (click)=\"edit()\"><i class=\"fa fa-pen\"></i></button>\n * </ng-template>\n * …body…\n * </mj-accordion-panel>\n * ```\n */\n@Directive({\n selector: '[mjAccordionActions]',\n standalone: true\n})\nexport class MJAccordionActionsDirective {\n constructor(public templateRef: TemplateRef<unknown>) {}\n}\n\n/**\n * Directive to mark a template as the accordion **body** — the panel's collapsible\n * content. Use this INSTEAD of placing content directly in the panel when the body\n * may be expensive (code editors, grids, large lists) OR just to be future-proof:\n * the accordion instantiates the template **lazily on first expand** and then keeps\n * it alive, so nothing is created until the user opens the panel, while later\n * open/close still animates. Consumers never have to reason about content weight or\n * write `@if (expanded)` themselves.\n *\n * @example\n * ```html\n * <mj-accordion-panel [Expanded]=\"open\" (ExpandedChange)=\"open = $event\">\n * <ng-template mjAccordionTitle>Configuration</ng-template>\n * <ng-template mjAccordionBody>\n * <mj-code-editor ...></mj-code-editor> <!-- not created until first opened -->\n * </ng-template>\n * </mj-accordion-panel>\n * ```\n */\n@Directive({\n selector: '[mjAccordionBody]',\n standalone: true\n})\nexport class MJAccordionBodyDirective {\n constructor(public templateRef: TemplateRef<unknown>) {}\n}\n\n/**\n * mj-accordion-panel — Collapsible panel. Replaces `<kendo-panelbar-item>` and `<kendo-expansionpanel>`.\n *\n * Supports two title modes:\n * - Simple string: `[Title]=\"'Details'\"` — plain text title\n * - Rich template: `<ng-template mjAccordionTitle>` — HTML with icons, badges, etc.\n *\n * @example\n * ```html\n * <!-- Simple string title -->\n * <mj-accordion-panel Title=\"Details\" [Expanded]=\"true\">\n * <p>Panel content here</p>\n * </mj-accordion-panel>\n *\n * <!-- Rich HTML title -->\n * <mj-accordion-panel [Expanded]=\"true\">\n * <ng-template mjAccordionTitle>\n * <i class=\"fa-solid fa-code\"></i> Template Editor\n * </ng-template>\n * <p>Panel content here</p>\n * </mj-accordion-panel>\n * ```\n */\n@Component({\n selector: 'mj-accordion-panel',\n standalone: true,\n imports: [NgTemplateOutlet],\n template: `\n <div class=\"mj-accordion-panel\" [class.mj-accordion-panel--expanded]=\"Expanded\" [class.mj-accordion-panel--disabled]=\"Disabled\"\n [class.mj-accordion-panel--muted-icon]=\"TitleIconMuted\"\n [class.mj-accordion-panel--sm]=\"Size === 'sm'\"\n [class.mj-accordion-panel--bare]=\"Bare\"\n [class.mj-accordion-panel--flush-body]=\"FlushBody\"\n [class.mj-accordion-panel--fill]=\"Fill\"\n [attr.data-variant]=\"Variant !== 'default' ? Variant : null\">\n <div class=\"mj-accordion-header-row\">\n <button class=\"mj-accordion-header\" type=\"button\"\n [id]=\"HeaderId\"\n [attr.aria-expanded]=\"Expanded\"\n [attr.aria-controls]=\"BodyId\"\n [disabled]=\"Disabled\"\n (click)=\"Toggle()\">\n <span class=\"mj-accordion-title\">\n @if (titleTemplate) {\n <ng-container [ngTemplateOutlet]=\"titleTemplate.templateRef\"></ng-container>\n } @else {\n {{ Title }}\n }\n </span>\n </button>\n @if (actionsTemplate) {\n <div class=\"mj-accordion-actions\">\n <ng-container [ngTemplateOutlet]=\"actionsTemplate.templateRef\"></ng-container>\n </div>\n }\n <!-- The chevron is ALWAYS the rightmost element of the header row (after any\n actions). It's a secondary, a11y-hidden toggle affordance — the primary\n disclosure control is the title button above (which owns aria-expanded). -->\n <button class=\"mj-accordion-chevron\" type=\"button\" tabindex=\"-1\" aria-hidden=\"true\"\n [disabled]=\"Disabled\" (click)=\"Toggle()\">\n <i class=\"fa-solid fa-chevron-down mj-accordion-icon\"></i>\n </button>\n </div>\n <div class=\"mj-accordion-body-outer\" [attr.inert]=\"Expanded ? null : ''\">\n <div class=\"mj-accordion-body-clip\">\n <div class=\"mj-accordion-body\" role=\"region\" [id]=\"BodyId\" [attr.aria-labelledby]=\"HeaderId\">\n <!-- Legacy: content placed directly in the panel (eager). -->\n <ng-content></ng-content>\n <!-- Preferred: [mjAccordionBody] template — instantiated lazily on first\n expand, then kept alive so later toggles still animate. -->\n @if (bodyTemplate && (Expanded || hasBeenExpanded)) {\n <ng-container [ngTemplateOutlet]=\"bodyTemplate.templateRef\"></ng-container>\n }\n </div>\n </div>\n </div>\n </div>\n `\n})\nexport class MJAccordionPanelComponent {\n @Input() Title = '';\n private _expanded = false;\n /** Latches true the first time the panel is expanded; never resets. Lets a\n * [mjAccordionBody] template instantiate lazily on first open and then stay\n * alive so subsequent open/close still animates. */\n private _everExpanded = false;\n @Input()\n set Expanded(value: boolean) {\n this._expanded = value;\n if (value) this._everExpanded = true;\n }\n get Expanded(): boolean { return this._expanded; }\n protected get hasBeenExpanded(): boolean { return this._everExpanded; }\n @Input() Disabled = false;\n /**\n * Emphasis variant for visual hierarchy:\n * - `primary` — bold, solid brand-colored header (use to make a panel stand out)\n * - `secondary` — subtle brand tint\n * - `default` — standard neutral header\n * All brand-token-driven, so dark-mode-safe and themeable.\n */\n @Input() Variant: 'default' | 'primary' | 'secondary' = 'default';\n /**\n * Render icons projected into the title slot in the muted color instead of the\n * header's primary text color. Lets consumers get the common \"quiet icon\" look\n * without writing CSS. Status/brand-colored icons can still be colored inline.\n */\n @Input() TitleIconMuted = false;\n /**\n * Density. `md` (default) is the standard size; `sm` tightens header padding and\n * font for dense contexts (sidebars, flyouts, nested panels).\n */\n @Input() Size: 'sm' | 'md' = 'md';\n /**\n * Bare chrome — drop the panel's own border and header background so the panel\n * sits cleanly inside a host that already provides chrome (e.g. an expandable\n * card). The toggle/title/chevron/body still work; only the box styling is removed.\n */\n @Input() Bare = false;\n /**\n * Remove the body's default padding, for bodies that manage their own spacing\n * (code editors, full-bleed grids, custom forms).\n */\n @Input() FlushBody = false;\n /**\n * Fill mode — for \"rail section that owns the leftover height\" cases (e.g. an\n * entity tree or grid that should consume all remaining vertical space and\n * scroll *internally*), rather than the default \"reveal stacked content\"\n * disclosure. When set AND expanded, the panel becomes a flex column that\n * fills its flex parent and its body becomes a `flex:1; min-height:0` region —\n * the projected content is expected to provide its own scroll child. While\n * collapsed, the panel behaves exactly like a normal panel (header only,\n * natural height) and does NOT claim the leftover space.\n *\n * Requires the panel's parent to be a flex column with `min-height:0`.\n * Note: the open/close height animation is skipped in fill mode (the body\n * fills rather than animating to content height).\n */\n @Input() Fill = false;\n @Output() ExpandedChange = new EventEmitter<boolean>();\n @ContentChild(MJAccordionTitleDirective) titleTemplate: MJAccordionTitleDirective | null = null;\n @ContentChild(MJAccordionActionsDirective) actionsTemplate: MJAccordionActionsDirective | null = null;\n @ContentChild(MJAccordionBodyDirective) bodyTemplate: MJAccordionBodyDirective | null = null;\n @HostBinding('class.mj-accordion-panel-host') readonly hostClass = true;\n /** Host claims flex:1 of its parent ONLY while a Fill panel is expanded —\n * so a collapsed Fill panel sits at natural (header) height like any other. */\n @HostBinding('class.mj-accordion-fill-active') get fillActive(): boolean {\n return this.Fill && this.Expanded;\n }\n\n /** Stable per-instance ids that programmatically associate the header\n * `<button>` with its body region (`aria-controls` ↔ `aria-labelledby`),\n * completing the WAI-ARIA accordion pattern so screen readers announce the\n * region with the header's name. */\n private readonly _uid = nextAccordionUid++;\n readonly HeaderId = `mj-accordion-header-${this._uid}`;\n readonly BodyId = `mj-accordion-body-${this._uid}`;\n\n Toggle(): void {\n if (this.Disabled) return;\n this.Expanded = !this.Expanded;\n this.ExpandedChange.emit(this.Expanded);\n }\n}\n\n/**\n * Convenience module bundling the accordion panel + all of its slot directives.\n * Import this ONE symbol instead of listing the component and each directive\n * separately:\n *\n * ```ts\n * import { MJAccordionModule } from '@memberjunction/ng-ui-components';\n * @NgModule({ imports: [MJAccordionModule, ...] }) // or @Component standalone imports\n * ```\n *\n * Why a module (not a bare `const [...]` array): Angular's AOT compiler can't\n * statically expand a value-array imported across a compiled-package boundary in\n * an `imports` array (NG1010), and `as const` makes it a readonly tuple the\n * `imports` type rejects (TS2322). An NgModule is always a valid `imports` entry\n * in both NgModule and standalone consumers. Adding a future accordion directive\n * here makes it available to every consumer automatically — no per-module churn.\n */\n@NgModule({\n imports: [\n MJAccordionPanelComponent,\n MJAccordionTitleDirective,\n MJAccordionActionsDirective,\n MJAccordionBodyDirective,\n ],\n exports: [\n MJAccordionPanelComponent,\n MJAccordionTitleDirective,\n MJAccordionActionsDirective,\n MJAccordionBodyDirective,\n ],\n})\nexport class MJAccordionModule {}\n"]}