Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(tab-nav-bar): support disabling tab links #5257

Merged
merged 2 commits into from
Jun 23, 2017
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions src/demo-app/tabs/tabs-demo.html
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ <h1>Tab Nav Bar</h1>
[active]="rla.isActive">
{{tabLink.label}}
</a>
<a md-tab-link disabled>Disabled Link</a>
</nav>
<router-outlet></router-outlet>
</div>
Expand Down
6 changes: 6 additions & 0 deletions src/lib/tabs/_tabs-common.scss
Original file line number Diff line number Diff line change
Expand Up @@ -14,10 +14,16 @@ $mat-tab-animation-duration: 500ms !default;
opacity: 0.6;
min-width: 160px;
text-align: center;

&:focus {
outline: none;
opacity: 1;
}

&.mat-tab-disabled {
cursor: default;
pointer-events: none;
}
}

// Mixin styles for the top section of the view; contains the tab labels.
Expand Down
4 changes: 1 addition & 3 deletions src/lib/tabs/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ import {MdTab} from './tab';
import {MdTabGroup} from './tab-group';
import {MdTabLabel} from './tab-label';
import {MdTabLabelWrapper} from './tab-label-wrapper';
import {MdTabNav, MdTabLink, MdTabLinkRipple} from './tab-nav-bar/tab-nav-bar';
import {MdTabNav, MdTabLink} from './tab-nav-bar/tab-nav-bar';
import {MdInkBar} from './ink-bar';
import {MdTabBody} from './tab-body';
import {VIEWPORT_RULER_PROVIDER} from '../core/overlay/position/viewport-ruler';
Expand All @@ -38,7 +38,6 @@ import {ScrollDispatchModule} from '../core/overlay/scroll/index';
MdTab,
MdTabNav,
MdTabLink,
MdTabLinkRipple
],
declarations: [
MdTabGroup,
Expand All @@ -49,7 +48,6 @@ import {ScrollDispatchModule} from '../core/overlay/scroll/index';
MdTabNav,
MdTabLink,
MdTabBody,
MdTabLinkRipple,
MdTabHeader
],
providers: [VIEWPORT_RULER_PROVIDER],
Expand Down
6 changes: 0 additions & 6 deletions src/lib/tabs/tab-group.scss
Original file line number Diff line number Diff line change
Expand Up @@ -55,9 +55,3 @@
overflow-y: hidden;
}
}

// Styling for any tab that is marked disabled
.mat-tab-disabled {
cursor: default;
pointer-events: none;
}
26 changes: 26 additions & 0 deletions src/lib/tabs/tab-nav-bar/tab-nav-bar.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,30 @@ describe('MdTabNavBar', () => {
expect(fixture.componentInstance.activeIndex).toBe(2);
});

it('should add the disabled class if disabled', () => {
const tabLinkElements = fixture.debugElement.queryAll(By.css('a'))
.map(tabLinkDebugEl => tabLinkDebugEl.nativeElement);

expect(tabLinkElements.every(tabLinkEl => !tabLinkEl.classList.contains('mat-tab-disabled')))
.toBe(true, 'Expected every tab link to not have the disabled class initially');

fixture.componentInstance.disabled = true;
fixture.detectChanges();

expect(tabLinkElements.every(tabLinkEl => tabLinkEl.classList.contains('mat-tab-disabled')))
.toBe(true, 'Expected every tab link to have the disabled class if set through binding');
});

it('should show ripples for tab links', () => {
const tabLink = fixture.debugElement.nativeElement.querySelector('.mat-tab-link');

dispatchMouseEvent(tabLink, 'mousedown');
dispatchMouseEvent(tabLink, 'mouseup');

expect(tabLink.querySelectorAll('.mat-ripple-element').length)
.toBe(1, 'Expected one ripple to show up if user clicks on tab link.');
});

it('should re-align the ink bar when the direction changes', () => {
const inkBar = fixture.componentInstance.tabNavBar._inkBar;

Expand Down Expand Up @@ -125,6 +149,7 @@ describe('MdTabNavBar', () => {
<a md-tab-link
*ngFor="let tab of tabs; let index = index"
[active]="activeIndex === index"
[disabled]="disabled"
(click)="activeIndex = index">
Tab link {{label}}
</a>
Expand All @@ -135,6 +160,7 @@ class SimpleTabNavBarTestApp {
@ViewChild(MdTabNav) tabNavBar: MdTabNav;

label = '';
disabled: boolean = false;
tabs = [0, 1, 2];

activeIndex = 0;
Expand Down
48 changes: 27 additions & 21 deletions src/lib/tabs/tab-nav-bar/tab-nav-bar.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,15 +20,16 @@ import {
ViewEncapsulation
} from '@angular/core';
import {MdInkBar} from '../ink-bar';
import {MdRipple} from '../../core/ripple/index';
import {CanDisable, mixinDisabled} from '../../core/common-behaviors/disabled';
import {MdRipple, coerceBooleanProperty} from '../../core';
import {ViewportRuler} from '../../core/overlay/position/viewport-ruler';
import {Directionality, MD_RIPPLE_GLOBAL_OPTIONS, Platform, RippleGlobalOptions} from '../../core';
import {Observable} from 'rxjs/Observable';
import {Subject} from 'rxjs/Subject';
import 'rxjs/add/operator/auditTime';
import 'rxjs/add/operator/takeUntil';
import 'rxjs/add/observable/of';
import 'rxjs/add/observable/merge';
import {Subject} from 'rxjs/Subject';

/**
* Navigation component matching the styles of the tab group header.
Expand Down Expand Up @@ -92,16 +93,28 @@ export class MdTabNav implements AfterContentInit, OnDestroy {
}
}


// Boilerplate for applying mixins to MdTabLink.
export class MdTabLinkBase {}
export const _MdTabLinkMixinBase = mixinDisabled(MdTabLinkBase);

/**
* Link inside of a `md-tab-nav-bar`.
*/
@Directive({
selector: '[md-tab-link], [mat-tab-link], [mdTabLink], [matTabLink]',
host: {'class': 'mat-tab-link'}
inputs: ['disabled'],
host: {
'class': 'mat-tab-link',
'[class.mat-tab-disabled]': 'disabled'
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Also needs aria-disabled and setting tabIndex to -1 (same as MdAnchor) with corresponding tests.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Addressed this.

}
})
export class MdTabLink {
export class MdTabLink extends _MdTabLinkMixinBase implements CanDisable {
private _isActive: boolean = false;

/** Reference to the instance of the ripple for the tab link. */
private _tabLinkRipple: MdRipple;

/** Whether the link is active. */
@Input()
get active(): boolean { return this._isActive; }
Expand All @@ -112,23 +125,16 @@ export class MdTabLink {
}
}

constructor(private _mdTabNavBar: MdTabNav, private _elementRef: ElementRef) {}
}
constructor(private _mdTabNavBar: MdTabNav,
private _elementRef: ElementRef,
ngZone: NgZone,
ruler: ViewportRuler,
platform: Platform,
@Optional() @Inject(MD_RIPPLE_GLOBAL_OPTIONS) globalOptions: RippleGlobalOptions) {
super();

/**
* Simple directive that extends the ripple and matches the selector of the MdTabLink. This
* adds the ripple behavior to nav bar labels.
*/
@Directive({
selector: '[md-tab-link], [mat-tab-link], [mdTabLink], [matTabLink]',
})
export class MdTabLinkRipple extends MdRipple {
constructor(
elementRef: ElementRef,
ngZone: NgZone,
ruler: ViewportRuler,
platform: Platform,
@Optional() @Inject(MD_RIPPLE_GLOBAL_OPTIONS) globalOptions: RippleGlobalOptions) {
super(elementRef, ngZone, ruler, platform, globalOptions);
// Manually create a ripple instance that uses the tab link element as trigger element.
// Notice that the lifecycle hook `ngOnChanges` for the ripple config can't be called anymore.
this._tabLinkRipple = new MdRipple(_elementRef, ngZone, ruler, platform, globalOptions);
}
}