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

Add expand to NavList #4686

Open
wants to merge 26 commits into
base: main
Choose a base branch
from
Open

Add expand to NavList #4686

wants to merge 26 commits into from

Conversation

TylerJDev
Copy link
Contributor

@TylerJDev TylerJDev commented Jun 19, 2024

Adds new component NavList.ShowMoreItem, allows native support for "expanding" content within a NavList.

Closes https://github.com/github/primer/issues/2637

Proposed API

Basic example:

<NavList>
  <NavList.Item href="#" aria-current="page">Item 1</NavList.Item>
  <NavList.Item href="#">Item 2</NavList.Item>
  <NavList.ShowMoreItem label="Show more">
    <NavList.Item href="#">Item 3</NavList.Item>
    <NavList.Item href="#">Item 4</NavList.Item>
  </NavList.ShowMoreItem>
</NavList>

Multiple expands:

<NavList>
  <NavList.Item href="#" aria-current="page">Item 1</NavList.Item>
  <NavList.Item href="#">Item 2</NavList.Item>
  <NavList.ShowMoreItem label="Show more">
    <NavList.Item href="#">Item 3</NavList.Item>
    <NavList.Item href="#">Item 4</NavList.Item>
    <NavList.ShowMoreItem label="Show more">
      <NavList.Item href="#">Item 5</NavList.Item>
      <NavList.Item href="#">Item 6</NavList.Item>
     </NavList.ShowMoreItem>
  </NavList.ShowMoreItem>
</NavList>

Group example (storybook)

Changelog

New

  • Adds new component NavList.ShowMoreItem

Rollout strategy

  • Patch release
  • Minor release
  • Major release; if selected, include a written rollout or migration plan
  • None; if selected, include a brief description as to why

Testing & Reviewing

Merge checklist

Copy link

changeset-bot bot commented Jun 19, 2024

🦋 Changeset detected

Latest commit: 88cbc80

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

This PR includes changesets to release 1 package
Name Type
@primer/react 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

Copy link
Contributor

github-actions bot commented Jun 19, 2024

size-limit report 📦

Path Size
packages/react/dist/browser.esm.js 91.36 KB (+0.21% 🔺)
packages/react/dist/browser.umd.js 91.66 KB (+0.15% 🔺)

@TylerJDev
Copy link
Contributor Author

I'd love to try and come up with a descriptive name but it's definitely challenging 🤔 Maybe we could use NavList.ShowMoreItem to align with PVC? Which I think has the method: with_show_more_item

I think going with parity is a good idea! I renamed it to ShowMoreItem so that we're more in sync with the PVC NavList. Thank you for the suggestion! 😁

@primer primer bot requested a review from a team as a code owner July 3, 2024 15:11
@primer primer bot requested a review from emilybrick July 3, 2024 15:11
@primer primer bot temporarily deployed to github-pages July 3, 2024 15:15 Inactive
@github-actions github-actions bot temporarily deployed to storybook-preview-4686 July 3, 2024 15:16 Inactive
Copy link
Member

@joshblack joshblack 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! Just left a couple of comments/questions. Super weird question, but we don't really have a way to mark this as "experimental" since it's a sub-component, do we? 😅

@@ -288,6 +290,54 @@ const Group: React.FC<NavListGroupProps> = ({title, children, sx: sxProp = defau
)
}

export type NavListShowMoreItemProps = {
children: React.ReactNode
label: string
Copy link
Member

Choose a reason for hiding this comment

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

Could this have a default value of "Show more" or is there really not a good default for the label that is used most of the time?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

We definitely could! I feel like most use cases will have context for what the items in the NavList are for. So adding a default "Show more" shouldn't hurt, as we allow consumers to customize it further if more context is needed.

</ActionList.Item>
</Box>
) : (
<ItemWithinGroup.Provider value={{groupId}}>{children}</ItemWithinGroup.Provider>
Copy link
Member

Choose a reason for hiding this comment

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

Could we memoize this value since we're passing it to a context provider? Would help with unnecessary re-renders since this is an object defined inline.


React.useEffect(() => {
if (expanded && !targetFocused.current) {
const focusTarget: HTMLAnchorElement | null = document.querySelector(`[data-show-more-group-id="${groupId}"]`)
Copy link
Member

Choose a reason for hiding this comment

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

Will this always be an HTMLAnchorElement or could it be another type? Couldn't quite tell from NavList if it forces <a> or not so wanted to double-check 👀

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 believe so. We don't seem to force it as NavList.Item as="button" works, but it's not officially supported (e.g. styles will most likely be incorrect if it's anything but a link <a>). I think it's a safe bet to rely on the HTMLAnchorElement, but we could make it more generic!

.changeset/many-rivers-deny.md Outdated Show resolved Hide resolved
Co-authored-by: Josh Black <joshblack@github.com>
@TylerJDev
Copy link
Contributor Author

Super weird question, but we don't really have a way to mark this as "experimental" since it's a sub-component, do we? 😅

I don't think we do, but maybe this is something we'd want to have for future sub-components? 🤔

@TylerJDev
Copy link
Contributor Author

Pinging @primer/engineer-reviewers for any additional reviews!

Copy link
Member

@joshblack joshblack left a comment

Choose a reason for hiding this comment

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

This is looking great! 🔥 Just had one comment around the effect to see what you thought 👀

Comment on lines +309 to +318
if (expanded && !targetFocused.current) {
const focusTarget: HTMLAnchorElement | null = document.querySelector(
`[data-show-more-group-id="${groupId.id}"]`,
)

if (focusTarget) {
focusTarget.focus()
targetFocused.current = true
}
}
Copy link
Member

Choose a reason for hiding this comment

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

Wanted to ask if this could run in the onClick handler instead of us needing to synchronize this with an effect 👀 The benefit of tying this to the handler would be that focus would shift naturally due to interacting with the button instead of potentially being stolen if one the dependencies of the effect change that is not tied to a user interaction

Copy link
Contributor Author

@TylerJDev TylerJDev Sep 23, 2024

Choose a reason for hiding this comment

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

We could, but I think the only issue is the timing, as the node we want to focus once expanded doesn't exist yet 🤔

Something like the following works, but I'm not sure if it's counterintuitive or not 😅

onClick={() => {
  flushSync(() => {
    setExpanded(true)
  })
  expandItem()
}}

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.

3 participants