Skip to content

Commit

Permalink
feat(material/tabs): add alignTabs in MatTabsConfig
Browse files Browse the repository at this point in the history
users can align tabs label via config now rather than adding `mat-tab-align` property on each tab group

fixes #29685
  • Loading branch information
naaajii committed Sep 25, 2024
1 parent 7c9bf99 commit 2b78e41
Show file tree
Hide file tree
Showing 4 changed files with 134 additions and 1 deletion.
3 changes: 3 additions & 0 deletions src/material/tabs/tab-config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,9 @@ export interface MatTabsConfig {

/** Whether tabs should be stretched to fill the header. */
stretchTabs?: boolean;

/** Alignment for the tabs label. */
alignTabs?: 'start' | 'center' | 'end';
}

/** Injection token that can be used to provide the default options the tabs module. */
Expand Down
121 changes: 121 additions & 0 deletions src/material/tabs/tab-group.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1187,6 +1187,95 @@ describe('MatTabNavBar with a default config', () => {
});
});

describe('MatTabGroup labels aligned with a config', () => {
it('should work with start align', () => {
const fixture = TestBed.configureTestingModule({
imports: [MatTabsModule, BrowserAnimationsModule, TabsWithAlignConfig],
providers: [
{
provide: MAT_TABS_CONFIG,
useValue: {alignTabs: 'start'},
},
],
}).createComponent(TabsWithAlignConfig);
fixture.detectChanges();

const tabElement = fixture.nativeElement.querySelector('[mat-align-tabs="start"]');
expect(tabElement).toBeTruthy();
});

it('should work with center align', () => {
const fixture = TestBed.configureTestingModule({
imports: [MatTabsModule, BrowserAnimationsModule, TabsWithAlignConfig],
providers: [
{
provide: MAT_TABS_CONFIG,
useValue: {alignTabs: 'center'},
},
],
}).createComponent(TabsWithAlignConfig);
fixture.detectChanges();

const tabElement = fixture.nativeElement.querySelector('[mat-align-tabs="center"]');
expect(tabElement).toBeTruthy();
});

it('should work with end align', () => {
const fixture = TestBed.configureTestingModule({
imports: [MatTabsModule, BrowserAnimationsModule, TabsWithAlignConfig],
providers: [
{
provide: MAT_TABS_CONFIG,
useValue: {alignTabs: 'end'},
},
],
}).createComponent(TabsWithAlignConfig);
fixture.detectChanges();

const tabElement = fixture.nativeElement.querySelector('[mat-align-tabs="end"]');
expect(tabElement).toBeTruthy();
});

it('should not add align if default config doesnt set align', () => {
const fixture = TestBed.configureTestingModule({
imports: [MatTabsModule, BrowserAnimationsModule, TabsWithAlignConfig],
}).createComponent(TabsWithAlignConfig);
fixture.detectChanges();

let tabElement = fixture.nativeElement.querySelector('[mat-align-tabs="start"]');
expect(tabElement).toBeFalsy();

tabElement = fixture.nativeElement.querySelector('[mat-align-tabs="center"]');
expect(tabElement).toBeFalsy();

tabElement = fixture.nativeElement.querySelector('[mat-align-tabs="end"]');
expect(tabElement).toBeFalsy();

tabElement = fixture.nativeElement.querySelector('.mat-mdc-tab-group');
expect(tabElement).toBeTruthy();
});

it('should not break if config sets align on already aligned tabs', () => {
const fixture = TestBed.configureTestingModule({
imports: [MatTabsModule, BrowserAnimationsModule, TabsWithAlignCenter],
providers: [{provide: MAT_TABS_CONFIG, useValue: {alignTabs: 'end'}}],
}).createComponent(TabsWithAlignCenter);
fixture.detectChanges();

let tabElement = fixture.nativeElement.querySelector('[mat-align-tabs="start"]');
expect(tabElement).toBeFalsy();

tabElement = fixture.nativeElement.querySelector('[mat-align-tabs="center"]');
expect(tabElement).toBeTruthy();

tabElement = fixture.nativeElement.querySelector('[mat-align-tabs="end"]');
expect(tabElement).toBeFalsy();

tabElement = fixture.nativeElement.querySelector('.mat-mdc-tab-group');
expect(tabElement).toBeTruthy();
});
});

@Component({
template: `
<mat-tab-group class="tab-group"
Expand Down Expand Up @@ -1547,3 +1636,35 @@ class TabsWithClassesTestApp {
labelClassList?: string | string[];
bodyClassList?: string | string[];
}

@Component({
template: `
<mat-tab-group>
<mat-tab>
First
</mat-tab>
<mat-tab>
Second
</mat-tab>
</mat-tab-group>
`,
standalone: true,
imports: [MatTabsModule],
})
class TabsWithAlignConfig {}

@Component({
template: `
<mat-tab-group mat-align-tabs="center">
<mat-tab>
First
</mat-tab>
<mat-tab>
Second
</mat-tab>
</mat-tab-group>
`,
standalone: true,
imports: [MatTabsModule],
})
class TabsWithAlignCenter {}
7 changes: 7 additions & 0 deletions src/material/tabs/tab-group.ts
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,7 @@ const ENABLE_BACKGROUND_INPUT = true;
'[class.mat-mdc-tab-group-dynamic-height]': 'dynamicHeight',
'[class.mat-mdc-tab-group-inverted-header]': 'headerPosition === "below"',
'[class.mat-mdc-tab-group-stretch-tabs]': 'stretchTabs',
'[attr.mat-align-tabs]': 'alignTabs',
'[style.--mat-tab-animation-duration]': 'animationDuration',
},
standalone: true,
Expand Down Expand Up @@ -147,6 +148,10 @@ export class MatTabGroup implements AfterContentInit, AfterContentChecked, OnDes
@Input({alias: 'mat-stretch-tabs', transform: booleanAttribute})
stretchTabs: boolean = true;

/** Alignment for tabs label. */
@Input({alias: 'mat-align-tabs'})
alignTabs: string | null = null;

/** Whether the tab group should grow to the size of the active tab. */
@Input({transform: booleanAttribute})
dynamicHeight: boolean = false;
Expand Down Expand Up @@ -293,6 +298,8 @@ export class MatTabGroup implements AfterContentInit, AfterContentChecked, OnDes
: false;
this.stretchTabs =
defaultConfig && defaultConfig.stretchTabs != null ? defaultConfig.stretchTabs : true;
this.alignTabs =
defaultConfig && defaultConfig.alignTabs != null ? defaultConfig.alignTabs : null;
}

/**
Expand Down
4 changes: 3 additions & 1 deletion tools/public_api_guard/material/tabs.md
Original file line number Diff line number Diff line change
Expand Up @@ -246,6 +246,7 @@ export class MatTabContent {
// @public
export class MatTabGroup implements AfterContentInit, AfterContentChecked, OnDestroy {
constructor(...args: unknown[]);
alignTabs: string | null;
_allTabs: QueryList<MatTab>;
readonly animationDone: EventEmitter<void>;
get animationDuration(): string;
Expand Down Expand Up @@ -315,7 +316,7 @@ export class MatTabGroup implements AfterContentInit, AfterContentChecked, OnDes
_tabs: QueryList<MatTab>;
updatePagination(): void;
// (undocumented)
static ɵcmp: i0.ɵɵComponentDeclaration<MatTabGroup, "mat-tab-group", ["matTabGroup"], { "color": { "alias": "color"; "required": false; }; "fitInkBarToContent": { "alias": "fitInkBarToContent"; "required": false; }; "stretchTabs": { "alias": "mat-stretch-tabs"; "required": false; }; "dynamicHeight": { "alias": "dynamicHeight"; "required": false; }; "selectedIndex": { "alias": "selectedIndex"; "required": false; }; "headerPosition": { "alias": "headerPosition"; "required": false; }; "animationDuration": { "alias": "animationDuration"; "required": false; }; "contentTabIndex": { "alias": "contentTabIndex"; "required": false; }; "disablePagination": { "alias": "disablePagination"; "required": false; }; "disableRipple": { "alias": "disableRipple"; "required": false; }; "preserveContent": { "alias": "preserveContent"; "required": false; }; "backgroundColor": { "alias": "backgroundColor"; "required": false; }; "ariaLabel": { "alias": "aria-label"; "required": false; }; "ariaLabelledby": { "alias": "aria-labelledby"; "required": false; }; }, { "selectedIndexChange": "selectedIndexChange"; "focusChange": "focusChange"; "animationDone": "animationDone"; "selectedTabChange": "selectedTabChange"; }, ["_allTabs"], ["*"], true, never>;
static ɵcmp: i0.ɵɵComponentDeclaration<MatTabGroup, "mat-tab-group", ["matTabGroup"], { "color": { "alias": "color"; "required": false; }; "fitInkBarToContent": { "alias": "fitInkBarToContent"; "required": false; }; "stretchTabs": { "alias": "mat-stretch-tabs"; "required": false; }; "alignTabs": { "alias": "mat-align-tabs"; "required": false; }; "dynamicHeight": { "alias": "dynamicHeight"; "required": false; }; "selectedIndex": { "alias": "selectedIndex"; "required": false; }; "headerPosition": { "alias": "headerPosition"; "required": false; }; "animationDuration": { "alias": "animationDuration"; "required": false; }; "contentTabIndex": { "alias": "contentTabIndex"; "required": false; }; "disablePagination": { "alias": "disablePagination"; "required": false; }; "disableRipple": { "alias": "disableRipple"; "required": false; }; "preserveContent": { "alias": "preserveContent"; "required": false; }; "backgroundColor": { "alias": "backgroundColor"; "required": false; }; "ariaLabel": { "alias": "aria-label"; "required": false; }; "ariaLabelledby": { "alias": "aria-labelledby"; "required": false; }; }, { "selectedIndexChange": "selectedIndexChange"; "focusChange": "focusChange"; "animationDone": "animationDone"; "selectedTabChange": "selectedTabChange"; }, ["_allTabs"], ["*"], true, never>;
// (undocumented)
static ɵfac: i0.ɵɵFactoryDeclaration<MatTabGroup, never>;
}
Expand Down Expand Up @@ -507,6 +508,7 @@ export const matTabsAnimations: {

// @public
export interface MatTabsConfig {
alignTabs?: 'start' | 'center' | 'end';
animationDuration?: string;
contentTabIndex?: number;
disablePagination?: boolean;
Expand Down

0 comments on commit 2b78e41

Please sign in to comment.