From 52783423015bc7b1cfd3718646923d36b1f9d32c Mon Sep 17 00:00:00 2001 From: m-akinc <7282195+m-akinc@users.noreply.github.com> Date: Wed, 13 Mar 2024 17:07:03 -0500 Subject: [PATCH 01/12] Fix missing element names in some Storybook docs (#1931) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## ๐Ÿคจ Rationale Some tag names in a few component docs were blank, because the wrong attribute was being set. ## ๐Ÿ‘ฉโ€๐Ÿ’ป Implementation Should be `` rather than ``. ## ๐Ÿงช Testing Storybook ## โœ… Checklist - [x] I have updated the project documentation to reflect my changes or determined no changes are needed. --------- Co-authored-by: Milan Raj --- ...le-components-e257f396-a221-4970-b66a-51678c50bb25.json | 7 +++++++ .../src/anchor-tabs/tests/anchor-tabs.mdx | 2 +- packages/nimble-components/src/card/tests/card.mdx | 4 ++-- packages/nimble-components/src/combobox/tests/combobox.mdx | 4 ++-- 4 files changed, 12 insertions(+), 5 deletions(-) create mode 100644 change/@ni-nimble-components-e257f396-a221-4970-b66a-51678c50bb25.json diff --git a/change/@ni-nimble-components-e257f396-a221-4970-b66a-51678c50bb25.json b/change/@ni-nimble-components-e257f396-a221-4970-b66a-51678c50bb25.json new file mode 100644 index 0000000000..e4fe0bf701 --- /dev/null +++ b/change/@ni-nimble-components-e257f396-a221-4970-b66a-51678c50bb25.json @@ -0,0 +1,7 @@ +{ + "type": "none", + "comment": "Fix missing element names in some Storybook docs", + "packageName": "@ni/nimble-components", + "email": "7282195+m-akinc@users.noreply.github.com", + "dependentChangeType": "none" +} diff --git a/packages/nimble-components/src/anchor-tabs/tests/anchor-tabs.mdx b/packages/nimble-components/src/anchor-tabs/tests/anchor-tabs.mdx index f176c47ade..89ff9ce3c8 100644 --- a/packages/nimble-components/src/anchor-tabs/tests/anchor-tabs.mdx +++ b/packages/nimble-components/src/anchor-tabs/tests/anchor-tabs.mdx @@ -29,7 +29,7 @@ tab panels hosted on the same page. ## Angular Usage In an Angular application, it is common to integrate with the router by setting `nimbleRouterLink` (rather than `href`) -on each element. In those cases, it is recommended to also set `replaceUrl="true"` so that switching +on each element. In those cases, it is recommended to also set `replaceUrl="true"` so that switching between tabs does not add to the browser history. {/* ## Accessibility */} diff --git a/packages/nimble-components/src/card/tests/card.mdx b/packages/nimble-components/src/card/tests/card.mdx index 4113b8eb7d..a5c8085597 100644 --- a/packages/nimble-components/src/card/tests/card.mdx +++ b/packages/nimble-components/src/card/tests/card.mdx @@ -6,8 +6,8 @@ import * as cardStories from './card.stories'; -The <Tag of={cardTag} /> is a container that is designed to contain arbitrary content that is specified by a client -application. The <Tag of={cardTag} /> is intended for grouping related content. +The <Tag name={cardTag} /> is a container that is designed to contain arbitrary content that is specified by a client +application. The <Tag name={cardTag} /> is intended for grouping related content. <Canvas of={cardStories.card} /> <Controls of={cardStories.card} /> diff --git a/packages/nimble-components/src/combobox/tests/combobox.mdx b/packages/nimble-components/src/combobox/tests/combobox.mdx index 254ea40c8e..0870896932 100644 --- a/packages/nimble-components/src/combobox/tests/combobox.mdx +++ b/packages/nimble-components/src/combobox/tests/combobox.mdx @@ -19,11 +19,11 @@ import { listOptionTag } from '../../list-option/'; ### Native element and Blazor -The value of the combobox comes from the text content of the selected autocomplete <Tag of={listOptionTag} />, or, if no matching autocomplete is found, the value is the user-entered text. +The value of the combobox comes from the text content of the selected autocomplete <Tag name={listOptionTag} />, or, if no matching autocomplete is found, the value is the user-entered text. ### Angular -In Angular, an autocomplete <Tag of={listOptionTag} /> can be created with an `ngValue`. In that case the `ngModel` of the combobox will be the `ngValue` of the matched autocomplete option. +In Angular, an autocomplete <Tag name={listOptionTag} /> can be created with an `ngValue`. In that case the `ngModel` of the combobox will be the `ngValue` of the matched autocomplete option. If no matching autocomplete option is found, the `ngModel` of the combobox will be set to `OPTION_NOT_FOUND`, and if the application needs to access the user-entered text, that should be done through the `value` property on the `NimbleComboboxDirective`. From 58ec343fb239c467f579dd23a88a3e0f85aabe7f Mon Sep 17 00:00:00 2001 From: rajsite <rajsite@users.noreply.github.com> Date: Wed, 13 Mar 2024 22:25:27 +0000 Subject: [PATCH 02/12] applying package updates [skip ci] --- ...ents-e257f396-a221-4970-b66a-51678c50bb25.json | 7 ------- packages/nimble-components/CHANGELOG.json | 15 +++++++++++++++ 2 files changed, 15 insertions(+), 7 deletions(-) delete mode 100644 change/@ni-nimble-components-e257f396-a221-4970-b66a-51678c50bb25.json diff --git a/change/@ni-nimble-components-e257f396-a221-4970-b66a-51678c50bb25.json b/change/@ni-nimble-components-e257f396-a221-4970-b66a-51678c50bb25.json deleted file mode 100644 index e4fe0bf701..0000000000 --- a/change/@ni-nimble-components-e257f396-a221-4970-b66a-51678c50bb25.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "type": "none", - "comment": "Fix missing element names in some Storybook docs", - "packageName": "@ni/nimble-components", - "email": "7282195+m-akinc@users.noreply.github.com", - "dependentChangeType": "none" -} diff --git a/packages/nimble-components/CHANGELOG.json b/packages/nimble-components/CHANGELOG.json index b9003caebc..2a6f2751f7 100644 --- a/packages/nimble-components/CHANGELOG.json +++ b/packages/nimble-components/CHANGELOG.json @@ -1,6 +1,21 @@ { "name": "@ni/nimble-components", "entries": [ + { + "date": "Wed, 13 Mar 2024 22:25:27 GMT", + "version": "21.10.2", + "tag": "@ni/nimble-components_v21.10.2", + "comments": { + "none": [ + { + "author": "7282195+m-akinc@users.noreply.github.com", + "package": "@ni/nimble-components", + "commit": "52783423015bc7b1cfd3718646923d36b1f9d32c", + "comment": "Fix missing element names in some Storybook docs" + } + ] + } + }, { "date": "Tue, 12 Mar 2024 22:17:11 GMT", "version": "21.10.2", From 518c229b964d2c4a2e77210692f5d367f2937ff4 Mon Sep 17 00:00:00 2001 From: Jesse Attas <jattasNI@users.noreply.github.com> Date: Wed, 13 Mar 2024 17:48:59 -0500 Subject: [PATCH 03/12] Update Angular and Blazor label provider directives to match nimble-components (#1927) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit # Pull Request ## ๐Ÿคจ Rationale #1747 has a maintenance task to ensure the default strings in Angular and Blazor directives match the default strings in nimble-components. ## ๐Ÿ‘ฉโ€๐Ÿ’ป Implementation Some labels were only provided in nimble-components, not nimble-angular or Blazor. Copied those values over following existing patterns in directives and test files. ## ๐Ÿงช Testing Updated tests but otherwise none since this is a mechanical change. ## โœ… Checklist <!--- Review the list and put an x in the boxes that apply or ~~strike through~~ around items that don't (along with an explanation). --> - [x] I have updated the project documentation to reflect my changes or determined no changes are needed. --------- Co-authored-by: Milan Raj <rajsite@users.noreply.github.com> --- ...l-provider-core-with-defaults.directive.ts | 5 + .../nimble-label-provider-core.directive.ts | 40 ++++ ...vider-core-with-defaults.directive.spec.ts | 12 +- ...mble-label-provider-core.directive.spec.ts | 190 ++++++++++++++++++ ...-provider-table-with-defaults.directive.ts | 2 + .../nimble-label-provider-table.directive.ts | 16 ++ ...ider-table-with-defaults.directive.spec.ts | 4 + ...ble-label-provider-table.directive.spec.ts | 124 +++++++++--- ...-bb7e376e-ce72-4760-bb8d-f5775b8eefa8.json | 7 + ...-8b481f76-2252-49bf-8f00-07c884c3b2d4.json | 7 + ...-01c69e77-25e6-4f6e-a42c-0254916345eb.json | 7 + .../Components/NimbleLabelProviderCore.razor | 5 + .../NimbleLabelProviderCore.razor.cs | 15 ++ .../Components/NimbleLabelProviderTable.razor | 2 + .../NimbleLabelProviderTable.razor.cs | 6 + .../NimbleLabelProviderCoreTests.cs | 5 + .../NimbleLabelProviderTableTests.cs | 2 + .../nimble-components/src/banner/template.ts | 12 +- .../src/label-provider/core/index.ts | 24 +-- .../core/label-token-defaults.ts | 6 +- .../src/label-provider/core/label-tokens.ts | 18 +- 21 files changed, 454 insertions(+), 55 deletions(-) create mode 100644 change/@ni-nimble-angular-bb7e376e-ce72-4760-bb8d-f5775b8eefa8.json create mode 100644 change/@ni-nimble-blazor-8b481f76-2252-49bf-8f00-07c884c3b2d4.json create mode 100644 change/@ni-nimble-components-01c69e77-25e6-4f6e-a42c-0254916345eb.json diff --git a/angular-workspace/projects/ni/nimble-angular/label-provider/core/nimble-label-provider-core-with-defaults.directive.ts b/angular-workspace/projects/ni/nimble-angular/label-provider/core/nimble-label-provider-core-with-defaults.directive.ts index bff9c0e24a..63d82cdbfb 100644 --- a/angular-workspace/projects/ni/nimble-angular/label-provider/core/nimble-label-provider-core-with-defaults.directive.ts +++ b/angular-workspace/projects/ni/nimble-angular/label-provider/core/nimble-label-provider-core-with-defaults.directive.ts @@ -15,5 +15,10 @@ export class NimbleLabelProviderCoreWithDefaultsDirective { this.elementRef.nativeElement.popupDismiss = $localize`:Nimble popup - dismiss|:Close`; this.elementRef.nativeElement.numericDecrement = $localize`:Nimble numeric - decrement|:Decrement`; this.elementRef.nativeElement.numericIncrement = $localize`:Nimble numeric - increment|:Increment`; + this.elementRef.nativeElement.popupIconError = $localize`:Nimble popup icon - error|:Error`; + this.elementRef.nativeElement.popupIconWarning = $localize`:Nimble popup icon - warning|:Warning`; + this.elementRef.nativeElement.popupIconInformation = $localize`:Nimble popup icon - information|:Information`; + this.elementRef.nativeElement.filterSearch = $localize`:Nimble select - search items|:Search`; + this.elementRef.nativeElement.filterNoResults = $localize`:Nimble select - no items|:No items found`; } } \ No newline at end of file diff --git a/angular-workspace/projects/ni/nimble-angular/label-provider/core/nimble-label-provider-core.directive.ts b/angular-workspace/projects/ni/nimble-angular/label-provider/core/nimble-label-provider-core.directive.ts index 6c6276d7bd..17fa20a4a7 100644 --- a/angular-workspace/projects/ni/nimble-angular/label-provider/core/nimble-label-provider-core.directive.ts +++ b/angular-workspace/projects/ni/nimble-angular/label-provider/core/nimble-label-provider-core.directive.ts @@ -37,4 +37,44 @@ export class NimbleLabelProviderCoreDirective { @Input('numeric-increment') public set numericIncrement(value: string | undefined) { this.renderer.setProperty(this.elementRef.nativeElement, 'numericIncrement', value); } + + public get popupIconError(): string | undefined { + return this.elementRef.nativeElement.popupIconError; + } + + @Input('popup-icon-error') public set popupIconError(value: string | undefined) { + this.renderer.setProperty(this.elementRef.nativeElement, 'popupIconError', value); + } + + public get popupIconWarning(): string | undefined { + return this.elementRef.nativeElement.popupIconWarning; + } + + @Input('popup-icon-warning') public set popupIconWarning(value: string | undefined) { + this.renderer.setProperty(this.elementRef.nativeElement, 'popupIconWarning', value); + } + + public get popupIconInformation(): string | undefined { + return this.elementRef.nativeElement.popupIconInformation; + } + + @Input('popup-icon-information') public set popupIconInformation(value: string | undefined) { + this.renderer.setProperty(this.elementRef.nativeElement, 'popupIconInformation', value); + } + + public get filterSearch(): string | undefined { + return this.elementRef.nativeElement.filterSearch; + } + + @Input('filter-search') public set filterSearch(value: string | undefined) { + this.renderer.setProperty(this.elementRef.nativeElement, 'filterSearch', value); + } + + public get filterNoResults(): string | undefined { + return this.elementRef.nativeElement.filterNoResults; + } + + @Input('filter-no-results') public set filterNoResults(value: string | undefined) { + this.renderer.setProperty(this.elementRef.nativeElement, 'filterNoResults', value); + } } \ No newline at end of file diff --git a/angular-workspace/projects/ni/nimble-angular/label-provider/core/tests/nimble-label-provider-core-with-defaults.directive.spec.ts b/angular-workspace/projects/ni/nimble-angular/label-provider/core/tests/nimble-label-provider-core-with-defaults.directive.spec.ts index 0b74b5a736..50a4b6bade 100644 --- a/angular-workspace/projects/ni/nimble-angular/label-provider/core/tests/nimble-label-provider-core-with-defaults.directive.spec.ts +++ b/angular-workspace/projects/ni/nimble-angular/label-provider/core/tests/nimble-label-provider-core-with-defaults.directive.spec.ts @@ -30,7 +30,12 @@ describe('Nimble LabelProviderCore withDefaults directive', () => { loadTranslations({ [computeMsgId('Close', 'Nimble popup - dismiss')]: 'Translated close', [computeMsgId('Decrement', 'Nimble numeric - decrement')]: 'Translated decrement', - [computeMsgId('Increment', 'Nimble numeric - increment')]: 'Translated increment' + [computeMsgId('Increment', 'Nimble numeric - increment')]: 'Translated increment', + [computeMsgId('Error', 'Nimble popup icon - error')]: 'Translated error', + [computeMsgId('Warning', 'Nimble popup icon - warning')]: 'Translated warning', + [computeMsgId('Information', 'Nimble popup icon - information')]: 'Translated information', + [computeMsgId('Search', 'Nimble select - search items')]: 'Translated search', + [computeMsgId('No items found', 'Nimble select - no items')]: 'Translated no items found' }); const fixture = TestBed.createComponent(TestHostComponent); const testHostComponent = fixture.componentInstance; @@ -42,5 +47,10 @@ describe('Nimble LabelProviderCore withDefaults directive', () => { expect(labelProvider.popupDismiss).toBe('Translated close'); expect(labelProvider.numericDecrement).toBe('Translated decrement'); expect(labelProvider.numericIncrement).toBe('Translated increment'); + expect(labelProvider.popupIconError).toBe('Translated error'); + expect(labelProvider.popupIconWarning).toBe('Translated warning'); + expect(labelProvider.popupIconInformation).toBe('Translated information'); + expect(labelProvider.filterSearch).toBe('Translated search'); + expect(labelProvider.filterNoResults).toBe('Translated no items found'); }); }); diff --git a/angular-workspace/projects/ni/nimble-angular/label-provider/core/tests/nimble-label-provider-core.directive.spec.ts b/angular-workspace/projects/ni/nimble-angular/label-provider/core/tests/nimble-label-provider-core.directive.spec.ts index 7a276c1b41..3249e7e4e4 100644 --- a/angular-workspace/projects/ni/nimble-angular/label-provider/core/tests/nimble-label-provider-core.directive.spec.ts +++ b/angular-workspace/projects/ni/nimble-angular/label-provider/core/tests/nimble-label-provider-core.directive.spec.ts @@ -7,6 +7,11 @@ describe('Nimble Label Provider Core', () => { const label1 = 'String 1'; const label2 = 'String 2'; const label3 = 'String 3'; + const label4 = 'String 4'; + const label5 = 'String 5'; + const label6 = 'String 6'; + const label7 = 'String 7'; + const label8 = 'String 8'; beforeEach(() => { TestBed.configureTestingModule({ @@ -58,6 +63,31 @@ describe('Nimble Label Provider Core', () => { expect(directive.numericIncrement).toBeUndefined(); expect(nativeElement.numericIncrement).toBeUndefined(); }); + + it('has expected defaults for popupIconError', () => { + expect(directive.popupIconError).toBeUndefined(); + expect(nativeElement.popupIconError).toBeUndefined(); + }); + + it('has expected defaults for popupIconWarning', () => { + expect(directive.popupIconWarning).toBeUndefined(); + expect(nativeElement.popupIconWarning).toBeUndefined(); + }); + + it('has expected defaults for popupIconInformation', () => { + expect(directive.popupIconInformation).toBeUndefined(); + expect(nativeElement.popupIconInformation).toBeUndefined(); + }); + + it('has expected defaults for filterSearch', () => { + expect(directive.filterSearch).toBeUndefined(); + expect(nativeElement.filterSearch).toBeUndefined(); + }); + + it('has expected defaults for filterNoResults', () => { + expect(directive.filterNoResults).toBeUndefined(); + expect(nativeElement.filterNoResults).toBeUndefined(); + }); }); describe('with template string values', () => { @@ -67,6 +97,11 @@ describe('Nimble Label Provider Core', () => { popup-dismiss="${label1}" numeric-decrement="${label2}" numeric-increment="${label3}" + popup-icon-error="${label4}" + popup-icon-warning="${label5}" + popup-icon-information="${label6}" + filter-search="${label7}" + filter-no-results="${label8}" > </nimble-label-provider-core> ` @@ -105,6 +140,31 @@ describe('Nimble Label Provider Core', () => { expect(directive.numericIncrement).toBe(label3); expect(nativeElement.numericIncrement).toBe(label3); }); + + it('will use template string values for popupIconError', () => { + expect(directive.popupIconError).toBe(label4); + expect(nativeElement.popupIconError).toBe(label4); + }); + + it('will use template string values for popupIconWarning', () => { + expect(directive.popupIconWarning).toBe(label5); + expect(nativeElement.popupIconWarning).toBe(label5); + }); + + it('will use template string values for popupIconInformation', () => { + expect(directive.popupIconInformation).toBe(label6); + expect(nativeElement.popupIconInformation).toBe(label6); + }); + + it('will use template string values for filterSearch', () => { + expect(directive.filterSearch).toBe(label7); + expect(nativeElement.filterSearch).toBe(label7); + }); + + it('will use template string values for filterNoResults', () => { + expect(directive.filterNoResults).toBe(label8); + expect(nativeElement.filterNoResults).toBe(label8); + }); }); describe('with property bound values', () => { @@ -114,6 +174,11 @@ describe('Nimble Label Provider Core', () => { [popupDismiss]="popupDismiss" [numericDecrement]="numericDecrement" [numericIncrement]="numericIncrement" + [popupIconError]="popupIconError" + [popupIconWarning]="popupIconWarning" + [popupIconInformation]="popupIconInformation" + [filterSearch]="filterSearch" + [filterNoResults]="filterNoResults" > </nimble-label-provider-core> ` @@ -124,6 +189,11 @@ describe('Nimble Label Provider Core', () => { public popupDismiss = label1; public numericDecrement = label1; public numericIncrement = label1; + public popupIconError = label1; + public popupIconWarning = label1; + public popupIconInformation = label1; + public filterSearch = label1; + public filterNoResults = label1; } let fixture: ComponentFixture<TestHostComponent>; @@ -173,6 +243,61 @@ describe('Nimble Label Provider Core', () => { expect(directive.numericIncrement).toBe(label2); expect(nativeElement.numericIncrement).toBe(label2); }); + + it('can be configured with property binding for popupIconError', () => { + expect(directive.popupIconError).toBe(label1); + expect(nativeElement.popupIconError).toBe(label1); + + fixture.componentInstance.popupIconError = label2; + fixture.detectChanges(); + + expect(directive.popupIconError).toBe(label2); + expect(nativeElement.popupIconError).toBe(label2); + }); + + it('can be configured with property binding for popupIconWarning', () => { + expect(directive.popupIconWarning).toBe(label1); + expect(nativeElement.popupIconWarning).toBe(label1); + + fixture.componentInstance.popupIconWarning = label2; + fixture.detectChanges(); + + expect(directive.popupIconWarning).toBe(label2); + expect(nativeElement.popupIconWarning).toBe(label2); + }); + + it('can be configured with property binding for popupIconInformation', () => { + expect(directive.popupIconInformation).toBe(label1); + expect(nativeElement.popupIconInformation).toBe(label1); + + fixture.componentInstance.popupIconInformation = label2; + fixture.detectChanges(); + + expect(directive.popupIconInformation).toBe(label2); + expect(nativeElement.popupIconInformation).toBe(label2); + }); + + it('can be configured with property binding for filterSearch', () => { + expect(directive.filterSearch).toBe(label1); + expect(nativeElement.filterSearch).toBe(label1); + + fixture.componentInstance.filterSearch = label2; + fixture.detectChanges(); + + expect(directive.filterSearch).toBe(label2); + expect(nativeElement.filterSearch).toBe(label2); + }); + + it('can be configured with property binding for filterNoResults', () => { + expect(directive.filterNoResults).toBe(label1); + expect(nativeElement.filterNoResults).toBe(label1); + + fixture.componentInstance.filterNoResults = label2; + fixture.detectChanges(); + + expect(directive.filterNoResults).toBe(label2); + expect(nativeElement.filterNoResults).toBe(label2); + }); }); describe('with attribute bound values', () => { @@ -182,6 +307,11 @@ describe('Nimble Label Provider Core', () => { [attr.popup-dismiss]="popupDismiss" [attr.numeric-decrement]="numericDecrement" [attr.numeric-increment]="numericIncrement" + [attr.popup-icon-error]="popupIconError" + [attr.popup-icon-warning]="popupIconWarning" + [attr.popup-icon-information]="popupIconInformation" + [attr.filter-search]="filterSearch" + [attr.filter-no-results]="filterNoResults" > </nimble-label-provider-core> ` @@ -192,6 +322,11 @@ describe('Nimble Label Provider Core', () => { public popupDismiss = label1; public numericDecrement = label1; public numericIncrement = label1; + public popupIconError = label1; + public popupIconWarning = label1; + public popupIconInformation = label1; + public filterSearch = label1; + public filterNoResults = label1; } let fixture: ComponentFixture<TestHostComponent>; @@ -241,5 +376,60 @@ describe('Nimble Label Provider Core', () => { expect(directive.numericIncrement).toBe(label2); expect(nativeElement.numericIncrement).toBe(label2); }); + + it('can be configured with attribute binding for popupIconError', () => { + expect(directive.popupIconError).toBe(label1); + expect(nativeElement.popupIconError).toBe(label1); + + fixture.componentInstance.popupIconError = label2; + fixture.detectChanges(); + + expect(directive.popupIconError).toBe(label2); + expect(nativeElement.popupIconError).toBe(label2); + }); + + it('can be configured with attribute binding for popupIconWarning', () => { + expect(directive.popupIconWarning).toBe(label1); + expect(nativeElement.popupIconWarning).toBe(label1); + + fixture.componentInstance.popupIconWarning = label2; + fixture.detectChanges(); + + expect(directive.popupIconWarning).toBe(label2); + expect(nativeElement.popupIconWarning).toBe(label2); + }); + + it('can be configured with attribute binding for popupIconInformation', () => { + expect(directive.popupIconInformation).toBe(label1); + expect(nativeElement.popupIconInformation).toBe(label1); + + fixture.componentInstance.popupIconInformation = label2; + fixture.detectChanges(); + + expect(directive.popupIconInformation).toBe(label2); + expect(nativeElement.popupIconInformation).toBe(label2); + }); + + it('can be configured with attribute binding for filterSearch', () => { + expect(directive.filterSearch).toBe(label1); + expect(nativeElement.filterSearch).toBe(label1); + + fixture.componentInstance.filterSearch = label2; + fixture.detectChanges(); + + expect(directive.filterSearch).toBe(label2); + expect(nativeElement.filterSearch).toBe(label2); + }); + + it('can be configured with attribute binding for filterNoResults', () => { + expect(directive.filterNoResults).toBe(label1); + expect(nativeElement.filterNoResults).toBe(label1); + + fixture.componentInstance.filterNoResults = label2; + fixture.detectChanges(); + + expect(directive.filterNoResults).toBe(label2); + expect(nativeElement.filterNoResults).toBe(label2); + }); }); }); diff --git a/angular-workspace/projects/ni/nimble-angular/label-provider/table/nimble-label-provider-table-with-defaults.directive.ts b/angular-workspace/projects/ni/nimble-angular/label-provider/table/nimble-label-provider-table-with-defaults.directive.ts index cbee2fcd95..4c4d2977b6 100644 --- a/angular-workspace/projects/ni/nimble-angular/label-provider/table/nimble-label-provider-table-with-defaults.directive.ts +++ b/angular-workspace/projects/ni/nimble-angular/label-provider/table/nimble-label-provider-table-with-defaults.directive.ts @@ -14,6 +14,8 @@ export class NimbleLabelProviderTableWithDefaultsDirective { public constructor(protected readonly renderer: Renderer2, protected readonly elementRef: ElementRef<LabelProviderTable>) { this.elementRef.nativeElement.groupCollapse = $localize`:Nimble table - collapse group|:Collapse group`; this.elementRef.nativeElement.groupExpand = $localize`:Nimble table - expand group|:Expand group`; + this.elementRef.nativeElement.rowCollapse = $localize`:Nimble table - collapse row|:Collapse row`; + this.elementRef.nativeElement.rowExpand = $localize`:Nimble table - expand row|:Expand row`; this.elementRef.nativeElement.collapseAll = $localize`:Nimble table - collapse all|:Collapse all`; this.elementRef.nativeElement.cellActionMenu = $localize`:Nimble table - cell action menu|:Options`; this.elementRef.nativeElement.columnHeaderGrouped = $localize`:Nimble table - column header grouped|:Grouped`; diff --git a/angular-workspace/projects/ni/nimble-angular/label-provider/table/nimble-label-provider-table.directive.ts b/angular-workspace/projects/ni/nimble-angular/label-provider/table/nimble-label-provider-table.directive.ts index 7f68fe9cb5..ebf09e6e20 100644 --- a/angular-workspace/projects/ni/nimble-angular/label-provider/table/nimble-label-provider-table.directive.ts +++ b/angular-workspace/projects/ni/nimble-angular/label-provider/table/nimble-label-provider-table.directive.ts @@ -30,6 +30,22 @@ export class NimbleLabelProviderTableDirective { this.renderer.setProperty(this.elementRef.nativeElement, 'groupExpand', value); } + public get rowCollapse(): string | undefined { + return this.elementRef.nativeElement.rowCollapse; + } + + @Input('row-collapse') public set rowCollapse(value: string | undefined) { + this.renderer.setProperty(this.elementRef.nativeElement, 'rowCollapse', value); + } + + public get rowExpand(): string | undefined { + return this.elementRef.nativeElement.rowExpand; + } + + @Input('row-expand') public set rowExpand(value: string | undefined) { + this.renderer.setProperty(this.elementRef.nativeElement, 'rowExpand', value); + } + public get collapseAll(): string | undefined { return this.elementRef.nativeElement.collapseAll; } diff --git a/angular-workspace/projects/ni/nimble-angular/label-provider/table/tests/nimble-label-provider-table-with-defaults.directive.spec.ts b/angular-workspace/projects/ni/nimble-angular/label-provider/table/tests/nimble-label-provider-table-with-defaults.directive.spec.ts index 6f62cb10b9..1f72c8079a 100644 --- a/angular-workspace/projects/ni/nimble-angular/label-provider/table/tests/nimble-label-provider-table-with-defaults.directive.spec.ts +++ b/angular-workspace/projects/ni/nimble-angular/label-provider/table/tests/nimble-label-provider-table-with-defaults.directive.spec.ts @@ -30,6 +30,8 @@ describe('Nimble LabelProviderTable withDefaults directive', () => { loadTranslations({ [computeMsgId('Collapse group', 'Nimble table - collapse group')]: 'Translated collapse group', [computeMsgId('Expand group', 'Nimble table - expand group')]: 'Translated expand group', + [computeMsgId('Collapse row', 'Nimble table - collapse row')]: 'Translated collapse row', + [computeMsgId('Expand row', 'Nimble table - expand row')]: 'Translated expand row', [computeMsgId('Collapse all', 'Nimble table - collapse all')]: 'Translated collapse all', [computeMsgId('Options', 'Nimble table - cell action menu')]: 'Translated options', [computeMsgId('Grouped', 'Nimble table - column header grouped')]: 'Translated grouped', @@ -50,6 +52,8 @@ describe('Nimble LabelProviderTable withDefaults directive', () => { it('applies translated values for each label', () => { expect(labelProvider.groupCollapse).toBe('Translated collapse group'); expect(labelProvider.groupExpand).toBe('Translated expand group'); + expect(labelProvider.rowCollapse).toBe('Translated collapse row'); + expect(labelProvider.rowExpand).toBe('Translated expand row'); expect(labelProvider.collapseAll).toBe('Translated collapse all'); expect(labelProvider.cellActionMenu).toBe('Translated options'); expect(labelProvider.columnHeaderGrouped).toBe('Translated grouped'); diff --git a/angular-workspace/projects/ni/nimble-angular/label-provider/table/tests/nimble-label-provider-table.directive.spec.ts b/angular-workspace/projects/ni/nimble-angular/label-provider/table/tests/nimble-label-provider-table.directive.spec.ts index 87f25ad84c..e0b96f47c4 100644 --- a/angular-workspace/projects/ni/nimble-angular/label-provider/table/tests/nimble-label-provider-table.directive.spec.ts +++ b/angular-workspace/projects/ni/nimble-angular/label-provider/table/tests/nimble-label-provider-table.directive.spec.ts @@ -16,6 +16,8 @@ describe('Nimble Label Provider Table', () => { const label10 = 'String 10'; const label11 = 'String 11'; const label12 = 'String 12'; + const label13 = 'String 13'; + const label14 = 'String 14'; beforeEach(() => { TestBed.configureTestingModule({ @@ -73,6 +75,16 @@ describe('Nimble Label Provider Table', () => { expect(nativeElement.groupExpand).toBeUndefined(); }); + it('has expected defaults for rowCollapse', () => { + expect(directive.rowCollapse).toBeUndefined(); + expect(nativeElement.rowCollapse).toBeUndefined(); + }); + + it('has expected defaults for rowExpand', () => { + expect(directive.rowExpand).toBeUndefined(); + expect(nativeElement.rowExpand).toBeUndefined(); + }); + it('has expected defaults for collapseAll', () => { expect(directive.collapseAll).toBeUndefined(); expect(nativeElement.collapseAll).toBeUndefined(); @@ -122,14 +134,16 @@ describe('Nimble Label Provider Table', () => { column-header-grouped="${label2}" group-collapse="${label3}" group-expand="${label4}" - collapse-all="${label5}" - column-header-sorted-ascending="${label6}" - column-header-sorted-descending="${label7}" - select-all="${label8}" - group-select-all="${label9}" - row-select="${label10}" - row-operation-column="${label11}" - row-loading="${label12}" + row-collapse="${label5}" + row-expand="${label6}" + collapse-all="${label7}" + column-header-sorted-ascending="${label8}" + column-header-sorted-descending="${label9}" + select-all="${label10}" + group-select-all="${label11}" + row-select="${label12}" + row-operation-column="${label13}" + row-loading="${label14}" > </nimble-label-provider-table> ` @@ -174,44 +188,54 @@ describe('Nimble Label Provider Table', () => { expect(nativeElement.groupExpand).toBe(label4); }); + it('will use template string values for rowCollapse', () => { + expect(directive.rowCollapse).toBe(label5); + expect(nativeElement.rowCollapse).toBe(label5); + }); + + it('will use template string values for rowExpand', () => { + expect(directive.rowExpand).toBe(label6); + expect(nativeElement.rowExpand).toBe(label6); + }); + it('will use template string values for collapseAll', () => { - expect(directive.collapseAll).toBe(label5); - expect(nativeElement.collapseAll).toBe(label5); + expect(directive.collapseAll).toBe(label7); + expect(nativeElement.collapseAll).toBe(label7); }); it('will use template string values for columnHeaderSortedAscending', () => { - expect(directive.columnHeaderSortedAscending).toBe(label6); - expect(nativeElement.columnHeaderSortedAscending).toBe(label6); + expect(directive.columnHeaderSortedAscending).toBe(label8); + expect(nativeElement.columnHeaderSortedAscending).toBe(label8); }); it('will use template string values for columnHeaderSortedDescending', () => { - expect(directive.columnHeaderSortedDescending).toBe(label7); - expect(nativeElement.columnHeaderSortedDescending).toBe(label7); + expect(directive.columnHeaderSortedDescending).toBe(label9); + expect(nativeElement.columnHeaderSortedDescending).toBe(label9); }); it('will use template string values for selectAll', () => { - expect(directive.selectAll).toBe(label8); - expect(nativeElement.selectAll).toBe(label8); + expect(directive.selectAll).toBe(label10); + expect(nativeElement.selectAll).toBe(label10); }); it('will use template string values for groupSelectAll', () => { - expect(directive.groupSelectAll).toBe(label9); - expect(nativeElement.groupSelectAll).toBe(label9); + expect(directive.groupSelectAll).toBe(label11); + expect(nativeElement.groupSelectAll).toBe(label11); }); it('will use template string values for rowSelect', () => { - expect(directive.rowSelect).toBe(label10); - expect(nativeElement.rowSelect).toBe(label10); + expect(directive.rowSelect).toBe(label12); + expect(nativeElement.rowSelect).toBe(label12); }); it('will use template string values for rowOperationColumn', () => { - expect(directive.rowOperationColumn).toBe(label11); - expect(nativeElement.rowOperationColumn).toBe(label11); + expect(directive.rowOperationColumn).toBe(label13); + expect(nativeElement.rowOperationColumn).toBe(label13); }); it('will use template string values for rowLoading', () => { - expect(directive.rowLoading).toBe(label12); - expect(nativeElement.rowLoading).toBe(label12); + expect(directive.rowLoading).toBe(label14); + expect(nativeElement.rowLoading).toBe(label14); }); }); @@ -223,6 +247,8 @@ describe('Nimble Label Provider Table', () => { [columnHeaderGrouped]="columnHeaderGrouped" [groupCollapse]="groupCollapse" [groupExpand]="groupExpand" + [rowCollapse]="rowCollapse" + [rowExpand]="rowExpand" [collapseAll]="collapseAll" [columnHeaderSortedAscending]="columnHeaderSortedAscending" [columnHeaderSortedDescending]="columnHeaderSortedDescending" @@ -242,6 +268,8 @@ describe('Nimble Label Provider Table', () => { public columnHeaderGrouped = label1; public groupCollapse = label1; public groupExpand = label1; + public rowCollapse = label1; + public rowExpand = label1; public collapseAll = label1; public columnHeaderSortedAscending = label1; public columnHeaderSortedDescending = label1; @@ -311,6 +339,28 @@ describe('Nimble Label Provider Table', () => { expect(nativeElement.groupExpand).toBe(label2); }); + it('can be configured with property binding for rowCollapse', () => { + expect(directive.rowCollapse).toBe(label1); + expect(nativeElement.rowCollapse).toBe(label1); + + fixture.componentInstance.rowCollapse = label2; + fixture.detectChanges(); + + expect(directive.rowCollapse).toBe(label2); + expect(nativeElement.rowCollapse).toBe(label2); + }); + + it('can be configured with property binding for rowExpand', () => { + expect(directive.rowExpand).toBe(label1); + expect(nativeElement.rowExpand).toBe(label1); + + fixture.componentInstance.rowExpand = label2; + fixture.detectChanges(); + + expect(directive.rowExpand).toBe(label2); + expect(nativeElement.rowExpand).toBe(label2); + }); + it('can be configured with property binding for collapseAll', () => { expect(directive.collapseAll).toBe(label1); expect(nativeElement.collapseAll).toBe(label1); @@ -408,6 +458,8 @@ describe('Nimble Label Provider Table', () => { [attr.column-header-grouped]="columnHeaderGrouped" [attr.group-collapse]="groupCollapse" [attr.group-expand]="groupExpand" + [attr.row-collapse]="rowCollapse" + [attr.row-expand]="rowExpand" [attr.collapse-all]="collapseAll" [attr.column-header-sorted-ascending]="columnHeaderSortedAscending" [attr.column-header-sorted-descending]="columnHeaderSortedDescending" @@ -427,6 +479,8 @@ describe('Nimble Label Provider Table', () => { public columnHeaderGrouped = label1; public groupCollapse = label1; public groupExpand = label1; + public rowCollapse = label1; + public rowExpand = label1; public collapseAll = label1; public columnHeaderSortedAscending = label1; public columnHeaderSortedDescending = label1; @@ -496,6 +550,28 @@ describe('Nimble Label Provider Table', () => { expect(nativeElement.groupExpand).toBe(label2); }); + it('can be configured with attribute binding for rowCollapse', () => { + expect(directive.rowCollapse).toBe(label1); + expect(nativeElement.rowCollapse).toBe(label1); + + fixture.componentInstance.rowCollapse = label2; + fixture.detectChanges(); + + expect(directive.rowCollapse).toBe(label2); + expect(nativeElement.rowCollapse).toBe(label2); + }); + + it('can be configured with attribute binding for rowExpand', () => { + expect(directive.rowExpand).toBe(label1); + expect(nativeElement.rowExpand).toBe(label1); + + fixture.componentInstance.rowExpand = label2; + fixture.detectChanges(); + + expect(directive.rowExpand).toBe(label2); + expect(nativeElement.rowExpand).toBe(label2); + }); + it('can be configured with attribute binding for collapseAll', () => { expect(directive.collapseAll).toBe(label1); expect(nativeElement.collapseAll).toBe(label1); diff --git a/change/@ni-nimble-angular-bb7e376e-ce72-4760-bb8d-f5775b8eefa8.json b/change/@ni-nimble-angular-bb7e376e-ce72-4760-bb8d-f5775b8eefa8.json new file mode 100644 index 0000000000..bc88667bdc --- /dev/null +++ b/change/@ni-nimble-angular-bb7e376e-ce72-4760-bb8d-f5775b8eefa8.json @@ -0,0 +1,7 @@ +{ + "type": "minor", + "comment": "Update default values in label provider directives and expose additional label provider properties", + "packageName": "@ni/nimble-angular", + "email": "jattasNI@users.noreply.github.com", + "dependentChangeType": "patch" +} diff --git a/change/@ni-nimble-blazor-8b481f76-2252-49bf-8f00-07c884c3b2d4.json b/change/@ni-nimble-blazor-8b481f76-2252-49bf-8f00-07c884c3b2d4.json new file mode 100644 index 0000000000..b1163223b2 --- /dev/null +++ b/change/@ni-nimble-blazor-8b481f76-2252-49bf-8f00-07c884c3b2d4.json @@ -0,0 +1,7 @@ +{ + "type": "minor", + "comment": "Expose additional label provider properties", + "packageName": "@ni/nimble-blazor", + "email": "jattasNI@users.noreply.github.com", + "dependentChangeType": "patch" +} diff --git a/change/@ni-nimble-components-01c69e77-25e6-4f6e-a42c-0254916345eb.json b/change/@ni-nimble-components-01c69e77-25e6-4f6e-a42c-0254916345eb.json new file mode 100644 index 0000000000..aeffcb7c25 --- /dev/null +++ b/change/@ni-nimble-components-01c69e77-25e6-4f6e-a42c-0254916345eb.json @@ -0,0 +1,7 @@ +{ + "type": "major", + "comment": "Rename icon labels to follow naming convention", + "packageName": "@ni/nimble-components", + "email": "jattasNI@users.noreply.github.com", + "dependentChangeType": "patch" +} diff --git a/packages/nimble-blazor/NimbleBlazor/Components/NimbleLabelProviderCore.razor b/packages/nimble-blazor/NimbleBlazor/Components/NimbleLabelProviderCore.razor index 4d7f99c505..f5a2274346 100644 --- a/packages/nimble-blazor/NimbleBlazor/Components/NimbleLabelProviderCore.razor +++ b/packages/nimble-blazor/NimbleBlazor/Components/NimbleLabelProviderCore.razor @@ -3,5 +3,10 @@ popup-dismiss="@PopupDismiss" numeric-decrement="@NumericDecrement" numeric-increment="@NumericIncrement" + popup-icon-error="@PopupIconError" + popup-icon-warning="@PopupIconWarning" + popup-icon-information="@PopupIconInformation" + filter-search="@FilterSearch" + filter-no-results="@FilterNoResults" @attributes="AdditionalAttributes"> </nimble-label-provider-core> diff --git a/packages/nimble-blazor/NimbleBlazor/Components/NimbleLabelProviderCore.razor.cs b/packages/nimble-blazor/NimbleBlazor/Components/NimbleLabelProviderCore.razor.cs index e2e23abe27..eeb080d23a 100644 --- a/packages/nimble-blazor/NimbleBlazor/Components/NimbleLabelProviderCore.razor.cs +++ b/packages/nimble-blazor/NimbleBlazor/Components/NimbleLabelProviderCore.razor.cs @@ -16,6 +16,21 @@ public partial class NimbleLabelProviderCore : ComponentBase [Parameter] public string? NumericDecrement { get; set; } + [Parameter] + public string? PopupIconError { get; set; } + + [Parameter] + public string? PopupIconWarning { get; set; } + + [Parameter] + public string? PopupIconInformation { get; set; } + + [Parameter] + public string? FilterSearch { get; set; } + + [Parameter] + public string? FilterNoResults { get; set; } + /// <summary> /// Gets or sets a collection of additional attributes that will be applied to the created element. /// </summary> diff --git a/packages/nimble-blazor/NimbleBlazor/Components/NimbleLabelProviderTable.razor b/packages/nimble-blazor/NimbleBlazor/Components/NimbleLabelProviderTable.razor index 50351dc8bc..a71b904408 100644 --- a/packages/nimble-blazor/NimbleBlazor/Components/NimbleLabelProviderTable.razor +++ b/packages/nimble-blazor/NimbleBlazor/Components/NimbleLabelProviderTable.razor @@ -2,6 +2,8 @@ <nimble-label-provider-table group-collapse="@GroupCollapse" group-expand="@GroupExpand" + row-collapse="@RowCollapse" + row-expand="@RowExpand" collapse-all="@CollapseAll" cell-action-menu="@CellActionMenu" column-header-grouped="@ColumnHeaderGrouped" diff --git a/packages/nimble-blazor/NimbleBlazor/Components/NimbleLabelProviderTable.razor.cs b/packages/nimble-blazor/NimbleBlazor/Components/NimbleLabelProviderTable.razor.cs index 60ab8da142..d91a701987 100644 --- a/packages/nimble-blazor/NimbleBlazor/Components/NimbleLabelProviderTable.razor.cs +++ b/packages/nimble-blazor/NimbleBlazor/Components/NimbleLabelProviderTable.razor.cs @@ -13,6 +13,12 @@ public partial class NimbleLabelProviderTable : ComponentBase [Parameter] public string? GroupExpand { get; set; } + [Parameter] + public string? RowCollapse { get; set; } + + [Parameter] + public string? RowExpand { get; set; } + [Parameter] public string? CollapseAll { get; set; } diff --git a/packages/nimble-blazor/Tests/NimbleBlazor.Tests/Unit/Components/NimbleLabelProviderCoreTests.cs b/packages/nimble-blazor/Tests/NimbleBlazor.Tests/Unit/Components/NimbleLabelProviderCoreTests.cs index 9a3c7da28f..1794135ea6 100644 --- a/packages/nimble-blazor/Tests/NimbleBlazor.Tests/Unit/Components/NimbleLabelProviderCoreTests.cs +++ b/packages/nimble-blazor/Tests/NimbleBlazor.Tests/Unit/Components/NimbleLabelProviderCoreTests.cs @@ -33,6 +33,11 @@ public void NimbleLabelProviderCore_SupportsAdditionalAttributes() [InlineData(nameof(NimbleLabelProviderCore.PopupDismiss))] [InlineData(nameof(NimbleLabelProviderCore.NumericDecrement))] [InlineData(nameof(NimbleLabelProviderCore.NumericIncrement))] + [InlineData(nameof(NimbleLabelProviderCore.PopupIconError))] + [InlineData(nameof(NimbleLabelProviderCore.PopupIconWarning))] + [InlineData(nameof(NimbleLabelProviderCore.PopupIconInformation))] + [InlineData(nameof(NimbleLabelProviderCore.FilterSearch))] + [InlineData(nameof(NimbleLabelProviderCore.FilterNoResults))] public void NimbleLabelProviderCore_LabelIsSet(string propertyName) { var labelValue = propertyName + "UpdatedValue"; diff --git a/packages/nimble-blazor/Tests/NimbleBlazor.Tests/Unit/Components/NimbleLabelProviderTableTests.cs b/packages/nimble-blazor/Tests/NimbleBlazor.Tests/Unit/Components/NimbleLabelProviderTableTests.cs index 0e607ee84d..32caad78a4 100644 --- a/packages/nimble-blazor/Tests/NimbleBlazor.Tests/Unit/Components/NimbleLabelProviderTableTests.cs +++ b/packages/nimble-blazor/Tests/NimbleBlazor.Tests/Unit/Components/NimbleLabelProviderTableTests.cs @@ -32,6 +32,8 @@ public void NimbleLabelProviderTable_SupportsAdditionalAttributes() [Theory] [InlineData(nameof(NimbleLabelProviderTable.GroupCollapse))] [InlineData(nameof(NimbleLabelProviderTable.GroupExpand))] + [InlineData(nameof(NimbleLabelProviderTable.RowCollapse))] + [InlineData(nameof(NimbleLabelProviderTable.RowExpand))] [InlineData(nameof(NimbleLabelProviderTable.CollapseAll))] [InlineData(nameof(NimbleLabelProviderTable.CellActionMenu))] [InlineData(nameof(NimbleLabelProviderTable.ColumnHeaderGrouped))] diff --git a/packages/nimble-components/src/banner/template.ts b/packages/nimble-components/src/banner/template.ts index 889b0025d8..c2568336d9 100644 --- a/packages/nimble-components/src/banner/template.ts +++ b/packages/nimble-components/src/banner/template.ts @@ -7,10 +7,10 @@ import { iconTriangleFilledTag } from '../icons/triangle-filled'; import { iconXmarkTag } from '../icons/xmark'; import { BannerSeverity } from './types'; import { - errorIconLabel, - informationIconLabel, + popupIconErrorLabel, + popupIconInformationLabel, popupDismissLabel, - warningIconLabel + popupIconWarningLabel } from '../label-provider/core/label-tokens'; // prettier-ignore @@ -40,13 +40,13 @@ export const template = html<Banner>` > <div class="icon"> ${when(x => x.severity === BannerSeverity.error, html<Banner>` - <${iconExclamationMarkTag} role="img" aria-label="${x => errorIconLabel.getValueFor(x)}"></${iconExclamationMarkTag}> + <${iconExclamationMarkTag} role="img" aria-label="${x => popupIconErrorLabel.getValueFor(x)}"></${iconExclamationMarkTag}> `)} ${when(x => x.severity === BannerSeverity.warning, html<Banner>` - <${iconTriangleFilledTag} role="img" aria-label="${x => warningIconLabel.getValueFor(x)}"></${iconTriangleFilledTag}> + <${iconTriangleFilledTag} role="img" aria-label="${x => popupIconWarningLabel.getValueFor(x)}"></${iconTriangleFilledTag}> `)} ${when(x => x.severity === BannerSeverity.information, html<Banner>` - <${iconInfoTag} role="img" aria-label="${x => informationIconLabel.getValueFor(x)}"></${iconInfoTag}> + <${iconInfoTag} role="img" aria-label="${x => popupIconInformationLabel.getValueFor(x)}"></${iconInfoTag}> `)} </div> <div class="text"> diff --git a/packages/nimble-components/src/label-provider/core/index.ts b/packages/nimble-components/src/label-provider/core/index.ts index f7c901dc12..b0a872a5e7 100644 --- a/packages/nimble-components/src/label-provider/core/index.ts +++ b/packages/nimble-components/src/label-provider/core/index.ts @@ -5,9 +5,9 @@ import { popupDismissLabel, numericDecrementLabel, numericIncrementLabel, - errorIconLabel, - warningIconLabel, - informationIconLabel, + popupIconErrorLabel, + popupIconWarningLabel, + popupIconInformationLabel, filterSearchLabel, filterNoResultsLabel } from './label-tokens'; @@ -22,9 +22,9 @@ const supportedLabels = { popupDismiss: popupDismissLabel, numericDecrement: numericDecrementLabel, numericIncrement: numericIncrementLabel, - errorIcon: errorIconLabel, - warningIcon: warningIconLabel, - informationIcon: informationIconLabel, + popupIconError: popupIconErrorLabel, + popupIconWarning: popupIconWarningLabel, + popupIconInformation: popupIconInformationLabel, filterSearch: filterSearchLabel, filterNoResults: filterNoResultsLabel } as const; @@ -44,14 +44,14 @@ export class LabelProviderCore @attr({ attribute: 'numeric-increment' }) public numericIncrement: string | undefined; - @attr({ attribute: 'error-icon' }) - public errorIcon: string | undefined; + @attr({ attribute: 'popup-icon-error' }) + public popupIconError: string | undefined; - @attr({ attribute: 'warning-icon' }) - public warningIcon: string | undefined; + @attr({ attribute: 'popup-icon-warning' }) + public popupIconWarning: string | undefined; - @attr({ attribute: 'information-icon' }) - public informationIcon: string | undefined; + @attr({ attribute: 'popup-icon-information' }) + public popupIconInformation: string | undefined; @attr({ attribute: 'filter-search' }) public filterSearch: string | undefined; diff --git a/packages/nimble-components/src/label-provider/core/label-token-defaults.ts b/packages/nimble-components/src/label-provider/core/label-token-defaults.ts index 91ed6e5993..b555c28f27 100644 --- a/packages/nimble-components/src/label-provider/core/label-token-defaults.ts +++ b/packages/nimble-components/src/label-provider/core/label-token-defaults.ts @@ -6,9 +6,9 @@ export const coreLabelDefaults: { readonly [key in TokenName]: string } = { popupDismissLabel: 'Close', numericIncrementLabel: 'Increment', numericDecrementLabel: 'Decrement', - errorIconLabel: 'Error', - warningIconLabel: 'Warning', - informationIconLabel: 'Information', + popupIconErrorLabel: 'Error', + popupIconWarningLabel: 'Warning', + popupIconInformationLabel: 'Information', filterSearchLabel: 'Search', filterNoResultsLabel: 'No items found' }; diff --git a/packages/nimble-components/src/label-provider/core/label-tokens.ts b/packages/nimble-components/src/label-provider/core/label-tokens.ts index 2cfe2debce..2f6f518ec5 100644 --- a/packages/nimble-components/src/label-provider/core/label-tokens.ts +++ b/packages/nimble-components/src/label-provider/core/label-tokens.ts @@ -16,20 +16,20 @@ export const numericIncrementLabel = DesignToken.create<string>({ cssCustomPropertyName: null }).withDefault(coreLabelDefaults.numericIncrementLabel); -export const errorIconLabel = DesignToken.create<string>({ - name: 'error-icon-label', +export const popupIconErrorLabel = DesignToken.create<string>({ + name: 'popup-icon-error-label', cssCustomPropertyName: null -}).withDefault(coreLabelDefaults.errorIconLabel); +}).withDefault(coreLabelDefaults.popupIconErrorLabel); -export const warningIconLabel = DesignToken.create<string>({ - name: 'warning-icon-label', +export const popupIconWarningLabel = DesignToken.create<string>({ + name: 'popup-icon-warning-label', cssCustomPropertyName: null -}).withDefault(coreLabelDefaults.warningIconLabel); +}).withDefault(coreLabelDefaults.popupIconWarningLabel); -export const informationIconLabel = DesignToken.create<string>({ - name: 'information-icon-label', +export const popupIconInformationLabel = DesignToken.create<string>({ + name: 'popup-icon-information-label', cssCustomPropertyName: null -}).withDefault(coreLabelDefaults.informationIconLabel); +}).withDefault(coreLabelDefaults.popupIconInformationLabel); export const filterSearchLabel = DesignToken.create<string>({ name: 'filter-search-label', From 266ebfe2a96e98f1b2bf1663291c5798a7fb4f38 Mon Sep 17 00:00:00 2001 From: rajsite <rajsite@users.noreply.github.com> Date: Wed, 13 Mar 2024 23:07:24 +0000 Subject: [PATCH 04/12] applying package updates [skip ci] --- .../projects/ni/nimble-angular/CHANGELOG.json | 21 +++++++++++++++++++ .../projects/ni/nimble-angular/CHANGELOG.md | 11 +++++++++- .../projects/ni/nimble-angular/package.json | 4 ++-- ...-bb7e376e-ce72-4760-bb8d-f5775b8eefa8.json | 7 ------- ...-8b481f76-2252-49bf-8f00-07c884c3b2d4.json | 7 ------- ...-01c69e77-25e6-4f6e-a42c-0254916345eb.json | 7 ------- package-lock.json | 8 +++---- packages/nimble-blazor/CHANGELOG.json | 15 +++++++++++++ packages/nimble-blazor/CHANGELOG.md | 10 ++++++++- packages/nimble-blazor/package.json | 2 +- packages/nimble-components/CHANGELOG.json | 15 +++++++++++++ packages/nimble-components/CHANGELOG.md | 10 ++++++++- packages/nimble-components/package.json | 2 +- 13 files changed, 87 insertions(+), 32 deletions(-) delete mode 100644 change/@ni-nimble-angular-bb7e376e-ce72-4760-bb8d-f5775b8eefa8.json delete mode 100644 change/@ni-nimble-blazor-8b481f76-2252-49bf-8f00-07c884c3b2d4.json delete mode 100644 change/@ni-nimble-components-01c69e77-25e6-4f6e-a42c-0254916345eb.json diff --git a/angular-workspace/projects/ni/nimble-angular/CHANGELOG.json b/angular-workspace/projects/ni/nimble-angular/CHANGELOG.json index 7fb9104a39..a444ad2c29 100644 --- a/angular-workspace/projects/ni/nimble-angular/CHANGELOG.json +++ b/angular-workspace/projects/ni/nimble-angular/CHANGELOG.json @@ -1,6 +1,27 @@ { "name": "@ni/nimble-angular", "entries": [ + { + "date": "Wed, 13 Mar 2024 23:07:24 GMT", + "version": "20.4.0", + "tag": "@ni/nimble-angular_v20.4.0", + "comments": { + "minor": [ + { + "author": "jattasNI@users.noreply.github.com", + "package": "@ni/nimble-angular", + "commit": "518c229b964d2c4a2e77210692f5d367f2937ff4", + "comment": "Update default values in label provider directives and expose additional label provider properties" + }, + { + "author": "beachball", + "package": "@ni/nimble-angular", + "comment": "Bump @ni/nimble-components to v22.0.0", + "commit": "not available" + } + ] + } + }, { "date": "Tue, 12 Mar 2024 22:17:11 GMT", "version": "20.3.0", diff --git a/angular-workspace/projects/ni/nimble-angular/CHANGELOG.md b/angular-workspace/projects/ni/nimble-angular/CHANGELOG.md index 4d6d629248..f623091397 100644 --- a/angular-workspace/projects/ni/nimble-angular/CHANGELOG.md +++ b/angular-workspace/projects/ni/nimble-angular/CHANGELOG.md @@ -1,9 +1,18 @@ # Change Log - @ni/nimble-angular -This log was last generated on Tue, 12 Mar 2024 22:17:11 GMT and should not be manually modified. +This log was last generated on Wed, 13 Mar 2024 23:07:24 GMT and should not be manually modified. <!-- Start content --> +## 20.4.0 + +Wed, 13 Mar 2024 23:07:24 GMT + +### Minor changes + +- Update default values in label provider directives and expose additional label provider properties ([ni/nimble@518c229](https://github.com/ni/nimble/commit/518c229b964d2c4a2e77210692f5d367f2937ff4)) +- Bump @ni/nimble-components to v22.0.0 + ## 20.3.0 Tue, 12 Mar 2024 22:17:11 GMT diff --git a/angular-workspace/projects/ni/nimble-angular/package.json b/angular-workspace/projects/ni/nimble-angular/package.json index df7247214d..bb0872330f 100644 --- a/angular-workspace/projects/ni/nimble-angular/package.json +++ b/angular-workspace/projects/ni/nimble-angular/package.json @@ -1,6 +1,6 @@ { "name": "@ni/nimble-angular", - "version": "20.3.0", + "version": "20.4.0", "description": "Angular components for the NI Nimble Design System", "scripts": { "invoke-publish": "cd ../../../ && npm run build:library && cd dist/ni/nimble-angular && npm publish" @@ -31,7 +31,7 @@ "@angular/forms": "^15.2.10", "@angular/localize": "^15.2.10", "@angular/router": "^15.2.10", - "@ni/nimble-components": "^21.10.2" + "@ni/nimble-components": "^22.0.0" }, "dependencies": { "tslib": "^2.2.0" diff --git a/change/@ni-nimble-angular-bb7e376e-ce72-4760-bb8d-f5775b8eefa8.json b/change/@ni-nimble-angular-bb7e376e-ce72-4760-bb8d-f5775b8eefa8.json deleted file mode 100644 index bc88667bdc..0000000000 --- a/change/@ni-nimble-angular-bb7e376e-ce72-4760-bb8d-f5775b8eefa8.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "type": "minor", - "comment": "Update default values in label provider directives and expose additional label provider properties", - "packageName": "@ni/nimble-angular", - "email": "jattasNI@users.noreply.github.com", - "dependentChangeType": "patch" -} diff --git a/change/@ni-nimble-blazor-8b481f76-2252-49bf-8f00-07c884c3b2d4.json b/change/@ni-nimble-blazor-8b481f76-2252-49bf-8f00-07c884c3b2d4.json deleted file mode 100644 index b1163223b2..0000000000 --- a/change/@ni-nimble-blazor-8b481f76-2252-49bf-8f00-07c884c3b2d4.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "type": "minor", - "comment": "Expose additional label provider properties", - "packageName": "@ni/nimble-blazor", - "email": "jattasNI@users.noreply.github.com", - "dependentChangeType": "patch" -} diff --git a/change/@ni-nimble-components-01c69e77-25e6-4f6e-a42c-0254916345eb.json b/change/@ni-nimble-components-01c69e77-25e6-4f6e-a42c-0254916345eb.json deleted file mode 100644 index aeffcb7c25..0000000000 --- a/change/@ni-nimble-components-01c69e77-25e6-4f6e-a42c-0254916345eb.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "type": "major", - "comment": "Rename icon labels to follow naming convention", - "packageName": "@ni/nimble-components", - "email": "jattasNI@users.noreply.github.com", - "dependentChangeType": "patch" -} diff --git a/package-lock.json b/package-lock.json index 3b1259fd35..6136bfa6b9 100644 --- a/package-lock.json +++ b/package-lock.json @@ -74,7 +74,7 @@ }, "angular-workspace/projects/ni/nimble-angular": { "name": "@ni/nimble-angular", - "version": "20.3.0", + "version": "20.4.0", "license": "MIT", "dependencies": { "tslib": "^2.2.0" @@ -85,7 +85,7 @@ "@angular/forms": "^15.2.10", "@angular/localize": "^15.2.10", "@angular/router": "^15.2.10", - "@ni/nimble-components": "^21.10.2" + "@ni/nimble-components": "^22.0.0" } }, "node_modules/@11ty/dependency-tree": { @@ -33939,7 +33939,7 @@ }, "packages/nimble-blazor": { "name": "@ni/nimble-blazor", - "version": "14.3.20", + "version": "14.4.0", "hasInstallScript": true, "license": "MIT", "devDependencies": { @@ -33975,7 +33975,7 @@ }, "packages/nimble-components": { "name": "@ni/nimble-components", - "version": "21.10.2", + "version": "22.0.0", "license": "MIT", "dependencies": { "@microsoft/fast-colors": "^5.3.1", diff --git a/packages/nimble-blazor/CHANGELOG.json b/packages/nimble-blazor/CHANGELOG.json index 58bd153016..8beb296a92 100644 --- a/packages/nimble-blazor/CHANGELOG.json +++ b/packages/nimble-blazor/CHANGELOG.json @@ -1,6 +1,21 @@ { "name": "@ni/nimble-blazor", "entries": [ + { + "date": "Wed, 13 Mar 2024 23:07:24 GMT", + "version": "14.4.0", + "tag": "@ni/nimble-blazor_v14.4.0", + "comments": { + "minor": [ + { + "author": "jattasNI@users.noreply.github.com", + "package": "@ni/nimble-blazor", + "commit": "518c229b964d2c4a2e77210692f5d367f2937ff4", + "comment": "Expose additional label provider properties" + } + ] + } + }, { "date": "Wed, 06 Mar 2024 17:56:10 GMT", "version": "14.3.17", diff --git a/packages/nimble-blazor/CHANGELOG.md b/packages/nimble-blazor/CHANGELOG.md index 182cfce82c..fce7a6df3e 100644 --- a/packages/nimble-blazor/CHANGELOG.md +++ b/packages/nimble-blazor/CHANGELOG.md @@ -1,9 +1,17 @@ # Change Log - @ni/nimble-blazor -This log was last generated on Tue, 05 Mar 2024 21:15:27 GMT and should not be manually modified. +This log was last generated on Wed, 13 Mar 2024 23:07:24 GMT and should not be manually modified. <!-- Start content --> +## 14.4.0 + +Wed, 13 Mar 2024 23:07:24 GMT + +### Minor changes + +- Expose additional label provider properties ([ni/nimble@518c229](https://github.com/ni/nimble/commit/518c229b964d2c4a2e77210692f5d367f2937ff4)) + ## 14.3.15 Tue, 05 Mar 2024 21:15:27 GMT diff --git a/packages/nimble-blazor/package.json b/packages/nimble-blazor/package.json index d4b26db722..86961fc07c 100644 --- a/packages/nimble-blazor/package.json +++ b/packages/nimble-blazor/package.json @@ -1,6 +1,6 @@ { "name": "@ni/nimble-blazor", - "version": "14.3.20", + "version": "14.4.0", "description": "Blazor components for the NI Nimble Design System", "scripts": { "postinstall": "node build/generate-playwright-version-properties/source/index.js", diff --git a/packages/nimble-components/CHANGELOG.json b/packages/nimble-components/CHANGELOG.json index 2a6f2751f7..7a2044897a 100644 --- a/packages/nimble-components/CHANGELOG.json +++ b/packages/nimble-components/CHANGELOG.json @@ -1,6 +1,21 @@ { "name": "@ni/nimble-components", "entries": [ + { + "date": "Wed, 13 Mar 2024 23:07:24 GMT", + "version": "22.0.0", + "tag": "@ni/nimble-components_v22.0.0", + "comments": { + "major": [ + { + "author": "jattasNI@users.noreply.github.com", + "package": "@ni/nimble-components", + "commit": "518c229b964d2c4a2e77210692f5d367f2937ff4", + "comment": "Rename icon labels to follow naming convention" + } + ] + } + }, { "date": "Wed, 13 Mar 2024 22:25:27 GMT", "version": "21.10.2", diff --git a/packages/nimble-components/CHANGELOG.md b/packages/nimble-components/CHANGELOG.md index a490334098..903568804d 100644 --- a/packages/nimble-components/CHANGELOG.md +++ b/packages/nimble-components/CHANGELOG.md @@ -1,9 +1,17 @@ # Change Log - @ni/nimble-components -This log was last generated on Tue, 12 Mar 2024 22:17:11 GMT and should not be manually modified. +This log was last generated on Wed, 13 Mar 2024 23:07:24 GMT and should not be manually modified. <!-- Start content --> +## 22.0.0 + +Wed, 13 Mar 2024 23:07:24 GMT + +### Major changes + +- Rename icon labels to follow naming convention ([ni/nimble@518c229](https://github.com/ni/nimble/commit/518c229b964d2c4a2e77210692f5d367f2937ff4)) + ## 21.10.2 Tue, 12 Mar 2024 22:17:11 GMT diff --git a/packages/nimble-components/package.json b/packages/nimble-components/package.json index 1fb3d19ebf..3728089982 100644 --- a/packages/nimble-components/package.json +++ b/packages/nimble-components/package.json @@ -1,6 +1,6 @@ { "name": "@ni/nimble-components", - "version": "21.10.2", + "version": "22.0.0", "description": "Styled web components for the NI Nimble Design System", "scripts": { "build": "npm run generate-icons && npm run generate-workers && npm run build-components && npm run bundle-components && npm run generate-scss && npm run build-storybook", From 2a9abefcd6160716070fd4f3bbca097919112d23 Mon Sep 17 00:00:00 2001 From: Milan Raj <rajsite@users.noreply.github.com> Date: Wed, 13 Mar 2024 18:38:57 -0500 Subject: [PATCH 05/12] Clean-up build warnings (#1932) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit # Pull Request ## ๐Ÿคจ Rationale - The apache-arrow dependency added new Circular dependency warnings - The performance package now reported vite build warnings ## ๐Ÿ‘ฉโ€๐Ÿ’ป Implementation - Suppressed the apache-arrow build warning and reported an issue to see what they think: https://github.com/apache/arrow/issues/40516 - Converted the performance package to `"type": "module"` to handle the deprecation warning: https://vitejs.dev/guide/troubleshooting.html#vite-cjs-node-api-deprecated ## ๐Ÿงช Testing rely on CI ## โœ… Checklist - [x] I have updated the project documentation to reflect my changes or determined no changes are needed. --- ...nents-5e1223df-9cdc-4024-ae9a-fa84d9e9649e.json | 7 +++++++ packages/nimble-components/rollup.config.js | 14 +++++++++----- .../performance/{.eslintrc.js => .eslintrc.cjs} | 6 ++++++ .../{lighthouserc.js => lighthouserc.cjs} | 0 packages/performance/package.json | 1 + packages/performance/src/vite.config.js | 1 - 6 files changed, 23 insertions(+), 6 deletions(-) create mode 100644 change/@ni-nimble-components-5e1223df-9cdc-4024-ae9a-fa84d9e9649e.json rename packages/performance/{.eslintrc.js => .eslintrc.cjs} (75%) rename packages/performance/{lighthouserc.js => lighthouserc.cjs} (100%) diff --git a/change/@ni-nimble-components-5e1223df-9cdc-4024-ae9a-fa84d9e9649e.json b/change/@ni-nimble-components-5e1223df-9cdc-4024-ae9a-fa84d9e9649e.json new file mode 100644 index 0000000000..49f25ca891 --- /dev/null +++ b/change/@ni-nimble-components-5e1223df-9cdc-4024-ae9a-fa84d9e9649e.json @@ -0,0 +1,7 @@ +{ + "type": "none", + "comment": "Build warnings for apache-arrow were cleaned up", + "packageName": "@ni/nimble-components", + "email": "rajsite@users.noreply.github.com", + "dependentChangeType": "none" +} diff --git a/packages/nimble-components/rollup.config.js b/packages/nimble-components/rollup.config.js index 787b48dd43..3c594bea3a 100644 --- a/packages/nimble-components/rollup.config.js +++ b/packages/nimble-components/rollup.config.js @@ -16,17 +16,21 @@ const umdProductionPlugin = () => replace({ preventAssignment: true }); -// d3 has circular dependencies it won't remove: -// https://github.com/d3/d3-selection/issues/168 -// So ignore just d3's circular dependencies following the pattern from: -// https://github.com/rollup/rollup/issues/1089#issuecomment-635564942 -// Updated to use current onwarn api: +// Custom onwarn handler for ignoring specific warnings: // https://rollupjs.org/configuration-options/#onwarn const onwarn = (warning, defaultHandler) => { const ignoredWarnings = [ + // d3 has circular dependencies it won't remove: + // See https://github.com/d3/d3-selection/issues/168 { code: 'CIRCULAR_DEPENDENCY', file: 'node_modules/d3-' + }, + // apache-arrow has circular dependencies: + // See https://github.com/apache/arrow/issues/40516 + { + code: 'CIRCULAR_DEPENDENCY', + file: 'node_modules/apache-arrow' } ]; diff --git a/packages/performance/.eslintrc.js b/packages/performance/.eslintrc.cjs similarity index 75% rename from packages/performance/.eslintrc.js rename to packages/performance/.eslintrc.cjs index 3e1be2eb59..f7f5374ae5 100644 --- a/packages/performance/.eslintrc.js +++ b/packages/performance/.eslintrc.cjs @@ -27,5 +27,11 @@ module.exports = { // Rules enabled due to strictNullChecks '@typescript-eslint/no-non-null-assertion': 'off', } + }, { + files: ['vite.config.js'], + rules: { + // Configuration scripts will not be in published package and are allowed to use devDependencies + 'import/no-extraneous-dependencies': ['error', { devDependencies: true }], + } }] }; diff --git a/packages/performance/lighthouserc.js b/packages/performance/lighthouserc.cjs similarity index 100% rename from packages/performance/lighthouserc.js rename to packages/performance/lighthouserc.cjs diff --git a/packages/performance/package.json b/packages/performance/package.json index b8041f3be2..a2b5b6af64 100644 --- a/packages/performance/package.json +++ b/packages/performance/package.json @@ -2,6 +2,7 @@ "name": "@ni-private/performance", "version": "1.0.0", "private": true, + "type": "module", "description": "A package to measure the performance of the Nimble Components", "scripts": { "build": "tsc && vite build src", diff --git a/packages/performance/src/vite.config.js b/packages/performance/src/vite.config.js index 2a8b74e794..8f5bec56a9 100644 --- a/packages/performance/src/vite.config.js +++ b/packages/performance/src/vite.config.js @@ -1,4 +1,3 @@ -// eslint-disable-next-line import/no-extraneous-dependencies import { defineConfig } from 'vite'; import { resolve } from 'path'; From ae965661ce231a7d8d136d911fa141e8c1143d8f Mon Sep 17 00:00:00 2001 From: rajsite <rajsite@users.noreply.github.com> Date: Wed, 13 Mar 2024 23:56:16 +0000 Subject: [PATCH 06/12] applying package updates [skip ci] --- ...ents-5e1223df-9cdc-4024-ae9a-fa84d9e9649e.json | 7 ------- packages/nimble-components/CHANGELOG.json | 15 +++++++++++++++ 2 files changed, 15 insertions(+), 7 deletions(-) delete mode 100644 change/@ni-nimble-components-5e1223df-9cdc-4024-ae9a-fa84d9e9649e.json diff --git a/change/@ni-nimble-components-5e1223df-9cdc-4024-ae9a-fa84d9e9649e.json b/change/@ni-nimble-components-5e1223df-9cdc-4024-ae9a-fa84d9e9649e.json deleted file mode 100644 index 49f25ca891..0000000000 --- a/change/@ni-nimble-components-5e1223df-9cdc-4024-ae9a-fa84d9e9649e.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "type": "none", - "comment": "Build warnings for apache-arrow were cleaned up", - "packageName": "@ni/nimble-components", - "email": "rajsite@users.noreply.github.com", - "dependentChangeType": "none" -} diff --git a/packages/nimble-components/CHANGELOG.json b/packages/nimble-components/CHANGELOG.json index 7a2044897a..f5a5f0bd2e 100644 --- a/packages/nimble-components/CHANGELOG.json +++ b/packages/nimble-components/CHANGELOG.json @@ -1,6 +1,21 @@ { "name": "@ni/nimble-components", "entries": [ + { + "date": "Wed, 13 Mar 2024 23:56:16 GMT", + "version": "22.0.0", + "tag": "@ni/nimble-components_v22.0.0", + "comments": { + "none": [ + { + "author": "rajsite@users.noreply.github.com", + "package": "@ni/nimble-components", + "commit": "2a9abefcd6160716070fd4f3bbca097919112d23", + "comment": "Build warnings for apache-arrow were cleaned up" + } + ] + } + }, { "date": "Wed, 13 Mar 2024 23:07:24 GMT", "version": "22.0.0", From a1eebb02b4fb66ca77e0e32bb52497b2da1cb4cf Mon Sep 17 00:00:00 2001 From: mollykreis <20542556+mollykreis@users.noreply.github.com> Date: Thu, 14 Mar 2024 09:30:24 -0500 Subject: [PATCH 07/12] Fix anchor drag (#1910) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit # Pull Request ## ๐Ÿคจ Rationale Fixes #1406 ## ๐Ÿ‘ฉโ€๐Ÿ’ป Implementation The issue with the anchor items is that the slotted content was blocking the pointer events (i.e. the drag attempt) and keeping the link from being dragged. By styling the children of the native anchor elements with `pointer-events: none;`, this is prevented and the link can be dragged from all parts of the component. ## ๐Ÿงช Testing Manually tested each changed component that the link can now be dragged by the slotted content, including any start/end slot icons. ## โœ… Checklist <!--- Review the list and put an x in the boxes that apply or ~~strike through~~ around items that don't (along with an explanation). --> - [ ] I have updated the project documentation to reflect my changes or determined no changes are needed. --- ...ponents-450fdd90-7444-494f-8c1f-8e7aba8c7804.json | 7 +++++++ .../nimble-components/src/anchor-button/styles.ts | 12 ++++++++++++ .../nimble-components/src/anchor-menu-item/styles.ts | 5 +++++ packages/nimble-components/src/anchor-tab/styles.ts | 1 + .../nimble-components/src/anchor-tree-item/styles.ts | 5 +++++ packages/nimble-components/src/anchor/styles.ts | 4 ++++ .../nimble-components/src/breadcrumb-item/styles.ts | 4 ++++ 7 files changed, 38 insertions(+) create mode 100644 change/@ni-nimble-components-450fdd90-7444-494f-8c1f-8e7aba8c7804.json diff --git a/change/@ni-nimble-components-450fdd90-7444-494f-8c1f-8e7aba8c7804.json b/change/@ni-nimble-components-450fdd90-7444-494f-8c1f-8e7aba8c7804.json new file mode 100644 index 0000000000..2be5a7deb6 --- /dev/null +++ b/change/@ni-nimble-components-450fdd90-7444-494f-8c1f-8e7aba8c7804.json @@ -0,0 +1,7 @@ +{ + "type": "patch", + "comment": "Fix bug where an anchor element's link couldn't be dragged correctly", + "packageName": "@ni/nimble-components", + "email": "20542556+mollykreis@users.noreply.github.com", + "dependentChangeType": "patch" +} diff --git a/packages/nimble-components/src/anchor-button/styles.ts b/packages/nimble-components/src/anchor-button/styles.ts index f57265ea8d..1393bd4360 100644 --- a/packages/nimble-components/src/anchor-button/styles.ts +++ b/packages/nimble-components/src/anchor-button/styles.ts @@ -11,4 +11,16 @@ export const styles = css` .control { text-decoration: none; } + + [part='start'] { + pointer-events: none; + } + + .content { + pointer-events: none; + } + + [part='end'] { + pointer-events: none; + } `; diff --git a/packages/nimble-components/src/anchor-menu-item/styles.ts b/packages/nimble-components/src/anchor-menu-item/styles.ts index d108f5dad6..fb5e5d8fe2 100644 --- a/packages/nimble-components/src/anchor-menu-item/styles.ts +++ b/packages/nimble-components/src/anchor-menu-item/styles.ts @@ -69,6 +69,7 @@ export const styles = css` [part='start'] { display: contents; + pointer-events: none; } slot[name='start']::slotted(*) { @@ -81,6 +82,10 @@ export const styles = css` grid-column: 1; } + .content { + pointer-events: none; + } + :host(.indent-1) .content { grid-column: 2; } diff --git a/packages/nimble-components/src/anchor-tab/styles.ts b/packages/nimble-components/src/anchor-tab/styles.ts index 467ce518dc..979e65b672 100644 --- a/packages/nimble-components/src/anchor-tab/styles.ts +++ b/packages/nimble-components/src/anchor-tab/styles.ts @@ -52,6 +52,7 @@ export const styles = css` } slot:not([name]) { + pointer-events: none; display: block; padding: ${mediumPadding} ${standardPadding} calc(${mediumPadding} - ${borderWidth}); diff --git a/packages/nimble-components/src/anchor-tree-item/styles.ts b/packages/nimble-components/src/anchor-tree-item/styles.ts index bf91df7fcc..f1b66ff96c 100644 --- a/packages/nimble-components/src/anchor-tree-item/styles.ts +++ b/packages/nimble-components/src/anchor-tree-item/styles.ts @@ -100,6 +100,7 @@ export const styles = css` } [part="start"] { width: ${iconSize}; + pointer-events: none; } ${/* the start class is applied when the corresponding slot is filled */ ''} @@ -115,6 +116,10 @@ export const styles = css` height: ${iconSize}; } + .content { + pointer-events: none; + } + [part='end'] { display: none; } diff --git a/packages/nimble-components/src/anchor/styles.ts b/packages/nimble-components/src/anchor/styles.ts index 9d1f1a9c0e..3e5ed018a9 100644 --- a/packages/nimble-components/src/anchor/styles.ts +++ b/packages/nimble-components/src/anchor/styles.ts @@ -93,6 +93,10 @@ export const styles = css` color: ${linkProminentDisabledFontColor}; } + .content { + pointer-events: none; + } + [part='end'] { display: none; } diff --git a/packages/nimble-components/src/breadcrumb-item/styles.ts b/packages/nimble-components/src/breadcrumb-item/styles.ts index f65b78859d..091265edf3 100644 --- a/packages/nimble-components/src/breadcrumb-item/styles.ts +++ b/packages/nimble-components/src/breadcrumb-item/styles.ts @@ -61,6 +61,10 @@ export const styles = css` display: none; } + .content { + pointer-events: none; + } + [part='end'] { display: none; } From aeaa29b6db90372e2c2adf3f88275b758f1e0771 Mon Sep 17 00:00:00 2001 From: rajsite <rajsite@users.noreply.github.com> Date: Thu, 14 Mar 2024 14:48:16 +0000 Subject: [PATCH 08/12] applying package updates [skip ci] --- .../projects/ni/nimble-angular/CHANGELOG.json | 15 +++++++++++++++ .../projects/ni/nimble-angular/CHANGELOG.md | 10 +++++++++- .../projects/ni/nimble-angular/package.json | 4 ++-- ...ents-450fdd90-7444-494f-8c1f-8e7aba8c7804.json | 7 ------- package-lock.json | 8 ++++---- packages/nimble-blazor/package.json | 2 +- packages/nimble-components/CHANGELOG.json | 15 +++++++++++++++ packages/nimble-components/CHANGELOG.md | 10 +++++++++- packages/nimble-components/package.json | 2 +- 9 files changed, 56 insertions(+), 17 deletions(-) delete mode 100644 change/@ni-nimble-components-450fdd90-7444-494f-8c1f-8e7aba8c7804.json diff --git a/angular-workspace/projects/ni/nimble-angular/CHANGELOG.json b/angular-workspace/projects/ni/nimble-angular/CHANGELOG.json index a444ad2c29..fc72ae7a4e 100644 --- a/angular-workspace/projects/ni/nimble-angular/CHANGELOG.json +++ b/angular-workspace/projects/ni/nimble-angular/CHANGELOG.json @@ -1,6 +1,21 @@ { "name": "@ni/nimble-angular", "entries": [ + { + "date": "Thu, 14 Mar 2024 14:48:16 GMT", + "version": "20.4.1", + "tag": "@ni/nimble-angular_v20.4.1", + "comments": { + "patch": [ + { + "author": "beachball", + "package": "@ni/nimble-angular", + "comment": "Bump @ni/nimble-components to v22.0.1", + "commit": "not available" + } + ] + } + }, { "date": "Wed, 13 Mar 2024 23:07:24 GMT", "version": "20.4.0", diff --git a/angular-workspace/projects/ni/nimble-angular/CHANGELOG.md b/angular-workspace/projects/ni/nimble-angular/CHANGELOG.md index f623091397..4668075987 100644 --- a/angular-workspace/projects/ni/nimble-angular/CHANGELOG.md +++ b/angular-workspace/projects/ni/nimble-angular/CHANGELOG.md @@ -1,9 +1,17 @@ # Change Log - @ni/nimble-angular -This log was last generated on Wed, 13 Mar 2024 23:07:24 GMT and should not be manually modified. +This log was last generated on Thu, 14 Mar 2024 14:48:16 GMT and should not be manually modified. <!-- Start content --> +## 20.4.1 + +Thu, 14 Mar 2024 14:48:16 GMT + +### Patches + +- Bump @ni/nimble-components to v22.0.1 + ## 20.4.0 Wed, 13 Mar 2024 23:07:24 GMT diff --git a/angular-workspace/projects/ni/nimble-angular/package.json b/angular-workspace/projects/ni/nimble-angular/package.json index bb0872330f..27fb5bfdf7 100644 --- a/angular-workspace/projects/ni/nimble-angular/package.json +++ b/angular-workspace/projects/ni/nimble-angular/package.json @@ -1,6 +1,6 @@ { "name": "@ni/nimble-angular", - "version": "20.4.0", + "version": "20.4.1", "description": "Angular components for the NI Nimble Design System", "scripts": { "invoke-publish": "cd ../../../ && npm run build:library && cd dist/ni/nimble-angular && npm publish" @@ -31,7 +31,7 @@ "@angular/forms": "^15.2.10", "@angular/localize": "^15.2.10", "@angular/router": "^15.2.10", - "@ni/nimble-components": "^22.0.0" + "@ni/nimble-components": "^22.0.1" }, "dependencies": { "tslib": "^2.2.0" diff --git a/change/@ni-nimble-components-450fdd90-7444-494f-8c1f-8e7aba8c7804.json b/change/@ni-nimble-components-450fdd90-7444-494f-8c1f-8e7aba8c7804.json deleted file mode 100644 index 2be5a7deb6..0000000000 --- a/change/@ni-nimble-components-450fdd90-7444-494f-8c1f-8e7aba8c7804.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "type": "patch", - "comment": "Fix bug where an anchor element's link couldn't be dragged correctly", - "packageName": "@ni/nimble-components", - "email": "20542556+mollykreis@users.noreply.github.com", - "dependentChangeType": "patch" -} diff --git a/package-lock.json b/package-lock.json index 6136bfa6b9..61914ea73d 100644 --- a/package-lock.json +++ b/package-lock.json @@ -74,7 +74,7 @@ }, "angular-workspace/projects/ni/nimble-angular": { "name": "@ni/nimble-angular", - "version": "20.4.0", + "version": "20.4.1", "license": "MIT", "dependencies": { "tslib": "^2.2.0" @@ -85,7 +85,7 @@ "@angular/forms": "^15.2.10", "@angular/localize": "^15.2.10", "@angular/router": "^15.2.10", - "@ni/nimble-components": "^22.0.0" + "@ni/nimble-components": "^22.0.1" } }, "node_modules/@11ty/dependency-tree": { @@ -33939,7 +33939,7 @@ }, "packages/nimble-blazor": { "name": "@ni/nimble-blazor", - "version": "14.4.0", + "version": "14.4.1", "hasInstallScript": true, "license": "MIT", "devDependencies": { @@ -33975,7 +33975,7 @@ }, "packages/nimble-components": { "name": "@ni/nimble-components", - "version": "22.0.0", + "version": "22.0.1", "license": "MIT", "dependencies": { "@microsoft/fast-colors": "^5.3.1", diff --git a/packages/nimble-blazor/package.json b/packages/nimble-blazor/package.json index 86961fc07c..20397b86da 100644 --- a/packages/nimble-blazor/package.json +++ b/packages/nimble-blazor/package.json @@ -1,6 +1,6 @@ { "name": "@ni/nimble-blazor", - "version": "14.4.0", + "version": "14.4.1", "description": "Blazor components for the NI Nimble Design System", "scripts": { "postinstall": "node build/generate-playwright-version-properties/source/index.js", diff --git a/packages/nimble-components/CHANGELOG.json b/packages/nimble-components/CHANGELOG.json index f5a5f0bd2e..81794ef2c8 100644 --- a/packages/nimble-components/CHANGELOG.json +++ b/packages/nimble-components/CHANGELOG.json @@ -1,6 +1,21 @@ { "name": "@ni/nimble-components", "entries": [ + { + "date": "Thu, 14 Mar 2024 14:48:16 GMT", + "version": "22.0.1", + "tag": "@ni/nimble-components_v22.0.1", + "comments": { + "patch": [ + { + "author": "20542556+mollykreis@users.noreply.github.com", + "package": "@ni/nimble-components", + "commit": "a1eebb02b4fb66ca77e0e32bb52497b2da1cb4cf", + "comment": "Fix bug where an anchor element's link couldn't be dragged correctly" + } + ] + } + }, { "date": "Wed, 13 Mar 2024 23:56:16 GMT", "version": "22.0.0", diff --git a/packages/nimble-components/CHANGELOG.md b/packages/nimble-components/CHANGELOG.md index 903568804d..2664591847 100644 --- a/packages/nimble-components/CHANGELOG.md +++ b/packages/nimble-components/CHANGELOG.md @@ -1,9 +1,17 @@ # Change Log - @ni/nimble-components -This log was last generated on Wed, 13 Mar 2024 23:07:24 GMT and should not be manually modified. +This log was last generated on Thu, 14 Mar 2024 14:48:16 GMT and should not be manually modified. <!-- Start content --> +## 22.0.1 + +Thu, 14 Mar 2024 14:48:16 GMT + +### Patches + +- Fix bug where an anchor element's link couldn't be dragged correctly ([ni/nimble@a1eebb0](https://github.com/ni/nimble/commit/a1eebb02b4fb66ca77e0e32bb52497b2da1cb4cf)) + ## 22.0.0 Wed, 13 Mar 2024 23:07:24 GMT diff --git a/packages/nimble-components/package.json b/packages/nimble-components/package.json index 3728089982..20bf058f61 100644 --- a/packages/nimble-components/package.json +++ b/packages/nimble-components/package.json @@ -1,6 +1,6 @@ { "name": "@ni/nimble-components", - "version": "22.0.0", + "version": "22.0.1", "description": "Styled web components for the NI Nimble Design System", "scripts": { "build": "npm run generate-icons && npm run generate-workers && npm run build-components && npm run bundle-components && npm run generate-scss && npm run build-storybook", From a112528ec429c96f2017e95bbbdb22e578be1c08 Mon Sep 17 00:00:00 2001 From: Jesse Attas <jattasNI@users.noreply.github.com> Date: Mon, 18 Mar 2024 11:18:06 -0500 Subject: [PATCH 09/12] Disable and tag tests failing in specific browsers (#1941) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit # Pull Request ## ๐Ÿคจ Rationale One of the tasks in #1747 is to run nimble-components tests in WebKit and see if there are any new failures. There are several. We also wanted to start tracking specific issues for each root cause rather than catch all issues like #1074 and #1075. ## ๐Ÿ‘ฉโ€๐Ÿ’ป Implementation Marked each failing test with one of these specific issues: - #1936 - #1938 TODO: ALSO FILE AZDO BUG - #1939 - #1940 - #1942 - #1943 Also re-enabled a couple of table header tests in Firefox which are now passing. ## ๐Ÿงช Testing Ran tests in Playwright webkit browser, Firefox, and Safari and and all the enabled tests now pass. ## โœ… Checklist <!--- Review the list and put an x in the boxes that apply or ~~strike through~~ around items that don't (along with an explanation). --> - [x] I have updated the project documentation to reflect my changes or determined no changes are needed. --------- Co-authored-by: Milan Raj <rajsite@users.noreply.github.com> --- ...-1e68ef0e-2e70-4f32-86a4-e9073c251a0e.json | 7 +++ .../src/dialog/tests/dialog.spec.ts | 12 ++--- .../src/drawer/tests/drawer.spec.ts | 14 ++--- .../tests/rich-text-editor-mention.spec.ts | 12 +++-- .../editor/tests/rich-text-editor.spec.ts | 53 ++++++++++++------- .../models/tests/markdown-serializer.spec.ts | 18 ++++--- .../tests/table-column-date-text.spec.ts | 18 ++++--- .../header/tests/table-header.spec.ts | 6 +-- .../table/tests/table-column-sizing.spec.ts | 3 +- .../src/table/tests/table.spec.ts | 3 +- 10 files changed, 92 insertions(+), 54 deletions(-) create mode 100644 change/@ni-nimble-components-1e68ef0e-2e70-4f32-86a4-e9073c251a0e.json diff --git a/change/@ni-nimble-components-1e68ef0e-2e70-4f32-86a4-e9073c251a0e.json b/change/@ni-nimble-components-1e68ef0e-2e70-4f32-86a4-e9073c251a0e.json new file mode 100644 index 0000000000..a9f32d1b2e --- /dev/null +++ b/change/@ni-nimble-components-1e68ef0e-2e70-4f32-86a4-e9073c251a0e.json @@ -0,0 +1,7 @@ +{ + "type": "none", + "comment": "Marking tests that fail on some browsers", + "packageName": "@ni/nimble-components", + "email": "jattasNI@users.noreply.github.com", + "dependentChangeType": "none" +} diff --git a/packages/nimble-components/src/dialog/tests/dialog.spec.ts b/packages/nimble-components/src/dialog/tests/dialog.spec.ts index 1dc9f0f293..89a81e6cdc 100644 --- a/packages/nimble-components/src/dialog/tests/dialog.spec.ts +++ b/packages/nimble-components/src/dialog/tests/dialog.spec.ts @@ -272,8 +272,8 @@ describe('Dialog', () => { await disconnect(); }); - // Firefox skipped, see: https://github.com/ni/nimble/issues/1075 - it('focuses the first button on the dialog when it opens #SkipFirefox', async () => { + // Some browsers skipped, see: https://github.com/ni/nimble/issues/1936 + it('focuses the first button on the dialog when it opens #SkipFirefox #SkipWebkit', async () => { const { element, connect, disconnect } = await setup(); await connect(); const okButton = document.getElementById('ok')!; @@ -285,8 +285,8 @@ describe('Dialog', () => { await disconnect(); }); - // Firefox skipped, see: https://github.com/ni/nimble/issues/1075 - it('focuses the button with autofocus when the dialog opens #SkipFirefox', async () => { + // Some browsers skipped, see: https://github.com/ni/nimble/issues/1936 + it('focuses the button with autofocus when the dialog opens #SkipFirefox #SkipWebkit', async () => { const { element, connect, disconnect } = await setup(); await connect(); const cancelButton = document.getElementById('cancel')!; @@ -300,8 +300,8 @@ describe('Dialog', () => { await disconnect(); }); - // Firefox skipped, see: https://github.com/ni/nimble/issues/1075 - it('supports opening multiple dialogs on top of each other #SkipFirefox', async () => { + // Some browsers skipped, see: https://github.com/ni/nimble/issues/1943 + it('supports opening multiple dialogs on top of each other #SkipFirefox #SkipWebkit', async () => { const { element, connect, disconnect } = await setup(); await connect(); const secondDialog = document.createElement('nimble-dialog'); diff --git a/packages/nimble-components/src/drawer/tests/drawer.spec.ts b/packages/nimble-components/src/drawer/tests/drawer.spec.ts index 99a99ff98f..eefa3b0f52 100644 --- a/packages/nimble-components/src/drawer/tests/drawer.spec.ts +++ b/packages/nimble-components/src/drawer/tests/drawer.spec.ts @@ -133,7 +133,7 @@ describe('Drawer', () => { await expectAsync(promise).toBePending(); }); - // Firefox skipped, see: https://github.com/ni/nimble/issues/1075 + // Firefox skipped, see: https://github.com/ni/nimble/issues/1937 it('should resolve promise if drawer completely opens before being closed #SkipFirefox', async () => { const promise = element.show(); await completeAnimationAsync(element); @@ -235,15 +235,15 @@ describe('Drawer', () => { expect(afterDrawerCloseActiveElement).toBe(button2); }); - // Firefox skipped, see: https://github.com/ni/nimble/issues/1075 - it('focuses the first button on the drawer when it opens #SkipFirefox', () => { + // Some browsers skipped, see: https://github.com/ni/nimble/issues/1936 + it('focuses the first button on the drawer when it opens #SkipFirefox #SkipWebkit', () => { const okButton = document.getElementById('ok')!; void element.show(); expect(document.activeElement).toBe(okButton); }); - // Firefox skipped, see: https://github.com/ni/nimble/issues/1075 - it('focuses the button with autofocus when the drawer opens #SkipFirefox', () => { + // Some browsers skipped, see: https://github.com/ni/nimble/issues/1936 + it('focuses the button with autofocus when the drawer opens #SkipFirefox #SkipWebkit', () => { const cancelButton = document.getElementById('cancel')!; cancelButton.setAttribute('autofocus', ''); processUpdates(); @@ -251,8 +251,8 @@ describe('Drawer', () => { expect(document.activeElement).toBe(cancelButton); }); - // Firefox skipped, see: https://github.com/ni/nimble/issues/1075 - it('supports opening multiple drawers on top of each other #SkipFirefox', () => { + // Some browsers skipped, see: https://github.com/ni/nimble/issues/1943 + it('supports opening multiple drawers on top of each other #SkipFirefox #SkipWebkit', () => { const secondDrawer = document.createElement('nimble-drawer'); const secondDrawerButton = document.createElement('nimble-button'); secondDrawer.append(secondDrawerButton); diff --git a/packages/nimble-components/src/rich-text/editor/tests/rich-text-editor-mention.spec.ts b/packages/nimble-components/src/rich-text/editor/tests/rich-text-editor-mention.spec.ts index f149d9bae7..40839a1bd4 100644 --- a/packages/nimble-components/src/rich-text/editor/tests/rich-text-editor-mention.spec.ts +++ b/packages/nimble-components/src/rich-text/editor/tests/rich-text-editor-mention.spec.ts @@ -353,7 +353,8 @@ describe('RichTextEditorMention', () => { expect(pageObject.getMentionButtonLabel(0)).toBe(''); }); - it('should have button title and text when `button-label` updated', async () => { + // WebKit skipped, see https://github.com/ni/nimble/issues/1938 + it('should have button title and text when `button-label` updated #SkipWebkit', async () => { const { userMentionElement } = await appendUserMentionConfiguration(element); userMentionElement.buttonLabel = 'at mention'; await waitForUpdatesAsync(); @@ -1032,7 +1033,8 @@ describe('RichTextEditor user mention via template', () => { expect(pageObject.getEditorFirstChildTextContent()).toBe('User @'); }); - it('should get `@` text without a preceding whitespace after a hard break, when button clicked', async () => { + // WebKit skipped, see https://github.com/ni/nimble/issues/1938 + it('should get `@` text without a preceding whitespace after a hard break, when button clicked #SkipWebkit', async () => { await pageObject.setEditorTextContent('User'); await pageObject.pressShiftEnterKeysInEditor(); await pageObject.clickUserMentionButton(); @@ -1045,7 +1047,8 @@ describe('RichTextEditor user mention via template', () => { expect(pageObject.getEditorFirstChildTextContent()).toBe('User@'); }); - it('should get `@` text with a single preceding whitespace after a hard break with a text, when button clicked', async () => { + // WebKit skipped, see https://github.com/ni/nimble/issues/1938 + it('should get `@` text with a single preceding whitespace after a hard break with a text, when button clicked #SkipWebkit', async () => { await pageObject.setEditorTextContent('User'); await pageObject.pressShiftEnterKeysInEditor(); await pageObject.setEditorTextContent('Text'); @@ -1354,7 +1357,8 @@ describe('RichTextEditorMentionListbox', () => { expect(pageObject.isMentionListboxOpened()).toBeFalse(); }); - it('setting `disabled` should close the mention popup', async () => { + // WebKit skipped, see https://github.com/ni/nimble/issues/1938 + it('setting `disabled` should close the mention popup #SkipWebkit', async () => { await appendUserMentionConfiguration(element, [ { key: 'user:1', displayName: 'username1' }, { key: 'user:2', displayName: 'username2' } diff --git a/packages/nimble-components/src/rich-text/editor/tests/rich-text-editor.spec.ts b/packages/nimble-components/src/rich-text/editor/tests/rich-text-editor.spec.ts index 2aebf54f11..a7bccd0633 100644 --- a/packages/nimble-components/src/rich-text/editor/tests/rich-text-editor.spec.ts +++ b/packages/nimble-components/src/rich-text/editor/tests/rich-text-editor.spec.ts @@ -215,20 +215,28 @@ describe('RichTextEditor', () => { describe('keyboard shortcuts should update the checked state of the buttons', () => { parameterizeSpec(formattingButtons, (spec, name, value) => { - spec(`"${name}" button keyboard shortcut check`, async () => { - expect( - pageObject.getButtonCheckedState(value.toolbarButtonIndex) - ).toBeFalse(); + spec( + // WebKit skipped, see https://github.com/ni/nimble/issues/1938 + `"${name}" button keyboard shortcut check #SkipWebkit`, + async () => { + expect( + pageObject.getButtonCheckedState( + value.toolbarButtonIndex + ) + ).toBeFalse(); - await pageObject.clickEditorShortcutKeys( - value.shortcutKey, - value.shiftKey - ); + await pageObject.clickEditorShortcutKeys( + value.shortcutKey, + value.shiftKey + ); - expect( - pageObject.getButtonCheckedState(value.toolbarButtonIndex) - ).toBeTrue(); - }); + expect( + pageObject.getButtonCheckedState( + value.toolbarButtonIndex + ) + ).toBeTrue(); + } + ); }); }); @@ -255,7 +263,8 @@ describe('RichTextEditor', () => { }); describe('rich text formatting options to its respective HTML elements', () => { - it('should have "br" tag name when clicking shift + enter', async () => { + // WebKit skipped, see https://github.com/ni/nimble/issues/1938 + it('should have br tag name when pressing shift + enter #SkipWebkit', async () => { await pageObject.setEditorTextContent('Plain text 1'); await pageObject.pressShiftEnterKeysInEditor(); await pageObject.setEditorTextContent('Plain text 2'); @@ -272,7 +281,8 @@ describe('RichTextEditor', () => { expect(pageObject.getEditorLeafContents()).toEqual(['bold']); }); - it('should have br tag name when pressing shift + Enter with bold content', async () => { + // WebKit skipped, see https://github.com/ni/nimble/issues/1938 + it('should have br tag name when pressing shift + Enter with bold content #SkipWebkit', async () => { await pageObject.toggleFooterButton(ToolbarButton.bold); await pageObject.setEditorTextContent('bold1'); await pageObject.pressShiftEnterKeysInEditor(); @@ -294,7 +304,8 @@ describe('RichTextEditor', () => { expect(pageObject.getEditorLeafContents()).toEqual(['italics']); }); - it('should have br tag name when pressing shift + Enter with Italics content', async () => { + // WebKit skipped, see https://github.com/ni/nimble/issues/1938 + it('should have br tag name when pressing shift + Enter with Italics content #SkipWebkit', async () => { await pageObject.toggleFooterButton(ToolbarButton.italics); await pageObject.setEditorTextContent('italics1'); await pageObject.pressShiftEnterKeysInEditor(); @@ -437,7 +448,8 @@ describe('RichTextEditor', () => { }); }); - it('should have br tag name when pressing shift + Enter with numbered list content', async () => { + // WebKit skipped, see https://github.com/ni/nimble/issues/1938 + it('should have br tag name when pressing shift + Enter with numbered list content #SkipWebkit', async () => { await pageObject.setEditorTextContent('numbered list1'); await pageObject.toggleFooterButton(ToolbarButton.numberedList); await pageObject.pressShiftEnterKeysInEditor(); @@ -496,7 +508,8 @@ describe('RichTextEditor', () => { ).toBeTrue(); }); - it('should have br tag name when pressing shift + Enter with nested numbered lists content', async () => { + // WebKit skipped, see https://github.com/ni/nimble/issues/1938 + it('should have br tag name when pressing shift + Enter with nested numbered lists content #SkipWebkit', async () => { await pageObject.setEditorTextContent('List'); await pageObject.toggleFooterButton(ToolbarButton.numberedList); await pageObject.pressEnterKeyInEditor(); @@ -585,7 +598,8 @@ describe('RichTextEditor', () => { expect(pageObject.getEditorLeafContents()).toEqual(['Bullet List']); }); - it('should have br tag name when pressing shift + Enter with bulleted list content', async () => { + // WebKit skipped, see https://github.com/ni/nimble/issues/1938 + it('should have br tag name when pressing shift + Enter with bulleted list content #SkipWebkit', async () => { await pageObject.setEditorTextContent('Bulleted List 1'); await pageObject.toggleFooterButton(ToolbarButton.bulletList); await pageObject.pressShiftEnterKeysInEditor(); @@ -644,7 +658,8 @@ describe('RichTextEditor', () => { ).toBeTrue(); }); - it('should have br tag name when pressing shift + Enter with nested bulleted lists content', async () => { + // WebKit skipped, see https://github.com/ni/nimble/issues/1938 + it('should have br tag name when pressing shift + Enter with nested bulleted lists content #SkipWebkit', async () => { await pageObject.setEditorTextContent('List'); await pageObject.toggleFooterButton(ToolbarButton.bulletList); await pageObject.pressEnterKeyInEditor(); diff --git a/packages/nimble-components/src/rich-text/models/tests/markdown-serializer.spec.ts b/packages/nimble-components/src/rich-text/models/tests/markdown-serializer.spec.ts index 493afc3567..121625c218 100644 --- a/packages/nimble-components/src/rich-text/models/tests/markdown-serializer.spec.ts +++ b/packages/nimble-components/src/rich-text/models/tests/markdown-serializer.spec.ts @@ -273,7 +273,8 @@ describe('Markdown serializer', () => { * Nested bulleted list`); }); - it('Hard break', async () => { + // WebKit skipped, see https://github.com/ni/nimble/issues/1938 + it('Hard break #SkipWebkit', async () => { await pageObject.setEditorTextContent('Plain text 1'); await pageObject.pressShiftEnterKeysInEditor(); await pageObject.setEditorTextContent('Plain text 2'); @@ -284,7 +285,8 @@ Plain text 2\ Plain text 3`); }); - it('Hard break with bold', async () => { + // WebKit skipped, see https://github.com/ni/nimble/issues/1938 + it('Hard break with bold #SkipWebkit', async () => { await pageObject.toggleFooterButton(ToolbarButton.bold); await pageObject.setEditorTextContent('Bold'); await pageObject.pressShiftEnterKeysInEditor(); @@ -293,7 +295,8 @@ Plain text 3`); **Bold**`); }); - it('Hard break with italics', async () => { + // WebKit skipped, see https://github.com/ni/nimble/issues/1938 + it('Hard break with italics #SkipWebkit', async () => { await pageObject.toggleFooterButton(ToolbarButton.italics); await pageObject.setEditorTextContent('Italics'); await pageObject.pressShiftEnterKeysInEditor(); @@ -302,7 +305,8 @@ Plain text 3`); *Italics*`); }); - it('Hard break with bulleted list', async () => { + // WebKit skipped, see https://github.com/ni/nimble/issues/1938 + it('Hard break with bulleted list #SkipWebkit', async () => { await pageObject.setEditorTextContent('Bulleted'); await pageObject.toggleFooterButton(ToolbarButton.bulletList); await pageObject.pressShiftEnterKeysInEditor(); @@ -311,7 +315,8 @@ Plain text 3`); list`); }); - it('Hard break with numbered list', async () => { + // WebKit skipped, see https://github.com/ni/nimble/issues/1938 + it('Hard break with numbered list #SkipWebkit', async () => { await pageObject.setEditorTextContent('Numbered'); await pageObject.toggleFooterButton(ToolbarButton.numberedList); await pageObject.pressShiftEnterKeysInEditor(); @@ -320,7 +325,8 @@ Plain text 3`); list`); }); - it('Hard break with mention node', async () => { + // WebKit skipped, see https://github.com/ni/nimble/issues/1938 + it('Hard break with mention node #SkipWebkit', async () => { await appendUserMentionConfiguration(element, [ { key: 'user:1', displayName: 'username1' } ]); diff --git a/packages/nimble-components/src/table-column/date-text/tests/table-column-date-text.spec.ts b/packages/nimble-components/src/table-column/date-text/tests/table-column-date-text.spec.ts index 17da6cf4de..39c27995ff 100644 --- a/packages/nimble-components/src/table-column/date-text/tests/table-column-date-text.spec.ts +++ b/packages/nimble-components/src/table-column/date-text/tests/table-column-date-text.spec.ts @@ -119,7 +119,8 @@ describe('TableColumnDateText', () => { }); }); - it('changing fieldName updates display', async () => { + // WebKit skipped, see https://github.com/ni/nimble/issues/1940 + it('changing fieldName updates display #SkipWebkit', async () => { await table.setData([ { field: new Date('Dec 10, 2012, 10:35:05 PM').valueOf(), @@ -136,7 +137,8 @@ describe('TableColumnDateText', () => { ); }); - it('changing data from value to null displays blank', async () => { + // WebKit skipped, see https://github.com/ni/nimble/issues/1940 + it('changing data from value to null displays blank #SkipWebkit', async () => { await table.setData([ { field: new Date('Dec 10, 2012, 10:35:05 PM').valueOf() } ]); @@ -153,7 +155,8 @@ describe('TableColumnDateText', () => { expect(pageObject.getRenderedCellContent(0, 0)).toEqual(''); }); - it('changing data from null to value displays value', async () => { + // WebKit skipped, see https://github.com/ni/nimble/issues/1940 + it('changing data from null to value displays value #SkipWebkit', async () => { await table.setData([{ field: null }]); await waitForUpdatesAsync(); expect(pageObject.getRenderedCellContent(0, 0)).toEqual(''); @@ -178,7 +181,8 @@ describe('TableColumnDateText', () => { expect(pageObject.getRenderedCellContent(0, 0)).toEqual(''); }); - it('sets title when cell text is ellipsized', async () => { + // WebKit skipped, see https://github.com/ni/nimble/issues/1940 + it('sets title when cell text is ellipsized #SkipWebkit', async () => { table.style.width = '200px'; await table.setData([ { field: new Date('Dec 10, 2012, 10:35:05 PM').valueOf() } @@ -230,7 +234,8 @@ describe('TableColumnDateText', () => { expect(pageObject.getCellTitle(0, 0)).toEqual(''); }); - it('sets group header text to rendered date value', async () => { + // WebKit skipped, see https://github.com/ni/nimble/issues/1940 + it('sets group header text to rendered date value #SkipWebkit', async () => { await table.setData([ { field: new Date('Dec 10, 2012, 10:35:05 PM').valueOf() } ]); @@ -250,7 +255,8 @@ describe('TableColumnDateText', () => { expect(pageObject.getRenderedCellContent(0, 0)).toBe('12/10/2012'); }); - it('updates displayed date when lang token changes', async () => { + // WebKit skipped, see https://github.com/ni/nimble/issues/1940 + it('updates displayed date when lang token changes #SkipWebkit', async () => { await table.setData([ { field: new Date('Dec 10, 2012, 10:35:05 PM').valueOf() } ]); diff --git a/packages/nimble-components/src/table/components/header/tests/table-header.spec.ts b/packages/nimble-components/src/table/components/header/tests/table-header.spec.ts index 73afb916b5..fd72467373 100644 --- a/packages/nimble-components/src/table/components/header/tests/table-header.spec.ts +++ b/packages/nimble-components/src/table/components/header/tests/table-header.spec.ts @@ -46,8 +46,7 @@ describe('TableHeader', () => { expect(pageObject.isSortDescendingIconVisible()).toBeFalse(); }); - // Firefox skipped, see: https://github.com/ni/nimble/issues/1075 - it('has correct state when sorted ascending #SkipFirefox', async () => { + it('has correct state when sorted ascending', async () => { element.sortDirection = TableColumnSortDirection.ascending; element.firstSortedColumn = true; await waitForUpdatesAsync(); @@ -57,8 +56,7 @@ describe('TableHeader', () => { expect(pageObject.isSortDescendingIconVisible()).toBeFalse(); }); - // Firefox skipped, see: https://github.com/ni/nimble/issues/1075 - it('has correct state when sorted descending #SkipFirefox', async () => { + it('has correct state when sorted descending', async () => { element.sortDirection = TableColumnSortDirection.descending; element.firstSortedColumn = true; await waitForUpdatesAsync(); diff --git a/packages/nimble-components/src/table/tests/table-column-sizing.spec.ts b/packages/nimble-components/src/table/tests/table-column-sizing.spec.ts index bbdc7e8086..56012c72c5 100644 --- a/packages/nimble-components/src/table/tests/table-column-sizing.spec.ts +++ b/packages/nimble-components/src/table/tests/table-column-sizing.spec.ts @@ -495,7 +495,8 @@ describe('Table Interactive Column Sizing', () => { expect(pageObject.isHorizontalScrollbarVisible()).toBeTrue(); }); - it('sizing table with a horizontal scrollbar does not change column widths until sized beyond current column pixel widths', async () => { + // WebKit skipped, see https://github.com/ni/nimble/issues/1939 + it('sizing table with a horizontal scrollbar does not change column widths until sized beyond current column pixel widths #SkipWebkit', async () => { // create horizontal scrollbar with total column width of 450 pageObject.dragSizeColumnByRightDivider(2, [100]); // size table below threshhold of total column widths diff --git a/packages/nimble-components/src/table/tests/table.spec.ts b/packages/nimble-components/src/table/tests/table.spec.ts index 8d0fad78c7..0eaaa3ee11 100644 --- a/packages/nimble-components/src/table/tests/table.spec.ts +++ b/packages/nimble-components/src/table/tests/table.spec.ts @@ -677,7 +677,8 @@ describe('Table', () => { verifyRenderedData(dataSubsetAtEnd); }); - it('and calls focusedRecycleCallback on focused cell views when a scroll happens', async () => { + // WebKit skipped, see https://github.com/ni/nimble/issues/1942 + it('and calls focusedRecycleCallback on focused cell views when a scroll happens #SkipWebkit', async () => { const focusableColumn = document.createElement( focusableColumnName ) as TestFocusableTableColumn; From 72c946755c19ac9d8027599978b87829da293eef Mon Sep 17 00:00:00 2001 From: rajsite <rajsite@users.noreply.github.com> Date: Mon, 18 Mar 2024 16:35:18 +0000 Subject: [PATCH 10/12] applying package updates [skip ci] --- ...ents-1e68ef0e-2e70-4f32-86a4-e9073c251a0e.json | 7 ------- packages/nimble-components/CHANGELOG.json | 15 +++++++++++++++ 2 files changed, 15 insertions(+), 7 deletions(-) delete mode 100644 change/@ni-nimble-components-1e68ef0e-2e70-4f32-86a4-e9073c251a0e.json diff --git a/change/@ni-nimble-components-1e68ef0e-2e70-4f32-86a4-e9073c251a0e.json b/change/@ni-nimble-components-1e68ef0e-2e70-4f32-86a4-e9073c251a0e.json deleted file mode 100644 index a9f32d1b2e..0000000000 --- a/change/@ni-nimble-components-1e68ef0e-2e70-4f32-86a4-e9073c251a0e.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "type": "none", - "comment": "Marking tests that fail on some browsers", - "packageName": "@ni/nimble-components", - "email": "jattasNI@users.noreply.github.com", - "dependentChangeType": "none" -} diff --git a/packages/nimble-components/CHANGELOG.json b/packages/nimble-components/CHANGELOG.json index 81794ef2c8..4d10a25568 100644 --- a/packages/nimble-components/CHANGELOG.json +++ b/packages/nimble-components/CHANGELOG.json @@ -1,6 +1,21 @@ { "name": "@ni/nimble-components", "entries": [ + { + "date": "Mon, 18 Mar 2024 16:35:18 GMT", + "version": "22.0.1", + "tag": "@ni/nimble-components_v22.0.1", + "comments": { + "none": [ + { + "author": "jattasNI@users.noreply.github.com", + "package": "@ni/nimble-components", + "commit": "a112528ec429c96f2017e95bbbdb22e578be1c08", + "comment": "Marking tests that fail on some browsers" + } + ] + } + }, { "date": "Thu, 14 Mar 2024 14:48:16 GMT", "version": "22.0.1", From 3bbf8d7cd86d0129e9ad6bb0eed245ea2bfc0fda Mon Sep 17 00:00:00 2001 From: mollykreis <20542556+mollykreis@users.noreply.github.com> Date: Mon, 18 Mar 2024 11:54:06 -0500 Subject: [PATCH 11/12] Add placeholder text to group rows (#1914) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit # Pull Request ## ๐Ÿคจ Rationale This is part of #1538 This PR adds support for placeholder text in group rows within the table. There is follow on work that will need to be done before the linked issue is resolved to add placeholders to cells, but that is not included in this PR. This PR is scoped to the following behavior changes to columns: - text column - Show "Empty" on group rows for empty string values - Show "No value" on group rows for `null` and `undefined` values - date-text column - Show "No value" on group rows for `null` and `undefined` values - number-text column - Show "No value" on group rows for `null` and `undefined` values - duration-text column - Show "No value" on group rows for `null` and `undefined` values - icon column - Show "No value" on group rows for `null` and `undefined` values - enum-text column - Show "No value" on group rows for `null` and `undefined` values - anchor column - Show "Empty" on group rows for empty label values - Show "No value" on group rows for `null` and `undefined` label values ## ๐Ÿ‘ฉโ€๐Ÿ’ป Implementation - Added new labels to the table label provider for _Empty_ and _No value_ - Added a `applyPlaceholderTextIfNeeded` function to `TableColumnTextGroupHeaderViewBase` that concrete classes can call to apply a placeholder - Update concrete instances of `TableColumnTextGroupHeaderViewBase` to call the new function ## ๐Ÿงช Testing - Wrote a number of new tests for each column to make sure the appropriate group row text was rendered for different values - Updated matrix tests to ensure each column included all possible placeholder group values in the matrix test - Note: This meant creating a new matrix story for the text column because those matrix stories had never been created ## โœ… Checklist <!--- Review the list and put an x in the boxes that apply or ~~strike through~~ around items that don't (along with an explanation). --> - [ ] I have updated the project documentation to reflect my changes or determined no changes are needed. --- ...-provider-table-with-defaults.directive.ts | 2 + .../nimble-label-provider-table.directive.ts | 16 ++ ...ider-table-with-defaults.directive.spec.ts | 4 + ...ble-label-provider-table.directive.spec.ts | 76 ++++++ ...-5cbff6bf-81b5-47ea-b3a5-ed8d4eb87269.json | 7 + ...-095e8126-0d1e-452f-9222-60684ac3f081.json | 7 + ...-561538cd-7588-4219-9fd7-1fe50633d0f7.json | 7 + .../Components/NimbleLabelProviderTable.razor | 2 + .../NimbleLabelProviderTable.razor.cs | 5 + .../NimbleLabelProviderTableTests.cs | 2 + .../src/icon-base/tests/icons.stories.ts | 3 +- .../tests/label-provider-stories-utils.ts | 6 +- .../src/label-provider/table/index.ts | 14 +- .../table/label-token-defaults.ts | 4 +- .../src/label-provider/table/label-tokens.ts | 10 + .../table-column-anchor-matrix.stories.ts | 7 +- .../date-text/group-header-view/index.ts | 10 +- .../tests/table-column-date-text.spec.ts | 85 +++++++ .../duration-text/group-header-view/index.ts | 10 +- .../tests/table-column-duration-text.spec.ts | 63 +++++ .../enum-text/group-header-view/index.ts | 20 +- .../tests/table-column-enum-text.spec.ts | 199 +++++++++------- .../icon/group-header-view/index.ts | 16 +- .../icon/group-header-view/template.ts | 9 + .../icon/tests/table-column-icon.spec.ts | 216 +++++++++++------- .../number-text/group-header-view/index.ts | 10 +- .../tests/table-column-number-text.spec.ts | 64 +++++- ...column-text-base-group-header-view.spec.ts | 141 ++++++++++++ .../text-base/group-header-view/index.ts | 83 ++++++- .../text/group-header-view/index.ts | 2 +- .../tests/table-column-text-matrix.stories.ts | 68 ++++++ .../text/tests/table-column-text.spec.ts | 125 +++++++--- .../src/tests/component-status.stories.ts | 6 +- 33 files changed, 1026 insertions(+), 273 deletions(-) create mode 100644 change/@ni-nimble-angular-5cbff6bf-81b5-47ea-b3a5-ed8d4eb87269.json create mode 100644 change/@ni-nimble-blazor-095e8126-0d1e-452f-9222-60684ac3f081.json create mode 100644 change/@ni-nimble-components-561538cd-7588-4219-9fd7-1fe50633d0f7.json create mode 100644 packages/nimble-components/src/table-column/text-base/cell-view/tests/table-column-text-base-group-header-view.spec.ts create mode 100644 packages/nimble-components/src/table-column/text/tests/table-column-text-matrix.stories.ts diff --git a/angular-workspace/projects/ni/nimble-angular/label-provider/table/nimble-label-provider-table-with-defaults.directive.ts b/angular-workspace/projects/ni/nimble-angular/label-provider/table/nimble-label-provider-table-with-defaults.directive.ts index 4c4d2977b6..c201830afb 100644 --- a/angular-workspace/projects/ni/nimble-angular/label-provider/table/nimble-label-provider-table-with-defaults.directive.ts +++ b/angular-workspace/projects/ni/nimble-angular/label-provider/table/nimble-label-provider-table-with-defaults.directive.ts @@ -26,5 +26,7 @@ export class NimbleLabelProviderTableWithDefaultsDirective { this.elementRef.nativeElement.rowSelect = $localize`:Nimble table - select row|:Select row`; this.elementRef.nativeElement.rowOperationColumn = $localize`:Nimble table - row operation column|:Row operations`; this.elementRef.nativeElement.rowLoading = $localize`:Nimble table - row loading|:Loading`; + this.elementRef.nativeElement.groupRowPlaceholderNoValue = $localize`:Nimble table - group row placeholder no value|:No value`; + this.elementRef.nativeElement.groupRowPlaceholderEmpty = $localize`:Nimble table - group row placeholder empty|:Empty`; } } \ No newline at end of file diff --git a/angular-workspace/projects/ni/nimble-angular/label-provider/table/nimble-label-provider-table.directive.ts b/angular-workspace/projects/ni/nimble-angular/label-provider/table/nimble-label-provider-table.directive.ts index ebf09e6e20..f68b7d3335 100644 --- a/angular-workspace/projects/ni/nimble-angular/label-provider/table/nimble-label-provider-table.directive.ts +++ b/angular-workspace/projects/ni/nimble-angular/label-provider/table/nimble-label-provider-table.directive.ts @@ -127,4 +127,20 @@ export class NimbleLabelProviderTableDirective { @Input('row-loading') public set rowLoading(value: string | undefined) { this.renderer.setProperty(this.elementRef.nativeElement, 'rowLoading', value); } + + public get groupRowPlaceholderNoValue(): string | undefined { + return this.elementRef.nativeElement.groupRowPlaceholderNoValue; + } + + @Input('group-row-placeholder-no-value') public set groupRowPlaceholderNoValue(value: string | undefined) { + this.renderer.setProperty(this.elementRef.nativeElement, 'groupRowPlaceholderNoValue', value); + } + + public get groupRowPlaceholderEmpty(): string | undefined { + return this.elementRef.nativeElement.groupRowPlaceholderEmpty; + } + + @Input('group-row-placeholder-empty') public set groupRowPlaceholderEmpty(value: string | undefined) { + this.renderer.setProperty(this.elementRef.nativeElement, 'groupRowPlaceholderEmpty', value); + } } \ No newline at end of file diff --git a/angular-workspace/projects/ni/nimble-angular/label-provider/table/tests/nimble-label-provider-table-with-defaults.directive.spec.ts b/angular-workspace/projects/ni/nimble-angular/label-provider/table/tests/nimble-label-provider-table-with-defaults.directive.spec.ts index 1f72c8079a..e7004f4d81 100644 --- a/angular-workspace/projects/ni/nimble-angular/label-provider/table/tests/nimble-label-provider-table-with-defaults.directive.spec.ts +++ b/angular-workspace/projects/ni/nimble-angular/label-provider/table/tests/nimble-label-provider-table-with-defaults.directive.spec.ts @@ -42,6 +42,8 @@ describe('Nimble LabelProviderTable withDefaults directive', () => { [computeMsgId('Select row', 'Nimble table - select row')]: 'Translated select row', [computeMsgId('Row operations', 'Nimble table - row operation column')]: 'Translated row operations', [computeMsgId('Loading', 'Nimble table - row loading')]: 'Translated loading', + [computeMsgId('No value', 'Nimble table - group row placeholder no value')]: 'Translated no value', + [computeMsgId('Empty', 'Nimble table - group row placeholder empty')]: 'Translated empty', }); const fixture = TestBed.createComponent(TestHostComponent); const testHostComponent = fixture.componentInstance; @@ -64,5 +66,7 @@ describe('Nimble LabelProviderTable withDefaults directive', () => { expect(labelProvider.rowSelect).toBe('Translated select row'); expect(labelProvider.rowOperationColumn).toBe('Translated row operations'); expect(labelProvider.rowLoading).toBe('Translated loading'); + expect(labelProvider.groupRowPlaceholderNoValue).toBe('Translated no value'); + expect(labelProvider.groupRowPlaceholderEmpty).toBe('Translated empty'); }); }); diff --git a/angular-workspace/projects/ni/nimble-angular/label-provider/table/tests/nimble-label-provider-table.directive.spec.ts b/angular-workspace/projects/ni/nimble-angular/label-provider/table/tests/nimble-label-provider-table.directive.spec.ts index e0b96f47c4..15c43912f0 100644 --- a/angular-workspace/projects/ni/nimble-angular/label-provider/table/tests/nimble-label-provider-table.directive.spec.ts +++ b/angular-workspace/projects/ni/nimble-angular/label-provider/table/tests/nimble-label-provider-table.directive.spec.ts @@ -18,6 +18,8 @@ describe('Nimble Label Provider Table', () => { const label12 = 'String 12'; const label13 = 'String 13'; const label14 = 'String 14'; + const label15 = 'String 15'; + const label16 = 'String 16'; beforeEach(() => { TestBed.configureTestingModule({ @@ -124,6 +126,16 @@ describe('Nimble Label Provider Table', () => { expect(directive.rowLoading).toBeUndefined(); expect(nativeElement.rowLoading).toBeUndefined(); }); + + it('has expected defaults for groupRowPlaceholderNoValue', () => { + expect(directive.groupRowPlaceholderNoValue).toBeUndefined(); + expect(nativeElement.groupRowPlaceholderNoValue).toBeUndefined(); + }); + + it('has expected defaults for groupRowPlaceholderEmpty', () => { + expect(directive.groupRowPlaceholderEmpty).toBeUndefined(); + expect(nativeElement.groupRowPlaceholderEmpty).toBeUndefined(); + }); }); describe('with template string values', () => { @@ -144,6 +156,8 @@ describe('Nimble Label Provider Table', () => { row-select="${label12}" row-operation-column="${label13}" row-loading="${label14}" + group-row-placeholder-no-value="${label15}" + group-row-placeholder-empty="${label16}" > </nimble-label-provider-table> ` @@ -237,6 +251,16 @@ describe('Nimble Label Provider Table', () => { expect(directive.rowLoading).toBe(label14); expect(nativeElement.rowLoading).toBe(label14); }); + + it('will use template string values for groupRowPlaceholderNoValue', () => { + expect(directive.groupRowPlaceholderNoValue).toBe(label15); + expect(nativeElement.groupRowPlaceholderNoValue).toBe(label15); + }); + + it('will use template string values for groupRowPlaceholderEmpty', () => { + expect(directive.groupRowPlaceholderEmpty).toBe(label16); + expect(nativeElement.groupRowPlaceholderEmpty).toBe(label16); + }); }); describe('with property bound values', () => { @@ -257,6 +281,8 @@ describe('Nimble Label Provider Table', () => { [rowSelect]="rowSelect" [rowOperationColumn]="rowOperationColumn" [rowLoading]="rowLoading" + [groupRowPlaceholderNoValue]="groupRowPlaceholderNoValue" + [groupRowPlaceholderEmpty]="groupRowPlaceholderEmpty" > </nimble-label-provider-table> ` @@ -278,6 +304,8 @@ describe('Nimble Label Provider Table', () => { public rowSelect = label1; public rowOperationColumn = label1; public rowLoading = label1; + public groupRowPlaceholderNoValue = label1; + public groupRowPlaceholderEmpty = label1; } let fixture: ComponentFixture<TestHostComponent>; @@ -448,6 +476,28 @@ describe('Nimble Label Provider Table', () => { expect(directive.rowLoading).toBe(label2); expect(nativeElement.rowLoading).toBe(label2); }); + + it('can be configured with property binding for groupRowPlaceholderNoValue', () => { + expect(directive.groupRowPlaceholderNoValue).toBe(label1); + expect(nativeElement.groupRowPlaceholderNoValue).toBe(label1); + + fixture.componentInstance.groupRowPlaceholderNoValue = label2; + fixture.detectChanges(); + + expect(directive.groupRowPlaceholderNoValue).toBe(label2); + expect(nativeElement.groupRowPlaceholderNoValue).toBe(label2); + }); + + it('can be configured with property binding for groupRowPlaceholderEmpty', () => { + expect(directive.groupRowPlaceholderEmpty).toBe(label1); + expect(nativeElement.groupRowPlaceholderEmpty).toBe(label1); + + fixture.componentInstance.groupRowPlaceholderEmpty = label2; + fixture.detectChanges(); + + expect(directive.groupRowPlaceholderEmpty).toBe(label2); + expect(nativeElement.groupRowPlaceholderEmpty).toBe(label2); + }); }); describe('with attribute bound values', () => { @@ -468,6 +518,8 @@ describe('Nimble Label Provider Table', () => { [attr.row-select]="rowSelect" [attr.row-operation-column]="rowOperationColumn" [attr.row-loading]="rowLoading" + [attr.group-row-placeholder-no-value]="groupRowPlaceholderNoValue" + [attr.group-row-placeholder-empty]="groupRowPlaceholderEmpty" > </nimble-label-provider-table> ` @@ -489,6 +541,8 @@ describe('Nimble Label Provider Table', () => { public rowSelect = label1; public rowOperationColumn = label1; public rowLoading = label1; + public groupRowPlaceholderNoValue = label1; + public groupRowPlaceholderEmpty = label1; } let fixture: ComponentFixture<TestHostComponent>; @@ -659,5 +713,27 @@ describe('Nimble Label Provider Table', () => { expect(directive.rowLoading).toBe(label2); expect(nativeElement.rowLoading).toBe(label2); }); + + it('can be configured with attribute binding for groupRowPlaceholderNoValue', () => { + expect(directive.groupRowPlaceholderNoValue).toBe(label1); + expect(nativeElement.groupRowPlaceholderNoValue).toBe(label1); + + fixture.componentInstance.groupRowPlaceholderNoValue = label2; + fixture.detectChanges(); + + expect(directive.groupRowPlaceholderNoValue).toBe(label2); + expect(nativeElement.groupRowPlaceholderNoValue).toBe(label2); + }); + + it('can be configured with attribute binding for groupRowPlaceholderEmpty', () => { + expect(directive.groupRowPlaceholderEmpty).toBe(label1); + expect(nativeElement.groupRowPlaceholderEmpty).toBe(label1); + + fixture.componentInstance.groupRowPlaceholderEmpty = label2; + fixture.detectChanges(); + + expect(directive.groupRowPlaceholderEmpty).toBe(label2); + expect(nativeElement.groupRowPlaceholderEmpty).toBe(label2); + }); }); }); diff --git a/change/@ni-nimble-angular-5cbff6bf-81b5-47ea-b3a5-ed8d4eb87269.json b/change/@ni-nimble-angular-5cbff6bf-81b5-47ea-b3a5-ed8d4eb87269.json new file mode 100644 index 0000000000..b03b663fa2 --- /dev/null +++ b/change/@ni-nimble-angular-5cbff6bf-81b5-47ea-b3a5-ed8d4eb87269.json @@ -0,0 +1,7 @@ +{ + "type": "minor", + "comment": "Add new properties to the table label provider", + "packageName": "@ni/nimble-angular", + "email": "20542556+mollykreis@users.noreply.github.com", + "dependentChangeType": "patch" +} diff --git a/change/@ni-nimble-blazor-095e8126-0d1e-452f-9222-60684ac3f081.json b/change/@ni-nimble-blazor-095e8126-0d1e-452f-9222-60684ac3f081.json new file mode 100644 index 0000000000..336ed4bd8e --- /dev/null +++ b/change/@ni-nimble-blazor-095e8126-0d1e-452f-9222-60684ac3f081.json @@ -0,0 +1,7 @@ +{ + "type": "minor", + "comment": "Add new properties to the table label provider", + "packageName": "@ni/nimble-blazor", + "email": "20542556+mollykreis@users.noreply.github.com", + "dependentChangeType": "patch" +} diff --git a/change/@ni-nimble-components-561538cd-7588-4219-9fd7-1fe50633d0f7.json b/change/@ni-nimble-components-561538cd-7588-4219-9fd7-1fe50633d0f7.json new file mode 100644 index 0000000000..91788ed748 --- /dev/null +++ b/change/@ni-nimble-components-561538cd-7588-4219-9fd7-1fe50633d0f7.json @@ -0,0 +1,7 @@ +{ + "type": "minor", + "comment": "Add placeholders for group rows in the table", + "packageName": "@ni/nimble-components", + "email": "20542556+mollykreis@users.noreply.github.com", + "dependentChangeType": "patch" +} diff --git a/packages/nimble-blazor/NimbleBlazor/Components/NimbleLabelProviderTable.razor b/packages/nimble-blazor/NimbleBlazor/Components/NimbleLabelProviderTable.razor index a71b904408..7d3a1ed2a6 100644 --- a/packages/nimble-blazor/NimbleBlazor/Components/NimbleLabelProviderTable.razor +++ b/packages/nimble-blazor/NimbleBlazor/Components/NimbleLabelProviderTable.razor @@ -14,5 +14,7 @@ row-select="@RowSelect" row-operation-column="@RowOperationColumn" row-loading="@RowLoading" + group-row-placeholder-no-value="@GroupRowPlaceholderNoValue" + group-row-placeholder-empty="@GroupRowPlaceholderEmpty" @attributes="AdditionalAttributes"> </nimble-label-provider-table> diff --git a/packages/nimble-blazor/NimbleBlazor/Components/NimbleLabelProviderTable.razor.cs b/packages/nimble-blazor/NimbleBlazor/Components/NimbleLabelProviderTable.razor.cs index d91a701987..2227e9896e 100644 --- a/packages/nimble-blazor/NimbleBlazor/Components/NimbleLabelProviderTable.razor.cs +++ b/packages/nimble-blazor/NimbleBlazor/Components/NimbleLabelProviderTable.razor.cs @@ -49,6 +49,11 @@ public partial class NimbleLabelProviderTable : ComponentBase [Parameter] public string? RowLoading { get; set; } + [Parameter] + public string? GroupRowPlaceholderNoValue { get; set; } + + [Parameter] + public string? GroupRowPlaceholderEmpty { get; set; } /// <summary> /// Gets or sets a collection of additional attributes that will be applied to the created element. /// </summary> diff --git a/packages/nimble-blazor/Tests/NimbleBlazor.Tests/Unit/Components/NimbleLabelProviderTableTests.cs b/packages/nimble-blazor/Tests/NimbleBlazor.Tests/Unit/Components/NimbleLabelProviderTableTests.cs index 32caad78a4..804cb57466 100644 --- a/packages/nimble-blazor/Tests/NimbleBlazor.Tests/Unit/Components/NimbleLabelProviderTableTests.cs +++ b/packages/nimble-blazor/Tests/NimbleBlazor.Tests/Unit/Components/NimbleLabelProviderTableTests.cs @@ -44,6 +44,8 @@ public void NimbleLabelProviderTable_SupportsAdditionalAttributes() [InlineData(nameof(NimbleLabelProviderTable.RowSelect))] [InlineData(nameof(NimbleLabelProviderTable.RowOperationColumn))] [InlineData(nameof(NimbleLabelProviderTable.RowLoading))] + [InlineData(nameof(NimbleLabelProviderTable.GroupRowPlaceholderNoValue))] + [InlineData(nameof(NimbleLabelProviderTable.GroupRowPlaceholderEmpty))] public void NimbleLabelProviderTable_LabelIsSet(string propertyName) { var labelValue = propertyName + "UpdatedValue"; diff --git a/packages/nimble-components/src/icon-base/tests/icons.stories.ts b/packages/nimble-components/src/icon-base/tests/icons.stories.ts index d59f18b9bd..ed53a74c52 100644 --- a/packages/nimble-components/src/icon-base/tests/icons.stories.ts +++ b/packages/nimble-components/src/icon-base/tests/icons.stories.ts @@ -56,6 +56,7 @@ const updateData = (tableRef: Table<Data>): void => { // Safari workaround: the table element instance is made at this point // but doesn't seem to be upgraded to a custom element yet await customElements.whenDefined('nimble-table'); + tableRef.style.setProperty('--data-length', data.length.toString()); await tableRef.setData(data); })(); }; @@ -82,7 +83,7 @@ export const icons: StoryObj<IconArgs> = { <${tableTag} ${ref('tableRef')} ${/* Make the table big enough to remove vertical scrollbar */ ''} - style="height: 6325px;" + style="height: calc((34px * var(--data-length)) + 32px);" data-unused="${x => updateData(x.tableRef)}" > <${tableColumnIconTag} field-name="tag" key-type="string"> diff --git a/packages/nimble-components/src/label-provider/base/tests/label-provider-stories-utils.ts b/packages/nimble-components/src/label-provider/base/tests/label-provider-stories-utils.ts index c439cfaba4..f8fb5f4144 100644 --- a/packages/nimble-components/src/label-provider/base/tests/label-provider-stories-utils.ts +++ b/packages/nimble-components/src/label-provider/base/tests/label-provider-stories-utils.ts @@ -63,7 +63,7 @@ export const labelProviderMetadata: Meta<LabelProviderArgs> = { } ${tableTag} { /* Make the table big enough to remove vertical scrollbar */ - height: 550px; + height: calc((34px * var(--data-length)) + 32px); } </style> ${x => createTemplate(x.labelProviderTag)} @@ -123,6 +123,10 @@ export const labelProviderMetadata: Meta<LabelProviderArgs> = { defaultValue: token[1].getValueFor(document.body) }; }); + x.tableRef.style.setProperty( + '--data-length', + data.length.toString() + ); await x.tableRef.setData(data); })(); } diff --git a/packages/nimble-components/src/label-provider/table/index.ts b/packages/nimble-components/src/label-provider/table/index.ts index 8081845910..20668452e6 100644 --- a/packages/nimble-components/src/label-provider/table/index.ts +++ b/packages/nimble-components/src/label-provider/table/index.ts @@ -15,7 +15,9 @@ import { tableRowOperationColumnLabel, tableRowSelectLabel, tableSelectAllLabel, - tableRowLoadingLabel + tableRowLoadingLabel, + tableGroupRowPlaceholderEmptyLabel, + tableGroupRowPlaceholderNoValueLabel } from './label-tokens'; declare global { @@ -38,7 +40,9 @@ const supportedLabels = { groupSelectAll: tableGroupSelectAllLabel, rowSelect: tableRowSelectLabel, rowOperationColumn: tableRowOperationColumnLabel, - rowLoading: tableRowLoadingLabel + rowLoading: tableRowLoadingLabel, + groupRowPlaceholderNoValue: tableGroupRowPlaceholderNoValueLabel, + groupRowPlaceholderEmpty: tableGroupRowPlaceholderEmptyLabel } as const; /** @@ -89,6 +93,12 @@ export class LabelProviderTable @attr({ attribute: 'row-loading' }) public rowLoading: string | undefined; + @attr({ attribute: 'group-row-placeholder-no-value' }) + public groupRowPlaceholderNoValue: string | undefined; + + @attr({ attribute: 'group-row-placeholder-empty' }) + public groupRowPlaceholderEmpty: string | undefined; + protected override readonly supportedLabels = supportedLabels; } diff --git a/packages/nimble-components/src/label-provider/table/label-token-defaults.ts b/packages/nimble-components/src/label-provider/table/label-token-defaults.ts index 79b553c018..ff243302a7 100644 --- a/packages/nimble-components/src/label-provider/table/label-token-defaults.ts +++ b/packages/nimble-components/src/label-provider/table/label-token-defaults.ts @@ -16,5 +16,7 @@ export const tableLabelDefaults: { readonly [key in TokenName]: string } = { tableGroupSelectAllLabel: 'Select all rows in group', tableRowSelectLabel: 'Select row', tableRowOperationColumnLabel: 'Row operations', - tableRowLoadingLabel: 'Loading' + tableRowLoadingLabel: 'Loading', + tableGroupRowPlaceholderNoValueLabel: 'No value', + tableGroupRowPlaceholderEmptyLabel: 'Empty' }; diff --git a/packages/nimble-components/src/label-provider/table/label-tokens.ts b/packages/nimble-components/src/label-provider/table/label-tokens.ts index 26edb26e30..e7d8bffb19 100644 --- a/packages/nimble-components/src/label-provider/table/label-tokens.ts +++ b/packages/nimble-components/src/label-provider/table/label-tokens.ts @@ -72,3 +72,13 @@ export const tableRowLoadingLabel = DesignToken.create<string>({ name: 'table-row-loading-label', cssCustomPropertyName: null }).withDefault(tableLabelDefaults.tableRowLoadingLabel); + +export const tableGroupRowPlaceholderNoValueLabel = DesignToken.create<string>({ + name: 'table-group-row-placeholder-no-value-label', + cssCustomPropertyName: null +}).withDefault(tableLabelDefaults.tableGroupRowPlaceholderNoValueLabel); + +export const tableGroupRowPlaceholderEmptyLabel = DesignToken.create<string>({ + name: 'table-group-row-placeholder-empty-label', + cssCustomPropertyName: null +}).withDefault(tableLabelDefaults.tableGroupRowPlaceholderEmptyLabel); diff --git a/packages/nimble-components/src/table-column/anchor/tests/table-column-anchor-matrix.stories.ts b/packages/nimble-components/src/table-column/anchor/tests/table-column-anchor-matrix.stories.ts index 84e03ecd55..a2606a7d3f 100644 --- a/packages/nimble-components/src/table-column/anchor/tests/table-column-anchor-matrix.stories.ts +++ b/packages/nimble-components/src/table-column/anchor/tests/table-column-anchor-matrix.stories.ts @@ -32,11 +32,16 @@ const data = [ }, { id: '1', + firstName: 'https://nimble.ni.dev', link: 'https://nimble.ni.dev' }, { id: '2', firstName: null + }, + { + id: '3', + firstName: '' } ] as const; @@ -57,7 +62,7 @@ const component = ( [underlineHiddenName, underlineHidden]: UnderlineHiddenState ): ViewTemplate => html` <label style="color: var(${controlLabelFontColor.cssCustomProperty}); font: var(${controlLabelFont.cssCustomProperty})">${appearanceName} ${underlineHiddenName} Anchor Table Column</label> - <${tableTag} id-field-name="id" style="height: 300px"> + <${tableTag} id-field-name="id" style="height: 320px"> <${tableColumnAnchorTag} label-field-name="firstName" href-field-name="link" diff --git a/packages/nimble-components/src/table-column/date-text/group-header-view/index.ts b/packages/nimble-components/src/table-column/date-text/group-header-view/index.ts index 9e9ebbf99b..d39d19961b 100644 --- a/packages/nimble-components/src/table-column/date-text/group-header-view/index.ts +++ b/packages/nimble-components/src/table-column/date-text/group-header-view/index.ts @@ -18,15 +18,7 @@ export class TableColumnDateTextGroupHeaderView extends TableColumnTextGroupHead TableNumberFieldValue, TableColumnDateTextColumnConfig > { - private columnConfigChanged(): void { - this.updateText(); - } - - private groupHeaderValueChanged(): void { - this.updateText(); - } - - private updateText(): void { + protected updateText(): void { if (this.columnConfig) { this.text = formatNumericDate( this.columnConfig.formatter, diff --git a/packages/nimble-components/src/table-column/date-text/tests/table-column-date-text.spec.ts b/packages/nimble-components/src/table-column/date-text/tests/table-column-date-text.spec.ts index 39c27995ff..9bcaefed03 100644 --- a/packages/nimble-components/src/table-column/date-text/tests/table-column-date-text.spec.ts +++ b/packages/nimble-components/src/table-column/date-text/tests/table-column-date-text.spec.ts @@ -8,6 +8,7 @@ import type { TableRecord } from '../../../table/types'; import { TablePageObject } from '../../../table/testing/table.pageobject'; import { TableColumnDateTextPageObject } from '../testing/table-column-date-text.pageobject'; import { lang, themeProviderTag } from '../../../theme-provider'; +import { DateTextFormat } from '../types'; interface SimpleTableRecord extends TableRecord { field?: number | null; @@ -515,6 +516,90 @@ describe('TableColumnDateText', () => { await waitForUpdatesAsync(); expect(column.validity.invalidCustomOptionsCombination).toBeFalse(); }); + + describe('placeholder', () => { + const testCases = [ + { + name: 'value is not specified', + data: [{}], + groupValue: 'No value' + }, + { + name: 'value is undefined', + data: [{ field: undefined }], + groupValue: 'No value' + }, + { + name: 'value is null', + data: [{ field: null }], + groupValue: 'No value' + }, + { + name: 'value is Number.NaN', + data: [{ field: Number.NaN }], + groupValue: '' + }, + { + name: 'value is valid and non-zero', + data: [{ field: 1708984169258 }], + groupValue: '2/26/2024' + }, + { + name: 'value is incorrect type', + data: [{ field: 'not a number' as unknown as number }], + groupValue: '' + }, + { + name: 'value is specified and falsey', + data: [{ field: 0 }], + groupValue: '1/1/1970' + }, + { + name: 'value is Inf', + data: [{ field: Number.POSITIVE_INFINITY }], + groupValue: '' + }, + { + name: 'value is -Inf', + data: [{ field: Number.NEGATIVE_INFINITY }], + groupValue: '' + }, + { + name: 'value is MAX_VALUE', + data: [{ field: Number.MAX_VALUE }], + groupValue: '' + }, + { + name: 'value is too large for Date', + data: [{ field: 8640000000000000 + 1 }], + groupValue: '' + }, + { + name: 'value is too small for Date', + data: [{ field: -8640000000000000 - 1 }], + groupValue: '' + } + ]; + + parameterizeSpec(testCases, (spec, name, value) => { + spec( + `group row renders expected value when ${name}`, + async () => { + // Set a custom time zone so that the behavior of the test does not + // depend on the configuration of the computer running the tests. + column.format = DateTextFormat.custom; + column.customTimeZone = 'UTC'; + await table.setData(value.data); + await connect(); + await waitForUpdatesAsync(); + + expect( + pageObject.getRenderedGroupHeaderContent(0) + ).toBe(value.groupValue); + } + ); + }); + }); }); describe('with static config', () => { diff --git a/packages/nimble-components/src/table-column/duration-text/group-header-view/index.ts b/packages/nimble-components/src/table-column/duration-text/group-header-view/index.ts index 08d900d3c0..d3d678ee89 100644 --- a/packages/nimble-components/src/table-column/duration-text/group-header-view/index.ts +++ b/packages/nimble-components/src/table-column/duration-text/group-header-view/index.ts @@ -17,15 +17,7 @@ export class TableColumnDurationTextGroupHeaderView extends TableColumnTextGroup TableNumberFieldValue, TableColumnDurationTextColumnConfig > { - private columnConfigChanged(): void { - this.updateText(); - } - - private groupHeaderValueChanged(): void { - this.updateText(); - } - - private updateText(): void { + protected updateText(): void { if (this.columnConfig) { this.text = this.columnConfig.formatter.format( this.groupHeaderValue diff --git a/packages/nimble-components/src/table-column/duration-text/tests/table-column-duration-text.spec.ts b/packages/nimble-components/src/table-column/duration-text/tests/table-column-duration-text.spec.ts index 6191ea3041..419d200602 100644 --- a/packages/nimble-components/src/table-column/duration-text/tests/table-column-duration-text.spec.ts +++ b/packages/nimble-components/src/table-column/duration-text/tests/table-column-duration-text.spec.ts @@ -1,4 +1,5 @@ import { html, ref } from '@microsoft/fast-element'; +import { parameterizeSpec } from '@ni/jasmine-parameterized'; import { tableTag, type Table } from '../../../table'; import { TableColumnDurationText, tableColumnDurationTextTag } from '..'; import { waitForUpdatesAsync } from '../../../testing/async-helpers'; @@ -178,4 +179,66 @@ describe('TableColumnDurationText', () => { '99 j, 14 h, 50 min, 22 s' ); }); + + describe('placeholder', () => { + const testCases = [ + { + name: 'value is not specified', + data: [{}], + groupValue: 'No value' + }, + { + name: 'value is undefined', + data: [{ field: undefined }], + groupValue: 'No value' + }, + { + name: 'value is null', + data: [{ field: null }], + groupValue: 'No value' + }, + { + name: 'value is Number.NaN', + data: [{ field: Number.NaN }], + groupValue: '' + }, + { + name: 'value is valid and non-zero', + data: [{ field: 20000 }], + groupValue: '20 sec' + }, + { + name: 'value is incorrect type', + data: [{ field: 'not a number' as unknown as number }], + groupValue: '' + }, + { + name: 'value is specified and falsey', + data: [{ field: 0 }], + groupValue: '0 sec' + }, + { + name: 'value is Inf', + data: [{ field: Number.POSITIVE_INFINITY }], + groupValue: '' + }, + { + name: 'value is negative', + data: [{ field: -5 }], + groupValue: '' + } + ]; + + parameterizeSpec(testCases, (spec, name, value) => { + spec(`group row renders expected value when ${name}`, async () => { + await table.setData(value.data); + await connect(); + await waitForUpdatesAsync(); + + expect(pageObject.getRenderedGroupHeaderContent(0)).toBe( + value.groupValue + ); + }); + }); + }); }); diff --git a/packages/nimble-components/src/table-column/enum-text/group-header-view/index.ts b/packages/nimble-components/src/table-column/enum-text/group-header-view/index.ts index b7c0f2ccc1..e4605b6549 100644 --- a/packages/nimble-components/src/table-column/enum-text/group-header-view/index.ts +++ b/packages/nimble-components/src/table-column/enum-text/group-header-view/index.ts @@ -19,22 +19,10 @@ export class TableColumnEnumTextGroupHeaderView extends TableColumnTextGroupHead TableFieldValue, TableColumnEnumColumnConfig > { - private columnConfigChanged(): void { - this.updateText(); - } - - private groupHeaderValueChanged(): void { - this.updateText(); - } - - private updateText(): void { - const value = this.groupHeaderValue; - if (value === undefined || value === null) { - this.text = ''; - return; - } - - const config = this.columnConfig?.mappingConfigs.get(value); + protected updateText(): void { + const config = this.columnConfig?.mappingConfigs.get( + this.groupHeaderValue! + ); this.text = config instanceof MappingTextConfig && config.text ? config.text : ''; diff --git a/packages/nimble-components/src/table-column/enum-text/tests/table-column-enum-text.spec.ts b/packages/nimble-components/src/table-column/enum-text/tests/table-column-enum-text.spec.ts index f638c6e553..dbb773ebf4 100644 --- a/packages/nimble-components/src/table-column/enum-text/tests/table-column-enum-text.spec.ts +++ b/packages/nimble-components/src/table-column/enum-text/tests/table-column-enum-text.spec.ts @@ -12,10 +12,11 @@ import { MappingText, mappingTextTag } from '../../../mapping/text'; import { mappingSpinnerTag } from '../../../mapping/spinner'; import { mappingIconTag } from '../../../mapping/icon'; import type { MappingKey } from '../../../mapping/base/types'; +import { themeProviderTag } from '../../../theme-provider'; interface SimpleTableRecord extends TableRecord { - field1?: MappingKey | undefined; - field2?: MappingKey | undefined; + field1?: MappingKey | null; + field2?: MappingKey | null; } interface BasicTextMapping { @@ -24,6 +25,7 @@ interface BasicTextMapping { } class Model { + public table!: Table<SimpleTableRecord>; public col1!: TableColumnEnumText; public col2!: TableColumnEnumText; } @@ -32,7 +34,6 @@ interface ModelFixture<T> extends Fixture<T> { } describe('TableColumnEnumText', () => { - let element: Table<SimpleTableRecord>; let connect: () => Promise<void>; let disconnect: () => Promise<void>; let pageObject: TablePageObject<SimpleTableRecord>; @@ -42,20 +43,22 @@ describe('TableColumnEnumText', () => { async function setup(mappings: BasicTextMapping[], keyType = 'string'): Promise<ModelFixture<Table<SimpleTableRecord>>> { const source = new Model(); const result = await fixture<Table<SimpleTableRecord>>(html<Model>` - <${tableTag} style="width: 700px"> - <${tableColumnEnumTextTag} ${ref('col1')} field-name="field1" key-type="${keyType}"> - Column 1 - ${repeat(() => mappings, html<BasicTextMapping>` - <${mappingTextTag} - key="${x => x.key}" - text="${x => x.text}"> - </${mappingTextTag}> - `)} - </${tableColumnEnumTextTag}> - <${tableColumnEnumTextTag} ${ref('col2')}> - Column 2 - </${tableColumnEnumTextTag}> - </${tableTag}>`, { source }); + <${themeProviderTag} lang="en-US"> + <${tableTag} ${ref('table')} style="width: 700px"> + <${tableColumnEnumTextTag} ${ref('col1')} field-name="field1" key-type="${keyType}"> + Column 1 + ${repeat(() => mappings, html<BasicTextMapping>` + <${mappingTextTag} + key="${x => x.key}" + text="${x => x.text}"> + </${mappingTextTag}> + `)} + </${tableColumnEnumTextTag}> + <${tableColumnEnumTextTag} ${ref('col2')}> + Column 2 + </${tableColumnEnumTextTag}> + </${tableTag}> + <${themeProviderTag}>`, { source }); return { ...result, model: source @@ -86,12 +89,14 @@ describe('TableColumnEnumText', () => { ] as const; parameterizeSpec(dataTypeTests, (spec, name, value) => { spec(`displays text mapped from ${name}`, async () => { - ({ element, connect, disconnect, model } = await setup( + ({ connect, disconnect, model } = await setup( [{ key: value.key, text: 'alpha' }], value.name )); - pageObject = new TablePageObject<SimpleTableRecord>(element); - await element.setData([{ field1: value.key }]); + pageObject = new TablePageObject<SimpleTableRecord>( + model.table + ); + await model.table.setData([{ field1: value.key }]); await connect(); await waitForUpdatesAsync(); @@ -103,11 +108,11 @@ describe('TableColumnEnumText', () => { }); it('displays blank when no matches', async () => { - ({ element, connect, disconnect, model } = await setup([ + ({ connect, disconnect, model } = await setup([ { key: 'a', text: 'alpha' } ])); - pageObject = new TablePageObject<SimpleTableRecord>(element); - await element.setData([{ field1: 'no match' }]); + pageObject = new TablePageObject<SimpleTableRecord>(model.table); + await model.table.setData([{ field1: 'no match' }]); await connect(); await waitForUpdatesAsync(); @@ -115,12 +120,12 @@ describe('TableColumnEnumText', () => { }); it('changing fieldName updates display', async () => { - ({ element, connect, disconnect, model } = await setup([ + ({ connect, disconnect, model } = await setup([ { key: 'a', text: 'alpha' }, { key: 'b', text: 'bravo' } ])); - pageObject = new TablePageObject<SimpleTableRecord>(element); - await element.setData([{ field1: 'a', field2: 'b' }]); + pageObject = new TablePageObject<SimpleTableRecord>(model.table); + await model.table.setData([{ field1: 'a', field2: 'b' }]); await connect(); await waitForUpdatesAsync(); @@ -132,11 +137,11 @@ describe('TableColumnEnumText', () => { }); it('changing mapping text updates display', async () => { - ({ element, connect, disconnect, model } = await setup([ + ({ connect, disconnect, model } = await setup([ { key: 'a', text: 'alpha' } ])); - pageObject = new TablePageObject<SimpleTableRecord>(element); - await element.setData([{ field1: 'a' }]); + pageObject = new TablePageObject<SimpleTableRecord>(model.table); + await model.table.setData([{ field1: 'a' }]); await connect(); await waitForUpdatesAsync(); @@ -148,11 +153,11 @@ describe('TableColumnEnumText', () => { }); it('changing mapping key updates display', async () => { - ({ element, connect, disconnect, model } = await setup([ + ({ connect, disconnect, model } = await setup([ { key: 'a', text: 'alpha' } ])); - pageObject = new TablePageObject<SimpleTableRecord>(element); - await element.setData([{ field1: 'b' }]); + pageObject = new TablePageObject<SimpleTableRecord>(model.table); + await model.table.setData([{ field1: 'b' }]); await connect(); await waitForUpdatesAsync(); @@ -166,11 +171,13 @@ describe('TableColumnEnumText', () => { describe('various string values render as expected', () => { parameterizeSpec(wackyStrings, (spec, name) => { spec(`data "${name}" renders as "${name}"`, async () => { - ({ element, connect, disconnect, model } = await setup([ + ({ connect, disconnect, model } = await setup([ { key: 'a', text: name } ])); - pageObject = new TablePageObject<SimpleTableRecord>(element); - await element.setData([{ field1: 'a' }]); + pageObject = new TablePageObject<SimpleTableRecord>( + model.table + ); + await model.table.setData([{ field1: 'a' }]); await connect(); await waitForUpdatesAsync(); @@ -182,11 +189,13 @@ describe('TableColumnEnumText', () => { describe('various string values render in group header as expected', () => { parameterizeSpec(wackyStrings, (spec, name) => { spec(`data "${name}" renders as "${name}"`, async () => { - ({ element, connect, disconnect, model } = await setup([ + ({ connect, disconnect, model } = await setup([ { key: 'a', text: name } ])); - pageObject = new TablePageObject<SimpleTableRecord>(element); - await element.setData([{ field1: 'a' }]); + pageObject = new TablePageObject<SimpleTableRecord>( + model.table + ); + await model.table.setData([{ field1: 'a' }]); await connect(); await waitForUpdatesAsync(); model.col1.groupIndex = 0; @@ -200,11 +209,11 @@ describe('TableColumnEnumText', () => { }); it('sets group header text to blank when unmatched', async () => { - ({ element, connect, disconnect, model } = await setup([ + ({ connect, disconnect, model } = await setup([ { key: 'b', text: 'bravo' } ])); - pageObject = new TablePageObject<SimpleTableRecord>(element); - await element.setData([{ field1: 'unmatched' }]); + pageObject = new TablePageObject<SimpleTableRecord>(model.table); + await model.table.setData([{ field1: 'unmatched' }]); await connect(); await waitForUpdatesAsync(); model.col1.groupIndex = 0; @@ -215,12 +224,12 @@ describe('TableColumnEnumText', () => { it('sets title when group header text is ellipsized', async () => { const cellContents = 'a very long value that should get ellipsized due to not fitting within the default cell width'; - ({ element, connect, disconnect, model } = await setup([ + ({ connect, disconnect, model } = await setup([ { key: 'a', text: cellContents } ])); - pageObject = new TablePageObject<SimpleTableRecord>(element); - await element.setData([{ field1: 'a' }]); - element.style.width = '200px'; + pageObject = new TablePageObject<SimpleTableRecord>(model.table); + await model.table.setData([{ field1: 'a' }]); + model.table.style.width = '200px'; await connect(); await waitForUpdatesAsync(); model.col1.groupIndex = 0; @@ -231,11 +240,11 @@ describe('TableColumnEnumText', () => { }); it('does not set title when group header text is fully visible', async () => { - ({ element, connect, disconnect, model } = await setup([ + ({ connect, disconnect, model } = await setup([ { key: 'a', text: 'alpha' } ])); - pageObject = new TablePageObject<SimpleTableRecord>(element); - await element.setData([{ field1: 'a' }]); + pageObject = new TablePageObject<SimpleTableRecord>(model.table); + await model.table.setData([{ field1: 'a' }]); await connect(); await waitForUpdatesAsync(); model.col1.groupIndex = 0; @@ -247,12 +256,12 @@ describe('TableColumnEnumText', () => { it('removes title on mouseout of group header', async () => { const cellContents = 'a very long value that should get ellipsized due to not fitting within the default cell width'; - ({ element, connect, disconnect, model } = await setup([ + ({ connect, disconnect, model } = await setup([ { key: 'a', text: cellContents } ])); - pageObject = new TablePageObject<SimpleTableRecord>(element); - await element.setData([{ field1: 'a' }]); - element.style.width = '200px'; + pageObject = new TablePageObject<SimpleTableRecord>(model.table); + await model.table.setData([{ field1: 'a' }]); + model.table.style.width = '200px'; await connect(); await waitForUpdatesAsync(); model.col1.groupIndex = 0; @@ -266,10 +275,7 @@ describe('TableColumnEnumText', () => { describe('validation', () => { it('is valid with no mappings', async () => { - ({ element, connect, disconnect, model } = await setup( - [], - 'number' - )); + ({ connect, disconnect, model } = await setup([], 'number')); await connect(); await waitForUpdatesAsync(); const column = model.col1; @@ -281,7 +287,7 @@ describe('TableColumnEnumText', () => { }); it('is valid with valid numeric key values', async () => { - ({ element, connect, disconnect, model } = await setup( + ({ connect, disconnect, model } = await setup( [ { key: '0', text: 'alpha' }, { key: '1', text: 'alpha' }, @@ -299,7 +305,7 @@ describe('TableColumnEnumText', () => { }); it('is invalid with invalid numeric key values', async () => { - ({ element, connect, disconnect, model } = await setup( + ({ connect, disconnect, model } = await setup( [{ key: 'a', text: 'alpha' }], 'number' )); @@ -311,7 +317,7 @@ describe('TableColumnEnumText', () => { }); it('is valid with valid boolean key values', async () => { - ({ element, connect, disconnect, model } = await setup( + ({ connect, disconnect, model } = await setup( [ { key: true, text: 'alpha' }, { key: false, text: 'alpha' } @@ -333,7 +339,7 @@ describe('TableColumnEnumText', () => { ] as const; parameterizeSpec(dataTypeTests, (spec, name, value) => { spec(name, async () => { - ({ element, connect, disconnect, model } = await setup( + ({ connect, disconnect, model } = await setup( [{ key: value.key, text: 'alpha' }], 'boolean' )); @@ -348,18 +354,11 @@ describe('TableColumnEnumText', () => { }); }); - class ModelInvalidMappings { - public col1!: TableColumnEnumText; - public col2!: TableColumnEnumText; - } - interface ModelInvalidMappingsFixture<T> extends Fixture<T> { - model: ModelInvalidMappings; - } // prettier-ignore - async function setupInvalidMappings(): Promise<ModelInvalidMappingsFixture<Table<SimpleTableRecord>>> { - const source = new ModelInvalidMappings(); - const result = await fixture<Table<SimpleTableRecord>>(html<ModelInvalidMappings>` - <${tableTag} style="width: 700px"> + async function setupInvalidMappings(): Promise<ModelFixture<Table<SimpleTableRecord>>> { + const source = new Model(); + const result = await fixture<Table<SimpleTableRecord>>(html<Model>` + <${tableTag} ${ref('table')} style="width: 700px"> <${tableColumnEnumTextTag} ${ref('col1')} field-name="field1"> Column 1 <${mappingTextTag} key="foo" label="foo"></${mappingTextTag}> @@ -378,7 +377,7 @@ describe('TableColumnEnumText', () => { }; } it('is invalid with icon or spinner mappings', async () => { - ({ element, connect, disconnect, model } = await setupInvalidMappings()); + ({ connect, disconnect, model } = await setupInvalidMappings()); await connect(); await waitForUpdatesAsync(); const column1 = model.col1; @@ -390,7 +389,7 @@ describe('TableColumnEnumText', () => { }); it('is invalid with duplicate key values', async () => { - ({ element, connect, disconnect, model } = await setup([ + ({ connect, disconnect, model } = await setup([ { key: 'a', text: 'alpha' }, { key: 'a', text: 'alpha' } ])); @@ -402,7 +401,7 @@ describe('TableColumnEnumText', () => { }); it('is invalid with equivalent numeric key values', async () => { - ({ element, connect, disconnect, model } = await setup( + ({ connect, disconnect, model } = await setup( [ { key: '0', text: 'alpha' }, { key: '0.0', text: 'alpha' } @@ -417,9 +416,7 @@ describe('TableColumnEnumText', () => { }); it('is invalid with missing key value', async () => { - ({ element, connect, disconnect, model } = await setup([ - { text: 'alpha' } - ])); + ({ connect, disconnect, model } = await setup([{ text: 'alpha' }])); await connect(); await waitForUpdatesAsync(); const column = model.col1; @@ -428,9 +425,7 @@ describe('TableColumnEnumText', () => { }); it('is invalid with missing text', async () => { - ({ element, connect, disconnect, model } = await setup([ - { key: 'a' } - ])); + ({ connect, disconnect, model } = await setup([{ key: 'a' }])); await connect(); await waitForUpdatesAsync(); const column = model.col1; @@ -438,4 +433,48 @@ describe('TableColumnEnumText', () => { expect(column.validity.missingTextValue).toBeTrue(); }); }); + + describe('placeholder', () => { + const testCases = [ + { + name: 'value is not specified', + data: [{}], + groupValue: 'No value' + }, + { + name: 'value is undefined', + data: [{ field1: undefined }], + groupValue: 'No value' + }, + { + name: 'value is null', + data: [{ field1: null }], + groupValue: 'No value' + }, + { + name: 'value is unmapped value', + data: [{ field1: 'no match' }], + groupValue: '' + } + ]; + + parameterizeSpec(testCases, (spec, name, value) => { + spec(`group row renders expected value when ${name}`, async () => { + ({ connect, disconnect, model } = await setup([ + { key: 'a', text: 'alpha' } + ])); + pageObject = new TablePageObject<SimpleTableRecord>( + model.table + ); + model.col1.groupIndex = 0; + await model.table.setData(value.data); + await connect(); + await waitForUpdatesAsync(); + + expect(pageObject.getRenderedGroupHeaderTextContent(0)).toBe( + value.groupValue + ); + }); + }); + }); }); diff --git a/packages/nimble-components/src/table-column/icon/group-header-view/index.ts b/packages/nimble-components/src/table-column/icon/group-header-view/index.ts index aefbcaae8e..a2a13efc77 100644 --- a/packages/nimble-components/src/table-column/icon/group-header-view/index.ts +++ b/packages/nimble-components/src/table-column/icon/group-header-view/index.ts @@ -36,24 +36,14 @@ export class TableColumnIconGroupHeaderView @observable public visual?: 'spinner' | 'icon'; - private columnConfigChanged(): void { - this.updateState(); - } - - private groupHeaderValueChanged(): void { - this.updateState(); - } - - private updateState(): void { + protected updateText(): void { this.visual = undefined; if (!this.columnConfig) { + this.text = ''; return; } const value = this.groupHeaderValue; - if (value === undefined || value === null) { - return; - } - const mappingConfig = this.columnConfig.mappingConfigs.get(value); + const mappingConfig = this.columnConfig.mappingConfigs.get(value!); if (mappingConfig instanceof MappingIconConfig) { this.visual = 'icon'; this.severity = mappingConfig.severity; diff --git a/packages/nimble-components/src/table-column/icon/group-header-view/template.ts b/packages/nimble-components/src/table-column/icon/group-header-view/template.ts index de5a04f639..9e23ef2cf8 100644 --- a/packages/nimble-components/src/table-column/icon/group-header-view/template.ts +++ b/packages/nimble-components/src/table-column/icon/group-header-view/template.ts @@ -29,4 +29,13 @@ export const template = html<TableColumnIconGroupHeaderView>` >${x => x.text}</span> ` )} + ${when( + x => x.visual === undefined, + html<TableColumnIconGroupHeaderView>` + <span + ${overflow('hasOverflow')} + title="${x => (x.hasOverflow && x.text ? x.text : null)}" + >${x => x.text}</span> + ` + )} `; diff --git a/packages/nimble-components/src/table-column/icon/tests/table-column-icon.spec.ts b/packages/nimble-components/src/table-column/icon/tests/table-column-icon.spec.ts index daabf451aa..3c2e597b3a 100644 --- a/packages/nimble-components/src/table-column/icon/tests/table-column-icon.spec.ts +++ b/packages/nimble-components/src/table-column/icon/tests/table-column-icon.spec.ts @@ -16,10 +16,11 @@ import { IconSeverity } from '../../../icon-base/types'; import { MappingKeyType } from '../../enum-base/types'; import { mappingSpinnerTag } from '../../../mapping/spinner'; import { spinnerTag } from '../../../spinner'; +import { themeProviderTag } from '../../../theme-provider'; interface SimpleTableRecord extends TableRecord { - field1?: MappingKey | undefined; - field2?: MappingKey | undefined; + field1?: MappingKey | null; + field2?: MappingKey | null; } interface BasicIconMapping { @@ -34,6 +35,7 @@ interface BasicSpinnerMapping { } class Model { + public table!: Table<SimpleTableRecord>; public col1!: TableColumnIcon; } interface ModelFixture<T> extends Fixture<T> { @@ -41,7 +43,6 @@ interface ModelFixture<T> extends Fixture<T> { } describe('TableColumnIcon', () => { - let element: Table<SimpleTableRecord>; let connect: () => Promise<void>; let disconnect: () => Promise<void>; let pageObject: TablePageObject<SimpleTableRecord>; @@ -55,24 +56,26 @@ describe('TableColumnIcon', () => { }): Promise<ModelFixture<Table<SimpleTableRecord>>> { const source = new Model(); const result = await fixture<Table<SimpleTableRecord>>(html<Model>` - <${tableTag} style="width: 700px"> - <${tableColumnIconTag} ${ref('col1')} field-name="field1" key-type="${options.keyType}"> - Column 1 - ${repeat(() => options.iconMappings, html<BasicIconMapping>` - <${mappingIconTag} + <${themeProviderTag} lang="en-US"> + <${tableTag} ${ref('table')} style="width: 700px"> + <${tableColumnIconTag} ${ref('col1')} field-name="field1" key-type="${options.keyType}"> + Column 1 + ${repeat(() => options.iconMappings, html<BasicIconMapping>` + <${mappingIconTag} + key="${x => x.key}" + text="${x => x.text}" + icon="${x => x.icon}"> + </${mappingIconTag}> + `)} + ${repeat(() => options.spinnerMappings, html<BasicSpinnerMapping>` + <${mappingSpinnerTag} key="${x => x.key}" text="${x => x.text}" - icon="${x => x.icon}"> - </${mappingIconTag}> - `)} - ${repeat(() => options.spinnerMappings, html<BasicSpinnerMapping>` - <${mappingSpinnerTag} - key="${x => x.key}" - text="${x => x.text}" - </${mappingSpinnerTag}> - `)} - </${tableColumnIconTag}> - </${tableTag}>`, { source }); + </${mappingSpinnerTag}> + `)} + </${tableColumnIconTag}> + </${tableTag}> + <${themeProviderTag}>`, { source }); return { ...result, model: source @@ -103,15 +106,17 @@ describe('TableColumnIcon', () => { ] as const; parameterizeSpec(dataTypeTests, (spec, name, value) => { spec(`displays icon mapped from ${name}`, async () => { - ({ element, connect, disconnect, model } = await setup({ + ({ connect, disconnect, model } = await setup({ keyType: value.name, iconMappings: [ { key: value.key, text: 'alpha', icon: iconXmarkTag } ], spinnerMappings: [] })); - pageObject = new TablePageObject<SimpleTableRecord>(element); - await element.setData([{ field1: value.key }]); + pageObject = new TablePageObject<SimpleTableRecord>( + model.table + ); + await model.table.setData([{ field1: value.key }]); await connect(); await waitForUpdatesAsync(); @@ -123,13 +128,15 @@ describe('TableColumnIcon', () => { parameterizeSpec(dataTypeTests, (spec, name, value) => { spec(`displays spinner mapped from ${name}`, async () => { - ({ element, connect, disconnect, model } = await setup({ + ({ connect, disconnect, model } = await setup({ keyType: value.name, iconMappings: [], spinnerMappings: [{ key: value.key, text: 'alpha' }] })); - pageObject = new TablePageObject<SimpleTableRecord>(element); - await element.setData([{ field1: value.key }]); + pageObject = new TablePageObject<SimpleTableRecord>( + model.table + ); + await model.table.setData([{ field1: value.key }]); await connect(); await waitForUpdatesAsync(); @@ -141,13 +148,13 @@ describe('TableColumnIcon', () => { }); it('displays blank when no matches', async () => { - ({ element, connect, disconnect, model } = await setup({ + ({ connect, disconnect, model } = await setup({ keyType: MappingKeyType.string, iconMappings: [{ key: 'a', text: 'alpha', icon: iconXmarkTag }], spinnerMappings: [] })); - pageObject = new TablePageObject<SimpleTableRecord>(element); - await element.setData([{ field1: 'no match' }]); + pageObject = new TablePageObject<SimpleTableRecord>(model.table); + await model.table.setData([{ field1: 'no match' }]); await connect(); await waitForUpdatesAsync(); @@ -155,13 +162,13 @@ describe('TableColumnIcon', () => { }); it('displays blank when no icon specified for mapping', async () => { - ({ element, connect, disconnect, model } = await setup({ + ({ connect, disconnect, model } = await setup({ keyType: MappingKeyType.string, iconMappings: [{ key: 'a', text: 'alpha', icon: undefined }], spinnerMappings: [] })); - pageObject = new TablePageObject<SimpleTableRecord>(element); - await element.setData([{ field1: 'a' }]); + pageObject = new TablePageObject<SimpleTableRecord>(model.table); + await model.table.setData([{ field1: 'a' }]); await connect(); await waitForUpdatesAsync(); @@ -169,7 +176,7 @@ describe('TableColumnIcon', () => { }); it('changing fieldName updates display', async () => { - ({ element, connect, disconnect, model } = await setup({ + ({ connect, disconnect, model } = await setup({ keyType: MappingKeyType.string, iconMappings: [ { key: 'a', text: 'alpha', icon: iconXmarkTag }, @@ -177,8 +184,8 @@ describe('TableColumnIcon', () => { ], spinnerMappings: [] })); - pageObject = new TablePageObject<SimpleTableRecord>(element); - await element.setData([{ field1: 'a', field2: 'b' }]); + pageObject = new TablePageObject<SimpleTableRecord>(model.table); + await model.table.setData([{ field1: 'a', field2: 'b' }]); await connect(); await waitForUpdatesAsync(); @@ -191,13 +198,13 @@ describe('TableColumnIcon', () => { }); it('changing mapping icon updates display', async () => { - ({ element, connect, disconnect, model } = await setup({ + ({ connect, disconnect, model } = await setup({ keyType: MappingKeyType.string, iconMappings: [{ key: 'a', text: 'alpha', icon: iconXmarkTag }], spinnerMappings: [] })); - pageObject = new TablePageObject<SimpleTableRecord>(element); - await element.setData([{ field1: 'a' }]); + pageObject = new TablePageObject<SimpleTableRecord>(model.table); + await model.table.setData([{ field1: 'a' }]); await connect(); await waitForUpdatesAsync(); @@ -211,13 +218,13 @@ describe('TableColumnIcon', () => { }); it('changing mapping severity updates display', async () => { - ({ element, connect, disconnect, model } = await setup({ + ({ connect, disconnect, model } = await setup({ keyType: MappingKeyType.string, iconMappings: [{ key: 'a', text: 'alpha', icon: iconXmarkTag }], spinnerMappings: [] })); - pageObject = new TablePageObject<SimpleTableRecord>(element); - await element.setData([{ field1: 'a' }]); + pageObject = new TablePageObject<SimpleTableRecord>(model.table); + await model.table.setData([{ field1: 'a' }]); await connect(); await waitForUpdatesAsync(); @@ -231,13 +238,13 @@ describe('TableColumnIcon', () => { }); it('changing mapping key updates display', async () => { - ({ element, connect, disconnect, model } = await setup({ + ({ connect, disconnect, model } = await setup({ keyType: MappingKeyType.string, iconMappings: [{ key: 'a', text: 'alpha', icon: iconXmarkTag }], spinnerMappings: [] })); - pageObject = new TablePageObject<SimpleTableRecord>(element); - await element.setData([{ field1: 'b' }]); + pageObject = new TablePageObject<SimpleTableRecord>(model.table); + await model.table.setData([{ field1: 'b' }]); await connect(); await waitForUpdatesAsync(); @@ -251,26 +258,26 @@ describe('TableColumnIcon', () => { }); it('sets label as title of icon', async () => { - ({ element, connect, disconnect, model } = await setup({ + ({ connect, disconnect, model } = await setup({ keyType: MappingKeyType.string, iconMappings: [{ key: 'a', text: 'alpha', icon: iconXmarkTag }], spinnerMappings: [] })); - pageObject = new TablePageObject<SimpleTableRecord>(element); - await element.setData([{ field1: 'a' }]); + pageObject = new TablePageObject<SimpleTableRecord>(model.table); + await model.table.setData([{ field1: 'a' }]); await connect(); await waitForUpdatesAsync(); expect(pageObject.getCellTitle(0, 0)).toBe('alpha'); }); it('sets label as aria-label of icon', async () => { - ({ element, connect, disconnect, model } = await setup({ + ({ connect, disconnect, model } = await setup({ keyType: MappingKeyType.string, iconMappings: [{ key: 'a', text: 'alpha', icon: iconXmarkTag }], spinnerMappings: [] })); - pageObject = new TablePageObject<SimpleTableRecord>(element); - await element.setData([{ field1: 'a' }]); + pageObject = new TablePageObject<SimpleTableRecord>(model.table); + await model.table.setData([{ field1: 'a' }]); await connect(); await waitForUpdatesAsync(); expect(pageObject.getRenderedIconColumnCellIconAriaLabel(0, 0)).toBe( @@ -281,7 +288,7 @@ describe('TableColumnIcon', () => { describe('various string values render in group header as expected', () => { parameterizeSpec(wackyStrings, (spec, name) => { spec(`data "${name}" renders as "${name}"`, async () => { - ({ element, connect, disconnect, model } = await setup({ + ({ connect, disconnect, model } = await setup({ keyType: MappingKeyType.string, iconMappings: [ { @@ -292,8 +299,10 @@ describe('TableColumnIcon', () => { ], spinnerMappings: [] })); - pageObject = new TablePageObject<SimpleTableRecord>(element); - await element.setData([{ field1: 'a' }]); + pageObject = new TablePageObject<SimpleTableRecord>( + model.table + ); + await model.table.setData([{ field1: 'a' }]); await connect(); await waitForUpdatesAsync(); model.col1.groupIndex = 0; @@ -306,30 +315,14 @@ describe('TableColumnIcon', () => { }); }); - it('sets group header text to blank when unmatched', async () => { - ({ element, connect, disconnect, model } = await setup({ - keyType: MappingKeyType.string, - iconMappings: [{ key: 'b', text: 'bravo', icon: iconXmarkTag }], - spinnerMappings: [] - })); - pageObject = new TablePageObject<SimpleTableRecord>(element); - await element.setData([{ field1: 'unmatched' }]); - await connect(); - await waitForUpdatesAsync(); - model.col1.groupIndex = 0; - await waitForUpdatesAsync(); - - expect(pageObject.getRenderedGroupHeaderTextContent(0)).toBe(''); - }); - it('sets group header text label and no icon when icon is undefined', async () => { - ({ element, connect, disconnect, model } = await setup({ + ({ connect, disconnect, model } = await setup({ keyType: MappingKeyType.string, iconMappings: [{ key: 'b', text: 'bravo', icon: undefined }], spinnerMappings: [] })); - pageObject = new TablePageObject<SimpleTableRecord>(element); - await element.setData([{ field1: 'b' }]); + pageObject = new TablePageObject<SimpleTableRecord>(model.table); + await model.table.setData([{ field1: 'b' }]); await connect(); await waitForUpdatesAsync(); model.col1.groupIndex = 0; @@ -340,13 +333,13 @@ describe('TableColumnIcon', () => { }); it('clears cell when mappings removed', async () => { - ({ element, connect, disconnect, model } = await setup({ + ({ connect, disconnect, model } = await setup({ keyType: MappingKeyType.string, iconMappings: [{ key: 'a', text: 'alpha', icon: iconXmarkTag }], spinnerMappings: [] })); - pageObject = new TablePageObject<SimpleTableRecord>(element); - await element.setData([{ field1: 'a' }]); + pageObject = new TablePageObject<SimpleTableRecord>(model.table); + await model.table.setData([{ field1: 'a' }]); await connect(); await waitForUpdatesAsync(); expect(pageObject.getRenderedIconColumnCellIconTagName(0, 0)).toBe( @@ -359,13 +352,13 @@ describe('TableColumnIcon', () => { }); it('clears group header when mappings removed', async () => { - ({ element, connect, disconnect, model } = await setup({ + ({ connect, disconnect, model } = await setup({ keyType: MappingKeyType.string, iconMappings: [{ key: 'a', text: 'alpha', icon: iconXmarkTag }], spinnerMappings: [] })); - pageObject = new TablePageObject<SimpleTableRecord>(element); - await element.setData([{ field1: 'a' }]); + pageObject = new TablePageObject<SimpleTableRecord>(model.table); + await model.table.setData([{ field1: 'a' }]); model.col1.groupIndex = 0; await connect(); await waitForUpdatesAsync(); @@ -380,7 +373,7 @@ describe('TableColumnIcon', () => { describe('validation', () => { it('is valid with no mappings', async () => { - ({ element, connect, disconnect, model } = await setup({ + ({ connect, disconnect, model } = await setup({ keyType: MappingKeyType.number, iconMappings: [], spinnerMappings: [] @@ -397,7 +390,7 @@ describe('TableColumnIcon', () => { }); it('is valid with valid numeric key values', async () => { - ({ element, connect, disconnect, model } = await setup({ + ({ connect, disconnect, model } = await setup({ keyType: MappingKeyType.number, iconMappings: [ { key: '0', text: 'alpha', icon: iconXmarkTag }, @@ -424,7 +417,7 @@ describe('TableColumnIcon', () => { ] as const; parameterizeSpec(dataTypeTests, (spec, name, value) => { spec(name, async () => { - ({ element, connect, disconnect, model } = await setup({ + ({ connect, disconnect, model } = await setup({ keyType: MappingKeyType.boolean, iconMappings: [ { @@ -446,7 +439,7 @@ describe('TableColumnIcon', () => { }); it('is invalid with invalid numeric key values', async () => { - ({ element, connect, disconnect, model } = await setup({ + ({ connect, disconnect, model } = await setup({ keyType: MappingKeyType.number, iconMappings: [{ key: 'a', text: 'alpha', icon: iconXmarkTag }], spinnerMappings: [] @@ -472,6 +465,7 @@ describe('TableColumnIcon', () => { ); } it('is invalid with text mapping', async () => { + let element: Table<SimpleTableRecord>; ({ element, connect, disconnect } = await setupInvalidMappings()); await connect(); await waitForUpdatesAsync(); @@ -481,7 +475,7 @@ describe('TableColumnIcon', () => { }); it('is invalid with duplicate key values', async () => { - ({ element, connect, disconnect, model } = await setup({ + ({ connect, disconnect, model } = await setup({ keyType: MappingKeyType.string, iconMappings: [ { key: 'a', text: 'alpha', icon: iconXmarkTag }, @@ -496,7 +490,7 @@ describe('TableColumnIcon', () => { }); it('is invalid with equivalent numeric key values', async () => { - ({ element, connect, disconnect, model } = await setup({ + ({ connect, disconnect, model } = await setup({ keyType: MappingKeyType.number, iconMappings: [ { key: '0', text: 'alpha', icon: iconXmarkTag }, @@ -511,7 +505,7 @@ describe('TableColumnIcon', () => { }); it('is invalid with missing key value', async () => { - ({ element, connect, disconnect, model } = await setup({ + ({ connect, disconnect, model } = await setup({ keyType: MappingKeyType.string, iconMappings: [{ text: 'alpha', icon: iconXmarkTag }], spinnerMappings: [] @@ -523,7 +517,7 @@ describe('TableColumnIcon', () => { }); it('is invalid with missing icon text value', async () => { - ({ element, connect, disconnect, model } = await setup({ + ({ connect, disconnect, model } = await setup({ keyType: MappingKeyType.string, iconMappings: [{ key: 'a', icon: iconXmarkTag }], spinnerMappings: [] @@ -535,7 +529,7 @@ describe('TableColumnIcon', () => { }); it('is invalid with non-icon icon value', async () => { - ({ element, connect, disconnect, model } = await setup({ + ({ connect, disconnect, model } = await setup({ keyType: MappingKeyType.string, iconMappings: [{ key: 'a', text: 'alpha', icon: 'div' }], spinnerMappings: [] @@ -547,7 +541,7 @@ describe('TableColumnIcon', () => { }); it('is invalid with completely made up icon value', async () => { - ({ element, connect, disconnect, model } = await setup({ + ({ connect, disconnect, model } = await setup({ keyType: MappingKeyType.string, iconMappings: [{ key: 'a', text: 'alpha', icon: 'foo' }], spinnerMappings: [] @@ -559,7 +553,7 @@ describe('TableColumnIcon', () => { }); it('is invalid with missing spinner text value', async () => { - ({ element, connect, disconnect, model } = await setup({ + ({ connect, disconnect, model } = await setup({ keyType: MappingKeyType.string, iconMappings: [], spinnerMappings: [{ key: 'a' }] @@ -570,4 +564,50 @@ describe('TableColumnIcon', () => { expect(model.col1.validity.missingTextValue).toBeTrue(); }); }); + + describe('placeholder', () => { + const testCases = [ + { + name: 'value is not specified', + data: [{}], + groupValue: 'No value' + }, + { + name: 'value is undefined', + data: [{ field1: undefined }], + groupValue: 'No value' + }, + { + name: 'value is null', + data: [{ field1: null }], + groupValue: 'No value' + }, + { + name: 'value is unmapped value', + data: [{ field1: 'no match' }], + groupValue: '' + } + ]; + + parameterizeSpec(testCases, (spec, name, value) => { + spec(`group row renders expected value when ${name}`, async () => { + ({ connect, disconnect, model } = await setup({ + keyType: MappingKeyType.string, + iconMappings: [], + spinnerMappings: [{ key: 'a', text: 'a' }] + })); + pageObject = new TablePageObject<SimpleTableRecord>( + model.table + ); + model.col1.groupIndex = 0; + await model.table.setData(value.data); + await connect(); + await waitForUpdatesAsync(); + + expect(pageObject.getRenderedGroupHeaderTextContent(0)).toBe( + value.groupValue + ); + }); + }); + }); }); diff --git a/packages/nimble-components/src/table-column/number-text/group-header-view/index.ts b/packages/nimble-components/src/table-column/number-text/group-header-view/index.ts index 17666de1aa..1fb5389b9e 100644 --- a/packages/nimble-components/src/table-column/number-text/group-header-view/index.ts +++ b/packages/nimble-components/src/table-column/number-text/group-header-view/index.ts @@ -17,15 +17,7 @@ export class TableColumnNumberTextGroupHeaderView extends TableColumnTextGroupHe TableNumberFieldValue, TableColumnNumberTextColumnConfig > { - private columnConfigChanged(): void { - this.updateText(); - } - - private groupHeaderValueChanged(): void { - this.updateText(); - } - - private updateText(): void { + protected updateText(): void { this.text = this.columnConfig?.formatter?.format(this.groupHeaderValue) ?? ''; } } diff --git a/packages/nimble-components/src/table-column/number-text/tests/table-column-number-text.spec.ts b/packages/nimble-components/src/table-column/number-text/tests/table-column-number-text.spec.ts index 75c2b9af7b..cc1163995f 100644 --- a/packages/nimble-components/src/table-column/number-text/tests/table-column-number-text.spec.ts +++ b/packages/nimble-components/src/table-column/number-text/tests/table-column-number-text.spec.ts @@ -170,7 +170,9 @@ describe('TableColumnNumberText', () => { await waitForUpdatesAsync(); expect(pageObject.getRenderedCellTextContent(0, 0)).toBe(''); - expect(pageObject.getRenderedGroupHeaderTextContent(0)).toBe(''); + expect(pageObject.getRenderedGroupHeaderTextContent(0)).toBe( + 'No value' + ); }); it('changing data from null to value displays value', async () => { @@ -178,7 +180,9 @@ describe('TableColumnNumberText', () => { await connect(); await waitForUpdatesAsync(); expect(pageObject.getRenderedCellTextContent(0, 0)).toBe(''); - expect(pageObject.getRenderedGroupHeaderTextContent(0)).toBe(''); + expect(pageObject.getRenderedGroupHeaderTextContent(0)).toBe( + 'No value' + ); await table.setData([{ number1: -16 }]); await waitForUpdatesAsync(); @@ -196,7 +200,9 @@ describe('TableColumnNumberText', () => { await waitForUpdatesAsync(); expect(pageObject.getRenderedCellTextContent(0, 0)).toBe(''); - expect(pageObject.getRenderedGroupHeaderTextContent(0)).toBe(''); + expect(pageObject.getRenderedGroupHeaderTextContent(0)).toBe( + 'No value' + ); }); describe('displays title when appropriate', () => { @@ -727,4 +733,56 @@ describe('TableColumnNumberText', () => { expect(cellView.alignment).toEqual(TextCellViewBaseAlignment.left); }); }); + + describe('placeholder', () => { + const testCases = [ + { + name: 'value is not specified', + data: [{}], + groupValue: 'No value' + }, + { + name: 'value is undefined', + data: [{ number1: undefined }], + groupValue: 'No value' + }, + { + name: 'value is null', + data: [{ number1: null }], + groupValue: 'No value' + }, + { + name: 'value is Number.NaN', + data: [{ number1: Number.NaN }], + groupValue: 'NaN' + }, + { + name: 'value is valid and non-zero', + data: [{ number1: 100 }], + groupValue: '100' + }, + { + name: 'value is incorrect type', + data: [{ number1: 'not a number' as unknown as number }], + groupValue: '' + }, + { + name: 'value is specified and falsey', + data: [{ number1: 0 }], + groupValue: '0' + } + ]; + + parameterizeSpec(testCases, (spec, name, value) => { + spec(`group row renders expected value when ${name}`, async () => { + await table.setData(value.data); + await connect(); + await waitForUpdatesAsync(); + + expect(pageObject.getRenderedGroupHeaderTextContent(0)).toBe( + value.groupValue + ); + }); + }); + }); }); diff --git a/packages/nimble-components/src/table-column/text-base/cell-view/tests/table-column-text-base-group-header-view.spec.ts b/packages/nimble-components/src/table-column/text-base/cell-view/tests/table-column-text-base-group-header-view.spec.ts new file mode 100644 index 0000000000..4875bed262 --- /dev/null +++ b/packages/nimble-components/src/table-column/text-base/cell-view/tests/table-column-text-base-group-header-view.spec.ts @@ -0,0 +1,141 @@ +// eslint-disable-next-line max-classes-per-file +import { customElement, html, ref } from '@microsoft/fast-element'; +import { parameterizeSpec } from '@ni/jasmine-parameterized'; +import { + uniqueElementName, + type Fixture, + fixture +} from '../../../../utilities/tests/fixture'; +import { waitForUpdatesAsync } from '../../../../testing/async-helpers'; +import { template as textBaseGroupHeaderViewTemplate } from '../template'; +import { styles as textBaseGroupHeaderViewStyles } from '../styles'; +import { TableColumnTextGroupHeaderViewBase } from '../../group-header-view'; +import { ThemeProvider, themeProviderTag } from '../../../../theme-provider'; +import { + LabelProviderTable, + labelProviderTableTag +} from '../../../../label-provider/table'; + +describe('TableColumnTextBaseGroupHeaderView', () => { + let labelProvider: LabelProviderTable; + let groupHeaderView: TableColumnTextGroupHeaderViewBase; + let connect: () => Promise<void>; + let disconnect: () => Promise<void>; + + const testTextBaseGroupHeaderViewTag = uniqueElementName(); + /** + * Simple concrete class extending TableColumnTextCellViewBase to use for testing + */ + @customElement({ + name: testTextBaseGroupHeaderViewTag, + template: textBaseGroupHeaderViewTemplate, + styles: textBaseGroupHeaderViewStyles + }) + // eslint-disable-next-line @typescript-eslint/no-unused-vars + class TestTextBaseGroupHeaderView extends TableColumnTextGroupHeaderViewBase { + protected override updateText(): void { + this.text = this.groupHeaderValue as string; + } + } + + class ElementReferences { + public labelProvider!: LabelProviderTable; + public groupView!: TableColumnTextGroupHeaderViewBase; + } + + async function setup( + source: ElementReferences + ): Promise<Fixture<ThemeProvider>> { + return fixture<ThemeProvider>( + html`<${themeProviderTag} lang="en-US"> + <${labelProviderTableTag} ${ref('labelProvider')}></${labelProviderTableTag}> + <${testTextBaseGroupHeaderViewTag} ${ref('groupView')}></${testTextBaseGroupHeaderViewTag}> + </${themeProviderTag}>`, + { source } + ); + } + + function getRenderedText(): string { + return groupHeaderView + .shadowRoot!.querySelector('span')! + .innerText.trim(); + } + + beforeEach(async () => { + const source = new ElementReferences(); + ({ connect, disconnect } = await setup(source)); + labelProvider = source.labelProvider; + groupHeaderView = source.groupView; + await connect(); + }); + + afterEach(async () => { + await disconnect(); + }); + + const testCases = [ + { + name: 'empty string', + value: '', + renderedText: 'Empty', + labelProviderProperty: 'groupRowPlaceholderEmpty' + }, + { + name: 'null', + value: null, + renderedText: 'No value', + labelProviderProperty: 'groupRowPlaceholderNoValue' + }, + { + name: 'undefined', + value: undefined, + renderedText: 'No value', + labelProviderProperty: 'groupRowPlaceholderNoValue' + } + ] as const; + + parameterizeSpec(testCases, (spec, name, value) => { + spec( + `uses default label provider string when the value is ${name}`, + async () => { + groupHeaderView.groupHeaderValue = value.value; + await waitForUpdatesAsync(); + expect(getRenderedText()).toBe(value.renderedText); + } + ); + }); + + parameterizeSpec(testCases, (spec, name, value) => { + spec( + `updates group row with modified label provider string when the value is ${name}`, + async () => { + const customLabelProviderValue = 'Custom label provider value'; + groupHeaderView.groupHeaderValue = value.value; + await waitForUpdatesAsync(); + labelProvider[value.labelProviderProperty] = customLabelProviderValue; + await waitForUpdatesAsync(); + + expect(getRenderedText()).toBe(customLabelProviderValue); + } + ); + }); + + parameterizeSpec(testCases, (spec, name, value) => { + spec( + `uses label provider value that was modified while the element was disconnected when the value is ${name}`, + async () => { + groupHeaderView.groupHeaderValue = value.value; + await waitForUpdatesAsync(); + await disconnect(); + + const customLabelProviderValue = 'Custom label provider value'; + labelProvider[value.labelProviderProperty] = customLabelProviderValue; + + await connect(); + await waitForUpdatesAsync(); + + expect(getRenderedText()).toBe(customLabelProviderValue); + } + ); + }); +}); diff --git a/packages/nimble-components/src/table-column/text-base/group-header-view/index.ts b/packages/nimble-components/src/table-column/text-base/group-header-view/index.ts index 299dc0008d..7da6d8df76 100644 --- a/packages/nimble-components/src/table-column/text-base/group-header-view/index.ts +++ b/packages/nimble-components/src/table-column/text-base/group-header-view/index.ts @@ -1,6 +1,11 @@ +import type { DesignTokenSubscriber } from '@microsoft/fast-foundation'; import { observable } from '@microsoft/fast-element'; import { TableGroupHeaderView } from '../../base/group-header-view'; import type { TableFieldValue } from '../../../table/types'; +import { + tableGroupRowPlaceholderEmptyLabel, + tableGroupRowPlaceholderNoValueLabel +} from '../../../label-provider/table/label-tokens'; /** * The group header view base class for displaying fields of any type as text. @@ -15,7 +20,83 @@ export abstract class TableColumnTextGroupHeaderViewBase< /** * Text to render in the cell. + * + * The value is initialized to `tableGroupRowPlaceholderNoValue` because if the group + * row never has a value defined on it, the change handlers may never get called but + * the text needs to be correct. */ @observable - public text = ''; + public text = tableGroupRowPlaceholderNoValueLabel.getValueFor(this); + + private readonly noValuePlaceholderLabelSubscriber: DesignTokenSubscriber< + typeof tableGroupRowPlaceholderNoValueLabel + > = { + handleChange: () => { + this.applyPlaceholderTextIfNeeded(); + } + }; + + private readonly emptyPlaceholderLabelSubscriber: DesignTokenSubscriber< + typeof tableGroupRowPlaceholderEmptyLabel + > = { + handleChange: () => { + this.applyPlaceholderTextIfNeeded(); + } + }; + + public override connectedCallback(): void { + super.connectedCallback(); + tableGroupRowPlaceholderNoValueLabel.subscribe( + this.noValuePlaceholderLabelSubscriber, + this + ); + tableGroupRowPlaceholderEmptyLabel.subscribe( + this.emptyPlaceholderLabelSubscriber, + this + ); + this.applyPlaceholderTextIfNeeded(); + } + + public override disconnectedCallback(): void { + super.disconnectedCallback(); + tableGroupRowPlaceholderNoValueLabel.unsubscribe( + this.noValuePlaceholderLabelSubscriber + ); + tableGroupRowPlaceholderEmptyLabel.unsubscribe( + this.emptyPlaceholderLabelSubscriber + ); + } + + protected abstract updateText(): void; + + private columnConfigChanged(): void { + if (!this.applyPlaceholderTextIfNeeded()) { + this.updateText(); + } + } + + private groupHeaderValueChanged(): void { + if (!this.applyPlaceholderTextIfNeeded()) { + this.updateText(); + } + } + + /** + * Sets `this.text` to the appropriate placeholder if `groupHeaderValue` warrants it. + * @returns `true` if `this.text` was set to a placeholder, `false` otherwise. + */ + private applyPlaceholderTextIfNeeded(): boolean { + if ( + this.groupHeaderValue === null + || this.groupHeaderValue === undefined + ) { + this.text = tableGroupRowPlaceholderNoValueLabel.getValueFor(this); + return true; + } + if (this.groupHeaderValue === '') { + this.text = tableGroupRowPlaceholderEmptyLabel.getValueFor(this); + return true; + } + return false; + } } diff --git a/packages/nimble-components/src/table-column/text/group-header-view/index.ts b/packages/nimble-components/src/table-column/text/group-header-view/index.ts index 7ce723aeba..44f67102a2 100644 --- a/packages/nimble-components/src/table-column/text/group-header-view/index.ts +++ b/packages/nimble-components/src/table-column/text/group-header-view/index.ts @@ -17,7 +17,7 @@ export class TableColumnTextGroupHeaderView extends TableColumnTextGroupHeaderVi TableStringFieldValue, TableColumnTextColumnConfig > { - private groupHeaderValueChanged(): void { + protected updateText(): void { this.text = typeof this.groupHeaderValue === 'string' ? this.groupHeaderValue : ''; diff --git a/packages/nimble-components/src/table-column/text/tests/table-column-text-matrix.stories.ts b/packages/nimble-components/src/table-column/text/tests/table-column-text-matrix.stories.ts new file mode 100644 index 0000000000..30e96422bf --- /dev/null +++ b/packages/nimble-components/src/table-column/text/tests/table-column-text-matrix.stories.ts @@ -0,0 +1,68 @@ +import type { StoryFn, Meta } from '@storybook/html'; +import { html, ViewTemplate } from '@microsoft/fast-element'; +import { + createMatrixThemeStory, + createMatrix, + sharedMatrixParameters +} from '../../../utilities/tests/matrix'; +import { Table, tableTag } from '../../../table'; +import { tableColumnTextTag } from '..'; + +const metadata: Meta = { + title: 'Tests/Table Column: Text', + parameters: { + ...sharedMatrixParameters() + } +}; + +export default metadata; + +const data = [ + { + id: '0', + firstName: 'Ralph' + }, + { + id: '1', + firstName: 'Milhouse' + }, + { + id: '2', + firstName: null + }, + { + id: '3', + firstName: '' + } +] as const; + +// prettier-ignore +const component = (): ViewTemplate => html` + <${tableTag} id-field-name="id" style="height: 320px"> + <${tableColumnTextTag} + field-name="id" + > + ID + </${tableColumnTextTag}> + <${tableColumnTextTag} + field-name="firstName" + group-index="0" + > + First name + </${tableColumnTextTag}> + </${tableTag}> +`; + +export const tableColumnTextThemeMatrix: StoryFn = createMatrixThemeStory( + createMatrix(component) +); + +tableColumnTextThemeMatrix.play = async (): Promise<void> => { + await Promise.all( + Array.from(document.querySelectorAll<Table>('nimble-table')).map( + async table => { + await table.setData(data); + } + ) + ); +}; diff --git a/packages/nimble-components/src/table-column/text/tests/table-column-text.spec.ts b/packages/nimble-components/src/table-column/text/tests/table-column-text.spec.ts index 46b243c8d9..0061dcc639 100644 --- a/packages/nimble-components/src/table-column/text/tests/table-column-text.spec.ts +++ b/packages/nimble-components/src/table-column/text/tests/table-column-text.spec.ts @@ -1,41 +1,54 @@ -import { html } from '@microsoft/fast-element'; +import { html, ref } from '@microsoft/fast-element'; import { parameterizeSpec } from '@ni/jasmine-parameterized'; -import type { Table } from '../../../table'; +import { tableTag, type Table } from '../../../table'; import { TableColumnText, tableColumnTextTag } from '..'; import { waitForUpdatesAsync } from '../../../testing/async-helpers'; import { type Fixture, fixture } from '../../../utilities/tests/fixture'; import type { TableRecord } from '../../../table/types'; import { TablePageObject } from '../../../table/testing/table.pageobject'; import { wackyStrings } from '../../../utilities/tests/wacky-strings'; +import { themeProviderTag } from '../../../theme-provider'; interface SimpleTableRecord extends TableRecord { field?: string | null; anotherField?: string | null; } +class ElementReferences { + public table!: Table; + public column!: TableColumnText; +} + // prettier-ignore -async function setup(): Promise<Fixture<Table<SimpleTableRecord>>> { +async function setup(source: ElementReferences): Promise<Fixture<Table<SimpleTableRecord>>> { return fixture<Table<SimpleTableRecord>>( - html`<nimble-table style="width: 700px"> - <${tableColumnTextTag} field-name="field" group-index="0"> - Column 1 - </${tableColumnTextTag}> - <${tableColumnTextTag} field-name="anotherField"> - Squeeze Column 1 - </${tableColumnTextTag}> - </nimble-table>` + html`<${themeProviderTag} lang="en-US"> + <${tableTag} ${ref('table')} style="width: 700px"> + <${tableColumnTextTag} ${ref('column')} field-name="field" group-index="0"> + Column 1 + </${tableColumnTextTag}> + <${tableColumnTextTag} field-name="anotherField"> + Squeeze Column 1 + </${tableColumnTextTag}> + </${tableTag}> + </${themeProviderTag}>`, + { source } ); } describe('TableColumnText', () => { - let element: Table<SimpleTableRecord>; + let table: Table<SimpleTableRecord>; + let column: TableColumnText; let connect: () => Promise<void>; let disconnect: () => Promise<void>; let pageObject: TablePageObject<SimpleTableRecord>; beforeEach(async () => { - ({ element, connect, disconnect } = await setup()); - pageObject = new TablePageObject<SimpleTableRecord>(element); + const elementReferences = new ElementReferences(); + ({ connect, disconnect } = await setup(elementReferences)); + table = elementReferences.table; + column = elementReferences.column; + pageObject = new TablePageObject<SimpleTableRecord>(table); }); afterEach(async () => { @@ -56,9 +69,7 @@ describe('TableColumnText', () => { await connect(); await waitForUpdatesAsync(); - const firstColumn = element.columns[0] as TableColumnText; - - expect(firstColumn.checkValidity()).toBeTrue(); + expect(column.checkValidity()).toBeTrue(); }); const noValueData = [ @@ -72,7 +83,7 @@ describe('TableColumnText', () => { ] as const; parameterizeSpec(noValueData, (spec, name, value) => { spec(`displays empty string when ${name}`, async () => { - await element.setData(value.data); + await table.setData(value.data); await connect(); await waitForUpdatesAsync(); @@ -81,38 +92,37 @@ describe('TableColumnText', () => { }); it('changing fieldName updates display', async () => { - await element.setData([{ field: 'foo', anotherField: 'bar' }]); + await table.setData([{ field: 'foo', anotherField: 'bar' }]); await connect(); await waitForUpdatesAsync(); - const firstColumn = element.columns[0] as TableColumnText; - firstColumn.fieldName = 'anotherField'; + column.fieldName = 'anotherField'; await waitForUpdatesAsync(); expect(pageObject.getRenderedCellTextContent(0, 0)).toBe('bar'); }); it('changing data from value to null displays blank', async () => { - await element.setData([{ field: 'foo' }]); + await table.setData([{ field: 'foo' }]); await connect(); await waitForUpdatesAsync(); expect(pageObject.getRenderedCellTextContent(0, 0)).toBe('foo'); const updatedValue = { field: null }; const updatedData = [updatedValue]; - await element.setData(updatedData); + await table.setData(updatedData); await waitForUpdatesAsync(); expect(pageObject.getRenderedCellTextContent(0, 0)).toBe(''); }); it('changing data from null to value displays value', async () => { - await element.setData([{ field: null }]); + await table.setData([{ field: null }]); await connect(); await waitForUpdatesAsync(); expect(pageObject.getRenderedCellTextContent(0, 0)).toBe(''); - await element.setData([{ field: 'foo' }]); + await table.setData([{ field: 'foo' }]); await waitForUpdatesAsync(); expect(pageObject.getRenderedCellTextContent(0, 0)).toBe('foo'); @@ -122,9 +132,8 @@ describe('TableColumnText', () => { await connect(); await waitForUpdatesAsync(); - const firstColumn = element.columns[0] as TableColumnText; - firstColumn.fieldName = undefined; - await element.setData([{ field: 'foo' }]); + column.fieldName = undefined; + await table.setData([{ field: 'foo' }]); await waitForUpdatesAsync(); expect(pageObject.getRenderedCellTextContent(0, 0)).toBe(''); @@ -132,7 +141,7 @@ describe('TableColumnText', () => { it('sets title when cell text is ellipsized', async () => { const cellContents = 'a very long value that should get ellipsized due to not fitting within the default cell width'; - await element.setData([{ field: cellContents }]); + await table.setData([{ field: cellContents }]); await connect(); await waitForUpdatesAsync(); pageObject.dispatchEventToCell(0, 0, new MouseEvent('mouseover')); @@ -142,7 +151,7 @@ describe('TableColumnText', () => { it('does not set title when cell text is fully visible', async () => { const cellContents = 'short value'; - await element.setData([{ field: cellContents }]); + await table.setData([{ field: cellContents }]); await connect(); await waitForUpdatesAsync(); pageObject.dispatchEventToCell(0, 0, new MouseEvent('mouseover')); @@ -152,7 +161,7 @@ describe('TableColumnText', () => { it('removes title on mouseout of cell', async () => { const cellContents = 'a very long value that should get ellipsized due to not fitting within the default cell width'; - await element.setData([{ field: cellContents }]); + await table.setData([{ field: cellContents }]); await connect(); await waitForUpdatesAsync(); pageObject.dispatchEventToCell(0, 0, new MouseEvent('mouseover')); @@ -164,8 +173,8 @@ describe('TableColumnText', () => { it('sets title when group header text is ellipsized', async () => { const cellContents = 'a very long value that should get ellipsized due to not fitting within the default cell width'; - await element.setData([{ field: cellContents }]); - element.style.width = '200px'; + await table.setData([{ field: cellContents }]); + table.style.width = '200px'; await connect(); await waitForUpdatesAsync(); pageObject.dispatchEventToGroupHeader(0, new MouseEvent('mouseover')); @@ -175,7 +184,7 @@ describe('TableColumnText', () => { it('does not set title when group header text is fully visible', async () => { const cellContents = 'foo'; - await element.setData([{ field: cellContents }]); + await table.setData([{ field: cellContents }]); await connect(); await waitForUpdatesAsync(); pageObject.dispatchEventToGroupHeader(0, new MouseEvent('mouseover')); @@ -185,7 +194,7 @@ describe('TableColumnText', () => { it('removes title on mouseout of group header', async () => { const cellContents = 'a very long value that should get ellipsized due to not fitting within the default cell width'; - await element.setData([{ field: cellContents }]); + await table.setData([{ field: cellContents }]); await connect(); await waitForUpdatesAsync(); pageObject.dispatchEventToGroupHeader(0, new MouseEvent('mouseover')); @@ -200,7 +209,7 @@ describe('TableColumnText', () => { spec(`data "${name}" renders as "${name}"`, async () => { await connect(); - await element.setData([{ field: name }]); + await table.setData([{ field: name }]); await waitForUpdatesAsync(); expect(pageObject.getRenderedCellTextContent(0, 0)).toBe(name); @@ -213,7 +222,7 @@ describe('TableColumnText', () => { spec(`data "${name}" renders as "${name}"`, async () => { await connect(); - await element.setData([{ field: name }]); + await table.setData([{ field: name }]); await waitForUpdatesAsync(); expect( @@ -222,4 +231,46 @@ describe('TableColumnText', () => { }); }); }); + + describe('placeholder', () => { + const testCases = [ + { + name: 'value is not specified', + data: [{}], + groupValue: 'No value' + }, + { + name: 'value is undefined', + data: [{ field: undefined }], + groupValue: 'No value' + }, + { + name: 'value is null', + data: [{ field: null }], + groupValue: 'No value' + }, + { + name: 'value is incorrect type', + data: [{ field: 100 as unknown as string }], + groupValue: '' + }, + { + name: 'value is an empty string', + data: [{ field: '' }], + groupValue: 'Empty' + } + ]; + + parameterizeSpec(testCases, (spec, name, value) => { + spec(`group row renders expected value when ${name}`, async () => { + await table.setData(value.data); + await connect(); + await waitForUpdatesAsync(); + + expect(pageObject.getRenderedGroupHeaderTextContent(0)).toBe( + value.groupValue + ); + }); + }); + }); }); diff --git a/packages/nimble-components/src/tests/component-status.stories.ts b/packages/nimble-components/src/tests/component-status.stories.ts index 37ec7819a1..ba39a01fd9 100644 --- a/packages/nimble-components/src/tests/component-status.stories.ts +++ b/packages/nimble-components/src/tests/component-status.stories.ts @@ -557,7 +557,7 @@ const metadata: Meta<TableArgs> = { ${ref('tableRef')} data-unused="${x => x.updateData(x)}" ${/* Make the table big enough to remove vertical scrollbar */ ''} - style="height: ${x => (x.status === 'active' ? '1200px' : '600px')};" + style="height: calc((34px * var(--data-length)) + 32px);" > <${tableColumnAnchorTag} target="_top" column-id="component-name-column" @@ -644,6 +644,10 @@ const metadata: Meta<TableArgs> = { const data = components.filter(component => (x.status === 'future' ? isFuture(component) : !isFuture(component))); + x.tableRef.style.setProperty( + '--data-length', + data.length.toString() + ); await x.tableRef.setData(data); })(); }, From 04b9d11bc99061a8a34d7f62bcd0343fca0639e8 Mon Sep 17 00:00:00 2001 From: rajsite <rajsite@users.noreply.github.com> Date: Mon, 18 Mar 2024 17:12:34 +0000 Subject: [PATCH 12/12] applying package updates [skip ci] --- .../projects/ni/nimble-angular/CHANGELOG.json | 21 +++++++++++++++++++ .../projects/ni/nimble-angular/CHANGELOG.md | 11 +++++++++- .../projects/ni/nimble-angular/package.json | 4 ++-- ...-5cbff6bf-81b5-47ea-b3a5-ed8d4eb87269.json | 7 ------- ...-095e8126-0d1e-452f-9222-60684ac3f081.json | 7 ------- ...-561538cd-7588-4219-9fd7-1fe50633d0f7.json | 7 ------- package-lock.json | 8 +++---- packages/nimble-blazor/CHANGELOG.json | 15 +++++++++++++ packages/nimble-blazor/CHANGELOG.md | 10 ++++++++- packages/nimble-blazor/package.json | 2 +- packages/nimble-components/CHANGELOG.json | 15 +++++++++++++ packages/nimble-components/CHANGELOG.md | 10 ++++++++- packages/nimble-components/package.json | 2 +- 13 files changed, 87 insertions(+), 32 deletions(-) delete mode 100644 change/@ni-nimble-angular-5cbff6bf-81b5-47ea-b3a5-ed8d4eb87269.json delete mode 100644 change/@ni-nimble-blazor-095e8126-0d1e-452f-9222-60684ac3f081.json delete mode 100644 change/@ni-nimble-components-561538cd-7588-4219-9fd7-1fe50633d0f7.json diff --git a/angular-workspace/projects/ni/nimble-angular/CHANGELOG.json b/angular-workspace/projects/ni/nimble-angular/CHANGELOG.json index fc72ae7a4e..9e9b860a35 100644 --- a/angular-workspace/projects/ni/nimble-angular/CHANGELOG.json +++ b/angular-workspace/projects/ni/nimble-angular/CHANGELOG.json @@ -1,6 +1,27 @@ { "name": "@ni/nimble-angular", "entries": [ + { + "date": "Mon, 18 Mar 2024 17:12:34 GMT", + "version": "20.5.0", + "tag": "@ni/nimble-angular_v20.5.0", + "comments": { + "minor": [ + { + "author": "20542556+mollykreis@users.noreply.github.com", + "package": "@ni/nimble-angular", + "commit": "3bbf8d7cd86d0129e9ad6bb0eed245ea2bfc0fda", + "comment": "Add new properties to the table label provider" + }, + { + "author": "beachball", + "package": "@ni/nimble-angular", + "comment": "Bump @ni/nimble-components to v22.1.0", + "commit": "not available" + } + ] + } + }, { "date": "Thu, 14 Mar 2024 14:48:16 GMT", "version": "20.4.1", diff --git a/angular-workspace/projects/ni/nimble-angular/CHANGELOG.md b/angular-workspace/projects/ni/nimble-angular/CHANGELOG.md index 4668075987..f7aafd80de 100644 --- a/angular-workspace/projects/ni/nimble-angular/CHANGELOG.md +++ b/angular-workspace/projects/ni/nimble-angular/CHANGELOG.md @@ -1,9 +1,18 @@ # Change Log - @ni/nimble-angular -This log was last generated on Thu, 14 Mar 2024 14:48:16 GMT and should not be manually modified. +This log was last generated on Mon, 18 Mar 2024 17:12:34 GMT and should not be manually modified. <!-- Start content --> +## 20.5.0 + +Mon, 18 Mar 2024 17:12:34 GMT + +### Minor changes + +- Add new properties to the table label provider ([ni/nimble@3bbf8d7](https://github.com/ni/nimble/commit/3bbf8d7cd86d0129e9ad6bb0eed245ea2bfc0fda)) +- Bump @ni/nimble-components to v22.1.0 + ## 20.4.1 Thu, 14 Mar 2024 14:48:16 GMT diff --git a/angular-workspace/projects/ni/nimble-angular/package.json b/angular-workspace/projects/ni/nimble-angular/package.json index 27fb5bfdf7..ffb4b78ba8 100644 --- a/angular-workspace/projects/ni/nimble-angular/package.json +++ b/angular-workspace/projects/ni/nimble-angular/package.json @@ -1,6 +1,6 @@ { "name": "@ni/nimble-angular", - "version": "20.4.1", + "version": "20.5.0", "description": "Angular components for the NI Nimble Design System", "scripts": { "invoke-publish": "cd ../../../ && npm run build:library && cd dist/ni/nimble-angular && npm publish" @@ -31,7 +31,7 @@ "@angular/forms": "^15.2.10", "@angular/localize": "^15.2.10", "@angular/router": "^15.2.10", - "@ni/nimble-components": "^22.0.1" + "@ni/nimble-components": "^22.1.0" }, "dependencies": { "tslib": "^2.2.0" diff --git a/change/@ni-nimble-angular-5cbff6bf-81b5-47ea-b3a5-ed8d4eb87269.json b/change/@ni-nimble-angular-5cbff6bf-81b5-47ea-b3a5-ed8d4eb87269.json deleted file mode 100644 index b03b663fa2..0000000000 --- a/change/@ni-nimble-angular-5cbff6bf-81b5-47ea-b3a5-ed8d4eb87269.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "type": "minor", - "comment": "Add new properties to the table label provider", - "packageName": "@ni/nimble-angular", - "email": "20542556+mollykreis@users.noreply.github.com", - "dependentChangeType": "patch" -} diff --git a/change/@ni-nimble-blazor-095e8126-0d1e-452f-9222-60684ac3f081.json b/change/@ni-nimble-blazor-095e8126-0d1e-452f-9222-60684ac3f081.json deleted file mode 100644 index 336ed4bd8e..0000000000 --- a/change/@ni-nimble-blazor-095e8126-0d1e-452f-9222-60684ac3f081.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "type": "minor", - "comment": "Add new properties to the table label provider", - "packageName": "@ni/nimble-blazor", - "email": "20542556+mollykreis@users.noreply.github.com", - "dependentChangeType": "patch" -} diff --git a/change/@ni-nimble-components-561538cd-7588-4219-9fd7-1fe50633d0f7.json b/change/@ni-nimble-components-561538cd-7588-4219-9fd7-1fe50633d0f7.json deleted file mode 100644 index 91788ed748..0000000000 --- a/change/@ni-nimble-components-561538cd-7588-4219-9fd7-1fe50633d0f7.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "type": "minor", - "comment": "Add placeholders for group rows in the table", - "packageName": "@ni/nimble-components", - "email": "20542556+mollykreis@users.noreply.github.com", - "dependentChangeType": "patch" -} diff --git a/package-lock.json b/package-lock.json index 61914ea73d..7a23d00821 100644 --- a/package-lock.json +++ b/package-lock.json @@ -74,7 +74,7 @@ }, "angular-workspace/projects/ni/nimble-angular": { "name": "@ni/nimble-angular", - "version": "20.4.1", + "version": "20.5.0", "license": "MIT", "dependencies": { "tslib": "^2.2.0" @@ -85,7 +85,7 @@ "@angular/forms": "^15.2.10", "@angular/localize": "^15.2.10", "@angular/router": "^15.2.10", - "@ni/nimble-components": "^22.0.1" + "@ni/nimble-components": "^22.1.0" } }, "node_modules/@11ty/dependency-tree": { @@ -33939,7 +33939,7 @@ }, "packages/nimble-blazor": { "name": "@ni/nimble-blazor", - "version": "14.4.1", + "version": "14.5.0", "hasInstallScript": true, "license": "MIT", "devDependencies": { @@ -33975,7 +33975,7 @@ }, "packages/nimble-components": { "name": "@ni/nimble-components", - "version": "22.0.1", + "version": "22.1.0", "license": "MIT", "dependencies": { "@microsoft/fast-colors": "^5.3.1", diff --git a/packages/nimble-blazor/CHANGELOG.json b/packages/nimble-blazor/CHANGELOG.json index 8beb296a92..bb6c73b2d4 100644 --- a/packages/nimble-blazor/CHANGELOG.json +++ b/packages/nimble-blazor/CHANGELOG.json @@ -1,6 +1,21 @@ { "name": "@ni/nimble-blazor", "entries": [ + { + "date": "Mon, 18 Mar 2024 17:12:34 GMT", + "version": "14.5.0", + "tag": "@ni/nimble-blazor_v14.5.0", + "comments": { + "minor": [ + { + "author": "20542556+mollykreis@users.noreply.github.com", + "package": "@ni/nimble-blazor", + "commit": "3bbf8d7cd86d0129e9ad6bb0eed245ea2bfc0fda", + "comment": "Add new properties to the table label provider" + } + ] + } + }, { "date": "Wed, 13 Mar 2024 23:07:24 GMT", "version": "14.4.0", diff --git a/packages/nimble-blazor/CHANGELOG.md b/packages/nimble-blazor/CHANGELOG.md index fce7a6df3e..ce65eafbdb 100644 --- a/packages/nimble-blazor/CHANGELOG.md +++ b/packages/nimble-blazor/CHANGELOG.md @@ -1,9 +1,17 @@ # Change Log - @ni/nimble-blazor -This log was last generated on Wed, 13 Mar 2024 23:07:24 GMT and should not be manually modified. +This log was last generated on Mon, 18 Mar 2024 17:12:34 GMT and should not be manually modified. <!-- Start content --> +## 14.5.0 + +Mon, 18 Mar 2024 17:12:34 GMT + +### Minor changes + +- Add new properties to the table label provider ([ni/nimble@3bbf8d7](https://github.com/ni/nimble/commit/3bbf8d7cd86d0129e9ad6bb0eed245ea2bfc0fda)) + ## 14.4.0 Wed, 13 Mar 2024 23:07:24 GMT diff --git a/packages/nimble-blazor/package.json b/packages/nimble-blazor/package.json index 20397b86da..e804ada040 100644 --- a/packages/nimble-blazor/package.json +++ b/packages/nimble-blazor/package.json @@ -1,6 +1,6 @@ { "name": "@ni/nimble-blazor", - "version": "14.4.1", + "version": "14.5.0", "description": "Blazor components for the NI Nimble Design System", "scripts": { "postinstall": "node build/generate-playwright-version-properties/source/index.js", diff --git a/packages/nimble-components/CHANGELOG.json b/packages/nimble-components/CHANGELOG.json index 4d10a25568..250edb4769 100644 --- a/packages/nimble-components/CHANGELOG.json +++ b/packages/nimble-components/CHANGELOG.json @@ -1,6 +1,21 @@ { "name": "@ni/nimble-components", "entries": [ + { + "date": "Mon, 18 Mar 2024 17:12:34 GMT", + "version": "22.1.0", + "tag": "@ni/nimble-components_v22.1.0", + "comments": { + "minor": [ + { + "author": "20542556+mollykreis@users.noreply.github.com", + "package": "@ni/nimble-components", + "commit": "3bbf8d7cd86d0129e9ad6bb0eed245ea2bfc0fda", + "comment": "Add placeholders for group rows in the table" + } + ] + } + }, { "date": "Mon, 18 Mar 2024 16:35:18 GMT", "version": "22.0.1", diff --git a/packages/nimble-components/CHANGELOG.md b/packages/nimble-components/CHANGELOG.md index 2664591847..28514fbac5 100644 --- a/packages/nimble-components/CHANGELOG.md +++ b/packages/nimble-components/CHANGELOG.md @@ -1,9 +1,17 @@ # Change Log - @ni/nimble-components -This log was last generated on Thu, 14 Mar 2024 14:48:16 GMT and should not be manually modified. +This log was last generated on Mon, 18 Mar 2024 17:12:34 GMT and should not be manually modified. <!-- Start content --> +## 22.1.0 + +Mon, 18 Mar 2024 17:12:34 GMT + +### Minor changes + +- Add placeholders for group rows in the table ([ni/nimble@3bbf8d7](https://github.com/ni/nimble/commit/3bbf8d7cd86d0129e9ad6bb0eed245ea2bfc0fda)) + ## 22.0.1 Thu, 14 Mar 2024 14:48:16 GMT diff --git a/packages/nimble-components/package.json b/packages/nimble-components/package.json index 20bf058f61..946cac8bb2 100644 --- a/packages/nimble-components/package.json +++ b/packages/nimble-components/package.json @@ -1,6 +1,6 @@ { "name": "@ni/nimble-components", - "version": "22.0.1", + "version": "22.1.0", "description": "Styled web components for the NI Nimble Design System", "scripts": { "build": "npm run generate-icons && npm run generate-workers && npm run build-components && npm run bundle-components && npm run generate-scss && npm run build-storybook",