diff --git a/packages/rich-text-editor/src/vaadin-rich-text-editor-mixin.js b/packages/rich-text-editor/src/vaadin-rich-text-editor-mixin.js index 532a976b28..76d9da1496 100644 --- a/packages/rich-text-editor/src/vaadin-rich-text-editor-mixin.js +++ b/packages/rich-text-editor/src/vaadin-rich-text-editor-mixin.js @@ -703,10 +703,26 @@ export const RichTextEditorMixin = (superClass) => */ dangerouslySetHtmlValue(htmlValue) { if (!this._editor) { - // The editor isn't ready yet, store the value for later - this.__pendingHtmlValue = htmlValue; - // Clear a possible value to prevent it from clearing the pending htmlValue once the editor property is set - this.value = ''; + this.__savePendingHtmlValue(htmlValue); + + return; + } + + // In Firefox, the styles are not properly computed when the element is placed + // in a Lit component, as the element is first attached to the DOM and then + // the shadowRoot is initialized. This causes the `hmlValue` to not be correctly + // parsed into the delta format used by Quill. To work around this, we check + // if the display property is set and if not, we wait for the element to intersect + // with the viewport before trying to set the value again. + if (!getComputedStyle(this).display) { + this.__savePendingHtmlValue(htmlValue); + const observer = new IntersectionObserver(() => { + if (getComputedStyle(this).display) { + this.__flushPendingHtmlValue(); + observer.disconnect(); + } + }); + observer.observe(this); return; } @@ -733,6 +749,14 @@ export const RichTextEditorMixin = (superClass) => this._editor.setContents(deltaFromHtml, SOURCE.API); } + /** @private */ + __savePendingHtmlValue(htmlValue) { + // The editor isn't ready yet, store the value for later + this.__pendingHtmlValue = htmlValue; + // Clear a possible value to prevent it from clearing the pending htmlValue once the editor property is set + this.value = ''; + } + /** @private */ __flushPendingHtmlValue() { if (this.__pendingHtmlValue) { diff --git a/packages/rich-text-editor/test/attach-lit.test.js b/packages/rich-text-editor/test/attach-lit.test.js new file mode 100644 index 0000000000..f1265383d6 --- /dev/null +++ b/packages/rich-text-editor/test/attach-lit.test.js @@ -0,0 +1,3 @@ +import '../theme/lumo/vaadin-rich-text-editor-styles.js'; +import '../src/vaadin-lit-rich-text-editor.js'; +import './attach.common.js'; diff --git a/packages/rich-text-editor/test/attach-polymer.test.js b/packages/rich-text-editor/test/attach-polymer.test.js new file mode 100644 index 0000000000..1cd4e8e513 --- /dev/null +++ b/packages/rich-text-editor/test/attach-polymer.test.js @@ -0,0 +1,3 @@ +import '../theme/lumo/vaadin-rich-text-editor-styles.js'; +import '../src/vaadin-rich-text-editor.js'; +import './attach.common.js'; diff --git a/packages/rich-text-editor/test/attach.common.js b/packages/rich-text-editor/test/attach.common.js new file mode 100644 index 0000000000..b39f210d82 --- /dev/null +++ b/packages/rich-text-editor/test/attach.common.js @@ -0,0 +1,90 @@ +import { expect } from '@vaadin/chai-plugins'; +import { fixtureSync, nextRender, nextUpdate } from '@vaadin/testing-helpers'; +import sinon from 'sinon'; + +describe('attach/detach', () => { + let rte, editor; + + const flushValueDebouncer = () => rte.__debounceSetValue && rte.__debounceSetValue.flush(); + + async function attach(shadow = false) { + const parent = fixtureSync('
'); + if (shadow) { + parent.attachShadow({ mode: 'open' }); + } + parent.appendChild(rte); + await nextRender(); + flushValueDebouncer(); + } + + beforeEach(async () => { + rte = fixtureSync('Foo
Foo
Vaadin
'); + }); + + it('should override the value', async () => { + rte.value = JSON.stringify([{ insert: 'Vaadin' }]); + rte.dangerouslySetHtmlValue('Vaadin
'); - }); - - it('should override the value', async () => { - rte.value = JSON.stringify([{ insert: 'Vaadin' }]); - rte.dangerouslySetHtmlValue('