Skip to content

Fix edit chrome cropped at top of viewport for first/top block (bd-pvcnea83)#346

Merged
cscheid merged 4 commits into
mainfrom
bugfix/bd-pvcnea83-edit-chrome-top-crop
Jun 26, 2026
Merged

Fix edit chrome cropped at top of viewport for first/top block (bd-pvcnea83)#346
cscheid merged 4 commits into
mainfrom
bugfix/bd-pvcnea83-edit-chrome-top-crop

Conversation

@cscheid

@cscheid cscheid commented Jun 26, 2026

Copy link
Copy Markdown
Member

Summary

Editing the first block of a title-less document (or any block scrolled near the viewport top) cropped the floating edit chrome. The rich-text toolbar and the standalone breadcrumb chip float above the edit box (bottom:100%), so for a block flush against the top of the scroll area they landed above the viewport top (with scrollTop already 0, unreachable) and were clipped — only a sliver showed. The inline nesting breadcrumb lives in the toolbar, so it cropped too.

Measured before: editor top:15, toolbar top:-15.4 → bottom:11 (height 26.4).

Fix — collision-aware flip (above → below)

Standard floating-toolbar behavior: when there isn't room above (surfaceTop − chromeHeight − gap < 0, viewport-relative), render the chrome below the block instead. While editing a top block the chrome then sits just under it, fully visible; the edited text is never covered. Parity-neutral (no change to document spacing) and generalizes to any near-top block, not just the literal first one.

  • New pure helper editChromeGeometry.shouldPlaceChromeBelow (unit-tested, 5 cases).
  • RichTextToolbar: useLayoutEffect measures the edit box top + toolbar height and adds q2-rt-toolbar-below (top:100%) when it would clip; guarded on a non-zero measured height so degenerate (jsdom) layouts keep the default above.
  • BreadcrumbChip: the geometry effect flips top below the surface under the same condition (guarded on sRect.height > 0); horizontal left-spill geometry unchanged.

Both decide from the surface's stable top (not the chrome's flipped position), so there's no flip/re-measure loop.

Verification

  • End-to-end in the real q2 binary + Chrome: editing the first paragraph flips the toolbar below (q2-rt-toolbar-below, top 48.5, uncropped); editing a first code block flips the standalone chip below (top 83.8, uncropped). Screenshots inspected.
  • New e2e q2-preview-spa/e2e/edit-chrome-placement.spec.ts (2 tests, real binary); full q2-preview-spa e2e suite green (39).
  • preview-renderer 505 unit + 515 integration; hub-client 662 unit + 76 integration; hub-client + SPA production builds; cargo xtask verify --skip-hub-build green (one flaky pampa-oracle roundtrip-spike failure on the first run — passed on re-run, unrelated to this change).

Plan: claude-notes/plans/2026-06-25-edit-chrome-top-crop.md

🤖 Generated with Claude Code

cscheid and others added 3 commits June 25, 2026 19:12
…ewport top (bd-pvcnea83)

Editing the first block of a title-less document (or any block scrolled near the
viewport top) cropped the floating edit chrome: the rich-text toolbar and the
standalone breadcrumb chip float ABOVE the edit box (`bottom:100%`), so for a
block flush against the top of the scroll area they landed above the viewport
(scrollTop already 0) and were clipped — only a sliver showed. The inline nesting
breadcrumb lives in the toolbar, so it cropped too.

Collision-aware flip: when there isn't room above
(`surfaceTop - chromeHeight - gap < 0`, viewport-relative), render the chrome
BELOW the block instead. Parity-neutral (no change to document spacing) and
generalizes to any near-top block, not just the literal first one.

- New pure helper `editChromeGeometry.shouldPlaceChromeBelow` (unit-tested).
- `RichTextToolbar`: useLayoutEffect measures the edit box top + toolbar height
  and adds `q2-rt-toolbar-below` (`top:100%`) when it would clip; guarded on a
  non-zero measured height so degenerate (jsdom) layouts keep the default above.
- `BreadcrumbChip`: the geometry effect flips `top` below the surface under the
  same condition (guarded on `sRect.height > 0`); horizontal left-spill geometry
  unchanged.

Both decide from the surface's stable top (not the chrome's flipped position), so
there is no flip/re-measure loop.

Verified end-to-end in the q2 binary: editing the first paragraph flips the
toolbar below (top 48.5, uncropped); editing a first code block flips the
standalone chip below (top 83.8, uncropped). e2e:
q2-preview-spa/e2e/edit-chrome-placement.spec.ts.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…ument top (bd-pvcnea83)

The edit-chrome flip (this branch) intentionally moves the breadcrumb chip BELOW
the edit surface when a block is flush against the viewport top — there is no room
above. The existing breadcrumb-geometry test asserted the chip is always ABOVE the
surface using a top-of-document paragraph fixture, so it became a hard CI failure
(chip bottom 116.30 > textarea top 66.00) once the flip landed.

- Rewrite that test to assert the flipped-below placement at the top: chip top ≥
  surface bottom (not overlapping the edited text), anchored near the surface
  bottom, and chip top ≥ 0 (uncropped — the whole point of the flip).
- Add a companion test proving the flip is CONDITIONAL: editing a later paragraph
  (ample headroom above) keeps the chip in its default ABOVE placement.

Both verified locally against the real hub e2e (chromium): top block → chip below
(textarea bottom 91.5, chip top 95.5); non-top block → chip above. Full
breadcrumb-geometry spec: 8 passed, 1 skipped, 1 pre-existing-flaky (4b
scroll-tracking, passed on retry — edits a mid-document block, unaffected).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@cscheid cscheid merged commit 76e6992 into main Jun 26, 2026
5 checks passed
@cscheid cscheid deleted the bugfix/bd-pvcnea83-edit-chrome-top-crop branch June 26, 2026 16:11
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.

1 participant