fix(block-editor): apply links to a selected image instead of replacing it#36368
Conversation
…ng it (#36361) In the new block editor, selecting an image and clicking the toolbar Link button deleted the image and replaced it with a text link. The image node already supports href/target attributes end-to-end; the break was purely in the UI flow, which always routed through the text-link insert path. - Toolbar Link button now detects a selected dotImage and opens the link popover in image-link mode (URL + open-in-new-tab only; no Text/Advanced), applying the link via updateAttributes('dotImage') so the image is preserved. - Add a Remove-link (trash) action when editing an image that already has a link. - Clicking a linked image no longer opens the text-link editor; it selects the image node (link is edited from the toolbar) and prevents navigation. - Fix layout jump/extra margin when a link wraps the image: zero the inline-block baseline gap and the Tailwind Typography img margin that returns once the image is no longer a direct figure child. - Toolbar Link button reflects an active state for linked images (isImageLinked), mirroring isLink for text links. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
|
Claude finished @rjvelazco's task in 1m 19s —— View job Rollback Safety Analysis
Result: ✅ Safe to Roll BackAll 10 changed files are frontend-only (Angular TypeScript/HTML/CSS) and one localization properties file. None of the changes fall into any rollback-unsafe category:
Summary: The PR exclusively modifies Angular component templates, TypeScript logic, CSS, and a Java |
🤖 dotBot Review (Bedrock)Reviewed 10 file(s); 7 candidate(s) → 5 confirmed, 1 uncertain (unverified, kept for review). Confirmed findings
🔎 Uncertain (could not confirm or disprove — review manually)
us.deepseek.r1-v1:0 · Run: #28457758185 · tokens: in: 60982 · out: 14949 · total: 75931 · calls: 22 · est. ~$0.163 |
| @@ -174,6 +178,19 @@ | |||
| } | |||
|
|
|||
| <div class="flex justify-end gap-2 pt-1"> | |||
There was a problem hiding this comment.
🟠 [High] Missing event handler implementation
The template references onRemoveImageLink() click handler but this method is not implemented in link-popover.component.ts, causing runtime errors when attempting to remove image links.
…top layout jump (#36361) Once the <a> wraps the image, the anchor (not the img) is the inline-level box in the figure's formatting context, so it sits on the baseline and the browser reserves font-descender space below it (~12px). Align the anchor to the top too. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The wrapping <a> made the browser treat clicks as link interactions, so ProseMirror needed several clicks before it node-selected the image and showed its toolbar options. Select the node on the first mousedown from the image node view and suppress the anchor's default behaviour. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…o-an-image-image-properties-menu-not-accessible
|
@claude review this changes, pretty please |
|
Claude finished @rjvelazco's task in 1m 21s —— View job Code Review
Overall AssessmentThis is a clean, well-scoped fix. The core approach is correct: routing the link toolbar button through Below are the issues I found, from most to least significant. 🔴 Bug:
|
| Severity | Issue | File | Line |
|---|---|---|---|
| 🔴 Bug (latent) | { href } spreads null into anchorAttrs |
image.extension.ts |
143 |
| 🟡 Missing tests | onRemoveImageLink has no spec |
link-popover.component.ts |
433 |
| 🟡 A11y | Remove button only responds to mousedown, not keyboard click |
link-popover.component.html |
187 |
The href: null spread is latent (current guard prevents it rendering), but it should be fixed before it causes confusion. Fix this →
- image.extension.ts: build anchorAttrs conditionally so a null href never serializes as href="null" (latent issue flagged in review). - link-popover.component.html: make the Remove-link button keyboard-accessible by splitting into (mousedown) preventDefault + (click) handler, so Enter/Space activate it without blurring the editor or double-firing on mouse. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
#36361) Gate the link-navigation preventDefault on the *clicked* element being an image (within the anchor) rather than any descendant img, so a text click in a mixed anchor still routes to the text-link editor. Addresses PR review feedback. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Review dispositionsThanks for the automated reviews. Summary of how each finding was handled: Addressed
False positives (no change)
Acknowledged, no change
Note on testsNo spec was added for |
The trash (Remove link) button now shows whenever editing an existing link, not just images. Generalized onRemoveImageLink → onRemoveLink: images clear href/target; text links unset the link mark over its full range. Gated on canRemoveLink (existing href for images, linkEl for text) so it never shows while creating a new link over selected text. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Proposed Changes
Fixes #36361 — in the new block editor, selecting an image and clicking the toolbar Link button deleted the image and replaced it with a text link. The
dotImagenode already supportshref/targetend-to-end (it parses a wrapping<a>and re-wraps the<img>on render); the break was purely in the UI flow, which always routed through the text-link insert path.What changed
dotImagenode is selected, the link popover opens in image-link mode (URL + "Open in new tab" only; Text/Advanced fields hidden) and applies the link viaupdateAttributes('dotImage', { href, target }), so the image is preserved instead of replaced.href/target.imgmargin that reappears once the image is no longer a direct<figure>child.isImageLinked), mirroringisLinkfor text links.The text-link flow is unchanged. No
dotImagenode name or stored-content shape changed — links round-trip through the existinghref/targetattributes, so no data migration is required.Files
link-popover.component.{ts,html}— image-link mode, Remove actiontoolbar.component.{ts,html}+editor-toolbar.store.ts— image detection, active stateeditor-chrome-click.ts— don't open the dialog on linked-image clickseditor.component.css— layout/margin fixeseditor-popover.service.ts—isImageLinkpayload flagLanguage.properties—dot.block.editor.dialog.link.removeTesting
pnpm nx lint new-block-editor✓tsc --noEmiton the lib ✓<a>(not replaced); re-select shows active Link button + trash to remove; no layout jump toggling the link; text-link flow unchanged.Video
video.mov
🤖 Generated with Claude Code