-
Notifications
You must be signed in to change notification settings - Fork 357
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat(tab-select): initial implementation for tab select *experimental* (
#1187) * feat(tab-select): initial implementation for tab select *experimental* first pass on tab select component and will be treated as experimental while we use it in multiple products to ensure quality * docs(tab-select): make backgroundColor optional in README * chore(tab-select): add initial set of unit tests * feat(): add disabled ripple on tabs for test-bed
- Loading branch information
1 parent
6f8a3bf
commit 66503a9
Showing
17 changed files
with
634 additions
and
2 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -12,5 +12,11 @@ | |
"Steven Ov <[email protected]>", | ||
"Jenn Medellin <[email protected]>", | ||
"Julie Knowles <[email protected]>" | ||
] | ||
], | ||
"peerDependencies": { | ||
"@angular/common": "^0.0.0-NG", | ||
"@angular/core": "^0.0.0-NG", | ||
"@angular/cdk": "^0.0.0-MATERIAL", | ||
"@angular/material": "^0.0.0-MATERIAL" | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1 +1,2 @@ | ||
export * from './template-rename-me-experiment-module/index'; | ||
export * from './tab-select/index'; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,90 @@ | ||
# td-tab-select (experimental) | ||
|
||
`td-tab-select` element generates a tab group component that behaves like a `mat-select`. | ||
|
||
## API Summary | ||
|
||
#### Inputs | ||
|
||
+ value?: any | ||
+ Sets the value of the component. | ||
+ disabled?: boolean | ||
+ Sets disabled state of the component. | ||
+ disabledRipple?: boolean | ||
+ Disables ripple effect on component. | ||
+ color?: ThemePalette | ||
+ Color of the tab group. | ||
+ backgroundColor?: ThemePalette | ||
+ Background color of the tab group. | ||
|
||
#### Events | ||
|
||
+ valueChange: function(value: any) | ||
+ Event that emits whenever the raw value of the select changes. | ||
+ This is here primarily to facilitate the two-way binding for the `value` input. | ||
|
||
# td-tab-option | ||
|
||
`td-tab-option` element generates a tab component to which a value can be binded to. | ||
|
||
## API Summary | ||
|
||
#### Inputs | ||
|
||
+ value?: any | ||
+ Bind a value to the component. | ||
+ disabled?: boolean | ||
+ Sets disabled state of the component. | ||
|
||
## Setup | ||
|
||
Import the [CovalentTabSelectModule] in your NgModule: | ||
|
||
```typescript | ||
import { CovalentTabSelectModule } from '@covalent/experimental/tab-select'; | ||
@NgModule({ | ||
imports: [ | ||
CovalentTabSelectModule, | ||
... | ||
], | ||
... | ||
}) | ||
export class MyModule {} | ||
``` | ||
|
||
## Usage | ||
|
||
Example without forms: | ||
|
||
```html | ||
<td-tab-select [(value)]="myValue"> | ||
<td-tab-option [value]="1">Label 1</td-tab-option> | ||
<td-tab-option [value]="2">Label 2</td-tab-option> | ||
<td-tab-option [value]="3">Label 3</td-tab-option> | ||
</td-tab-select> | ||
``` | ||
|
||
Example with forms: | ||
|
||
```html | ||
<td-tab-select [(ngModel)]="myValue"> | ||
<td-tab-option [value]="1">Label 1</td-tab-option> | ||
<td-tab-option [value]="2">Label 2</td-tab-option> | ||
<td-tab-option [value]="3">Label 3</td-tab-option> | ||
</td-tab-select> | ||
``` | ||
|
||
Example with all inputs/outputs: | ||
|
||
```html | ||
<td-tab-select [value]="myValue" | ||
[backgroundColor]="'primary'" | ||
[color]="'accent'" | ||
[disabled]="false" | ||
[disabledRipple]="false" | ||
(valueChange)="myValue = $event"> | ||
<td-tab-option [value]="1" [disabled]="false">Label 1</td-tab-option> | ||
<td-tab-option [value]="2">Label 2</td-tab-option> | ||
<td-tab-option [value]="3" [disabled]="true">Label 3</td-tab-option> | ||
</td-tab-select> | ||
``` |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
export * from './public-api'; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
{ | ||
"ngPackage": { | ||
"lib": { | ||
"entryFile": "index.ts" | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
export * from './tab-select.module'; | ||
export * from './tab-select.component'; | ||
export * from './tab-option.component'; |
3 changes: 3 additions & 0 deletions
3
src/platform/experimental/tab-select/tab-option.component.html
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
<ng-template> | ||
<ng-content></ng-content> | ||
</ng-template> |
Empty file.
54 changes: 54 additions & 0 deletions
54
src/platform/experimental/tab-select/tab-option.component.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,54 @@ | ||
import { | ||
Component, | ||
Input, | ||
ChangeDetectionStrategy, | ||
ChangeDetectorRef, | ||
ViewChild, | ||
TemplateRef, | ||
OnInit, | ||
ViewContainerRef, | ||
} from '@angular/core'; | ||
|
||
import { TemplatePortal } from '@angular/cdk/portal'; | ||
import { mixinDisabled, ICanDisable } from '@covalent/core/common'; | ||
|
||
export class TdTabOptionBase { | ||
constructor(public _viewContainerRef: ViewContainerRef, | ||
public _changeDetectorRef: ChangeDetectorRef) {} | ||
} | ||
|
||
/* tslint:disable-next-line */ | ||
export const _TdTabOptionMixinBase = mixinDisabled(TdTabOptionBase); | ||
|
||
@Component({ | ||
selector: 'td-tab-option', | ||
templateUrl: './tab-option.component.html', | ||
styleUrls: ['./tab-option.component.scss'], | ||
changeDetection: ChangeDetectionStrategy.OnPush, | ||
/* tslint:disable-next-line */ | ||
inputs: ['disabled'], | ||
}) | ||
export class TdTabOptionComponent extends _TdTabOptionMixinBase implements ICanDisable, OnInit { | ||
|
||
private _contentPortal: TemplatePortal<any>; | ||
get content(): TemplatePortal<any> { | ||
return this._contentPortal; | ||
} | ||
|
||
@ViewChild(TemplateRef) _content: TemplateRef<any>; | ||
|
||
/** | ||
* Value to which the option will be binded to. | ||
*/ | ||
@Input('value') value: any; | ||
|
||
constructor(_viewContainerRef: ViewContainerRef, | ||
_changeDetectorRef: ChangeDetectorRef) { | ||
super(_viewContainerRef, _changeDetectorRef); | ||
} | ||
|
||
ngOnInit(): void { | ||
this._contentPortal = new TemplatePortal(this._content, this._viewContainerRef); | ||
} | ||
|
||
} |
16 changes: 16 additions & 0 deletions
16
src/platform/experimental/tab-select/tab-select.component.html
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,16 @@ | ||
<mat-tab-group [backgroundColor]="backgroundColor" | ||
[color]="color" | ||
[disableRipple]="disableRipple" | ||
[selectedIndex]="selectedIndex" | ||
(selectedIndexChange)="selectedIndexChange($event)"> | ||
<ng-template let-tabOption | ||
ngFor | ||
[ngForOf]="tabOptions"> | ||
<mat-tab [disabled]="tabOption.disabled || disabled"> | ||
<ng-template matTabLabel> | ||
<ng-template [cdkPortalOutlet]="tabOption.content"> | ||
</ng-template> | ||
</ng-template> | ||
</mat-tab> | ||
</ng-template> | ||
</mat-tab-group> |
Empty file.
185 changes: 185 additions & 0 deletions
185
src/platform/experimental/tab-select/tab-select.component.spec.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,185 @@ | ||
import { | ||
TestBed, | ||
inject, | ||
async, | ||
ComponentFixture, | ||
} from '@angular/core/testing'; | ||
import { | ||
Component, | ||
DebugElement, | ||
} from '@angular/core'; | ||
import { | ||
FormsModule, | ||
} from '@angular/forms'; | ||
import { NoopAnimationsModule } from '@angular/platform-browser/animations'; | ||
import { By } from '@angular/platform-browser'; | ||
import { | ||
CovalentTabSelectModule, | ||
} from './public-api'; | ||
|
||
describe('Component: TabSelect', () => { | ||
|
||
beforeEach(async(() => { | ||
TestBed.configureTestingModule({ | ||
declarations: [ | ||
TdTabSelectBasicTestComponent, | ||
TdTabSelectFormsTestComponent, | ||
TdTabSelectDynamicTestComponent, | ||
], | ||
imports: [ | ||
NoopAnimationsModule, | ||
FormsModule, | ||
CovalentTabSelectModule, | ||
], | ||
}); | ||
TestBed.compileComponents(); | ||
})); | ||
|
||
it('should render tab select with all tabs disabled', | ||
async(inject([], () => { | ||
let fixture: ComponentFixture<any> = TestBed.createComponent(TdTabSelectBasicTestComponent); | ||
let component: TdTabSelectBasicTestComponent = fixture.debugElement.componentInstance; | ||
component.disabled = true; | ||
fixture.detectChanges(); | ||
fixture.whenStable().then(() => { | ||
expect(fixture.componentInstance.value).toBe(undefined); | ||
expect(fixture.debugElement.queryAll(By.css('.mat-tab-disabled')).length).toBe(3); | ||
}); | ||
}), | ||
)); | ||
|
||
it('should render tab select with all options and click on second option to activate it', | ||
async(inject([], () => { | ||
let fixture: ComponentFixture<any> = TestBed.createComponent(TdTabSelectBasicTestComponent); | ||
let component: TdTabSelectBasicTestComponent = fixture.debugElement.componentInstance; | ||
fixture.detectChanges(); | ||
fixture.whenStable().then(() => { | ||
expect(fixture.debugElement.queryAll(By.css('.mat-tab-label')).length).toBe(3); | ||
fixture.debugElement.queryAll(By.css('.mat-tab-label'))[1].nativeElement.click(); | ||
fixture.detectChanges(); | ||
fixture.whenStable().then(() => { | ||
expect(fixture.debugElement.queryAll(By.css('.mat-tab-label'))[1].nativeElement.className).toContain('mat-tab-label-active'); | ||
}); | ||
}); | ||
}), | ||
)); | ||
|
||
it('should render tab select with all options with the second option active', | ||
async(inject([], () => { | ||
let fixture: ComponentFixture<any> = TestBed.createComponent(TdTabSelectBasicTestComponent); | ||
let component: TdTabSelectBasicTestComponent = fixture.debugElement.componentInstance; | ||
fixture.detectChanges(); | ||
fixture.whenStable().then(() => { | ||
expect(fixture.componentInstance.value).toBe(undefined); | ||
expect(fixture.debugElement.queryAll(By.css('.mat-tab-label')).length).toBe(3); | ||
fixture.componentInstance.value = 2; | ||
fixture.detectChanges(); | ||
fixture.whenStable().then(() => { | ||
expect(fixture.debugElement.queryAll(By.css('.mat-tab-label'))[1].nativeElement.className).toContain('mat-tab-label-active'); | ||
}); | ||
}); | ||
}), | ||
)); | ||
|
||
it('should render tab select with first option active and then switch to 3rd option (value)', | ||
async(inject([], () => { | ||
let fixture: ComponentFixture<any> = TestBed.createComponent(TdTabSelectBasicTestComponent); | ||
let component: TdTabSelectBasicTestComponent = fixture.debugElement.componentInstance; | ||
fixture.detectChanges(); | ||
fixture.whenStable().then(() => { | ||
expect(fixture.componentInstance.value).toBe(undefined); | ||
expect(fixture.debugElement.queryAll(By.css('.mat-tab-label')).length).toBe(3); | ||
fixture.detectChanges(); | ||
fixture.whenStable().then(() => { | ||
expect(fixture.debugElement.queryAll(By.css('.mat-tab-label'))[0].nativeElement.className).toContain('mat-tab-label-active'); | ||
fixture.componentInstance.value = 3; | ||
fixture.detectChanges(); | ||
fixture.whenStable().then(() => { | ||
expect(fixture.debugElement.queryAll(By.css('.mat-tab-label'))[2].nativeElement.className).toContain('mat-tab-label-active'); | ||
}); | ||
}); | ||
}); | ||
}), | ||
)); | ||
|
||
it('should render tab select with first option active and then switch to 3rd option (ngModel)', | ||
async(inject([], () => { | ||
let fixture: ComponentFixture<any> = TestBed.createComponent(TdTabSelectFormsTestComponent); | ||
let component: TdTabSelectFormsTestComponent = fixture.debugElement.componentInstance; | ||
fixture.detectChanges(); | ||
fixture.whenStable().then(() => { | ||
expect(fixture.componentInstance.value).toBe(1); | ||
expect(fixture.debugElement.queryAll(By.css('.mat-tab-label')).length).toBe(3); | ||
fixture.detectChanges(); | ||
fixture.whenStable().then(() => { | ||
expect(fixture.debugElement.queryAll(By.css('.mat-tab-label'))[0].nativeElement.className).toContain('mat-tab-label-active'); | ||
fixture.componentInstance.value = 3; | ||
fixture.detectChanges(); | ||
fixture.whenStable().then(() => { | ||
fixture.detectChanges(); | ||
fixture.whenStable().then(() => { | ||
expect(fixture.debugElement.queryAll(By.css('.mat-tab-label'))[2].nativeElement.className).toContain('mat-tab-label-active'); | ||
}); | ||
}); | ||
}); | ||
}); | ||
}), | ||
)); | ||
|
||
it('should render dynamic tab options from an ngFor loop', | ||
async(inject([], () => { | ||
let fixture: ComponentFixture<any> = TestBed.createComponent(TdTabSelectDynamicTestComponent); | ||
fixture.detectChanges(); | ||
fixture.whenStable().then(() => { | ||
expect(fixture.componentInstance.value).toBe(undefined); | ||
expect(fixture.debugElement.queryAll(By.css('.mat-tab-label')).length).toBe(3); | ||
|
||
let tabNo: number = 1; | ||
fixture.debugElement.queryAll(By.css('.mat-tab-label .mat-tab-label-content')).forEach((element: DebugElement) => { | ||
expect((<HTMLElement>element.nativeElement).innerHTML).toContain('Option ' + tabNo++); | ||
}); | ||
}); | ||
}))); | ||
}); | ||
|
||
@Component({ | ||
selector: 'td-tab-select-basic-test', | ||
template: ` | ||
<td-tab-select [(value)]="value" [disabled]="disabled"> | ||
<td-tab-option [value]="1">Option 1</td-tab-option> | ||
<td-tab-option [value]="2">Option 2</td-tab-option> | ||
<td-tab-option [value]="3">Option 3</td-tab-option> | ||
</td-tab-select> | ||
`, | ||
}) | ||
class TdTabSelectBasicTestComponent { | ||
disabled: boolean = false; | ||
value: any; | ||
} | ||
|
||
@Component({ | ||
selector: 'td-tab-forms-basic-test', | ||
template: ` | ||
<td-tab-select [(ngModel)]="value"> | ||
<td-tab-option [value]="1">Option 1</td-tab-option> | ||
<td-tab-option [value]="2">Option 2</td-tab-option> | ||
<td-tab-option [value]="3">Option 3</td-tab-option> | ||
</td-tab-select> | ||
`, | ||
}) | ||
class TdTabSelectFormsTestComponent { | ||
value: any; | ||
} | ||
|
||
@Component({ | ||
selector: 'td-tab-select-dynamic-test', | ||
template: ` | ||
<td-tab-select [(value)]="value"> | ||
<td-tab-option *ngFor="let option of options" [value]="option.value">{{option.label}}</td-tab-option> | ||
</td-tab-select> | ||
`, | ||
}) | ||
class TdTabSelectDynamicTestComponent { | ||
options: any[] = [{label: 'Option 1', value: 1}, {label: 'Option 2', value: 2}, {label: 'Option 3', value: 3}]; | ||
value: any; | ||
} |
Oops, something went wrong.