fix(react): resize handles in an overlay layer — grab the divider from either side under sticky headers#86
Merged
Merged
Conversation
…from either side Under sticky headers (the stickyHeader prop and the row-virtualization surface) every header th forms an equal-z stacking context, so a neighbouring cell paints over the previous cell's overhanging resize handle. The hit zone — and the col-resize cursor — only worked when grabbing from the inner side of the divider; the outer half was covered. No z-index on an in-th handle can escape its own cell's stacking context. Lift the handles into one overlay layer (ResizeHandleOverlay), a child of .yable-main outside every th, so they paint above all header cells with a single z-index and each hit zone straddles its divider symmetrically. Handle positions are MEASURED from the real header rects (relative to the layer) and refreshed on scroll, container resize, and column size/order changes — so alignment holds across sticky/non-sticky headers, pinned columns, row/column virtualization, horizontal scroll, and RTL. The visible bar stays exactly on the divider; the outer (grid-edge) handle stays flush inside to avoid phantom horizontal scroll. The React table no longer renders the in-cell .yable-resize-handle; handles are .yable-resize-overlay-handle in .yable-resize-overlay. The vanilla package still renders the in-cell handle (its themes CSS is retained). e2e: new both-sides drag test under a sticky virtualized header (grabbing the OUTER side of the divider now resizes — the regression Kirby kept hitting); all handle-alignment and live-resize tests migrated to the overlay handle. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
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.
The bug (Kirby: "fix once and for all")
Under sticky headers — the
stickyHeaderprop and the row-virtualization surface (which pinsthunconditionally) — every header cell getsposition: sticky; z-index: var(--yable-z-header). Equal-zsiblingths each form their own stacking context, so a later cell paints over the previous cell's overhanging resize handle. The pointer hit zone and thecol-resizecursor only worked when grabbing from the inner (left) side of the divider; the outer half was covered. All Bevrly tables run sticky + virtualization, so this is exactly the drift Kirby kept feeling. Noz-indexon an in-thhandle can escape its own cell's stacking context — hence the overlay.The fix
ResizeHandleOverlayrenders all handles in one layer (.yable-resize-overlay), a child of.yable-mainoutside everyth, painting above all header cells with a single z-index (--yable-z-resize-overlay: 35, above sticky+pinned header = 30, below content overlays = 40). Each hit zone straddles its divider symmetrically — the grab works identically from either side of the line, cursor shown across the full zone, visible bar exactly on the divider.Handle positions are measured from the real header rects (relative to the layer) and refreshed on scroll (rAF-throttled, capture-phase for nested scrollers), container resize (ResizeObserver), and column size/order changes (a signature that also tracks a live
onChangedrag). Because it mirrors what the browser actually painted, one code path is correct across: sticky/non-sticky headers, pinned columns, row + column virtualization, horizontal scroll, and RTL. The grid-edge handle stays flush inside to avoid phantom horizontal scrollWidth.Compatibility
The React table no longer renders the in-cell
.yable-resize-handle; handles are.yable-resize-overlay-handleinside.yable-resize-overlay. Consumers styling the old class for the React grid should move to the overlay classes.@zvndev/yable-vanillastill renders the in-cell handle — its themes CSS is retained unchanged.Tests
grid-virtual). The OUTER-side grab now resizes — previously it hit the neighbouringthand did nothing.Verification
core 583 passed · react 328 passed · e2e 55 passed · typecheck clean · lint 0 errors.
Bumps:
@zvndev/yable-reactminor (0.19.0),@zvndev/yable-themespatch (0.6.3). No majors; core/vanilla untouched.🤖 Generated with Claude Code
Need help on this PR? Tag
/codesmithwith what you need. Autofix is disabled.