Skip to content

Commit e1630b3

Browse files
committed
fix: fixed #2579
1 parent e5af3bc commit e1630b3

File tree

2 files changed

+39
-0
lines changed

2 files changed

+39
-0
lines changed

CHANGELOG.md

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -171,6 +171,14 @@
171171
selected placeholder, the characters would disappear or trigger unwanted
172172
behaviors. The placeholder is now deleted before keystroke processing,
173173
allowing all keybindings and character handling to work correctly.
174+
- **#2579** Fixed multiple mathfields showing blinking cursors simultaneously
175+
when `focus()` is called rapidly on multiple mathfields. This occurred
176+
because Chromium browsers don't fire blur events reliably during rapid focus
177+
changes, causing multiple mathfields to remain in a focused state. The fix
178+
implements global focus tracking to ensure only one mathfield can be focused
179+
at a time, explicitly blurring any previously focused mathfield when a new
180+
one gains focus. This handles browser blur event quirks while maintaining
181+
backward compatibility with all existing focus/blur behavior.
174182
- **#2619** Fixed placeholders in multi-row array environments (like
175183
`\displaylines`) not being focusable with pointer clicks. The hit-testing
176184
logic now properly determines which row was clicked before searching for

src/editor-mathfield/mathfield-private.ts

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -147,6 +147,13 @@ const MENU_GLYPH = `<svg xmlns="http://www.w3.org/2000/svg" style="height: 18px;
147147

148148
/** @internal */
149149
export class _Mathfield implements Mathfield, KeyboardDelegateInterface {
150+
/**
151+
* Global tracker for the currently focused mathfield.
152+
* Used to handle cases where browsers don't fire blur events reliably
153+
* (e.g., when focus() is called rapidly on multiple mathfields).
154+
*/
155+
private static _globallyFocusedMathfield: _Mathfield | undefined;
156+
150157
readonly model: _Model;
151158

152159
readonly undoManager: UndoManager;
@@ -1697,9 +1704,27 @@ If you are using Vue, this may be because you are using the runtime-only build o
16971704

16981705
onFocus(options?: { suppressEvents?: boolean }): void {
16991706
if (this.disabled || this.focusBlurInProgress || !this.blurred) return;
1707+
1708+
// If another mathfield is globally tracked as focused, blur it first.
1709+
// This handles cases where browsers don't fire blur events reliably
1710+
// (e.g., rapid focus() calls on multiple mathfields in Chromium).
1711+
const previouslyFocusedMathfield = _Mathfield._globallyFocusedMathfield;
1712+
if (
1713+
previouslyFocusedMathfield &&
1714+
previouslyFocusedMathfield !== this &&
1715+
!previouslyFocusedMathfield.disabled &&
1716+
previouslyFocusedMathfield.hasFocus()
1717+
) {
1718+
// Call onBlur directly to avoid DOM event timing issues
1719+
previouslyFocusedMathfield.onBlur({ dispatchEvents: true });
1720+
}
1721+
17001722
this.focusBlurInProgress = true;
17011723
this.blurred = false;
17021724

1725+
// Update the global tracker to point to this mathfield
1726+
_Mathfield._globallyFocusedMathfield = this;
1727+
17031728
this.stopCoalescingUndo();
17041729

17051730
// Save the current value.
@@ -1775,6 +1800,12 @@ If you are using Vue, this may be because you are using the runtime-only build o
17751800
this.stopCoalescingUndo();
17761801

17771802
this.blurred = true;
1803+
1804+
// Clear the global tracker if it points to this mathfield
1805+
if (_Mathfield._globallyFocusedMathfield === this) {
1806+
_Mathfield._globallyFocusedMathfield = undefined;
1807+
}
1808+
17781809
this.ariaLiveText!.textContent = '';
17791810

17801811
hideSuggestionPopover(this);

0 commit comments

Comments
 (0)