-
Notifications
You must be signed in to change notification settings - Fork 36
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
feat(atomic): add configurable query suggestions & recent queries to search box #1261
Conversation
Thanks for your contribution @ThibodeauJF !
|
Pull Request Report PR Title ❌ Title should follow the conventional commit spec: (optional scope): Example: feat(headless): add result-list controller Bundle Size
|
|
||
public initialize() { | ||
this.id = randomID('atomic-search-box-'); | ||
this.querySetActions = loadQuerySetActions(this.bindings.engine); | ||
this.searchBox = buildSearchBox(this.bindings.engine, { | ||
options: { | ||
id: this.id, | ||
numberOfSuggestions: 8, // TODO: handle when adding query suggestion component | ||
numberOfSuggestions: 0, |
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 is the new initial value 0
?
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.
We can't let the search box manage the registering and fetching of query suggestions, mainly for the promise we need to wait for before rendering all suggestions. The other atomic-search-box-query-suggestions
handles it
tag: 'atomic-search-box-query-suggestions', | ||
shadow: true, | ||
}) | ||
export class AtomicSearchBoxQuerySuggestions { |
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 ending the name with a singular would make it easier to understand? Could it also be possible to shorten by removing SearchBox
? e.g.
AtomicSearchBoxQuerySuggestionList
AtomicQuerySuggestionList
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.
Fair enough, but I wanted it to be clear they are for the search box and you can't see them as independent. I could see these AtomicQuerySuggestions/AtomicRecentQueries being standalone somewhere in the page, like quantic uses recent queries
({engine, id, searchBoxController, numberOfQueries}) => { | ||
const {registerQuerySuggest, fetchQuerySuggestions} = | ||
loadQuerySuggestActions(engine); | ||
|
||
(engine as SearchEngine<QuerySuggestionSection>).dispatch( | ||
registerQuerySuggest({ | ||
id, | ||
count: numberOfQueries, | ||
}) | ||
); | ||
|
||
return { | ||
onInput: () => | ||
(engine as SearchEngine<QuerySuggestionSection>).dispatch( | ||
fetchQuerySuggestions({ | ||
id, | ||
}) | ||
), | ||
renderItems: () => | ||
// TODO: limit values according to maxWithQuery/maxWithoutQuery | ||
searchBoxController.state.suggestions.map((suggestion) => ({ | ||
content: <span innerHTML={suggestion.highlightedValue}></span>, | ||
value: suggestion.rawValue, | ||
onClick: () => | ||
searchBoxController.selectSuggestion(suggestion.rawValue), |
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 this block would be easier to follow if it was broken up into multiple smaller functions.
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'll do it in the other PR
); | ||
if (canceled) { | ||
throw new Error( | ||
'The Atomic search box suggestion component was not handled, as it is not a child of a search box 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 think it would be nice to include the tag, or an example, in the message to help devs understand, have something that they can copy-paste in case of a typo. e.g.
<atomic-search-box>
<atomic-search-box-suggestions/>
</atomic-search-box>
element: Element | ||
) => { | ||
const canceled = element.dispatchEvent( | ||
buildCustomEvent('atomic/searchBoxSuggestion', event) |
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.
Would the event's role be clearer if it included /register
or similar at the end? e.g.
atomic/searchBoxSuggestion/register
|
||
@State() public error!: Error; | ||
|
||
@Prop() public maxWithQuery?: number; |
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.
Do we really need two different prop for this ? Just one for both could do, no ? 🤔
Why would it be important to have separate option for both mode ?
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.
From the design (figma), you put as many recent queries as possible when the input is empty, but then you match up to 3
queries. I could remove the options here for query suggest, but I find it more consistent.
* - atomic-search-box-query-suggestions | ||
* - atomic-search-box-recent-queries | ||
*/ | ||
@Prop() public numberOfQueries = 8; |
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.
numberOfSuggestions
? What do you think ?
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.
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 instead of making this an option here, we could have an opiniated default, and if people want to override it then they need to specify atomic-search-box-query-suggestions
and atomic-search-box-recent-queries
themselves.
Otherwise, I find it confusing to predict what number of suggestions & recent queries will each appear based on this option.
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 why each of the sub elements, atomic-search-box-query-suggestions and atomic-search-box-recent-queries, have maximums, which when not defined, fill up the numberOfQueries
value. How else could we configure the following:
- I want a max of 8 queries at all times (any type)
- When there is no query in the input, I want all the recent queries I can up to 8, but fill the rest with query suggestions
- When there is a query, I want up to 3 matching recent queries, and fill the rest with query suggestions
import {buildCustomEvent} from '../../utils/event-utils'; | ||
import {Bindings} from '../../utils/initialization-utils'; | ||
|
||
export interface SearchBoxSuggestionElement { |
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.
When we want to make the "Custom Atomic component" API official, it means we will need to make the mechanism to extend "search box suggestions" provider public. And that can be a pretty tricky thing to get right.
A couple notes/thoughts:
-
Since the
content
(the VNode) is ultimately rendered inside anul
/li
in atomic-search-box, I guess that not all HTML elements would be valid ? I'm perfectly fine with this, by the way, but if there's any restriction, they need to be clear and (potentially) automatically handled (read: rejected) by the system so that users don't get random errors. Another approach would be to accept anything here, but to make it possible to control the "container" inatomic-search-box
(being able to changeul
/li
to something else. This does add complexity, however. -
If someone wants to provide very rich/complex suggestion (eg: A product image with lots of metadata section), how would the keyboard navigation plays into that ? If you could navigate to different subsection on a suggestion. Should the system forbid that ?
-
What happens if you want to have multiple clickable/interactive element in a given suggestion element ? Would the
onClick
cause a problem then ? -
Is the integration of that
dispatchSearchBoxSuggestionsEvent
inside thecomponentWillLoad
function as clean as it could be ? Could it be a more straightforward interface that you need to implement (or clever usage of an annotation).
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 want that limitation, the search box manages all the interactivity with the search box. The li is needed to be correctly accessible too.
- Yes, a single element means a single possible interaction, more than that get's too complex for all our use cases.
- Same as point 2
- What would you propose like interface? I will certainly be extended upon in the future, modify with our needs. It's not public yet and before it is we will have improved upon it to support instant results and recently viewed.
import {Bindings} from '../../utils/initialization-utils'; | ||
|
||
export interface SearchBoxSuggestionElement { | ||
value: string; |
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.
Unless I am mistaken, we use value
here as a key
for JSX code.
Could we just name it key
then ?
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 could change when adding results, but the way suggestion worked is the value (used for key & data-value) will affect the query when you use the arrows, just like on google.com & the JSUI
|
||
@State() public error!: Error; | ||
|
||
@Prop() public maxWithQuery?: number; |
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.
Similar as above, why do we need two prop for this ?
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.
|
||
export interface SearchBoxSuggestionElement { | ||
value: string; | ||
onClick(): void; |
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.
Suggestion: onSelect
since it's not always going to be a click. eg: touch on mobile, or enter is using a keyboard.
export interface SearchBoxSuggestionElement { | ||
value: string; | ||
onClick(): void; | ||
content: VNode; |
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.
The type VNode works great in Stencil and maybe in other JSX frameworks, but I don't know if it's possible without those frameworks to provide a VNode.
}); | ||
|
||
return { | ||
onInput: () => {}, |
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.
Should we show all recent queries in the suggestions or only those that include what we typed so far?
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's in the mockups, when no query, we display them as is, when there is a query, we filter them out, you can refer to the part 2 for the implementation!
https://coveord.atlassian.net/browse/KIT-853
Design doc (updated): https://docs.google.com/document/d/14BP1npUVEDwkWeVe3thbf9nSs7b8z4tCFAtWAR5BkhI/edit#