fix(webview): key the concealed fence gap offset on the gap border, not the language tag - #396
Merged
Merged
Conversation
…ot the language tag A concealed fenced block with no language tag drew its copy button 4px ABOVE the panel's painted top edge, hanging over the rounded corner. Its tagged twin sat 4px inside. The panel fill is `background-clip: padding-box`, so a visible open edge that carries blockEdgeGapCorner's transparent --quoll-block-gap-y top border paints its surface that far below its border box. In the revealed state the copy button's anchor IS that bordered line, so `top: 0.3em` resolves against the paint. In the concealed state the anchor is the zero-height `.quoll-fenced-code-fence-hidden` row, which sits at the border box's top and has no border of its own — the same `top` resolves against a datum 8px too high. The rule that adds the gap back existed, but it was gated on the NEXT line being a `-has-language` header, and its comment declared bare blocks deliberately untouched. The language tag was never what asked for the offset — the gap border is, and a bare block's panel carries exactly the same one. The gate had simply frozen an attribute that happened to correlate while the header bar (a tagged-only feature) was being built. Widening it also fixes a second miss on the same axis: block-style suppresses the fenced `-outer-open` inside a blockquote and lets `quoll-blockquote-outer-open` supply the identical border instead, so blockquote-nested blocks were uncorrected too — tagged ones included. `concealedGapAnchor` now spells both sources as a selector LIST, which cannot double-count: the two classes are mutually exclusive on a fenced open edge, and two matching branches still apply one declaration. Measured in the real-browser harness across bare/tagged x concealed/revealed x top-level/blockquote/list/bodyless, plus a directly-adjacent pair (whose second block correctly needs no offset because it yields its `-outer-open`). Every state now lands 4px inside the paint; the already-correct ones did not move.
The intro comment above fencedHeaderBarThemeSpec's "Conceal/reveal geometry" paragraph said "two :has(+ …) / descendant rules" re-add the alignment offsets, but the spec actually has three: two independent `:has(+ …)` selector lists from concealedGapAnchor (one per control — copy button, label) for the vertical gap-y offset, plus one descendant rule for the label's horizontal column inset. The undercount predates this PR; this PR only touched the paragraph while generalizing concealedGapAnchor to take a control argument, so resolve the pre-existing ambiguity while the comment is already being edited. Comment-only change, no selectors or behaviour touched.
…r pins paintedPanelTop's `lines[i] as HTMLElement` restated a type the array already has, and the cases array declared an `expected?: number` field no case ever set and no assertion ever read — the band comes from the module-level EXPECTED_INSET / TOLERANCE. Both are cosmetic; no assertion, statement, or selector changed.
insets[0] is already typed number (copyInsets returns number[], and noUncheckedIndexedAccess is not enabled in any tsconfig), so the 'as number' cast at line 208 was a no-op. Cycle 1 refactor commit b46e98e removed the same-shape cast at line 146 but missed this one. Consistency cleanup, not a correctness fix.
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
A concealed fenced code block with no language tag drew its copy button 4px above the panel's painted top edge, hanging over the rounded corner; its language-tagged twin sat 4px inside. The correction that fixes this already existed — it was just gated on the wrong thing.
Why it happened
The panel fill is
background-clip: padding-box, so a visible open edge carryingblockEdgeGapCorner's transparent--quoll-block-gap-ytop border paints its surface that far below its border box.top: 0.3emresolves against the paint..quoll-fenced-code-fence-hiddenrow, which sits at the border box's top and has no border of its own — the sametopresolves against a datum 8px too high, netting −4px.The rule adding that 8px back was scoped to
:has(+ .cm-line.quoll-fenced-code-has-language.quoll-fenced-code-outer-open), and its comment declared bare blocks deliberately untouched. But the language tag never asked for the offset — the gap border does, and a bare block's panel carries the identical one. The gate had frozen an attribute that merely correlated while the header bar (a tagged-only feature) was being built.Changes
concealedGapAnchorkeys the offset on the gap border, not the language tag. This also fixes a second miss on the same axis:block-style.tssuppresses the fenced-outer-openinside a blockquote and letsquoll-blockquote-outer-opensupply the same border, so blockquote-nested blocks were uncorrected too — tagged ones included.:not(.quoll-blockquote)guards a genuine two-path double-count.)fencedHeaderBarThemeSpecgains an explicitRecord<string, Record<string, string>>annotation — the two computed template-literal keys otherwise make TS infer a union that no longer satisfiesStyleSpec's index signature.Related
Test Plan
Real-pixel regression pins in
test/webview-browser/fenced-header-bar.browser.test.tsmeasure the copy button's top against the panel's painted top edge (the open-edge line's rect top plus itsborderTopWidth), pairing each button with its own panel. happy-dom cannot see any of this — no layout, and it dropscalc()/var().-outer-open, so it needs no offset and gets nonetheme.tsturns 5 of these red (and 2 spec-contract pins incm-fenced-code-language-picker.test.ts), while the already-correct states stay greenpnpm compile,pnpm lint,pnpm test:unit(5212),pnpm test:browser(74),pnpm build,pnpm package(audit clean), force-install + reload