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

fix(Tabs): refactoring tabs selection #5539

Merged
merged 5 commits into from
Aug 5, 2019
Merged
Show file tree
Hide file tree
Changes from 3 commits
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
64 changes: 14 additions & 50 deletions projects/igniteui-angular/src/lib/tabs/tab-item.component.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ import { IgxTabItemTemplateDirective } from './tabs.directives';
templateUrl: 'tab-item.component.html'
})

export class IgxTabItemComponent implements IgxTabItemBase {
export class IgxTabItemComponent extends IgxTabItemBase {

/**
* Gets the group associated with the tab.
Expand Down Expand Up @@ -80,10 +80,10 @@ export class IgxTabItemComponent implements IgxTabItemBase {

private _nativeTabItem: ElementRef;
private _changesCount = 0; // changes and updates accordingly applied to the tab.
private _isSelected = false;
private _disabled = false;

constructor(private _tabs: IgxTabsBase, private _element: ElementRef) {
super();
this._nativeTabItem = _element;
}

Expand Down Expand Up @@ -158,9 +158,7 @@ export class IgxTabItemComponent implements IgxTabItemBase {
@HostListener('window:resize', ['$event'])
public onResize(event) {
if (this.isSelected) {
this._tabs.selectedIndicator.nativeElement.style.visibility = 'visible';
this._tabs.selectedIndicator.nativeElement.style.width = `${this.nativeTabItem.nativeElement.offsetWidth}px`;
this._tabs.selectedIndicator.nativeElement.style.transform = `translate(${this.nativeTabItem.nativeElement.offsetLeft}px)`;
this._tabs.transformIndicatorAnimation(this.nativeTabItem.nativeElement);
}
}

Expand Down Expand Up @@ -241,63 +239,28 @@ export class IgxTabItemComponent implements IgxTabItemBase {
return this.relatedGroup ? this.relatedGroup.isSelected : this._isSelected;
}
set isSelected(newValue: boolean) {
if (this.relatedGroup) {
this.relatedGroup.isSelected = newValue;
} else if (this._isSelected !== newValue) {
this._isSelected = newValue;
if (this._isSelected) {
this.select();
}
if (!this.disabled && this.isSelected !== newValue) {
this._tabs.performSelectionChange(newValue ? this : null);
}
}

/**
* @hidden
*/
get index(): number {
if (this._tabs.tabs) {
return this._tabs.tabs.toArray().indexOf(this);
public select(): void {
if (!this.disabled && !this.isSelected) {
this._tabs.performSelectionChange(this);
}
}

/**
* @hidden
*/
public select(focusDelay = 200): void {
if (this.relatedGroup) {
this.relatedGroup.select(focusDelay);
} else {
this._isSelected = true;
this._tabs.onTabItemSelected.emit({ tab: this, group: null });
this.handleTabSelectionAnimation();
}
}

private handleTabSelectionAnimation(): void {
const tabElement = this.nativeTabItem.nativeElement;

// Scroll to the left
if (tabElement.offsetLeft < this._tabs.offset) {
this._tabs.scrollElement(tabElement, false);
}

// Scroll to the right
const viewPortOffsetWidth = this._tabs.viewPort.nativeElement.offsetWidth;
const delta = (tabElement.offsetLeft + tabElement.offsetWidth) - (viewPortOffsetWidth + this._tabs.offset);
// Fix for IE 11, a difference is accumulated from the widths calculations
if (delta > 1) {
this._tabs.scrollElement(tabElement, true);
}

this.transformIndicatorAnimation(tabElement);
}

private transformIndicatorAnimation(element: HTMLElement): void {
if (this._tabs && this._tabs.selectedIndicator) {
this._tabs.selectedIndicator.nativeElement.style.visibility = `visible`;
this._tabs.selectedIndicator.nativeElement.style.width = `${element.offsetWidth}px`;
this._tabs.selectedIndicator.nativeElement.style.transform = `translate(${element.offsetLeft}px)`;
get index(): number {
if (this._tabs.tabs) {
return this._tabs.tabs.toArray().indexOf(this);
}
return -1;
}

private onKeyDown(isLeftArrow: boolean, index = null): void {
Expand All @@ -308,7 +271,7 @@ export class IgxTabItemComponent implements IgxTabItemBase {
: (this._tabs.selectedIndex === tabsArray.length - 1) ? 0 : this._tabs.selectedIndex + 1;
}
const tab = tabsArray[index];
tab.select(200);
tab.select();
}

/**
Expand All @@ -330,4 +293,5 @@ export class IgxTabItemComponent implements IgxTabItemBase {
public get context(): any {
return this.relatedGroup ? this.relatedGroup : this;
}

}
70 changes: 11 additions & 59 deletions projects/igniteui-angular/src/lib/tabs/tabs-group.component.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,12 +19,7 @@ import { IgxTabsBase, IgxTabsGroupBase } from './tabs.common';
templateUrl: 'tabs-group.component.html'
})

export class IgxTabsGroupComponent implements IgxTabsGroupBase, AfterContentInit, AfterViewChecked {

/**
* @hidden
*/
private _isSelected = false;
export class IgxTabsGroupComponent extends IgxTabsGroupBase implements AfterContentInit, AfterViewChecked {

/**
* An @Input property that allows you to enable/disable the `IgxTabGroupComponent`.
Expand Down Expand Up @@ -68,12 +63,8 @@ export class IgxTabsGroupComponent implements IgxTabsGroupBase, AfterContentInit
return this._isSelected;
}
public set isSelected(newValue: boolean) {
if (this._isSelected !== newValue) {
if (newValue) {
this.select();
} else {
this._isSelected = newValue;
}
if (!this.disabled && this.isSelected !== newValue) {
this._tabs.performSelectionChange(newValue ? this.relatedTab : null);
}
}

Expand All @@ -86,6 +77,7 @@ export class IgxTabsGroupComponent implements IgxTabsGroupBase, AfterContentInit
private _tabTemplate: TemplateRef<any>;

constructor(private _tabs: IgxTabsBase, private _element: ElementRef) {
super();
}

/**
Expand All @@ -103,7 +95,7 @@ export class IgxTabsGroupComponent implements IgxTabsGroupBase, AfterContentInit
@HostListener('window:resize', ['$event'])
public onResize(event) {
if (this.isSelected) {
this.transformContentAnimation(0);
this._tabs.transformContentAnimation(this.relatedTab, 0);
}
}

Expand Down Expand Up @@ -137,6 +129,7 @@ export class IgxTabsGroupComponent implements IgxTabsGroupBase, AfterContentInit
if (this._tabs.groups) {
return this._tabs.groups.toArray().indexOf(this);
}
return -1;
}

/**
Expand Down Expand Up @@ -171,8 +164,8 @@ export class IgxTabsGroupComponent implements IgxTabsGroupBase, AfterContentInit

if (this.isSelected) {
const tabItem = this.relatedTab.nativeTabItem.nativeElement;
this.transformContentAnimation(0);
this.transformIndicatorAnimation(tabItem);
this._tabs.transformContentAnimation(this.relatedTab, 0);
this._tabs.transformIndicatorAnimation(tabItem);
}
}

Expand All @@ -188,51 +181,10 @@ export class IgxTabsGroupComponent implements IgxTabsGroupBase, AfterContentInit
*```
* @param focusDelay A number representing the expected delay.
*/
public select(focusDelay = 200): void {
if (this.disabled || this.isSelected) {
return;
public select(): void {
if (!this.disabled && !this.isSelected) {
this._tabs.performSelectionChange(this.relatedTab);
}

this._isSelected = true;
this.relatedTab.tabindex = 0;

if (focusDelay !== 0) {
setTimeout(() => {
this.relatedTab.nativeTabItem.nativeElement.focus();
}, focusDelay);
}
this.handleSelection();
this._tabs.onTabItemSelected.emit({ tab: this._tabs.tabs.toArray()[this.index], group: this });
}

private handleSelection(): void {
const tabElement = this.relatedTab.nativeTabItem.nativeElement;

// Scroll to the left
if (tabElement.offsetLeft < this._tabs.offset) {
this._tabs.scrollElement(tabElement, false);
}

// Scroll to the right
const viewPortOffsetWidth = this._tabs.viewPort.nativeElement.offsetWidth;
const delta = (tabElement.offsetLeft + tabElement.offsetWidth) - (viewPortOffsetWidth + this._tabs.offset);
// Fix for IE 11, a difference is accumulated from the widths calculations
if (delta > 1) {
this._tabs.scrollElement(tabElement, true);
}

this.transformContentAnimation(0.2);
this.transformIndicatorAnimation(tabElement);
}

private transformContentAnimation(duration: number): void {
const contentOffset = this._tabs.tabsContainer.nativeElement.offsetWidth * this.index;
this._tabs.contentsContainer.nativeElement.style.transitionDuration = `${duration}s`;
this._tabs.contentsContainer.nativeElement.style.transform = `translate(${-contentOffset}px)`;
}

private transformIndicatorAnimation(element: HTMLElement): void {
this._tabs.selectedIndicator.nativeElement.style.width = `${element.offsetWidth}px`;
this._tabs.selectedIndicator.nativeElement.style.transform = `translate(${element.offsetLeft}px)`;
}
}
15 changes: 11 additions & 4 deletions projects/igniteui-angular/src/lib/tabs/tabs.common.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,15 +15,22 @@ export abstract class IgxTabsBase {
onTabItemSelected: EventEmitter<{}>; // TODO: Define event arg interface!
hasContentTabs: boolean;
scrollElement(element: any, scrollRight: boolean) {}
performSelectionChange(newTab: IgxTabItemBase) {}
transformContentAnimation(tab: IgxTabItemBase, duration: number) {}
transformIndicatorAnimation(element: HTMLElement) {}
}

/** @hidden */
export interface IgxTabItemBase {
export abstract class IgxTabItemBase {
nativeTabItem: ElementRef;
select(focusDelay?: number);
_isSelected = false;
rmkrmk marked this conversation as resolved.
Show resolved Hide resolved
tabindex;
select(focusDelay?: number): void {}
rmkrmk marked this conversation as resolved.
Show resolved Hide resolved
get index(): number { return 0; }
}

/** @hidden */
export interface IgxTabsGroupBase {
select(focusDelay?: number);
export abstract class IgxTabsGroupBase {
_isSelected = false;
select(focusDelay?: number): void {}
}
9 changes: 9 additions & 0 deletions projects/igniteui-angular/src/lib/tabs/tabs.component.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -531,11 +531,13 @@ describe('IgxTabs', () => {
});

describe('Tabs-only Mode With Initial Selection Set on TabItems Tests', () => {
let router;
let fixture;
let tabsComp;
let theTabs;

beforeEach(async(() => {
router = TestBed.get(Router);
fixture = TestBed.createComponent(TabsTabsOnlyModeTest1Component);
tabsComp = fixture.componentInstance.tabs;
fixture.detectChanges();
Expand Down Expand Up @@ -576,6 +578,13 @@ describe('IgxTabs', () => {
expect(theTabs[2].nativeTabItem.nativeElement.classList.contains(tabItemSelectedCssClass)).toBe(true);
});

it('should hide the selection indicator when no tab item is selected', () => {
expect(tabsComp.selectedIndicator.nativeElement.style.visibility).toBe('visible');
theTabs[1].isSelected = false;
fixture.detectChanges();
expect(tabsComp.selectedIndicator.nativeElement.style.visibility).toBe('hidden');
});

});

describe('Tabs-only Mode With Initial Selection Set on Tabs Component Tests', () => {
Expand Down
Loading