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

EuiComboBox #567

Merged
merged 61 commits into from
Mar 30, 2018
Merged

EuiComboBox #567

merged 61 commits into from
Mar 30, 2018

Conversation

cjcenizal
Copy link
Contributor

@cjcenizal cjcenizal commented Mar 23, 2018

Replaces #52

Input

  • When the user start typing into the input, it should move to the next line if necessary to give the user as much room to type as possible.

Options list

  • Options should highlight substrings which match the search input.
  • Consumer needs to be able to group options.
  • Nice-to-have: Options should be custom-renderable.
  • The list should render inside a portal, and reposition itself when it's about to flow off-screen.

Use cases

Empty states

  • When nothing matches the input, suggest adding it by hitting enter.
  • When there are no suggestions remaining, surface some appropriate feedback, e.g. "You've selected all available options".

Keyboard accessibility

  • Tabbing to the component will focus the input
  • When the cursor is at the beginning of the input:
    • hitting backspace will delete the preceding pill
    • hitting left arrow will focus that pill
  • Left and right arrow keys can be used to navigate through the pills
  • Up and down arrow keys can be used to navigate into, throughout, and out of the options list

Screen reader accessibility

  • Possible actions will be announced at each stage of the above
  • The value of the input will contain the selected values; we'll use aria-label to read the humanized values aloud

Async actions

  • We'll want to be able to display a loading spinner while it's waiting on options to be loaded (isLoading prop)
  • We'll also want the ability to save a new pill value

@cjcenizal
Copy link
Contributor Author

@nreese @snide @peteharverson Could you please take a look at how this behaves in the browser and give me your thoughts before I add tests? @timroes Could you do the same, especially regarding screen reader and keyboard accessibility? Thanks!

@snide
Copy link
Contributor

snide commented Mar 28, 2018

This is great and covers almost all the use cases I can think of (minus the single select one, which I see you have as another item). I'll have some styling to refine it, but all the bits are there so it should be a T-Ball. Big thumbs up. The following are some finesse suggestions.

  1. We need a placeholder prop. It can just place itself in the "input". I can see instances where the placeholder might be different if there are or are not pills already set, so if you happen to set up two props for it, that would be pretty awesome.
  2. I think we should separate the up/down selection from the input focus. Right now you can't move up and down and type at the same time. I think you want to keep the cursor focused in the input as they move up and down. I know that means you don't get the benefit of auto-scrolling because of the item focus, but having them as separate actions means your hands need to do much less work to move around. With the aria stuff I think you'd have to read the selection independently, but you can see the benefit there too, since it will read the first match as you type.
  3. Tied to that, I'd auto-select the first option so you can just jam on enter immediately. As mentioned before, should also help speed up a screen reader's time to action as well.
  4. I think the "pill" should be tabable. And that you should have to tab through them to get to the input. Right now it's pretty hard to get to them with your keyboard. There's no way to delete the first item of three with the keyboard. You have to delete all or nothing.
  5. Similarly, for your backspace mechanic, I'd suggest using the first Backspace to do a "shift-tab" action, that actually selects the item, then the second backspace actually deletes it. This prevents people from inadvertently deleting things by accident. It's a small thing, but really helps these kinds of interactions. Here's an example of one I built awhile ago. The "blue" state is the first backspace, and then the second backspace confirms it. If you end up added something like that, i can think up some proper styling if you pass over an isSelected prop on the pill itself.

I know this is a big one so I'm sure I'll have other stuff, but those are the bits that jumped out at me immediately. All that said it's really impressive and mostly there, certainly from a functionality scenario.

@cjcenizal
Copy link
Contributor Author

@bevacqua This component supports a mode in which the suggestions list is hidden and the user can only type custom values which get turned into pills. It looks like this could possibly replace #353. Can you take a look and let me know if this satisfies your use cases for that component?

@timroes
Copy link
Contributor

timroes commented Mar 28, 2018

Thanks for creating this. I will try to review (accessibility) as soon as possible.

Single select would btw be a "super-nice-to-have", since that would make it usable in most places where we currently use react-select in vis editors (or older Angular components) for all the aggregation selection, etc.

@jgowdyelastic
Copy link
Member

jgowdyelastic commented Mar 28, 2018

Great progress!
For this to be a complete replacement for ML's use of ui-select we would definitely need single selection.
For example, this select in our Multi-metric job creation page where we group by field type.
image

@bevacqua
Copy link
Contributor

@cjcenizal Ideally, I'd port insignia to React for the tag editor use case, and make it compatible with a different component that only did autocompletion (like horsey), or we could merge them.

The tag editor on its own is nice because it allows you to focus on that use case, so you get things like the ability to enter random stuff, validation, text editing that feels very natural in the case of insignia (where out the box you can use arrow navigation to edit the tags, for instance), and conversely you can attach the autocompletion component to things like textareas, divs, inputs, or anything you like, making it pretty flexible as well and useful for later use cases like adding user mentions, which is a requirement EUI will definitely get at a certain point in its lifetime, so we might as well start considering those now.

@cjcenizal
Copy link
Contributor Author

@bevacqua Thanks for your feedback. It sounds like this component could substitute for some of the use cases of your discrete input component, but it's not quite as flexible as you want. I think it will probably make both development and consumption easier if we pursue the direction you suggest as a separate component.

@timroes @jgowdyelastic I'll implement single-selection before merging. Thanks for pointing out its importance.

@nreese Per our convo I'll also render the options list within a portal, so EuiComboBox can be used inside of dashboards.

@snide Thanks for your comments. To your points:

  1. Good idea on the placeholder. I'll implement a placeholder for when there aren't any pills for now, and create an issue for a placeholder when there are pills. I see how you used it in the Guidebook example. I was looking at examples from Uniform and react-select and they felt pretty intuitive to me without the persistent placeholder so I wonder if the component is better without it.
  2. I think keeping focus on the input as you traverse the options is a really neat idea. I think I know how we can implement this but I don't think I have the time to do it right now, so I'll create an issue for this.
  3. Same.
  4. Same here. Great idea, something I thought of too.
  5. Another great idea. I'm all for protecting against accidental destructive actions. I'll create an issue for it.

@cjcenizal
Copy link
Contributor Author

@snide @timroes @jgowdyelastic @nreese I've addressed your comments. Please take another look so I can merge this. I hate to do it but I think tests will have to come separately.

@nreese
Copy link
Contributor

nreese commented Mar 29, 2018

@cjcenizal I am seeing some weird behavior with the latest version in Kibana. Opening the options list makes the rest of the page content disappear. There are no errors or warnings in the console. Here is my WIP PR that is showing the weird behavior

portal_problems

@nreese
Copy link
Contributor

nreese commented Mar 29, 2018

@cjcenizal Thanks for the note about the euiBody-hasToolTip rename to euiBody-hasPortalContent. Kibana has a css rule overriding euiBody-hasToolTip position and when that override was applied, the problems above were fixed

Copy link
Contributor

@snide snide left a comment

Choose a reason for hiding this comment

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

This is great. I ran through the code a bit and it was pretty easy to follow. Really nice work. This one was super tricky.

I set up a PR to utilize EuiBadge for the pill component and did some other misc. cleanup. Let's us apply coloring so that it'll work better with @nreese's tagging system.

cjcenizal#2

image

Only bug i noticed was that it breaks a little bit when you utilize EuiFormRow. The label to input gets busted and the dropdown has trouble disappearing). Heres a gif showing the issue.

@nreese
Copy link
Contributor

nreese commented Mar 29, 2018

Sometimes the options box is wider than the input.

screen shot 2018-03-29 at 9 14 48 am

};
}

onChange = (selectedOption) => {
Copy link
Contributor

Choose a reason for hiding this comment

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

This example is a little confusing because selectedOption is an array. Maybe it would be clearer if its written like

onChange = (selectedOptions) => {
  let selectedOption;
  if (selectedOptions.length > 0) {
    selectedOption = selectedOptions[0];
  this.setState({
    selectedOption
  });
}

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Will do.

@cjcenizal
Copy link
Contributor Author

cjcenizal commented Mar 30, 2018

I think I've run out of time on this. I'm on PTO tomorrow and next week I need to shift my focus to Cloud. Unless anyone objects, I'm going to merge this tomorrow morning. Here are the outstanding issues I know of that still need to be addressed:

  • There's a TODO in combo_box.js which notes that we need to wait for the EUI CSS to be loaded before calling this.autoSizeInput.copyInputStyles() (docs). Ideally we should listen for the styles to load instead of using a static timeout. Until we fix this, users are bound to see the input text with the incorrect font-size and style.
  • EuiComboBox doesn't work inside of EuiModal. There's a problem with the tab order and the way the ESCAPE keypress is handled.
  • Nate's sizing issue hasn't been addressed yet. We need to intelligently set the width of the options list to match that of the input box.

Once this is merged I'll break out individual issues for these.

@cjcenizal
Copy link
Contributor Author

I addressed the bug @nreese found. Merging now!

@cjcenizal cjcenizal merged commit ff9d5aa into elastic:master Mar 30, 2018
@cjcenizal cjcenizal deleted the combo-box branch March 30, 2018 16:31
Copy link
Contributor

@nreese nreese left a comment

Choose a reason for hiding this comment

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

Your last commits fixed the problems I was seeing.

lgtm

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

Successfully merging this pull request may close these issues.

6 participants