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

[useCombobox] InputKeyDownEnter action not triggering when focus is on the input field #1114

Closed
JReinhold opened this issue Jul 8, 2020 · 6 comments · Fixed by #1150
Closed

Comments

@JReinhold
Copy link

  • downshift version: 5.4.5
  • node version: `12.16.3
  • npm (or yarn) version: npm v6.14.4

Relevant code or config

stateReducer: (state, actionAndChanges) => {
  const {type, changes} = actionAndChanges
  switch (type) {
    case useCombobox.stateChangeTypes.InputKeyDownEnter: {
      // doesn't log when user has focus on the input, only when focus is on menu
      console.log(type)
      return changes
    }
    default: {
      return changes
    }
  }
},

What you did:

Had a basic combobox. Typed in the input field, and pressed the Enter key.

What happened:

Nothing happened. I expected the action InputKeyDownEnter to be fired in the stateReducer, but it didn't.

Reproduction repository:

https://codesandbox.io/s/usecombobox-usage-nrqhf

  1. focus input with click
  2. press enter
  3. observe that the action is not logged
  4. type a few characters
  5. highlight an item in the menu
  6. observe now, that the action is correctly logged
  7. type again (effectively moving focus to the input field)
  8. press enter
  9. observe that the action is not logged

Problem description:

The action InputKeyDownEnter only seems to get fired when user is pressing Enter with the dropdown in focus, ie. when the user is highlighting an item in the menu with arrow keys or with the mouse. If the user presses enter just after focusing the input, or just after typing a character in the input, the action isn't dispatched.

This is NOT an issue with the other built in "KeyDown" actions. The following types DOES trigger correctly:

  • InputKeyDownEscape
  • InputKeyDownEnd
  • InputKeyDownHome
  • InputKeyDownArrowDown
  • InputKeyDownArrowUp

Suggested solution:

Without knowing if this would be a "breaking change" or have other repercussions, I'd suggest making the InputKeyDownEnter action also trigger when input is in focus.

Current workaround:

adding a keydown event listener directly on the input element is possible, but not ideal:

<input
  {...getInputProps({
    onKeyDown: (event) => {
      switch (event.key) {
        case 'Enter': {
          event.preventDefault();
          // do stuff here
        }
      }
    },
  })}
/>
@silviuaavram
Copy link
Collaborator

Hi @JReinhold ! Thank you for using our library!

To answer your question, I need to know what you exactly want to do when the Enter key is pressed. Because depending on that there is a correct way for each scenario.

  1. If you want to do some action on the keyDown Enter every time, then your workaround is actually the way to go.
  2. If you want to tweak the state that is about to change, based on the Enter key down event, then use the stateReducer.
  3. If you want to trigger an action based on a state change, as a consequence of the Enter key down event, then use the onStateChange.

To clarify, stateReducer is trigger only when the state is about to be changed, so this explains why you are not getting the Enter type every time you press it, because only when an item is highlighted then the state changes.
Also, the stateReducer is a pure function meaning that it should only return the next state, nothing else, no any other side effects.

Hope this helps you with developing your combobox. Let me know how it goes, good luck!

@JReinhold
Copy link
Author

JReinhold commented Jul 8, 2020

@silviuaavram

  1. If you want to tweak the state that is about to change, based on the Enter key down event, then use the stateReducer.

This is what I want. basically, whenever the users presses Enter, and there is only one item shown in the menu, I want to select that, regardless of it being highlighted or not.

something like

stateReducer: (state, { type, changes }) => {
  switch (type) {
    case useCombobox.stateChangeTypes.InputKeyDownEnter: {
      if(shownItems.length === 1){
        return { ...changes, selectedItem: shownItems[0]}
      }
    }
  return changes;
},
  1. If you want to trigger an action based on a state change, as a consequence of the Enter key down event, then use the onStateChange.

This wouldn't be possible currently, since no state changes as a consequence of the Enter key down, so the onStateChange is not triggered.

To clarify, stateReducer is trigger only when the state is about to be changed, so this explains why you are not getting the Enter type every time you press it, because only when an item is highlighted then the state changes.

That statement confuses me, because if that was the case, why is the stateReducer triggered when pressing Escape in a "pristine" input field? pressing Escape repeatedly without the menu open doesn't change any state at all, so shouldn't that be repressed as well? (same goes for the other keys, Home, End, Arrows, they all have some cases where the state doesn't change when pressed, but they still trigger the stateReducer).

@silviuaavram
Copy link
Collaborator

You are right, this is a bug, we should fix it.

Escape, Home, End, and Enter should behave the same, as far as the stateReducer is concerned.

@silviuaavram
Copy link
Collaborator

Ok, I was wrong, I'm sorry. stateReducer should be triggered all the time, only the state change handlers are executed when the state changes.

I will submit a PR to fix Enter. This is what prevents it from triggering the dispatch: if (latestState.isOpen && latestState.highlightedIndex > -1) { and should be removed. Will also check the tests to see if everything is OK. Thank you again for sticking with this!

@JReinhold
Copy link
Author

Sounds good, thanks! And thanks for the support.

@silviuaavram
Copy link
Collaborator

🎉 This issue has been resolved in version 6.0.4 🎉

The release is available on:

Your semantic-release bot 📦🚀

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging a pull request may close this issue.

2 participants