fix(muya): size an image from where its resize handle was grabbed (#5392) by Jocs · Pull Request #5535 · marktext/marktext · GitHub
Skip to content

fix(muya): size an image from where its resize handle was grabbed (#5392) - #5535

Merged
Jocs merged 1 commit into
developfrom
fix/image-resize-left-handle-5392
Sep 23, 2026
Merged

Jocs merged 1 commit into
developfrom
fix/image-resize-left-handle-5392

Conversation

@Jocs

@Jocs Jocs commented Sep 23, 2026

Copy link
Copy Markdown
Member

Fixes #5392.

The bug

Dragging an image's left resize handle resized it several times faster than the pointer moved. A 60 px outward drag widened a 400 px image to 610 px instead of 460; the image hit the column width after about 25 px of travel, and the width saved to the file was larger than the one displayed. A 60 px inward drag collapsed the image to the 50 px floor. The right handle was correct.

Reproduced on develop with real Chromium input. Width sampled every 10 px of pointer travel on a 400 px image:

pointer travel 10 20 30 40 50 60
before 410 430 460 500 550 610
after 410 420 430 440 450 460

Root cause

_mouseMove computed the width from the opposite handle's current position, read fresh on every event:

// left handle
width = relativeAnchor.getBoundingClientRect().left + CIRCLE_RADIO - clientX

For the left handle that reference is the image's right edge. A left-aligned image is pinned on its left and grows on its right, so every width the handler wrote moved the very edge the next event measured from. Each move therefore re-added the whole accumulated delta — width += (leftEdge - clientX) — which compounds per mousemove, so the result depended on drag speed and on how many move events the browser delivered.

The right handle measured against the left edge, which does not move, so it tracked the pointer correctly. That asymmetry is why only one handle misbehaved.

The display/save mismatch follows from the same loop: once the runaway width exceeded the column, max-width: 100% clamped what was rendered while the width attribute kept climbing.

The fix

Snapshot the pointer position and the image width at mousedown, and offset from those. Nothing read during the drag is affected by what the drag writes, so the feedback loop is gone rather than compensated for. This also drops the need to read either handle's geometry while dragging.

Because the reference is no longer a particular edge, the fix is layout-independent: verified 1:1 tracking for data-align center and right as well as the default left-aligned image.

Tests

  • packages/muya/e2e/tests/drag/image-resize-left-handle-5392.spec.ts — new. Drags each handle 60 px in six steps with real Chromium mouse input and asserts the saved width lands within 4 px of the distance dragged, plus that the saved width matches the displayed one. A/B verified: the two left-handle cases fail by 150 px on the unfixed source and pass on the fixed one; the right-handle case passes on both.
  • imageResizeBar.spec.ts — the unit drag helper built its mousedown with no coordinates, which no real browser does; it now carries x like the mousemove already did. The pinned width changes from 195 to 200 because the width is now measured from the press rather than from a handle's rect.

Fixture note: the spec uses a 400×300 image on purpose. usesDefaultObjectSize pins an inline style="width" on any image measuring 300 wide or 150 tall (#4991), and that inline style overrides the width attribute the bar writes, so such an image does not resize at all — a fixture of those dimensions passes the test without exercising the code.

Verification

  • packages/muya/e2e tests/drag/ — 72/72 (24 × 3 repeats), and 48/48 on a final re-run.
  • muya unit suite, ESLint, tsc --noEmit, madge --circular — clean. (The worktree is missing packages/muya/node_modules, which reds out 10 export/prism/katex spec files; that failure set is byte-identical with and without this change.)
  • Full muya e2e run compared A/B against the unfixed source: identical failure sets apart from Cmd/Ctrl+D applies strikethrough, which flips ✘✘✓✘ across four identical repeats with this change in place — flaky, and untouched by it.

🤖 Generated with Claude Code

)

`_mouseMove` measured the new width against the opposite handle's current
position, read fresh on every event. For the left handle that reference is
the image's right edge, and a left-aligned image grows on its right side --
so each width it wrote moved the very edge the next event measured from,
re-adding the whole accumulated delta. A 60 px drag widened the image by
210 px, ran away to the column width after ~25 px of travel, and saved a
width wider than the one on screen. The right handle measured against the
left edge, which does not move, so it tracked the pointer correctly.

Snapshot the pointer position and the image width at mousedown and offset
from those instead. Nothing read during the drag is affected by what the
drag writes, so both handles now track the pointer 1:1, for centre- and
right-aligned images as much as the default left-aligned one.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@Jocs
Jocs force-pushed the fix/image-resize-left-handle-5392 branch from d8dbecb to 0940711 Compare September 23, 2026 14:49
@Jocs
Jocs merged commit 9b34d72 into develop Sep 23, 2026
7 checks passed
@Jocs
Jocs deleted the fix/image-resize-left-handle-5392 branch September 23, 2026 14:56
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] Dragging an image's left resize handle resizes it several times faster than the pointer moves

1 participant