Skip to content

fix(search): don't re-center visible matches on find navigation (SD-3315)#3572

Merged
caio-pizzol merged 4 commits into
mainfrom
caio/sd-3315-find-replace-scroll
May 29, 2026
Merged

fix(search): don't re-center visible matches on find navigation (SD-3315)#3572
caio-pizzol merged 4 commits into
mainfrom
caio/sd-3315-find-replace-scroll

Conversation

@caio-pizzol
Copy link
Copy Markdown
Contributor

@caio-pizzol caio-pizzol commented May 29, 2026

Find navigation felt unstable: the page jumped on every next/previous. This fixes it in two layers, both in search navigation only.

1. Stop re-centering an already-visible match. goToSearchResult scrolled with block: 'center' every time, so the document jumped ~50px even when the match was already on screen. scrollToPosition gains ifNeeded: when the match element is already fully inside the scroll container it downgrades to nearest (a no-op); off-screen/clipped matches still center. goToFirstMatch keeps plain centering for the initial jump.

2. Stop the selection-sync scroll from fighting search nav. Fixing (1) exposed a second scroll: navigating via the find UI restores focus to the find input, which fires a selectionUpdate that reverts the editor selection to its pre-search caret; selection-sync then scrolled the viewport to that stale caret and the RAF re-assert yanked it back — a visible flash on every navigation. scrollToPosition gains suppressSelectionSyncScroll: while a search-owned scroll is in flight (set before its scroll, cleared in its RAF re-assert) #scrollActiveEndIntoView is skipped, so it can't fight the search scroll. The selection overlay still renders; normal keyboard/pointer selection scroll resumes the next frame. Active-match tracking and Replace are storage-owned, so the selection revert doesn't affect them.

Both options are opt-in and only set by search next/previous; other callers of scrollToPosition (AI nav, PositionTracker, public navigateTo) are unchanged.

Reported in #3500.

Review: focus on the two new options in scrollToPosition / scrollToPositionAsync, the #scrollActiveEndIntoView early-return, and that goToFirstMatch still centers. Lint warnings in PresentationEditor.ts are pre-existing.
Verified: instrumented runtime trace through the real find UI — visible match = 0px scroll, off-screen = centered, 30 consecutive navigations with zero flash; full search + scroll unit suites (208) and tsc -b pass. Cross-browser Playwright matrix was green on layer (1); needs a re-run for (2).
Test note: the selection-sync suppression is verified at runtime; it is not cleanly unit-testable in the super-editor mock harness (the gate is a private, event-driven method and the jitter needs the superdoc find-UI focus dynamics). A find-UI E2E regression test is a recommended fast-follow.

…315)

Search next/previous re-centered the active match on every move via
scrollToPosition({ block: 'center' }), jumping the document ~50px even when
the match was already on screen. Add an opt-in `ifNeeded` mode that downgrades
to 'nearest' (a no-op) when the match is fully visible, keeping center for
off-screen matches. goToFirstMatch still centers the initial result.
@caio-pizzol caio-pizzol requested a review from a team as a code owner May 29, 2026 17:23
@linear-code
Copy link
Copy Markdown

linear-code Bot commented May 29, 2026

SD-3315

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: eaa582479a

ℹ️ About Codex in GitHub

Codex has been enabled to automatically 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 👍.

When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".

Copy link
Copy Markdown

@cubic-dev-ai cubic-dev-ai Bot left a comment

Choose a reason for hiding this comment

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

cubic analysis

No issues found across 4 files

Linked issue analysis

Linked issue: SD-3315: Bug: Find & replace scrolls the page ~50px on every match navigation, even when the match is already visible

Status Acceptance criteria Notes
Per-match (next/previous) navigation does not re-center an already-fully-visible match (no ~50px jump). PresentationEditor.scrollToPosition gained an ifNeeded mode that downgrades to 'nearest' when the precise target element is fully visible, and search.next/previous calls opt into ifNeeded. Tests verify the 'nearest' call for a fully-visible match.
Off-screen or partially-clipped matches still center (preserve expected centering when needed). The implementation only downgrades to 'nearest' for a fully-visible target; off-screen or partially-clipped elements keep the requested block (center). Tests cover both off-screen and partially-clipped cases and expect centering.
Initial/first-match navigation still recenters (first-match jump unchanged). The change is explicitly limited to per-match navigation—first-match logic was not modified and remains centered. The PR description and code changes show only next/previous opting into ifNeeded.
The fix does not reintroduce the hidden-editor selection-sync jump: scroll path retains the RAF re-assert (no early-return). The implementation intentionally downgrades to 'nearest' rather than early-returning so the existing scrollIntoView + RAF re-assert behavior remains in place and continues to defend against the hidden editor's selection-sync scroll.

Tip: cubic could auto-approve low-risk PRs like this, if it thinks it's safe to merge. Learn more

Re-trigger cubic

@codecov-commenter
Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.

📢 Thoughts on this report? Let us know!

@caio-pizzol caio-pizzol marked this pull request as draft May 29, 2026 17:57
caio-pizzol and others added 2 commits May 29, 2026 15:24
…315)

The ifNeeded scroll removed the per-match re-center, but exposed a second
scroll: navigating via the find UI restores focus to the find input, which
fires a selectionUpdate that reverts the editor selection to its pre-search
caret; selection-sync then scrolled the viewport to that stale caret and the
RAF re-assert yanked it back — a jump/flash on every navigation.

Add an opt-in `suppressSelectionSyncScroll` to scrollToPosition: while a
search-owned scroll is in flight (set before its scroll, cleared in its RAF
re-assert), #scrollActiveEndIntoView is skipped so it can't fight the search
scroll. The selection overlay still renders; normal keyboard/pointer selection
scroll resumes the next frame. Active-match tracking and replace are
storage-owned, so the selection revert does not affect them.
@caio-pizzol caio-pizzol marked this pull request as ready for review May 29, 2026 18:46
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: a7ccb7b334

ℹ️ About Codex in GitHub

Codex has been enabled to automatically 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 👍.

When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".

Comment thread packages/super-editor/src/editors/v1/extensions/search/search.js
Copy link
Copy Markdown

@cubic-dev-ai cubic-dev-ai Bot left a comment

Choose a reason for hiding this comment

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

cubic analysis

1 issue found across 4 files

Linked issue analysis

Linked issue: SD-3315: Bug: Find & replace scrolls the page ~50px on every match navigation, even when the match is already visible

Status Acceptance criteria Notes
Do not re-center an already-visible match when navigating next/previous (no ~50px jump) scrollToPosition gained an ifNeeded mode that downgrades to 'nearest' for fully-visible match elements; search navigation passes ifNeeded so already-visible matches are not re-centered.
Keep centering behavior for off-screen matches and initial jump ifNeeded only downgrades when the precise match element is fully visible; off-screen or partially-clipped matches still use the requested 'center' block. The PR also preserves plain centering for the initial jump.
⚠️ Prevent selection-sync from fighting search navigation (avoid selection-scroll flash/jitter during find nav) The PR implements a suppressSelectionSyncScroll option and a #suppressSelectionScrollUntilRaf flag which is set/cleared around the RAF re-assert and causes #scrollActiveEndIntoView to early-return while the search-owned scroll is in flight. This matches the intended suppression behavior, but the change is difficult to unit-test in the mock harness and the PR notes the runtime verification is instrumented rather than fully covered by unit tests / cross-browser bits need re-run, so a follow-up E2E regression is recommended.

Reply with feedback, questions, or to request a fix.

Fix all with cubic | Re-trigger cubic

Comment thread packages/super-editor/src/editors/v1/extensions/search/search.js
…315)

scrollToPositionAsync forwarded ifNeeded:true into its post-mount retry. A match
that was off-screen at call time (hence the async/mount path) could end up
edge-visible after the page scrolls into view, then downgrade to 'nearest' and
skip the centering it should get. Force ifNeeded:false on the retry (keeping
suppressSelectionSyncScroll); the fast path keeps ifNeeded for already-mounted
matches. Flagged in review by Codex and cubic.
@caio-pizzol caio-pizzol linked an issue May 29, 2026 that may be closed by this pull request
@caio-pizzol caio-pizzol self-assigned this May 29, 2026
@caio-pizzol caio-pizzol merged commit 633849a into main May 29, 2026
69 checks passed
@caio-pizzol caio-pizzol deleted the caio/sd-3315-find-replace-scroll branch May 29, 2026 19:24
@superdoc-bot
Copy link
Copy Markdown
Contributor

superdoc-bot Bot commented May 29, 2026

🎉 This PR is included in superdoc-cli v0.15.0

The release is available on GitHub release

@superdoc-bot
Copy link
Copy Markdown
Contributor

superdoc-bot Bot commented May 29, 2026

🎉 This PR is included in superdoc-sdk v1.14.0

@superdoc-bot
Copy link
Copy Markdown
Contributor

superdoc-bot Bot commented May 29, 2026

🎉 This PR is included in @superdoc-dev/mcp v0.10.0

The release is available on GitHub release

@superdoc-bot
Copy link
Copy Markdown
Contributor

superdoc-bot Bot commented May 29, 2026

🎉 This PR is included in superdoc v1.38.0

The release is available on GitHub release

@superdoc-bot
Copy link
Copy Markdown
Contributor

superdoc-bot Bot commented May 29, 2026

🎉 This PR is included in @superdoc-dev/react v1.9.0

The release is available on GitHub release

@superdoc-bot
Copy link
Copy Markdown
Contributor

superdoc-bot Bot commented May 29, 2026

🎉 This PR is included in vscode-ext v2.10.0

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Find & Replace feature scroll issue

2 participants