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
6 changes: 6 additions & 0 deletions .changeset/proud-timers-grow.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
---
"@primer/react": patch
---

Breadcrumbs: Remove feature flag for overflow_menu, this behavior is now the default

60 changes: 13 additions & 47 deletions packages/react/src/Breadcrumbs/Breadcrumbs.features.stories.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@ import type {Meta} from '@storybook/react-vite'
import type React from 'react'
import type {ComponentProps} from '../utils/types'
import Breadcrumbs from './Breadcrumbs'
import {FeatureFlags} from '../FeatureFlags'

export default {
title: 'Components/Breadcrumbs/Features',
Expand All @@ -23,23 +22,7 @@ export const OverflowWrap = () => (
</Breadcrumbs>
)

export const OverflowMenuFeatureFlagEnabled = () => (
<FeatureFlags flags={{primer_react_breadcrumbs_overflow_menu: true}}>
<Breadcrumbs overflow="menu">
<Breadcrumbs.Item href="#">Home</Breadcrumbs.Item>
<Breadcrumbs.Item href="#">Products</Breadcrumbs.Item>
<Breadcrumbs.Item href="#">Category</Breadcrumbs.Item>
<Breadcrumbs.Item href="#">Subcategory</Breadcrumbs.Item>
<Breadcrumbs.Item href="#">Item</Breadcrumbs.Item>
<Breadcrumbs.Item href="#">Details</Breadcrumbs.Item>
<Breadcrumbs.Item href="#" selected>
Current Page
</Breadcrumbs.Item>
</Breadcrumbs>
</FeatureFlags>
)

export const OverflowMenuFeatureFlagDisabled = () => (
export const OverflowMenu = () => (
<Breadcrumbs overflow="menu">
<Breadcrumbs.Item href="#">Home</Breadcrumbs.Item>
<Breadcrumbs.Item href="#">Products</Breadcrumbs.Item>
Expand All @@ -53,7 +36,7 @@ export const OverflowMenuFeatureFlagDisabled = () => (
</Breadcrumbs>
)

export const OverflowMenuShowRootFeatureFlagDisabled = () => (
export const OverflowMenuShowRoot = () => (
<Breadcrumbs overflow="menu-with-root">
<Breadcrumbs.Item href="#">github</Breadcrumbs.Item>
<Breadcrumbs.Item href="#">Teams</Breadcrumbs.Item>
Expand All @@ -66,35 +49,18 @@ export const OverflowMenuShowRootFeatureFlagDisabled = () => (
</Breadcrumbs>
)

export const OverflowMenuShowRootFeatureFlagEnabled = () => (
<FeatureFlags flags={{primer_react_breadcrumbs_overflow_menu: true}}>
<Breadcrumbs overflow="menu-with-root">
<Breadcrumbs.Item href="#">github</Breadcrumbs.Item>
<Breadcrumbs.Item href="#">Teams</Breadcrumbs.Item>
<Breadcrumbs.Item href="#">Engineering</Breadcrumbs.Item>
<Breadcrumbs.Item href="#">core-productivity</Breadcrumbs.Item>
<Breadcrumbs.Item href="#">collaboration-workflows-flex</Breadcrumbs.Item>
<Breadcrumbs.Item href="#" selected>
global-navigation-reviewers
</Breadcrumbs.Item>
</Breadcrumbs>
</FeatureFlags>
)

export const SpaciousVariantWithOverflowMenu = () => (
<FeatureFlags flags={{primer_react_breadcrumbs_overflow_menu: true}}>
<Breadcrumbs overflow="menu" variant="spacious">
<Breadcrumbs.Item href="#">Home</Breadcrumbs.Item>
<Breadcrumbs.Item href="#">Products</Breadcrumbs.Item>
<Breadcrumbs.Item href="#">Category</Breadcrumbs.Item>
<Breadcrumbs.Item href="#">Subcategory</Breadcrumbs.Item>
<Breadcrumbs.Item href="#">Item</Breadcrumbs.Item>
<Breadcrumbs.Item href="#">Details</Breadcrumbs.Item>
<Breadcrumbs.Item href="#" selected>
Current Page
</Breadcrumbs.Item>
</Breadcrumbs>
</FeatureFlags>
<Breadcrumbs overflow="menu" variant="spacious">
<Breadcrumbs.Item href="#">Home</Breadcrumbs.Item>
<Breadcrumbs.Item href="#">Products</Breadcrumbs.Item>
<Breadcrumbs.Item href="#">Category</Breadcrumbs.Item>
<Breadcrumbs.Item href="#">Subcategory</Breadcrumbs.Item>
<Breadcrumbs.Item href="#">Item</Breadcrumbs.Item>
<Breadcrumbs.Item href="#">Details</Breadcrumbs.Item>
<Breadcrumbs.Item href="#" selected>
Current Page
</Breadcrumbs.Item>
</Breadcrumbs>
)

export const SpaciousVariantWithOverflowWrap = () => (
Expand Down
118 changes: 47 additions & 71 deletions packages/react/src/Breadcrumbs/Breadcrumbs.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@ import {useResizeObserver} from '../hooks/useResizeObserver'
import type {ResizeObserverEntry} from '../hooks/useResizeObserver'
import {useOnEscapePress} from '../hooks/useOnEscapePress'
import {useOnOutsideClick} from '../hooks/useOnOutsideClick'
import {useFeatureFlag} from '../FeatureFlags'

export type BreadcrumbsProps = React.PropsWithChildren<{
/**
Expand Down Expand Up @@ -145,8 +144,6 @@ const getValidChildren = (children: React.ReactNode) => {
}

function Breadcrumbs({className, children, style, overflow = 'wrap', variant = 'normal'}: BreadcrumbsProps) {
const overflowMenuEnabled = useFeatureFlag('primer_react_breadcrumbs_overflow_menu')
const wrappedChildren = React.Children.map(children, child => <li className={classes.ItemWrapper}>{child}</li>)
const containerRef = useRef<HTMLElement>(null)

const measureMenuButton = useCallback((element: HTMLDetailsElement | null) => {
Expand Down Expand Up @@ -176,18 +173,13 @@ function Breadcrumbs({className, children, style, overflow = 'wrap', variant = '

useEffect(() => {
const listElement = containerRef.current?.querySelector('ol')
if (
overflowMenuEnabled &&
listElement &&
listElement.children.length > 0 &&
listElement.children.length === childArray.length
) {
if (listElement && listElement.children.length > 0 && listElement.children.length === childArray.length) {
const listElementArray = Array.from(listElement.children) as HTMLElement[]
const widths = listElementArray.map(child => child.offsetWidth)
setChildArrayWidths(widths)
setRootItemWidth(listElementArray[0].offsetWidth)
}
}, [childArray, overflowMenuEnabled])
}, [childArray])

const calculateOverflow = useCallback(
(availableWidth: number) => {
Expand Down Expand Up @@ -247,7 +239,7 @@ function Breadcrumbs({className, children, style, overflow = 'wrap', variant = '

const handleResize = useCallback(
(entries: ResizeObserverEntry[]) => {
if (overflowMenuEnabled && entries[0]) {
if (entries[0]) {
const containerWidth = entries[0].contentRect.width
const result = calculateOverflow(containerWidth)
if (
Expand All @@ -260,73 +252,66 @@ function Breadcrumbs({className, children, style, overflow = 'wrap', variant = '
}
}
},
[calculateOverflow, effectiveHideRoot, menuItems.length, overflowMenuEnabled, visibleItems.length],
[calculateOverflow, effectiveHideRoot, menuItems.length, visibleItems.length],
)

useResizeObserver(handleResize, containerRef)

useEffect(() => {
if (
overflowMenuEnabled &&
(overflow === 'menu' || overflow === 'menu-with-root') &&
childArray.length > 5 &&
menuItems.length === 0
) {
if ((overflow === 'menu' || overflow === 'menu-with-root') && childArray.length > 5 && menuItems.length === 0) {
const containerWidth = containerRef.current?.offsetWidth || 800
const result = calculateOverflow(containerWidth)
setVisibleItems(result.visibleItems)
setMenuItems(result.menuItems)
setEffectiveHideRoot(result.effectiveHideRoot)
}
}, [overflow, childArray, calculateOverflow, menuItems.length, overflowMenuEnabled])
}, [overflow, childArray, calculateOverflow, menuItems.length])

const finalChildren = React.useMemo(() => {
if (overflowMenuEnabled) {
if (overflow === 'wrap' || menuItems.length === 0) {
return React.Children.map(children, child => <li className={classes.ItemWrapper}>{child}</li>)
}
if (overflow === 'wrap' || menuItems.length === 0) {
return React.Children.map(children, child => <li className={classes.ItemWrapper}>{child}</li>)
}

let effectiveMenuItems = [...menuItems]
// In 'menu-with-root' mode, include the root item inside the menu even if it's visible in the breadcrumbs
if (!effectiveHideRoot) {
effectiveMenuItems = [...menuItems.slice(1)]
}
const menuElement = (
<li className={classes.BreadcrumbsItem} key="breadcrumbs-menu">
<BreadcrumbsMenuItem
ref={measureMenuButton}
items={effectiveMenuItems}
aria-label={`${effectiveMenuItems.length} more breadcrumb items`}
/>
<ItemSeparator />
</li>
)

const visibleElements = visibleItems.map((child, index) => (
<li className={classes.BreadcrumbsItem} key={`visible + ${index}`}>
{child}
<ItemSeparator />
</li>
))

const rootElement = (
<li className={classes.BreadcrumbsItem} key={`rootElement`}>
{rootItem}
<ItemSeparator />
</li>
)

if (effectiveHideRoot) {
// Show: [overflow menu, leaf breadcrumb]
return [menuElement, ...visibleElements]
} else {
// Show: [root breadcrumb, overflow menu, leaf breadcrumb]
return [rootElement, menuElement, ...visibleElements]
}
let effectiveMenuItems = [...menuItems]
// In 'menu-with-root' mode, include the root item inside the menu even if it's visible in the breadcrumbs
if (!effectiveHideRoot) {
effectiveMenuItems = [...menuItems.slice(1)]
}
const menuElement = (
<li className={classes.BreadcrumbsItem} key="breadcrumbs-menu">
<BreadcrumbsMenuItem
ref={measureMenuButton}
items={effectiveMenuItems}
aria-label={`${effectiveMenuItems.length} more breadcrumb items`}
/>
<ItemSeparator />
</li>
)

const visibleElements = visibleItems.map((child, index) => (
<li className={classes.BreadcrumbsItem} key={`visible + ${index}`}>
{child}
<ItemSeparator />
</li>
))

const rootElement = (
<li className={classes.BreadcrumbsItem} key={`rootElement`}>
{rootItem}
<ItemSeparator />
</li>
)

if (effectiveHideRoot) {
// Show: [overflow menu, leaf breadcrumb]
return [menuElement, ...visibleElements]
} else {
// Show: [root breadcrumb, overflow menu, leaf breadcrumb]
return [rootElement, menuElement, ...visibleElements]
}
}, [overflowMenuEnabled, overflow, menuItems, effectiveHideRoot, measureMenuButton, visibleItems, rootItem, children])
}, [overflow, menuItems, effectiveHideRoot, measureMenuButton, visibleItems, rootItem, children])

return overflowMenuEnabled ? (
return (
<nav
className={clsx(className, classes.BreadcrumbsBase)}
aria-label="Breadcrumbs"
Expand All @@ -337,15 +322,6 @@ function Breadcrumbs({className, children, style, overflow = 'wrap', variant = '
>
<BreadcrumbsList>{finalChildren}</BreadcrumbsList>
</nav>
) : (
<nav
className={clsx(className, classes.BreadcrumbsBase)}
aria-label="Breadcrumbs"
style={style}
data-variant={variant}
>
<BreadcrumbsList>{wrappedChildren}</BreadcrumbsList>
</nav>
)
}

Expand Down
Loading
Loading