fix(projects): one element per anchor — tab panels own the hash - #471
Merged
Conversation
Left over from the tab conversion. The sections had ids from when they were
scroll anchors (`id="feedback"`, `id="settings"`, ...), and the new panels
took ids of their own — so both existed for the same concept: a panel
`panel-feedback` wrapping a section still called `feedback`.
That is not cosmetic. Every panel stays mounted, because they hold unsaved
drafts and poll while work is in flight. So loading /projects/<id>#feedback
handed the browser a real element to scroll to that was inside a HIDDEN
panel — native anchor behaviour racing the tab logic over the same name.
ControlInbox and FeedbackItemRow both link exactly that way, so it is the
common path, not an edge case.
The panel is the anchor now: `id={tab.id}`, `aria-controls={tab.id}`,
`scroll-mt-28` to clear the sticky tab bar. The six nested ids are gone.
What the browser scrolls to is what becomes visible.
Pinned by scripts/test/project-tab-anchors.ts rather than left to review:
it reads the tab ids out of ProjectWorkspaceView, asserts the panel uses
them, asserts no component under components/projects re-declares one as an
element id, and asserts ControlInbox still deep-links to #feedback — the
link that makes the invariant matter in the first place.
Proven by mutation: reintroducing id="feedback" on the section turns
exactly that one assertion red.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Leftover from the tab conversion in #468, and the kind of thing a diff review does not catch.
The conflict
The sections carried ids from when they were scroll anchors (
id="feedback",id="settings", …), and the new panels took ids of their own. So both existed for the same concept: a panelpanel-feedbackwrapping a section still calledfeedback.That is not cosmetic. Every panel stays mounted — deliberately, because they hold unsaved drafts and poll while work is in flight. So loading
/projects/<id>#feedbackhanded the browser a real element to scroll to that lived inside a hidden panel: native anchor behaviour racing the tab logic over the same name.Not an edge case either —
ControlInboxandFeedbackItemRowboth deep-link exactly that way.The fix
The panel is the anchor:
id={tab.id},aria-controls={tab.id},scroll-mt-28to clear the sticky tab bar. The six nested ids are gone. What the browser scrolls to is now what becomes visible.Closing the class, not the instance
scripts/test/project-tab-anchors.ts(12 assertions):ProjectWorkspaceViewrather than hardcoding themid={tab.id}and not apanel-prefixcomponents/projectsre-declares a tab id as an element idControlInboxstill deep-links to#feedback— the link that makes the invariant matterProven by mutation: reintroducing
id="feedback"on the section turns exactly that one assertion red, and restoring it turns it green.This bug was created by a refactor that looked complete. The test is the part that stops it recurring.
npm run verifyexits 0.