Skip to content

A dropdown can match its field's width and close on an outside click (RFC-0036) - #242

Open
Briany4717 wants to merge 1 commit into
feat/canvas-gradient-strokesfrom
feat/overlay-match-width
Open

A dropdown can match its field's width and close on an outside click (RFC-0036)#242
Briany4717 wants to merge 1 commit into
feat/canvas-gradient-strokesfrom
feat/overlay-match-width

Conversation

@Briany4717

Copy link
Copy Markdown
Owner

Stacked on #241. This diff is the top commit only.

The two tails RFC-0036 left off. Both read the anchor's resolved rect, which is why they arrive together and why they share a diagnostic.

width: match(ref)

Sizes a panel to its anchor. Not by widening the finished rect, which is the obvious extension of how placement already works and is wrong: the panel's own children were laid out against the width it had, so its rows would sit in a box they no longer fill. There is a test for exactly that, and it is the one that fails against the cheap version.

Instead the anchor's width is written onto the panel's node once the main tree has painted, and layout runs again. That is not the layout cycle the RFC worried about: the dependency runs one way and the overlay cannot influence its anchor, so no amount of iterating would change either answer.

What it is is a cost. The second pass is skipped whenever the width has not moved, which is every steady frame — set_style marks a node dirty in Taffy whether or not the value changed, so re-applying it unconditionally would turn the retained path back into a full one for any screen with a dropdown open. The test states this as a difference against the same screen with a fixed width rather than as an absolute count, because a frame already runs one retained pass of its own and that number is nobody's invariant.

on dismiss

An observer, not a scrim. The modal dismissal that already exists is the wrong mechanism here: its scrim covers the viewport, raises the router's modal floor, and swallows every event beneath it. An autocomplete that froze the page under it would be a worse bug than the one it solves. So this blocks nothing, fires on a press outside both the panel and its anchor, and answers to Escape.

Keeping the anchor's rect is the half that is easy to leave out, and its absence looks like a rendering glitch rather than a logic error: the press that opens a dropdown would also be the press that closes it. There is a test for it, and one asserting the page underneath still receives its events, which is what fails if somebody reaches for the scrim after all.

Watched failing

The width tests with each half of the mechanism removed in turn; the dismiss tests with the anchor rect dropped, and then with a scrim substituted (three of the six go red).

Diagnostics

Either tail on an element that anchors to nothing is a compile error, and a match naming an untagged element gets the same nearest-name hint anchor_to gets. There is no rect to read, so the property would quietly do nothing.

Example

crates/byard-cli/examples/anchored_overlay — two fields of different widths, one Panel view, two panels that come out different widths, with a full-width row inside each so "the panel is the right size" and "its contents are" are visibly separate claims. Rendered and eyeballed.

Gates

cargo fmt --all --check, cargo clippy --locked --workspace --all-targets -- -D warnings, cargo test --locked --workspace (97 suites, 0 failures), cargo run -p byard-cli -- check crates/byard-cli/examples/anchored_overlay.

…k away (RFC-0036)

The two tails RFC-0036 left off. Both read the anchor's resolved rect, which
is why they arrive together and why they share a diagnostic.

`width: match(searchField)` sizes a panel to its anchor. Not by widening the
finished rect, which is the obvious extension of how placement works and is
wrong: the panel's own children were laid out against the width it had, so its
rows would sit in a box they no longer fill. The anchor's width is written
onto the panel's node once the main tree has painted, and layout runs again.

That is not the layout cycle the RFC worried about. The dependency runs one
way, the overlay cannot influence its anchor, and no amount of iterating would
change either answer. What it *is* is a cost, so the second pass is skipped
whenever the width has not moved, which is every steady frame; `set_style`
marks a node dirty in Taffy whether or not the value changed, so re-applying
it unconditionally would have turned the retained path back into a full one
for any screen with a dropdown open. The test states that as a difference
against the same screen with a fixed width rather than as an absolute count,
because a frame already runs one retained pass of its own and that number is
nobody's invariant.

`dismiss =>` on an anchored child is an observer, not a scrim. The modal
dismissal that already exists is the wrong mechanism here: its scrim covers
the viewport, raises the router's modal floor and swallows every event beneath
it. An autocomplete that froze the page under it would be a worse bug than the
one it solves. So this blocks nothing, fires on a press outside both the panel
and its anchor, and answers to Escape.

Keeping the anchor's rect is the half that is easy to leave out, and its
absence looks like a rendering glitch rather than a logic error: the press
that opens a dropdown would also be the press that closes it. There is a test
for it, and one for the page underneath still receiving its events, which is
what fails if somebody reaches for the scrim after all.

Both were watched failing: the width tests with each half of the mechanism
removed in turn, the dismiss tests with the anchor rect dropped and then with
a scrim substituted.

Either tail on an element that anchors to nothing is a diagnostic. There is no
rect to read, so the property would quietly do nothing, and a `width:` that
quietly does nothing reads as a bug in the panel.
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