Skip to content

Address review findings: navigation edge cases, dropdown stacking, verse-0 dead code#103

Merged
imnasnainaec merged 8 commits into
refine-segment-viewfrom
rsv2
Jun 12, 2026
Merged

Address review findings: navigation edge cases, dropdown stacking, verse-0 dead code#103
imnasnainaec merged 8 commits into
refine-segment-viewfrom
rsv2

Conversation

@imnasnainaec

@imnasnainaec imnasnainaec commented Jun 12, 2026

Copy link
Copy Markdown
Contributor

Devin: https://app.devin.ai/review/sillsdev/interlinearizer-extension/pull/103

Follow-ups to the segment-view rework, addressing code-review findings. Two navigation edge-case bugs, one real-browser click-handling fix, removal of an unreachable code path, and documentation hardening around fragile patterns the review called out.

Navigation fixes

Continuous strip: external navigation interrupting an in-flight internal step. The strip tracks its pending phrase index in a ref so two rapid arrow clicks advance two groups before React re-renders. But when the parent imposed a new external focusedTokenRef while an internal step was still awaiting its echo, the in-flight marker suppressed the render-phase resync and the next step advanced from the stale index. The trigger is narrow but real: the focus-change effect early-returns when the new prop equals the currently displayed ref, so an external navigation landing on the displayed verse left the marker stuck indefinitely. The render-phase sync now detects an external override (the prop changed to something other than the in-flight internal ref), clears the marker, and resyncs the pending index. Covered by a regression test alongside the existing rapid-double-click test.

Internal-navigation markers now expire. When React batches rapid internal clicks into one update, the host echoes only the final reference, stranding the earlier verse's marker forever; a later external navigation to that verse would then be misclassified as internal and skip its recenter fade. Markers are now stamped (Map<verseKey, timestamp>) and expire after INTERNAL_NAV_TTL_MS (3 s — legitimate echoes round-trip in milliseconds, so nothing real can expire early). Both readers honor the TTL through a single shared freshness helper so they cannot drift: consumeInternalNav (which also evicts expired entries to bound the map) and the render-phase mid-reveal curtain guard (a pure read — no map mutation during render). Tests cover both the stranded-marker expiry and the mid-reveal re-engage with an expired marker naming the target verse.

View-options dropdown: gear toggle works in real browsers

The portaled click-catcher backdrop sat at z-20, while the toolbar (sticky + z-10) caps all its descendants at level 10 — so in a real browser the gear button could never receive a click while the dropdown was open, and the tested toggle-closed path only passed because jsdom ignores z-index for hit-testing. Raising the button cannot work (the toolbar's stacking context caps it), so the backdrop drops to z-5 instead: panel above toolbar above backdrop above page content. The backdrop is invisible, so this changes hit-testing only. One deliberate behavior change: while the dropdown is open, clicks on other toolbar controls now reach those controls directly instead of merely dismissing the dropdown.

Unreachable verse-0 handling removed

normalizeScrRef maps a verse-0 (chapter heading) selection to verse 1 before the reference ever reaches the display layer, so the chapter-heading active/snap branches in SegmentListView and useSegmentWindow.snapActiveToTop could never run in production — their tests only passed by injecting verseNum: 0 directly as a prop, bypassing the nav context. Those branches, the now-unconsumed data-chapter-start attribute, and their prop-injection tests are removed. Since the "scrRef is always normalized" assumption is now load-bearing, it is stated explicitly on Interlinearizer's scrRef prop.

Documentation hardening

The review flagged two effect dependency arrays as easy to break without understanding the design. Their comments now spell out the consequence: adding focusedTokenRef/tokenSegmentMap to the external-reseed effect would clobber the deliberately focused token on every focus move (they are guard-reads, not triggers), and the revert effect's correctness depends on isRevert staying derived directly from phraseMode.

Testing

Full Jest suite green (893 tests, 34 suites), ESLint/stylelint/typecheck clean.

This change is Reviewable

imnasnainaec and others added 3 commits June 12, 2026 09:16
An external focusedTokenRef change arriving while an internal nav was
still awaiting its echo left the in-flight marker set, so the
render-phase guard never resynced pendingPhraseIndexRef and the next
step() advanced from the stale index. Clear the marker when the prop
changes to something other than the in-flight ref.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
When React batches rapid internal navigations, the host echoes only the
final reference, stranding the earlier verse marker in the pending set
forever; a later external navigation to that verse would then be
misclassified as internal and skip its recenter fade. Store markers
with a timestamp and evict entries older than 3s on consume.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
normalizeScrRef maps verse 0 to verse 1 before the reference reaches
the display layer, so the chapter-heading active/snap branches in
SegmentListView and snapActiveToTop could never run in production.
Remove them and the tests that injected verse 0 directly as a prop.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@coderabbitai

coderabbitai Bot commented Jun 12, 2026

Copy link
Copy Markdown

Important

Review skipped

Auto reviews are disabled on base/target branches other than the default branch.

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 5812e340-5fef-4ae7-9cf1-ab76683e6b12

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch rsv2

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

imnasnainaec and others added 4 commits June 12, 2026 10:23
The verse-0 display handling was removed as unreachable, so the
"scrRef is always normalized" assumption is now load-bearing; state it
on the prop. Also spell out why focusedTokenRef/tokenSegmentMap and
phraseMode must stay out of their effects' dependency arrays, so the
eslint-disables are not removed without understanding the consequence.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The invisible click-catcher backdrop sat at z-20 while the toolbar
(sticky, z-10) caps all its descendants at level 10, so in a real
browser the gear button could never receive a click while the dropdown
was open -- the tested toggle-closed path only worked because jsdom
ignores z-index for hit-testing. Lower the backdrop to z-5 so the gear
toggle is the real mechanism; the panel itself stays at z-30.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The TTL added to consumeInternalNav was bypassed by the render-phase
mid-reveal guard, which still checked the marker map with a bare
has(): an expired stranded marker (batched rapid-click whose echo
never arrived) would wrongly exempt a later external navigation from
re-engaging the cross-book curtain during the fade-in. Extract the
freshness check into a shared helper used by both readers; the guard
reads purely (no eviction during render) while consumeInternalNav
keeps evicting to bound the map.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@imnasnainaec imnasnainaec changed the title Rsv2 Address review findings: navigation edge cases, dropdown stacking, verse-0 dead code Jun 12, 2026
@imnasnainaec

Copy link
Copy Markdown
Contributor Author

@alex-rawlings-yyc This pr is Claude Fable addressing Devin's remaining comments on #98 , but I haven't actually had a chance to review any of these changes myself. So as I break for lunch, you can decide whether you want to look at this yet.

@alex-rawlings-yyc alex-rawlings-yyc 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.

I think these are worthy changes to make. Continue

@alex-rawlings-yyc reviewed 10 files and all commit messages, and made 1 comment.
Reviewable status: :shipit: complete! all files reviewed, all discussions resolved (waiting on imnasnainaec).

@imnasnainaec imnasnainaec marked this pull request as ready for review June 12, 2026 17:59

@alex-rawlings-yyc alex-rawlings-yyc 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.

@alex-rawlings-yyc reviewed 2 files and all commit messages.
Reviewable status: :shipit: complete! all files reviewed, all discussions resolved (waiting on imnasnainaec).

@imnasnainaec imnasnainaec merged commit 1d0e9ea into refine-segment-view Jun 12, 2026
2 checks passed
@imnasnainaec imnasnainaec deleted the rsv2 branch June 12, 2026 18:17
alex-rawlings-yyc added a commit that referenced this pull request Jun 12, 2026
* Change segment view to allow for infinite scroll within a book

* Fix external scrRef change-related issues (UNFINISHED)

* Adjust animation/fade timing

* Refactor scrRef navigation with new hook

* Post-refactor adjustments

* Hoist SegmentListView into own component, fix lingering external nav fade/realignment timing issues, add chapter markers and associated setting

* Cleanup

* Fix snapping issues

* Extract useLatestRef/useRecenterSnap hooks, fix verse-0 echo nav

* Add shared hooks to reduce odds of drift

* Minor improvements

* Minor adjustments

* Stabilize duplicate results from PAPI scripture picker

* Update doc

* Fix alignment issues when toggling Continuous Scroll Mode

* Prevent scroll from going past final segment

* Clear timeout for stale fade-in

* Add same verse ref guard to handleSegmentSelect

* Improve test coverage

* Minor adjustments

* Refactor useSegmentWindow hook

* Fix flicker after external nav double-sends new ref

* Address review findings: navigation edge cases, dropdown stacking, verse-0 dead code (#103)

Co-authored-by: Claude Fable 5 <noreply@anthropic.com>

* Cleanup

---------

Co-authored-by: D. Ror. <imnasnainaec@gmail.com>
Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
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