Skip to content

fix(media): drag selection follows the pointer beyond the pane and auto-scrolls at edges - #342

Draft
jlocala1 wants to merge 4 commits into
mieweb:mainfrom
jlocala1:fix/transcript-drag-autoscroll
Draft

fix(media): drag selection follows the pointer beyond the pane and auto-scrolls at edges#342
jlocala1 wants to merge 4 commits into
mieweb:mainfrom
jlocala1:fix/transcript-drag-autoscroll

Conversation

@jlocala1

Copy link
Copy Markdown
Collaborator

Problem

Drag-selecting words in the MediaEditor transcript is unreliable at the pane boundaries:

  • Drag the highlight toward the bottom (or top) of the pane and keep going — the selection stops following the mouse.
  • Hold the drag at the edge — the pane never scrolls, so you can't select past what's currently visible.

Cause

  1. onMouseLeave on the listbox called handleMouseUp, silently ending the drag the moment the pointer left the pane.
  2. Selection only extended via per-word mouseenter, so padding, end-of-line whitespace, and anything outside the pane never extended it — and there was no auto-scroll loop at all.

Fix

For the lifetime of one drag, document-level mousemove/mouseup listeners take over:

  • The selection extends to the word under the clamped pointer position (elementFromPoint, with fallback probe points for whitespace misses), so it keeps tracking wherever the mouse goes.
  • While the pointer is held at or beyond a pane edge, an animation-frame loop scrolls the pane (speed scales with overshoot, capped) and keeps extending the selection as new words scroll under the pointer.
  • Releasing outside the window ends the drag (buttons === 0 guard on mousemove).
  • Leaving the pane now only cancels the pending long-press (its previous side effect), never the drag itself.
  • Listeners and the scroll frame are detached on mouseup and on unmount.

Tests

Two regression tests added — both fail against the previous implementation (verified by stashing the fix):

  • selection keeps extending while the pointer is outside the pane, and stops changing after mouseup
  • mouseleave no longer cancels an in-progress drag

Gates: lint ✅ typecheck ✅ format ✅ 399/399 tests ✅

🤖 Generated with Claude Code

…to-scrolls at edges

Two defects made drag-highlight unreliable in the transcript editor:

1. onMouseLeave on the listbox called handleMouseUp, silently ending the
   drag the moment the pointer left the pane.
2. Selection only extended via per-word mouseenter, so padding,
   end-of-line whitespace, and anything outside the pane never extended
   it - and nothing scrolled while holding at an edge.

The drag now attaches document-level mousemove/mouseup listeners for its
lifetime: the selection extends to the word under the clamped pointer
(elementFromPoint with fallback probes), the pane auto-scrolls while the
pointer is held at or past an edge, releasing outside the window ends
the drag (buttons === 0 guard), and leaving the pane only cancels the
pending long-press, not the drag. Regression tests fail on the previous
implementation.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Copilot AI review requested due to automatic review settings July 27, 2026 17:05

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.

Pull request overview

Improves transcript drag-selection behavior in MediaEditor so selections keep tracking the pointer outside the transcript pane and the pane auto-scrolls when dragging at its edges.

Changes:

  • Switches drag-selection tracking to document-level mousemove/mouseup listeners for the lifetime of a drag.
  • Adds an animation-frame auto-scroll loop that scrolls the transcript pane when the pointer is held near/over the top/bottom edges.
  • Adds regression tests covering selection extension outside the pane and ensuring mouseleave no longer cancels an in-progress drag.

Reviewed changes

Copilot reviewed 2 out of 2 changed files in this pull request and generated 2 comments.

File Description
src/components/MediaEditor/MediaEditor.tsx Implements document-level drag tracking, selection extension via elementFromPoint, and edge auto-scroll; removes onMouseLeave ending the drag.
src/components/MediaEditor/MediaEditor.test.tsx Adds regression tests for dragging selection beyond the pane and preventing mouseleave from canceling a drag.

Comment thread src/components/MediaEditor/MediaEditor.tsx
Comment thread src/components/MediaEditor/MediaEditor.tsx
elementFromPoint only resolves inside the viewport, but the transcript
pane can extend beyond it (found on the deployed app at laptop viewport
sizes: auto-scroll ran but the highlight stalled at the anchor). Probe
points and the edge zones now use the intersection of the pane rect and
the viewport, and a zero-area pane extends nothing.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Copilot AI review requested due to automatic review settings July 27, 2026 17:52

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.

Pull request overview

Copilot reviewed 2 out of 2 changed files in this pull request and generated 2 comments.

Comment thread src/components/MediaEditor/MediaEditor.tsx Outdated
Comment thread src/components/MediaEditor/MediaEditor.tsx
… sits in empty pane space

Dragging below the last line of a short or fully scrolled transcript put
the clamped probe point in the pane's empty bottom area where no word
span exists, so the selection stalled. When every probe misses, extend
to the last word above the point (or the first word when above all),
matching standard text-editor drag behavior.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Copilot AI review requested due to automatic review settings July 27, 2026 18:05

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.

Pull request overview

Copilot reviewed 2 out of 2 changed files in this pull request and generated 1 comment.

Comments suppressed due to low confidence (2)

src/components/MediaEditor/MediaEditor.tsx:810

  • stepDragAutoScroll schedules a new requestAnimationFrame unconditionally, even when the pointer is nowhere near an edge and no scrolling happens (step === 0). This creates a continuous 60fps loop for the entire drag, which is unnecessary work for long drags.
      if (step !== 0) {
        container.scrollTop += step;
        extendSelectionToPointer();
      }
      dragScrollFrame.current = requestAnimationFrame(stepDragAutoScroll);

src/components/MediaEditor/MediaEditor.tsx:853

  • If the auto-scroll loop is made conditional (only running while step !== 0), it needs a way to restart when the pointer later moves back into an edge zone. A lightweight approach is to request a frame on mousemove only when no frame is currently queued.
        if (e.buttons === 0) {
          up();
          return;
        }
        dragPointer.current = { x: e.clientX, y: e.clientY };

Comment thread src/components/MediaEditor/MediaEditor.tsx
@jlocala1

Copy link
Copy Markdown
Collaborator Author

Two follow-up commits from testing on the deployed pulseclip dev instance:

  • d5d637d — clamp probe points and auto-scroll edge zones to the visible pane (viewport ∩ container): elementFromPoint only resolves inside the viewport, so panes extending past it stalled the highlight while scroll kept running.
  • f46023f — when every probe misses because the pointer sits in empty pane space (below the last line of a short or fully scrolled transcript), extend to the nearest end — standard editor behavior.

Verified on the deployed instance: drag held below the viewport scrolls the pane to its limit and extends the selection to the final word (298/303 words, last word selected). All gates green, 399/399 tests.

🤖 Generated with Claude Code

- Clear a pending long-press timer on unmount alongside the listeners
  and scroll frame
- Clamp every probe X into the pane so narrow panes cannot resolve
  unrelated DOM
- Guard the auto-scroll step against a fully offscreen pane (keep the
  loop alive, never scroll)
- Extend to the first word when the pointer sits in the top padding
  above all spans, mirroring the past-the-end fallback

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Copilot AI review requested due to automatic review settings July 27, 2026 18:24

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.

Pull request overview

Copilot reviewed 2 out of 2 changed files in this pull request and generated no new comments.

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.

2 participants