fix(folders): rail counts sit flush right; the ⋯ menu takes their place on hover - #18
Conversation
a04de65 to
1990d3b
Compare
fb27a54 to
6006089
Compare
…lace on hover The trailing ⋯ slot reserved a 24px column beside every count, holding the numbers ~30px off the rail's edge even with no menu showing, and a long name's ellipsis stopped at that box rather than at the digits. The slot is now exactly as wide as its count — digits sit flush at the row padding, a plain flex-gap from the name — and on hover/focus the menu takes the count's place: parked out of flow (invisible, click-through) at rest, it re-enters the flow to reveal, so the slot re-sizes to the 24px button and the name re-flows to make the room. The All Notes badge lines up as the row's last flex item, so the spacer is gone entirely. The selected row holds its ⋯ permanently, as the selected note-list item holds its actions — at the price of its count (a debatable trade, noted in a comment). Beyond that, the reveal listens to the row's own focus, this row's menu being open (a row_menu-open modifier), or keyboard focus on the ⋯ itself — Tab steps from a focused row into its menu button, as in the note list. The parked state is never display: none (a Tab target that loses its box mid-hand-over gets dropped, stranding focus on body), and the button leg uses :focus-visible, not :focus: closing the menu can strand pointer-given focus on the button (the panel divider's pointerdown preventDefault suppresses the blurring focus move), which must not pin the reveal. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
6006089 to
39bab0b
Compare
There was a problem hiding this comment.
*ai generated
LGTM. It took me a while to convince myself the position static/absolute dance is safe, notes below.
The one thing I'd actually change: use position: relative instead of static in the two reveal rules. .g-button draws its hover wash, press effect and focus ring on abspos ::before/::after with inset: 0, so with the button un-positioned those anchor to .folder-rail__trailing instead — 19px wide and shifted by the -5px margin, i.e. a clipped wash and a misplaced Tab ring. The only reason it renders correctly today is that .g-button happens to carry transform: scale(1), which makes it a containing block anyway. I'd rather not depend on uikit keeping that transform around. relative with no offsets behaves exactly like static in flex layout (still in flow, the slot still resizes), and it's what .g-button sets for itself anyway.
On the selected-row-loses-its-count question — fine by me, keep it. The selected folder is the one whose contents are already listed in the middle pane, so its count is the least useful of the bunch, and consistency with the note list's held actions is worth more. Worth noting the row:focus leg means j/k browsing hides the count under the cursor too. Same trade, symmetric with hover, I just want to make sure that part is deliberate.
Things I checked and am fine with:
- tab parity with the note list is real (its ⋯ has no tabIndex either), and this actually closes a hole: the rail menu was completely unreachable by keyboard before, Pin had no keyboard path at all. Extra tab stops per row, but that ship sailed with the note list.
- the focus-visible-not-focus choice on the button: the stranded-pointer-focus reasoning holds, and the worst case (Enter on an invisibly focused button) just opens the menu, which reveals it via
_menu-open. Self-correcting. :has()— this file already uses it for the rename row, so no new browser baseline.- touch: the hover guard is intact, and the parked button is pointer-events: none, so first taps still hit the row.
- menu anchoring unchanged (the anchor was already
e.currentTarget), and_menu-opencovers the pointer-wanders-off case the old:focus-withinnever did.
Nit, not blocking: an empty folder's zero-width trailing slot still costs one 6px flex gap, so its name ellipsizes 6px earlier than All Notes' does when that one has no count (it renders no trailing element at all). Invisible in practice, and still better than the 24px gutter.
Ran the suite (972 green) and typecheck on the branch myself. The two new tests are the right ones — the tab hand-over and the _menu-open lifecycle are exactly the bits that would regress.
.g-button paints its hover wash, press effect and focus ring on abspos ::before/::after with inset: 0, so an un-positioned button anchors those to .folder-rail__trailing — 19px wide and shifted by the -5px pull-in — i.e. a clipped wash and a misplaced Tab ring. It renders correctly today only because uikit's own transform: scale(1) on .g-button makes it a containing block anyway; not worth depending on. Offset-less relative is identical to static in flex flow (the slot still re-sizes), and it's what .g-button sets for itself. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
|
Done in 1155575 — I reproduced your concern on the stand before changing anything: force The Thanks for the careful read. |
The folder rail reserves a fixed 24px trailing slot for the ⋯ menu on every row, so the note counts sit ~30px in from the rail's edge even when no menu is showing, and a long name's ellipsis stops at that empty box rather than at the digits. The rail reads airier than it needs to be, and the count column floats away from the edge it's visually anchored to.
This PR removes the reserved gutter:
(hover: hover)-guarded, as before), on the selected row (held permanently, as the selected note-list item holds its actions), on the row's own focus (keyboard nav), while the row's menu is open, and while the ⋯ itself holds keyboard focus — Tab steps from a focused row into it, matching the note list's ⋯.On revisiting 48dae41
I'm aware the fixed slot came in deliberately with 48dae41 ("Counts: stay visible on hover … no longer replaced by the ⋯ menu"), and this brings the take-the-count's-place reveal back, so let me argue the trade honestly. What 48dae41 fixed stays fixed: counts align across all rows, including All Notes — better than the pre-48dae41 layout, which reserved no slot there at all. What returns: the hovered row swaps its count for the menu, one row at a time, under the pointer that's about to use it — and the selected row holds its ⋯ permanently for cross-pane consistency, so its count yields for good. That last bit is the most debatable part (the one count you never see is the folder you're in — flagged in a code comment, challenge welcome); every unselected, unhovered row keeps its count visible. In exchange the numbers stop floating ~30px off the edge and long names keep their ellipsis next to the digits. Happy to adjust or close if you'd rather keep the reserved column.
Details
position: absolute; opacity: 0; pointer-events: none— neverdisplay: none: the ⋯ is Tab-reachable now (itstabIndex={-1}is gone, matching the note list), and a Tab target that loses its box mid-hand-over gets dropped by the browser, stranding focus on body. Parked, it stays focusable and reveals the moment it holds keyboard focus.:focus-visible, not:focus: closing the menu can strand pointer-given focus on the ⋯ — e.g. the panel divider'spointerdowncallspreventDefault(), suppressing the focus move that would blur it — and a plain-focus reveal would then pin the swap after the pointer leaves (found while dragging the divider with a menu open). A stranded button just stays parked: invisible, inert, yielding on the next focus move.npm run lint/format:check/typecheck/testall green (972/972; tests added for the menu-open mark and the tab order).🤖 Generated with Claude Code