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

ListOptionGroup integration to Angular/Blazor #2161

Merged
merged 8 commits into from
Jun 6, 2024
Merged
Show file tree
Hide file tree
Changes from all 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
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
{
"type": "minor",
"comment": "Angular integration for ListOptionGroup",
"packageName": "@ni/nimble-angular",
"email": "26874831+atmgrifter00@users.noreply.github.com",
"dependentChangeType": "patch"
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
{
"type": "minor",
"comment": "Blazor integration for ListOptionGroup",
"packageName": "@ni/nimble-blazor",
"email": "26874831+atmgrifter00@users.noreply.github.com",
"dependentChangeType": "patch"
}
1 change: 1 addition & 0 deletions packages/angular-workspace/.eslintrc.js
Original file line number Diff line number Diff line change
Expand Up @@ -121,6 +121,7 @@ module.exports = {
'action-menu-label',
'aria-label',
'button-label',
'label',
'placeholder',
'text',
'title'
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,8 @@ import { NimbleTextAreaModule, NimbleTextFieldModule, NimbleNumberFieldModule, N
NimbleIconAddModule, NimbleSwitchModule, NimbleToolbarModule, NimbleMenuButtonModule, NimbleComboboxModule, NimbleTooltipModule,
NimbleCardButtonModule, NimbleDialogModule, NimbleRadioGroupModule, NimbleRadioModule, NimbleSpinnerModule,
NimbleAnchorModule, NimbleAnchorButtonModule, NimbleAnchorTabModule, NimbleAnchorTabsModule,
NimbleIconCheckModule, NimbleBannerModule, NimbleAnchorMenuItemModule, NimbleAnchorTreeItemModule, NimbleIconXmarkCheckModule } from '@ni/nimble-angular';
NimbleIconCheckModule, NimbleBannerModule, NimbleAnchorMenuItemModule, NimbleAnchorTreeItemModule, NimbleIconXmarkCheckModule,
NimbleListOptionGroupModule } from '@ni/nimble-angular';
import { NimbleCardModule } from '@ni/nimble-angular/card';
import { NimbleLabelProviderCoreModule } from '@ni/nimble-angular/label-provider/core';
import { NimbleLabelProviderRichTextModule } from '@ni/nimble-angular/label-provider/rich-text';
Expand Down Expand Up @@ -53,6 +54,7 @@ import { HeaderComponent } from './header/header.component';
NimbleNumberFieldModule,
NimbleSelectModule,
NimbleListOptionModule,
NimbleListOptionGroupModule,
NimbleButtonModule,
NimbleTreeViewModule,
NimbleTreeItemModule,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -152,21 +152,36 @@
<div class="container-label">Select</div>
<nimble-select filter-mode="standard" appearance="underline">
<nimble-list-option hidden selected disabled>Select an option</nimble-list-option>
<nimble-list-option>Option 1</nimble-list-option>
<nimble-list-option>Option 2</nimble-list-option>
<nimble-list-option>Option 3</nimble-list-option>
<nimble-list-option-group label="Group 1">
<nimble-list-option>Option 1</nimble-list-option>
<nimble-list-option>Option 2</nimble-list-option>
</nimble-list-option-group>
<nimble-list-option-group label="Group 2">
<nimble-list-option>Option 3</nimble-list-option>
<nimble-list-option>Option 4</nimble-list-option>
</nimble-list-option-group>
</nimble-select>
<nimble-select appearance="outline">
<nimble-list-option hidden selected disabled>Select an option</nimble-list-option>
<nimble-list-option>Option 1</nimble-list-option>
<nimble-list-option>Option 2</nimble-list-option>
<nimble-list-option>Option 3</nimble-list-option>
<nimble-list-option-group label="Group 1">
<nimble-list-option>Option 1</nimble-list-option>
<nimble-list-option>Option 2</nimble-list-option>
</nimble-list-option-group>
<nimble-list-option-group label="Group 2">
<nimble-list-option>Option 3</nimble-list-option>
<nimble-list-option>Option 4</nimble-list-option>
</nimble-list-option-group>
</nimble-select>
<nimble-select appearance="block">
<nimble-list-option hidden selected disabled>Select an option</nimble-list-option>
<nimble-list-option>Option 1</nimble-list-option>
<nimble-list-option>Option 2</nimble-list-option>
<nimble-list-option>Option 3</nimble-list-option>
<nimble-list-option-group label="Group 1">
<nimble-list-option>Option 1</nimble-list-option>
<nimble-list-option>Option 2</nimble-list-option>
</nimble-list-option-group>
<nimble-list-option-group label="Group 2">
<nimble-list-option>Option 3</nimble-list-option>
<nimble-list-option>Option 4</nimble-list-option>
</nimble-list-option-group>
</nimble-select>
</div>
<div class="sub-container">
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
import { Directive, Input, ElementRef, Renderer2 } from '@angular/core';
import { type BooleanValueOrAttribute, toBooleanProperty } from '@ni/nimble-angular/internal-utilities';
import type { ListOptionGroup, listOptionGroupTag } from '@ni/nimble-components/dist/esm/list-option-group';

export type { ListOptionGroup };
export { listOptionGroupTag };

/**
* Directive to provide Angular integration for the list option group.
*/
@Directive({
selector: 'nimble-list-option-group'
})
export class NimbleListOptionGroupDirective {
public get label(): string | undefined {
return this.elementRef.nativeElement.label;
}

@Input() public set label(value: string | undefined) {
this.renderer.setProperty(this.elementRef.nativeElement, 'label', value);
}

public get hidden(): boolean {
return this.elementRef.nativeElement.hidden;
}

@Input() public set hidden(value: BooleanValueOrAttribute) {
this.renderer.setProperty(this.elementRef.nativeElement, 'hidden', toBooleanProperty(value));
}

public constructor(
private readonly elementRef: ElementRef<ListOptionGroup>,
private readonly renderer: Renderer2,
) { }
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
import { NgModule } from '@angular/core';
import { CommonModule } from '@angular/common';
import { NimbleListOptionGroupDirective } from './nimble-list-option-group.directive';

import '@ni/nimble-components/dist/esm/list-option';

@NgModule({
declarations: [
NimbleListOptionGroupDirective
],
imports: [CommonModule],
exports: [
NimbleListOptionGroupDirective
]
})
export class NimbleListOptionGroupModule { }
Original file line number Diff line number Diff line change
@@ -0,0 +1,207 @@
import { ComponentFixture, TestBed } from '@angular/core/testing';
import { Component, ElementRef, ViewChild } from '@angular/core';
import type { BooleanValueOrAttribute } from '@ni/nimble-angular/internal-utilities';
import { NimbleListOptionGroupModule } from '../nimble-list-option-group.module';
import type { ListOptionGroup } from '../../../public-api';
import { NimbleListOptionGroupDirective } from '../nimble-list-option-group.directive';

describe('Nimble listbox option group', () => {
describe('module', () => {
beforeEach(() => {
TestBed.configureTestingModule({
imports: [NimbleListOptionGroupModule]
});
});

it('custom element is defined', () => {
expect(customElements.get('nimble-list-option-group')).not.toBeUndefined();
});
});

describe('with no values in template', () => {
@Component({
template: `
<nimble-list-option-group #listOptionGroup></nimble-list-option-group>
`
})
class TestHostComponent {
@ViewChild('listOptionGroup', { read: NimbleListOptionGroupDirective }) public directive: NimbleListOptionGroupDirective;
@ViewChild('listOptionGroup', { read: ElementRef }) public elementRef: ElementRef<ListOptionGroup>;
}

let fixture: ComponentFixture<TestHostComponent>;
let directive: NimbleListOptionGroupDirective;
let nativeElement: ListOptionGroup;

beforeEach(() => {
TestBed.configureTestingModule({
declarations: [TestHostComponent],
imports: [NimbleListOptionGroupModule]
});
fixture = TestBed.createComponent(TestHostComponent);
fixture.detectChanges();
directive = fixture.componentInstance.directive;
nativeElement = fixture.componentInstance.elementRef.nativeElement;
});

it('has expected defaults for label', () => {
expect(directive.label).toBeUndefined();
expect(nativeElement.label).toBeUndefined();
});

it('has expected defaults for hidden', () => {
expect(directive.hidden).toBeFalse();
expect(nativeElement.hidden).toBeFalse();
});
});

describe('with template string values', () => {
@Component({
template: `
<nimble-list-option-group #listOptionGroup
hidden
label="foo"
></nimble-list-option-group>
`
})
class TestHostComponent {
@ViewChild('listOptionGroup', { read: NimbleListOptionGroupDirective }) public directive: NimbleListOptionGroupDirective;
@ViewChild('listOptionGroup', { read: ElementRef }) public elementRef: ElementRef<ListOptionGroup>;
}

let fixture: ComponentFixture<TestHostComponent>;
let directive: NimbleListOptionGroupDirective;
let nativeElement: ListOptionGroup;

beforeEach(() => {
TestBed.configureTestingModule({
declarations: [TestHostComponent],
imports: [NimbleListOptionGroupModule]
});
fixture = TestBed.createComponent(TestHostComponent);
fixture.detectChanges();
directive = fixture.componentInstance.directive;
nativeElement = fixture.componentInstance.elementRef.nativeElement;
});

it('will use template string values for label', () => {
expect(directive.label).toBe('foo');
expect(nativeElement.label).toBe('foo');
});

it('will use template string values for hidden', () => {
expect(directive.hidden).toBeTrue();
expect(nativeElement.hidden).toBeTrue();
});
});

describe('with property bound values', () => {
@Component({
template: `
<nimble-list-option-group #listOptionGroup
[label]="label"
[hidden]="hidden"
></nimble-list-option-group>
`
})
class TestHostComponent {
@ViewChild('listOptionGroup', { read: NimbleListOptionGroupDirective }) public directive: NimbleListOptionGroupDirective;
@ViewChild('listOptionGroup', { read: ElementRef }) public elementRef: ElementRef<ListOptionGroup>;

public label = '';
public hidden = false;
}

let fixture: ComponentFixture<TestHostComponent>;
let directive: NimbleListOptionGroupDirective;
let nativeElement: ListOptionGroup;

beforeEach(() => {
TestBed.configureTestingModule({
declarations: [TestHostComponent],
imports: [NimbleListOptionGroupModule]
});
fixture = TestBed.createComponent(TestHostComponent);
fixture.detectChanges();
directive = fixture.componentInstance.directive;
nativeElement = fixture.componentInstance.elementRef.nativeElement;
});

it('can be configured with property binding for label', () => {
expect(directive.label).toBe('');
expect(nativeElement.label).toBe('');

fixture.componentInstance.label = 'foo';
fixture.detectChanges();

expect(directive.label).toBe('foo');
expect(nativeElement.label).toBe('foo');
});

it('can be configured with property binding for hidden', () => {
expect(directive.hidden).toBeFalse();
expect(nativeElement.hidden).toBeFalse();

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

expect(directive.hidden).toBeTrue();
expect(nativeElement.hidden).toBeTrue();
});
});

describe('with property attribute values', () => {
@Component({
template: `
<nimble-list-option-group #listOptionGroup
[attr.label]="label"
[attr.hidden]="hidden">
</nimble-list-option-group>
`
})
class TestHostComponent {
@ViewChild('listOptionGroup', { read: NimbleListOptionGroupDirective }) public directive: NimbleListOptionGroupDirective;
@ViewChild('listOptionGroup', { read: ElementRef }) public elementRef: ElementRef<ListOptionGroup>;

public label = 'foo';
public hidden: BooleanValueOrAttribute = null;
}

let fixture: ComponentFixture<TestHostComponent>;
let directive: NimbleListOptionGroupDirective;
let nativeElement: ListOptionGroup;

beforeEach(() => {
TestBed.configureTestingModule({
declarations: [TestHostComponent],
imports: [NimbleListOptionGroupModule]
});
fixture = TestBed.createComponent(TestHostComponent);
fixture.detectChanges();
directive = fixture.componentInstance.directive;
nativeElement = fixture.componentInstance.elementRef.nativeElement;
});

it('can be configured with attribute binding for label', () => {
expect(directive.label).toBe('foo');
expect(nativeElement.label).toBe('foo');

fixture.componentInstance.label = 'bar';
fixture.detectChanges();

expect(directive.label).toBe('bar');
expect(nativeElement.label).toBe('bar');
});

it('can be configured with attribute binding for hidden', () => {
expect(directive.hidden).toBeFalse();
expect(nativeElement.hidden).toBeFalse();

fixture.componentInstance.hidden = '';
fixture.detectChanges();

expect(directive.hidden).toBeTrue();
expect(nativeElement.hidden).toBeTrue();
});
});
});
2 changes: 2 additions & 0 deletions packages/angular-workspace/nimble-angular/src/public-api.ts
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,8 @@ export * from './directives/list-option/nimble-combobox-list-option.directive';
export * from './directives/list-option/nimble-list-option.directive';
export * from './directives/list-option/nimble-select-list-option.directive';
export * from './directives/list-option/nimble-list-option.module';
export * from './directives/list-option-group/nimble-list-option-group.directive';
export * from './directives/list-option-group/nimble-list-option-group.module';
export * from './directives/menu/nimble-menu.directive';
export * from './directives/menu/nimble-menu.module';
export * from './directives/menu-button/nimble-menu-button.directive';
Expand Down
Loading
Loading