fix: escape propagation from RuiMenu and first-segment focus on an empty picker - #566
Merged
Merged
Conversation
The root wrapper and the popover both bound `@keydown.esc.stop`, so every Escape that passed through a menu had its propagation stopped, whether or not the menu was open. A consumer that closes its own editor on Escape therefore never saw the key, not even after the menu had closed. `onLeave` already stops the event itself, and only when the menu is open, so passing the event to it and dropping `.stop` gives the intended behaviour: swallowed while open, forwarded while closed.
Focusing an untouched field expands the format tokens into the input's value. That write lands after `handleFocus` has selected the first segment and clears the selection with it, leaving the caret after the tokens instead of on DD. Re-select the first segment once the tokens are in the field, so focusing an empty picker starts on the first segment like a filled one does.
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## main #566 +/- ##
==========================================
+ Coverage 87.03% 87.05% +0.02%
==========================================
Files 159 159
Lines 6307 6311 +4
Branches 1939 1940 +1
==========================================
+ Hits 5489 5494 +5
+ Misses 818 817 -1 ☔ View full report in Codecov by Harness. 🚀 New features to boost your workflow:
|
Nothing in the example app opened a menu from inside another one, so the one-level-at-a-time escape behaviour had no coverage. The new section on the menus page opens an inner menu from the outer menu's content, and the e2e test walks both levels back with two Escape presses.
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.
Two fixes found while wiring
RuiDateTimePickerinto an editor in rotki/rotki.1.
RuiMenuswallowed Escape even while closedThe root wrapper and the teleported popover both bound
@keydown.esc.stop.withKeysonly runs the handler for Escape, but when it did run,.stopfired regardless of whether the menu was open, so an ancestor listener never saw the key: not on the first press, not on any later one.onLeavealready callsstopPropagationitself, and only when the menu is open, so the fix is to pass it the event and drop.stop. Escape is swallowed while the menu is open (it closes the menu) and forwarded while it is closed.Measured before the fix, with a keydown listener on an ancestor of the menu:
2. Focusing an empty picker put the caret after the format tokens
An untouched field holds no value: the tokens are shown through the placeholder, and
formattedDisplayonly expands them into the value once the field is focused. That value write lands afterhandleFocushas run itssetSelectionRange, and writing an input's value drops the selection, so the caret ended up at the end (position 16 ofDD/MM/YYYY HH:mm) instead of onDD.A filled field was never affected: it already selects the first segment (0-2). Now an empty one re-selects the first segment once the tokens are actually in the field, so both start in the same place.
Testing
RuiMenu.spec.ts: escape forwarded while closed, swallowed while open, other keys always forwarded.RuiDateTimePicker.spec.ts: first segment highlighted on autofocus, for a filled and for an empty field. The empty-field test fails onmain(expected 16 to be +0).pnpm run test:run(1351 passing),pnpm run typecheck,pnpm run lintwith no new warnings.