Skip to content

fix(inline-toolbar): make tool shortcuts work with several Editors on a page - #3048

Open
playlikeboy wants to merge 4 commits into
codex-team:nextfrom
playlikeboy:fix/3002-inline-shortcuts-multiple-editors
Open

playlikeboy wants to merge 4 commits into
codex-team:nextfrom
playlikeboy:fix/3002-inline-shortcuts-multiple-editors

Conversation

@playlikeboy

Copy link
Copy Markdown
Contributor

Summary

Fixes #3002. With two Editors on a page, Inline Tools shortcuts (CMD+B, CMD+I, ...) only work in the Editor whose Inline Toolbar opened first. The same happens to an Editor created after another one was destroyed.

Root cause

Since #2832 the shortcuts are bound to document (needed for read-only mode), but they are still stored in the page-wide Shortcuts registry, which allows one handler per shortcut name and element:

  • The second Editor's Shortcuts.add() throws "already registered". The try/catch around enableShortcuts() swallows it, so its shortcuts are never bound. The first Editor's handler runs, but its popover is closed, so nothing happens.
  • close() calls Shortcuts.remove(redactor, shortcut), but the shortcut is bound to document, so it is never removed. destroy() does not remove it either, so the handler of a destroyed Editor stays on the document and blocks every Editor created later.

Changes

  • src/components/modules/toolbar/inline.ts
    • The Inline Toolbar keeps its own Shortcut instances (still on document), registers each once, and removes them in destroy().
    • The handler returns early unless the selection is inside this Editor's wrapper, so a shortcut pressed in one Editor is not handled by another.
    • Removed the Shortcuts.remove(redactor, ...) call from close(). It never matched an inline shortcut, and it could remove a Block Tool shortcut with the same name that the Toolbox bound to the redactor.
    • Removed the empty try/catch, which is no longer needed.
  • test/cypress/tests/modules/InlineToolbar.cy.ts: two tests (two Editors on a page; an Editor created after another one was destroyed).
  • docs/CHANGELOG.md line and package.json bumped to 2.32.0-rc.4 (same as fix(sanitizer): merge sanitize rules for the same tag instead of overwriting them #3041; I'll re-bump whichever of the two lands second).

Testing

  • eslint on the changed files: no errors.
  • vite build in production and test mode: passes.
  • I could not run Cypress locally (my machine has no Xvfb), so CI is the first real run of the new tests. To check the behaviour I drove the built UMD bundle in headless Chrome with the same steps as the tests:
Scenario next this branch
CMD+B in the 2nd Editor on the page text unchanged <b>Second</b> editor text
CMD+B in an Editor created after the first was destroyed text unchanged <b>Second</b> editor text
First Editor after pressing the shortcut in the second unchanged unchanged

Note: tsc reports the missing type declaration for @codexteam/shortcuts on the new import, the same as it already does for utils/shortcuts.ts.

🤖 Generated with Claude Code

Inline Tools shortcuts are bound to the document so they work in
read-only mode, but they were stored in the page-wide Shortcuts registry,
which allows one handler per shortcut and element. The second Editor on a
page failed to register its shortcuts (the error was swallowed), so
CMD+B and others did nothing there. The same happened to an Editor
created after another one was destroyed, because close() removed the
shortcuts from the redactor, where they were never bound, and destroy()
did not remove them at all.

Each Inline Toolbar now keeps its own shortcuts, handles one only when
the selection is inside its Editor, and removes them on destroy.

Co-Authored-By: Claude Fable 5.2 <noreply@anthropic.com>
Follow the pattern of the Link tool tests: select the text, give the Inline
Toolbar time to open and register its shortcuts, then press the shortcut.

Co-Authored-By: Claude Fable 5.2 <noreply@anthropic.com>

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Changes recommended

The destroy/recreate test does not verify document-listener cleanup, so it can pass even when leaked handlers retain destroyed Editors.

1 open issue
What changed in this PR

Fixes #3002 by giving each Editor its own inline-tool shortcut handlers, avoiding conflicts between instances while preserving document-level binding for read-only support.

Changes:

  • Registers shortcuts per Editor, scopes handling to its selection, and removes handlers on destruction.
  • Adds regression tests for multiple Editors and destroy/recreate behavior.
  • Documents the fix and bumps the package to 2.32.0-rc.4.
File Description
test/​cypress/​tests/​modules/​InlineToolbar.cy.ts Adds multi-instance and destroy/recreate shortcut tests.
src/​components/​modules/​toolbar/​inline.ts Manages per-Editor shortcuts, selection checks, and cleanup.
package.json Bumps the release candidate version.
docs/​CHANGELOG.md Records the inline shortcut fix.

Review effort: Balanced

Comment on lines +152 to +153
this.registeredShortcuts.forEach((shortcut) => shortcut.remove());
this.registeredShortcuts.clear();

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Added in 03f4e91: the new test records the keydown listeners bound to the document, checks that opening the Inline Toolbar adds some, and expects none to be left after destroy(). With the two cleanup lines removed, three listeners stay bound, so the test fails without them.

playlikeboy and others added 2 commits November 15, 2026 00:48
Co-Authored-By: Claude Fable 5.2 <noreply@anthropic.com>
…rom the document

Co-Authored-By: Claude Fable 5.2 <noreply@anthropic.com>

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Multiple EditorJS instances on the same page cause inline shortcut registration to fail

2 participants