diff --git a/angular-workspace/projects/example-client-app/src/app/app.module.ts b/angular-workspace/projects/example-client-app/src/app/app.module.ts index 45721b321b..b47de93b03 100644 --- a/angular-workspace/projects/example-client-app/src/app/app.module.ts +++ b/angular-workspace/projects/example-client-app/src/app/app.module.ts @@ -22,6 +22,7 @@ import { NimbleTableColumnDateTextModule } from '@ni/nimble-angular/table-column import { NimbleTableColumnEnumTextModule } from '@ni/nimble-angular/table-column/enum-text'; import { NimbleTableColumnIconModule } from '@ni/nimble-angular/table-column/icon'; import { NimbleRichTextViewerModule } from '@ni/nimble-angular/rich-text-viewer'; +import { NimbleRichTextEditorModule } from '@ni/nimble-angular/rich-text-editor'; import { AppComponent } from './app.component'; import { CustomAppComponent } from './customapp/customapp.component'; import { HeaderComponent } from './header/header.component'; @@ -84,6 +85,7 @@ import { HeaderComponent } from './header/header.component'; NimbleMappingTextModule, NimbleBannerModule, NimbleRichTextViewerModule, + NimbleRichTextEditorModule, NimbleTableColumnIconModule, NimbleMappingIconModule, NimbleMappingSpinnerModule, diff --git a/angular-workspace/projects/example-client-app/src/app/customapp/customapp.component.html b/angular-workspace/projects/example-client-app/src/app/customapp/customapp.component.html index 8f42865860..cd00a06c35 100644 --- a/angular-workspace/projects/example-client-app/src/app/customapp/customapp.component.html +++ b/angular-workspace/projects/example-client-app/src/app/customapp/customapp.component.html @@ -170,10 +170,18 @@ {{ item ? item.first : '' }} +
+
Rich Text Editor
+
+ + Load Content + +
+
Rich Text Viewer
- +
diff --git a/angular-workspace/projects/example-client-app/src/app/customapp/customapp.component.scss b/angular-workspace/projects/example-client-app/src/app/customapp/customapp.component.scss index def466ea8f..065d6d542b 100644 --- a/angular-workspace/projects/example-client-app/src/app/customapp/customapp.component.scss +++ b/angular-workspace/projects/example-client-app/src/app/customapp/customapp.component.scss @@ -83,3 +83,7 @@ nimble-table { padding: $ni-nimble-small-padding; width: 350px; } + +.rich-text-editor-container { + padding: $ni-nimble-small-padding; +} diff --git a/angular-workspace/projects/example-client-app/src/app/customapp/customapp.component.ts b/angular-workspace/projects/example-client-app/src/app/customapp/customapp.component.ts index d39d1b18fc..aecf4ecb72 100644 --- a/angular-workspace/projects/example-client-app/src/app/customapp/customapp.component.ts +++ b/angular-workspace/projects/example-client-app/src/app/customapp/customapp.component.ts @@ -3,6 +3,7 @@ import { Component, Inject, ViewChild } from '@angular/core'; import { ActivatedRoute } from '@angular/router'; import { DrawerLocation, MenuItem, NimbleDialogDirective, NimbleDrawerDirective, OptionNotFound, OPTION_NOT_FOUND, UserDismissed } from '@ni/nimble-angular'; import type { TableRecord } from '@ni/nimble-angular/table'; +import { NimbleRichTextEditorDirective } from '@ni/nimble-angular/rich-text-editor'; import { BehaviorSubject, Observable } from 'rxjs'; interface ComboboxItem { @@ -44,7 +45,7 @@ export class CustomAppComponent { public selectedRadio = 'mango'; public activeTabId = 'tab-1'; public activeAnchorTabId = 'a-tab-2'; - public markdownString = `Supported rich text formatting options: + public viewerMarkdownString = `Supported rich text formatting options: 1. **Bold** 2. *Italics* 3. Numbered lists @@ -56,11 +57,23 @@ export class CustomAppComponent { 5. Absolute link: `; + public editorMarkdownString = `Supported rich text formatting options: +1. **Bold** +2. *Italics* +3. Numbered lists + 1. Option 1 + 2. Option 2 +4. Bulleted lists + * Option 1 + * Option 2 +`; + public readonly tableData$: Observable; private readonly tableDataSubject = new BehaviorSubject([]); @ViewChild('dialog', { read: NimbleDialogDirective }) private readonly dialog: NimbleDialogDirective; @ViewChild('drawer', { read: NimbleDrawerDirective }) private readonly drawer: NimbleDrawerDirective; + @ViewChild('editor', { read: NimbleRichTextEditorDirective }) private readonly editor: NimbleRichTextEditorDirective; public constructor(@Inject(ActivatedRoute) public readonly route: ActivatedRoute) { this.tableData$ = this.tableDataSubject.asObservable(); @@ -115,4 +128,8 @@ export class CustomAppComponent { }); this.tableDataSubject.next(tableData); } + + public loadRichTextEditorContent(): void { + this.editor.setMarkdown(this.editorMarkdownString); + } } diff --git a/angular-workspace/projects/ni/nimble-angular/rich-text-editor/ng-package.json b/angular-workspace/projects/ni/nimble-angular/rich-text-editor/ng-package.json new file mode 100644 index 0000000000..7945e60e70 --- /dev/null +++ b/angular-workspace/projects/ni/nimble-angular/rich-text-editor/ng-package.json @@ -0,0 +1,6 @@ +{ + "$schema": "../../../../../node_modules/ng-packagr/ng-package.schema.json", + "lib": { + "entryFile": "public-api.ts" + } +} \ No newline at end of file diff --git a/angular-workspace/projects/ni/nimble-angular/rich-text-editor/nimble-rich-text-editor.directive.ts b/angular-workspace/projects/ni/nimble-angular/rich-text-editor/nimble-rich-text-editor.directive.ts new file mode 100644 index 0000000000..abd5a2a0a8 --- /dev/null +++ b/angular-workspace/projects/ni/nimble-angular/rich-text-editor/nimble-rich-text-editor.directive.ts @@ -0,0 +1,83 @@ +import { Directive, ElementRef, EventEmitter, HostListener, Input, Output, Renderer2 } from '@angular/core'; +import type { RichTextEditor } from '@ni/nimble-components/dist/esm/rich-text-editor'; +import { BooleanValueOrAttribute, toBooleanProperty } from '@ni/nimble-angular/internal-utilities'; + +export type { RichTextEditor }; + +/** + * Directive to provide Angular integration for the rich text editor element. + */ +@Directive({ + selector: 'nimble-rich-text-editor' +}) + +export class NimbleRichTextEditorDirective { + @Output() public inputEvent = new EventEmitter(); + + public get disabled(): boolean { + return this.elementRef.nativeElement.disabled; + } + + @Input() public set disabled(value: BooleanValueOrAttribute) { + this.renderer.setProperty(this.elementRef.nativeElement, 'disabled', toBooleanProperty(value)); + } + + public get footerHidden(): boolean { + return this.elementRef.nativeElement.footerHidden; + } + + // Renaming because property should have camel casing, but attribute should not + // eslint-disable-next-line @angular-eslint/no-input-rename + @Input('footer-hidden') public set footerHidden(value: BooleanValueOrAttribute) { + this.renderer.setProperty(this.elementRef.nativeElement, 'footerHidden', toBooleanProperty(value)); + } + + public get errorVisible(): boolean { + return this.elementRef.nativeElement.errorVisible; + } + + // Renaming because property should have camel casing, but attribute should not + // eslint-disable-next-line @angular-eslint/no-input-rename + @Input('error-visible') public set errorVisible(value: BooleanValueOrAttribute) { + this.renderer.setProperty(this.elementRef.nativeElement, 'errorVisible', toBooleanProperty(value)); + } + + public get errorText(): string | undefined { + return this.elementRef.nativeElement.errorText; + } + + // Renaming because property should have camel casing, but attribute should not + // eslint-disable-next-line @angular-eslint/no-input-rename + @Input('error-text') public set errorText(value: string | undefined) { + this.renderer.setProperty(this.elementRef.nativeElement, 'errorText', value); + } + + public get placeholder(): string | undefined { + return this.elementRef.nativeElement.placeholder; + } + + @Input() public set placeholder(value: string | undefined) { + this.renderer.setProperty(this.elementRef.nativeElement, 'placeholder', value); + } + + public constructor(private readonly renderer: Renderer2, private readonly elementRef: ElementRef) { } + + public getMarkdown(): string { + return this.elementRef.nativeElement.getMarkdown(); + } + + public setMarkdown(value: string): void { + this.elementRef.nativeElement.setMarkdown(value); + } + + public get empty(): boolean { + return this.elementRef.nativeElement.empty; + } + + @HostListener('input', ['$event']) + public onInput($event: Event): void { + if ($event.target === this.elementRef.nativeElement) { + this.inputEvent.emit(); + } + } +} diff --git a/angular-workspace/projects/ni/nimble-angular/rich-text-editor/nimble-rich-text-editor.module.ts b/angular-workspace/projects/ni/nimble-angular/rich-text-editor/nimble-rich-text-editor.module.ts new file mode 100644 index 0000000000..0c6c57ce98 --- /dev/null +++ b/angular-workspace/projects/ni/nimble-angular/rich-text-editor/nimble-rich-text-editor.module.ts @@ -0,0 +1,12 @@ +import { NgModule } from '@angular/core'; +import { CommonModule } from '@angular/common'; +import { NimbleRichTextEditorDirective } from './nimble-rich-text-editor.directive'; + +import '@ni/nimble-components/dist/esm/rich-text-editor'; + +@NgModule({ + declarations: [NimbleRichTextEditorDirective], + imports: [CommonModule], + exports: [NimbleRichTextEditorDirective] +}) +export class NimbleRichTextEditorModule { } diff --git a/angular-workspace/projects/ni/nimble-angular/rich-text-editor/public-api.ts b/angular-workspace/projects/ni/nimble-angular/rich-text-editor/public-api.ts new file mode 100644 index 0000000000..fe7585d3da --- /dev/null +++ b/angular-workspace/projects/ni/nimble-angular/rich-text-editor/public-api.ts @@ -0,0 +1,2 @@ +export * from './nimble-rich-text-editor.directive'; +export * from './nimble-rich-text-editor.module'; \ No newline at end of file diff --git a/angular-workspace/projects/ni/nimble-angular/rich-text-editor/testing/ng-package.json b/angular-workspace/projects/ni/nimble-angular/rich-text-editor/testing/ng-package.json new file mode 100644 index 0000000000..e5440110fb --- /dev/null +++ b/angular-workspace/projects/ni/nimble-angular/rich-text-editor/testing/ng-package.json @@ -0,0 +1,6 @@ +{ + "$schema": "../../../../../../node_modules/ng-packagr/ng-package.schema.json", + "lib": { + "entryFile": "public-api.ts" + } +} \ No newline at end of file diff --git a/angular-workspace/projects/ni/nimble-angular/rich-text-editor/testing/public-api.ts b/angular-workspace/projects/ni/nimble-angular/rich-text-editor/testing/public-api.ts new file mode 100644 index 0000000000..82a3ed3c52 --- /dev/null +++ b/angular-workspace/projects/ni/nimble-angular/rich-text-editor/testing/public-api.ts @@ -0,0 +1 @@ +export * from './rich-text-editor.pageobject'; \ No newline at end of file diff --git a/angular-workspace/projects/ni/nimble-angular/rich-text-editor/testing/rich-text-editor.pageobject.ts b/angular-workspace/projects/ni/nimble-angular/rich-text-editor/testing/rich-text-editor.pageobject.ts new file mode 100644 index 0000000000..075882fc1b --- /dev/null +++ b/angular-workspace/projects/ni/nimble-angular/rich-text-editor/testing/rich-text-editor.pageobject.ts @@ -0,0 +1,5 @@ +import { RichTextEditorPageObject } from '@ni/nimble-components/dist/esm/rich-text-editor/testing/rich-text-editor.pageobject'; +import type { ToolbarButton } from '@ni/nimble-components/dist/esm/rich-text-editor/testing/types'; + +export { RichTextEditorPageObject }; +export type { ToolbarButton }; \ No newline at end of file diff --git a/angular-workspace/projects/ni/nimble-angular/rich-text-editor/tests/nimble-rich-text-editor.directive.spec.ts b/angular-workspace/projects/ni/nimble-angular/rich-text-editor/tests/nimble-rich-text-editor.directive.spec.ts new file mode 100644 index 0000000000..2646bb0448 --- /dev/null +++ b/angular-workspace/projects/ni/nimble-angular/rich-text-editor/tests/nimble-rich-text-editor.directive.spec.ts @@ -0,0 +1,349 @@ +import { ComponentFixture, TestBed } from '@angular/core/testing'; +import { Component, ElementRef, ViewChild } from '@angular/core'; +import type { BooleanValueOrAttribute } from '@ni/nimble-angular/internal-utilities'; +import { NimbleRichTextEditorModule } from '../nimble-rich-text-editor.module'; +import { NimbleRichTextEditorDirective, RichTextEditor } from '../nimble-rich-text-editor.directive'; + +describe('Nimble Rich Text Editor', () => { + describe('module', () => { + beforeEach(() => { + TestBed.configureTestingModule({ + imports: [NimbleRichTextEditorModule] + }); + }); + + it('custom element is defined', () => { + expect(customElements.get('nimble-rich-text-editor')).not.toBeUndefined(); + }); + }); + + describe('with no values in template', () => { + @Component({ + template: ` + + ` + }) + class TestHostComponent { + @ViewChild('editor', { read: NimbleRichTextEditorDirective }) public directive: NimbleRichTextEditorDirective; + @ViewChild('editor', { read: ElementRef }) public elementRef: ElementRef; + } + + let fixture: ComponentFixture; + let directive: NimbleRichTextEditorDirective; + let nativeElement: RichTextEditor; + + beforeEach(() => { + TestBed.configureTestingModule({ + declarations: [TestHostComponent], + imports: [NimbleRichTextEditorModule] + }); + fixture = TestBed.createComponent(TestHostComponent); + fixture.detectChanges(); + directive = fixture.componentInstance.directive; + nativeElement = fixture.componentInstance.elementRef.nativeElement; + }); + + it('has expected defaults for markdown', () => { + expect(directive.getMarkdown()).toBe(''); + expect(nativeElement.getMarkdown()).toBe(''); + }); + + it('has expected defaults for disabled', () => { + expect(directive.disabled).toBeFalse(); + expect(nativeElement.disabled).toBeFalse(); + }); + + it('has expected defaults for footerHidden', () => { + expect(directive.footerHidden).toBeFalse(); + expect(nativeElement.footerHidden).toBeFalse(); + }); + + it('has expected defaults for errorVisible', () => { + expect(directive.errorVisible).toBeFalse(); + expect(nativeElement.errorVisible).toBeFalse(); + }); + + it('has expected defaults for errorText', () => { + expect(directive.errorText).toBeUndefined(); + expect(nativeElement.errorText).toBeUndefined(); + }); + + it('has expected defaults for placeholder', () => { + expect(directive.placeholder).toBeUndefined(); + expect(nativeElement.placeholder).toBeUndefined(); + }); + + it('has expected defaults for empty', () => { + expect(directive.empty).toBeTrue(); + expect(nativeElement.empty).toBeTrue(); + }); + }); + + describe('with template string values', () => { + @Component({ + template: ` + + ` + }) + class TestHostComponent { + @ViewChild('editor', { read: NimbleRichTextEditorDirective }) public directive: NimbleRichTextEditorDirective; + @ViewChild('editor', { read: ElementRef }) public elementRef: ElementRef; + } + + let fixture: ComponentFixture; + let directive: NimbleRichTextEditorDirective; + let nativeElement: RichTextEditor; + + beforeEach(() => { + TestBed.configureTestingModule({ + declarations: [TestHostComponent], + imports: [NimbleRichTextEditorModule] + }); + fixture = TestBed.createComponent(TestHostComponent); + fixture.detectChanges(); + directive = fixture.componentInstance.directive; + nativeElement = fixture.componentInstance.elementRef.nativeElement; + }); + + it('will use template string values for disabled', () => { + expect(directive.disabled).toBeTrue(); + expect(nativeElement.disabled).toBeTrue(); + }); + + it('will use template string values for footerHidden', () => { + expect(directive.footerHidden).toBeTrue(); + expect(nativeElement.footerHidden).toBeTrue(); + }); + + it('will use template string values for errorVisible', () => { + expect(directive.errorVisible).toBeTrue(); + expect(nativeElement.errorVisible).toBeTrue(); + }); + + it('will use template string values for errorText', () => { + expect(directive.errorText).toBe('Error text'); + expect(nativeElement.errorText).toBe('Error text'); + }); + + it('will use template string values for placeholder', () => { + expect(directive.placeholder).toBe('Placeholder value'); + expect(nativeElement.placeholder).toBe('Placeholder value'); + }); + }); + + describe('with property bound values', () => { + @Component({ + template: ` + + ` + }) + class TestHostComponent { + @ViewChild('editor', { read: NimbleRichTextEditorDirective }) public directive: NimbleRichTextEditorDirective; + @ViewChild('editor', { read: ElementRef }) public elementRef: ElementRef; + public disabled = false; + public footerHidden = false; + public errorVisible = false; + public errorText = 'initial'; + public placeholder = 'initial'; + } + + let fixture: ComponentFixture; + let directive: NimbleRichTextEditorDirective; + let nativeElement: RichTextEditor; + + beforeEach(() => { + TestBed.configureTestingModule({ + declarations: [TestHostComponent], + imports: [NimbleRichTextEditorModule] + }); + fixture = TestBed.createComponent(TestHostComponent); + fixture.detectChanges(); + directive = fixture.componentInstance.directive; + nativeElement = fixture.componentInstance.elementRef.nativeElement; + nativeElement.setMarkdown('1. ***Numbered list with bold and italics***\n\n* ___Bulleted list with bold and italics___'); + fixture.detectChanges(); + }); + + it('can be configured with method for markdown', () => { + expect(directive.getMarkdown()).toBe('1. ***Numbered list with bold and italics***\n\n* ***Bulleted list with bold and italics***'); + expect(nativeElement.getMarkdown()).toBe('1. ***Numbered list with bold and italics***\n\n* ***Bulleted list with bold and italics***'); + + nativeElement.setMarkdown('**Updated value**'); + fixture.detectChanges(); + + expect(directive.getMarkdown()).toBe('**Updated value**'); + expect(nativeElement.getMarkdown()).toBe('**Updated value**'); + }); + + it('can be configured with property binding for disabled', () => { + expect(directive.disabled).toBeFalse(); + expect(nativeElement.disabled).toBeFalse(); + + fixture.componentInstance.disabled = true; + fixture.detectChanges(); + + expect(directive.disabled).toBeTrue(); + expect(nativeElement.disabled).toBeTrue(); + }); + + it('can be configured with property binding for footerHidden', () => { + expect(directive.footerHidden).toBeFalse(); + expect(nativeElement.footerHidden).toBeFalse(); + + fixture.componentInstance.footerHidden = true; + fixture.detectChanges(); + + expect(directive.footerHidden).toBeTrue(); + expect(nativeElement.footerHidden).toBeTrue(); + }); + + it('can be configured with property binding for errorVisible', () => { + expect(directive.errorVisible).toBeFalse(); + expect(nativeElement.errorVisible).toBeFalse(); + + fixture.componentInstance.errorVisible = true; + fixture.detectChanges(); + + expect(directive.errorVisible).toBeTrue(); + expect(nativeElement.errorVisible).toBeTrue(); + }); + + it('can be configured with property binding for errorText', () => { + expect(directive.errorText).toBe('initial'); + expect(nativeElement.errorText).toBe('initial'); + + fixture.componentInstance.errorText = 'updated error text'; + fixture.detectChanges(); + + expect(directive.errorText).toBe('updated error text'); + expect(nativeElement.errorText).toBe('updated error text'); + }); + + it('can be configured with property binding for placeholder', () => { + expect(directive.placeholder).toBe('initial'); + expect(nativeElement.placeholder).toBe('initial'); + + fixture.componentInstance.placeholder = 'updated placeholder value'; + fixture.detectChanges(); + + expect(directive.placeholder).toBe('updated placeholder value'); + expect(nativeElement.placeholder).toBe('updated placeholder value'); + }); + + it('updates empty when markdown is cleared', () => { + expect(directive.empty).toBeFalse(); + expect(nativeElement.empty).toBeFalse(); + + nativeElement.setMarkdown(''); + fixture.detectChanges(); + + expect(directive.empty).toBeTrue(); + expect(nativeElement.empty).toBeTrue(); + }); + }); + + describe('with attribute bound values', () => { + @Component({ + template: ` + + ` + }) + class TestHostComponent { + @ViewChild('editor', { read: NimbleRichTextEditorDirective }) public directive: NimbleRichTextEditorDirective; + @ViewChild('editor', { read: ElementRef }) public elementRef: ElementRef; + public disabled: BooleanValueOrAttribute = null; + public footerHidden: BooleanValueOrAttribute = null; + public errorVisible: BooleanValueOrAttribute = null; + public errorText = 'initial'; + public placeholder = 'initial'; + } + + let fixture: ComponentFixture; + let directive: NimbleRichTextEditorDirective; + let nativeElement: RichTextEditor; + + beforeEach(() => { + TestBed.configureTestingModule({ + declarations: [TestHostComponent], + imports: [NimbleRichTextEditorModule] + }); + fixture = TestBed.createComponent(TestHostComponent); + fixture.detectChanges(); + directive = fixture.componentInstance.directive; + nativeElement = fixture.componentInstance.elementRef.nativeElement; + }); + + it('can be configured with attribute binding for disabled', () => { + expect(directive.disabled).toBeFalse(); + expect(nativeElement.disabled).toBeFalse(); + + fixture.componentInstance.disabled = ''; + fixture.detectChanges(); + + expect(directive.disabled).toBeTrue(); + expect(nativeElement.disabled).toBeTrue(); + }); + + it('can be configured with attribute binding for footerHidden', () => { + expect(directive.footerHidden).toBeFalse(); + expect(nativeElement.footerHidden).toBeFalse(); + + fixture.componentInstance.footerHidden = ''; + fixture.detectChanges(); + + expect(directive.footerHidden).toBeTrue(); + expect(nativeElement.footerHidden).toBeTrue(); + }); + + it('can be configured with attribute binding for errorVisible', () => { + expect(directive.errorVisible).toBeFalse(); + expect(nativeElement.errorVisible).toBeFalse(); + + fixture.componentInstance.errorVisible = ''; + fixture.detectChanges(); + + expect(directive.errorVisible).toBeTrue(); + expect(nativeElement.errorVisible).toBeTrue(); + }); + + it('can be configured with attribute binding for errorText', () => { + expect(directive.errorText).toBe('initial'); + expect(nativeElement.errorText).toBe('initial'); + + fixture.componentInstance.errorText = 'updated error text'; + fixture.detectChanges(); + + expect(directive.errorText).toBe('updated error text'); + expect(nativeElement.errorText).toBe('updated error text'); + }); + + it('can be configured with attribute binding for placeholder', () => { + expect(directive.placeholder).toBe('initial'); + expect(nativeElement.placeholder).toBe('initial'); + + fixture.componentInstance.placeholder = 'updated placeholder value'; + fixture.detectChanges(); + + expect(directive.placeholder).toBe('updated placeholder value'); + expect(nativeElement.placeholder).toBe('updated placeholder value'); + }); + }); +}); \ No newline at end of file diff --git a/angular-workspace/projects/ni/nimble-angular/rich-text-viewer/testing/ng-package.json b/angular-workspace/projects/ni/nimble-angular/rich-text-viewer/testing/ng-package.json new file mode 100644 index 0000000000..e5440110fb --- /dev/null +++ b/angular-workspace/projects/ni/nimble-angular/rich-text-viewer/testing/ng-package.json @@ -0,0 +1,6 @@ +{ + "$schema": "../../../../../../node_modules/ng-packagr/ng-package.schema.json", + "lib": { + "entryFile": "public-api.ts" + } +} \ No newline at end of file diff --git a/angular-workspace/projects/ni/nimble-angular/rich-text-viewer/testing/public-api.ts b/angular-workspace/projects/ni/nimble-angular/rich-text-viewer/testing/public-api.ts new file mode 100644 index 0000000000..88af2dc5ae --- /dev/null +++ b/angular-workspace/projects/ni/nimble-angular/rich-text-viewer/testing/public-api.ts @@ -0,0 +1 @@ +export * from './rich-text-viewer.pageobject'; \ No newline at end of file diff --git a/angular-workspace/projects/ni/nimble-angular/rich-text-viewer/testing/rich-text-viewer.pageobject.ts b/angular-workspace/projects/ni/nimble-angular/rich-text-viewer/testing/rich-text-viewer.pageobject.ts new file mode 100644 index 0000000000..0deb789be0 --- /dev/null +++ b/angular-workspace/projects/ni/nimble-angular/rich-text-viewer/testing/rich-text-viewer.pageobject.ts @@ -0,0 +1,3 @@ +import { RichTextViewerPageObject } from '@ni/nimble-components/dist/esm/rich-text-viewer/testing/rich-text-viewer.pageobject'; + +export { RichTextViewerPageObject }; \ No newline at end of file diff --git a/change/@ni-nimble-angular-71e4b21c-6096-4e8c-85d5-d54801e0e17b.json b/change/@ni-nimble-angular-71e4b21c-6096-4e8c-85d5-d54801e0e17b.json new file mode 100644 index 0000000000..9a49834bae --- /dev/null +++ b/change/@ni-nimble-angular-71e4b21c-6096-4e8c-85d5-d54801e0e17b.json @@ -0,0 +1,7 @@ +{ + "type": "patch", + "comment": "Angular integration for rich text editor component", + "packageName": "@ni/nimble-angular", + "email": "123377523+vivinkrishna-ni@users.noreply.github.com", + "dependentChangeType": "patch" +}