-
Notifications
You must be signed in to change notification settings - Fork 28
Conversation
afb36e9
to
e7506db
Compare
e7506db
to
96070d8
Compare
f0fe4ae
to
a7a94c3
Compare
c656e0a
to
b10586e
Compare
5aac874
to
baf66a4
Compare
ce4b62e
to
fc8f376
Compare
src/components/TopBar.jsx
Outdated
const onSelectSuggestion = (item, query) => { | ||
selectItem(item, { query }); | ||
inputRef.current.blur(); | ||
}; | ||
|
||
const onSubmit = async e => { | ||
e.preventDefault(); | ||
Telemetry.add(Telemetry.SUGGEST_SUBMIT); | ||
const query = inputRef.current.value; | ||
const results = await fetchSuggests(query, { | ||
withCategories: true, | ||
useFocus: true, | ||
}); | ||
onSelectSuggestion(results[0], { | ||
query, | ||
replaceUrl: 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.
src/components/ui/Suggest.jsx
Outdated
useEffect(() => { | ||
const handleFocus = () => { | ||
if (inputNode.value === '' || isMobile) { | ||
setIsOpen(true); | ||
fetchItems(inputNode.value); | ||
} | ||
}; | ||
|
||
const handleBlur = () => { | ||
if (!hasFocus) { | ||
close(); | ||
}; | ||
} else if (isMobile) { | ||
setIsOpen(true); | ||
} | ||
}, [hasFocus, isMobile]); | ||
|
||
const handleInput = e => { | ||
const { value } = e.target; | ||
useEffect(() => { | ||
setHighlighted(null); | ||
if (value !== null) { | ||
fetchItems(value); | ||
setIsOpen(true); | ||
setLastQuery(value); | ||
}; | ||
} | ||
}, [fetchItems, value]); |
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.
These 2 useEffect
do not handle correctly the case when a empty input is focused. A list of favorites should appear as suggestions and it's no longer the case (probably related to the condition inputNode.value === ''
that has been 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.
I replaced these 2 effects by a single one, which makes things actually simpler. I hope I haven't overlooked yet another edge-case…
setUserInputValue(inputRef.current.value + e.key); | ||
inputRef.current.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.
It works, but I am not sure to understand why calling setUserInputValue()
is necessary.
Isn't the input value supposed to change (and trigger onChange
) after the input has been focused ?
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.
This is the point which is driving me mad…
The focus is done and yes this is supposed to work like you say, but the first onChange
isn't triggered and the first letter is "lost". Honestly I've not figured exactly why yet, after a long debugging time spent on it…
I think it's related to the management of the user input value in PanelManager
, as in one of the previous commits it was managed as local state in TopBar
and it worked fine.
Feel free to spend time on it, maybe you'll understand what I wasn't able to, and I would be very interested in another PoV.
But if this is the last remaining hack I guess it's not too bad compared to the previous implementation.
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 am still not sure about what is going on here. Has this behavior ever worked with a "controlled" input? It looks like
React manages a custom cycle of events for keystrokes in this case.
An alternative solution would be to re-dispatch the "keydown" event after the input has been focused. Then, the dependency to setUserInputValue
could be removed:
setUserInputValue(inputRef.current.value + e.key); | |
inputRef.current.focus(); | |
inputRef.current.focus(); | |
inputRef.current.dispatchEvent(new KeyboardEvent(e.type, e)); |
It may be more consistent with the initial implementation, but I am not sure it is any 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.
wow, that's a big, but very clean rewrite!
Works great according to my local tests.
as for the "hack", I agree that it's not too bad if it's just that.
Description
Introduce a new
<TopBar>
component:Suggest
I/O and state management, removing some hacks and sources of bugsSearchInput
globalMenu
renderingThe
TopBar
itself was quite straightforward to move to React. Most of this PR content deals with the second point, the refacto ofSuggest
, which continues work done in #1079.The most important part is that the input field itself is now rendered by the
Suggest
component, but to let the parent control how it renders, I use a render function. This seems a bit complicated at first but is actually better than manipulating a DOM ref all the way. And it makes the life cycles easier to control deterministically.I also chose to separate more clearly the three different values that the input field can take:
Previously, confusion between these three values made the different cases hard to follow and debug.
As the
DirectionInput
also usesSuggest
, I had to adapt things in it too.I tried to do things step-by-step, but could not separate this. And this seemed like the better option to do that when moving the input field in React, as the main reason we used a ref before was to ensure compatibility with the static input.
The downside is this makes a very big PR 😞 Sorry… I propose we do a guided review if you think it's useful.
BTW, I did not push some markup and CSS simplifications that could be also done, because they can wait.