diff --git a/angular-workspace/projects/example-client-app/src/app/app.module.ts b/angular-workspace/projects/example-client-app/src/app/app.module.ts index ef8ca76b4d..d823596896 100644 --- a/angular-workspace/projects/example-client-app/src/app/app.module.ts +++ b/angular-workspace/projects/example-client-app/src/app/app.module.ts @@ -10,14 +10,12 @@ import { NimbleTextAreaModule, NimbleTextFieldModule, NimbleNumberFieldModule, N NimbleCardButtonModule, NimbleDialogModule, NimbleRadioGroupModule, NimbleRadioButtonModule } from '@ni/nimble-angular'; import { AppComponent } from './app.component'; import { CustomAppComponent } from './customapp/customapp.component'; -import { LoginComponent } from './login/login.component'; import { HeaderComponent } from './header/header.component'; import { NavDrawerComponent } from './nav-drawer/nav-drawer.component'; @NgModule({ declarations: [ AppComponent, - LoginComponent, HeaderComponent, NavDrawerComponent, CustomAppComponent @@ -57,8 +55,7 @@ import { NavDrawerComponent } from './nav-drawer/nav-drawer.component'; NimbleRadioGroupModule, NimbleRadioButtonModule, RouterModule.forRoot([ - { path: '', redirectTo: '/login', pathMatch: 'full' }, - { path: 'login', component: LoginComponent }, + { path: '', redirectTo: '/customapp', pathMatch: 'full' }, { path: 'customapp', component: CustomAppComponent } ], { useHash: true }) diff --git a/angular-workspace/projects/example-client-app/src/app/customapp/customapp.component.html b/angular-workspace/projects/example-client-app/src/app/customapp/customapp.component.html index 47b958b336..f6e0b1f8f2 100644 --- a/angular-workspace/projects/example-client-app/src/app/customapp/customapp.component.html +++ b/angular-workspace/projects/example-client-app/src/app/customapp/customapp.component.html @@ -193,13 +193,13 @@

This is a dialog

Default Tooltip label Fail - Tooltip label + Tooltip label Information - Tooltip label + Tooltip label Fail Icon - Tooltip label + Tooltip label Information Icon - Tooltip label + Tooltip label
Tree View
diff --git a/angular-workspace/projects/example-client-app/src/app/header/header.component.html b/angular-workspace/projects/example-client-app/src/app/header/header.component.html index f95eda59fe..92dc954dc3 100644 --- a/angular-workspace/projects/example-client-app/src/app/header/header.component.html +++ b/angular-workspace/projects/example-client-app/src/app/header/header.component.html @@ -13,7 +13,6 @@

User settings

Menu User Settings - Logout
diff --git a/angular-workspace/projects/example-client-app/src/app/header/header.component.ts b/angular-workspace/projects/example-client-app/src/app/header/header.component.ts index 24c4623c6e..38aa1f55c9 100644 --- a/angular-workspace/projects/example-client-app/src/app/header/header.component.ts +++ b/angular-workspace/projects/example-client-app/src/app/header/header.component.ts @@ -36,11 +36,6 @@ export class HeaderComponent { this.userSettingsDrawer.hide(); } - public onLogoutSelected(): void { - this.toggleMenuHidden(); - void this.router.navigate(['/login']); - } - private toggleMenuHidden(): void { this.hideMenu = !this.hideMenu; } diff --git a/angular-workspace/projects/example-client-app/src/app/login/login.component.html b/angular-workspace/projects/example-client-app/src/app/login/login.component.html deleted file mode 100644 index cdca4f757a..0000000000 --- a/angular-workspace/projects/example-client-app/src/app/login/login.component.html +++ /dev/null @@ -1,24 +0,0 @@ -
-
- - Username - - - Password - - - Login - -
-
diff --git a/angular-workspace/projects/example-client-app/src/app/login/login.component.scss b/angular-workspace/projects/example-client-app/src/app/login/login.component.scss deleted file mode 100644 index 6c9ee0a34f..0000000000 --- a/angular-workspace/projects/example-client-app/src/app/login/login.component.scss +++ /dev/null @@ -1,25 +0,0 @@ -@import '~@ni/nimble-angular/styles/tokens'; - -:host { - background-color: $ni-nimble-application-background-color; - display: flex; - flex: auto; - justify-content: center; - align-items: center; - height: 100%; -} - -.login-container { - display: flex; - flex-direction: column; -} - -nimble-button { - margin-bottom: 12px; - width: fit-content; -} - -nimble-text-field { - width: 150px; - margin-bottom: 12px; -} diff --git a/angular-workspace/projects/example-client-app/src/app/login/login.component.ts b/angular-workspace/projects/example-client-app/src/app/login/login.component.ts deleted file mode 100644 index f006b2cd3b..0000000000 --- a/angular-workspace/projects/example-client-app/src/app/login/login.component.ts +++ /dev/null @@ -1,22 +0,0 @@ -import { Component, Inject } from '@angular/core'; -import { FormBuilder, FormGroup, Validators } from '@angular/forms'; -import { Router } from '@angular/router'; - -@Component({ - selector: 'example-login', - templateUrl: './login.component.html', - styleUrls: ['./login.component.scss'] -}) -export class LoginComponent { - public loginForm: FormGroup; - public constructor(private readonly formBuilder: FormBuilder, @Inject(Router) private readonly router: Router) { - this.loginForm = this.formBuilder.group({ - username: ['someuser', Validators.required], - password: ['password', Validators.required] - }); - } - - public onSubmit(): void { - void this.router.navigate(['/customapp']); - } -} diff --git a/angular-workspace/projects/ni/nimble-angular/build/generate-icons/source/index.js b/angular-workspace/projects/ni/nimble-angular/build/generate-icons/source/index.js index 174925b48d..67c3eb83dc 100644 --- a/angular-workspace/projects/ni/nimble-angular/build/generate-icons/source/index.js +++ b/angular-workspace/projects/ni/nimble-angular/build/generate-icons/source/index.js @@ -52,6 +52,7 @@ for (const key of Object.keys(icons)) { const directiveFileContents = `${generatedFilePrefix} import { Directive } from '@angular/core'; import type { ${className} } from '@ni/nimble-components/dist/esm/icons/${directoryName}'; +import { NimbleIconBaseDirective } from '../../icon-base/nimble-icon-base.directive'; export type { ${className} }; @@ -61,7 +62,7 @@ export type { ${className} }; @Directive({ selector: '${elementName}' }) -export class ${directiveName} { +export class ${directiveName} extends NimbleIconBaseDirective { } `; const directiveFileName = `${elementName}.directive`; diff --git a/angular-workspace/projects/ni/nimble-angular/src/directives/breadcrumb/nimble-breadcrumb.directive.ts b/angular-workspace/projects/ni/nimble-angular/src/directives/breadcrumb/nimble-breadcrumb.directive.ts index 8110f8b8f7..c51d339daa 100644 --- a/angular-workspace/projects/ni/nimble-angular/src/directives/breadcrumb/nimble-breadcrumb.directive.ts +++ b/angular-workspace/projects/ni/nimble-angular/src/directives/breadcrumb/nimble-breadcrumb.directive.ts @@ -1,7 +1,9 @@ -import { Directive } from '@angular/core'; +import { Directive, ElementRef, Input, Renderer2 } from '@angular/core'; import type { Breadcrumb } from '@ni/nimble-components/dist/esm/breadcrumb'; +import { BreadcrumbAppearance } from '@ni/nimble-components/dist/esm/breadcrumb/types'; export type { Breadcrumb }; +export { BreadcrumbAppearance }; /** * Directive to provide Angular integration for the breadcrumb. @@ -10,4 +12,13 @@ export type { Breadcrumb }; selector: 'nimble-breadcrumb' }) export class NimbleBreadcrumbDirective { + public get appearance(): BreadcrumbAppearance { + return this.elementRef.nativeElement.appearance; + } + + @Input() public set appearance(value: BreadcrumbAppearance) { + this.renderer.setProperty(this.elementRef.nativeElement, 'appearance', value); + } + + public constructor(private readonly renderer: Renderer2, private readonly elementRef: ElementRef) {} } diff --git a/angular-workspace/projects/ni/nimble-angular/src/directives/breadcrumb/tests/nimble-breadcrumb.directive.spec.ts b/angular-workspace/projects/ni/nimble-angular/src/directives/breadcrumb/tests/nimble-breadcrumb.directive.spec.ts new file mode 100644 index 0000000000..8ad317e987 --- /dev/null +++ b/angular-workspace/projects/ni/nimble-angular/src/directives/breadcrumb/tests/nimble-breadcrumb.directive.spec.ts @@ -0,0 +1,166 @@ +import { Component, ElementRef, ViewChild } from '@angular/core'; +import { ComponentFixture, TestBed } from '@angular/core/testing'; +import { Breadcrumb, BreadcrumbAppearance, NimbleBreadcrumbDirective } from '../nimble-breadcrumb.directive'; +import { NimbleBreadcrumbModule } from '../nimble-breadcrumb.module'; + +describe('Nimble breadcrumb', () => { + beforeEach(() => { + TestBed.configureTestingModule({ + imports: [NimbleBreadcrumbModule] + }); + }); + + it('custom element is defined', () => { + expect(customElements.get('nimble-breadcrumb')).not.toBeUndefined(); + }); + + describe('with no values in template', () => { + @Component({ + template: ` + + ` + }) + class TestHostComponent { + @ViewChild('target', { read: NimbleBreadcrumbDirective }) public directive: NimbleBreadcrumbDirective; + @ViewChild('target', { read: ElementRef }) public elementRef: ElementRef; + } + + let fixture: ComponentFixture; + let directive: NimbleBreadcrumbDirective; + let nativeElement: Breadcrumb; + + beforeEach(() => { + TestBed.configureTestingModule({ + declarations: [TestHostComponent], + imports: [NimbleBreadcrumbModule] + }); + fixture = TestBed.createComponent(TestHostComponent); + fixture.detectChanges(); + directive = fixture.componentInstance.directive; + nativeElement = fixture.componentInstance.elementRef.nativeElement; + }); + + it('has expected defaults for appearance', () => { + expect(directive.appearance).toBe(BreadcrumbAppearance.default); + expect(nativeElement.appearance).toBe(BreadcrumbAppearance.default); + }); + }); + + describe('with template string values', () => { + @Component({ + template: ` + + ` + }) + class TestHostComponent { + @ViewChild('target', { read: NimbleBreadcrumbDirective }) public directive: NimbleBreadcrumbDirective; + @ViewChild('target', { read: ElementRef }) public elementRef: ElementRef; + } + + let fixture: ComponentFixture; + let directive: NimbleBreadcrumbDirective; + let nativeElement: Breadcrumb; + + beforeEach(() => { + TestBed.configureTestingModule({ + declarations: [TestHostComponent], + imports: [NimbleBreadcrumbModule] + }); + fixture = TestBed.createComponent(TestHostComponent); + fixture.detectChanges(); + directive = fixture.componentInstance.directive; + nativeElement = fixture.componentInstance.elementRef.nativeElement; + }); + + it('will use template string values for appearance', () => { + expect(directive.appearance).toBe(BreadcrumbAppearance.prominent); + expect(nativeElement.appearance).toBe(BreadcrumbAppearance.prominent); + }); + }); + + describe('with property bound values', () => { + @Component({ + template: ` + + + ` + }) + class TestHostComponent { + @ViewChild('target', { read: NimbleBreadcrumbDirective }) public directive: NimbleBreadcrumbDirective; + @ViewChild('target', { read: ElementRef }) public elementRef: ElementRef; + public appearance: BreadcrumbAppearance; + } + + let fixture: ComponentFixture; + let directive: NimbleBreadcrumbDirective; + let nativeElement: Breadcrumb; + + beforeEach(() => { + TestBed.configureTestingModule({ + declarations: [TestHostComponent], + imports: [NimbleBreadcrumbModule] + }); + fixture = TestBed.createComponent(TestHostComponent); + fixture.detectChanges(); + directive = fixture.componentInstance.directive; + nativeElement = fixture.componentInstance.elementRef.nativeElement; + }); + + it('can be configured with property binding for appearance', () => { + expect(directive.appearance).toBe(BreadcrumbAppearance.default); + expect(nativeElement.appearance).toBe(BreadcrumbAppearance.default); + + fixture.componentInstance.appearance = BreadcrumbAppearance.prominent; + fixture.detectChanges(); + + expect(directive.appearance).toBe(BreadcrumbAppearance.prominent); + expect(nativeElement.appearance).toBe(BreadcrumbAppearance.prominent); + }); + }); + + describe('with attribute bound values', () => { + @Component({ + template: ` + + + ` + }) + class TestHostComponent { + @ViewChild('target', { read: NimbleBreadcrumbDirective }) public directive: NimbleBreadcrumbDirective; + @ViewChild('target', { read: ElementRef }) public elementRef: ElementRef; + public appearance: BreadcrumbAppearance; + } + + let fixture: ComponentFixture; + let directive: NimbleBreadcrumbDirective; + let nativeElement: Breadcrumb; + + beforeEach(() => { + TestBed.configureTestingModule({ + declarations: [TestHostComponent], + imports: [NimbleBreadcrumbModule] + }); + fixture = TestBed.createComponent(TestHostComponent); + fixture.detectChanges(); + directive = fixture.componentInstance.directive; + nativeElement = fixture.componentInstance.elementRef.nativeElement; + }); + + it('can be configured with attribute binding for appearance', () => { + expect(directive.appearance).toBe(BreadcrumbAppearance.default); + expect(nativeElement.appearance).toBe(BreadcrumbAppearance.default); + + fixture.componentInstance.appearance = BreadcrumbAppearance.prominent; + fixture.detectChanges(); + + expect(directive.appearance).toBe(BreadcrumbAppearance.prominent); + expect(nativeElement.appearance).toBe(BreadcrumbAppearance.prominent); + }); + }); +}); diff --git a/angular-workspace/projects/ni/nimble-angular/src/directives/button/nimble-button.directive.ts b/angular-workspace/projects/ni/nimble-angular/src/directives/button/nimble-button.directive.ts index 6c30121b0c..9af2197ef0 100644 --- a/angular-workspace/projects/ni/nimble-angular/src/directives/button/nimble-button.directive.ts +++ b/angular-workspace/projects/ni/nimble-angular/src/directives/button/nimble-button.directive.ts @@ -1,9 +1,11 @@ import { Directive, ElementRef, Input, Renderer2 } from '@angular/core'; import type { Button } from '@ni/nimble-components/dist/esm/button'; -import type { ButtonAppearance, ButtonType } from '@ni/nimble-components/dist/esm/button/types'; +import type { ButtonAppearance } from '@ni/nimble-components/dist/esm/button/types'; +import { ButtonType, ButtonAppearanceVariant } from '@ni/nimble-components/dist/esm/button/types'; import { BooleanValueOrAttribute, toBooleanProperty } from '../utilities/template-value-helpers'; -export type { Button, ButtonType }; +export type { Button }; +export { ButtonType, ButtonAppearanceVariant }; /** * Directive to provide Angular integration for the button. @@ -20,6 +22,16 @@ export class NimbleButtonDirective { this.renderer.setProperty(this.elementRef.nativeElement, 'appearance', value); } + public get appearanceVariant(): ButtonAppearanceVariant { + return this.elementRef.nativeElement.appearanceVariant; + } + + // Renaming because property should have camel casing, but attribute should not + // eslint-disable-next-line @angular-eslint/no-input-rename + @Input('appearance-variant') public set appearanceVariant(value: ButtonAppearanceVariant) { + this.renderer.setProperty(this.elementRef.nativeElement, 'appearanceVariant', value); + } + public get disabled(): boolean { return this.elementRef.nativeElement.disabled; } @@ -40,7 +52,7 @@ export class NimbleButtonDirective { return this.elementRef.nativeElement.contentHidden; } - // contentHidden property intentionally maps to the content-hidden attribute + // Renaming because property should have camel casing, but attribute should not // eslint-disable-next-line @angular-eslint/no-input-rename @Input('content-hidden') public set contentHidden(value: BooleanValueOrAttribute) { this.renderer.setProperty(this.elementRef.nativeElement, 'contentHidden', toBooleanProperty(value)); diff --git a/angular-workspace/projects/ni/nimble-angular/src/directives/button/tests/nimble-button.directive.spec.ts b/angular-workspace/projects/ni/nimble-angular/src/directives/button/tests/nimble-button.directive.spec.ts index b3490b0651..b9fb4bd51e 100644 --- a/angular-workspace/projects/ni/nimble-angular/src/directives/button/tests/nimble-button.directive.spec.ts +++ b/angular-workspace/projects/ni/nimble-angular/src/directives/button/tests/nimble-button.directive.spec.ts @@ -2,7 +2,7 @@ import { Component, ElementRef, ViewChild } from '@angular/core'; import { ComponentFixture, TestBed } from '@angular/core/testing'; import { ButtonAppearance } from '../../../public-api'; import type { BooleanValueOrAttribute } from '../../utilities/template-value-helpers'; -import { Button, NimbleButtonDirective } from '../nimble-button.directive'; +import { Button, NimbleButtonDirective, ButtonAppearanceVariant } from '../nimble-button.directive'; import { NimbleButtonModule } from '../nimble-button.module'; describe('Nimble button', () => { @@ -54,6 +54,11 @@ describe('Nimble button', () => { expect(nativeElement.appearance).toBe(ButtonAppearance.outline); }); + it('has expected defaults for appearanceVariant', () => { + expect(directive.appearanceVariant).toBe(ButtonAppearanceVariant.default); + expect(nativeElement.appearanceVariant).toBe(ButtonAppearanceVariant.default); + }); + it('has expected defaults for contentHidden', () => { expect(directive.contentHidden).toBeFalse(); expect(nativeElement.contentHidden).toBeFalse(); @@ -65,7 +70,8 @@ describe('Nimble button', () => { template: ` ` }) @@ -99,6 +105,11 @@ describe('Nimble button', () => { expect(nativeElement.appearance).toBe(ButtonAppearance.ghost); }); + it('will use template string values for appearanceVariant', () => { + expect(directive.appearanceVariant).toBe(ButtonAppearanceVariant.primary); + expect(nativeElement.appearanceVariant).toBe(ButtonAppearanceVariant.primary); + }); + it('will use template string values for contentHidden', () => { expect(directive.contentHidden).toBeTrue(); expect(nativeElement.contentHidden).toBeTrue(); @@ -111,6 +122,7 @@ describe('Nimble button', () => { ` @@ -120,6 +132,7 @@ describe('Nimble button', () => { @ViewChild('button', { read: ElementRef }) public elementRef: ElementRef