Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .changeset/revert-underline-nav-layout.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@primer/react': patch
---

UnderlineNav: Revert layout changes that caused issues
5 changes: 0 additions & 5 deletions .changeset/underline-item-list-flex-grow.md

This file was deleted.

Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
71 changes: 13 additions & 58 deletions packages/react/src/UnderlineNav/UnderlineNav.module.css
Original file line number Diff line number Diff line change
Expand Up @@ -4,79 +4,34 @@
is slightly better for animations. */
animation: detect-overflow linear;
animation-timeline: scroll(self block);
container-type: inline-size;

--UnderlineNav_moreButton-display: none;
--UnderlineNav_moreButton-visibility: hidden;
--UnderlineNav_icons-display: inline;

&[data-hide-icons='true'] {
--UnderlineNav_icons-display: none;
}

&[data-has-overflow='true'] {
--UnderlineNav_moreButton-display: flex;
--UnderlineNav_moreButton-visibility: visible;
}
}

/* Set overflow button visibility with pure CSS to avoid a layout shift on hydration */
@keyframes detect-overflow {
0%,
100% {
--UnderlineNav_moreButton-display: flex;
}
}

.UnderlineWrapper[data-hide-icons-breakpoint='xsmall'] {
@container (width < 20rem) {
.ItemsList [data-component='icon'] {
display: none;
}
}
}

.UnderlineWrapper[data-hide-icons-breakpoint='small'] {
@container (width < 34rem) {
.ItemsList [data-component='icon'] {
display: none;
}
}
}

.UnderlineWrapper[data-hide-icons-breakpoint='medium'] {
@container (width < 48rem) {
.ItemsList [data-component='icon'] {
display: none;
}
}
}

.UnderlineWrapper[data-hide-icons-breakpoint='large'] {
@container (width < 63.25rem) {
.ItemsList [data-component='icon'] {
display: none;
}
}
}

.UnderlineWrapper[data-hide-icons-breakpoint='xlarge'] {
@container (width < 80rem) {
.ItemsList [data-component='icon'] {
display: none;
}
}
}

.UnderlineWrapper[data-hide-icons-breakpoint='xxlarge'] {
@container (width < 87.5rem) {
.ItemsList [data-component='icon'] {
display: none;
}
--UnderlineNav_moreButton-visibility: visible;
--UnderlineNav_icons-display: none;
}
}

.WrapSpacer {
/* Cancel out the flex gap so the first real item has no leading gap */
/* stylelint-disable-next-line primer/spacing -- negative margin required to cancel the flex gap from the list */
margin-inline-end: calc(-1 * var(--stack-gap-condensed));
.ItemsList [data-component='icon'] {
display: var(--UnderlineNav_icons-display);
}

.MoreButtonContainer {
display: var(--UnderlineNav_moreButton-display, flex);
display: flex;
visibility: var(--UnderlineNav_moreButton-visibility);
align-items: center;
}

Expand Down
15 changes: 6 additions & 9 deletions packages/react/src/UnderlineNav/UnderlineNav.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -31,11 +31,6 @@ export type UnderlineNavProps = {
* Setting this to `flush` will remove the horizontal padding on the items.
*/
variant?: 'inset' | 'flush'
/**
* Customize when the icons are hidden to save space. Set to `null` to always show icons.
* Defaults to `xxlarge`; if you know there won't be very many tabs you might set this to a smaller value.
*/
hideIconsBreakpoint?: 'xsmall' | 'small' | 'medium' | 'large' | 'xlarge' | 'xxlarge' | null
}

export const UnderlineNav = forwardRef(
Expand All @@ -47,21 +42,24 @@ export const UnderlineNav = forwardRef(
variant = 'inset',
className,
children,
hideIconsBreakpoint = 'xxlarge',
}: UnderlineNavProps,
forwardedRef,
) => {
const backupRef = useRef<HTMLElement>(null)
const navRef = (forwardedRef ?? backupRef) as RefObject<HTMLElement>
const listRef = useRef<HTMLUListElement>(null)

/** Tracks whether any item has ever overflowed for the lifecycle of this component. Used to prevent flickering. */
const [hasEverOverflowed, setHasOverflowed] = useState(false)

const [registeredItems, setRegisteredItems] = UnderlineNavItemsRegistry.useRegistryState()

const overflowMenuItems = Array.from(registeredItems?.entries() ?? []).filter(
(entry): entry is [string, UnderlineNavItemProps] => entry[1] !== null,
)

const isOverflowing = overflowMenuItems.length > 0
if (isOverflowing && !hasEverOverflowed) setHasOverflowed(true)

// Find the current item if it has overflowed into the menu, so we can reflect
// its "current" state on the overflow menu anchor.
Expand Down Expand Up @@ -98,13 +96,12 @@ export const UnderlineNav = forwardRef(
ref={navRef}
data-variant={variant}
data-overflow-mode="wrap"
data-hide-icons-breakpoint={hideIconsBreakpoint ?? undefined}
// Force icons to stay hidden, avoiding flickering as icons create/remove overflow
data-hide-icons={hasEverOverflowed ? 'true' : undefined}
// Ensure button is shown (after initial render) on browsers that don't support scroll-driven animations
data-has-overflow={isOverflowing ? 'true' : undefined}
>
<UnderlineItemList ref={listRef} role="list" className={classes.ItemsList}>
{/* Empty first element allows real first item to wrap out of view on tiny screens */}
<li role="presentation" aria-hidden className={classes.WrapSpacer} />
<OverflowObserverProvider rootRef={navRef}>
<UnderlineNavItemsRegistry.Provider setRegistry={setRegisteredItems}>
{children}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,10 @@
padding-inline: unset;
}

&[data-hide-icons='true'] [data-component='icon'] {
display: none;
}

&[data-overflow-mode='wrap'] {
/* Wrap items onto hidden next lines */
overflow: hidden;
Expand All @@ -29,7 +33,6 @@
padding-block: var(--base-size-8) 0 !important;

.UnderlineItemList {
flex-grow: 1;
flex-wrap: wrap;
overflow: hidden;
}
Expand Down
Loading