Skip to content
Open
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/clever-geese-cover.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@primer/react': patch
---

UnderlineNav: Adds `overflow: hidden` when the "More" button isn't present
37 changes: 27 additions & 10 deletions packages/react/src/UnderlineNav/UnderlineNav.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -47,11 +47,12 @@ const overflowEffect = (
childArray: Array<React.ReactElement<any>>,
childWidthArray: ChildWidthArray,
noIconChildWidthArray: ChildWidthArray,
updateListAndMenu: (props: ResponsiveProps, iconsVisible: boolean) => void,
updateListAndMenu: (props: ResponsiveProps, iconsVisible: boolean, overflowMeasured: boolean) => void,
) => {
let iconsVisible = true
if (childWidthArray.length === 0) {
updateListAndMenu({items: childArray, menuItems: []}, iconsVisible)
updateListAndMenu({items: childArray, menuItems: []}, iconsVisible, false)
return
}
const numberOfItemsPossible = calculatePossibleItems(childWidthArray, navWidth)
const numberOfItemsWithoutIconPossible = calculatePossibleItems(noIconChildWidthArray, navWidth)
Expand Down Expand Up @@ -104,7 +105,7 @@ const overflowEffect = (
}
}
}
updateListAndMenu({items, menuItems}, iconsVisible)
updateListAndMenu({items, menuItems}, iconsVisible, true)
}

export const getValidChildren = (children: React.ReactNode) => {
Expand Down Expand Up @@ -166,6 +167,8 @@ export const UnderlineNav = forwardRef(
const [iconsVisible, setIconsVisible] = useState<boolean>(true)
const [childWidthArray, setChildWidthArray] = useState<ChildWidthArray>([])
const [noIconChildWidthArray, setNoIconChildWidthArray] = useState<ChildWidthArray>([])
// Track whether the initial overflow calculation is complete to prevent CLS
const [isOverflowMeasured, setIsOverflowMeasured] = useState(false)

const validChildren = getValidChildren(children)

Expand Down Expand Up @@ -209,7 +212,7 @@ export const UnderlineNav = forwardRef(
prospectiveListItem: React.ReactElement<any>,
indexOfProspectiveListItem: number,
event: React.MouseEvent<HTMLAnchorElement> | React.KeyboardEvent<HTMLAnchorElement>,
callback: (props: ResponsiveProps, displayIcons: boolean) => void,
callback: (props: ResponsiveProps, displayIcons: boolean, overflowMeasured: boolean) => void,
) => {
// get the selected menu item's width
const widthToFitIntoList = getItemsWidth(prospectiveListItem.props.children)
Expand All @@ -229,7 +232,7 @@ export const UnderlineNav = forwardRef(
const updatedMenuItems = [...menuItems]
// Add itemsToAddToMenu array's items to the menu at the index of the prospectiveListItem and remove 1 count of items (prospectiveListItem)
updatedMenuItems.splice(indexOfProspectiveListItem, 1, ...itemsToAddToMenu)
callback({items: updatedItemList, menuItems: updatedMenuItems}, false)
callback({items: updatedItemList, menuItems: updatedMenuItems}, false, true)
}
// How many items do we need to pull in to the menu to make room for the selected menu item.
function getBreakpointForItemSwapping(widthToFitIntoList: number, availableSpace: number) {
Expand All @@ -245,10 +248,17 @@ export const UnderlineNav = forwardRef(
return breakpoint
}

const updateListAndMenu = useCallback((props: ResponsiveProps, displayIcons: boolean) => {
setResponsiveProps(props)
setIconsVisible(displayIcons)
}, [])
const updateListAndMenu = useCallback(
(props: ResponsiveProps, displayIcons: boolean, overflowMeasured: boolean) => {
setResponsiveProps(props)
setIconsVisible(displayIcons)

if (overflowMeasured) {
setIsOverflowMeasured(true)
}
},
[],
)
const setChildrenWidth = useCallback((size: ChildSize) => {
setChildWidthArray(arr => {
const newArr = [...arr, size]
Expand Down Expand Up @@ -330,7 +340,14 @@ export const UnderlineNav = forwardRef(
}}
>
{ariaLabel && <VisuallyHidden as="h2">{`${ariaLabel} navigation`}</VisuallyHidden>}
<UnderlineWrapper as={as} aria-label={ariaLabel} className={className} ref={navRef} data-variant={variant}>
<UnderlineWrapper
as={as}
aria-label={ariaLabel}
className={className}
ref={navRef}
data-variant={variant}
data-overflow-measured={isOverflowMeasured ? 'true' : 'false'}
>
<UnderlineItemList ref={listRef} role="list">
{listItems}
{menuItems.length > 0 && (
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,17 @@
/* stylelint-disable-next-line primer/box-shadow */
box-shadow: inset 0 -1px var(--borderColor-muted);

/* Hide overflow until calculation is complete to prevent CLS */
overflow: visible;

&[data-overflow-measured='false'] {
overflow: hidden;
}

&[data-overflow-measured='true'] {
overflow: visible;
}

&[data-variant='flush'] {
/* stylelint-disable-next-line primer/spacing */
padding-inline: unset;
Expand Down
Loading