Skip to content

Commit ac4888c

Browse files
authored
feat: implement tabs parity (#3352)
Signed-off-by: Akshat Patel <38994122+Akshat55@users.noreply.github.com>
1 parent 04802ac commit ac4888c

23 files changed

Lines changed: 3412 additions & 261 deletions

src/tabs/base-tab-header.component.ts

Lines changed: 62 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -19,8 +19,8 @@ import { EventService } from "carbon-components-angular/utils";
1919
})
2020
export class BaseTabHeader {
2121
/**
22-
* Set to 'true' to have `Tab` items cached and not reloaded on tab switching.
23-
* Duplicate from `n-tabs` to support standalone headers
22+
* Set to `true` to have `Tab` items cached and not reloaded on tab switching.
23+
* Duplicated from `cds-tabs` to support standalone headers.
2424
*/
2525
@Input() cacheActive = false;
2626
/**
@@ -36,19 +36,68 @@ export class BaseTabHeader {
3636
*/
3737
@Input() ariaLabelledby: string;
3838

39+
/**
40+
* Template projected before tab items inside the tab list.
41+
*/
3942
@Input() contentBefore: TemplateRef<any>;
43+
/**
44+
* Template projected after tab items inside the tab list.
45+
*/
4046
@Input() contentAfter: TemplateRef<any>;
4147

48+
/**
49+
* Visual style of the tab list: `line` or `contained`.
50+
*/
4251
@Input() type: "line" | "contained" = "line";
52+
/**
53+
* Theme for contained tabs: `dark` or `light`.
54+
*/
4355
@Input() theme: "dark" | "light" = "dark";
4456

57+
/**
58+
* When using icon-only tabs, icon size: `default` (16px) or `lg` (20px).
59+
*/
60+
@Input() iconSize: "default" | "lg";
61+
62+
/**
63+
* **Contained only**: Evenly sized tabs across the row (**must** have fewer than 9 tabs).
64+
*/
65+
@Input() fullWidth = false;
66+
67+
/**
68+
* Show a close control on each tab.
69+
*/
70+
@Input() dismissable = false;
71+
72+
/**
73+
* Scroll the active tab into view on focus/select.
74+
*/
75+
@Input() scrollIntoView = false;
76+
77+
/**
78+
* Debounce (ms) for tab list scroll events; affects overflow chevron updates.
79+
*/
80+
@Input() scrollDebounceWait = 200;
81+
4582
@HostBinding("class.cds--tabs") tabsClass = true;
4683
@HostBinding("class.cds--tabs--contained") get containedClass() {
4784
return this.type === "contained";
4885
}
4986
@HostBinding("class.cds--tabs--light") get themeClass() {
5087
return this.theme === "light";
5188
}
89+
@HostBinding("class.cds--tabs--dismissable") get dismissableClass() {
90+
return this.dismissable;
91+
}
92+
@HostBinding("class.cds--tabs__icon--default") get iconSizeDefaultClass() {
93+
return this.iconSize === "default";
94+
}
95+
@HostBinding("class.cds--tabs__icon--lg") get iconSizeLgClass() {
96+
return this.iconSize === "lg";
97+
}
98+
@HostBinding("class.cds--layout--size-lg") get layoutSizeLgClass() {
99+
return this.iconSize === "lg";
100+
}
52101

53102
/**
54103
* Gets the Unordered List element that holds the `Tab` headings from the view DOM.
@@ -66,6 +115,7 @@ export class BaseTabHeader {
66115

67116
protected longPressInterval = null;
68117
protected tickInterval = null;
118+
protected scrollDebounceTimer: any = null;
69119

70120
get hasHorizontalOverflow() {
71121
const tabList = this.headerContainer.nativeElement;
@@ -91,7 +141,16 @@ export class BaseTabHeader {
91141
) { }
92142

93143
handleScroll() {
94-
this.changeDetectorRef.markForCheck();
144+
// Debounce the change detection trigger so the scroll arrow visibility
145+
// updates do not fire on every scroll tick.
146+
if (this.scrollDebounceWait <= 0) {
147+
this.changeDetectorRef.markForCheck();
148+
return;
149+
}
150+
clearTimeout(this.scrollDebounceTimer);
151+
this.scrollDebounceTimer = setTimeout(() => {
152+
this.changeDetectorRef.markForCheck();
153+
}, this.scrollDebounceWait);
95154
}
96155

97156
handleOverflowNavClick(direction: number, numOftabs = 0) {

src/tabs/icon-tab.component.ts

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
import {
2+
Component,
3+
forwardRef,
4+
Input
5+
} from "@angular/core";
6+
import { Tab } from "./tab.component";
7+
8+
/**
9+
* Icon-only approach for `cds-tab` variant: `[icon]` template plus `label` for tooltip.
10+
*
11+
* ```html
12+
* <ng-template #i><svg cdsIcon="activity" size="16"></svg></ng-template>
13+
* <cds-tabs>
14+
* <cds-icon-tab label="Activity" [icon]="i">Panel</cds-icon-tab>
15+
* </cds-tabs>
16+
* ```
17+
*/
18+
@Component({
19+
selector: "cds-icon-tab, ibm-icon-tab",
20+
template: `
21+
<ng-container *ngIf="shouldRender()">
22+
<ng-template
23+
*ngIf="isTemplate(tabContent)"
24+
[ngTemplateOutlet]="tabContent"
25+
[ngTemplateOutletContext]="{ $implicit: templateContext }">
26+
</ng-template>
27+
<ng-content></ng-content>
28+
</ng-container>
29+
`,
30+
providers: [
31+
// tslint:disable-next-line:no-forward-ref
32+
{ provide: Tab, useExisting: forwardRef(() => IconTab) }
33+
]
34+
})
35+
export class IconTab extends Tab {
36+
/**
37+
* Accessible label and tooltip text for the icon tab.
38+
*/
39+
@Input()
40+
set label(value: string) {
41+
this.iconLabel = value;
42+
}
43+
44+
get label(): string {
45+
return this.iconLabel;
46+
}
47+
48+
/**
49+
* Icon tabs are only for icons, so iconOnly by default
50+
*/
51+
override iconOnly = true;
52+
}

src/tabs/index.ts

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,18 @@
11
export { BaseTabHeader } from "./base-tab-header.component";
22
export { TabHeaderGroup } from "./tab-header-group.component";
3+
export { TabHeaderGroupVertical } from "./tab-header-group-vertical.component";
4+
export { TabHeaderBase } from "./tab-header.directive";
5+
/**
6+
* @deprecated Use `TabHeaderComponent` and the `cds-tab-header` host element.
7+
*/
38
export { TabHeader } from "./tab-header.directive";
9+
export { TabHeaderComponent } from "./tab-header.component";
410
export { TabHeaders } from "./tab-headers.component";
11+
export { TabHeadersVertical } from "./tab-headers-vertical.component";
512
export { Tab } from "./tab.component";
13+
export { IconTab } from "./icon-tab.component";
614
export { Tabs } from "./tabs.component";
15+
export { TabsVertical } from "./tabs-vertical.component";
16+
export { TabsVerticalGrouped } from "./tabs-vertical-grouped.component";
717
export { TabSkeleton } from "./tab-skeleton.component";
818
export * from "./tabs.module";

0 commit comments

Comments
 (0)