Skip to content

feat(penpal): highlight expansion for images and mermaid diagrams#547

Merged
loganj merged 7 commits intomainfrom
phase-2-implementation-begins
Mar 30, 2026
Merged

feat(penpal): highlight expansion for images and mermaid diagrams#547
loganj merged 7 commits intomainfrom
phase-2-implementation-begins

Conversation

@loganj
Copy link
Copy Markdown
Collaborator

@loganj loganj commented Mar 30, 2026

Summary

  • When you highlight text that includes an image or mermaid diagram, the entire media element is now highlighted along with the surrounding text — no more partial/missing highlights on media
  • Mermaid diagrams show a yellow border (Google Docs style) instead of trying to paint over the SVG
  • Selecting text that starts at, ends within, or passes through a mermaid diagram all work correctly now
  • If you start a rectangle selection inside a mermaid diagram and drag outside it, the selection automatically switches to normal text selection mode — including the whole diagram — instead of producing weird artifacts
  • Works in both directions (dragging up into a diagram from below, or down out of a diagram)

🤖 Generated with Claude Code

loganj and others added 7 commits March 29, 2026 22:35
…pping

Define the product requirement for expanding highlights to encompass
entire images and mermaid diagrams when they intersect with text, and
the corresponding engineering requirement for the rehype plugin behavior.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…PENPAL-HIGHLIGHT-MEDIA)

Expand highlight marks to encompass entire images and mermaid diagrams
when the highlight also spans adjacent text. Mermaid blocks use annotation
(dataMermaidHighlight on <code>) + CSS classes instead of <mark> wrapping
to avoid breaking imperative SVG rendering. Adds mermaidCrossed flag to
continuation state so post-mermaid text matching handles SVG-polluted
remaining text from sel.toString().

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…rmaid selection behaviors

Broaden P-PENPAL-HIGHLIGHT-MEDIA to cover selections starting at or
dragging out of diagrams. Update E-PENPAL-HIGHLIGHT-MEDIA with rehype
plugin mermaid-start handling and MermaidSelection drag-escape. Cross-ref
E-PENPAL-SVG-DRAG with the escape-to-text transition.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…am (E-PENPAL-HIGHLIGHT-MEDIA)

Two fixes for mermaid + highlight interactions:

1. Rehype plugin: highlights whose startLine falls on a mermaid block now
   annotate the diagram and schedule continuation with mermaidCrossed,
   so text before/after the diagram is also highlighted. Previously the
   mermaid handler SKIP'd before reaching the "start new highlights" path.

2. MermaidSelection: dragging outside the container cancels SVG rect mode
   and transitions to a text selection (via setBaseAndExtent + extend)
   that includes the whole diagram, handing off to SelectionToolbar.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
… (E-PENPAL-HIGHLIGHT-MEDIA)

- Remove dead isMermaid check in handleCodeBlock (caller already SKIPs)
- Media-only block: only SKIP when a wrap actually happened
- Guard wrapInlineMedia behind continuationMatched flag
- Add MarkdownViewer integration test for mermaid highlight class
- Add rehype test for startLine lineOffset resolving to mermaid
- Update TESTING.md with MarkdownViewer coverage and e2e drag-out gap

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…AL-HIGHLIGHT-MEDIA)

Closes the e2e coverage gap: verifies that dragging from inside a
mermaid diagram to outside cancels the SVG rect and transitions to
a text selection with the SelectionToolbar visible.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…ard drag-out

- MarkdownViewer: verify pending-highlight class applied to mermaid
  container div (not just prose marks)
- e2e: verify dragging upward out of mermaid into preceding text
  cancels SVG rect and creates text selection (isAbove branch)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@loganj loganj merged commit 9d765f6 into main Mar 30, 2026
4 checks passed
@loganj loganj deleted the phase-2-implementation-begins branch March 30, 2026 03:11
Copy link
Copy Markdown

@chatgpt-codex-connector chatgpt-codex-connector bot left a comment

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 00d9a89021

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment on lines +111 to +114
const normSelected = normalizeSelected(highlight.selectedText);
if (normSelected.length >= 3) {
continuing.set(highlight.threadId, {
highlight,
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Avoid unconditional continuation for mermaid-only selections

When a highlight starts on a mermaid block, this code always seeds continuing with the full selectedText, even if the user selected only the diagram. In that case, the next prose element is still eligible for continuation matching, so text after the diagram can be incorrectly marked if it shares a prefix with diagram labels (for example, a paragraph starting with "Login" after selecting a diagram containing "Login"). This causes false positive highlights outside the user’s selection.

Useful? React with 👍 / 👎.

// Create a text selection from the mermaid container to the mouse position
const sel = window.getSelection();
sel?.removeAllRanges();
const caretRange = document.caretRangeFromPoint(e2.clientX, e2.clientY);
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Add fallback when creating caret range from pointer position

The drag-to-text handoff calls document.caretRangeFromPoint(...) directly, but that API is non-standard and absent in some browser engines (notably Firefox, which uses caretPositionFromPoint). In those environments this throws at runtime on drag-out, breaking mermaid selection handoff entirely instead of showing the text-selection toolbar.

Useful? React with 👍 / 👎.

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.

1 participant