Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -139,6 +139,20 @@ export class PopoverItemDefault extends PopoverItem {
this.disableSpecialHoverAndFocusBehavior();
}

/**
* Prevents stale hover state until the pointer enters the item again
*/
public suppressHoverUntilPointerEnters(): void {
const root = this.nodes.root;

if (root === null || root.classList.contains(css.noHover)) {
return;
}

root.classList.add(css.noHover);
root.addEventListener('mouseenter', this.removeSpecialHoverBehavior, { once: true });
}

/**
* Constructs HTML element corresponding to popover item params
*
Expand Down Expand Up @@ -256,8 +270,6 @@ export class PopoverItemDefault extends PopoverItem {
private disableSpecialHoverAndFocusBehavior(): void {
this.removeSpecialFocusBehavior();
this.removeSpecialHoverBehavior();

this.nodes.root?.removeEventListener('mouseleave', this.removeSpecialHoverBehavior);
}

/**
Expand All @@ -271,7 +283,12 @@ export class PopoverItemDefault extends PopoverItem {
* Removes class responsible for special hover behavior on an item
*/
private removeSpecialHoverBehavior = (): void => {
this.nodes.root?.classList.remove(css.noHover);
const root = this.nodes.root;

root?.classList.remove(css.noHover);
root?.removeEventListener('mouseleave', this.removeSpecialHoverBehavior);
root?.removeEventListener('mouseenter', this.removeSpecialHoverBehavior);
root?.removeEventListener('mousemove', this.removeSpecialHoverBehavior);
};

/**
Expand All @@ -283,7 +300,10 @@ export class PopoverItemDefault extends PopoverItem {
if (!('confirmation' in item) || item.confirmation === undefined) {
try {
item.onActivate?.(item);
this.disableConfirmationMode();

if (this.isConfirmationStateEnabled) {
this.disableConfirmationMode();
}
} catch {
this.animateError();
}
Expand Down
2 changes: 2 additions & 0 deletions src/components/utils/popover/popover-desktop.ts
Original file line number Diff line number Diff line change
Expand Up @@ -156,6 +156,8 @@ export class PopoverDesktop extends PopoverAbstract {
public hide = (): void => {
super.hide();

this.itemsDefault.forEach(item => item.suppressHoverUntilPointerEnters());

this.destroyNestedPopoverIfExists();

this.flipper?.deactivate();
Expand Down
47 changes: 47 additions & 0 deletions test/cypress/tests/ui/toolbox.cy.ts
Original file line number Diff line number Diff line change
Expand Up @@ -215,4 +215,51 @@ describe('Toolbox', function () {
.should('exist');
});
});

it('should not keep a toolbox item hovered after closing and reopening the toolbox', function () {
/** Tool with one toolbox item for the hover regression. */
class HoverTool extends ToolMock {
/** Returns the toolbox entry displayed by this tool. */
public static get toolbox(): ToolboxConfig {
return {
icon: '',
title: 'Hover tool',
};
}
}

cy.createEditor({
tools: {
hoverTool: HoverTool,
},
}).as('editorInstance');

cy.get('[data-cy=editorjs]')
.find('.ce-paragraph')
.click();

cy.get<EditorJS>('@editorInstance').then((editor) => {
editor.toolbar.toggleToolbox(true);
});
cy.get('[data-item-name="hoverTool"]')
.should('be.visible')
.click();

cy.get('[data-item-name="hoverTool"]')
.should('have.class', 'ce-popover-item--no-hover');

cy.get<EditorJS>('@editorInstance').then((editor) => {
editor.toolbar.toggleToolbox(true);
});
cy.get('[data-item-name="hoverTool"]')
.should('be.visible')
.should('have.class', 'ce-popover-item--no-hover')
.should(($item) => {
expect($item[0].matches(':hover')).to.be.false;
});

cy.get('[data-item-name="hoverTool"]')
.trigger('mouseenter')
.should('not.have.class', 'ce-popover-item--no-hover');
});
});