-
Notifications
You must be signed in to change notification settings - Fork 4k
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(Dropdown): fix multiple problems #1795
Conversation
Codecov Report
@@ Coverage Diff @@
## master #1795 +/- ##
==========================================
+ Coverage 99.75% 99.75% +<.01%
==========================================
Files 145 145
Lines 2477 2488 +11
==========================================
+ Hits 2471 2482 +11
Misses 6 6
Continue to review full report at Codecov.
|
this.open(e) | ||
return | ||
} | ||
if (this.searchRef) this.searchRef.focus() |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@levithomason this method does not make me happy, do you have ideas how we can refactor it?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hm, I don't think so. React has no focus mechanism so we'll have to use a ref or querySelector here. Since this section of logic is only reachable if this is a closed search dropdown, I think it makes sense.
What specifically are you not happy with and perhaps I can recommend better?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Too many conditions for one method as I think.
_.invoke(this.props, 'onClick', e, this.props) | ||
// prevent handleClick() | ||
e.stopPropagation() | ||
this.toggle(e) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't want to split this to separate method, however I don't see any other way. The initial idea was to compare e.target
in handleClick
this the Icon
's ref, but the Icon
component is stateless and doesn't have refs.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yep, I'd much rather have a separate explicit click handler here. This is OK. We are doing something entirely different when the icon is clicked.
d6bed05
to
725941f
Compare
725941f
to
642fe6a
Compare
src/modules/Dropdown/Dropdown.js
Outdated
@@ -848,12 +861,12 @@ export default class Dropdown extends Component { | |||
// Setters | |||
// ---------------------------------------- | |||
|
|||
setValue = (value) => { | |||
setValue = (value, resetQuery = true) => { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm not sure that the idea with resetQuery
is the best possible, hovewer I don't see another path, as I see in all other cases searchQuery
should be reset.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think we should split this into two methods. setValue
only sets the value and clearSearchQuery
only clears the query. It is easier to test and reason about complex interactions when the methods are small and explicit.
There are also enough use cases to warrant seprating them I think:
componentWillMount
This calls setValue
, however, it calls it with this.state.value
. This is a redundant operation. It seems the only reason we call it is for the other logic in setValue
, clearing the search query and setting the selected index.
We don't need to clear the query on mount, but we do need to set the selected index. I think this is duplicating work, but at the least, we don't need to clear the query on mount.
componentWillReceiveProps
This calls setValue
when a new value is received. Though this is correct, I also don't think we want to clear the user's query when this happens. If a new value comes down while a query is entered, I think it should only change the value, not the query.
makeSelectedItemActive
This method currently takes a resetQuery
argument and passes it down to setValue
. I think this method should only make the selected item active and not do anything else. The call sites for this method should be responsible for also deciding to clear the query or not:
moveSelectionOnKeyDown
- should never clear the queryselectItemOnEnter
- should only clear query when !multiplehandleBlur
- should clear the query (it is already only called when !multiple)
removeItemOnBackspace
Currently resets the query but is not necessary, there is no query at this point. Also, if the user enters a query and moves the cursor to the begining of the query and then presses backspace, we wouldn't want to clear the query either:
[ LabelA x ] [ LabelB x ] | My query
^ cursor, backspace should not clear the query
I know we don't support this yet, but we technically could/should in the future.
handleItemClick
This currently resets the query when an menu item is made active, however, I have always found this to be a usability issue with multiple
dropdowns. When there are lots of items, it is often more helpful to keep the query while clicking items. Otherwise, the user has to enter the same query over and over for every item. Example, selecting all states that start with ma
:
If we separate setValue
and clearSearchQuery
, then we can call only setValue
in the multiple condition in this method. The other branch (not multiple) we can safely clear the query becuase we know the user is done making selections.
handleLabelRemove
This will currently clear the query also but probably never should have done so. Here I'm again selecting states with ma
. I "accidentally" select Alabama
and continue making selections. I then remove Alabama
while I have a query entered and my query gets removed :/
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@levithomason Thanks for a detailed feedback, I'm fully agree with your suggestions. Will make a changes soon
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think that we should extract behaviour of removeItemOnBackspace
to separate issue, I fully agree that we need to impliment it.
I performed required changes, in most cases the @levithomason your review is very necessary, also I will be happy to hear @klerkendev there. |
…github.com/Semantic-Org/Semantic-UI-React into fix/dropdown-min-characters
|
||
handleIconOverrides = predefinedProps => ({ | ||
onClick: (e) => { | ||
_.invoke(predefinedProps, 'onClick', e, predefinedProps) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please take an attention to this line, Icon
component doesn't have onClick
handler, so it doesn't have second argument. There are two possible solutions: remove the second argument or add onClick
hanlder to the Icon
component.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I see the issue here, however, I think this is going to be rare enough of an edge case to leave as-is for now. We shall see :)
311d59c
to
f6539f0
Compare
requiredProps = {}, | ||
} = options | ||
const { assertRequired } = helpers('implementsShorthandProp', Component) | ||
const assertMethod = strictAssert ? 'contain' : 'containMatchingElement' |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why? contains
is too strict while I added onClick
handler to the Icon
it was real pain. I think it's a quite elegant solution, as I remember we had same problem with the Input
component.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@levithomason we're ready for review there.
…React into fix/dropdown-min-characters # Conflicts: # test/specs/modules/Dropdown/Dropdown-test.js
Requires #1845. |
…React into fix/dropdown-min-characters # Conflicts: # test/specs/modules/Dropdown/Dropdown-test.js
b51fd58
to
002f411
Compare
@layershifter #1845 has been merged, should be unblocked here. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I've left some notes regarding splitting setValue
, clearSearchQuery
, and makeSelectedItemActive
.
…ntic-Org/Semantic-UI-React into fix/dropdown-min-characters
…React into fix/dropdown-min-characters
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@levithomason I've performed requested changes
This looks great, thanks for pressing through on this! |
Released in |
Fixes #1787.
Fixes #1858.
Codepen
Single select, placeholder
Click on placeholder doesn't capture the search input focus.
Expected behaviour
Single select, arrows
Click on
up
ordown
arrows resets current search value.Current behaviour
Expected behaviour
Single select
Click on
dropdown icon
should always open the dropdown.Current behaviour
Expected behaviour
Multi select, click
Click the dropdown (doesn't matter where) doesn't make anything.
Expected behaviour