diff --git a/src/material-experimental/mdc-tabs/tab-group.spec.ts b/src/material-experimental/mdc-tabs/tab-group.spec.ts index 144ae001c2bb..7cccb3bf5cbc 100644 --- a/src/material-experimental/mdc-tabs/tab-group.spec.ts +++ b/src/material-experimental/mdc-tabs/tab-group.spec.ts @@ -6,7 +6,7 @@ import {By} from '@angular/platform-browser'; import {BrowserAnimationsModule, NoopAnimationsModule} from '@angular/platform-browser/animations'; import {CommonModule} from '@angular/common'; import {Observable} from 'rxjs'; -import {MatTab, MatTabGroup, MatTabHeaderPosition, MatTabsModule} from './index'; +import {MAT_TABS_CONFIG, MatTab, MatTabGroup, MatTabHeaderPosition, MatTabsModule} from './index'; describe('MatTabGroup', () => { @@ -698,6 +698,7 @@ describe('MatTabGroup with ink bar fit to content', () => { const tabElement = fixture.nativeElement.querySelector('.mdc-tab'); const contentElement = tabElement.querySelector('.mdc-tab__content'); const indicatorElement = tabElement.querySelector('.mdc-tab-indicator'); + expect(indicatorElement.parentElement).toBeTruthy(); expect(indicatorElement.parentElement).toBe(contentElement); }); @@ -707,12 +708,44 @@ describe('MatTabGroup with ink bar fit to content', () => { const tabElement = fixture.nativeElement.querySelector('.mdc-tab'); const indicatorElement = tabElement.querySelector('.mdc-tab-indicator'); + expect(indicatorElement.parentElement).toBeTruthy(); expect(indicatorElement.parentElement).toBe(tabElement); fixture.componentInstance.fitInkBarToContent = true; fixture.detectChanges(); const contentElement = tabElement.querySelector('.mdc-tab__content'); + expect(indicatorElement.parentElement).toBeTruthy(); + expect(indicatorElement.parentElement).toBe(contentElement); + }); +}); + + +describe('MatTabNavBar with a default config', () => { + let fixture: ComponentFixture; + + beforeEach(fakeAsync(() => { + TestBed.configureTestingModule({ + imports: [MatTabsModule, BrowserAnimationsModule], + declarations: [SimpleTabsTestApp], + providers: [ + {provide: MAT_TABS_CONFIG, useValue: {fitInkBarToContent: true}} + ] + }); + + TestBed.compileComponents(); + })); + + beforeEach(() => { + fixture = TestBed.createComponent(SimpleTabsTestApp); + fixture.detectChanges(); + }); + + it('should set whether the ink bar fits to content', () => { + const tabElement = fixture.nativeElement.querySelector('.mdc-tab'); + const contentElement = tabElement.querySelector('.mdc-tab__content'); + const indicatorElement = tabElement.querySelector('.mdc-tab-indicator'); + expect(indicatorElement.parentElement).toBeTruthy(); expect(indicatorElement.parentElement).toBe(contentElement); }); }); diff --git a/src/material-experimental/mdc-tabs/tab-group.ts b/src/material-experimental/mdc-tabs/tab-group.ts index d6ad53300b17..d7b7bbbc0ce0 100644 --- a/src/material-experimental/mdc-tabs/tab-group.ts +++ b/src/material-experimental/mdc-tabs/tab-group.ts @@ -70,5 +70,7 @@ export class MatTabGroup extends _MatTabGroupBase { @Inject(MAT_TABS_CONFIG) @Optional() defaultConfig?: MatTabsConfig, @Optional() @Inject(ANIMATION_MODULE_TYPE) animationMode?: string) { super(elementRef, changeDetectorRef, defaultConfig, animationMode); + this.fitInkBarToContent = defaultConfig && defaultConfig.fitInkBarToContent != null ? + defaultConfig.fitInkBarToContent : false; } } diff --git a/src/material-experimental/mdc-tabs/tab-nav-bar/tab-nav-bar.spec.ts b/src/material-experimental/mdc-tabs/tab-nav-bar/tab-nav-bar.spec.ts index 03e33be1c754..b42ad360d5f8 100644 --- a/src/material-experimental/mdc-tabs/tab-nav-bar/tab-nav-bar.spec.ts +++ b/src/material-experimental/mdc-tabs/tab-nav-bar/tab-nav-bar.spec.ts @@ -7,6 +7,8 @@ import {Direction, Directionality} from '@angular/cdk/bidi'; import {Subject} from 'rxjs'; import {MatTabsModule} from '../module'; import {MatTabLink, MatTabNav} from './tab-nav-bar'; +import {BrowserAnimationsModule} from '@angular/platform-browser/animations'; +import {MAT_TABS_CONFIG} from '../index'; describe('MatTabNavBar', () => { @@ -335,6 +337,7 @@ describe('MatTabNavBar', () => { const tabElement = fixture.nativeElement.querySelector('.mdc-tab'); const contentElement = tabElement.querySelector('.mdc-tab__content'); const indicatorElement = tabElement.querySelector('.mdc-tab-indicator'); + expect(indicatorElement.parentElement).toBeTruthy(); expect(indicatorElement.parentElement).toBe(contentElement); }); @@ -344,17 +347,49 @@ describe('MatTabNavBar', () => { const tabElement = fixture.nativeElement.querySelector('.mdc-tab'); const indicatorElement = tabElement.querySelector('.mdc-tab-indicator'); + expect(indicatorElement.parentElement).toBeTruthy(); expect(indicatorElement.parentElement).toBe(tabElement); fixture.componentInstance.fitInkBarToContent = true; fixture.detectChanges(); const contentElement = tabElement.querySelector('.mdc-tab__content'); + expect(indicatorElement.parentElement).toBeTruthy(); expect(indicatorElement.parentElement).toBe(contentElement); }); }); }); +describe('MatTabNavBar with a default config', () => { + let fixture: ComponentFixture; + + beforeEach(fakeAsync(() => { + TestBed.configureTestingModule({ + imports: [MatTabsModule, BrowserAnimationsModule], + declarations: [TabLinkWithTabIndexBinding], + providers: [ + {provide: MAT_TABS_CONFIG, useValue: {fitInkBarToContent: true}} + ] + }); + + TestBed.compileComponents(); + })); + + beforeEach(() => { + fixture = TestBed.createComponent(TabLinkWithTabIndexBinding); + fixture.detectChanges(); + }); + + it('should set whether the ink bar fits to content', () => { + const tabElement = fixture.nativeElement.querySelector('.mdc-tab'); + const contentElement = tabElement.querySelector('.mdc-tab__content'); + const indicatorElement = tabElement.querySelector('.mdc-tab-indicator'); + expect(indicatorElement.parentElement).toBeTruthy(); + expect(indicatorElement.parentElement).toBe(contentElement); + }); +}); + + @Component({ selector: 'test-app', template: ` diff --git a/src/material-experimental/mdc-tabs/tab-nav-bar/tab-nav-bar.ts b/src/material-experimental/mdc-tabs/tab-nav-bar/tab-nav-bar.ts index c5ab5b9688f5..f49840105ceb 100644 --- a/src/material-experimental/mdc-tabs/tab-nav-bar/tab-nav-bar.ts +++ b/src/material-experimental/mdc-tabs/tab-nav-bar/tab-nav-bar.ts @@ -25,7 +25,12 @@ import { import {ANIMATION_MODULE_TYPE} from '@angular/platform-browser/animations'; import {MAT_RIPPLE_GLOBAL_OPTIONS, RippleGlobalOptions} from '@angular/material/core'; import {FocusMonitor} from '@angular/cdk/a11y'; -import {_MatTabNavBase, _MatTabLinkBase} from '@angular/material/tabs'; +import { + _MatTabNavBase, + _MatTabLinkBase, + MAT_TABS_CONFIG, + MatTabsConfig +} from '@angular/material/tabs'; import {DOCUMENT} from '@angular/common'; import {Directionality} from '@angular/cdk/bidi'; import {ViewportRuler} from '@angular/cdk/scrolling'; @@ -81,8 +86,13 @@ export class MatTabNav extends _MatTabNavBase implements AfterContentInit { * @deprecated @breaking-change 9.0.0 `platform` parameter to become required. */ @Optional() platform?: Platform, - @Optional() @Inject(ANIMATION_MODULE_TYPE) animationMode?: string) { + @Optional() @Inject(ANIMATION_MODULE_TYPE) animationMode?: string, + @Optional() @Inject(MAT_TABS_CONFIG) defaultConfig?: MatTabsConfig) { super(elementRef, dir, ngZone, changeDetectorRef, viewportRuler, platform, animationMode); + this.disablePagination = defaultConfig && defaultConfig.disablePagination != null ? + defaultConfig.disablePagination : false; + this.fitInkBarToContent = defaultConfig && defaultConfig.fitInkBarToContent != null ? + defaultConfig.fitInkBarToContent : false; } ngAfterContentInit() { diff --git a/src/material/tabs/public-api.ts b/src/material/tabs/public-api.ts index fc8dac396f64..cfce3a1ec09f 100644 --- a/src/material/tabs/public-api.ts +++ b/src/material/tabs/public-api.ts @@ -24,3 +24,4 @@ export {MatTabNav, MatTabLink, _MatTabNavBase, _MatTabLinkBase} from './tab-nav- export {MatTabContent} from './tab-content'; export {ScrollDirection} from './paginated-tab-header'; export * from './tabs-animations'; +export {MAT_TABS_CONFIG, MatTabsConfig} from './tab-config'; diff --git a/src/material/tabs/tab-config.ts b/src/material/tabs/tab-config.ts new file mode 100644 index 000000000000..985208102ddc --- /dev/null +++ b/src/material/tabs/tab-config.ts @@ -0,0 +1,29 @@ +/** + * @license + * Copyright Google LLC All Rights Reserved. + * + * Use of this source code is governed by an MIT-style license that can be + * found in the LICENSE file at https://angular.io/license + */ +import {InjectionToken} from '@angular/core'; + +/** Object that can be used to configure the default options for the tabs module. */ +export interface MatTabsConfig { + /** Duration for the tab animation. Must be a valid CSS value (e.g. 600ms). */ + animationDuration?: string; + + /** + * Whether pagination should be disabled. This can be used to avoid unnecessary + * layout recalculations if it's known that pagination won't be required. + */ + disablePagination?: boolean; + + /** + * Whether the ink bar should fit its width to the size of the tab label content. + * This only applies to the MDC-based tabs. + */ + fitInkBarToContent?: boolean; +} + +/** Injection token that can be used to provide the default options the tabs module. */ +export const MAT_TABS_CONFIG = new InjectionToken('MAT_TABS_CONFIG'); diff --git a/src/material/tabs/tab-group.ts b/src/material/tabs/tab-group.ts index fd9318bfc627..1eb6205cddcd 100644 --- a/src/material/tabs/tab-group.ts +++ b/src/material/tabs/tab-group.ts @@ -14,18 +14,17 @@ import { ChangeDetectorRef, Component, ContentChildren, + Directive, ElementRef, EventEmitter, + Inject, Input, OnDestroy, + Optional, Output, QueryList, ViewChild, ViewEncapsulation, - Optional, - Inject, - InjectionToken, - Directive, } from '@angular/core'; import { CanColor, @@ -39,7 +38,8 @@ import { import {ANIMATION_MODULE_TYPE} from '@angular/platform-browser/animations'; import {merge, Subscription} from 'rxjs'; import {startWith} from 'rxjs/operators'; -import {MatTab, MAT_TAB_GROUP} from './tab'; +import {MAT_TAB_GROUP, MatTab} from './tab'; +import {MAT_TABS_CONFIG, MatTabsConfig} from './tab-config'; /** Used to generate unique ID's for each tab component */ @@ -56,21 +56,6 @@ export class MatTabChangeEvent { /** Possible positions for the tab header. */ export type MatTabHeaderPosition = 'above' | 'below'; -/** Object that can be used to configure the default options for the tabs module. */ -export interface MatTabsConfig { - /** Duration for the tab animation. Must be a valid CSS value (e.g. 600ms). */ - animationDuration?: string; - - /** - * Whether pagination should be disabled. This can be used to avoid unnecessary - * layout recalculations if it's known that pagination won't be required. - */ - disablePagination?: boolean; -} - -/** Injection token that can be used to provide the default options the tabs module. */ -export const MAT_TABS_CONFIG = new InjectionToken('MAT_TABS_CONFIG'); - // Boilerplate for applying mixins to MatTabGroup. /** @docs-private */ class MatTabGroupMixinBase { diff --git a/tools/public_api_guard/material/tabs.d.ts b/tools/public_api_guard/material/tabs.d.ts index 549f02d1ee82..b986704b184e 100644 --- a/tools/public_api_guard/material/tabs.d.ts +++ b/tools/public_api_guard/material/tabs.d.ts @@ -199,6 +199,7 @@ export declare const matTabsAnimations: { export interface MatTabsConfig { animationDuration?: string; disablePagination?: boolean; + fitInkBarToContent?: boolean; } export declare class MatTabsModule {