From f7402995deaf7687a4dd0f3d8f97b57a77c11d2b Mon Sep 17 00:00:00 2001 From: arimieandreea Date: Tue, 23 Jun 2026 17:19:29 +0300 Subject: [PATCH 1/3] fix: prevent toolbar from opening on text selection and Cmd+A PIE-699 --- .../editable-html-tip-tap/src/extensions/math.js | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/packages/editable-html-tip-tap/src/extensions/math.js b/packages/editable-html-tip-tap/src/extensions/math.js index 5c100d560..97d297624 100644 --- a/packages/editable-html-tip-tap/src/extensions/math.js +++ b/packages/editable-html-tip-tap/src/extensions/math.js @@ -232,11 +232,19 @@ export const MathNodeView = (props) => { editor.commands.focus(); }; + // Only open the toolbar when this node is *explicitly* selected + // via a NodeSelection — not when it's merely included in a broader + // TextSelection or AllSelection (e.g. click-drag across math, or Cmd+A). useEffect(() => { - if (selected) { + if (!selected) return; + + const { selection } = editor.state; + const isNodeSelected = selection.node?.type?.name === 'math'; + + if (isNodeSelected) { setShowToolbar(true); } - }, [selected]); + }, [selected, editor]); useEffect(() => { setToolbarOpened(editor, selected || showToolbar); From af3b72cb60c2ec31f6c9a1a6063e25af3439fd3c Mon Sep 17 00:00:00 2001 From: arimieandreea Date: Wed, 24 Jun 2026 16:06:54 +0300 Subject: [PATCH 2/3] fix: add test for math node selection PIE-699 --- .../src/extensions/__tests__/math.test.js | 56 ++++++++++++++++++- 1 file changed, 55 insertions(+), 1 deletion(-) diff --git a/packages/editable-html-tip-tap/src/extensions/__tests__/math.test.js b/packages/editable-html-tip-tap/src/extensions/__tests__/math.test.js index ac3d40393..a956c1b12 100644 --- a/packages/editable-html-tip-tap/src/extensions/__tests__/math.test.js +++ b/packages/editable-html-tip-tap/src/extensions/__tests__/math.test.js @@ -1,5 +1,5 @@ import React from 'react'; -import { render, waitFor, fireEvent } from '@testing-library/react'; +import { render, waitFor, fireEvent, act } from '@testing-library/react'; import { EnsureTextAfterMathPlugin, MathNode, MathNodeView, ZeroWidthSpaceHandlingPlugin } from '../math'; import * as toolbarUtils from '../../utils/toolbar'; @@ -390,6 +390,7 @@ describe('MathNodeView', () => { selection: { from: 0, to: 1, + node: { type: { name: 'math' } }, }, tr: { setSelection: jest.fn().mockReturnThis(), @@ -724,6 +725,59 @@ describe('MathNodeView', () => { }); }); + describe('selection-based toolbar guard', () => { + it('opens toolbar when selected transitions to true and the editor has a NodeSelection on math', async () => { + // Start unselected (as the component always mounts in the real editor), + // then simulate TipTap delivering selected=true with a proper math NodeSelection. + const { queryByTestId, rerender } = render(); + expect(queryByTestId('math-toolbar')).not.toBeInTheDocument(); + + rerender(); + await waitFor(() => { + expect(queryByTestId('math-toolbar')).toBeInTheDocument(); + }); + }); + + it('does not open toolbar when selected briefly becomes true but editor selection has no node (Cmd+A / drag case)', async () => { + // Real-world timing: ProseMirror calls selectNode() (setting selected=true) + // while the editor's actual selection is already a TextSelection or AllSelection + // with no `.node`. The effect must notice this and keep the toolbar closed. + const editor = { + ...defaultProps.editor, + state: { + ...defaultProps.editor.state, + selection: { from: 0, to: 100 }, // no .node — TextSelection / AllSelection shape + }, + }; + + const { queryByTestId, rerender } = render( + , + ); + rerender(); + + await act(async () => {}); + expect(queryByTestId('math-toolbar')).not.toBeInTheDocument(); + }); + + it('does not open toolbar when selected briefly becomes true but NodeSelection targets a non-math node', async () => { + const editor = { + ...defaultProps.editor, + state: { + ...defaultProps.editor.state, + selection: { from: 0, to: 1, node: { type: { name: 'image' } } }, + }, + }; + + const { queryByTestId, rerender } = render( + , + ); + rerender(); + + await act(async () => {}); + expect(queryByTestId('math-toolbar')).not.toBeInTheDocument(); + }); + }); + it('does not close toolbar when clicking equation editor dropdown', async () => { const { queryByTestId } = render(); From cd4dc8939f7b8313a80290176806467ef9a928ec Mon Sep 17 00:00:00 2001 From: arimieandreea Date: Wed, 24 Jun 2026 16:08:25 +0300 Subject: [PATCH 3/3] fix: add test for math node selection PIE-699 --- .../src/extensions/__tests__/math.test.js | 5 ----- 1 file changed, 5 deletions(-) diff --git a/packages/editable-html-tip-tap/src/extensions/__tests__/math.test.js b/packages/editable-html-tip-tap/src/extensions/__tests__/math.test.js index a956c1b12..35087bc40 100644 --- a/packages/editable-html-tip-tap/src/extensions/__tests__/math.test.js +++ b/packages/editable-html-tip-tap/src/extensions/__tests__/math.test.js @@ -727,8 +727,6 @@ describe('MathNodeView', () => { describe('selection-based toolbar guard', () => { it('opens toolbar when selected transitions to true and the editor has a NodeSelection on math', async () => { - // Start unselected (as the component always mounts in the real editor), - // then simulate TipTap delivering selected=true with a proper math NodeSelection. const { queryByTestId, rerender } = render(); expect(queryByTestId('math-toolbar')).not.toBeInTheDocument(); @@ -739,9 +737,6 @@ describe('MathNodeView', () => { }); it('does not open toolbar when selected briefly becomes true but editor selection has no node (Cmd+A / drag case)', async () => { - // Real-world timing: ProseMirror calls selectNode() (setting selected=true) - // while the editor's actual selection is already a TextSelection or AllSelection - // with no `.node`. The effect must notice this and keep the toolbar closed. const editor = { ...defaultProps.editor, state: {