@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 +7 -0
- package/README.md +9 -1
- package/dist/lib/module.d.ts +2 -1
- package/dist/lib/module.d.ts.map +1 -1
- package/dist/lib/module.js +5 -1
- package/dist/lib/module.js.map +1 -1
- package/dist/lib/tab/tab.component.d.ts.map +1 -1
- package/dist/lib/tab/tab.component.js +17 -14
- package/dist/lib/tab/tab.component.js.map +1 -1
- package/dist/lib/tab-body/tab-body.component.d.ts +6 -2
- package/dist/lib/tab-body/tab-body.component.d.ts.map +1 -1
- package/dist/lib/tab-body/tab-body.component.js +11 -7
- package/dist/lib/tab-body/tab-body.component.js.map +1 -1
- package/dist/lib/tab-strip/tab-strip.component.d.ts +26 -0
- package/dist/lib/tab-strip/tab-strip.component.d.ts.map +1 -1
- package/dist/lib/tab-strip/tab-strip.component.js +91 -53
- package/dist/lib/tab-strip/tab-strip.component.js.map +1 -1
- package/package.json +15 -12
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
|
|
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
|
|
package/dist/lib/module.d.ts
CHANGED
|
@@ -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
|
package/dist/lib/module.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"module.d.ts","sourceRoot":"","sources":["../../src/lib/module.ts"],"names":[],"mappings":"
|
|
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"}
|
package/dist/lib/module.js
CHANGED
|
@@ -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
|
|
40
|
+
ContainerDirectivesModule,
|
|
41
|
+
MJTabListDirective], exports: [MJTabStripComponent,
|
|
38
42
|
MJTabBodyComponent,
|
|
39
43
|
MJTabComponent] }); })();
|
|
40
44
|
//# sourceMappingURL=module.js.map
|
package/dist/lib/module.js.map
CHANGED
|
@@ -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;;
|
|
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,
|
|
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
|
|
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, "
|
|
11
|
-
i0.ɵɵlistener("click", function
|
|
12
|
-
i0.ɵɵ
|
|
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:
|
|
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.ɵɵ
|
|
114
|
-
i0.ɵɵ
|
|
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.ɵɵ
|
|
118
|
-
i0.ɵɵ
|
|
119
|
-
i0.ɵɵ
|
|
120
|
-
|
|
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
|
|
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:
|
|
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":"AAAA,OAAO,EAAE,SAAS,EAAE,KAAK,EAAwB,IAAI,EAAiC,MAAM,eAAe,CAAC;AAC5G,OAAO,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;;;;;;;;
|
|
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":"
|
|
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,
|
|
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
|
|
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
|
|
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,
|
|
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":"AAAA,OAAO,EAAoB,YAAY,EAA2B,SAAS,EAA2B,UAAU,EAAE,gBAAgB,EAAE,mBAAmB,EAAE,aAAa,EAAE,iBAAiB,EAAE,MAAM,eAAe,CAAC;
|
|
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
|
|
10
|
-
i0.ɵɵelementStart(0, "
|
|
11
|
-
i0.ɵɵlistener("click", function
|
|
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
|
|
17
|
-
i0.ɵɵelementStart(0, "
|
|
18
|
-
i0.ɵɵlistener("click", function
|
|
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
|
|
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
|
|
269
|
-
|
|
270
|
-
|
|
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
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
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
|
-
//
|
|
302
|
-
//
|
|
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
|
|
306
|
-
|
|
307
|
-
|
|
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"], [
|
|
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, "
|
|
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, "
|
|
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
|
-
} },
|
|
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 <
|
|
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:
|
|
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": "
|
|
4
|
-
"description": "
|
|
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": "
|
|
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": "
|
|
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
|
+
}
|