diff --git a/docs/CHANGELOG.md b/docs/CHANGELOG.md index 5c50865e3..eecd87f9b 100644 --- a/docs/CHANGELOG.md +++ b/docs/CHANGELOG.md @@ -4,6 +4,7 @@ – `Fix` – Fix the display of ‘Convert To’ near blocks that do not have the ‘conversionConfig.export’ rule specified – `Fix` – The Plus button does not appear when the editor is loaded in an iframe in Chrome +- `Fix` - Prevent inline toolbar from closing in nested instance of editor ### 2.30.5 diff --git a/src/components/modules/ui.ts b/src/components/modules/ui.ts index f9c3cbef6..6bbcdb8ce 100644 --- a/src/components/modules/ui.ts +++ b/src/components/modules/ui.ts @@ -847,9 +847,11 @@ export default class UI extends Module { /** * Event can be fired on clicks at non-block-content elements, - * for example, at the Inline Toolbar or some Block Tune element + * for example, at the Inline Toolbar or some Block Tune element. + * We also make sure that the closest block belongs to the current editor and not a parent */ - const clickedOutsideBlockContent = focusedElement.closest(`.${Block.CSS.content}`) === null; + const closestBlock = focusedElement.closest(`.${Block.CSS.content}`); + const clickedOutsideBlockContent = closestBlock === null || (closestBlock.closest(`.${Selection.CSS.editorWrapper}`) !== this.nodes.wrapper); if (clickedOutsideBlockContent) { /** diff --git a/test/cypress/support/utils/nestedEditorInstance.ts b/test/cypress/support/utils/nestedEditorInstance.ts new file mode 100644 index 000000000..f335cbcee --- /dev/null +++ b/test/cypress/support/utils/nestedEditorInstance.ts @@ -0,0 +1,31 @@ +import type { BlockTool, BlockToolConstructorOptions } from '../../../../types'; +import { createEditorWithTextBlocks } from './createEditorWithTextBlocks'; + +export const NESTED_EDITOR_ID = 'nested-editor'; + +/** + * Creates nested Editor instance with paragraph block + */ +export default class NestedEditor implements BlockTool { + private data: { text: string }; + + constructor(value: BlockToolConstructorOptions) { + this.data = value.data; + } + + public render(): HTMLDivElement { + const editorEl = Object.assign(document.createElement('div'), { + id: NESTED_EDITOR_ID, + }); + + editorEl.setAttribute('data-cy', NESTED_EDITOR_ID); + + createEditorWithTextBlocks([ this.data.text ], { holder: NESTED_EDITOR_ID }); + + return editorEl; + } + + public save(): string { + return this.data.text; + } +} diff --git a/test/cypress/tests/modules/InlineToolbar.cy.ts b/test/cypress/tests/modules/InlineToolbar.cy.ts index bc8990bda..ebdb71d67 100644 --- a/test/cypress/tests/modules/InlineToolbar.cy.ts +++ b/test/cypress/tests/modules/InlineToolbar.cy.ts @@ -1,4 +1,5 @@ import Header from '@editorjs/header'; +import NestedEditor, { NESTED_EDITOR_ID } from '../../support/utils/nestedEditorInstance'; describe('Inline Toolbar', () => { it('should appear aligned with left coord of selection rect', () => { @@ -164,4 +165,56 @@ describe('Inline Toolbar', () => { }); }); }); + + describe('Nested Editor instance inline toolbar', () => { + it('should not close inline toolbar of the nested Editor instance when clicking within that toolbar', () => { + cy.createEditor({ + tools: { + nestedEditor: { + class: NestedEditor, + }, + }, + data: { + blocks: [ + { + type: 'paragraph', + data: { + text: 'Lorem ipsum dolor sit amet, consectetur adipiscing elit.', + }, + }, + { + type: 'nestedEditor', + data: { + text: 'Nunc pellentesque, tortor nec luctus venenatis', + }, + }, + ], + }, + }); + + cy.get(`[data-cy=${NESTED_EDITOR_ID}]`) + .find('.ce-paragraph') + .selectText('tortor nec luctus'); + + cy.get(`[data-cy=${NESTED_EDITOR_ID}]`) + .find('[data-item-name=link]') + .click(); + + // `wait()` function below is required. without it the test will always pass + // because cypress types the text in the field without delay, while we need some delay (just like user) + // to test the actual case that nested editor inline toolbar is still visible and not closed + + cy.get(`[data-cy=${NESTED_EDITOR_ID}]`) + .find('.ce-inline-tool-input') + .click() + .wait(100) + .type('https://editorjs.io'); + + cy.get(`[data-cy=${NESTED_EDITOR_ID}]`) + .find('.ce-popover__container') + .then(($toolbar) => { + expect($toolbar).to.be.visible; + }); + }); + }); });