-
Notifications
You must be signed in to change notification settings - Fork 650
Handle React elements in UnderlineNav.Item children #7451
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
base: main
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change | ||||
|---|---|---|---|---|---|---|
|
|
@@ -14,6 +14,7 @@ import { | |||||
| import type {Meta} from '@storybook/react-vite' | ||||||
| import {UnderlineNav} from './index' | ||||||
| import {INITIAL_VIEWPORTS} from 'storybook/viewport' | ||||||
| import Popover from '../Popover' | ||||||
|
|
||||||
| const meta = { | ||||||
| title: 'Components/UnderlineNav/Features', | ||||||
|
|
@@ -154,3 +155,35 @@ export const VariantFlush = () => { | |||||
| </UnderlineNav> | ||||||
| ) | ||||||
| } | ||||||
|
|
||||||
| export const WithPopover = () => { | ||||||
| return ( | ||||||
| <UnderlineNav aria-label="Repository"> | ||||||
| <UnderlineNav.Item href="#code" leadingVisual={<CodeIcon />}> | ||||||
| Code | ||||||
| </UnderlineNav.Item> | ||||||
| <UnderlineNav.Item href="#issues" leadingVisual={<IssueOpenedIcon />}> | ||||||
| Issues | ||||||
| </UnderlineNav.Item> | ||||||
| <UnderlineNav.Item href="#security" leadingVisual={<ShieldLockIcon />} counter={12}> | ||||||
| Security | ||||||
| <Popover | ||||||
| open={true} | ||||||
|
||||||
| open={true} | |
| open |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -13,6 +13,20 @@ import {clsx} from 'clsx' | |
| // The gap between the list items. It is a constant because the gap is used to calculate the possible number of items that can fit in the container. | ||
| export const GAP = 8 | ||
|
|
||
| // Helper to extract direct text content from children for the data-content attribute. | ||
| // This is used by CSS to reserve space for bold text (preventing layout shift). | ||
| // Only extracts strings/numbers, not text from nested React elements (e.g., Popovers). | ||
| function getTextContent(children: React.ReactNode): string { | ||
| if (typeof children === 'string' || typeof children === 'number') { | ||
| return String(children) | ||
| } | ||
| if (Array.isArray(children)) { | ||
| return children.map(getTextContent).join('') | ||
| } | ||
| // Skip React elements - we only want direct text content, not text from nested components | ||
| return '' | ||
| } | ||
|
Comment on lines
+19
to
+28
|
||
|
|
||
| type UnderlineWrapperProps<As extends React.ElementType> = { | ||
| slot?: string | ||
| as?: As | ||
|
|
@@ -59,11 +73,12 @@ export type UnderlineItemProps<As extends React.ElementType> = { | |
|
|
||
| export const UnderlineItem = React.forwardRef((props, ref) => { | ||
| const {as: Component = 'a', children, counter, icon: Icon, iconsVisible, loadingCounters, className, ...rest} = props | ||
| const textContent = getTextContent(children) | ||
| return ( | ||
| <Component {...rest} ref={ref} className={clsx(classes.UnderlineItem, className)}> | ||
| {iconsVisible && Icon && <span data-component="icon">{isElement(Icon) ? Icon : <Icon />}</span>} | ||
| {children && ( | ||
| <span data-component="text" data-content={children}> | ||
| <span data-component="text" data-content={textContent || undefined}> | ||
| {children} | ||
| </span> | ||
| )} | ||
|
|
||
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.
Ran into this on slack, so leaving some unsolicited notes:
There are a few things to consider here:
anchorRefto attach itself to?I'll leave these with @hectahertz :)
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.
Ah yeah I see what you mean especially with point #3. I personally had a hard time trying to nicely position the popover on the NavItems while also rendering it outside of the UnderlineNav, so my mind is moving towards the idea of having Popover take an
anchorRefor just using a customAnchoredOverlayin github-ui where I add a custom caret to simulate the popover experience (since AnchoredOverlay already takes anchorRefs). Let me take this back to the drawing board and I'll keep in touchIn the meantime, do yall want me to continue with the fix in this PR? I can update the PR to keep the fix and I'll just remove the story I added. Otherwise I can just close it
Uh oh!
There was an error while loading. Please reload this page.
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.
Oh, I should also ask yall for the recommended guidance to achieve this popover experience on the nav bar 😅. What do you think between the custom
AchoredOverlayapproach with a caret vs adding ananchorRefto Popover? Imo adding an anchorRef to popover makes sense but I'm far from the experienced one here