fix(muya): take the image references from the live DOM after selecting (#5391) by Jocs · Pull Request #5534 · marktext/marktext · GitHub
Skip to content

fix(muya): take the image references from the live DOM after selecting (#5391) - #5534

Merged
Jocs merged 1 commit into
developfrom
fix/image-resize-bar-caret-on-image-line-5391
Sep 23, 2026
Merged

Jocs merged 1 commit into
developfrom
fix/image-resize-bar-caret-on-image-line-5391

Conversation

@Jocs

@Jocs Jocs commented Sep 23, 2026

Copy link
Copy Markdown
Member

Closes #5391.

The bug

With the caret on the image's line, the first click on an image showed the image toolbar but no resize handles — both were drawn at the window's top-left corner (left: -5px; top: -25px), where only a ~5px sliver is visible and dragging cannot resize. A second click placed them correctly.

Root cause

ImageSelection._handleClickInlineImage emitted muya-transformer (and the toolbar's rect) from the nodes present at click time, and only afterwards called selectImage. That call nulls editor.activeContentBlock, which runs Format.blurHandler → checkNeedRender() → update(), and InlineRenderer.patch reassigns the paragraph's innerHTML — replacing the clicked image's wrapper and container.

checkNeedRender() is true whenever the caret sits within one character of a token's range, so a caret anywhere on the image's own line always triggers it. That is the state a document opening on an image is already in: Editor.init() focuses the first block at offset 0.

ImageResizeBar renders on a setTimeout, so it was left holding a detached container — an all-zero bounding rect, hence the corner. Its autoUpdate loop never recovers, because a detached node never moves. The second click found the block already blurred, so nothing re-rendered and the handles landed correctly.

Instrumented confirmation (tagging the container before the click):

emit muya-transformer → reference tagged "A"
after the click       → live container has no tag, its left is 290
                        bar style left: -5px, top: -25px

The fix

Select first, then read both references off the live DOM. The clicked image is re-found by its position among the paragraph's images, which survives the re-render; ids do not identify it (images sharing a src and paragraph offset render with the same id, which is why the previous code resolved from the clicked wrapper in the first place).

Taking the toolbar's rect after the re-render too fixes a second manifestation found while investigating: when the caret had revealed the markers of another token in the same paragraph, hiding them on blur reflows the line and shifts the image sideways (measured: 35.25px for **bold** ![alt](…) tail), so the pre-render snapshot left the toolbar behind by that offset.

Tests

  • packages/muya/src/selection/__tests__/imageResizeBarCaretOnImageLine.spec.ts — 2 unit specs asserting the emitted reference is still attached to the document, and is the clicked one when a paragraph holds several. Both fail on develop.
  • packages/muya/e2e/tests/drag/image-resize-bar-caret-on-image-line-5391.spec.ts — 3 Playwright specs measuring real handle/toolbar geometry for the issue's three entry paths. All three fail on develop (handles off by 290px).

Verified locally: full muya unit suite unchanged apart from the 2 new passes; full muya e2e chromium run 390 passed, the remaining failures reproduced identically on develop in isolation (plantuml/sequence network flakes, inline/format-toolbar).

🤖 Generated with Claude Code

#5391)

Clicking an image emitted `muya-transformer` (and the image toolbar's rect)
from the nodes that were in the document at click time, and only then called
`selectImage`. That call nulls `editor.activeContentBlock`, which runs
`Format.blurHandler` -> `checkNeedRender()` -> `update()`, and the inline
renderer's `patch` reassigns the paragraph's `innerHTML`. Every node inside
it, the clicked image's wrapper and container included, is replaced.

`checkNeedRender()` is true whenever the caret sits within one character of a
token's range, so a caret anywhere on the image's own line always triggers it
-- the state a document that opens on an image is already in, since
`Editor.init()` focuses the first block at offset 0. `ImageResizeBar` renders
on a `setTimeout`, so by then it held a detached container: an all-zero
bounding rect, drawing both handles at `left: -5px; top: -25px` instead of on
the image's edges, where only a sliver shows and dragging cannot resize.
`autoUpdate` never recovers, because a detached node never moves. A second
click found the block already blurred, hence no re-render and correct handles.

Select first, then read both references off the live DOM. The clicked image is
re-found by its position among the paragraph's images, which survives the
re-render -- ids do not identify it (images sharing a src and paragraph offset
render with the same id). Taking the toolbar's rect afterwards too fixes the
second manifestation: when the caret revealed markers of another token in the
paragraph, hiding them on blur reflows the line and shifts the image sideways,
so the pre-render rect left the toolbar behind by that offset.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@Jocs
Jocs merged commit 82e5201 into develop Sep 23, 2026
7 checks passed
@Jocs
Jocs deleted the fix/image-resize-bar-caret-on-image-line-5391 branch September 23, 2026 14:39
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.

[Bug] First click on an image puts its resize handles in the window's top-left corner when the caret is on the image's line

1 participant