Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix FirstOptionSelectionMode:selected clearing on typing #82

Merged
merged 5 commits into from
Feb 26, 2024

Conversation

anleac
Copy link

@anleac anleac commented Feb 23, 2024

When the FirstOptionSelectionMode prop is set to selected, this would correctly set the first element to selected on open, but on typing, remove this state.

This was easily reproducible with a test-case that I should have had in my prior PR here: #81

To encourage a simple code path that's shared with the active state for FirstOptionSelectionMode, I refactored the code a bit and also cleaned up some call paths that were not necessary on closing flows.

This PR adds:

  • Many tests
  • A new method, resetSelection to be distinct from clearSelection. Why?
    • Previously, clearSelection also handled the "state reset" for active/selected state, but this broken in the case for "active" as it would try to navigate when the list was not visible, as clearSelection was called on .stop, .destroy etc. This flow didn't make sense, but didn't throw errors for the active state as there was no navigations on option lists but rather attribute settings.
    • This new flow now explicitly calls resetSelection when appropriate, which is, on non-special character typing, and when we navigate through the last element (this should cycle back). (First open is applicable, but we call indicateDefaultOption directly.

@anleac anleac requested a review from a team as a code owner February 23, 2024 18:26
Copy link
Member

@iansan5653 iansan5653 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks great - just two suggestions to cover potential edge cases

@@ -141,10 +141,11 @@ export default class Combobox {
for (const el of this.list.querySelectorAll('[aria-selected="true"]')) {
el.removeAttribute('aria-selected')
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we should probably also remove data- attribute that indicates the 'active' default option here:

Suggested change
el.removeAttribute('aria-selected')
el.removeAttribute('aria-selected')
el.removeAttribute('data-combobox-option-default')

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Totally, that's a good catch, will add!

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Addressed in 7182ef5 🙇

src/index.ts Show resolved Hide resolved
Copy link
Member

@iansan5653 iansan5653 Feb 23, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can't comment on unchanged lines (maybe one day 🙏) but I think maybe we should replace the indicateDefaultOption call on line 82 with resetSelection, just to make sure the state is cleared when the menu opens. It's shouldn't be necessary since selection is cleared on close, but it feels safer.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Addressed in 7182ef5

src/index.ts Outdated
@@ -108,7 +108,7 @@ export default class Combobox {
const focusIndex = els.indexOf(focusEl)

if ((focusIndex === els.length - 1 && indexDiff === 1) || (focusIndex === 0 && indexDiff === -1)) {
this.clearSelection()
this.resetSelection()
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks like this is the case where the user reaches the end of the options in either direction. Based on current behavior I think we do want to clear the selection in this case, not just reset it:

Screen.Recording.2024-02-26.at.9.35.13.AM.mov

Might be good to add a test for this, but it's not a blocker IMO.

Suggested change
this.resetSelection()
this.clearSelection()

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If we clear the selection here instead; this will also be a regression in behaviour for the active option which previously set the default attribute, in this case, we wouldn't reset that attribute and that may break the option being selected on enter press? 🤔

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think that's an acceptable change - if the first option is active by default but then the user uses the arrow keys to navigate through all the options, it's fine to deselect the first option at that point. That's actually probably preferrable to the current behavior

Copy link
Author

@anleac anleac Feb 26, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Makes sense! Updated in dbf90b5

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.

2 participants