@jigisha_ruparel/taf-client-tabs-angular 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
|
@@ -0,0 +1,195 @@
|
|
|
1
|
+
import * as i1 from '@angular/common';
|
|
2
|
+
import { CommonModule } from '@angular/common';
|
|
3
|
+
import * as i0 from '@angular/core';
|
|
4
|
+
import { inject, ChangeDetectorRef, EventEmitter, booleanAttribute, Output, Input, ViewChild, ChangeDetectionStrategy, Component } from '@angular/core';
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* `<taf-tabs>` — the strip of tabs above a panel. It renders the strip only; the host still decides
|
|
8
|
+
* what the active tab shows, which is how these screens are already written.
|
|
9
|
+
*
|
|
10
|
+
* The strip owns no state: it renders `[active]` and emits `(activeChange)`, so a host keeps the
|
|
11
|
+
* signal or route param it already has. Closing is the same — `(closeTab)` fires and the host
|
|
12
|
+
* decides whether the tab actually goes.
|
|
13
|
+
*
|
|
14
|
+
* `scrollable` adds the overflow affordance a long strip needs: the arrows appear only when the
|
|
15
|
+
* strip actually overflows, and scroll it by roughly a tab's width.
|
|
16
|
+
*
|
|
17
|
+
* Ships NO theme — `taf-tabs__*` class hooks plus `data-active` / `data-variant`, so the host app
|
|
18
|
+
* decides whether a tab reads as an underline, a pill or a filled strip.
|
|
19
|
+
*/
|
|
20
|
+
class TafTabsComponent {
|
|
21
|
+
stripRef;
|
|
22
|
+
cdr = inject(ChangeDetectorRef);
|
|
23
|
+
tabs = [];
|
|
24
|
+
/** The active tab's `key`. */
|
|
25
|
+
active = '';
|
|
26
|
+
/** Surfaces as `data-variant` — the host theme decides what each looks like. */
|
|
27
|
+
variant = '';
|
|
28
|
+
/** Show arrows and scroll the strip when it overflows. */
|
|
29
|
+
scrollable = false;
|
|
30
|
+
/** Hide every close affordance, for a strip the user may read but not change. */
|
|
31
|
+
readonly = false;
|
|
32
|
+
activeChange = new EventEmitter();
|
|
33
|
+
/** A tab's ✕ was pressed. The host decides whether it closes. */
|
|
34
|
+
closeTab = new EventEmitter();
|
|
35
|
+
overflowing = false;
|
|
36
|
+
trackKey = (_, t) => t.key;
|
|
37
|
+
ngAfterViewInit() {
|
|
38
|
+
this.syncOverflow();
|
|
39
|
+
}
|
|
40
|
+
syncOverflow() {
|
|
41
|
+
const el = this.stripRef?.nativeElement;
|
|
42
|
+
if (!el)
|
|
43
|
+
return;
|
|
44
|
+
const next = el.scrollWidth > el.clientWidth + 1;
|
|
45
|
+
if (next !== this.overflowing) {
|
|
46
|
+
this.overflowing = next;
|
|
47
|
+
// OnPush: the arrows appear as a result of a measurement, not of an input changing.
|
|
48
|
+
this.cdr.markForCheck();
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
scrollBy(direction) {
|
|
52
|
+
const el = this.stripRef?.nativeElement;
|
|
53
|
+
if (!el)
|
|
54
|
+
return;
|
|
55
|
+
const tab = el.querySelector('.taf-tabs__tab');
|
|
56
|
+
el.scrollBy({ left: direction * (tab?.offsetWidth ?? 120), behavior: 'smooth' });
|
|
57
|
+
}
|
|
58
|
+
pick(t) {
|
|
59
|
+
if (t.disabled || t.key === this.active)
|
|
60
|
+
return;
|
|
61
|
+
this.activeChange.emit(t.key);
|
|
62
|
+
}
|
|
63
|
+
close(event, t) {
|
|
64
|
+
event.stopPropagation();
|
|
65
|
+
this.closeTab.emit(t.key);
|
|
66
|
+
}
|
|
67
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.5", ngImport: i0, type: TafTabsComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
68
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "16.1.0", version: "22.1.5", type: TafTabsComponent, isStandalone: true, selector: "taf-tabs", inputs: { tabs: "tabs", active: "active", variant: "variant", scrollable: ["scrollable", "scrollable", booleanAttribute], readonly: ["readonly", "readonly", booleanAttribute] }, outputs: { activeChange: "activeChange", closeTab: "closeTab" }, viewQueries: [{ propertyName: "stripRef", first: true, predicate: ["strip"], descendants: true }], ngImport: i0, template: `
|
|
69
|
+
<div class="taf-tabs" [attr.data-variant]="variant || null">
|
|
70
|
+
<button
|
|
71
|
+
*ngIf="scrollable && overflowing"
|
|
72
|
+
type="button"
|
|
73
|
+
class="taf-tabs__arrow taf-tabs__arrow--start"
|
|
74
|
+
aria-label="Scroll tabs left"
|
|
75
|
+
(click)="scrollBy(-1)"
|
|
76
|
+
>‹</button>
|
|
77
|
+
|
|
78
|
+
<div class="taf-tabs__strip" role="tablist" #strip (scroll)="syncOverflow()">
|
|
79
|
+
<button
|
|
80
|
+
*ngFor="let t of tabs; trackBy: trackKey"
|
|
81
|
+
type="button"
|
|
82
|
+
role="tab"
|
|
83
|
+
class="taf-tabs__tab"
|
|
84
|
+
[attr.data-key]="t.key"
|
|
85
|
+
[attr.data-active]="t.key === active ? '' : null"
|
|
86
|
+
[attr.aria-selected]="t.key === active"
|
|
87
|
+
[attr.title]="t.hint || null"
|
|
88
|
+
[disabled]="!!t.disabled"
|
|
89
|
+
(click)="pick(t)"
|
|
90
|
+
>
|
|
91
|
+
<span class="taf-tabs__icon" *ngIf="t.icon" aria-hidden="true">{{ t.icon }}</span>
|
|
92
|
+
<span class="taf-tabs__label">{{ t.label }}</span>
|
|
93
|
+
<span class="taf-tabs__count" *ngIf="t.count !== undefined">{{ t.count }}</span>
|
|
94
|
+
<span
|
|
95
|
+
*ngIf="t.closeable && !readonly"
|
|
96
|
+
class="taf-tabs__close"
|
|
97
|
+
role="button"
|
|
98
|
+
tabindex="0"
|
|
99
|
+
[attr.aria-label]="'Close ' + t.label"
|
|
100
|
+
(click)="close($event, t)"
|
|
101
|
+
(keydown.enter)="close($event, t)"
|
|
102
|
+
>✕</span>
|
|
103
|
+
</button>
|
|
104
|
+
</div>
|
|
105
|
+
|
|
106
|
+
<button
|
|
107
|
+
*ngIf="scrollable && overflowing"
|
|
108
|
+
type="button"
|
|
109
|
+
class="taf-tabs__arrow taf-tabs__arrow--end"
|
|
110
|
+
aria-label="Scroll tabs right"
|
|
111
|
+
(click)="scrollBy(1)"
|
|
112
|
+
>›</button>
|
|
113
|
+
|
|
114
|
+
<ng-content select="[tafTabsEnd]"></ng-content>
|
|
115
|
+
</div>
|
|
116
|
+
`, isInline: true, styles: ["taf-tabs{display:contents}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "directive", type: i1.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
117
|
+
}
|
|
118
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.5", ngImport: i0, type: TafTabsComponent, decorators: [{
|
|
119
|
+
type: Component,
|
|
120
|
+
args: [{ selector: 'taf-tabs', standalone: true, imports: [CommonModule], changeDetection: ChangeDetectionStrategy.OnPush, template: `
|
|
121
|
+
<div class="taf-tabs" [attr.data-variant]="variant || null">
|
|
122
|
+
<button
|
|
123
|
+
*ngIf="scrollable && overflowing"
|
|
124
|
+
type="button"
|
|
125
|
+
class="taf-tabs__arrow taf-tabs__arrow--start"
|
|
126
|
+
aria-label="Scroll tabs left"
|
|
127
|
+
(click)="scrollBy(-1)"
|
|
128
|
+
>‹</button>
|
|
129
|
+
|
|
130
|
+
<div class="taf-tabs__strip" role="tablist" #strip (scroll)="syncOverflow()">
|
|
131
|
+
<button
|
|
132
|
+
*ngFor="let t of tabs; trackBy: trackKey"
|
|
133
|
+
type="button"
|
|
134
|
+
role="tab"
|
|
135
|
+
class="taf-tabs__tab"
|
|
136
|
+
[attr.data-key]="t.key"
|
|
137
|
+
[attr.data-active]="t.key === active ? '' : null"
|
|
138
|
+
[attr.aria-selected]="t.key === active"
|
|
139
|
+
[attr.title]="t.hint || null"
|
|
140
|
+
[disabled]="!!t.disabled"
|
|
141
|
+
(click)="pick(t)"
|
|
142
|
+
>
|
|
143
|
+
<span class="taf-tabs__icon" *ngIf="t.icon" aria-hidden="true">{{ t.icon }}</span>
|
|
144
|
+
<span class="taf-tabs__label">{{ t.label }}</span>
|
|
145
|
+
<span class="taf-tabs__count" *ngIf="t.count !== undefined">{{ t.count }}</span>
|
|
146
|
+
<span
|
|
147
|
+
*ngIf="t.closeable && !readonly"
|
|
148
|
+
class="taf-tabs__close"
|
|
149
|
+
role="button"
|
|
150
|
+
tabindex="0"
|
|
151
|
+
[attr.aria-label]="'Close ' + t.label"
|
|
152
|
+
(click)="close($event, t)"
|
|
153
|
+
(keydown.enter)="close($event, t)"
|
|
154
|
+
>✕</span>
|
|
155
|
+
</button>
|
|
156
|
+
</div>
|
|
157
|
+
|
|
158
|
+
<button
|
|
159
|
+
*ngIf="scrollable && overflowing"
|
|
160
|
+
type="button"
|
|
161
|
+
class="taf-tabs__arrow taf-tabs__arrow--end"
|
|
162
|
+
aria-label="Scroll tabs right"
|
|
163
|
+
(click)="scrollBy(1)"
|
|
164
|
+
>›</button>
|
|
165
|
+
|
|
166
|
+
<ng-content select="[tafTabsEnd]"></ng-content>
|
|
167
|
+
</div>
|
|
168
|
+
`, styles: ["taf-tabs{display:contents}\n"] }]
|
|
169
|
+
}], propDecorators: { stripRef: [{
|
|
170
|
+
type: ViewChild,
|
|
171
|
+
args: ['strip']
|
|
172
|
+
}], tabs: [{
|
|
173
|
+
type: Input
|
|
174
|
+
}], active: [{
|
|
175
|
+
type: Input
|
|
176
|
+
}], variant: [{
|
|
177
|
+
type: Input
|
|
178
|
+
}], scrollable: [{
|
|
179
|
+
type: Input,
|
|
180
|
+
args: [{ transform: booleanAttribute }]
|
|
181
|
+
}], readonly: [{
|
|
182
|
+
type: Input,
|
|
183
|
+
args: [{ transform: booleanAttribute }]
|
|
184
|
+
}], activeChange: [{
|
|
185
|
+
type: Output
|
|
186
|
+
}], closeTab: [{
|
|
187
|
+
type: Output
|
|
188
|
+
}] } });
|
|
189
|
+
|
|
190
|
+
/**
|
|
191
|
+
* Generated bundle index. Do not edit.
|
|
192
|
+
*/
|
|
193
|
+
|
|
194
|
+
export { TafTabsComponent };
|
|
195
|
+
//# sourceMappingURL=jigisha_ruparel-taf-client-tabs-angular.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"jigisha_ruparel-taf-client-tabs-angular.mjs","sources":["../../src/taf-tabs.component.ts","../../src/jigisha_ruparel-taf-client-tabs-angular.ts"],"sourcesContent":["import { CommonModule } from '@angular/common';\nimport {\n ChangeDetectionStrategy,\n ChangeDetectorRef,\n Component,\n ElementRef,\n EventEmitter,\n Input,\n Output,\n ViewChild,\n booleanAttribute,\n inject,\n} from '@angular/core';\nimport type { AfterViewInit } from '@angular/core';\n\n/** One tab. `key` is what `active` matches and what the outputs emit. */\nexport interface TafTab {\n key: string;\n label: string;\n /** A count beside the label — how many rows sit behind this tab. */\n count?: number;\n /** A leading glyph or icon ligature. */\n icon?: string;\n disabled?: boolean;\n /** Shows a ✕ on this tab; closing is the host's decision, via `(closeTab)`. */\n closeable?: boolean;\n /** A title attribute, where the label is truncated. */\n hint?: string;\n}\n\n/**\n * `<taf-tabs>` — the strip of tabs above a panel. It renders the strip only; the host still decides\n * what the active tab shows, which is how these screens are already written.\n *\n * The strip owns no state: it renders `[active]` and emits `(activeChange)`, so a host keeps the\n * signal or route param it already has. Closing is the same — `(closeTab)` fires and the host\n * decides whether the tab actually goes.\n *\n * `scrollable` adds the overflow affordance a long strip needs: the arrows appear only when the\n * strip actually overflows, and scroll it by roughly a tab's width.\n *\n * Ships NO theme — `taf-tabs__*` class hooks plus `data-active` / `data-variant`, so the host app\n * decides whether a tab reads as an underline, a pill or a filled strip.\n */\n@Component({\n selector: 'taf-tabs',\n standalone: true,\n imports: [CommonModule],\n changeDetection: ChangeDetectionStrategy.OnPush,\n template: `\n <div class=\"taf-tabs\" [attr.data-variant]=\"variant || null\">\n <button\n *ngIf=\"scrollable && overflowing\"\n type=\"button\"\n class=\"taf-tabs__arrow taf-tabs__arrow--start\"\n aria-label=\"Scroll tabs left\"\n (click)=\"scrollBy(-1)\"\n >‹</button>\n\n <div class=\"taf-tabs__strip\" role=\"tablist\" #strip (scroll)=\"syncOverflow()\">\n <button\n *ngFor=\"let t of tabs; trackBy: trackKey\"\n type=\"button\"\n role=\"tab\"\n class=\"taf-tabs__tab\"\n [attr.data-key]=\"t.key\"\n [attr.data-active]=\"t.key === active ? '' : null\"\n [attr.aria-selected]=\"t.key === active\"\n [attr.title]=\"t.hint || null\"\n [disabled]=\"!!t.disabled\"\n (click)=\"pick(t)\"\n >\n <span class=\"taf-tabs__icon\" *ngIf=\"t.icon\" aria-hidden=\"true\">{{ t.icon }}</span>\n <span class=\"taf-tabs__label\">{{ t.label }}</span>\n <span class=\"taf-tabs__count\" *ngIf=\"t.count !== undefined\">{{ t.count }}</span>\n <span\n *ngIf=\"t.closeable && !readonly\"\n class=\"taf-tabs__close\"\n role=\"button\"\n tabindex=\"0\"\n [attr.aria-label]=\"'Close ' + t.label\"\n (click)=\"close($event, t)\"\n (keydown.enter)=\"close($event, t)\"\n >✕</span>\n </button>\n </div>\n\n <button\n *ngIf=\"scrollable && overflowing\"\n type=\"button\"\n class=\"taf-tabs__arrow taf-tabs__arrow--end\"\n aria-label=\"Scroll tabs right\"\n (click)=\"scrollBy(1)\"\n >›</button>\n\n <ng-content select=\"[tafTabsEnd]\"></ng-content>\n </div>\n `,\n styles: [\n `\n taf-tabs { display: contents; }\n `,\n ],\n})\nexport class TafTabsComponent implements AfterViewInit {\n @ViewChild('strip') private stripRef?: ElementRef<HTMLElement>;\n private readonly cdr = inject(ChangeDetectorRef);\n\n @Input() tabs: readonly TafTab[] = [];\n /** The active tab's `key`. */\n @Input() active = '';\n /** Surfaces as `data-variant` — the host theme decides what each looks like. */\n @Input() variant = '';\n /** Show arrows and scroll the strip when it overflows. */\n @Input({ transform: booleanAttribute }) scrollable = false;\n /** Hide every close affordance, for a strip the user may read but not change. */\n @Input({ transform: booleanAttribute }) readonly = false;\n\n @Output() readonly activeChange = new EventEmitter<string>();\n /** A tab's ✕ was pressed. The host decides whether it closes. */\n @Output() readonly closeTab = new EventEmitter<string>();\n\n protected overflowing = false;\n\n protected trackKey = (_: number, t: TafTab) => t.key;\n\n ngAfterViewInit(): void {\n this.syncOverflow();\n }\n\n protected syncOverflow(): void {\n const el = this.stripRef?.nativeElement;\n if (!el) return;\n const next = el.scrollWidth > el.clientWidth + 1;\n if (next !== this.overflowing) {\n this.overflowing = next;\n // OnPush: the arrows appear as a result of a measurement, not of an input changing.\n this.cdr.markForCheck();\n }\n }\n\n protected scrollBy(direction: 1 | -1): void {\n const el = this.stripRef?.nativeElement;\n if (!el) return;\n const tab = el.querySelector<HTMLElement>('.taf-tabs__tab');\n el.scrollBy({ left: direction * (tab?.offsetWidth ?? 120), behavior: 'smooth' });\n }\n\n protected pick(t: TafTab): void {\n if (t.disabled || t.key === this.active) return;\n this.activeChange.emit(t.key);\n }\n\n protected close(event: Event, t: TafTab): void {\n event.stopPropagation();\n this.closeTab.emit(t.key);\n }\n}\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './index';\n"],"names":[],"mappings":"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"}
|
package/package.json
ADDED
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@jigisha_ruparel/taf-client-tabs-angular",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "<taf-tabs> — the themeless tab strip above a panel: counts, icons, closeable tabs, overflow scrolling.",
|
|
5
|
+
"publishConfig": {
|
|
6
|
+
"access": "public",
|
|
7
|
+
"directory": "dist"
|
|
8
|
+
},
|
|
9
|
+
"peerDependencies": {
|
|
10
|
+
"@angular/core": ">=17",
|
|
11
|
+
"@angular/common": ">=17"
|
|
12
|
+
},
|
|
13
|
+
"dependencies": {
|
|
14
|
+
"tslib": "^2.3.0"
|
|
15
|
+
},
|
|
16
|
+
"module": "fesm2022/jigisha_ruparel-taf-client-tabs-angular.mjs",
|
|
17
|
+
"typings": "types/jigisha_ruparel-taf-client-tabs-angular.d.ts",
|
|
18
|
+
"exports": {
|
|
19
|
+
"./package.json": {
|
|
20
|
+
"default": "./package.json"
|
|
21
|
+
},
|
|
22
|
+
".": {
|
|
23
|
+
"types": "./types/jigisha_ruparel-taf-client-tabs-angular.d.ts",
|
|
24
|
+
"default": "./fesm2022/jigisha_ruparel-taf-client-tabs-angular.mjs"
|
|
25
|
+
}
|
|
26
|
+
},
|
|
27
|
+
"sideEffects": false,
|
|
28
|
+
"type": "module"
|
|
29
|
+
}
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
import * as i0 from '@angular/core';
|
|
2
|
+
import { AfterViewInit, EventEmitter } from '@angular/core';
|
|
3
|
+
|
|
4
|
+
/** One tab. `key` is what `active` matches and what the outputs emit. */
|
|
5
|
+
interface TafTab {
|
|
6
|
+
key: string;
|
|
7
|
+
label: string;
|
|
8
|
+
/** A count beside the label — how many rows sit behind this tab. */
|
|
9
|
+
count?: number;
|
|
10
|
+
/** A leading glyph or icon ligature. */
|
|
11
|
+
icon?: string;
|
|
12
|
+
disabled?: boolean;
|
|
13
|
+
/** Shows a ✕ on this tab; closing is the host's decision, via `(closeTab)`. */
|
|
14
|
+
closeable?: boolean;
|
|
15
|
+
/** A title attribute, where the label is truncated. */
|
|
16
|
+
hint?: string;
|
|
17
|
+
}
|
|
18
|
+
/**
|
|
19
|
+
* `<taf-tabs>` — the strip of tabs above a panel. It renders the strip only; the host still decides
|
|
20
|
+
* what the active tab shows, which is how these screens are already written.
|
|
21
|
+
*
|
|
22
|
+
* The strip owns no state: it renders `[active]` and emits `(activeChange)`, so a host keeps the
|
|
23
|
+
* signal or route param it already has. Closing is the same — `(closeTab)` fires and the host
|
|
24
|
+
* decides whether the tab actually goes.
|
|
25
|
+
*
|
|
26
|
+
* `scrollable` adds the overflow affordance a long strip needs: the arrows appear only when the
|
|
27
|
+
* strip actually overflows, and scroll it by roughly a tab's width.
|
|
28
|
+
*
|
|
29
|
+
* Ships NO theme — `taf-tabs__*` class hooks plus `data-active` / `data-variant`, so the host app
|
|
30
|
+
* decides whether a tab reads as an underline, a pill or a filled strip.
|
|
31
|
+
*/
|
|
32
|
+
declare class TafTabsComponent implements AfterViewInit {
|
|
33
|
+
private stripRef?;
|
|
34
|
+
private readonly cdr;
|
|
35
|
+
tabs: readonly TafTab[];
|
|
36
|
+
/** The active tab's `key`. */
|
|
37
|
+
active: string;
|
|
38
|
+
/** Surfaces as `data-variant` — the host theme decides what each looks like. */
|
|
39
|
+
variant: string;
|
|
40
|
+
/** Show arrows and scroll the strip when it overflows. */
|
|
41
|
+
scrollable: boolean;
|
|
42
|
+
/** Hide every close affordance, for a strip the user may read but not change. */
|
|
43
|
+
readonly: boolean;
|
|
44
|
+
readonly activeChange: EventEmitter<string>;
|
|
45
|
+
/** A tab's ✕ was pressed. The host decides whether it closes. */
|
|
46
|
+
readonly closeTab: EventEmitter<string>;
|
|
47
|
+
protected overflowing: boolean;
|
|
48
|
+
protected trackKey: (_: number, t: TafTab) => string;
|
|
49
|
+
ngAfterViewInit(): void;
|
|
50
|
+
protected syncOverflow(): void;
|
|
51
|
+
protected scrollBy(direction: 1 | -1): void;
|
|
52
|
+
protected pick(t: TafTab): void;
|
|
53
|
+
protected close(event: Event, t: TafTab): void;
|
|
54
|
+
static ɵfac: i0.ɵɵFactoryDeclaration<TafTabsComponent, never>;
|
|
55
|
+
static ɵcmp: i0.ɵɵComponentDeclaration<TafTabsComponent, "taf-tabs", never, { "tabs": { "alias": "tabs"; "required": false; }; "active": { "alias": "active"; "required": false; }; "variant": { "alias": "variant"; "required": false; }; "scrollable": { "alias": "scrollable"; "required": false; }; "readonly": { "alias": "readonly"; "required": false; }; }, { "activeChange": "activeChange"; "closeTab": "closeTab"; }, never, ["[tafTabsEnd]"], true, never>;
|
|
56
|
+
static ngAcceptInputType_scrollable: unknown;
|
|
57
|
+
static ngAcceptInputType_readonly: unknown;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
export { TafTabsComponent };
|
|
61
|
+
export type { TafTab };
|