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

Dropdown: add support for allowAdditions #356

Merged
merged 1 commit into from
Aug 18, 2016
Merged

Dropdown: add support for allowAdditions #356

merged 1 commit into from
Aug 18, 2016

Conversation

dylankiss
Copy link
Contributor

No description provided.

@levithomason
Copy link
Member

Thanks, I will review this tomorrow. Could you please add an example to the doc site so we can try it out? You can reference the other Dropdown examples in docs/app/Examples/modules/Dropdown. Just add an example file (probably types/AllowAdditions.js), then update the index.js in that directory.

@codecov-io
Copy link

codecov-io commented Aug 2, 2016

Current coverage is 94.89% (diff: 100%)

Merging #356 into master will increase coverage by 0.03%

@@             master       #356   diff @@
==========================================
  Files            85         85          
  Lines          1110       1117     +7   
  Methods           0          0          
  Messages          0          0          
  Branches          0          0          
==========================================
+ Hits           1053       1060     +7   
  Misses           57         57          
  Partials          0          0          

Powered by Codecov. Last update 4557289...ec24ec7

@dylankiss
Copy link
Contributor Author

@levithomason I added a simple example to the docs.

{ text: 'Spanish', value: 'Spanish' },
{ text: 'German', value: 'German' },
{ text: 'Chinese', value: 'Chinese' },
]}
Copy link
Member

Choose a reason for hiding this comment

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

Let's pull these options into a const above the example. This way we can reuse them. Also, they'll be created once instead of every render.

Then, let's add a single and multiple dropdown that use the same options and both allow additions. Similar to http://semantic-ui.com/modules/dropdown.html#tagging-and-user-additions.

This raised the first bug, multiple dropdowns do not allow adding multiple additions.

@dylankiss
Copy link
Contributor Author

@levithomason Thanks for your very useful remarks! I will look into it as soon as possible.

@dylankiss
Copy link
Contributor Author

dylankiss commented Aug 5, 2016

@levithomason I'm trying to add tests for my component, but when I try to run them using npm test, I get the following error:

05 08 2016 12:44:04.986:ERROR [config]: Invalid config file!
  SyntaxError: Unexpected token {
    at exports.runInThisContext (vm.js:53:16)
    at Module._compile (module.js:373:25)
    at Object.Module._extensions..js (module.js:416:10)
    at Module.load (module.js:343:32)
    at Function.Module._load (module.js:300:12)
    at Module.require (module.js:353:17)
    at require (internal/module.js:12:17)
    at Object.parseConfig (/Users/dkiss/projects/stardust/node_modules/karma/lib/config.js:284:22)
    at new Server (/Users/dkiss/projects/stardust/node_modules/karma/lib/server.js:57:20)
    at Object.exports.run (/Users/dkiss/projects/stardust/node_modules/karma/lib/cli.js:243:7)
    at requireCliAndRun (/Users/dkiss/projects/stardust/node_modules/karma-cli/bin/karma:44:16)
    at /Users/dkiss/projects/stardust/node_modules/karma-cli/bin/karma:54:12
    at /Users/dkiss/projects/stardust/node_modules/resolve/lib/async.js:44:21
    at ondir (/Users/dkiss/projects/stardust/node_modules/resolve/lib/async.js:187:31)
    at /Users/dkiss/projects/stardust/node_modules/resolve/lib/async.js:153:39
    at onex (/Users/dkiss/projects/stardust/node_modules/resolve/lib/async.js:93:22)

I haven't changed anything in the config file. Do you know immediately what this problem could be?

@dylankiss
Copy link
Contributor Author

@levithomason I have changed the behavior to your suggestions and added an example for single and multi-select. I also added a few test cases to cover the code changes.

Still unable to run the tests locally, so it was just: write a test -> push ... :)

@levithomason
Copy link
Member

Which version of Node do you have? This project requires Node 6. See CONTRIBUTING.md Getting Started for more.

@dylankiss
Copy link
Contributor Author

Well, that will be it. We're working with Node 4. Will try with Node 6 next time :)

@dylankiss
Copy link
Contributor Author

@levithomason While adding this feature I noticed that there is this behavior in the Dropdown that automatically selects the first suggestion in the list if you press enter. This makes that you can't add a substring of an existing option as a new option. I don't know what the best behavior would be to allow this, because you will still want to select your first option by pressing enter also when you are allowed to add a new one.

@levithomason
Copy link
Member

levithomason commented Aug 6, 2016

This makes that you can't add a substring of an existing option as a new option.

Hm, some refactors are probably necessary. On mobile but I'll try to guide you.

There is a single "selected" item in a selection Dropdown. This is the highlighted item in the menu. It is made "active" on pressing Enter. The active items make up the Dropdown value.

There is a "selectedIndex" state key. The menu item at the index matching the selectedIndex is "selected", meaning it is highlighted. The up/down arrow keys decrement and increment the selectedIndex. When the search query changes, the selectedIndex is set to 0 (the first search result). When the search query doesn't match anything, the selectedIndex is set to -1 (iirc) so no item is selected.

Here's where the refactor may be needed. We currently match on string "includes". Perhaps when there is not an exact match, we include an item at the bottom of the list that says "Add: <search query >". If the user chooses this item, we call the "onAddition" callback.

When there are no matching results, this would replace the "No results" message that is currently shown.

Hope this helps. I'll be out the rest of today but will look more into this as soon as I can.

@dylankiss
Copy link
Contributor Author

dylankiss commented Aug 6, 2016

I was also considering something like that. I'd rather put it at the top of the list instead of at the bottom though. Because you could possibly have a lot of options that start with the same letter(s) and that would make the Add: ... option only visible when you scroll to the bottom. When it's at the top it's immediately clear you can add that value. The first predefined option is just one "arrow down" away then :)

What's your opinion on this?

BTW: The vanilla Semantic UI dropdown has the same behavior for user additions (also unable to add a substring).

@levithomason
Copy link
Member

What's your opinion on this?

My intuition is that the most common use case will be selecting existing items and the least common use case will be adding items. Because of this, I think the more common use case should have fewer keystrokes and more visibility. Meaning, the Add: ... would be at the bottom.

Because you could possibly have a lot of options that start with the same letter(s) and that would make the Add: ... option only visible when you scroll to the bottom.

This is a really valid point. I think when adding an item you'll have a search query that will match little to no existing items. In this case you'll be able to see the Add: ... as either the first item, or just a minimal number of items down the list. Being this should be the exception, not the norm, I think it makes sense to offer the existing items first to the user. Then, in those less common edge cases that they are searching for a non-existent item with many substring matches, they may have to scroll to find the Add: ... I think that will be the intuitive behavior of a person looking for their match in the list when they can't see it.

BTW: The vanilla Semantic UI dropdown has the same behavior for user additions (also unable to add a substring).

Had no idea 😄, though it seems like a common enough problem and great feature we should add still. Thoughts?

@dylankiss
Copy link
Contributor Author

My intuition is that the most common use case will be selecting existing items and the least common use case will be adding items.

I guess this depends on the specific use case for this control. For my use case it is the other way round. I basically want to use it as a text field with a history list of used values that the user could re-use, but primarily he should be able to simply add a new value here.

Ideally just tabbing from the control after having entered his custom value should call onAddition and onChange, as does the vanilla SUI Dropdown too. But that's another issue, I think.

What are your thoughts on adding another prop to select whether you want to go 'insert-first' or 'select-first' and depending on that, show the Add: ... option at the top or bottom of the list?

@levithomason
Copy link
Member

What are your thoughts on adding another prop to select whether you want to go 'insert-first' or 'select-first' and depending on that, show the Add: ... option at the top or bottom of the list?

Sure, something like additionPosition={'top'|'bottom'} or similar would be great.

@dylankiss
Copy link
Contributor Author

Alright, I will look into it probably tonight or tomorrow.

@dylankiss
Copy link
Contributor Author

@levithomason Another discrepancy between Stardust and Semantic UI Dropdown is the way it handles blurs (and tab).

In Semantic UI, when you use the keyboard to browse through dropdown list, the placeholder changes to the entry you are currently highlighting. When losing focus after that (by clicking somewhere else or pressing tab) the highlighted value gets selected.

In Stardust

  • it does not update the placeholder value when browsing trough the list with the up and down keys
  • when clicking outside the component the value stays what it was before, or the search text stays in the search box when there was text in there
  • when pressing tab, the dropdown menu does not collapse and for the rest it has the same behavior as clicking outside the component

Is there a reason for these discrepancies, or are they just things that were overseen?

@levithomason
Copy link
Member

There is an issue with closing on blur. There are todos in the code and tests explaining this.

All the other features can be implemented afaik, PRs welcome! It might make sense to open a separate issue/PR since the allowAdditions is entirely separate from these features.

@dylankiss
Copy link
Contributor Author

Okay, I might work on these issues then after this one is ready :)

@dylankiss
Copy link
Contributor Author

dylankiss commented Aug 15, 2016

@levithomason Sorry for the delay. I managed to incorporate the Add: ... option (that now allows substrings) with an optional additionPosition, being 'top' or 'bottom' (default). The single select example uses no additionPosition (defaults to bottom) and the multi select uses 'top'. I also added tests to cover all the changes.

Could you take a look to see whether this looks good to you?
Thanks :)

@levithomason
Copy link
Member

Awesome! Pulling and reviewing now.

@levithomason
Copy link
Member

Looking much better, thanks for docs as well. There is one issue remaining. When typing a query that doesn't exists, then removing it, then "Add: " text is still shown:

image

This is also true for multiple dropdowns, but only when it already has a value:

image

onAddition: PropTypes.func,

/** Position of the `Add: ...` option in the dropdown list ('top' or 'bottom'). */
additionPosition: PropTypes.string,
Copy link
Member

Choose a reason for hiding this comment

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

-PropTypes.string,
+PropTypes.oneOf(_meta.props.additionPosition),

At the top of the file:

const _meta = {
  name: 'Dropdown',
  type: META.TYPES.MODULE,
  props: {
    pointing: ['bottom left', 'bottom right'],
+    additionPosition: ['top', 'bottom'],
  },
}

]),

/** Called with the new value added by the user. Use this to update the options list. */
onAddition: PropTypes.func,
Copy link
Member

Choose a reason for hiding this comment

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

Looking back on this now, this prop probably makes more sense as onAddItem. Mind updating?

Side note, I plan on updating the options prop to items so it follows SUI closer. Then the, Select component will use options.

@levithomason
Copy link
Member

Could you take a look to see whether this looks good to you?

All comments in! Let me know if you'd like any help on this PR. I don't want to over burden you with changes. If you would like some help, just add me as a collaborator on your fork and I can make updates along with you.

Thanks much, cheers!

@dylankiss
Copy link
Contributor Author

@levithomason Valid point concerning the state ;) I changed it. Also renamed the onAddition prop as per your proposal. I agree it is better.

Could you have another look please?

@levithomason
Copy link
Member

Will do, thanks

this.setState({
options: newOptions,
Copy link
Member

Choose a reason for hiding this comment

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

This can be removed since there is now no use of state for options.

@dylankiss
Copy link
Contributor Author

dylankiss commented Aug 17, 2016

Changed to all your comments. Stupid that I didn't see these :)

(Sorry for the delay in response btw, but there's a huge time difference ...)

@dylankiss
Copy link
Contributor Author

@levithomason What do you think of removing the Add: prefix for our custom option and show it as a regular option? Or make it configurable?

If I think of my use case I definitely don't need the Add: prefix, but maybe other use cases require it to be clear that you are adding something.

@levithomason
Copy link
Member

Don't fret over the changes and responsiveness, it's just how software goes. I appreciate all your time and effort here 👍

A configurable addition label would be superb. Maybe additionLabel and default it to Add:? What do you think?

@dylankiss
Copy link
Contributor Author

@levithomason Sounds good to me. I added the prop and tests for it. This feature is now fully usable for me. What do you think?

@levithomason
Copy link
Member

Awesome, let's get tests passing and merge it.

@dylankiss
Copy link
Contributor Author

I just rebased before pushing without re-running the tests :) Since you added defaultProps and I did too (at another position), mine overruled yours. Should be fixed now.

@levithomason
Copy link
Member

Woop! Thanks for the work here, merging.

@levithomason levithomason merged commit ba1c9b3 into Semantic-Org:master Aug 18, 2016
@levithomason
Copy link
Member

Released in v0.34.4

@levithomason levithomason changed the title Added support for allowAdditions to Dropdown Dropdown: add support for allowAdditions Aug 18, 2016
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.

3 participants