@memberjunction/ng-tabstrip 5.51.0 → 6.1.0-edge.1

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.
package/LICENSE ADDED
@@ -0,0 +1,7 @@
1
+ ISC License
2
+
3
+ Copyright (c) 2023 MemberJunction
4
+
5
+ Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies.
6
+
7
+ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
package/README.md CHANGED
@@ -1,6 +1,14 @@
1
1
  # @memberjunction/ng-tabstrip
2
2
 
3
- A lightweight, zero-dependency Angular tab strip component for MemberJunction applications. Provides dynamic tab management with closeable tabs, scroll overflow handling, context menus, and programmatic tab control.
3
+ A projected-children Angular tab strip (`<mj-tabstrip>` / `<mj-tab>` / `<mj-tab-body>`) with closeable tabs, scroll overflow handling, context menus, and programmatic tab control.
4
+
5
+ **Appearance and keyboard behaviour are shared, not local.** Tabs are styled by the global `.mj-tabs*` chrome and driven by the `mjTabList` ARIA directive, both from `@memberjunction/ng-ui-components` — one definition shared with `mj-workspace-tab-strip`, so MJ's tab strips cannot drift apart. Inside MJ Explorer the chrome is already loaded; a **standalone host must import it globally** or tabs render as unstyled divs:
6
+
7
+ ```scss
8
+ @import '@memberjunction/ng-ui-components/dist/lib/tabs/tabs';
9
+ ```
10
+
11
+ The strip sizes to its content — the host owns region sizing (the old viewport-height behavior is gone; give your container a height if you want an internally-scrolling tab region). For data-driven tabs, prefer `mj-tab-nav` or `mj-workspace-tab-strip` from `ng-ui-components`.
4
12
 
5
13
  ## Installation
6
14
 
@@ -4,9 +4,10 @@ import * as i2 from "./tab-body/tab-body.component";
4
4
  import * as i3 from "./tab/tab.component";
5
5
  import * as i4 from "@angular/common";
6
6
  import * as i5 from "@memberjunction/ng-container-directives";
7
+ import * as i6 from "@memberjunction/ng-ui-components";
7
8
  export declare class MJTabStripModule {
8
9
  static ɵfac: i0.ɵɵFactoryDeclaration<MJTabStripModule, never>;
9
- static ɵmod: i0.ɵɵNgModuleDeclaration<MJTabStripModule, [typeof i1.MJTabStripComponent, typeof i2.MJTabBodyComponent, typeof i3.MJTabComponent], [typeof i4.CommonModule, typeof i5.ContainerDirectivesModule], [typeof i1.MJTabStripComponent, typeof i2.MJTabBodyComponent, typeof i3.MJTabComponent]>;
10
+ static ɵmod: i0.ɵɵNgModuleDeclaration<MJTabStripModule, [typeof i1.MJTabStripComponent, typeof i2.MJTabBodyComponent, typeof i3.MJTabComponent], [typeof i4.CommonModule, typeof i5.ContainerDirectivesModule, typeof i6.MJTabListDirective], [typeof i1.MJTabStripComponent, typeof i2.MJTabBodyComponent, typeof i3.MJTabComponent]>;
10
11
  static ɵinj: i0.ɵɵInjectorDeclaration<MJTabStripModule>;
11
12
  }
12
13
  //# sourceMappingURL=module.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"module.d.ts","sourceRoot":"","sources":["../../src/lib/module.ts"],"names":[],"mappings":";;;;;;AASA,qBAgBa,gBAAgB;yCAAhB,gBAAgB;0CAAhB,gBAAgB;0CAAhB,gBAAgB;CAAI"}
1
+ {"version":3,"file":"module.d.ts","sourceRoot":"","sources":["../../src/lib/module.ts"],"names":[],"mappings":";;;;;;;AAWA,qBAiBa,gBAAgB;yCAAhB,gBAAgB;0CAAhB,gBAAgB;0CAAhB,gBAAgB;CAAI"}
@@ -5,6 +5,8 @@ import { MJTabStripComponent } from './tab-strip/tab-strip.component';
5
5
  import { MJTabBodyComponent } from './tab-body/tab-body.component';
6
6
  import { MJTabComponent } from './tab/tab.component';
7
7
  import { ContainerDirectivesModule } from '@memberjunction/ng-container-directives';
8
+ // The ARIA tabs keyboard contract, shared with the draft/workspace strip so the two cannot drift.
9
+ import { MJTabListDirective } from '@memberjunction/ng-ui-components';
8
10
  import * as i0 from "@angular/core";
9
11
  export class MJTabStripModule {
10
12
  static ɵfac = function MJTabStripModule_Factory(__ngFactoryType__) { return new (__ngFactoryType__ || MJTabStripModule)(); };
@@ -23,6 +25,7 @@ export class MJTabStripModule {
23
25
  imports: [
24
26
  CommonModule,
25
27
  ContainerDirectivesModule,
28
+ MJTabListDirective,
26
29
  ],
27
30
  exports: [
28
31
  MJTabStripComponent,
@@ -34,7 +37,8 @@ export class MJTabStripModule {
34
37
  (function () { (typeof ngJitMode === "undefined" || ngJitMode) && i0.ɵɵsetNgModuleScope(MJTabStripModule, { declarations: [MJTabStripComponent,
35
38
  MJTabBodyComponent,
36
39
  MJTabComponent], imports: [CommonModule,
37
- ContainerDirectivesModule], exports: [MJTabStripComponent,
40
+ ContainerDirectivesModule,
41
+ MJTabListDirective], exports: [MJTabStripComponent,
38
42
  MJTabBodyComponent,
39
43
  MJTabComponent] }); })();
40
44
  //# sourceMappingURL=module.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"module.js","sourceRoot":"","sources":["../../src/lib/module.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAC;AACzC,OAAO,EAAE,YAAY,EAAE,MAAM,iBAAiB,CAAC;AAE/C,QAAQ;AACR,OAAO,EAAE,mBAAmB,EAAE,MAAM,iCAAiC,CAAC;AACtE,OAAO,EAAE,kBAAkB,EAAE,MAAM,+BAA+B,CAAC;AACnE,OAAO,EAAE,cAAc,EAAE,MAAM,qBAAqB,CAAC;AACrD,OAAO,EAAE,yBAAyB,EAAE,MAAM,yCAAyC,CAAC;;AAkBpF,MAAM,OAAO,gBAAgB;0GAAhB,gBAAgB;4DAAhB,gBAAgB;gEATzB,YAAY;YACZ,yBAAyB;;iFAQhB,gBAAgB;cAhB5B,QAAQ;eAAC;gBACR,YAAY,EAAE;oBACZ,mBAAmB;oBACnB,kBAAkB;oBAClB,cAAc;iBACf;gBACD,OAAO,EAAE;oBACP,YAAY;oBACZ,yBAAyB;iBAC1B;gBACD,OAAO,EAAE;oBACP,mBAAmB;oBACnB,kBAAkB;oBAClB,cAAc;iBACf;aACF;;wFACY,gBAAgB,mBAdzB,mBAAmB;QACnB,kBAAkB;QAClB,cAAc,aAGd,YAAY;QACZ,yBAAyB,aAGzB,mBAAmB;QACnB,kBAAkB;QAClB,cAAc","sourcesContent":["import { NgModule } from '@angular/core';\nimport { CommonModule } from '@angular/common';\n\n// LOCAL\nimport { MJTabStripComponent } from './tab-strip/tab-strip.component';\nimport { MJTabBodyComponent } from './tab-body/tab-body.component';\nimport { MJTabComponent } from './tab/tab.component';\nimport { ContainerDirectivesModule } from '@memberjunction/ng-container-directives';\n\n@NgModule({\n declarations: [\n MJTabStripComponent,\n MJTabBodyComponent,\n MJTabComponent\n ],\n imports: [\n CommonModule,\n ContainerDirectivesModule,\n ],\n exports: [\n MJTabStripComponent,\n MJTabBodyComponent,\n MJTabComponent\n ]\n})\nexport class MJTabStripModule { }"]}
1
+ {"version":3,"file":"module.js","sourceRoot":"","sources":["../../src/lib/module.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAC;AACzC,OAAO,EAAE,YAAY,EAAE,MAAM,iBAAiB,CAAC;AAE/C,QAAQ;AACR,OAAO,EAAE,mBAAmB,EAAE,MAAM,iCAAiC,CAAC;AACtE,OAAO,EAAE,kBAAkB,EAAE,MAAM,+BAA+B,CAAC;AACnE,OAAO,EAAE,cAAc,EAAE,MAAM,qBAAqB,CAAC;AACrD,OAAO,EAAE,yBAAyB,EAAE,MAAM,yCAAyC,CAAC;AACpF,kGAAkG;AAClG,OAAO,EAAE,kBAAkB,EAAE,MAAM,kCAAkC,CAAC;;AAmBtE,MAAM,OAAO,gBAAgB;0GAAhB,gBAAgB;4DAAhB,gBAAgB;gEAVzB,YAAY;YACZ,yBAAyB;;iFAShB,gBAAgB;cAjB5B,QAAQ;eAAC;gBACR,YAAY,EAAE;oBACZ,mBAAmB;oBACnB,kBAAkB;oBAClB,cAAc;iBACf;gBACD,OAAO,EAAE;oBACP,YAAY;oBACZ,yBAAyB;oBACzB,kBAAkB;iBACnB;gBACD,OAAO,EAAE;oBACP,mBAAmB;oBACnB,kBAAkB;oBAClB,cAAc;iBACf;aACF;;wFACY,gBAAgB,mBAfzB,mBAAmB;QACnB,kBAAkB;QAClB,cAAc,aAGd,YAAY;QACZ,yBAAyB;QACzB,kBAAkB,aAGlB,mBAAmB;QACnB,kBAAkB;QAClB,cAAc","sourcesContent":["import { NgModule } from '@angular/core';\nimport { CommonModule } from '@angular/common';\n\n// LOCAL\nimport { MJTabStripComponent } from './tab-strip/tab-strip.component';\nimport { MJTabBodyComponent } from './tab-body/tab-body.component';\nimport { MJTabComponent } from './tab/tab.component';\nimport { ContainerDirectivesModule } from '@memberjunction/ng-container-directives';\n// The ARIA tabs keyboard contract, shared with the draft/workspace strip so the two cannot drift.\nimport { MJTabListDirective } from '@memberjunction/ng-ui-components';\n\n@NgModule({\n declarations: [\n MJTabStripComponent,\n MJTabBodyComponent,\n MJTabComponent\n ],\n imports: [\n CommonModule,\n ContainerDirectivesModule,\n MJTabListDirective,\n ],\n exports: [\n MJTabStripComponent,\n MJTabBodyComponent,\n MJTabComponent\n ]\n})\nexport class MJTabStripModule { }"]}
@@ -1 +1 @@
1
- {"version":3,"file":"tab.component.d.ts","sourceRoot":"","sources":["../../../src/lib/tab/tab.component.ts"],"names":[],"mappings":"AAAA,OAAO,EAAgD,iBAAiB,EAAE,UAAU,EAAE,MAAM,eAAe,CAAC;AAC5G,OAAO,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AACxC,OAAO,EAAE,mBAAmB,EAAE,MAAM,kCAAkC,CAAC;;AAEvE;;GAEG;AACH,qBAMa,cAAe,SAAQ,SAAS;IAuEvB,OAAO,CAAC,QAAQ;IACxB,OAAO,CAAC,GAAG;IACJ,UAAU,EAAE,UAAU;IAxEzC,OAAO,CAAC,YAAY,CAAkB;IACtC;;OAEG;IACH,IAAa,WAAW,IAGD,OAAO,CAD7B;IACD,IAAI,WAAW,CAAC,KAAK,EAAE,OAAO,EAG7B;IAED,OAAO,CAAC,QAAQ,CAAiB;IACjC,IAAa,OAAO,IAAI,OAAO,CAE9B;IACD,IAAW,OAAO,CAAC,KAAK,EAAE,OAAO,EAchC;IAED,OAAO,CAAC,KAAK,CAAa;IAC1B,IAAa,IAAI,IAAI,MAAM,CAE1B;IACD,IAAW,IAAI,CAAC,KAAK,EAAE,MAAM,EAE5B;IAED,OAAO,CAAC,GAAG,CAAa;IACxB,IAAa,EAAE,IAAI,GAAG,CAErB;IACD,IAAW,EAAE,CAAC,KAAK,EAAE,GAAG,EAEvB;IAED,OAAO,CAAC,MAAM,CAAa;IAC3B;;OAEG;IACH,IAAa,KAAK,IAAI,GAAG,CAExB;IACD,IAAW,KAAK,CAAC,KAAK,EAAE,GAAG,EAE1B;IAED;;OAEG;IACM,YAAY,EAAE,OAAO,CAAS;IAEvC;;OAEG;IACH,IAAW,QAAQ,IAAI,mBAAmB,CAEzC;gBAC2B,QAAQ,EAAE,mBAAmB,EACrC,GAAG,EAAE,iBAAiB,EACvB,UAAU,EAAE,UAAU;IAIzC;;;OAGG;IACI,SAAS;IAIhB;;OAEG;IACI,QAAQ,CAAC,MAAM,EAAE,UAAU;IAK3B,iBAAiB,CAAC,MAAM,EAAE,UAAU;yCA7FhC,cAAc;2CAAd,cAAc;CAiG1B"}
1
+ {"version":3,"file":"tab.component.d.ts","sourceRoot":"","sources":["../../../src/lib/tab/tab.component.ts"],"names":[],"mappings":"AAAA,OAAO,EAAgD,iBAAiB,EAAE,UAAU,EAAE,MAAM,eAAe,CAAC;AAC5G,OAAO,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AACxC,OAAO,EAAE,mBAAmB,EAAE,MAAM,kCAAkC,CAAC;;AAEvE;;GAEG;AACH,qBASa,cAAe,SAAQ,SAAS;IAuEvB,OAAO,CAAC,QAAQ;IACxB,OAAO,CAAC,GAAG;IACJ,UAAU,EAAE,UAAU;IAxEzC,OAAO,CAAC,YAAY,CAAkB;IACtC;;OAEG;IACH,IAAa,WAAW,IAGD,OAAO,CAD7B;IACD,IAAI,WAAW,CAAC,KAAK,EAAE,OAAO,EAG7B;IAED,OAAO,CAAC,QAAQ,CAAiB;IACjC,IAAa,OAAO,IAAI,OAAO,CAE9B;IACD,IAAW,OAAO,CAAC,KAAK,EAAE,OAAO,EAchC;IAED,OAAO,CAAC,KAAK,CAAa;IAC1B,IAAa,IAAI,IAAI,MAAM,CAE1B;IACD,IAAW,IAAI,CAAC,KAAK,EAAE,MAAM,EAE5B;IAED,OAAO,CAAC,GAAG,CAAa;IACxB,IAAa,EAAE,IAAI,GAAG,CAErB;IACD,IAAW,EAAE,CAAC,KAAK,EAAE,GAAG,EAEvB;IAED,OAAO,CAAC,MAAM,CAAa;IAC3B;;OAEG;IACH,IAAa,KAAK,IAAI,GAAG,CAExB;IACD,IAAW,KAAK,CAAC,KAAK,EAAE,GAAG,EAE1B;IAED;;OAEG;IACM,YAAY,EAAE,OAAO,CAAS;IAEvC;;OAEG;IACH,IAAW,QAAQ,IAAI,mBAAmB,CAEzC;gBAC2B,QAAQ,EAAE,mBAAmB,EACrC,GAAG,EAAE,iBAAiB,EACvB,UAAU,EAAE,UAAU;IAIzC;;;OAGG;IACI,SAAS;IAIhB;;OAEG;IACI,QAAQ,CAAC,MAAM,EAAE,UAAU;IAK3B,iBAAiB,CAAC,MAAM,EAAE,UAAU;yCA7FhC,cAAc;2CAAd,cAAc;CAiG1B"}
@@ -4,12 +4,12 @@ import * as i0 from "@angular/core";
4
4
  import * as i1 from "../tab-strip/tab-strip.component";
5
5
  import * as i2 from "@angular/common";
6
6
  const _c0 = ["*"];
7
- const _c1 = a0 => ({ "single-tab-selected": a0 });
8
- function MJTabComponent_Conditional_2_Template(rf, ctx) { if (rf & 1) {
7
+ const _c1 = (a0, a1) => ({ "single-tab-selected": a0, "mj-tabs__tab--active": a1 });
8
+ function MJTabComponent_Conditional_3_Template(rf, ctx) { if (rf & 1) {
9
9
  const _r1 = i0.ɵɵgetCurrentView();
10
- i0.ɵɵelementStart(0, "span", 2);
11
- i0.ɵɵlistener("click", function MJTabComponent_Conditional_2_Template_span_click_0_listener($event) { i0.ɵɵrestoreView(_r1); const ctx_r1 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r1.closeTab($event)); });
12
- i0.ɵɵtext(1, "\u2716");
10
+ i0.ɵɵelementStart(0, "button", 3);
11
+ i0.ɵɵlistener("click", function MJTabComponent_Conditional_3_Template_button_click_0_listener($event) { i0.ɵɵrestoreView(_r1); const ctx_r1 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r1.closeTab($event)); });
12
+ i0.ɵɵelement(1, "i", 4);
13
13
  i0.ɵɵelementEnd();
14
14
  } }
15
15
  /**
@@ -106,22 +106,25 @@ export class MJTabComponent extends MJTabBase {
106
106
  this.tabstrip.handleTabContextMenu($event, this);
107
107
  }
108
108
  static ɵfac = function MJTabComponent_Factory(__ngFactoryType__) { return new (__ngFactoryType__ || MJTabComponent)(i0.ɵɵdirectiveInject(i1.MJTabStripComponent, 1), i0.ɵɵdirectiveInject(i0.ChangeDetectorRef), i0.ɵɵdirectiveInject(i0.ElementRef)); };
109
- static ɵcmp = /*@__PURE__*/ i0.ɵɵdefineComponent({ type: MJTabComponent, selectors: [["mj-tab"]], inputs: { TabSelected: "TabSelected", Visible: "Visible", Name: "Name", ID: "ID", Props: "Props", TabCloseable: "TabCloseable" }, standalone: false, features: [i0.ɵɵInheritDefinitionFeature], ngContentSelectors: _c0, decls: 3, vars: 4, consts: [[1, "single-tab", 3, "click", "contextmenu", "ngClass"], [1, "tab-close-button"], [1, "tab-close-button", 3, "click"]], template: function MJTabComponent_Template(rf, ctx) { if (rf & 1) {
109
+ static ɵcmp = /*@__PURE__*/ i0.ɵɵdefineComponent({ type: MJTabComponent, selectors: [["mj-tab"]], hostAttrs: ["role", "presentation"], inputs: { TabSelected: "TabSelected", Visible: "Visible", Name: "Name", ID: "ID", Props: "Props", TabCloseable: "TabCloseable" }, standalone: false, features: [i0.ɵɵInheritDefinitionFeature], ngContentSelectors: _c0, decls: 4, vars: 6, consts: [["role", "tab", 1, "single-tab", "mj-tabs__tab", 3, "click", "contextmenu", "ngClass"], [1, "mj-tabs__label"], ["type", "button", "tabindex", "-1", "aria-label", "Close tab", 1, "tab-close-button", "mj-tabs__close"], ["type", "button", "tabindex", "-1", "aria-label", "Close tab", 1, "tab-close-button", "mj-tabs__close", 3, "click"], ["aria-hidden", "true", 1, "fa-solid", "fa-xmark"]], template: function MJTabComponent_Template(rf, ctx) { if (rf & 1) {
110
110
  i0.ɵɵprojectionDef();
111
111
  i0.ɵɵelementStart(0, "div", 0);
112
112
  i0.ɵɵlistener("click", function MJTabComponent_Template_div_click_0_listener() { return ctx.selectTab(); })("contextmenu", function MJTabComponent_Template_div_contextmenu_0_listener($event) { return ctx.handleContextMenu($event); });
113
- i0.ɵɵprojection(1);
114
- i0.ɵɵconditionalCreate(2, MJTabComponent_Conditional_2_Template, 2, 0, "span", 1);
113
+ i0.ɵɵelementStart(1, "span", 1);
114
+ i0.ɵɵprojection(2);
115
+ i0.ɵɵelementEnd();
116
+ i0.ɵɵconditionalCreate(3, MJTabComponent_Conditional_3_Template, 2, 0, "button", 2);
115
117
  i0.ɵɵelementEnd();
116
118
  } if (rf & 2) {
117
- i0.ɵɵproperty("ngClass", i0.ɵɵpureFunction1(2, _c1, ctx.TabSelected));
118
- i0.ɵɵadvance(2);
119
- i0.ɵɵconditional(ctx.TabCloseable ? 2 : -1);
120
- } }, dependencies: [i2.NgClass], styles: [".single-tab[_ngcontent-%COMP%] {\n flex: 0 0 auto;\n cursor: pointer;\n display: flex;\n align-items: center;\n margin-right: 2px;\n padding: .5rem;\n border-radius: var(--mj-radius-md) var(--mj-radius-md) 0 0;\n border-top: solid 1px var(--gray-600);\n border-left: solid 1px var(--gray-600);\n border-right: solid 1px var(--gray-600);\n border-bottom: 0;\n background-color: var(--mj-bg-surface);\n}\n\n.single-tab-selected[_ngcontent-%COMP%] {\n color: var(--mj-blue);\n}\n\n.tab-close-button[_ngcontent-%COMP%] {\n cursor: pointer;\n margin-left: 10px;\n padding: 2px;\n font-size: var(--mj-text-xs);\n border-radius: var(--mj-radius-lg);\n color: var(--gray-800);\n}\n\n.tab-close-button[_ngcontent-%COMP%]:hover {\n color: var(--gray-900);\n}"] });
119
+ i0.ɵɵproperty("ngClass", i0.ɵɵpureFunction2(3, _c1, ctx.TabSelected, ctx.TabSelected));
120
+ i0.ɵɵattribute("aria-selected", ctx.TabSelected);
121
+ i0.ɵɵadvance(3);
122
+ i0.ɵɵconditional(ctx.TabCloseable ? 3 : -1);
123
+ } }, dependencies: [i2.NgClass], encapsulation: 2 });
121
124
  }
122
125
  (() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassMetadata(MJTabComponent, [{
123
126
  type: Component,
124
- args: [{ standalone: false, selector: 'mj-tab', template: "<div class=\"single-tab\" [ngClass]=\"{'single-tab-selected': TabSelected}\" (click)=\"selectTab()\" (contextmenu)=\"handleContextMenu($event)\">\n <ng-content><!--CONTENT PROJECTION GOES HERE--></ng-content>\n @if (TabCloseable) {\n <span class=\"tab-close-button\" (click)=\"closeTab($event)\" >\u2716</span>\n }\n</div>", styles: [".single-tab {\n flex: 0 0 auto;\n cursor: pointer;\n display: flex;\n align-items: center;\n margin-right: 2px;\n padding: .5rem;\n border-radius: var(--mj-radius-md) var(--mj-radius-md) 0 0;\n border-top: solid 1px var(--gray-600);\n border-left: solid 1px var(--gray-600);\n border-right: solid 1px var(--gray-600);\n border-bottom: 0;\n background-color: var(--mj-bg-surface);\n}\n\n.single-tab-selected {\n color: var(--mj-blue);\n}\n\n.tab-close-button {\n cursor: pointer;\n margin-left: 10px;\n padding: 2px;\n font-size: var(--mj-text-xs);\n border-radius: var(--mj-radius-lg);\n color: var(--gray-800);\n}\n\n.tab-close-button:hover {\n color: var(--gray-900);\n}"] }]
127
+ args: [{ standalone: false, selector: 'mj-tab', host: { role: 'presentation' }, template: "<!-- role=\"tab\" sits on the element that actually takes focus, and `tabindex` is owned by the\n mjTabList directive on the parent (roving) \u2014 so it is deliberately not bound here. Chrome comes\n from the global .mj-tabs* stylesheet, shared with the draft/workspace strip. The legacy\n `single-tab` classes are kept alongside so existing selectors (incl. the test-utils example)\n keep resolving. -->\n<div\n class=\"single-tab mj-tabs__tab\"\n [ngClass]=\"{'single-tab-selected': TabSelected, 'mj-tabs__tab--active': TabSelected}\"\n role=\"tab\"\n [attr.aria-selected]=\"TabSelected\"\n (click)=\"selectTab()\"\n (contextmenu)=\"handleContextMenu($event)\">\n <span class=\"mj-tabs__label\"><ng-content><!--CONTENT PROJECTION GOES HERE--></ng-content></span>\n @if (TabCloseable) {\n <!-- tabindex=\"-1\": the TAB is the focus stop and Delete closes it, so a second stop per tab\n would double the strip's length in the page tab order. -->\n <button\n type=\"button\"\n class=\"tab-close-button mj-tabs__close\"\n tabindex=\"-1\"\n aria-label=\"Close tab\"\n (click)=\"closeTab($event)\">\n <i class=\"fa-solid fa-xmark\" aria-hidden=\"true\"></i>\n </button>\n }\n</div>\n", styles: ["/* Intentionally (almost) empty.\n *\n * A tab's appearance is defined ONCE, in the global `.mj-tabs*` chrome shipped by\n * @memberjunction/ng-ui-components (lib/tabs/tabs.scss) and shared with the draft/workspace strip.\n * Rules here would silently win that argument \u2014 Angular's emulated encapsulation adds an attribute\n * selector, so a component-scoped `.single-tab` out-specifies the global `.mj-tabs__tab` \u2014 which is\n * exactly how the two strips came to look different in the first place.\n *\n * What was removed and why it is not worth restoring:\n * - borders on `--gray-600`, close button on `--gray-800`/`--gray-900`: legacy aliases that\n * resolve to PRIMITIVE tokens, so they never re-pointed in dark mode;\n * - a selected state expressed only as `color: var(--mj-blue)`: a text-colour change alone, with\n * no surface or weight shift, which read as barely-selected next to the rest of Explorer;\n * - a hand-typed `\u2716` close glyph, against the Font Awesome convention.\n *\n * If a tab genuinely needs to look different here, that is a change to the shared sheet, not a\n * local override.\n */\n"] }]
125
128
  }], () => [{ type: i1.MJTabStripComponent, decorators: [{
126
129
  type: Host
127
130
  }] }, { type: i0.ChangeDetectorRef }, { type: i0.ElementRef }], { TabSelected: [{
@@ -137,5 +140,5 @@ export class MJTabComponent extends MJTabBase {
137
140
  }], TabCloseable: [{
138
141
  type: Input
139
142
  }] }); })();
140
- (() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassDebugInfo(MJTabComponent, { className: "MJTabComponent", filePath: "src/lib/tab/tab.component.ts", lineNumber: 14 }); })();
143
+ (() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassDebugInfo(MJTabComponent, { className: "MJTabComponent", filePath: "src/lib/tab/tab.component.ts", lineNumber: 17 }); })();
141
144
  //# sourceMappingURL=tab.component.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"tab.component.js","sourceRoot":"","sources":["../../../src/lib/tab/tab.component.ts","../../../src/lib/tab/tab.component.html"],"names":[],"mappings":"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","sourcesContent":["import { Component, Input, Output, EventEmitter, Host, ChangeDetectorRef, ElementRef } from '@angular/core';\nimport { MJTabBase } from '../tab.base';\nimport { MJTabStripComponent } from '../tab-strip/tab-strip.component';\n\n/**\n * Represents the tab in the header of a given tab strip\n */\n@Component({\n standalone: false,\n selector: 'mj-tab',\n templateUrl: './tab.component.html',\n styleUrl: './tab.component.css'\n})\nexport class MJTabComponent extends MJTabBase {\n private _tabSelected: boolean = false;\n /**\n * Determines if the tab is currently selected or not. This is set by the TabStrip component automatically when the SelectedTabIndex is set, do not set this directly.\n */\n @Input() get TabSelected() {\n return this._tabSelected;\n } \n set TabSelected(value: boolean) {\n this._tabSelected = value;\n this.cdr.detectChanges(); // Manually trigger change detection to update the view\n }\n\n private _visible: boolean = true;\n @Input() get Visible(): boolean {\n return this._visible;\n }\n public set Visible(value: boolean) {\n this._visible = value;\n // whenever the visible property changes we need to set the display style to none if it is not visible and make sure\n // we're not selected and set to tab index of 0 if we're selected\n\n // Step 1 - get the elementRef and set our display to none\n if (!this._visible)\n this.elementRef.nativeElement.style.display = value ? \"\" : \"none\";\n else\n this.elementRef.nativeElement.style.display = \"\";\n\n // Step 2 - if we're not visible, make sure we're not selected\n if (!this._visible)\n this.tabstrip.SelectedTabIndex = 0;\n }\n\n private _name: string = \"\"\n @Input() get Name(): string {\n return this._name;\n }\n public set Name(value: string) {\n this._name = value;\n }\n\n private _id: any = null;\n @Input() get ID(): any {\n return this._id;\n }\n public set ID(value: any) {\n this._id = value;\n }\n\n private _props: any = null;\n /**\n * A property bag that can be used to store any additional properties that you want to associate with this tab.\n */\n @Input() get Props(): any {\n return this._props;\n }\n public set Props(value: any) {\n this._props = value;\n }\n\n /**\n * Determines if the tab can be closed by a user, or not. Defaults to false.\n */\n @Input() TabCloseable: boolean = false;\n\n /**\n * Returns a reference to the tab strip that this tab belongs to.\n */\n public get TabStrip(): MJTabStripComponent {\n return this.tabstrip;\n }\n constructor(@Host() private tabstrip: MJTabStripComponent, \n private cdr: ChangeDetectorRef,\n public elementRef: ElementRef) {\n super();\n }\n\n /**\n * Event handler for when this tab is clicked to select it, generally not a great idea to call this directly, but it is possible to call directly to simulate a click. \n * The preferred approach is to set the SelectedTabIndex property on the TabStrip component directly.\n */\n public selectTab() {\n this.tabstrip.SelectedTabIndex = this.index;\n }\n\n /**\n * Event handler for when the close button is clicked on the tab. This will fire the BeforeTabClosed event on the TabStrip component, and if it is not cancelled, will then fire the AfterTabClosed event.\n */\n public closeTab($event: MouseEvent) {\n $event.stopPropagation(); // prevent click from going to the tab\n this.tabstrip.CloseTab(this.index);\n }\n\n public handleContextMenu($event: MouseEvent) {\n $event.preventDefault();\n this.tabstrip.handleTabContextMenu($event, this);\n }\n}\n","<div class=\"single-tab\" [ngClass]=\"{'single-tab-selected': TabSelected}\" (click)=\"selectTab()\" (contextmenu)=\"handleContextMenu($event)\">\n <ng-content><!--CONTENT PROJECTION GOES HERE--></ng-content>\n @if (TabCloseable) {\n <span class=\"tab-close-button\" (click)=\"closeTab($event)\" >✖</span>\n }\n</div>"]}
1
+ {"version":3,"file":"tab.component.js","sourceRoot":"","sources":["../../../src/lib/tab/tab.component.ts","../../../src/lib/tab/tab.component.html"],"names":[],"mappings":"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","sourcesContent":["import { Component, Input, Output, EventEmitter, Host, ChangeDetectorRef, ElementRef } from '@angular/core';\nimport { MJTabBase } from '../tab.base';\nimport { MJTabStripComponent } from '../tab-strip/tab-strip.component';\n\n/**\n * Represents the tab in the header of a given tab strip\n */\n@Component({\n standalone: false,\n selector: 'mj-tab',\n templateUrl: './tab.component.html',\n styleUrl: './tab.component.css',\n // The ARIA tablist's children must be the role=\"tab\" elements; this host element is an extra\n // layer between them, so it opts out of the accessibility tree's structure.\n host: { role: 'presentation' },\n})\nexport class MJTabComponent extends MJTabBase {\n private _tabSelected: boolean = false;\n /**\n * Determines if the tab is currently selected or not. This is set by the TabStrip component automatically when the SelectedTabIndex is set, do not set this directly.\n */\n @Input() get TabSelected() {\n return this._tabSelected;\n } \n set TabSelected(value: boolean) {\n this._tabSelected = value;\n this.cdr.detectChanges(); // Manually trigger change detection to update the view\n }\n\n private _visible: boolean = true;\n @Input() get Visible(): boolean {\n return this._visible;\n }\n public set Visible(value: boolean) {\n this._visible = value;\n // whenever the visible property changes we need to set the display style to none if it is not visible and make sure\n // we're not selected and set to tab index of 0 if we're selected\n\n // Step 1 - get the elementRef and set our display to none\n if (!this._visible)\n this.elementRef.nativeElement.style.display = value ? \"\" : \"none\";\n else\n this.elementRef.nativeElement.style.display = \"\";\n\n // Step 2 - if we're not visible, make sure we're not selected\n if (!this._visible)\n this.tabstrip.SelectedTabIndex = 0;\n }\n\n private _name: string = \"\"\n @Input() get Name(): string {\n return this._name;\n }\n public set Name(value: string) {\n this._name = value;\n }\n\n private _id: any = null;\n @Input() get ID(): any {\n return this._id;\n }\n public set ID(value: any) {\n this._id = value;\n }\n\n private _props: any = null;\n /**\n * A property bag that can be used to store any additional properties that you want to associate with this tab.\n */\n @Input() get Props(): any {\n return this._props;\n }\n public set Props(value: any) {\n this._props = value;\n }\n\n /**\n * Determines if the tab can be closed by a user, or not. Defaults to false.\n */\n @Input() TabCloseable: boolean = false;\n\n /**\n * Returns a reference to the tab strip that this tab belongs to.\n */\n public get TabStrip(): MJTabStripComponent {\n return this.tabstrip;\n }\n constructor(@Host() private tabstrip: MJTabStripComponent, \n private cdr: ChangeDetectorRef,\n public elementRef: ElementRef) {\n super();\n }\n\n /**\n * Event handler for when this tab is clicked to select it, generally not a great idea to call this directly, but it is possible to call directly to simulate a click. \n * The preferred approach is to set the SelectedTabIndex property on the TabStrip component directly.\n */\n public selectTab() {\n this.tabstrip.SelectedTabIndex = this.index;\n }\n\n /**\n * Event handler for when the close button is clicked on the tab. This will fire the BeforeTabClosed event on the TabStrip component, and if it is not cancelled, will then fire the AfterTabClosed event.\n */\n public closeTab($event: MouseEvent) {\n $event.stopPropagation(); // prevent click from going to the tab\n this.tabstrip.CloseTab(this.index);\n }\n\n public handleContextMenu($event: MouseEvent) {\n $event.preventDefault();\n this.tabstrip.handleTabContextMenu($event, this);\n }\n}\n","<!-- role=\"tab\" sits on the element that actually takes focus, and `tabindex` is owned by the\n mjTabList directive on the parent (roving) — so it is deliberately not bound here. Chrome comes\n from the global .mj-tabs* stylesheet, shared with the draft/workspace strip. The legacy\n `single-tab` classes are kept alongside so existing selectors (incl. the test-utils example)\n keep resolving. -->\n<div\n class=\"single-tab mj-tabs__tab\"\n [ngClass]=\"{'single-tab-selected': TabSelected, 'mj-tabs__tab--active': TabSelected}\"\n role=\"tab\"\n [attr.aria-selected]=\"TabSelected\"\n (click)=\"selectTab()\"\n (contextmenu)=\"handleContextMenu($event)\">\n <span class=\"mj-tabs__label\"><ng-content><!--CONTENT PROJECTION GOES HERE--></ng-content></span>\n @if (TabCloseable) {\n <!-- tabindex=\"-1\": the TAB is the focus stop and Delete closes it, so a second stop per tab\n would double the strip's length in the page tab order. -->\n <button\n type=\"button\"\n class=\"tab-close-button mj-tabs__close\"\n tabindex=\"-1\"\n aria-label=\"Close tab\"\n (click)=\"closeTab($event)\">\n <i class=\"fa-solid fa-xmark\" aria-hidden=\"true\"></i>\n </button>\n }\n</div>\n"]}
@@ -1,13 +1,17 @@
1
+ import { ElementRef } from '@angular/core';
1
2
  import { MJTabBase } from '../tab.base';
2
3
  import { MJTabStripComponent } from '../tab-strip/tab-strip.component';
3
4
  import * as i0 from "@angular/core";
4
5
  export declare class MJTabBodyComponent extends MJTabBase {
5
6
  private tabStrip;
7
+ elementRef: ElementRef;
6
8
  TabVisible: boolean;
9
+ /** @deprecated No longer read — the body sizes to content and the HOST owns region sizing. Kept only so existing bindings compile; remove on the next major. */
7
10
  FillWidth: boolean;
11
+ /** @deprecated No longer read — the body sizes to content and the HOST owns region sizing. Kept only so existing bindings compile; remove on the next major. */
8
12
  FillHeight: boolean;
9
- constructor(tabStrip: MJTabStripComponent);
10
- static ɵfac: i0.ɵɵFactoryDeclaration<MJTabBodyComponent, [{ host: true; }]>;
13
+ constructor(tabStrip: MJTabStripComponent, elementRef: ElementRef);
14
+ static ɵfac: i0.ɵɵFactoryDeclaration<MJTabBodyComponent, [{ host: true; }, null]>;
11
15
  static ɵcmp: i0.ɵɵComponentDeclaration<MJTabBodyComponent, "mj-tab-body", never, { "TabVisible": { "alias": "TabVisible"; "required": false; }; "FillWidth": { "alias": "FillWidth"; "required": false; }; "FillHeight": { "alias": "FillHeight"; "required": false; }; }, {}, never, ["*"], false, never>;
12
16
  }
13
17
  //# sourceMappingURL=tab-body.component.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"tab-body.component.d.ts","sourceRoot":"","sources":["../../../src/lib/tab-body/tab-body.component.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AACxC,OAAO,EAAE,mBAAmB,EAAE,MAAM,kCAAkC,CAAC;;AAEvE,qBAMa,kBAAmB,SAAQ,SAAS;IAM3B,OAAO,CAAC,QAAQ;IAL3B,UAAU,UAAS;IAEnB,SAAS,EAAE,OAAO,CAAQ;IAC1B,UAAU,EAAE,OAAO,CAAQ;gBAER,QAAQ,EAAE,mBAAmB;yCAN9C,kBAAkB;2CAAlB,kBAAkB;CAS9B"}
1
+ {"version":3,"file":"tab-body.component.d.ts","sourceRoot":"","sources":["../../../src/lib/tab-body/tab-body.component.ts"],"names":[],"mappings":"AACA,OAAO,EAAa,UAAU,EAAe,MAAM,eAAe,CAAC;AACnE,OAAO,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AACxC,OAAO,EAAE,mBAAmB,EAAE,MAAM,kCAAkC,CAAC;;AAEvE,qBAMa,kBAAmB,SAAQ,SAAS;IAQ3B,OAAO,CAAC,QAAQ;IAA8B,UAAU,EAAE,UAAU;IAP/E,UAAU,UAAS;IAE5B,gKAAgK;IACvJ,SAAS,EAAE,OAAO,CAAQ;IACnC,gKAAgK;IACvJ,UAAU,EAAE,OAAO,CAAQ;gBAER,QAAQ,EAAE,mBAAmB,EAAS,UAAU,EAAE,UAAU;yCAR7E,kBAAkB;2CAAlB,kBAAkB;CAW9B"}
@@ -1,33 +1,37 @@
1
- import { Component, Input, Host } from '@angular/core';
1
+ import { Component, Host, Input } from '@angular/core';
2
2
  import { MJTabBase } from '../tab.base';
3
3
  import * as i0 from "@angular/core";
4
4
  import * as i1 from "../tab-strip/tab-strip.component";
5
5
  const _c0 = ["*"];
6
6
  export class MJTabBodyComponent extends MJTabBase {
7
7
  tabStrip;
8
+ elementRef;
8
9
  TabVisible = false;
10
+ /** @deprecated No longer read — the body sizes to content and the HOST owns region sizing. Kept only so existing bindings compile; remove on the next major. */
9
11
  FillWidth = true;
12
+ /** @deprecated No longer read — the body sizes to content and the HOST owns region sizing. Kept only so existing bindings compile; remove on the next major. */
10
13
  FillHeight = true;
11
- constructor(tabStrip) {
14
+ constructor(tabStrip, elementRef) {
12
15
  super();
13
16
  this.tabStrip = tabStrip;
17
+ this.elementRef = elementRef;
14
18
  }
15
- static ɵfac = function MJTabBodyComponent_Factory(__ngFactoryType__) { return new (__ngFactoryType__ || MJTabBodyComponent)(i0.ɵɵdirectiveInject(i1.MJTabStripComponent, 1)); };
16
- static ɵcmp = /*@__PURE__*/ i0.ɵɵdefineComponent({ type: MJTabBodyComponent, selectors: [["mj-tab-body"]], inputs: { TabVisible: "TabVisible", FillWidth: "FillWidth", FillHeight: "FillHeight" }, standalone: false, features: [i0.ɵɵInheritDefinitionFeature], ngContentSelectors: _c0, decls: 2, vars: 1, consts: [[1, "tab-body", 3, "hidden"]], template: function MJTabBodyComponent_Template(rf, ctx) { if (rf & 1) {
19
+ static ɵfac = function MJTabBodyComponent_Factory(__ngFactoryType__) { return new (__ngFactoryType__ || MJTabBodyComponent)(i0.ɵɵdirectiveInject(i1.MJTabStripComponent, 1), i0.ɵɵdirectiveInject(i0.ElementRef)); };
20
+ static ɵcmp = /*@__PURE__*/ i0.ɵɵdefineComponent({ type: MJTabBodyComponent, selectors: [["mj-tab-body"]], inputs: { TabVisible: "TabVisible", FillWidth: "FillWidth", FillHeight: "FillHeight" }, standalone: false, features: [i0.ɵɵInheritDefinitionFeature], ngContentSelectors: _c0, decls: 2, vars: 1, consts: [["role", "tabpanel", 1, "tab-body", 3, "hidden"]], template: function MJTabBodyComponent_Template(rf, ctx) { if (rf & 1) {
17
21
  i0.ɵɵprojectionDef();
18
22
  i0.ɵɵelementStart(0, "div", 0);
19
23
  i0.ɵɵprojection(1);
20
24
  i0.ɵɵelementEnd();
21
25
  } if (rf & 2) {
22
26
  i0.ɵɵproperty("hidden", !ctx.TabVisible);
23
- } }, styles: [".tab-body[_ngcontent-%COMP%] {\n border-top: 0;\n width: 100%;\n display: block;\n overflow-y: auto;\n overflow-x: hidden;\n height: calc(100vh - 123px);\n }\n\n .tab-body[_ngcontent-%COMP%] .tab-body[_ngcontent-%COMP%] {\n height: auto;\n }"] });
27
+ } }, styles: ["\n\n\n\n\n\n\n\n\n\n.tab-body[_ngcontent-%COMP%] {\n border-top: 0;\n width: 100%;\n display: block;\n}"] });
24
28
  }
25
29
  (() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassMetadata(MJTabBodyComponent, [{
26
30
  type: Component,
27
- args: [{ standalone: false, selector: 'mj-tab-body', template: "<div class=\"tab-body\" [hidden]=\"!TabVisible\">\n <ng-content><!--CONTENT PROJECTION GOES HERE--></ng-content>\n</div> ", styles: [" .tab-body {\n border-top: 0;\n width: 100%;\n display: block;\n overflow-y: auto;\n overflow-x: hidden;\n height: calc(100vh - 123px);\n }\n\n .tab-body .tab-body {\n height: auto;\n }"] }]
31
+ args: [{ standalone: false, selector: 'mj-tab-body', template: "<div\n class=\"tab-body\"\n role=\"tabpanel\"\n [hidden]=\"!TabVisible\">\n <ng-content><!--CONTENT PROJECTION GOES HERE--></ng-content>\n</div>\n", styles: ["/* Sizes to CONTENT; the host decides how tall the tab region is.\n *\n * The removed `height: calc(100vh - 123px)` was the last of the strip's three viewport-math\n * hardcodings (container, header, body). A body pinned to viewport height blows out any host that\n * isn't a full page \u2014 one line of content rendered 641px tall in a card \u2014 which pushes whatever\n * follows the strip below the fold, so merely Tab-bing focus to the next element forces the pane\n * to scroll and the whole area visibly jumps. A host that wants a fixed-height, internally\n * scrolling tab region sets that height on ITS container, like every other MJ widget. */\n\n.tab-body {\n border-top: 0;\n width: 100%;\n display: block;\n}\n"] }]
28
32
  }], () => [{ type: i1.MJTabStripComponent, decorators: [{
29
33
  type: Host
30
- }] }], { TabVisible: [{
34
+ }] }, { type: i0.ElementRef }], { TabVisible: [{
31
35
  type: Input
32
36
  }], FillWidth: [{
33
37
  type: Input
@@ -1 +1 @@
1
- {"version":3,"file":"tab-body.component.js","sourceRoot":"","sources":["../../../src/lib/tab-body/tab-body.component.ts","../../../src/lib/tab-body/tab-body.component.html"],"names":[],"mappings":"AACA,OAAO,EAAE,SAAS,EAAE,KAAK,EAAE,IAAI,EAAE,MAAM,eAAe,CAAC;AACvD,OAAO,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;;;;AASxC,MAAM,OAAO,kBAAmB,SAAQ,SAAS;IAMnB;IALnB,UAAU,GAAG,KAAK,CAAC;IAEnB,SAAS,GAAY,IAAI,CAAC;IAC1B,UAAU,GAAY,IAAI,CAAC;IAEpC,YAA4B,QAA6B;QACvD,KAAK,EAAE,CAAC;QADkB,aAAQ,GAAR,QAAQ,CAAqB;IAEzD,CAAC;4GARU,kBAAkB;6DAAlB,kBAAkB;;YCX/B,8BAA6C;YACzC,kBAA4D;YAChE,iBAAM;;YAFgB,wCAAsB;;;iFDW/B,kBAAkB;cAN9B,SAAS;6BACI,KAAK,YACP,aAAa;;sBAUV,IAAI;;kBALhB,KAAK;;kBAEL,KAAK;;kBACL,KAAK;;kFAJK,kBAAkB","sourcesContent":["\nimport { Component, Input, Host } from '@angular/core';\nimport { MJTabBase } from '../tab.base';\nimport { MJTabStripComponent } from '../tab-strip/tab-strip.component';\n\n@Component({\n standalone: false,\n selector: 'mj-tab-body',\n templateUrl: './tab-body.component.html',\n styleUrl: './tab-body.component.css'\n})\nexport class MJTabBodyComponent extends MJTabBase {\n @Input() TabVisible = false;\n\n @Input() FillWidth: boolean = true;\n @Input() FillHeight: boolean = true;\n \n constructor(@Host() private tabStrip: MJTabStripComponent) {\n super();\n }\n}\n","<div class=\"tab-body\" [hidden]=\"!TabVisible\">\n <ng-content><!--CONTENT PROJECTION GOES HERE--></ng-content>\n</div> "]}
1
+ {"version":3,"file":"tab-body.component.js","sourceRoot":"","sources":["../../../src/lib/tab-body/tab-body.component.ts","../../../src/lib/tab-body/tab-body.component.html"],"names":[],"mappings":"AACA,OAAO,EAAE,SAAS,EAAc,IAAI,EAAE,KAAK,EAAE,MAAM,eAAe,CAAC;AACnE,OAAO,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;;;;AASxC,MAAM,OAAO,kBAAmB,SAAQ,SAAS;IAQnB;IAAsC;IAPzD,UAAU,GAAG,KAAK,CAAC;IAE5B,gKAAgK;IACvJ,SAAS,GAAY,IAAI,CAAC;IACnC,gKAAgK;IACvJ,UAAU,GAAY,IAAI,CAAC;IAEpC,YAA4B,QAA6B,EAAS,UAAsB;QACtF,KAAK,EAAE,CAAC;QADkB,aAAQ,GAAR,QAAQ,CAAqB;QAAS,eAAU,GAAV,UAAU,CAAY;IAExF,CAAC;4GAVU,kBAAkB;6DAAlB,kBAAkB;;YCX/B,8BAGyB;YACrB,kBAA4D;YAChE,iBAAM;;YAFJ,wCAAsB;;;iFDQX,kBAAkB;cAN9B,SAAS;6BACI,KAAK,YACP,aAAa;;sBAYV,IAAI;;kBAPhB,KAAK;;kBAGL,KAAK;;kBAEL,KAAK;;kFANK,kBAAkB","sourcesContent":["\nimport { Component, ElementRef, Host, Input } from '@angular/core';\nimport { MJTabBase } from '../tab.base';\nimport { MJTabStripComponent } from '../tab-strip/tab-strip.component';\n\n@Component({\n standalone: false,\n selector: 'mj-tab-body',\n templateUrl: './tab-body.component.html',\n styleUrl: './tab-body.component.css'\n})\nexport class MJTabBodyComponent extends MJTabBase {\n @Input() TabVisible = false;\n\n /** @deprecated No longer read — the body sizes to content and the HOST owns region sizing. Kept only so existing bindings compile; remove on the next major. */\n @Input() FillWidth: boolean = true;\n /** @deprecated No longer read — the body sizes to content and the HOST owns region sizing. Kept only so existing bindings compile; remove on the next major. */\n @Input() FillHeight: boolean = true;\n \n constructor(@Host() private tabStrip: MJTabStripComponent, public elementRef: ElementRef) {\n super();\n }\n}\n","<div\n class=\"tab-body\"\n role=\"tabpanel\"\n [hidden]=\"!TabVisible\">\n <ng-content><!--CONTENT PROJECTION GOES HERE--></ng-content>\n</div>\n"]}
@@ -29,8 +29,15 @@ export declare class MJTabStripComponent implements AfterContentInit, AfterConte
29
29
  static OutputDebugInfo: boolean;
30
30
  protected static OutputDebugMessage(message: string): void;
31
31
  constructor(cdr: ChangeDetectorRef);
32
+ /** @deprecated No longer read — the strip sizes to content and the HOST owns region sizing. Kept only so existing bindings compile; remove on the next major. */
32
33
  FillWidth: boolean;
34
+ /** @deprecated No longer read — the strip sizes to content and the HOST owns region sizing. Kept only so existing bindings compile; remove on the next major. */
33
35
  FillHeight: boolean;
36
+ /**
37
+ * Per-instance id base pairing each tab with its panel (`aria-controls` / `aria-labelledby`).
38
+ * Index-suffixed by the tab/body components themselves once `syncTabIndexes` has run.
39
+ */
40
+ readonly IdBase: string;
34
41
  /**
35
42
  * This event is raised whenever the TabStrip component determines it would be advisable to conduct any necessary
36
43
  * resizing action in the parent container. Implement an event handler to handle this, if desired, for your application.
@@ -111,6 +118,25 @@ export declare class MJTabStripComponent implements AfterContentInit, AfterConte
111
118
  ScrollAmount: number;
112
119
  scrollLeft(): void;
113
120
  scrollRight(): void;
121
+ /**
122
+ * Keyboard navigation from the shared `mjTabList` directive (arrows / Home / End / Enter).
123
+ *
124
+ * The directive reports a POSITION among the rendered `[role="tab"]` elements, which is already
125
+ * this component's identity model, so the mapping is direct. Selecting also scrolls the tab into
126
+ * view — arrowing to a tab hidden behind the overflow edge would otherwise move focus somewhere
127
+ * the user cannot see.
128
+ */
129
+ onTabActivateRequested(request: {
130
+ Index: number;
131
+ }): void;
132
+ /**
133
+ * Delete / Backspace on a focused tab. Routed through the SAME `CloseTab` path a click on the
134
+ * close button uses, so the cancelable `BeforeTabClosed` contract holds for keyboard users too.
135
+ * Ignored for tabs that are not closeable.
136
+ */
137
+ onTabCloseRequested(request: {
138
+ Index: number;
139
+ }): void;
114
140
  /**
115
141
  * This method will scroll the specified tab index into view if it is not currently visible in the tab strip.
116
142
  * @param tabIndex
@@ -1 +1 @@
1
- {"version":3,"file":"tab-strip.component.d.ts","sourceRoot":"","sources":["../../../src/lib/tab-strip/tab-strip.component.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"tab-strip.component.d.ts","sourceRoot":"","sources":["../../../src/lib/tab-strip/tab-strip.component.ts"],"names":[],"mappings":"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"}
@@ -1,21 +1,23 @@
1
1
  import { Component, Input, EventEmitter, Output, ContentChildren, ViewChild, HostListener } from '@angular/core';
2
+ import { warnIfTabChromeMissing } from '@memberjunction/ng-ui-components';
2
3
  import { MJTabComponent } from '../tab/tab.component';
3
4
  import { MJTabBodyComponent } from '../tab-body/tab-body.component';
4
5
  import * as i0 from "@angular/core";
6
+ import * as i1 from "@memberjunction/ng-ui-components";
5
7
  const _c0 = ["tabInnerContainer"];
6
8
  const _c1 = [[["mj-tab"]], [["mj-tab-body"]]];
7
9
  const _c2 = ["mj-tab", "mj-tab-body"];
8
10
  function MJTabStripComponent_Conditional_2_Template(rf, ctx) { if (rf & 1) {
9
- const _r1 = i0.ɵɵgetCurrentView();
10
- i0.ɵɵelementStart(0, "div", 7);
11
- i0.ɵɵlistener("click", function MJTabStripComponent_Conditional_2_Template_div_click_0_listener() { i0.ɵɵrestoreView(_r1); const ctx_r1 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r1.scrollLeft()); });
11
+ const _r2 = i0.ɵɵgetCurrentView();
12
+ i0.ɵɵelementStart(0, "button", 7);
13
+ i0.ɵɵlistener("click", function MJTabStripComponent_Conditional_2_Template_button_click_0_listener() { i0.ɵɵrestoreView(_r2); const ctx_r2 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r2.scrollLeft()); });
12
14
  i0.ɵɵelement(1, "span", 8);
13
15
  i0.ɵɵelementEnd();
14
16
  } }
15
17
  function MJTabStripComponent_Conditional_6_Template(rf, ctx) { if (rf & 1) {
16
- const _r3 = i0.ɵɵgetCurrentView();
17
- i0.ɵɵelementStart(0, "div", 9);
18
- i0.ɵɵlistener("click", function MJTabStripComponent_Conditional_6_Template_div_click_0_listener() { i0.ɵɵrestoreView(_r3); const ctx_r1 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r1.scrollRight()); });
18
+ const _r4 = i0.ɵɵgetCurrentView();
19
+ i0.ɵɵelementStart(0, "button", 9);
20
+ i0.ɵɵlistener("click", function MJTabStripComponent_Conditional_6_Template_button_click_0_listener() { i0.ɵɵrestoreView(_r4); const ctx_r2 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r2.scrollRight()); });
19
21
  i0.ɵɵelement(1, "span", 10);
20
22
  i0.ɵɵelementEnd();
21
23
  } }
@@ -40,6 +42,8 @@ export class TabClosedEvent extends TabEvent {
40
42
  export class TabContextMenuEvent extends TabEvent {
41
43
  mouseEvent;
42
44
  }
45
+ /** Source of per-instance DOM id bases — see {@link MJTabStripComponent.IdBase}. */
46
+ let tabStripIdSeq = 0;
43
47
  export class MJTabStripComponent {
44
48
  cdr;
45
49
  _selectedTabIndex = 0; // default to negative 1 so any valid value of 0+ will invoke a state change internally later
@@ -52,8 +56,15 @@ export class MJTabStripComponent {
52
56
  constructor(cdr) {
53
57
  this.cdr = cdr;
54
58
  }
59
+ /** @deprecated No longer read — the strip sizes to content and the HOST owns region sizing. Kept only so existing bindings compile; remove on the next major. */
55
60
  FillWidth = true;
61
+ /** @deprecated No longer read — the strip sizes to content and the HOST owns region sizing. Kept only so existing bindings compile; remove on the next major. */
56
62
  FillHeight = true;
63
+ /**
64
+ * Per-instance id base pairing each tab with its panel (`aria-controls` / `aria-labelledby`).
65
+ * Index-suffixed by the tab/body components themselves once `syncTabIndexes` has run.
66
+ */
67
+ IdBase = `mj-tabstrip-${++tabStripIdSeq}`;
57
68
  /**
58
69
  * This event is raised whenever the TabStrip component determines it would be advisable to conduct any necessary
59
70
  * resizing action in the parent container. Implement an event handler to handle this, if desired, for your application.
@@ -157,6 +168,9 @@ export class MJTabStripComponent {
157
168
  _viewInitialized = false;
158
169
  ngAfterViewInit() {
159
170
  this._viewInitialized = true;
171
+ // Dev-mode guard: the .mj-tabs* chrome lives in a global stylesheet a standalone host must
172
+ // import; a missing import renders bare divs with no error. Warn instead of staying silent.
173
+ warnIfTabChromeMissing(this.tabInnerContainer?.nativeElement?.closest('.mj-tabs') ?? undefined);
160
174
  this.SelectedTabIndex = this.SelectedTabIndex; // force a refresh of the tab visibility
161
175
  this.syncTabIndexes();
162
176
  this.checkTabScrollButtons();
@@ -179,10 +193,28 @@ export class MJTabStripComponent {
179
193
  }
180
194
  syncTabIndexes() {
181
195
  if (!this._viewInitialized)
182
- return; // don't do anything until the view is initialized
196
+ return; // don't do anything until the view is initialized
183
197
  // Automatically assign indices to tabs and tab bodies
184
198
  this.tabs.forEach((tab, index) => tab.index = index);
185
199
  this.tabBodies.forEach((body, index) => body.index = index);
200
+ // Pair each tab with its panel for assistive tech (`aria-controls` / `aria-labelledby`).
201
+ // Written directly to the DOM rather than template-bound, because `index` is only known HERE —
202
+ // after the first render — and a binding that changes mid-cycle trips NG0100 in dev mode.
203
+ // Idempotent, and re-run whenever the tab set changes, so ids follow reorders/removals.
204
+ this.tabs.forEach((tab, index) => {
205
+ const el = tab.elementRef?.nativeElement?.querySelector('[role="tab"]');
206
+ if (el) {
207
+ el.id = `${this.IdBase}-tab-${index}`;
208
+ el.setAttribute('aria-controls', `${this.IdBase}-panel-${index}`);
209
+ }
210
+ });
211
+ this.tabBodies.forEach((body, index) => {
212
+ const el = body.elementRef?.nativeElement?.querySelector('[role="tabpanel"]');
213
+ if (el) {
214
+ el.id = `${this.IdBase}-panel-${index}`;
215
+ el.setAttribute('aria-labelledby', `${this.IdBase}-tab-${index}`);
216
+ }
217
+ });
186
218
  if (this.SelectedTabIndex === null && this.tabs.length > 0) {
187
219
  this.SelectedTabIndex = 0;
188
220
  }
@@ -263,25 +295,24 @@ export class MJTabStripComponent {
263
295
  this.checkTabScrollButtons();
264
296
  }
265
297
  checkTabScrollButtons() {
266
- if (this.tabInnerContainer && this.tabInnerContainer.nativeElement && this.tabInnerContainer.nativeElement.parentElement) {
298
+ if (this.tabInnerContainer && this.tabInnerContainer.nativeElement) {
299
+ // The list itself is the scroller now (`.mj-tabs__list` is `overflow-x: auto`), so overflow
300
+ // and position are read off its NATIVE scroll state — the old scheme of animating a `left`
301
+ // offset against a relatively-positioned wrapper is gone with the wrapper's CSS.
267
302
  const container = this.tabInnerContainer.nativeElement;
268
- const parent = container.parentElement;
269
- const currentLeft = container.style.left ? parseInt(container.style.left) : 0;
270
- // show the right button if the container is wider than the parent AND the left position(which is zero or negative) + the container width is greater than the parent width
271
- this.showRightButton = container.clientWidth > parent.clientWidth &&
272
- currentLeft + container.clientWidth > parent.clientWidth;
273
- // Show left button if left position is less than 0, meaning some of the left side of the container is off screen
274
- this.showLeftButton = currentLeft < 0;
303
+ const overflow = container.scrollWidth - container.clientWidth;
304
+ this.showLeftButton = overflow > 0 && container.scrollLeft > 0;
305
+ this.showRightButton = overflow > 0 && container.scrollLeft < overflow - 1;
275
306
  }
276
307
  }
277
308
  scrollTabHeader(scrollAmount) {
278
- const style = this.tabInnerContainer.nativeElement.style;
279
- if (style) {
280
- const curLeft = style.left ? parseInt(style.left) : 0;
281
- style.left = (curLeft + scrollAmount) + 'px';
282
- this.checkTabScrollButtons(); // can do immediately because the above is direct DOM manipulation so the effect is immediate
283
- this.TabScrolled.emit();
284
- }
309
+ // Positive amount = reveal content to the LEFT (the old `left`-offset convention, preserved so
310
+ // ScrollAmount and the button wiring keep their meaning); native scrollLeft counts the other way.
311
+ const container = this.tabInnerContainer.nativeElement;
312
+ container.scrollBy({ left: -scrollAmount, behavior: 'smooth' });
313
+ // Smooth scrolling settles asynchronously; re-evaluate the buttons when it has.
314
+ setTimeout(() => this.checkTabScrollButtons(), 300);
315
+ this.TabScrolled.emit();
285
316
  }
286
317
  /**
287
318
  * This property determines how many pixels to scroll when the scrollLeft or scrollRight methods are called.
@@ -293,37 +324,42 @@ export class MJTabStripComponent {
293
324
  scrollRight() {
294
325
  this.scrollTabHeader(-150);
295
326
  }
327
+ /**
328
+ * Keyboard navigation from the shared `mjTabList` directive (arrows / Home / End / Enter).
329
+ *
330
+ * The directive reports a POSITION among the rendered `[role="tab"]` elements, which is already
331
+ * this component's identity model, so the mapping is direct. Selecting also scrolls the tab into
332
+ * view — arrowing to a tab hidden behind the overflow edge would otherwise move focus somewhere
333
+ * the user cannot see.
334
+ */
335
+ onTabActivateRequested(request) {
336
+ if (request.Index >= 0 && request.Index < this.tabs.length) {
337
+ this.SelectedTabIndex = request.Index;
338
+ this.scrollIntoView(request.Index);
339
+ }
340
+ }
341
+ /**
342
+ * Delete / Backspace on a focused tab. Routed through the SAME `CloseTab` path a click on the
343
+ * close button uses, so the cancelable `BeforeTabClosed` contract holds for keyboard users too.
344
+ * Ignored for tabs that are not closeable.
345
+ */
346
+ onTabCloseRequested(request) {
347
+ const tab = this.tabs?.toArray()[request.Index];
348
+ if (tab?.TabCloseable) {
349
+ void this.CloseTab(request.Index);
350
+ }
351
+ }
296
352
  /**
297
353
  * This method will scroll the specified tab index into view if it is not currently visible in the tab strip.
298
354
  * @param tabIndex
299
355
  */
300
356
  scrollIntoView(tabIndex) {
301
- // In this method, we need to calculate the current left position of the specified tab,
302
- // if it is not visible we need to scroll left or scroll right sufficiently in order to ensure that the tab specified is visible
303
- // we do NOT change tab selection, the caller can do that separately if they want to
357
+ // We do NOT change tab selection the caller does that separately if they want to. The list
358
+ // is a native horizontal scroller now, so the browser's own logic does the geometry.
304
359
  if (tabIndex >= 0 && tabIndex < this.tabs.length) {
305
- const tab = this.tabs.toArray()[tabIndex];
306
- if (tab) {
307
- const tabElement = tab.elementRef.nativeElement;
308
- if (tabElement) {
309
- const tabLeft = tabElement.offsetLeft;
310
- const tabRight = tabLeft + tabElement.offsetWidth;
311
- const container = this.tabInnerContainer.nativeElement;
312
- const containerLeft = container.offsetLeft;
313
- const containerRight = containerLeft + container.offsetWidth;
314
- if (tabLeft < containerLeft) {
315
- // tab is off to the left, scroll left
316
- this.scrollTabHeader(tabLeft - containerLeft);
317
- }
318
- else if (tabRight > containerRight) {
319
- // tab is off to the right, scroll right
320
- this.scrollTabHeader(tabRight - containerRight);
321
- }
322
- else {
323
- // tab is already visible, do nothing
324
- }
325
- }
326
- }
360
+ const tabElement = this.tabs.toArray()[tabIndex]?.elementRef?.nativeElement;
361
+ tabElement?.scrollIntoView({ block: 'nearest', inline: 'nearest', behavior: 'smooth' });
362
+ setTimeout(() => this.checkTabScrollButtons(), 300);
327
363
  }
328
364
  }
329
365
  static ɵfac = function MJTabStripComponent_Factory(__ngFactoryType__) { return new (__ngFactoryType__ || MJTabStripComponent)(i0.ɵɵdirectiveInject(i0.ChangeDetectorRef)); };
@@ -340,14 +376,16 @@ export class MJTabStripComponent {
340
376
  i0.ɵɵqueryRefresh(_t = i0.ɵɵloadQuery()) && (ctx.tabInnerContainer = _t.first);
341
377
  } }, hostBindings: function MJTabStripComponent_HostBindings(rf, ctx) { if (rf & 1) {
342
378
  i0.ɵɵlistener("resize", function MJTabStripComponent_resize_HostBindingHandler($event) { return ctx.onResize($event); }, i0.ɵɵresolveWindow);
343
- } }, inputs: { FillWidth: "FillWidth", FillHeight: "FillHeight", SelectedTabIndex: "SelectedTabIndex", ScrollAmount: "ScrollAmount" }, outputs: { ResizeContainer: "ResizeContainer", BeforeTabSelected: "BeforeTabSelected", TabSelected: "TabSelected", BeforeTabClosed: "BeforeTabClosed", TabClosed: "TabClosed", TabContextMenu: "TabContextMenu", TabScrolled: "TabScrolled" }, standalone: false, ngContentSelectors: _c2, decls: 9, vars: 2, consts: [["tabInnerContainer", ""], [1, "tabstrip-container"], [1, "tab-header-outer"], [1, "tab-scroll-button", "tab-scroll-button-left"], [1, "tab-header-inner"], [1, "tab-scroll-button", "tab-scroll-button-right"], [1, "tab-bodies"], [1, "tab-scroll-button", "tab-scroll-button-left", 3, "click"], [1, "fa-solid", "fa-caret-left"], [1, "tab-scroll-button", "tab-scroll-button-right", 3, "click"], [1, "fa-solid", "fa-caret-right"]], template: function MJTabStripComponent_Template(rf, ctx) { if (rf & 1) {
379
+ } }, inputs: { FillWidth: "FillWidth", FillHeight: "FillHeight", SelectedTabIndex: "SelectedTabIndex", ScrollAmount: "ScrollAmount" }, outputs: { ResizeContainer: "ResizeContainer", BeforeTabSelected: "BeforeTabSelected", TabSelected: "TabSelected", BeforeTabClosed: "BeforeTabClosed", TabClosed: "TabClosed", TabContextMenu: "TabContextMenu", TabScrolled: "TabScrolled" }, standalone: false, ngContentSelectors: _c2, decls: 9, vars: 2, consts: [["tabInnerContainer", ""], [1, "tabstrip-container"], [1, "tab-header-outer", "mj-tabs", "mj-tabs__bar"], ["type", "button", "tabindex", "-1", "aria-label", "Scroll tabs left", 1, "mj-tabs__scroll"], ["mjTabList", "", 1, "tab-header-inner", "mj-tabs__list", 3, "scroll", "TabActivateRequested", "TabCloseRequested"], ["type", "button", "tabindex", "-1", "aria-label", "Scroll tabs right", 1, "mj-tabs__scroll"], [1, "tab-bodies"], ["type", "button", "tabindex", "-1", "aria-label", "Scroll tabs left", 1, "mj-tabs__scroll", 3, "click"], ["aria-hidden", "true", 1, "fa-solid", "fa-caret-left"], ["type", "button", "tabindex", "-1", "aria-label", "Scroll tabs right", 1, "mj-tabs__scroll", 3, "click"], ["aria-hidden", "true", 1, "fa-solid", "fa-caret-right"]], template: function MJTabStripComponent_Template(rf, ctx) { if (rf & 1) {
380
+ const _r1 = i0.ɵɵgetCurrentView();
344
381
  i0.ɵɵprojectionDef(_c1);
345
382
  i0.ɵɵelementStart(0, "div", 1)(1, "div", 2);
346
- i0.ɵɵconditionalCreate(2, MJTabStripComponent_Conditional_2_Template, 2, 0, "div", 3);
383
+ i0.ɵɵconditionalCreate(2, MJTabStripComponent_Conditional_2_Template, 2, 0, "button", 3);
347
384
  i0.ɵɵelementStart(3, "div", 4, 0);
385
+ i0.ɵɵlistener("scroll", function MJTabStripComponent_Template_div_scroll_3_listener() { i0.ɵɵrestoreView(_r1); return i0.ɵɵresetView(ctx.checkTabScrollButtons()); })("TabActivateRequested", function MJTabStripComponent_Template_div_TabActivateRequested_3_listener($event) { i0.ɵɵrestoreView(_r1); return i0.ɵɵresetView(ctx.onTabActivateRequested($event)); })("TabCloseRequested", function MJTabStripComponent_Template_div_TabCloseRequested_3_listener($event) { i0.ɵɵrestoreView(_r1); return i0.ɵɵresetView(ctx.onTabCloseRequested($event)); });
348
386
  i0.ɵɵprojection(5);
349
387
  i0.ɵɵelementEnd();
350
- i0.ɵɵconditionalCreate(6, MJTabStripComponent_Conditional_6_Template, 2, 0, "div", 5);
388
+ i0.ɵɵconditionalCreate(6, MJTabStripComponent_Conditional_6_Template, 2, 0, "button", 5);
351
389
  i0.ɵɵelementEnd();
352
390
  i0.ɵɵelementStart(7, "div", 6);
353
391
  i0.ɵɵprojection(8, 1);
@@ -357,11 +395,11 @@ export class MJTabStripComponent {
357
395
  i0.ɵɵconditional(ctx.showLeftButton ? 2 : -1);
358
396
  i0.ɵɵadvance(4);
359
397
  i0.ɵɵconditional(ctx.showRightButton ? 6 : -1);
360
- } }, styles: [".tabstrip-container[_ngcontent-%COMP%] {\n display: block;\n height: calc(100vh - 80px);\n overflow-y: auto;\n}\n\n.tabstrip-container[_ngcontent-%COMP%] .tabstrip-container[_ngcontent-%COMP%] {\n display: block;\n height: auto;\n}\n\n.tab-header-outer[_ngcontent-%COMP%] {\n position: relative;\n display: flex;\n align-items: center;\n overflow: hidden;\n \n\n background-color: var(--gray-600);\n}\n\n.tab-header-inner[_ngcontent-%COMP%] {\n display: flex;\n flex-direction: row;\n white-space: nowrap;\n \n\n position: relative;\n \n\n z-index: 1;\n \n\n padding-left: 5px;\n padding-top: 5px;\n}\n\n.tab-scroll-button-left[_ngcontent-%COMP%], \n.tab-scroll-button-right[_ngcontent-%COMP%] {\n position: absolute;\n top: 50%;\n transform: translateY(-50%);\n z-index: 2;\n \n\n}\n\n.tab-scroll-button-left[_ngcontent-%COMP%] {\n left: 0;\n}\n\n.tab-scroll-button-right[_ngcontent-%COMP%] {\n right: 0;\n}\n\n.tab-scroll-button[_ngcontent-%COMP%] {\n padding: 8px 10px 10px 8px;\n cursor: pointer;\n border-radius: 6px;\n background-color: var(--gray-700);\n}\n\n.tab-scroll-button[_ngcontent-%COMP%]:hover {\n background-color: var(--mj-blue);\n}"] });
398
+ } }, dependencies: [i1.MJTabListDirective], styles: ["\n\n\n\n\n\n\n\n\n\n\n\n.tabstrip-container[_ngcontent-%COMP%] {\n display: block;\n}"] });
361
399
  }
362
400
  (() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassMetadata(MJTabStripComponent, [{
363
401
  type: Component,
364
- args: [{ standalone: false, selector: 'mj-tabstrip', template: "<div class=\"tabstrip-container\">\n <!-- Tab Headers -->\n <div class=\"tab-header-outer\">\n @if (showLeftButton) {\n <div class=\"tab-scroll-button tab-scroll-button-left\" (click)=\"scrollLeft()\">\n <span class=\"fa-solid fa-caret-left\"></span>\n </div>\n }\n <div class=\"tab-header-inner\" #tabInnerContainer>\n <ng-content select=\"mj-tab\"></ng-content> <!-- Where <mj-tab> components are projected -->\n </div>\n @if (showRightButton) {\n <div class=\"tab-scroll-button tab-scroll-button-right\" (click)=\"scrollRight()\">\n <span class=\"fa-solid fa-caret-right\"></span>\n </div>\n }\n </div>\n <!-- Tab Content -->\n <div class=\"tab-bodies\">\n <ng-content select=\"mj-tab-body\"></ng-content> <!-- Where <mj-tab-body> components are projected -->\n </div>\n</div>", styles: [".tabstrip-container {\n display: block;\n height: calc(100vh - 80px);\n overflow-y: auto;\n}\n\n.tabstrip-container .tabstrip-container {\n display: block;\n height: auto;\n}\n\n.tab-header-outer {\n position: relative;\n display: flex;\n align-items: center;\n overflow: hidden;\n /* Hide the overflow */\n background-color: var(--gray-600);\n}\n\n.tab-header-inner {\n display: flex;\n flex-direction: row;\n white-space: nowrap;\n /* Prevent wrapping of tabs */\n position: relative;\n /* Needed for z-index to work */\n z-index: 1;\n /* Place tabs above the content */\n padding-left: 5px;\n padding-top: 5px;\n}\n\n.tab-scroll-button-left,\n.tab-scroll-button-right {\n position: absolute;\n top: 50%;\n transform: translateY(-50%);\n z-index: 2;\n /* Ensure buttons are above the content */\n}\n\n.tab-scroll-button-left {\n left: 0;\n}\n\n.tab-scroll-button-right {\n right: 0;\n}\n\n.tab-scroll-button {\n padding: 8px 10px 10px 8px;\n cursor: pointer;\n border-radius: 6px;\n background-color: var(--gray-700);\n}\n\n.tab-scroll-button:hover {\n background-color: var(--mj-blue);\n}"] }]
402
+ args: [{ standalone: false, selector: 'mj-tabstrip', template: "<div class=\"tabstrip-container\">\n <!-- Tab Headers. Chrome classes (.mj-tabs*) come from the GLOBAL stylesheet in\n @memberjunction/ng-ui-components (lib/tabs/tabs.scss), which is the single definition of what\n an MJ tab looks like \u2014 shared with the draft/workspace strip. Keyboard behaviour comes from\n the mjTabList directive in the same package: roving tabindex, arrow/Home/End navigation, and\n Delete to close. Neither is redefined here; that is the whole point. -->\n <div class=\"tab-header-outer mj-tabs mj-tabs__bar\">\n @if (showLeftButton) {\n <button type=\"button\" class=\"mj-tabs__scroll\" (click)=\"scrollLeft()\" tabindex=\"-1\" aria-label=\"Scroll tabs left\">\n <span class=\"fa-solid fa-caret-left\" aria-hidden=\"true\"></span>\n </button>\n }\n <div\n class=\"tab-header-inner mj-tabs__list\"\n #tabInnerContainer\n mjTabList\n (scroll)=\"checkTabScrollButtons()\"\n (TabActivateRequested)=\"onTabActivateRequested($event)\"\n (TabCloseRequested)=\"onTabCloseRequested($event)\">\n <ng-content select=\"mj-tab\"></ng-content> <!-- Where <mj-tab> components are projected -->\n </div>\n @if (showRightButton) {\n <button type=\"button\" class=\"mj-tabs__scroll\" (click)=\"scrollRight()\" tabindex=\"-1\" aria-label=\"Scroll tabs right\">\n <span class=\"fa-solid fa-caret-right\" aria-hidden=\"true\"></span>\n </button>\n }\n </div>\n <!-- Tab Content -->\n <div class=\"tab-bodies\">\n <ng-content select=\"mj-tab-body\"></ng-content> <!-- Where <mj-tab-body> components are projected -->\n </div>\n</div>\n", styles: ["/* Structure only. All tab VISUALS live in the global `.mj-tabs*` chrome shipped by\n * @memberjunction/ng-ui-components (lib/tabs/tabs.scss), shared with the draft/workspace strip \u2014\n * see tab.component.css for what was removed from the per-tab layer and why local rules must not\n * come back (component-scoped selectors out-specify the global sheet and the strips drift apart).\n *\n * Notably removed here: `height: calc(100vh - 80px)` on the container. A component hardcoding\n * itself to viewport height blows up inside any host that isn't a full page (a card, a form\n * section, a lab stage), and every focus/selection change then scrolls the host pane around\n * inside the oversized box \u2014 visible as the whole area jumping. The strip now sizes to its\n * content; the HOST decides how tall the region is, like every other MJ widget. */\n\n.tabstrip-container {\n display: block;\n}\n"] }]
365
403
  }], () => [{ type: i0.ChangeDetectorRef }], { FillWidth: [{
366
404
  type: Input
367
405
  }], FillHeight: [{
@@ -397,5 +435,5 @@ export class MJTabStripComponent {
397
435
  }], ScrollAmount: [{
398
436
  type: Input
399
437
  }] }); })();
400
- (() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassDebugInfo(MJTabStripComponent, { className: "MJTabStripComponent", filePath: "src/lib/tab-strip/tab-strip.component.ts", lineNumber: 34 }); })();
438
+ (() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassDebugInfo(MJTabStripComponent, { className: "MJTabStripComponent", filePath: "src/lib/tab-strip/tab-strip.component.ts", lineNumber: 38 }); })();
401
439
  //# sourceMappingURL=tab-strip.component.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"tab-strip.component.js","sourceRoot":"","sources":["../../../src/lib/tab-strip/tab-strip.component.ts","../../../src/lib/tab-strip/tab-strip.component.html"],"names":[],"mappings":"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","sourcesContent":["import { Component, Input, EventEmitter, Output, ContentChildren, QueryList, ViewChild, HostListener, ElementRef, AfterContentInit, AfterContentChecked, AfterViewInit, ChangeDetectorRef } from '@angular/core';\nimport { MJTabComponent } from '../tab/tab.component';\nimport { MJTabBodyComponent } from '../tab-body/tab-body.component';\n\n \nexport class TabEvent {\n public index!: number;\n public tab: MJTabComponent | null = null;\n public body: MJTabBodyComponent | null = null;\n}\nexport class TabCancelableEvent extends TabEvent {\n public cancel: boolean = false;\n}\nexport class TabClosedEvent extends TabEvent {\n /**\n * This property provides the default calculation for what the new tab index will be and can be overriden by the container component to set a different value.\n */\n public newTabIndex!: number\n /**\n * Whenever the container is done processing, it MUST call this done method to signal that it is done. \n */\n public done!: (error?: any) => {};\n}\nexport class TabContextMenuEvent extends TabEvent {\n public mouseEvent!: MouseEvent;\n}\n\n@Component({\n standalone: false,\n selector: 'mj-tabstrip',\n templateUrl: './tab-strip.component.html',\n styleUrls: ['./tab-strip.component.css']\n})\nexport class MJTabStripComponent implements AfterContentInit, AfterContentChecked, AfterViewInit {\n protected _selectedTabIndex: number = 0; // default to negative 1 so any valid value of 0+ will invoke a state change internally later\n\n public static OutputDebugInfo: boolean = false;\n protected static OutputDebugMessage(message: string): void {\n if (MJTabStripComponent.OutputDebugInfo) {\n console.log(message);\n }\n }\n\n constructor(private cdr: ChangeDetectorRef) { }\n @Input() FillWidth: boolean = true;\n @Input() FillHeight: boolean = true;\n\n /**\n * This event is raised whenever the TabStrip component determines it would be advisable to conduct any necessary\n * resizing action in the parent container. Implement an event handler to handle this, if desired, for your application.\n */\n @Output() ResizeContainer = new EventEmitter();\n\n /**\n * The index of the selected tab. You can get/set this value and it will change the displayed tab.\n */\n @Input() get SelectedTabIndex(): number {\n return this._selectedTabIndex;\n }\n set SelectedTabIndex(index: number) {\n // check to make sure that the new index is different from the current index and only do the work here if it is different\n MJTabStripComponent.OutputDebugMessage(`MJTabStripComponent.SelectedTabIndex(${index})`);\n if (index !== this._selectedTabIndex) {\n const props = { \n index: index!, \n tab: index !== null && this.tabs ? this.tabs.toArray()[index] : null,\n body: index !== null && this.tabBodies ? this.tabBodies.toArray()[index] : null,\n cancel: false\n };\n if (props.tab?.Visible) {\n this.BeforeTabSelected.emit(props);\n if (!props.cancel) {\n this._selectedTabIndex = index;\n \n this.innerRefreshTabVisibility(index); \n \n const afterProps = {\n index: index!,\n tab: props.tab,\n body: props.body\n }\n this.TabSelected.emit(afterProps); \n } \n }\n else\n throw new Error(`Tab index ${index} is not visible and cannot be selected.`);\n }\n else {\n // always do this even if we're not firing event since we're already on the right tab\n this.innerRefreshTabVisibility(index); \n }\n }\n\n /**\n * This method will attempt to set the current tab by name. If the tab is found, it will be selected and the method will return the tab object. If the tab is not found, the method will return undefined.\n * @param tabName \n * @returns \n */\n public SelectTabByName(tabName: string): MJTabComponent | undefined {\n const tab = this.GetTabByName(tabName);\n if (tab) {\n if (tab.Visible)\n this.SelectedTabIndex = tab.index;\n else\n throw new Error(`Tab ${tabName} is not visible and cannot be selected.`);\n }\n return tab;\n }\n\n public GetTabByName(tabName: string): MJTabComponent | undefined {\n return this.tabs.find(t => t.Name?.trim().toLowerCase() === tabName.trim().toLowerCase());\n }\n\n protected innerRefreshTabVisibility(index: number) {\n Promise.resolve().then(() => {\n MJTabStripComponent.OutputDebugMessage(`MJTabStripComponent.innerRefreshTabVisibility(${index})`);\n // do this within a Promise.resolve() to ensure that the change detection has a chance to catch up before we start changing things\n\n // now, we have to tell each of our tabs they have been selected or not, and also to tell the bodies if they are visible or not\n this.tabs?.forEach((tab, i) => tab.TabSelected = i === index);\n this.tabBodies?.forEach((body, i) => body.TabVisible = i === index);\n\n // let angular now it needs to update its change detection\n this.cdr.detectChanges();\n \n // also ask for a resize now\n this.ResizeContainer.emit();\n });\n }\n\n /**\n * This event is fired before a tab is selected. If you set cancel to true, the tab will not be selected.\n */\n @Output() BeforeTabSelected = new EventEmitter<TabCancelableEvent>();\n\n /**\n * This event is fired when a tab is selected.\n */\n @Output() TabSelected = new EventEmitter<TabEvent>();\n\n /**\n * This event is fired before a tab is closed. If you set cancel to true, the tab will not be closed.\n */\n @Output() BeforeTabClosed = new EventEmitter<TabCancelableEvent>();\n\n /**\n * This event is fired after a tab is closed.\n */\n @Output() TabClosed = new EventEmitter<TabClosedEvent>(true);\n\n /**\n * This event is fired when a tab is right-clicked and the context menu event from the tab header fires.\n */\n @Output() TabContextMenu = new EventEmitter<TabContextMenuEvent>();\n\n /**\n * This event is fired whenever the tab control is scrolled left or right. This event can be invoked either due to a user clicking on the left/right buttons or by calling the scrollLeft/scrollRight methods, or by\n * the ScrollIntoView method being called.\n */\n @Output() TabScrolled = new EventEmitter();\n\n\n @ContentChildren(MJTabComponent) tabs!: QueryList<MJTabComponent>;\n @ContentChildren(MJTabBodyComponent) tabBodies!: QueryList<MJTabBodyComponent>;\n \n\n private _viewInitialized: boolean = false;\n ngAfterViewInit() {\n this._viewInitialized = true;\n this.SelectedTabIndex = this.SelectedTabIndex; // force a refresh of the tab visibility\n this.syncTabIndexes();\n this.checkTabScrollButtons();\n }\n ngAfterContentInit() {\n this.syncTabIndexes();\n }\n ngAfterContentChecked(): void {\n this.syncTabIndexes();\n this.checkTabScrollButtons();\n }\n\n /**\n * Call this method if you are ever dynamically adding or removing tabs from the component over time using @if or *ngIf or other similar methods. This will force the tab strip to \n * re-evaluate the tabs and tab bodies and update the display accordingly.\n */\n public RefreshTabs() {\n this.cdr.detectChanges();\n this.syncTabIndexes();\n this.innerRefreshTabVisibility(this.SelectedTabIndex);\n }\n\n protected syncTabIndexes() {\n if (!this._viewInitialized) return; // don't do anything until the view is initialized \n\n // Automatically assign indices to tabs and tab bodies\n this.tabs.forEach((tab, index) => tab.index = index);\n this.tabBodies.forEach((body, index) => body.index = index);\n if (this.SelectedTabIndex === null && this.tabs.length > 0) {\n this.SelectedTabIndex = 0;\n }\n else if (this.tabs.length === 0)\n this.SelectedTabIndex = -1;\n }\n\n /**\n * Returns a read-only (copy) of the tabs in this tab strip.\n */\n public get Tabs(): MJTabComponent[] {\n return this.tabs.toArray();\n }\n\n /**\n * Returns a read-only (copy) of the tab bodies in this tab strip.\n */\n public get TabBodies(): MJTabBodyComponent[] {\n return this.tabBodies.toArray();\n }\n\n /**\n * Method will close the specified tab number. It is automatically called by a tab that has TabCloseable set to true, if the user clicks the close button, and can be called programatically as well.\n */\n public async CloseTab(tabIndex: number) {\n MJTabStripComponent.OutputDebugMessage(`MJTabStripComponent.CloseTab(${tabIndex})`);\n if (tabIndex >= 0 && tabIndex < this.tabs.length) {\n // figure out what the new tab index will be so we can share with our container component\n let newTabIndex;\n if (this.tabs.length === 1) {\n // deleting the only tab we have, shouldn't happen but if so, set to -1\n newTabIndex = -1;\n }\n else if (this.SelectedTabIndex >= this.tabs.length - 1) {\n // we are ABOUT to delete the last tab, so select what will be the new last tab\n newTabIndex = this.tabs.length - 2; // substract 2 becuase subtracting 1 would be the last tab, but we are about to delete it\n }\n else {\n // deleting a tab that is not the last one, so we don't need to do anything special, just set the index to what it was before\n newTabIndex = this.SelectedTabIndex; \n }\n\n const props: any = { \n index: tabIndex,\n tab: this.tabs.toArray()[tabIndex],\n body: this.tabBodies.toArray()[tabIndex],\n cancel: false,\n };\n this.BeforeTabClosed.emit(props);\n if (!props.cancel) {\n // Convert callback to a promise\n const waitForCompletion = new Promise((resolve, reject) => {\n props.done = (error?: any) => {\n if (error) {\n reject(error);\n } else {\n resolve(true);\n }\n };\n }); \n props.newTabIndex = newTabIndex;\n\n // fire off the event to the container component\n this.TabClosed.emit(props);\n // wait for callback to occur from the event handler\n await waitForCompletion; \n\n // finally, set the tab index to the props.newTabIndex value which allows the container to override our default calculation for new tab index\n this.SelectedTabIndex = props.newTabIndex;\n }\n }\n else\n throw new Error(\"Invalid tab index: \" + tabIndex);\n }\n\n\n public handleTabContextMenu($event: MouseEvent, tab: MJTabComponent) {\n this.TabContextMenu.emit({ index: tab.index, tab: tab, body: this.tabBodies.toArray()[tab.index], mouseEvent: $event });\n }\n\n\n /* INTERNAL IMPLEMENTATION */\n @ViewChild('tabInnerContainer') tabInnerContainer!: ElementRef;\n\n showLeftButton: boolean = false;\n showRightButton: boolean = false;\n\n @HostListener('window:resize', ['$event'])\n onResize(event: any) {\n this.checkTabScrollButtons();\n }\n\n protected checkTabScrollButtons() {\n if (this.tabInnerContainer && this.tabInnerContainer.nativeElement && this.tabInnerContainer.nativeElement.parentElement) {\n const container = this.tabInnerContainer.nativeElement;\n const parent = container.parentElement;\n const currentLeft = container.style.left ? parseInt(container.style.left) : 0;\n\n // show the right button if the container is wider than the parent AND the left position(which is zero or negative) + the container width is greater than the parent width\n this.showRightButton = container.clientWidth > parent.clientWidth && \n currentLeft + container.clientWidth > parent.clientWidth;\n\n // Show left button if left position is less than 0, meaning some of the left side of the container is off screen\n this.showLeftButton = currentLeft < 0; \n }\n }\n\n protected scrollTabHeader(scrollAmount: number) {\n const style = this.tabInnerContainer.nativeElement.style\n if (style) {\n const curLeft = style.left ? parseInt(style.left) : 0; \n style.left = (curLeft + scrollAmount) + 'px';\n this.checkTabScrollButtons(); // can do immediately because the above is direct DOM manipulation so the effect is immediate\n this.TabScrolled.emit();\n }\n }\n\n /**\n * This property determines how many pixels to scroll when the scrollLeft or scrollRight methods are called.\n */\n @Input() ScrollAmount: number = 150;\n public scrollLeft() {\n this.scrollTabHeader(150)\n }\n public scrollRight() {\n this.scrollTabHeader(-150)\n }\n\n\n /**\n * This method will scroll the specified tab index into view if it is not currently visible in the tab strip.\n * @param tabIndex \n */\n public scrollIntoView(tabIndex: number) {\n // In this method, we need to calculate the current left position of the specified tab, \n // if it is not visible we need to scroll left or scroll right sufficiently in order to ensure that the tab specified is visible\n // we do NOT change tab selection, the caller can do that separately if they want to\n if (tabIndex >= 0 && tabIndex < this.tabs.length) {\n const tab = this.tabs.toArray()[tabIndex];\n if (tab) {\n const tabElement = tab.elementRef.nativeElement;\n if (tabElement) {\n const tabLeft = tabElement.offsetLeft;\n const tabRight = tabLeft + tabElement.offsetWidth;\n const container = this.tabInnerContainer.nativeElement;\n const containerLeft = container.offsetLeft;\n const containerRight = containerLeft + container.offsetWidth;\n\n if (tabLeft < containerLeft) {\n // tab is off to the left, scroll left\n this.scrollTabHeader(tabLeft - containerLeft);\n }\n else if (tabRight > containerRight) {\n // tab is off to the right, scroll right\n this.scrollTabHeader(tabRight - containerRight);\n }\n else {\n // tab is already visible, do nothing\n }\n }\n }\n }\n }\n}\n","<div class=\"tabstrip-container\">\n <!-- Tab Headers -->\n <div class=\"tab-header-outer\">\n @if (showLeftButton) {\n <div class=\"tab-scroll-button tab-scroll-button-left\" (click)=\"scrollLeft()\">\n <span class=\"fa-solid fa-caret-left\"></span>\n </div>\n }\n <div class=\"tab-header-inner\" #tabInnerContainer>\n <ng-content select=\"mj-tab\"></ng-content> <!-- Where <mj-tab> components are projected -->\n </div>\n @if (showRightButton) {\n <div class=\"tab-scroll-button tab-scroll-button-right\" (click)=\"scrollRight()\">\n <span class=\"fa-solid fa-caret-right\"></span>\n </div>\n }\n </div>\n <!-- Tab Content -->\n <div class=\"tab-bodies\">\n <ng-content select=\"mj-tab-body\"></ng-content> <!-- Where <mj-tab-body> components are projected -->\n </div>\n</div>"]}
1
+ {"version":3,"file":"tab-strip.component.js","sourceRoot":"","sources":["../../../src/lib/tab-strip/tab-strip.component.ts","../../../src/lib/tab-strip/tab-strip.component.html"],"names":[],"mappings":"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","sourcesContent":["import { Component, Input, EventEmitter, Output, ContentChildren, QueryList, ViewChild, HostListener, ElementRef, AfterContentInit, AfterContentChecked, AfterViewInit, ChangeDetectorRef } from '@angular/core';\nimport { warnIfTabChromeMissing } from '@memberjunction/ng-ui-components';\nimport { MJTabComponent } from '../tab/tab.component';\nimport { MJTabBodyComponent } from '../tab-body/tab-body.component';\n\n \nexport class TabEvent {\n public index!: number;\n public tab: MJTabComponent | null = null;\n public body: MJTabBodyComponent | null = null;\n}\nexport class TabCancelableEvent extends TabEvent {\n public cancel: boolean = false;\n}\nexport class TabClosedEvent extends TabEvent {\n /**\n * This property provides the default calculation for what the new tab index will be and can be overriden by the container component to set a different value.\n */\n public newTabIndex!: number\n /**\n * Whenever the container is done processing, it MUST call this done method to signal that it is done. \n */\n public done!: (error?: any) => {};\n}\nexport class TabContextMenuEvent extends TabEvent {\n public mouseEvent!: MouseEvent;\n}\n\n/** Source of per-instance DOM id bases — see {@link MJTabStripComponent.IdBase}. */\nlet tabStripIdSeq = 0;\n\n@Component({\n standalone: false,\n selector: 'mj-tabstrip',\n templateUrl: './tab-strip.component.html',\n styleUrls: ['./tab-strip.component.css']\n})\nexport class MJTabStripComponent implements AfterContentInit, AfterContentChecked, AfterViewInit {\n protected _selectedTabIndex: number = 0; // default to negative 1 so any valid value of 0+ will invoke a state change internally later\n\n public static OutputDebugInfo: boolean = false;\n protected static OutputDebugMessage(message: string): void {\n if (MJTabStripComponent.OutputDebugInfo) {\n console.log(message);\n }\n }\n\n constructor(private cdr: ChangeDetectorRef) { }\n /** @deprecated No longer read — the strip sizes to content and the HOST owns region sizing. Kept only so existing bindings compile; remove on the next major. */\n @Input() FillWidth: boolean = true;\n /** @deprecated No longer read — the strip sizes to content and the HOST owns region sizing. Kept only so existing bindings compile; remove on the next major. */\n @Input() FillHeight: boolean = true;\n\n /**\n * Per-instance id base pairing each tab with its panel (`aria-controls` / `aria-labelledby`).\n * Index-suffixed by the tab/body components themselves once `syncTabIndexes` has run.\n */\n public readonly IdBase: string = `mj-tabstrip-${++tabStripIdSeq}`;\n\n /**\n * This event is raised whenever the TabStrip component determines it would be advisable to conduct any necessary\n * resizing action in the parent container. Implement an event handler to handle this, if desired, for your application.\n */\n @Output() ResizeContainer = new EventEmitter();\n\n /**\n * The index of the selected tab. You can get/set this value and it will change the displayed tab.\n */\n @Input() get SelectedTabIndex(): number {\n return this._selectedTabIndex;\n }\n set SelectedTabIndex(index: number) {\n // check to make sure that the new index is different from the current index and only do the work here if it is different\n MJTabStripComponent.OutputDebugMessage(`MJTabStripComponent.SelectedTabIndex(${index})`);\n if (index !== this._selectedTabIndex) {\n const props = { \n index: index!, \n tab: index !== null && this.tabs ? this.tabs.toArray()[index] : null,\n body: index !== null && this.tabBodies ? this.tabBodies.toArray()[index] : null,\n cancel: false\n };\n if (props.tab?.Visible) {\n this.BeforeTabSelected.emit(props);\n if (!props.cancel) {\n this._selectedTabIndex = index;\n \n this.innerRefreshTabVisibility(index); \n \n const afterProps = {\n index: index!,\n tab: props.tab,\n body: props.body\n }\n this.TabSelected.emit(afterProps); \n } \n }\n else\n throw new Error(`Tab index ${index} is not visible and cannot be selected.`);\n }\n else {\n // always do this even if we're not firing event since we're already on the right tab\n this.innerRefreshTabVisibility(index); \n }\n }\n\n /**\n * This method will attempt to set the current tab by name. If the tab is found, it will be selected and the method will return the tab object. If the tab is not found, the method will return undefined.\n * @param tabName \n * @returns \n */\n public SelectTabByName(tabName: string): MJTabComponent | undefined {\n const tab = this.GetTabByName(tabName);\n if (tab) {\n if (tab.Visible)\n this.SelectedTabIndex = tab.index;\n else\n throw new Error(`Tab ${tabName} is not visible and cannot be selected.`);\n }\n return tab;\n }\n\n public GetTabByName(tabName: string): MJTabComponent | undefined {\n return this.tabs.find(t => t.Name?.trim().toLowerCase() === tabName.trim().toLowerCase());\n }\n\n protected innerRefreshTabVisibility(index: number) {\n Promise.resolve().then(() => {\n MJTabStripComponent.OutputDebugMessage(`MJTabStripComponent.innerRefreshTabVisibility(${index})`);\n // do this within a Promise.resolve() to ensure that the change detection has a chance to catch up before we start changing things\n\n // now, we have to tell each of our tabs they have been selected or not, and also to tell the bodies if they are visible or not\n this.tabs?.forEach((tab, i) => tab.TabSelected = i === index);\n this.tabBodies?.forEach((body, i) => body.TabVisible = i === index);\n\n // let angular now it needs to update its change detection\n this.cdr.detectChanges();\n \n // also ask for a resize now\n this.ResizeContainer.emit();\n });\n }\n\n /**\n * This event is fired before a tab is selected. If you set cancel to true, the tab will not be selected.\n */\n @Output() BeforeTabSelected = new EventEmitter<TabCancelableEvent>();\n\n /**\n * This event is fired when a tab is selected.\n */\n @Output() TabSelected = new EventEmitter<TabEvent>();\n\n /**\n * This event is fired before a tab is closed. If you set cancel to true, the tab will not be closed.\n */\n @Output() BeforeTabClosed = new EventEmitter<TabCancelableEvent>();\n\n /**\n * This event is fired after a tab is closed.\n */\n @Output() TabClosed = new EventEmitter<TabClosedEvent>(true);\n\n /**\n * This event is fired when a tab is right-clicked and the context menu event from the tab header fires.\n */\n @Output() TabContextMenu = new EventEmitter<TabContextMenuEvent>();\n\n /**\n * This event is fired whenever the tab control is scrolled left or right. This event can be invoked either due to a user clicking on the left/right buttons or by calling the scrollLeft/scrollRight methods, or by\n * the ScrollIntoView method being called.\n */\n @Output() TabScrolled = new EventEmitter();\n\n\n @ContentChildren(MJTabComponent) tabs!: QueryList<MJTabComponent>;\n @ContentChildren(MJTabBodyComponent) tabBodies!: QueryList<MJTabBodyComponent>;\n \n\n private _viewInitialized: boolean = false;\n ngAfterViewInit() {\n this._viewInitialized = true;\n // Dev-mode guard: the .mj-tabs* chrome lives in a global stylesheet a standalone host must\n // import; a missing import renders bare divs with no error. Warn instead of staying silent.\n warnIfTabChromeMissing(this.tabInnerContainer?.nativeElement?.closest('.mj-tabs') ?? undefined);\n this.SelectedTabIndex = this.SelectedTabIndex; // force a refresh of the tab visibility\n this.syncTabIndexes();\n this.checkTabScrollButtons();\n }\n ngAfterContentInit() {\n this.syncTabIndexes();\n }\n ngAfterContentChecked(): void {\n this.syncTabIndexes();\n this.checkTabScrollButtons();\n }\n\n /**\n * Call this method if you are ever dynamically adding or removing tabs from the component over time using @if or *ngIf or other similar methods. This will force the tab strip to \n * re-evaluate the tabs and tab bodies and update the display accordingly.\n */\n public RefreshTabs() {\n this.cdr.detectChanges();\n this.syncTabIndexes();\n this.innerRefreshTabVisibility(this.SelectedTabIndex);\n }\n\n protected syncTabIndexes() {\n if (!this._viewInitialized) return; // don't do anything until the view is initialized\n\n // Automatically assign indices to tabs and tab bodies\n this.tabs.forEach((tab, index) => tab.index = index);\n this.tabBodies.forEach((body, index) => body.index = index);\n\n // Pair each tab with its panel for assistive tech (`aria-controls` / `aria-labelledby`).\n // Written directly to the DOM rather than template-bound, because `index` is only known HERE —\n // after the first render — and a binding that changes mid-cycle trips NG0100 in dev mode.\n // Idempotent, and re-run whenever the tab set changes, so ids follow reorders/removals.\n this.tabs.forEach((tab, index) => {\n const el: HTMLElement | null = tab.elementRef?.nativeElement?.querySelector('[role=\"tab\"]');\n if (el) {\n el.id = `${this.IdBase}-tab-${index}`;\n el.setAttribute('aria-controls', `${this.IdBase}-panel-${index}`);\n }\n });\n this.tabBodies.forEach((body, index) => {\n const el: HTMLElement | null = body.elementRef?.nativeElement?.querySelector('[role=\"tabpanel\"]');\n if (el) {\n el.id = `${this.IdBase}-panel-${index}`;\n el.setAttribute('aria-labelledby', `${this.IdBase}-tab-${index}`);\n }\n });\n if (this.SelectedTabIndex === null && this.tabs.length > 0) {\n this.SelectedTabIndex = 0;\n }\n else if (this.tabs.length === 0)\n this.SelectedTabIndex = -1;\n }\n\n /**\n * Returns a read-only (copy) of the tabs in this tab strip.\n */\n public get Tabs(): MJTabComponent[] {\n return this.tabs.toArray();\n }\n\n /**\n * Returns a read-only (copy) of the tab bodies in this tab strip.\n */\n public get TabBodies(): MJTabBodyComponent[] {\n return this.tabBodies.toArray();\n }\n\n /**\n * Method will close the specified tab number. It is automatically called by a tab that has TabCloseable set to true, if the user clicks the close button, and can be called programatically as well.\n */\n public async CloseTab(tabIndex: number) {\n MJTabStripComponent.OutputDebugMessage(`MJTabStripComponent.CloseTab(${tabIndex})`);\n if (tabIndex >= 0 && tabIndex < this.tabs.length) {\n // figure out what the new tab index will be so we can share with our container component\n let newTabIndex;\n if (this.tabs.length === 1) {\n // deleting the only tab we have, shouldn't happen but if so, set to -1\n newTabIndex = -1;\n }\n else if (this.SelectedTabIndex >= this.tabs.length - 1) {\n // we are ABOUT to delete the last tab, so select what will be the new last tab\n newTabIndex = this.tabs.length - 2; // substract 2 becuase subtracting 1 would be the last tab, but we are about to delete it\n }\n else {\n // deleting a tab that is not the last one, so we don't need to do anything special, just set the index to what it was before\n newTabIndex = this.SelectedTabIndex; \n }\n\n const props: any = { \n index: tabIndex,\n tab: this.tabs.toArray()[tabIndex],\n body: this.tabBodies.toArray()[tabIndex],\n cancel: false,\n };\n this.BeforeTabClosed.emit(props);\n if (!props.cancel) {\n // Convert callback to a promise\n const waitForCompletion = new Promise((resolve, reject) => {\n props.done = (error?: any) => {\n if (error) {\n reject(error);\n } else {\n resolve(true);\n }\n };\n }); \n props.newTabIndex = newTabIndex;\n\n // fire off the event to the container component\n this.TabClosed.emit(props);\n // wait for callback to occur from the event handler\n await waitForCompletion; \n\n // finally, set the tab index to the props.newTabIndex value which allows the container to override our default calculation for new tab index\n this.SelectedTabIndex = props.newTabIndex;\n }\n }\n else\n throw new Error(\"Invalid tab index: \" + tabIndex);\n }\n\n\n public handleTabContextMenu($event: MouseEvent, tab: MJTabComponent) {\n this.TabContextMenu.emit({ index: tab.index, tab: tab, body: this.tabBodies.toArray()[tab.index], mouseEvent: $event });\n }\n\n\n /* INTERNAL IMPLEMENTATION */\n @ViewChild('tabInnerContainer') tabInnerContainer!: ElementRef;\n\n showLeftButton: boolean = false;\n showRightButton: boolean = false;\n\n @HostListener('window:resize', ['$event'])\n onResize(event: any) {\n this.checkTabScrollButtons();\n }\n\n protected checkTabScrollButtons() {\n if (this.tabInnerContainer && this.tabInnerContainer.nativeElement) {\n // The list itself is the scroller now (`.mj-tabs__list` is `overflow-x: auto`), so overflow\n // and position are read off its NATIVE scroll state — the old scheme of animating a `left`\n // offset against a relatively-positioned wrapper is gone with the wrapper's CSS.\n const container: HTMLElement = this.tabInnerContainer.nativeElement;\n const overflow = container.scrollWidth - container.clientWidth;\n this.showLeftButton = overflow > 0 && container.scrollLeft > 0;\n this.showRightButton = overflow > 0 && container.scrollLeft < overflow - 1;\n }\n }\n\n protected scrollTabHeader(scrollAmount: number) {\n // Positive amount = reveal content to the LEFT (the old `left`-offset convention, preserved so\n // ScrollAmount and the button wiring keep their meaning); native scrollLeft counts the other way.\n const container: HTMLElement = this.tabInnerContainer.nativeElement;\n container.scrollBy({ left: -scrollAmount, behavior: 'smooth' });\n // Smooth scrolling settles asynchronously; re-evaluate the buttons when it has.\n setTimeout(() => this.checkTabScrollButtons(), 300);\n this.TabScrolled.emit();\n }\n\n /**\n * This property determines how many pixels to scroll when the scrollLeft or scrollRight methods are called.\n */\n @Input() ScrollAmount: number = 150;\n public scrollLeft() {\n this.scrollTabHeader(150)\n }\n public scrollRight() {\n this.scrollTabHeader(-150)\n }\n\n /**\n * Keyboard navigation from the shared `mjTabList` directive (arrows / Home / End / Enter).\n *\n * The directive reports a POSITION among the rendered `[role=\"tab\"]` elements, which is already\n * this component's identity model, so the mapping is direct. Selecting also scrolls the tab into\n * view — arrowing to a tab hidden behind the overflow edge would otherwise move focus somewhere\n * the user cannot see.\n */\n public onTabActivateRequested(request: { Index: number }): void {\n if (request.Index >= 0 && request.Index < this.tabs.length) {\n this.SelectedTabIndex = request.Index;\n this.scrollIntoView(request.Index);\n }\n }\n\n /**\n * Delete / Backspace on a focused tab. Routed through the SAME `CloseTab` path a click on the\n * close button uses, so the cancelable `BeforeTabClosed` contract holds for keyboard users too.\n * Ignored for tabs that are not closeable.\n */\n public onTabCloseRequested(request: { Index: number }): void {\n const tab = this.tabs?.toArray()[request.Index];\n if (tab?.TabCloseable) {\n void this.CloseTab(request.Index);\n }\n }\n\n\n /**\n * This method will scroll the specified tab index into view if it is not currently visible in the tab strip.\n * @param tabIndex \n */\n public scrollIntoView(tabIndex: number) {\n // We do NOT change tab selection — the caller does that separately if they want to. The list\n // is a native horizontal scroller now, so the browser's own logic does the geometry.\n if (tabIndex >= 0 && tabIndex < this.tabs.length) {\n const tabElement: HTMLElement | undefined = this.tabs.toArray()[tabIndex]?.elementRef?.nativeElement;\n tabElement?.scrollIntoView({ block: 'nearest', inline: 'nearest', behavior: 'smooth' });\n setTimeout(() => this.checkTabScrollButtons(), 300);\n }\n }\n}\n","<div class=\"tabstrip-container\">\n <!-- Tab Headers. Chrome classes (.mj-tabs*) come from the GLOBAL stylesheet in\n @memberjunction/ng-ui-components (lib/tabs/tabs.scss), which is the single definition of what\n an MJ tab looks like — shared with the draft/workspace strip. Keyboard behaviour comes from\n the mjTabList directive in the same package: roving tabindex, arrow/Home/End navigation, and\n Delete to close. Neither is redefined here; that is the whole point. -->\n <div class=\"tab-header-outer mj-tabs mj-tabs__bar\">\n @if (showLeftButton) {\n <button type=\"button\" class=\"mj-tabs__scroll\" (click)=\"scrollLeft()\" tabindex=\"-1\" aria-label=\"Scroll tabs left\">\n <span class=\"fa-solid fa-caret-left\" aria-hidden=\"true\"></span>\n </button>\n }\n <div\n class=\"tab-header-inner mj-tabs__list\"\n #tabInnerContainer\n mjTabList\n (scroll)=\"checkTabScrollButtons()\"\n (TabActivateRequested)=\"onTabActivateRequested($event)\"\n (TabCloseRequested)=\"onTabCloseRequested($event)\">\n <ng-content select=\"mj-tab\"></ng-content> <!-- Where <mj-tab> components are projected -->\n </div>\n @if (showRightButton) {\n <button type=\"button\" class=\"mj-tabs__scroll\" (click)=\"scrollRight()\" tabindex=\"-1\" aria-label=\"Scroll tabs right\">\n <span class=\"fa-solid fa-caret-right\" aria-hidden=\"true\"></span>\n </button>\n }\n </div>\n <!-- Tab Content -->\n <div class=\"tab-bodies\">\n <ng-content select=\"mj-tab-body\"></ng-content> <!-- Where <mj-tab-body> components are projected -->\n </div>\n</div>\n"]}
package/package.json CHANGED
@@ -1,37 +1,40 @@
1
1
  {
2
2
  "name": "@memberjunction/ng-tabstrip",
3
- "version": "5.51.0",
4
- "description": "DEPRECATED: Simple tab strip component. Use Kendo TabStrip or mj-collapsible-panel instead.",
3
+ "version": "6.1.0-edge.1",
4
+ "description": "Projected-children tab strip (<mj-tabstrip>/<mj-tab>/<mj-tab-body>) sharing MJ's canonical tab chrome and mjTabList keyboard contract from @memberjunction/ng-ui-components. For data-driven tabs prefer mj-tab-nav or mj-workspace-tab-strip from ng-ui-components.",
5
5
  "main": "./dist/public-api.js",
6
6
  "typings": "./dist/public-api.d.ts",
7
7
  "files": [
8
8
  "/dist"
9
9
  ],
10
- "scripts": {
11
- "test": "vitest run",
12
- "build": "ngc",
13
- "test:watch": "vitest"
14
- },
15
10
  "keywords": [],
16
11
  "author": "",
17
12
  "license": "ISC",
18
13
  "devDependencies": {
19
14
  "@angular/compiler": "21.1.3",
20
15
  "@angular/compiler-cli": "21.1.3",
21
- "@memberjunction/ng-test-utils": "5.51.0",
16
+ "@memberjunction/ng-test-utils": "6.1.0-edge.1",
22
17
  "vitest": "^4.0.18"
23
18
  },
24
19
  "peerDependencies": {
25
- "@angular/common": "21.1.3",
26
- "@angular/core": "21.1.3"
20
+ "@angular/common": "^21.1.3",
21
+ "@angular/core": "^21.1.3"
27
22
  },
28
23
  "dependencies": {
29
- "@memberjunction/ng-container-directives": "5.51.0",
24
+ "@memberjunction/ng-container-directives": "6.1.0-edge.1",
25
+ "@memberjunction/ng-ui-components": "6.1.0-edge.1",
30
26
  "tslib": "^2.8.1"
31
27
  },
32
28
  "sideEffects": false,
33
29
  "repository": {
34
30
  "type": "git",
35
31
  "url": "https://github.com/MemberJunction/MJ"
32
+ },
33
+ "mjUILayer": "widgets",
34
+ "scripts": {
35
+ "test": "vitest run",
36
+ "test:types": "tsc --noEmit -p tsconfig.spec.json",
37
+ "build": "ngc",
38
+ "test:watch": "vitest"
36
39
  }
37
- }
40
+ }