From fcc12d554b6342d1751f6bc54d598189d5465fc3 Mon Sep 17 00:00:00 2001 From: aagash-ni <123377167+aagash-ni@users.noreply.github.com> Date: Fri, 1 Sep 2023 00:25:25 +0530 Subject: [PATCH] Rich Text Editor | Fix for Editor's blinking caret disappearing issue in Firefox browser (#1455) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit # Pull Request ## ๐Ÿคจ Rationale This PR contains workaround for resolves https://github.com/ni/nimble/issues/1454 Firefox issue when the editor gets focused, the blinking caret will be visible until we click format buttons (Bold, Italic ...). But once any of the buttons are clicked, the editor internally has its focus but the blinking caret disappears. Issue Link : https://github.com/ni/nimble/issues/1454 ## ๐Ÿ‘ฉโ€๐Ÿ’ป Implementation - Triggering `Blur()` and setting `focus()` in the editor will make the caret re-appears when clicking the formatting buttons. ## ๐Ÿงช Testing - Verified the caret visibility in the Firefox browser when clicking on the format button. Since Firefox is reporting the editor as an active element even though Caret is not rendered, manually verified this behavior. - Added a test case to verify the active element in the browser especially when clicking the format button. ## โœ… Checklist - [x] I have updated the project documentation to reflect my changes or determined no changes are needed. --------- Co-authored-by: Aagash Raaj --- ...ts-46b1fdfb-63b3-4a04-ac71-1124855a4e45.json | 7 +++++++ .../src/rich-text-editor/index.ts | 17 +++++++++++++++++ .../testing/rich-text-editor.pageobject.ts | 8 ++++++++ .../tests/rich-text-editor.spec.ts | 6 ++++++ 4 files changed, 38 insertions(+) create mode 100644 change/@ni-nimble-components-46b1fdfb-63b3-4a04-ac71-1124855a4e45.json diff --git a/change/@ni-nimble-components-46b1fdfb-63b3-4a04-ac71-1124855a4e45.json b/change/@ni-nimble-components-46b1fdfb-63b3-4a04-ac71-1124855a4e45.json new file mode 100644 index 0000000000..45837b8b83 --- /dev/null +++ b/change/@ni-nimble-components-46b1fdfb-63b3-4a04-ac71-1124855a4e45.json @@ -0,0 +1,7 @@ +{ + "type": "patch", + "comment": "Fix for Firefox caret disappearing issue", + "packageName": "@ni/nimble-components", + "email": "123377167+aagash-ni@users.noreply.github.com", + "dependentChangeType": "patch" +} diff --git a/packages/nimble-components/src/rich-text-editor/index.ts b/packages/nimble-components/src/rich-text-editor/index.ts index d0ae18e4f5..cd0dbacbbc 100644 --- a/packages/nimble-components/src/rich-text-editor/index.ts +++ b/packages/nimble-components/src/rich-text-editor/index.ts @@ -220,6 +220,7 @@ export class RichTextEditor extends FoundationElement implements ErrorPattern { */ public boldButtonClick(): void { this.tiptapEditor.chain().focus().toggleBold().run(); + this.forceFocusEditor(); } /** @@ -229,6 +230,7 @@ export class RichTextEditor extends FoundationElement implements ErrorPattern { public boldButtonKeyDown(event: KeyboardEvent): boolean { if (this.keyActivatesButton(event)) { this.tiptapEditor.chain().focus().toggleBold().run(); + this.forceFocusEditor(); return false; } return true; @@ -240,6 +242,7 @@ export class RichTextEditor extends FoundationElement implements ErrorPattern { */ public italicsButtonClick(): void { this.tiptapEditor.chain().focus().toggleItalic().run(); + this.forceFocusEditor(); } /** @@ -249,6 +252,7 @@ export class RichTextEditor extends FoundationElement implements ErrorPattern { public italicsButtonKeyDown(event: KeyboardEvent): boolean { if (this.keyActivatesButton(event)) { this.tiptapEditor.chain().focus().toggleItalic().run(); + this.forceFocusEditor(); return false; } return true; @@ -260,6 +264,7 @@ export class RichTextEditor extends FoundationElement implements ErrorPattern { */ public bulletListButtonClick(): void { this.tiptapEditor.chain().focus().toggleBulletList().run(); + this.forceFocusEditor(); } /** @@ -269,6 +274,7 @@ export class RichTextEditor extends FoundationElement implements ErrorPattern { public bulletListButtonKeyDown(event: KeyboardEvent): boolean { if (this.keyActivatesButton(event)) { this.tiptapEditor.chain().focus().toggleBulletList().run(); + this.forceFocusEditor(); return false; } return true; @@ -280,6 +286,7 @@ export class RichTextEditor extends FoundationElement implements ErrorPattern { */ public numberedListButtonClick(): void { this.tiptapEditor.chain().focus().toggleOrderedList().run(); + this.forceFocusEditor(); } /** @@ -289,6 +296,7 @@ export class RichTextEditor extends FoundationElement implements ErrorPattern { public numberedListButtonKeyDown(event: KeyboardEvent): boolean { if (this.keyActivatesButton(event)) { this.tiptapEditor.chain().focus().toggleOrderedList().run(); + this.forceFocusEditor(); return false; } return true; @@ -546,6 +554,15 @@ export class RichTextEditor extends FoundationElement implements ErrorPattern { } }); } + + // In Firefox browser, once the editor gets focused, the blinking caret will be visible until we click format buttons (Bold, Italic ...) in the Firefox browser (changing focus). + // But once any of the toolbar button is clicked, editor internally has its focus but the blinking caret disappears. + // As a workaround, manually triggering blur and setting focus on editor makes the blinking caret to re-appear. + // Mozilla issue https://bugzilla.mozilla.org/show_bug.cgi?id=1496769 tracks removal of this workaround. + private forceFocusEditor(): void { + this.tiptapEditor.commands.blur(); + this.tiptapEditor.commands.focus(); + } } // eslint-disable-next-line @typescript-eslint/no-empty-interface diff --git a/packages/nimble-components/src/rich-text-editor/testing/rich-text-editor.pageobject.ts b/packages/nimble-components/src/rich-text-editor/testing/rich-text-editor.pageobject.ts index 478a087dde..3784f5e858 100644 --- a/packages/nimble-components/src/rich-text-editor/testing/rich-text-editor.pageobject.ts +++ b/packages/nimble-components/src/rich-text-editor/testing/rich-text-editor.pageobject.ts @@ -136,6 +136,14 @@ export class RichTextEditorPageObject { .map(el => el.textContent || ''); } + public isRichTextEditorActiveElement(): boolean { + return ( + document.activeElement === this.richTextEditorElement + && document.activeElement?.shadowRoot?.activeElement + === this.getTiptapEditor() + ); + } + public getEditorTabIndex(): string { return this.getTiptapEditor()?.getAttribute('tabindex') ?? ''; } 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 6ea1bc3570..c5b8647286 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 @@ -132,6 +132,12 @@ describe('RichTextEditor', () => { expect(okButtonSpy).toHaveBeenCalledTimes(1); }); + it('Should return editor as active element after clicking formatting button', async () => { + await pageObject.setEditorTextContent('Sample Text'); + await pageObject.clickFooterButton(ToolbarButton.bulletList); + expect(pageObject.isRichTextEditorActiveElement()).toBeTrue(); + }); + const formattingButtons: { name: string, toolbarButtonIndex: ToolbarButton,