Repository navigation
fix(panel): every gap in Files changed opens alike: its words show all of it, its arrows twenty lines - #4111
Merged
Merged
Conversation
…l of it, its arrows twenty lines
A gap's words now open the whole gap on every gap, short or long, at a
file's top, between two hunks, or at its foot, as Pierre opens a gap from
its own hidden Expand all; the trailing "More unchanged context" reads the
file first and opens it to its end. The arrows keep opening twenty lines
their way, or all of a short gap. The words and the arrows hover alike on
every gap (the words lift their ink, no underline; an arrow fills its own
cell), and the band itself no longer passes the pointer through to an
arrow. Each control is a named button in the tab order, pressed by Enter or
Space, its hint its name ("Show all N lines", "Show 20 more lines").
Co-authored-by: luke-agent[bot] <339870089+luke-agent[bot]@users.noreply.github.com>
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
…its arrows and the focus Co-authored-by: luke-agent[bot] <339870089+luke-agent[bot]@users.noreply.github.com>
…xpand # Conflicts: # packages/panel/src/diff-view/index.ts # packages/panel/src/tasks/diff-list.tsx
This branch was successfully deployed
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.
Summary
The developer said:
Every gap between hunks in Files changed now opens and hovers the same way:
data-expand-all-buttonmark, so Pierre's own click handler opens them withexpandHunk(i, "both", ∞). The trailing "More unchanged context may be available" words read the file first, then open it to its end. Files that can't expand keep feat(desktop): expand context lines in Files changed #3762's behaviour: no arrows, and the words are unmarked and can't be clicked.--diffs-fg, the same ink the arrow lifts to). There is no underline; Pierre's underline on the content area is overridden.pointer-events: noneon the words, and the arrow's full-width::after). The band itself reacts to nothing.role="button"withtabindex="0"and anaria-label. Enter or Space presses them the way a click does, ⇧ included.:host-context(:root:not([data-keyboard="true"]))).How
diff-view/gap-controls.ts(new): Pierre rewrites a file's rows throughinnerHTMLon every draw, so a MutationObserver on each file's shadow root puts the marks back before paint. It is scoped to stay cheap while scrolling:[data-content](the code rows, which are the bulk of every write) and records with no added nodes.[data-gutter] [data-separator][data-expand-index]). The hidden copies among the code rows are left alone.onPostRender"unmount" phase and starts again when the element draws a file. Every watch stops when the list unmounts.contract.ts: gainsGAP_CONTROL_ATTRIBUTEandGAP_CONTROL, which the LOOK_CSS styles and the view's tooltip key on.diff-list.tsx: the hint reads the control'saria-labelinstead of guessing from Pierre's DOM. It also shows onfocusin, and goes away onfocusoutor a key press. Those are native listeners, so Biome's static-element rule holds.Screenshots
Taken from the real built
diff-view.js(apps/desktop && node scripts/build.mjs), mounted withmountListin a harness in headless Chromium. One file has a top gap, a two-arrow middle gap, and the trailing gap. The window's tooltip is React's own and isn't in this harness; the tests cover it.In the same harness I checked by hand, counting rows in the real bundle:
Scroll cost
I built
diff-view.jsfrommainand from this branch and mounted each withmountListon PR #2908's 122 real patches. This was headless Chromium at 1280×800, scrolling 60 px per frame for 4 s after a 4 s settle, median of 3 runs. Every MutationObserver callback on the page was timed, Pierre's own included.mainThe marking costs about 2.6 ms per 4 s scroll, roughly 0.65 ms per scroll second. This is Linux headless Chromium, not Electron on a Mac, so compare the columns rather than the absolute values.
Evidence
pnpm check:affectedran out of memory in the sandbox, as expected, so I ran the steps one by one:tsc --noEmitfor panel: clean.vitest run packages/panel/src/diff-view packages/panel/src/tasks: 127 files, 1303 tests passed. The full panel project also passed before the final, CSS-only edits../scripts/oxlint.sh: 0 warnings, 0 errors.pnpm knip: clean../scripts/repository-checks.sh: passed. It caught avar(--diffs-fg)with no fallback, nowvar(--diffs-fg, var(--luke-color-text)).biome checkon the changed files: clean.cd apps/desktop && node scripts/build.mjspasses.diff-view/gap-controls.test.tsrun on real PierreFileDiffin jsdom, withline-info-basicand 20 lines per press:main, where the words open 20 lines each way.data-gap-control,role, andtabindex, and they are named for what they open.drawnAmong, the reading feat(panel): review threads move onto lines a gap opens in Files changed #4008 uses to move review threads onto the lines a gap opens. So the threads-move path is checked for every label click.agent-changes-tab.test.ts: the old "⇧-click for all" hint test is replaced by "a gap's control under the pointer or the keyboard's focus hangs its hint, what it opens, and a press lets it go".Invariants
./scripts/check.shgreen: its pieces were run one by one, as listed above, and CI runs the whole of it.astype assertion.Effect.run*.setTimeoutis in a test's settle only.gap-controls.test.ts(the eighth is the keyboard case from Devin's review: a long gap pressed from both ends keeps its two arrows and the focus); one hint test rewritten.CLAUDE.md/AGENTS.mdchange needed.PRIVACY.mdunchanged. The newaria-labels are masked by session replay's attribute list.Notes
Made with Luke