From a8e143a44e29d6711845ba6e6ebed644ca31a1ec Mon Sep 17 00:00:00 2001 From: Armagan Ersoz Date: Fri, 21 Oct 2022 17:30:26 +1000 Subject: [PATCH 1/7] Disclosure pattern implementation --- src/UnderlineNav2/UnderlineNav.tsx | 139 ++++++++++++++++++++--------- src/UnderlineNav2/styles.ts | 25 +++++- src/hooks/useOnOutsideClick.tsx | 2 +- 3 files changed, 119 insertions(+), 47 deletions(-) diff --git a/src/UnderlineNav2/UnderlineNav.tsx b/src/UnderlineNav2/UnderlineNav.tsx index cf256f9409a..fce52563426 100644 --- a/src/UnderlineNav2/UnderlineNav.tsx +++ b/src/UnderlineNav2/UnderlineNav.tsx @@ -2,16 +2,21 @@ import React, {useRef, forwardRef, useCallback, useState, MutableRefObject, RefO import Box from '../Box' import sx, {merge, BetterSystemStyleObject, SxProp} from '../sx' import {UnderlineNavContext} from './UnderlineNavContext' -import {ActionMenu} from '../ActionMenu' -import {ActionList} from '../ActionList' import {useResizeObserver, ResizeObserverEntry} from '../hooks/useResizeObserver' import CounterLabel from '../CounterLabel' import {useTheme} from '../ThemeProvider' import {ChildWidthArray, ResponsiveProps} from './types' -import {moreBtnStyles, getDividerStyle, getNavStyles, ulStyles, menuItemStyles, GAP} from './styles' +import {moreBtnStyles, getDividerStyle, getNavStyles, ulStyles, getMenuStyles, menuItemStyles, GAP} from './styles' import styled from 'styled-components' import {LoadingCounter} from './LoadingCounter' +import {Button} from '../Button' +import {useFocusZone} from '../hooks/useFocusZone' +import {FocusKeys} from '@primer/behaviors' +import {TriangleDownIcon} from '@primer/octicons-react' +import {useOnEscapePress} from '../hooks/useOnEscapePress' +import {useOnOutsideClick} from '../hooks/useOnOutsideClick' +import {ActionList} from '../ActionList' export type UnderlineNavProps = { 'aria-label'?: React.AriaAttributes['aria-label'] @@ -129,6 +134,8 @@ export const UnderlineNav = forwardRef( const navRef = (forwardedRef ?? backupRef) as MutableRefObject const listRef = useRef(null) const moreMenuRef = useRef(null) + const moreMenuBtnRef = useRef(null) + const containerRef = React.useRef(null) const {theme} = useTheme() @@ -194,6 +201,7 @@ export const UnderlineNav = forwardRef( const afterSelectHandler = (event: React.MouseEvent | React.KeyboardEvent) => { if (!event.defaultPrevented) { if (typeof afterSelect === 'function') afterSelect(event) + closeOverlay() } } @@ -235,6 +243,46 @@ export const UnderlineNav = forwardRef( // eslint-disable-next-line no-console console.warn('Use the `aria-label` prop to provide an accessible label for assistive technology') } + const [isWidgetOpen, setIsWidgetOpen] = useState(false) + + const closeOverlay = React.useCallback(() => { + setIsWidgetOpen(false) + }, [setIsWidgetOpen]) + + const toggleOverlay = React.useCallback(() => { + setIsWidgetOpen(!isWidgetOpen) + }, [setIsWidgetOpen, isWidgetOpen]) + + const focusOnMoreMenuBtn = React.useCallback(() => { + moreMenuBtnRef.current?.focus() + }, []) + + useFocusZone({ + containerRef: backupRef, + bindKeys: FocusKeys.ArrowVertical | FocusKeys.ArrowHorizontal | FocusKeys.HomeAndEnd | FocusKeys.Tab + }) + + useOnEscapePress( + (event: KeyboardEvent) => { + if (isWidgetOpen) { + event.preventDefault() + closeOverlay() + focusOnMoreMenuBtn() + } + }, + [isWidgetOpen] + ) + + useOnOutsideClick({onClickOutside: closeOverlay, containerRef, ignoreClickRefs: [moreMenuBtnRef]}) + const onAnchorClick = useCallback( + (event: React.MouseEvent) => { + if (event.defaultPrevented || event.button !== 0) { + return + } + toggleOverlay() + }, + [toggleOverlay] + ) return ( 0 && ( - - More - - - {actions.map((action, index) => { - const {children: actionElementChildren, ...actionElementProps} = action.props - return ( - - | React.KeyboardEvent - ) => { - swapMenuItemWithListItem(action, index, event, updateListAndMenu) - setSelectEvent(event) - }} - > - - {actionElementChildren} - - {loadingCounters ? ( - - ) : ( - actionElementProps.counter !== undefined && ( - {actionElementProps.counter} - ) - )} - - + + + {actions.map((action, index) => { + const {children: actionElementChildren, ...actionElementProps} = action.props + return ( + + | React.KeyboardEvent) => { + swapMenuItemWithListItem(action, index, event, updateListAndMenu) + setSelectEvent(event) + closeOverlay() + focusOnMoreMenuBtn() + }} + > + + {actionElementChildren} + + {loadingCounters ? ( + + ) : ( + actionElementProps.counter !== undefined && ( + {actionElementProps.counter} + ) + )} - ) - })} - - - + + + ) + })} + )} diff --git a/src/UnderlineNav2/styles.ts b/src/UnderlineNav2/styles.ts index 5b82b8190ce..de949690580 100644 --- a/src/UnderlineNav2/styles.ts +++ b/src/UnderlineNav2/styles.ts @@ -39,8 +39,7 @@ export const getNavStyles = (theme?: Theme, props?: Partial ({ @@ -71,7 +71,10 @@ export const moreBtnStyles = { fontWeight: 'normal', boxShadow: 'none', paddingY: 1, - paddingX: 2 + paddingX: 2, + '& > span[data-component="trailingIcon"]': { + marginLeft: 0 + } } export const getLinkStyles = ( @@ -142,3 +145,17 @@ export const menuItemStyles = { // To reset the style when the menu items are rendered as react router links textDecoration: 'none' } + +export const getMenuStyles = (theme?: Theme, isWidgetOpen?: boolean) => ({ + position: 'absolute', + top: '90%', + right: '0', + boxShadow: '0 1px 3px rgba(0, 0, 0, 0.12), 0 1px 2px rgba(0, 0, 0, 0.24)', + borderRadius: '12px', + backgroundColor: `${theme?.colors.canvas.overlay}`, + listStyle: 'none', + // Values are from ActionMenu + minWidth: '192px', + maxWidth: '640px', + display: isWidgetOpen ? 'block' : 'none' +}) diff --git a/src/hooks/useOnOutsideClick.tsx b/src/hooks/useOnOutsideClick.tsx index 9cc3d38c404..58af086f1d8 100644 --- a/src/hooks/useOnOutsideClick.tsx +++ b/src/hooks/useOnOutsideClick.tsx @@ -4,7 +4,7 @@ export type TouchOrMouseEvent = MouseEvent | TouchEvent type TouchOrMouseEventCallback = (event: TouchOrMouseEvent) => boolean | undefined export type UseOnOutsideClickSettings = { - containerRef: React.RefObject + containerRef: React.RefObject | React.RefObject ignoreClickRefs?: React.RefObject[] onClickOutside: (e: TouchOrMouseEvent) => void } From 9f99f33bb4d9ff9fe9221e1ee28128682ca099a0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arma=C4=9Fan?= Date: Tue, 25 Oct 2022 11:10:04 +1000 Subject: [PATCH 2/7] use token name for colours instead of accessing them from theme Co-authored-by: Siddharth Kshetrapal --- src/UnderlineNav2/styles.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/UnderlineNav2/styles.ts b/src/UnderlineNav2/styles.ts index de949690580..27a60d5a0c5 100644 --- a/src/UnderlineNav2/styles.ts +++ b/src/UnderlineNav2/styles.ts @@ -152,7 +152,7 @@ export const getMenuStyles = (theme?: Theme, isWidgetOpen?: boolean) => ({ right: '0', boxShadow: '0 1px 3px rgba(0, 0, 0, 0.12), 0 1px 2px rgba(0, 0, 0, 0.24)', borderRadius: '12px', - backgroundColor: `${theme?.colors.canvas.overlay}`, +backgroundColor: 'canvas.overlay' listStyle: 'none', // Values are from ActionMenu minWidth: '192px', From cbee596aa377097ae8b02d85e7e54514c22a163f Mon Sep 17 00:00:00 2001 From: Armagan Ersoz Date: Tue, 25 Oct 2022 11:39:52 +1000 Subject: [PATCH 3/7] code review feedback <3 --- src/UnderlineNav2/UnderlineNav.tsx | 31 +++++++++++++----------------- src/UnderlineNav2/styles.ts | 9 ++++----- 2 files changed, 17 insertions(+), 23 deletions(-) diff --git a/src/UnderlineNav2/UnderlineNav.tsx b/src/UnderlineNav2/UnderlineNav.tsx index fce52563426..08f19c19768 100644 --- a/src/UnderlineNav2/UnderlineNav.tsx +++ b/src/UnderlineNav2/UnderlineNav.tsx @@ -6,8 +6,7 @@ import {useResizeObserver, ResizeObserverEntry} from '../hooks/useResizeObserver import CounterLabel from '../CounterLabel' import {useTheme} from '../ThemeProvider' import {ChildWidthArray, ResponsiveProps} from './types' - -import {moreBtnStyles, getDividerStyle, getNavStyles, ulStyles, getMenuStyles, menuItemStyles, GAP} from './styles' +import {moreBtnStyles, getDividerStyle, getNavStyles, ulStyles, menuStyles, menuItemStyles, GAP} from './styles' import styled from 'styled-components' import {LoadingCounter} from './LoadingCounter' import {Button} from '../Button' @@ -17,6 +16,7 @@ import {TriangleDownIcon} from '@primer/octicons-react' import {useOnEscapePress} from '../hooks/useOnEscapePress' import {useOnOutsideClick} from '../hooks/useOnOutsideClick' import {ActionList} from '../ActionList' +import {useSSRSafeId} from '@react-aria/ssr' export type UnderlineNavProps = { 'aria-label'?: React.AriaAttributes['aria-label'] @@ -136,6 +136,7 @@ export const UnderlineNav = forwardRef( const moreMenuRef = useRef(null) const moreMenuBtnRef = useRef(null) const containerRef = React.useRef(null) + const disclosureWidgetId = useSSRSafeId() const {theme} = useTheme() @@ -249,10 +250,6 @@ export const UnderlineNav = forwardRef( setIsWidgetOpen(false) }, [setIsWidgetOpen]) - const toggleOverlay = React.useCallback(() => { - setIsWidgetOpen(!isWidgetOpen) - }, [setIsWidgetOpen, isWidgetOpen]) - const focusOnMoreMenuBtn = React.useCallback(() => { moreMenuBtnRef.current?.focus() }, []) @@ -274,15 +271,12 @@ export const UnderlineNav = forwardRef( ) useOnOutsideClick({onClickOutside: closeOverlay, containerRef, ignoreClickRefs: [moreMenuBtnRef]}) - const onAnchorClick = useCallback( - (event: React.MouseEvent) => { - if (event.defaultPrevented || event.button !== 0) { - return - } - toggleOverlay() - }, - [toggleOverlay] - ) + const onAnchorClick = useCallback((event: React.MouseEvent) => { + if (event.defaultPrevented || event.button !== 0) { + return + } + setIsWidgetOpen(isWidgetOpen => !isWidgetOpen) + }, []) return ( {actions.map((action, index) => { const {children: actionElementChildren, ...actionElementProps} = action.props diff --git a/src/UnderlineNav2/styles.ts b/src/UnderlineNav2/styles.ts index 27a60d5a0c5..e0eda108de1 100644 --- a/src/UnderlineNav2/styles.ts +++ b/src/UnderlineNav2/styles.ts @@ -146,16 +146,15 @@ export const menuItemStyles = { textDecoration: 'none' } -export const getMenuStyles = (theme?: Theme, isWidgetOpen?: boolean) => ({ +export const menuStyles = { position: 'absolute', top: '90%', right: '0', boxShadow: '0 1px 3px rgba(0, 0, 0, 0.12), 0 1px 2px rgba(0, 0, 0, 0.24)', borderRadius: '12px', -backgroundColor: 'canvas.overlay' + backgroundColor: 'canvas.overlay', listStyle: 'none', // Values are from ActionMenu minWidth: '192px', - maxWidth: '640px', - display: isWidgetOpen ? 'block' : 'none' -}) + maxWidth: '640px' +} From 53edba88f50dfab4804e13bb10e9ef601ab63788 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arma=C4=9Fan?= Date: Tue, 25 Oct 2022 12:41:58 +1000 Subject: [PATCH 4/7] [UnderlineNav2]: Always show at least 2 items in the overflow menu (A11y remediations) (#2471) * Display at least two items in the menu * add changeset --- .changeset/moody-garlics-know.md | 5 +++++ src/UnderlineNav2/UnderlineNav.tsx | 25 ++++++++++++++++++------- 2 files changed, 23 insertions(+), 7 deletions(-) create mode 100644 .changeset/moody-garlics-know.md diff --git a/.changeset/moody-garlics-know.md b/.changeset/moody-garlics-know.md new file mode 100644 index 00000000000..31af99f60e7 --- /dev/null +++ b/.changeset/moody-garlics-know.md @@ -0,0 +1,5 @@ +--- +'@primer/react': minor +--- + +UnderlineNav2: Always show at least two items in the overflow menu diff --git a/src/UnderlineNav2/UnderlineNav.tsx b/src/UnderlineNav2/UnderlineNav.tsx index 08f19c19768..9cccd2491fa 100644 --- a/src/UnderlineNav2/UnderlineNav.tsx +++ b/src/UnderlineNav2/UnderlineNav.tsx @@ -68,23 +68,34 @@ const overflowEffect = ( const items: Array = [] const actions: Array = [] - // For fine pointer devices, first we check if we can fit all the items with icons + // First, we check if we can fit all the items with their icons if (childArray.length <= numberOfItemsPossible) { items.push(...childArray) } else if (childArray.length <= numberOfItemsWithoutIconPossible) { - // if we can't fit all the items with icons, we check if we can fit all the items without icons + // if we can't fit all the items with their icons, we check if we can fit all the items without their icons iconsVisible = false items.push(...childArray) } else { - // if we can't fit all the items without icons, we keep the icons hidden and show the rest in the menu + // if we can't fit all the items without their icons, we keep the icons hidden and show the ones that doesn't fit into the list in the overflow menu iconsVisible = false + + /* Below is an accessibiility requirement. Never show only one item in the overflow menu. + * If there is only one item left to display in the overflow menu according to the calculation, + * we need to pull another item from the list into the overflow menu. + */ + const numberOfItemsInMenu = childArray.length - numberOfItemsPossibleWithMoreMenu + const numberOfListItems = + numberOfItemsInMenu === 1 ? numberOfItemsPossibleWithMoreMenu - 1 : numberOfItemsPossibleWithMoreMenu + for (const [index, child] of childArray.entries()) { - if (index < numberOfItemsPossibleWithMoreMenu) { + if (index < numberOfListItems) { items.push(child) - // keeping selected item always visible. + // We need to make sure to keep the selected item always visible. } else if (child.props.selected) { - // If selected item's index couldn't make the list, we swap it with the last item in the list. - const propsectiveAction = items.splice(numberOfItemsPossibleWithMoreMenu - 1, 1, child)[0] + // If selected item can't make it to the list, we swap it with the last item in the list. + const indexToReplaceAt = numberOfListItems - 1 // because we are replacing the last item in the list + // splice method modifies the array by removing 1 item here at the given index and replace it with the "child" element then returns the removed item. + const propsectiveAction = items.splice(indexToReplaceAt, 1, child)[0] actions.push(propsectiveAction) } else { actions.push(child) From 858b449ba0efb9c05a56ca61ebde8c633f137d3c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arma=C4=9Fan?= Date: Tue, 25 Oct 2022 12:43:16 +1000 Subject: [PATCH 5/7] [UnderlineNav2]: Add visually hidden heading where `aria-label` is present (#2470) * Add visually hidden heading * add changeset and a test * append 'navigation' to the aria-label string --- .changeset/twelve-spoons-walk.md | 5 +++++ src/UnderlineNav2/UnderlineNav.test.tsx | 6 ++++++ src/UnderlineNav2/UnderlineNav.tsx | 2 ++ 3 files changed, 13 insertions(+) create mode 100644 .changeset/twelve-spoons-walk.md diff --git a/.changeset/twelve-spoons-walk.md b/.changeset/twelve-spoons-walk.md new file mode 100644 index 00000000000..883a16eb6a3 --- /dev/null +++ b/.changeset/twelve-spoons-walk.md @@ -0,0 +1,5 @@ +--- +'@primer/react': patch +--- + +UnderlineNav2: Render a visually hidden heading for screen readers when aria-label is present diff --git a/src/UnderlineNav2/UnderlineNav.test.tsx b/src/UnderlineNav2/UnderlineNav.test.tsx index 9231b4b9b90..ff303fdb070 100644 --- a/src/UnderlineNav2/UnderlineNav.test.tsx +++ b/src/UnderlineNav2/UnderlineNav.test.tsx @@ -112,4 +112,10 @@ describe('UnderlineNav', () => { expect(loadingCounter?.className).toContain('LoadingCounter') expect(loadingCounter?.textContent).toBe('') }) + it('renders a visually hidden h2 heading for screen readers when aria-label is present', () => { + const {container} = render() + const heading = container.getElementsByTagName('h2')[0] + expect(heading.className).toContain('VisuallyHidden') + expect(heading.textContent).toBe('Repository navigation') + }) }) diff --git a/src/UnderlineNav2/UnderlineNav.tsx b/src/UnderlineNav2/UnderlineNav.tsx index 9cccd2491fa..45e17bfa157 100644 --- a/src/UnderlineNav2/UnderlineNav.tsx +++ b/src/UnderlineNav2/UnderlineNav.tsx @@ -6,6 +6,7 @@ import {useResizeObserver, ResizeObserverEntry} from '../hooks/useResizeObserver import CounterLabel from '../CounterLabel' import {useTheme} from '../ThemeProvider' import {ChildWidthArray, ResponsiveProps} from './types' +import VisuallyHidden from '../_VisuallyHidden' import {moreBtnStyles, getDividerStyle, getNavStyles, ulStyles, menuStyles, menuItemStyles, GAP} from './styles' import styled from 'styled-components' import {LoadingCounter} from './LoadingCounter' @@ -307,6 +308,7 @@ export const UnderlineNav = forwardRef( iconsVisible }} > + {ariaLabel && {`${ariaLabel} navigation`}} (getNavStyles(theme, {align}), sxProp)} From 5c907fd7d8ecb411374d496508593ff0908966b8 Mon Sep 17 00:00:00 2001 From: Armagan Ersoz Date: Tue, 25 Oct 2022 18:16:47 +1000 Subject: [PATCH 6/7] use prop for 'as' --- src/UnderlineNav2/UnderlineNav.tsx | 5 +---- src/UnderlineNav2/UnderlineNavContext.tsx | 2 -- src/UnderlineNav2/UnderlineNavItem.tsx | 6 +----- src/UnderlineNav2/examples.stories.tsx | 21 +++++++++++---------- 4 files changed, 13 insertions(+), 21 deletions(-) diff --git a/src/UnderlineNav2/UnderlineNav.tsx b/src/UnderlineNav2/UnderlineNav.tsx index 45e17bfa157..b58470ecdc3 100644 --- a/src/UnderlineNav2/UnderlineNav.tsx +++ b/src/UnderlineNav2/UnderlineNav.tsx @@ -207,8 +207,6 @@ export const UnderlineNav = forwardRef( React.MouseEvent | React.KeyboardEvent | null >(null) - const [asNavItem, setAsNavItem] = useState('a') - const [iconsVisible, setIconsVisible] = useState(true) const afterSelectHandler = (event: React.MouseEvent | React.KeyboardEvent) => { @@ -300,7 +298,6 @@ export const UnderlineNav = forwardRef( setSelectedLink, selectedLinkText, setSelectedLinkText, - setAsNavItem, selectEvent, afterSelect: afterSelectHandler, variant, @@ -343,8 +340,8 @@ export const UnderlineNav = forwardRef( | React.KeyboardEvent) => { swapMenuItemWithListItem(action, index, event, updateListAndMenu) setSelectEvent(event) diff --git a/src/UnderlineNav2/UnderlineNavContext.tsx b/src/UnderlineNav2/UnderlineNavContext.tsx index 08521017f7a..0e2b79668b2 100644 --- a/src/UnderlineNav2/UnderlineNavContext.tsx +++ b/src/UnderlineNav2/UnderlineNavContext.tsx @@ -10,7 +10,6 @@ export const UnderlineNavContext = createContext<{ selectedLinkText: string setSelectedLinkText: React.Dispatch> selectEvent: React.MouseEvent | React.KeyboardEvent | null - setAsNavItem: React.Dispatch> afterSelect?: (event: React.MouseEvent | React.KeyboardEvent) => void variant: 'default' | 'small' loadingCounters: boolean @@ -24,7 +23,6 @@ export const UnderlineNavContext = createContext<{ selectedLinkText: '', setSelectedLinkText: () => null, selectEvent: null, - setAsNavItem: () => null, variant: 'default', loadingCounters: false, iconsVisible: true diff --git a/src/UnderlineNav2/UnderlineNavItem.tsx b/src/UnderlineNav2/UnderlineNavItem.tsx index 288a088e04f..be89953c72a 100644 --- a/src/UnderlineNav2/UnderlineNavItem.tsx +++ b/src/UnderlineNav2/UnderlineNavItem.tsx @@ -72,7 +72,6 @@ export const UnderlineNavItem = forwardRef( selectedLinkText, setSelectedLinkText, selectEvent, - setAsNavItem, afterSelect, variant, loadingCounters, @@ -107,7 +106,6 @@ export const UnderlineNavItem = forwardRef( if (typeof onSelect === 'function' && selectEvent !== null) onSelect(selectEvent) setSelectedLinkText('') } - setAsNavItem(Component) }, [ ref, preSelected, @@ -118,9 +116,7 @@ export const UnderlineNavItem = forwardRef( setChildrenWidth, setNoIconChildrenWidth, onSelect, - selectEvent, - setAsNavItem, - Component + selectEvent ]) const keyPressHandler = React.useCallback( diff --git a/src/UnderlineNav2/examples.stories.tsx b/src/UnderlineNav2/examples.stories.tsx index 8f224053ff7..de02290a690 100644 --- a/src/UnderlineNav2/examples.stories.tsx +++ b/src/UnderlineNav2/examples.stories.tsx @@ -72,16 +72,16 @@ export const withCounterLabels = () => { ) } -const items: {navigation: string; icon: React.FC; counter?: number | string}[] = [ - {navigation: 'Code', icon: CodeIcon}, - {navigation: 'Issues', icon: IssueOpenedIcon, counter: '12K'}, - {navigation: 'Pull Requests', icon: GitPullRequestIcon, counter: 13}, - {navigation: 'Discussions', icon: CommentDiscussionIcon, counter: 5}, - {navigation: 'Actions', icon: PlayIcon, counter: 4}, - {navigation: 'Projects', icon: ProjectIcon, counter: 9}, - {navigation: 'Insights', icon: GraphIcon, counter: '0'}, - {navigation: 'Settings', icon: GearIcon, counter: 10}, - {navigation: 'Security', icon: ShieldLockIcon} +const items: {navigation: string; icon: React.FC; counter?: number | string; href?: string}[] = [ + {navigation: 'Code', icon: CodeIcon, href: '#code'}, + {navigation: 'Issues', icon: IssueOpenedIcon, counter: '12K', href: '#issues'}, + {navigation: 'Pull Requests', icon: GitPullRequestIcon, counter: 13, href: '#pull-requests'}, + {navigation: 'Discussions', icon: CommentDiscussionIcon, counter: 5, href: '#discussions'}, + {navigation: 'Actions', icon: PlayIcon, counter: 4, href: '#actions'}, + {navigation: 'Projects', icon: ProjectIcon, counter: 9, href: '#projects'}, + {navigation: 'Insights', icon: GraphIcon, counter: '0', href: '#insights'}, + {navigation: 'Settings', icon: GearIcon, counter: 10, href: '#settings'}, + {navigation: 'Security', icon: ShieldLockIcon, href: '#security'} ] export const InternalResponsiveNav = () => { @@ -96,6 +96,7 @@ export const InternalResponsiveNav = () => { selected={index === selectedIndex} onSelect={() => setSelectedIndex(index)} counter={item.counter} + href={item.href} > {item.navigation} From f1e411ea9f46ccc19610f98e731f51b2d42e92a0 Mon Sep 17 00:00:00 2001 From: Armagan Ersoz Date: Tue, 25 Oct 2022 18:57:55 +1000 Subject: [PATCH 7/7] add changeset --- .changeset/curly-hornets-bathe.md | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 .changeset/curly-hornets-bathe.md diff --git a/.changeset/curly-hornets-bathe.md b/.changeset/curly-hornets-bathe.md new file mode 100644 index 00000000000..a729d86b6a2 --- /dev/null +++ b/.changeset/curly-hornets-bathe.md @@ -0,0 +1,5 @@ +--- +'@primer/react': minor +--- + +UnderlineNav2: Introduce disclosure widget pattern