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

Adds autocomplete components #1490

Merged
merged 110 commits into from
Oct 13, 2021
Merged

Adds autocomplete components #1490

merged 110 commits into from
Oct 13, 2021

Conversation

mperrotti
Copy link
Contributor

@mperrotti mperrotti commented Sep 30, 2021

Adds components that support adding autocomplete functionality to a text input.

Screenshots

Screen Shot 2021-10-04 at 9 04 11 PM
Screen Shot 2021-10-04 at 9 05 40 PM

Merge checklist

  • Added/updated tests
  • Added/updated documentation
  • Tested in Chrome
  • Tested in Firefox
  • Tested in Safari
  • Tested in Edge

Take a look at the What we look for in reviews section of the contributing guidelines for more information on how we review PRs.

@mperrotti mperrotti requested review from a team and smockle and removed request for a team September 30, 2021 22:41
@changeset-bot
Copy link

changeset-bot bot commented Sep 30, 2021

🦋 Changeset detected

Latest commit: 43a84f4

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 1 package
Name Type
@primer/components Minor

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

@mperrotti mperrotti marked this pull request as draft September 30, 2021 22:43
@github-actions
Copy link
Contributor

github-actions bot commented Sep 30, 2021

size-limit report 📦

Path Size
dist/browser.esm.js 63.01 KB (+4.16% 🔺)
dist/browser.umd.js 63.39 KB (+4.21% 🔺)

mperrotti and others added 4 commits October 4, 2021 11:21
- allows the user to pass a custom scrollContainerRef if the menu is rendered inside a scrolling element besides AutocompleteOverlay
- hides the AutocompleteMenu when it is rendered outside of the AutocompleteOverlay component
mperrotti and others added 5 commits October 4, 2021 16:41
@siddharthkp
Copy link
Member

siddharthkp commented Oct 5, 2021

These are nit picks / tiny annoyances that I ran into while exploring the stories. I think both of these are polish and not deal breakers though.

 

  1. Chrome tries to autofill the input which leads to 2 autocompletes at the same time. We might be able to turn the native one off with autocomplete="off"

    autocomplete-annoying-chrome

 

  1. When using keyboard navigation, I (wrongly?) expected to open the menu with Enter, but found this edge case instead where the focus is still on the last element and it can be toggled on/off with Enter

    autcomplete-edge-case-return

@mperrotti mperrotti removed the request for review from smockle October 11, 2021 18:42
Copy link
Contributor

@jfuchs jfuchs left a comment

Choose a reason for hiding this comment

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

Overall: 😍 💅🏻 🤠 🎇

This is all great and very impressive. I have some questions for sure, but some of them might be mostly about my lack of context. Happy to jump on a call if that helps.

Unsolicited UX feedback

Another thing (already discussed over zoom) — it feels odd that hovering my mouse over the autocomplete suggestions would update the text input — I found that to be too much mutation to be driven off of a hover.

Something surprising: deleting a token results in the token text being put in the input.

Bug?

Not sure if it's a documentation bug or what but I noticed this odd text clipping:

CleanShot.2021-10-11.at.14.05.59.mp4

src/Autocomplete/Autocomplete.tsx Outdated Show resolved Hide resolved
import AutocompleteMenu from './AutocompleteMenu'
import AutocompleteOverlay from './AutocompleteOverlay'

const Autocomplete: React.FC<{id?: string}> = ({children, id: idProp}) => {
Copy link
Contributor

Choose a reason for hiding this comment

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

🤔 what's the use case for id as an external prop? I couldn't find a story or doc indicating why you'd want that.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I wanted to give an easy way to select elements for integration tests. If you think there are better ways to do this, I'm happy to get rid of this prop.

src/Autocomplete/Autocomplete.tsx Outdated Show resolved Hide resolved
src/Autocomplete/Autocomplete.tsx Outdated Show resolved Hide resolved
src/utils/types/MandateProps.ts Show resolved Hide resolved
src/Autocomplete/AutocompleteOverlay.tsx Show resolved Hide resolved
src/Autocomplete/AutocompleteMenu.tsx Outdated Show resolved Hide resolved
filterFn = getDefaultItemFilter(inputValue),
'aria-labelledby': ariaLabelledBy,
onOpenChange,
onSelectedChange = getDefaultOnSelectionChange(setInputValue),
Copy link
Contributor

Choose a reason for hiding this comment

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

if a user doesn't pass an onSelectedChange, I think that means you'll be creating a new onSelectedChange with each render, and it looks like there's a useMemo call below with onSelectedChange in its dependencies array.

edit: same thing for filterFn

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Good catch. Any ideas for how we could avoid the re-renders?

My first thought is to export the "default" functions and require engineers to explicitly pass a filterFn and onSelectedChange

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I ended up just removing the assignments from the destructured props. If the prop is undefined, we just call the default functions defined up top.

However, I could still see a case for exporting getDefaultItemFilter and requiring a value for filterFn.

I'd love to hear your thoughts.

Copy link
Contributor

Choose a reason for hiding this comment

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

I think you can just change it to:

const AutocompleteMenu = ({
  onSelectedChange // (don't assign a default yet here)
}): Props => {
  // ...
  const onSelectedChangeOrDefault = useMemo(() => {
    return onSelectedChange || defaultOnSelectedChange(setInputValue)
  }, [...])
}

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Ah ok, that works too.

Did you intentionally use useMemo instead of useCallback? I thought useCallback was the one for memoizing functions.

src/Autocomplete/AutocompleteMenu.tsx Show resolved Hide resolved
src/Autocomplete/AutocompleteMenu.tsx Outdated Show resolved Hide resolved
@mperrotti
Copy link
Contributor Author

mperrotti commented Oct 12, 2021

Not sure if it's a documentation bug or what but I noticed this odd text clipping

I hadn't seen that when working in Storybook, but I wasn't working with strings that long. I'll take a look.

Edit: I fixed the styling issue in the docs example. However, I noticed that the horizontal padding in the TextInput component causes some text clipping. We should file an issue.

Screen Shot 2021-10-12 at 11 22 24 AM

@colebemis
Copy link
Contributor

Noticed a few odds behaviors in the live code examples:

  1. In the issue label example, the label colors reset when a new label is selected:
CleanShot.2021-10-12.at.15.06.05.mp4
  1. In the multiple values example, selecting an item causes an error:
CleanShot.2021-10-12.at.15.09.35.mp4

@mperrotti
Copy link
Contributor Author

Thanks @colebemis! I see what the problems are. Thankfully they're both just silly mistakes with the example code and not bugs in the components.

@@ -30,6 +30,7 @@ export {useConfirm} from './Dialog/ConfirmationDialog'
export {ActionList} from './ActionList'
export {ActionMenu} from './ActionMenu'
export type {ActionMenuProps} from './ActionMenu'
export {default as Autocomplete} from './Autocomplete'
Copy link
Contributor

Choose a reason for hiding this comment

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

Should we also export the props here?

Copy link
Contributor

Choose a reason for hiding this comment

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

@jfuchs Can we right tests to ensure that components and their prop types are being exported?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Probably. It looks like we do it for other components.

Copy link
Contributor

@colebemis colebemis left a comment

Choose a reason for hiding this comment

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

Looks great! ✨

A couple of things before we merge this:

  • Add a changeset
  • Export the prop types from the src/index.ts

Base automatically changed from mp/text-input-with-tokens-component to main October 13, 2021 17:35
@mperrotti mperrotti merged commit c156b07 into main Oct 13, 2021
@mperrotti mperrotti deleted the mp/autocomplete-components branch October 13, 2021 17:46
@primer-css primer-css mentioned this pull request Oct 13, 2021
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

4 participants